Chromium Code Reviews| Index: src/gpu/GrInOrderDrawBuffer.cpp |
| diff --git a/src/gpu/GrInOrderDrawBuffer.cpp b/src/gpu/GrInOrderDrawBuffer.cpp |
| index e6b53f837442a8ddd8f92d75fe8a6c0284d5c917..1ff912ef6464f39eb923c855cca169d33660f662 100644 |
| --- a/src/gpu/GrInOrderDrawBuffer.cpp |
| +++ b/src/gpu/GrInOrderDrawBuffer.cpp |
| @@ -106,77 +106,247 @@ template<typename T> static void reset_data_buffer(SkTDArray<T>* buffer, int min |
| } |
| } |
| -void GrInOrderDrawBuffer::onDrawRect(GrPipelineBuilder* pipelineBuilder, |
| - GrColor color, |
| - const SkMatrix& viewMatrix, |
| - const SkRect& rect, |
| - const SkRect* localRect, |
| - const SkMatrix* localMatrix) { |
| - GrPipelineBuilder::AutoRestoreEffects are(pipelineBuilder); |
| +class RectBatch : public GrBatch { |
| +public: |
|
robertphillips
2015/02/20 17:29:38
That'a a lot of data!
|
| + struct Geometry { |
| + GrColor fColor; |
| + SkMatrix fViewMatrix; |
| + SkRect fRect; |
|
robertphillips
2015/02/20 17:29:38
Does reordering the bools yield better packing?
joshualitt
2015/02/20 17:49:07
I can try putting them at the end, that is a good
|
| + bool fHasLocalRect; |
| + bool fHasLocalMatrix; |
| + SkRect fLocalRect; |
| + SkMatrix fLocalMatrix; |
| + }; |
| + |
| + static GrBatch* Create(const Geometry& geometry) { |
| + return SkNEW_ARGS(RectBatch, (geometry)); |
| + } |
| + |
| + const char* name() const SK_OVERRIDE { return "RectBatch"; } |
| + |
| + void getInvariantOutputColor(GrInitInvariantOutput* out) const SK_OVERRIDE { |
| + // When this is called on a batch, there is only one geometry bundle |
| + if (GrColorIsOpaque(fGeoData[0].fColor)) { |
| + out->setUnknownOpaqueFourComponents(); |
| + } else { |
| + out->setUnknownFourComponents(); |
| + } |
| + } |
| - // Go to device coords to allow batching across matrix changes |
| - SkMatrix invert = SkMatrix::I(); |
| + void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE { |
| + out->setUnknownSingleComponent(); |
| + } |
| - // if we have a local rect, then we apply the localMatrix directly to the localRect to generate |
| - // vertex local coords |
| - bool hasExplicitLocalCoords = SkToBool(localRect); |
| - if (!hasExplicitLocalCoords) { |
| - if (!viewMatrix.isIdentity() && !viewMatrix.invert(&invert)) { |
| - SkDebugf("Could not invert\n"); |
| - return; |
| + void initBatchTracker(const GrPipelineInfo& init) SK_OVERRIDE { |
| + // Handle any color overrides |
| + if (init.fColorIgnored) { |
| + fGeoData[0].fColor = GrColor_ILLEGAL; |
| + } else if (GrColor_ILLEGAL != init.fOverrideColor) { |
| + fGeoData[0].fColor = init.fOverrideColor; |
| } |
| - if (localMatrix) { |
| - invert.preConcat(*localMatrix); |
| + // setup batch properties |
| + fBatch.fColorIgnored = init.fColorIgnored; |
| + fBatch.fColor = fGeoData[0].fColor; |
| + fBatch.fUsesLocalCoords = init.fUsesLocalCoords; |
| + fBatch.fCoverageIgnored = init.fCoverageIgnored; |
| + } |
| + |
| + void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) SK_OVERRIDE { |
| + // Go to device coords to allow batching across matrix changes |
| + SkMatrix invert = SkMatrix::I(); |
| + |
| + // if we have a local rect, then we apply the localMatrix directly to the localRect to |
| + // generate vertex local coords |
| + bool hasExplicitLocalCoords = this->hasLocalRect(); |
| + if (!hasExplicitLocalCoords) { |
| + if (!this->viewMatrix().isIdentity() && !this->viewMatrix().invert(&invert)) { |
| + SkDebugf("Could not invert\n"); |
| + return; |
| + } |
| + |
| + if (this->hasLocalMatrix()) { |
| + invert.preConcat(this->localMatrix()); |
| + } |
| + } |
| + |
| + SkAutoTUnref<const GrGeometryProcessor> gp(create_rect_gp(hasExplicitLocalCoords, |
| + this->color(), |
| + &invert)); |
| + |
| + batchTarget->initDraw(gp, pipeline); |
| + |
| + // TODO this is hacky, but the only way we have to initialize the GP is to use the |
| + // GrPipelineInfo struct so we can generate the correct shader. Once we have GrBatch |
| + // everywhere we can remove this nastiness |
| + GrPipelineInfo init; |
| + init.fColorIgnored = fBatch.fColorIgnored; |
| + init.fOverrideColor = GrColor_ILLEGAL; |
| + init.fCoverageIgnored = fBatch.fCoverageIgnored; |
| + init.fUsesLocalCoords = this->usesLocalCoords(); |
| + gp->initBatchTracker(batchTarget->currentBatchTracker(), init); |
| + |
| + size_t vertexStride = gp->getVertexStride(); |
| + |
| + SkASSERT(hasExplicitLocalCoords ? |
| + vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr) : |
| + vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAttr)); |
| + |
| + int instanceCount = fGeoData.count(); |
| + int vertexCount = kVertsPerRect * instanceCount; |
| + |
| + const GrVertexBuffer* vertexBuffer; |
| + int firstVertex; |
| + |
| + void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride, |
| + vertexCount, |
| + &vertexBuffer, |
| + &firstVertex); |
| + |
| + for (int i = 0; i < instanceCount; i++) { |
| + const Geometry& args = fGeoData[i]; |
| + |
| + intptr_t offset = GrTCast<intptr_t>(vertices) + kVertsPerRect * i * vertexStride; |
| + SkPoint* positions = GrTCast<SkPoint*>(offset); |
| + |
| + positions->setRectFan(args.fRect.fLeft, args.fRect.fTop, |
| + args.fRect.fRight, args.fRect.fBottom, vertexStride); |
| + args.fViewMatrix.mapPointsWithStride(positions, vertexStride, kVertsPerRect); |
| + |
| + if (args.fHasLocalRect) { |
| + static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor); |
| + SkPoint* coords = GrTCast<SkPoint*>(offset + kLocalOffset); |
| + coords->setRectFan(args.fLocalRect.fLeft, args.fLocalRect.fTop, |
| + args.fLocalRect.fRight, args.fLocalRect.fBottom, |
| + vertexStride); |
| + if (args.fHasLocalMatrix) { |
| + args.fLocalMatrix.mapPointsWithStride(coords, vertexStride, kVertsPerRect); |
| + } |
| + } |
| + |
| + static const int kColorOffset = sizeof(SkPoint); |
| + GrColor* vertColor = GrTCast<GrColor*>(offset + kColorOffset); |
| + for (int j = 0; j < 4; ++j) { |
| + *vertColor = args.fColor; |
| + vertColor = (GrColor*) ((intptr_t) vertColor + vertexStride); |
| + } |
| } |
| + |
| + const GrIndexBuffer* quadIndexBuffer = batchTarget->quadIndexBuffer(); |
| + |
| + GrDrawTarget::DrawInfo drawInfo; |
| + drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType); |
| + drawInfo.setStartVertex(0); |
| + drawInfo.setStartIndex(0); |
| + drawInfo.setVerticesPerInstance(kVertsPerRect); |
| + drawInfo.setIndicesPerInstance(kIndicesPerRect); |
| + drawInfo.adjustStartVertex(firstVertex); |
| + drawInfo.setVertexBuffer(vertexBuffer); |
| + drawInfo.setIndexBuffer(quadIndexBuffer); |
| + |
| + int maxInstancesPerDraw = quadIndexBuffer->maxQuads(); |
| + while (instanceCount) { |
| + drawInfo.setInstanceCount(SkTMin(instanceCount, maxInstancesPerDraw)); |
| + drawInfo.setVertexCount(drawInfo.instanceCount() * drawInfo.verticesPerInstance()); |
| + drawInfo.setIndexCount(drawInfo.instanceCount() * drawInfo.indicesPerInstance()); |
| + |
| + batchTarget->draw(drawInfo); |
| + |
| + drawInfo.setStartVertex(drawInfo.startVertex() + drawInfo.vertexCount()); |
| + instanceCount -= drawInfo.instanceCount(); |
| + } |
| } |
| - SkAutoTUnref<const GrGeometryProcessor> gp(create_rect_gp(hasExplicitLocalCoords, |
| - color, |
| - &invert)); |
| + SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; } |
| - size_t vstride = gp->getVertexStride(); |
| - SkASSERT(vstride == sizeof(SkPoint) + sizeof(GrColor) + (SkToBool(localRect) ? sizeof(SkPoint) : |
| - 0)); |
| - AutoReleaseGeometry geo(this, 4, vstride, 0); |
| - if (!geo.succeeded()) { |
| - SkDebugf("Failed to get space for vertices!\n"); |
| - return; |
| +private: |
| + RectBatch(const Geometry& geometry) { |
| + this->initClassID<RectBatch>(); |
| + fGeoData.push_back(geometry); |
| } |
| - geo.positions()->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vstride); |
| - viewMatrix.mapPointsWithStride(geo.positions(), vstride, 4); |
| + 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; } |
| - // When the caller has provided an explicit source rect for a stage then we don't want to |
| - // modify that stage's matrix. Otherwise if the effect is generating its source rect from |
| - // the vertex positions then we have to account for the view matrix |
| - SkRect devBounds; |
| + bool onCombineIfPossible(GrBatch* t) SK_OVERRIDE { |
| + RectBatch* that = t->cast<RectBatch>(); |
| - // since we already computed the dev verts, set the bounds hint. This will help us avoid |
| - // unnecessary clipping in our onDraw(). |
| - get_vertex_bounds(geo.vertices(), vstride, 4, &devBounds); |
| + if (this->hasLocalRect() != that->hasLocalRect()) { |
| + return false; |
| + } |
| - if (localRect) { |
| - static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor); |
| - SkPoint* coords = GrTCast<SkPoint*>(GrTCast<intptr_t>(geo.vertices()) + kLocalOffset); |
| - coords->setRectFan(localRect->fLeft, localRect->fTop, |
| - localRect->fRight, localRect->fBottom, |
| - vstride); |
| - if (localMatrix) { |
| - localMatrix->mapPointsWithStride(coords, vstride, 4); |
| + SkASSERT(this->usesLocalCoords() == that->usesLocalCoords()); |
| + if (!this->hasLocalRect() && this->usesLocalCoords()) { |
|
robertphillips
2015/02/20 17:29:38
Do we need a view matrix for each one then?
joshualitt
2015/02/20 17:49:07
Well, I think the most common case by far is to no
|
| + if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) { |
| + return false; |
| + } |
| + |
| + if (this->hasLocalMatrix() != that->hasLocalMatrix()) { |
| + return false; |
| + } |
| + |
|
robertphillips
2015/02/20 17:29:38
Ditto for local matrix?
|
| + if (this->hasLocalMatrix() && !this->localMatrix().cheapEqualTo(that->localMatrix())) { |
| + return false; |
| + } |
| } |
| + |
| + if (this->color() != that->color()) { |
| + fBatch.fColor = GrColor_ILLEGAL; |
| + } |
| + fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin()); |
| + return true; |
| } |
| - static const int kColorOffset = sizeof(SkPoint); |
| - GrColor* vertColor = GrTCast<GrColor*>(GrTCast<intptr_t>(geo.vertices()) + kColorOffset); |
| - for (int i = 0; i < 4; ++i) { |
| - *vertColor = color; |
| - vertColor = (GrColor*) ((intptr_t) vertColor + vstride); |
| + struct BatchTracker { |
| + GrColor fColor; |
| + bool fUsesLocalCoords; |
| + bool fColorIgnored; |
| + bool fCoverageIgnored; |
| + }; |
| + |
| + const static int kVertsPerRect = 4; |
| + const static int kIndicesPerRect = 6; |
| + |
| + BatchTracker fBatch; |
| + SkSTArray<1, Geometry, true> fGeoData; |
| +}; |
| + |
| +void GrInOrderDrawBuffer::onDrawRect(GrPipelineBuilder* pipelineBuilder, |
| + GrColor color, |
| + const SkMatrix& viewMatrix, |
| + const SkRect& rect, |
| + const SkRect* localRect, |
| + const SkMatrix* localMatrix) { |
| + GrPipelineBuilder::AutoRestoreEffects are(pipelineBuilder); |
| + RectBatch::Geometry geometry; |
| + geometry.fColor = color; |
| + geometry.fViewMatrix = viewMatrix; |
| + geometry.fRect = rect; |
| + |
| + if (localRect) { |
| + geometry.fHasLocalRect = true; |
| + geometry.fLocalRect = *localRect; |
| + } else { |
| + geometry.fHasLocalRect = false; |
| } |
| - this->setIndexSourceToBuffer(this->getContext()->getQuadIndexBuffer()); |
| - this->drawIndexedInstances(pipelineBuilder, gp, kTriangles_GrPrimitiveType, 1, 4, 6, |
| - &devBounds); |
| + if (localMatrix) { |
| + geometry.fHasLocalMatrix = true; |
| + geometry.fLocalMatrix = *localMatrix; |
| + } else { |
| + geometry.fHasLocalMatrix = false; |
| + } |
| + |
| + SkAutoTUnref<GrBatch> batch(RectBatch::Create(geometry)); |
| + |
| + SkRect bounds = rect; |
| + viewMatrix.mapRect(&bounds); |
| + this->drawBatch(pipelineBuilder, batch, &bounds); |
| } |
| int GrInOrderDrawBuffer::concatInstancedDraw(const DrawInfo& info) { |
| @@ -288,6 +458,7 @@ void GrInOrderDrawBuffer::onStencilPath(const GrPipelineBuilder& pipelineBuilder |
| StencilPath* sp = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, StencilPath, |
| (path, pipelineBuilder.getRenderTarget())); |
| + |
| sp->fScissor = scissorState; |
| sp->fUseHWAA = pipelineBuilder.isHWAntialias(); |
| sp->fViewMatrix = pathProc->viewMatrix(); |