Chromium Code Reviews| 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 |