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