Chromium Code Reviews| Index: src/gpu/batches/GrBWFillRectBatch.cpp |
| diff --git a/src/gpu/batches/GrBWFillRectBatch.cpp b/src/gpu/batches/GrBWFillRectBatch.cpp |
| index c0c93c7614ddd2fae6f23c68b290153961585278..26f5a4f3e05a1c8766af96660293c41e71bdd55a 100644 |
| --- a/src/gpu/batches/GrBWFillRectBatch.cpp |
| +++ b/src/gpu/batches/GrBWFillRectBatch.cpp |
| @@ -17,20 +17,34 @@ class GrBatchTarget; |
| class SkMatrix; |
| struct SkRect; |
| +/* |
| + * BWFillRectBatch is templated to optionally allow the insertion of an additional |
| + * attribute for explicit local coordinates and also to handle an optional localMatrix |
| + * To use this template, an implementation must define the following static functions: |
| + * A Geometry struct |
| + * |
| + * bool CanCombineLocalCoords(const SkMatrix& mine, const SkMatrix& theirs, |
| + * bool usesLocalCoords) |
| + * |
| + * GrDefaultGeoProcFactory::LocalCoords::Type LocalCoordsType() |
| + * |
| + * bool StrideCheck(size_t vertexStride, bool canTweakAlphaForCoverage, |
| + * bool usesLocalCoords) |
| + * |
| + * void FillInAttributes(intptr_t startVertex, size_t vertexStride, |
| + * SkPoint* fan0Position, const Geometry&) |
| + * |
| + * const GrGeometryProcessor* CreateGP(const Geometry& geo, |
| + * const GrDefaultGeoProcFactory::Color& color, |
| + * const GrDefaultGeoProcFactory::Coverage& coverage) |
| + */ |
| +template <typename Base> |
|
bsalomon
2015/08/14 14:37:48
I don't Base is a good a name for the template par
|
| class BWFillRectBatch : public GrVertexBatch { |
| public: |
| - struct Geometry { |
| - SkMatrix fViewMatrix; |
| - SkRect fRect; |
| - SkRect fLocalRect; |
| - SkMatrix fLocalMatrix; |
| - GrColor fColor; |
| - bool fHasLocalRect; |
| - bool fHasLocalMatrix; |
| - }; |
| + typedef typename Base::Geometry Geometry; |
| - static GrDrawBatch* Create(const Geometry& geometry) { |
| - return SkNEW_ARGS(BWFillRectBatch, (geometry)); |
| + static BWFillRectBatch* Create() { |
| + return SkNEW(BWFillRectBatch); |
| } |
| const char* name() const override { return "RectBatch"; } |
| @@ -59,7 +73,7 @@ public: |
| } |
| void generateGeometry(GrBatchTarget* batchTarget) override { |
| - SkAutoTUnref<const GrGeometryProcessor> gp(this->createRectGP()); |
| + SkAutoTUnref<const GrGeometryProcessor> gp(this->createGP(fGeoData[0])); |
| if (!gp) { |
| SkDebugf("Could not create GrGeometryProcessor\n"); |
| return; |
| @@ -69,9 +83,7 @@ public: |
| int instanceCount = fGeoData.count(); |
| size_t vertexStride = gp->getVertexStride(); |
| - SkASSERT(this->hasLocalRect() ? |
| - vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr) : |
| - vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAttr)); |
| + SkASSERT(Base::StrideCheck(vertexStride)); |
| QuadHelper helper; |
| void* vertices = helper.init(batchTarget, vertexStride, instanceCount); |
| @@ -88,19 +100,10 @@ public: |
| positions->setRectFan(geom.fRect.fLeft, geom.fRect.fTop, |
| geom.fRect.fRight, geom.fRect.fBottom, vertexStride); |
|
robertphillips
2015/08/14 14:42:57
space before '(' ?
|
| + // TODO we are mapping the rect twice(three times in the GrDrawContext::drawRect case) |
| geom.fViewMatrix.mapPointsWithStride(positions, vertexStride, kVerticesPerQuad); |
| - // TODO we should only do this if local coords are being read |
| - if (geom.fHasLocalRect) { |
| - static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor); |
| - SkPoint* coords = reinterpret_cast<SkPoint*>(offset + kLocalOffset); |
| - coords->setRectFan(geom.fLocalRect.fLeft, geom.fLocalRect.fTop, |
| - geom.fLocalRect.fRight, geom.fLocalRect.fBottom, |
| - vertexStride); |
| - if (geom.fHasLocalMatrix) { |
| - geom.fLocalMatrix.mapPointsWithStride(coords, vertexStride, kVerticesPerQuad); |
| - } |
| - } |
| + Base::FillInAttributes(offset, vertexStride, geom); |
| static const int kColorOffset = sizeof(SkPoint); |
| GrColor* vertColor = reinterpret_cast<GrColor*>(offset + kColorOffset); |
| @@ -115,22 +118,25 @@ public: |
| SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; } |
| -private: |
| - BWFillRectBatch(const Geometry& geometry) { |
| - this->initClassID<BWFillRectBatch>(); |
| - fGeoData.push_back(geometry); |
| + // to avoid even the initial copy of the struct, we have a getter for the first item which |
| + // is used to seed the batch with its initial geometry. After seeding, the client should call |
| + // init() so the Batch can initialize itself |
| + Geometry* geometry() { return &fGeoData[0]; } |
| + void init() { |
| + const Geometry& geo = fGeoData[0]; |
| + geo.fViewMatrix.mapRect(&fBounds, geo.fRect); |
| + } |
| - fBounds = geometry.fRect; |
| - geometry.fViewMatrix.mapRect(&fBounds); |
| +private: |
| + BWFillRectBatch() { |
| + this->initClassID<BWFillRectBatch<Base>>(); |
| + fGeoData.push_back(); |
| } |
| GrColor color() const { return fBatch.fColor; } |
| bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; } |
| bool colorIgnored() const { return fBatch.fColorIgnored; } |
| const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; } |
| - const SkMatrix& localMatrix() const { return fGeoData[0].fLocalMatrix; } |
| - bool hasLocalRect() const { return fGeoData[0].fHasLocalRect; } |
| - bool hasLocalMatrix() const { return fGeoData[0].fHasLocalMatrix; } |
| bool coverageIgnored() const { return fBatch.fCoverageIgnored; } |
| bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { |
| @@ -140,25 +146,11 @@ private: |
| return false; |
| } |
| - if (this->hasLocalRect() != that->hasLocalRect()) { |
| + if (!Base::CanCombineLocalCoords(this->viewMatrix(), that->viewMatrix(), |
| + this->usesLocalCoords())) { |
| return false; |
| } |
| - SkASSERT(this->usesLocalCoords() == that->usesLocalCoords()); |
| - if (!this->hasLocalRect() && this->usesLocalCoords()) { |
| - if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) { |
| - return false; |
| - } |
| - |
| - if (this->hasLocalMatrix() != that->hasLocalMatrix()) { |
| - return false; |
| - } |
| - |
| - if (this->hasLocalMatrix() && !this->localMatrix().cheapEqualTo(that->localMatrix())) { |
| - return false; |
| - } |
| - } |
| - |
| if (this->color() != that->color()) { |
| fBatch.fColor = GrColor_ILLEGAL; |
| } |
| @@ -179,22 +171,12 @@ private: |
| The vertex attrib order is always pos, color, [local coords]. |
| */ |
| - const GrGeometryProcessor* createRectGP() const { |
| + const GrGeometryProcessor* createGP(const Geometry& geo) const { |
| using namespace GrDefaultGeoProcFactory; |
| Color color(Color::kAttribute_Type); |
| Coverage coverage(this->coverageIgnored() ? Coverage::kNone_Type : Coverage::kSolid_Type); |
| - // if we have a local rect, then we apply the localMatrix directly to the localRect to |
| - // generate vertex local coords |
| - if (this->hasLocalRect()) { |
| - LocalCoords localCoords(LocalCoords::kHasExplicit_Type); |
| - return GrDefaultGeoProcFactory::Create(color, coverage, localCoords, SkMatrix::I()); |
| - } else { |
| - LocalCoords localCoords(LocalCoords::kUsePosition_Type, |
| - this->hasLocalMatrix() ? &this->localMatrix() : NULL); |
| - return GrDefaultGeoProcFactory::CreateForDeviceSpace(color, coverage, localCoords, |
| - this->viewMatrix()); |
| - } |
| + return Base::CreateGP(geo, color, coverage); |
| } |
| struct BatchTracker { |
| @@ -208,32 +190,183 @@ private: |
| SkSTArray<1, Geometry, true> fGeoData; |
| }; |
| +/* |
| + * Right now we have 4 variants of BWFillRect. BWFillRect with no local matrix or local rect, |
|
bsalomon
2015/08/14 14:37:48
Maybe write this as bullets? Kind of hard to follo
|
| + * BWFillRect who has a uniform localMatrix, BWFillRect who has a localRect, and a BWFillRect who |
| + * applies its localMatrix to its localRect |
|
robertphillips
2015/08/14 14:42:57
// These classes are created by having two levels
|
| + */ |
| +template <class Base> |
| +class GrBWFillRectBatchNoLocalRectImp : public Base { |
| +public: |
| + typedef typename Base::Geometry Geometry; |
| + |
| + inline static bool CanCombineLocalCoords(const SkMatrix& mine, const SkMatrix& theirs, |
| + bool usesLocalCoords) { |
| + // We apply the viewmatrix to the rect points on the cpu. However, if the pipeline uses |
| + // local coords then we won't be able to batch. We could actually upload the viewmatrix |
| + // using vertex attributes in these cases, but haven't investigated that |
| + return !usesLocalCoords || mine.cheapEqualTo(theirs); |
| + } |
| + |
| + inline static bool StrideCheck(size_t vertexStride) { |
| + return vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAttr); |
| + } |
| + |
| + inline static void FillInAttributes(intptr_t vertices, size_t vertexStride, |
|
robertphillips
2015/08/14 14:42:57
We don't have to invoke "Base::OnFillInAttributes(
|
| + const Geometry& args) {} |
| +}; |
| + |
| +template <class Base> |
| +class GrBWFillRectBatchLocalRectImp { |
| +public: |
| + typedef typename Base::Geometry Geometry; |
| + |
| + inline static bool CanCombineLocalCoords(const SkMatrix& mine, const SkMatrix& theirs, |
| + bool usesLocalCoords) { |
|
robertphillips
2015/08/14 14:42:57
// We can always combine b.c. ...
?
|
| + return true; |
| + } |
| + |
| + inline static const GrGeometryProcessor* CreateGP( |
| + const Geometry& geo, |
| + const GrDefaultGeoProcFactory::Color& color, |
| + const GrDefaultGeoProcFactory::Coverage& coverage) { |
| + using namespace GrDefaultGeoProcFactory; |
| + LocalCoords localCoords(LocalCoords::kHasExplicit_Type); |
| + return GrDefaultGeoProcFactory::Create(color, coverage, localCoords, SkMatrix::I()); |
| + } |
| + |
| + inline static bool StrideCheck(size_t vertexStride) { |
| + return vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr); |
| + } |
| + |
| + inline static void FillInAttributes(intptr_t vertices, size_t vertexStride, |
| + const Geometry& args) { |
| + static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor); |
| + SkPoint* coords = reinterpret_cast<SkPoint*>(vertices + kLocalOffset); |
| + coords->setRectFan(args.fLocalRect.fLeft, args.fLocalRect.fTop, |
| + args.fLocalRect.fRight, args.fLocalRect.fBottom, |
| + vertexStride); |
| + Base::OnFillInAttributes(coords, vertexStride, args); |
| + } |
| +}; |
| + |
| +class BWFillRectBatchSimpleImp { |
| +public: |
| + struct Geometry { |
| + SkMatrix fViewMatrix; |
| + SkRect fRect; |
| + GrColor fColor; |
| + }; |
| + |
| + inline static const GrGeometryProcessor* CreateGP( |
| + const Geometry& geo, |
| + const GrDefaultGeoProcFactory::Color& color, |
| + const GrDefaultGeoProcFactory::Coverage& coverage) { |
| + using namespace GrDefaultGeoProcFactory; |
| + LocalCoords localCoords(LocalCoords::kUsePosition_Type); |
| + return GrDefaultGeoProcFactory::CreateForDeviceSpace(color, coverage, localCoords, |
| + geo.fViewMatrix); |
| + } |
| +}; |
| + |
| +class BWFillRectBatchLocalMatrixImp { |
| +public: |
| + struct Geometry { |
| + SkMatrix fViewMatrix; |
| + SkMatrix fLocalMatrix; |
| + SkRect fRect; |
| + GrColor fColor; |
| + }; |
| + |
| + inline static const GrGeometryProcessor* CreateGP( |
| + const Geometry& geo, |
| + const GrDefaultGeoProcFactory::Color& color, |
| + const GrDefaultGeoProcFactory::Coverage& coverage) { |
| + using namespace GrDefaultGeoProcFactory; |
| + LocalCoords localCoords(LocalCoords::kUsePosition_Type, &geo.fLocalMatrix); |
| + return GrDefaultGeoProcFactory::CreateForDeviceSpace(color, coverage, localCoords, |
| + geo.fViewMatrix); |
| + } |
| +}; |
| + |
| +class BWFillRectBatchLocalRectImp { |
| +public: |
| + struct Geometry { |
| + SkMatrix fViewMatrix; |
| + SkRect fRect; |
| + SkRect fLocalRect; |
| + GrColor fColor; |
| + }; |
| + inline static void OnFillInAttributes(SkPoint* coords, size_t vertexStride, |
|
robertphillips
2015/08/14 14:42:57
call base class ?
|
| + const Geometry& args) {} |
| +}; |
| + |
| +class BWFillRectBatchLocalMatrixLocalRectImp { |
| +public: |
| + struct Geometry { |
| + SkMatrix fViewMatrix; |
| + SkMatrix fLocalMatrix; |
| + SkRect fRect; |
| + SkRect fLocalRect; |
| + GrColor fColor; |
| + }; |
| + inline static void OnFillInAttributes(SkPoint* coords, size_t vertexStride, |
| + const Geometry& args) { |
| + args.fLocalMatrix.mapPointsWithStride(coords, vertexStride, kVerticesPerQuad); |
| + } |
| + static const int kVerticesPerQuad = 4; |
| +}; |
| + |
| + |
| +typedef BWFillRectBatch<GrBWFillRectBatchNoLocalRectImp<BWFillRectBatchSimpleImp>> BWFillRectBatchSimple; |
| +typedef BWFillRectBatch<GrBWFillRectBatchNoLocalRectImp<BWFillRectBatchLocalMatrixImp>> BWFillRectBatchLocalMatrix; |
| +typedef BWFillRectBatch<GrBWFillRectBatchLocalRectImp<BWFillRectBatchLocalRectImp>> BWFillRectBatchLocalRect; |
| +typedef BWFillRectBatch<GrBWFillRectBatchLocalRectImp<BWFillRectBatchLocalMatrixLocalRectImp>> BWFillRectBatchLocalMatrixLocalRect; |
| + |
| namespace GrBWFillRectBatch { |
| GrDrawBatch* Create(GrColor color, |
| const SkMatrix& viewMatrix, |
| const SkRect& rect, |
| const SkRect* localRect, |
| const SkMatrix* localMatrix) { |
| - BWFillRectBatch::Geometry geometry; |
| - geometry.fColor = color; |
| - geometry.fViewMatrix = viewMatrix; |
| - geometry.fRect = rect; |
| - |
| - if (localRect) { |
| - geometry.fHasLocalRect = true; |
| - geometry.fLocalRect = *localRect; |
| + // TODO bubble these up as separate calls |
| + if (localRect && localMatrix) { |
| + BWFillRectBatchLocalMatrixLocalRect* batch = BWFillRectBatchLocalMatrixLocalRect::Create(); |
| + BWFillRectBatchLocalMatrixLocalRect::Geometry& geo = *batch->geometry(); |
| + geo.fColor = color; |
| + geo.fViewMatrix = viewMatrix; |
| + geo.fLocalMatrix = *localMatrix; |
| + geo.fRect = rect; |
| + geo.fLocalRect = *localRect; |
| + batch->init(); |
| + return batch; |
| + } else if (localRect) { |
| + BWFillRectBatchLocalRect* batch = BWFillRectBatchLocalRect::Create(); |
| + BWFillRectBatchLocalRect::Geometry& geo = *batch->geometry(); |
| + geo.fColor = color; |
| + geo.fViewMatrix = viewMatrix; |
| + geo.fRect = rect; |
| + geo.fLocalRect = *localRect; |
| + batch->init(); |
| + return batch; |
| + } else if (localMatrix) { |
| + BWFillRectBatchLocalMatrix* batch = BWFillRectBatchLocalMatrix::Create(); |
| + BWFillRectBatchLocalMatrix::Geometry& geo = *batch->geometry(); |
| + geo.fColor = color; |
| + geo.fViewMatrix = viewMatrix; |
| + geo.fLocalMatrix = *localMatrix; |
| + geo.fRect = rect; |
| + batch->init(); |
| + return batch; |
| } else { |
| - geometry.fHasLocalRect = false; |
| + BWFillRectBatchSimple* batch = BWFillRectBatchSimple::Create(); |
| + BWFillRectBatchSimple::Geometry& geo = *batch->geometry(); |
| + geo.fColor = color; |
| + geo.fViewMatrix = viewMatrix; |
| + geo.fRect = rect; |
| + batch->init(); |
| + return batch; |
| } |
| - |
| - if (localMatrix) { |
| - geometry.fHasLocalMatrix = true; |
| - geometry.fLocalMatrix = *localMatrix; |
| - } else { |
| - geometry.fHasLocalMatrix = false; |
| - } |
| - |
| - return BWFillRectBatch::Create(geometry); |
| } |
| }; |
| @@ -244,25 +377,16 @@ GrDrawBatch* Create(GrColor color, |
| #include "GrBatchTest.h" |
| DRAW_BATCH_TEST_DEFINE(RectBatch) { |
| - BWFillRectBatch::Geometry geometry; |
| - geometry.fColor = GrRandomColor(random); |
| - |
| - geometry.fRect = GrTest::TestRect(random); |
| - geometry.fHasLocalRect = random->nextBool(); |
| - |
| - if (geometry.fHasLocalRect) { |
| - geometry.fViewMatrix = GrTest::TestMatrixInvertible(random); |
| - geometry.fLocalRect = GrTest::TestRect(random); |
| - } else { |
| - geometry.fViewMatrix = GrTest::TestMatrix(random); |
| - } |
| - |
| - geometry.fHasLocalMatrix = random->nextBool(); |
| - if (geometry.fHasLocalMatrix) { |
| - geometry.fLocalMatrix = GrTest::TestMatrix(random); |
| - } |
| - |
| - return BWFillRectBatch::Create(geometry); |
| + GrColor color = GrRandomColor(random); |
| + SkRect rect = GrTest::TestRect(random); |
| + SkRect localRect = GrTest::TestRect(random); |
| + SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random); |
| + SkMatrix localMatrix = GrTest::TestMatrix(random); |
| + |
| + bool hasLocalRect = random->nextBool(); |
| + bool hasLocalMatrix = random->nextBool(); |
| + return GrBWFillRectBatch::Create(color, viewMatrix, rect, hasLocalRect ? &localRect : nullptr, |
| + hasLocalMatrix ? &localMatrix : nullptr); |
| } |
| #endif |