blob: 8481b0827b384a6266932226a252ee6c2c278d52 [file] [log] [blame]
/*
* Copyright 2013 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "src/gpu/ganesh/effects/GrBezierEffect.h"
#include "include/core/SkColor.h"
#include "src/base/SkRandom.h"
#include "src/gpu/KeyBuilder.h"
#include "src/gpu/ganesh/GrColor.h"
#include "src/gpu/ganesh/GrShaderVar.h"
#include "src/gpu/ganesh/GrTestUtils.h"
#include "src/gpu/ganesh/glsl/GrGLSLFragmentShaderBuilder.h"
#include "src/gpu/ganesh/glsl/GrGLSLProgramDataManager.h"
#include "src/gpu/ganesh/glsl/GrGLSLUniformHandler.h"
#include "src/gpu/ganesh/glsl/GrGLSLVarying.h"
#include "src/gpu/ganesh/glsl/GrGLSLVertexGeoBuilder.h"
#include <iterator>
class GrConicEffect::Impl : public ProgramImpl {
public:
void setData(const GrGLSLProgramDataManager& pdman,
const GrShaderCaps& shaderCaps,
const GrGeometryProcessor& geomProc) override {
const GrConicEffect& ce = geomProc.cast<GrConicEffect>();
SetTransform(pdman, shaderCaps, fViewMatrixUniform, ce.fViewMatrix, &fViewMatrix);
SetTransform(pdman, shaderCaps, fLocalMatrixUniform, ce.fLocalMatrix, &fLocalMatrix);
if (fColor != ce.fColor) {
pdman.set4fv(fColorUniform, 1, ce.fColor.vec());
fColor = ce.fColor;
}
if (ce.fCoverageScale != 0xff && ce.fCoverageScale != fCoverageScale) {
pdman.set1f(fCoverageScaleUniform, GrNormalizeByteToFloat(ce.fCoverageScale));
fCoverageScale = ce.fCoverageScale;
}
}
private:
void onEmitCode(EmitArgs&, GrGPArgs*) override;
SkMatrix fViewMatrix = SkMatrix::InvalidMatrix();
SkMatrix fLocalMatrix = SkMatrix::InvalidMatrix();
SkPMColor4f fColor = SK_PMColor4fILLEGAL;
uint8_t fCoverageScale = 0xFF;
UniformHandle fColorUniform;
UniformHandle fCoverageScaleUniform;
UniformHandle fViewMatrixUniform;
UniformHandle fLocalMatrixUniform;
};
void GrConicEffect::Impl::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) {
GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
const GrConicEffect& gp = args.fGeomProc.cast<GrConicEffect>();
GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
// emit attributes
varyingHandler->emitAttributes(gp);
GrGLSLVarying v(SkSLType::kFloat4);
varyingHandler->addVarying("ConicCoeffs", &v);
vertBuilder->codeAppendf("%s = %s;", v.vsOut(), gp.inConicCoeffs().name());
GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
// Setup pass through color
fragBuilder->codeAppendf("half4 %s;", args.fOutputColor);
this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, &fColorUniform);
// Setup position
WriteOutputPosition(vertBuilder,
uniformHandler,
*args.fShaderCaps,
gpArgs,
gp.inPosition().name(),
gp.fViewMatrix,
&fViewMatrixUniform);
if (gp.fUsesLocalCoords) {
WriteLocalCoord(vertBuilder,
uniformHandler,
*args.fShaderCaps,
gpArgs,
gp.inPosition().asShaderVar(),
gp.fLocalMatrix,
&fLocalMatrixUniform);
}
// TODO: we should check on the number of bits float and half provide and use the smallest one
// that suffices. Additionally we should assert that the upstream code only lets us get here if
// either float or half provides the required number of bits.
GrShaderVar edgeAlpha("edgeAlpha", SkSLType::kHalf, 0);
GrShaderVar dklmdx("dklmdx", SkSLType::kFloat3, 0);
GrShaderVar dklmdy("dklmdy", SkSLType::kFloat3, 0);
GrShaderVar dfdx("dfdx", SkSLType::kFloat, 0);
GrShaderVar dfdy("dfdy", SkSLType::kFloat, 0);
GrShaderVar gF("gF", SkSLType::kFloat2, 0);
GrShaderVar gFM("gFM", SkSLType::kFloat, 0);
GrShaderVar func("func", SkSLType::kFloat, 0);
fragBuilder->declAppend(edgeAlpha);
fragBuilder->declAppend(dklmdx);
fragBuilder->declAppend(dklmdy);
fragBuilder->declAppend(dfdx);
fragBuilder->declAppend(dfdy);
fragBuilder->declAppend(gF);
fragBuilder->declAppend(gFM);
fragBuilder->declAppend(func);
fragBuilder->codeAppendf("%s = dFdx(%s.xyz);", dklmdx.c_str(), v.fsIn());
fragBuilder->codeAppendf("%s = dFdy(%s.xyz);", dklmdy.c_str(), v.fsIn());
fragBuilder->codeAppendf("%s = 2.0 * %s.x * %s.x - %s.y * %s.z - %s.z * %s.y;",
dfdx.c_str(),
v.fsIn(), dklmdx.c_str(),
v.fsIn(), dklmdx.c_str(),
v.fsIn(), dklmdx.c_str());
fragBuilder->codeAppendf("%s = 2.0 * %s.x * %s.x - %s.y * %s.z - %s.z * %s.y;",
dfdy.c_str(),
v.fsIn(), dklmdy.c_str(),
v.fsIn(), dklmdy.c_str(),
v.fsIn(), dklmdy.c_str());
fragBuilder->codeAppendf("%s = float2(%s, %s);", gF.c_str(), dfdx.c_str(),
dfdy.c_str());
fragBuilder->codeAppendf("%s = sqrt(dot(%s, %s));",
gFM.c_str(), gF.c_str(), gF.c_str());
fragBuilder->codeAppendf("%s = %s.x*%s.x - %s.y*%s.z;",
func.c_str(), v.fsIn(), v.fsIn(), v.fsIn(), v.fsIn());
fragBuilder->codeAppendf("%s = abs(%s);", func.c_str(), func.c_str());
fragBuilder->codeAppendf("%s = half(%s / %s);",
edgeAlpha.c_str(), func.c_str(), gFM.c_str());
fragBuilder->codeAppendf("%s = max(1.0 - %s, 0.0);",
edgeAlpha.c_str(), edgeAlpha.c_str());
// Add line below for smooth cubic ramp
// fragBuilder->codeAppend("edgeAlpha = edgeAlpha*edgeAlpha*(3.0-2.0*edgeAlpha);");
// TODO should we really be doing this?
if (gp.fCoverageScale != 0xff) {
const char* coverageScale;
fCoverageScaleUniform = uniformHandler->addUniform(nullptr,
kFragment_GrShaderFlag,
SkSLType::kFloat,
"Coverage",
&coverageScale);
fragBuilder->codeAppendf("half4 %s = half4(half(%s) * %s);",
args.fOutputCoverage, coverageScale, edgeAlpha.c_str());
} else {
fragBuilder->codeAppendf("half4 %s = half4(%s);", args.fOutputCoverage, edgeAlpha.c_str());
}
}
//////////////////////////////////////////////////////////////////////////////
GrConicEffect::~GrConicEffect() = default;
void GrConicEffect::addToKey(const GrShaderCaps& caps, skgpu::KeyBuilder* b) const {
uint32_t key = 0;
key |= fCoverageScale == 0xff ? 0x8 : 0x0;
key |= fUsesLocalCoords ? 0x10 : 0x0;
key = ProgramImpl::AddMatrixKeys(caps,
key,
fViewMatrix,
fUsesLocalCoords ? fLocalMatrix : SkMatrix::I());
b->add32(key);
}
std::unique_ptr<GrGeometryProcessor::ProgramImpl> GrConicEffect::makeProgramImpl(
const GrShaderCaps&) const {
return std::make_unique<Impl>();
}
GrConicEffect::GrConicEffect(const SkPMColor4f& color, const SkMatrix& viewMatrix, uint8_t coverage,
const SkMatrix& localMatrix, bool usesLocalCoords)
: INHERITED(kGrConicEffect_ClassID)
, fColor(color)
, fViewMatrix(viewMatrix)
, fLocalMatrix(viewMatrix)
, fUsesLocalCoords(usesLocalCoords)
, fCoverageScale(coverage) {
this->setVertexAttributesWithImplicitOffsets(kAttributes, std::size(kAttributes));
}
//////////////////////////////////////////////////////////////////////////////
GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrConicEffect)
#if defined(GR_TEST_UTILS)
GrGeometryProcessor* GrConicEffect::TestCreate(GrProcessorTestData* d) {
GrColor color = GrTest::RandomColor(d->fRandom);
SkMatrix viewMatrix = GrTest::TestMatrix(d->fRandom);
SkMatrix localMatrix = GrTest::TestMatrix(d->fRandom);
bool usesLocalCoords = d->fRandom->nextBool();
return GrConicEffect::Make(d->allocator(),
SkPMColor4f::FromBytes_RGBA(color),
viewMatrix,
*d->caps(),
localMatrix,
usesLocalCoords);
}
#endif
//////////////////////////////////////////////////////////////////////////////
// Quad
//////////////////////////////////////////////////////////////////////////////
class GrQuadEffect::Impl : public ProgramImpl {
public:
void setData(const GrGLSLProgramDataManager& pdman,
const GrShaderCaps& shaderCaps,
const GrGeometryProcessor& geomProc) override {
const GrQuadEffect& qe = geomProc.cast<GrQuadEffect>();
SetTransform(pdman, shaderCaps, fViewMatrixUniform, qe.fViewMatrix, &fViewMatrix);
SetTransform(pdman, shaderCaps, fLocalMatrixUniform, qe.fLocalMatrix, &fLocalMatrix);
if (qe.fColor != fColor) {
pdman.set4fv(fColorUniform, 1, qe.fColor.vec());
fColor = qe.fColor;
}
if (qe.fCoverageScale != 0xff && qe.fCoverageScale != fCoverageScale) {
pdman.set1f(fCoverageScaleUniform, GrNormalizeByteToFloat(qe.fCoverageScale));
fCoverageScale = qe.fCoverageScale;
}
}
private:
void onEmitCode(EmitArgs&, GrGPArgs*) override;
SkMatrix fViewMatrix = SkMatrix::InvalidMatrix();
SkMatrix fLocalMatrix = SkMatrix::InvalidMatrix();
SkPMColor4f fColor = SK_PMColor4fILLEGAL;
uint8_t fCoverageScale = 0xFF;
UniformHandle fColorUniform;
UniformHandle fCoverageScaleUniform;
UniformHandle fViewMatrixUniform;
UniformHandle fLocalMatrixUniform;
};
void GrQuadEffect::Impl::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) {
GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
const GrQuadEffect& gp = args.fGeomProc.cast<GrQuadEffect>();
GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
// emit attributes
varyingHandler->emitAttributes(gp);
GrGLSLVarying v(SkSLType::kHalf4);
varyingHandler->addVarying("HairQuadEdge", &v);
vertBuilder->codeAppendf("%s = %s;", v.vsOut(), gp.inHairQuadEdge().name());
GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
// Setup pass through color
fragBuilder->codeAppendf("half4 %s;", args.fOutputColor);
this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, &fColorUniform);
// Setup position
WriteOutputPosition(vertBuilder,
uniformHandler,
*args.fShaderCaps,
gpArgs,
gp.inPosition().name(),
gp.fViewMatrix,
&fViewMatrixUniform);
if (gp.fUsesLocalCoords) {
WriteLocalCoord(vertBuilder,
uniformHandler,
*args.fShaderCaps,
gpArgs,
gp.inPosition().asShaderVar(),
gp.fLocalMatrix,
&fLocalMatrixUniform);
}
fragBuilder->codeAppendf("half edgeAlpha;");
fragBuilder->codeAppendf("half2 duvdx = half2(dFdx(%s.xy));", v.fsIn());
fragBuilder->codeAppendf("half2 duvdy = half2(dFdy(%s.xy));", v.fsIn());
fragBuilder->codeAppendf("half2 gF = half2(2.0 * %s.x * duvdx.x - duvdx.y,"
" 2.0 * %s.x * duvdy.x - duvdy.y);",
v.fsIn(), v.fsIn());
fragBuilder->codeAppendf("edgeAlpha = half(%s.x * %s.x - %s.y);",
v.fsIn(), v.fsIn(), v.fsIn());
fragBuilder->codeAppend("edgeAlpha = sqrt(edgeAlpha * edgeAlpha / dot(gF, gF));");
fragBuilder->codeAppend("edgeAlpha = max(1.0 - edgeAlpha, 0.0);");
// Add line below for smooth cubic ramp
// fragBuilder->codeAppend("edgeAlpha = edgeAlpha*edgeAlpha*(3.0-2.0*edgeAlpha);");
if (gp.fCoverageScale != 0xFF) {
const char* coverageScale;
fCoverageScaleUniform = uniformHandler->addUniform(nullptr,
kFragment_GrShaderFlag,
SkSLType::kHalf,
"Coverage",
&coverageScale);
fragBuilder->codeAppendf("half4 %s = half4(%s * edgeAlpha);", args.fOutputCoverage,
coverageScale);
} else {
fragBuilder->codeAppendf("half4 %s = half4(edgeAlpha);", args.fOutputCoverage);
}
}
//////////////////////////////////////////////////////////////////////////////
GrQuadEffect::~GrQuadEffect() = default;
void GrQuadEffect::addToKey(const GrShaderCaps& caps, skgpu::KeyBuilder* b) const {
uint32_t key = 0;
key |= fCoverageScale != 0xff ? 0x8 : 0x0;
key |= fUsesLocalCoords ? 0x10 : 0x0;
key = ProgramImpl::AddMatrixKeys(caps,
key,
fViewMatrix,
fUsesLocalCoords ? fLocalMatrix : SkMatrix::I());
b->add32(key);
}
std::unique_ptr<GrGeometryProcessor::ProgramImpl> GrQuadEffect::makeProgramImpl(
const GrShaderCaps&) const {
return std::make_unique<Impl>();
}
GrQuadEffect::GrQuadEffect(const SkPMColor4f& color, const SkMatrix& viewMatrix, uint8_t coverage,
const SkMatrix& localMatrix, bool usesLocalCoords)
: INHERITED(kGrQuadEffect_ClassID)
, fColor(color)
, fViewMatrix(viewMatrix)
, fLocalMatrix(localMatrix)
, fUsesLocalCoords(usesLocalCoords)
, fCoverageScale(coverage) {
this->setVertexAttributesWithImplicitOffsets(kAttributes, std::size(kAttributes));
}
//////////////////////////////////////////////////////////////////////////////
GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrQuadEffect)
#if defined(GR_TEST_UTILS)
GrGeometryProcessor* GrQuadEffect::TestCreate(GrProcessorTestData* d) {
GrColor color = GrTest::RandomColor(d->fRandom);
SkMatrix viewMatrix = GrTest::TestMatrix(d->fRandom);
SkMatrix localMatrix = GrTest::TestMatrix(d->fRandom);
bool usesLocalCoords = d->fRandom->nextBool();
return GrQuadEffect::Make(d->allocator(),
SkPMColor4f::FromBytes_RGBA(color),
viewMatrix,
*d->caps(),
localMatrix,
usesLocalCoords);
}
#endif