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