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 "GrAnalyticRectBatch.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;", |
| 107 widthHeightVary.vsOut(), rgp.inWidthHeight(
)->fName); |
| 108 |
| 109 GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder; |
| 110 |
| 111 // setup pass through color |
| 112 varyingHandler->addPassThroughAttribute(rgp.inColor(), args.fOutputC
olor); |
| 113 |
| 114 // Setup position |
| 115 this->setupPosition(vertBuilder, gpArgs, rgp.inPosition()->fName); |
| 116 |
| 117 // emit transforms |
| 118 this->emitTransforms(vertBuilder, |
| 119 varyingHandler, |
| 120 uniformHandler, |
| 121 gpArgs->fPositionVar, |
| 122 rgp.inPosition()->fName, |
| 123 rgp.localMatrix(), |
| 124 args.fTransformsIn, |
| 125 args.fTransformsOut); |
| 126 |
| 127 // TODO: compute all these offsets, spans, and scales in the VS |
| 128 fragBuilder->codeAppendf("float insetW = min(1.0, %s.x) - 0.5;", |
| 129 widthHeightVary.fsIn()); |
| 130 fragBuilder->codeAppendf("float insetH = min(1.0, %s.y) - 0.5;", |
| 131 widthHeightVary.fsIn()); |
| 132 fragBuilder->codeAppend("float outset = 0.5;"); |
| 133 // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0
). For rects |
| 134 // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a
0 .. 1 range. |
| 135 fragBuilder->codeAppend("float spanW = insetW + outset;"); |
| 136 fragBuilder->codeAppend("float spanH = insetH + outset;"); |
| 137 // For rects < 1 pixel wide or tall, these scale factors are used to
cap the maximum |
| 138 // value of coverage that is used. In other words it is the coverage
that is |
| 139 // used in the interior of the rect after the ramp. |
| 140 fragBuilder->codeAppend("float scaleW = min(1.0, 2.0*insetW/spanW);"
); |
| 141 fragBuilder->codeAppend("float scaleH = min(1.0, 2.0*insetH/spanH);"
); |
| 142 // Compute the coverage for the rect's width |
| 143 fragBuilder->codeAppendf("vec2 offset = %s.xy - %s.xy;", |
| 144 positionVary.fsIn(), rectEdgeVary.fsIn()); |
| 145 fragBuilder->codeAppendf("float perpDot = abs(offset.x * %s.w - offs
et.y * %s.z);", |
| 146 rectEdgeVary.fsIn(), rectEdgeVary.fsIn()); |
| 147 |
| 148 if (args.fDistanceVectorName) { |
| 149 fragBuilder->codeAppendf("float widthDistance = %s.x - perpDot;"
, |
| 150 widthHeightVary.fsIn()); |
| 151 } |
| 152 |
| 153 fragBuilder->codeAppendf( |
| 154 "float coverage = scaleW*clamp((%s.x-perpDot)/spanW, 0.0, 1.
0);", |
| 155 widthHeightVary.fsIn()); |
| 156 // Compute the coverage for the rect's height and merge with the wid
th |
| 157 fragBuilder->codeAppendf("perpDot = abs(dot(offset, %s.zw));", |
| 158 rectEdgeVary.fsIn()); |
| 159 |
| 160 if (args.fDistanceVectorName) { |
| 161 fragBuilder->codeAppendf("float heightDistance = %s.y - perpDot;
", |
| 162 widthHeightVary.fsIn()); |
| 163 } |
| 164 |
| 165 fragBuilder->codeAppendf( |
| 166 "coverage = coverage*scaleH*clamp((%s.y-perpDot)/spanH, 0.0,
1.0);", |
| 167 widthHeightVary.fsIn()); |
| 168 |
| 169 fragBuilder->codeAppendf("%s = vec4(coverage);", args.fOutputCoverag
e); |
| 170 |
| 171 if (args.fDistanceVectorName) { |
| 172 fragBuilder->codeAppend( "// Calculating distance vector\n"); |
| 173 fragBuilder->codeAppend( "vec2 dvAxis;"); |
| 174 fragBuilder->codeAppend( "float dvLength;"); |
| 175 |
| 176 fragBuilder->codeAppend( "if (heightDistance < widthDistance) {"
); |
| 177 fragBuilder->codeAppendf(" dvAxis = %s.zw;", rectEdgeVary.fsI
n()); |
| 178 fragBuilder->codeAppend( " dvLength = heightDistance;"); |
| 179 fragBuilder->codeAppend( "} else {"); |
| 180 fragBuilder->codeAppendf(" dvAxis = vec2(-%s.w, %s.z);", |
| 181 rectEdgeVary.fsIn(), rectEdgeVary.fsIn(
)); |
| 182 fragBuilder->codeAppend( " dvLength = widthDistance;"); |
| 183 fragBuilder->codeAppend( "}"); |
| 184 |
| 185 fragBuilder->codeAppend( "float dvSign = sign(dot(offset, dvAxis
));"); |
| 186 fragBuilder->codeAppendf("%s = vec3(dvSign * dvAxis, dvLength);"
, |
| 187 args.fDistanceVectorName); |
| 188 |
| 189 } |
| 190 } |
| 191 |
| 192 static void GenKey(const GrGeometryProcessor& gp, |
| 193 const GrGLSLCaps&, |
| 194 GrProcessorKeyBuilder* b) { |
| 195 b->add32(0x0); |
| 196 } |
| 197 |
| 198 void setData(const GrGLSLProgramDataManager& pdman, |
| 199 const GrPrimitiveProcessor& gp) override {} |
| 200 |
| 201 void setTransformData(const GrPrimitiveProcessor& primProc, |
| 202 const GrGLSLProgramDataManager& pdman, |
| 203 int index, |
| 204 const SkTArray<const GrCoordTransform*, true>& tra
nsforms) override { |
| 205 this->setTransformDataHelper<RectGeometryProcessor>(primProc, pdman,
index, transforms); |
| 206 } |
| 207 |
| 208 private: |
| 209 typedef GrGLSLGeometryProcessor INHERITED; |
| 210 }; |
| 211 |
| 212 void getGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) c
onst override { |
| 213 GLSLProcessor::GenKey(*this, caps, b); |
| 214 } |
| 215 |
| 216 GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const overri
de { |
| 217 return new GLSLProcessor(); |
| 218 } |
| 219 |
| 220 private: |
| 221 SkMatrix fLocalMatrix; |
| 222 |
| 223 const Attribute* fInPosition; |
| 224 const Attribute* fInColor; |
| 225 const Attribute* fInRectEdge; |
| 226 const Attribute* fInWidthHeight; |
| 227 |
| 228 GR_DECLARE_GEOMETRY_PROCESSOR_TEST; |
| 229 |
| 230 typedef GrGeometryProcessor INHERITED; |
| 231 }; |
| 232 |
| 233 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(RectGeometryProcessor); |
| 234 |
| 235 sk_sp<GrGeometryProcessor> RectGeometryProcessor::TestCreate(GrProcessorTestData
* d) { |
| 236 return sk_sp<GrGeometryProcessor>( |
| 237 new RectGeometryProcessor(GrTest::TestMatrix(d->fRandom))); |
| 238 } |
| 239 |
| 240 /////////////////////////////////////////////////////////////////////////////// |
| 241 |
| 242 class AnalyticRectBatch : public GrVertexBatch { |
| 243 public: |
| 244 DEFINE_BATCH_CLASS_ID |
| 245 |
| 246 AnalyticRectBatch(GrColor color, const SkMatrix& viewMatrix, const SkRect& r
ect, |
| 247 const SkRect& croppedRect, const SkRect& bounds) |
| 248 : INHERITED(ClassID()) |
| 249 , fViewMatrixIfUsingLocalCoords(viewMatrix) { |
| 250 SkPoint center = SkPoint::Make(rect.centerX(), rect.centerY()); |
| 251 viewMatrix.mapPoints(¢er, 1); |
| 252 SkScalar halfWidth = viewMatrix.mapRadius(SkScalarHalf(rect.width())); |
| 253 SkScalar halfHeight = viewMatrix.mapRadius(SkScalarHalf(rect.height())); |
| 254 SkVector downDir = viewMatrix.mapVector(0.0f, 1.0f); |
| 255 downDir.normalize(); |
| 256 |
| 257 SkRect deviceSpaceCroppedRect = croppedRect; |
| 258 viewMatrix.mapRect(&deviceSpaceCroppedRect); |
| 259 |
| 260 fGeoData.emplace_back(Geometry {color, center, downDir, halfWidth, halfH
eight, |
| 261 deviceSpaceCroppedRect}); |
| 262 |
| 263 this->setBounds(bounds, HasAABloat::kYes, IsZeroArea::kNo); |
| 264 } |
| 265 |
| 266 const char* name() const override { return "AnalyticRectBatch"; } |
| 267 |
| 268 SkString dumpInfo() const override { |
| 269 SkString string; |
| 270 for (int i = 0; i < fGeoData.count(); ++i) { |
| 271 string.appendf("Color: 0x%08x Rect [C:(%.2f, %.2f) D:<%.2f,%.3f> W/2
:%.2f H/2:%.2f]\n", |
| 272 fGeoData[i].fColor, |
| 273 fGeoData[i].fCenter.x(), fGeoData[i].fCenter.y(), |
| 274 fGeoData[i].fDownDir.x(), fGeoData[i].fDownDir.y(), |
| 275 fGeoData[i].fHalfWidth, |
| 276 fGeoData[i].fHalfHeight); |
| 277 } |
| 278 string.append(INHERITED::dumpInfo()); |
| 279 return string; |
| 280 } |
| 281 |
| 282 void computePipelineOptimizations(GrInitInvariantOutput* color, |
| 283 GrInitInvariantOutput* coverage, |
| 284 GrBatchToXPOverrides* overrides) const ove
rride { |
| 285 // When this is called on a batch, there is only one geometry bundle |
| 286 color->setKnownFourComponents(fGeoData[0].fColor); |
| 287 coverage->setUnknownSingleComponent(); |
| 288 } |
| 289 |
| 290 private: |
| 291 void initBatchTracker(const GrXPOverridesForBatch& overrides) override { |
| 292 // Handle any overrides that affect our GP. |
| 293 overrides.getOverrideColorIfSet(&fGeoData[0].fColor); |
| 294 if (!overrides.readsLocalCoords()) { |
| 295 fViewMatrixIfUsingLocalCoords.reset(); |
| 296 } |
| 297 } |
| 298 |
| 299 void onPrepareDraws(Target* target) const override { |
| 300 SkMatrix localMatrix; |
| 301 if (!fViewMatrixIfUsingLocalCoords.invert(&localMatrix)) { |
| 302 return; |
| 303 } |
| 304 |
| 305 // Setup geometry processor |
| 306 SkAutoTUnref<GrGeometryProcessor> gp(new RectGeometryProcessor(localMatr
ix)); |
| 307 |
| 308 int instanceCount = fGeoData.count(); |
| 309 size_t vertexStride = gp->getVertexStride(); |
| 310 SkASSERT(vertexStride == sizeof(RectVertex)); |
| 311 QuadHelper helper; |
| 312 RectVertex* verts = reinterpret_cast<RectVertex*>(helper.init(target, ve
rtexStride, |
| 313 instanceCo
unt)); |
| 314 if (!verts) { |
| 315 return; |
| 316 } |
| 317 |
| 318 for (int i = 0; i < instanceCount; i++) { |
| 319 const Geometry& geom = fGeoData[i]; |
| 320 |
| 321 GrColor color = geom.fColor; |
| 322 SkPoint center = geom.fCenter; |
| 323 SkVector downDir = geom.fDownDir; |
| 324 SkScalar halfWidth = geom.fHalfWidth; |
| 325 SkScalar halfHeight = geom.fHalfHeight; |
| 326 SkRect croppedRect = geom.fCroppedRect; |
| 327 |
| 328 SkVector rightDir; |
| 329 downDir.rotateCCW(&rightDir); |
| 330 |
| 331 verts[0].fPos = {croppedRect.fLeft, croppedRect.fTop}; |
| 332 verts[0].fColor = color; |
| 333 verts[0].fCenter = center; |
| 334 verts[0].fDownDir = downDir; |
| 335 verts[0].fHalfWidth = halfWidth; |
| 336 verts[0].fHalfHeight = halfHeight; |
| 337 |
| 338 verts[1].fPos = {croppedRect.fRight, croppedRect.fTop}; |
| 339 verts[1].fColor = color; |
| 340 verts[1].fCenter = center; |
| 341 verts[1].fDownDir = downDir; |
| 342 verts[1].fHalfWidth = halfWidth; |
| 343 verts[1].fHalfHeight = halfHeight; |
| 344 |
| 345 verts[2].fPos = {croppedRect.fRight, croppedRect.fBottom}; |
| 346 verts[2].fColor = color; |
| 347 verts[2].fCenter = center; |
| 348 verts[2].fDownDir = downDir; |
| 349 verts[2].fHalfWidth = halfWidth; |
| 350 verts[2].fHalfHeight = halfHeight; |
| 351 |
| 352 verts[3].fPos = {croppedRect.fLeft, croppedRect.fBottom}; |
| 353 verts[3].fColor = color; |
| 354 verts[3].fCenter = center; |
| 355 verts[3].fDownDir = downDir; |
| 356 verts[3].fHalfWidth = halfWidth; |
| 357 verts[3].fHalfHeight = halfHeight; |
| 358 |
| 359 verts += kVerticesPerQuad; |
| 360 } |
| 361 helper.recordDraw(target, gp); |
| 362 } |
| 363 |
| 364 bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { |
| 365 AnalyticRectBatch* that = t->cast<AnalyticRectBatch>(); |
| 366 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pi
peline(), |
| 367 that->bounds(), caps)) { |
| 368 return false; |
| 369 } |
| 370 |
| 371 if (!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsing
LocalCoords)) { |
| 372 return false; |
| 373 } |
| 374 |
| 375 fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin()); |
| 376 this->joinBounds(*that); |
| 377 return true; |
| 378 } |
| 379 |
| 380 struct Geometry { |
| 381 GrColor fColor; |
| 382 SkPoint fCenter; |
| 383 SkVector fDownDir; |
| 384 SkScalar fHalfWidth; |
| 385 SkScalar fHalfHeight; |
| 386 SkRect fCroppedRect; |
| 387 }; |
| 388 |
| 389 SkMatrix fViewMatrixIfUsingLocalCoords; |
| 390 SkSTArray<1, Geometry, true> fGeoData; |
| 391 |
| 392 typedef GrVertexBatch INHERITED; |
| 393 }; |
| 394 |
| 395 GrDrawBatch* GrAnalyticRectBatch::CreateAnalyticRectBatch(GrColor color, |
| 396 const SkMatrix& viewMa
trix, |
| 397 const SkRect& rect, |
| 398 const SkRect& croppedR
ect, |
| 399 const SkRect& bounds)
{ |
| 400 return new AnalyticRectBatch(color, viewMatrix, rect, croppedRect, bounds); |
| 401 } |
| 402 |
| 403 #ifdef GR_TEST_UTILS |
| 404 |
| 405 DRAW_BATCH_TEST_DEFINE(AnalyticRectBatch) { |
| 406 SkMatrix viewMatrix = GrTest::TestMatrix(random); |
| 407 GrColor color = GrRandomColor(random); |
| 408 SkRect rect = GrTest::TestSquare(random); |
| 409 SkRect croppedRect = GrTest::TestSquare(random); |
| 410 SkRect bounds = GrTest::TestSquare(random); |
| 411 return new AnalyticRectBatch(color, viewMatrix, rect, croppedRect, bounds); |
| 412 } |
| 413 |
| 414 #endif |
OLD | NEW |