1/*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef gr_instanced_InstancedRenderingTypes_DEFINED
9#define gr_instanced_InstancedRenderingTypes_DEFINED
10
11#include "GrTypes.h"
12#include "GrTypesPriv.h"
13#include "SkRRect.h"
14
15namespace gr_instanced {
16
17/**
18 * Per-vertex data. These values get fed into normal vertex attribs.
19 */
20struct ShapeVertex {
21    float     fX, fY;  //!< Shape coordinates.
22    int32_t   fAttrs;  //!< Shape-specific vertex attributes, if needed.
23};
24
25/**
26 * Per-instance data. These values get fed into instanced vertex attribs.
27 */
28struct Instance {
29    uint32_t   fInfo;               //!< Packed info about the instance. See InfoBits.
30    float      fShapeMatrix2x3[6];  //!< Maps canonical shape coords -> device space coords.
31    uint32_t   fColor;              //!< Color to be written out by the primitive processor.
32    float      fLocalRect[4];       //!< Local coords rect that spans [-1, +1] in shape coords.
33};
34
35enum class Attrib : uint8_t {
36    kShapeCoords,
37    kVertexAttrs,
38    kInstanceInfo,
39    kShapeMatrixX,
40    kShapeMatrixY,
41    kColor,
42    kLocalRect
43};
44constexpr int kNumAttribs = 1 + (int)Attrib::kLocalRect;
45
46enum class ShapeType : uint8_t {
47    kRect,
48    kOval,
49    kSimpleRRect,
50    kNinePatch,
51    kComplexRRect
52};
53constexpr int kNumShapeTypes = 1 + (int)ShapeType::kComplexRRect;
54
55inline static ShapeType GetRRectShapeType(const SkRRect& rrect) {
56    SkASSERT(rrect.getType() >= SkRRect::kRect_Type &&
57             rrect.getType() <= SkRRect::kComplex_Type);
58    return static_cast<ShapeType>(rrect.getType() - 1);
59
60    GR_STATIC_ASSERT((int)ShapeType::kRect == SkRRect::kRect_Type - 1);
61    GR_STATIC_ASSERT((int)ShapeType::kOval == SkRRect::kOval_Type - 1);
62    GR_STATIC_ASSERT((int)ShapeType::kSimpleRRect == SkRRect::kSimple_Type - 1);
63    GR_STATIC_ASSERT((int)ShapeType::kNinePatch == SkRRect::kNinePatch_Type - 1);
64    GR_STATIC_ASSERT((int)ShapeType::kComplexRRect == SkRRect::kComplex_Type - 1);
65    GR_STATIC_ASSERT(kNumShapeTypes == SkRRect::kComplex_Type);
66}
67
68enum ShapeFlag {
69    kRect_ShapeFlag          = (1 << (int)ShapeType::kRect),
70    kOval_ShapeFlag          = (1 << (int)ShapeType::kOval),
71    kSimpleRRect_ShapeFlag   = (1 << (int)ShapeType::kSimpleRRect),
72    kNinePatch_ShapeFlag     = (1 << (int)ShapeType::kNinePatch),
73    kComplexRRect_ShapeFlag  = (1 << (int)ShapeType::kComplexRRect),
74
75    kRRect_ShapesMask = kSimpleRRect_ShapeFlag | kNinePatch_ShapeFlag | kComplexRRect_ShapeFlag
76};
77
78constexpr uint8_t GetShapeFlag(ShapeType type) { return 1 << (int)type; }
79
80/**
81 * Defines what data is stored at which bits in the fInfo field of the instanced data.
82 */
83enum InfoBits {
84    kShapeType_InfoBit       = 29,
85    kInnerShapeType_InfoBit  = 27,
86    kPerspective_InfoBit     = 26,
87    kLocalMatrix_InfoBit     = 25,
88    kParamsIdx_InfoBit       =  0
89};
90
91enum InfoMasks {
92    kShapeType_InfoMask       = 0u - (1 << kShapeType_InfoBit),
93    kInnerShapeType_InfoMask  = (1 << kShapeType_InfoBit) - (1 << kInnerShapeType_InfoBit),
94    kPerspective_InfoFlag     = (1 << kPerspective_InfoBit),
95    kLocalMatrix_InfoFlag     = (1 << kLocalMatrix_InfoBit),
96    kParamsIdx_InfoMask       = (1 << kLocalMatrix_InfoBit) - 1
97};
98
99GR_STATIC_ASSERT((kNumShapeTypes - 1) <= (uint32_t)kShapeType_InfoMask >> kShapeType_InfoBit);
100GR_STATIC_ASSERT((int)ShapeType::kSimpleRRect <=
101                 kInnerShapeType_InfoMask >> kInnerShapeType_InfoBit);
102
103/**
104 * Additional parameters required by some instances (e.g. round rect radii, perspective column,
105 * local matrix). These are accessed via texel buffer.
106 */
107struct ParamsTexel {
108    float fX, fY, fZ, fW;
109};
110
111GR_STATIC_ASSERT(0 == offsetof(ParamsTexel, fX));
112GR_STATIC_ASSERT(4 * 4 == sizeof(ParamsTexel));
113
114/**
115 * Tracks all information needed in order to draw a op of instances. This struct also serves
116 * as an all-in-one shader key for the op.
117 */
118struct OpInfo {
119    OpInfo() : fData(0) {}
120    explicit OpInfo(uint32_t data) : fData(data) {}
121
122    static bool CanCombine(const OpInfo& a, const OpInfo& b);
123
124    bool isSimpleRects() const {
125        return !((fShapeTypes & ~kRect_ShapeFlag) | fInnerShapeTypes);
126    }
127
128    GrAAType aaType() const { return static_cast<GrAAType>(fAAType); }
129    void setAAType(GrAAType aaType) { fAAType = static_cast<uint8_t>(aaType); }
130
131    union {
132        struct {
133            uint8_t         fAAType;  // GrAAType
134            uint8_t         fShapeTypes;
135            uint8_t         fInnerShapeTypes;
136            bool            fHasPerspective               : 1;
137            bool            fHasLocalMatrix               : 1;
138            bool            fHasParams                    : 1;
139            bool            fNonSquare                    : 1;
140            bool            fUsesLocalCoords              : 1;
141            bool            fCannotTweakAlphaForCoverage  : 1;
142            bool            fCannotDiscard                : 1;
143        };
144        uint32_t fData;
145    };
146};
147
148inline bool OpInfo::CanCombine(const OpInfo& a, const OpInfo& b) {
149    if (a.fAAType != b.fAAType) {
150        return false;
151    }
152    if (SkToBool(a.fInnerShapeTypes) != SkToBool(b.fInnerShapeTypes)) {
153        // GrInstanceProcessor can't currently combine draws with and without inner shapes.
154        return false;
155    }
156    if (a.fCannotDiscard != b.fCannotDiscard) {
157        // For stencil draws, the use of discard can be a requirement.
158        return false;
159    }
160    return true;
161}
162
163inline OpInfo operator|(const OpInfo& a, const OpInfo& b) {
164    SkASSERT(OpInfo::CanCombine(a, b));
165    return OpInfo(a.fData | b.fData);
166}
167
168// This is required since all the data must fit into 32 bits of a shader key.
169GR_STATIC_ASSERT(sizeof(uint32_t) == sizeof(OpInfo));
170GR_STATIC_ASSERT(kNumShapeTypes <= 8);
171
172struct IndexRange {
173    bool operator ==(const IndexRange& that) const {
174        SkASSERT(fStart != that.fStart || fCount == that.fCount);
175        return fStart == that.fStart;
176    }
177    bool operator !=(const IndexRange& that) const { return !(*this == that); }
178
179    bool isEmpty() const { return fCount <= 0; }
180    int end() { return fStart + fCount; }
181
182    int16_t fStart;
183    int16_t fCount;
184};
185
186}
187
188#endif
189