michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* vim: set ts=8 sts=4 et sw=4 tw=80: */ 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 michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "GLBlitHelper.h" michael@0: #include "GLContext.h" michael@0: #include "ScopedGLHelpers.h" michael@0: #include "mozilla/Preferences.h" michael@0: michael@0: namespace mozilla { michael@0: namespace gl { michael@0: michael@0: static void michael@0: RenderbufferStorageBySamples(GLContext* aGL, GLsizei aSamples, michael@0: GLenum aInternalFormat, const gfx::IntSize& aSize) michael@0: { michael@0: if (aSamples) { michael@0: aGL->fRenderbufferStorageMultisample(LOCAL_GL_RENDERBUFFER, michael@0: aSamples, michael@0: aInternalFormat, michael@0: aSize.width, aSize.height); michael@0: } else { michael@0: aGL->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, michael@0: aInternalFormat, michael@0: aSize.width, aSize.height); michael@0: } michael@0: } michael@0: michael@0: michael@0: GLuint michael@0: CreateTexture(GLContext* aGL, GLenum aInternalFormat, GLenum aFormat, michael@0: GLenum aType, const gfx::IntSize& aSize) michael@0: { michael@0: GLuint tex = 0; michael@0: aGL->fGenTextures(1, &tex); michael@0: ScopedBindTexture autoTex(aGL, tex); michael@0: michael@0: aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR); michael@0: aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR); michael@0: aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE); michael@0: aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE); michael@0: michael@0: aGL->fTexImage2D(LOCAL_GL_TEXTURE_2D, michael@0: 0, michael@0: aInternalFormat, michael@0: aSize.width, aSize.height, michael@0: 0, michael@0: aFormat, michael@0: aType, michael@0: nullptr); michael@0: michael@0: return tex; michael@0: } michael@0: michael@0: michael@0: GLuint michael@0: CreateTextureForOffscreen(GLContext* aGL, const GLFormats& aFormats, michael@0: const gfx::IntSize& aSize) michael@0: { michael@0: MOZ_ASSERT(aFormats.color_texInternalFormat); michael@0: MOZ_ASSERT(aFormats.color_texFormat); michael@0: MOZ_ASSERT(aFormats.color_texType); michael@0: michael@0: return CreateTexture(aGL, michael@0: aFormats.color_texInternalFormat, michael@0: aFormats.color_texFormat, michael@0: aFormats.color_texType, michael@0: aSize); michael@0: } michael@0: michael@0: michael@0: GLuint michael@0: CreateRenderbuffer(GLContext* aGL, GLenum aFormat, GLsizei aSamples, michael@0: const gfx::IntSize& aSize) michael@0: { michael@0: GLuint rb = 0; michael@0: aGL->fGenRenderbuffers(1, &rb); michael@0: ScopedBindRenderbuffer autoRB(aGL, rb); michael@0: michael@0: RenderbufferStorageBySamples(aGL, aSamples, aFormat, aSize); michael@0: michael@0: return rb; michael@0: } michael@0: michael@0: michael@0: void michael@0: CreateRenderbuffersForOffscreen(GLContext* aGL, const GLFormats& aFormats, michael@0: const gfx::IntSize& aSize, bool aMultisample, michael@0: GLuint* aColorMSRB, GLuint* aDepthRB, michael@0: GLuint* aStencilRB) michael@0: { michael@0: GLsizei samples = aMultisample ? aFormats.samples : 0; michael@0: if (aColorMSRB) { michael@0: MOZ_ASSERT(aFormats.samples > 0); michael@0: MOZ_ASSERT(aFormats.color_rbFormat); michael@0: michael@0: *aColorMSRB = CreateRenderbuffer(aGL, aFormats.color_rbFormat, samples, aSize); michael@0: } michael@0: michael@0: if (aDepthRB && michael@0: aStencilRB && michael@0: aFormats.depthStencil) michael@0: { michael@0: *aDepthRB = CreateRenderbuffer(aGL, aFormats.depthStencil, samples, aSize); michael@0: *aStencilRB = *aDepthRB; michael@0: } else { michael@0: if (aDepthRB) { michael@0: MOZ_ASSERT(aFormats.depth); michael@0: michael@0: *aDepthRB = CreateRenderbuffer(aGL, aFormats.depth, samples, aSize); michael@0: } michael@0: michael@0: if (aStencilRB) { michael@0: MOZ_ASSERT(aFormats.stencil); michael@0: michael@0: *aStencilRB = CreateRenderbuffer(aGL, aFormats.stencil, samples, aSize); michael@0: } michael@0: } michael@0: } michael@0: michael@0: michael@0: GLBlitHelper::GLBlitHelper(GLContext* gl) michael@0: : mGL(gl) michael@0: , mTexBlit_Buffer(0) michael@0: , mTexBlit_VertShader(0) michael@0: , mTex2DBlit_FragShader(0) michael@0: , mTex2DRectBlit_FragShader(0) michael@0: , mTex2DBlit_Program(0) michael@0: , mTex2DRectBlit_Program(0) michael@0: { michael@0: } michael@0: michael@0: GLBlitHelper::~GLBlitHelper() michael@0: { michael@0: DeleteTexBlitProgram(); michael@0: } michael@0: michael@0: // Allowed to be destructive of state we restore in functions below. michael@0: bool michael@0: GLBlitHelper::InitTexQuadProgram(GLenum target) michael@0: { michael@0: const char kTexBlit_VertShaderSource[] = "\ michael@0: attribute vec2 aPosition; \n\ michael@0: \n\ michael@0: varying vec2 vTexCoord; \n\ michael@0: \n\ michael@0: void main(void) { \n\ michael@0: vTexCoord = aPosition; \n\ michael@0: vec2 vertPos = aPosition * 2.0 - 1.0; \n\ michael@0: gl_Position = vec4(vertPos, 0.0, 1.0); \n\ michael@0: } \n\ michael@0: "; michael@0: michael@0: const char kTex2DBlit_FragShaderSource[] = "\ michael@0: #ifdef GL_FRAGMENT_PRECISION_HIGH \n\ michael@0: precision highp float; \n\ michael@0: #else \n\ michael@0: precision mediump float; \n\ michael@0: #endif \n\ michael@0: \n\ michael@0: uniform sampler2D uTexUnit; \n\ michael@0: \n\ michael@0: varying vec2 vTexCoord; \n\ michael@0: \n\ michael@0: void main(void) { \n\ michael@0: gl_FragColor = texture2D(uTexUnit, vTexCoord); \n\ michael@0: } \n\ michael@0: "; michael@0: michael@0: const char kTex2DRectBlit_FragShaderSource[] = "\ michael@0: #ifdef GL_FRAGMENT_PRECISION_HIGH \n\ michael@0: precision highp float; \n\ michael@0: #else \n\ michael@0: precision mediump float; \n\ michael@0: #endif \n\ michael@0: \n\ michael@0: uniform sampler2D uTexUnit; \n\ michael@0: uniform vec2 uTexCoordMult; \n\ michael@0: \n\ michael@0: varying vec2 vTexCoord; \n\ michael@0: \n\ michael@0: void main(void) { \n\ michael@0: gl_FragColor = texture2DRect(uTexUnit, \n\ michael@0: vTexCoord * uTexCoordMult); \n\ michael@0: } \n\ michael@0: "; michael@0: michael@0: MOZ_ASSERT(target == LOCAL_GL_TEXTURE_2D || michael@0: target == LOCAL_GL_TEXTURE_RECTANGLE_ARB); michael@0: bool success = false; michael@0: michael@0: GLuint *programPtr; michael@0: GLuint *fragShaderPtr; michael@0: const char* fragShaderSource; michael@0: if (target == LOCAL_GL_TEXTURE_2D) { michael@0: programPtr = &mTex2DBlit_Program; michael@0: fragShaderPtr = &mTex2DBlit_FragShader; michael@0: fragShaderSource = kTex2DBlit_FragShaderSource; michael@0: } else { michael@0: programPtr = &mTex2DRectBlit_Program; michael@0: fragShaderPtr = &mTex2DRectBlit_FragShader; michael@0: fragShaderSource = kTex2DRectBlit_FragShaderSource; michael@0: } michael@0: michael@0: GLuint& program = *programPtr; michael@0: GLuint& fragShader = *fragShaderPtr; michael@0: michael@0: // Use do-while(false) to let us break on failure michael@0: do { michael@0: if (program) { michael@0: // Already have it... michael@0: success = true; michael@0: break; michael@0: } michael@0: michael@0: if (!mTexBlit_Buffer) { michael@0: michael@0: /* CCW tri-strip: michael@0: * 2---3 michael@0: * | \ | michael@0: * 0---1 michael@0: */ michael@0: GLfloat verts[] = { michael@0: 0.0f, 0.0f, michael@0: 1.0f, 0.0f, michael@0: 0.0f, 1.0f, michael@0: 1.0f, 1.0f michael@0: }; michael@0: michael@0: MOZ_ASSERT(!mTexBlit_Buffer); michael@0: mGL->fGenBuffers(1, &mTexBlit_Buffer); michael@0: mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mTexBlit_Buffer); michael@0: michael@0: const size_t vertsSize = sizeof(verts); michael@0: // Make sure we have a sane size. michael@0: MOZ_ASSERT(vertsSize >= 3 * sizeof(GLfloat)); michael@0: mGL->fBufferData(LOCAL_GL_ARRAY_BUFFER, vertsSize, verts, LOCAL_GL_STATIC_DRAW); michael@0: } michael@0: michael@0: if (!mTexBlit_VertShader) { michael@0: michael@0: const char* vertShaderSource = kTexBlit_VertShaderSource; michael@0: michael@0: mTexBlit_VertShader = mGL->fCreateShader(LOCAL_GL_VERTEX_SHADER); michael@0: mGL->fShaderSource(mTexBlit_VertShader, 1, &vertShaderSource, nullptr); michael@0: mGL->fCompileShader(mTexBlit_VertShader); michael@0: } michael@0: michael@0: MOZ_ASSERT(!fragShader); michael@0: fragShader = mGL->fCreateShader(LOCAL_GL_FRAGMENT_SHADER); michael@0: mGL->fShaderSource(fragShader, 1, &fragShaderSource, nullptr); michael@0: mGL->fCompileShader(fragShader); michael@0: michael@0: program = mGL->fCreateProgram(); michael@0: mGL->fAttachShader(program, mTexBlit_VertShader); michael@0: mGL->fAttachShader(program, fragShader); michael@0: mGL->fBindAttribLocation(program, 0, "aPosition"); michael@0: mGL->fLinkProgram(program); michael@0: michael@0: if (mGL->DebugMode()) { michael@0: GLint status = 0; michael@0: mGL->fGetShaderiv(mTexBlit_VertShader, LOCAL_GL_COMPILE_STATUS, &status); michael@0: if (status != LOCAL_GL_TRUE) { michael@0: NS_ERROR("Vert shader compilation failed."); michael@0: michael@0: GLint length = 0; michael@0: mGL->fGetShaderiv(mTexBlit_VertShader, LOCAL_GL_INFO_LOG_LENGTH, &length); michael@0: if (!length) { michael@0: printf_stderr("No shader info log available.\n"); michael@0: break; michael@0: } michael@0: michael@0: nsAutoArrayPtr buffer(new char[length]); michael@0: mGL->fGetShaderInfoLog(mTexBlit_VertShader, length, nullptr, buffer); michael@0: michael@0: printf_stderr("Shader info log (%d bytes): %s\n", length, buffer.get()); michael@0: break; michael@0: } michael@0: michael@0: status = 0; michael@0: mGL->fGetShaderiv(fragShader, LOCAL_GL_COMPILE_STATUS, &status); michael@0: if (status != LOCAL_GL_TRUE) { michael@0: NS_ERROR("Frag shader compilation failed."); michael@0: michael@0: GLint length = 0; michael@0: mGL->fGetShaderiv(fragShader, LOCAL_GL_INFO_LOG_LENGTH, &length); michael@0: if (!length) { michael@0: printf_stderr("No shader info log available.\n"); michael@0: break; michael@0: } michael@0: michael@0: nsAutoArrayPtr buffer(new char[length]); michael@0: mGL->fGetShaderInfoLog(fragShader, length, nullptr, buffer); michael@0: michael@0: printf_stderr("Shader info log (%d bytes): %s\n", length, buffer.get()); michael@0: break; michael@0: } michael@0: } michael@0: michael@0: GLint status = 0; michael@0: mGL->fGetProgramiv(program, LOCAL_GL_LINK_STATUS, &status); michael@0: if (status != LOCAL_GL_TRUE) { michael@0: if (mGL->DebugMode()) { michael@0: NS_ERROR("Linking blit program failed."); michael@0: GLint length = 0; michael@0: mGL->fGetProgramiv(program, LOCAL_GL_INFO_LOG_LENGTH, &length); michael@0: if (!length) { michael@0: printf_stderr("No program info log available.\n"); michael@0: break; michael@0: } michael@0: michael@0: nsAutoArrayPtr buffer(new char[length]); michael@0: mGL->fGetProgramInfoLog(program, length, nullptr, buffer); michael@0: michael@0: printf_stderr("Program info log (%d bytes): %s\n", length, buffer.get()); michael@0: } michael@0: break; michael@0: } michael@0: michael@0: MOZ_ASSERT(mGL->fGetAttribLocation(program, "aPosition") == 0); michael@0: GLint texUnitLoc = mGL->fGetUniformLocation(program, "uTexUnit"); michael@0: MOZ_ASSERT(texUnitLoc != -1, "uniform not found"); michael@0: michael@0: // Set uniforms here: michael@0: mGL->fUseProgram(program); michael@0: mGL->fUniform1i(texUnitLoc, 0); michael@0: michael@0: success = true; michael@0: } while (false); michael@0: michael@0: if (!success) { michael@0: NS_ERROR("Creating program for texture blit failed!"); michael@0: michael@0: // Clean up: michael@0: DeleteTexBlitProgram(); michael@0: return false; michael@0: } michael@0: michael@0: mGL->fUseProgram(program); michael@0: mGL->fEnableVertexAttribArray(0); michael@0: mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mTexBlit_Buffer); michael@0: mGL->fVertexAttribPointer(0, michael@0: 2, michael@0: LOCAL_GL_FLOAT, michael@0: false, michael@0: 0, michael@0: nullptr); michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: GLBlitHelper::UseTexQuadProgram(GLenum target, const gfx::IntSize& srcSize) michael@0: { michael@0: if (!InitTexQuadProgram(target)) { michael@0: return false; michael@0: } michael@0: michael@0: if (target == LOCAL_GL_TEXTURE_RECTANGLE_ARB) { michael@0: GLint texCoordMultLoc = mGL->fGetUniformLocation(mTex2DRectBlit_Program, "uTexCoordMult"); michael@0: MOZ_ASSERT(texCoordMultLoc != -1, "uniform not found"); michael@0: mGL->fUniform2f(texCoordMultLoc, srcSize.width, srcSize.height); michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: GLBlitHelper::DeleteTexBlitProgram() michael@0: { michael@0: if (mTexBlit_Buffer) { michael@0: mGL->fDeleteBuffers(1, &mTexBlit_Buffer); michael@0: mTexBlit_Buffer = 0; michael@0: } michael@0: if (mTexBlit_VertShader) { michael@0: mGL->fDeleteShader(mTexBlit_VertShader); michael@0: mTexBlit_VertShader = 0; michael@0: } michael@0: if (mTex2DBlit_FragShader) { michael@0: mGL->fDeleteShader(mTex2DBlit_FragShader); michael@0: mTex2DBlit_FragShader = 0; michael@0: } michael@0: if (mTex2DRectBlit_FragShader) { michael@0: mGL->fDeleteShader(mTex2DRectBlit_FragShader); michael@0: mTex2DRectBlit_FragShader = 0; michael@0: } michael@0: if (mTex2DBlit_Program) { michael@0: mGL->fDeleteProgram(mTex2DBlit_Program); michael@0: mTex2DBlit_Program = 0; michael@0: } michael@0: if (mTex2DRectBlit_Program) { michael@0: mGL->fDeleteProgram(mTex2DRectBlit_Program); michael@0: mTex2DRectBlit_Program = 0; michael@0: } michael@0: } michael@0: michael@0: void michael@0: GLBlitHelper::BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB, michael@0: const gfx::IntSize& srcSize, michael@0: const gfx::IntSize& destSize) michael@0: { michael@0: MOZ_ASSERT(!srcFB || mGL->fIsFramebuffer(srcFB)); michael@0: MOZ_ASSERT(!destFB || mGL->fIsFramebuffer(destFB)); michael@0: michael@0: MOZ_ASSERT(mGL->IsSupported(GLFeature::framebuffer_blit)); michael@0: michael@0: ScopedBindFramebuffer boundFB(mGL); michael@0: ScopedGLState scissor(mGL, LOCAL_GL_SCISSOR_TEST, false); michael@0: michael@0: mGL->BindReadFB(srcFB); michael@0: mGL->BindDrawFB(destFB); michael@0: michael@0: mGL->fBlitFramebuffer(0, 0, srcSize.width, srcSize.height, michael@0: 0, 0, destSize.width, destSize.height, michael@0: LOCAL_GL_COLOR_BUFFER_BIT, michael@0: LOCAL_GL_NEAREST); michael@0: } michael@0: michael@0: void michael@0: GLBlitHelper::BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB, michael@0: const gfx::IntSize& srcSize, michael@0: const gfx::IntSize& destSize, michael@0: const GLFormats& srcFormats) michael@0: { michael@0: MOZ_ASSERT(!srcFB || mGL->fIsFramebuffer(srcFB)); michael@0: MOZ_ASSERT(!destFB || mGL->fIsFramebuffer(destFB)); michael@0: michael@0: if (mGL->IsSupported(GLFeature::framebuffer_blit)) { michael@0: BlitFramebufferToFramebuffer(srcFB, destFB, michael@0: srcSize, destSize); michael@0: return; michael@0: } michael@0: michael@0: GLuint tex = CreateTextureForOffscreen(mGL, srcFormats, srcSize); michael@0: MOZ_ASSERT(tex); michael@0: michael@0: BlitFramebufferToTexture(srcFB, tex, srcSize, srcSize); michael@0: BlitTextureToFramebuffer(tex, destFB, srcSize, destSize); michael@0: michael@0: mGL->fDeleteTextures(1, &tex); michael@0: } michael@0: michael@0: void michael@0: GLBlitHelper::BlitTextureToFramebuffer(GLuint srcTex, GLuint destFB, michael@0: const gfx::IntSize& srcSize, michael@0: const gfx::IntSize& destSize, michael@0: GLenum srcTarget) michael@0: { michael@0: MOZ_ASSERT(mGL->fIsTexture(srcTex)); michael@0: MOZ_ASSERT(!destFB || mGL->fIsFramebuffer(destFB)); michael@0: michael@0: if (mGL->IsSupported(GLFeature::framebuffer_blit)) { michael@0: ScopedFramebufferForTexture srcWrapper(mGL, srcTex, srcTarget); michael@0: MOZ_ASSERT(srcWrapper.IsComplete()); michael@0: michael@0: BlitFramebufferToFramebuffer(srcWrapper.FB(), destFB, michael@0: srcSize, destSize); michael@0: return; michael@0: } michael@0: michael@0: michael@0: ScopedBindFramebuffer boundFB(mGL, destFB); michael@0: // UseTexQuadProgram initializes a shader that reads michael@0: // from texture unit 0. michael@0: ScopedBindTextureUnit boundTU(mGL, LOCAL_GL_TEXTURE0); michael@0: ScopedBindTexture boundTex(mGL, srcTex, srcTarget); michael@0: michael@0: GLuint boundProgram = 0; michael@0: mGL->GetUIntegerv(LOCAL_GL_CURRENT_PROGRAM, &boundProgram); michael@0: michael@0: GLuint boundBuffer = 0; michael@0: mGL->GetUIntegerv(LOCAL_GL_ARRAY_BUFFER_BINDING, &boundBuffer); michael@0: michael@0: /* michael@0: * mGL->fGetVertexAttribiv takes: michael@0: * VERTEX_ATTRIB_ARRAY_ENABLED michael@0: * VERTEX_ATTRIB_ARRAY_SIZE, michael@0: * VERTEX_ATTRIB_ARRAY_STRIDE, michael@0: * VERTEX_ATTRIB_ARRAY_TYPE, michael@0: * VERTEX_ATTRIB_ARRAY_NORMALIZED, michael@0: * VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, michael@0: * CURRENT_VERTEX_ATTRIB michael@0: * michael@0: * CURRENT_VERTEX_ATTRIB is vertex shader state. \o/ michael@0: * Others appear to be vertex array state, michael@0: * or alternatively in the internal vertex array state michael@0: * for a buffer object. michael@0: */ michael@0: michael@0: GLint attrib0_enabled = 0; michael@0: GLint attrib0_size = 0; michael@0: GLint attrib0_stride = 0; michael@0: GLint attrib0_type = 0; michael@0: GLint attrib0_normalized = 0; michael@0: GLint attrib0_bufferBinding = 0; michael@0: void* attrib0_pointer = nullptr; michael@0: michael@0: mGL->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_ENABLED, &attrib0_enabled); michael@0: mGL->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_SIZE, &attrib0_size); michael@0: mGL->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_STRIDE, &attrib0_stride); michael@0: mGL->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_TYPE, &attrib0_type); michael@0: mGL->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &attrib0_normalized); michael@0: mGL->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &attrib0_bufferBinding); michael@0: mGL->fGetVertexAttribPointerv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_POINTER, &attrib0_pointer); michael@0: // Note that uniform values are program state, so we don't need to rebind those. michael@0: michael@0: ScopedGLState blend (mGL, LOCAL_GL_BLEND, false); michael@0: ScopedGLState cullFace (mGL, LOCAL_GL_CULL_FACE, false); michael@0: ScopedGLState depthTest (mGL, LOCAL_GL_DEPTH_TEST, false); michael@0: ScopedGLState dither (mGL, LOCAL_GL_DITHER, false); michael@0: ScopedGLState polyOffsFill(mGL, LOCAL_GL_POLYGON_OFFSET_FILL, false); michael@0: ScopedGLState sampleAToC (mGL, LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE, false); michael@0: ScopedGLState sampleCover (mGL, LOCAL_GL_SAMPLE_COVERAGE, false); michael@0: ScopedGLState scissor (mGL, LOCAL_GL_SCISSOR_TEST, false); michael@0: ScopedGLState stencil (mGL, LOCAL_GL_STENCIL_TEST, false); michael@0: michael@0: realGLboolean colorMask[4]; michael@0: mGL->fGetBooleanv(LOCAL_GL_COLOR_WRITEMASK, colorMask); michael@0: mGL->fColorMask(LOCAL_GL_TRUE, michael@0: LOCAL_GL_TRUE, michael@0: LOCAL_GL_TRUE, michael@0: LOCAL_GL_TRUE); michael@0: michael@0: GLint viewport[4]; michael@0: mGL->fGetIntegerv(LOCAL_GL_VIEWPORT, viewport); michael@0: mGL->fViewport(0, 0, destSize.width, destSize.height); michael@0: michael@0: // Does destructive things to (only!) what we just saved above. michael@0: bool good = UseTexQuadProgram(srcTarget, srcSize); michael@0: if (!good) { michael@0: // We're up against the wall, so bail. michael@0: // This should really be MOZ_CRASH(why) or MOZ_RUNTIME_ASSERT(good). michael@0: printf_stderr("[%s:%d] Fatal Error: Failed to prepare to blit texture->framebuffer.\n", michael@0: __FILE__, __LINE__); michael@0: MOZ_CRASH(); michael@0: } michael@0: mGL->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4); michael@0: michael@0: mGL->fViewport(viewport[0], viewport[1], michael@0: viewport[2], viewport[3]); michael@0: michael@0: mGL->fColorMask(colorMask[0], michael@0: colorMask[1], michael@0: colorMask[2], michael@0: colorMask[3]); michael@0: michael@0: if (attrib0_enabled) michael@0: mGL->fEnableVertexAttribArray(0); michael@0: michael@0: mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, attrib0_bufferBinding); michael@0: mGL->fVertexAttribPointer(0, michael@0: attrib0_size, michael@0: attrib0_type, michael@0: attrib0_normalized, michael@0: attrib0_stride, michael@0: attrib0_pointer); michael@0: michael@0: mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, boundBuffer); michael@0: michael@0: mGL->fUseProgram(boundProgram); michael@0: } michael@0: michael@0: void michael@0: GLBlitHelper::BlitFramebufferToTexture(GLuint srcFB, GLuint destTex, michael@0: const gfx::IntSize& srcSize, michael@0: const gfx::IntSize& destSize, michael@0: GLenum destTarget) michael@0: { michael@0: MOZ_ASSERT(!srcFB || mGL->fIsFramebuffer(srcFB)); michael@0: MOZ_ASSERT(mGL->fIsTexture(destTex)); michael@0: michael@0: if (mGL->IsSupported(GLFeature::framebuffer_blit)) { michael@0: ScopedFramebufferForTexture destWrapper(mGL, destTex, destTarget); michael@0: michael@0: BlitFramebufferToFramebuffer(srcFB, destWrapper.FB(), michael@0: srcSize, destSize); michael@0: return; michael@0: } michael@0: michael@0: ScopedBindTexture autoTex(mGL, destTex, destTarget); michael@0: ScopedBindFramebuffer boundFB(mGL, srcFB); michael@0: ScopedGLState scissor(mGL, LOCAL_GL_SCISSOR_TEST, false); michael@0: michael@0: mGL->fCopyTexSubImage2D(destTarget, 0, michael@0: 0, 0, michael@0: 0, 0, michael@0: srcSize.width, srcSize.height); michael@0: } michael@0: michael@0: void michael@0: GLBlitHelper::BlitTextureToTexture(GLuint srcTex, GLuint destTex, michael@0: const gfx::IntSize& srcSize, michael@0: const gfx::IntSize& destSize, michael@0: GLenum srcTarget, GLenum destTarget) michael@0: { michael@0: MOZ_ASSERT(mGL->fIsTexture(srcTex)); michael@0: MOZ_ASSERT(mGL->fIsTexture(destTex)); michael@0: michael@0: // Generally, just use the CopyTexSubImage path michael@0: ScopedFramebufferForTexture srcWrapper(mGL, srcTex, srcTarget); michael@0: michael@0: BlitFramebufferToTexture(srcWrapper.FB(), destTex, michael@0: srcSize, destSize, destTarget); michael@0: } michael@0: michael@0: } michael@0: }