Line data Source code
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 "gfxEnv.h"
9 : #include "gfxRect.h" // for gfxRect
10 : #include "gfxUtils.h"
11 : #include "mozilla/DebugOnly.h" // for DebugOnly
12 : #include "mozilla/layers/Compositor.h" // for BlendOpIsMixBlendMode
13 : #include "nsAString.h"
14 : #include "nsString.h" // for nsAutoCString
15 : #include "Layers.h"
16 : #include "GLContext.h"
17 :
18 : namespace mozilla {
19 : namespace layers {
20 :
21 : using namespace std;
22 :
23 : #define GAUSSIAN_KERNEL_HALF_WIDTH 11
24 : #define GAUSSIAN_KERNEL_STEP 0.2
25 :
26 : void
27 0 : AddUniforms(ProgramProfileOGL& aProfile)
28 : {
29 : // This needs to be kept in sync with the KnownUniformName enum
30 : static const char *sKnownUniformNames[] = {
31 : "uLayerTransform",
32 : "uLayerTransformInverse",
33 : "uMaskTransform",
34 : "uBackdropTransform",
35 : "uLayerRects",
36 : "uMatrixProj",
37 : "uTextureTransform",
38 : "uTextureRects",
39 : "uRenderTargetOffset",
40 : "uLayerOpacity",
41 : "uTexture",
42 : "uYTexture",
43 : "uCbTexture",
44 : "uCrTexture",
45 : "uBlackTexture",
46 : "uWhiteTexture",
47 : "uMaskTexture",
48 : "uBackdropTexture",
49 : "uRenderColor",
50 : "uTexCoordMultiplier",
51 : "uCbCrTexCoordMultiplier",
52 : "uTexturePass2",
53 : "uColorMatrix",
54 : "uColorMatrixVector",
55 : "uBlurRadius",
56 : "uBlurOffset",
57 : "uBlurAlpha",
58 : "uBlurGaussianKernel",
59 : "uSSEdges",
60 : "uViewportSize",
61 : "uVisibleCenter",
62 : "uYuvColorMatrix",
63 : nullptr
64 : };
65 :
66 0 : for (int i = 0; sKnownUniformNames[i] != nullptr; ++i) {
67 0 : aProfile.mUniforms[i].mNameString = sKnownUniformNames[i];
68 0 : aProfile.mUniforms[i].mName = (KnownUniform::KnownUniformName) i;
69 : }
70 0 : }
71 :
72 : void
73 0 : ShaderConfigOGL::SetRenderColor(bool aEnabled)
74 : {
75 0 : SetFeature(ENABLE_RENDER_COLOR, aEnabled);
76 0 : }
77 :
78 : void
79 0 : ShaderConfigOGL::SetTextureTarget(GLenum aTarget)
80 : {
81 0 : SetFeature(ENABLE_TEXTURE_EXTERNAL | ENABLE_TEXTURE_RECT, false);
82 0 : switch (aTarget) {
83 : case LOCAL_GL_TEXTURE_EXTERNAL:
84 0 : SetFeature(ENABLE_TEXTURE_EXTERNAL, true);
85 0 : break;
86 : case LOCAL_GL_TEXTURE_RECTANGLE_ARB:
87 0 : SetFeature(ENABLE_TEXTURE_RECT, true);
88 0 : break;
89 : }
90 0 : }
91 :
92 : void
93 0 : ShaderConfigOGL::SetRBSwap(bool aEnabled)
94 : {
95 0 : SetFeature(ENABLE_TEXTURE_RB_SWAP, aEnabled);
96 0 : }
97 :
98 : void
99 0 : ShaderConfigOGL::SetNoAlpha(bool aEnabled)
100 : {
101 0 : SetFeature(ENABLE_TEXTURE_NO_ALPHA, aEnabled);
102 0 : }
103 :
104 : void
105 0 : ShaderConfigOGL::SetOpacity(bool aEnabled)
106 : {
107 0 : SetFeature(ENABLE_OPACITY, aEnabled);
108 0 : }
109 :
110 : void
111 0 : ShaderConfigOGL::SetYCbCr(bool aEnabled)
112 : {
113 0 : SetFeature(ENABLE_TEXTURE_YCBCR, aEnabled);
114 0 : MOZ_ASSERT(!(mFeatures & ENABLE_TEXTURE_NV12));
115 0 : }
116 :
117 : void
118 0 : ShaderConfigOGL::SetNV12(bool aEnabled)
119 : {
120 0 : SetFeature(ENABLE_TEXTURE_NV12, aEnabled);
121 0 : MOZ_ASSERT(!(mFeatures & ENABLE_TEXTURE_YCBCR));
122 0 : }
123 :
124 : void
125 0 : ShaderConfigOGL::SetComponentAlpha(bool aEnabled)
126 : {
127 0 : SetFeature(ENABLE_TEXTURE_COMPONENT_ALPHA, aEnabled);
128 0 : }
129 :
130 : void
131 0 : ShaderConfigOGL::SetColorMatrix(bool aEnabled)
132 : {
133 0 : SetFeature(ENABLE_COLOR_MATRIX, aEnabled);
134 0 : }
135 :
136 : void
137 0 : ShaderConfigOGL::SetBlur(bool aEnabled)
138 : {
139 0 : SetFeature(ENABLE_BLUR, aEnabled);
140 0 : }
141 :
142 : void
143 0 : ShaderConfigOGL::SetMask(bool aEnabled)
144 : {
145 0 : SetFeature(ENABLE_MASK, aEnabled);
146 0 : }
147 :
148 : void
149 0 : ShaderConfigOGL::SetNoPremultipliedAlpha()
150 : {
151 0 : SetFeature(ENABLE_NO_PREMUL_ALPHA, true);
152 0 : }
153 :
154 : void
155 0 : ShaderConfigOGL::SetDEAA(bool aEnabled)
156 : {
157 0 : SetFeature(ENABLE_DEAA, aEnabled);
158 0 : }
159 :
160 : void
161 0 : ShaderConfigOGL::SetCompositionOp(gfx::CompositionOp aOp)
162 : {
163 0 : mCompositionOp = aOp;
164 0 : }
165 :
166 : void
167 0 : ShaderConfigOGL::SetDynamicGeometry(bool aEnabled)
168 : {
169 0 : SetFeature(ENABLE_DYNAMIC_GEOMETRY, aEnabled);
170 0 : }
171 :
172 : /* static */ ProgramProfileOGL
173 0 : ProgramProfileOGL::GetProfileFor(ShaderConfigOGL aConfig)
174 : {
175 0 : ProgramProfileOGL result;
176 0 : ostringstream fs, vs;
177 :
178 0 : AddUniforms(result);
179 :
180 0 : gfx::CompositionOp blendOp = aConfig.mCompositionOp;
181 :
182 0 : vs << "#ifdef GL_ES" << endl;
183 0 : vs << "#define EDGE_PRECISION mediump" << endl;
184 0 : vs << "#else" << endl;
185 0 : vs << "#define EDGE_PRECISION" << endl;
186 0 : vs << "#endif" << endl;
187 0 : vs << "uniform mat4 uMatrixProj;" << endl;
188 0 : vs << "uniform vec4 uLayerRects[4];" << endl;
189 0 : vs << "uniform mat4 uLayerTransform;" << endl;
190 0 : if (aConfig.mFeatures & ENABLE_DEAA) {
191 0 : vs << "uniform mat4 uLayerTransformInverse;" << endl;
192 0 : vs << "uniform EDGE_PRECISION vec3 uSSEdges[4];" << endl;
193 0 : vs << "uniform vec2 uVisibleCenter;" << endl;
194 0 : vs << "uniform vec2 uViewportSize;" << endl;
195 : }
196 0 : vs << "uniform vec2 uRenderTargetOffset;" << endl;
197 :
198 0 : if (!(aConfig.mFeatures & ENABLE_DYNAMIC_GEOMETRY)) {
199 0 : vs << "attribute vec4 aCoord;" << endl;
200 : } else {
201 0 : vs << "attribute vec2 aCoord;" << endl;
202 : }
203 :
204 0 : result.mAttributes.AppendElement(Pair<nsCString, GLuint> {"aCoord", 0});
205 :
206 0 : if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
207 0 : vs << "uniform mat4 uTextureTransform;" << endl;
208 0 : vs << "uniform vec4 uTextureRects[4];" << endl;
209 0 : vs << "varying vec2 vTexCoord;" << endl;
210 :
211 0 : if (aConfig.mFeatures & ENABLE_DYNAMIC_GEOMETRY) {
212 0 : vs << "attribute vec2 aTexCoord;" << endl;
213 0 : result.mAttributes.AppendElement(Pair<nsCString, GLuint> {"aTexCoord", 1});
214 : }
215 : }
216 :
217 0 : if (BlendOpIsMixBlendMode(blendOp)) {
218 0 : vs << "uniform mat4 uBackdropTransform;" << endl;
219 0 : vs << "varying vec2 vBackdropCoord;" << endl;
220 : }
221 :
222 0 : if (aConfig.mFeatures & ENABLE_MASK) {
223 0 : vs << "uniform mat4 uMaskTransform;" << endl;
224 0 : vs << "varying vec3 vMaskCoord;" << endl;
225 : }
226 :
227 0 : vs << "void main() {" << endl;
228 :
229 0 : if (aConfig.mFeatures & ENABLE_DYNAMIC_GEOMETRY) {
230 0 : vs << " vec4 finalPosition = vec4(aCoord.xy, 0.0, 1.0);" << endl;
231 : } else {
232 0 : vs << " int vertexID = int(aCoord.w);" << endl;
233 0 : vs << " vec4 layerRect = uLayerRects[vertexID];" << endl;
234 0 : vs << " vec4 finalPosition = vec4(aCoord.xy * layerRect.zw + layerRect.xy, 0.0, 1.0);" << endl;
235 : }
236 :
237 0 : vs << " finalPosition = uLayerTransform * finalPosition;" << endl;
238 :
239 0 : if (aConfig.mFeatures & ENABLE_DEAA) {
240 : // XXX kip - The DEAA shader could be made simpler if we switch to
241 : // using dynamic vertex buffers instead of sending everything
242 : // in through uniforms. This would enable passing information
243 : // about how to dilate each vertex explicitly and eliminate the
244 : // need to extrapolate this with the sub-pixel coverage
245 : // calculation in the vertex shader.
246 :
247 : // Calculate the screen space position of this vertex, in screen pixels
248 0 : vs << " vec4 ssPos = finalPosition;" << endl;
249 0 : vs << " ssPos.xy -= uRenderTargetOffset * finalPosition.w;" << endl;
250 0 : vs << " ssPos = uMatrixProj * ssPos;" << endl;
251 0 : vs << " ssPos.xy = ((ssPos.xy/ssPos.w)*0.5+0.5)*uViewportSize;" << endl;
252 :
253 0 : if (aConfig.mFeatures & ENABLE_MASK ||
254 0 : !(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
255 0 : vs << " vec4 coordAdjusted;" << endl;
256 0 : vs << " coordAdjusted.xy = aCoord.xy;" << endl;
257 : }
258 :
259 : // It is necessary to dilate edges away from uVisibleCenter to ensure that
260 : // fragments with less than 50% sub-pixel coverage will be shaded.
261 : // This offset is applied when the sub-pixel coverage of the vertex is
262 : // less than 100%. Expanding by 0.5 pixels in screen space is sufficient
263 : // to include these pixels.
264 0 : vs << " if (dot(uSSEdges[0], vec3(ssPos.xy, 1.0)) < 1.5 ||" << endl;
265 0 : vs << " dot(uSSEdges[1], vec3(ssPos.xy, 1.0)) < 1.5 ||" << endl;
266 0 : vs << " dot(uSSEdges[2], vec3(ssPos.xy, 1.0)) < 1.5 ||" << endl;
267 0 : vs << " dot(uSSEdges[3], vec3(ssPos.xy, 1.0)) < 1.5) {" << endl;
268 : // If the shader reaches this branch, then this vertex is on the edge of
269 : // the layer's visible rect and should be dilated away from the center of
270 : // the visible rect. We don't want to hit this for inner facing
271 : // edges between tiles, as the pixels may be covered twice without clipping
272 : // against uSSEdges. If all edges were dilated, it would result in
273 : // artifacts visible within semi-transparent layers with multiple tiles.
274 0 : vs << " vec4 visibleCenter = uLayerTransform * vec4(uVisibleCenter, 0.0, 1.0);" << endl;
275 0 : vs << " vec2 dilateDir = finalPosition.xy / finalPosition.w - visibleCenter.xy / visibleCenter.w;" << endl;
276 0 : vs << " vec2 offset = sign(dilateDir) * 0.5;" << endl;
277 0 : vs << " finalPosition.xy += offset * finalPosition.w;" << endl;
278 0 : if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
279 : // We must adjust the texture coordinates to compensate for the dilation
280 0 : vs << " coordAdjusted = uLayerTransformInverse * finalPosition;" << endl;
281 0 : vs << " coordAdjusted /= coordAdjusted.w;" << endl;
282 :
283 0 : if (!(aConfig.mFeatures & ENABLE_DYNAMIC_GEOMETRY)) {
284 0 : vs << " coordAdjusted.xy -= layerRect.xy;" << endl;
285 0 : vs << " coordAdjusted.xy /= layerRect.zw;" << endl;
286 : }
287 : }
288 0 : vs << " }" << endl;
289 :
290 0 : if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
291 0 : if (aConfig.mFeatures & ENABLE_DYNAMIC_GEOMETRY) {
292 0 : vs << " vTexCoord = (uTextureTransform * vec4(aTexCoord, 0.0, 1.0)).xy;" << endl;
293 : } else {
294 0 : vs << " vec4 textureRect = uTextureRects[vertexID];" << endl;
295 0 : vs << " vec2 texCoord = coordAdjusted.xy * textureRect.zw + textureRect.xy;" << endl;
296 0 : vs << " vTexCoord = (uTextureTransform * vec4(texCoord, 0.0, 1.0)).xy;" << endl;
297 : }
298 : }
299 0 : } else if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
300 0 : if (aConfig.mFeatures & ENABLE_DYNAMIC_GEOMETRY) {
301 0 : vs << " vTexCoord = (uTextureTransform * vec4(aTexCoord, 0.0, 1.0)).xy;" << endl;
302 : } else {
303 0 : vs << " vec4 textureRect = uTextureRects[vertexID];" << endl;
304 0 : vs << " vec2 texCoord = aCoord.xy * textureRect.zw + textureRect.xy;" << endl;
305 0 : vs << " vTexCoord = (uTextureTransform * vec4(texCoord, 0.0, 1.0)).xy;" << endl;
306 : }
307 : }
308 :
309 0 : if (aConfig.mFeatures & ENABLE_MASK) {
310 0 : vs << " vMaskCoord.xy = (uMaskTransform * (finalPosition / finalPosition.w)).xy;" << endl;
311 : // correct for perspective correct interpolation, see comment in D3D11 shader
312 0 : vs << " vMaskCoord.z = 1.0;" << endl;
313 0 : vs << " vMaskCoord *= finalPosition.w;" << endl;
314 : }
315 0 : vs << " finalPosition.xy -= uRenderTargetOffset * finalPosition.w;" << endl;
316 0 : vs << " finalPosition = uMatrixProj * finalPosition;" << endl;
317 0 : if (BlendOpIsMixBlendMode(blendOp)) {
318 : // Translate from clip space (-1, 1) to (0..1), apply the backdrop
319 : // transform, then invert the y-axis.
320 0 : vs << " vBackdropCoord.x = (finalPosition.x + 1.0) / 2.0;" << endl;
321 0 : vs << " vBackdropCoord.y = 1.0 - (finalPosition.y + 1.0) / 2.0;" << endl;
322 0 : vs << " vBackdropCoord = (uBackdropTransform * vec4(vBackdropCoord.xy, 0.0, 1.0)).xy;" << endl;
323 0 : vs << " vBackdropCoord.y = 1.0 - vBackdropCoord.y;" << endl;
324 : }
325 0 : vs << " gl_Position = finalPosition;" << endl;
326 0 : vs << "}" << endl;
327 :
328 0 : if (aConfig.mFeatures & ENABLE_TEXTURE_RECT) {
329 0 : fs << "#extension GL_ARB_texture_rectangle : require" << endl;
330 : }
331 0 : if (aConfig.mFeatures & ENABLE_TEXTURE_EXTERNAL) {
332 0 : fs << "#extension GL_OES_EGL_image_external : require" << endl;
333 : }
334 0 : fs << "#ifdef GL_ES" << endl;
335 0 : fs << "precision mediump float;" << endl;
336 0 : fs << "#define COLOR_PRECISION lowp" << endl;
337 0 : fs << "#define EDGE_PRECISION mediump" << endl;
338 0 : fs << "#else" << endl;
339 0 : fs << "#define COLOR_PRECISION" << endl;
340 0 : fs << "#define EDGE_PRECISION" << endl;
341 0 : fs << "#endif" << endl;
342 0 : if (aConfig.mFeatures & ENABLE_RENDER_COLOR) {
343 0 : fs << "uniform COLOR_PRECISION vec4 uRenderColor;" << endl;
344 : } else {
345 : // for tiling, texcoord can be greater than the lowfp range
346 0 : fs << "varying vec2 vTexCoord;" << endl;
347 0 : if (aConfig.mFeatures & ENABLE_BLUR) {
348 0 : fs << "uniform bool uBlurAlpha;" << endl;
349 0 : fs << "uniform vec2 uBlurRadius;" << endl;
350 0 : fs << "uniform vec2 uBlurOffset;" << endl;
351 0 : fs << "uniform float uBlurGaussianKernel[" << GAUSSIAN_KERNEL_HALF_WIDTH << "];" << endl;
352 : }
353 0 : if (aConfig.mFeatures & ENABLE_COLOR_MATRIX) {
354 0 : fs << "uniform mat4 uColorMatrix;" << endl;
355 0 : fs << "uniform vec4 uColorMatrixVector;" << endl;
356 : }
357 0 : if (aConfig.mFeatures & ENABLE_OPACITY) {
358 0 : fs << "uniform COLOR_PRECISION float uLayerOpacity;" << endl;
359 : }
360 : }
361 0 : if (BlendOpIsMixBlendMode(blendOp)) {
362 0 : fs << "varying vec2 vBackdropCoord;" << endl;
363 : }
364 :
365 0 : const char *sampler2D = "sampler2D";
366 0 : const char *texture2D = "texture2D";
367 :
368 0 : if (aConfig.mFeatures & ENABLE_TEXTURE_RECT) {
369 0 : fs << "uniform vec2 uTexCoordMultiplier;" << endl;
370 0 : if (aConfig.mFeatures & ENABLE_TEXTURE_YCBCR ||
371 0 : aConfig.mFeatures & ENABLE_TEXTURE_NV12) {
372 0 : fs << "uniform vec2 uCbCrTexCoordMultiplier;" << endl;
373 : }
374 0 : sampler2D = "sampler2DRect";
375 0 : texture2D = "texture2DRect";
376 : }
377 :
378 0 : if (aConfig.mFeatures & ENABLE_TEXTURE_EXTERNAL) {
379 0 : sampler2D = "samplerExternalOES";
380 : }
381 :
382 0 : if (aConfig.mFeatures & ENABLE_TEXTURE_YCBCR) {
383 0 : fs << "uniform sampler2D uYTexture;" << endl;
384 0 : fs << "uniform sampler2D uCbTexture;" << endl;
385 0 : fs << "uniform sampler2D uCrTexture;" << endl;
386 0 : fs << "uniform mat3 uYuvColorMatrix;" << endl;
387 0 : } else if (aConfig.mFeatures & ENABLE_TEXTURE_NV12) {
388 0 : fs << "uniform " << sampler2D << " uYTexture;" << endl;
389 0 : fs << "uniform " << sampler2D << " uCbTexture;" << endl;
390 0 : } else if (aConfig.mFeatures & ENABLE_TEXTURE_COMPONENT_ALPHA) {
391 0 : fs << "uniform " << sampler2D << " uBlackTexture;" << endl;
392 0 : fs << "uniform " << sampler2D << " uWhiteTexture;" << endl;
393 0 : fs << "uniform bool uTexturePass2;" << endl;
394 : } else {
395 0 : fs << "uniform " << sampler2D << " uTexture;" << endl;
396 : }
397 :
398 0 : if (BlendOpIsMixBlendMode(blendOp)) {
399 : // Component alpha should be flattened away inside blend containers.
400 0 : MOZ_ASSERT(!(aConfig.mFeatures & ENABLE_TEXTURE_COMPONENT_ALPHA));
401 :
402 0 : fs << "uniform sampler2D uBackdropTexture;" << endl;
403 : }
404 :
405 0 : if (aConfig.mFeatures & ENABLE_MASK) {
406 0 : fs << "varying vec3 vMaskCoord;" << endl;
407 0 : fs << "uniform sampler2D uMaskTexture;" << endl;
408 : }
409 :
410 0 : if (aConfig.mFeatures & ENABLE_DEAA) {
411 0 : fs << "uniform EDGE_PRECISION vec3 uSSEdges[4];" << endl;
412 : }
413 :
414 0 : if (BlendOpIsMixBlendMode(blendOp)) {
415 0 : BuildMixBlender(aConfig, fs);
416 : }
417 :
418 0 : if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
419 0 : fs << "vec4 sample(vec2 coord) {" << endl;
420 0 : fs << " vec4 color;" << endl;
421 0 : if (aConfig.mFeatures & ENABLE_TEXTURE_YCBCR ||
422 0 : aConfig.mFeatures & ENABLE_TEXTURE_NV12) {
423 0 : if (aConfig.mFeatures & ENABLE_TEXTURE_YCBCR) {
424 0 : if (aConfig.mFeatures & ENABLE_TEXTURE_RECT) {
425 0 : fs << " COLOR_PRECISION float y = texture2D(uYTexture, coord * uTexCoordMultiplier).r;" << endl;
426 0 : fs << " COLOR_PRECISION float cb = texture2D(uCbTexture, coord * uCbCrTexCoordMultiplier).r;" << endl;
427 0 : fs << " COLOR_PRECISION float cr = texture2D(uCrTexture, coord * uCbCrTexCoordMultiplier).r;" << endl;
428 : } else {
429 0 : fs << " COLOR_PRECISION float y = texture2D(uYTexture, coord).r;" << endl;
430 0 : fs << " COLOR_PRECISION float cb = texture2D(uCbTexture, coord).r;" << endl;
431 0 : fs << " COLOR_PRECISION float cr = texture2D(uCrTexture, coord).r;" << endl;
432 : }
433 : } else {
434 0 : if (aConfig.mFeatures & ENABLE_TEXTURE_RECT) {
435 0 : fs << " COLOR_PRECISION float y = " << texture2D << "(uYTexture, coord * uTexCoordMultiplier).r;" << endl;
436 0 : fs << " COLOR_PRECISION float cb = " << texture2D << "(uCbTexture, coord * uCbCrTexCoordMultiplier).r;" << endl;
437 0 : fs << " COLOR_PRECISION float cr = " << texture2D << "(uCbTexture, coord * uCbCrTexCoordMultiplier).a;" << endl;
438 : } else {
439 0 : fs << " COLOR_PRECISION float y = " << texture2D << "(uYTexture, coord).r;" << endl;
440 0 : fs << " COLOR_PRECISION float cb = " << texture2D << "(uCbTexture, coord).r;" << endl;
441 0 : fs << " COLOR_PRECISION float cr = " << texture2D << "(uCbTexture, coord).a;" << endl;
442 : }
443 : }
444 :
445 0 : fs << " y = y - 0.06275;" << endl;
446 0 : fs << " cb = cb - 0.50196;" << endl;
447 0 : fs << " cr = cr - 0.50196;" << endl;
448 0 : fs << " vec3 yuv = vec3(y, cb, cr);" << endl;
449 0 : fs << " color.rgb = uYuvColorMatrix * yuv;" << endl;
450 0 : fs << " color.a = 1.0;" << endl;
451 0 : } else if (aConfig.mFeatures & ENABLE_TEXTURE_COMPONENT_ALPHA) {
452 0 : if (aConfig.mFeatures & ENABLE_TEXTURE_RECT) {
453 0 : fs << " COLOR_PRECISION vec3 onBlack = " << texture2D << "(uBlackTexture, coord * uTexCoordMultiplier).rgb;" << endl;
454 0 : fs << " COLOR_PRECISION vec3 onWhite = " << texture2D << "(uWhiteTexture, coord * uTexCoordMultiplier).rgb;" << endl;
455 : } else {
456 0 : fs << " COLOR_PRECISION vec3 onBlack = " << texture2D << "(uBlackTexture, coord).rgb;" << endl;
457 0 : fs << " COLOR_PRECISION vec3 onWhite = " << texture2D << "(uWhiteTexture, coord).rgb;" << endl;
458 : }
459 0 : fs << " COLOR_PRECISION vec4 alphas = (1.0 - onWhite + onBlack).rgbg;" << endl;
460 0 : fs << " if (uTexturePass2)" << endl;
461 0 : fs << " color = vec4(onBlack, alphas.a);" << endl;
462 0 : fs << " else" << endl;
463 0 : fs << " color = alphas;" << endl;
464 : } else {
465 0 : if (aConfig.mFeatures & ENABLE_TEXTURE_RECT) {
466 0 : fs << " color = " << texture2D << "(uTexture, coord * uTexCoordMultiplier);" << endl;
467 : } else {
468 0 : fs << " color = " << texture2D << "(uTexture, coord);" << endl;
469 : }
470 : }
471 0 : if (aConfig.mFeatures & ENABLE_TEXTURE_RB_SWAP) {
472 0 : fs << " color = color.bgra;" << endl;
473 : }
474 0 : if (aConfig.mFeatures & ENABLE_TEXTURE_NO_ALPHA) {
475 0 : fs << " color = vec4(color.rgb, 1.0);" << endl;
476 : }
477 0 : fs << " return color;" << endl;
478 0 : fs << "}" << endl;
479 0 : if (aConfig.mFeatures & ENABLE_BLUR) {
480 0 : fs << "vec4 sampleAtRadius(vec2 coord, float radius) {" << endl;
481 0 : fs << " coord += uBlurOffset;" << endl;
482 0 : fs << " coord += radius * uBlurRadius;" << endl;
483 0 : fs << " if (coord.x < 0. || coord.y < 0. || coord.x > 1. || coord.y > 1.)" << endl;
484 0 : fs << " return vec4(0, 0, 0, 0);" << endl;
485 0 : fs << " return sample(coord);" << endl;
486 0 : fs << "}" << endl;
487 0 : fs << "vec4 blur(vec4 color, vec2 coord) {" << endl;
488 0 : fs << " vec4 total = color * uBlurGaussianKernel[0];" << endl;
489 0 : fs << " for (int i = 1; i < " << GAUSSIAN_KERNEL_HALF_WIDTH << "; ++i) {" << endl;
490 0 : fs << " float r = float(i) * " << GAUSSIAN_KERNEL_STEP << ";" << endl;
491 0 : fs << " float k = uBlurGaussianKernel[i];" << endl;
492 0 : fs << " total += sampleAtRadius(coord, r) * k;" << endl;
493 0 : fs << " total += sampleAtRadius(coord, -r) * k;" << endl;
494 0 : fs << " }" << endl;
495 0 : fs << " if (uBlurAlpha) {" << endl;
496 0 : fs << " color *= total.a;" << endl;
497 0 : fs << " } else {" << endl;
498 0 : fs << " color = total;" << endl;
499 0 : fs << " }" << endl;
500 0 : fs << " return color;" << endl;
501 0 : fs << "}" << endl;
502 : }
503 : }
504 0 : fs << "void main() {" << endl;
505 0 : if (aConfig.mFeatures & ENABLE_RENDER_COLOR) {
506 0 : fs << " vec4 color = uRenderColor;" << endl;
507 : } else {
508 0 : fs << " vec4 color = sample(vTexCoord);" << endl;
509 0 : if (aConfig.mFeatures & ENABLE_BLUR) {
510 0 : fs << " color = blur(color, vTexCoord);" << endl;
511 : }
512 0 : if (aConfig.mFeatures & ENABLE_COLOR_MATRIX) {
513 0 : fs << " color = uColorMatrix * vec4(color.rgb / color.a, color.a) + uColorMatrixVector;" << endl;
514 0 : fs << " color.rgb *= color.a;" << endl;
515 : }
516 0 : if (aConfig.mFeatures & ENABLE_OPACITY) {
517 0 : fs << " color *= uLayerOpacity;" << endl;
518 : }
519 : }
520 0 : if (aConfig.mFeatures & ENABLE_DEAA) {
521 : // Calculate the sub-pixel coverage of the pixel and modulate its opacity
522 : // by that amount to perform DEAA.
523 0 : fs << " vec3 ssPos = vec3(gl_FragCoord.xy, 1.0);" << endl;
524 0 : fs << " float deaaCoverage = clamp(dot(uSSEdges[0], ssPos), 0.0, 1.0);" << endl;
525 0 : fs << " deaaCoverage *= clamp(dot(uSSEdges[1], ssPos), 0.0, 1.0);" << endl;
526 0 : fs << " deaaCoverage *= clamp(dot(uSSEdges[2], ssPos), 0.0, 1.0);" << endl;
527 0 : fs << " deaaCoverage *= clamp(dot(uSSEdges[3], ssPos), 0.0, 1.0);" << endl;
528 0 : fs << " color *= deaaCoverage;" << endl;
529 : }
530 0 : if (BlendOpIsMixBlendMode(blendOp)) {
531 0 : fs << " vec4 backdrop = texture2D(uBackdropTexture, vBackdropCoord);" << endl;
532 0 : fs << " color = mixAndBlend(backdrop, color);" << endl;
533 : }
534 0 : if (aConfig.mFeatures & ENABLE_MASK) {
535 0 : fs << " vec2 maskCoords = vMaskCoord.xy / vMaskCoord.z;" << endl;
536 0 : fs << " COLOR_PRECISION float mask = texture2D(uMaskTexture, maskCoords).r;" << endl;
537 0 : fs << " color *= mask;" << endl;
538 : } else {
539 0 : fs << " COLOR_PRECISION float mask = 1.0;" << endl;
540 0 : fs << " color *= mask;" << endl;
541 : }
542 0 : fs << " gl_FragColor = color;" << endl;
543 0 : fs << "}" << endl;
544 :
545 0 : result.mVertexShaderString = vs.str();
546 0 : result.mFragmentShaderString = fs.str();
547 :
548 0 : if (aConfig.mFeatures & ENABLE_RENDER_COLOR) {
549 0 : result.mTextureCount = 0;
550 : } else {
551 0 : if (aConfig.mFeatures & ENABLE_TEXTURE_YCBCR) {
552 0 : result.mTextureCount = 3;
553 0 : } else if (aConfig.mFeatures & ENABLE_TEXTURE_NV12) {
554 0 : result.mTextureCount = 2;
555 0 : } else if (aConfig.mFeatures & ENABLE_TEXTURE_COMPONENT_ALPHA) {
556 0 : result.mTextureCount = 2;
557 : } else {
558 0 : result.mTextureCount = 1;
559 : }
560 : }
561 0 : if (aConfig.mFeatures & ENABLE_MASK) {
562 0 : result.mTextureCount = 1;
563 : }
564 0 : if (BlendOpIsMixBlendMode(blendOp)) {
565 0 : result.mTextureCount += 1;
566 : }
567 :
568 0 : return result;
569 : }
570 :
571 : void
572 0 : ProgramProfileOGL::BuildMixBlender(const ShaderConfigOGL& aConfig, std::ostringstream& fs)
573 : {
574 : // From the "Compositing and Blending Level 1" spec.
575 : // Generate helper functions first.
576 0 : switch (aConfig.mCompositionOp) {
577 : case gfx::CompositionOp::OP_OVERLAY:
578 : case gfx::CompositionOp::OP_HARD_LIGHT:
579 : // Note: we substitute (2*src-1) into the screen formula below.
580 0 : fs << "float hardlight(float dest, float src) {" << endl;
581 0 : fs << " if (src <= 0.5) {" << endl;
582 0 : fs << " return dest * (2.0 * src);" << endl;
583 0 : fs << " } else {" << endl;
584 0 : fs << " return 2.0*dest + 2.0*src - 1.0 - 2.0*dest*src;" << endl;
585 0 : fs << " }" << endl;
586 0 : fs << "}" << endl;
587 0 : break;
588 : case gfx::CompositionOp::OP_COLOR_DODGE:
589 0 : fs << "float dodge(float dest, float src) {" << endl;
590 0 : fs << " if (dest == 0.0) {" << endl;
591 0 : fs << " return 0.0;" << endl;
592 0 : fs << " } else if (src == 1.0) {" << endl;
593 0 : fs << " return 1.0;" << endl;
594 0 : fs << " } else {" << endl;
595 0 : fs << " return min(1.0, dest / (1.0 - src));" << endl;
596 0 : fs << " }" << endl;
597 0 : fs << "}" << endl;
598 0 : break;
599 : case gfx::CompositionOp::OP_COLOR_BURN:
600 0 : fs << "float burn(float dest, float src) {" << endl;
601 0 : fs << " if (dest == 1.0) {" << endl;
602 0 : fs << " return 1.0;" << endl;
603 0 : fs << " } else if (src == 0.0) {" << endl;
604 0 : fs << " return 0.0;" << endl;
605 0 : fs << " } else {" << endl;
606 0 : fs << " return 1.0 - min(1.0, (1.0 - dest) / src);" << endl;
607 0 : fs << " }" << endl;
608 0 : fs << "}" << endl;
609 0 : break;
610 : case gfx::CompositionOp::OP_SOFT_LIGHT:
611 0 : fs << "float darken(float dest) {" << endl;
612 0 : fs << " if (dest <= 0.25) {" << endl;
613 0 : fs << " return ((16.0 * dest - 12.0) * dest + 4.0) * dest;" << endl;
614 0 : fs << " } else {" << endl;
615 0 : fs << " return sqrt(dest);" << endl;
616 0 : fs << " }" << endl;
617 0 : fs << "}" << endl;
618 0 : fs << "float softlight(float dest, float src) {" << endl;
619 0 : fs << " if (src <= 0.5) {" << endl;
620 0 : fs << " return dest - (1.0 - 2.0 * src) * dest * (1.0 - dest);" << endl;
621 0 : fs << " } else {" << endl;
622 0 : fs << " return dest + (2.0 * src - 1.0) * (darken(dest) - dest);" << endl;
623 0 : fs << " }" << endl;
624 0 : fs << "}" << endl;
625 0 : break;
626 : case gfx::CompositionOp::OP_HUE:
627 : case gfx::CompositionOp::OP_SATURATION:
628 : case gfx::CompositionOp::OP_COLOR:
629 : case gfx::CompositionOp::OP_LUMINOSITY:
630 0 : fs << "float Lum(vec3 c) {" << endl;
631 0 : fs << " return dot(vec3(0.3, 0.59, 0.11), c);" << endl;
632 0 : fs << "}" << endl;
633 0 : fs << "vec3 ClipColor(vec3 c) {" << endl;
634 0 : fs << " float L = Lum(c);" << endl;
635 0 : fs << " float n = min(min(c.r, c.g), c.b);" << endl;
636 0 : fs << " float x = max(max(c.r, c.g), c.b);" << endl;
637 0 : fs << " if (n < 0.0) {" << endl;
638 0 : fs << " c = L + (((c - L) * L) / (L - n));" << endl;
639 0 : fs << " }" << endl;
640 0 : fs << " if (x > 1.0) {" << endl;
641 0 : fs << " c = L + (((c - L) * (1.0 - L)) / (x - L));" << endl;
642 0 : fs << " }" << endl;
643 0 : fs << " return c;" << endl;
644 0 : fs << "}" << endl;
645 0 : fs << "vec3 SetLum(vec3 c, float L) {" << endl;
646 0 : fs << " float d = L - Lum(c);" << endl;
647 0 : fs << " return ClipColor(vec3(" << endl;
648 0 : fs << " c.r + d," << endl;
649 0 : fs << " c.g + d," << endl;
650 0 : fs << " c.b + d));" << endl;
651 0 : fs << "}" << endl;
652 0 : fs << "float Sat(vec3 c) {" << endl;
653 0 : fs << " return max(max(c.r, c.g), c.b) - min(min(c.r, c.g), c.b);" << endl;
654 0 : fs << "}" << endl;
655 :
656 : // To use this helper, re-arrange rgb such that r=min, g=mid, and b=max.
657 0 : fs << "vec3 SetSatInner(vec3 c, float s) {" << endl;
658 0 : fs << " if (c.b > c.r) {" << endl;
659 0 : fs << " c.g = (((c.g - c.r) * s) / (c.b - c.r));" << endl;
660 0 : fs << " c.b = s;" << endl;
661 0 : fs << " } else {" << endl;
662 0 : fs << " c.gb = vec2(0.0, 0.0);" << endl;
663 0 : fs << " }" << endl;
664 0 : fs << " return vec3(0.0, c.gb);" << endl;
665 0 : fs << "}" << endl;
666 :
667 0 : fs << "vec3 SetSat(vec3 c, float s) {" << endl;
668 0 : fs << " if (c.r <= c.g) {" << endl;
669 0 : fs << " if (c.g <= c.b) {" << endl;
670 0 : fs << " c.rgb = SetSatInner(c.rgb, s);" << endl;
671 0 : fs << " } else if (c.r <= c.b) {" << endl;
672 0 : fs << " c.rbg = SetSatInner(c.rbg, s);" << endl;
673 0 : fs << " } else {" << endl;
674 0 : fs << " c.brg = SetSatInner(c.brg, s);" << endl;
675 0 : fs << " }" << endl;
676 0 : fs << " } else if (c.r <= c.b) {" << endl;
677 0 : fs << " c.grb = SetSatInner(c.grb, s);" << endl;
678 0 : fs << " } else if (c.g <= c.b) {" << endl;
679 0 : fs << " c.gbr = SetSatInner(c.gbr, s);" << endl;
680 0 : fs << " } else {" << endl;
681 0 : fs << " c.bgr = SetSatInner(c.bgr, s);" << endl;
682 0 : fs << " }" << endl;
683 0 : fs << " return c;" << endl;
684 0 : fs << "}" << endl;
685 0 : break;
686 : default:
687 0 : break;
688 : }
689 :
690 : // Generate the main blending helper.
691 0 : fs << "vec3 blend(vec3 dest, vec3 src) {" << endl;
692 0 : switch (aConfig.mCompositionOp) {
693 : case gfx::CompositionOp::OP_MULTIPLY:
694 0 : fs << " return dest * src;" << endl;
695 0 : break;
696 : case gfx::CompositionOp::OP_SCREEN:
697 0 : fs << " return dest + src - (dest * src);" << endl;
698 0 : break;
699 : case gfx::CompositionOp::OP_OVERLAY:
700 0 : fs << " return vec3(" << endl;
701 0 : fs << " hardlight(src.r, dest.r)," << endl;
702 0 : fs << " hardlight(src.g, dest.g)," << endl;
703 0 : fs << " hardlight(src.b, dest.b));" << endl;
704 0 : break;
705 : case gfx::CompositionOp::OP_DARKEN:
706 0 : fs << " return min(dest, src);" << endl;
707 0 : break;
708 : case gfx::CompositionOp::OP_LIGHTEN:
709 0 : fs << " return max(dest, src);" << endl;
710 0 : break;
711 : case gfx::CompositionOp::OP_COLOR_DODGE:
712 0 : fs << " return vec3(" << endl;
713 0 : fs << " dodge(dest.r, src.r)," << endl;
714 0 : fs << " dodge(dest.g, src.g)," << endl;
715 0 : fs << " dodge(dest.b, src.b));" << endl;
716 0 : break;
717 : case gfx::CompositionOp::OP_COLOR_BURN:
718 0 : fs << " return vec3(" << endl;
719 0 : fs << " burn(dest.r, src.r)," << endl;
720 0 : fs << " burn(dest.g, src.g)," << endl;
721 0 : fs << " burn(dest.b, src.b));" << endl;
722 0 : break;
723 : case gfx::CompositionOp::OP_HARD_LIGHT:
724 0 : fs << " return vec3(" << endl;
725 0 : fs << " hardlight(dest.r, src.r)," << endl;
726 0 : fs << " hardlight(dest.g, src.g)," << endl;
727 0 : fs << " hardlight(dest.b, src.b));" << endl;
728 0 : break;
729 : case gfx::CompositionOp::OP_SOFT_LIGHT:
730 0 : fs << " return vec3(" << endl;
731 0 : fs << " softlight(dest.r, src.r)," << endl;
732 0 : fs << " softlight(dest.g, src.g)," << endl;
733 0 : fs << " softlight(dest.b, src.b));" << endl;
734 0 : break;
735 : case gfx::CompositionOp::OP_DIFFERENCE:
736 0 : fs << " return abs(dest - src);" << endl;
737 0 : break;
738 : case gfx::CompositionOp::OP_EXCLUSION:
739 0 : fs << " return dest + src - 2.0*dest*src;" << endl;
740 0 : break;
741 : case gfx::CompositionOp::OP_HUE:
742 0 : fs << " return SetLum(SetSat(src, Sat(dest)), Lum(dest));" << endl;
743 0 : break;
744 : case gfx::CompositionOp::OP_SATURATION:
745 0 : fs << " return SetLum(SetSat(dest, Sat(src)), Lum(dest));" << endl;
746 0 : break;
747 : case gfx::CompositionOp::OP_COLOR:
748 0 : fs << " return SetLum(src, Lum(dest));" << endl;
749 0 : break;
750 : case gfx::CompositionOp::OP_LUMINOSITY:
751 0 : fs << " return SetLum(dest, Lum(src));" << endl;
752 0 : break;
753 : default:
754 0 : MOZ_ASSERT_UNREACHABLE("unknown blend mode");
755 : }
756 0 : fs << "}" << endl;
757 :
758 : // Generate the mix-blend function the fragment shader will call.
759 0 : fs << "vec4 mixAndBlend(vec4 backdrop, vec4 color) {" << endl;
760 :
761 : // Shortcut when the backdrop or source alpha is 0, otherwise we may leak
762 : // Infinity into the blend function and return incorrect results.
763 0 : fs << " if (backdrop.a == 0.0) {" << endl;
764 0 : fs << " return color;" << endl;
765 0 : fs << " }" << endl;
766 0 : fs << " if (color.a == 0.0) {" << endl;
767 0 : fs << " return vec4(0.0, 0.0, 0.0, 0.0);" << endl;
768 0 : fs << " }" << endl;
769 :
770 : // The spec assumes there is no premultiplied alpha. The backdrop is always
771 : // premultiplied, so undo the premultiply. If the source is premultiplied we
772 : // must fix that as well.
773 0 : fs << " backdrop.rgb /= backdrop.a;" << endl;
774 0 : if (!(aConfig.mFeatures & ENABLE_NO_PREMUL_ALPHA)) {
775 0 : fs << " color.rgb /= color.a;" << endl;
776 : }
777 0 : fs << " vec3 blended = blend(backdrop.rgb, color.rgb);" << endl;
778 0 : fs << " color.rgb = (1.0 - backdrop.a) * color.rgb + backdrop.a * blended.rgb;" << endl;
779 0 : fs << " color.rgb *= color.a;" << endl;
780 0 : fs << " return color;" << endl;
781 0 : fs << "}" << endl;
782 0 : }
783 :
784 0 : ShaderProgramOGL::ShaderProgramOGL(GLContext* aGL, const ProgramProfileOGL& aProfile)
785 : : mGL(aGL)
786 : , mProgram(0)
787 : , mProfile(aProfile)
788 0 : , mProgramState(STATE_NEW)
789 : {
790 0 : }
791 :
792 0 : ShaderProgramOGL::~ShaderProgramOGL()
793 : {
794 0 : if (mProgram <= 0) {
795 0 : return;
796 : }
797 :
798 0 : RefPtr<GLContext> ctx = mGL->GetSharedContext();
799 0 : if (!ctx) {
800 0 : ctx = mGL;
801 : }
802 0 : ctx->MakeCurrent();
803 0 : ctx->fDeleteProgram(mProgram);
804 0 : }
805 :
806 : bool
807 0 : ShaderProgramOGL::Initialize()
808 : {
809 0 : NS_ASSERTION(mProgramState == STATE_NEW, "Shader program has already been initialised");
810 :
811 0 : ostringstream vs, fs;
812 0 : for (uint32_t i = 0; i < mProfile.mDefines.Length(); ++i) {
813 0 : vs << mProfile.mDefines[i] << endl;
814 0 : fs << mProfile.mDefines[i] << endl;
815 : }
816 0 : vs << mProfile.mVertexShaderString << endl;
817 0 : fs << mProfile.mFragmentShaderString << endl;
818 :
819 0 : if (!CreateProgram(vs.str().c_str(), fs.str().c_str())) {
820 0 : mProgramState = STATE_ERROR;
821 0 : return false;
822 : }
823 :
824 0 : mProgramState = STATE_OK;
825 :
826 0 : for (uint32_t i = 0; i < KnownUniform::KnownUniformCount; ++i) {
827 0 : mProfile.mUniforms[i].mLocation =
828 0 : mGL->fGetUniformLocation(mProgram, mProfile.mUniforms[i].mNameString);
829 : }
830 :
831 0 : return true;
832 : }
833 :
834 : GLint
835 0 : ShaderProgramOGL::CreateShader(GLenum aShaderType, const char *aShaderSource)
836 : {
837 0 : GLint success, len = 0;
838 :
839 0 : GLint sh = mGL->fCreateShader(aShaderType);
840 0 : mGL->fShaderSource(sh, 1, (const GLchar**)&aShaderSource, nullptr);
841 0 : mGL->fCompileShader(sh);
842 0 : mGL->fGetShaderiv(sh, LOCAL_GL_COMPILE_STATUS, &success);
843 0 : mGL->fGetShaderiv(sh, LOCAL_GL_INFO_LOG_LENGTH, (GLint*) &len);
844 : /* Even if compiling is successful, there may still be warnings. Print them
845 : * in a debug build. The > 10 is to catch silly compilers that might put
846 : * some whitespace in the log but otherwise leave it empty.
847 : */
848 0 : if (!success
849 : #ifdef DEBUG
850 0 : || (len > 10 && gfxEnv::DebugShaders())
851 : #endif
852 : )
853 : {
854 0 : nsAutoCString log;
855 0 : log.SetCapacity(len);
856 0 : mGL->fGetShaderInfoLog(sh, len, (GLint*) &len, (char*) log.BeginWriting());
857 0 : log.SetLength(len);
858 :
859 0 : if (!success) {
860 0 : printf_stderr("=== SHADER COMPILATION FAILED ===\n");
861 : } else {
862 0 : printf_stderr("=== SHADER COMPILATION WARNINGS ===\n");
863 : }
864 :
865 0 : printf_stderr("=== Source:\n%s\n", aShaderSource);
866 0 : printf_stderr("=== Log:\n%s\n", log.get());
867 0 : printf_stderr("============\n");
868 :
869 0 : if (!success) {
870 0 : mGL->fDeleteShader(sh);
871 0 : return 0;
872 : }
873 : }
874 :
875 0 : return sh;
876 : }
877 :
878 : bool
879 0 : ShaderProgramOGL::CreateProgram(const char *aVertexShaderString,
880 : const char *aFragmentShaderString)
881 : {
882 0 : GLuint vertexShader = CreateShader(LOCAL_GL_VERTEX_SHADER, aVertexShaderString);
883 0 : GLuint fragmentShader = CreateShader(LOCAL_GL_FRAGMENT_SHADER, aFragmentShaderString);
884 :
885 0 : if (!vertexShader || !fragmentShader)
886 0 : return false;
887 :
888 0 : GLint result = mGL->fCreateProgram();
889 0 : mGL->fAttachShader(result, vertexShader);
890 0 : mGL->fAttachShader(result, fragmentShader);
891 :
892 0 : for (Pair<nsCString, GLuint>& attribute : mProfile.mAttributes) {
893 0 : mGL->fBindAttribLocation(result, attribute.second(),
894 0 : attribute.first().get());
895 : }
896 :
897 0 : mGL->fLinkProgram(result);
898 :
899 : GLint success, len;
900 0 : mGL->fGetProgramiv(result, LOCAL_GL_LINK_STATUS, &success);
901 0 : mGL->fGetProgramiv(result, LOCAL_GL_INFO_LOG_LENGTH, (GLint*) &len);
902 : /* Even if linking is successful, there may still be warnings. Print them
903 : * in a debug build. The > 10 is to catch silly compilers that might put
904 : * some whitespace in the log but otherwise leave it empty.
905 : */
906 0 : if (!success
907 : #ifdef DEBUG
908 0 : || (len > 10 && gfxEnv::DebugShaders())
909 : #endif
910 : )
911 : {
912 0 : nsAutoCString log;
913 0 : log.SetCapacity(len);
914 0 : mGL->fGetProgramInfoLog(result, len, (GLint*) &len, (char*) log.BeginWriting());
915 0 : log.SetLength(len);
916 :
917 0 : if (!success) {
918 0 : printf_stderr("=== PROGRAM LINKING FAILED ===\n");
919 : } else {
920 0 : printf_stderr("=== PROGRAM LINKING WARNINGS ===\n");
921 : }
922 0 : printf_stderr("=== Log:\n%s\n", log.get());
923 0 : printf_stderr("============\n");
924 : }
925 :
926 : // We can mark the shaders for deletion; they're attached to the program
927 : // and will remain attached.
928 0 : mGL->fDeleteShader(vertexShader);
929 0 : mGL->fDeleteShader(fragmentShader);
930 :
931 0 : if (!success) {
932 0 : mGL->fDeleteProgram(result);
933 0 : return false;
934 : }
935 :
936 0 : mProgram = result;
937 0 : return true;
938 : }
939 :
940 : GLuint
941 0 : ShaderProgramOGL::GetProgram()
942 : {
943 0 : if (mProgramState == STATE_NEW) {
944 0 : if (!Initialize()) {
945 0 : NS_WARNING("Shader could not be initialised");
946 : }
947 : }
948 0 : MOZ_ASSERT(HasInitialized(), "Attempting to get a program that's not been initialized!");
949 0 : return mProgram;
950 : }
951 :
952 : void
953 0 : ShaderProgramOGL::SetBlurRadius(float aRX, float aRY)
954 : {
955 0 : float f[] = {aRX, aRY};
956 0 : SetUniform(KnownUniform::BlurRadius, 2, f);
957 :
958 : float gaussianKernel[GAUSSIAN_KERNEL_HALF_WIDTH];
959 0 : float sum = 0.0f;
960 0 : for (int i = 0; i < GAUSSIAN_KERNEL_HALF_WIDTH; i++) {
961 0 : float x = i * GAUSSIAN_KERNEL_STEP;
962 0 : float sigma = 1.0f;
963 0 : gaussianKernel[i] = exp(-x * x / (2 * sigma * sigma)) / sqrt(2 * M_PI * sigma * sigma);
964 0 : sum += gaussianKernel[i] * (i == 0 ? 1 : 2);
965 : }
966 0 : for (int i = 0; i < GAUSSIAN_KERNEL_HALF_WIDTH; i++) {
967 0 : gaussianKernel[i] /= sum;
968 : }
969 0 : SetArrayUniform(KnownUniform::BlurGaussianKernel, GAUSSIAN_KERNEL_HALF_WIDTH, gaussianKernel);
970 0 : }
971 :
972 : void
973 0 : ShaderProgramOGL::SetYUVColorSpace(YUVColorSpace aYUVColorSpace)
974 : {
975 0 : const float* yuvToRgb = gfxUtils::YuvToRgbMatrix3x3ColumnMajor(aYUVColorSpace);
976 0 : SetMatrix3fvUniform(KnownUniform::YuvColorMatrix, yuvToRgb);
977 0 : }
978 :
979 : } // namespace layers
980 : } // namespace mozilla
|