| OLD | NEW |
| (Empty) |
| 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 "GrBatchFlushState.h" | |
| 11 #include "GrColor.h" | |
| 12 #include "GrDefaultGeoProcFactory.h" | |
| 13 #include "GrPrimitiveProcessor.h" | |
| 14 #include "GrResourceProvider.h" | |
| 15 #include "GrTInstanceBatch.h" | |
| 16 #include "GrQuad.h" | |
| 17 #include "GrVertexBatch.h" | |
| 18 | |
| 19 // Common functions | |
| 20 class BWFillRectBatchBase { | |
| 21 public: | |
| 22 static const int kVertsPerInstance = 4; | |
| 23 static const int kIndicesPerInstance = 6; | |
| 24 | |
| 25 static void InitInvariantOutputCoverage(GrInitInvariantOutput* out) { | |
| 26 out->setKnownSingleComponent(0xff); | |
| 27 } | |
| 28 | |
| 29 static const GrIndexBuffer* GetIndexBuffer(GrResourceProvider* rp) { | |
| 30 return rp->refQuadIndexBuffer(); | |
| 31 } | |
| 32 | |
| 33 template <typename Geometry> | |
| 34 static void SetBounds(const Geometry& geo, SkRect* outBounds) { | |
| 35 geo.fViewMatrix.mapRect(outBounds, geo.fRect); | |
| 36 } | |
| 37 }; | |
| 38 | |
| 39 /** We always use per-vertex colors so that rects can be batched across color ch
anges. Sometimes | |
| 40 we have explicit local coords and sometimes not. We *could* always provide
explicit local | |
| 41 coords and just duplicate the positions when the caller hasn't provided a lo
cal coord rect, | |
| 42 but we haven't seen a use case which frequently switches between local rect
and no local | |
| 43 rect draws. | |
| 44 | |
| 45 The vertex attrib order is always pos, color, [local coords]. | |
| 46 */ | |
| 47 static const GrGeometryProcessor* create_gp(const SkMatrix& viewMatrix, | |
| 48 bool readsCoverage, | |
| 49 bool hasExplicitLocalCoords, | |
| 50 const SkMatrix* localMatrix) { | |
| 51 using namespace GrDefaultGeoProcFactory; | |
| 52 Color color(Color::kAttribute_Type); | |
| 53 Coverage coverage(readsCoverage ? Coverage::kSolid_Type : Coverage::kNone_Ty
pe); | |
| 54 | |
| 55 // If we have perspective on the viewMatrix then we won't map on the CPU, no
r will we map | |
| 56 // the local rect on the cpu (in case the localMatrix also has perspective). | |
| 57 // Otherwise, if we have a local rect, then we apply the localMatrix directl
y to the localRect | |
| 58 // to generate vertex local coords | |
| 59 if (viewMatrix.hasPerspective()) { | |
| 60 LocalCoords localCoords(hasExplicitLocalCoords ? LocalCoords::kHasExplic
it_Type : | |
| 61 LocalCoords::kUsePositi
on_Type, | |
| 62 localMatrix); | |
| 63 return GrDefaultGeoProcFactory::Create(color, coverage, localCoords, vie
wMatrix); | |
| 64 } else if (hasExplicitLocalCoords) { | |
| 65 LocalCoords localCoords(LocalCoords::kHasExplicit_Type); | |
| 66 return GrDefaultGeoProcFactory::Create(color, coverage, localCoords, SkM
atrix::I()); | |
| 67 } else { | |
| 68 LocalCoords localCoords(LocalCoords::kUsePosition_Type, localMatrix); | |
| 69 return GrDefaultGeoProcFactory::CreateForDeviceSpace(color, coverage, lo
calCoords, | |
| 70 viewMatrix); | |
| 71 } | |
| 72 } | |
| 73 | |
| 74 static void tesselate(intptr_t vertices, | |
| 75 size_t vertexStride, | |
| 76 GrColor color, | |
| 77 const SkMatrix& viewMatrix, | |
| 78 const SkRect& rect, | |
| 79 const GrQuad* localQuad) { | |
| 80 SkPoint* positions = reinterpret_cast<SkPoint*>(vertices); | |
| 81 | |
| 82 positions->setRectFan(rect.fLeft, rect.fTop, | |
| 83 rect.fRight, rect.fBottom, vertexStride); | |
| 84 | |
| 85 if (!viewMatrix.hasPerspective()) { | |
| 86 viewMatrix.mapPointsWithStride(positions, vertexStride, | |
| 87 BWFillRectBatchBase::kVertsPerInstance); | |
| 88 } | |
| 89 | |
| 90 // Setup local coords | |
| 91 // TODO we should only do this if local coords are being read | |
| 92 if (localQuad) { | |
| 93 static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor); | |
| 94 for (int i = 0; i < BWFillRectBatchBase::kVertsPerInstance; i++) { | |
| 95 SkPoint* coords = reinterpret_cast<SkPoint*>(vertices + kLocalOffset
+ | |
| 96 i * vertexStride); | |
| 97 *coords = localQuad->point(i); | |
| 98 } | |
| 99 } | |
| 100 | |
| 101 static const int kColorOffset = sizeof(SkPoint); | |
| 102 GrColor* vertColor = reinterpret_cast<GrColor*>(vertices + kColorOffset); | |
| 103 for (int j = 0; j < 4; ++j) { | |
| 104 *vertColor = color; | |
| 105 vertColor = (GrColor*) ((intptr_t) vertColor + vertexStride); | |
| 106 } | |
| 107 } | |
| 108 | |
| 109 class BWFillRectBatchNoLocalMatrixImp : public BWFillRectBatchBase { | |
| 110 public: | |
| 111 struct Geometry { | |
| 112 SkMatrix fViewMatrix; | |
| 113 SkRect fRect; | |
| 114 GrQuad fLocalQuad; | |
| 115 GrColor fColor; | |
| 116 }; | |
| 117 | |
| 118 static const char* Name() { return "BWFillRectBatchNoLocalMatrix"; } | |
| 119 | |
| 120 static bool CanCombine(const Geometry& mine, const Geometry& theirs, | |
| 121 const GrPipelineOptimizations& opts) { | |
| 122 return true; | |
| 123 } | |
| 124 | |
| 125 static const GrGeometryProcessor* CreateGP(const Geometry& geo, | |
| 126 const GrPipelineOptimizations& op
ts) { | |
| 127 const GrGeometryProcessor* gp = create_gp(geo.fViewMatrix, opts.readsCov
erage(), true, | |
| 128 nullptr); | |
| 129 | |
| 130 SkASSERT(gp->getVertexStride() == | |
| 131 sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr)); | |
| 132 return gp; | |
| 133 } | |
| 134 | |
| 135 static void Tesselate(intptr_t vertices, size_t vertexStride, const Geometry
& geo, | |
| 136 const GrPipelineOptimizations& opts) { | |
| 137 tesselate(vertices, vertexStride, geo.fColor, geo.fViewMatrix, geo.fRect
, &geo.fLocalQuad); | |
| 138 } | |
| 139 }; | |
| 140 | |
| 141 // We handle perspective in the local matrix or viewmatrix with special batches | |
| 142 class BWFillRectBatchPerspectiveImp : public BWFillRectBatchBase { | |
| 143 public: | |
| 144 struct Geometry { | |
| 145 SkMatrix fViewMatrix; | |
| 146 SkMatrix fLocalMatrix; | |
| 147 SkRect fRect; | |
| 148 SkRect fLocalRect; | |
| 149 GrColor fColor; | |
| 150 bool fHasLocalMatrix; | |
| 151 bool fHasLocalRect; | |
| 152 }; | |
| 153 | |
| 154 static const char* Name() { return "BWFillRectBatchPerspective"; } | |
| 155 | |
| 156 static bool CanCombine(const Geometry& mine, const Geometry& theirs, | |
| 157 const GrPipelineOptimizations& opts) { | |
| 158 // We could batch across perspective vm changes if we really wanted to | |
| 159 return mine.fViewMatrix.cheapEqualTo(theirs.fViewMatrix) && | |
| 160 (!mine.fHasLocalMatrix || mine.fLocalMatrix.cheapEqualTo(theirs.f
LocalMatrix)); | |
| 161 } | |
| 162 | |
| 163 static const GrGeometryProcessor* CreateGP(const Geometry& geo, | |
| 164 const GrPipelineOptimizations& op
ts) { | |
| 165 const GrGeometryProcessor* gp = create_gp(geo.fViewMatrix, opts.readsCov
erage(), | |
| 166 geo.fHasLocalRect, | |
| 167 geo.fHasLocalMatrix ? &geo.fLo
calMatrix : | |
| 168 nullptr)
; | |
| 169 | |
| 170 SkASSERT(geo.fHasLocalRect ? | |
| 171 gp->getVertexStride() == sizeof(GrDefaultGeoProcFactory::PositionCo
lorLocalCoordAttr) : | |
| 172 gp->getVertexStride() == sizeof(GrDefaultGeoProcFactory::PositionCo
lorAttr)); | |
| 173 return gp; | |
| 174 } | |
| 175 | |
| 176 static void Tesselate(intptr_t vertices, size_t vertexStride, const Geometry
& geo, | |
| 177 const GrPipelineOptimizations& opts) { | |
| 178 if (geo.fHasLocalRect) { | |
| 179 GrQuad quad(geo.fLocalRect); | |
| 180 tesselate(vertices, vertexStride, geo.fColor, geo.fViewMatrix, geo.f
Rect, &quad); | |
| 181 } else { | |
| 182 tesselate(vertices, vertexStride, geo.fColor, geo.fViewMatrix, geo.f
Rect, nullptr); | |
| 183 } | |
| 184 } | |
| 185 }; | |
| 186 | |
| 187 typedef GrTInstanceBatch<BWFillRectBatchNoLocalMatrixImp> BWFillRectBatchSimple; | |
| 188 typedef GrTInstanceBatch<BWFillRectBatchPerspectiveImp> BWFillRectBatchPerspecti
ve; | |
| 189 | |
| 190 namespace GrBWFillRectBatch { | |
| 191 GrDrawBatch* Create(GrColor color, | |
| 192 const SkMatrix& viewMatrix, | |
| 193 const SkRect& rect, | |
| 194 const SkRect* localRect, | |
| 195 const SkMatrix* localMatrix) { | |
| 196 | |
| 197 /* Perspective has to be handled in a slow path for now */ | |
| 198 if (viewMatrix.hasPerspective() || (localMatrix && localMatrix->hasPerspecti
ve())) { | |
| 199 BWFillRectBatchPerspective* batch = BWFillRectBatchPerspective::Create()
; | |
| 200 BWFillRectBatchPerspective::Geometry& geo = *batch->geometry(); | |
| 201 | |
| 202 geo.fColor = color; | |
| 203 geo.fViewMatrix = viewMatrix; | |
| 204 geo.fRect = rect; | |
| 205 geo.fHasLocalRect = SkToBool(localRect); | |
| 206 geo.fHasLocalMatrix = SkToBool(localMatrix); | |
| 207 if (localMatrix) { | |
| 208 geo.fLocalMatrix = *localMatrix; | |
| 209 } | |
| 210 if (localRect) { | |
| 211 geo.fLocalRect = *localRect; | |
| 212 } | |
| 213 | |
| 214 batch->init(); | |
| 215 return batch; | |
| 216 } else { | |
| 217 // TODO bubble these up as separate calls | |
| 218 BWFillRectBatchSimple* batch = BWFillRectBatchSimple::Create(); | |
| 219 BWFillRectBatchSimple::Geometry& geo = *batch->geometry(); | |
| 220 | |
| 221 geo.fColor = color; | |
| 222 geo.fViewMatrix = viewMatrix; | |
| 223 geo.fRect = rect; | |
| 224 | |
| 225 if (localRect && localMatrix) { | |
| 226 geo.fLocalQuad.setFromMappedRect(*localRect, *localMatrix); | |
| 227 } else if (localRect) { | |
| 228 geo.fLocalQuad.set(*localRect); | |
| 229 } else if (localMatrix) { | |
| 230 geo.fLocalQuad.setFromMappedRect(rect, *localMatrix); | |
| 231 } else { | |
| 232 geo.fLocalQuad.set(rect); | |
| 233 } | |
| 234 | |
| 235 batch->init(); | |
| 236 return batch; | |
| 237 } | |
| 238 } | |
| 239 }; | |
| 240 | |
| 241 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | |
| 242 | |
| 243 #ifdef GR_TEST_UTILS | |
| 244 | |
| 245 #include "GrBatchTest.h" | |
| 246 | |
| 247 DRAW_BATCH_TEST_DEFINE(RectBatch) { | |
| 248 GrColor color = GrRandomColor(random); | |
| 249 SkRect rect = GrTest::TestRect(random); | |
| 250 SkRect localRect = GrTest::TestRect(random); | |
| 251 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random); | |
| 252 SkMatrix localMatrix = GrTest::TestMatrix(random); | |
| 253 | |
| 254 bool hasLocalRect = random->nextBool(); | |
| 255 bool hasLocalMatrix = random->nextBool(); | |
| 256 return GrBWFillRectBatch::Create(color, viewMatrix, rect, hasLocalRect ? &lo
calRect : nullptr, | |
| 257 hasLocalMatrix ? &localMatrix : nullptr); | |
| 258 } | |
| 259 | |
| 260 #endif | |
| OLD | NEW |