aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gyp/gpu.gypi2
-rw-r--r--include/core/SkCanvas.h4
-rw-r--r--include/gpu/GrDrawContext.h16
-rw-r--r--src/gpu/GrDrawContext.cpp30
-rw-r--r--src/gpu/SkGpuDevice.cpp15
-rw-r--r--src/gpu/SkGpuDevice.h1
-rw-r--r--src/gpu/batches/GrRegionBatch.cpp176
-rw-r--r--src/gpu/batches/GrRegionBatch.h25
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