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:
parent
7d6fb2c92d
commit
cc319b95a5
@ -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',
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -217,6 +217,20 @@ public:
|
||||
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.
|
||||
*
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
176
src/gpu/batches/GrRegionBatch.cpp
Normal file
176
src/gpu/batches/GrRegionBatch.cpp
Normal 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);
|
||||
}
|
||||
|
||||
};
|
25
src/gpu/batches/GrRegionBatch.h
Normal file
25
src/gpu/batches/GrRegionBatch.h
Normal 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
|
Loading…
Reference in New Issue
Block a user