diff options
author | jvanverth <jvanverth@google.com> | 2015-08-07 10:09:28 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-08-07 10:09:28 -0700 |
commit | 31ff762dc8bfcd86eb4af92b18fdad36913a04e5 (patch) | |
tree | c5ea4bb600204ff997ec32f69a8a459968700a3f /src | |
parent | 767276e4bd97ebea690884d156862d5e6e8aa7fd (diff) |
First pass at drawAtlas batching.
Moves drawAtlas setup into its own method in GrDrawContext, and adds
DrawAtlasBatch.
Uses pre-built index buffer for quads.
TBR=bsalomon@google.com
Review URL: https://codereview.chromium.org/1277933003
Diffstat (limited to 'src')
-rw-r--r-- | src/gpu/GrDrawContext.cpp | 244 | ||||
-rw-r--r-- | src/gpu/SkGpuDevice.cpp | 61 |
2 files changed, 264 insertions, 41 deletions
diff --git a/src/gpu/GrDrawContext.cpp b/src/gpu/GrDrawContext.cpp index 40188c575b..c3d2548d18 100644 --- a/src/gpu/GrDrawContext.cpp +++ b/src/gpu/GrDrawContext.cpp @@ -10,6 +10,7 @@ #include "GrAtlasTextContext.h" #include "GrBatch.h" #include "GrBatchTest.h" +#include "GrColor.h" #include "GrDefaultGeoProcFactory.h" #include "GrDrawContext.h" #include "GrOvalRenderer.h" @@ -19,6 +20,9 @@ #include "GrStrokeRectBatch.h" #include "GrStencilAndCoverTextContext.h" +#include "SkGr.h" +#include "SkRSXform.h" + #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == fContext) #define RETURN_IF_ABANDONED if (!fDrawTarget) { return; } #define RETURN_FALSE_IF_ABANDONED if (!fDrawTarget) { return false; } @@ -690,6 +694,246 @@ void GrDrawContext::drawVertices(GrRenderTarget* rt, /////////////////////////////////////////////////////////////////////////////// +class DrawAtlasBatch : public GrBatch { +public: + struct Geometry { + GrColor fColor; + SkTDArray<SkPoint> fPositions; + SkTDArray<GrColor> fColors; + SkTDArray<SkPoint> fLocalCoords; + }; + + static GrBatch* Create(const Geometry& geometry, const SkMatrix& viewMatrix, + const SkPoint* positions, int vertexCount, + const GrColor* colors, const SkPoint* localCoords, + const SkRect& bounds) { + return SkNEW_ARGS(DrawAtlasBatch, (geometry, viewMatrix, positions, + vertexCount, colors, localCoords, bounds)); + } + + const char* name() const override { return "DrawAtlasBatch"; } + + void getInvariantOutputColor(GrInitInvariantOutput* out) const override { + // When this is called on a batch, there is only one geometry bundle + if (this->hasColors()) { + out->setUnknownFourComponents(); + } else { + out->setKnownFourComponents(fGeoData[0].fColor); + } + } + + void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override { + out->setKnownSingleComponent(0xff); + } + + void initBatchTracker(const GrPipelineInfo& init) override { + // Handle any color overrides + if (!init.readsColor()) { + fGeoData[0].fColor = GrColor_ILLEGAL; + } + init.getOverrideColorIfSet(&fGeoData[0].fColor); + + // setup batch properties + fColorIgnored = !init.readsColor(); + fColor = fGeoData[0].fColor; + SkASSERT(init.readsLocalCoords()); + fCoverageIgnored = !init.readsCoverage(); + } + + void generateGeometry(GrBatchTarget* batchTarget) override { + int colorOffset = -1, texOffset = -1; + // Setup geometry processor + SkAutoTUnref<const GrGeometryProcessor> gp( + set_vertex_attributes(true, this->hasColors(), &colorOffset, + &texOffset, this->color(), this->viewMatrix(), + this->coverageIgnored())); + + batchTarget->initDraw(gp, this->pipeline()); + + int instanceCount = fGeoData.count(); + size_t vertexStride = gp->getVertexStride(); + SkASSERT(vertexStride == sizeof(SkPoint) + sizeof(SkPoint) + + (this->hasColors() ? sizeof(GrColor) : 0)); + + QuadHelper helper; + int numQuads = this->vertexCount()/4; + void* verts = helper.init(batchTarget, vertexStride, numQuads); + if (!verts) { + SkDebugf("Could not allocate vertices\n"); + return; + } + + int vertexOffset = 0; + for (int i = 0; i < instanceCount; i++) { + const Geometry& args = fGeoData[i]; + + for (int j = 0; j < args.fPositions.count(); ++j) { + *((SkPoint*)verts) = args.fPositions[j]; + if (this->hasColors()) { + *(GrColor*)((intptr_t)verts + colorOffset) = args.fColors[j]; + } + *(SkPoint*)((intptr_t)verts + texOffset) = args.fLocalCoords[j]; + verts = (void*)((intptr_t)verts + vertexStride); + vertexOffset++; + } + } + helper.issueDraw(batchTarget); + } + + SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; } + +private: + DrawAtlasBatch(const Geometry& geometry, const SkMatrix& viewMatrix, + const SkPoint* positions, int vertexCount, + const GrColor* colors, const SkPoint* localCoords, const SkRect& bounds) { + this->initClassID<DrawVerticesBatch>(); + SkASSERT(positions); + SkASSERT(localCoords); + + fViewMatrix = viewMatrix; + Geometry& installedGeo = fGeoData.push_back(geometry); + + installedGeo.fPositions.append(vertexCount, positions); + + if (colors) { + installedGeo.fColors.append(vertexCount, colors); + fHasColors = true; + } else { + fHasColors = false; + } + + installedGeo.fLocalCoords.append(vertexCount, localCoords); + fVertexCount = vertexCount; + + this->setBounds(bounds); + } + + GrColor color() const { return fColor; } + bool colorIgnored() const { return fColorIgnored; } + const SkMatrix& viewMatrix() const { return fViewMatrix; } + bool hasColors() const { return fHasColors; } + int vertexCount() const { return fVertexCount; } + bool coverageIgnored() const { return fCoverageIgnored; } + + bool onCombineIfPossible(GrBatch* t) override { + if (!this->pipeline()->isEqual(*t->pipeline())) { + return false; + } + + DrawAtlasBatch* that = t->cast<DrawAtlasBatch>(); + + // We currently use a uniform viewmatrix for this batch + if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) { + return false; + } + + if (this->hasColors() != that->hasColors()) { + return false; + } + + if (!this->hasColors() && this->color() != that->color()) { + return false; + } + + if (this->color() != that->color()) { + fColor = GrColor_ILLEGAL; + } + fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin()); + fVertexCount += that->vertexCount(); + + this->joinBounds(that->bounds()); + return true; + } + + SkSTArray<1, Geometry, true> fGeoData; + + SkMatrix fViewMatrix; + GrColor fColor; + int fVertexCount; + bool fColorIgnored; + bool fCoverageIgnored; + bool fHasColors; +}; + +void GrDrawContext::drawAtlas(GrRenderTarget* rt, + const GrClip& clip, + const GrPaint& paint, + const SkMatrix& viewMatrix, + int spriteCount, + const SkRSXform xform[], + const SkRect texRect[], + const SkColor colors[]) { + RETURN_IF_ABANDONED + AutoCheckFlush acf(fContext); + if (!this->prepareToDraw(rt)) { + return; + } + + GrPipelineBuilder pipelineBuilder(paint, rt, clip); + + // now build the renderable geometry + const int vertCount = spriteCount * 4; + SkAutoTMalloc<SkPoint> vertStorage(vertCount * 2); + SkPoint* verts = vertStorage.get(); + SkPoint* texs = verts + vertCount; + + for (int i = 0; i < spriteCount; ++i) { + xform[i].toQuad(texRect[i].width(), texRect[i].height(), verts); + texRect[i].toQuad(texs); + verts += 4; + texs += 4; + } + + // TODO clients should give us bounds + SkRect bounds; + if (!bounds.setBoundsCheck(vertStorage.get(), vertCount)) { + SkDebugf("drawAtlas call empty bounds\n"); + return; + } + + viewMatrix.mapRect(&bounds); + + // If we don't have AA then we outset for a half pixel in each direction to account for + // snapping + if (!paint.isAntiAlias()) { + bounds.outset(0.5f, 0.5f); + } + + SkAutoTMalloc<GrColor> colorStorage; + GrColor* vertCols = NULL; + if (colors) { + colorStorage.reset(vertCount); + vertCols = colorStorage.get(); + + int paintAlpha = GrColorUnpackA(paint.getColor()); + + // need to convert byte order and from non-PM to PM + for (int i = 0; i < spriteCount; ++i) { + SkColor color = colors[i]; + if (paintAlpha != 255) { + color = SkColorSetA(color, SkMulDiv255Round(SkColorGetA(color), paintAlpha)); + } + GrColor grColor = SkColor2GrColor(color); + + vertCols[0] = vertCols[1] = vertCols[2] = vertCols[3] = grColor; + vertCols += 4; + } + } + + verts = vertStorage.get(); + texs = verts + vertCount; + vertCols = colorStorage.get(); + + DrawAtlasBatch::Geometry geometry; + geometry.fColor = paint.getColor(); + SkAutoTUnref<GrBatch> batch(DrawAtlasBatch::Create(geometry, viewMatrix, verts, vertCount, + vertCols, texs, bounds)); + + fDrawTarget->drawBatch(pipelineBuilder, batch); +} + +/////////////////////////////////////////////////////////////////////////////// + void GrDrawContext::drawRRect(GrRenderTarget*rt, const GrClip& clip, const GrPaint& paint, diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index cd257b360a..c5fccfc2e2 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -1665,59 +1665,38 @@ void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode, /////////////////////////////////////////////////////////////////////////////// -static void append_quad_indices(uint16_t indices[], int quadIndex) { - int i = quadIndex * 4; - indices[0] = i + 0; indices[1] = i + 1; indices[2] = i + 2; - indices[3] = i + 2; indices[4] = i + 3; indices[5] = i + 0; -} - -void SkGpuDevice::drawAtlas(const SkDraw& d, const SkImage* atlas, const SkRSXform xform[], +void SkGpuDevice::drawAtlas(const SkDraw& draw, const SkImage* atlas, const SkRSXform xform[], const SkRect texRect[], const SkColor colors[], int count, SkXfermode::Mode mode, const SkPaint& paint) { if (paint.isAntiAlias()) { - this->INHERITED::drawAtlas(d, atlas, xform, texRect, colors, count, mode, paint); + this->INHERITED::drawAtlas(draw, atlas, xform, texRect, colors, count, mode, paint); return; } + CHECK_SHOULD_DRAW(draw); + GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawText", fContext); + SkPaint p(paint); p.setShader(atlas->newShader(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode))->unref(); - const int vertCount = count * 4; - const int indexCount = count * 6; - SkAutoTMalloc<SkPoint> vertStorage(vertCount * 2); - SkPoint* verts = vertStorage.get(); - SkPoint* texs = verts + vertCount; - SkAutoTMalloc<uint16_t> indexStorage(indexCount); - uint16_t* indices = indexStorage.get(); - SkAutoTUnref<SkXfermode> xfer(SkXfermode::Create(mode)); - - for (int i = 0; i < count; ++i) { - xform[i].toQuad(texRect[i].width(), texRect[i].height(), verts); - texRect[i].toQuad(texs); - append_quad_indices(indices, i); - verts += 4; - texs += 4; - indices += 6; - } - - SkAutoTMalloc<SkColor> colorStorage; - SkColor* vertCols = NULL; + GrPaint grPaint; + if (!SkPaint2GrPaint(this->context(), fRenderTarget, p, *draw.fMatrix, !colors, &grPaint)) { + return; + } + + SkDEBUGCODE(this->validate();) + +#if 0 if (colors) { - colorStorage.reset(vertCount); - vertCols = colorStorage.get(); - - for (int i = 0; i < count; ++i) { - vertCols[0] = vertCols[1] = vertCols[2] = vertCols[3] = colors[i]; - vertCols += 4; + if (SkXfermode::kModulate_Mode != mode) { + SkDebugf("Unsupported vertex-color/texture xfer mode.\n"); + return; } } - - verts = vertStorage.get(); - texs = verts + vertCount; - vertCols = colorStorage.get(); - indices = indexStorage.get(); - this->drawVertices(d, SkCanvas::kTriangles_VertexMode, vertCount, verts, texs, vertCols, xfer, - indices, indexCount, p); +#endif + + fDrawContext->drawAtlas(fRenderTarget, fClip, grPaint, *draw.fMatrix, + count, xform, texRect, colors); } /////////////////////////////////////////////////////////////////////////////// |