Coverage Report

Created: 2024-09-14 07:19

/src/skia/src/sksl/transform/SkSLFindAndDeclareBuiltinFunctions.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2022 Google LLC
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 "include/core/SkTypes.h"
9
#include "src/core/SkTHash.h"
10
#include "src/sksl/SkSLContext.h"
11
#include "src/sksl/SkSLIntrinsicList.h"
12
#include "src/sksl/SkSLProgramSettings.h"
13
#include "src/sksl/analysis/SkSLProgramUsage.h"
14
#include "src/sksl/ir/SkSLFunctionDeclaration.h"
15
#include "src/sksl/ir/SkSLFunctionDefinition.h"
16
#include "src/sksl/ir/SkSLProgram.h"
17
#include "src/sksl/ir/SkSLSymbol.h"
18
#include "src/sksl/transform/SkSLTransform.h"
19
20
#include <algorithm>
21
#include <cstddef>
22
#include <memory>
23
#include <string>
24
#include <string_view>
25
#include <vector>
26
27
namespace SkSL {
28
29
class ProgramElement;
30
31
340
void Transform::FindAndDeclareBuiltinFunctions(Program& program) {
32
340
    ProgramUsage* usage = program.fUsage.get();
33
340
    Context& context = *program.fContext;
34
35
340
    std::vector<const FunctionDefinition*> addedBuiltins;
36
401
    for (;;) {
37
        // Find all the built-ins referenced by the program but not yet included in the code.
38
401
        size_t numBuiltinsAtStart = addedBuiltins.size();
39
418
        for (const auto& [symbol, count] : usage->fCallCounts) {
40
418
            const FunctionDeclaration& fn = symbol->as<FunctionDeclaration>();
41
418
            if (!fn.isBuiltin() || count == 0) {
42
                // Not a built-in; skip it.
43
42
                continue;
44
42
            }
45
376
            if (fn.intrinsicKind() == k_dFdy_IntrinsicKind) {
46
                // Programs that invoke the `dFdy` intrinsic will need the RTFlip input.
47
0
                if (!context.fConfig->fSettings.fForceNoRTFlip) {
48
0
                    program.fInterface.fRTFlipUniform |= Program::Interface::kRTFlip_Derivative;
49
0
                }
50
0
            }
51
376
            if (const FunctionDefinition* builtinDef = fn.definition()) {
52
                // Make sure we only add a built-in function once. We rarely add more than a handful
53
                // of builtin functions, so linear search here is good enough.
54
131
                if (std::find(addedBuiltins.begin(), addedBuiltins.end(), builtinDef) ==
55
131
                    addedBuiltins.end()) {
56
65
                    addedBuiltins.push_back(builtinDef);
57
65
                }
58
131
            }
59
376
        }
60
61
401
        if (addedBuiltins.size() == numBuiltinsAtStart) {
62
            // If we didn't reference any more built-in functions than before, we're done.
63
340
            break;
64
340
        }
65
66
        // Sort the referenced builtin functions into a consistent order; otherwise our output will
67
        // become non-deterministic. The exact order isn't particularly important; we sort backwards
68
        // because we add elements to the shared-elements in reverse order at the end.
69
61
        std::sort(addedBuiltins.begin() + numBuiltinsAtStart,
70
61
                  addedBuiltins.end(),
71
61
                  [](const FunctionDefinition* aDefinition, const FunctionDefinition* bDefinition) {
72
4
                      const FunctionDeclaration& a = aDefinition->declaration();
73
4
                      const FunctionDeclaration& b = bDefinition->declaration();
74
4
                      if (a.name() != b.name()) {
75
4
                          return a.name() > b.name();
76
4
                      }
77
0
                      return a.description() > b.description();
78
4
                  });
79
80
        // Update the ProgramUsage to track all these newly discovered functions.
81
61
        int usageCallCounts = usage->fCallCounts.count();
82
83
126
        for (size_t index = numBuiltinsAtStart; index < addedBuiltins.size(); ++index) {
84
65
            usage->add(*addedBuiltins[index]);
85
65
        }
86
87
61
        if (usage->fCallCounts.count() == usageCallCounts) {
88
            // If we aren't making any more unique function calls than before, we're done.
89
0
            break;
90
0
        }
91
61
    }
92
93
    // Insert the new functions into the program's shared elements, right at the front.
94
    // They are added in reverse so that the deepest dependencies are added to the top.
95
340
    program.fSharedElements.insert(program.fSharedElements.begin(),
96
340
                                   addedBuiltins.rbegin(), addedBuiltins.rend());
97
340
}
98
99
}  // namespace SkSL