void GLBlitHelper::BlitTextureToTexture(GLuint srcTex, GLuint destTex, const gfxIntSize& srcSize, const gfxIntSize& destSize, GLenum srcTarget, GLenum destTarget) { MOZ_ASSERT(mGL->fIsTexture(srcTex)); MOZ_ASSERT(mGL->fIsTexture(destTex)); // Generally, just use the CopyTexSubImage path ScopedFramebufferForTexture srcWrapper(mGL, srcTex, srcTarget); BlitFramebufferToTexture(srcWrapper.FB(), destTex, srcSize, destSize, destTarget); }
/*static*/ void SharedSurface::ProdCopy(SharedSurface* src, SharedSurface* dest, SurfaceFactory* factory) { GLContext* gl = src->mGL; // If `src` begins locked, it must end locked, though we may // temporarily unlock it if we need to. MOZ_ASSERT((src == gl->GetLockedSurface()) == src->IsLocked()); gl->MakeCurrent(); if (src->mAttachType == AttachmentType::Screen && dest->mAttachType == AttachmentType::Screen) { // Here, we actually need to blit through a temp surface, so let's make one. nsAutoPtr<SharedSurface_GLTexture> tempSurf; tempSurf = SharedSurface_GLTexture::Create(gl, gl, factory->mFormats, src->mSize, factory->mCaps.alpha); ProdCopy(src, tempSurf, factory); ProdCopy(tempSurf, dest, factory); return; } if (src->mAttachType == AttachmentType::Screen) { SharedSurface* origLocked = gl->GetLockedSurface(); bool srcNeedsUnlock = false; bool origNeedsRelock = false; if (origLocked != src) { if (origLocked) { origLocked->UnlockProd(); origNeedsRelock = true; } src->LockProd(); srcNeedsUnlock = true; } if (dest->mAttachType == AttachmentType::GLTexture) { GLuint destTex = dest->ProdTexture(); GLenum destTarget = dest->ProdTextureTarget(); gl->BlitHelper()->BlitFramebufferToTexture(0, destTex, src->mSize, dest->mSize, destTarget); } else if (dest->mAttachType == AttachmentType::GLRenderbuffer) { GLuint destRB = dest->ProdRenderbuffer(); ScopedFramebufferForRenderbuffer destWrapper(gl, destRB); gl->BlitHelper()->BlitFramebufferToFramebuffer(0, destWrapper.FB(), src->mSize, dest->mSize); } else { MOZ_CRASH("Unhandled dest->mAttachType."); } if (srcNeedsUnlock) src->UnlockProd(); if (origNeedsRelock) origLocked->LockProd(); return; } if (dest->mAttachType == AttachmentType::Screen) { SharedSurface* origLocked = gl->GetLockedSurface(); bool destNeedsUnlock = false; bool origNeedsRelock = false; if (origLocked != dest) { if (origLocked) { origLocked->UnlockProd(); origNeedsRelock = true; } dest->LockProd(); destNeedsUnlock = true; } if (src->mAttachType == AttachmentType::GLTexture) { GLuint srcTex = src->ProdTexture(); GLenum srcTarget = src->ProdTextureTarget(); gl->BlitHelper()->BlitTextureToFramebuffer(srcTex, 0, src->mSize, dest->mSize, srcTarget); } else if (src->mAttachType == AttachmentType::GLRenderbuffer) { GLuint srcRB = src->ProdRenderbuffer(); ScopedFramebufferForRenderbuffer srcWrapper(gl, srcRB); gl->BlitHelper()->BlitFramebufferToFramebuffer(srcWrapper.FB(), 0, src->mSize, dest->mSize); } else { MOZ_CRASH("Unhandled src->mAttachType."); } if (destNeedsUnlock) dest->UnlockProd(); if (origNeedsRelock) origLocked->LockProd(); return; } // Alright, done with cases involving Screen types. // Only {src,dest}x{texture,renderbuffer} left. if (src->mAttachType == AttachmentType::GLTexture) { GLuint srcTex = src->ProdTexture(); GLenum srcTarget = src->ProdTextureTarget(); if (dest->mAttachType == AttachmentType::GLTexture) { GLuint destTex = dest->ProdTexture(); GLenum destTarget = dest->ProdTextureTarget(); gl->BlitHelper()->BlitTextureToTexture(srcTex, destTex, src->mSize, dest->mSize, srcTarget, destTarget); return; } if (dest->mAttachType == AttachmentType::GLRenderbuffer) { GLuint destRB = dest->ProdRenderbuffer(); ScopedFramebufferForRenderbuffer destWrapper(gl, destRB); gl->BlitHelper()->BlitTextureToFramebuffer(srcTex, destWrapper.FB(), src->mSize, dest->mSize, srcTarget); return; } MOZ_CRASH("Unhandled dest->mAttachType."); } if (src->mAttachType == AttachmentType::GLRenderbuffer) { GLuint srcRB = src->ProdRenderbuffer(); ScopedFramebufferForRenderbuffer srcWrapper(gl, srcRB); if (dest->mAttachType == AttachmentType::GLTexture) { GLuint destTex = dest->ProdTexture(); GLenum destTarget = dest->ProdTextureTarget(); gl->BlitHelper()->BlitFramebufferToTexture(srcWrapper.FB(), destTex, src->mSize, dest->mSize, destTarget); return; } if (dest->mAttachType == AttachmentType::GLRenderbuffer) { GLuint destRB = dest->ProdRenderbuffer(); ScopedFramebufferForRenderbuffer destWrapper(gl, destRB); gl->BlitHelper()->BlitFramebufferToFramebuffer(srcWrapper.FB(), destWrapper.FB(), src->mSize, dest->mSize); return; } MOZ_CRASH("Unhandled dest->mAttachType."); } MOZ_CRASH("Unhandled src->mAttachType."); }
// |src| must begin and end locked, though we may // temporarily unlock it if we need to. void SharedSurface_GL::ProdCopy(SharedSurface_GL* src, SharedSurface_GL* dest, SurfaceFactory_GL* factory) { GLContext* gl = src->GL(); gl->MakeCurrent(); if (src->AttachType() == AttachmentType::Screen && dest->AttachType() == AttachmentType::Screen) { // Here, we actually need to blit through a temp surface, so let's make one. nsAutoPtr<SharedSurface_GLTexture> tempSurf( SharedSurface_GLTexture::Create(gl, gl, factory->Formats(), src->Size(), factory->Caps().alpha)); ProdCopy(src, tempSurf, factory); ProdCopy(tempSurf, dest, factory); return; } if (src->AttachType() == AttachmentType::Screen) { SharedSurface_GL* origLocked = gl->GetLockedSurface(); bool srcNeedsUnlock = false; bool origNeedsRelock = false; if (origLocked != src) { if (origLocked) { origLocked->UnlockProd(); origNeedsRelock = true; } src->LockProd(); srcNeedsUnlock = true; } if (dest->AttachType() == AttachmentType::GLTexture) { GLuint destTex = dest->ProdTexture(); GLenum destTarget = dest->ProdTextureTarget(); gl->BlitHelper()->BlitFramebufferToTexture(0, destTex, src->Size(), dest->Size(), destTarget); } else if (dest->AttachType() == AttachmentType::GLRenderbuffer) { GLuint destRB = dest->ProdRenderbuffer(); ScopedFramebufferForRenderbuffer destWrapper(gl, destRB); gl->BlitHelper()->BlitFramebufferToFramebuffer(0, destWrapper.FB(), src->Size(), dest->Size()); } else { MOZ_CRASH("Unhandled dest->AttachType()."); } if (srcNeedsUnlock) src->UnlockProd(); if (origNeedsRelock) origLocked->LockProd(); return; } if (dest->AttachType() == AttachmentType::Screen) { SharedSurface_GL* origLocked = gl->GetLockedSurface(); bool destNeedsUnlock = false; bool origNeedsRelock = false; if (origLocked != dest) { if (origLocked) { origLocked->UnlockProd(); origNeedsRelock = true; } dest->LockProd(); destNeedsUnlock = true; } if (src->AttachType() == AttachmentType::GLTexture) { GLuint srcTex = src->ProdTexture(); GLenum srcTarget = src->ProdTextureTarget(); gl->BlitHelper()->BlitTextureToFramebuffer(srcTex, 0, src->Size(), dest->Size(), srcTarget); } else if (src->AttachType() == AttachmentType::GLRenderbuffer) { GLuint srcRB = src->ProdRenderbuffer(); ScopedFramebufferForRenderbuffer srcWrapper(gl, srcRB); gl->BlitHelper()->BlitFramebufferToFramebuffer(srcWrapper.FB(), 0, src->Size(), dest->Size()); } else { MOZ_CRASH("Unhandled src->AttachType()."); } if (destNeedsUnlock) dest->UnlockProd(); if (origNeedsRelock) origLocked->LockProd(); return; } // Alright, done with cases involving Screen types. // Only {src,dest}x{texture,renderbuffer} left. if (src->AttachType() == AttachmentType::GLTexture) { GLuint srcTex = src->ProdTexture(); GLenum srcTarget = src->ProdTextureTarget(); if (dest->AttachType() == AttachmentType::GLTexture) { GLuint destTex = dest->ProdTexture(); GLenum destTarget = dest->ProdTextureTarget(); gl->BlitHelper()->BlitTextureToTexture(srcTex, destTex, src->Size(), dest->Size(), srcTarget, destTarget); return; } if (dest->AttachType() == AttachmentType::GLRenderbuffer) { GLuint destRB = dest->ProdRenderbuffer(); ScopedFramebufferForRenderbuffer destWrapper(gl, destRB); gl->BlitHelper()->BlitTextureToFramebuffer(srcTex, destWrapper.FB(), src->Size(), dest->Size(), srcTarget); return; } MOZ_CRASH("Unhandled dest->AttachType()."); } if (src->AttachType() == AttachmentType::GLRenderbuffer) { GLuint srcRB = src->ProdRenderbuffer(); ScopedFramebufferForRenderbuffer srcWrapper(gl, srcRB); if (dest->AttachType() == AttachmentType::GLTexture) { GLuint destTex = dest->ProdTexture(); GLenum destTarget = dest->ProdTextureTarget(); gl->BlitHelper()->BlitFramebufferToTexture(srcWrapper.FB(), destTex, src->Size(), dest->Size(), destTarget); return; } if (dest->AttachType() == AttachmentType::GLRenderbuffer) { GLuint destRB = dest->ProdRenderbuffer(); ScopedFramebufferForRenderbuffer destWrapper(gl, destRB); gl->BlitHelper()->BlitFramebufferToFramebuffer(srcWrapper.FB(), destWrapper.FB(), src->Size(), dest->Size()); return; } MOZ_CRASH("Unhandled dest->AttachType()."); } MOZ_CRASH("Unhandled src->AttachType()."); }
void GLBlitHelper::BlitTextureToFramebuffer(GLuint srcTex, GLuint destFB, const gfxIntSize& srcSize, const gfxIntSize& destSize, GLenum srcTarget) { MOZ_ASSERT(mGL->fIsTexture(srcTex)); MOZ_ASSERT(!destFB || mGL->fIsFramebuffer(destFB)); if (mGL->IsSupported(GLFeature::framebuffer_blit)) { ScopedFramebufferForTexture srcWrapper(mGL, srcTex, srcTarget); MOZ_ASSERT(srcWrapper.IsComplete()); BlitFramebufferToFramebuffer(srcWrapper.FB(), destFB, srcSize, destSize); return; } ScopedBindFramebuffer boundFB(mGL, destFB); // UseTexQuadProgram initializes a shader that reads // from texture unit 0. ScopedBindTextureUnit boundTU(mGL, LOCAL_GL_TEXTURE0); ScopedBindTexture boundTex(mGL, srcTex, srcTarget); GLuint boundProgram = 0; mGL->GetUIntegerv(LOCAL_GL_CURRENT_PROGRAM, &boundProgram); GLuint boundBuffer = 0; mGL->GetUIntegerv(LOCAL_GL_ARRAY_BUFFER_BINDING, &boundBuffer); /* * mGL->fGetVertexAttribiv takes: * VERTEX_ATTRIB_ARRAY_ENABLED * VERTEX_ATTRIB_ARRAY_SIZE, * VERTEX_ATTRIB_ARRAY_STRIDE, * VERTEX_ATTRIB_ARRAY_TYPE, * VERTEX_ATTRIB_ARRAY_NORMALIZED, * VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, * CURRENT_VERTEX_ATTRIB * * CURRENT_VERTEX_ATTRIB is vertex shader state. \o/ * Others appear to be vertex array state, * or alternatively in the internal vertex array state * for a buffer object. */ GLint attrib0_enabled = 0; GLint attrib0_size = 0; GLint attrib0_stride = 0; GLint attrib0_type = 0; GLint attrib0_normalized = 0; GLint attrib0_bufferBinding = 0; void* attrib0_pointer = nullptr; mGL->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_ENABLED, &attrib0_enabled); mGL->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_SIZE, &attrib0_size); mGL->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_STRIDE, &attrib0_stride); mGL->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_TYPE, &attrib0_type); mGL->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &attrib0_normalized); mGL->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &attrib0_bufferBinding); mGL->fGetVertexAttribPointerv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_POINTER, &attrib0_pointer); // Note that uniform values are program state, so we don't need to rebind those. ScopedGLState blend (mGL, LOCAL_GL_BLEND, false); ScopedGLState cullFace (mGL, LOCAL_GL_CULL_FACE, false); ScopedGLState depthTest (mGL, LOCAL_GL_DEPTH_TEST, false); ScopedGLState dither (mGL, LOCAL_GL_DITHER, false); ScopedGLState polyOffsFill(mGL, LOCAL_GL_POLYGON_OFFSET_FILL, false); ScopedGLState sampleAToC (mGL, LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE, false); ScopedGLState sampleCover (mGL, LOCAL_GL_SAMPLE_COVERAGE, false); ScopedGLState scissor (mGL, LOCAL_GL_SCISSOR_TEST, false); ScopedGLState stencil (mGL, LOCAL_GL_STENCIL_TEST, false); realGLboolean colorMask[4]; mGL->fGetBooleanv(LOCAL_GL_COLOR_WRITEMASK, colorMask); mGL->fColorMask(LOCAL_GL_TRUE, LOCAL_GL_TRUE, LOCAL_GL_TRUE, LOCAL_GL_TRUE); GLint viewport[4]; mGL->fGetIntegerv(LOCAL_GL_VIEWPORT, viewport); mGL->fViewport(0, 0, destSize.width, destSize.height); // Does destructive things to (only!) what we just saved above. bool good = UseTexQuadProgram(srcTarget, srcSize); if (!good) { // We're up against the wall, so bail. // This should really be MOZ_CRASH(why) or MOZ_RUNTIME_ASSERT(good). printf_stderr("[%s:%d] Fatal Error: Failed to prepare to blit texture->framebuffer.\n", __FILE__, __LINE__); MOZ_CRASH(); } mGL->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4); mGL->fViewport(viewport[0], viewport[1], viewport[2], viewport[3]); mGL->fColorMask(colorMask[0], colorMask[1], colorMask[2], colorMask[3]); if (attrib0_enabled) mGL->fEnableVertexAttribArray(0); mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, attrib0_bufferBinding); mGL->fVertexAttribPointer(0, attrib0_size, attrib0_type, attrib0_normalized, attrib0_stride, attrib0_pointer); mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, boundBuffer); mGL->fUseProgram(boundProgram); }