OLD | NEW |
---|---|
(Empty) | |
1 /* | |
2 * Copyright 2016 Google Inc. | |
3 * | |
4 * Use of this source code is governed by a BSD-style license that can be | |
5 * found in the LICENSE file. | |
6 */ | |
7 | |
8 #include "GrRectRenderer.h" | |
9 | |
10 #include "GrBatchFlushState.h" | |
11 #include "GrBatchTest.h" | |
12 #include "GrGeometryProcessor.h" | |
13 #include "GrInvariantOutput.h" | |
14 #include "GrProcessor.h" | |
15 #include "GrResourceProvider.h" | |
16 #include "SkRRect.h" | |
17 #include "SkStrokeRec.h" | |
18 #include "batches/GrVertexBatch.h" | |
19 #include "glsl/GrGLSLFragmentShaderBuilder.h" | |
20 #include "glsl/GrGLSLGeometryProcessor.h" | |
21 #include "glsl/GrGLSLProgramDataManager.h" | |
22 #include "glsl/GrGLSLVarying.h" | |
23 #include "glsl/GrGLSLVertexShaderBuilder.h" | |
24 #include "glsl/GrGLSLUniformHandler.h" | |
25 #include "glsl/GrGLSLUtil.h" | |
26 | |
27 namespace { | |
28 | |
29 struct RectVertex { | |
30 SkPoint fPos; | |
31 GrColor fColor; | |
32 SkPoint fCenter; | |
33 SkVector fDownDir; | |
34 SkScalar fHalfWidth; | |
35 SkScalar fHalfHeight; | |
36 }; | |
37 | |
38 } | |
39 | |
40 /////////////////////////////////////////////////////////////////////////////// | |
41 | |
42 /** | |
43 * The output of this effect is the input color and coverage for an arbitrarily oriented rect. The | |
44 * rect is specified as: | |
45 * Center of the rect | |
46 * Unit vector point down the height of the rect | |
47 * Half width + 0.5 | |
48 * Half height + 0.5 | |
49 * The center and vector are stored in a vec4 varying ("RectEdge") with the | |
50 * center in the xy components and the vector in the zw components. | |
51 * The munged width and height are stored in a vec2 varying ("WidthHeight") | |
52 * with the width in x and the height in y. | |
53 */ | |
54 class RectGeometryProcessor : public GrGeometryProcessor { | |
55 public: | |
56 RectGeometryProcessor(const SkMatrix& localMatrix) : fLocalMatrix(localMatri x){ | |
57 this->initClassID<RectGeometryProcessor>(); | |
58 fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_G rVertexAttribType, | |
59 kHigh_GrSLPrecision)); | |
60 fInColor = &this->addVertexAttrib(Attribute("inColor", kVec4ub_GrV ertexAttribType)); | |
61 fInRectEdge = &this->addVertexAttrib(Attribute("inRectEdge", kVec4f_G rVertexAttribType)); | |
62 fInWidthHeight = &this->addVertexAttrib(Attribute("inWidthHeight", | |
63 kVec2f_GrVertexAttribT ype)); | |
64 } | |
65 | |
66 bool implementsDistanceVector() const override { return true; }; | |
67 | |
68 const Attribute* inPosition() const { return fInPosition; } | |
69 const Attribute* inColor() const { return fInColor; } | |
70 const Attribute* inRectEdge() const { return fInRectEdge; } | |
71 const Attribute* inWidthHeight() const { return fInWidthHeight; } | |
72 | |
73 const SkMatrix& localMatrix() const { return fLocalMatrix; } | |
74 | |
75 virtual ~RectGeometryProcessor() {} | |
76 | |
77 const char* name() const override { return "RectEdge"; } | |
78 | |
79 class GLSLProcessor : public GrGLSLGeometryProcessor { | |
80 public: | |
81 GLSLProcessor() {} | |
82 | |
83 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{ | |
84 const RectGeometryProcessor& rgp = args.fGP.cast<RectGeometryProcess or>(); | |
85 GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; | |
86 GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; | |
87 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; | |
88 | |
89 // emit attributes | |
90 varyingHandler->emitAttributes(rgp); | |
91 | |
92 // setup the varying for the position | |
93 GrGLSLVertToFrag positionVary(kVec2f_GrSLType); | |
94 varyingHandler->addVarying("Position", &positionVary); | |
95 vertBuilder->codeAppendf("%s = %s;", positionVary.vsOut(), rgp.inPos ition()->fName); | |
96 | |
97 // setup the varying for the center point and the unit vector that p oints down the | |
98 // height of the rect | |
99 GrGLSLVertToFrag rectEdgeVary(kVec4f_GrSLType); | |
100 varyingHandler->addVarying("RectEdge", &rectEdgeVary); | |
101 vertBuilder->codeAppendf("%s = %s;", rectEdgeVary.vsOut(), rgp.inRec tEdge()->fName); | |
102 | |
103 // setup the varying for the width/2+.5 and height/2+.5 | |
104 GrGLSLVertToFrag widthHeightVary(kVec2f_GrSLType); | |
105 varyingHandler->addVarying("WidthHeight", &widthHeightVary); | |
106 vertBuilder->codeAppendf("%s = %s;", widthHeightVary.vsOut(), rgp.in WidthHeight()->fName); | |
egdaniel
2016/08/12 17:37:06
100 chars
dvonbeck
2016/08/12 18:29:48
Done.
| |
107 | |
108 GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder; | |
109 | |
110 // setup pass through color | |
111 varyingHandler->addPassThroughAttribute(rgp.inColor(), args.fOutputC olor); | |
112 | |
113 // Setup position | |
114 this->setupPosition(vertBuilder, gpArgs, rgp.inPosition()->fName); | |
115 | |
116 // emit transforms | |
117 this->emitTransforms(vertBuilder, | |
118 varyingHandler, | |
119 uniformHandler, | |
120 gpArgs->fPositionVar, | |
121 rgp.inPosition()->fName, | |
122 rgp.localMatrix(), | |
123 args.fTransformsIn, | |
124 args.fTransformsOut); | |
125 | |
126 // TODO: compute all these offsets, spans, and scales in the VS | |
127 fragBuilder->codeAppendf("float insetW = min(1.0, %s.x) - 0.5;", wid thHeightVary.fsIn()); | |
egdaniel
2016/08/12 17:37:06
100 chars
dvonbeck
2016/08/12 18:29:48
Done.
| |
128 fragBuilder->codeAppendf("float insetH = min(1.0, %s.y) - 0.5;", wid thHeightVary.fsIn()); | |
129 fragBuilder->codeAppend("float outset = 0.5;"); | |
130 // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0 ). For rects | |
131 // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range. | |
132 fragBuilder->codeAppend("float spanW = insetW + outset;"); | |
133 fragBuilder->codeAppend("float spanH = insetH + outset;"); | |
134 // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum | |
135 // value of coverage that is used. In other words it is the coverage that is | |
136 // used in the interior of the rect after the ramp. | |
137 fragBuilder->codeAppend("float scaleW = min(1.0, 2.0*insetW/spanW);" ); | |
138 fragBuilder->codeAppend("float scaleH = min(1.0, 2.0*insetH/spanH);" ); | |
139 // Compute the coverage for the rect's width | |
140 fragBuilder->codeAppendf("vec2 offset = %s.xy - %s.xy;", | |
141 positionVary.fsIn(), rectEdgeVary.fsIn()); | |
142 fragBuilder->codeAppendf("float perpDot = abs(offset.x * %s.w - offs et.y * %s.z);", | |
143 rectEdgeVary.fsIn(), rectEdgeVary.fsIn()); | |
144 | |
145 if (args.fDistanceVectorName) { | |
146 fragBuilder->codeAppendf("float widthDistance = %s.x - perpDot;" , | |
147 widthHeightVary.fsIn()); | |
148 } | |
149 | |
150 fragBuilder->codeAppendf( | |
151 "float coverage = scaleW*clamp((%s.x-perpDot)/spanW, 0.0, 1. 0);", | |
152 widthHeightVary.fsIn()); | |
153 // Compute the coverage for the rect's height and merge with the wid th | |
154 fragBuilder->codeAppendf("perpDot = abs(dot(offset, %s.zw));", | |
155 rectEdgeVary.fsIn()); | |
156 | |
157 if (args.fDistanceVectorName) { | |
158 fragBuilder->codeAppendf("float heightDistance = %s.y - perpDot; ", | |
159 widthHeightVary.fsIn()); | |
160 } | |
161 | |
162 fragBuilder->codeAppendf( | |
163 "coverage = coverage*scaleH*clamp((%s.y-perpDot)/spanH, 0.0, 1.0);", | |
164 widthHeightVary.fsIn()); | |
165 | |
166 fragBuilder->codeAppendf("%s = vec4(coverage);", args.fOutputCoverag e); | |
167 | |
168 if (args.fDistanceVectorName) { | |
169 fragBuilder->codeAppend( "// Calculating distance vector\n"); | |
170 fragBuilder->codeAppend( "vec2 dvAxis;"); | |
171 fragBuilder->codeAppend( "float dvLength;"); | |
172 | |
173 fragBuilder->codeAppend( "if (heightDistance < widthDistance) {" ); | |
174 fragBuilder->codeAppendf(" dvAxis = %s.zw;", rectEdgeVary.fsI n()); | |
175 fragBuilder->codeAppend( " dvLength = heightDistance;"); | |
176 fragBuilder->codeAppend( "} else {"); | |
177 fragBuilder->codeAppendf(" dvAxis = vec2(-%s.w, %s.z);", | |
178 rectEdgeVary.fsIn(), rectEdgeVary.fsIn( )); | |
179 fragBuilder->codeAppend( " dvLength = widthDistance;"); | |
180 fragBuilder->codeAppend( "}"); | |
181 | |
182 fragBuilder->codeAppend( "float dvSign = sign(dot(offset, dvAxis ));"); | |
183 fragBuilder->codeAppendf("%s = vec3(dvSign * dvAxis, dvLength);" , | |
184 args.fDistanceVectorName); | |
185 | |
186 } | |
187 } | |
188 | |
189 static void GenKey(const GrGeometryProcessor& gp, | |
190 const GrGLSLCaps&, | |
191 GrProcessorKeyBuilder* b) { | |
192 b->add32(0x0); | |
193 } | |
194 | |
195 void setData(const GrGLSLProgramDataManager& pdman, | |
196 const GrPrimitiveProcessor& gp) override {} | |
197 | |
198 void setTransformData(const GrPrimitiveProcessor& primProc, | |
199 const GrGLSLProgramDataManager& pdman, | |
200 int index, | |
201 const SkTArray<const GrCoordTransform*, true>& tra nsforms) override { | |
202 this->setTransformDataHelper<RectGeometryProcessor>(primProc, pdman, index, transforms); | |
203 } | |
204 | |
205 private: | |
206 typedef GrGLSLGeometryProcessor INHERITED; | |
207 }; | |
208 | |
209 void getGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) c onst override { | |
210 GLSLProcessor::GenKey(*this, caps, b); | |
211 } | |
212 | |
213 GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const overri de { | |
214 return new GLSLProcessor(); | |
215 } | |
216 | |
217 private: | |
218 SkMatrix fLocalMatrix; | |
219 | |
220 const Attribute* fInPosition; | |
221 const Attribute* fInColor; | |
222 const Attribute* fInRectEdge; | |
223 const Attribute* fInWidthHeight; | |
224 | |
225 GR_DECLARE_GEOMETRY_PROCESSOR_TEST; | |
226 | |
227 typedef GrGeometryProcessor INHERITED; | |
228 }; | |
229 | |
230 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(RectGeometryProcessor); | |
231 | |
232 sk_sp<GrGeometryProcessor> RectGeometryProcessor::TestCreate(GrProcessorTestData * d) { | |
233 return sk_sp<GrGeometryProcessor>( | |
234 new RectGeometryProcessor(GrTest::TestMatrix(d->fRandom))); | |
235 } | |
236 | |
237 /////////////////////////////////////////////////////////////////////////////// | |
238 | |
239 class AnalyticRectBatch : public GrVertexBatch { | |
240 public: | |
241 DEFINE_BATCH_CLASS_ID | |
242 | |
243 AnalyticRectBatch(GrColor color, const SkMatrix& viewMatrix, const SkRect& r ect, | |
244 const SkRect& croppedRect, const SkRect& bounds) | |
245 : INHERITED(ClassID()) | |
246 , fViewMatrixIfUsingLocalCoords(viewMatrix) { | |
247 SkPoint center = SkPoint::Make(rect.centerX(), rect.centerY()); | |
248 viewMatrix.mapPoints(¢er, 1); | |
249 SkScalar halfWidth = viewMatrix.mapRadius(SkScalarHalf(rect.width())); | |
250 SkScalar halfHeight = viewMatrix.mapRadius(SkScalarHalf(rect.height())); | |
251 SkVector downDir = viewMatrix.mapVector(0.0f, 1.0f); | |
252 downDir.normalize(); | |
253 | |
254 SkRect deviceSpaceCroppedRect = croppedRect; | |
255 viewMatrix.mapRect(&deviceSpaceCroppedRect); | |
256 | |
257 fGeoData.emplace_back(Geometry {color, center, downDir, halfWidth, halfH eight, | |
258 deviceSpaceCroppedRect}); | |
259 | |
260 this->setBounds(bounds, HasAABloat::kYes, IsZeroArea::kNo); | |
261 } | |
262 | |
263 const char* name() const override { return "AnalyticRectBatch"; } | |
264 | |
265 SkString dumpInfo() const override { | |
266 SkString string; | |
267 for (int i = 0; i < fGeoData.count(); ++i) { | |
268 string.appendf("Color: 0x%08x Rect [C:(%.2f, %.2f) D:<%.2f,%.3f> W/2 :%.2f H/2:%.2f]\n", | |
269 fGeoData[i].fColor, | |
270 fGeoData[i].fCenter.x(), fGeoData[i].fCenter.y(), | |
271 fGeoData[i].fDownDir.x(), fGeoData[i].fDownDir.y(), | |
272 fGeoData[i].fHalfWidth, | |
273 fGeoData[i].fHalfHeight); | |
274 } | |
275 string.append(INHERITED::dumpInfo()); | |
276 return string; | |
277 } | |
278 | |
279 void computePipelineOptimizations(GrInitInvariantOutput* color, | |
280 GrInitInvariantOutput* coverage, | |
281 GrBatchToXPOverrides* overrides) const ove rride { | |
282 // When this is called on a batch, there is only one geometry bundle | |
283 color->setKnownFourComponents(fGeoData[0].fColor); | |
284 coverage->setUnknownSingleComponent(); | |
285 } | |
286 | |
287 private: | |
288 void initBatchTracker(const GrXPOverridesForBatch& overrides) override { | |
289 // Handle any overrides that affect our GP. | |
290 overrides.getOverrideColorIfSet(&fGeoData[0].fColor); | |
291 if (!overrides.readsLocalCoords()) { | |
292 fViewMatrixIfUsingLocalCoords.reset(); | |
293 } | |
294 } | |
295 | |
296 void onPrepareDraws(Target* target) const override { | |
297 SkMatrix localMatrix; | |
298 if (!fViewMatrixIfUsingLocalCoords.invert(&localMatrix)) { | |
299 return; | |
300 } | |
301 | |
302 // Setup geometry processor | |
303 SkAutoTUnref<GrGeometryProcessor> gp(new RectGeometryProcessor(localMatr ix)); | |
304 | |
305 int instanceCount = fGeoData.count(); | |
306 size_t vertexStride = gp->getVertexStride(); | |
307 SkASSERT(vertexStride == sizeof(RectVertex)); | |
308 QuadHelper helper; | |
309 RectVertex* verts = reinterpret_cast<RectVertex*>(helper.init(target, ve rtexStride, | |
310 instanceCo unt)); | |
311 if (!verts) { | |
312 return; | |
313 } | |
314 | |
315 for (int i = 0; i < instanceCount; i++) { | |
316 const Geometry& geom = fGeoData[i]; | |
317 | |
318 GrColor color = geom.fColor; | |
319 SkPoint center = geom.fCenter; | |
320 SkVector downDir = geom.fDownDir; | |
321 SkScalar halfWidth = geom.fHalfWidth; | |
322 SkScalar halfHeight = geom.fHalfHeight; | |
323 SkRect croppedRect = geom.fCroppedRect; | |
324 | |
325 SkVector rightDir; | |
326 downDir.rotateCCW(&rightDir); | |
327 | |
328 verts[0].fPos = {croppedRect.fLeft, croppedRect.fTop}; | |
329 verts[0].fColor = color; | |
330 verts[0].fCenter = center; | |
331 verts[0].fDownDir = downDir; | |
332 verts[0].fHalfWidth = halfWidth; | |
333 verts[0].fHalfHeight = halfHeight; | |
334 | |
335 verts[1].fPos = {croppedRect.fRight, croppedRect.fTop}; | |
336 verts[1].fColor = color; | |
337 verts[1].fCenter = center; | |
338 verts[1].fDownDir = downDir; | |
339 verts[1].fHalfWidth = halfWidth; | |
340 verts[1].fHalfHeight = halfHeight; | |
341 | |
342 verts[2].fPos = {croppedRect.fRight, croppedRect.fBottom}; | |
343 verts[2].fColor = color; | |
344 verts[2].fCenter = center; | |
345 verts[2].fDownDir = downDir; | |
346 verts[2].fHalfWidth = halfWidth; | |
347 verts[2].fHalfHeight = halfHeight; | |
348 | |
349 verts[3].fPos = {croppedRect.fLeft, croppedRect.fBottom}; | |
350 verts[3].fColor = color; | |
351 verts[3].fCenter = center; | |
352 verts[3].fDownDir = downDir; | |
353 verts[3].fHalfWidth = halfWidth; | |
354 verts[3].fHalfHeight = halfHeight; | |
355 | |
356 verts += kVerticesPerQuad; | |
357 } | |
358 helper.recordDraw(target, gp); | |
359 } | |
360 | |
361 bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { | |
362 AnalyticRectBatch* that = t->cast<AnalyticRectBatch>(); | |
363 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pi peline(), | |
364 that->bounds(), caps)) { | |
365 return false; | |
366 } | |
367 | |
368 if (!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsing LocalCoords)) { | |
369 return false; | |
370 } | |
371 | |
372 fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin()); | |
373 this->joinBounds(*that); | |
374 return true; | |
375 } | |
376 | |
377 struct Geometry { | |
378 GrColor fColor; | |
379 SkPoint fCenter; | |
380 SkVector fDownDir; | |
381 SkScalar fHalfWidth; | |
382 SkScalar fHalfHeight; | |
383 SkRect fCroppedRect; | |
384 }; | |
385 | |
386 SkMatrix fViewMatrixIfUsingLocalCoords; | |
387 SkSTArray<1, Geometry, true> fGeoData; | |
388 | |
389 typedef GrVertexBatch INHERITED; | |
390 }; | |
391 | |
392 GrDrawBatch* GrRectRenderer::CreateAnalyticRectBatch(GrColor color, | |
393 const SkMatrix& viewMatrix, | |
394 const SkRect& rect, | |
395 const SkRect& croppedRect, | |
396 const SkRect& bounds) { | |
397 return new AnalyticRectBatch(color, viewMatrix, rect, croppedRect, bounds); | |
398 } | |
399 | |
400 #ifdef GR_TEST_UTILS | |
401 | |
402 DRAW_BATCH_TEST_DEFINE(AnalyticRectBatch) { | |
403 SkMatrix viewMatrix = GrTest::TestMatrix(random); | |
404 GrColor color = GrRandomColor(random); | |
405 SkRect rect = GrTest::TestSquare(random); | |
406 SkRect croppedRect = GrTest::TestSquare(random); | |
407 SkRect bounds = GrTest::TestSquare(random); | |
408 return new AnalyticRectBatch(color, viewMatrix, rect, croppedRect, bounds); | |
409 } | |
410 | |
411 #endif | |
OLD | NEW |