LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/gpu/ops - GrAnalyticRectOp.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 194 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 31 0.0 %
Legend: Lines: hit not hit

          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(&center, 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

Generated by: LCOV version 1.13