1/* 2 * Copyright 2015 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 "GrLatticeOp.h" 9 10#include "GrDefaultGeoProcFactory.h" 11#include "GrMeshDrawOp.h" 12#include "GrOpFlushState.h" 13#include "GrResourceProvider.h" 14#include "SkBitmap.h" 15#include "SkLatticeIter.h" 16#include "SkRect.h" 17 18static sk_sp<GrGeometryProcessor> create_gp() { 19 using namespace GrDefaultGeoProcFactory; 20 return GrDefaultGeoProcFactory::Make(Color::kPremulGrColorAttribute_Type, Coverage::kSolid_Type, 21 LocalCoords::kHasExplicit_Type, SkMatrix::I()); 22} 23 24class NonAALatticeOp final : public GrMeshDrawOp { 25public: 26 DEFINE_OP_CLASS_ID 27 28 static const int kVertsPerRect = 4; 29 static const int kIndicesPerRect = 6; 30 31 NonAALatticeOp(GrColor color, const SkMatrix& viewMatrix, int imageWidth, int imageHeight, 32 std::unique_ptr<SkLatticeIter> iter, const SkRect& dst) 33 : INHERITED(ClassID()) { 34 Patch& patch = fPatches.push_back(); 35 patch.fViewMatrix = viewMatrix; 36 patch.fColor = color; 37 patch.fIter = std::move(iter); 38 patch.fDst = dst; 39 40 fImageWidth = imageWidth; 41 fImageHeight = imageHeight; 42 43 // setup bounds 44 this->setTransformedBounds(patch.fDst, viewMatrix, HasAABloat::kNo, IsZeroArea::kNo); 45 } 46 47 const char* name() const override { return "NonAALatticeOp"; } 48 49 SkString dumpInfo() const override { 50 SkString str; 51 52 for (int i = 0; i < fPatches.count(); ++i) { 53 str.appendf("%d: Color: 0x%08x Dst [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", i, 54 fPatches[i].fColor, fPatches[i].fDst.fLeft, fPatches[i].fDst.fTop, 55 fPatches[i].fDst.fRight, fPatches[i].fDst.fBottom); 56 } 57 58 str.append(DumpPipelineInfo(*this->pipeline())); 59 str.append(INHERITED::dumpInfo()); 60 return str; 61 } 62 63private: 64 void getFragmentProcessorAnalysisInputs(GrPipelineAnalysisColor* color, 65 GrPipelineAnalysisCoverage* coverage) const override { 66 color->setToUnknown(); 67 *coverage = GrPipelineAnalysisCoverage::kNone; 68 } 69 70 void applyPipelineOptimizations(const GrPipelineOptimizations& analysioptimizations) override { 71 analysioptimizations.getOverrideColorIfSet(&fPatches[0].fColor); 72 } 73 74 void onPrepareDraws(Target* target) const override { 75 sk_sp<GrGeometryProcessor> gp(create_gp()); 76 if (!gp) { 77 SkDebugf("Couldn't create GrGeometryProcessor\n"); 78 return; 79 } 80 81 size_t vertexStride = gp->getVertexStride(); 82 int patchCnt = fPatches.count(); 83 int numRects = 0; 84 for (int i = 0; i < patchCnt; i++) { 85 numRects += fPatches[i].fIter->numRectsToDraw(); 86 } 87 88 sk_sp<const GrBuffer> indexBuffer(target->resourceProvider()->refQuadIndexBuffer()); 89 InstancedHelper helper; 90 void* vertices = helper.init(target, kTriangles_GrPrimitiveType, vertexStride, 91 indexBuffer.get(), kVertsPerRect, kIndicesPerRect, numRects); 92 if (!vertices || !indexBuffer) { 93 SkDebugf("Could not allocate vertices\n"); 94 return; 95 } 96 97 intptr_t verts = reinterpret_cast<intptr_t>(vertices); 98 for (int i = 0; i < patchCnt; i++) { 99 const Patch& patch = fPatches[i]; 100 101 // Apply the view matrix here if it is scale-translate. Otherwise, we need to 102 // wait until we've created the dst rects. 103 bool isScaleTranslate = patch.fViewMatrix.isScaleTranslate(); 104 if (isScaleTranslate) { 105 patch.fIter->mapDstScaleTranslate(patch.fViewMatrix); 106 } 107 108 SkRect srcR, dstR; 109 intptr_t patchVerts = verts; 110 while (patch.fIter->next(&srcR, &dstR)) { 111 SkPoint* positions = reinterpret_cast<SkPoint*>(verts); 112 positions->setRectFan(dstR.fLeft, dstR.fTop, dstR.fRight, dstR.fBottom, 113 vertexStride); 114 115 // Setup local coords 116 static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor); 117 SkPoint* coords = reinterpret_cast<SkPoint*>(verts + kLocalOffset); 118 coords->setRectFan(srcR.fLeft, srcR.fTop, srcR.fRight, srcR.fBottom, vertexStride); 119 120 static const int kColorOffset = sizeof(SkPoint); 121 GrColor* vertColor = reinterpret_cast<GrColor*>(verts + kColorOffset); 122 for (int j = 0; j < 4; ++j) { 123 *vertColor = patch.fColor; 124 vertColor = (GrColor*)((intptr_t)vertColor + vertexStride); 125 } 126 verts += kVertsPerRect * vertexStride; 127 } 128 129 // If we didn't handle it above, apply the matrix here. 130 if (!isScaleTranslate) { 131 SkPoint* positions = reinterpret_cast<SkPoint*>(patchVerts); 132 patch.fViewMatrix.mapPointsWithStride( 133 positions, vertexStride, kVertsPerRect * patch.fIter->numRectsToDraw()); 134 } 135 } 136 helper.recordDraw(target, gp.get()); 137 } 138 139 bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override { 140 NonAALatticeOp* that = t->cast<NonAALatticeOp>(); 141 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(), 142 that->bounds(), caps)) { 143 return false; 144 } 145 146 SkASSERT(this->fImageWidth == that->fImageWidth && 147 this->fImageHeight == that->fImageHeight); 148 149 fPatches.move_back_n(that->fPatches.count(), that->fPatches.begin()); 150 this->joinBounds(*that); 151 return true; 152 } 153 154 struct Patch { 155 SkMatrix fViewMatrix; 156 std::unique_ptr<SkLatticeIter> fIter; 157 SkRect fDst; 158 GrColor fColor; 159 }; 160 161 int fImageWidth; 162 int fImageHeight; 163 SkSTArray<1, Patch, true> fPatches; 164 165 typedef GrMeshDrawOp INHERITED; 166}; 167 168namespace GrLatticeOp { 169std::unique_ptr<GrMeshDrawOp> MakeNonAA(GrColor color, const SkMatrix& viewMatrix, int imageWidth, 170 int imageHeight, std::unique_ptr<SkLatticeIter> iter, 171 const SkRect& dst) { 172 return std::unique_ptr<GrMeshDrawOp>( 173 new NonAALatticeOp(color, viewMatrix, imageWidth, imageHeight, std::move(iter), dst)); 174} 175}; 176