GrNonAAFillRectOp.cpp revision 9c80b5ff592caf1c18b43e98c85bc8340b3ac531
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 "GrBWFillRectBatch.h" 9 10#include "GrBatch.h" 11#include "GrBatchTarget.h" 12#include "GrColor.h" 13#include "GrDefaultGeoProcFactory.h" 14#include "GrPrimitiveProcessor.h" 15 16class GrBatchTarget; 17class SkMatrix; 18struct SkRect; 19 20class BWFillRectBatch : public GrBatch { 21public: 22 struct Geometry { 23 SkMatrix fViewMatrix; 24 SkRect fRect; 25 SkRect fLocalRect; 26 SkMatrix fLocalMatrix; 27 GrColor fColor; 28 bool fHasLocalRect; 29 bool fHasLocalMatrix; 30 }; 31 32 static GrBatch* Create(const Geometry& geometry) { 33 return SkNEW_ARGS(BWFillRectBatch, (geometry)); 34 } 35 36 const char* name() const override { return "RectBatch"; } 37 38 void getInvariantOutputColor(GrInitInvariantOutput* out) const override { 39 // When this is called on a batch, there is only one geometry bundle 40 out->setKnownFourComponents(fGeoData[0].fColor); 41 } 42 43 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override { 44 out->setKnownSingleComponent(0xff); 45 } 46 47 void initBatchTracker(const GrPipelineOptimizations& init) override { 48 // Handle any color overrides 49 if (!init.readsColor()) { 50 fGeoData[0].fColor = GrColor_ILLEGAL; 51 } 52 init.getOverrideColorIfSet(&fGeoData[0].fColor); 53 54 // setup batch properties 55 fBatch.fColorIgnored = !init.readsColor(); 56 fBatch.fColor = fGeoData[0].fColor; 57 fBatch.fUsesLocalCoords = init.readsLocalCoords(); 58 fBatch.fCoverageIgnored = !init.readsCoverage(); 59 } 60 61 void generateGeometry(GrBatchTarget* batchTarget) override { 62 SkAutoTUnref<const GrGeometryProcessor> gp(this->createRectGP()); 63 if (!gp) { 64 SkDebugf("Could not create GrGeometryProcessor\n"); 65 return; 66 } 67 68 batchTarget->initDraw(gp, this->pipeline()); 69 70 int instanceCount = fGeoData.count(); 71 size_t vertexStride = gp->getVertexStride(); 72 SkASSERT(this->hasLocalRect() ? 73 vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr) : 74 vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAttr)); 75 QuadHelper helper; 76 void* vertices = helper.init(batchTarget, vertexStride, instanceCount); 77 78 if (!vertices) { 79 return; 80 } 81 82 for (int i = 0; i < instanceCount; i++) { 83 const Geometry& geom = fGeoData[i]; 84 85 intptr_t offset = reinterpret_cast<intptr_t>(vertices) + 86 kVerticesPerQuad * i * vertexStride; 87 SkPoint* positions = reinterpret_cast<SkPoint*>(offset); 88 89 positions->setRectFan(geom.fRect.fLeft, geom.fRect.fTop, 90 geom.fRect.fRight, geom.fRect.fBottom, vertexStride); 91 geom.fViewMatrix.mapPointsWithStride(positions, vertexStride, kVerticesPerQuad); 92 93 // TODO we should only do this if local coords are being read 94 if (geom.fHasLocalRect) { 95 static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor); 96 SkPoint* coords = reinterpret_cast<SkPoint*>(offset + kLocalOffset); 97 coords->setRectFan(geom.fLocalRect.fLeft, geom.fLocalRect.fTop, 98 geom.fLocalRect.fRight, geom.fLocalRect.fBottom, 99 vertexStride); 100 if (geom.fHasLocalMatrix) { 101 geom.fLocalMatrix.mapPointsWithStride(coords, vertexStride, kVerticesPerQuad); 102 } 103 } 104 105 static const int kColorOffset = sizeof(SkPoint); 106 GrColor* vertColor = reinterpret_cast<GrColor*>(offset + kColorOffset); 107 for (int j = 0; j < 4; ++j) { 108 *vertColor = geom.fColor; 109 vertColor = (GrColor*) ((intptr_t) vertColor + vertexStride); 110 } 111 } 112 113 helper.issueDraw(batchTarget); 114 } 115 116 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; } 117 118private: 119 BWFillRectBatch(const Geometry& geometry) { 120 this->initClassID<BWFillRectBatch>(); 121 fGeoData.push_back(geometry); 122 123 fBounds = geometry.fRect; 124 geometry.fViewMatrix.mapRect(&fBounds); 125 } 126 127 GrColor color() const { return fBatch.fColor; } 128 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; } 129 bool colorIgnored() const { return fBatch.fColorIgnored; } 130 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; } 131 const SkMatrix& localMatrix() const { return fGeoData[0].fLocalMatrix; } 132 bool hasLocalRect() const { return fGeoData[0].fHasLocalRect; } 133 bool hasLocalMatrix() const { return fGeoData[0].fHasLocalMatrix; } 134 bool coverageIgnored() const { return fBatch.fCoverageIgnored; } 135 136 bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { 137 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *t->pipeline(), t->bounds(), 138 caps)) { 139 return false; 140 } 141 142 BWFillRectBatch* that = t->cast<BWFillRectBatch>(); 143 144 if (this->hasLocalRect() != that->hasLocalRect()) { 145 return false; 146 } 147 148 SkASSERT(this->usesLocalCoords() == that->usesLocalCoords()); 149 if (!this->hasLocalRect() && this->usesLocalCoords()) { 150 if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) { 151 return false; 152 } 153 154 if (this->hasLocalMatrix() != that->hasLocalMatrix()) { 155 return false; 156 } 157 158 if (this->hasLocalMatrix() && !this->localMatrix().cheapEqualTo(that->localMatrix())) { 159 return false; 160 } 161 } 162 163 if (this->color() != that->color()) { 164 fBatch.fColor = GrColor_ILLEGAL; 165 } 166 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin()); 167 this->joinBounds(that->bounds()); 168 return true; 169 } 170 171 172 /** We always use per-vertex colors so that rects can be batched across color changes. Sometimes 173 we have explicit local coords and sometimes not. We *could* always provide explicit local 174 coords and just duplicate the positions when the caller hasn't provided a local coord rect, 175 but we haven't seen a use case which frequently switches between local rect and no local 176 rect draws. 177 178 The color param is used to determine whether the opaque hint can be set on the draw state. 179 The caller must populate the vertex colors itself. 180 181 The vertex attrib order is always pos, color, [local coords]. 182 */ 183 const GrGeometryProcessor* createRectGP() const { 184 using namespace GrDefaultGeoProcFactory; 185 Color color(Color::kAttribute_Type); 186 Coverage coverage(this->coverageIgnored() ? Coverage::kNone_Type : Coverage::kSolid_Type); 187 188 // if we have a local rect, then we apply the localMatrix directly to the localRect to 189 // generate vertex local coords 190 if (this->hasLocalRect()) { 191 LocalCoords localCoords(LocalCoords::kHasExplicit_Type); 192 return GrDefaultGeoProcFactory::Create(color, coverage, localCoords, SkMatrix::I()); 193 } else { 194 LocalCoords localCoords(LocalCoords::kUsePosition_Type, 195 this->hasLocalMatrix() ? &this->localMatrix() : NULL); 196 return GrDefaultGeoProcFactory::CreateForDeviceSpace(color, coverage, localCoords, 197 this->viewMatrix()); 198 } 199 } 200 201 struct BatchTracker { 202 GrColor fColor; 203 bool fUsesLocalCoords; 204 bool fColorIgnored; 205 bool fCoverageIgnored; 206 }; 207 208 BatchTracker fBatch; 209 SkSTArray<1, Geometry, true> fGeoData; 210}; 211 212namespace GrBWFillRectBatch { 213GrBatch* Create(GrColor color, 214 const SkMatrix& viewMatrix, 215 const SkRect& rect, 216 const SkRect* localRect, 217 const SkMatrix* localMatrix) { 218 BWFillRectBatch::Geometry geometry; 219 geometry.fColor = color; 220 geometry.fViewMatrix = viewMatrix; 221 geometry.fRect = rect; 222 223 if (localRect) { 224 geometry.fHasLocalRect = true; 225 geometry.fLocalRect = *localRect; 226 } else { 227 geometry.fHasLocalRect = false; 228 } 229 230 if (localMatrix) { 231 geometry.fHasLocalMatrix = true; 232 geometry.fLocalMatrix = *localMatrix; 233 } else { 234 geometry.fHasLocalMatrix = false; 235 } 236 237 return BWFillRectBatch::Create(geometry); 238} 239}; 240 241/////////////////////////////////////////////////////////////////////////////////////////////////// 242 243#ifdef GR_TEST_UTILS 244 245#include "GrBatchTest.h" 246 247BATCH_TEST_DEFINE(RectBatch) { 248 BWFillRectBatch::Geometry geometry; 249 geometry.fColor = GrRandomColor(random); 250 251 geometry.fRect = GrTest::TestRect(random); 252 geometry.fHasLocalRect = random->nextBool(); 253 254 if (geometry.fHasLocalRect) { 255 geometry.fViewMatrix = GrTest::TestMatrixInvertible(random); 256 geometry.fLocalRect = GrTest::TestRect(random); 257 } else { 258 geometry.fViewMatrix = GrTest::TestMatrix(random); 259 } 260 261 geometry.fHasLocalMatrix = random->nextBool(); 262 if (geometry.fHasLocalMatrix) { 263 geometry.fLocalMatrix = GrTest::TestMatrix(random); 264 } 265 266 return BWFillRectBatch::Create(geometry); 267} 268 269#endif 270