diff options
-rw-r--r-- | gyp/gpu.gypi | 2 | ||||
-rw-r--r-- | include/core/SkCanvas.h | 4 | ||||
-rw-r--r-- | include/gpu/GrDrawContext.h | 16 | ||||
-rw-r--r-- | src/gpu/GrDrawContext.cpp | 30 | ||||
-rw-r--r-- | src/gpu/SkGpuDevice.cpp | 15 | ||||
-rw-r--r-- | src/gpu/SkGpuDevice.h | 1 | ||||
-rw-r--r-- | src/gpu/batches/GrRegionBatch.cpp | 176 | ||||
-rw-r--r-- | src/gpu/batches/GrRegionBatch.h | 25 |
8 files changed, 268 insertions, 1 deletions
diff --git a/gyp/gpu.gypi b/gyp/gpu.gypi index eb99cfeb0f..d1a6952f13 100644 --- a/gyp/gpu.gypi +++ b/gyp/gpu.gypi @@ -259,6 +259,8 @@ '<(skia_src_path)/gpu/batches/GrPLSPathRenderer.h', '<(skia_src_path)/gpu/batches/GrRectBatchFactory.h', '<(skia_src_path)/gpu/batches/GrRectBatchFactory.cpp', + '<(skia_src_path)/gpu/batches/GrRegionBatch.cpp', + '<(skia_src_path)/gpu/batches/GrRegionBatch.h', '<(skia_src_path)/gpu/batches/GrStencilAndCoverPathRenderer.cpp', '<(skia_src_path)/gpu/batches/GrStencilAndCoverPathRenderer.h', '<(skia_src_path)/gpu/batches/GrStencilPathBatch.h', diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h index 780af107af..d9b3282d3e 100644 --- a/include/core/SkCanvas.h +++ b/include/core/SkCanvas.h @@ -708,6 +708,10 @@ public: @param paint The paint used to draw the region */ void drawRegion(const SkRegion& region, const SkPaint& paint) { + if (region.isEmpty()) { + return; + } + this->onDrawRegion(region, paint); } diff --git a/include/gpu/GrDrawContext.h b/include/gpu/GrDrawContext.h index 993bb56f9e..29c7d1c12e 100644 --- a/include/gpu/GrDrawContext.h +++ b/include/gpu/GrDrawContext.h @@ -216,7 +216,21 @@ public: const SkRSXform xform[], const SkRect texRect[], const SkColor colors[]); - + + /** + * Draws a region. + * + * @param paint describes how to color pixels + * @param viewMatrix transformation matrix + * @param region the region to be drawn + * @param style style to apply to the region + */ + void drawRegion(const GrClip&, + const GrPaint& paint, + const SkMatrix& viewMatrix, + const SkRegion& region, + const GrStyle& style); + /** * Draws an oval. * diff --git a/src/gpu/GrDrawContext.cpp b/src/gpu/GrDrawContext.cpp index 5bda884655..5afb2eaec9 100644 --- a/src/gpu/GrDrawContext.cpp +++ b/src/gpu/GrDrawContext.cpp @@ -26,6 +26,7 @@ #include "batches/GrDrawVerticesBatch.h" #include "batches/GrRectBatchFactory.h" #include "batches/GrNinePatch.h" // TODO Factory +#include "batches/GrRegionBatch.h" #include "effects/GrRRectEffect.h" @@ -944,6 +945,35 @@ void GrDrawContext::drawDRRect(const GrClip& clip, /////////////////////////////////////////////////////////////////////////////// +static inline bool is_int(float x) { + return x == (float) sk_float_round2int(x); +} + +void GrDrawContext::drawRegion(const GrClip& clip, + const GrPaint& paint, + const SkMatrix& viewMatrix, + const SkRegion& region, + const GrStyle& style) { + ASSERT_SINGLE_OWNER + RETURN_IF_ABANDONED + SkDEBUGCODE(this->validate();) + GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawRegion"); + + bool isNonTranslate = SkToBool(viewMatrix.getType() & ~(SkMatrix::kTranslate_Mask)); + bool complexStyle = !style.isSimpleFill(); + bool antiAlias = paint.isAntiAlias() && (!is_int(viewMatrix.getTranslateX()) || + !is_int(viewMatrix.getTranslateY())); + if (isNonTranslate || complexStyle || antiAlias) { + SkPath path; + region.getBoundaryPath(&path); + return this->drawPath(clip, paint, viewMatrix, path, style); + } + + SkAutoTUnref<GrDrawBatch> batch(GrRegionBatch::Create(paint.getColor(), viewMatrix, region)); + GrPipelineBuilder pipelineBuilder(paint, false); + this->getDrawTarget()->drawBatch(pipelineBuilder, this, clip, batch); +} + void GrDrawContext::drawOval(const GrClip& clip, const GrPaint& paint, const SkMatrix& viewMatrix, diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index c91331f4b9..2d9b3ef623 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -523,6 +523,21 @@ void SkGpuDevice::drawDRRect(const SkDraw& draw, const SkRRect& outer, ///////////////////////////////////////////////////////////////////////////// +void SkGpuDevice::drawRegion(const SkDraw& draw, const SkRegion& region, const SkPaint& paint) { + if (paint.getMaskFilter()) { + SkPath path; + region.getBoundaryPath(&path); + return this->drawPath(draw, path, paint, nullptr, false); + } + + GrPaint grPaint; + if (!SkPaintToGrPaint(this->context(), fDrawContext.get(), paint, *draw.fMatrix, &grPaint)) { + return; + } + + fDrawContext->drawRegion(fClip, grPaint, *draw.fMatrix, region, GrStyle(paint)); +} + void SkGpuDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint& paint) { ASSERT_SINGLE_OWNER GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawOval", fContext); diff --git a/src/gpu/SkGpuDevice.h b/src/gpu/SkGpuDevice.h index cbe86a4607..a49d160732 100644 --- a/src/gpu/SkGpuDevice.h +++ b/src/gpu/SkGpuDevice.h @@ -73,6 +73,7 @@ public: void drawRRect(const SkDraw&, const SkRRect& r, const SkPaint& paint) override; void drawDRRect(const SkDraw& draw, const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) override; + void drawRegion(const SkDraw&, const SkRegion& r, const SkPaint& paint) override; void drawOval(const SkDraw&, const SkRect& oval, const SkPaint& paint) override; void drawArc(const SkDraw&, const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool useCenter, const SkPaint& paint) override; diff --git a/src/gpu/batches/GrRegionBatch.cpp b/src/gpu/batches/GrRegionBatch.cpp new file mode 100644 index 0000000000..271f6c5b7e --- /dev/null +++ b/src/gpu/batches/GrRegionBatch.cpp @@ -0,0 +1,176 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrRegionBatch.h" + +#include "GrDefaultGeoProcFactory.h" +#include "GrBatchFlushState.h" +#include "GrResourceProvider.h" +#include "GrVertexBatch.h" +#include "SkMatrixPriv.h" +#include "SkRegion.h" + +static const int kVertsPerInstance = 4; +static const int kIndicesPerInstance = 6; + +static sk_sp<GrGeometryProcessor> make_gp(bool readsCoverage) { + using namespace GrDefaultGeoProcFactory; + Color color(Color::kAttribute_Type); + Coverage coverage(readsCoverage ? Coverage::kSolid_Type : Coverage::kNone_Type); + + LocalCoords localCoords(LocalCoords::kHasExplicit_Type); + return GrDefaultGeoProcFactory::Make(color, coverage, localCoords, SkMatrix::I()); +} + +static int tesselate_region(intptr_t vertices, + size_t vertexStride, + GrColor color, + const SkMatrix& viewMatrix, + const SkRegion& region) { + SkRegion::Iterator iter(region); + + intptr_t verts = vertices; + while (!iter.done()) { + SkIRect rect = iter.rect(); + SkPoint* position = (SkPoint*) verts; + position->setIRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vertexStride); + + static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor); + SkPoint* localPosition = (SkPoint*) (verts + kLocalOffset); + localPosition->setIRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vertexStride); + + static const int kColorOffset = sizeof(SkPoint); + GrColor* vertColor = reinterpret_cast<GrColor*>(verts + kColorOffset); + for (int i = 0; i < kVertsPerInstance; i++) { + *vertColor = color; + vertColor = (GrColor*) ((intptr_t) vertColor + vertexStride); + } + + verts += vertexStride * kVertsPerInstance; + iter.next(); + } + + SkPoint* positions = reinterpret_cast<SkPoint*>(vertices); + int numRects = region.computeRegionComplexity(); + SkMatrixPriv::MapPointsWithStride(viewMatrix, positions, vertexStride, + numRects * kVertsPerInstance); + + return numRects; +} + +class RegionBatch : public GrVertexBatch { +public: + DEFINE_BATCH_CLASS_ID + + RegionBatch(GrColor color, const SkMatrix& viewMatrix, const SkRegion& region) + : INHERITED(ClassID()) { + + RegionInfo& info = fRegions.push_back(); + info.fColor = color; + info.fViewMatrix = viewMatrix; + info.fRegion = region; + + SkRect bounds = SkRect::Make(region.getBounds()); + this->setTransformedBounds(bounds, viewMatrix, HasAABloat::kNo, IsZeroArea::kNo); + } + + const char* name() const override { return "GrRegionBatch"; } + + SkString dumpInfo() const override { + SkString str; + str.appendf("# batched: %d\n", fRegions.count()); + for (int i = 0; i < fRegions.count(); ++i) { + const RegionInfo& info = fRegions[i]; + str.appendf("%d: Color: 0x%08x, Region with %d rects\n", + i, info.fColor, info.fRegion.computeRegionComplexity()); + } + str.append(INHERITED::dumpInfo()); + return str; + } + + void computePipelineOptimizations(GrInitInvariantOutput* color, + GrInitInvariantOutput* coverage, + GrBatchToXPOverrides* overrides) const override { + // When this is called on a batch, there is only one region. + color->setKnownFourComponents(fRegions[0].fColor); + coverage->setKnownSingleComponent(0xff); + } + + void initBatchTracker(const GrXPOverridesForBatch& overrides) override { + overrides.getOverrideColorIfSet(&fRegions[0].fColor); + fOverrides = overrides; + } + +private: + + void onPrepareDraws(Target* target) const override { + sk_sp<GrGeometryProcessor> gp = make_gp(fOverrides.readsCoverage()); + if (!gp) { + SkDebugf("Couldn't create GrGeometryProcessor\n"); + return; + } + SkASSERT(gp->getVertexStride() == + sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr)); + + int numRegions = fRegions.count(); + int numRects = 0; + for (int i = 0; i < numRegions; i++) { + numRects += fRegions[i].fRegion.computeRegionComplexity(); + } + + size_t vertexStride = gp->getVertexStride(); + SkAutoTUnref<const GrBuffer> indexBuffer(target->resourceProvider()->refQuadIndexBuffer()); + InstancedHelper helper; + void* vertices = helper.init(target, kTriangles_GrPrimitiveType, vertexStride, + indexBuffer, kVertsPerInstance, kIndicesPerInstance, numRects); + if (!vertices || !indexBuffer) { + SkDebugf("Could not allocate vertices\n"); + return; + } + + intptr_t verts = reinterpret_cast<intptr_t>(vertices); + for (int i = 0; i < numRegions; i++) { + int numRectsInRegion = tesselate_region(verts, vertexStride, fRegions[i].fColor, + fRegions[i].fViewMatrix, fRegions[i].fRegion); + verts += numRectsInRegion * kVertsPerInstance * vertexStride; + } + helper.recordDraw(target, gp.get()); + } + + bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { + RegionBatch* that = t->cast<RegionBatch>(); + if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(), + that->bounds(), caps)) { + return false; + } + + fRegions.push_back_n(that->fRegions.count(), that->fRegions.begin()); + this->joinBounds(*that); + return true; + } + + struct RegionInfo { + GrColor fColor; + SkMatrix fViewMatrix; + SkRegion fRegion; + }; + + GrXPOverridesForBatch fOverrides; + SkSTArray<1, RegionInfo, true> fRegions; + + typedef GrVertexBatch INHERITED; +}; + +namespace GrRegionBatch { + +GrDrawBatch* Create(GrColor color, + const SkMatrix& viewMatrix, + const SkRegion& region) { + return new RegionBatch(color, viewMatrix, region); +} + +}; diff --git a/src/gpu/batches/GrRegionBatch.h b/src/gpu/batches/GrRegionBatch.h new file mode 100644 index 0000000000..d928d0a9cd --- /dev/null +++ b/src/gpu/batches/GrRegionBatch.h @@ -0,0 +1,25 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrRegionBatch_DEFINED +#define GrRegionBatch_DEFINED + +#include "GrColor.h" + +class GrDrawBatch; +class SkMatrix; +class SkRegion; + +namespace GrRegionBatch { + +GrDrawBatch* Create(GrColor color, + const SkMatrix& viewMatrix, + const SkRegion& region); + +}; + +#endif |