/* * 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/ganesh/ops/AtlasInstancedHelper.h" #include "include/core/SkSize.h" #include "include/private/gpu/ganesh/GrTypesPriv.h" #include "src/core/SkSLTypeShared.h" #include "src/gpu/BufferWriter.h" #include "src/gpu/KeyBuilder.h" #include "src/gpu/ganesh/GrShaderVar.h" #include "src/gpu/ganesh/glsl/GrGLSLFragmentShaderBuilder.h" #include "src/gpu/ganesh/glsl/GrGLSLProgramDataManager.h" #include "src/gpu/ganesh/glsl/GrGLSLVarying.h" #include "src/gpu/ganesh/glsl/GrGLSLVertexGeoBuilder.h" using namespace skia_private; namespace skgpu::ganesh { void AtlasInstancedHelper::getKeyBits(KeyBuilder* b) const { b->addBits(kNumShaderFlags, (int)fShaderFlags, "atlasFlags"); } void AtlasInstancedHelper::appendInstanceAttribs( TArray* instanceAttribs) const { instanceAttribs->emplace_back("locations", kFloat4_GrVertexAttribType, SkSLType::kFloat4); if (fShaderFlags & ShaderFlags::kCheckBounds) { instanceAttribs->emplace_back("sizeInAtlas", kFloat2_GrVertexAttribType, SkSLType::kFloat2); } } void AtlasInstancedHelper::writeInstanceData(VertexWriter* instanceWriter, const Instance* i) const { SkASSERT(i->fLocationInAtlas.x() >= 0); SkASSERT(i->fLocationInAtlas.y() >= 0); *instanceWriter << // 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() << VertexWriter::If(fShaderFlags & ShaderFlags::kCheckBounds, SkSize::Make(i->fPathDevIBounds.size())); } void AtlasInstancedHelper::injectShaderCode( const GrGeometryProcessor::ProgramImpl::EmitArgs& args, const GrShaderVar& devCoord, GrGLSLUniformHandler::UniformHandle* atlasAdjustUniformHandle) const { GrGLSLVarying atlasCoord(SkSLType::kFloat2); args.fVaryingHandler->addVarying("atlasCoord", &atlasCoord); const char* atlasAdjustName; *atlasAdjustUniformHandle = args.fUniformHandler->addUniform( nullptr, kVertex_GrShaderFlag, SkSLType::kFloat2, "atlas_adjust", &atlasAdjustName); args.fVertBuilder->codeAppendf( // 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(SkSLType::kFloat4); 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( "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 AtlasInstancedHelper::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()); } } // namespace skgpu::ganesh