gfx/layers/opengl/OGLShaderProgram.cpp

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:eee231206d13
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 */

mercurial