1/*
2 * Copyright 2018 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/mtl/GrMtlPipelineStateDataManager.h"
9
10#include "src/gpu/mtl/GrMtlBuffer.h"
11#include "src/gpu/mtl/GrMtlGpu.h"
12
13#if !__has_feature(objc_arc)
14#error This file must be compiled with Arc. Use -fobjc-arc flag
15#endif
16
17GrMtlPipelineStateDataManager::GrMtlPipelineStateDataManager(const UniformInfoArray& uniforms,
18                                                             uint32_t uniformSize)
19        : fUniformSize(uniformSize)
20        , fUniformsDirty(false) {
21    fUniformData.reset(uniformSize);
22    int count = uniforms.count();
23    fUniforms.push_back_n(count);
24    // We must add uniforms in same order is the UniformInfoArray so that UniformHandles already
25    // owned by other objects will still match up here.
26    for (int i = 0; i < count; i++) {
27        Uniform& uniform = fUniforms[i];
28        const GrMtlUniformHandler::UniformInfo uniformInfo = uniforms[i];
29        SkASSERT(GrShaderVar::kNonArray == uniformInfo.fVariable.getArrayCount() ||
30                 uniformInfo.fVariable.getArrayCount() > 0);
31        SkDEBUGCODE(
32            uniform.fArrayCount = uniformInfo.fVariable.getArrayCount();
33            uniform.fType = uniformInfo.fVariable.getType();
34        );
35        uniform.fOffset = uniformInfo.fUBOffset;
36    }
37}
38
39void* GrMtlPipelineStateDataManager::getBufferPtrAndMarkDirty(const Uniform& uni) const {
40    fUniformsDirty = true;
41    return static_cast<char*>(fUniformData.get())+uni.fOffset;
42}
43
44void GrMtlPipelineStateDataManager::set1i(UniformHandle u, int32_t i) const {
45    const Uniform& uni = fUniforms[u.toIndex()];
46    SkASSERT(uni.fType == kInt_GrSLType || uni.fType == kShort_GrSLType);
47    SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount);
48    void* buffer = this->getBufferPtrAndMarkDirty(uni);
49    memcpy(buffer, &i, sizeof(int32_t));
50}
51
52void GrMtlPipelineStateDataManager::set1iv(UniformHandle u,
53                                           int arrayCount,
54                                           const int32_t v[]) const {
55    const Uniform& uni = fUniforms[u.toIndex()];
56    SkASSERT(uni.fType == kInt_GrSLType || uni.fType == kShort_GrSLType);
57    SkASSERT(arrayCount > 0);
58    SkASSERT(arrayCount <= uni.fArrayCount ||
59             (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount));
60
61    void* buffer = this->getBufferPtrAndMarkDirty(uni);
62    SkASSERT(sizeof(int32_t) == 4);
63    for (int i = 0; i < arrayCount; ++i) {
64        const int32_t* curVec = &v[i];
65        memcpy(buffer, curVec, sizeof(int32_t));
66        buffer = static_cast<char*>(buffer) + 4*sizeof(int32_t);
67    }
68}
69
70void GrMtlPipelineStateDataManager::set1f(UniformHandle u, float v0) const {
71    const Uniform& uni = fUniforms[u.toIndex()];
72    SkASSERT(uni.fType == kFloat_GrSLType || uni.fType == kHalf_GrSLType);
73    SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount);
74    void* buffer = this->getBufferPtrAndMarkDirty(uni);
75    SkASSERT(sizeof(float) == 4);
76    memcpy(buffer, &v0, sizeof(float));
77}
78
79void GrMtlPipelineStateDataManager::set1fv(UniformHandle u,
80                                           int arrayCount,
81                                           const float v[]) const {
82    const Uniform& uni = fUniforms[u.toIndex()];
83    SkASSERT(uni.fType == kFloat_GrSLType || uni.fType == kHalf_GrSLType);
84    SkASSERT(arrayCount > 0);
85    SkASSERT(arrayCount <= uni.fArrayCount ||
86             (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount));
87
88    void* buffer = this->getBufferPtrAndMarkDirty(uni);
89    SkASSERT(sizeof(float) == 4);
90    memcpy(buffer, v, arrayCount * sizeof(float));
91}
92
93void GrMtlPipelineStateDataManager::set2i(UniformHandle u, int32_t i0, int32_t i1) const {
94    const Uniform& uni = fUniforms[u.toIndex()];
95    SkASSERT(uni.fType == kInt2_GrSLType || uni.fType == kShort2_GrSLType);
96    SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount);
97    void* buffer = this->getBufferPtrAndMarkDirty(uni);
98    int32_t v[2] = { i0, i1 };
99    memcpy(buffer, v, 2 * sizeof(int32_t));
100}
101
102void GrMtlPipelineStateDataManager::set2iv(UniformHandle u,
103                                           int arrayCount,
104                                           const int32_t v[]) const {
105    const Uniform& uni = fUniforms[u.toIndex()];
106    SkASSERT(uni.fType == kInt2_GrSLType || uni.fType == kShort2_GrSLType);
107    SkASSERT(arrayCount > 0);
108    SkASSERT(arrayCount <= uni.fArrayCount ||
109             (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount));
110
111    void* buffer = this->getBufferPtrAndMarkDirty(uni);
112    SkASSERT(sizeof(int32_t) == 4);
113    memcpy(buffer, v, arrayCount*sizeof(int32_t));
114}
115
116void GrMtlPipelineStateDataManager::set2f(UniformHandle u, float v0, float v1) const {
117    const Uniform& uni = fUniforms[u.toIndex()];
118    SkASSERT(uni.fType == kFloat2_GrSLType || uni.fType == kHalf2_GrSLType);
119    SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount);
120    void* buffer = this->getBufferPtrAndMarkDirty(uni);
121    SkASSERT(sizeof(float) == 4);
122    float v[2] = { v0, v1 };
123    memcpy(buffer, v, 2 * sizeof(float));
124}
125
126void GrMtlPipelineStateDataManager::set2fv(UniformHandle u,
127                                           int arrayCount,
128                                           const float v[]) const {
129    const Uniform& uni = fUniforms[u.toIndex()];
130    SkASSERT(uni.fType == kFloat2_GrSLType || uni.fType == kHalf2_GrSLType);
131    SkASSERT(arrayCount > 0);
132    SkASSERT(arrayCount <= uni.fArrayCount ||
133             (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount));
134
135    void* buffer = this->getBufferPtrAndMarkDirty(uni);
136    SkASSERT(sizeof(float) == 4);
137    memcpy(buffer, v, arrayCount * 2 * sizeof(float));
138}
139
140void GrMtlPipelineStateDataManager::set3i(UniformHandle u,
141                                          int32_t i0,
142                                          int32_t i1,
143                                          int32_t i2) const {
144    const Uniform& uni = fUniforms[u.toIndex()];
145    SkASSERT(uni.fType == kInt3_GrSLType || uni.fType == kShort3_GrSLType);
146    SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount);
147    void* buffer = this->getBufferPtrAndMarkDirty(uni);
148    int32_t v[3] = { i0, i1, i2 };
149    memcpy(buffer, v, 3 * sizeof(int32_t));
150}
151
152void GrMtlPipelineStateDataManager::set3iv(UniformHandle u,
153                                           int arrayCount,
154                                           const int32_t v[]) const {
155    const Uniform& uni = fUniforms[u.toIndex()];
156    SkASSERT(uni.fType == kInt3_GrSLType || uni.fType == kShort3_GrSLType);
157    SkASSERT(arrayCount > 0);
158    SkASSERT(arrayCount <= uni.fArrayCount ||
159             (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount));
160
161    void* buffer = this->getBufferPtrAndMarkDirty(uni);
162    SkASSERT(sizeof(int32_t) == 4);
163    for (int i = 0; i < arrayCount; ++i) {
164        const int32_t* curVec = &v[3 * i];
165        memcpy(buffer, curVec, 3 * sizeof(int32_t));
166        buffer = static_cast<char*>(buffer) + 4*sizeof(int32_t);
167    }
168}
169
170void GrMtlPipelineStateDataManager::set3f(UniformHandle u, float v0, float v1, float v2) const {
171    const Uniform& uni = fUniforms[u.toIndex()];
172    SkASSERT(uni.fType == kFloat3_GrSLType || uni.fType == kHalf3_GrSLType);
173    SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount);
174    void* buffer = this->getBufferPtrAndMarkDirty(uni);
175    SkASSERT(sizeof(float) == 4);
176    float v[3] = { v0, v1, v2 };
177    memcpy(buffer, v, 3 * sizeof(float));
178}
179
180void GrMtlPipelineStateDataManager::set3fv(UniformHandle u,
181                                           int arrayCount,
182                                           const float v[]) const {
183    const Uniform& uni = fUniforms[u.toIndex()];
184    SkASSERT(uni.fType == kFloat3_GrSLType || uni.fType == kHalf3_GrSLType);
185    SkASSERT(arrayCount > 0);
186    SkASSERT(arrayCount <= uni.fArrayCount ||
187             (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount));
188
189    void* buffer = this->getBufferPtrAndMarkDirty(uni);
190    SkASSERT(sizeof(float) == 4);
191    for (int i = 0; i < arrayCount; ++i) {
192        const float* curVec = &v[3 * i];
193        memcpy(buffer, curVec, 3 * sizeof(float));
194        buffer = static_cast<char*>(buffer) + 4*sizeof(float);
195    }
196}
197
198void GrMtlPipelineStateDataManager::set4i(UniformHandle u,
199                                          int32_t i0,
200                                          int32_t i1,
201                                          int32_t i2,
202                                          int32_t i3) const {
203    const Uniform& uni = fUniforms[u.toIndex()];
204    SkASSERT(uni.fType == kInt4_GrSLType || uni.fType == kShort4_GrSLType);
205    SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount);
206    void* buffer = this->getBufferPtrAndMarkDirty(uni);
207    int32_t v[4] = { i0, i1, i2, i3 };
208    memcpy(buffer, v, 4 * sizeof(int32_t));
209}
210
211void GrMtlPipelineStateDataManager::set4iv(UniformHandle u,
212                                           int arrayCount,
213                                           const int32_t v[]) const {
214    const Uniform& uni = fUniforms[u.toIndex()];
215    SkASSERT(uni.fType == kInt4_GrSLType || uni.fType == kShort4_GrSLType);
216    SkASSERT(arrayCount > 0);
217    SkASSERT(arrayCount <= uni.fArrayCount ||
218             (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount));
219
220    void* buffer = this->getBufferPtrAndMarkDirty(uni);
221    SkASSERT(sizeof(int32_t) == 4);
222    memcpy(buffer, v, arrayCount * 4 * sizeof(int32_t));
223}
224
225void GrMtlPipelineStateDataManager::set4f(UniformHandle u,
226                                          float v0,
227                                          float v1,
228                                          float v2,
229                                          float v3) const {
230    const Uniform& uni = fUniforms[u.toIndex()];
231    SkASSERT(uni.fType == kFloat4_GrSLType || uni.fType == kHalf4_GrSLType);
232    SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount);
233    void* buffer = this->getBufferPtrAndMarkDirty(uni);
234    SkASSERT(sizeof(float) == 4);
235    float v[4] = { v0, v1, v2, v3 };
236    memcpy(buffer, v, 4 * sizeof(float));
237}
238
239void GrMtlPipelineStateDataManager::set4fv(UniformHandle u,
240                                           int arrayCount,
241                                           const float v[]) const {
242    const Uniform& uni = fUniforms[u.toIndex()];
243    SkASSERT(uni.fType == kFloat4_GrSLType || uni.fType == kHalf4_GrSLType);
244    SkASSERT(arrayCount > 0);
245    SkASSERT(arrayCount <= uni.fArrayCount ||
246             (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount));
247
248    void* buffer = this->getBufferPtrAndMarkDirty(uni);
249    SkASSERT(sizeof(float) == 4);
250    memcpy(buffer, v, arrayCount * 4 * sizeof(float));
251}
252
253void GrMtlPipelineStateDataManager::setMatrix2f(UniformHandle u, const float matrix[]) const {
254    this->setMatrices<2>(u, 1, matrix);
255}
256
257void GrMtlPipelineStateDataManager::setMatrix2fv(UniformHandle u,
258                                                 int arrayCount,
259                                                 const float m[]) const {
260    this->setMatrices<2>(u, arrayCount, m);
261}
262
263void GrMtlPipelineStateDataManager::setMatrix3f(UniformHandle u, const float matrix[]) const {
264    this->setMatrices<3>(u, 1, matrix);
265}
266
267void GrMtlPipelineStateDataManager::setMatrix3fv(UniformHandle u,
268                                                 int arrayCount,
269                                                 const float m[]) const {
270    this->setMatrices<3>(u, arrayCount, m);
271}
272
273void GrMtlPipelineStateDataManager::setMatrix4f(UniformHandle u, const float matrix[]) const {
274    this->setMatrices<4>(u, 1, matrix);
275}
276
277void GrMtlPipelineStateDataManager::setMatrix4fv(UniformHandle u,
278                                                 int arrayCount,
279                                                 const float m[]) const {
280    this->setMatrices<4>(u, arrayCount, m);
281}
282
283template<int N> struct set_uniform_matrix;
284
285template<int N> inline void GrMtlPipelineStateDataManager::setMatrices(
286        UniformHandle u,
287        int arrayCount,
288        const float matrices[]) const {
289    const Uniform& uni = fUniforms[u.toIndex()];
290    SkASSERT(uni.fType == kFloat2x2_GrSLType + (N - 2) ||
291             uni.fType == kHalf2x2_GrSLType + (N - 2));
292    SkASSERT(arrayCount > 0);
293    SkASSERT(arrayCount <= uni.fArrayCount ||
294             (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount));
295
296    fUniformsDirty = true;
297    set_uniform_matrix<N>::set(fUniformData.get(), uni.fOffset, arrayCount, matrices);
298}
299
300template<> struct set_uniform_matrix<2> {
301    inline static void set(void* buffer, int uniformOffset, int count, const float matrices[]) {
302        GR_STATIC_ASSERT(sizeof(float) == 4);
303        buffer = static_cast<char*>(buffer) + uniformOffset;
304        memcpy(buffer, matrices, count * 4 * sizeof(float));
305    }
306};
307
308template<> struct set_uniform_matrix<3> {
309    inline static void set(void* buffer, int uniformOffset, int count, const float matrices[]) {
310        GR_STATIC_ASSERT(sizeof(float) == 4);
311        buffer = static_cast<char*>(buffer) + uniformOffset;
312        for (int i = 0; i < count; ++i) {
313            const float* matrix = &matrices[3 * 3 * i];
314            for (int j = 0; j < 3; ++j) {
315                memcpy(buffer, &matrix[j * 3], 3 * sizeof(float));
316                buffer = static_cast<char*>(buffer) + 4 * sizeof(float);
317            }
318        }
319    }
320};
321
322template<> struct set_uniform_matrix<4> {
323    inline static void set(void* buffer, int uniformOffset, int count, const float matrices[]) {
324        GR_STATIC_ASSERT(sizeof(float) == 4);
325        buffer = static_cast<char*>(buffer) + uniformOffset;
326        memcpy(buffer, matrices, count * 16 * sizeof(float));
327    }
328};
329
330void GrMtlPipelineStateDataManager::uploadAndBindUniformBuffers(
331        GrMtlGpu* gpu,
332        id<MTLRenderCommandEncoder> renderCmdEncoder) const {
333    if (fUniformSize && fUniformsDirty) {
334        SkASSERT(fUniformSize < 4*1024);
335        if (@available(macOS 10.11, iOS 8.3, *)) {
336            [renderCmdEncoder setVertexBytes: fUniformData.get()
337                                      length: fUniformSize
338                                     atIndex: GrMtlUniformHandler::kUniformBinding];
339            [renderCmdEncoder setFragmentBytes: fUniformData.get()
340                                        length: fUniformSize
341                                       atIndex: GrMtlUniformHandler::kUniformBinding];
342        } else {
343            size_t bufferOffset;
344            id<MTLBuffer> uniformBuffer = gpu->resourceProvider().getDynamicBuffer(
345                                                  fUniformSize, &bufferOffset);
346            SkASSERT(uniformBuffer);
347            char* bufferData = (char*) uniformBuffer.contents + bufferOffset;
348            memcpy(bufferData, fUniformData.get(), fUniformSize);
349            [renderCmdEncoder setVertexBuffer: uniformBuffer
350                                       offset: bufferOffset
351                                      atIndex: GrMtlUniformHandler::kUniformBinding];
352            [renderCmdEncoder setFragmentBuffer: uniformBuffer
353                                         offset: bufferOffset
354                                        atIndex: GrMtlUniformHandler::kUniformBinding];
355        }
356        fUniformsDirty = false;
357    }
358}
359
360void GrMtlPipelineStateDataManager::resetDirtyBits() {
361    fUniformsDirty = true;
362}
363