void GLScreenBuffer::DeprecatedReadback(SharedSurface_GL* src, gfxImageSurface* dest) { MOZ_ASSERT(src && dest); MOZ_ASSERT(ToIntSize(dest->GetSize()) == src->Size()); MOZ_ASSERT(dest->Format() == (src->HasAlpha() ? gfxImageFormat::ARGB32 : gfxImageFormat::RGB24)); mGL->MakeCurrent(); bool needsSwap = src != SharedSurf(); if (needsSwap) { SharedSurf()->UnlockProd(); src->LockProd(); } ReadBuffer* buffer = CreateRead(src); MOZ_ASSERT(buffer); ScopedBindFramebuffer autoFB(mGL, buffer->FB()); ReadPixelsIntoImageSurface(mGL, dest); delete buffer; if (needsSwap) { src->UnlockProd(); SharedSurf()->LockProd(); } }
SharedSurface_Basic::SharedSurface_Basic(GLContext* gl, const IntSize& size, bool hasAlpha, SurfaceFormat format, GLuint tex) : SharedSurface_GL(SharedSurfaceType::Basic, AttachmentType::GLTexture, gl, size, hasAlpha) , mTex(tex), mFB(0) { mGL->MakeCurrent(); mGL->fGenFramebuffers(1, &mFB); ScopedBindFramebuffer autoFB(mGL, mFB); mGL->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, LOCAL_GL_TEXTURE_2D, mTex, 0); GLenum status = mGL->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) { mGL->fDeleteFramebuffers(1, &mFB); mFB = 0; } mData = Factory::CreateDataSourceSurfaceWithStride(size, format, GetAlignedStride<4>(size.width * BytesPerPixel(format))); }
void SharedSurface_Basic::Fence() { mGL->MakeCurrent(); ScopedBindFramebuffer autoFB(mGL, mFB); ReadPixelsIntoDataSurface(mGL, mData); }
void SharedSurface_Basic::Fence() { mGL->MakeCurrent(); ScopedBindFramebuffer autoFB(mGL, mFB); DataSourceSurface::MappedSurface map; mData->Map(DataSourceSurface::MapType::WRITE, &map); nsRefPtr<gfxImageSurface> wrappedData = new gfxImageSurface(map.mData, ThebesIntSize(mData->GetSize()), map.mStride, SurfaceFormatToImageFormat(mData->GetFormat())); ReadPixelsIntoImageSurface(mGL, wrappedData); mData->Unmap(); }
ScopedFramebufferForRenderbuffer::ScopedFramebufferForRenderbuffer(GLContext* aGL, GLuint aRB) : ScopedGLWrapper<ScopedFramebufferForRenderbuffer>(aGL) , mComplete(false) , mFB(0) { mGL->fGenFramebuffers(1, &mFB); ScopedBindFramebuffer autoFB(aGL, mFB); mGL->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, LOCAL_GL_RENDERBUFFER, aRB); GLenum status = mGL->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); if (status == LOCAL_GL_FRAMEBUFFER_COMPLETE) { mComplete = true; } else { mGL->fDeleteFramebuffers(1, &mFB); mFB = 0; } }
/* ScopedFramebufferForTexture ************************************************/ ScopedFramebufferForTexture::ScopedFramebufferForTexture(GLContext* aGL, GLuint aTexture, GLenum aTarget) : ScopedGLWrapper<ScopedFramebufferForTexture>(aGL) , mComplete(false) , mFB(0) { mGL->fGenFramebuffers(1, &mFB); ScopedBindFramebuffer autoFB(aGL, mFB); mGL->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, aTarget, aTexture, 0); GLenum status = mGL->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); if (status == LOCAL_GL_FRAMEBUFFER_COMPLETE) { mComplete = true; } else { mGL->fDeleteFramebuffers(1, &mFB); mFB = 0; } }
void GLScreenBuffer::Attach(SharedSurface* surface, const gfx::IntSize& size) { ScopedBindFramebuffer autoFB(mGL); SharedSurface_GL* surf = SharedSurface_GL::Cast(surface); if (mRead && SharedSurf()) SharedSurf()->UnlockProd(); surf->LockProd(); if (mRead && surf->AttachType() == SharedSurf()->AttachType() && size == Size()) { // Same size, same type, ready for reuse! mRead->Attach(surf); } else { // Else something changed, so resize: DrawBuffer* draw = CreateDraw(size); // Can be null. ReadBuffer* read = CreateRead(surf); MOZ_ASSERT(read); // Should never fail if SwapProd succeeded. delete mDraw; delete mRead; mDraw = draw; mRead = read; } // Check that we're all set up. MOZ_ASSERT(SharedSurf() == surf); if (!PreserveBuffer()) { // DiscardFramebuffer here could help perf on some mobile platforms. } }
bool WebGLFramebuffer::ValidateAndInitAttachments(const char* funcName) { MOZ_ASSERT(mContext->mBoundDrawFramebuffer == this || mContext->mBoundReadFramebuffer == this); nsCString fbStatusInfo; const auto fbStatus = CheckFramebufferStatus(&fbStatusInfo); if (fbStatus != LOCAL_GL_FRAMEBUFFER_COMPLETE) { nsCString errorText = nsPrintfCString("Incomplete framebuffer: Status 0x%04x", fbStatus.get()); if (fbStatusInfo.Length()) { errorText += ": "; errorText += fbStatusInfo; } mContext->ErrorInvalidFramebufferOperation("%s: %s.", funcName, errorText.BeginReading()); return false; } // Cool! We've checked out ok. Just need to initialize. // Check if we need to initialize anything { bool hasUninitializedAttachments = false; if (mColorAttachment0.HasImage() && IsDrawBuffer(0)) hasUninitializedAttachments |= mColorAttachment0.HasUninitializedImageData(); size_t i = 1; for (const auto& cur : mMoreColorAttachments) { if (cur.HasImage() && IsDrawBuffer(i)) hasUninitializedAttachments |= cur.HasUninitializedImageData(); ++i; } if (mDepthAttachment.HasImage()) hasUninitializedAttachments |= mDepthAttachment.HasUninitializedImageData(); if (mStencilAttachment.HasImage()) hasUninitializedAttachments |= mStencilAttachment.HasUninitializedImageData(); if (mDepthStencilAttachment.HasImage()) hasUninitializedAttachments |= mDepthStencilAttachment.HasUninitializedImageData(); if (!hasUninitializedAttachments) return true; } // Get buffer-bit-mask and color-attachment-mask-list uint32_t clearBits = 0; std::vector<GLenum> tempDrawBuffers(1 + mMoreColorAttachments.Size(), LOCAL_GL_NONE); if (mColorAttachment0.HasUninitializedImageData() && IsDrawBuffer(0)) { clearBits |= LOCAL_GL_COLOR_BUFFER_BIT; tempDrawBuffers[0] = LOCAL_GL_COLOR_ATTACHMENT0; } size_t i = 1; for (const auto& cur : mMoreColorAttachments) { if (cur.HasUninitializedImageData() && IsDrawBuffer(i)) { clearBits |= LOCAL_GL_COLOR_BUFFER_BIT; tempDrawBuffers[i] = LOCAL_GL_COLOR_ATTACHMENT0 + i; } ++i; } if (mDepthAttachment.HasUninitializedImageData() || mDepthStencilAttachment.HasUninitializedImageData()) { clearBits |= LOCAL_GL_DEPTH_BUFFER_BIT; } if (mStencilAttachment.HasUninitializedImageData() || mDepthStencilAttachment.HasUninitializedImageData()) { clearBits |= LOCAL_GL_STENCIL_BUFFER_BIT; } mContext->MakeContextCurrent(); const auto fnDrawBuffers = [this](const std::vector<GLenum>& list) { const GLenum* ptr = nullptr; if (list.size()) { ptr = &(list[0]); } this->mContext->gl->fDrawBuffers(list.size(), ptr); }; const auto drawBufferExt = WebGLExtensionID::WEBGL_draw_buffers; const bool hasDrawBuffers = (mContext->IsWebGL2() || mContext->IsExtensionEnabled(drawBufferExt)); if (hasDrawBuffers) { fnDrawBuffers(tempDrawBuffers); } // Clear! { // This FB maybe bind to GL_READ_FRAMEBUFFER and glClear only // clear GL_DRAW_FRAMEBUFFER. So bind FB to GL_DRAW_FRAMEBUFFER // here. gl::ScopedBindFramebuffer autoFB(mContext->gl, mGLName); mContext->ForceClearFramebufferWithDefaultValues(clearBits, false); } if (hasDrawBuffers) { fnDrawBuffers(mDrawBuffers); } // Mark all the uninitialized images as initialized. if (mDepthAttachment.HasUninitializedImageData()) mDepthAttachment.SetImageDataStatus(WebGLImageDataStatus::InitializedImageData); if (mStencilAttachment.HasUninitializedImageData()) mStencilAttachment.SetImageDataStatus(WebGLImageDataStatus::InitializedImageData); if (mDepthStencilAttachment.HasUninitializedImageData()) mDepthStencilAttachment.SetImageDataStatus(WebGLImageDataStatus::InitializedImageData); if (mColorAttachment0.HasUninitializedImageData() && IsDrawBuffer(0)) { mColorAttachment0.SetImageDataStatus(WebGLImageDataStatus::InitializedImageData); } i = 1; for (auto& cur : mMoreColorAttachments) { if (cur.HasUninitializedImageData() && IsDrawBuffer(i)) cur.SetImageDataStatus(WebGLImageDataStatus::InitializedImageData); ++i; } return true; }
void ReadScreenIntoImageSurface(GLContext* gl, gfxImageSurface* dest) { ScopedBindFramebuffer autoFB(gl, 0); ReadPixelsIntoImageSurface(gl, dest); }
// `mask` from glClear. static bool ClearWithTempFB(WebGLContext* webgl, GLuint tex, TexImageTarget texImageTarget, GLint level, TexInternalFormat baseInternalFormat, GLsizei width, GLsizei height) { MOZ_ASSERT(texImageTarget == LOCAL_GL_TEXTURE_2D); gl::GLContext* gl = webgl->GL(); MOZ_ASSERT(gl->IsCurrent()); gl::ScopedFramebuffer fb(gl); gl::ScopedBindFramebuffer autoFB(gl, fb.FB()); GLbitfield mask = 0; switch (baseInternalFormat.get()) { case LOCAL_GL_LUMINANCE: case LOCAL_GL_LUMINANCE_ALPHA: case LOCAL_GL_ALPHA: case LOCAL_GL_RGB: case LOCAL_GL_RGBA: case LOCAL_GL_BGR: case LOCAL_GL_BGRA: mask = LOCAL_GL_COLOR_BUFFER_BIT; gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, texImageTarget.get(), tex, level); break; case LOCAL_GL_DEPTH_COMPONENT32_OES: case LOCAL_GL_DEPTH_COMPONENT24_OES: case LOCAL_GL_DEPTH_COMPONENT16: case LOCAL_GL_DEPTH_COMPONENT: mask = LOCAL_GL_DEPTH_BUFFER_BIT; gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT, texImageTarget.get(), tex, level); break; case LOCAL_GL_DEPTH24_STENCIL8: case LOCAL_GL_DEPTH_STENCIL: mask = LOCAL_GL_DEPTH_BUFFER_BIT | LOCAL_GL_STENCIL_BUFFER_BIT; gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT, texImageTarget.get(), tex, level); gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT, texImageTarget.get(), tex, level); break; default: return false; } MOZ_ASSERT(mask); if (ClearByMask(webgl, mask)) return true; // Failed to simply build an FB from the tex, but maybe it needs a // color buffer to be complete. if (mask & LOCAL_GL_COLOR_BUFFER_BIT) { // Nope, it already had one. return false; } gl::ScopedRenderbuffer rb(gl); { // Only GLES guarantees RGBA4. GLenum format = gl->IsGLES() ? LOCAL_GL_RGBA4 : LOCAL_GL_RGBA8; gl::ScopedBindRenderbuffer rbBinding(gl, rb.RB()); gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, format, width, height); } gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, LOCAL_GL_RENDERBUFFER, rb.RB()); mask |= LOCAL_GL_COLOR_BUFFER_BIT; // Last chance! return ClearByMask(webgl, mask); }