Extract a GrAtlasInstancedHelper subclass
This helper will allow other GPs that use instancing to also clip against an atlas. Bug: chromium:928984 Change-Id: I5a3bb221220bace46c6c9d799c2db68e2a2c67b7 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/425979 Commit-Queue: Chris Dalton <csmartdalton@google.com> Reviewed-by: Robert Phillips <robertphillips@google.com>
This commit is contained in:
parent
bdc412f149
commit
b1fd64e82e
@ -375,6 +375,8 @@ skia_gpu_sources = [
|
||||
"$_src/gpu/gradients/GrGradientShader.h",
|
||||
|
||||
# tessellate
|
||||
"$_src/gpu/tessellate/GrAtlasInstancedHelper.cpp",
|
||||
"$_src/gpu/tessellate/GrAtlasInstancedHelper.h",
|
||||
"$_src/gpu/tessellate/GrAtlasRenderTask.cpp",
|
||||
"$_src/gpu/tessellate/GrAtlasRenderTask.h",
|
||||
"$_src/gpu/tessellate/GrCullTest.h",
|
||||
|
100
src/gpu/tessellate/GrAtlasInstancedHelper.cpp
Normal file
100
src/gpu/tessellate/GrAtlasInstancedHelper.cpp
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright 2020 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/tessellate/GrAtlasInstancedHelper.h"
|
||||
|
||||
#include "src/gpu/GrVertexWriter.h"
|
||||
#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
|
||||
#include "src/gpu/glsl/GrGLSLVarying.h"
|
||||
#include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
|
||||
|
||||
void GrAtlasInstancedHelper::appendInstanceAttribs(
|
||||
SkTArray<GrGeometryProcessor::Attribute>* instanceAttribs) const {
|
||||
instanceAttribs->emplace_back("locations", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
|
||||
if (fShaderFlags & ShaderFlags::kCheckBounds) {
|
||||
instanceAttribs->emplace_back("sizeInAtlas", kFloat2_GrVertexAttribType, kFloat2_GrSLType);
|
||||
}
|
||||
}
|
||||
|
||||
void GrAtlasInstancedHelper::writeInstanceData(GrVertexWriter* instanceWriter,
|
||||
const Instance* i) const {
|
||||
SkASSERT(i->fLocationInAtlas.x() >= 0);
|
||||
SkASSERT(i->fLocationInAtlas.y() >= 0);
|
||||
instanceWriter->write(
|
||||
// A negative x coordinate in the atlas indicates that the path is transposed.
|
||||
// Also add 1 since we can't negate zero.
|
||||
(float)(i->fTransposedInAtlas ? -i->fLocationInAtlas.x() - 1
|
||||
: i->fLocationInAtlas.x() + 1),
|
||||
(float)i->fLocationInAtlas.y(),
|
||||
(float)i->fPathDevIBounds.left(),
|
||||
(float)i->fPathDevIBounds.top(),
|
||||
GrVertexWriter::If(fShaderFlags & ShaderFlags::kCheckBounds,
|
||||
SkSize::Make(i->fPathDevIBounds.size())));
|
||||
}
|
||||
|
||||
void GrAtlasInstancedHelper::injectShaderCode(
|
||||
const GrGLSLGeometryProcessor::EmitArgs& args, const GrShaderVar& devCoord,
|
||||
GrGLSLUniformHandler::UniformHandle* atlasAdjustUniformHandle) const {
|
||||
GrGLSLVarying atlasCoord(kFloat2_GrSLType);
|
||||
args.fVaryingHandler->addVarying("atlasCoord", &atlasCoord);
|
||||
|
||||
const char* atlasAdjustName;
|
||||
*atlasAdjustUniformHandle = args.fUniformHandler->addUniform(
|
||||
nullptr, kVertex_GrShaderFlag, kFloat2_GrSLType, "atlas_adjust", &atlasAdjustName);
|
||||
|
||||
args.fVertBuilder->codeAppendf(R"(
|
||||
// A negative x coordinate in the atlas indicates that the path is transposed.
|
||||
// We also added 1 since we can't negate zero.
|
||||
float2 atlasTopLeft = float2(abs(locations.x) - 1, locations.y);
|
||||
float2 devTopLeft = locations.zw;
|
||||
bool transposed = locations.x < 0;
|
||||
float2 atlasCoord = %s - devTopLeft;
|
||||
if (transposed) {
|
||||
atlasCoord = atlasCoord.yx;
|
||||
}
|
||||
atlasCoord += atlasTopLeft;
|
||||
%s = atlasCoord * %s;)", devCoord.c_str(), atlasCoord.vsOut(), atlasAdjustName);
|
||||
|
||||
if (fShaderFlags & ShaderFlags::kCheckBounds) {
|
||||
GrGLSLVarying atlasBounds(kFloat4_GrSLType);
|
||||
args.fVaryingHandler->addVarying("atlasbounds", &atlasBounds,
|
||||
GrGLSLVaryingHandler::Interpolation::kCanBeFlat);
|
||||
args.fVertBuilder->codeAppendf(R"(
|
||||
float4 atlasBounds = atlasTopLeft.xyxy + (transposed ? sizeInAtlas.00yx
|
||||
: sizeInAtlas.00xy);
|
||||
%s = atlasBounds * %s.xyxy;)", atlasBounds.vsOut(), atlasAdjustName);
|
||||
|
||||
args.fFragBuilder->codeAppendf(R"(
|
||||
half atlasCoverage = 0;
|
||||
float2 atlasCoord = %s;
|
||||
float4 atlasBounds = %s;
|
||||
if (all(greaterThan(atlasCoord, atlasBounds.xy)) &&
|
||||
all(lessThan(atlasCoord, atlasBounds.zw))) {
|
||||
atlasCoverage = )", atlasCoord.fsIn(), atlasBounds.fsIn());
|
||||
args.fFragBuilder->appendTextureLookup(args.fTexSamplers[0], "atlasCoord");
|
||||
args.fFragBuilder->codeAppendf(R"(.a;
|
||||
})");
|
||||
} else {
|
||||
args.fFragBuilder->codeAppendf("half atlasCoverage = ");
|
||||
args.fFragBuilder->appendTextureLookup(args.fTexSamplers[0], atlasCoord.fsIn());
|
||||
args.fFragBuilder->codeAppendf(".a;");
|
||||
}
|
||||
|
||||
if (fShaderFlags & ShaderFlags::kInvertCoverage) {
|
||||
args.fFragBuilder->codeAppendf("%s *= (1 - atlasCoverage);", args.fOutputCoverage);
|
||||
} else {
|
||||
args.fFragBuilder->codeAppendf("%s *= atlasCoverage;", args.fOutputCoverage);
|
||||
}
|
||||
}
|
||||
|
||||
void GrAtlasInstancedHelper::setUniformData(
|
||||
const GrGLSLProgramDataManager& pdman,
|
||||
const GrGLSLUniformHandler::UniformHandle& atlasAdjustUniformHandle) const {
|
||||
SkASSERT(fAtlasProxy->isInstantiated());
|
||||
SkISize dimensions = fAtlasProxy->backingStoreDimensions();
|
||||
pdman.set2f(atlasAdjustUniformHandle, 1.f / dimensions.width(), 1.f / dimensions.height());
|
||||
}
|
100
src/gpu/tessellate/GrAtlasInstancedHelper.h
Normal file
100
src/gpu/tessellate/GrAtlasInstancedHelper.h
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright 2021 Google LLC.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef GrGrAtlasInstancedHelper_DEFINED
|
||||
#define GrGrAtlasInstancedHelper_DEFINED
|
||||
|
||||
#include "src/core/SkIPoint16.h"
|
||||
#include "src/gpu/GrGeometryProcessor.h"
|
||||
#include "src/gpu/GrSurfaceProxyView.h"
|
||||
#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
|
||||
#include "src/gpu/glsl/GrGLSLUniformHandler.h"
|
||||
|
||||
struct GrVertexWriter;
|
||||
|
||||
// This class encapsulates all the necessary steps for an instanced GrGeometryProcessor to clip
|
||||
// against a path mask from an atlas.
|
||||
class GrAtlasInstancedHelper {
|
||||
public:
|
||||
enum class ShaderFlags {
|
||||
kNone = 0,
|
||||
kInvertCoverage = 1 << 0,
|
||||
kCheckBounds = 1 << 1
|
||||
};
|
||||
|
||||
GR_DECL_BITFIELD_CLASS_OPS_FRIENDS(ShaderFlags);
|
||||
|
||||
constexpr static int kNumShaderFlags = 2;
|
||||
|
||||
GrAtlasInstancedHelper(GrSurfaceProxyView atlasView, ShaderFlags shaderFlags)
|
||||
: fAtlasProxy(atlasView.detachProxy())
|
||||
, fAtlasSwizzle(atlasView.swizzle())
|
||||
, fShaderFlags(shaderFlags) {
|
||||
// Bottom left origin is not supported.
|
||||
SkASSERT(atlasView.origin() == kTopLeft_GrSurfaceOrigin);
|
||||
}
|
||||
|
||||
GrSurfaceProxy* proxy() const { return fAtlasProxy.get(); }
|
||||
const GrSwizzle& atlasSwizzle() const { return fAtlasSwizzle; }
|
||||
|
||||
// Returns whether the two helpers can be batched together in a single draw.
|
||||
bool isCompatible(const GrAtlasInstancedHelper& helper) {
|
||||
// TODO: We may want to consider two helpers compatible if they only differ in the
|
||||
// kCheckBounds flag -- we can always promote one to checking its bounds.
|
||||
SkASSERT(fAtlasProxy != helper.fAtlasProxy || fAtlasSwizzle == helper.fAtlasSwizzle);
|
||||
return fAtlasProxy == helper.fAtlasProxy && fShaderFlags == helper.fShaderFlags;
|
||||
}
|
||||
|
||||
// Adds bits to the shader key that uniquely identify this specific helper's shader code.
|
||||
void getKeyBits(GrProcessorKeyBuilder* b) const {
|
||||
b->addBits(kNumShaderFlags, (int)fShaderFlags, "atlasFlags");
|
||||
}
|
||||
|
||||
// Appends the instanced input attribs to the back of the array that we will need in order to
|
||||
// locate our path in the atlas.
|
||||
void appendInstanceAttribs(SkTArray<GrGeometryProcessor::Attribute>* instanceAttribs) const;
|
||||
|
||||
struct Instance {
|
||||
Instance(SkIPoint16 locationInAtlas, const SkIRect& pathDevIBounds, bool transposedInAtlas)
|
||||
: fLocationInAtlas(locationInAtlas)
|
||||
, fPathDevIBounds(pathDevIBounds)
|
||||
, fTransposedInAtlas(transposedInAtlas) {
|
||||
SkASSERT(fLocationInAtlas.x() >= 0);
|
||||
SkASSERT(fLocationInAtlas.y() >= 0);
|
||||
}
|
||||
SkIPoint16 fLocationInAtlas;
|
||||
SkIRect fPathDevIBounds;
|
||||
bool fTransposedInAtlas;
|
||||
};
|
||||
|
||||
// Writes out the given instance data, formatted for the specific attribs that we added during
|
||||
// appendInstanceAttribs().
|
||||
void writeInstanceData(GrVertexWriter* instanceWriter, const Instance*) const;
|
||||
|
||||
// Injects vertex code, fragment code, varyings, and uniforms to ultimately multiply
|
||||
// "args.fOutputCoverage" in the fragment shader by the atlas coverage.
|
||||
//
|
||||
// The caller is responsible to store "atlasAdjustUniformHandle" and pass it to
|
||||
// setUniformData().
|
||||
void injectShaderCode(const GrGLSLGeometryProcessor::EmitArgs&, const GrShaderVar& devCoord,
|
||||
GrGLSLUniformHandler::UniformHandle* atlasAdjustUniformHandle) const;
|
||||
|
||||
// The atlas clip requires one uniform value -- "atlasAdjustUniform". The caller should have
|
||||
// stored this handle after its call to injectShaderCode(). This method sets its value prior to
|
||||
// drawing.
|
||||
void setUniformData(const GrGLSLProgramDataManager&,
|
||||
const GrGLSLUniformHandler::UniformHandle& atlasAdjustUniformHandle) const;
|
||||
|
||||
private:
|
||||
const sk_sp<GrSurfaceProxy> fAtlasProxy;
|
||||
const GrSwizzle fAtlasSwizzle;
|
||||
const ShaderFlags fShaderFlags;
|
||||
};
|
||||
|
||||
GR_MAKE_BITFIELD_CLASS_OPS(GrAtlasInstancedHelper::ShaderFlags);
|
||||
|
||||
#endif
|
@ -12,7 +12,6 @@
|
||||
#include "src/gpu/GrProgramInfo.h"
|
||||
#include "src/gpu/GrResourceProvider.h"
|
||||
#include "src/gpu/GrVertexWriter.h"
|
||||
#include "src/gpu/GrVx.h"
|
||||
#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
|
||||
#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
|
||||
#include "src/gpu/glsl/GrGLSLVarying.h"
|
||||
@ -22,13 +21,13 @@ namespace {
|
||||
|
||||
class DrawAtlasPathShader : public GrGeometryProcessor {
|
||||
public:
|
||||
DrawAtlasPathShader(const GrTextureProxy* atlasProxy, GrSwizzle swizzle, bool isInverseFill,
|
||||
bool usesLocalCoords, const GrShaderCaps& shaderCaps)
|
||||
DrawAtlasPathShader(bool usesLocalCoords, const GrAtlasInstancedHelper* atlasHelper,
|
||||
const GrShaderCaps& shaderCaps)
|
||||
: GrGeometryProcessor(kDrawAtlasPathShader_ClassID)
|
||||
, fAtlasAccess(GrSamplerState::Filter::kNearest, atlasProxy->backendFormat(), swizzle)
|
||||
, fAtlasDimensions(atlasProxy->backingStoreDimensions())
|
||||
, fIsInverseFill(isInverseFill)
|
||||
, fUsesLocalCoords(usesLocalCoords) {
|
||||
, fUsesLocalCoords(usesLocalCoords)
|
||||
, fAtlasHelper(atlasHelper)
|
||||
, fAtlasAccess(GrSamplerState::Filter::kNearest, fAtlasHelper->proxy()->backendFormat(),
|
||||
fAtlasHelper->atlasSwizzle()) {
|
||||
if (!shaderCaps.vertexIDSupport()) {
|
||||
constexpr static Attribute kUnitCoordAttrib("unitCoord", kFloat2_GrVertexAttribType,
|
||||
kFloat2_GrSLType);
|
||||
@ -41,10 +40,8 @@ public:
|
||||
}
|
||||
SkASSERT(fAttribs.count() == this->colorAttribIdx());
|
||||
fAttribs.emplace_back("color", kFloat4_GrVertexAttribType, kHalf4_GrSLType);
|
||||
fAttribs.emplace_back("locations", kFloat4_GrVertexAttribType, kFloat4_GrSLType);
|
||||
if (fIsInverseFill) {
|
||||
fAttribs.emplace_back("sizeInAtlas", kFloat2_GrVertexAttribType, kFloat2_GrSLType);
|
||||
}
|
||||
fAtlasHelper->appendInstanceAttribs(&fAttribs);
|
||||
SkASSERT(fAttribs.count() <= kMaxInstanceAttribs);
|
||||
this->setInstanceAttributes(fAttribs.data(), fAttribs.count());
|
||||
this->setTextureSamplerCnt(1);
|
||||
}
|
||||
@ -53,16 +50,17 @@ private:
|
||||
int colorAttribIdx() const { return fUsesLocalCoords ? 3 : 1; }
|
||||
const char* name() const override { return "DrawAtlasPathShader"; }
|
||||
void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override {
|
||||
b->add32((fUsesLocalCoords << 1) | (int)fIsInverseFill);
|
||||
b->addBits(1, fUsesLocalCoords, "localCoords");
|
||||
fAtlasHelper->getKeyBits(b);
|
||||
}
|
||||
const TextureSampler& onTextureSampler(int) const override { return fAtlasAccess; }
|
||||
GrGLSLGeometryProcessor* createGLSLInstance(const GrShaderCaps&) const override;
|
||||
|
||||
const TextureSampler fAtlasAccess;
|
||||
const SkISize fAtlasDimensions;
|
||||
const bool fIsInverseFill;
|
||||
const bool fUsesLocalCoords;
|
||||
SkSTArray<6, GrGeometryProcessor::Attribute> fAttribs;
|
||||
const GrAtlasInstancedHelper* const fAtlasHelper;
|
||||
TextureSampler fAtlasAccess;
|
||||
constexpr static int kMaxInstanceAttribs = 6;
|
||||
SkSTArray<kMaxInstanceAttribs, GrGeometryProcessor::Attribute> fAttribs;
|
||||
|
||||
class Impl;
|
||||
};
|
||||
@ -72,13 +70,6 @@ class DrawAtlasPathShader::Impl : public GrGLSLGeometryProcessor {
|
||||
const auto& shader = args.fGeomProc.cast<DrawAtlasPathShader>();
|
||||
args.fVaryingHandler->emitAttributes(shader);
|
||||
|
||||
GrGLSLVarying atlasCoord(kFloat2_GrSLType);
|
||||
args.fVaryingHandler->addVarying("atlasCoord", &atlasCoord);
|
||||
|
||||
const char* atlasAdjust;
|
||||
fAtlasAdjustUniform = args.fUniformHandler->addUniform(
|
||||
nullptr, kVertex_GrShaderFlag, kFloat2_GrSLType, "atlas_adjust", &atlasAdjust);
|
||||
|
||||
if (args.fShaderCaps->vertexIDSupport()) {
|
||||
// If we don't have sk_VertexID support then "unitCoord" already came in as a vertex
|
||||
// attrib.
|
||||
@ -97,44 +88,8 @@ class DrawAtlasPathShader::Impl : public GrGLSLGeometryProcessor {
|
||||
gpArgs->fLocalCoordVar.set(kFloat2_GrSLType, "localCoord");
|
||||
}
|
||||
|
||||
args.fVertBuilder->codeAppendf(R"(
|
||||
// A negative x coordinate in the atlas indicates that the path is transposed.
|
||||
// We also added 1 since we can't negate zero.
|
||||
float2 atlasTopLeft = float2(abs(locations.x) - 1, locations.y);
|
||||
float2 devTopLeft = locations.zw;
|
||||
bool transposed = locations.x < 0;
|
||||
float2 atlasCoord = devCoord - devTopLeft;
|
||||
if (transposed) {
|
||||
atlasCoord = atlasCoord.yx;
|
||||
}
|
||||
atlasCoord += atlasTopLeft;
|
||||
%s = atlasCoord * %s;)", atlasCoord.vsOut(), atlasAdjust);
|
||||
|
||||
if (shader.fIsInverseFill) {
|
||||
GrGLSLVarying atlasBounds(kFloat4_GrSLType);
|
||||
args.fVaryingHandler->addVarying("atlasbounds", &atlasBounds,
|
||||
GrGLSLVaryingHandler::Interpolation::kCanBeFlat);
|
||||
args.fVertBuilder->codeAppendf(R"(
|
||||
float4 atlasBounds = atlasTopLeft.xyxy + (transposed ? sizeInAtlas.00yx
|
||||
: sizeInAtlas.00xy);
|
||||
%s = atlasBounds * %s.xyxy;)", atlasBounds.vsOut(), atlasAdjust);
|
||||
|
||||
args.fFragBuilder->codeAppendf(R"(
|
||||
half coverage = 0;
|
||||
float2 atlasCoord = %s;
|
||||
float4 atlasBounds = %s;
|
||||
if (all(greaterThan(atlasCoord, atlasBounds.xy)) &&
|
||||
all(lessThan(atlasCoord, atlasBounds.zw))) {
|
||||
coverage = )", atlasCoord.fsIn(), atlasBounds.fsIn());
|
||||
args.fFragBuilder->appendTextureLookup(args.fTexSamplers[0], "atlasCoord");
|
||||
args.fFragBuilder->codeAppendf(R"(.a;
|
||||
}
|
||||
half4 %s = half4(1 - coverage);)", args.fOutputCoverage);
|
||||
} else {
|
||||
args.fFragBuilder->codeAppendf("half4 %s = ", args.fOutputCoverage);
|
||||
args.fFragBuilder->appendTextureLookup(args.fTexSamplers[0], atlasCoord.fsIn());
|
||||
args.fFragBuilder->codeAppendf(".aaaa;");
|
||||
}
|
||||
args.fFragBuilder->codeAppendf("half4 %s = half4(1);", args.fOutputCoverage);
|
||||
shader.fAtlasHelper->injectShaderCode(args, gpArgs->fPositionVar, &fAtlasAdjustUniform);
|
||||
|
||||
args.fFragBuilder->codeAppendf("half4 %s;", args.fOutputColor);
|
||||
args.fVaryingHandler->addPassThroughAttribute(
|
||||
@ -145,8 +100,8 @@ class DrawAtlasPathShader::Impl : public GrGLSLGeometryProcessor {
|
||||
void setData(const GrGLSLProgramDataManager& pdman,
|
||||
const GrShaderCaps&,
|
||||
const GrGeometryProcessor& geomProc) override {
|
||||
const SkISize& dimensions = geomProc.cast<DrawAtlasPathShader>().fAtlasDimensions;
|
||||
pdman.set2f(fAtlasAdjustUniform, 1.f / dimensions.width(), 1.f / dimensions.height());
|
||||
auto* atlasHelper = geomProc.cast<DrawAtlasPathShader>().fAtlasHelper;
|
||||
atlasHelper->setUniformData(pdman, fAtlasAdjustUniform);
|
||||
}
|
||||
|
||||
GrGLSLUniformHandler::UniformHandle fAtlasAdjustUniform;
|
||||
@ -167,13 +122,12 @@ GrProcessorSet::Analysis GrDrawAtlasPathOp::finalize(const GrCaps& caps, const G
|
||||
return analysis;
|
||||
}
|
||||
|
||||
GrOp::CombineResult GrDrawAtlasPathOp::onCombineIfPossible(
|
||||
GrOp* op, SkArenaAlloc* alloc, const GrCaps&) {
|
||||
GrOp::CombineResult GrDrawAtlasPathOp::onCombineIfPossible(GrOp* op, SkArenaAlloc*, const GrCaps&) {
|
||||
auto* that = op->cast<GrDrawAtlasPathOp>();
|
||||
SkASSERT(fAtlasProxy == that->fAtlasProxy);
|
||||
SkASSERT(fEnableHWAA == that->fEnableHWAA);
|
||||
|
||||
if (fIsInverseFill != that->fIsInverseFill || fProcessors != that->fProcessors) {
|
||||
if (!fAtlasHelper.isCompatible(that->fAtlasHelper) ||
|
||||
fProcessors != that->fProcessors) {
|
||||
return CombineResult::kCannotCombine;
|
||||
}
|
||||
|
||||
@ -200,9 +154,8 @@ void GrDrawAtlasPathOp::prepareProgram(const GrCaps& caps, SkArenaAlloc* arena,
|
||||
initArgs.fWriteSwizzle = writeView.swizzle();
|
||||
auto pipeline = arena->make<GrPipeline>(initArgs, std::move(fProcessors),
|
||||
std::move(appliedClip));
|
||||
GrSwizzle swizzle = caps.getReadSwizzle(fAtlasProxy->backendFormat(), GrColorType::kAlpha_8);
|
||||
auto shader = arena->make<DrawAtlasPathShader>(fAtlasProxy.get(), swizzle, fIsInverseFill,
|
||||
fUsesLocalCoords, *caps.shaderCaps());
|
||||
auto shader = arena->make<DrawAtlasPathShader>(fUsesLocalCoords, &fAtlasHelper,
|
||||
*caps.shaderCaps());
|
||||
fProgram = arena->make<GrProgramInfo>(writeView, pipeline, &GrUserStencilSettings::kUnused,
|
||||
shader, GrPrimitiveType::kTriangleStrip, 0,
|
||||
renderPassXferBarriers, colorLoadOp);
|
||||
@ -233,23 +186,13 @@ void GrDrawAtlasPathOp::onPrepare(GrOpFlushState* flushState) {
|
||||
if (GrVertexWriter instanceWriter = flushState->makeVertexSpace(
|
||||
fProgram->geomProc().instanceStride(), fInstanceCount, &fInstanceBuffer,
|
||||
&fBaseInstance)) {
|
||||
for (const Instance* instance = fHeadInstance; instance; instance = instance->fNext) {
|
||||
SkASSERT(instance->fLocationInAtlas.x() >= 0);
|
||||
SkASSERT(instance->fLocationInAtlas.y() >= 0);
|
||||
for (const Instance* i = fHeadInstance; i; i = i->fNext) {
|
||||
instanceWriter.write(
|
||||
SkRect::Make(instance->fFillBounds),
|
||||
SkRect::Make(i->fFillBounds),
|
||||
GrVertexWriter::If(fUsesLocalCoords,
|
||||
instance->fLocalToDeviceIfUsingLocalCoords),
|
||||
instance->fColor,
|
||||
// A negative x coordinate in the atlas indicates that the path is transposed.
|
||||
// Also add 1 since we can't negate zero.
|
||||
(float)(instance->fTransposedInAtlas ? -instance->fLocationInAtlas.x() - 1
|
||||
: instance->fLocationInAtlas.x() + 1),
|
||||
(float)instance->fLocationInAtlas.y(),
|
||||
(float)instance->fPathDevIBounds.left(),
|
||||
(float)instance->fPathDevIBounds.top(),
|
||||
GrVertexWriter::If(fIsInverseFill,
|
||||
SkSize::Make(instance->fPathDevIBounds.size())));
|
||||
i->fLocalToDeviceIfUsingLocalCoords),
|
||||
i->fColor);
|
||||
fAtlasHelper.writeInstanceData(&instanceWriter, &i->fAtlasInstance);
|
||||
}
|
||||
}
|
||||
|
||||
@ -264,9 +207,8 @@ void GrDrawAtlasPathOp::onPrepare(GrOpFlushState* flushState) {
|
||||
}
|
||||
|
||||
void GrDrawAtlasPathOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) {
|
||||
SkASSERT(fAtlasProxy->isInstantiated());
|
||||
flushState->bindPipelineAndScissorClip(*fProgram, this->bounds());
|
||||
flushState->bindTextures(fProgram->geomProc(), *fAtlasProxy, fProgram->pipeline());
|
||||
flushState->bindTextures(fProgram->geomProc(), *fAtlasHelper.proxy(), fProgram->pipeline());
|
||||
flushState->bindBuffers(nullptr, std::move(fInstanceBuffer), fVertexBufferIfNoIDSupport);
|
||||
flushState->drawInstanced(fInstanceCount, fBaseInstance, 4, 0);
|
||||
}
|
||||
|
@ -10,24 +10,26 @@
|
||||
|
||||
#include "src/core/SkIPoint16.h"
|
||||
#include "src/gpu/ops/GrDrawOp.h"
|
||||
#include "src/gpu/tessellate/GrAtlasInstancedHelper.h"
|
||||
|
||||
// Fills a rectangle of pixels with a clip against coverage values from an atlas.
|
||||
class GrDrawAtlasPathOp : public GrDrawOp {
|
||||
public:
|
||||
DEFINE_OP_CLASS_ID
|
||||
|
||||
GrDrawAtlasPathOp(SkArenaAlloc* arena, const SkIRect& fillBounds,
|
||||
const SkMatrix& localToDevice, GrPaint&& paint,
|
||||
SkIPoint16 locationInAtlas, const SkIRect& pathDevIBounds,
|
||||
bool transposedInAtlas, sk_sp<GrTextureProxy> atlasProxy, bool isInverseFill,
|
||||
GrDrawAtlasPathOp(SkArenaAlloc* arena, const SkIRect& fillBounds, const SkMatrix& localToDevice,
|
||||
GrPaint&& paint, SkIPoint16 locationInAtlas, const SkIRect& pathDevIBounds,
|
||||
bool transposedInAtlas, GrSurfaceProxyView atlasView, bool isInverseFill,
|
||||
int numRenderTargetSamples)
|
||||
: GrDrawOp(ClassID())
|
||||
, fHeadInstance(arena->make<Instance>(fillBounds, localToDevice, paint.getColor4f(),
|
||||
locationInAtlas, pathDevIBounds,
|
||||
transposedInAtlas))
|
||||
, fTailInstance(&fHeadInstance->fNext)
|
||||
, fAtlasProxy(std::move(atlasProxy))
|
||||
, fIsInverseFill(isInverseFill)
|
||||
, fAtlasHelper(std::move(atlasView),
|
||||
isInverseFill ? GrAtlasInstancedHelper::ShaderFlags::kCheckBounds |
|
||||
GrAtlasInstancedHelper::ShaderFlags::kInvertCoverage
|
||||
: GrAtlasInstancedHelper::ShaderFlags::kNone)
|
||||
, fEnableHWAA(numRenderTargetSamples > 1)
|
||||
, fProcessors(std::move(paint)) {
|
||||
this->setBounds(SkRect::Make(fillBounds), HasAABloat::kYes, IsHairline::kNo);
|
||||
@ -38,7 +40,7 @@ public:
|
||||
return fEnableHWAA ? FixedFunctionFlags::kUsesHWAA : FixedFunctionFlags::kNone;
|
||||
}
|
||||
void visitProxies(const GrVisitProxyFunc& func) const override {
|
||||
func(fAtlasProxy.get(), GrMipmapped::kNo);
|
||||
func(fAtlasHelper.proxy(), GrMipmapped::kNo);
|
||||
fProcessors.visitProxies(func);
|
||||
}
|
||||
GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*, GrClampType) override;
|
||||
@ -63,26 +65,19 @@ private:
|
||||
m.getSkewX(), m.getScaleY(),
|
||||
m.getTranslateX(), m.getTranslateY()}
|
||||
, fColor(color)
|
||||
, fLocationInAtlas(locationInAtlas)
|
||||
, fPathDevIBounds(pathDevIBounds)
|
||||
, fTransposedInAtlas(transposedInAtlas) {
|
||||
SkASSERT(fLocationInAtlas.x() >= 0);
|
||||
SkASSERT(fLocationInAtlas.y() >= 0);
|
||||
, fAtlasInstance(locationInAtlas, pathDevIBounds, transposedInAtlas) {
|
||||
}
|
||||
SkIRect fFillBounds;
|
||||
std::array<float, 6> fLocalToDeviceIfUsingLocalCoords;
|
||||
SkPMColor4f fColor;
|
||||
SkIPoint16 fLocationInAtlas;
|
||||
SkIRect fPathDevIBounds;
|
||||
bool fTransposedInAtlas;
|
||||
GrAtlasInstancedHelper::Instance fAtlasInstance;
|
||||
Instance* fNext = nullptr;
|
||||
};
|
||||
|
||||
Instance* fHeadInstance;
|
||||
Instance** fTailInstance;
|
||||
|
||||
const sk_sp<GrTextureProxy> fAtlasProxy;
|
||||
const bool fIsInverseFill;
|
||||
GrAtlasInstancedHelper fAtlasHelper;
|
||||
const bool fEnableHWAA;
|
||||
bool fUsesLocalCoords = false;
|
||||
|
||||
|
@ -170,6 +170,7 @@ bool GrTessellationPathRenderer::onDrawPath(const DrawPathArgs& args) {
|
||||
if (this->tryAddPathToAtlas(args.fContext, *args.fViewMatrix, path, pathDevBounds,
|
||||
args.fAAType != GrAAType::kNone, &devIBounds, &locationInAtlas,
|
||||
&transposedInAtlas, visitProxiesUsedByDraw)) {
|
||||
const GrCaps& caps = *args.fSurfaceDrawContext->caps();
|
||||
const SkIRect& fillBounds = path.isInverseFillType()
|
||||
? (args.fClip
|
||||
? args.fClip->getConservativeBounds()
|
||||
@ -178,7 +179,7 @@ bool GrTessellationPathRenderer::onDrawPath(const DrawPathArgs& args) {
|
||||
auto op = GrOp::Make<GrDrawAtlasPathOp>(
|
||||
args.fContext, args.fSurfaceDrawContext->arenaAlloc(), fillBounds,
|
||||
*args.fViewMatrix, std::move(args.fPaint), locationInAtlas, devIBounds,
|
||||
transposedInAtlas, sk_ref_sp(fAtlasRenderTasks.back()->atlasProxy()),
|
||||
transposedInAtlas, fAtlasRenderTasks.back()->readView(caps),
|
||||
path.isInverseFillType(), surfaceDrawContext->numSamples());
|
||||
surfaceDrawContext->addDrawOp(args.fClip, std::move(op));
|
||||
return true;
|
||||
|
Loading…
Reference in New Issue
Block a user