|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
|
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 #include "OGLShaderProgram.h" |
|
6 #include <stdint.h> // for uint32_t |
|
7 #include <sstream> // for ostringstream |
|
8 #include "gfxRect.h" // for gfxRect |
|
9 #include "mozilla/DebugOnly.h" // for DebugOnly |
|
10 #include "nsAString.h" |
|
11 #include "nsAutoPtr.h" // for nsRefPtr |
|
12 #include "nsString.h" // for nsAutoCString |
|
13 #include "prenv.h" // for PR_GetEnv |
|
14 #include "Layers.h" |
|
15 #include "GLContext.h" |
|
16 |
|
17 struct gfxRGBA; |
|
18 |
|
19 namespace mozilla { |
|
20 namespace layers { |
|
21 |
|
22 using namespace std; |
|
23 |
|
24 typedef ProgramProfileOGL::Argument Argument; |
|
25 |
|
26 #define GAUSSIAN_KERNEL_HALF_WIDTH 11 |
|
27 #define GAUSSIAN_KERNEL_STEP 0.2 |
|
28 |
|
29 void |
|
30 AddUniforms(ProgramProfileOGL& aProfile) |
|
31 { |
|
32 static const char *sKnownUniformNames[] = { |
|
33 "uLayerTransform", |
|
34 "uMaskQuadTransform", |
|
35 "uLayerQuadTransform", |
|
36 "uMatrixProj", |
|
37 "uTextureTransform", |
|
38 "uRenderTargetOffset", |
|
39 "uLayerOpacity", |
|
40 "uTexture", |
|
41 "uYTexture", |
|
42 "uCbTexture", |
|
43 "uCrTexture", |
|
44 "uBlackTexture", |
|
45 "uWhiteTexture", |
|
46 "uMaskTexture", |
|
47 "uRenderColor", |
|
48 "uTexCoordMultiplier", |
|
49 "uTexturePass2", |
|
50 nullptr |
|
51 }; |
|
52 |
|
53 for (int i = 0; sKnownUniformNames[i] != nullptr; ++i) { |
|
54 aProfile.mUniforms[i].mNameString = sKnownUniformNames[i]; |
|
55 aProfile.mUniforms[i].mName = (KnownUniform::KnownUniformName) i; |
|
56 } |
|
57 } |
|
58 |
|
59 void |
|
60 ShaderConfigOGL::SetRenderColor(bool aEnabled) |
|
61 { |
|
62 SetFeature(ENABLE_RENDER_COLOR, aEnabled); |
|
63 } |
|
64 |
|
65 void |
|
66 ShaderConfigOGL::SetTextureTarget(GLenum aTarget) |
|
67 { |
|
68 SetFeature(ENABLE_TEXTURE_EXTERNAL | ENABLE_TEXTURE_RECT, false); |
|
69 switch (aTarget) { |
|
70 case LOCAL_GL_TEXTURE_EXTERNAL: |
|
71 SetFeature(ENABLE_TEXTURE_EXTERNAL, true); |
|
72 break; |
|
73 case LOCAL_GL_TEXTURE_RECTANGLE_ARB: |
|
74 SetFeature(ENABLE_TEXTURE_RECT, true); |
|
75 break; |
|
76 } |
|
77 } |
|
78 |
|
79 void |
|
80 ShaderConfigOGL::SetRBSwap(bool aEnabled) |
|
81 { |
|
82 SetFeature(ENABLE_TEXTURE_RB_SWAP, aEnabled); |
|
83 } |
|
84 |
|
85 void |
|
86 ShaderConfigOGL::SetNoAlpha(bool aEnabled) |
|
87 { |
|
88 SetFeature(ENABLE_TEXTURE_NO_ALPHA, aEnabled); |
|
89 } |
|
90 |
|
91 void |
|
92 ShaderConfigOGL::SetOpacity(bool aEnabled) |
|
93 { |
|
94 SetFeature(ENABLE_OPACITY, aEnabled); |
|
95 } |
|
96 |
|
97 void |
|
98 ShaderConfigOGL::SetYCbCr(bool aEnabled) |
|
99 { |
|
100 SetFeature(ENABLE_TEXTURE_YCBCR, aEnabled); |
|
101 } |
|
102 |
|
103 void |
|
104 ShaderConfigOGL::SetComponentAlpha(bool aEnabled) |
|
105 { |
|
106 SetFeature(ENABLE_TEXTURE_COMPONENT_ALPHA, aEnabled); |
|
107 } |
|
108 |
|
109 void |
|
110 ShaderConfigOGL::SetColorMatrix(bool aEnabled) |
|
111 { |
|
112 SetFeature(ENABLE_COLOR_MATRIX, aEnabled); |
|
113 } |
|
114 |
|
115 void |
|
116 ShaderConfigOGL::SetBlur(bool aEnabled) |
|
117 { |
|
118 SetFeature(ENABLE_BLUR, aEnabled); |
|
119 } |
|
120 |
|
121 void |
|
122 ShaderConfigOGL::SetMask2D(bool aEnabled) |
|
123 { |
|
124 SetFeature(ENABLE_MASK_2D, aEnabled); |
|
125 } |
|
126 |
|
127 void |
|
128 ShaderConfigOGL::SetMask3D(bool aEnabled) |
|
129 { |
|
130 SetFeature(ENABLE_MASK_3D, aEnabled); |
|
131 } |
|
132 |
|
133 /* static */ ProgramProfileOGL |
|
134 ProgramProfileOGL::GetProfileFor(ShaderConfigOGL aConfig) |
|
135 { |
|
136 ProgramProfileOGL result; |
|
137 ostringstream fs, vs; |
|
138 |
|
139 AddUniforms(result); |
|
140 |
|
141 vs << "uniform mat4 uMatrixProj;" << endl; |
|
142 vs << "uniform mat4 uLayerQuadTransform;" << endl; |
|
143 vs << "uniform mat4 uLayerTransform;" << endl; |
|
144 vs << "uniform vec4 uRenderTargetOffset;" << endl; |
|
145 |
|
146 vs << "attribute vec4 aVertexCoord;" << endl; |
|
147 |
|
148 if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) { |
|
149 vs << "uniform mat4 uTextureTransform;" << endl; |
|
150 vs << "attribute vec2 aTexCoord;" << endl; |
|
151 vs << "varying vec2 vTexCoord;" << endl; |
|
152 } |
|
153 |
|
154 if (aConfig.mFeatures & ENABLE_MASK_2D || |
|
155 aConfig.mFeatures & ENABLE_MASK_3D) { |
|
156 vs << "uniform mat4 uMaskQuadTransform;" << endl; |
|
157 vs << "varying vec3 vMaskCoord;" << endl; |
|
158 } |
|
159 |
|
160 vs << "void main() {" << endl; |
|
161 vs << " vec4 finalPosition = aVertexCoord;" << endl; |
|
162 vs << " finalPosition = uLayerQuadTransform * finalPosition;" << endl; |
|
163 vs << " finalPosition = uLayerTransform * finalPosition;" << endl; |
|
164 vs << " finalPosition.xyz /= finalPosition.w;" << endl; |
|
165 |
|
166 if (aConfig.mFeatures & ENABLE_MASK_3D) { |
|
167 vs << " vMaskCoord.xy = (uMaskQuadTransform * vec4(finalPosition.xyz, 1.0)).xy;" << endl; |
|
168 // correct for perspective correct interpolation, see comment in D3D10 shader |
|
169 vs << " vMaskCoord.z = 1.0;" << endl; |
|
170 vs << " vMaskCoord *= finalPosition.w;" << endl; |
|
171 } else if (aConfig.mFeatures & ENABLE_MASK_2D) { |
|
172 vs << " vMaskCoord.xy = (uMaskQuadTransform * finalPosition).xy;" << endl; |
|
173 } |
|
174 |
|
175 vs << " finalPosition = finalPosition - uRenderTargetOffset;" << endl; |
|
176 vs << " finalPosition.xyz *= finalPosition.w;" << endl; |
|
177 vs << " finalPosition = uMatrixProj * finalPosition;" << endl; |
|
178 |
|
179 if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) { |
|
180 vs << " vTexCoord = (uTextureTransform * vec4(aTexCoord.x, aTexCoord.y, 0.0, 1.0)).xy;" << endl; |
|
181 } |
|
182 |
|
183 vs << " gl_Position = finalPosition;" << endl; |
|
184 vs << "}" << endl; |
|
185 |
|
186 if (aConfig.mFeatures & ENABLE_TEXTURE_RECT) { |
|
187 fs << "#extension GL_ARB_texture_rectangle : require" << endl; |
|
188 } |
|
189 if (aConfig.mFeatures & ENABLE_TEXTURE_EXTERNAL) { |
|
190 fs << "#extension GL_OES_EGL_image_external : require" << endl; |
|
191 } |
|
192 fs << "#ifdef GL_ES" << endl; |
|
193 fs << "precision mediump float;" << endl; |
|
194 fs << "#define COLOR_PRECISION lowp" << endl; |
|
195 fs << "#else" << endl; |
|
196 fs << "#define COLOR_PRECISION" << endl; |
|
197 fs << "#endif" << endl; |
|
198 if (aConfig.mFeatures & ENABLE_RENDER_COLOR) { |
|
199 fs << "uniform COLOR_PRECISION vec4 uRenderColor;" << endl; |
|
200 } else { |
|
201 // for tiling, texcoord can be greater than the lowfp range |
|
202 fs << "varying vec2 vTexCoord;" << endl; |
|
203 if (aConfig.mFeatures & ENABLE_BLUR) { |
|
204 fs << "uniform bool uBlurAlpha;" << endl; |
|
205 fs << "uniform vec2 uBlurRadius;" << endl; |
|
206 fs << "uniform vec2 uBlurOffset;" << endl; |
|
207 fs << "uniform float uBlurGaussianKernel[" << GAUSSIAN_KERNEL_HALF_WIDTH << "];" << endl; |
|
208 } |
|
209 if (aConfig.mFeatures & ENABLE_COLOR_MATRIX) { |
|
210 fs << "uniform mat4 uColorMatrix;" << endl; |
|
211 fs << "uniform vec4 uColorMatrixVector;" << endl; |
|
212 } |
|
213 if (aConfig.mFeatures & ENABLE_OPACITY) { |
|
214 fs << "uniform COLOR_PRECISION float uLayerOpacity;" << endl; |
|
215 } |
|
216 } |
|
217 |
|
218 const char *sampler2D = "sampler2D"; |
|
219 const char *texture2D = "texture2D"; |
|
220 |
|
221 if (aConfig.mFeatures & ENABLE_TEXTURE_RECT) { |
|
222 fs << "uniform vec2 uTexCoordMultiplier;" << endl; |
|
223 sampler2D = "sampler2DRect"; |
|
224 texture2D = "texture2DRect"; |
|
225 } |
|
226 |
|
227 if (aConfig.mFeatures & ENABLE_TEXTURE_EXTERNAL) { |
|
228 sampler2D = "samplerExternalOES"; |
|
229 } |
|
230 |
|
231 if (aConfig.mFeatures & ENABLE_TEXTURE_YCBCR) { |
|
232 fs << "uniform sampler2D uYTexture;" << endl; |
|
233 fs << "uniform sampler2D uCbTexture;" << endl; |
|
234 fs << "uniform sampler2D uCrTexture;" << endl; |
|
235 } else if (aConfig.mFeatures & ENABLE_TEXTURE_COMPONENT_ALPHA) { |
|
236 fs << "uniform sampler2D uBlackTexture;" << endl; |
|
237 fs << "uniform sampler2D uWhiteTexture;" << endl; |
|
238 fs << "uniform bool uTexturePass2;" << endl; |
|
239 } else { |
|
240 fs << "uniform " << sampler2D << " uTexture;" << endl; |
|
241 } |
|
242 |
|
243 if (aConfig.mFeatures & ENABLE_MASK_2D || |
|
244 aConfig.mFeatures & ENABLE_MASK_3D) { |
|
245 fs << "varying vec3 vMaskCoord;" << endl; |
|
246 fs << "uniform sampler2D uMaskTexture;" << endl; |
|
247 } |
|
248 |
|
249 if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) { |
|
250 fs << "vec4 sample(vec2 coord) {" << endl; |
|
251 fs << " vec4 color;" << endl; |
|
252 if (aConfig.mFeatures & ENABLE_TEXTURE_YCBCR) { |
|
253 fs << " COLOR_PRECISION float y = texture2D(uYTexture, coord).r;" << endl; |
|
254 fs << " COLOR_PRECISION float cb = texture2D(uCbTexture, coord).r;" << endl; |
|
255 fs << " COLOR_PRECISION float cr = texture2D(uCrTexture, coord).r;" << endl; |
|
256 fs << " y = (y - 0.0625) * 1.164;" << endl; |
|
257 fs << " cb = cb - 0.5;" << endl; |
|
258 fs << " cr = cr - 0.5;" << endl; |
|
259 fs << " color.r = y + cr * 1.596;" << endl; |
|
260 fs << " color.g = y - 0.813 * cr - 0.391 * cb;" << endl; |
|
261 fs << " color.b = y + cb * 2.018;" << endl; |
|
262 fs << " color.a = 1.0;" << endl; |
|
263 } else if (aConfig.mFeatures & ENABLE_TEXTURE_COMPONENT_ALPHA) { |
|
264 fs << " COLOR_PRECISION vec3 onBlack = texture2D(uBlackTexture, coord).rgb;" << endl; |
|
265 fs << " COLOR_PRECISION vec3 onWhite = texture2D(uWhiteTexture, coord).rgb;" << endl; |
|
266 fs << " COLOR_PRECISION vec4 alphas = (1.0 - onWhite + onBlack).rgbg;" << endl; |
|
267 fs << " if (uTexturePass2)" << endl; |
|
268 fs << " color = vec4(onBlack, alphas.a);" << endl; |
|
269 fs << " else" << endl; |
|
270 fs << " color = alphas;" << endl; |
|
271 } else { |
|
272 fs << " color = " << texture2D << "(uTexture, coord);" << endl; |
|
273 } |
|
274 if (aConfig.mFeatures & ENABLE_TEXTURE_RB_SWAP) { |
|
275 fs << " color = color.bgra;" << endl; |
|
276 } |
|
277 if (aConfig.mFeatures & ENABLE_TEXTURE_NO_ALPHA) { |
|
278 fs << " color = vec4(color.rgb, 1.0);" << endl; |
|
279 } |
|
280 fs << " return color;" << endl; |
|
281 fs << "}" << endl; |
|
282 if (aConfig.mFeatures & ENABLE_BLUR) { |
|
283 fs << "vec4 sampleAtRadius(vec2 coord, float radius) {" << endl; |
|
284 fs << " coord += uBlurOffset;" << endl; |
|
285 fs << " coord += radius * uBlurRadius;" << endl; |
|
286 fs << " if (coord.x < 0. || coord.y < 0. || coord.x > 1. || coord.y > 1.)" << endl; |
|
287 fs << " return vec4(0, 0, 0, 0);" << endl; |
|
288 fs << " return sample(coord);" << endl; |
|
289 fs << "}" << endl; |
|
290 fs << "vec4 blur(vec4 color, vec2 coord) {" << endl; |
|
291 fs << " vec4 total = color * uBlurGaussianKernel[0];" << endl; |
|
292 fs << " for (int i = 1; i < " << GAUSSIAN_KERNEL_HALF_WIDTH << "; ++i) {" << endl; |
|
293 fs << " float r = float(i) * " << GAUSSIAN_KERNEL_STEP << " << endl;" << endl; |
|
294 fs << " float k = uBlurGaussianKernel[i];" << endl; |
|
295 fs << " total += sampleAtRadius(coord, r) * k;" << endl; |
|
296 fs << " total += sampleAtRadius(coord, -r) * k;" << endl; |
|
297 fs << " }" << endl; |
|
298 fs << " if (uBlurAlpha) {" << endl; |
|
299 fs << " color *= total.a;" << endl; |
|
300 fs << " } else {" << endl; |
|
301 fs << " color = total;" << endl; |
|
302 fs << " }" << endl; |
|
303 fs << " return color;" << endl; |
|
304 fs << "}" << endl; |
|
305 } |
|
306 } |
|
307 fs << "void main() {" << endl; |
|
308 if (aConfig.mFeatures & ENABLE_RENDER_COLOR) { |
|
309 fs << " vec4 color = uRenderColor;" << endl; |
|
310 } else { |
|
311 if (aConfig.mFeatures & ENABLE_TEXTURE_RECT) { |
|
312 fs << " vec4 color = sample(vTexCoord * uTexCoordMultiplier);" << endl; |
|
313 } else { |
|
314 fs << " vec4 color = sample(vTexCoord);" << endl; |
|
315 } |
|
316 if (aConfig.mFeatures & ENABLE_BLUR) { |
|
317 fs << " color = blur(color, vTexCoord);" << endl; |
|
318 } |
|
319 if (aConfig.mFeatures & ENABLE_COLOR_MATRIX) { |
|
320 fs << " color = uColorMatrix * vec4(color.rgb / color.a, color.a) + uColorMatrixVector;" << endl; |
|
321 fs << " color.rgb *= color.a;" << endl; |
|
322 } |
|
323 if (aConfig.mFeatures & ENABLE_OPACITY) { |
|
324 fs << " color *= uLayerOpacity;" << endl; |
|
325 } |
|
326 } |
|
327 if (aConfig.mFeatures & ENABLE_MASK_3D) { |
|
328 fs << " vec2 maskCoords = vMaskCoord.xy / vMaskCoord.z;" << endl; |
|
329 fs << " COLOR_PRECISION float mask = texture2D(uMaskTexture, maskCoords).r;" << endl; |
|
330 fs << " color *= mask;" << endl; |
|
331 } else if (aConfig.mFeatures & ENABLE_MASK_2D) { |
|
332 fs << " COLOR_PRECISION float mask = texture2D(uMaskTexture, vMaskCoord.xy).r;" << endl; |
|
333 fs << " color *= mask;" << endl; |
|
334 } else { |
|
335 fs << " COLOR_PRECISION float mask = 1.0;" << endl; |
|
336 fs << " color *= mask;" << endl; |
|
337 } |
|
338 fs << " gl_FragColor = color;" << endl; |
|
339 fs << "}" << endl; |
|
340 |
|
341 result.mVertexShaderString = vs.str(); |
|
342 result.mFragmentShaderString = fs.str(); |
|
343 |
|
344 result.mAttributes.AppendElement(Argument("aVertexCoord")); |
|
345 if (aConfig.mFeatures & ENABLE_RENDER_COLOR) { |
|
346 result.mTextureCount = 0; |
|
347 } else { |
|
348 result.mAttributes.AppendElement(Argument("aTexCoord")); |
|
349 if (aConfig.mFeatures & ENABLE_TEXTURE_YCBCR) { |
|
350 result.mTextureCount = 3; |
|
351 } else if (aConfig.mFeatures & ENABLE_TEXTURE_COMPONENT_ALPHA) { |
|
352 result.mTextureCount = 2; |
|
353 } else { |
|
354 result.mTextureCount = 1; |
|
355 } |
|
356 } |
|
357 if (aConfig.mFeatures & ENABLE_MASK_2D || |
|
358 aConfig.mFeatures & ENABLE_MASK_3D) { |
|
359 result.mTextureCount = 1; |
|
360 } |
|
361 |
|
362 return result; |
|
363 } |
|
364 |
|
365 const char* const ShaderProgramOGL::VertexCoordAttrib = "aVertexCoord"; |
|
366 const char* const ShaderProgramOGL::TexCoordAttrib = "aTexCoord"; |
|
367 |
|
368 ShaderProgramOGL::ShaderProgramOGL(GLContext* aGL, const ProgramProfileOGL& aProfile) |
|
369 : mGL(aGL) |
|
370 , mProgram(0) |
|
371 , mProfile(aProfile) |
|
372 , mProgramState(STATE_NEW) |
|
373 { |
|
374 } |
|
375 |
|
376 ShaderProgramOGL::~ShaderProgramOGL() |
|
377 { |
|
378 if (mProgram <= 0) { |
|
379 return; |
|
380 } |
|
381 |
|
382 nsRefPtr<GLContext> ctx = mGL->GetSharedContext(); |
|
383 if (!ctx) { |
|
384 ctx = mGL; |
|
385 } |
|
386 ctx->MakeCurrent(); |
|
387 ctx->fDeleteProgram(mProgram); |
|
388 } |
|
389 |
|
390 bool |
|
391 ShaderProgramOGL::Initialize() |
|
392 { |
|
393 NS_ASSERTION(mProgramState == STATE_NEW, "Shader program has already been initialised"); |
|
394 |
|
395 ostringstream vs, fs; |
|
396 for (uint32_t i = 0; i < mProfile.mDefines.Length(); ++i) { |
|
397 vs << mProfile.mDefines[i] << endl; |
|
398 fs << mProfile.mDefines[i] << endl; |
|
399 } |
|
400 vs << mProfile.mVertexShaderString << endl; |
|
401 fs << mProfile.mFragmentShaderString << endl; |
|
402 |
|
403 if (!CreateProgram(vs.str().c_str(), fs.str().c_str())) { |
|
404 mProgramState = STATE_ERROR; |
|
405 return false; |
|
406 } |
|
407 |
|
408 mProgramState = STATE_OK; |
|
409 |
|
410 for (uint32_t i = 0; i < KnownUniform::KnownUniformCount; ++i) { |
|
411 mProfile.mUniforms[i].mLocation = |
|
412 mGL->fGetUniformLocation(mProgram, mProfile.mUniforms[i].mNameString); |
|
413 } |
|
414 |
|
415 for (uint32_t i = 0; i < mProfile.mAttributes.Length(); ++i) { |
|
416 mProfile.mAttributes[i].mLocation = |
|
417 mGL->fGetAttribLocation(mProgram, mProfile.mAttributes[i].mName); |
|
418 NS_ASSERTION(mProfile.mAttributes[i].mLocation >= 0, "Bad attribute location."); |
|
419 } |
|
420 |
|
421 //mProfile.mHasMatrixProj = mProfile.mUniforms[KnownUniform::MatrixProj].mLocation != -1; |
|
422 |
|
423 return true; |
|
424 } |
|
425 |
|
426 GLint |
|
427 ShaderProgramOGL::CreateShader(GLenum aShaderType, const char *aShaderSource) |
|
428 { |
|
429 GLint success, len = 0; |
|
430 |
|
431 GLint sh = mGL->fCreateShader(aShaderType); |
|
432 mGL->fShaderSource(sh, 1, (const GLchar**)&aShaderSource, nullptr); |
|
433 mGL->fCompileShader(sh); |
|
434 mGL->fGetShaderiv(sh, LOCAL_GL_COMPILE_STATUS, &success); |
|
435 mGL->fGetShaderiv(sh, LOCAL_GL_INFO_LOG_LENGTH, (GLint*) &len); |
|
436 /* Even if compiling is successful, there may still be warnings. Print them |
|
437 * in a debug build. The > 10 is to catch silly compilers that might put |
|
438 * some whitespace in the log but otherwise leave it empty. |
|
439 */ |
|
440 if (!success |
|
441 #ifdef DEBUG |
|
442 || (len > 10 && PR_GetEnv("MOZ_DEBUG_SHADERS")) |
|
443 #endif |
|
444 ) |
|
445 { |
|
446 nsAutoCString log; |
|
447 log.SetCapacity(len); |
|
448 mGL->fGetShaderInfoLog(sh, len, (GLint*) &len, (char*) log.BeginWriting()); |
|
449 log.SetLength(len); |
|
450 |
|
451 if (!success) { |
|
452 printf_stderr("=== SHADER COMPILATION FAILED ===\n"); |
|
453 } else { |
|
454 printf_stderr("=== SHADER COMPILATION WARNINGS ===\n"); |
|
455 } |
|
456 |
|
457 printf_stderr("=== Source:\n%s\n", aShaderSource); |
|
458 printf_stderr("=== Log:\n%s\n", log.get()); |
|
459 printf_stderr("============\n"); |
|
460 |
|
461 if (!success) { |
|
462 mGL->fDeleteShader(sh); |
|
463 return 0; |
|
464 } |
|
465 } |
|
466 |
|
467 return sh; |
|
468 } |
|
469 |
|
470 bool |
|
471 ShaderProgramOGL::CreateProgram(const char *aVertexShaderString, |
|
472 const char *aFragmentShaderString) |
|
473 { |
|
474 GLuint vertexShader = CreateShader(LOCAL_GL_VERTEX_SHADER, aVertexShaderString); |
|
475 GLuint fragmentShader = CreateShader(LOCAL_GL_FRAGMENT_SHADER, aFragmentShaderString); |
|
476 |
|
477 if (!vertexShader || !fragmentShader) |
|
478 return false; |
|
479 |
|
480 GLint result = mGL->fCreateProgram(); |
|
481 mGL->fAttachShader(result, vertexShader); |
|
482 mGL->fAttachShader(result, fragmentShader); |
|
483 |
|
484 mGL->fLinkProgram(result); |
|
485 |
|
486 GLint success, len; |
|
487 mGL->fGetProgramiv(result, LOCAL_GL_LINK_STATUS, &success); |
|
488 mGL->fGetProgramiv(result, LOCAL_GL_INFO_LOG_LENGTH, (GLint*) &len); |
|
489 /* Even if linking is successful, there may still be warnings. Print them |
|
490 * in a debug build. The > 10 is to catch silly compilers that might put |
|
491 * some whitespace in the log but otherwise leave it empty. |
|
492 */ |
|
493 if (!success |
|
494 #ifdef DEBUG |
|
495 || (len > 10 && PR_GetEnv("MOZ_DEBUG_SHADERS")) |
|
496 #endif |
|
497 ) |
|
498 { |
|
499 nsAutoCString log; |
|
500 log.SetCapacity(len); |
|
501 mGL->fGetProgramInfoLog(result, len, (GLint*) &len, (char*) log.BeginWriting()); |
|
502 log.SetLength(len); |
|
503 |
|
504 if (!success) { |
|
505 printf_stderr("=== PROGRAM LINKING FAILED ===\n"); |
|
506 } else { |
|
507 printf_stderr("=== PROGRAM LINKING WARNINGS ===\n"); |
|
508 } |
|
509 printf_stderr("=== Log:\n%s\n", log.get()); |
|
510 printf_stderr("============\n"); |
|
511 } |
|
512 |
|
513 // We can mark the shaders for deletion; they're attached to the program |
|
514 // and will remain attached. |
|
515 mGL->fDeleteShader(vertexShader); |
|
516 mGL->fDeleteShader(fragmentShader); |
|
517 |
|
518 if (!success) { |
|
519 mGL->fDeleteProgram(result); |
|
520 return false; |
|
521 } |
|
522 |
|
523 mProgram = result; |
|
524 return true; |
|
525 } |
|
526 |
|
527 void |
|
528 ShaderProgramOGL::Activate() |
|
529 { |
|
530 if (mProgramState == STATE_NEW) { |
|
531 if (!Initialize()) { |
|
532 NS_WARNING("Shader could not be initialised"); |
|
533 return; |
|
534 } |
|
535 } |
|
536 NS_ASSERTION(HasInitialized(), "Attempting to activate a program that's not in use!"); |
|
537 mGL->fUseProgram(mProgram); |
|
538 } |
|
539 |
|
540 } /* layers */ |
|
541 } /* mozilla */ |