blob: 01613aeba1efdeb86205d3f3918d238128d4fb52 [file] [log] [blame]
/*
* Copyright 2019 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/ccpr/GrSampleMaskProcessor.h"
#include "src/gpu/GrOpsRenderPass.h"
#include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
class GrSampleMaskProcessor::Impl : public GrGLSLGeometryProcessor {
public:
Impl(std::unique_ptr<Shader> shader) : fShader(std::move(shader)) {}
private:
void setData(const GrGLSLProgramDataManager&, const GrPrimitiveProcessor&) override {}
void onEmitCode(EmitArgs&, GrGPArgs*) override;
const std::unique_ptr<Shader> fShader;
};
void GrSampleMaskProcessor::Impl::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) {
const GrSampleMaskProcessor& proc = args.fGP.cast<GrSampleMaskProcessor>();
GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
GrGLSLVertexBuilder* v = args.fVertBuilder;
int numInputPoints = proc.numInputPoints();
int inputWidth = (4 == numInputPoints || proc.hasInputWeight()) ? 4 : 3;
varyingHandler->emitAttributes(proc);
SkASSERT(!*args.fFPCoordTransformHandler);
if (PrimitiveType::kTriangles == proc.fPrimitiveType) {
SkASSERT(!proc.hasInstanceAttributes()); // Triangles are drawn with vertex arrays.
gpArgs->fPositionVar = proc.fInputAttribs.front().asShaderVar();
} else {
SkASSERT(!proc.hasVertexAttributes()); // Curves are drawn with instanced rendering.
// Shaders expect a global "bloat" variable when calculating gradients.
v->defineConstant("half", "bloat", ".5");
const char* swizzle = (4 == numInputPoints || proc.hasInputWeight()) ? "xyzw" : "xyz";
v->codeAppendf("float%ix2 pts = transpose(float2x%i(X.%s, Y.%s));",
inputWidth, inputWidth, swizzle, swizzle);
const char* hullPts = "pts";
fShader->emitSetupCode(v, "pts", &hullPts);
v->codeAppendf("float2 vertexpos = %s[sk_VertexID ^ (sk_VertexID >> 1)];", hullPts);
gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertexpos");
fShader->emitVaryings(varyingHandler, GrGLSLVarying::Scope::kVertToFrag,
&AccessCodeString(v), "vertexpos", nullptr, nullptr, nullptr);
}
// Fragment shader.
fShader->emitSampleMaskCode(args.fFragBuilder);
}
void GrSampleMaskProcessor::reset(PrimitiveType primitiveType, int subpassIdx,
GrResourceProvider* rp) {
SkASSERT(subpassIdx == 0);
fPrimitiveType = primitiveType; // This will affect the return values for numInputPoints, etc.
SkASSERT(PrimitiveType::kWeightedTriangles != fPrimitiveType);
this->resetCustomFeatures();
fInputAttribs.reset();
switch (fPrimitiveType) {
case PrimitiveType::kTriangles:
case PrimitiveType::kWeightedTriangles:
fInputAttribs.emplace_back("point", kFloat2_GrVertexAttribType, kFloat2_GrSLType);
this->setVertexAttributes(fInputAttribs.begin(), 1);
this->setInstanceAttributes(nullptr, 0);
break;
case PrimitiveType::kQuadratics:
case PrimitiveType::kCubics:
case PrimitiveType::kConics: {
auto instanceAttribType = (PrimitiveType::kQuadratics == fPrimitiveType)
? kFloat3_GrVertexAttribType : kFloat4_GrVertexAttribType;
auto shaderVarType = (PrimitiveType::kQuadratics == fPrimitiveType)
? kFloat3_GrSLType : kFloat4_GrSLType;
fInputAttribs.emplace_back("X", instanceAttribType, shaderVarType);
fInputAttribs.emplace_back("Y", instanceAttribType, shaderVarType);
this->setVertexAttributes(nullptr, 0);
this->setInstanceAttributes(fInputAttribs.begin(), fInputAttribs.count());
this->setWillUseCustomFeature(CustomFeatures::kSampleLocations);
break;
}
}
}
GrPrimitiveType GrSampleMaskProcessor::primType() const {
SkASSERT(PrimitiveType::kWeightedTriangles != fPrimitiveType);
switch (fPrimitiveType) {
case PrimitiveType::kTriangles:
case PrimitiveType::kWeightedTriangles:
return GrPrimitiveType::kTriangles;
case PrimitiveType::kQuadratics:
case PrimitiveType::kCubics:
case PrimitiveType::kConics:
return GrPrimitiveType::kTriangleStrip;
default:
return GrPrimitiveType::kTriangleStrip;
}
}
void GrSampleMaskProcessor::bindBuffers(GrOpsRenderPass* renderPass,
sk_sp<const GrBuffer> instanceBuffer) const {
SkASSERT(PrimitiveType::kWeightedTriangles != fPrimitiveType);
switch (fPrimitiveType) {
case PrimitiveType::kTriangles:
case PrimitiveType::kWeightedTriangles: {
renderPass->bindBuffers(nullptr, nullptr, std::move(instanceBuffer));
break;
}
case PrimitiveType::kQuadratics:
case PrimitiveType::kCubics:
case PrimitiveType::kConics: {
renderPass->bindBuffers(nullptr, std::move(instanceBuffer), nullptr);
break;
}
}
}
void GrSampleMaskProcessor::drawInstances(GrOpsRenderPass* renderPass, int instanceCount,
int baseInstance) const {
SkASSERT(PrimitiveType::kWeightedTriangles != fPrimitiveType);
switch (fPrimitiveType) {
case PrimitiveType::kTriangles:
case PrimitiveType::kWeightedTriangles: {
renderPass->draw(instanceCount * 3, baseInstance * 3);
break;
}
case PrimitiveType::kQuadratics:
case PrimitiveType::kCubics:
case PrimitiveType::kConics: {
renderPass->drawInstanced(instanceCount, baseInstance, 4, 0);
break;
}
}
}
GrGLSLPrimitiveProcessor* GrSampleMaskProcessor::onCreateGLSLInstance(
std::unique_ptr<Shader> shader) const {
return new Impl(std::move(shader));
}