Coverage Report

Created: 2024-05-20 07:14

/src/skia/src/gpu/graphite/UniformManager.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2021 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 "src/gpu/graphite/UniformManager.h"
9
10
#include "src/gpu/graphite/PipelineData.h"
11
12
// ensure that these types are the sizes the uniform data is expecting
13
static_assert(sizeof(int32_t) == 4);
14
static_assert(sizeof(float) == 4);
15
static_assert(sizeof(SkHalf) == 2);
16
17
namespace skgpu::graphite {
18
19
0
int UniformOffsetCalculator::advanceOffset(SkSLType type, int count) {
20
0
    SkASSERT(SkSLTypeCanBeUniformValue(type));
21
22
0
    int dimension = SkSLTypeMatrixSize(type);
23
0
    if (dimension > 0) {
24
        // All SkSL matrices are square and can be interpreted as an array of column vectors
25
0
        count = std::max(count, 1) * dimension;
26
0
    } else {
27
0
        dimension = SkSLTypeVecLength(type);
28
0
    }
29
0
    SkASSERT(1 <= dimension && dimension <= 4);
30
31
    // Bump dimension up to 4 if the array or vec3 consumes 4 primitives per element
32
    // NOTE: This affects the size, alignment already rounds up to a power of 2 automatically.
33
0
    const bool isArray = count > Uniform::kNonArray;
34
0
    if ((isArray && LayoutRules::AlignArraysAsVec4(fLayout)) ||
35
0
        (dimension == 3 && (isArray || LayoutRules::PadVec3Size(fLayout)))) {
36
0
        dimension = 4;
37
0
    }
38
39
0
    const int primitiveSize = LayoutRules::UseFullPrecision(fLayout) ||
40
0
                              SkSLTypeIsFullPrecisionNumericType(type) ? 4 : 2;
41
0
    const int align = SkNextPow2(dimension) * primitiveSize;
42
0
    const int alignedOffset = SkAlignTo(fOffset, align);
43
0
    fOffset = alignedOffset + dimension * primitiveSize * std::max(count, 1);
44
0
    fReqAlignment = std::max(fReqAlignment, align);
45
46
0
    return alignedOffset;
47
0
}
Unexecuted instantiation: skgpu::graphite::UniformOffsetCalculator::advanceOffset(SkSLType, int)
Unexecuted instantiation: skgpu::graphite::UniformOffsetCalculator::advanceOffset(SkSLType, int)
48
49
//////////////////////////////////////////////////////////////////////////////
50
51
0
UniformDataBlock UniformManager::finishUniformDataBlock() {
52
0
    size_t size = SkAlignTo(fStorage.size(), fReqAlignment);
53
0
    size_t paddingSize = size - fStorage.size();
54
0
    if (paddingSize > 0) {
55
0
        char* padding = fStorage.append(paddingSize);
56
0
        memset(padding, 0, paddingSize);
57
0
    }
58
0
    return UniformDataBlock(SkSpan(fStorage.begin(), size));
59
0
}
60
61
0
void UniformManager::resetWithNewLayout(Layout layout) {
62
0
    fStorage.clear();
63
0
    fLayout = layout;
64
0
    fReqAlignment = 0;
65
0
    fWrotePaintColor = false;
66
67
#ifdef SK_DEBUG
68
    fOffsetCalculator = UniformOffsetCalculator(layout, 0);
69
    fExpectedUniforms = {};
70
    fExpectedUniformIndex = 0;
71
#endif
72
0
}
73
74
0
static std::pair<SkSLType, int> adjust_for_matrix_type(SkSLType type, int count) {
75
    // All Layouts flatten matrices and arrays of matrices into arrays of columns, so update
76
    // 'type' to be the column type and either multiply 'count' by the number of columns for
77
    // arrays of matrices, or set to exactly the number of columns for a "non-array" matrix.
78
0
    switch(type) {
79
0
        case SkSLType::kFloat2x2: return {SkSLType::kFloat2, 2*std::max(1, count)};
80
0
        case SkSLType::kFloat3x3: return {SkSLType::kFloat3, 3*std::max(1, count)};
81
0
        case SkSLType::kFloat4x4: return {SkSLType::kFloat4, 4*std::max(1, count)};
82
83
0
        case SkSLType::kHalf2x2:  return {SkSLType::kHalf2,  2*std::max(1, count)};
84
0
        case SkSLType::kHalf3x3:  return {SkSLType::kHalf3,  3*std::max(1, count)};
85
0
        case SkSLType::kHalf4x4:  return {SkSLType::kHalf4,  4*std::max(1, count)};
86
87
        // Otherwise leave type and count alone.
88
0
        default:                  return {type, count};
89
0
    }
90
0
}
91
92
0
void UniformManager::write(const Uniform& u, const void* data) {
93
0
    SkASSERT(SkSLTypeCanBeUniformValue(u.type()));
94
0
    SkASSERT(!u.isPaintColor()); // Must go through writePaintColor()
95
96
0
    auto [type, count] = adjust_for_matrix_type(u.type(), u.count());
97
0
    SkASSERT(SkSLTypeMatrixSize(type) < 0); // Matrix types should have been flattened
98
99
0
    const bool fullPrecision = LayoutRules::UseFullPrecision(fLayout) || !IsHalfVector(type);
100
0
    if (count == Uniform::kNonArray) {
101
0
        if (fullPrecision) {
102
0
            switch(SkSLTypeVecLength(type)) {
103
0
                case 1: this->write<1, /*Half=*/false>(data, type); break;
104
0
                case 2: this->write<2, /*Half=*/false>(data, type); break;
105
0
                case 3: this->write<3, /*Half=*/false>(data, type); break;
106
0
                case 4: this->write<4, /*Half=*/false>(data, type); break;
107
0
            }
108
0
        } else {
109
0
            switch(SkSLTypeVecLength(type)) {
110
0
                case 1: this->write<1, /*Half=*/true>(data, type); break;
111
0
                case 2: this->write<2, /*Half=*/true>(data, type); break;
112
0
                case 3: this->write<3, /*Half=*/true>(data, type); break;
113
0
                case 4: this->write<4, /*Half=*/true>(data, type); break;
114
0
            }
115
0
        }
116
0
    } else {
117
0
        if (fullPrecision) {
118
0
            switch(SkSLTypeVecLength(type)) {
119
0
                case 1: this->writeArray<1, /*Half=*/false>(data, count, type); break;
120
0
                case 2: this->writeArray<2, /*Half=*/false>(data, count, type); break;
121
0
                case 3: this->writeArray<3, /*Half=*/false>(data, count, type); break;
122
0
                case 4: this->writeArray<4, /*Half=*/false>(data, count, type); break;
123
0
            }
124
0
        } else {
125
0
            switch(SkSLTypeVecLength(type)) {
126
0
                case 1: this->writeArray<1, /*Half=*/true>(data, count, type); break;
127
0
                case 2: this->writeArray<2, /*Half=*/true>(data, count, type); break;
128
0
                case 3: this->writeArray<3, /*Half=*/true>(data, count, type); break;
129
0
                case 4: this->writeArray<4, /*Half=*/true>(data, count, type); break;
130
0
            }
131
0
        }
132
0
    }
133
0
}
Unexecuted instantiation: skgpu::graphite::UniformManager::write(skgpu::graphite::Uniform const&, void const*)
Unexecuted instantiation: skgpu::graphite::UniformManager::write(skgpu::graphite::Uniform const&, void const*)
134
135
#ifdef SK_DEBUG
136
137
0
bool UniformManager::checkExpected(const void* dst, SkSLType type, int count) {
138
0
    if (fExpectedUniformIndex >= (int) fExpectedUniforms.size()) {
139
        // A write() outside of a UniformExpectationsVisitor or too many uniforms written for what
140
        // is expected.
141
0
        return false;
142
0
    }
143
144
0
    const Uniform& expected = fExpectedUniforms[fExpectedUniformIndex++];
145
0
    if (!SkSLTypeCanBeUniformValue(expected.type())) {
146
        // Not all types are supported as uniforms or supported by UniformManager
147
0
        return false;
148
0
    }
149
150
0
    auto [expectedType, expectedCount] = adjust_for_matrix_type(expected.type(), expected.count());
151
0
    if (expectedType != type || expectedCount != count) {
152
0
        return false;
153
0
    }
154
155
0
    if (dst) {
156
        // If we have 'dst', it's the aligned starting offset of the uniform being checked, so
157
        // subtracting the address of the first byte in fStorage gives us the offset.
158
0
        int offset = static_cast<int>(reinterpret_cast<intptr_t>(dst) -
159
0
                                      reinterpret_cast<intptr_t>(fStorage.data()));
160
        // Pass original expected type and count to the offset calculator for validation.
161
0
        if (offset != fOffsetCalculator.advanceOffset(expected.type(), expected.count())) {
162
0
            return false;
163
0
        }
164
0
        if (fReqAlignment != fOffsetCalculator.requiredAlignment()) {
165
0
            return false;
166
0
        }
167
        // And if it is the paint color uniform, we should not have already written it
168
0
        return !(fWrotePaintColor && expected.isPaintColor());
169
0
    } else {
170
        // If 'dst' is null, it's an already-visited paint color uniform, so it's not being written
171
        // and not changing the offset.
172
0
        SkASSERT(fWrotePaintColor);
173
0
        return expected.isPaintColor();
174
0
    }
175
0
}
176
177
0
bool UniformManager::isReset() const {
178
0
    return fStorage.empty();
179
0
}
180
181
0
void UniformManager::setExpectedUniforms(SkSpan<const Uniform> expected) {
182
0
    fExpectedUniforms = expected;
183
0
    fExpectedUniformIndex = 0;
184
0
}
185
186
0
void UniformManager::doneWithExpectedUniforms() {
187
0
    SkASSERT(fExpectedUniformIndex == static_cast<int>(fExpectedUniforms.size()));
188
0
    fExpectedUniforms = {};
189
0
}
190
191
#endif // SK_DEBUG
192
193
} // namespace skgpu::graphite