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