1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2017 Google Inc.
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#ifndef GrAtlasedShaderHelpers_DEFINED
9cb93a386Sopenharmony_ci#define GrAtlasedShaderHelpers_DEFINED
10cb93a386Sopenharmony_ci
11cb93a386Sopenharmony_ci#include "src/gpu/GrDrawOpAtlas.h"
12cb93a386Sopenharmony_ci#include "src/gpu/GrShaderCaps.h"
13cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
14cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLVarying.h"
15cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
16cb93a386Sopenharmony_ci
17cb93a386Sopenharmony_cistatic void append_index_uv_varyings(GrGeometryProcessor::ProgramImpl::EmitArgs& args,
18cb93a386Sopenharmony_ci                                     int numTextureSamplers,
19cb93a386Sopenharmony_ci                                     const char* inTexCoordsName,
20cb93a386Sopenharmony_ci                                     const char* atlasDimensionsInvName,
21cb93a386Sopenharmony_ci                                     GrGLSLVarying* uv,
22cb93a386Sopenharmony_ci                                     GrGLSLVarying* texIdx,
23cb93a386Sopenharmony_ci                                     GrGLSLVarying* st) {
24cb93a386Sopenharmony_ci    using Interpolation = GrGLSLVaryingHandler::Interpolation;
25cb93a386Sopenharmony_ci    // This extracts the texture index and texel coordinates from the same variable
26cb93a386Sopenharmony_ci    // Packing structure: texel coordinates have the 2-bit texture page encoded in bits 13 & 14 of
27cb93a386Sopenharmony_ci    // the x coordinate. It would be nice to use bits 14 and 15, but iphone6 has problem with those
28cb93a386Sopenharmony_ci    // bits when in gles. Iphone6 works fine with bits 14 and 15 in metal.
29cb93a386Sopenharmony_ci    if (args.fShaderCaps->integerSupport()) {
30cb93a386Sopenharmony_ci        if (numTextureSamplers <= 1) {
31cb93a386Sopenharmony_ci            args.fVertBuilder->codeAppendf(R"code(
32cb93a386Sopenharmony_ci                int texIdx = 0;
33cb93a386Sopenharmony_ci                float2 unormTexCoords = float2(%s.x, %s.y);
34cb93a386Sopenharmony_ci           )code", inTexCoordsName, inTexCoordsName);
35cb93a386Sopenharmony_ci        } else {
36cb93a386Sopenharmony_ci#ifdef SK_ENABLE_SMALL_PAGE
37cb93a386Sopenharmony_ci            args.fVertBuilder->codeAppendf(R"code(
38cb93a386Sopenharmony_ci                int2 coords = int2(%s.x, %s.y);
39cb93a386Sopenharmony_ci                int texIdx = ((coords.x >> 12) & 0xc) + ((coords.y >> 14) & 0x3);
40cb93a386Sopenharmony_ci                float2 unormTexCoords = float2(coords.x & 0x3FFF, coords.y & 0x3FFF);
41cb93a386Sopenharmony_ci            )code", inTexCoordsName, inTexCoordsName);
42cb93a386Sopenharmony_ci#else
43cb93a386Sopenharmony_ci            args.fVertBuilder->codeAppendf(R"code(
44cb93a386Sopenharmony_ci                int2 coords = int2(%s.x, %s.y);
45cb93a386Sopenharmony_ci                int texIdx = coords.x >> 13;
46cb93a386Sopenharmony_ci                float2 unormTexCoords = float2(coords.x & 0x1FFF, coords.y);
47cb93a386Sopenharmony_ci            )code", inTexCoordsName, inTexCoordsName);
48cb93a386Sopenharmony_ci#endif
49cb93a386Sopenharmony_ci        }
50cb93a386Sopenharmony_ci    } else {
51cb93a386Sopenharmony_ci        if (numTextureSamplers <= 1) {
52cb93a386Sopenharmony_ci            args.fVertBuilder->codeAppendf(R"code(
53cb93a386Sopenharmony_ci                float texIdx = 0;
54cb93a386Sopenharmony_ci                float2 unormTexCoords = float2(%s.x, %s.y);
55cb93a386Sopenharmony_ci            )code", inTexCoordsName, inTexCoordsName);
56cb93a386Sopenharmony_ci        } else {
57cb93a386Sopenharmony_ci#ifdef SK_ENABLE_SMALL_PAGE
58cb93a386Sopenharmony_ci             args.fVertBuilder->codeAppendf(R"code(
59cb93a386Sopenharmony_ci                float2 coord = float2(%s.x, %s.y);
60cb93a386Sopenharmony_ci                float diff0 = floor(coord.x * exp2(-14));
61cb93a386Sopenharmony_ci                float diff1 = floor(coord.y * exp2(-14));
62cb93a386Sopenharmony_ci                float texIdx = 4 * diff0 + diff1;
63cb93a386Sopenharmony_ci                float2 unormTexCoords = float2(coord.x - diff0, coord.y - diff1);
64cb93a386Sopenharmony_ci            )code", inTexCoordsName, inTexCoordsName);
65cb93a386Sopenharmony_ci#else
66cb93a386Sopenharmony_ci            args.fVertBuilder->codeAppendf(R"code(
67cb93a386Sopenharmony_ci                float2 coord = float2(%s.x, %s.y);
68cb93a386Sopenharmony_ci                float texIdx = floor(coord.x * exp2(-13));
69cb93a386Sopenharmony_ci                float2 unormTexCoords = float2(coord.x - texIdx * exp2(13), coord.y);
70cb93a386Sopenharmony_ci            )code", inTexCoordsName, inTexCoordsName);
71cb93a386Sopenharmony_ci#endif
72cb93a386Sopenharmony_ci        }
73cb93a386Sopenharmony_ci    }
74cb93a386Sopenharmony_ci
75cb93a386Sopenharmony_ci    // Multiply by 1/atlasDimensions to get normalized texture coordinates
76cb93a386Sopenharmony_ci    uv->reset(kFloat2_GrSLType);
77cb93a386Sopenharmony_ci    args.fVaryingHandler->addVarying("TextureCoords", uv);
78cb93a386Sopenharmony_ci    args.fVertBuilder->codeAppendf(
79cb93a386Sopenharmony_ci            "%s = unormTexCoords * %s;", uv->vsOut(), atlasDimensionsInvName);
80cb93a386Sopenharmony_ci
81cb93a386Sopenharmony_ci    // On ANGLE there is a significant cost to using an int varying. We don't know of any case where
82cb93a386Sopenharmony_ci    // it is worse to use a float so for now we always do.
83cb93a386Sopenharmony_ci    texIdx->reset(kFloat_GrSLType);
84cb93a386Sopenharmony_ci    // If we computed the local var "texIdx" as an int we will need to cast it to float
85cb93a386Sopenharmony_ci    const char* cast = args.fShaderCaps->integerSupport() ? "float" : "";
86cb93a386Sopenharmony_ci    args.fVaryingHandler->addVarying("TexIndex", texIdx, Interpolation::kCanBeFlat);
87cb93a386Sopenharmony_ci    args.fVertBuilder->codeAppendf("%s = %s(texIdx);", texIdx->vsOut(), cast);
88cb93a386Sopenharmony_ci
89cb93a386Sopenharmony_ci    if (st) {
90cb93a386Sopenharmony_ci        st->reset(kFloat2_GrSLType);
91cb93a386Sopenharmony_ci        args.fVaryingHandler->addVarying("IntTextureCoords", st);
92cb93a386Sopenharmony_ci        args.fVertBuilder->codeAppendf("%s = unormTexCoords;", st->vsOut());
93cb93a386Sopenharmony_ci    }
94cb93a386Sopenharmony_ci}
95cb93a386Sopenharmony_ci
96cb93a386Sopenharmony_cistatic void append_multitexture_lookup(GrGeometryProcessor::ProgramImpl::EmitArgs& args,
97cb93a386Sopenharmony_ci                                       int numTextureSamplers,
98cb93a386Sopenharmony_ci                                       const GrGLSLVarying& texIdx,
99cb93a386Sopenharmony_ci                                       const char* coordName,
100cb93a386Sopenharmony_ci                                       const char* colorName) {
101cb93a386Sopenharmony_ci    SkASSERT(numTextureSamplers > 0);
102cb93a386Sopenharmony_ci    // This shouldn't happen, but will avoid a crash if it does
103cb93a386Sopenharmony_ci    if (numTextureSamplers <= 0) {
104cb93a386Sopenharmony_ci        args.fFragBuilder->codeAppendf("%s = float4(1, 1, 1, 1);", colorName);
105cb93a386Sopenharmony_ci        return;
106cb93a386Sopenharmony_ci    }
107cb93a386Sopenharmony_ci
108cb93a386Sopenharmony_ci    // conditionally load from the indexed texture sampler
109cb93a386Sopenharmony_ci    for (int i = 0; i < numTextureSamplers-1; ++i) {
110cb93a386Sopenharmony_ci        args.fFragBuilder->codeAppendf("if (%s == %d) { %s = ", texIdx.fsIn(), i, colorName);
111cb93a386Sopenharmony_ci        args.fFragBuilder->appendTextureLookup(args.fTexSamplers[i], coordName);
112cb93a386Sopenharmony_ci        args.fFragBuilder->codeAppend("; } else ");
113cb93a386Sopenharmony_ci    }
114cb93a386Sopenharmony_ci    args.fFragBuilder->codeAppendf("{ %s = ", colorName);
115cb93a386Sopenharmony_ci    args.fFragBuilder->appendTextureLookup(args.fTexSamplers[numTextureSamplers - 1], coordName);
116cb93a386Sopenharmony_ci    args.fFragBuilder->codeAppend("; }");
117cb93a386Sopenharmony_ci}
118cb93a386Sopenharmony_ci
119cb93a386Sopenharmony_ci#endif
120