blob: 4c8f04c87311eb60e7690311a768ebebe8029dab [file] [log] [blame]
/*
* Copyright 2021 Google LLC.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "src/gpu/ops/PathTessellateOp.h"
#include "src/gpu/GrAppliedClip.h"
#include "src/gpu/GrOpFlushState.h"
#include "src/gpu/tessellate/PathWedgeTessellator.h"
#include "src/gpu/tessellate/shaders/GrPathTessellationShader.h"
namespace skgpu::v1 {
void PathTessellateOp::visitProxies(const GrVisitProxyFunc& func) const {
if (fTessellationProgram) {
fTessellationProgram->pipeline().visitProxies(func);
} else {
fProcessors.visitProxies(func);
}
}
GrProcessorSet::Analysis PathTessellateOp::finalize(const GrCaps& caps,
const GrAppliedClip* clip,
GrClampType clampType) {
auto analysis = fProcessors.finalize(this->headDraw().fColor,
GrProcessorAnalysisCoverage::kNone,
clip,
nullptr,
caps,
clampType,
&this->headDraw().fColor);
if (!analysis.usesLocalCoords()) {
// Since we don't need local coords, we can transform on CPU instead of in the shader. This
// gives us better batching potential.
this->headDraw().fPathMatrix = fShaderMatrix;
fShaderMatrix = SkMatrix::I();
}
return analysis;
}
GrDrawOp::CombineResult PathTessellateOp::onCombineIfPossible(GrOp* grOp,
SkArenaAlloc*,
const GrCaps&) {
auto* op = grOp->cast<PathTessellateOp>();
bool canMerge = fAAType == op->fAAType &&
fStencil == op->fStencil &&
fProcessors == op->fProcessors &&
fShaderMatrix == op->fShaderMatrix;
if (canMerge) {
fTotalCombinedPathVerbCnt += op->fTotalCombinedPathVerbCnt;
fPatchAttribs |= op->fPatchAttribs;
if (!(fPatchAttribs & PatchAttribs::kColor) &&
this->headDraw().fColor != op->headDraw().fColor) {
// Color is no longer uniform. Move it into patch attribs.
fPatchAttribs |= PatchAttribs::kColor;
}
*fPathDrawTail = op->fPathDrawList;
fPathDrawTail = op->fPathDrawTail;
return CombineResult::kMerged;
}
return CombineResult::kCannotCombine;
}
void PathTessellateOp::prepareTessellator(const GrTessellationShader::ProgramArgs& args,
GrAppliedClip&& appliedClip) {
SkASSERT(!fTessellator);
SkASSERT(!fTessellationProgram);
auto* pipeline = GrTessellationShader::MakePipeline(args, fAAType, std::move(appliedClip),
std::move(fProcessors));
fTessellator = PathWedgeTessellator::Make(args.fArena,
args.fCaps->shaderCaps()->infinitySupport(),
fPatchAttribs);
auto* tessShader = GrPathTessellationShader::Make(args.fArena,
fShaderMatrix,
this->headDraw().fColor,
fTotalCombinedPathVerbCnt,
*pipeline,
fTessellator->patchAttribs(),
*args.fCaps);
fTessellationProgram = GrTessellationShader::MakeProgram(args, tessShader, pipeline, fStencil);
}
void PathTessellateOp::onPrePrepare(GrRecordingContext* context,
const GrSurfaceProxyView& writeView, GrAppliedClip* clip,
const GrDstProxyView& dstProxyView,
GrXferBarrierFlags renderPassXferBarriers,
GrLoadOp colorLoadOp) {
// DMSAA is not supported on DDL.
bool usesMSAASurface = writeView.asRenderTargetProxy()->numSamples() > 1;
this->prepareTessellator({context->priv().recordTimeAllocator(), writeView, usesMSAASurface,
&dstProxyView, renderPassXferBarriers, colorLoadOp,
context->priv().caps()},
(clip) ? std::move(*clip) : GrAppliedClip::Disabled());
SkASSERT(fTessellationProgram);
context->priv().recordProgramInfo(fTessellationProgram);
}
void PathTessellateOp::onPrepare(GrOpFlushState* flushState) {
if (!fTessellator) {
this->prepareTessellator({flushState->allocator(), flushState->writeView(),
flushState->usesMSAASurface(), &flushState->dstProxyView(),
flushState->renderPassBarriers(), flushState->colorLoadOp(),
&flushState->caps()}, flushState->detachAppliedClip());
SkASSERT(fTessellator);
}
auto tessShader = &fTessellationProgram->geomProc().cast<GrPathTessellationShader>();
fTessellator->prepare(flushState,
tessShader->maxTessellationSegments(*flushState->caps().shaderCaps()),
fShaderMatrix,
*fPathDrawList,
fTotalCombinedPathVerbCnt,
tessShader->willUseTessellationShaders());
}
void PathTessellateOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) {
SkASSERT(fTessellator);
SkASSERT(fTessellationProgram);
flushState->bindPipelineAndScissorClip(*fTessellationProgram, this->bounds());
flushState->bindTextures(fTessellationProgram->geomProc(), nullptr,
fTessellationProgram->pipeline());
fTessellator->draw(flushState, fTessellationProgram->geomProc().willUseTessellationShaders());
}
} // namespace skgpu::v1