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