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(arrayCount <= uni.fArrayCount || \
15                  (1 == arrayCount && GrGLSLShaderVar::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(GrGLSLShaderVar::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        // TODO: Move the Xoom uniform array in both FS and VS bug workaround here.
34
35        if (kVertex_GrShaderFlag & builderUniform.fVisibility) {
36            uniform.fVSLocation = builderUniform.fLocation;
37        } else {
38            uniform.fVSLocation = kUnusedUniform;
39        }
40        if (kFragment_GrShaderFlag & builderUniform.fVisibility) {
41            uniform.fFSLocation = builderUniform.fLocation;
42        } else {
43            uniform.fFSLocation = kUnusedUniform;
44        }
45    }
46
47    // NVPR programs have separable varyings
48    count = pathProcVaryings.count();
49    fPathProcVaryings.push_back_n(count);
50    for (int i = 0; i < count; i++) {
51        SkASSERT(fGpu->glCaps().shaderCaps()->pathRenderingSupport());
52        PathProcVarying& pathProcVarying = fPathProcVaryings[i];
53        const VaryingInfo& builderPathProcVarying = pathProcVaryings[i];
54        SkASSERT(GrGLSLShaderVar::kNonArray == builderPathProcVarying.fVariable.getArrayCount() ||
55                 builderPathProcVarying.fVariable.getArrayCount() > 0);
56        SkDEBUGCODE(
57            pathProcVarying.fArrayCount = builderPathProcVarying.fVariable.getArrayCount();
58            pathProcVarying.fType = builderPathProcVarying.fVariable.getType();
59        );
60        pathProcVarying.fLocation = builderPathProcVarying.fLocation;
61    }
62}
63
64void GrGLProgramDataManager::setSampler(UniformHandle u, int texUnit) const {
65    const Uniform& uni = fUniforms[u.toIndex()];
66    SkASSERT(uni.fType == kSampler2D_GrSLType || uni.fType == kSamplerExternal_GrSLType ||
67             uni.fType == kSampler2DRect_GrSLType);
68    SkASSERT(GrGLSLShaderVar::kNonArray == uni.fArrayCount);
69    // FIXME: We still insert a single sampler uniform for every stage. If the shader does not
70    // reference the sampler then the compiler may have optimized it out. Uncomment this assert
71    // once stages insert their own samplers.
72    // this->printUnused(uni);
73    if (kUnusedUniform != uni.fFSLocation) {
74        GR_GL_CALL(fGpu->glInterface(), Uniform1i(uni.fFSLocation, texUnit));
75    }
76    if (kUnusedUniform != uni.fVSLocation && uni.fVSLocation != uni.fFSLocation) {
77        GR_GL_CALL(fGpu->glInterface(), Uniform1i(uni.fVSLocation, texUnit));
78    }
79}
80
81void GrGLProgramDataManager::set1f(UniformHandle u, float v0) const {
82    const Uniform& uni = fUniforms[u.toIndex()];
83    SkASSERT(uni.fType == kFloat_GrSLType);
84    SkASSERT(GrGLSLShaderVar::kNonArray == uni.fArrayCount);
85    SkDEBUGCODE(this->printUnused(uni);)
86    if (kUnusedUniform != uni.fFSLocation) {
87        GR_GL_CALL(fGpu->glInterface(), Uniform1f(uni.fFSLocation, v0));
88    }
89    if (kUnusedUniform != uni.fVSLocation && uni.fVSLocation != uni.fFSLocation) {
90        GR_GL_CALL(fGpu->glInterface(), Uniform1f(uni.fVSLocation, v0));
91    }
92}
93
94void GrGLProgramDataManager::set1fv(UniformHandle u,
95                                    int arrayCount,
96                                    const float v[]) const {
97    const Uniform& uni = fUniforms[u.toIndex()];
98    SkASSERT(uni.fType == kFloat_GrSLType);
99    SkASSERT(arrayCount > 0);
100    ASSERT_ARRAY_UPLOAD_IN_BOUNDS(uni, arrayCount);
101    // This assert fires in some instances of the two-pt gradient for its VSParams.
102    // Once the uniform manager is responsible for inserting the duplicate uniform
103    // arrays in VS and FS driver bug workaround, this can be enabled.
104    // this->printUni(uni);
105    if (kUnusedUniform != uni.fFSLocation) {
106        GR_GL_CALL(fGpu->glInterface(), Uniform1fv(uni.fFSLocation, arrayCount, v));
107    }
108    if (kUnusedUniform != uni.fVSLocation && uni.fVSLocation != uni.fFSLocation) {
109        GR_GL_CALL(fGpu->glInterface(), Uniform1fv(uni.fVSLocation, arrayCount, v));
110    }
111}
112
113void GrGLProgramDataManager::set2f(UniformHandle u, float v0, float v1) const {
114    const Uniform& uni = fUniforms[u.toIndex()];
115    SkASSERT(uni.fType == kVec2f_GrSLType);
116    SkASSERT(GrGLSLShaderVar::kNonArray == uni.fArrayCount);
117    SkDEBUGCODE(this->printUnused(uni);)
118    if (kUnusedUniform != uni.fFSLocation) {
119        GR_GL_CALL(fGpu->glInterface(), Uniform2f(uni.fFSLocation, v0, v1));
120    }
121    if (kUnusedUniform != uni.fVSLocation && uni.fVSLocation != uni.fFSLocation) {
122        GR_GL_CALL(fGpu->glInterface(), Uniform2f(uni.fVSLocation, v0, v1));
123    }
124}
125
126void GrGLProgramDataManager::set2fv(UniformHandle u,
127                                    int arrayCount,
128                                    const float v[]) const {
129    const Uniform& uni = fUniforms[u.toIndex()];
130    SkASSERT(uni.fType == kVec2f_GrSLType);
131    SkASSERT(arrayCount > 0);
132    ASSERT_ARRAY_UPLOAD_IN_BOUNDS(uni, arrayCount);
133    SkDEBUGCODE(this->printUnused(uni);)
134    if (kUnusedUniform != uni.fFSLocation) {
135        GR_GL_CALL(fGpu->glInterface(), Uniform2fv(uni.fFSLocation, arrayCount, v));
136    }
137    if (kUnusedUniform != uni.fVSLocation && uni.fVSLocation != uni.fFSLocation) {
138        GR_GL_CALL(fGpu->glInterface(), Uniform2fv(uni.fVSLocation, arrayCount, v));
139    }
140}
141
142void GrGLProgramDataManager::set3f(UniformHandle u, float v0, float v1, float v2) const {
143    const Uniform& uni = fUniforms[u.toIndex()];
144    SkASSERT(uni.fType == kVec3f_GrSLType);
145    SkASSERT(GrGLSLShaderVar::kNonArray == uni.fArrayCount);
146    SkDEBUGCODE(this->printUnused(uni);)
147    if (kUnusedUniform != uni.fFSLocation) {
148        GR_GL_CALL(fGpu->glInterface(), Uniform3f(uni.fFSLocation, v0, v1, v2));
149    }
150    if (kUnusedUniform != uni.fVSLocation && uni.fVSLocation != uni.fFSLocation) {
151        GR_GL_CALL(fGpu->glInterface(), Uniform3f(uni.fVSLocation, v0, v1, v2));
152    }
153}
154
155void GrGLProgramDataManager::set3fv(UniformHandle u,
156                                    int arrayCount,
157                                    const float v[]) const {
158    const Uniform& uni = fUniforms[u.toIndex()];
159    SkASSERT(uni.fType == kVec3f_GrSLType);
160    SkASSERT(arrayCount > 0);
161    ASSERT_ARRAY_UPLOAD_IN_BOUNDS(uni, arrayCount);
162    SkDEBUGCODE(this->printUnused(uni);)
163    if (kUnusedUniform != uni.fFSLocation) {
164        GR_GL_CALL(fGpu->glInterface(), Uniform3fv(uni.fFSLocation, arrayCount, v));
165    }
166    if (kUnusedUniform != uni.fVSLocation && uni.fVSLocation != uni.fFSLocation) {
167        GR_GL_CALL(fGpu->glInterface(), Uniform3fv(uni.fVSLocation, arrayCount, v));
168    }
169}
170
171void GrGLProgramDataManager::set4f(UniformHandle u,
172                                   float v0,
173                                   float v1,
174                                   float v2,
175                                   float v3) const {
176    const Uniform& uni = fUniforms[u.toIndex()];
177    SkASSERT(uni.fType == kVec4f_GrSLType);
178    SkASSERT(GrGLSLShaderVar::kNonArray == uni.fArrayCount);
179    SkDEBUGCODE(this->printUnused(uni);)
180    if (kUnusedUniform != uni.fFSLocation) {
181        GR_GL_CALL(fGpu->glInterface(), Uniform4f(uni.fFSLocation, v0, v1, v2, v3));
182    }
183    if (kUnusedUniform != uni.fVSLocation && uni.fVSLocation != uni.fFSLocation) {
184        GR_GL_CALL(fGpu->glInterface(), Uniform4f(uni.fVSLocation, v0, v1, v2, v3));
185    }
186}
187
188void GrGLProgramDataManager::set4fv(UniformHandle u,
189                                    int arrayCount,
190                                    const float v[]) const {
191    const Uniform& uni = fUniforms[u.toIndex()];
192    SkASSERT(uni.fType == kVec4f_GrSLType);
193    SkASSERT(arrayCount > 0);
194    ASSERT_ARRAY_UPLOAD_IN_BOUNDS(uni, arrayCount);
195    SkDEBUGCODE(this->printUnused(uni);)
196    if (kUnusedUniform != uni.fFSLocation) {
197        GR_GL_CALL(fGpu->glInterface(), Uniform4fv(uni.fFSLocation, arrayCount, v));
198    }
199    if (kUnusedUniform != uni.fVSLocation && uni.fVSLocation != uni.fFSLocation) {
200        GR_GL_CALL(fGpu->glInterface(), Uniform4fv(uni.fVSLocation, arrayCount, v));
201    }
202}
203
204void GrGLProgramDataManager::setMatrix3f(UniformHandle u, const float matrix[]) const {
205    const Uniform& uni = fUniforms[u.toIndex()];
206    SkASSERT(uni.fType == kMat33f_GrSLType);
207    SkASSERT(GrGLSLShaderVar::kNonArray == uni.fArrayCount);
208    SkDEBUGCODE(this->printUnused(uni);)
209    if (kUnusedUniform != uni.fFSLocation) {
210        GR_GL_CALL(fGpu->glInterface(), UniformMatrix3fv(uni.fFSLocation, 1, false, matrix));
211    }
212    if (kUnusedUniform != uni.fVSLocation && uni.fVSLocation != uni.fFSLocation) {
213        GR_GL_CALL(fGpu->glInterface(), UniformMatrix3fv(uni.fVSLocation, 1, false, matrix));
214    }
215}
216
217void GrGLProgramDataManager::setMatrix4f(UniformHandle u, const float matrix[]) const {
218    const Uniform& uni = fUniforms[u.toIndex()];
219    SkASSERT(uni.fType == kMat44f_GrSLType);
220    SkASSERT(GrGLSLShaderVar::kNonArray == uni.fArrayCount);
221    SkDEBUGCODE(this->printUnused(uni);)
222    if (kUnusedUniform != uni.fFSLocation) {
223        GR_GL_CALL(fGpu->glInterface(), UniformMatrix4fv(uni.fFSLocation, 1, false, matrix));
224    }
225    if (kUnusedUniform != uni.fVSLocation && uni.fVSLocation != uni.fFSLocation) {
226        GR_GL_CALL(fGpu->glInterface(), UniformMatrix4fv(uni.fVSLocation, 1, false, matrix));
227    }
228}
229
230void GrGLProgramDataManager::setMatrix3fv(UniformHandle u,
231                                          int arrayCount,
232                                          const float matrices[]) const {
233    const Uniform& uni = fUniforms[u.toIndex()];
234    SkASSERT(uni.fType == kMat33f_GrSLType);
235    SkASSERT(arrayCount > 0);
236    ASSERT_ARRAY_UPLOAD_IN_BOUNDS(uni, arrayCount);
237    SkDEBUGCODE(this->printUnused(uni);)
238    if (kUnusedUniform != uni.fFSLocation) {
239        GR_GL_CALL(fGpu->glInterface(),
240                   UniformMatrix3fv(uni.fFSLocation, arrayCount, false, matrices));
241    }
242    if (kUnusedUniform != uni.fVSLocation && uni.fVSLocation != uni.fFSLocation) {
243        GR_GL_CALL(fGpu->glInterface(),
244                   UniformMatrix3fv(uni.fVSLocation, arrayCount, false, matrices));
245    }
246}
247
248void GrGLProgramDataManager::setMatrix4fv(UniformHandle u,
249                                          int arrayCount,
250                                          const float matrices[]) const {
251    const Uniform& uni = fUniforms[u.toIndex()];
252    SkASSERT(uni.fType == kMat44f_GrSLType);
253    SkASSERT(arrayCount > 0);
254    ASSERT_ARRAY_UPLOAD_IN_BOUNDS(uni, arrayCount);
255    SkDEBUGCODE(this->printUnused(uni);)
256    if (kUnusedUniform != uni.fFSLocation) {
257        GR_GL_CALL(fGpu->glInterface(),
258                   UniformMatrix4fv(uni.fFSLocation, arrayCount, false, matrices));
259    }
260    if (kUnusedUniform != uni.fVSLocation && uni.fVSLocation != uni.fFSLocation) {
261        GR_GL_CALL(fGpu->glInterface(),
262                   UniformMatrix4fv(uni.fVSLocation, arrayCount, false, matrices));
263    }
264}
265
266void GrGLProgramDataManager::setPathFragmentInputTransform(VaryingHandle u,
267                                                           int components,
268                                                           const SkMatrix& matrix) const {
269    SkASSERT(fGpu->glCaps().shaderCaps()->pathRenderingSupport());
270    const PathProcVarying& fragmentInput = fPathProcVaryings[u.toIndex()];
271
272    SkASSERT((components == 2 && fragmentInput.fType == kVec2f_GrSLType) ||
273              (components == 3 && fragmentInput.fType == kVec3f_GrSLType));
274
275    fGpu->glPathRendering()->setProgramPathFragmentInputTransform(fProgramID,
276                                                                  fragmentInput.fLocation,
277                                                                  GR_GL_OBJECT_LINEAR,
278                                                                  components,
279                                                                  matrix);
280}
281
282#ifdef SK_DEBUG
283void GrGLProgramDataManager::printUnused(const Uniform& uni) const {
284    if (kUnusedUniform == uni.fFSLocation && kUnusedUniform == uni.fVSLocation) {
285        GrCapsDebugf(fGpu->caps(), "Unused uniform in shader\n");
286    }
287}
288#endif
289