Coverage Report

Created: 2021-08-22 09:07

/src/skia/src/gpu/glsl/GrGLSLShaderBuilder.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2014 Google Inc.
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/glsl/GrGLSLShaderBuilder.h"
9
10
#include "include/sksl/DSL.h"
11
#include "src/gpu/GrShaderCaps.h"
12
#include "src/gpu/GrShaderVar.h"
13
#include "src/gpu/GrSwizzle.h"
14
#include "src/gpu/glsl/GrGLSLBlend.h"
15
#include "src/gpu/glsl/GrGLSLColorSpaceXformHelper.h"
16
#include "src/gpu/glsl/GrGLSLProgramBuilder.h"
17
#include "src/sksl/dsl/priv/DSLWriter.h"
18
#include "src/sksl/ir/SkSLVarDeclarations.h"
19
20
GrGLSLShaderBuilder::GrGLSLShaderBuilder(GrGLSLProgramBuilder* program)
21
    : fProgramBuilder(program)
22
    , fInputs(GrGLSLProgramBuilder::kVarsPerBlock)
23
    , fOutputs(GrGLSLProgramBuilder::kVarsPerBlock)
24
    , fFeaturesAddedMask(0)
25
    , fCodeIndex(kCode)
26
    , fFinalized(false)
27
0
    , fTmpVariableCounter(0) {
28
    // We push back some placeholder pointers which will later become our header
29
0
    for (int i = 0; i <= kCode; i++) {
30
0
        fShaderStrings.push_back();
31
0
    }
32
33
0
    this->main() = "void main() {";
34
0
}
35
36
0
void GrGLSLShaderBuilder::declAppend(const GrShaderVar& var) {
37
0
    SkString tempDecl;
38
0
    var.appendDecl(fProgramBuilder->shaderCaps(), &tempDecl);
39
0
    this->codeAppendf("%s;", tempDecl.c_str());
40
0
}
41
42
0
void GrGLSLShaderBuilder::declareGlobal(const GrShaderVar& v) {
43
0
    v.appendDecl(this->getProgramBuilder()->shaderCaps(), &this->definitions());
44
0
    this->definitions().append(";");
45
0
}
46
47
0
SkString GrGLSLShaderBuilder::getMangledFunctionName(const char* baseName) {
48
0
    return fProgramBuilder->nameVariable(/*prefix=*/'\0', baseName);
49
0
}
50
51
void GrGLSLShaderBuilder::appendFunctionDecl(GrSLType returnType,
52
                                             const char* mangledName,
53
0
                                             SkSpan<const GrShaderVar> args) {
54
0
    this->functions().appendf("%s %s(", GrGLSLTypeString(returnType), mangledName);
55
0
    for (size_t i = 0; i < args.size(); ++i) {
56
0
        if (i > 0) {
57
0
            this->functions().append(", ");
58
0
        }
59
0
        args[i].appendDecl(fProgramBuilder->shaderCaps(), &this->functions());
60
0
    }
61
62
0
    this->functions().append(")");
63
0
}
64
65
void GrGLSLShaderBuilder::emitFunction(GrSLType returnType,
66
                                       const char* mangledName,
67
                                       SkSpan<const GrShaderVar> args,
68
0
                                       const char* body) {
69
0
    this->appendFunctionDecl(returnType, mangledName, args);
70
0
    this->functions().appendf(" {\n"
71
0
                              "%s"
72
0
                              "}\n\n", body);
73
0
}
74
75
0
void GrGLSLShaderBuilder::emitFunction(const char* declaration, const char* body) {
76
0
    this->functions().appendf("%s {\n"
77
0
                              "%s"
78
0
                              "}\n\n", declaration, body);
79
0
}
80
81
void GrGLSLShaderBuilder::emitFunctionPrototype(GrSLType returnType,
82
                                                const char* mangledName,
83
0
                                                SkSpan<const GrShaderVar> args) {
84
0
    this->appendFunctionDecl(returnType, mangledName, args);
85
0
    this->functions().append(";\n");
86
0
}
87
88
0
void GrGLSLShaderBuilder::codeAppend(std::unique_ptr<SkSL::Statement> stmt) {
89
0
    SkASSERT(SkSL::dsl::DSLWriter::CurrentProcessor());
90
0
    SkASSERT(stmt);
91
0
    this->codeAppend(stmt->description().c_str());
92
0
    if (stmt->is<SkSL::VarDeclaration>()) {
93
0
        fDeclarations.push_back(std::move(stmt));
94
0
    }
95
0
}
Unexecuted instantiation: GrGLSLShaderBuilder::codeAppend(std::__1::unique_ptr<SkSL::Statement, std::__1::default_delete<SkSL::Statement> >)
Unexecuted instantiation: GrGLSLShaderBuilder::codeAppend(std::__1::unique_ptr<SkSL::Statement, std::__1::default_delete<SkSL::Statement> >)
96
97
0
static inline void append_texture_swizzle(SkString* out, GrSwizzle swizzle) {
98
0
    if (swizzle != GrSwizzle::RGBA()) {
99
0
        out->appendf(".%s", swizzle.asString().c_str());
100
0
    }
101
0
}
102
103
void GrGLSLShaderBuilder::appendTextureLookup(SkString* out,
104
                                              SamplerHandle samplerHandle,
105
0
                                              const char* coordName) const {
106
0
    const char* sampler = fProgramBuilder->samplerVariable(samplerHandle);
107
0
    out->appendf("sample(%s, %s)", sampler, coordName);
108
0
    append_texture_swizzle(out, fProgramBuilder->samplerSwizzle(samplerHandle));
109
0
}
110
111
void GrGLSLShaderBuilder::appendTextureLookup(SamplerHandle samplerHandle,
112
                                              const char* coordName,
113
0
                                              GrGLSLColorSpaceXformHelper* colorXformHelper) {
114
0
    SkString lookup;
115
0
    this->appendTextureLookup(&lookup, samplerHandle, coordName);
116
0
    this->appendColorGamutXform(lookup.c_str(), colorXformHelper);
117
0
}
118
119
void GrGLSLShaderBuilder::appendTextureLookupAndBlend(
120
        const char* dst,
121
        SkBlendMode mode,
122
        SamplerHandle samplerHandle,
123
        const char* coordName,
124
0
        GrGLSLColorSpaceXformHelper* colorXformHelper) {
125
0
    if (!dst) {
126
0
        dst = "half4(1)";
127
0
    }
128
0
    SkString lookup;
129
    // This works around an issue in SwiftShader where the texture lookup is messed up
130
    // if we use blend_modulate instead of simply operator * on dst and the sampled result.
131
    // At this time it's unknown if the same problem exists for other modes.
132
0
    if (mode == SkBlendMode::kModulate) {
133
0
        this->codeAppend("(");
134
0
        this->appendTextureLookup(&lookup, samplerHandle, coordName);
135
0
        this->appendColorGamutXform(lookup.c_str(), colorXformHelper);
136
0
        this->codeAppendf(" * %s)", dst);
137
0
    } else {
138
0
        this->codeAppendf("%s(", GrGLSLBlend::BlendFuncName(mode));
139
0
        this->appendTextureLookup(&lookup, samplerHandle, coordName);
140
0
        this->appendColorGamutXform(lookup.c_str(), colorXformHelper);
141
0
        this->codeAppendf(", %s)", dst);
142
0
    }
143
0
}
144
145
0
void GrGLSLShaderBuilder::appendInputLoad(SamplerHandle samplerHandle) {
146
0
    const char* input = fProgramBuilder->inputSamplerVariable(samplerHandle);
147
0
    SkString load;
148
0
    load.appendf("subpassLoad(%s)", input);
149
0
    append_texture_swizzle(&load, fProgramBuilder->inputSamplerSwizzle(samplerHandle));
150
0
    this->codeAppend(load.c_str());
151
0
}
152
153
void GrGLSLShaderBuilder::appendColorGamutXform(SkString* out,
154
                                                const char* srcColor,
155
0
                                                GrGLSLColorSpaceXformHelper* colorXformHelper) {
156
0
    if (!colorXformHelper || colorXformHelper->isNoop()) {
157
0
        *out = srcColor;
158
0
        return;
159
0
    }
160
161
0
    GrGLSLUniformHandler* uniformHandler = fProgramBuilder->uniformHandler();
162
163
    // We define up to three helper functions, to keep things clearer. One for the source transfer
164
    // function, one for the (inverse) destination transfer function, and one for the gamut xform.
165
    // Any combination of these may be present, although some configurations are much more likely.
166
167
0
    auto emitTFFunc = [=](const char* name, GrGLSLProgramDataManager::UniformHandle uniform,
168
0
                          TFKind kind) {
169
0
        const GrShaderVar gTFArgs[] = { GrShaderVar("x", kHalf_GrSLType) };
170
0
        const char* coeffs = uniformHandler->getUniformCStr(uniform);
171
0
        SkString body;
172
        // Temporaries to make evaluation line readable. We always use the sRGBish names, so the
173
        // PQ and HLG math is confusing.
174
0
        body.appendf("half G = %s[0];", coeffs);
175
0
        body.appendf("half A = %s[1];", coeffs);
176
0
        body.appendf("half B = %s[2];", coeffs);
177
0
        body.appendf("half C = %s[3];", coeffs);
178
0
        body.appendf("half D = %s[4];", coeffs);
179
0
        body.appendf("half E = %s[5];", coeffs);
180
0
        body.appendf("half F = %s[6];", coeffs);
181
0
        body.append("half s = sign(x);");
182
0
        body.append("x = abs(x);");
183
0
        switch (kind) {
184
0
            case TFKind::sRGBish_TF:
185
0
                body.append("x = (x < D) ? (C * x) + F : pow(A * x + B, G) + E;");
186
0
                break;
187
0
            case TFKind::PQish_TF:
188
0
                body.append("x = pow(max(A + B * pow(x, C), 0) / (D + E * pow(x, C)), F);");
189
0
                break;
190
0
            case TFKind::HLGish_TF:
191
0
                body.append("x = (x*A <= 1) ? pow(x*A, B) : exp((x-E)*C) + D; x *= (F+1);");
192
0
                break;
193
0
            case TFKind::HLGinvish_TF:
194
0
                body.append("x /= (F+1); x = (x <= 1) ? A * pow(x, B) : C * log(x - D) + E;");
195
0
                break;
196
0
            default:
197
0
                SkASSERT(false);
198
0
                break;
199
0
        }
200
0
        body.append("return s * x;");
201
0
        SkString funcName = this->getMangledFunctionName(name);
202
0
        this->emitFunction(kHalf_GrSLType, funcName.c_str(), {gTFArgs, SK_ARRAY_COUNT(gTFArgs)},
203
0
                           body.c_str());
204
0
        return funcName;
205
0
    };
Unexecuted instantiation: GrGLSLShaderBuilder.cpp:GrGLSLShaderBuilder::appendColorGamutXform(SkString*, char const*, GrGLSLColorSpaceXformHelper*)::$_0::operator()(char const*, GrResourceHandle<GrGLSLProgramDataManager::UniformHandleKind>, TFKind) const
Unexecuted instantiation: GrGLSLShaderBuilder.cpp:GrGLSLShaderBuilder::appendColorGamutXform(SkString*, char const*, GrGLSLColorSpaceXformHelper*)::$_2::operator()(char const*, GrResourceHandle<GrGLSLProgramDataManager::UniformHandleKind>, TFKind) const
206
207
0
    SkString srcTFFuncName;
208
0
    if (colorXformHelper->applySrcTF()) {
209
0
        srcTFFuncName = emitTFFunc("src_tf", colorXformHelper->srcTFUniform(),
210
0
                                   colorXformHelper->srcTFKind());
211
0
    }
212
213
0
    SkString dstTFFuncName;
214
0
    if (colorXformHelper->applyDstTF()) {
215
0
        dstTFFuncName = emitTFFunc("dst_tf", colorXformHelper->dstTFUniform(),
216
0
                                   colorXformHelper->dstTFKind());
217
0
    }
218
219
0
    SkString gamutXformFuncName;
220
0
    if (colorXformHelper->applyGamutXform()) {
221
0
        const GrShaderVar gGamutXformArgs[] = { GrShaderVar("color", kHalf4_GrSLType) };
222
0
        const char* xform = uniformHandler->getUniformCStr(colorXformHelper->gamutXformUniform());
223
0
        SkString body;
224
0
        body.appendf("color.rgb = (%s * color.rgb);", xform);
225
0
        body.append("return color;");
226
0
        gamutXformFuncName = this->getMangledFunctionName("gamut_xform");
227
0
        this->emitFunction(kHalf4_GrSLType, gamutXformFuncName.c_str(),
228
0
                           {gGamutXformArgs, SK_ARRAY_COUNT(gGamutXformArgs)}, body.c_str());
229
0
    }
230
231
    // Now define a wrapper function that applies all the intermediate steps
232
0
    {
233
        // Some GPUs require full float to get results that are as accurate as expected/required.
234
        // Most GPUs work just fine with half float. Strangely, the GPUs that have this bug
235
        // (Mali G series) only require us to promote the type of a few temporaries here --
236
        // the helper functions above can always be written to use half.
237
0
        bool useFloat = fProgramBuilder->shaderCaps()->colorSpaceMathNeedsFloat();
238
239
0
        const GrShaderVar gColorXformArgs[] = {
240
0
                GrShaderVar("color", useFloat ? kFloat4_GrSLType : kHalf4_GrSLType)};
241
0
        SkString body;
242
0
        if (colorXformHelper->applyUnpremul()) {
243
0
            body.append("color = unpremul(color);");
244
0
        }
245
0
        if (colorXformHelper->applySrcTF()) {
246
0
            body.appendf("color.r = %s(half(color.r));", srcTFFuncName.c_str());
247
0
            body.appendf("color.g = %s(half(color.g));", srcTFFuncName.c_str());
248
0
            body.appendf("color.b = %s(half(color.b));", srcTFFuncName.c_str());
249
0
        }
250
0
        if (colorXformHelper->applyGamutXform()) {
251
0
            body.appendf("color = %s(half4(color));", gamutXformFuncName.c_str());
252
0
        }
253
0
        if (colorXformHelper->applyDstTF()) {
254
0
            body.appendf("color.r = %s(half(color.r));", dstTFFuncName.c_str());
255
0
            body.appendf("color.g = %s(half(color.g));", dstTFFuncName.c_str());
256
0
            body.appendf("color.b = %s(half(color.b));", dstTFFuncName.c_str());
257
0
        }
258
0
        if (colorXformHelper->applyPremul()) {
259
0
            body.append("color.rgb *= color.a;");
260
0
        }
261
0
        body.append("return half4(color);");
262
0
        SkString colorXformFuncName = this->getMangledFunctionName("color_xform");
263
0
        this->emitFunction(kHalf4_GrSLType, colorXformFuncName.c_str(),
264
0
                           {gColorXformArgs, SK_ARRAY_COUNT(gColorXformArgs)}, body.c_str());
265
0
        out->appendf("%s(%s)", colorXformFuncName.c_str(), srcColor);
266
0
    }
267
0
}
268
269
void GrGLSLShaderBuilder::appendColorGamutXform(const char* srcColor,
270
0
                                                GrGLSLColorSpaceXformHelper* colorXformHelper) {
271
0
    SkString xform;
272
0
    this->appendColorGamutXform(&xform, srcColor, colorXformHelper);
273
0
    this->codeAppend(xform.c_str());
274
0
}
275
276
0
bool GrGLSLShaderBuilder::addFeature(uint32_t featureBit, const char* extensionName) {
277
0
    if (featureBit & fFeaturesAddedMask) {
278
0
        return false;
279
0
    }
280
0
    this->extensions().appendf("#extension %s: require\n", extensionName);
281
0
    fFeaturesAddedMask |= featureBit;
282
0
    return true;
283
0
}
284
285
0
void GrGLSLShaderBuilder::appendDecls(const VarArray& vars, SkString* out) const {
286
0
    for (const auto& v : vars.items()) {
287
0
        v.appendDecl(fProgramBuilder->shaderCaps(), out);
288
0
        out->append(";\n");
289
0
    }
290
0
}
291
292
0
void GrGLSLShaderBuilder::addLayoutQualifier(const char* param, InterfaceQualifier interface) {
293
0
    SkASSERT(fProgramBuilder->shaderCaps()->generation() >= k330_GrGLSLGeneration ||
294
0
             fProgramBuilder->shaderCaps()->mustEnableAdvBlendEqs());
295
0
    fLayoutParams[interface].push_back() = param;
296
0
}
Unexecuted instantiation: GrGLSLShaderBuilder::addLayoutQualifier(char const*, GrGLSLShaderBuilder::InterfaceQualifier)
Unexecuted instantiation: GrGLSLShaderBuilder::addLayoutQualifier(char const*, GrGLSLShaderBuilder::InterfaceQualifier)
297
298
0
void GrGLSLShaderBuilder::compileAndAppendLayoutQualifiers() {
299
0
    static const char* interfaceQualifierNames[] = {
300
0
        "in",
301
0
        "out"
302
0
    };
303
304
0
    for (int interface = 0; interface <= kLastInterfaceQualifier; ++interface) {
305
0
        const SkTArray<SkString>& params = fLayoutParams[interface];
306
0
        if (params.empty()) {
307
0
            continue;
308
0
        }
309
0
        this->layoutQualifiers().appendf("layout(%s", params[0].c_str());
310
0
        for (int i = 1; i < params.count(); ++i) {
311
0
            this->layoutQualifiers().appendf(", %s", params[i].c_str());
312
0
        }
313
0
        this->layoutQualifiers().appendf(") %s;\n", interfaceQualifierNames[interface]);
314
0
    }
315
316
0
    static_assert(0 == GrGLSLShaderBuilder::kIn_InterfaceQualifier);
317
0
    static_assert(1 == GrGLSLShaderBuilder::kOut_InterfaceQualifier);
318
0
    static_assert(SK_ARRAY_COUNT(interfaceQualifierNames) == kLastInterfaceQualifier + 1);
319
0
}
320
321
0
void GrGLSLShaderBuilder::finalize(uint32_t visibility) {
322
0
    SkASSERT(!fFinalized);
323
0
    this->compileAndAppendLayoutQualifiers();
324
0
    SkASSERT(visibility);
325
0
    fProgramBuilder->appendUniformDecls((GrShaderFlags) visibility, &this->uniforms());
326
0
    this->appendDecls(fInputs, &this->inputs());
327
0
    this->appendDecls(fOutputs, &this->outputs());
328
0
    this->onFinalize();
329
    // append the 'footer' to code
330
0
    this->code().append("}");
331
332
0
    for (int i = 0; i <= fCodeIndex; i++) {
333
0
        fCompilerString.append(fShaderStrings[i].c_str(), fShaderStrings[i].size());
334
0
    }
335
336
0
    fFinalized = true;
337
0
}
Unexecuted instantiation: GrGLSLShaderBuilder::finalize(unsigned int)
Unexecuted instantiation: GrGLSLShaderBuilder::finalize(unsigned int)