michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "OGLShaderProgram.h" michael@0: #include // for uint32_t michael@0: #include // for ostringstream michael@0: #include "gfxRect.h" // for gfxRect michael@0: #include "mozilla/DebugOnly.h" // for DebugOnly michael@0: #include "nsAString.h" michael@0: #include "nsAutoPtr.h" // for nsRefPtr michael@0: #include "nsString.h" // for nsAutoCString michael@0: #include "prenv.h" // for PR_GetEnv michael@0: #include "Layers.h" michael@0: #include "GLContext.h" michael@0: michael@0: struct gfxRGBA; michael@0: michael@0: namespace mozilla { michael@0: namespace layers { michael@0: michael@0: using namespace std; michael@0: michael@0: typedef ProgramProfileOGL::Argument Argument; michael@0: michael@0: #define GAUSSIAN_KERNEL_HALF_WIDTH 11 michael@0: #define GAUSSIAN_KERNEL_STEP 0.2 michael@0: michael@0: void michael@0: AddUniforms(ProgramProfileOGL& aProfile) michael@0: { michael@0: static const char *sKnownUniformNames[] = { michael@0: "uLayerTransform", michael@0: "uMaskQuadTransform", michael@0: "uLayerQuadTransform", michael@0: "uMatrixProj", michael@0: "uTextureTransform", michael@0: "uRenderTargetOffset", michael@0: "uLayerOpacity", michael@0: "uTexture", michael@0: "uYTexture", michael@0: "uCbTexture", michael@0: "uCrTexture", michael@0: "uBlackTexture", michael@0: "uWhiteTexture", michael@0: "uMaskTexture", michael@0: "uRenderColor", michael@0: "uTexCoordMultiplier", michael@0: "uTexturePass2", michael@0: nullptr michael@0: }; michael@0: michael@0: for (int i = 0; sKnownUniformNames[i] != nullptr; ++i) { michael@0: aProfile.mUniforms[i].mNameString = sKnownUniformNames[i]; michael@0: aProfile.mUniforms[i].mName = (KnownUniform::KnownUniformName) i; michael@0: } michael@0: } michael@0: michael@0: void michael@0: ShaderConfigOGL::SetRenderColor(bool aEnabled) michael@0: { michael@0: SetFeature(ENABLE_RENDER_COLOR, aEnabled); michael@0: } michael@0: michael@0: void michael@0: ShaderConfigOGL::SetTextureTarget(GLenum aTarget) michael@0: { michael@0: SetFeature(ENABLE_TEXTURE_EXTERNAL | ENABLE_TEXTURE_RECT, false); michael@0: switch (aTarget) { michael@0: case LOCAL_GL_TEXTURE_EXTERNAL: michael@0: SetFeature(ENABLE_TEXTURE_EXTERNAL, true); michael@0: break; michael@0: case LOCAL_GL_TEXTURE_RECTANGLE_ARB: michael@0: SetFeature(ENABLE_TEXTURE_RECT, true); michael@0: break; michael@0: } michael@0: } michael@0: michael@0: void michael@0: ShaderConfigOGL::SetRBSwap(bool aEnabled) michael@0: { michael@0: SetFeature(ENABLE_TEXTURE_RB_SWAP, aEnabled); michael@0: } michael@0: michael@0: void michael@0: ShaderConfigOGL::SetNoAlpha(bool aEnabled) michael@0: { michael@0: SetFeature(ENABLE_TEXTURE_NO_ALPHA, aEnabled); michael@0: } michael@0: michael@0: void michael@0: ShaderConfigOGL::SetOpacity(bool aEnabled) michael@0: { michael@0: SetFeature(ENABLE_OPACITY, aEnabled); michael@0: } michael@0: michael@0: void michael@0: ShaderConfigOGL::SetYCbCr(bool aEnabled) michael@0: { michael@0: SetFeature(ENABLE_TEXTURE_YCBCR, aEnabled); michael@0: } michael@0: michael@0: void michael@0: ShaderConfigOGL::SetComponentAlpha(bool aEnabled) michael@0: { michael@0: SetFeature(ENABLE_TEXTURE_COMPONENT_ALPHA, aEnabled); michael@0: } michael@0: michael@0: void michael@0: ShaderConfigOGL::SetColorMatrix(bool aEnabled) michael@0: { michael@0: SetFeature(ENABLE_COLOR_MATRIX, aEnabled); michael@0: } michael@0: michael@0: void michael@0: ShaderConfigOGL::SetBlur(bool aEnabled) michael@0: { michael@0: SetFeature(ENABLE_BLUR, aEnabled); michael@0: } michael@0: michael@0: void michael@0: ShaderConfigOGL::SetMask2D(bool aEnabled) michael@0: { michael@0: SetFeature(ENABLE_MASK_2D, aEnabled); michael@0: } michael@0: michael@0: void michael@0: ShaderConfigOGL::SetMask3D(bool aEnabled) michael@0: { michael@0: SetFeature(ENABLE_MASK_3D, aEnabled); michael@0: } michael@0: michael@0: /* static */ ProgramProfileOGL michael@0: ProgramProfileOGL::GetProfileFor(ShaderConfigOGL aConfig) michael@0: { michael@0: ProgramProfileOGL result; michael@0: ostringstream fs, vs; michael@0: michael@0: AddUniforms(result); michael@0: michael@0: vs << "uniform mat4 uMatrixProj;" << endl; michael@0: vs << "uniform mat4 uLayerQuadTransform;" << endl; michael@0: vs << "uniform mat4 uLayerTransform;" << endl; michael@0: vs << "uniform vec4 uRenderTargetOffset;" << endl; michael@0: michael@0: vs << "attribute vec4 aVertexCoord;" << endl; michael@0: michael@0: if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) { michael@0: vs << "uniform mat4 uTextureTransform;" << endl; michael@0: vs << "attribute vec2 aTexCoord;" << endl; michael@0: vs << "varying vec2 vTexCoord;" << endl; michael@0: } michael@0: michael@0: if (aConfig.mFeatures & ENABLE_MASK_2D || michael@0: aConfig.mFeatures & ENABLE_MASK_3D) { michael@0: vs << "uniform mat4 uMaskQuadTransform;" << endl; michael@0: vs << "varying vec3 vMaskCoord;" << endl; michael@0: } michael@0: michael@0: vs << "void main() {" << endl; michael@0: vs << " vec4 finalPosition = aVertexCoord;" << endl; michael@0: vs << " finalPosition = uLayerQuadTransform * finalPosition;" << endl; michael@0: vs << " finalPosition = uLayerTransform * finalPosition;" << endl; michael@0: vs << " finalPosition.xyz /= finalPosition.w;" << endl; michael@0: michael@0: if (aConfig.mFeatures & ENABLE_MASK_3D) { michael@0: vs << " vMaskCoord.xy = (uMaskQuadTransform * vec4(finalPosition.xyz, 1.0)).xy;" << endl; michael@0: // correct for perspective correct interpolation, see comment in D3D10 shader michael@0: vs << " vMaskCoord.z = 1.0;" << endl; michael@0: vs << " vMaskCoord *= finalPosition.w;" << endl; michael@0: } else if (aConfig.mFeatures & ENABLE_MASK_2D) { michael@0: vs << " vMaskCoord.xy = (uMaskQuadTransform * finalPosition).xy;" << endl; michael@0: } michael@0: michael@0: vs << " finalPosition = finalPosition - uRenderTargetOffset;" << endl; michael@0: vs << " finalPosition.xyz *= finalPosition.w;" << endl; michael@0: vs << " finalPosition = uMatrixProj * finalPosition;" << endl; michael@0: michael@0: if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) { michael@0: vs << " vTexCoord = (uTextureTransform * vec4(aTexCoord.x, aTexCoord.y, 0.0, 1.0)).xy;" << endl; michael@0: } michael@0: michael@0: vs << " gl_Position = finalPosition;" << endl; michael@0: vs << "}" << endl; michael@0: michael@0: if (aConfig.mFeatures & ENABLE_TEXTURE_RECT) { michael@0: fs << "#extension GL_ARB_texture_rectangle : require" << endl; michael@0: } michael@0: if (aConfig.mFeatures & ENABLE_TEXTURE_EXTERNAL) { michael@0: fs << "#extension GL_OES_EGL_image_external : require" << endl; michael@0: } michael@0: fs << "#ifdef GL_ES" << endl; michael@0: fs << "precision mediump float;" << endl; michael@0: fs << "#define COLOR_PRECISION lowp" << endl; michael@0: fs << "#else" << endl; michael@0: fs << "#define COLOR_PRECISION" << endl; michael@0: fs << "#endif" << endl; michael@0: if (aConfig.mFeatures & ENABLE_RENDER_COLOR) { michael@0: fs << "uniform COLOR_PRECISION vec4 uRenderColor;" << endl; michael@0: } else { michael@0: // for tiling, texcoord can be greater than the lowfp range michael@0: fs << "varying vec2 vTexCoord;" << endl; michael@0: if (aConfig.mFeatures & ENABLE_BLUR) { michael@0: fs << "uniform bool uBlurAlpha;" << endl; michael@0: fs << "uniform vec2 uBlurRadius;" << endl; michael@0: fs << "uniform vec2 uBlurOffset;" << endl; michael@0: fs << "uniform float uBlurGaussianKernel[" << GAUSSIAN_KERNEL_HALF_WIDTH << "];" << endl; michael@0: } michael@0: if (aConfig.mFeatures & ENABLE_COLOR_MATRIX) { michael@0: fs << "uniform mat4 uColorMatrix;" << endl; michael@0: fs << "uniform vec4 uColorMatrixVector;" << endl; michael@0: } michael@0: if (aConfig.mFeatures & ENABLE_OPACITY) { michael@0: fs << "uniform COLOR_PRECISION float uLayerOpacity;" << endl; michael@0: } michael@0: } michael@0: michael@0: const char *sampler2D = "sampler2D"; michael@0: const char *texture2D = "texture2D"; michael@0: michael@0: if (aConfig.mFeatures & ENABLE_TEXTURE_RECT) { michael@0: fs << "uniform vec2 uTexCoordMultiplier;" << endl; michael@0: sampler2D = "sampler2DRect"; michael@0: texture2D = "texture2DRect"; michael@0: } michael@0: michael@0: if (aConfig.mFeatures & ENABLE_TEXTURE_EXTERNAL) { michael@0: sampler2D = "samplerExternalOES"; michael@0: } michael@0: michael@0: if (aConfig.mFeatures & ENABLE_TEXTURE_YCBCR) { michael@0: fs << "uniform sampler2D uYTexture;" << endl; michael@0: fs << "uniform sampler2D uCbTexture;" << endl; michael@0: fs << "uniform sampler2D uCrTexture;" << endl; michael@0: } else if (aConfig.mFeatures & ENABLE_TEXTURE_COMPONENT_ALPHA) { michael@0: fs << "uniform sampler2D uBlackTexture;" << endl; michael@0: fs << "uniform sampler2D uWhiteTexture;" << endl; michael@0: fs << "uniform bool uTexturePass2;" << endl; michael@0: } else { michael@0: fs << "uniform " << sampler2D << " uTexture;" << endl; michael@0: } michael@0: michael@0: if (aConfig.mFeatures & ENABLE_MASK_2D || michael@0: aConfig.mFeatures & ENABLE_MASK_3D) { michael@0: fs << "varying vec3 vMaskCoord;" << endl; michael@0: fs << "uniform sampler2D uMaskTexture;" << endl; michael@0: } michael@0: michael@0: if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) { michael@0: fs << "vec4 sample(vec2 coord) {" << endl; michael@0: fs << " vec4 color;" << endl; michael@0: if (aConfig.mFeatures & ENABLE_TEXTURE_YCBCR) { michael@0: fs << " COLOR_PRECISION float y = texture2D(uYTexture, coord).r;" << endl; michael@0: fs << " COLOR_PRECISION float cb = texture2D(uCbTexture, coord).r;" << endl; michael@0: fs << " COLOR_PRECISION float cr = texture2D(uCrTexture, coord).r;" << endl; michael@0: fs << " y = (y - 0.0625) * 1.164;" << endl; michael@0: fs << " cb = cb - 0.5;" << endl; michael@0: fs << " cr = cr - 0.5;" << endl; michael@0: fs << " color.r = y + cr * 1.596;" << endl; michael@0: fs << " color.g = y - 0.813 * cr - 0.391 * cb;" << endl; michael@0: fs << " color.b = y + cb * 2.018;" << endl; michael@0: fs << " color.a = 1.0;" << endl; michael@0: } else if (aConfig.mFeatures & ENABLE_TEXTURE_COMPONENT_ALPHA) { michael@0: fs << " COLOR_PRECISION vec3 onBlack = texture2D(uBlackTexture, coord).rgb;" << endl; michael@0: fs << " COLOR_PRECISION vec3 onWhite = texture2D(uWhiteTexture, coord).rgb;" << endl; michael@0: fs << " COLOR_PRECISION vec4 alphas = (1.0 - onWhite + onBlack).rgbg;" << endl; michael@0: fs << " if (uTexturePass2)" << endl; michael@0: fs << " color = vec4(onBlack, alphas.a);" << endl; michael@0: fs << " else" << endl; michael@0: fs << " color = alphas;" << endl; michael@0: } else { michael@0: fs << " color = " << texture2D << "(uTexture, coord);" << endl; michael@0: } michael@0: if (aConfig.mFeatures & ENABLE_TEXTURE_RB_SWAP) { michael@0: fs << " color = color.bgra;" << endl; michael@0: } michael@0: if (aConfig.mFeatures & ENABLE_TEXTURE_NO_ALPHA) { michael@0: fs << " color = vec4(color.rgb, 1.0);" << endl; michael@0: } michael@0: fs << " return color;" << endl; michael@0: fs << "}" << endl; michael@0: if (aConfig.mFeatures & ENABLE_BLUR) { michael@0: fs << "vec4 sampleAtRadius(vec2 coord, float radius) {" << endl; michael@0: fs << " coord += uBlurOffset;" << endl; michael@0: fs << " coord += radius * uBlurRadius;" << endl; michael@0: fs << " if (coord.x < 0. || coord.y < 0. || coord.x > 1. || coord.y > 1.)" << endl; michael@0: fs << " return vec4(0, 0, 0, 0);" << endl; michael@0: fs << " return sample(coord);" << endl; michael@0: fs << "}" << endl; michael@0: fs << "vec4 blur(vec4 color, vec2 coord) {" << endl; michael@0: fs << " vec4 total = color * uBlurGaussianKernel[0];" << endl; michael@0: fs << " for (int i = 1; i < " << GAUSSIAN_KERNEL_HALF_WIDTH << "; ++i) {" << endl; michael@0: fs << " float r = float(i) * " << GAUSSIAN_KERNEL_STEP << " << endl;" << endl; michael@0: fs << " float k = uBlurGaussianKernel[i];" << endl; michael@0: fs << " total += sampleAtRadius(coord, r) * k;" << endl; michael@0: fs << " total += sampleAtRadius(coord, -r) * k;" << endl; michael@0: fs << " }" << endl; michael@0: fs << " if (uBlurAlpha) {" << endl; michael@0: fs << " color *= total.a;" << endl; michael@0: fs << " } else {" << endl; michael@0: fs << " color = total;" << endl; michael@0: fs << " }" << endl; michael@0: fs << " return color;" << endl; michael@0: fs << "}" << endl; michael@0: } michael@0: } michael@0: fs << "void main() {" << endl; michael@0: if (aConfig.mFeatures & ENABLE_RENDER_COLOR) { michael@0: fs << " vec4 color = uRenderColor;" << endl; michael@0: } else { michael@0: if (aConfig.mFeatures & ENABLE_TEXTURE_RECT) { michael@0: fs << " vec4 color = sample(vTexCoord * uTexCoordMultiplier);" << endl; michael@0: } else { michael@0: fs << " vec4 color = sample(vTexCoord);" << endl; michael@0: } michael@0: if (aConfig.mFeatures & ENABLE_BLUR) { michael@0: fs << " color = blur(color, vTexCoord);" << endl; michael@0: } michael@0: if (aConfig.mFeatures & ENABLE_COLOR_MATRIX) { michael@0: fs << " color = uColorMatrix * vec4(color.rgb / color.a, color.a) + uColorMatrixVector;" << endl; michael@0: fs << " color.rgb *= color.a;" << endl; michael@0: } michael@0: if (aConfig.mFeatures & ENABLE_OPACITY) { michael@0: fs << " color *= uLayerOpacity;" << endl; michael@0: } michael@0: } michael@0: if (aConfig.mFeatures & ENABLE_MASK_3D) { michael@0: fs << " vec2 maskCoords = vMaskCoord.xy / vMaskCoord.z;" << endl; michael@0: fs << " COLOR_PRECISION float mask = texture2D(uMaskTexture, maskCoords).r;" << endl; michael@0: fs << " color *= mask;" << endl; michael@0: } else if (aConfig.mFeatures & ENABLE_MASK_2D) { michael@0: fs << " COLOR_PRECISION float mask = texture2D(uMaskTexture, vMaskCoord.xy).r;" << endl; michael@0: fs << " color *= mask;" << endl; michael@0: } else { michael@0: fs << " COLOR_PRECISION float mask = 1.0;" << endl; michael@0: fs << " color *= mask;" << endl; michael@0: } michael@0: fs << " gl_FragColor = color;" << endl; michael@0: fs << "}" << endl; michael@0: michael@0: result.mVertexShaderString = vs.str(); michael@0: result.mFragmentShaderString = fs.str(); michael@0: michael@0: result.mAttributes.AppendElement(Argument("aVertexCoord")); michael@0: if (aConfig.mFeatures & ENABLE_RENDER_COLOR) { michael@0: result.mTextureCount = 0; michael@0: } else { michael@0: result.mAttributes.AppendElement(Argument("aTexCoord")); michael@0: if (aConfig.mFeatures & ENABLE_TEXTURE_YCBCR) { michael@0: result.mTextureCount = 3; michael@0: } else if (aConfig.mFeatures & ENABLE_TEXTURE_COMPONENT_ALPHA) { michael@0: result.mTextureCount = 2; michael@0: } else { michael@0: result.mTextureCount = 1; michael@0: } michael@0: } michael@0: if (aConfig.mFeatures & ENABLE_MASK_2D || michael@0: aConfig.mFeatures & ENABLE_MASK_3D) { michael@0: result.mTextureCount = 1; michael@0: } michael@0: michael@0: return result; michael@0: } michael@0: michael@0: const char* const ShaderProgramOGL::VertexCoordAttrib = "aVertexCoord"; michael@0: const char* const ShaderProgramOGL::TexCoordAttrib = "aTexCoord"; michael@0: michael@0: ShaderProgramOGL::ShaderProgramOGL(GLContext* aGL, const ProgramProfileOGL& aProfile) michael@0: : mGL(aGL) michael@0: , mProgram(0) michael@0: , mProfile(aProfile) michael@0: , mProgramState(STATE_NEW) michael@0: { michael@0: } michael@0: michael@0: ShaderProgramOGL::~ShaderProgramOGL() michael@0: { michael@0: if (mProgram <= 0) { michael@0: return; michael@0: } michael@0: michael@0: nsRefPtr ctx = mGL->GetSharedContext(); michael@0: if (!ctx) { michael@0: ctx = mGL; michael@0: } michael@0: ctx->MakeCurrent(); michael@0: ctx->fDeleteProgram(mProgram); michael@0: } michael@0: michael@0: bool michael@0: ShaderProgramOGL::Initialize() michael@0: { michael@0: NS_ASSERTION(mProgramState == STATE_NEW, "Shader program has already been initialised"); michael@0: michael@0: ostringstream vs, fs; michael@0: for (uint32_t i = 0; i < mProfile.mDefines.Length(); ++i) { michael@0: vs << mProfile.mDefines[i] << endl; michael@0: fs << mProfile.mDefines[i] << endl; michael@0: } michael@0: vs << mProfile.mVertexShaderString << endl; michael@0: fs << mProfile.mFragmentShaderString << endl; michael@0: michael@0: if (!CreateProgram(vs.str().c_str(), fs.str().c_str())) { michael@0: mProgramState = STATE_ERROR; michael@0: return false; michael@0: } michael@0: michael@0: mProgramState = STATE_OK; michael@0: michael@0: for (uint32_t i = 0; i < KnownUniform::KnownUniformCount; ++i) { michael@0: mProfile.mUniforms[i].mLocation = michael@0: mGL->fGetUniformLocation(mProgram, mProfile.mUniforms[i].mNameString); michael@0: } michael@0: michael@0: for (uint32_t i = 0; i < mProfile.mAttributes.Length(); ++i) { michael@0: mProfile.mAttributes[i].mLocation = michael@0: mGL->fGetAttribLocation(mProgram, mProfile.mAttributes[i].mName); michael@0: NS_ASSERTION(mProfile.mAttributes[i].mLocation >= 0, "Bad attribute location."); michael@0: } michael@0: michael@0: //mProfile.mHasMatrixProj = mProfile.mUniforms[KnownUniform::MatrixProj].mLocation != -1; michael@0: michael@0: return true; michael@0: } michael@0: michael@0: GLint michael@0: ShaderProgramOGL::CreateShader(GLenum aShaderType, const char *aShaderSource) michael@0: { michael@0: GLint success, len = 0; michael@0: michael@0: GLint sh = mGL->fCreateShader(aShaderType); michael@0: mGL->fShaderSource(sh, 1, (const GLchar**)&aShaderSource, nullptr); michael@0: mGL->fCompileShader(sh); michael@0: mGL->fGetShaderiv(sh, LOCAL_GL_COMPILE_STATUS, &success); michael@0: mGL->fGetShaderiv(sh, LOCAL_GL_INFO_LOG_LENGTH, (GLint*) &len); michael@0: /* Even if compiling is successful, there may still be warnings. Print them michael@0: * in a debug build. The > 10 is to catch silly compilers that might put michael@0: * some whitespace in the log but otherwise leave it empty. michael@0: */ michael@0: if (!success michael@0: #ifdef DEBUG michael@0: || (len > 10 && PR_GetEnv("MOZ_DEBUG_SHADERS")) michael@0: #endif michael@0: ) michael@0: { michael@0: nsAutoCString log; michael@0: log.SetCapacity(len); michael@0: mGL->fGetShaderInfoLog(sh, len, (GLint*) &len, (char*) log.BeginWriting()); michael@0: log.SetLength(len); michael@0: michael@0: if (!success) { michael@0: printf_stderr("=== SHADER COMPILATION FAILED ===\n"); michael@0: } else { michael@0: printf_stderr("=== SHADER COMPILATION WARNINGS ===\n"); michael@0: } michael@0: michael@0: printf_stderr("=== Source:\n%s\n", aShaderSource); michael@0: printf_stderr("=== Log:\n%s\n", log.get()); michael@0: printf_stderr("============\n"); michael@0: michael@0: if (!success) { michael@0: mGL->fDeleteShader(sh); michael@0: return 0; michael@0: } michael@0: } michael@0: michael@0: return sh; michael@0: } michael@0: michael@0: bool michael@0: ShaderProgramOGL::CreateProgram(const char *aVertexShaderString, michael@0: const char *aFragmentShaderString) michael@0: { michael@0: GLuint vertexShader = CreateShader(LOCAL_GL_VERTEX_SHADER, aVertexShaderString); michael@0: GLuint fragmentShader = CreateShader(LOCAL_GL_FRAGMENT_SHADER, aFragmentShaderString); michael@0: michael@0: if (!vertexShader || !fragmentShader) michael@0: return false; michael@0: michael@0: GLint result = mGL->fCreateProgram(); michael@0: mGL->fAttachShader(result, vertexShader); michael@0: mGL->fAttachShader(result, fragmentShader); michael@0: michael@0: mGL->fLinkProgram(result); michael@0: michael@0: GLint success, len; michael@0: mGL->fGetProgramiv(result, LOCAL_GL_LINK_STATUS, &success); michael@0: mGL->fGetProgramiv(result, LOCAL_GL_INFO_LOG_LENGTH, (GLint*) &len); michael@0: /* Even if linking is successful, there may still be warnings. Print them michael@0: * in a debug build. The > 10 is to catch silly compilers that might put michael@0: * some whitespace in the log but otherwise leave it empty. michael@0: */ michael@0: if (!success michael@0: #ifdef DEBUG michael@0: || (len > 10 && PR_GetEnv("MOZ_DEBUG_SHADERS")) michael@0: #endif michael@0: ) michael@0: { michael@0: nsAutoCString log; michael@0: log.SetCapacity(len); michael@0: mGL->fGetProgramInfoLog(result, len, (GLint*) &len, (char*) log.BeginWriting()); michael@0: log.SetLength(len); michael@0: michael@0: if (!success) { michael@0: printf_stderr("=== PROGRAM LINKING FAILED ===\n"); michael@0: } else { michael@0: printf_stderr("=== PROGRAM LINKING WARNINGS ===\n"); michael@0: } michael@0: printf_stderr("=== Log:\n%s\n", log.get()); michael@0: printf_stderr("============\n"); michael@0: } michael@0: michael@0: // We can mark the shaders for deletion; they're attached to the program michael@0: // and will remain attached. michael@0: mGL->fDeleteShader(vertexShader); michael@0: mGL->fDeleteShader(fragmentShader); michael@0: michael@0: if (!success) { michael@0: mGL->fDeleteProgram(result); michael@0: return false; michael@0: } michael@0: michael@0: mProgram = result; michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: ShaderProgramOGL::Activate() michael@0: { michael@0: if (mProgramState == STATE_NEW) { michael@0: if (!Initialize()) { michael@0: NS_WARNING("Shader could not be initialised"); michael@0: return; michael@0: } michael@0: } michael@0: NS_ASSERTION(HasInitialized(), "Attempting to activate a program that's not in use!"); michael@0: mGL->fUseProgram(mProgram); michael@0: } michael@0: michael@0: } /* layers */ michael@0: } /* mozilla */