tor-browser

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

ScopedGLHelpers.cpp (15266B)


      1 /* -*- Mode: C++; tab-width: 8; 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 "GLContext.h"
      7 #include "ScopedGLHelpers.h"
      8 
      9 namespace mozilla {
     10 namespace gl {
     11 
     12 /* ScopedGLState - Wraps glEnable/glDisable. **********************************/
     13 
     14 // Use |newState = true| to enable, |false| to disable.
     15 ScopedGLState::ScopedGLState(GLContext* aGL, GLenum aCapability, bool aNewState)
     16    : mGL(aGL), mCapability(aCapability) {
     17  mOldState = mGL->fIsEnabled(mCapability);
     18 
     19  // Early out if we're already in the right state.
     20  if (aNewState == mOldState) return;
     21 
     22  if (aNewState) {
     23    mGL->fEnable(mCapability);
     24  } else {
     25    mGL->fDisable(mCapability);
     26  }
     27 }
     28 
     29 ScopedGLState::ScopedGLState(GLContext* aGL, GLenum aCapability)
     30    : mGL(aGL), mCapability(aCapability) {
     31  mOldState = mGL->fIsEnabled(mCapability);
     32 }
     33 
     34 ScopedGLState::~ScopedGLState() {
     35  if (mOldState) {
     36    mGL->fEnable(mCapability);
     37  } else {
     38    mGL->fDisable(mCapability);
     39  }
     40 }
     41 
     42 /* ScopedBindFramebuffer - Saves and restores with GetUserBoundFB and
     43 * BindUserFB. */
     44 
     45 void ScopedBindFramebuffer::Init() {
     46  if (mGL->IsSupported(GLFeature::split_framebuffer)) {
     47    mOldReadFB = mGL->GetReadFB();
     48    mOldDrawFB = mGL->GetDrawFB();
     49  } else {
     50    mOldReadFB = mOldDrawFB = mGL->GetFB();
     51  }
     52 }
     53 
     54 ScopedBindFramebuffer::ScopedBindFramebuffer(GLContext* aGL) : mGL(aGL) {
     55  Init();
     56 }
     57 
     58 ScopedBindFramebuffer::ScopedBindFramebuffer(GLContext* aGL, GLuint aNewFB)
     59    : mGL(aGL) {
     60  Init();
     61  mGL->BindFB(aNewFB);
     62 }
     63 
     64 ScopedBindFramebuffer::~ScopedBindFramebuffer() {
     65  if (mOldReadFB == mOldDrawFB) {
     66    mGL->BindFB(mOldDrawFB);
     67  } else {
     68    mGL->BindDrawFB(mOldDrawFB);
     69    mGL->BindReadFB(mOldReadFB);
     70  }
     71 }
     72 
     73 /* ScopedBindTextureUnit ******************************************************/
     74 
     75 ScopedBindTextureUnit::ScopedBindTextureUnit(GLContext* aGL, GLenum aTexUnit)
     76    : mGL(aGL), mOldTexUnit(0) {
     77  MOZ_ASSERT(aTexUnit >= LOCAL_GL_TEXTURE0);
     78  mGL->GetUIntegerv(LOCAL_GL_ACTIVE_TEXTURE, &mOldTexUnit);
     79  mGL->fActiveTexture(aTexUnit);
     80 }
     81 
     82 ScopedBindTextureUnit::~ScopedBindTextureUnit() {
     83  mGL->fActiveTexture(mOldTexUnit);
     84 }
     85 
     86 /* ScopedTexture **************************************************************/
     87 
     88 ScopedTexture::ScopedTexture(GLContext* aGL) : mGL(aGL), mTexture(0) {
     89  mGL->fGenTextures(1, &mTexture);
     90 }
     91 
     92 ScopedTexture::~ScopedTexture() { mGL->fDeleteTextures(1, &mTexture); }
     93 
     94 /* ScopedFramebuffer
     95 * **************************************************************/
     96 
     97 ScopedFramebuffer::ScopedFramebuffer(GLContext* aGL) : mGL(aGL), mFB(0) {
     98  mGL->fGenFramebuffers(1, &mFB);
     99 }
    100 
    101 ScopedFramebuffer::~ScopedFramebuffer() { mGL->fDeleteFramebuffers(1, &mFB); }
    102 
    103 /* ScopedRenderbuffer
    104 * **************************************************************/
    105 
    106 ScopedRenderbuffer::ScopedRenderbuffer(GLContext* aGL) : mGL(aGL), mRB(0) {
    107  mGL->fGenRenderbuffers(1, &mRB);
    108 }
    109 
    110 ScopedRenderbuffer::~ScopedRenderbuffer() {
    111  mGL->fDeleteRenderbuffers(1, &mRB);
    112 }
    113 
    114 /* ScopedBindTexture **********************************************************/
    115 
    116 static GLuint GetBoundTexture(GLContext* gl, GLenum texTarget) {
    117  GLenum bindingTarget;
    118  switch (texTarget) {
    119    case LOCAL_GL_TEXTURE_2D:
    120      bindingTarget = LOCAL_GL_TEXTURE_BINDING_2D;
    121      break;
    122 
    123    case LOCAL_GL_TEXTURE_CUBE_MAP:
    124      bindingTarget = LOCAL_GL_TEXTURE_BINDING_CUBE_MAP;
    125      break;
    126 
    127    case LOCAL_GL_TEXTURE_3D:
    128      bindingTarget = LOCAL_GL_TEXTURE_BINDING_3D;
    129      break;
    130 
    131    case LOCAL_GL_TEXTURE_2D_ARRAY:
    132      bindingTarget = LOCAL_GL_TEXTURE_BINDING_2D_ARRAY;
    133      break;
    134 
    135    case LOCAL_GL_TEXTURE_RECTANGLE_ARB:
    136      bindingTarget = LOCAL_GL_TEXTURE_BINDING_RECTANGLE_ARB;
    137      break;
    138 
    139    case LOCAL_GL_TEXTURE_EXTERNAL:
    140      bindingTarget = LOCAL_GL_TEXTURE_BINDING_EXTERNAL;
    141      break;
    142 
    143    default:
    144      MOZ_CRASH("bad texTarget");
    145  }
    146 
    147  GLuint ret = 0;
    148  gl->GetUIntegerv(bindingTarget, &ret);
    149  return ret;
    150 }
    151 
    152 ScopedBindTexture::ScopedBindTexture(GLContext* aGL, GLuint aNewTex,
    153                                     GLenum aTarget)
    154    : mGL(aGL), mTarget(aTarget), mOldTex(GetBoundTexture(aGL, aTarget)) {
    155  mGL->fBindTexture(mTarget, aNewTex);
    156 }
    157 
    158 ScopedBindTexture::~ScopedBindTexture() { mGL->fBindTexture(mTarget, mOldTex); }
    159 
    160 /* ScopedBindRenderbuffer *****************************************************/
    161 
    162 void ScopedBindRenderbuffer::Init() {
    163  mOldRB = 0;
    164  mGL->GetUIntegerv(LOCAL_GL_RENDERBUFFER_BINDING, &mOldRB);
    165 }
    166 
    167 ScopedBindRenderbuffer::ScopedBindRenderbuffer(GLContext* aGL) : mGL(aGL) {
    168  Init();
    169 }
    170 
    171 ScopedBindRenderbuffer::ScopedBindRenderbuffer(GLContext* aGL, GLuint aNewRB)
    172    : mGL(aGL) {
    173  Init();
    174  mGL->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, aNewRB);
    175 }
    176 
    177 ScopedBindRenderbuffer::~ScopedBindRenderbuffer() {
    178  mGL->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mOldRB);
    179 }
    180 
    181 /* ScopedFramebufferForTexture ************************************************/
    182 ScopedFramebufferForTexture::ScopedFramebufferForTexture(GLContext* aGL,
    183                                                         GLuint aTexture,
    184                                                         GLenum aTarget)
    185    : mGL(aGL), mComplete(false), mFB(0) {
    186  mGL->fGenFramebuffers(1, &mFB);
    187  ScopedBindFramebuffer autoFB(aGL, mFB);
    188  mGL->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0,
    189                             aTarget, aTexture, 0);
    190 
    191  GLenum status = mGL->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
    192  if (status == LOCAL_GL_FRAMEBUFFER_COMPLETE) {
    193    mComplete = true;
    194  } else {
    195    mGL->fDeleteFramebuffers(1, &mFB);
    196    mFB = 0;
    197  }
    198 }
    199 
    200 ScopedFramebufferForTexture::~ScopedFramebufferForTexture() {
    201  if (!mFB) return;
    202 
    203  mGL->fDeleteFramebuffers(1, &mFB);
    204  mFB = 0;
    205 }
    206 
    207 /* ScopedFramebufferForRenderbuffer *******************************************/
    208 
    209 ScopedFramebufferForRenderbuffer::ScopedFramebufferForRenderbuffer(
    210    GLContext* aGL, GLuint aRB)
    211    : mGL(aGL), mComplete(false), mFB(0) {
    212  mGL->fGenFramebuffers(1, &mFB);
    213  ScopedBindFramebuffer autoFB(aGL, mFB);
    214  mGL->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
    215                                LOCAL_GL_COLOR_ATTACHMENT0,
    216                                LOCAL_GL_RENDERBUFFER, aRB);
    217 
    218  GLenum status = mGL->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
    219  if (status == LOCAL_GL_FRAMEBUFFER_COMPLETE) {
    220    mComplete = true;
    221  } else {
    222    mGL->fDeleteFramebuffers(1, &mFB);
    223    mFB = 0;
    224  }
    225 }
    226 
    227 ScopedFramebufferForRenderbuffer::~ScopedFramebufferForRenderbuffer() {
    228  if (!mFB) return;
    229 
    230  mGL->fDeleteFramebuffers(1, &mFB);
    231  mFB = 0;
    232 }
    233 
    234 /* ScopedViewportRect *********************************************************/
    235 
    236 ScopedViewportRect::ScopedViewportRect(GLContext* aGL, GLint x, GLint y,
    237                                       GLsizei width, GLsizei height)
    238    : mGL(aGL) {
    239  mGL->fGetIntegerv(LOCAL_GL_VIEWPORT, mSavedViewportRect);
    240  mGL->fViewport(x, y, width, height);
    241 }
    242 
    243 ScopedViewportRect::~ScopedViewportRect() {
    244  mGL->fViewport(mSavedViewportRect[0], mSavedViewportRect[1],
    245                 mSavedViewportRect[2], mSavedViewportRect[3]);
    246 }
    247 
    248 /* ScopedScissorRect **********************************************************/
    249 
    250 ScopedScissorRect::ScopedScissorRect(GLContext* aGL, GLint x, GLint y,
    251                                     GLsizei width, GLsizei height)
    252    : mGL(aGL) {
    253  mGL->fGetIntegerv(LOCAL_GL_SCISSOR_BOX, mSavedScissorRect);
    254  mGL->fScissor(x, y, width, height);
    255 }
    256 
    257 ScopedScissorRect::ScopedScissorRect(GLContext* aGL) : mGL(aGL) {
    258  mGL->fGetIntegerv(LOCAL_GL_SCISSOR_BOX, mSavedScissorRect);
    259 }
    260 
    261 ScopedScissorRect::~ScopedScissorRect() {
    262  mGL->fScissor(mSavedScissorRect[0], mSavedScissorRect[1],
    263                mSavedScissorRect[2], mSavedScissorRect[3]);
    264 }
    265 
    266 /* ScopedVertexAttribPointer **************************************************/
    267 
    268 ScopedVertexAttribPointer::ScopedVertexAttribPointer(
    269    GLContext* aGL, GLuint index, GLint size, GLenum type,
    270    realGLboolean normalized, GLsizei stride, GLuint buffer,
    271    const GLvoid* pointer)
    272    : mGL(aGL),
    273      mAttribEnabled(0),
    274      mAttribSize(0),
    275      mAttribStride(0),
    276      mAttribType(0),
    277      mAttribNormalized(0),
    278      mAttribBufferBinding(0),
    279      mAttribPointer(nullptr),
    280      mBoundBuffer(0) {
    281  WrapImpl(index);
    282  mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, buffer);
    283  mGL->fVertexAttribPointer(index, size, type, normalized, stride, pointer);
    284  mGL->fEnableVertexAttribArray(index);
    285 }
    286 
    287 ScopedVertexAttribPointer::ScopedVertexAttribPointer(GLContext* aGL,
    288                                                     GLuint index)
    289    : mGL(aGL),
    290      mAttribEnabled(0),
    291      mAttribSize(0),
    292      mAttribStride(0),
    293      mAttribType(0),
    294      mAttribNormalized(0),
    295      mAttribBufferBinding(0),
    296      mAttribPointer(nullptr),
    297      mBoundBuffer(0) {
    298  WrapImpl(index);
    299 }
    300 
    301 void ScopedVertexAttribPointer::WrapImpl(GLuint index) {
    302  mAttribIndex = index;
    303 
    304  /*
    305   * mGL->fGetVertexAttribiv takes:
    306   *  VERTEX_ATTRIB_ARRAY_ENABLED
    307   *  VERTEX_ATTRIB_ARRAY_SIZE,
    308   *  VERTEX_ATTRIB_ARRAY_STRIDE,
    309   *  VERTEX_ATTRIB_ARRAY_TYPE,
    310   *  VERTEX_ATTRIB_ARRAY_NORMALIZED,
    311   *  VERTEX_ATTRIB_ARRAY_BUFFER_BINDING,
    312   *  CURRENT_VERTEX_ATTRIB
    313   *
    314   * CURRENT_VERTEX_ATTRIB is vertex shader state. \o/
    315   * Others appear to be vertex array state,
    316   * or alternatively in the internal vertex array state
    317   * for a buffer object.
    318   */
    319 
    320  mGL->fGetVertexAttribiv(mAttribIndex, LOCAL_GL_VERTEX_ATTRIB_ARRAY_ENABLED,
    321                          &mAttribEnabled);
    322  mGL->fGetVertexAttribiv(mAttribIndex, LOCAL_GL_VERTEX_ATTRIB_ARRAY_SIZE,
    323                          &mAttribSize);
    324  mGL->fGetVertexAttribiv(mAttribIndex, LOCAL_GL_VERTEX_ATTRIB_ARRAY_STRIDE,
    325                          &mAttribStride);
    326  mGL->fGetVertexAttribiv(mAttribIndex, LOCAL_GL_VERTEX_ATTRIB_ARRAY_TYPE,
    327                          &mAttribType);
    328  mGL->fGetVertexAttribiv(mAttribIndex, LOCAL_GL_VERTEX_ATTRIB_ARRAY_NORMALIZED,
    329                          &mAttribNormalized);
    330  mGL->fGetVertexAttribiv(mAttribIndex,
    331                          LOCAL_GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING,
    332                          &mAttribBufferBinding);
    333  mGL->fGetVertexAttribPointerv(
    334      mAttribIndex, LOCAL_GL_VERTEX_ATTRIB_ARRAY_POINTER, &mAttribPointer);
    335 
    336  // Note that uniform values are program state, so we don't need to rebind
    337  // those.
    338 
    339  mGL->GetUIntegerv(LOCAL_GL_ARRAY_BUFFER_BINDING, &mBoundBuffer);
    340 }
    341 
    342 ScopedVertexAttribPointer::~ScopedVertexAttribPointer() {
    343  mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mAttribBufferBinding);
    344  mGL->fVertexAttribPointer(mAttribIndex, mAttribSize, mAttribType,
    345                            mAttribNormalized, mAttribStride, mAttribPointer);
    346  if (mAttribEnabled)
    347    mGL->fEnableVertexAttribArray(mAttribIndex);
    348  else
    349    mGL->fDisableVertexAttribArray(mAttribIndex);
    350  mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mBoundBuffer);
    351 }
    352 
    353 ////////////////////////////////////////////////////////////////////////
    354 // ScopedPackState
    355 
    356 ScopedPackState::ScopedPackState(GLContext* gl)
    357    : mGL(gl),
    358      mAlignment(0),
    359      mPixelBuffer(0),
    360      mRowLength(0),
    361      mSkipPixels(0),
    362      mSkipRows(0) {
    363  mGL->fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT, &mAlignment);
    364 
    365  if (mAlignment != 4) mGL->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, 4);
    366 
    367  if (!mGL->HasPBOState()) return;
    368 
    369  mGL->fGetIntegerv(LOCAL_GL_PIXEL_PACK_BUFFER_BINDING, (GLint*)&mPixelBuffer);
    370  mGL->fGetIntegerv(LOCAL_GL_PACK_ROW_LENGTH, &mRowLength);
    371  mGL->fGetIntegerv(LOCAL_GL_PACK_SKIP_PIXELS, &mSkipPixels);
    372  mGL->fGetIntegerv(LOCAL_GL_PACK_SKIP_ROWS, &mSkipRows);
    373 
    374  if (mPixelBuffer != 0) mGL->fBindBuffer(LOCAL_GL_PIXEL_PACK_BUFFER, 0);
    375  if (mRowLength != 0) mGL->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH, 0);
    376  if (mSkipPixels != 0) mGL->fPixelStorei(LOCAL_GL_PACK_SKIP_PIXELS, 0);
    377  if (mSkipRows != 0) mGL->fPixelStorei(LOCAL_GL_PACK_SKIP_ROWS, 0);
    378 }
    379 
    380 bool ScopedPackState::SetForWidthAndStrideRGBA(GLsizei aWidth,
    381                                               GLsizei aStride) {
    382  MOZ_ASSERT(aStride % 4 == 0, "RGBA data should always be 4-byte aligned");
    383  MOZ_ASSERT(aStride / 4 >= aWidth, "Stride too small");
    384  if (aStride / 4 == aWidth) {
    385    // No special handling needed.
    386    return true;
    387  }
    388  if (mGL->HasPBOState()) {
    389    // HasPBOState implies support for GL_PACK_ROW_LENGTH.
    390    mGL->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH, aStride / 4);
    391    return true;
    392  }
    393  return false;
    394 }
    395 
    396 ScopedPackState::~ScopedPackState() {
    397  mGL->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, mAlignment);
    398 
    399  if (!mGL->HasPBOState()) return;
    400 
    401  mGL->fBindBuffer(LOCAL_GL_PIXEL_PACK_BUFFER, mPixelBuffer);
    402  mGL->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH, mRowLength);
    403  mGL->fPixelStorei(LOCAL_GL_PACK_SKIP_PIXELS, mSkipPixels);
    404  mGL->fPixelStorei(LOCAL_GL_PACK_SKIP_ROWS, mSkipRows);
    405 }
    406 
    407 ////////////////////////////////////////////////////////////////////////
    408 // ResetUnpackState
    409 
    410 ResetUnpackState::ResetUnpackState(GLContext* gl)
    411    : mGL(gl),
    412      mAlignment(0),
    413      mPBO(0),
    414      mRowLength(0),
    415      mImageHeight(0),
    416      mSkipPixels(0),
    417      mSkipRows(0),
    418      mSkipImages(0) {
    419  const auto fnReset = [&](GLenum pname, GLuint val, GLuint* const out_old) {
    420    mGL->GetUIntegerv(pname, out_old);
    421    if (*out_old != val) {
    422      mGL->fPixelStorei(pname, val);
    423    }
    424  };
    425 
    426  // Default is 4, but 1 is more useful.
    427  fnReset(LOCAL_GL_UNPACK_ALIGNMENT, 1, &mAlignment);
    428 
    429  if (!mGL->HasPBOState()) return;
    430 
    431  mGL->GetUIntegerv(LOCAL_GL_PIXEL_UNPACK_BUFFER_BINDING, &mPBO);
    432  if (mPBO != 0) mGL->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, 0);
    433 
    434  fnReset(LOCAL_GL_UNPACK_ROW_LENGTH, 0, &mRowLength);
    435  fnReset(LOCAL_GL_UNPACK_IMAGE_HEIGHT, 0, &mImageHeight);
    436  fnReset(LOCAL_GL_UNPACK_SKIP_PIXELS, 0, &mSkipPixels);
    437  fnReset(LOCAL_GL_UNPACK_SKIP_ROWS, 0, &mSkipRows);
    438  fnReset(LOCAL_GL_UNPACK_SKIP_IMAGES, 0, &mSkipImages);
    439 }
    440 
    441 ResetUnpackState::~ResetUnpackState() {
    442  mGL->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, mAlignment);
    443 
    444  if (!mGL->HasPBOState()) return;
    445 
    446  mGL->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, mPBO);
    447 
    448  mGL->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, mRowLength);
    449  mGL->fPixelStorei(LOCAL_GL_UNPACK_IMAGE_HEIGHT, mImageHeight);
    450  mGL->fPixelStorei(LOCAL_GL_UNPACK_SKIP_PIXELS, mSkipPixels);
    451  mGL->fPixelStorei(LOCAL_GL_UNPACK_SKIP_ROWS, mSkipRows);
    452  mGL->fPixelStorei(LOCAL_GL_UNPACK_SKIP_IMAGES, mSkipImages);
    453 }
    454 
    455 ////////////////////////////////////////////////////////////////////////
    456 // ScopedBindPBO
    457 
    458 static GLuint GetPBOBinding(GLContext* gl, GLenum target) {
    459  if (!gl->HasPBOState()) return 0;
    460 
    461  GLenum targetBinding;
    462  switch (target) {
    463    case LOCAL_GL_PIXEL_PACK_BUFFER:
    464      targetBinding = LOCAL_GL_PIXEL_PACK_BUFFER_BINDING;
    465      break;
    466 
    467    case LOCAL_GL_PIXEL_UNPACK_BUFFER:
    468      targetBinding = LOCAL_GL_PIXEL_UNPACK_BUFFER_BINDING;
    469      break;
    470 
    471    default:
    472      MOZ_CRASH();
    473  }
    474 
    475  return gl->GetIntAs<GLuint>(targetBinding);
    476 }
    477 
    478 ScopedBindPBO::ScopedBindPBO(GLContext* gl, GLenum target)
    479    : mGL(gl), mTarget(target), mPBO(GetPBOBinding(mGL, mTarget)) {}
    480 
    481 ScopedBindPBO::~ScopedBindPBO() {
    482  if (!mGL->HasPBOState()) return;
    483 
    484  mGL->fBindBuffer(mTarget, mPBO);
    485 }
    486 
    487 } /* namespace gl */
    488 } /* namespace mozilla */