blob: 8626eb92d4108ba6ae668e202554b3a4e97d28b2 [file] [log] [blame]
csmartdaltona7f29642016-07-07 08:49:11 -07001/*
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#include "InstanceProcessor.h"
9
10#include "GrContext.h"
11#include "GrRenderTargetPriv.h"
12#include "GrResourceCache.h"
13#include "GrResourceProvider.h"
Brian Salomon94efbf52016-11-29 13:43:05 -050014#include "GrShaderCaps.h"
csmartdaltona7f29642016-07-07 08:49:11 -070015#include "glsl/GrGLSLGeometryProcessor.h"
16#include "glsl/GrGLSLFragmentShaderBuilder.h"
17#include "glsl/GrGLSLProgramBuilder.h"
18#include "glsl/GrGLSLVarying.h"
19
20namespace gr_instanced {
21
Brian Salomon1edc5b92016-11-29 13:43:46 -050022GrCaps::InstancedSupport InstanceProcessor::CheckSupport(const GrShaderCaps& shaderCaps,
csmartdaltone0d36292016-07-29 08:14:20 -070023 const GrCaps& caps) {
Brian Salomon1edc5b92016-11-29 13:43:46 -050024 if (!shaderCaps.canUseAnyFunctionInShader() ||
25 !shaderCaps.flatInterpolationSupport() ||
26 !shaderCaps.integerSupport() ||
27 0 == shaderCaps.maxVertexSamplers() ||
csmartdaltona7f29642016-07-07 08:49:11 -070028 !caps.shaderCaps()->texelBufferSupport() ||
29 caps.maxVertexAttributes() < kNumAttribs) {
csmartdaltone0d36292016-07-29 08:14:20 -070030 return GrCaps::InstancedSupport::kNone;
csmartdaltona7f29642016-07-07 08:49:11 -070031 }
csmartdaltone0d36292016-07-29 08:14:20 -070032 if (!caps.sampleLocationsSupport() ||
Brian Salomon1edc5b92016-11-29 13:43:46 -050033 !shaderCaps.sampleVariablesSupport() ||
34 !shaderCaps.shaderDerivativeSupport()) {
csmartdaltone0d36292016-07-29 08:14:20 -070035 return GrCaps::InstancedSupport::kBasic;
csmartdaltona7f29642016-07-07 08:49:11 -070036 }
csmartdaltone0d36292016-07-29 08:14:20 -070037 if (0 == caps.maxRasterSamples() ||
Brian Salomon1edc5b92016-11-29 13:43:46 -050038 !shaderCaps.sampleMaskOverrideCoverageSupport()) {
csmartdaltone0d36292016-07-29 08:14:20 -070039 return GrCaps::InstancedSupport::kMultisampled;
40 }
41 return GrCaps::InstancedSupport::kMixedSampled;
csmartdaltona7f29642016-07-07 08:49:11 -070042}
43
Brian Salomon99ad1642016-12-16 09:50:45 -050044InstanceProcessor::InstanceProcessor(OpInfo opInfo, GrBuffer* paramsBuffer) : fOpInfo(opInfo) {
csmartdaltona7f29642016-07-07 08:49:11 -070045 this->initClassID<InstanceProcessor>();
46
bsalomon6cb807b2016-08-17 11:33:39 -070047 this->addVertexAttrib("shapeCoords", kVec2f_GrVertexAttribType, kHigh_GrSLPrecision);
48 this->addVertexAttrib("vertexAttrs", kInt_GrVertexAttribType);
49 this->addVertexAttrib("instanceInfo", kUint_GrVertexAttribType);
50 this->addVertexAttrib("shapeMatrixX", kVec3f_GrVertexAttribType, kHigh_GrSLPrecision);
51 this->addVertexAttrib("shapeMatrixY", kVec3f_GrVertexAttribType, kHigh_GrSLPrecision);
52 this->addVertexAttrib("color", kVec4f_GrVertexAttribType, kLow_GrSLPrecision);
53 this->addVertexAttrib("localRect", kVec4f_GrVertexAttribType, kHigh_GrSLPrecision);
csmartdaltona7f29642016-07-07 08:49:11 -070054
55 GR_STATIC_ASSERT(0 == (int)Attrib::kShapeCoords);
56 GR_STATIC_ASSERT(1 == (int)Attrib::kVertexAttrs);
57 GR_STATIC_ASSERT(2 == (int)Attrib::kInstanceInfo);
58 GR_STATIC_ASSERT(3 == (int)Attrib::kShapeMatrixX);
59 GR_STATIC_ASSERT(4 == (int)Attrib::kShapeMatrixY);
60 GR_STATIC_ASSERT(5 == (int)Attrib::kColor);
61 GR_STATIC_ASSERT(6 == (int)Attrib::kLocalRect);
62 GR_STATIC_ASSERT(7 == kNumAttribs);
63
Brian Salomon99ad1642016-12-16 09:50:45 -050064 if (fOpInfo.fHasParams) {
csmartdaltona7f29642016-07-07 08:49:11 -070065 SkASSERT(paramsBuffer);
66 fParamsAccess.reset(kRGBA_float_GrPixelConfig, paramsBuffer, kVertex_GrShaderFlag);
67 this->addBufferAccess(&fParamsAccess);
68 }
69
Brian Salomon99ad1642016-12-16 09:50:45 -050070 if (fOpInfo.fAntialiasMode >= AntialiasMode::kMSAA) {
71 if (!fOpInfo.isSimpleRects() || AntialiasMode::kMixedSamples == fOpInfo.fAntialiasMode) {
csmartdaltona7f29642016-07-07 08:49:11 -070072 this->setWillUseSampleLocations();
73 }
74 }
75}
76
77class GLSLInstanceProcessor : public GrGLSLGeometryProcessor {
78public:
79 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override;
80
81private:
bsalomona624bf32016-09-20 09:12:47 -070082 void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor&,
83 FPCoordTransformIter&& transformIter) override {
84 this->setTransformDataHelper(SkMatrix::I(), pdman, &transformIter);
85 }
csmartdaltona7f29642016-07-07 08:49:11 -070086
87 class VertexInputs;
88 class Backend;
89 class BackendNonAA;
90 class BackendCoverage;
91 class BackendMultisample;
92
93 typedef GrGLSLGeometryProcessor INHERITED;
94};
95
Brian Salomon94efbf52016-11-29 13:43:05 -050096GrGLSLPrimitiveProcessor* InstanceProcessor::createGLSLInstance(const GrShaderCaps&) const {
csmartdaltona7f29642016-07-07 08:49:11 -070097 return new GLSLInstanceProcessor();
98}
99
100class GLSLInstanceProcessor::VertexInputs {
101public:
102 VertexInputs(const InstanceProcessor& instProc, GrGLSLVertexBuilder* vertexBuilder)
103 : fInstProc(instProc),
104 fVertexBuilder(vertexBuilder) {
105 }
106
107 void initParams(const SamplerHandle paramsBuffer) {
108 fParamsBuffer = paramsBuffer;
Ethan Nicholas1fc83b12016-11-22 09:31:35 -0500109 fVertexBuilder->codeAppendf("highp int paramsIdx = int(%s & 0x%x);",
ethannicholas5961bc92016-10-12 06:39:56 -0700110 this->attr(Attrib::kInstanceInfo),
111 kParamsIdx_InfoMask);
csmartdaltona7f29642016-07-07 08:49:11 -0700112 }
113
114 const char* attr(Attrib attr) const { return fInstProc.getAttrib((int)attr).fName; }
115
116 void fetchNextParam(GrSLType type = kVec4f_GrSLType) const {
117 SkASSERT(fParamsBuffer.isValid());
118 if (type != kVec4f_GrSLType) {
119 fVertexBuilder->codeAppendf("%s(", GrGLSLTypeString(type));
120 }
121 fVertexBuilder->appendTexelFetch(fParamsBuffer, "paramsIdx++");
122 if (type != kVec4f_GrSLType) {
123 fVertexBuilder->codeAppend(")");
124 }
125 }
126
127 void skipParams(unsigned n) const {
128 SkASSERT(fParamsBuffer.isValid());
129 fVertexBuilder->codeAppendf("paramsIdx += %u;", n);
130 }
131
132private:
133 const InstanceProcessor& fInstProc;
134 GrGLSLVertexBuilder* fVertexBuilder;
135 SamplerHandle fParamsBuffer;
136};
137
138class GLSLInstanceProcessor::Backend {
139public:
Brian Salomon99ad1642016-12-16 09:50:45 -0500140 static Backend* SK_WARN_UNUSED_RESULT Create(const GrPipeline&, OpInfo, const VertexInputs&);
csmartdaltona7f29642016-07-07 08:49:11 -0700141 virtual ~Backend() {}
142
143 void init(GrGLSLVaryingHandler*, GrGLSLVertexBuilder*);
144 virtual void setupRect(GrGLSLVertexBuilder*) = 0;
145 virtual void setupOval(GrGLSLVertexBuilder*) = 0;
csmartdalton0caee172016-07-13 08:48:53 -0700146 void setupRRect(GrGLSLVertexBuilder*, int* usedShapeDefinitions);
csmartdaltona7f29642016-07-07 08:49:11 -0700147
148 void initInnerShape(GrGLSLVaryingHandler*, GrGLSLVertexBuilder*);
149 virtual void setupInnerRect(GrGLSLVertexBuilder*) = 0;
150 virtual void setupInnerOval(GrGLSLVertexBuilder*) = 0;
csmartdalton0caee172016-07-13 08:48:53 -0700151 void setupInnerSimpleRRect(GrGLSLVertexBuilder*);
csmartdaltona7f29642016-07-07 08:49:11 -0700152
153 const char* outShapeCoords() {
154 return fModifiedShapeCoords ? fModifiedShapeCoords : fInputs.attr(Attrib::kShapeCoords);
155 }
156
157 void emitCode(GrGLSLVertexBuilder*, GrGLSLPPFragmentBuilder*, const char* outCoverage,
158 const char* outColor);
159
160protected:
Brian Salomon99ad1642016-12-16 09:50:45 -0500161 Backend(OpInfo opInfo, const VertexInputs& inputs)
162 : fOpInfo(opInfo)
163 , fInputs(inputs)
164 , fModifiesCoverage(false)
165 , fModifiesColor(false)
166 , fNeedsNeighborRadii(false)
167 , fColor(kVec4f_GrSLType)
168 , fTriangleIsArc(kInt_GrSLType)
169 , fArcCoords(kVec2f_GrSLType)
170 , fInnerShapeCoords(kVec2f_GrSLType)
171 , fInnerRRect(kVec4f_GrSLType)
172 , fModifiedShapeCoords(nullptr) {
173 if (fOpInfo.fShapeTypes & kRRect_ShapesMask) {
csmartdaltona7f29642016-07-07 08:49:11 -0700174 fModifiedShapeCoords = "adjustedShapeCoords";
175 }
176 }
177
178 virtual void onInit(GrGLSLVaryingHandler*, GrGLSLVertexBuilder*) = 0;
179 virtual void adjustRRectVertices(GrGLSLVertexBuilder*);
180 virtual void onSetupRRect(GrGLSLVertexBuilder*) {}
181
182 virtual void onInitInnerShape(GrGLSLVaryingHandler*, GrGLSLVertexBuilder*) = 0;
csmartdalton0caee172016-07-13 08:48:53 -0700183 virtual void onSetupInnerSimpleRRect(GrGLSLVertexBuilder*) = 0;
csmartdaltona7f29642016-07-07 08:49:11 -0700184
185 virtual void onEmitCode(GrGLSLVertexBuilder*, GrGLSLPPFragmentBuilder*,
186 const char* outCoverage, const char* outColor) = 0;
187
188 void setupSimpleRadii(GrGLSLVertexBuilder*);
189 void setupNinePatchRadii(GrGLSLVertexBuilder*);
190 void setupComplexRadii(GrGLSLVertexBuilder*);
191
Brian Salomon99ad1642016-12-16 09:50:45 -0500192 const OpInfo fOpInfo;
193 const VertexInputs& fInputs;
194 bool fModifiesCoverage;
195 bool fModifiesColor;
196 bool fNeedsNeighborRadii;
197 GrGLSLVertToFrag fColor;
198 GrGLSLVertToFrag fTriangleIsArc;
199 GrGLSLVertToFrag fArcCoords;
200 GrGLSLVertToFrag fInnerShapeCoords;
201 GrGLSLVertToFrag fInnerRRect;
202 const char* fModifiedShapeCoords;
csmartdaltona7f29642016-07-07 08:49:11 -0700203};
204
205void GLSLInstanceProcessor::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) {
206 const GrPipeline& pipeline = args.fVertBuilder->getProgramBuilder()->pipeline();
207 const InstanceProcessor& ip = args.fGP.cast<InstanceProcessor>();
208 GrGLSLUniformHandler* uniHandler = args.fUniformHandler;
209 GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
210 GrGLSLVertexBuilder* v = args.fVertBuilder;
211 GrGLSLPPFragmentBuilder* f = args.fFragBuilder;
212
213 varyingHandler->emitAttributes(ip);
214
215 VertexInputs inputs(ip, v);
Brian Salomon99ad1642016-12-16 09:50:45 -0500216 if (ip.opInfo().fHasParams) {
csmartdaltona7f29642016-07-07 08:49:11 -0700217 SkASSERT(1 == ip.numBuffers());
218 inputs.initParams(args.fBufferSamplers[0]);
219 }
220
Brian Salomon99ad1642016-12-16 09:50:45 -0500221 if (!ip.opInfo().fHasPerspective) {
csmartdaltona7f29642016-07-07 08:49:11 -0700222 v->codeAppendf("mat2x3 shapeMatrix = mat2x3(%s, %s);",
223 inputs.attr(Attrib::kShapeMatrixX), inputs.attr(Attrib::kShapeMatrixY));
224 } else {
ethannicholas5961bc92016-10-12 06:39:56 -0700225 v->defineConstantf("int", "PERSPECTIVE_FLAG", "0x%x", kPerspective_InfoFlag);
csmartdaltona7f29642016-07-07 08:49:11 -0700226 v->codeAppendf("mat3 shapeMatrix = mat3(%s, %s, vec3(0, 0, 1));",
227 inputs.attr(Attrib::kShapeMatrixX), inputs.attr(Attrib::kShapeMatrixY));
ethannicholas5961bc92016-10-12 06:39:56 -0700228 v->codeAppendf("if (0 != (%s & PERSPECTIVE_FLAG)) {",
csmartdaltona7f29642016-07-07 08:49:11 -0700229 inputs.attr(Attrib::kInstanceInfo));
230 v->codeAppend ( "shapeMatrix[2] = ");
231 inputs.fetchNextParam(kVec3f_GrSLType);
232 v->codeAppend ( ";");
233 v->codeAppend ("}");
234 }
235
Brian Salomon99ad1642016-12-16 09:50:45 -0500236 bool hasSingleShapeType = SkIsPow2(ip.opInfo().fShapeTypes);
csmartdaltona7f29642016-07-07 08:49:11 -0700237 if (!hasSingleShapeType) {
ethannicholas5961bc92016-10-12 06:39:56 -0700238 v->defineConstant("SHAPE_TYPE_BIT", kShapeType_InfoBit);
csmartdaltona7f29642016-07-07 08:49:11 -0700239 v->codeAppendf("uint shapeType = %s >> SHAPE_TYPE_BIT;",
240 inputs.attr(Attrib::kInstanceInfo));
241 }
242
Brian Salomon99ad1642016-12-16 09:50:45 -0500243 std::unique_ptr<Backend> backend(Backend::Create(pipeline, ip.opInfo(), inputs));
csmartdaltona7f29642016-07-07 08:49:11 -0700244 backend->init(varyingHandler, v);
245
csmartdalton0caee172016-07-13 08:48:53 -0700246 int usedShapeDefinitions = 0;
247
Brian Salomon99ad1642016-12-16 09:50:45 -0500248 if (hasSingleShapeType || !(ip.opInfo().fShapeTypes & ~kRRect_ShapesMask)) {
249 if (kRect_ShapeFlag == ip.opInfo().fShapeTypes) {
csmartdaltona7f29642016-07-07 08:49:11 -0700250 backend->setupRect(v);
Brian Salomon99ad1642016-12-16 09:50:45 -0500251 } else if (kOval_ShapeFlag == ip.opInfo().fShapeTypes) {
csmartdaltona7f29642016-07-07 08:49:11 -0700252 backend->setupOval(v);
253 } else {
csmartdalton0caee172016-07-13 08:48:53 -0700254 backend->setupRRect(v, &usedShapeDefinitions);
csmartdaltona7f29642016-07-07 08:49:11 -0700255 }
256 } else {
Brian Salomon99ad1642016-12-16 09:50:45 -0500257 if (ip.opInfo().fShapeTypes & kRRect_ShapesMask) {
csmartdalton0caee172016-07-13 08:48:53 -0700258 v->codeAppend ("if (shapeType >= SIMPLE_R_RECT_SHAPE_TYPE) {");
259 backend->setupRRect(v, &usedShapeDefinitions);
260 v->codeAppend ("}");
261 usedShapeDefinitions |= kSimpleRRect_ShapeFlag;
csmartdaltona7f29642016-07-07 08:49:11 -0700262 }
Brian Salomon99ad1642016-12-16 09:50:45 -0500263 if (ip.opInfo().fShapeTypes & kOval_ShapeFlag) {
264 if (ip.opInfo().fShapeTypes & kRect_ShapeFlag) {
265 if (ip.opInfo().fShapeTypes & kRRect_ShapesMask) {
csmartdalton0caee172016-07-13 08:48:53 -0700266 v->codeAppend ("else ");
267 }
268 v->codeAppend ("if (OVAL_SHAPE_TYPE == shapeType) {");
269 usedShapeDefinitions |= kOval_ShapeFlag;
270 } else {
271 v->codeAppend ("else {");
272 }
csmartdaltona7f29642016-07-07 08:49:11 -0700273 backend->setupOval(v);
csmartdalton0caee172016-07-13 08:48:53 -0700274 v->codeAppend ("}");
csmartdaltona7f29642016-07-07 08:49:11 -0700275 }
Brian Salomon99ad1642016-12-16 09:50:45 -0500276 if (ip.opInfo().fShapeTypes & kRect_ShapeFlag) {
csmartdalton0caee172016-07-13 08:48:53 -0700277 v->codeAppend ("else {");
278 backend->setupRect(v);
279 v->codeAppend ("}");
csmartdaltona7f29642016-07-07 08:49:11 -0700280 }
csmartdaltona7f29642016-07-07 08:49:11 -0700281 }
282
Brian Salomon99ad1642016-12-16 09:50:45 -0500283 if (ip.opInfo().fInnerShapeTypes) {
284 bool hasSingleInnerShapeType = SkIsPow2(ip.opInfo().fInnerShapeTypes);
csmartdaltona7f29642016-07-07 08:49:11 -0700285 if (!hasSingleInnerShapeType) {
ethannicholas5961bc92016-10-12 06:39:56 -0700286 v->defineConstantf("int", "INNER_SHAPE_TYPE_MASK", "0x%x", kInnerShapeType_InfoMask);
287 v->defineConstant("INNER_SHAPE_TYPE_BIT", kInnerShapeType_InfoBit);
csmartdaltona7f29642016-07-07 08:49:11 -0700288 v->codeAppendf("uint innerShapeType = ((%s & INNER_SHAPE_TYPE_MASK) >> "
289 "INNER_SHAPE_TYPE_BIT);",
290 inputs.attr(Attrib::kInstanceInfo));
291 }
292 // Here we take advantage of the fact that outerRect == localRect in recordDRRect.
293 v->codeAppendf("vec4 outer = %s;", inputs.attr(Attrib::kLocalRect));
294 v->codeAppend ("vec4 inner = ");
295 inputs.fetchNextParam();
296 v->codeAppend (";");
297 // outer2Inner is a transform from shape coords to inner shape coords:
298 // e.g. innerShapeCoords = shapeCoords * outer2Inner.xy + outer2Inner.zw
299 v->codeAppend ("vec4 outer2Inner = vec4(outer.zw - outer.xy, "
300 "outer.xy + outer.zw - inner.xy - inner.zw) / "
301 "(inner.zw - inner.xy).xyxy;");
302 v->codeAppendf("vec2 innerShapeCoords = %s * outer2Inner.xy + outer2Inner.zw;",
303 backend->outShapeCoords());
304
305 backend->initInnerShape(varyingHandler, v);
306
Brian Salomon99ad1642016-12-16 09:50:45 -0500307 SkASSERT(0 == (ip.opInfo().fInnerShapeTypes & kRRect_ShapesMask) ||
308 kSimpleRRect_ShapeFlag == (ip.opInfo().fInnerShapeTypes & kRRect_ShapesMask));
csmartdalton0caee172016-07-13 08:48:53 -0700309
csmartdaltona7f29642016-07-07 08:49:11 -0700310 if (hasSingleInnerShapeType) {
Brian Salomon99ad1642016-12-16 09:50:45 -0500311 if (kRect_ShapeFlag == ip.opInfo().fInnerShapeTypes) {
csmartdaltona7f29642016-07-07 08:49:11 -0700312 backend->setupInnerRect(v);
Brian Salomon99ad1642016-12-16 09:50:45 -0500313 } else if (kOval_ShapeFlag == ip.opInfo().fInnerShapeTypes) {
csmartdaltona7f29642016-07-07 08:49:11 -0700314 backend->setupInnerOval(v);
315 } else {
csmartdalton0caee172016-07-13 08:48:53 -0700316 backend->setupInnerSimpleRRect(v);
csmartdaltona7f29642016-07-07 08:49:11 -0700317 }
318 } else {
Brian Salomon99ad1642016-12-16 09:50:45 -0500319 if (ip.opInfo().fInnerShapeTypes & kSimpleRRect_ShapeFlag) {
csmartdalton0caee172016-07-13 08:48:53 -0700320 v->codeAppend ("if (SIMPLE_R_RECT_SHAPE_TYPE == innerShapeType) {");
321 backend->setupInnerSimpleRRect(v);
322 v->codeAppend("}");
323 usedShapeDefinitions |= kSimpleRRect_ShapeFlag;
csmartdaltona7f29642016-07-07 08:49:11 -0700324 }
Brian Salomon99ad1642016-12-16 09:50:45 -0500325 if (ip.opInfo().fInnerShapeTypes & kOval_ShapeFlag) {
326 if (ip.opInfo().fInnerShapeTypes & kRect_ShapeFlag) {
327 if (ip.opInfo().fInnerShapeTypes & kSimpleRRect_ShapeFlag) {
csmartdalton0caee172016-07-13 08:48:53 -0700328 v->codeAppend ("else ");
329 }
330 v->codeAppend ("if (OVAL_SHAPE_TYPE == innerShapeType) {");
331 usedShapeDefinitions |= kOval_ShapeFlag;
332 } else {
333 v->codeAppend ("else {");
334 }
csmartdaltona7f29642016-07-07 08:49:11 -0700335 backend->setupInnerOval(v);
csmartdalton0caee172016-07-13 08:48:53 -0700336 v->codeAppend("}");
csmartdaltona7f29642016-07-07 08:49:11 -0700337 }
Brian Salomon99ad1642016-12-16 09:50:45 -0500338 if (ip.opInfo().fInnerShapeTypes & kRect_ShapeFlag) {
csmartdalton0caee172016-07-13 08:48:53 -0700339 v->codeAppend("else {");
340 backend->setupInnerRect(v);
341 v->codeAppend("}");
csmartdaltona7f29642016-07-07 08:49:11 -0700342 }
csmartdaltona7f29642016-07-07 08:49:11 -0700343 }
344 }
345
csmartdalton0caee172016-07-13 08:48:53 -0700346 if (usedShapeDefinitions & kOval_ShapeFlag) {
ethannicholas5961bc92016-10-12 06:39:56 -0700347 v->defineConstant("OVAL_SHAPE_TYPE", (int)ShapeType::kOval);
csmartdaltona7f29642016-07-07 08:49:11 -0700348 }
csmartdalton0caee172016-07-13 08:48:53 -0700349 if (usedShapeDefinitions & kSimpleRRect_ShapeFlag) {
ethannicholas5961bc92016-10-12 06:39:56 -0700350 v->defineConstant("SIMPLE_R_RECT_SHAPE_TYPE", (int)ShapeType::kSimpleRRect);
csmartdalton0caee172016-07-13 08:48:53 -0700351 }
352 if (usedShapeDefinitions & kNinePatch_ShapeFlag) {
ethannicholas5961bc92016-10-12 06:39:56 -0700353 v->defineConstant("NINE_PATCH_SHAPE_TYPE", (int)ShapeType::kNinePatch);
csmartdalton0caee172016-07-13 08:48:53 -0700354 }
355 SkASSERT(!(usedShapeDefinitions & (kRect_ShapeFlag | kComplexRRect_ShapeFlag)));
csmartdaltona7f29642016-07-07 08:49:11 -0700356
Brian Salomon8c852be2017-01-04 10:44:42 -0500357 backend->emitCode(v, f, args.fOutputCoverage, args.fOutputColor);
csmartdaltona7f29642016-07-07 08:49:11 -0700358
359 const char* localCoords = nullptr;
Brian Salomon99ad1642016-12-16 09:50:45 -0500360 if (ip.opInfo().fUsesLocalCoords) {
csmartdaltona7f29642016-07-07 08:49:11 -0700361 localCoords = "localCoords";
362 v->codeAppendf("vec2 t = 0.5 * (%s + vec2(1));", backend->outShapeCoords());
363 v->codeAppendf("vec2 localCoords = (1.0 - t) * %s.xy + t * %s.zw;",
364 inputs.attr(Attrib::kLocalRect), inputs.attr(Attrib::kLocalRect));
365 }
Brian Salomon99ad1642016-12-16 09:50:45 -0500366 if (ip.opInfo().fHasLocalMatrix && ip.opInfo().fHasParams) {
ethannicholas5961bc92016-10-12 06:39:56 -0700367 v->defineConstantf("int", "LOCAL_MATRIX_FLAG", "0x%x", kLocalMatrix_InfoFlag);
368 v->codeAppendf("if (0 != (%s & LOCAL_MATRIX_FLAG)) {",
csmartdaltona7f29642016-07-07 08:49:11 -0700369 inputs.attr(Attrib::kInstanceInfo));
Brian Salomon99ad1642016-12-16 09:50:45 -0500370 if (!ip.opInfo().fUsesLocalCoords) {
csmartdaltona7f29642016-07-07 08:49:11 -0700371 inputs.skipParams(2);
372 } else {
373 v->codeAppendf( "mat2x3 localMatrix;");
374 v->codeAppend ( "localMatrix[0] = ");
375 inputs.fetchNextParam(kVec3f_GrSLType);
376 v->codeAppend ( ";");
377 v->codeAppend ( "localMatrix[1] = ");
378 inputs.fetchNextParam(kVec3f_GrSLType);
379 v->codeAppend ( ";");
380 v->codeAppend ( "localCoords = (vec3(localCoords, 1) * localMatrix).xy;");
381 }
382 v->codeAppend("}");
383 }
384
Brian Salomon99ad1642016-12-16 09:50:45 -0500385 GrSLType positionType = ip.opInfo().fHasPerspective ? kVec3f_GrSLType : kVec2f_GrSLType;
csmartdaltona7f29642016-07-07 08:49:11 -0700386 v->codeAppendf("%s deviceCoords = vec3(%s, 1) * shapeMatrix;",
387 GrGLSLTypeString(positionType), backend->outShapeCoords());
388 gpArgs->fPositionVar.set(positionType, "deviceCoords");
389
390 this->emitTransforms(v, varyingHandler, uniHandler, gpArgs->fPositionVar, localCoords,
bsalomona624bf32016-09-20 09:12:47 -0700391 args.fFPCoordTransformHandler);
csmartdaltona7f29642016-07-07 08:49:11 -0700392}
393
394////////////////////////////////////////////////////////////////////////////////////////////////////
395
396void GLSLInstanceProcessor::Backend::init(GrGLSLVaryingHandler* varyingHandler,
397 GrGLSLVertexBuilder* v) {
398 if (fModifiedShapeCoords) {
399 v->codeAppendf("vec2 %s = %s;", fModifiedShapeCoords, fInputs.attr(Attrib::kShapeCoords));
400 }
401
402 this->onInit(varyingHandler, v);
403
404 if (!fColor.vsOut()) {
405 varyingHandler->addFlatVarying("color", &fColor, kLow_GrSLPrecision);
406 v->codeAppendf("%s = %s;", fColor.vsOut(), fInputs.attr(Attrib::kColor));
407 }
408}
409
csmartdalton0caee172016-07-13 08:48:53 -0700410void GLSLInstanceProcessor::Backend::setupRRect(GrGLSLVertexBuilder* v, int* usedShapeDefinitions) {
csmartdaltona7f29642016-07-07 08:49:11 -0700411 v->codeAppendf("uvec2 corner = uvec2(%s & 1, (%s >> 1) & 1);",
412 fInputs.attr(Attrib::kVertexAttrs), fInputs.attr(Attrib::kVertexAttrs));
413 v->codeAppend ("vec2 cornerSign = vec2(corner) * 2.0 - 1.0;");
414 v->codeAppendf("vec2 radii%s;", fNeedsNeighborRadii ? ", neighborRadii" : "");
415 v->codeAppend ("mat2 p = ");
416 fInputs.fetchNextParam(kMat22f_GrSLType);
417 v->codeAppend (";");
Brian Salomon99ad1642016-12-16 09:50:45 -0500418 uint8_t types = fOpInfo.fShapeTypes & kRRect_ShapesMask;
csmartdaltona7f29642016-07-07 08:49:11 -0700419 if (0 == (types & (types - 1))) {
420 if (kSimpleRRect_ShapeFlag == types) {
421 this->setupSimpleRadii(v);
422 } else if (kNinePatch_ShapeFlag == types) {
423 this->setupNinePatchRadii(v);
424 } else if (kComplexRRect_ShapeFlag == types) {
425 this->setupComplexRadii(v);
426 }
427 } else {
csmartdaltona7f29642016-07-07 08:49:11 -0700428 if (types & kSimpleRRect_ShapeFlag) {
csmartdalton0caee172016-07-13 08:48:53 -0700429 v->codeAppend ("if (SIMPLE_R_RECT_SHAPE_TYPE == shapeType) {");
csmartdaltona7f29642016-07-07 08:49:11 -0700430 this->setupSimpleRadii(v);
csmartdalton0caee172016-07-13 08:48:53 -0700431 v->codeAppend ("}");
432 *usedShapeDefinitions |= kSimpleRRect_ShapeFlag;
csmartdaltona7f29642016-07-07 08:49:11 -0700433 }
434 if (types & kNinePatch_ShapeFlag) {
csmartdalton0caee172016-07-13 08:48:53 -0700435 if (types & kComplexRRect_ShapeFlag) {
436 if (types & kSimpleRRect_ShapeFlag) {
437 v->codeAppend ("else ");
438 }
439 v->codeAppend ("if (NINE_PATCH_SHAPE_TYPE == shapeType) {");
440 *usedShapeDefinitions |= kNinePatch_ShapeFlag;
441 } else {
442 v->codeAppend ("else {");
443 }
csmartdaltona7f29642016-07-07 08:49:11 -0700444 this->setupNinePatchRadii(v);
csmartdalton0caee172016-07-13 08:48:53 -0700445 v->codeAppend ("}");
csmartdaltona7f29642016-07-07 08:49:11 -0700446 }
447 if (types & kComplexRRect_ShapeFlag) {
csmartdalton0caee172016-07-13 08:48:53 -0700448 v->codeAppend ("else {");
csmartdaltona7f29642016-07-07 08:49:11 -0700449 this->setupComplexRadii(v);
csmartdalton0caee172016-07-13 08:48:53 -0700450 v->codeAppend ("}");
csmartdaltona7f29642016-07-07 08:49:11 -0700451 }
csmartdaltona7f29642016-07-07 08:49:11 -0700452 }
453
454 this->adjustRRectVertices(v);
455
456 if (fArcCoords.vsOut()) {
457 v->codeAppendf("%s = (cornerSign * %s + radii - vec2(1)) / radii;",
458 fArcCoords.vsOut(), fModifiedShapeCoords);
459 }
460 if (fTriangleIsArc.vsOut()) {
461 v->codeAppendf("%s = int(all(equal(vec2(1), abs(%s))));",
462 fTriangleIsArc.vsOut(), fInputs.attr(Attrib::kShapeCoords));
463 }
464
465 this->onSetupRRect(v);
466}
467
468void GLSLInstanceProcessor::Backend::setupSimpleRadii(GrGLSLVertexBuilder* v) {
469 if (fNeedsNeighborRadii) {
470 v->codeAppend ("neighborRadii = ");
471 }
472 v->codeAppend("radii = p[0] * 2.0 / p[1];");
473}
474
475void GLSLInstanceProcessor::Backend::setupNinePatchRadii(GrGLSLVertexBuilder* v) {
476 v->codeAppend("radii = vec2(p[0][corner.x], p[1][corner.y]);");
477 if (fNeedsNeighborRadii) {
478 v->codeAppend("neighborRadii = vec2(p[0][1u - corner.x], p[1][1u - corner.y]);");
479 }
480}
481
482void GLSLInstanceProcessor::Backend::setupComplexRadii(GrGLSLVertexBuilder* v) {
483 /**
484 * The x and y radii of each arc are stored in separate vectors,
485 * in the following order:
486 *
487 * __x1 _ _ _ x3__
488 *
489 * y1 | | y2
490 *
491 * | |
492 *
493 * y3 |__ _ _ _ __| y4
494 * x2 x4
495 *
496 */
497 v->codeAppend("mat2 p2 = ");
498 fInputs.fetchNextParam(kMat22f_GrSLType);
499 v->codeAppend(";");
500 v->codeAppend("radii = vec2(p[corner.x][corner.y], p2[corner.y][corner.x]);");
501 if (fNeedsNeighborRadii) {
502 v->codeAppend("neighborRadii = vec2(p[1u - corner.x][corner.y], "
503 "p2[1u - corner.y][corner.x]);");
504 }
505}
506
507void GLSLInstanceProcessor::Backend::adjustRRectVertices(GrGLSLVertexBuilder* v) {
508 // Resize the 4 triangles that arcs are drawn into so they match their corresponding radii.
509 // 0.5 is a special value that indicates the edge of an arc triangle.
510 v->codeAppendf("if (abs(%s.x) == 0.5)"
511 "%s.x = cornerSign.x * (1.0 - radii.x);",
512 fInputs.attr(Attrib::kShapeCoords), fModifiedShapeCoords);
513 v->codeAppendf("if (abs(%s.y) == 0.5) "
514 "%s.y = cornerSign.y * (1.0 - radii.y);",
515 fInputs.attr(Attrib::kShapeCoords), fModifiedShapeCoords);
516}
517
518void GLSLInstanceProcessor::Backend::initInnerShape(GrGLSLVaryingHandler* varyingHandler,
519 GrGLSLVertexBuilder* v) {
Brian Salomon99ad1642016-12-16 09:50:45 -0500520 SkASSERT(!(fOpInfo.fInnerShapeTypes & (kNinePatch_ShapeFlag | kComplexRRect_ShapeFlag)));
csmartdaltona7f29642016-07-07 08:49:11 -0700521
522 this->onInitInnerShape(varyingHandler, v);
523
524 if (fInnerShapeCoords.vsOut()) {
525 v->codeAppendf("%s = innerShapeCoords;", fInnerShapeCoords.vsOut());
526 }
527}
528
csmartdalton0caee172016-07-13 08:48:53 -0700529void GLSLInstanceProcessor::Backend::setupInnerSimpleRRect(GrGLSLVertexBuilder* v) {
csmartdaltona7f29642016-07-07 08:49:11 -0700530 v->codeAppend("mat2 innerP = ");
531 fInputs.fetchNextParam(kMat22f_GrSLType);
532 v->codeAppend(";");
533 v->codeAppend("vec2 innerRadii = innerP[0] * 2.0 / innerP[1];");
csmartdalton0caee172016-07-13 08:48:53 -0700534 this->onSetupInnerSimpleRRect(v);
csmartdaltona7f29642016-07-07 08:49:11 -0700535}
536
537void GLSLInstanceProcessor::Backend::emitCode(GrGLSLVertexBuilder* v, GrGLSLPPFragmentBuilder* f,
538 const char* outCoverage, const char* outColor) {
539 SkASSERT(!fModifiesCoverage || outCoverage);
540 this->onEmitCode(v, f, fModifiesCoverage ? outCoverage : nullptr,
541 fModifiesColor ? outColor : nullptr);
542 if (outCoverage && !fModifiesCoverage) {
543 // Even though the subclass doesn't use coverage, we are expected to assign some value.
544 f->codeAppendf("%s = vec4(1);", outCoverage);
545 }
546 if (!fModifiesColor) {
547 // The subclass didn't assign a value to the output color.
548 f->codeAppendf("%s = %s;", outColor, fColor.fsIn());
549 }
550}
551
552////////////////////////////////////////////////////////////////////////////////////////////////////
553
554class GLSLInstanceProcessor::BackendNonAA : public Backend {
555public:
Brian Salomon99ad1642016-12-16 09:50:45 -0500556 BackendNonAA(OpInfo opInfo, const VertexInputs& inputs) : INHERITED(opInfo, inputs) {
557 if (fOpInfo.fCannotDiscard && !fOpInfo.isSimpleRects()) {
558 fModifiesColor = !fOpInfo.fCannotTweakAlphaForCoverage;
csmartdaltona7f29642016-07-07 08:49:11 -0700559 fModifiesCoverage = !fModifiesColor;
560 }
561 }
562
563private:
564 void onInit(GrGLSLVaryingHandler*, GrGLSLVertexBuilder*) override;
565 void setupRect(GrGLSLVertexBuilder*) override;
566 void setupOval(GrGLSLVertexBuilder*) override;
567
568 void onInitInnerShape(GrGLSLVaryingHandler*, GrGLSLVertexBuilder*) override;
569 void setupInnerRect(GrGLSLVertexBuilder*) override;
570 void setupInnerOval(GrGLSLVertexBuilder*) override;
csmartdalton0caee172016-07-13 08:48:53 -0700571 void onSetupInnerSimpleRRect(GrGLSLVertexBuilder*) override;
csmartdaltona7f29642016-07-07 08:49:11 -0700572
573 void onEmitCode(GrGLSLVertexBuilder*, GrGLSLPPFragmentBuilder*, const char*,
574 const char*) override;
575
576 typedef Backend INHERITED;
577};
578
579void GLSLInstanceProcessor::BackendNonAA::onInit(GrGLSLVaryingHandler* varyingHandler,
580 GrGLSLVertexBuilder*) {
Brian Salomon99ad1642016-12-16 09:50:45 -0500581 if (kRect_ShapeFlag != fOpInfo.fShapeTypes) {
csmartdaltondd57dd72016-07-13 08:59:52 -0700582 varyingHandler->addFlatVarying("triangleIsArc", &fTriangleIsArc, kLow_GrSLPrecision);
csmartdaltona7f29642016-07-07 08:49:11 -0700583 varyingHandler->addVarying("arcCoords", &fArcCoords, kMedium_GrSLPrecision);
584 }
585}
586
587void GLSLInstanceProcessor::BackendNonAA::setupRect(GrGLSLVertexBuilder* v) {
588 if (fTriangleIsArc.vsOut()) {
589 v->codeAppendf("%s = 0;", fTriangleIsArc.vsOut());
590 }
591}
592
593void GLSLInstanceProcessor::BackendNonAA::setupOval(GrGLSLVertexBuilder* v) {
594 SkASSERT(fArcCoords.vsOut());
595 SkASSERT(fTriangleIsArc.vsOut());
596 v->codeAppendf("%s = %s;", fArcCoords.vsOut(), this->outShapeCoords());
597 v->codeAppendf("%s = %s & 1;", fTriangleIsArc.vsOut(), fInputs.attr(Attrib::kVertexAttrs));
598}
599
600void GLSLInstanceProcessor::BackendNonAA::onInitInnerShape(GrGLSLVaryingHandler* varyingHandler,
601 GrGLSLVertexBuilder*) {
602 varyingHandler->addVarying("innerShapeCoords", &fInnerShapeCoords, kMedium_GrSLPrecision);
Brian Salomon99ad1642016-12-16 09:50:45 -0500603 if (kRect_ShapeFlag != fOpInfo.fInnerShapeTypes &&
604 kOval_ShapeFlag != fOpInfo.fInnerShapeTypes) {
csmartdaltona7f29642016-07-07 08:49:11 -0700605 varyingHandler->addFlatVarying("innerRRect", &fInnerRRect, kMedium_GrSLPrecision);
606 }
607}
608
609void GLSLInstanceProcessor::BackendNonAA::setupInnerRect(GrGLSLVertexBuilder* v) {
610 if (fInnerRRect.vsOut()) {
611 v->codeAppendf("%s = vec4(1);", fInnerRRect.vsOut());
612 }
613}
614
615void GLSLInstanceProcessor::BackendNonAA::setupInnerOval(GrGLSLVertexBuilder* v) {
616 if (fInnerRRect.vsOut()) {
617 v->codeAppendf("%s = vec4(0, 0, 1, 1);", fInnerRRect.vsOut());
618 }
619}
620
csmartdalton0caee172016-07-13 08:48:53 -0700621void GLSLInstanceProcessor::BackendNonAA::onSetupInnerSimpleRRect(GrGLSLVertexBuilder* v) {
csmartdaltona7f29642016-07-07 08:49:11 -0700622 v->codeAppendf("%s = vec4(1.0 - innerRadii, 1.0 / innerRadii);", fInnerRRect.vsOut());
623}
624
625void GLSLInstanceProcessor::BackendNonAA::onEmitCode(GrGLSLVertexBuilder*,
626 GrGLSLPPFragmentBuilder* f,
627 const char* outCoverage,
628 const char* outColor) {
629 const char* dropFragment = nullptr;
Brian Salomon99ad1642016-12-16 09:50:45 -0500630 if (!fOpInfo.fCannotDiscard) {
csmartdaltona7f29642016-07-07 08:49:11 -0700631 dropFragment = "discard";
632 } else if (fModifiesCoverage) {
Ethan Nicholas1fc83b12016-11-22 09:31:35 -0500633 f->codeAppend ("lowp float covered = 1.0;");
csmartdaltona7f29642016-07-07 08:49:11 -0700634 dropFragment = "covered = 0.0";
635 } else if (fModifiesColor) {
Ethan Nicholas1fc83b12016-11-22 09:31:35 -0500636 f->codeAppendf("lowp vec4 color = %s;", fColor.fsIn());
csmartdaltona7f29642016-07-07 08:49:11 -0700637 dropFragment = "color = vec4(0)";
638 }
639 if (fTriangleIsArc.fsIn()) {
640 SkASSERT(dropFragment);
641 f->codeAppendf("if (%s != 0 && dot(%s, %s) > 1.0) %s;",
642 fTriangleIsArc.fsIn(), fArcCoords.fsIn(), fArcCoords.fsIn(), dropFragment);
643 }
Brian Salomon99ad1642016-12-16 09:50:45 -0500644 if (fOpInfo.fInnerShapeTypes) {
csmartdaltona7f29642016-07-07 08:49:11 -0700645 SkASSERT(dropFragment);
646 f->codeAppendf("// Inner shape.\n");
Brian Salomon99ad1642016-12-16 09:50:45 -0500647 if (kRect_ShapeFlag == fOpInfo.fInnerShapeTypes) {
csmartdaltona7f29642016-07-07 08:49:11 -0700648 f->codeAppendf("if (all(lessThanEqual(abs(%s), vec2(1)))) %s;",
649 fInnerShapeCoords.fsIn(), dropFragment);
Brian Salomon99ad1642016-12-16 09:50:45 -0500650 } else if (kOval_ShapeFlag == fOpInfo.fInnerShapeTypes) {
csmartdaltona7f29642016-07-07 08:49:11 -0700651 f->codeAppendf("if ((dot(%s, %s) <= 1.0)) %s;",
652 fInnerShapeCoords.fsIn(), fInnerShapeCoords.fsIn(), dropFragment);
653 } else {
654 f->codeAppendf("if (all(lessThan(abs(%s), vec2(1)))) {", fInnerShapeCoords.fsIn());
655 f->codeAppendf( "vec2 distanceToArcEdge = abs(%s) - %s.xy;",
656 fInnerShapeCoords.fsIn(), fInnerRRect.fsIn());
657 f->codeAppend ( "if (any(lessThan(distanceToArcEdge, vec2(0)))) {");
658 f->codeAppendf( "%s;", dropFragment);
659 f->codeAppend ( "} else {");
660 f->codeAppendf( "vec2 rrectCoords = distanceToArcEdge * %s.zw;",
661 fInnerRRect.fsIn());
662 f->codeAppend ( "if (dot(rrectCoords, rrectCoords) <= 1.0) {");
663 f->codeAppendf( "%s;", dropFragment);
664 f->codeAppend ( "}");
665 f->codeAppend ( "}");
666 f->codeAppend ("}");
667 }
668 }
669 if (fModifiesCoverage) {
670 f->codeAppendf("%s = vec4(covered);", outCoverage);
671 } else if (fModifiesColor) {
672 f->codeAppendf("%s = color;", outColor);
673 }
674}
675
676////////////////////////////////////////////////////////////////////////////////////////////////////
677
678class GLSLInstanceProcessor::BackendCoverage : public Backend {
679public:
Brian Salomon99ad1642016-12-16 09:50:45 -0500680 BackendCoverage(OpInfo opInfo, const VertexInputs& inputs)
681 : INHERITED(opInfo, inputs)
682 , fColorTimesRectCoverage(kVec4f_GrSLType)
683 , fRectCoverage(kFloat_GrSLType)
684 , fEllipseCoords(kVec2f_GrSLType)
685 , fEllipseName(kVec2f_GrSLType)
686 , fBloatedRadius(kFloat_GrSLType)
687 , fDistanceToInnerEdge(kVec2f_GrSLType)
688 , fInnerShapeBloatedHalfSize(kVec2f_GrSLType)
689 , fInnerEllipseCoords(kVec2f_GrSLType)
690 , fInnerEllipseName(kVec2f_GrSLType) {
691 fShapeIsCircle = !fOpInfo.fNonSquare && !(fOpInfo.fShapeTypes & kRRect_ShapesMask);
692 fTweakAlphaForCoverage = !fOpInfo.fCannotTweakAlphaForCoverage && !fOpInfo.fInnerShapeTypes;
csmartdaltona7f29642016-07-07 08:49:11 -0700693 fModifiesCoverage = !fTweakAlphaForCoverage;
694 fModifiesColor = fTweakAlphaForCoverage;
695 fModifiedShapeCoords = "bloatedShapeCoords";
696 }
697
698private:
699 void onInit(GrGLSLVaryingHandler*, GrGLSLVertexBuilder*) override;
700 void setupRect(GrGLSLVertexBuilder*) override;
701 void setupOval(GrGLSLVertexBuilder*) override;
702 void adjustRRectVertices(GrGLSLVertexBuilder*) override;
703 void onSetupRRect(GrGLSLVertexBuilder*) override;
704
705 void onInitInnerShape(GrGLSLVaryingHandler*, GrGLSLVertexBuilder*) override;
706 void setupInnerRect(GrGLSLVertexBuilder*) override;
707 void setupInnerOval(GrGLSLVertexBuilder*) override;
csmartdalton0caee172016-07-13 08:48:53 -0700708 void onSetupInnerSimpleRRect(GrGLSLVertexBuilder*) override;
csmartdaltona7f29642016-07-07 08:49:11 -0700709
710 void onEmitCode(GrGLSLVertexBuilder*, GrGLSLPPFragmentBuilder*, const char* outCoverage,
711 const char* outColor) override;
712
713 void emitRect(GrGLSLPPFragmentBuilder*, const char* outCoverage, const char* outColor);
714 void emitCircle(GrGLSLPPFragmentBuilder*, const char* outCoverage);
715 void emitArc(GrGLSLPPFragmentBuilder* f, const char* ellipseCoords, const char* ellipseName,
716 bool ellipseCoordsNeedClamp, bool ellipseCoordsMayBeNegative,
717 const char* outCoverage);
718 void emitInnerRect(GrGLSLPPFragmentBuilder*, const char* outCoverage);
719
720 GrGLSLVertToFrag fColorTimesRectCoverage;
721 GrGLSLVertToFrag fRectCoverage;
722 GrGLSLVertToFrag fEllipseCoords;
723 GrGLSLVertToFrag fEllipseName;
724 GrGLSLVertToFrag fBloatedRadius;
725 GrGLSLVertToFrag fDistanceToInnerEdge;
726 GrGLSLVertToFrag fInnerShapeBloatedHalfSize;
727 GrGLSLVertToFrag fInnerEllipseCoords;
728 GrGLSLVertToFrag fInnerEllipseName;
729 bool fShapeIsCircle;
730 bool fTweakAlphaForCoverage;
731
732 typedef Backend INHERITED;
733};
734
735void GLSLInstanceProcessor::BackendCoverage::onInit(GrGLSLVaryingHandler* varyingHandler,
736 GrGLSLVertexBuilder* v) {
737 v->codeAppend ("mat2 shapeTransposeMatrix = transpose(mat2(shapeMatrix));");
738 v->codeAppend ("vec2 shapeHalfSize = vec2(length(shapeTransposeMatrix[0]), "
739 "length(shapeTransposeMatrix[1]));");
740 v->codeAppend ("vec2 bloat = 0.5 / shapeHalfSize;");
741 v->codeAppendf("bloatedShapeCoords = %s * (1.0 + bloat);", fInputs.attr(Attrib::kShapeCoords));
742
Brian Salomon99ad1642016-12-16 09:50:45 -0500743 if (kOval_ShapeFlag != fOpInfo.fShapeTypes) {
csmartdaltona7f29642016-07-07 08:49:11 -0700744 if (fTweakAlphaForCoverage) {
745 varyingHandler->addVarying("colorTimesRectCoverage", &fColorTimesRectCoverage,
746 kLow_GrSLPrecision);
Brian Salomon99ad1642016-12-16 09:50:45 -0500747 if (kRect_ShapeFlag == fOpInfo.fShapeTypes) {
csmartdaltona7f29642016-07-07 08:49:11 -0700748 fColor = fColorTimesRectCoverage;
749 }
750 } else {
751 varyingHandler->addVarying("rectCoverage", &fRectCoverage, kLow_GrSLPrecision);
752 }
753 v->codeAppend("float rectCoverage = 0.0;");
754 }
Brian Salomon99ad1642016-12-16 09:50:45 -0500755 if (kRect_ShapeFlag != fOpInfo.fShapeTypes) {
csmartdaltondd57dd72016-07-13 08:59:52 -0700756 varyingHandler->addFlatVarying("triangleIsArc", &fTriangleIsArc, kLow_GrSLPrecision);
csmartdaltona7f29642016-07-07 08:49:11 -0700757 if (!fShapeIsCircle) {
csmartdaltondd57dd72016-07-13 08:59:52 -0700758 varyingHandler->addVarying("ellipseCoords", &fEllipseCoords, kMedium_GrSLPrecision);
csmartdaltona7f29642016-07-07 08:49:11 -0700759 varyingHandler->addFlatVarying("ellipseName", &fEllipseName, kHigh_GrSLPrecision);
760 } else {
csmartdaltone0d36292016-07-29 08:14:20 -0700761 varyingHandler->addVarying("circleCoords", &fEllipseCoords, kHigh_GrSLPrecision);
762 varyingHandler->addFlatVarying("bloatedRadius", &fBloatedRadius, kHigh_GrSLPrecision);
csmartdaltona7f29642016-07-07 08:49:11 -0700763 }
764 }
765}
766
767void GLSLInstanceProcessor::BackendCoverage::setupRect(GrGLSLVertexBuilder* v) {
768 // Make the border one pixel wide. Inner vs outer is indicated by coordAttrs.
769 v->codeAppendf("vec2 rectBloat = (%s != 0) ? bloat : -bloat;",
770 fInputs.attr(Attrib::kVertexAttrs));
771 // Here we use the absolute value, because when the rect is thinner than a pixel, this makes it
772 // mark the spot where pixel center is within half a pixel of the *opposite* edge. This,
773 // combined with the "maxCoverage" logic below gives us mathematically correct coverage even for
774 // subpixel rectangles.
775 v->codeAppendf("bloatedShapeCoords = %s * abs(vec2(1.0 + rectBloat));",
776 fInputs.attr(Attrib::kShapeCoords));
777
778 // Determine coverage at the vertex. Coverage naturally ramps from 0 to 1 unless the rect is
779 // narrower than a pixel.
780 v->codeAppend ("float maxCoverage = 4.0 * min(0.5, shapeHalfSize.x) *"
781 "min(0.5, shapeHalfSize.y);");
782 v->codeAppendf("rectCoverage = (%s != 0) ? 0.0 : maxCoverage;",
783 fInputs.attr(Attrib::kVertexAttrs));
784
785 if (fTriangleIsArc.vsOut()) {
786 v->codeAppendf("%s = 0;", fTriangleIsArc.vsOut());
787 }
788}
789
790void GLSLInstanceProcessor::BackendCoverage::setupOval(GrGLSLVertexBuilder* v) {
791 // Offset the inner and outer octagons by one pixel. Inner vs outer is indicated by coordAttrs.
792 v->codeAppendf("vec2 ovalBloat = (%s != 0) ? bloat : -bloat;",
793 fInputs.attr(Attrib::kVertexAttrs));
794 v->codeAppendf("bloatedShapeCoords = %s * max(vec2(1.0 + ovalBloat), vec2(0));",
795 fInputs.attr(Attrib::kShapeCoords));
796 v->codeAppendf("%s = bloatedShapeCoords * shapeHalfSize;", fEllipseCoords.vsOut());
797 if (fEllipseName.vsOut()) {
798 v->codeAppendf("%s = 1.0 / (shapeHalfSize * shapeHalfSize);", fEllipseName.vsOut());
799 }
800 if (fBloatedRadius.vsOut()) {
801 SkASSERT(fShapeIsCircle);
802 v->codeAppendf("%s = shapeHalfSize.x + 0.5;", fBloatedRadius.vsOut());
803 }
804 if (fTriangleIsArc.vsOut()) {
805 v->codeAppendf("%s = int(%s != 0);",
806 fTriangleIsArc.vsOut(), fInputs.attr(Attrib::kVertexAttrs));
807 }
808 if (fColorTimesRectCoverage.vsOut() || fRectCoverage.vsOut()) {
809 v->codeAppendf("rectCoverage = 1.0;");
810 }
811}
812
813void GLSLInstanceProcessor::BackendCoverage::adjustRRectVertices(GrGLSLVertexBuilder* v) {
814 // We try to let the AA borders line up with the arc edges on their particular side, but we
815 // can't allow them to get closer than one half pixel to the edge or they might overlap with
816 // their neighboring border.
817 v->codeAppend("vec2 innerEdge = max(1.0 - bloat, vec2(0));");
818 v->codeAppend ("vec2 borderEdge = cornerSign * clamp(1.0 - radii, -innerEdge, innerEdge);");
819 // 0.5 is a special value that indicates this vertex is an arc edge.
820 v->codeAppendf("if (abs(%s.x) == 0.5)"
821 "bloatedShapeCoords.x = borderEdge.x;", fInputs.attr(Attrib::kShapeCoords));
822 v->codeAppendf("if (abs(%s.y) == 0.5)"
823 "bloatedShapeCoords.y = borderEdge.y;", fInputs.attr(Attrib::kShapeCoords));
824
825 // Adjust the interior border vertices to make the border one pixel wide. 0.75 is a special
826 // value to indicate these points.
827 v->codeAppendf("if (abs(%s.x) == 0.75) "
828 "bloatedShapeCoords.x = cornerSign.x * innerEdge.x;",
829 fInputs.attr(Attrib::kShapeCoords));
830 v->codeAppendf("if (abs(%s.y) == 0.75) "
831 "bloatedShapeCoords.y = cornerSign.y * innerEdge.y;",
832 fInputs.attr(Attrib::kShapeCoords));
833}
834
835void GLSLInstanceProcessor::BackendCoverage::onSetupRRect(GrGLSLVertexBuilder* v) {
836 // The geometry is laid out in such a way that rectCoverage will be 0 and 1 on the vertices, but
837 // we still need to recompute this value because when the rrect gets thinner than one pixel, the
838 // interior edge of the border will necessarily clamp, and we need to match the AA behavior of
839 // the arc segments (i.e. distance from bloated edge only; ignoring the fact that the pixel
840 // actully has less coverage because it's not completely inside the opposite edge.)
841 v->codeAppend("vec2 d = shapeHalfSize + 0.5 - abs(bloatedShapeCoords) * shapeHalfSize;");
842 v->codeAppend("rectCoverage = min(d.x, d.y);");
843
844 SkASSERT(!fShapeIsCircle);
845 // The AA border does not get closer than one half pixel to the edge of the rect, so to get a
846 // smooth transition from flat edge to arc, we don't allow the radii to be smaller than one half
847 // pixel. (We don't worry about the transition on the opposite side when a radius is so large
848 // that the border clamped on that side.)
849 v->codeAppendf("vec2 clampedRadii = max(radii, bloat);");
850 v->codeAppendf("%s = (cornerSign * bloatedShapeCoords + clampedRadii - vec2(1)) * "
851 "shapeHalfSize;", fEllipseCoords.vsOut());
852 v->codeAppendf("%s = 1.0 / (clampedRadii * clampedRadii * shapeHalfSize * shapeHalfSize);",
853 fEllipseName.vsOut());
854}
855
856void GLSLInstanceProcessor::BackendCoverage::onInitInnerShape(GrGLSLVaryingHandler* varyingHandler,
857 GrGLSLVertexBuilder* v) {
858 v->codeAppend("vec2 innerShapeHalfSize = shapeHalfSize / outer2Inner.xy;");
859
Brian Salomon99ad1642016-12-16 09:50:45 -0500860 if (kOval_ShapeFlag == fOpInfo.fInnerShapeTypes) {
csmartdaltona7f29642016-07-07 08:49:11 -0700861 varyingHandler->addVarying("innerEllipseCoords", &fInnerEllipseCoords,
862 kMedium_GrSLPrecision);
csmartdaltondd57dd72016-07-13 08:59:52 -0700863 varyingHandler->addFlatVarying("innerEllipseName", &fInnerEllipseName, kHigh_GrSLPrecision);
csmartdaltona7f29642016-07-07 08:49:11 -0700864 } else {
865 varyingHandler->addVarying("distanceToInnerEdge", &fDistanceToInnerEdge,
866 kMedium_GrSLPrecision);
867 varyingHandler->addFlatVarying("innerShapeBloatedHalfSize", &fInnerShapeBloatedHalfSize,
868 kMedium_GrSLPrecision);
Brian Salomon99ad1642016-12-16 09:50:45 -0500869 if (kRect_ShapeFlag != fOpInfo.fInnerShapeTypes) {
csmartdaltondd57dd72016-07-13 08:59:52 -0700870 varyingHandler->addVarying("innerShapeCoords", &fInnerShapeCoords,
871 kMedium_GrSLPrecision);
csmartdaltona7f29642016-07-07 08:49:11 -0700872 varyingHandler->addFlatVarying("innerEllipseName", &fInnerEllipseName,
csmartdaltondd57dd72016-07-13 08:59:52 -0700873 kHigh_GrSLPrecision);
874 varyingHandler->addFlatVarying("innerRRect", &fInnerRRect, kMedium_GrSLPrecision);
csmartdaltona7f29642016-07-07 08:49:11 -0700875 }
876 }
877}
878
879void GLSLInstanceProcessor::BackendCoverage::setupInnerRect(GrGLSLVertexBuilder* v) {
880 if (fInnerRRect.vsOut()) {
881 // The fragment shader will generalize every inner shape as a round rect. Since this one
882 // is a rect, we simply emit bogus parameters for the round rect (effectively negative
883 // radii) that ensure the fragment shader always takes the "emitRect" codepath.
884 v->codeAppendf("%s.xy = abs(outer2Inner.xy) * (1.0 + bloat) + abs(outer2Inner.zw);",
885 fInnerRRect.vsOut());
886 }
887}
888
889void GLSLInstanceProcessor::BackendCoverage::setupInnerOval(GrGLSLVertexBuilder* v) {
890 v->codeAppendf("%s = 1.0 / (innerShapeHalfSize * innerShapeHalfSize);",
891 fInnerEllipseName.vsOut());
892 if (fInnerEllipseCoords.vsOut()) {
893 v->codeAppendf("%s = innerShapeCoords * innerShapeHalfSize;", fInnerEllipseCoords.vsOut());
894 }
895 if (fInnerRRect.vsOut()) {
896 v->codeAppendf("%s = vec4(0, 0, innerShapeHalfSize);", fInnerRRect.vsOut());
897 }
898}
899
csmartdalton0caee172016-07-13 08:48:53 -0700900void GLSLInstanceProcessor::BackendCoverage::onSetupInnerSimpleRRect(GrGLSLVertexBuilder* v) {
csmartdaltona7f29642016-07-07 08:49:11 -0700901 // The distance to ellipse formula doesn't work well when the radii are less than half a pixel.
902 v->codeAppend ("innerRadii = max(innerRadii, bloat);");
903 v->codeAppendf("%s = 1.0 / (innerRadii * innerRadii * innerShapeHalfSize * "
904 "innerShapeHalfSize);",
905 fInnerEllipseName.vsOut());
906 v->codeAppendf("%s = vec4(1.0 - innerRadii, innerShapeHalfSize);", fInnerRRect.vsOut());
907}
908
909void GLSLInstanceProcessor::BackendCoverage::onEmitCode(GrGLSLVertexBuilder* v,
910 GrGLSLPPFragmentBuilder* f,
911 const char* outCoverage,
912 const char* outColor) {
913 if (fColorTimesRectCoverage.vsOut()) {
914 SkASSERT(!fRectCoverage.vsOut());
915 v->codeAppendf("%s = %s * rectCoverage;",
916 fColorTimesRectCoverage.vsOut(), fInputs.attr(Attrib::kColor));
917 }
918 if (fRectCoverage.vsOut()) {
919 SkASSERT(!fColorTimesRectCoverage.vsOut());
920 v->codeAppendf("%s = rectCoverage;", fRectCoverage.vsOut());
921 }
922
Ethan Nicholas6762dd62016-11-22 15:40:27 -0500923 SkString coverage("lowp float coverage");
Brian Salomon99ad1642016-12-16 09:50:45 -0500924 if (fOpInfo.fInnerShapeTypes || (!fTweakAlphaForCoverage && fTriangleIsArc.fsIn())) {
csmartdaltona7f29642016-07-07 08:49:11 -0700925 f->codeAppendf("%s;", coverage.c_str());
926 coverage = "coverage";
927 }
928 if (fTriangleIsArc.fsIn()) {
929 f->codeAppendf("if (%s == 0) {", fTriangleIsArc.fsIn());
930 this->emitRect(f, coverage.c_str(), outColor);
931 f->codeAppend ("} else {");
932 if (fShapeIsCircle) {
933 this->emitCircle(f, coverage.c_str());
934 } else {
Brian Salomon99ad1642016-12-16 09:50:45 -0500935 bool ellipseCoordsMayBeNegative = SkToBool(fOpInfo.fShapeTypes & kOval_ShapeFlag);
csmartdaltona7f29642016-07-07 08:49:11 -0700936 this->emitArc(f, fEllipseCoords.fsIn(), fEllipseName.fsIn(),
937 true /*ellipseCoordsNeedClamp*/, ellipseCoordsMayBeNegative,
938 coverage.c_str());
939 }
940 if (fTweakAlphaForCoverage) {
941 f->codeAppendf("%s = %s * coverage;", outColor, fColor.fsIn());
942 }
943 f->codeAppend ("}");
944 } else {
945 this->emitRect(f, coverage.c_str(), outColor);
946 }
947
Brian Salomon99ad1642016-12-16 09:50:45 -0500948 if (fOpInfo.fInnerShapeTypes) {
csmartdaltona7f29642016-07-07 08:49:11 -0700949 f->codeAppendf("// Inner shape.\n");
Ethan Nicholas6762dd62016-11-22 15:40:27 -0500950 SkString innerCoverageDecl("lowp float innerCoverage");
Brian Salomon99ad1642016-12-16 09:50:45 -0500951 if (kOval_ShapeFlag == fOpInfo.fInnerShapeTypes) {
csmartdaltona7f29642016-07-07 08:49:11 -0700952 this->emitArc(f, fInnerEllipseCoords.fsIn(), fInnerEllipseName.fsIn(),
953 true /*ellipseCoordsNeedClamp*/, true /*ellipseCoordsMayBeNegative*/,
954 innerCoverageDecl.c_str());
955 } else {
956 v->codeAppendf("%s = innerShapeCoords * innerShapeHalfSize;",
957 fDistanceToInnerEdge.vsOut());
958 v->codeAppendf("%s = innerShapeHalfSize + 0.5;", fInnerShapeBloatedHalfSize.vsOut());
959
Brian Salomon99ad1642016-12-16 09:50:45 -0500960 if (kRect_ShapeFlag == fOpInfo.fInnerShapeTypes) {
csmartdaltona7f29642016-07-07 08:49:11 -0700961 this->emitInnerRect(f, innerCoverageDecl.c_str());
962 } else {
963 f->codeAppendf("%s = 0.0;", innerCoverageDecl.c_str());
Ethan Nicholas1fc83b12016-11-22 09:31:35 -0500964 f->codeAppendf("mediump vec2 distanceToArcEdge = abs(%s) - %s.xy;",
csmartdaltona7f29642016-07-07 08:49:11 -0700965 fInnerShapeCoords.fsIn(), fInnerRRect.fsIn());
966 f->codeAppend ("if (any(lessThan(distanceToArcEdge, vec2(1e-5)))) {");
967 this->emitInnerRect(f, "innerCoverage");
968 f->codeAppend ("} else {");
Ethan Nicholas1fc83b12016-11-22 09:31:35 -0500969 f->codeAppendf( "mediump vec2 ellipseCoords = distanceToArcEdge * %s.zw;",
csmartdaltona7f29642016-07-07 08:49:11 -0700970 fInnerRRect.fsIn());
971 this->emitArc(f, "ellipseCoords", fInnerEllipseName.fsIn(),
972 false /*ellipseCoordsNeedClamp*/,
973 false /*ellipseCoordsMayBeNegative*/, "innerCoverage");
974 f->codeAppend ("}");
975 }
976 }
977 f->codeAppendf("%s = vec4(max(coverage - innerCoverage, 0.0));", outCoverage);
978 } else if (!fTweakAlphaForCoverage) {
979 f->codeAppendf("%s = vec4(coverage);", outCoverage);
980 }
981}
982
983void GLSLInstanceProcessor::BackendCoverage::emitRect(GrGLSLPPFragmentBuilder* f,
984 const char* outCoverage,
985 const char* outColor) {
986 if (fColorTimesRectCoverage.fsIn()) {
987 f->codeAppendf("%s = %s;", outColor, fColorTimesRectCoverage.fsIn());
988 } else if (fTweakAlphaForCoverage) {
989 // We are drawing just ovals. The interior rect always has 100% coverage.
990 f->codeAppendf("%s = %s;", outColor, fColor.fsIn());
991 } else if (fRectCoverage.fsIn()) {
992 f->codeAppendf("%s = %s;", outCoverage, fRectCoverage.fsIn());
993 } else {
994 f->codeAppendf("%s = 1.0;", outCoverage);
995 }
996}
997
998void GLSLInstanceProcessor::BackendCoverage::emitCircle(GrGLSLPPFragmentBuilder* f,
999 const char* outCoverage) {
1000 // TODO: circleCoords = max(circleCoords, 0) if we decide to do this optimization on rrects.
Brian Salomon99ad1642016-12-16 09:50:45 -05001001 SkASSERT(!(kRRect_ShapesMask & fOpInfo.fShapeTypes));
Ethan Nicholas1fc83b12016-11-22 09:31:35 -05001002 f->codeAppendf("mediump float distanceToEdge = %s - length(%s);",
csmartdaltona7f29642016-07-07 08:49:11 -07001003 fBloatedRadius.fsIn(), fEllipseCoords.fsIn());
1004 f->codeAppendf("%s = clamp(distanceToEdge, 0.0, 1.0);", outCoverage);
1005}
1006
1007void GLSLInstanceProcessor::BackendCoverage::emitArc(GrGLSLPPFragmentBuilder* f,
1008 const char* ellipseCoords,
1009 const char* ellipseName,
1010 bool ellipseCoordsNeedClamp,
1011 bool ellipseCoordsMayBeNegative,
1012 const char* outCoverage) {
1013 SkASSERT(!ellipseCoordsMayBeNegative || ellipseCoordsNeedClamp);
1014 if (ellipseCoordsNeedClamp) {
1015 // This serves two purposes:
1016 // - To restrict the arcs of rounded rects to their positive quadrants.
1017 // - To avoid inversesqrt(0) in the ellipse formula.
1018 if (ellipseCoordsMayBeNegative) {
Ethan Nicholas1fc83b12016-11-22 09:31:35 -05001019 f->codeAppendf("mediump vec2 ellipseClampedCoords = max(abs(%s), vec2(1e-4));",
1020 ellipseCoords);
csmartdaltona7f29642016-07-07 08:49:11 -07001021 } else {
Ethan Nicholas1fc83b12016-11-22 09:31:35 -05001022 f->codeAppendf("mediump vec2 ellipseClampedCoords = max(%s, vec2(1e-4));",
1023 ellipseCoords);
csmartdaltona7f29642016-07-07 08:49:11 -07001024 }
1025 ellipseCoords = "ellipseClampedCoords";
1026 }
1027 // ellipseCoords are in pixel space and ellipseName is 1 / rx^2, 1 / ry^2.
Ethan Nicholas1fc83b12016-11-22 09:31:35 -05001028 f->codeAppendf("highp vec2 Z = %s * %s;", ellipseCoords, ellipseName);
csmartdaltona7f29642016-07-07 08:49:11 -07001029 // implicit is the evaluation of (x/rx)^2 + (y/ry)^2 - 1.
Ethan Nicholas1fc83b12016-11-22 09:31:35 -05001030 f->codeAppendf("highp float implicit = dot(Z, %s) - 1.0;", ellipseCoords);
csmartdaltona7f29642016-07-07 08:49:11 -07001031 // gradDot is the squared length of the gradient of the implicit.
Ethan Nicholas1fc83b12016-11-22 09:31:35 -05001032 f->codeAppendf("highp float gradDot = 4.0 * dot(Z, Z);");
1033 f->codeAppend ("mediump float approxDist = implicit * inversesqrt(gradDot);");
csmartdaltona7f29642016-07-07 08:49:11 -07001034 f->codeAppendf("%s = clamp(0.5 - approxDist, 0.0, 1.0);", outCoverage);
1035}
1036
1037void GLSLInstanceProcessor::BackendCoverage::emitInnerRect(GrGLSLPPFragmentBuilder* f,
1038 const char* outCoverage) {
Ethan Nicholas1fc83b12016-11-22 09:31:35 -05001039 f->codeAppendf("lowp vec2 c = %s - abs(%s);",
csmartdaltona7f29642016-07-07 08:49:11 -07001040 fInnerShapeBloatedHalfSize.fsIn(), fDistanceToInnerEdge.fsIn());
1041 f->codeAppendf("%s = clamp(min(c.x, c.y), 0.0, 1.0);", outCoverage);
1042}
1043
1044////////////////////////////////////////////////////////////////////////////////////////////////////
1045
1046class GLSLInstanceProcessor::BackendMultisample : public Backend {
1047public:
Brian Salomon99ad1642016-12-16 09:50:45 -05001048 BackendMultisample(OpInfo opInfo, const VertexInputs& inputs, int effectiveSampleCnt)
1049 : INHERITED(opInfo, inputs)
1050 , fEffectiveSampleCnt(effectiveSampleCnt)
1051 , fShapeCoords(kVec2f_GrSLType)
1052 , fShapeInverseMatrix(kMat22f_GrSLType)
1053 , fFragShapeHalfSpan(kVec2f_GrSLType)
1054 , fArcTest(kVec2f_GrSLType)
1055 , fArcInverseMatrix(kMat22f_GrSLType)
1056 , fFragArcHalfSpan(kVec2f_GrSLType)
1057 , fEarlyAccept(kInt_GrSLType)
1058 , fInnerShapeInverseMatrix(kMat22f_GrSLType)
1059 , fFragInnerShapeHalfSpan(kVec2f_GrSLType) {
1060 fRectTrianglesMaySplit = fOpInfo.fHasPerspective;
1061 fNeedsNeighborRadii = this->isMixedSampled() && !fOpInfo.fHasPerspective;
csmartdaltona7f29642016-07-07 08:49:11 -07001062 }
1063
1064private:
Brian Salomon99ad1642016-12-16 09:50:45 -05001065 bool isMixedSampled() const { return AntialiasMode::kMixedSamples == fOpInfo.fAntialiasMode; }
csmartdaltona7f29642016-07-07 08:49:11 -07001066
1067 void onInit(GrGLSLVaryingHandler*, GrGLSLVertexBuilder*) override;
1068 void setupRect(GrGLSLVertexBuilder*) override;
1069 void setupOval(GrGLSLVertexBuilder*) override;
1070 void adjustRRectVertices(GrGLSLVertexBuilder*) override;
1071 void onSetupRRect(GrGLSLVertexBuilder*) override;
1072
1073 void onInitInnerShape(GrGLSLVaryingHandler*, GrGLSLVertexBuilder*) override;
1074 void setupInnerRect(GrGLSLVertexBuilder*) override;
1075 void setupInnerOval(GrGLSLVertexBuilder*) override;
csmartdalton0caee172016-07-13 08:48:53 -07001076 void onSetupInnerSimpleRRect(GrGLSLVertexBuilder*) override;
csmartdaltona7f29642016-07-07 08:49:11 -07001077
1078 void onEmitCode(GrGLSLVertexBuilder*, GrGLSLPPFragmentBuilder*, const char*,
1079 const char*) override;
1080
1081 struct EmitShapeCoords {
1082 const GrGLSLVarying* fVarying;
1083 const char* fInverseMatrix;
1084 const char* fFragHalfSpan;
1085 };
1086
1087 struct EmitShapeOpts {
1088 bool fIsTightGeometry;
1089 bool fResolveMixedSamples;
1090 bool fInvertCoverage;
1091 };
1092
1093 void emitRect(GrGLSLPPFragmentBuilder*, const EmitShapeCoords&, const EmitShapeOpts&);
1094 void emitArc(GrGLSLPPFragmentBuilder*, const EmitShapeCoords&, bool coordsMayBeNegative,
1095 bool clampCoords, const EmitShapeOpts&);
1096 void emitSimpleRRect(GrGLSLPPFragmentBuilder*, const EmitShapeCoords&, const char* rrect,
1097 const EmitShapeOpts&);
1098 void interpolateAtSample(GrGLSLPPFragmentBuilder*, const GrGLSLVarying&, const char* sampleIdx,
1099 const char* interpolationMatrix);
1100 void acceptOrRejectWholeFragment(GrGLSLPPFragmentBuilder*, bool inside, const EmitShapeOpts&);
1101 void acceptCoverageMask(GrGLSLPPFragmentBuilder*, const char* shapeMask, const EmitShapeOpts&,
1102 bool maybeSharedEdge = true);
1103
1104 int fEffectiveSampleCnt;
1105 bool fRectTrianglesMaySplit;
1106 GrGLSLVertToFrag fShapeCoords;
1107 GrGLSLVertToFrag fShapeInverseMatrix;
1108 GrGLSLVertToFrag fFragShapeHalfSpan;
1109 GrGLSLVertToFrag fArcTest;
1110 GrGLSLVertToFrag fArcInverseMatrix;
1111 GrGLSLVertToFrag fFragArcHalfSpan;
1112 GrGLSLVertToFrag fEarlyAccept;
1113 GrGLSLVertToFrag fInnerShapeInverseMatrix;
1114 GrGLSLVertToFrag fFragInnerShapeHalfSpan;
1115 SkString fSquareFun;
1116
1117 typedef Backend INHERITED;
1118};
1119
1120void GLSLInstanceProcessor::BackendMultisample::onInit(GrGLSLVaryingHandler* varyingHandler,
1121 GrGLSLVertexBuilder* v) {
1122 if (!this->isMixedSampled()) {
Brian Salomon99ad1642016-12-16 09:50:45 -05001123 if (kRect_ShapeFlag != fOpInfo.fShapeTypes) {
csmartdaltondd57dd72016-07-13 08:59:52 -07001124 varyingHandler->addFlatVarying("triangleIsArc", &fTriangleIsArc, kLow_GrSLPrecision);
csmartdaltona7f29642016-07-07 08:49:11 -07001125 varyingHandler->addVarying("arcCoords", &fArcCoords, kHigh_GrSLPrecision);
Brian Salomon99ad1642016-12-16 09:50:45 -05001126 if (!fOpInfo.fHasPerspective) {
csmartdaltona7f29642016-07-07 08:49:11 -07001127 varyingHandler->addFlatVarying("arcInverseMatrix", &fArcInverseMatrix,
1128 kHigh_GrSLPrecision);
1129 varyingHandler->addFlatVarying("fragArcHalfSpan", &fFragArcHalfSpan,
1130 kHigh_GrSLPrecision);
1131 }
Brian Salomon99ad1642016-12-16 09:50:45 -05001132 } else if (!fOpInfo.fInnerShapeTypes) {
csmartdaltona7f29642016-07-07 08:49:11 -07001133 return;
1134 }
1135 } else {
1136 varyingHandler->addVarying("shapeCoords", &fShapeCoords, kHigh_GrSLPrecision);
Brian Salomon99ad1642016-12-16 09:50:45 -05001137 if (!fOpInfo.fHasPerspective) {
csmartdaltona7f29642016-07-07 08:49:11 -07001138 varyingHandler->addFlatVarying("shapeInverseMatrix", &fShapeInverseMatrix,
1139 kHigh_GrSLPrecision);
1140 varyingHandler->addFlatVarying("fragShapeHalfSpan", &fFragShapeHalfSpan,
1141 kHigh_GrSLPrecision);
1142 }
Brian Salomon99ad1642016-12-16 09:50:45 -05001143 if (fOpInfo.fShapeTypes & kRRect_ShapesMask) {
csmartdaltona7f29642016-07-07 08:49:11 -07001144 varyingHandler->addVarying("arcCoords", &fArcCoords, kHigh_GrSLPrecision);
1145 varyingHandler->addVarying("arcTest", &fArcTest, kHigh_GrSLPrecision);
Brian Salomon99ad1642016-12-16 09:50:45 -05001146 if (!fOpInfo.fHasPerspective) {
csmartdaltona7f29642016-07-07 08:49:11 -07001147 varyingHandler->addFlatVarying("arcInverseMatrix", &fArcInverseMatrix,
1148 kHigh_GrSLPrecision);
1149 varyingHandler->addFlatVarying("fragArcHalfSpan", &fFragArcHalfSpan,
1150 kHigh_GrSLPrecision);
1151 }
Brian Salomon99ad1642016-12-16 09:50:45 -05001152 } else if (fOpInfo.fShapeTypes & kOval_ShapeFlag) {
csmartdaltona7f29642016-07-07 08:49:11 -07001153 fArcCoords = fShapeCoords;
1154 fArcInverseMatrix = fShapeInverseMatrix;
1155 fFragArcHalfSpan = fFragShapeHalfSpan;
Brian Salomon99ad1642016-12-16 09:50:45 -05001156 if (fOpInfo.fShapeTypes & kRect_ShapeFlag) {
csmartdaltona7f29642016-07-07 08:49:11 -07001157 varyingHandler->addFlatVarying("triangleIsArc", &fTriangleIsArc,
csmartdaltondd57dd72016-07-13 08:59:52 -07001158 kLow_GrSLPrecision);
csmartdaltona7f29642016-07-07 08:49:11 -07001159 }
1160 }
Brian Salomon99ad1642016-12-16 09:50:45 -05001161 if (kRect_ShapeFlag != fOpInfo.fShapeTypes) {
1162 v->defineConstantf("int", "SAMPLE_MASK_ALL", "0x%x", (1 << fEffectiveSampleCnt) - 1);
1163 varyingHandler->addFlatVarying("earlyAccept", &fEarlyAccept, kHigh_GrSLPrecision);
csmartdaltona7f29642016-07-07 08:49:11 -07001164 }
1165 }
Brian Salomon99ad1642016-12-16 09:50:45 -05001166 if (!fOpInfo.fHasPerspective) {
csmartdaltona7f29642016-07-07 08:49:11 -07001167 v->codeAppend("mat2 shapeInverseMatrix = inverse(mat2(shapeMatrix));");
1168 v->codeAppend("vec2 fragShapeSpan = abs(vec4(shapeInverseMatrix).xz) + "
1169 "abs(vec4(shapeInverseMatrix).yw);");
1170 }
1171}
1172
1173void GLSLInstanceProcessor::BackendMultisample::setupRect(GrGLSLVertexBuilder* v) {
1174 if (fShapeCoords.vsOut()) {
1175 v->codeAppendf("%s = %s;", fShapeCoords.vsOut(), this->outShapeCoords());
1176 }
1177 if (fShapeInverseMatrix.vsOut()) {
1178 v->codeAppendf("%s = shapeInverseMatrix;", fShapeInverseMatrix.vsOut());
1179 }
1180 if (fFragShapeHalfSpan.vsOut()) {
1181 v->codeAppendf("%s = 0.5 * fragShapeSpan;", fFragShapeHalfSpan.vsOut());
1182 }
1183 if (fArcTest.vsOut()) {
1184 // Pick a value that is not > 0.
1185 v->codeAppendf("%s = vec2(0);", fArcTest.vsOut());
1186 }
1187 if (fTriangleIsArc.vsOut()) {
1188 v->codeAppendf("%s = 0;", fTriangleIsArc.vsOut());
1189 }
1190 if (fEarlyAccept.vsOut()) {
1191 v->codeAppendf("%s = SAMPLE_MASK_ALL;", fEarlyAccept.vsOut());
1192 }
1193}
1194
1195void GLSLInstanceProcessor::BackendMultisample::setupOval(GrGLSLVertexBuilder* v) {
1196 v->codeAppendf("%s = abs(%s);", fArcCoords.vsOut(), this->outShapeCoords());
1197 if (fArcInverseMatrix.vsOut()) {
1198 v->codeAppendf("vec2 s = sign(%s);", this->outShapeCoords());
1199 v->codeAppendf("%s = shapeInverseMatrix * mat2(s.x, 0, 0 , s.y);",
1200 fArcInverseMatrix.vsOut());
1201 }
1202 if (fFragArcHalfSpan.vsOut()) {
1203 v->codeAppendf("%s = 0.5 * fragShapeSpan;", fFragArcHalfSpan.vsOut());
1204 }
1205 if (fArcTest.vsOut()) {
1206 // Pick a value that is > 0.
1207 v->codeAppendf("%s = vec2(1);", fArcTest.vsOut());
1208 }
1209 if (fTriangleIsArc.vsOut()) {
1210 if (!this->isMixedSampled()) {
1211 v->codeAppendf("%s = %s & 1;",
1212 fTriangleIsArc.vsOut(), fInputs.attr(Attrib::kVertexAttrs));
1213 } else {
1214 v->codeAppendf("%s = 1;", fTriangleIsArc.vsOut());
1215 }
1216 }
1217 if (fEarlyAccept.vsOut()) {
1218 v->codeAppendf("%s = ~%s & SAMPLE_MASK_ALL;",
1219 fEarlyAccept.vsOut(), fInputs.attr(Attrib::kVertexAttrs));
1220 }
1221}
1222
1223void GLSLInstanceProcessor::BackendMultisample::adjustRRectVertices(GrGLSLVertexBuilder* v) {
1224 if (!this->isMixedSampled()) {
1225 INHERITED::adjustRRectVertices(v);
1226 return;
1227 }
1228
Brian Salomon99ad1642016-12-16 09:50:45 -05001229 if (!fOpInfo.fHasPerspective) {
csmartdaltona7f29642016-07-07 08:49:11 -07001230 // For the mixed samples algorithm it's best to bloat the corner triangles a bit so that
1231 // more of the pixels that cross into the arc region are completely inside the shared edges.
1232 // We also snap to a regular rect if the radii shrink smaller than a pixel.
1233 v->codeAppend ("vec2 midpt = 0.5 * (neighborRadii - radii);");
1234 v->codeAppend ("vec2 cornerSize = any(lessThan(radii, fragShapeSpan)) ? "
1235 "vec2(0) : min(radii + 0.5 * fragShapeSpan, 1.0 - midpt);");
1236 } else {
1237 // TODO: We could still bloat the corner triangle in the perspective case; we would just
1238 // need to find the screen-space derivative of shape coords at this particular point.
1239 v->codeAppend ("vec2 cornerSize = any(lessThan(radii, vec2(1e-3))) ? vec2(0) : radii;");
1240 }
1241
1242 v->codeAppendf("if (abs(%s.x) == 0.5)"
1243 "%s.x = cornerSign.x * (1.0 - cornerSize.x);",
1244 fInputs.attr(Attrib::kShapeCoords), fModifiedShapeCoords);
1245 v->codeAppendf("if (abs(%s.y) == 0.5)"
1246 "%s.y = cornerSign.y * (1.0 - cornerSize.y);",
1247 fInputs.attr(Attrib::kShapeCoords), fModifiedShapeCoords);
1248}
1249
1250void GLSLInstanceProcessor::BackendMultisample::onSetupRRect(GrGLSLVertexBuilder* v) {
1251 if (fShapeCoords.vsOut()) {
1252 v->codeAppendf("%s = %s;", fShapeCoords.vsOut(), this->outShapeCoords());
1253 }
1254 if (fShapeInverseMatrix.vsOut()) {
1255 v->codeAppendf("%s = shapeInverseMatrix;", fShapeInverseMatrix.vsOut());
1256 }
1257 if (fFragShapeHalfSpan.vsOut()) {
1258 v->codeAppendf("%s = 0.5 * fragShapeSpan;", fFragShapeHalfSpan.vsOut());
1259 }
1260 if (fArcInverseMatrix.vsOut()) {
1261 v->codeAppend ("vec2 s = cornerSign / radii;");
1262 v->codeAppendf("%s = shapeInverseMatrix * mat2(s.x, 0, 0, s.y);",
1263 fArcInverseMatrix.vsOut());
1264 }
1265 if (fFragArcHalfSpan.vsOut()) {
1266 v->codeAppendf("%s = 0.5 * (abs(vec4(%s).xz) + abs(vec4(%s).yw));",
1267 fFragArcHalfSpan.vsOut(), fArcInverseMatrix.vsOut(),
1268 fArcInverseMatrix.vsOut());
1269 }
1270 if (fArcTest.vsOut()) {
1271 // The interior triangles are laid out as a fan. fArcTest is both distances from shared
1272 // edges of a fan triangle to a point within that triangle. fArcTest is used to check if a
1273 // fragment is too close to either shared edge, in which case we point sample the shape as a
1274 // rect at that point in order to guarantee the mixed samples discard logic works correctly.
1275 v->codeAppendf("%s = (cornerSize == vec2(0)) ? vec2(0) : "
1276 "cornerSign * %s * mat2(1, cornerSize.x - 1.0, cornerSize.y - 1.0, 1);",
1277 fArcTest.vsOut(), fModifiedShapeCoords);
Brian Salomon99ad1642016-12-16 09:50:45 -05001278 if (!fOpInfo.fHasPerspective) {
csmartdaltona7f29642016-07-07 08:49:11 -07001279 // Shift the point at which distances to edges are measured from the center of the pixel
1280 // to the corner. This way the sign of fArcTest will quickly tell us whether a pixel
1281 // is completely inside the shared edge. Perspective mode will accomplish this same task
1282 // by finding the derivatives in the fragment shader.
1283 v->codeAppendf("%s -= 0.5 * (fragShapeSpan.yx * abs(radii - 1.0) + fragShapeSpan);",
1284 fArcTest.vsOut());
1285 }
1286 }
1287 if (fEarlyAccept.vsOut()) {
1288 SkASSERT(this->isMixedSampled());
1289 v->codeAppendf("%s = all(equal(vec2(1), abs(%s))) ? 0 : SAMPLE_MASK_ALL;",
1290 fEarlyAccept.vsOut(), fInputs.attr(Attrib::kShapeCoords));
1291 }
1292}
1293
1294void
1295GLSLInstanceProcessor::BackendMultisample::onInitInnerShape(GrGLSLVaryingHandler* varyingHandler,
1296 GrGLSLVertexBuilder* v) {
1297 varyingHandler->addVarying("innerShapeCoords", &fInnerShapeCoords, kHigh_GrSLPrecision);
Brian Salomon99ad1642016-12-16 09:50:45 -05001298 if (kOval_ShapeFlag != fOpInfo.fInnerShapeTypes &&
1299 kRect_ShapeFlag != fOpInfo.fInnerShapeTypes) {
csmartdaltona7f29642016-07-07 08:49:11 -07001300 varyingHandler->addFlatVarying("innerRRect", &fInnerRRect, kHigh_GrSLPrecision);
1301 }
Brian Salomon99ad1642016-12-16 09:50:45 -05001302 if (!fOpInfo.fHasPerspective) {
csmartdaltona7f29642016-07-07 08:49:11 -07001303 varyingHandler->addFlatVarying("innerShapeInverseMatrix", &fInnerShapeInverseMatrix,
1304 kHigh_GrSLPrecision);
1305 v->codeAppendf("%s = shapeInverseMatrix * mat2(outer2Inner.x, 0, 0, outer2Inner.y);",
1306 fInnerShapeInverseMatrix.vsOut());
1307 varyingHandler->addFlatVarying("fragInnerShapeHalfSpan", &fFragInnerShapeHalfSpan,
1308 kHigh_GrSLPrecision);
1309 v->codeAppendf("%s = 0.5 * fragShapeSpan * outer2Inner.xy;",
1310 fFragInnerShapeHalfSpan.vsOut());
1311 }
1312}
1313
1314void GLSLInstanceProcessor::BackendMultisample::setupInnerRect(GrGLSLVertexBuilder* v) {
1315 if (fInnerRRect.vsOut()) {
1316 // The fragment shader will generalize every inner shape as a round rect. Since this one
1317 // is a rect, we simply emit bogus parameters for the round rect (negative radii) that
1318 // ensure the fragment shader always takes the "sample as rect" codepath.
1319 v->codeAppendf("%s = vec4(2.0 * (inner.zw - inner.xy) / (outer.zw - outer.xy), vec2(0));",
1320 fInnerRRect.vsOut());
1321 }
1322}
1323
1324void GLSLInstanceProcessor::BackendMultisample::setupInnerOval(GrGLSLVertexBuilder* v) {
1325 if (fInnerRRect.vsOut()) {
1326 v->codeAppendf("%s = vec4(0, 0, 1, 1);", fInnerRRect.vsOut());
1327 }
1328}
1329
csmartdalton0caee172016-07-13 08:48:53 -07001330void GLSLInstanceProcessor::BackendMultisample::onSetupInnerSimpleRRect(GrGLSLVertexBuilder* v) {
csmartdaltona7f29642016-07-07 08:49:11 -07001331 // Avoid numeric instability by not allowing the inner radii to get smaller than 1/10th pixel.
1332 if (fFragInnerShapeHalfSpan.vsOut()) {
1333 v->codeAppendf("innerRadii = max(innerRadii, 2e-1 * %s);", fFragInnerShapeHalfSpan.vsOut());
1334 } else {
1335 v->codeAppend ("innerRadii = max(innerRadii, vec2(1e-4));");
1336 }
1337 v->codeAppendf("%s = vec4(1.0 - innerRadii, 1.0 / innerRadii);", fInnerRRect.vsOut());
1338}
1339
1340void GLSLInstanceProcessor::BackendMultisample::onEmitCode(GrGLSLVertexBuilder*,
1341 GrGLSLPPFragmentBuilder* f,
1342 const char*, const char*) {
ethannicholas5961bc92016-10-12 06:39:56 -07001343 f->defineConstant("SAMPLE_COUNT", fEffectiveSampleCnt);
csmartdaltona7f29642016-07-07 08:49:11 -07001344 if (this->isMixedSampled()) {
ethannicholas5961bc92016-10-12 06:39:56 -07001345 f->defineConstantf("int", "SAMPLE_MASK_ALL", "0x%x", (1 << fEffectiveSampleCnt) - 1);
1346 f->defineConstantf("int", "SAMPLE_MASK_MSB", "0x%x", 1 << (fEffectiveSampleCnt - 1));
csmartdaltona7f29642016-07-07 08:49:11 -07001347 }
1348
Brian Salomon99ad1642016-12-16 09:50:45 -05001349 if (kRect_ShapeFlag != (fOpInfo.fShapeTypes | fOpInfo.fInnerShapeTypes)) {
Brian Salomon99938a82016-11-21 13:41:08 -05001350 GrShaderVar x("x", kVec2f_GrSLType, GrShaderVar::kNonArray, kHigh_GrSLPrecision);
csmartdaltona7f29642016-07-07 08:49:11 -07001351 f->emitFunction(kFloat_GrSLType, "square", 1, &x, "return dot(x, x);", &fSquareFun);
1352 }
1353
1354 EmitShapeCoords shapeCoords;
1355 shapeCoords.fVarying = &fShapeCoords;
1356 shapeCoords.fInverseMatrix = fShapeInverseMatrix.fsIn();
1357 shapeCoords.fFragHalfSpan = fFragShapeHalfSpan.fsIn();
1358
1359 EmitShapeCoords arcCoords;
1360 arcCoords.fVarying = &fArcCoords;
1361 arcCoords.fInverseMatrix = fArcInverseMatrix.fsIn();
1362 arcCoords.fFragHalfSpan = fFragArcHalfSpan.fsIn();
Brian Salomon99ad1642016-12-16 09:50:45 -05001363 bool clampArcCoords = this->isMixedSampled() && (fOpInfo.fShapeTypes & kRRect_ShapesMask);
csmartdaltona7f29642016-07-07 08:49:11 -07001364
1365 EmitShapeOpts opts;
1366 opts.fIsTightGeometry = true;
1367 opts.fResolveMixedSamples = this->isMixedSampled();
1368 opts.fInvertCoverage = false;
1369
Brian Salomon99ad1642016-12-16 09:50:45 -05001370 if (fOpInfo.fHasPerspective && fOpInfo.fInnerShapeTypes) {
csmartdaltona7f29642016-07-07 08:49:11 -07001371 // This determines if the fragment should consider the inner shape in its sample mask.
1372 // We take the derivative early in case discards may occur before we get to the inner shape.
Ethan Nicholas1fc83b12016-11-22 09:31:35 -05001373 f->codeAppendf("highp vec2 fragInnerShapeApproxHalfSpan = 0.5 * fwidth(%s);",
csmartdaltona7f29642016-07-07 08:49:11 -07001374 fInnerShapeCoords.fsIn());
1375 }
1376
1377 if (!this->isMixedSampled()) {
1378 SkASSERT(!fArcTest.fsIn());
1379 if (fTriangleIsArc.fsIn()) {
1380 f->codeAppendf("if (%s != 0) {", fTriangleIsArc.fsIn());
1381 this->emitArc(f, arcCoords, false, clampArcCoords, opts);
1382
1383 f->codeAppend ("}");
1384 }
1385 } else {
1386 const char* arcTest = fArcTest.fsIn();
Brian Salomon99ad1642016-12-16 09:50:45 -05001387 if (arcTest && fOpInfo.fHasPerspective) {
csmartdaltone0d36292016-07-29 08:14:20 -07001388 // The non-perspective version accounts for fwidth() in the vertex shader.
csmartdaltona7f29642016-07-07 08:49:11 -07001389 // We make sure to take the derivative here, before a neighbor pixel may early accept.
Ethan Nicholas1fc83b12016-11-22 09:31:35 -05001390 f->codeAppendf("highp vec2 arcTest = %s - 0.5 * fwidth(%s);",
csmartdaltona7f29642016-07-07 08:49:11 -07001391 fArcTest.fsIn(), fArcTest.fsIn());
1392 arcTest = "arcTest";
1393 }
1394 const char* earlyAccept = fEarlyAccept.fsIn() ? fEarlyAccept.fsIn() : "SAMPLE_MASK_ALL";
1395 f->codeAppendf("if (gl_SampleMaskIn[0] == %s) {", earlyAccept);
1396 f->overrideSampleCoverage(earlyAccept);
1397 f->codeAppend ("} else {");
1398 if (arcTest) {
1399 // At this point, if the sample mask is all set it means we are inside an arc triangle.
1400 f->codeAppendf("if (gl_SampleMaskIn[0] == SAMPLE_MASK_ALL || "
1401 "all(greaterThan(%s, vec2(0)))) {", arcTest);
1402 this->emitArc(f, arcCoords, false, clampArcCoords, opts);
1403 f->codeAppend ("} else {");
1404 this->emitRect(f, shapeCoords, opts);
1405 f->codeAppend ("}");
1406 } else if (fTriangleIsArc.fsIn()) {
1407 f->codeAppendf("if (%s == 0) {", fTriangleIsArc.fsIn());
1408 this->emitRect(f, shapeCoords, opts);
1409 f->codeAppend ("} else {");
1410 this->emitArc(f, arcCoords, false, clampArcCoords, opts);
1411 f->codeAppend ("}");
Brian Salomon99ad1642016-12-16 09:50:45 -05001412 } else if (fOpInfo.fShapeTypes == kOval_ShapeFlag) {
csmartdaltona7f29642016-07-07 08:49:11 -07001413 this->emitArc(f, arcCoords, false, clampArcCoords, opts);
1414 } else {
Brian Salomon99ad1642016-12-16 09:50:45 -05001415 SkASSERT(fOpInfo.fShapeTypes == kRect_ShapeFlag);
csmartdaltona7f29642016-07-07 08:49:11 -07001416 this->emitRect(f, shapeCoords, opts);
1417 }
1418 f->codeAppend ("}");
1419 }
1420
Brian Salomon99ad1642016-12-16 09:50:45 -05001421 if (fOpInfo.fInnerShapeTypes) {
csmartdaltona7f29642016-07-07 08:49:11 -07001422 f->codeAppendf("// Inner shape.\n");
1423
1424 EmitShapeCoords innerShapeCoords;
1425 innerShapeCoords.fVarying = &fInnerShapeCoords;
Brian Salomon99ad1642016-12-16 09:50:45 -05001426 if (!fOpInfo.fHasPerspective) {
csmartdaltona7f29642016-07-07 08:49:11 -07001427 innerShapeCoords.fInverseMatrix = fInnerShapeInverseMatrix.fsIn();
1428 innerShapeCoords.fFragHalfSpan = fFragInnerShapeHalfSpan.fsIn();
1429 }
1430
1431 EmitShapeOpts innerOpts;
1432 innerOpts.fIsTightGeometry = false;
1433 innerOpts.fResolveMixedSamples = false; // Mixed samples are resolved in the outer shape.
1434 innerOpts.fInvertCoverage = true;
1435
Brian Salomon99ad1642016-12-16 09:50:45 -05001436 if (kOval_ShapeFlag == fOpInfo.fInnerShapeTypes) {
csmartdaltona7f29642016-07-07 08:49:11 -07001437 this->emitArc(f, innerShapeCoords, true, false, innerOpts);
1438 } else {
1439 f->codeAppendf("if (all(lessThan(abs(%s), 1.0 + %s))) {", fInnerShapeCoords.fsIn(),
Brian Salomon99ad1642016-12-16 09:50:45 -05001440 !fOpInfo.fHasPerspective ? innerShapeCoords.fFragHalfSpan
1441 : "fragInnerShapeApproxHalfSpan"); // Above.
1442 if (kRect_ShapeFlag == fOpInfo.fInnerShapeTypes) {
csmartdaltona7f29642016-07-07 08:49:11 -07001443 this->emitRect(f, innerShapeCoords, innerOpts);
1444 } else {
1445 this->emitSimpleRRect(f, innerShapeCoords, fInnerRRect.fsIn(), innerOpts);
1446 }
1447 f->codeAppend ("}");
1448 }
1449 }
1450}
1451
1452void GLSLInstanceProcessor::BackendMultisample::emitRect(GrGLSLPPFragmentBuilder* f,
1453 const EmitShapeCoords& coords,
1454 const EmitShapeOpts& opts) {
1455 // Full MSAA doesn't need to do anything to draw a rect.
1456 SkASSERT(!opts.fIsTightGeometry || opts.fResolveMixedSamples);
1457 if (coords.fFragHalfSpan) {
1458 f->codeAppendf("if (all(lessThanEqual(abs(%s), 1.0 - %s))) {",
1459 coords.fVarying->fsIn(), coords.fFragHalfSpan);
1460 // The entire pixel is inside the rect.
1461 this->acceptOrRejectWholeFragment(f, true, opts);
1462 f->codeAppend ("} else ");
1463 if (opts.fIsTightGeometry && !fRectTrianglesMaySplit) {
1464 f->codeAppendf("if (any(lessThan(abs(%s), 1.0 - %s))) {",
1465 coords.fVarying->fsIn(), coords.fFragHalfSpan);
1466 // The pixel falls on an edge of the rectangle and is known to not be on a shared edge.
1467 this->acceptCoverageMask(f, "gl_SampleMaskIn[0]", opts, false);
1468 f->codeAppend ("} else");
1469 }
1470 f->codeAppend ("{");
1471 }
1472 f->codeAppend ("int rectMask = 0;");
1473 f->codeAppend ("for (int i = 0; i < SAMPLE_COUNT; i++) {");
Ethan Nicholas1fc83b12016-11-22 09:31:35 -05001474 f->codeAppend ( "highp vec2 pt = ");
csmartdaltona7f29642016-07-07 08:49:11 -07001475 this->interpolateAtSample(f, *coords.fVarying, "i", coords.fInverseMatrix);
1476 f->codeAppend ( ";");
1477 f->codeAppend ( "if (all(lessThan(abs(pt), vec2(1)))) rectMask |= (1 << i);");
1478 f->codeAppend ("}");
1479 this->acceptCoverageMask(f, "rectMask", opts);
1480 if (coords.fFragHalfSpan) {
1481 f->codeAppend ("}");
1482 }
1483}
1484
1485void GLSLInstanceProcessor::BackendMultisample::emitArc(GrGLSLPPFragmentBuilder* f,
1486 const EmitShapeCoords& coords,
1487 bool coordsMayBeNegative, bool clampCoords,
1488 const EmitShapeOpts& opts) {
1489 if (coords.fFragHalfSpan) {
1490 SkString absArcCoords;
1491 absArcCoords.printf(coordsMayBeNegative ? "abs(%s)" : "%s", coords.fVarying->fsIn());
1492 if (clampCoords) {
1493 f->codeAppendf("if (%s(max(%s + %s, vec2(0))) < 1.0) {",
1494 fSquareFun.c_str(), absArcCoords.c_str(), coords.fFragHalfSpan);
1495 } else {
1496 f->codeAppendf("if (%s(%s + %s) < 1.0) {",
1497 fSquareFun.c_str(), absArcCoords.c_str(), coords.fFragHalfSpan);
1498 }
1499 // The entire pixel is inside the arc.
1500 this->acceptOrRejectWholeFragment(f, true, opts);
1501 f->codeAppendf("} else if (%s(max(%s - %s, vec2(0))) >= 1.0) {",
1502 fSquareFun.c_str(), absArcCoords.c_str(), coords.fFragHalfSpan);
1503 // The entire pixel is outside the arc.
1504 this->acceptOrRejectWholeFragment(f, false, opts);
1505 f->codeAppend ("} else {");
1506 }
1507 f->codeAppend ( "int arcMask = 0;");
1508 f->codeAppend ( "for (int i = 0; i < SAMPLE_COUNT; i++) {");
Ethan Nicholas1fc83b12016-11-22 09:31:35 -05001509 f->codeAppend ( "highp vec2 pt = ");
csmartdaltona7f29642016-07-07 08:49:11 -07001510 this->interpolateAtSample(f, *coords.fVarying, "i", coords.fInverseMatrix);
1511 f->codeAppend ( ";");
1512 if (clampCoords) {
1513 SkASSERT(!coordsMayBeNegative);
1514 f->codeAppend ( "pt = max(pt, vec2(0));");
1515 }
1516 f->codeAppendf( "if (%s(pt) < 1.0) arcMask |= (1 << i);", fSquareFun.c_str());
1517 f->codeAppend ( "}");
1518 this->acceptCoverageMask(f, "arcMask", opts);
1519 if (coords.fFragHalfSpan) {
1520 f->codeAppend ("}");
1521 }
1522}
1523
1524void GLSLInstanceProcessor::BackendMultisample::emitSimpleRRect(GrGLSLPPFragmentBuilder* f,
1525 const EmitShapeCoords& coords,
1526 const char* rrect,
1527 const EmitShapeOpts& opts) {
Ethan Nicholas1fc83b12016-11-22 09:31:35 -05001528 f->codeAppendf("highp vec2 distanceToArcEdge = abs(%s) - %s.xy;", coords.fVarying->fsIn(),
1529 rrect);
csmartdaltona7f29642016-07-07 08:49:11 -07001530 f->codeAppend ("if (any(lessThan(distanceToArcEdge, vec2(0)))) {");
1531 this->emitRect(f, coords, opts);
1532 f->codeAppend ("} else {");
1533 if (coords.fInverseMatrix && coords.fFragHalfSpan) {
Ethan Nicholas1fc83b12016-11-22 09:31:35 -05001534 f->codeAppendf("highp vec2 rrectCoords = distanceToArcEdge * %s.zw;", rrect);
1535 f->codeAppendf("highp vec2 fragRRectHalfSpan = %s * %s.zw;", coords.fFragHalfSpan, rrect);
csmartdaltona7f29642016-07-07 08:49:11 -07001536 f->codeAppendf("if (%s(rrectCoords + fragRRectHalfSpan) <= 1.0) {", fSquareFun.c_str());
1537 // The entire pixel is inside the round rect.
1538 this->acceptOrRejectWholeFragment(f, true, opts);
1539 f->codeAppendf("} else if (%s(max(rrectCoords - fragRRectHalfSpan, vec2(0))) >= 1.0) {",
1540 fSquareFun.c_str());
1541 // The entire pixel is outside the round rect.
1542 this->acceptOrRejectWholeFragment(f, false, opts);
1543 f->codeAppend ("} else {");
Ethan Nicholas1fc83b12016-11-22 09:31:35 -05001544 f->codeAppendf( "highp vec2 s = %s.zw * sign(%s);", rrect, coords.fVarying->fsIn());
1545 f->codeAppendf( "highp mat2 innerRRectInverseMatrix = %s * mat2(s.x, 0, 0, s.y);",
csmartdaltona7f29642016-07-07 08:49:11 -07001546 coords.fInverseMatrix);
Ethan Nicholas1fc83b12016-11-22 09:31:35 -05001547 f->codeAppend ( "highp int rrectMask = 0;");
csmartdaltona7f29642016-07-07 08:49:11 -07001548 f->codeAppend ( "for (int i = 0; i < SAMPLE_COUNT; i++) {");
Ethan Nicholas1fc83b12016-11-22 09:31:35 -05001549 f->codeAppend ( "highp vec2 pt = rrectCoords + ");
csmartdaltona7f29642016-07-07 08:49:11 -07001550 f->appendOffsetToSample("i", GrGLSLFPFragmentBuilder::kSkiaDevice_Coordinates);
1551 f->codeAppend ( "* innerRRectInverseMatrix;");
1552 f->codeAppendf( "if (%s(max(pt, vec2(0))) < 1.0) rrectMask |= (1 << i);",
1553 fSquareFun.c_str());
1554 f->codeAppend ( "}");
1555 this->acceptCoverageMask(f, "rrectMask", opts);
1556 f->codeAppend ("}");
1557 } else {
1558 f->codeAppend ("int rrectMask = 0;");
1559 f->codeAppend ("for (int i = 0; i < SAMPLE_COUNT; i++) {");
Ethan Nicholas1fc83b12016-11-22 09:31:35 -05001560 f->codeAppend ( "highp vec2 shapePt = ");
csmartdaltona7f29642016-07-07 08:49:11 -07001561 this->interpolateAtSample(f, *coords.fVarying, "i", nullptr);
1562 f->codeAppend ( ";");
Ethan Nicholas1fc83b12016-11-22 09:31:35 -05001563 f->codeAppendf( "highp vec2 rrectPt = max(abs(shapePt) - %s.xy, vec2(0)) * %s.zw;",
csmartdaltona7f29642016-07-07 08:49:11 -07001564 rrect, rrect);
1565 f->codeAppendf( "if (%s(rrectPt) < 1.0) rrectMask |= (1 << i);", fSquareFun.c_str());
1566 f->codeAppend ("}");
1567 this->acceptCoverageMask(f, "rrectMask", opts);
1568 }
1569 f->codeAppend ("}");
1570}
1571
1572void GLSLInstanceProcessor::BackendMultisample::interpolateAtSample(GrGLSLPPFragmentBuilder* f,
1573 const GrGLSLVarying& varying,
1574 const char* sampleIdx,
1575 const char* interpolationMatrix) {
1576 if (interpolationMatrix) {
1577 f->codeAppendf("(%s + ", varying.fsIn());
1578 f->appendOffsetToSample(sampleIdx, GrGLSLFPFragmentBuilder::kSkiaDevice_Coordinates);
1579 f->codeAppendf(" * %s)", interpolationMatrix);
1580 } else {
1581 SkAssertResult(
1582 f->enableFeature(GrGLSLFragmentBuilder::kMultisampleInterpolation_GLSLFeature));
1583 f->codeAppendf("interpolateAtOffset(%s, ", varying.fsIn());
1584 f->appendOffsetToSample(sampleIdx, GrGLSLFPFragmentBuilder::kGLSLWindow_Coordinates);
1585 f->codeAppend(")");
1586 }
1587}
1588
1589void
1590GLSLInstanceProcessor::BackendMultisample::acceptOrRejectWholeFragment(GrGLSLPPFragmentBuilder* f,
1591 bool inside,
1592 const EmitShapeOpts& opts) {
1593 if (inside != opts.fInvertCoverage) { // Accept the entire fragment.
1594 if (opts.fResolveMixedSamples) {
1595 // This is a mixed sampled fragment in the interior of the shape. Reassign 100% coverage
1596 // to one fragment, and drop all other fragments that may fall on this same pixel. Since
1597 // our geometry is water tight and non-overlapping, we can take advantage of the
1598 // properties that (1) the incoming sample masks will be disjoint across fragments that
1599 // fall on a common pixel, and (2) since the entire fragment is inside the shape, each
1600 // sample's corresponding bit will be set in the incoming sample mask of exactly one
1601 // fragment.
1602 f->codeAppend("if ((gl_SampleMaskIn[0] & SAMPLE_MASK_MSB) == 0) {");
1603 // Drop this fragment.
Brian Salomon99ad1642016-12-16 09:50:45 -05001604 if (!fOpInfo.fCannotDiscard) {
csmartdaltona7f29642016-07-07 08:49:11 -07001605 f->codeAppend("discard;");
1606 } else {
1607 f->overrideSampleCoverage("0");
1608 }
1609 f->codeAppend("} else {");
1610 // Override the lone surviving fragment to full coverage.
1611 f->overrideSampleCoverage("-1");
1612 f->codeAppend("}");
1613 }
1614 } else { // Reject the entire fragment.
Brian Salomon99ad1642016-12-16 09:50:45 -05001615 if (!fOpInfo.fCannotDiscard) {
csmartdaltona7f29642016-07-07 08:49:11 -07001616 f->codeAppend("discard;");
1617 } else if (opts.fResolveMixedSamples) {
1618 f->overrideSampleCoverage("0");
1619 } else {
1620 f->maskSampleCoverage("0");
1621 }
1622 }
1623}
1624
1625void GLSLInstanceProcessor::BackendMultisample::acceptCoverageMask(GrGLSLPPFragmentBuilder* f,
1626 const char* shapeMask,
1627 const EmitShapeOpts& opts,
1628 bool maybeSharedEdge) {
1629 if (opts.fResolveMixedSamples) {
1630 if (maybeSharedEdge) {
1631 // This is a mixed sampled fragment, potentially on the outer edge of the shape, with
1632 // only partial shape coverage. Override the coverage of one fragment to "shapeMask",
1633 // and drop all other fragments that may fall on this same pixel. Since our geometry is
1634 // water tight, non-overlapping, and completely contains the shape, this means that each
1635 // "on" bit from shapeMask is guaranteed to be set in the incoming sample mask of one,
1636 // and only one, fragment that falls on this same pixel.
1637 SkASSERT(!opts.fInvertCoverage);
1638 f->codeAppendf("if ((gl_SampleMaskIn[0] & (1 << findMSB(%s))) == 0) {", shapeMask);
1639 // Drop this fragment.
Brian Salomon99ad1642016-12-16 09:50:45 -05001640 if (!fOpInfo.fCannotDiscard) {
csmartdaltona7f29642016-07-07 08:49:11 -07001641 f->codeAppend ("discard;");
1642 } else {
1643 f->overrideSampleCoverage("0");
1644 }
1645 f->codeAppend ("} else {");
1646 // Override the coverage of the lone surviving fragment to "shapeMask".
1647 f->overrideSampleCoverage(shapeMask);
1648 f->codeAppend ("}");
1649 } else {
1650 f->overrideSampleCoverage(shapeMask);
1651 }
1652 } else {
1653 f->maskSampleCoverage(shapeMask, opts.fInvertCoverage);
1654 }
1655}
1656
1657////////////////////////////////////////////////////////////////////////////////////////////////////
1658
Brian Salomon99ad1642016-12-16 09:50:45 -05001659GLSLInstanceProcessor::Backend* GLSLInstanceProcessor::Backend::Create(const GrPipeline& pipeline,
1660 OpInfo opInfo,
1661 const VertexInputs& inputs) {
1662 switch (opInfo.fAntialiasMode) {
csmartdaltona7f29642016-07-07 08:49:11 -07001663 default:
1664 SkFAIL("Unexpected antialias mode.");
1665 case AntialiasMode::kNone:
Brian Salomon99ad1642016-12-16 09:50:45 -05001666 return new BackendNonAA(opInfo, inputs);
csmartdaltona7f29642016-07-07 08:49:11 -07001667 case AntialiasMode::kCoverage:
Brian Salomon99ad1642016-12-16 09:50:45 -05001668 return new BackendCoverage(opInfo, inputs);
csmartdaltona7f29642016-07-07 08:49:11 -07001669 case AntialiasMode::kMSAA:
1670 case AntialiasMode::kMixedSamples: {
1671 const GrRenderTargetPriv& rtp = pipeline.getRenderTarget()->renderTargetPriv();
csmartdaltonc633abb2016-11-01 08:55:55 -07001672 const GrGpu::MultisampleSpecs& specs = rtp.getMultisampleSpecs(pipeline);
Brian Salomon99ad1642016-12-16 09:50:45 -05001673 return new BackendMultisample(opInfo, inputs, specs.fEffectiveSampleCnt);
csmartdaltona7f29642016-07-07 08:49:11 -07001674 }
1675 }
1676}
1677
1678////////////////////////////////////////////////////////////////////////////////////////////////////
1679
1680const ShapeVertex kVertexData[] = {
1681 // Rectangle.
1682 {+1, +1, ~0}, /*0*/
1683 {-1, +1, ~0}, /*1*/
1684 {-1, -1, ~0}, /*2*/
1685 {+1, -1, ~0}, /*3*/
1686 // The next 4 are for the bordered version.
1687 {+1, +1, 0}, /*4*/
1688 {-1, +1, 0}, /*5*/
1689 {-1, -1, 0}, /*6*/
1690 {+1, -1, 0}, /*7*/
1691
1692 // Octagon that inscribes the unit circle, cut by an interior unit octagon.
1693 {+1.000000f, 0.000000f, 0}, /* 8*/
1694 {+1.000000f, +0.414214f, ~0}, /* 9*/
1695 {+0.707106f, +0.707106f, 0}, /*10*/
1696 {+0.414214f, +1.000000f, ~0}, /*11*/
1697 { 0.000000f, +1.000000f, 0}, /*12*/
1698 {-0.414214f, +1.000000f, ~0}, /*13*/
1699 {-0.707106f, +0.707106f, 0}, /*14*/
1700 {-1.000000f, +0.414214f, ~0}, /*15*/
1701 {-1.000000f, 0.000000f, 0}, /*16*/
1702 {-1.000000f, -0.414214f, ~0}, /*17*/
1703 {-0.707106f, -0.707106f, 0}, /*18*/
1704 {-0.414214f, -1.000000f, ~0}, /*19*/
1705 { 0.000000f, -1.000000f, 0}, /*20*/
1706 {+0.414214f, -1.000000f, ~0}, /*21*/
1707 {+0.707106f, -0.707106f, 0}, /*22*/
1708 {+1.000000f, -0.414214f, ~0}, /*23*/
1709 // This vertex is for the fanned versions.
1710 { 0.000000f, 0.000000f, ~0}, /*24*/
1711
1712 // Rectangle with disjoint corner segments.
1713 {+1.0, +0.5, 0x3}, /*25*/
1714 {+1.0, +1.0, 0x3}, /*26*/
1715 {+0.5, +1.0, 0x3}, /*27*/
1716 {-0.5, +1.0, 0x2}, /*28*/
1717 {-1.0, +1.0, 0x2}, /*29*/
1718 {-1.0, +0.5, 0x2}, /*30*/
1719 {-1.0, -0.5, 0x0}, /*31*/
1720 {-1.0, -1.0, 0x0}, /*32*/
1721 {-0.5, -1.0, 0x0}, /*33*/
1722 {+0.5, -1.0, 0x1}, /*34*/
1723 {+1.0, -1.0, 0x1}, /*35*/
1724 {+1.0, -0.5, 0x1}, /*36*/
1725 // The next 4 are for the fanned version.
1726 { 0.0, 0.0, 0x3}, /*37*/
1727 { 0.0, 0.0, 0x2}, /*38*/
1728 { 0.0, 0.0, 0x0}, /*39*/
1729 { 0.0, 0.0, 0x1}, /*40*/
1730 // The next 8 are for the bordered version.
1731 {+0.75, +0.50, 0x3}, /*41*/
1732 {+0.50, +0.75, 0x3}, /*42*/
1733 {-0.50, +0.75, 0x2}, /*43*/
1734 {-0.75, +0.50, 0x2}, /*44*/
1735 {-0.75, -0.50, 0x0}, /*45*/
1736 {-0.50, -0.75, 0x0}, /*46*/
1737 {+0.50, -0.75, 0x1}, /*47*/
1738 {+0.75, -0.50, 0x1}, /*48*/
1739
1740 // 16-gon that inscribes the unit circle, cut by an interior unit 16-gon.
1741 {+1.000000f, +0.000000f, 0}, /*49*/
1742 {+1.000000f, +0.198913f, ~0}, /*50*/
1743 {+0.923879f, +0.382683f, 0}, /*51*/
1744 {+0.847760f, +0.566455f, ~0}, /*52*/
1745 {+0.707106f, +0.707106f, 0}, /*53*/
1746 {+0.566455f, +0.847760f, ~0}, /*54*/
1747 {+0.382683f, +0.923879f, 0}, /*55*/
1748 {+0.198913f, +1.000000f, ~0}, /*56*/
1749 {+0.000000f, +1.000000f, 0}, /*57*/
1750 {-0.198913f, +1.000000f, ~0}, /*58*/
1751 {-0.382683f, +0.923879f, 0}, /*59*/
1752 {-0.566455f, +0.847760f, ~0}, /*60*/
1753 {-0.707106f, +0.707106f, 0}, /*61*/
1754 {-0.847760f, +0.566455f, ~0}, /*62*/
1755 {-0.923879f, +0.382683f, 0}, /*63*/
1756 {-1.000000f, +0.198913f, ~0}, /*64*/
1757 {-1.000000f, +0.000000f, 0}, /*65*/
1758 {-1.000000f, -0.198913f, ~0}, /*66*/
1759 {-0.923879f, -0.382683f, 0}, /*67*/
1760 {-0.847760f, -0.566455f, ~0}, /*68*/
1761 {-0.707106f, -0.707106f, 0}, /*69*/
1762 {-0.566455f, -0.847760f, ~0}, /*70*/
1763 {-0.382683f, -0.923879f, 0}, /*71*/
1764 {-0.198913f, -1.000000f, ~0}, /*72*/
1765 {-0.000000f, -1.000000f, 0}, /*73*/
1766 {+0.198913f, -1.000000f, ~0}, /*74*/
1767 {+0.382683f, -0.923879f, 0}, /*75*/
1768 {+0.566455f, -0.847760f, ~0}, /*76*/
1769 {+0.707106f, -0.707106f, 0}, /*77*/
1770 {+0.847760f, -0.566455f, ~0}, /*78*/
1771 {+0.923879f, -0.382683f, 0}, /*79*/
1772 {+1.000000f, -0.198913f, ~0}, /*80*/
1773};
1774
1775const uint8_t kIndexData[] = {
1776 // Rectangle.
1777 0, 1, 2,
1778 0, 2, 3,
1779
1780 // Rectangle with a border.
1781 0, 1, 5,
1782 5, 4, 0,
1783 1, 2, 6,
1784 6, 5, 1,
1785 2, 3, 7,
1786 7, 6, 2,
1787 3, 0, 4,
1788 4, 7, 3,
1789 4, 5, 6,
1790 6, 7, 4,
1791
1792 // Octagon that inscribes the unit circle, cut by an interior unit octagon.
1793 10, 8, 9,
1794 12, 10, 11,
1795 14, 12, 13,
1796 16, 14, 15,
1797 18, 16, 17,
1798 20, 18, 19,
1799 22, 20, 21,
1800 8, 22, 23,
1801 8, 10, 12,
1802 12, 14, 16,
1803 16, 18, 20,
1804 20, 22, 8,
1805 8, 12, 16,
1806 16, 20, 8,
1807
1808 // Same octagons, but with the interior arranged as a fan. Used by mixed samples.
1809 10, 8, 9,
1810 12, 10, 11,
1811 14, 12, 13,
1812 16, 14, 15,
1813 18, 16, 17,
1814 20, 18, 19,
1815 22, 20, 21,
1816 8, 22, 23,
1817 24, 8, 10,
1818 12, 24, 10,
1819 24, 12, 14,
1820 16, 24, 14,
1821 24, 16, 18,
1822 20, 24, 18,
1823 24, 20, 22,
1824 8, 24, 22,
1825
1826 // Same octagons, but with the inner and outer disjoint. Used by coverage AA.
1827 8, 22, 23,
1828 9, 8, 23,
1829 10, 8, 9,
1830 11, 10, 9,
1831 12, 10, 11,
1832 13, 12, 11,
1833 14, 12, 13,
1834 15, 14, 13,
1835 16, 14, 15,
1836 17, 16, 15,
1837 18, 16, 17,
1838 19, 18, 17,
1839 20, 18, 19,
1840 21, 20, 19,
1841 22, 20, 21,
1842 23, 22, 21,
1843 22, 8, 10,
1844 10, 12, 14,
1845 14, 16, 18,
1846 18, 20, 22,
1847 22, 10, 14,
1848 14, 18, 22,
1849
1850 // Rectangle with disjoint corner segments.
1851 27, 25, 26,
1852 30, 28, 29,
1853 33, 31, 32,
1854 36, 34, 35,
1855 25, 27, 28,
1856 28, 30, 31,
1857 31, 33, 34,
1858 34, 36, 25,
1859 25, 28, 31,
1860 31, 34, 25,
1861
1862 // Same rectangle with disjoint corners, but with the interior arranged as a fan. Used by
1863 // mixed samples.
1864 27, 25, 26,
1865 30, 28, 29,
1866 33, 31, 32,
1867 36, 34, 35,
1868 27, 37, 25,
1869 28, 37, 27,
1870 30, 38, 28,
1871 31, 38, 30,
1872 33, 39, 31,
1873 34, 39, 33,
1874 36, 40, 34,
1875 25, 40, 36,
1876
1877 // Same rectangle with disjoint corners, with a border as well. Used by coverage AA.
1878 41, 25, 26,
1879 42, 41, 26,
1880 27, 42, 26,
1881 43, 28, 29,
1882 44, 43, 29,
1883 30, 44, 29,
1884 45, 31, 32,
1885 46, 45, 32,
1886 33, 46, 32,
1887 47, 34, 35,
1888 48, 47, 35,
1889 36, 48, 35,
1890 27, 28, 42,
1891 42, 28, 43,
1892 30, 31, 44,
1893 44, 31, 45,
1894 33, 34, 46,
1895 46, 34, 47,
1896 36, 25, 48,
1897 48, 25, 41,
1898 41, 42, 43,
1899 43, 44, 45,
1900 45, 46, 47,
1901 47, 48, 41,
1902 41, 43, 45,
1903 45, 47, 41,
1904
1905 // Same as the disjoint octagons, but with 16-gons instead. Used by coverage AA when the oval is
1906 // sufficiently large.
1907 49, 79, 80,
1908 50, 49, 80,
1909 51, 49, 50,
1910 52, 51, 50,
1911 53, 51, 52,
1912 54, 53, 52,
1913 55, 53, 54,
1914 56, 55, 54,
1915 57, 55, 56,
1916 58, 57, 56,
1917 59, 57, 58,
1918 60, 59, 58,
1919 61, 59, 60,
1920 62, 61, 60,
1921 63, 61, 62,
1922 64, 63, 62,
1923 65, 63, 64,
1924 66, 65, 64,
1925 67, 65, 66,
1926 68, 67, 66,
1927 69, 67, 68,
1928 70, 69, 68,
1929 71, 69, 70,
1930 72, 71, 70,
1931 73, 71, 72,
1932 74, 73, 72,
1933 75, 73, 74,
1934 76, 75, 74,
1935 77, 75, 76,
1936 78, 77, 76,
1937 79, 77, 78,
1938 80, 79, 78,
1939 49, 51, 53,
1940 53, 55, 57,
1941 57, 59, 61,
1942 61, 63, 65,
1943 65, 67, 69,
1944 69, 71, 73,
1945 73, 75, 77,
1946 77, 79, 49,
1947 49, 53, 57,
1948 57, 61, 65,
1949 65, 69, 73,
1950 73, 77, 49,
1951 49, 57, 65,
1952 65, 73, 49,
1953};
1954
1955enum {
1956 kRect_FirstIndex = 0,
1957 kRect_TriCount = 2,
1958
1959 kFramedRect_FirstIndex = 6,
1960 kFramedRect_TriCount = 10,
1961
1962 kOctagons_FirstIndex = 36,
1963 kOctagons_TriCount = 14,
1964
1965 kOctagonsFanned_FirstIndex = 78,
1966 kOctagonsFanned_TriCount = 16,
1967
1968 kDisjointOctagons_FirstIndex = 126,
1969 kDisjointOctagons_TriCount = 22,
1970
1971 kCorneredRect_FirstIndex = 192,
1972 kCorneredRect_TriCount = 10,
1973
1974 kCorneredRectFanned_FirstIndex = 222,
1975 kCorneredRectFanned_TriCount = 12,
1976
1977 kCorneredFramedRect_FirstIndex = 258,
1978 kCorneredFramedRect_TriCount = 26,
1979
1980 kDisjoint16Gons_FirstIndex = 336,
1981 kDisjoint16Gons_TriCount = 46,
1982};
1983
1984GR_DECLARE_STATIC_UNIQUE_KEY(gShapeVertexBufferKey);
1985
1986const GrBuffer* InstanceProcessor::FindOrCreateVertexBuffer(GrGpu* gpu) {
1987 GR_DEFINE_STATIC_UNIQUE_KEY(gShapeVertexBufferKey);
1988 GrResourceCache* cache = gpu->getContext()->getResourceCache();
1989 if (GrGpuResource* cached = cache->findAndRefUniqueResource(gShapeVertexBufferKey)) {
1990 return static_cast<GrBuffer*>(cached);
1991 }
1992 if (GrBuffer* buffer = gpu->createBuffer(sizeof(kVertexData), kVertex_GrBufferType,
1993 kStatic_GrAccessPattern, kVertexData)) {
1994 buffer->resourcePriv().setUniqueKey(gShapeVertexBufferKey);
1995 return buffer;
1996 }
1997 return nullptr;
1998}
1999
2000GR_DECLARE_STATIC_UNIQUE_KEY(gShapeIndexBufferKey);
2001
2002const GrBuffer* InstanceProcessor::FindOrCreateIndex8Buffer(GrGpu* gpu) {
2003 GR_DEFINE_STATIC_UNIQUE_KEY(gShapeIndexBufferKey);
2004 GrResourceCache* cache = gpu->getContext()->getResourceCache();
2005 if (GrGpuResource* cached = cache->findAndRefUniqueResource(gShapeIndexBufferKey)) {
2006 return static_cast<GrBuffer*>(cached);
2007 }
2008 if (GrBuffer* buffer = gpu->createBuffer(sizeof(kIndexData), kIndex_GrBufferType,
2009 kStatic_GrAccessPattern, kIndexData)) {
2010 buffer->resourcePriv().setUniqueKey(gShapeIndexBufferKey);
2011 return buffer;
2012 }
2013 return nullptr;
2014}
2015
2016IndexRange InstanceProcessor::GetIndexRangeForRect(AntialiasMode aa) {
2017 static constexpr IndexRange kRectRanges[kNumAntialiasModes] = {
2018 {kRect_FirstIndex, 3 * kRect_TriCount}, // kNone
2019 {kFramedRect_FirstIndex, 3 * kFramedRect_TriCount}, // kCoverage
2020 {kRect_FirstIndex, 3 * kRect_TriCount}, // kMSAA
2021 {kRect_FirstIndex, 3 * kRect_TriCount} // kMixedSamples
2022 };
2023
2024 SkASSERT(aa >= AntialiasMode::kNone && aa <= AntialiasMode::kMixedSamples);
2025 return kRectRanges[(int)aa];
2026
2027 GR_STATIC_ASSERT(0 == (int)AntialiasMode::kNone);
2028 GR_STATIC_ASSERT(1 == (int)AntialiasMode::kCoverage);
2029 GR_STATIC_ASSERT(2 == (int)AntialiasMode::kMSAA);
2030 GR_STATIC_ASSERT(3 == (int)AntialiasMode::kMixedSamples);
2031}
2032
2033IndexRange InstanceProcessor::GetIndexRangeForOval(AntialiasMode aa, const SkRect& devBounds) {
2034 if (AntialiasMode::kCoverage == aa && devBounds.height() * devBounds.width() >= 256 * 256) {
2035 // This threshold was chosen quasi-scientifically on Tegra X1.
2036 return {kDisjoint16Gons_FirstIndex, 3 * kDisjoint16Gons_TriCount};
2037 }
2038
2039 static constexpr IndexRange kOvalRanges[kNumAntialiasModes] = {
2040 {kOctagons_FirstIndex, 3 * kOctagons_TriCount}, // kNone
2041 {kDisjointOctagons_FirstIndex, 3 * kDisjointOctagons_TriCount}, // kCoverage
2042 {kOctagons_FirstIndex, 3 * kOctagons_TriCount}, // kMSAA
2043 {kOctagonsFanned_FirstIndex, 3 * kOctagonsFanned_TriCount} // kMixedSamples
2044 };
2045
2046 SkASSERT(aa >= AntialiasMode::kNone && aa <= AntialiasMode::kMixedSamples);
2047 return kOvalRanges[(int)aa];
2048
2049 GR_STATIC_ASSERT(0 == (int)AntialiasMode::kNone);
2050 GR_STATIC_ASSERT(1 == (int)AntialiasMode::kCoverage);
2051 GR_STATIC_ASSERT(2 == (int)AntialiasMode::kMSAA);
2052 GR_STATIC_ASSERT(3 == (int)AntialiasMode::kMixedSamples);
2053}
2054
2055IndexRange InstanceProcessor::GetIndexRangeForRRect(AntialiasMode aa) {
2056 static constexpr IndexRange kRRectRanges[kNumAntialiasModes] = {
2057 {kCorneredRect_FirstIndex, 3 * kCorneredRect_TriCount}, // kNone
2058 {kCorneredFramedRect_FirstIndex, 3 * kCorneredFramedRect_TriCount}, // kCoverage
2059 {kCorneredRect_FirstIndex, 3 * kCorneredRect_TriCount}, // kMSAA
2060 {kCorneredRectFanned_FirstIndex, 3 * kCorneredRectFanned_TriCount} // kMixedSamples
2061 };
2062
2063 SkASSERT(aa >= AntialiasMode::kNone && aa <= AntialiasMode::kMixedSamples);
2064 return kRRectRanges[(int)aa];
2065
2066 GR_STATIC_ASSERT(0 == (int)AntialiasMode::kNone);
2067 GR_STATIC_ASSERT(1 == (int)AntialiasMode::kCoverage);
2068 GR_STATIC_ASSERT(2 == (int)AntialiasMode::kMSAA);
2069 GR_STATIC_ASSERT(3 == (int)AntialiasMode::kMixedSamples);
2070}
2071
2072const char* InstanceProcessor::GetNameOfIndexRange(IndexRange range) {
2073 switch (range.fStart) {
2074 case kRect_FirstIndex: return "basic_rect";
2075 case kFramedRect_FirstIndex: return "coverage_rect";
2076
2077 case kOctagons_FirstIndex: return "basic_oval";
2078 case kDisjointOctagons_FirstIndex: return "coverage_oval";
2079 case kDisjoint16Gons_FirstIndex: return "coverage_large_oval";
2080 case kOctagonsFanned_FirstIndex: return "mixed_samples_oval";
2081
2082 case kCorneredRect_FirstIndex: return "basic_round_rect";
2083 case kCorneredFramedRect_FirstIndex: return "coverage_round_rect";
2084 case kCorneredRectFanned_FirstIndex: return "mixed_samples_round_rect";
2085
2086 default: return "unknown";
2087 }
2088}
2089
2090}