| /* |
| * Copyright 2020 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/ops/GrAtlasInstancedHelper.h" |
| |
| #include "src/gpu/GrVertexWriter.h" |
| #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h" |
| #include "src/gpu/glsl/GrGLSLVarying.h" |
| #include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h" |
| |
| void GrAtlasInstancedHelper::appendInstanceAttribs( |
| SkTArray<GrGeometryProcessor::Attribute>* instanceAttribs) const { |
| instanceAttribs->emplace_back("locations", kFloat4_GrVertexAttribType, kFloat4_GrSLType); |
| if (fShaderFlags & ShaderFlags::kCheckBounds) { |
| instanceAttribs->emplace_back("sizeInAtlas", kFloat2_GrVertexAttribType, kFloat2_GrSLType); |
| } |
| } |
| |
| void GrAtlasInstancedHelper::writeInstanceData(GrVertexWriter* instanceWriter, |
| const Instance* i) const { |
| SkASSERT(i->fLocationInAtlas.x() >= 0); |
| SkASSERT(i->fLocationInAtlas.y() >= 0); |
| instanceWriter->write( |
| // A negative x coordinate in the atlas indicates that the path is transposed. |
| // Also add 1 since we can't negate zero. |
| (float)(i->fTransposedInAtlas ? -i->fLocationInAtlas.x() - 1 |
| : i->fLocationInAtlas.x() + 1), |
| (float)i->fLocationInAtlas.y(), |
| (float)i->fPathDevIBounds.left(), |
| (float)i->fPathDevIBounds.top(), |
| GrVertexWriter::If(fShaderFlags & ShaderFlags::kCheckBounds, |
| SkSize::Make(i->fPathDevIBounds.size()))); |
| } |
| |
| void GrAtlasInstancedHelper::injectShaderCode( |
| const GrGLSLGeometryProcessor::EmitArgs& args, const GrShaderVar& devCoord, |
| GrGLSLUniformHandler::UniformHandle* atlasAdjustUniformHandle) const { |
| GrGLSLVarying atlasCoord(kFloat2_GrSLType); |
| args.fVaryingHandler->addVarying("atlasCoord", &atlasCoord); |
| |
| const char* atlasAdjustName; |
| *atlasAdjustUniformHandle = args.fUniformHandler->addUniform( |
| nullptr, kVertex_GrShaderFlag, kFloat2_GrSLType, "atlas_adjust", &atlasAdjustName); |
| |
| args.fVertBuilder->codeAppendf(R"( |
| // A negative x coordinate in the atlas indicates that the path is transposed. |
| // We also added 1 since we can't negate zero. |
| float2 atlasTopLeft = float2(abs(locations.x) - 1, locations.y); |
| float2 devTopLeft = locations.zw; |
| bool transposed = locations.x < 0; |
| float2 atlasCoord = %s - devTopLeft; |
| if (transposed) { |
| atlasCoord = atlasCoord.yx; |
| } |
| atlasCoord += atlasTopLeft; |
| %s = atlasCoord * %s;)", devCoord.c_str(), atlasCoord.vsOut(), atlasAdjustName); |
| |
| if (fShaderFlags & ShaderFlags::kCheckBounds) { |
| GrGLSLVarying atlasBounds(kFloat4_GrSLType); |
| args.fVaryingHandler->addVarying("atlasbounds", &atlasBounds, |
| GrGLSLVaryingHandler::Interpolation::kCanBeFlat); |
| args.fVertBuilder->codeAppendf(R"( |
| float4 atlasBounds = atlasTopLeft.xyxy + (transposed ? sizeInAtlas.00yx |
| : sizeInAtlas.00xy); |
| %s = atlasBounds * %s.xyxy;)", atlasBounds.vsOut(), atlasAdjustName); |
| |
| args.fFragBuilder->codeAppendf(R"( |
| half atlasCoverage = 0; |
| float2 atlasCoord = %s; |
| float4 atlasBounds = %s; |
| if (all(greaterThan(atlasCoord, atlasBounds.xy)) && |
| all(lessThan(atlasCoord, atlasBounds.zw))) { |
| atlasCoverage = )", atlasCoord.fsIn(), atlasBounds.fsIn()); |
| args.fFragBuilder->appendTextureLookup(args.fTexSamplers[0], "atlasCoord"); |
| args.fFragBuilder->codeAppendf(R"(.a; |
| })"); |
| } else { |
| args.fFragBuilder->codeAppendf("half atlasCoverage = "); |
| args.fFragBuilder->appendTextureLookup(args.fTexSamplers[0], atlasCoord.fsIn()); |
| args.fFragBuilder->codeAppendf(".a;"); |
| } |
| |
| if (fShaderFlags & ShaderFlags::kInvertCoverage) { |
| args.fFragBuilder->codeAppendf("%s *= (1 - atlasCoverage);", args.fOutputCoverage); |
| } else { |
| args.fFragBuilder->codeAppendf("%s *= atlasCoverage;", args.fOutputCoverage); |
| } |
| } |
| |
| void GrAtlasInstancedHelper::setUniformData( |
| const GrGLSLProgramDataManager& pdman, |
| const GrGLSLUniformHandler::UniformHandle& atlasAdjustUniformHandle) const { |
| SkASSERT(fAtlasProxy->isInstantiated()); |
| SkISize dimensions = fAtlasProxy->backingStoreDimensions(); |
| pdman.set2f(atlasAdjustUniformHandle, 1.f / dimensions.width(), 1.f / dimensions.height()); |
| } |