1/*
2 * Copyright 2012 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 "SkMatrix.h"
9#include "gl/GrGLProgramDataManager.h"
10#include "gl/GrGLGpu.h"
11#include "glsl/GrGLSLUniformHandler.h"
12
13#define ASSERT_ARRAY_UPLOAD_IN_BOUNDS(UNI, COUNT) \
14         SkASSERT((COUNT) <= (UNI).fArrayCount || \
15                  (1 == (COUNT) && GrShaderVar::kNonArray == (UNI).fArrayCount))
16
17GrGLProgramDataManager::GrGLProgramDataManager(GrGLGpu* gpu, GrGLuint programID,
18                                               const UniformInfoArray& uniforms,
19                                               const VaryingInfoArray& pathProcVaryings)
20    : fGpu(gpu)
21    , fProgramID(programID) {
22    int count = uniforms.count();
23    fUniforms.push_back_n(count);
24    for (int i = 0; i < count; i++) {
25        Uniform& uniform = fUniforms[i];
26        const UniformInfo& builderUniform = uniforms[i];
27        SkASSERT(GrShaderVar::kNonArray == builderUniform.fVariable.getArrayCount() ||
28                 builderUniform.fVariable.getArrayCount() > 0);
29        SkDEBUGCODE(
30            uniform.fArrayCount = builderUniform.fVariable.getArrayCount();
31            uniform.fType = builderUniform.fVariable.getType();
32        );
33        uniform.fLocation = builderUniform.fLocation;
34    }
35
36    // NVPR programs have separable varyings
37    count = pathProcVaryings.count();
38    fPathProcVaryings.push_back_n(count);
39    for (int i = 0; i < count; i++) {
40        SkASSERT(fGpu->glCaps().shaderCaps()->pathRenderingSupport());
41        PathProcVarying& pathProcVarying = fPathProcVaryings[i];
42        const VaryingInfo& builderPathProcVarying = pathProcVaryings[i];
43        SkASSERT(GrShaderVar::kNonArray == builderPathProcVarying.fVariable.getArrayCount() ||
44                 builderPathProcVarying.fVariable.getArrayCount() > 0);
45        SkDEBUGCODE(
46            pathProcVarying.fArrayCount = builderPathProcVarying.fVariable.getArrayCount();
47            pathProcVarying.fType = builderPathProcVarying.fVariable.getType();
48        );
49        pathProcVarying.fLocation = builderPathProcVarying.fLocation;
50    }
51}
52
53void GrGLProgramDataManager::setSamplerUniforms(const UniformInfoArray& samplers,
54                                                int startUnit) const {
55    for (int i = 0; i < samplers.count(); ++i) {
56        const UniformInfo& sampler = samplers[i];
57        SkASSERT(sampler.fVisibility);
58        if (kUnusedUniform != sampler.fLocation) {
59            GR_GL_CALL(fGpu->glInterface(), Uniform1i(sampler.fLocation, i + startUnit));
60        }
61    }
62}
63
64void GrGLProgramDataManager::setImageStorages(const UniformInfoArray& images) const {
65    for (int i = 0; i < images.count(); ++i) {
66        const UniformInfo& image = images[i];
67        SkASSERT(image.fVisibility);
68        if (kUnusedUniform != image.fLocation) {
69            GR_GL_CALL(fGpu->glInterface(), Uniform1i(image.fLocation, i));
70        }
71    }
72}
73
74void GrGLProgramDataManager::set1i(UniformHandle u, int32_t i) const {
75    const Uniform& uni = fUniforms[u.toIndex()];
76    SkASSERT(uni.fType == kInt_GrSLType);
77    SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount);
78    if (kUnusedUniform != uni.fLocation) {
79        GR_GL_CALL(fGpu->glInterface(), Uniform1i(uni.fLocation, i));
80    }
81}
82
83void GrGLProgramDataManager::set1iv(UniformHandle u,
84                                    int arrayCount,
85                                    const int v[]) const {
86    const Uniform& uni = fUniforms[u.toIndex()];
87    SkASSERT(uni.fType == kInt_GrSLType);
88    SkASSERT(arrayCount > 0);
89    ASSERT_ARRAY_UPLOAD_IN_BOUNDS(uni, arrayCount);
90    if (kUnusedUniform != uni.fLocation) {
91        GR_GL_CALL(fGpu->glInterface(), Uniform1iv(uni.fLocation, arrayCount, v));
92    }
93}
94
95void GrGLProgramDataManager::set1f(UniformHandle u, float v0) const {
96    const Uniform& uni = fUniforms[u.toIndex()];
97    SkASSERT(uni.fType == kFloat_GrSLType);
98    SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount);
99    if (kUnusedUniform != uni.fLocation) {
100        GR_GL_CALL(fGpu->glInterface(), Uniform1f(uni.fLocation, v0));
101    }
102}
103
104void GrGLProgramDataManager::set1fv(UniformHandle u,
105                                    int arrayCount,
106                                    const float v[]) const {
107    const Uniform& uni = fUniforms[u.toIndex()];
108    SkASSERT(uni.fType == kFloat_GrSLType);
109    SkASSERT(arrayCount > 0);
110    ASSERT_ARRAY_UPLOAD_IN_BOUNDS(uni, arrayCount);
111    // This assert fires in some instances of the two-pt gradient for its VSParams.
112    // Once the uniform manager is responsible for inserting the duplicate uniform
113    // arrays in VS and FS driver bug workaround, this can be enabled.
114    // this->printUni(uni);
115    if (kUnusedUniform != uni.fLocation) {
116        GR_GL_CALL(fGpu->glInterface(), Uniform1fv(uni.fLocation, arrayCount, v));
117    }
118}
119
120void GrGLProgramDataManager::set2f(UniformHandle u, float v0, float v1) const {
121    const Uniform& uni = fUniforms[u.toIndex()];
122    SkASSERT(uni.fType == kVec2f_GrSLType);
123    SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount);
124    if (kUnusedUniform != uni.fLocation) {
125        GR_GL_CALL(fGpu->glInterface(), Uniform2f(uni.fLocation, v0, v1));
126    }
127}
128
129void GrGLProgramDataManager::set2fv(UniformHandle u,
130                                    int arrayCount,
131                                    const float v[]) const {
132    const Uniform& uni = fUniforms[u.toIndex()];
133    SkASSERT(uni.fType == kVec2f_GrSLType);
134    SkASSERT(arrayCount > 0);
135    ASSERT_ARRAY_UPLOAD_IN_BOUNDS(uni, arrayCount);
136    if (kUnusedUniform != uni.fLocation) {
137        GR_GL_CALL(fGpu->glInterface(), Uniform2fv(uni.fLocation, arrayCount, v));
138    }
139}
140
141void GrGLProgramDataManager::set3f(UniformHandle u, float v0, float v1, float v2) const {
142    const Uniform& uni = fUniforms[u.toIndex()];
143    SkASSERT(uni.fType == kVec3f_GrSLType);
144    SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount);
145    if (kUnusedUniform != uni.fLocation) {
146        GR_GL_CALL(fGpu->glInterface(), Uniform3f(uni.fLocation, v0, v1, v2));
147    }
148}
149
150void GrGLProgramDataManager::set3fv(UniformHandle u,
151                                    int arrayCount,
152                                    const float v[]) const {
153    const Uniform& uni = fUniforms[u.toIndex()];
154    SkASSERT(uni.fType == kVec3f_GrSLType);
155    SkASSERT(arrayCount > 0);
156    ASSERT_ARRAY_UPLOAD_IN_BOUNDS(uni, arrayCount);
157    if (kUnusedUniform != uni.fLocation) {
158        GR_GL_CALL(fGpu->glInterface(), Uniform3fv(uni.fLocation, arrayCount, v));
159    }
160}
161
162void GrGLProgramDataManager::set4f(UniformHandle u,
163                                   float v0,
164                                   float v1,
165                                   float v2,
166                                   float v3) const {
167    const Uniform& uni = fUniforms[u.toIndex()];
168    SkASSERT(uni.fType == kVec4f_GrSLType);
169    SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount);
170    if (kUnusedUniform != uni.fLocation) {
171        GR_GL_CALL(fGpu->glInterface(), Uniform4f(uni.fLocation, v0, v1, v2, v3));
172    }
173}
174
175void GrGLProgramDataManager::set4fv(UniformHandle u,
176                                    int arrayCount,
177                                    const float v[]) const {
178    const Uniform& uni = fUniforms[u.toIndex()];
179    SkASSERT(uni.fType == kVec4f_GrSLType);
180    SkASSERT(arrayCount > 0);
181    ASSERT_ARRAY_UPLOAD_IN_BOUNDS(uni, arrayCount);
182    if (kUnusedUniform != uni.fLocation) {
183        GR_GL_CALL(fGpu->glInterface(), Uniform4fv(uni.fLocation, arrayCount, v));
184    }
185}
186
187void GrGLProgramDataManager::setMatrix2f(UniformHandle u, const float matrix[]) const {
188    this->setMatrices<2>(u, 1, matrix);
189}
190
191void GrGLProgramDataManager::setMatrix3f(UniformHandle u, const float matrix[]) const {
192    this->setMatrices<3>(u, 1, matrix);
193}
194
195void GrGLProgramDataManager::setMatrix4f(UniformHandle u, const float matrix[]) const {
196    this->setMatrices<4>(u, 1, matrix);
197}
198
199void GrGLProgramDataManager::setMatrix2fv(UniformHandle u, int arrayCount, const float m[]) const {
200    this->setMatrices<2>(u, arrayCount, m);
201}
202
203void GrGLProgramDataManager::setMatrix3fv(UniformHandle u, int arrayCount, const float m[]) const {
204    this->setMatrices<3>(u, arrayCount, m);
205}
206
207void GrGLProgramDataManager::setMatrix4fv(UniformHandle u, int arrayCount, const float m[]) const {
208    this->setMatrices<4>(u, arrayCount, m);
209}
210
211template<int N> struct set_uniform_matrix;
212
213template<int N> inline void GrGLProgramDataManager::setMatrices(UniformHandle u,
214                                                                int arrayCount,
215                                                                const float matrices[]) const {
216    const Uniform& uni = fUniforms[u.toIndex()];
217    SkASSERT(uni.fType == kMat22f_GrSLType + (N - 2));
218    SkASSERT(arrayCount > 0);
219    ASSERT_ARRAY_UPLOAD_IN_BOUNDS(uni, arrayCount);
220    if (kUnusedUniform != uni.fLocation) {
221        set_uniform_matrix<N>::set(fGpu->glInterface(), uni.fLocation, arrayCount, matrices);
222    }
223}
224
225template<> struct set_uniform_matrix<2> {
226    inline static void set(const GrGLInterface* gli, const GrGLint loc, int cnt, const float m[]) {
227        GR_GL_CALL(gli, UniformMatrix2fv(loc, cnt, false, m));
228    }
229};
230
231template<> struct set_uniform_matrix<3> {
232    inline static void set(const GrGLInterface* gli, const GrGLint loc, int cnt, const float m[]) {
233        GR_GL_CALL(gli, UniformMatrix3fv(loc, cnt, false, m));
234    }
235};
236
237template<> struct set_uniform_matrix<4> {
238    inline static void set(const GrGLInterface* gli, const GrGLint loc, int cnt, const float m[]) {
239        GR_GL_CALL(gli, UniformMatrix4fv(loc, cnt, false, m));
240    }
241};
242
243void GrGLProgramDataManager::setPathFragmentInputTransform(VaryingHandle u,
244                                                           int components,
245                                                           const SkMatrix& matrix) const {
246    SkASSERT(fGpu->glCaps().shaderCaps()->pathRenderingSupport());
247    const PathProcVarying& fragmentInput = fPathProcVaryings[u.toIndex()];
248
249    SkASSERT((components == 2 && fragmentInput.fType == kVec2f_GrSLType) ||
250              (components == 3 && fragmentInput.fType == kVec3f_GrSLType));
251
252    fGpu->glPathRendering()->setProgramPathFragmentInputTransform(fProgramID,
253                                                                  fragmentInput.fLocation,
254                                                                  GR_GL_OBJECT_LINEAR,
255                                                                  components,
256                                                                  matrix);
257}
258