tor-browser

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

WebGLRenderbuffer.cpp (8418B)


      1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      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 "WebGLRenderbuffer.h"
      7 
      8 #include "GLContext.h"
      9 #include "ScopedGLHelpers.h"
     10 #include "WebGLContext.h"
     11 #include "WebGLFormats.h"
     12 #include "WebGLStrongTypes.h"
     13 #include "WebGLTexture.h"
     14 #include "mozilla/dom/WebGLRenderingContextBinding.h"
     15 
     16 namespace mozilla {
     17 
     18 static GLenum DepthFormatForDepthStencilEmu(gl::GLContext* gl) {
     19  // We might not be able to get 24-bit, so let's pretend!
     20  if (gl->IsGLES() && !gl->IsExtensionSupported(gl::GLContext::OES_depth24))
     21    return LOCAL_GL_DEPTH_COMPONENT16;
     22 
     23  return LOCAL_GL_DEPTH_COMPONENT24;
     24 }
     25 
     26 static GLuint DoCreateRenderbuffer(gl::GLContext* gl) {
     27  GLuint ret = 0;
     28  gl->fGenRenderbuffers(1, &ret);
     29  return ret;
     30 }
     31 
     32 static bool EmulatePackedDepthStencil(gl::GLContext* gl) {
     33  return !gl->IsSupported(gl::GLFeature::packed_depth_stencil);
     34 }
     35 
     36 WebGLRenderbuffer::WebGLRenderbuffer(WebGLContext* webgl)
     37    : WebGLContextBoundObject(webgl),
     38      mPrimaryRB(DoCreateRenderbuffer(webgl->gl)),
     39      mEmulatePackedDepthStencil(EmulatePackedDepthStencil(webgl->gl)),
     40      mSecondaryRB(0) {
     41  // Bind our RB, or we might end up calling FramebufferRenderbuffer before we
     42  // ever call BindRenderbuffer, since webgl.bindRenderbuffer doesn't actually
     43  // call glBindRenderbuffer anymore.
     44  mContext->gl->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mPrimaryRB);
     45  mContext->gl->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, 0);
     46 }
     47 
     48 WebGLRenderbuffer::~WebGLRenderbuffer() {
     49  mImageInfo = webgl::ImageInfo();
     50 
     51  if (!mContext) return;
     52 
     53  mContext->gl->fDeleteRenderbuffers(1, &mPrimaryRB);
     54  if (mSecondaryRB) {
     55    mContext->gl->fDeleteRenderbuffers(1, &mSecondaryRB);
     56  }
     57 }
     58 
     59 static GLenum DoRenderbufferStorageMaybeMultisample(gl::GLContext* gl,
     60                                                    GLsizei samples,
     61                                                    GLenum internalFormat,
     62                                                    GLsizei width,
     63                                                    GLsizei height) {
     64  MOZ_ASSERT_IF(samples >= 1,
     65                gl->IsSupported(gl::GLFeature::framebuffer_multisample));
     66 
     67  // Certain OpenGL ES renderbuffer formats may not exist on desktop OpenGL.
     68  switch (internalFormat) {
     69    case LOCAL_GL_RGBA4:
     70    case LOCAL_GL_RGB5_A1:
     71      // 16-bit RGBA formats are not supported on desktop GL.
     72      if (!gl->IsGLES()) internalFormat = LOCAL_GL_RGBA8;
     73      break;
     74 
     75    case LOCAL_GL_RGB565:
     76      // RGB565 is not supported on desktop GL.
     77      if (!gl->IsGLES()) internalFormat = LOCAL_GL_RGB8;
     78      break;
     79 
     80    case LOCAL_GL_DEPTH_COMPONENT16:
     81      if (!gl->IsGLES() || gl->IsExtensionSupported(gl::GLContext::OES_depth24))
     82        internalFormat = LOCAL_GL_DEPTH_COMPONENT24;
     83      else if (gl->IsSupported(gl::GLFeature::packed_depth_stencil))
     84        internalFormat = LOCAL_GL_DEPTH24_STENCIL8;
     85      break;
     86 
     87    case LOCAL_GL_DEPTH_STENCIL:
     88      MOZ_CRASH("GFX: GL_DEPTH_STENCIL is not valid here.");
     89      break;
     90 
     91    default:
     92      break;
     93  }
     94 
     95  gl::GLContext::LocalErrorScope errorScope(*gl);
     96 
     97  if (samples > 0) {
     98    gl->fRenderbufferStorageMultisample(LOCAL_GL_RENDERBUFFER, samples,
     99                                        internalFormat, width, height);
    100  } else {
    101    gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, internalFormat, width,
    102                             height);
    103  }
    104 
    105  return errorScope.GetError();
    106 }
    107 
    108 GLenum WebGLRenderbuffer::DoRenderbufferStorage(
    109    uint32_t samples, const webgl::FormatUsageInfo* format, uint32_t width,
    110    uint32_t height) {
    111  gl::GLContext* gl = mContext->gl;
    112  MOZ_ASSERT(samples <= 256);  // Sanity check.
    113 
    114  GLenum primaryFormat = format->format->sizedFormat;
    115  GLenum secondaryFormat = 0;
    116 
    117  if (mEmulatePackedDepthStencil &&
    118      primaryFormat == LOCAL_GL_DEPTH24_STENCIL8) {
    119    primaryFormat = DepthFormatForDepthStencilEmu(gl);
    120    secondaryFormat = LOCAL_GL_STENCIL_INDEX8;
    121  }
    122 
    123  gl->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mPrimaryRB);
    124  GLenum error = DoRenderbufferStorageMaybeMultisample(
    125      gl, samples, primaryFormat, width, height);
    126  gl->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, 0);
    127  if (error) return error;
    128 
    129  if (secondaryFormat) {
    130    if (!mSecondaryRB) {
    131      gl->fGenRenderbuffers(1, &mSecondaryRB);
    132    }
    133 
    134    gl->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mSecondaryRB);
    135    error = DoRenderbufferStorageMaybeMultisample(gl, samples, secondaryFormat,
    136                                                  width, height);
    137    gl->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, 0);
    138    if (error) return error;
    139  } else if (mSecondaryRB) {
    140    gl->fDeleteRenderbuffers(1, &mSecondaryRB);
    141    mSecondaryRB = 0;
    142  }
    143 
    144  return 0;
    145 }
    146 
    147 void WebGLRenderbuffer::RenderbufferStorage(uint32_t samples,
    148                                            GLenum internalFormat,
    149                                            uint32_t width, uint32_t height) {
    150  const auto usage = mContext->mFormatUsage->GetRBUsage(internalFormat);
    151  if (!usage) {
    152    mContext->ErrorInvalidEnum("Invalid `internalFormat`: 0x%04x.",
    153                               internalFormat);
    154    return;
    155  }
    156 
    157  if (width > mContext->mGLMaxRenderbufferSize ||
    158      height > mContext->mGLMaxRenderbufferSize) {
    159    mContext->ErrorInvalidValue(
    160        "Width or height exceeds maximum renderbuffer"
    161        " size.");
    162    return;
    163  }
    164 
    165  const auto maxSamples = usage->MaxSamples(*mContext->gl);
    166  if (samples > maxSamples) {
    167    mContext->ErrorInvalidOperation("`samples` is out of the valid range.");
    168    return;
    169  }
    170 
    171  // Validation complete.
    172 
    173  const GLenum error = DoRenderbufferStorage(samples, usage, width, height);
    174  if (error) {
    175    mContext->GenerateWarning("Unexpected error %s", EnumString(error).c_str());
    176    if (error == LOCAL_GL_OUT_OF_MEMORY) {
    177      // Truncate.
    178      mImageInfo = {};
    179      InvalidateCaches();
    180    }
    181    return;
    182  }
    183 
    184  mContext->OnDataAllocCall();
    185 
    186  const uint32_t depth = 1;
    187  std::vector<bool> uninitializedSlices(depth, true);
    188  mImageInfo = {
    189      usage,           width, height, depth, std::move(uninitializedSlices),
    190      uint8_t(samples)};
    191  InvalidateCaches();
    192 }
    193 
    194 void WebGLRenderbuffer::DoFramebufferRenderbuffer(
    195    const GLenum attachment) const {
    196  gl::GLContext* gl = mContext->gl;
    197 
    198  if (attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
    199    const GLuint stencilRB = (mSecondaryRB ? mSecondaryRB : mPrimaryRB);
    200    gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
    201                                 LOCAL_GL_DEPTH_ATTACHMENT,
    202                                 LOCAL_GL_RENDERBUFFER, mPrimaryRB);
    203    gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
    204                                 LOCAL_GL_STENCIL_ATTACHMENT,
    205                                 LOCAL_GL_RENDERBUFFER, stencilRB);
    206    return;
    207  }
    208 
    209  gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, attachment,
    210                               LOCAL_GL_RENDERBUFFER, mPrimaryRB);
    211 }
    212 
    213 GLint WebGLRenderbuffer::GetRenderbufferParameter(RBParam pname) const {
    214  gl::GLContext* gl = mContext->gl;
    215 
    216  switch (pname.get()) {
    217    case LOCAL_GL_RENDERBUFFER_STENCIL_SIZE:
    218      if (!mImageInfo.mFormat) return 0;
    219 
    220      if (!mImageInfo.mFormat->format->s) return 0;
    221 
    222      return 8;
    223 
    224    case LOCAL_GL_RENDERBUFFER_SAMPLES:
    225    case LOCAL_GL_RENDERBUFFER_WIDTH:
    226    case LOCAL_GL_RENDERBUFFER_HEIGHT:
    227    case LOCAL_GL_RENDERBUFFER_RED_SIZE:
    228    case LOCAL_GL_RENDERBUFFER_GREEN_SIZE:
    229    case LOCAL_GL_RENDERBUFFER_BLUE_SIZE:
    230    case LOCAL_GL_RENDERBUFFER_ALPHA_SIZE:
    231    case LOCAL_GL_RENDERBUFFER_DEPTH_SIZE: {
    232      gl->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mPrimaryRB);
    233      GLint i = 0;
    234      gl->fGetRenderbufferParameteriv(LOCAL_GL_RENDERBUFFER, pname.get(), &i);
    235      gl->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, 0);
    236      return i;
    237    }
    238 
    239    case LOCAL_GL_RENDERBUFFER_INTERNAL_FORMAT: {
    240      GLenum ret = LOCAL_GL_RGBA4;
    241      if (mImageInfo.mFormat) {
    242        ret = mImageInfo.mFormat->format->sizedFormat;
    243 
    244        if (!mContext->IsWebGL2() && ret == LOCAL_GL_DEPTH24_STENCIL8) {
    245          ret = LOCAL_GL_DEPTH_STENCIL;
    246        }
    247      }
    248      return ret;
    249    }
    250  }
    251 
    252  MOZ_ASSERT(false, "This function should only be called with valid `pname`.");
    253  return 0;
    254 }
    255 
    256 }  // namespace mozilla