1/*
2 * Copyright 2019 Google LLC.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "src/gpu/ccpr/GrSampleMaskProcessor.h"
9
10#include "src/gpu/GrOpsRenderPass.h"
11#include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
12
13class GrSampleMaskProcessor::Impl : public GrGLSLGeometryProcessor {
14public:
15 Impl(std::unique_ptr<Shader> shader) : fShader(std::move(shader)) {}
16
17private:
18 void setData(const GrGLSLProgramDataManager&, const GrPrimitiveProcessor&) override {}
19
20 void onEmitCode(EmitArgs&, GrGPArgs*) override;
21
22 const std::unique_ptr<Shader> fShader;
23};
24
25void GrSampleMaskProcessor::Impl::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) {
26 const GrSampleMaskProcessor& proc = args.fGP.cast<GrSampleMaskProcessor>();
27 GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
28 GrGLSLVertexBuilder* v = args.fVertBuilder;
29 int numInputPoints = proc.numInputPoints();
30 int inputWidth = (4 == numInputPoints || proc.hasInputWeight()) ? 4 : 3;
31
32 varyingHandler->emitAttributes(proc);
33 SkASSERT(!*args.fFPCoordTransformHandler);
34
35 if (PrimitiveType::kTriangles == proc.fPrimitiveType) {
36 SkASSERT(!proc.hasInstanceAttributes()); // Triangles are drawn with vertex arrays.
37 gpArgs->fPositionVar = proc.fInputAttribs.front().asShaderVar();
38 } else {
39 SkASSERT(!proc.hasVertexAttributes()); // Curves are drawn with instanced rendering.
40
41 // Shaders expect a global "bloat" variable when calculating gradients.
42 v->defineConstant("half", "bloat", ".5");
43
44 const char* swizzle = (4 == numInputPoints || proc.hasInputWeight()) ? "xyzw" : "xyz";
45 v->codeAppendf("float%ix2 pts = transpose(float2x%i(X.%s, Y.%s));",
46 inputWidth, inputWidth, swizzle, swizzle);
47
48 const char* hullPts = "pts";
49 fShader->emitSetupCode(v, "pts", &hullPts);
50 v->codeAppendf("float2 vertexpos = %s[sk_VertexID ^ (sk_VertexID >> 1)];", hullPts);
51 gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertexpos");
52
53 fShader->emitVaryings(varyingHandler, GrGLSLVarying::Scope::kVertToFrag,
54 &AccessCodeString(v), "vertexpos", nullptr, nullptr, nullptr);
55 }
56
57 // Fragment shader.
58 fShader->emitSampleMaskCode(args.fFragBuilder);
59}
60
61void GrSampleMaskProcessor::reset(PrimitiveType primitiveType, int subpassIdx,
62 GrResourceProvider* rp) {
63 SkASSERT(subpassIdx == 0);
64 fPrimitiveType = primitiveType; // This will affect the return values for numInputPoints, etc.
65 SkASSERT(PrimitiveType::kWeightedTriangles != fPrimitiveType);
66
67 this->resetCustomFeatures();
68 fInputAttribs.reset();
69
70 switch (fPrimitiveType) {
71 case PrimitiveType::kTriangles:
72 case PrimitiveType::kWeightedTriangles:
73 fInputAttribs.emplace_back("point", kFloat2_GrVertexAttribType, kFloat2_GrSLType);
74 this->setVertexAttributes(fInputAttribs.begin(), 1);
75 this->setInstanceAttributes(nullptr, 0);
76 break;
77 case PrimitiveType::kQuadratics:
78 case PrimitiveType::kCubics:
79 case PrimitiveType::kConics: {
80 auto instanceAttribType = (PrimitiveType::kQuadratics == fPrimitiveType)
81 ? kFloat3_GrVertexAttribType : kFloat4_GrVertexAttribType;
82 auto shaderVarType = (PrimitiveType::kQuadratics == fPrimitiveType)
83 ? kFloat3_GrSLType : kFloat4_GrSLType;
84 fInputAttribs.emplace_back("X", instanceAttribType, shaderVarType);
85 fInputAttribs.emplace_back("Y", instanceAttribType, shaderVarType);
86 this->setVertexAttributes(nullptr, 0);
87 this->setInstanceAttributes(fInputAttribs.begin(), fInputAttribs.count());
88 this->setWillUseCustomFeature(CustomFeatures::kSampleLocations);
89 break;
90 }
91 }
92}
93
94GrPrimitiveType GrSampleMaskProcessor::primType() const {
95 SkASSERT(PrimitiveType::kWeightedTriangles != fPrimitiveType);
96
97 switch (fPrimitiveType) {
98 case PrimitiveType::kTriangles:
99 case PrimitiveType::kWeightedTriangles:
100 return GrPrimitiveType::kTriangles;
101 case PrimitiveType::kQuadratics:
102 case PrimitiveType::kCubics:
103 case PrimitiveType::kConics:
104 return GrPrimitiveType::kTriangleStrip;
105 default:
106 return GrPrimitiveType::kTriangleStrip;
107 }
108}
109
110void GrSampleMaskProcessor::bindBuffers(GrOpsRenderPass* renderPass,
111 sk_sp<const GrBuffer> instanceBuffer) const {
112 SkASSERT(PrimitiveType::kWeightedTriangles != fPrimitiveType);
113
114 switch (fPrimitiveType) {
115 case PrimitiveType::kTriangles:
116 case PrimitiveType::kWeightedTriangles: {
117 renderPass->bindBuffers(nullptr, nullptr, std::move(instanceBuffer));
118 break;
119 }
120 case PrimitiveType::kQuadratics:
121 case PrimitiveType::kCubics:
122 case PrimitiveType::kConics: {
123 renderPass->bindBuffers(nullptr, std::move(instanceBuffer), nullptr);
124 break;
125 }
126 }
127}
128
129void GrSampleMaskProcessor::drawInstances(GrOpsRenderPass* renderPass, int instanceCount,
130 int baseInstance) const {
131 SkASSERT(PrimitiveType::kWeightedTriangles != fPrimitiveType);
132
133 switch (fPrimitiveType) {
134 case PrimitiveType::kTriangles:
135 case PrimitiveType::kWeightedTriangles: {
136 renderPass->draw(instanceCount * 3, baseInstance * 3);
137 break;
138 }
139 case PrimitiveType::kQuadratics:
140 case PrimitiveType::kCubics:
141 case PrimitiveType::kConics: {
142 renderPass->drawInstanced(instanceCount, baseInstance, 4, 0);
143 break;
144 }
145 }
146}
147
148GrGLSLPrimitiveProcessor* GrSampleMaskProcessor::onCreateGLSLInstance(
149 std::unique_ptr<Shader> shader) const {
150 return new Impl(std::move(shader));
151}
152