1 /*
2 * Copyright 2020 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/ganesh/ops/AtlasInstancedHelper.h"
9
10 #include "src/gpu/BufferWriter.h"
11 #include "src/gpu/KeyBuilder.h"
12 #include "src/gpu/ganesh/glsl/GrGLSLFragmentShaderBuilder.h"
13 #include "src/gpu/ganesh/glsl/GrGLSLVarying.h"
14 #include "src/gpu/ganesh/glsl/GrGLSLVertexGeoBuilder.h"
15
16 namespace skgpu::v1 {
17
getKeyBits(KeyBuilder * b) const18 void AtlasInstancedHelper::getKeyBits(KeyBuilder* b) const {
19 b->addBits(kNumShaderFlags, (int)fShaderFlags, "atlasFlags");
20 }
21
appendInstanceAttribs(SkTArray<GrGeometryProcessor::Attribute> * instanceAttribs) const22 void AtlasInstancedHelper::appendInstanceAttribs(
23 SkTArray<GrGeometryProcessor::Attribute>* instanceAttribs) const {
24 instanceAttribs->emplace_back("locations", kFloat4_GrVertexAttribType, SkSLType::kFloat4);
25 if (fShaderFlags & ShaderFlags::kCheckBounds) {
26 instanceAttribs->emplace_back("sizeInAtlas", kFloat2_GrVertexAttribType, SkSLType::kFloat2);
27 }
28 }
29
writeInstanceData(VertexWriter * instanceWriter,const Instance * i) const30 void AtlasInstancedHelper::writeInstanceData(VertexWriter* instanceWriter,
31 const Instance* i) const {
32 SkASSERT(i->fLocationInAtlas.x() >= 0);
33 SkASSERT(i->fLocationInAtlas.y() >= 0);
34 *instanceWriter <<
35 // A negative x coordinate in the atlas indicates that the path is transposed.
36 // Also add 1 since we can't negate zero.
37 ((float)(i->fTransposedInAtlas ? -i->fLocationInAtlas.x() - 1
38 : i->fLocationInAtlas.x() + 1)) <<
39 (float)i->fLocationInAtlas.y() <<
40 (float)i->fPathDevIBounds.left() <<
41 (float)i->fPathDevIBounds.top() <<
42 VertexWriter::If(fShaderFlags & ShaderFlags::kCheckBounds,
43 SkSize::Make(i->fPathDevIBounds.size()));
44 }
45
injectShaderCode(const GrGeometryProcessor::ProgramImpl::EmitArgs & args,const GrShaderVar & devCoord,GrGLSLUniformHandler::UniformHandle * atlasAdjustUniformHandle) const46 void AtlasInstancedHelper::injectShaderCode(
47 const GrGeometryProcessor::ProgramImpl::EmitArgs& args,
48 const GrShaderVar& devCoord,
49 GrGLSLUniformHandler::UniformHandle* atlasAdjustUniformHandle) const {
50 GrGLSLVarying atlasCoord(SkSLType::kFloat2);
51 args.fVaryingHandler->addVarying("atlasCoord", &atlasCoord);
52
53 const char* atlasAdjustName;
54 *atlasAdjustUniformHandle = args.fUniformHandler->addUniform(
55 nullptr, kVertex_GrShaderFlag, SkSLType::kFloat2, "atlas_adjust", &atlasAdjustName);
56
57 args.fVertBuilder->codeAppendf(
58 // A negative x coordinate in the atlas indicates that the path is transposed.
59 // We also added 1 since we can't negate zero.
60 "float2 atlasTopLeft = float2(abs(locations.x) - 1, locations.y);"
61 "float2 devTopLeft = locations.zw;"
62 "bool transposed = locations.x < 0;"
63 "float2 atlasCoord = %s - devTopLeft;"
64 "if (transposed) {"
65 "atlasCoord = atlasCoord.yx;"
66 "}"
67 "atlasCoord += atlasTopLeft;"
68 "%s = atlasCoord * %s;", devCoord.c_str(), atlasCoord.vsOut(), atlasAdjustName);
69
70 if (fShaderFlags & ShaderFlags::kCheckBounds) {
71 GrGLSLVarying atlasBounds(SkSLType::kFloat4);
72 args.fVaryingHandler->addVarying("atlasbounds", &atlasBounds,
73 GrGLSLVaryingHandler::Interpolation::kCanBeFlat);
74 args.fVertBuilder->codeAppendf(R"(
75 float4 atlasBounds = atlasTopLeft.xyxy + (transposed ? sizeInAtlas.00yx
76 : sizeInAtlas.00xy);
77 %s = atlasBounds * %s.xyxy;)", atlasBounds.vsOut(), atlasAdjustName);
78
79 args.fFragBuilder->codeAppendf(
80 "half atlasCoverage = 0;"
81 "float2 atlasCoord = %s;"
82 "float4 atlasBounds = %s;"
83 "if (all(greaterThan(atlasCoord, atlasBounds.xy)) &&"
84 "all(lessThan(atlasCoord, atlasBounds.zw))) {"
85 "atlasCoverage = ", atlasCoord.fsIn(), atlasBounds.fsIn());
86 args.fFragBuilder->appendTextureLookup(args.fTexSamplers[0], "atlasCoord");
87 args.fFragBuilder->codeAppendf(R"(.a;
88 })");
89 } else {
90 args.fFragBuilder->codeAppendf("half atlasCoverage = ");
91 args.fFragBuilder->appendTextureLookup(args.fTexSamplers[0], atlasCoord.fsIn());
92 args.fFragBuilder->codeAppendf(".a;");
93 }
94
95 if (fShaderFlags & ShaderFlags::kInvertCoverage) {
96 args.fFragBuilder->codeAppendf("%s *= (1 - atlasCoverage);", args.fOutputCoverage);
97 } else {
98 args.fFragBuilder->codeAppendf("%s *= atlasCoverage;", args.fOutputCoverage);
99 }
100 }
101
setUniformData(const GrGLSLProgramDataManager & pdman,const GrGLSLUniformHandler::UniformHandle & atlasAdjustUniformHandle) const102 void AtlasInstancedHelper::setUniformData(
103 const GrGLSLProgramDataManager& pdman,
104 const GrGLSLUniformHandler::UniformHandle& atlasAdjustUniformHandle) const {
105 SkASSERT(fAtlasProxy->isInstantiated());
106 SkISize dimensions = fAtlasProxy->backingStoreDimensions();
107 pdman.set2f(atlasAdjustUniformHandle, 1.f / dimensions.width(), 1.f / dimensions.height());
108 }
109
110 } // namespace skgpu::v1
111