tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

MozFramebuffer.cpp (7722B)


      1 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 4; -*- */
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 #include "MozFramebuffer.h"
      7 
      8 #include "GLContext.h"
      9 #include "mozilla/gfx/Logging.h"
     10 #include "ScopedGLHelpers.h"
     11 
     12 namespace mozilla {
     13 namespace gl {
     14 
     15 static void DeleteByTarget(GLContext* const gl, const GLenum target,
     16                           const GLuint name) {
     17  if (target == LOCAL_GL_RENDERBUFFER) {
     18    gl->DeleteRenderbuffer(name);
     19  } else {
     20    gl->DeleteTexture(name);
     21  }
     22 }
     23 
     24 UniquePtr<MozFramebuffer> MozFramebuffer::Create(GLContext* const gl,
     25                                                 const gfx::IntSize& size,
     26                                                 const uint32_t samples,
     27                                                 const bool depthStencil) {
     28  if (samples && !gl->IsSupported(GLFeature::framebuffer_multisample))
     29    return nullptr;
     30 
     31  if (uint32_t(size.width) > gl->MaxTexOrRbSize() ||
     32      uint32_t(size.height) > gl->MaxTexOrRbSize() ||
     33      samples > gl->MaxSamples()) {
     34    return nullptr;
     35  }
     36 
     37  gl->MakeCurrent();
     38 
     39  GLContext::LocalErrorScope errorScope(*gl);
     40 
     41  GLenum colorTarget;
     42  GLuint colorName;
     43  if (samples) {
     44    colorTarget = LOCAL_GL_RENDERBUFFER;
     45    colorName = gl->CreateRenderbuffer();
     46    const ScopedBindRenderbuffer bindRB(gl, colorName);
     47    gl->fRenderbufferStorageMultisample(colorTarget, samples, LOCAL_GL_RGBA8,
     48                                        size.width, size.height);
     49  } else {
     50    colorTarget = LOCAL_GL_TEXTURE_2D;
     51    colorName = gl->CreateTexture();
     52    const ScopedBindTexture bindTex(gl, colorName, colorTarget);
     53    gl->TexParams_SetClampNoMips(colorTarget);
     54    gl->fTexImage2D(colorTarget, 0, LOCAL_GL_RGBA, size.width, size.height, 0,
     55                    LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, nullptr);
     56  }
     57 
     58  const auto err = errorScope.GetError();
     59  if (err) {
     60    if (err != LOCAL_GL_OUT_OF_MEMORY) {
     61      gfxCriticalNote << "Unexpected error: " << gfx::hexa(err) << ": "
     62                      << GLContext::GLErrorToString(err);
     63    }
     64    DeleteByTarget(gl, colorTarget, colorName);
     65    return nullptr;
     66  }
     67 
     68  return CreateImpl(
     69      gl, size, samples,
     70      depthStencil ? DepthAndStencilBuffer::Create(gl, size, samples) : nullptr,
     71      colorTarget, colorName);
     72 }
     73 
     74 UniquePtr<MozFramebuffer> MozFramebuffer::CreateForBacking(
     75    GLContext* const gl, const gfx::IntSize& size, const uint32_t samples,
     76    bool depthStencil, const GLenum colorTarget, const GLuint colorName) {
     77  return CreateImpl(
     78      gl, size, samples,
     79      depthStencil ? DepthAndStencilBuffer::Create(gl, size, samples) : nullptr,
     80      colorTarget, colorName);
     81 }
     82 
     83 /* static */ UniquePtr<MozFramebuffer>
     84 MozFramebuffer::CreateForBackingWithSharedDepthAndStencil(
     85    const gfx::IntSize& size, const uint32_t samples, GLenum colorTarget,
     86    GLuint colorName,
     87    const RefPtr<DepthAndStencilBuffer>& depthAndStencilBuffer) {
     88  auto gl = depthAndStencilBuffer->gl();
     89  if (!gl || !gl->MakeCurrent()) {
     90    return nullptr;
     91  }
     92  return CreateImpl(gl, size, samples, depthAndStencilBuffer, colorTarget,
     93                    colorName);
     94 }
     95 
     96 /* static */ UniquePtr<MozFramebuffer> MozFramebuffer::CreateImpl(
     97    GLContext* const gl, const gfx::IntSize& size, const uint32_t samples,
     98    const RefPtr<DepthAndStencilBuffer>& depthAndStencilBuffer,
     99    const GLenum colorTarget, const GLuint colorName) {
    100  GLuint fb = gl->CreateFramebuffer();
    101  const ScopedBindFramebuffer bindFB(gl, fb);
    102 
    103  if (colorTarget == LOCAL_GL_RENDERBUFFER) {
    104    gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
    105                                 LOCAL_GL_COLOR_ATTACHMENT0, colorTarget,
    106                                 colorName);
    107  } else {
    108    gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0,
    109                              colorTarget, colorName, 0);
    110  }
    111 
    112  if (depthAndStencilBuffer) {
    113    gl->fFramebufferRenderbuffer(
    114        LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT, LOCAL_GL_RENDERBUFFER,
    115        depthAndStencilBuffer->mDepthRB);
    116    gl->fFramebufferRenderbuffer(
    117        LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT,
    118        LOCAL_GL_RENDERBUFFER, depthAndStencilBuffer->mStencilRB);
    119  }
    120 
    121  const auto status = gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
    122  if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
    123    gfxCriticalNote << "MozFramebuffer::CreateImpl(size:" << size
    124                    << ", samples:" << samples
    125                    << ", depthAndStencil:" << bool(depthAndStencilBuffer)
    126                    << ", colorTarget:" << gfx::hexa(colorTarget)
    127                    << ", colorName:" << colorName << "): Incomplete: 0x"
    128                    << gfx::hexa(status);
    129    return nullptr;
    130  }
    131 
    132  return UniquePtr<MozFramebuffer>(new MozFramebuffer(
    133      gl, size, fb, samples, depthAndStencilBuffer, colorTarget, colorName));
    134 }
    135 
    136 /* static */ RefPtr<DepthAndStencilBuffer> DepthAndStencilBuffer::Create(
    137    GLContext* const gl, const gfx::IntSize& size, const uint32_t samples) {
    138  const auto fnAllocRB = [&](GLenum format) {
    139    GLuint rb = gl->CreateRenderbuffer();
    140    const ScopedBindRenderbuffer bindRB(gl, rb);
    141    if (samples) {
    142      gl->fRenderbufferStorageMultisample(LOCAL_GL_RENDERBUFFER, samples,
    143                                          format, size.width, size.height);
    144    } else {
    145      gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, format, size.width,
    146                               size.height);
    147    }
    148    return rb;
    149  };
    150 
    151  GLuint depthRB, stencilRB;
    152  {
    153    GLContext::LocalErrorScope errorScope(*gl);
    154 
    155    if (gl->IsSupported(GLFeature::packed_depth_stencil)) {
    156      depthRB = fnAllocRB(LOCAL_GL_DEPTH24_STENCIL8);
    157      stencilRB = depthRB;  // Ignore unused mStencilRB.
    158    } else {
    159      depthRB = fnAllocRB(LOCAL_GL_DEPTH_COMPONENT24);
    160      stencilRB = fnAllocRB(LOCAL_GL_STENCIL_INDEX8);
    161    }
    162 
    163    const auto err = errorScope.GetError();
    164    if (err) {
    165      MOZ_ASSERT(err == LOCAL_GL_OUT_OF_MEMORY);
    166      return nullptr;
    167    }
    168  }
    169 
    170  return new DepthAndStencilBuffer(gl, size, depthRB, stencilRB);
    171 }
    172 
    173 ////////////////////
    174 
    175 MozFramebuffer::MozFramebuffer(
    176    GLContext* const gl, const gfx::IntSize& size, GLuint fb,
    177    const uint32_t samples, RefPtr<DepthAndStencilBuffer> depthAndStencilBuffer,
    178    const GLenum colorTarget, const GLuint colorName)
    179    : mWeakGL(gl),
    180      mSize(size),
    181      mSamples(samples),
    182      mFB(fb),
    183      mColorTarget(colorTarget),
    184      mDepthAndStencilBuffer(std::move(depthAndStencilBuffer)),
    185      mColorName(colorName) {
    186  MOZ_ASSERT(mColorTarget);
    187  MOZ_ASSERT(mColorName);
    188 }
    189 
    190 MozFramebuffer::~MozFramebuffer() {
    191  GLContext* const gl = mWeakGL;
    192  if (!gl || !gl->MakeCurrent()) {
    193    return;
    194  }
    195 
    196  gl->DeleteFramebuffer(mFB);
    197 
    198  DeleteByTarget(gl, mColorTarget, mColorName);
    199 }
    200 
    201 bool MozFramebuffer::HasDepth() const {
    202  return mDepthAndStencilBuffer && mDepthAndStencilBuffer->mDepthRB;
    203 }
    204 
    205 bool MozFramebuffer::HasStencil() const {
    206  return mDepthAndStencilBuffer && mDepthAndStencilBuffer->mStencilRB;
    207 }
    208 
    209 DepthAndStencilBuffer::DepthAndStencilBuffer(GLContext* gl,
    210                                             const gfx::IntSize& size,
    211                                             GLuint depthRB, GLuint stencilRB)
    212    : mWeakGL(gl), mSize(size), mDepthRB(depthRB), mStencilRB(stencilRB) {}
    213 
    214 DepthAndStencilBuffer::~DepthAndStencilBuffer() {
    215  GLContext* const gl = mWeakGL;
    216  if (!gl || !gl->MakeCurrent()) {
    217    return;
    218  }
    219 
    220  gl->DeleteRenderbuffer(mDepthRB);
    221  gl->DeleteRenderbuffer(mStencilRB);
    222 }
    223 
    224 }  // namespace gl
    225 }  // namespace mozilla