Update AAHairlineOp to surface its programInfos at record time

This CL is interesting bc the AAHairlineOp is the first one that requires multiple programInfos.
Correspondingly, it is also the first one that shares a pipeline between said multiple programInfos.

Bug: skia:9455
Change-Id: I2369abbdeaf4eac2bc9547ad36631beba29bd641
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/277203
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
This commit is contained in:
Robert Phillips 2020-03-18 08:13:53 -04:00 committed by Skia Commit-Bot
parent f6784a8c84
commit 4f93c573e2
7 changed files with 261 additions and 82 deletions

View File

@ -70,7 +70,11 @@ public:
}
void visitProxies(const VisitProxyFunc& func) const override {
fProcessorSet.visitProxies(func);
if (fProgramInfo) {
fProgramInfo->visitFPProxies(func);
} else {
fProcessorSet.visitProxies(func);
}
}
protected:

View File

@ -20,6 +20,7 @@
#include "src/gpu/GrDrawOpTest.h"
#include "src/gpu/GrOpFlushState.h"
#include "src/gpu/GrProcessor.h"
#include "src/gpu/GrProgramInfo.h"
#include "src/gpu/GrResourceProvider.h"
#include "src/gpu/GrStyle.h"
#include "src/gpu/effects/GrBezierEffect.h"
@ -772,8 +773,6 @@ bool check_bounds(const SkMatrix& viewMatrix, const SkRect& devBounds, void* ver
return true;
}
namespace {
class AAHairlineOp final : public GrMeshDrawOp {
private:
using Helper = GrSimpleMeshDrawOpHelperWithStencil;
@ -823,7 +822,18 @@ public:
const char* name() const override { return "AAHairlineOp"; }
void visitProxies(const VisitProxyFunc& func) const override {
fHelper.visitProxies(func);
bool visited = false;
for (int i = 0; i < 3; ++i) {
if (fProgramInfos[i]) {
fProgramInfos[i]->visitFPProxies(func);
visited = true;
}
}
if (!visited) {
fHelper.visitProxies(func);
}
}
#ifdef SK_DEBUG
@ -848,16 +858,26 @@ public:
nullptr);
}
enum Program : uint8_t {
kNone_Program = 0x0,
kLine_Program = 0x1,
kQuad_Program = 0x2,
kConic_Program = 0x4,
};
private:
GrGeometryProcessor* makeLineGP(const GrCaps&, SkArenaAlloc*,
const SkMatrix* geometryProcessorViewM,
const SkMatrix* geometryProcessorLocalM);
GrGeometryProcessor* makeQuadGP(const GrCaps&, SkArenaAlloc*,
const SkMatrix* geometryProcessorViewM,
const SkMatrix* geometryProcessorLocalM);
GrGeometryProcessor* makeConicGP(const GrCaps&, SkArenaAlloc*,
const SkMatrix* geometryProcessorViewM,
const SkMatrix* geometryProcessorLocalM);
void makeLineProgramInfo(const GrCaps&, SkArenaAlloc*, const GrPipeline*,
const GrSurfaceProxyView* outputView,
const SkMatrix* geometryProcessorViewM,
const SkMatrix* geometryProcessorLocalM);
void makeQuadProgramInfo(const GrCaps&, SkArenaAlloc*, const GrPipeline*,
const GrSurfaceProxyView* outputView,
const SkMatrix* geometryProcessorViewM,
const SkMatrix* geometryProcessorLocalM);
void makeConicProgramInfo(const GrCaps&, SkArenaAlloc*, const GrPipeline*,
const GrSurfaceProxyView* outputView,
const SkMatrix* geometryProcessorViewM,
const SkMatrix* geometryProcessorLocalM);
GrProgramInfo* programInfo() override {
// This Op has 3 programInfos and implements its own onPrePrepareDraws so this entry point
@ -866,20 +886,18 @@ private:
return nullptr;
}
Program predictPrograms(const GrCaps*) const;
void onCreateProgramInfo(const GrCaps*,
SkArenaAlloc*,
const GrSurfaceProxyView* outputView,
GrAppliedClip&&,
const GrXferProcessor::DstProxyView&) override {
// TODO [PI]: implement
}
const GrXferProcessor::DstProxyView&) override;
void onPrePrepareDraws(GrRecordingContext*,
const GrSurfaceProxyView* outputView,
GrAppliedClip*,
const GrXferProcessor::DstProxyView&) override {
// TODO [PI]: implement
}
const GrXferProcessor::DstProxyView&) override;
void onPrepareDraws(Target*) override;
void onExecute(GrOpFlushState*, const SkRect& chainBounds) override;
@ -942,34 +960,55 @@ private:
SkPMColor4f fColor;
uint8_t fCoverage;
Program fCharacterization = kNone_Program; // holds a mask of required programs
GrSimpleMesh* fMeshes[3] = { nullptr };
GrProgramInfo* fProgramInfos[3] = { nullptr };
typedef GrMeshDrawOp INHERITED;
};
} // anonymous namespace
GR_MAKE_BITFIELD_OPS(AAHairlineOp::Program)
GrGeometryProcessor* AAHairlineOp::makeLineGP(const GrCaps& caps, SkArenaAlloc* arena,
const SkMatrix* geometryProcessorViewM,
const SkMatrix* geometryProcessorLocalM) {
using namespace GrDefaultGeoProcFactory;
void AAHairlineOp::makeLineProgramInfo(const GrCaps& caps, SkArenaAlloc* arena,
const GrPipeline* pipeline,
const GrSurfaceProxyView* outputView,
const SkMatrix* geometryProcessorViewM,
const SkMatrix* geometryProcessorLocalM) {
if (fProgramInfos[0]) {
return;
}
Color color(this->color());
LocalCoords localCoords(fHelper.usesLocalCoords() ? LocalCoords::kUsePosition_Type
: LocalCoords::kUnused_Type);
localCoords.fMatrix = geometryProcessorLocalM;
GrGeometryProcessor* lineGP;
{
using namespace GrDefaultGeoProcFactory;
GrGeometryProcessor* lineGP = GrDefaultGeoProcFactory::Make(arena,
color,
Coverage::kAttribute_Type,
localCoords,
*geometryProcessorViewM);
SkASSERT(sizeof(LineVertex) == lineGP->vertexStride());
Color color(this->color());
LocalCoords localCoords(fHelper.usesLocalCoords() ? LocalCoords::kUsePosition_Type
: LocalCoords::kUnused_Type);
localCoords.fMatrix = geometryProcessorLocalM;
return lineGP;
lineGP = GrDefaultGeoProcFactory::Make(arena,
color,
Coverage::kAttribute_Type,
localCoords,
*geometryProcessorViewM);
SkASSERT(sizeof(LineVertex) == lineGP->vertexStride());
}
fProgramInfos[0] = GrSimpleMeshDrawOpHelper::CreateProgramInfo(arena, pipeline,
outputView, lineGP,
GrPrimitiveType::kTriangles);
}
GrGeometryProcessor* AAHairlineOp::makeQuadGP(const GrCaps& caps, SkArenaAlloc* arena,
const SkMatrix* geometryProcessorViewM,
const SkMatrix* geometryProcessorLocalM) {
void AAHairlineOp::makeQuadProgramInfo(const GrCaps& caps, SkArenaAlloc* arena,
const GrPipeline* pipeline,
const GrSurfaceProxyView* outputView,
const SkMatrix* geometryProcessorViewM,
const SkMatrix* geometryProcessorLocalM) {
if (fProgramInfos[1]) {
return;
}
GrGeometryProcessor* quadGP = GrQuadEffect::Make(arena,
this->color(),
*geometryProcessorViewM,
@ -980,12 +1019,20 @@ GrGeometryProcessor* AAHairlineOp::makeQuadGP(const GrCaps& caps, SkArenaAlloc*
this->coverage());
SkASSERT(sizeof(BezierVertex) == quadGP->vertexStride());
return quadGP;
fProgramInfos[1] = GrSimpleMeshDrawOpHelper::CreateProgramInfo(arena, pipeline,
outputView, quadGP,
GrPrimitiveType::kTriangles);
}
GrGeometryProcessor* AAHairlineOp::makeConicGP(const GrCaps& caps, SkArenaAlloc* arena,
const SkMatrix* geometryProcessorViewM,
const SkMatrix* geometryProcessorLocalM) {
void AAHairlineOp::makeConicProgramInfo(const GrCaps& caps, SkArenaAlloc* arena,
const GrPipeline* pipeline,
const GrSurfaceProxyView* outputView,
const SkMatrix* geometryProcessorViewM,
const SkMatrix* geometryProcessorLocalM) {
if (fProgramInfos[2]) {
return;
}
GrGeometryProcessor* conicGP = GrConicEffect::Make(arena,
this->color(),
*geometryProcessorViewM,
@ -996,10 +1043,42 @@ GrGeometryProcessor* AAHairlineOp::makeConicGP(const GrCaps& caps, SkArenaAlloc*
this->coverage());
SkASSERT(sizeof(BezierVertex) == conicGP->vertexStride());
return conicGP;
fProgramInfos[2] = GrSimpleMeshDrawOpHelper::CreateProgramInfo(arena, pipeline,
outputView, conicGP,
GrPrimitiveType::kTriangles);
}
void AAHairlineOp::onPrepareDraws(Target* target) {
AAHairlineOp::Program AAHairlineOp::predictPrograms(const GrCaps* caps) const {
bool convertConicsToQuads = !caps->shaderCaps()->floatIs32Bits();
// When predicting the programs we always include the lineProgram bc it is used as a fallback
// for quads and conics. In non-DDL mode there are cases where it sometimes isn't needed for a
// given path.
Program neededPrograms = kLine_Program;
for (int i = 0; i < fPaths.count(); i++) {
uint32_t mask = fPaths[i].fPath.getSegmentMasks();
if (mask & (SkPath::kQuad_SegmentMask | SkPath::kCubic_SegmentMask)) {
neededPrograms |= kQuad_Program;
}
if (mask & SkPath::kConic_SegmentMask) {
if (convertConicsToQuads) {
neededPrograms |= kQuad_Program;
} else {
neededPrograms |= kConic_Program;
}
}
}
return neededPrograms;
}
void AAHairlineOp::onCreateProgramInfo(const GrCaps* caps,
SkArenaAlloc* arena,
const GrSurfaceProxyView* outputView,
GrAppliedClip&& appliedClip,
const GrXferProcessor::DstProxyView& dstProxyView) {
// Setup the viewmatrix and localmatrix for the GrGeometryProcessor.
SkMatrix invert;
if (!this->viewMatrix().invert(&invert)) {
@ -1010,15 +1089,67 @@ void AAHairlineOp::onPrepareDraws(Target* target) {
bool hasPerspective = this->viewMatrix().hasPerspective();
const SkMatrix* geometryProcessorViewM = &SkMatrix::I();
const SkMatrix* geometryProcessorLocalM = &invert;
const SkMatrix* toDevice = nullptr;
const SkMatrix* toSrc = nullptr;
if (hasPerspective) {
geometryProcessorViewM = &this->viewMatrix();
geometryProcessorLocalM = &SkMatrix::I();
}
auto pipeline = fHelper.createPipelineWithStencil(caps, arena, outputView->swizzle(),
std::move(appliedClip), dstProxyView);
if (fCharacterization & kLine_Program) {
this->makeLineProgramInfo(*caps, arena, pipeline, outputView,
geometryProcessorViewM, geometryProcessorLocalM);
}
if (fCharacterization & kQuad_Program) {
this->makeQuadProgramInfo(*caps, arena, pipeline, outputView,
geometryProcessorViewM, geometryProcessorLocalM);
}
if (fCharacterization & kConic_Program) {
this->makeConicProgramInfo(*caps, arena, pipeline, outputView,
geometryProcessorViewM, geometryProcessorLocalM);
}
}
void AAHairlineOp::onPrePrepareDraws(GrRecordingContext* context,
const GrSurfaceProxyView* outputView,
GrAppliedClip* clip,
const GrXferProcessor::DstProxyView& dstProxyView) {
SkArenaAlloc* arena = context->priv().recordTimeAllocator();
const GrCaps* caps = context->priv().caps();
// This is equivalent to a GrOpFlushState::detachAppliedClip
GrAppliedClip appliedClip = clip ? std::move(*clip) : GrAppliedClip();
// Conservatively predict which programs will be required
fCharacterization = this->predictPrograms(caps);
this->createProgramInfo(caps, arena, outputView, std::move(appliedClip), dstProxyView);
context->priv().recordProgramInfo(fProgramInfos[0]);
context->priv().recordProgramInfo(fProgramInfos[1]);
context->priv().recordProgramInfo(fProgramInfos[2]);
}
void AAHairlineOp::onPrepareDraws(Target* target) {
// Setup the viewmatrix and localmatrix for the GrGeometryProcessor.
SkMatrix invert;
if (!this->viewMatrix().invert(&invert)) {
return;
}
// we will transform to identity space if the viewmatrix does not have perspective
const SkMatrix* toDevice = nullptr;
const SkMatrix* toSrc = nullptr;
if (this->viewMatrix().hasPerspective()) {
toDevice = &this->viewMatrix();
toSrc = &invert;
}
SkDEBUGCODE(Program predictedPrograms = this->predictPrograms(&target->caps()));
Program actualPrograms = kNone_Program;
// This is hand inlined for maximum performance.
PREALLOC_PTARRAY(128) lines;
PREALLOC_PTARRAY(128) quads;
@ -1048,6 +1179,9 @@ void AAHairlineOp::onPrepareDraws(Target* target) {
// do lines first
if (lineCount) {
SkASSERT(predictedPrograms & kLine_Program);
actualPrograms |= kLine_Program;
sk_sp<const GrBuffer> linesIndexBuffer = get_lines_index_buffer(target->resourceProvider());
GrMeshDrawOp::PatternHelper helper(target, GrPrimitiveType::kTriangles, sizeof(LineVertex),
@ -1064,11 +1198,7 @@ void AAHairlineOp::onPrepareDraws(Target* target) {
add_line(&lines[2*i], toSrc, this->coverage(), &verts);
}
GrGeometryProcessor* lineGP = this->makeLineGP(target->caps(), target->allocator(),
geometryProcessorViewM,
geometryProcessorLocalM);
helper.recordDraw(target, lineGP);
fMeshes[0] = helper.mesh();
}
if (quadCount || conicCount) {
@ -1101,36 +1231,43 @@ void AAHairlineOp::onPrepareDraws(Target* target) {
}
if (quadCount > 0) {
GrGeometryProcessor* quadGP = this->makeQuadGP(target->caps(), target->allocator(),
geometryProcessorViewM,
geometryProcessorLocalM);
SkASSERT(predictedPrograms & kQuad_Program);
actualPrograms |= kQuad_Program;
GrSimpleMesh* mesh = target->allocMesh();
mesh->setIndexedPatterned(quadsIndexBuffer, kIdxsPerQuad, quadCount,
kQuadsNumInIdxBuffer, vertexBuffer, kQuadNumVertices,
firstVertex);
target->recordDraw(quadGP, mesh, 1, GrPrimitiveType::kTriangles);
fMeshes[1] = target->allocMesh();
fMeshes[1]->setIndexedPatterned(quadsIndexBuffer, kIdxsPerQuad, quadCount,
kQuadsNumInIdxBuffer, vertexBuffer, kQuadNumVertices,
firstVertex);
firstVertex += quadCount * kQuadNumVertices;
}
if (conicCount > 0) {
GrGeometryProcessor* conicGP = this->makeConicGP(target->caps(), target->allocator(),
geometryProcessorViewM,
geometryProcessorLocalM);
SkASSERT(predictedPrograms & kConic_Program);
actualPrograms |= kConic_Program;
GrSimpleMesh* mesh = target->allocMesh();
mesh->setIndexedPatterned(std::move(quadsIndexBuffer), kIdxsPerQuad, conicCount,
kQuadsNumInIdxBuffer, std::move(vertexBuffer),
kQuadNumVertices, firstVertex);
target->recordDraw(conicGP, mesh, 1, GrPrimitiveType::kTriangles);
fMeshes[2] = target->allocMesh();
fMeshes[2]->setIndexedPatterned(std::move(quadsIndexBuffer), kIdxsPerQuad, conicCount,
kQuadsNumInIdxBuffer, std::move(vertexBuffer),
kQuadNumVertices, firstVertex);
}
}
// In DDL mode this will replace the predicted program requirements with the actual ones.
// However, we will already have surfaced the predicted programs to the DDL.
fCharacterization = actualPrograms;
}
void AAHairlineOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) {
auto pipeline = fHelper.createPipelineWithStencil(flushState);
this->createProgramInfo(flushState);
flushState->executeDrawsAndUploadsForMeshDrawOp(this, chainBounds, pipeline);
for (int i = 0; i < 3; ++i) {
if (fProgramInfos[i] && fMeshes[i]) {
flushState->bindPipelineAndScissorClip(*fProgramInfos[i], chainBounds);
flushState->bindTextures(fProgramInfos[i]->primProc(), nullptr,
fProgramInfos[i]->pipeline());
flushState->drawMesh(*fMeshes[i]);
}
}
}
bool GrAAHairLinePathRenderer::onDrawPath(const DrawPathArgs& args) {

View File

@ -110,7 +110,7 @@ GrProcessorSet::Analysis GrSimpleMeshDrawOpHelper::finalizeProcessors(
const GrPipeline* GrSimpleMeshDrawOpHelper::CreatePipeline(
const GrCaps* caps,
SkArenaAlloc* arena,
const GrSurfaceProxyView* outputView,
GrSwizzle outputViewSwizzle,
GrAppliedClip&& appliedClip,
const GrXferProcessor::DstProxyView& dstProxyView,
GrProcessorSet&& processorSet,
@ -122,7 +122,7 @@ const GrPipeline* GrSimpleMeshDrawOpHelper::CreatePipeline(
pipelineArgs.fUserStencil = stencilSettings;
pipelineArgs.fCaps = caps;
pipelineArgs.fDstProxyView = dstProxyView;
pipelineArgs.fOutputSwizzle = outputView->swizzle();
pipelineArgs.fOutputSwizzle = outputViewSwizzle;
return arena->make<GrPipeline>(pipelineArgs,
std::move(processorSet),
@ -136,7 +136,7 @@ const GrPipeline* GrSimpleMeshDrawOpHelper::CreatePipeline(
const GrUserStencilSettings* stencilSettings) {
return CreatePipeline(&flushState->caps(),
flushState->allocator(),
flushState->outputView(),
flushState->outputView()->swizzle(),
flushState->detachAppliedClip(),
flushState->dstProxyView(),
std::move(processorSet),
@ -147,7 +147,7 @@ const GrPipeline* GrSimpleMeshDrawOpHelper::CreatePipeline(
const GrPipeline* GrSimpleMeshDrawOpHelper::createPipeline(GrOpFlushState* flushState) {
return CreatePipeline(&flushState->caps(),
flushState->allocator(),
flushState->outputView(),
flushState->outputView()->swizzle(),
flushState->detachAppliedClip(),
flushState->dstProxyView(),
this->detachProcessorSet(),
@ -167,13 +167,21 @@ GrProgramInfo* GrSimpleMeshDrawOpHelper::CreateProgramInfo(
const GrUserStencilSettings* stencilSettings) {
auto pipeline = CreatePipeline(caps,
arena,
outputView,
outputView->swizzle(),
std::move(appliedClip),
dstProxyView,
std::move(processorSet),
pipelineFlags,
stencilSettings);
return CreateProgramInfo(arena, pipeline, outputView, geometryProcessor, primitiveType);
}
GrProgramInfo* GrSimpleMeshDrawOpHelper::CreateProgramInfo(SkArenaAlloc* arena,
const GrPipeline* pipeline,
const GrSurfaceProxyView* outputView,
GrGeometryProcessor* geometryProcessor,
GrPrimitiveType primitiveType) {
GrRenderTargetProxy* outputProxy = outputView->asRenderTargetProxy();
auto tmp = arena->make<GrProgramInfo>(outputProxy->numSamples(),

View File

@ -126,7 +126,7 @@ public:
static const GrPipeline* CreatePipeline(
const GrCaps*,
SkArenaAlloc*,
const GrSurfaceProxyView* outputView,
GrSwizzle outputViewSwizzle,
GrAppliedClip&&,
const GrXferProcessor::DstProxyView&,
GrProcessorSet&&,
@ -140,6 +140,12 @@ public:
const GrPipeline* createPipeline(GrOpFlushState* flushState);
static GrProgramInfo* CreateProgramInfo(SkArenaAlloc*,
const GrPipeline*,
const GrSurfaceProxyView* outputView,
GrGeometryProcessor*,
GrPrimitiveType);
// Create a programInfo with the following properties:
// its primitive processor uses no textures
// it has no dynamic state besides the scissor clip

View File

@ -8,17 +8,30 @@
#include "src/gpu/ops/GrSimpleMeshDrawOpHelperWithStencil.h"
const GrPipeline* GrSimpleMeshDrawOpHelperWithStencil::createPipelineWithStencil(
GrOpFlushState* flushState) {
return GrSimpleMeshDrawOpHelper::CreatePipeline(&flushState->caps(),
flushState->allocator(),
flushState->outputView(),
flushState->detachAppliedClip(),
flushState->dstProxyView(),
const GrCaps* caps,
SkArenaAlloc* arena,
GrSwizzle outputViewSwizzle,
GrAppliedClip&& appliedClip,
const GrXferProcessor::DstProxyView& dstProxyView) {
return GrSimpleMeshDrawOpHelper::CreatePipeline(caps,
arena,
outputViewSwizzle,
std::move(appliedClip),
dstProxyView,
this->detachProcessorSet(),
this->pipelineFlags(),
this->stencilSettings());
}
const GrPipeline* GrSimpleMeshDrawOpHelperWithStencil::createPipelineWithStencil(
GrOpFlushState* flushState) {
return this->createPipelineWithStencil(&flushState->caps(),
flushState->allocator(),
flushState->outputView()->swizzle(),
flushState->detachAppliedClip(),
flushState->dstProxyView());
}
GrSimpleMeshDrawOpHelperWithStencil::GrSimpleMeshDrawOpHelperWithStencil(
const MakeArgs& args, GrAAType aaType, const GrUserStencilSettings* stencilSettings,
InputFlags inputFlags)

View File

@ -22,6 +22,12 @@ public:
using GrSimpleMeshDrawOpHelper::visitProxies;
const GrPipeline* createPipelineWithStencil(const GrCaps*,
SkArenaAlloc*,
GrSwizzle outputViewSwizzle,
GrAppliedClip&&,
const GrXferProcessor::DstProxyView&);
const GrPipeline* createPipelineWithStencil(GrOpFlushState* flushState);
GrProgramInfo* createProgramInfoWithStencil(const GrCaps*,

View File

@ -12,6 +12,7 @@
#include "src/gpu/GrGeometryProcessor.h"
#include "src/gpu/GrMemoryPool.h"
#include "src/gpu/GrOpFlushState.h"
#include "src/gpu/GrProgramInfo.h"
#include "src/gpu/GrVertexWriter.h"
#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
@ -90,7 +91,11 @@ public:
GrClampType) override;
void visitProxies(const VisitProxyFunc& func) const override {
fProcessorSet.visitProxies(func);
if (fProgramInfo) {
fProgramInfo->visitFPProxies(func);
} else {
fProcessorSet.visitProxies(func);
}
}
private: