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