diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
commit | 6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch) | |
tree | a68f146d7fa01f0134297619fbe7e33db084e0aa /gfx/gl/MozFramebuffer.cpp | |
parent | Initial commit. (diff) | |
download | thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.tar.xz thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.zip |
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'gfx/gl/MozFramebuffer.cpp')
-rw-r--r-- | gfx/gl/MozFramebuffer.cpp | 225 |
1 files changed, 225 insertions, 0 deletions
diff --git a/gfx/gl/MozFramebuffer.cpp b/gfx/gl/MozFramebuffer.cpp new file mode 100644 index 0000000000..10995a7ee1 --- /dev/null +++ b/gfx/gl/MozFramebuffer.cpp @@ -0,0 +1,225 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 4; -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "MozFramebuffer.h" + +#include "GLContext.h" +#include "mozilla/gfx/Logging.h" +#include "ScopedGLHelpers.h" + +namespace mozilla { +namespace gl { + +static void DeleteByTarget(GLContext* const gl, const GLenum target, + const GLuint name) { + if (target == LOCAL_GL_RENDERBUFFER) { + gl->DeleteRenderbuffer(name); + } else { + gl->DeleteTexture(name); + } +} + +UniquePtr<MozFramebuffer> MozFramebuffer::Create(GLContext* const gl, + const gfx::IntSize& size, + const uint32_t samples, + const bool depthStencil) { + if (samples && !gl->IsSupported(GLFeature::framebuffer_multisample)) + return nullptr; + + if (uint32_t(size.width) > gl->MaxTexOrRbSize() || + uint32_t(size.height) > gl->MaxTexOrRbSize() || + samples > gl->MaxSamples()) { + return nullptr; + } + + gl->MakeCurrent(); + + GLContext::LocalErrorScope errorScope(*gl); + + GLenum colorTarget; + GLuint colorName; + if (samples) { + colorTarget = LOCAL_GL_RENDERBUFFER; + colorName = gl->CreateRenderbuffer(); + const ScopedBindRenderbuffer bindRB(gl, colorName); + gl->fRenderbufferStorageMultisample(colorTarget, samples, LOCAL_GL_RGBA8, + size.width, size.height); + } else { + colorTarget = LOCAL_GL_TEXTURE_2D; + colorName = gl->CreateTexture(); + const ScopedBindTexture bindTex(gl, colorName); + gl->TexParams_SetClampNoMips(); + gl->fTexImage2D(colorTarget, 0, LOCAL_GL_RGBA, size.width, size.height, 0, + LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, nullptr); + } + + const auto err = errorScope.GetError(); + if (err) { + if (err != LOCAL_GL_OUT_OF_MEMORY) { + gfxCriticalNote << "Unexpected error: " << gfx::hexa(err) << ": " + << GLContext::GLErrorToString(err); + } + DeleteByTarget(gl, colorTarget, colorName); + return nullptr; + } + + return CreateImpl( + gl, size, samples, + depthStencil ? DepthAndStencilBuffer::Create(gl, size, samples) : nullptr, + colorTarget, colorName); +} + +UniquePtr<MozFramebuffer> MozFramebuffer::CreateForBacking( + GLContext* const gl, const gfx::IntSize& size, const uint32_t samples, + bool depthStencil, const GLenum colorTarget, const GLuint colorName) { + return CreateImpl( + gl, size, samples, + depthStencil ? DepthAndStencilBuffer::Create(gl, size, samples) : nullptr, + colorTarget, colorName); +} + +/* static */ UniquePtr<MozFramebuffer> +MozFramebuffer::CreateForBackingWithSharedDepthAndStencil( + const gfx::IntSize& size, const uint32_t samples, GLenum colorTarget, + GLuint colorName, + const RefPtr<DepthAndStencilBuffer>& depthAndStencilBuffer) { + auto gl = depthAndStencilBuffer->gl(); + if (!gl || !gl->MakeCurrent()) { + return nullptr; + } + return CreateImpl(gl, size, samples, depthAndStencilBuffer, colorTarget, + colorName); +} + +/* static */ UniquePtr<MozFramebuffer> MozFramebuffer::CreateImpl( + GLContext* const gl, const gfx::IntSize& size, const uint32_t samples, + const RefPtr<DepthAndStencilBuffer>& depthAndStencilBuffer, + const GLenum colorTarget, const GLuint colorName) { + GLuint fb = gl->CreateFramebuffer(); + const ScopedBindFramebuffer bindFB(gl, fb); + + if (colorTarget == LOCAL_GL_RENDERBUFFER) { + gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, + LOCAL_GL_COLOR_ATTACHMENT0, colorTarget, + colorName); + } else { + gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, + colorTarget, colorName, 0); + } + + if (depthAndStencilBuffer) { + gl->fFramebufferRenderbuffer( + LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT, LOCAL_GL_RENDERBUFFER, + depthAndStencilBuffer->mDepthRB); + gl->fFramebufferRenderbuffer( + LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT, + LOCAL_GL_RENDERBUFFER, depthAndStencilBuffer->mStencilRB); + } + + const auto status = gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); + if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) { + gfxCriticalNote << "MozFramebuffer::CreateImpl(size:" << size + << ", samples:" << samples + << ", depthAndStencil:" << bool(depthAndStencilBuffer) + << ", colorTarget:" << gfx::hexa(colorTarget) + << ", colorName:" << colorName << "): Incomplete: 0x" + << gfx::hexa(status); + return nullptr; + } + + return UniquePtr<MozFramebuffer>(new MozFramebuffer( + gl, size, fb, samples, depthAndStencilBuffer, colorTarget, colorName)); +} + +/* static */ RefPtr<DepthAndStencilBuffer> DepthAndStencilBuffer::Create( + GLContext* const gl, const gfx::IntSize& size, const uint32_t samples) { + const auto fnAllocRB = [&](GLenum format) { + GLuint rb = gl->CreateRenderbuffer(); + const ScopedBindRenderbuffer bindRB(gl, rb); + if (samples) { + gl->fRenderbufferStorageMultisample(LOCAL_GL_RENDERBUFFER, samples, + format, size.width, size.height); + } else { + gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, format, size.width, + size.height); + } + return rb; + }; + + GLuint depthRB, stencilRB; + { + GLContext::LocalErrorScope errorScope(*gl); + + if (gl->IsSupported(GLFeature::packed_depth_stencil)) { + depthRB = fnAllocRB(LOCAL_GL_DEPTH24_STENCIL8); + stencilRB = depthRB; // Ignore unused mStencilRB. + } else { + depthRB = fnAllocRB(LOCAL_GL_DEPTH_COMPONENT24); + stencilRB = fnAllocRB(LOCAL_GL_STENCIL_INDEX8); + } + + const auto err = errorScope.GetError(); + if (err) { + MOZ_ASSERT(err == LOCAL_GL_OUT_OF_MEMORY); + return nullptr; + } + } + + return new DepthAndStencilBuffer(gl, size, depthRB, stencilRB); +} + +//////////////////// + +MozFramebuffer::MozFramebuffer( + GLContext* const gl, const gfx::IntSize& size, GLuint fb, + const uint32_t samples, RefPtr<DepthAndStencilBuffer> depthAndStencilBuffer, + const GLenum colorTarget, const GLuint colorName) + : mWeakGL(gl), + mSize(size), + mSamples(samples), + mFB(fb), + mColorTarget(colorTarget), + mDepthAndStencilBuffer(std::move(depthAndStencilBuffer)), + mColorName(colorName) { + MOZ_ASSERT(mColorTarget); + MOZ_ASSERT(mColorName); +} + +MozFramebuffer::~MozFramebuffer() { + GLContext* const gl = mWeakGL; + if (!gl || !gl->MakeCurrent()) { + return; + } + + gl->DeleteFramebuffer(mFB); + + DeleteByTarget(gl, mColorTarget, mColorName); +} + +bool MozFramebuffer::HasDepth() const { + return mDepthAndStencilBuffer && mDepthAndStencilBuffer->mDepthRB; +} + +bool MozFramebuffer::HasStencil() const { + return mDepthAndStencilBuffer && mDepthAndStencilBuffer->mStencilRB; +} + +DepthAndStencilBuffer::DepthAndStencilBuffer(GLContext* gl, + const gfx::IntSize& size, + GLuint depthRB, GLuint stencilRB) + : mWeakGL(gl), mSize(size), mDepthRB(depthRB), mStencilRB(stencilRB) {} + +DepthAndStencilBuffer::~DepthAndStencilBuffer() { + GLContext* const gl = mWeakGL; + if (!gl || !gl->MakeCurrent()) { + return; + } + + gl->DeleteRenderbuffer(mDepthRB); + gl->DeleteRenderbuffer(mStencilRB); +} + +} // namespace gl +} // namespace mozilla |