GPU implementation of drawRegion()

Nexus 6P drawregion Bench Performance
Before 48.0ms
After  3.57ms

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2267273006

Review-Url: https://codereview.chromium.org/2267273006
This commit is contained in:
msarett 2016-08-25 18:07:18 -07:00 committed by Commit bot
parent 7d6fb2c92d
commit cc319b95a5
8 changed files with 268 additions and 1 deletions

View File

@ -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',

View File

@ -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);
}

View File

@ -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.
*

View File

@ -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,

View File

@ -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);

View File

@ -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;

View File

@ -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);
}
};

View File

@ -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