Make DefaultPathOp surface its programInfo at record time
Here is another Op w/ multiple GrMeshes drawn w/ a single programInfo (cf., AAConvexPathOp).
Bug: skia:9455
Change-Id: I3d1eec03d1d9d4fc8e117aa2960472027ea96105
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/276220
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
diff --git a/src/gpu/ops/GrDefaultPathRenderer.cpp b/src/gpu/ops/GrDefaultPathRenderer.cpp
index 0bb6e05..bbd9e40 100644
--- a/src/gpu/ops/GrDefaultPathRenderer.cpp
+++ b/src/gpu/ops/GrDefaultPathRenderer.cpp
@@ -19,6 +19,7 @@
#include "src/gpu/GrFixedClip.h"
#include "src/gpu/GrMesh.h"
#include "src/gpu/GrOpFlushState.h"
+#include "src/gpu/GrProgramInfo.h"
#include "src/gpu/GrRenderTargetContextPriv.h"
#include "src/gpu/GrStyle.h"
#include "src/gpu/GrSurfaceContextPriv.h"
@@ -66,20 +67,21 @@
class PathGeoBuilder {
public:
- PathGeoBuilder(GrPrimitiveType primitiveType, GrMeshDrawOp::Target* target,
- const GrGeometryProcessor* geometryProcessor)
+ PathGeoBuilder(GrPrimitiveType primitiveType,
+ GrMeshDrawOp::Target* target,
+ SkTDArray<GrMesh*>* meshes)
: fPrimitiveType(primitiveType)
, fTarget(target)
, fVertexStride(sizeof(SkPoint))
- , fGeometryProcessor(geometryProcessor)
, fFirstIndex(0)
, fIndicesInChunk(0)
- , fIndices(nullptr) {
+ , fIndices(nullptr)
+ , fMeshes(meshes) {
this->allocNewBuffers();
}
~PathGeoBuilder() {
- this->emitMeshAndPutBackReserve();
+ this->createMeshAndPutBackReserve();
}
/**
@@ -262,14 +264,15 @@
}
// Emits a single draw with all accumulated vertex/index data
- void emitMeshAndPutBackReserve() {
+ void createMeshAndPutBackReserve() {
int vertexCount = fCurVert - fVertices;
int indexCount = fCurIdx - fIndices;
SkASSERT(vertexCount <= fVerticesInChunk);
SkASSERT(indexCount <= fIndicesInChunk);
+ GrMesh* mesh = nullptr;
if (this->isIndexed() ? SkToBool(indexCount) : SkToBool(vertexCount)) {
- GrMesh* mesh = fTarget->allocMesh();
+ mesh = fTarget->allocMesh();
if (!this->isIndexed()) {
mesh->setNonIndexedNonInstanced(vertexCount);
} else {
@@ -277,11 +280,14 @@
vertexCount - 1, GrPrimitiveRestart::kNo);
}
mesh->setVertexData(std::move(fVertexBuffer), fFirstVertex);
- fTarget->recordDraw(fGeometryProcessor, mesh, 1, fPrimitiveType);
}
fTarget->putBackIndices((size_t)(fIndicesInChunk - indexCount));
fTarget->putBackVertices((size_t)(fVerticesInChunk - vertexCount), fVertexStride);
+
+ if (mesh) {
+ fMeshes->push_back(mesh);
+ }
}
void needSpace(int vertsNeeded, int indicesNeeded = 0) {
@@ -297,7 +303,7 @@
SkPoint subpathStartPt = fVertices[fSubpathIndexStart];
// Draw the mesh we've accumulated, and put back any unused space
- this->emitMeshAndPutBackReserve();
+ this->createMeshAndPutBackReserve();
// Get new buffers
this->allocNewBuffers();
@@ -313,7 +319,6 @@
GrPrimitiveType fPrimitiveType;
GrMeshDrawOp::Target* fTarget;
size_t fVertexStride;
- const GrGeometryProcessor* fGeometryProcessor;
sk_sp<const GrBuffer> fVertexBuffer;
int fFirstVertex;
@@ -327,6 +332,8 @@
uint16_t* fIndices;
uint16_t* fCurIdx;
uint16_t fSubpathIndexStart;
+
+ SkTDArray<GrMesh*>* fMeshes;
};
class DefaultPathOp final : public GrMeshDrawOp {
@@ -354,7 +361,11 @@
const char* name() const override { return "DefaultPathOp"; }
void visitProxies(const VisitProxyFunc& func) const override {
- fHelper.visitProxies(func);
+ if (fProgramInfo) {
+ fProgramInfo->visitProxies(func);
+ } else {
+ fHelper.visitProxies(func);
+ }
}
#ifdef SK_DEBUG
@@ -401,7 +412,25 @@
}
private:
- void onPrepareDraws(Target* target) override {
+ GrPrimitiveType primType() const {
+ if (this->isHairline()) {
+ int instanceCount = fPaths.count();
+
+ // We avoid indices when we have a single hairline contour.
+ bool isIndexed = instanceCount > 1 ||
+ PathGeoBuilder::PathHasMultipleSubpaths(fPaths[0].fPath);
+
+ return isIndexed ? GrPrimitiveType::kLines : GrPrimitiveType::kLineStrip;
+ }
+
+ return GrPrimitiveType::kTriangles;
+ }
+
+ GrProgramInfo* createProgramInfo(const GrCaps* caps,
+ SkArenaAlloc* arena,
+ const GrSurfaceProxyView* outputView,
+ GrAppliedClip&& appliedClip,
+ const GrXferProcessor::DstProxyView& dstProxyView) {
GrGeometryProcessor* gp;
{
using namespace GrDefaultGeoProcFactory;
@@ -409,8 +438,8 @@
Coverage coverage(this->coverage());
LocalCoords localCoords(fHelper.usesLocalCoords() ? LocalCoords::kUsePosition_Type
: LocalCoords::kUnused_Type);
- gp = GrDefaultGeoProcFactory::Make(target->allocator(),
- target->caps().shaderCaps(),
+ gp = GrDefaultGeoProcFactory::Make(arena,
+ caps->shaderCaps(),
color,
coverage,
localCoords,
@@ -419,32 +448,57 @@
SkASSERT(gp->vertexStride() == sizeof(SkPoint));
- int instanceCount = fPaths.count();
+ return fHelper.createProgramInfoWithStencil(caps, arena, outputView, std::move(appliedClip),
+ dstProxyView, gp, this->primType());
- // We avoid indices when we have a single hairline contour.
- bool isIndexed = !this->isHairline() || instanceCount > 1 ||
- PathGeoBuilder::PathHasMultipleSubpaths(fPaths[0].fPath);
+ }
- // determine primitiveType
- GrPrimitiveType primitiveType;
- if (this->isHairline()) {
- primitiveType = isIndexed ? GrPrimitiveType::kLines : GrPrimitiveType::kLineStrip;
- } else {
- primitiveType = GrPrimitiveType::kTriangles;
- }
- PathGeoBuilder pathGeoBuilder(primitiveType, target, gp);
+ GrProgramInfo* createProgramInfo(Target* target) {
+ return this->createProgramInfo(&target->caps(),
+ target->allocator(),
+ target->outputView(),
+ target->detachAppliedClip(),
+ target->dstProxyView());
+ }
+
+ void onPrePrepareDraws(GrRecordingContext* context,
+ const GrSurfaceProxyView* outputView,
+ GrAppliedClip* clip,
+ const GrXferProcessor::DstProxyView& dstProxyView) override {
+ SkArenaAlloc* arena = context->priv().recordTimeAllocator();
+
+ // This is equivalent to a GrOpFlushState::detachAppliedClip
+ GrAppliedClip appliedClip = clip ? std::move(*clip) : GrAppliedClip();
+
+ fProgramInfo = this->createProgramInfo(context->priv().caps(), arena, outputView,
+ std::move(appliedClip), dstProxyView);
+
+ context->priv().recordProgramInfo(fProgramInfo);
+ }
+
+ void onPrepareDraws(Target* target) override {
+ PathGeoBuilder pathGeoBuilder(this->primType(), target, &fMeshes);
// fill buffers
- for (int i = 0; i < instanceCount; i++) {
+ for (int i = 0; i < fPaths.count(); i++) {
const PathData& args = fPaths[i];
pathGeoBuilder.addPath(args.fPath, args.fTolerance);
}
}
void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
- auto pipeline = fHelper.createPipelineWithStencil(flushState);
+ if (!fProgramInfo) {
+ fProgramInfo = this->createProgramInfo(flushState);
+ }
- flushState->executeDrawsAndUploadsForMeshDrawOp(this, chainBounds, pipeline);
+ if (!fProgramInfo || !fMeshes.count()) {
+ return;
+ }
+
+ flushState->opsRenderPass()->bindPipeline(*fProgramInfo, chainBounds);
+ for (int i = 0; i < fMeshes.count(); ++i) {
+ flushState->opsRenderPass()->drawMeshes(*fProgramInfo, fMeshes[i], 1);
+ }
}
CombineResult onCombineIfPossible(GrOp* t, GrRecordingContext::Arenas*,
@@ -491,6 +545,9 @@
SkMatrix fViewMatrix;
bool fIsHairline;
+ SkTDArray<GrMesh*> fMeshes;
+ GrProgramInfo* fProgramInfo = nullptr;
+
typedef GrMeshDrawOp INHERITED;
};