aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu/ops/GrSmallPathRenderer.h
blob: 8794f1b42c327ca9e2e7c0c62f0dc42271b3f79f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/*
 * Copyright 2014 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#ifndef GrSmallPathRenderer_DEFINED
#define GrSmallPathRenderer_DEFINED

#include "GrDrawOpAtlas.h"
#include "GrOnFlushResourceProvider.h"
#include "GrPathRenderer.h"
#include "GrRect.h"
#include "GrShape.h"

#include "SkOpts.h"
#include "SkTDynamicHash.h"

class GrContext;

class GrSmallPathRenderer : public GrPathRenderer, public GrOnFlushCallbackObject {
public:
    GrSmallPathRenderer();
    ~GrSmallPathRenderer() override;

    class SmallPathOp;
    struct PathTestStruct;

    // GrOnFlushCallbackObject overrides
    //
    // Note: because this class is associated with a path renderer we want it to be removed from
    // the list of active OnFlushBackkbackObjects in an freeGpuResources call (i.e., we accept the
    // default retainOnFreeGpuResources implementation).

    void preFlush(GrOnFlushResourceProvider*, const uint32_t*, int,
                  SkTArray<sk_sp<GrRenderTargetContext>>*) override {}

    void postFlush(GrDeferredUploadToken startTokenForNextFlush) override {
        if (fAtlas) {
            fAtlas->compact(startTokenForNextFlush);
        }
    }

private:
    StencilSupport onGetStencilSupport(const GrShape&) const override {
        return GrPathRenderer::kNoSupport_StencilSupport;
    }

    CanDrawPath onCanDrawPath(const CanDrawPathArgs&) const override;

    bool onDrawPath(const DrawPathArgs&) override;

    struct ShapeData {
        class Key {
        public:
            Key() {}
            Key(const Key& that) { *this = that; }
            Key(const GrShape& shape, uint32_t dim) { this->set(shape, dim); }
            Key(const GrShape& shape, const SkMatrix& ctm) { this->set(shape, ctm); }

            Key& operator=(const Key& that) {
                fKey.reset(that.fKey.count());
                memcpy(fKey.get(), that.fKey.get(), fKey.count() * sizeof(uint32_t));
                return *this;
            }

            // for SDF paths
            void set(const GrShape& shape, uint32_t dim) {
                // Shapes' keys are for their pre-style geometry, but by now we shouldn't have any
                // relevant styling information.
                SkASSERT(shape.style().isSimpleFill());
                SkASSERT(shape.hasUnstyledKey());
                int shapeKeySize = shape.unstyledKeySize();
                fKey.reset(1 + shapeKeySize);
                fKey[0] = dim;
                shape.writeUnstyledKey(&fKey[1]);
            }

            // for bitmap paths
            void set(const GrShape& shape, const SkMatrix& ctm) {
                // Shapes' keys are for their pre-style geometry, but by now we shouldn't have any
                // relevant styling information.
                SkASSERT(shape.style().isSimpleFill());
                SkASSERT(shape.hasUnstyledKey());
                // We require the upper left 2x2 of the matrix to match exactly for a cache hit.
                SkScalar sx = ctm.get(SkMatrix::kMScaleX);
                SkScalar sy = ctm.get(SkMatrix::kMScaleY);
                SkScalar kx = ctm.get(SkMatrix::kMSkewX);
                SkScalar ky = ctm.get(SkMatrix::kMSkewY);
                SkScalar tx = ctm.get(SkMatrix::kMTransX);
                SkScalar ty = ctm.get(SkMatrix::kMTransY);
                // Allow 8 bits each in x and y of subpixel positioning.
                SkFixed fracX = SkScalarToFixed(SkScalarFraction(tx)) & 0x0000FF00;
                SkFixed fracY = SkScalarToFixed(SkScalarFraction(ty)) & 0x0000FF00;
                int shapeKeySize = shape.unstyledKeySize();
                fKey.reset(5 + shapeKeySize);
                fKey[0] = SkFloat2Bits(sx);
                fKey[1] = SkFloat2Bits(sy);
                fKey[2] = SkFloat2Bits(kx);
                fKey[3] = SkFloat2Bits(ky);
                fKey[4] = fracX | (fracY >> 8);
                shape.writeUnstyledKey(&fKey[5]);
            }

            bool operator==(const Key& that) const {
                return fKey.count() == that.fKey.count() &&
                        0 == memcmp(fKey.get(), that.fKey.get(), sizeof(uint32_t) * fKey.count());
            }

            int count32() const { return fKey.count(); }
            const uint32_t* data() const { return fKey.get(); }

        private:
            // The key is composed of the GrShape's key, and either the dimensions of the DF
            // generated for the path (32x32 max, 64x64 max, 128x128 max) if an SDF image or
            // the matrix for the path with only fractional translation.
            SkAutoSTArray<24, uint32_t> fKey;
        };
        Key                    fKey;
        GrDrawOpAtlas::AtlasID fID;
        SkRect                 fBounds;
        GrIRect16              fTextureCoords;
        SK_DECLARE_INTERNAL_LLIST_INTERFACE(ShapeData);

        static inline const Key& GetKey(const ShapeData& data) {
            return data.fKey;
        }

        static inline uint32_t Hash(Key key) {
            return SkOpts::hash(key.data(), sizeof(uint32_t) * key.count32());
        }
    };

    static void HandleEviction(GrDrawOpAtlas::AtlasID, void*);

    typedef SkTDynamicHash<ShapeData, ShapeData::Key> ShapeCache;
    typedef SkTInternalLList<ShapeData> ShapeDataList;

    std::unique_ptr<GrDrawOpAtlas> fAtlas;
    ShapeCache fShapeCache;
    ShapeDataList fShapeList;

    typedef GrPathRenderer INHERITED;
};

#endif