tor-browser

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

WebGLContextBuffers.cpp (8237B)


      1 /* -*- Mode: C++; tab-width: 4; 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 "ClientWebGLContext.h"
      7 #include "GLContext.h"
      8 #include "WebGLBuffer.h"
      9 #include "WebGLContext.h"
     10 #include "WebGLTransformFeedback.h"
     11 #include "WebGLVertexArray.h"
     12 
     13 namespace mozilla {
     14 
     15 RefPtr<WebGLBuffer>* WebGLContext::ValidateBufferSlot(GLenum target) {
     16  RefPtr<WebGLBuffer>* slot = nullptr;
     17 
     18  switch (target) {
     19    case LOCAL_GL_ARRAY_BUFFER:
     20      slot = &mBoundArrayBuffer;
     21      break;
     22 
     23    case LOCAL_GL_ELEMENT_ARRAY_BUFFER:
     24      slot = &(mBoundVertexArray->mElementArrayBuffer);
     25      break;
     26  }
     27 
     28  if (IsWebGL2()) {
     29    switch (target) {
     30      case LOCAL_GL_COPY_READ_BUFFER:
     31        slot = &mBoundCopyReadBuffer;
     32        break;
     33 
     34      case LOCAL_GL_COPY_WRITE_BUFFER:
     35        slot = &mBoundCopyWriteBuffer;
     36        break;
     37 
     38      case LOCAL_GL_PIXEL_PACK_BUFFER:
     39        slot = &mBoundPixelPackBuffer;
     40        break;
     41 
     42      case LOCAL_GL_PIXEL_UNPACK_BUFFER:
     43        slot = &mBoundPixelUnpackBuffer;
     44        break;
     45 
     46      case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
     47        slot = &mBoundTransformFeedbackBuffer;
     48        break;
     49 
     50      case LOCAL_GL_UNIFORM_BUFFER:
     51        slot = &mBoundUniformBuffer;
     52        break;
     53    }
     54  }
     55 
     56  if (!slot) {
     57    ErrorInvalidEnumInfo("target", target);
     58    return nullptr;
     59  }
     60 
     61  return slot;
     62 }
     63 
     64 WebGLBuffer* WebGLContext::ValidateBufferSelection(GLenum target) const {
     65  const auto& slot =
     66      const_cast<WebGLContext*>(this)->ValidateBufferSlot(target);
     67  if (!slot) return nullptr;
     68  const auto& buffer = *slot;
     69 
     70  if (!buffer) {
     71    ErrorInvalidOperation("Buffer for `target` is null.");
     72    return nullptr;
     73  }
     74 
     75  if (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER) {
     76    if (mBoundTransformFeedback->IsActiveAndNotPaused()) {
     77      ErrorInvalidOperation(
     78          "Cannot select TRANSFORM_FEEDBACK_BUFFER when"
     79          " transform feedback is active and unpaused.");
     80      return nullptr;
     81    }
     82    const auto tfBuffers = std::vector<webgl::BufferAndIndex>{{
     83        {buffer},
     84    }};
     85 
     86    if (!ValidateBuffersForTf(tfBuffers)) return nullptr;
     87  } else {
     88    if (mBoundTransformFeedback && !ValidateBufferForNonTf(buffer, target))
     89      return nullptr;
     90  }
     91 
     92  return buffer.get();
     93 }
     94 
     95 IndexedBufferBinding* WebGLContext::ValidateIndexedBufferSlot(GLenum target,
     96                                                              GLuint index) {
     97  decltype(mIndexedUniformBufferBindings)* bindings;
     98  const char* maxIndexEnum;
     99  switch (target) {
    100    case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
    101      if (mBoundTransformFeedback->mIsActive &&
    102          !mBoundTransformFeedback->mIsPaused) {
    103        ErrorInvalidOperation("Transform feedback active and not paused.");
    104        return nullptr;
    105      }
    106      bindings = &(mBoundTransformFeedback->mIndexedBindings);
    107      maxIndexEnum = "MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS";
    108      break;
    109 
    110    case LOCAL_GL_UNIFORM_BUFFER:
    111      bindings = &mIndexedUniformBufferBindings;
    112      maxIndexEnum = "MAX_UNIFORM_BUFFER_BINDINGS";
    113      break;
    114 
    115    default:
    116      ErrorInvalidEnumInfo("target", target);
    117      return nullptr;
    118  }
    119 
    120  if (index >= bindings->size()) {
    121    ErrorInvalidValue("`index` >= %s.", maxIndexEnum);
    122    return nullptr;
    123  }
    124 
    125  return &(*bindings)[index];
    126 }
    127 
    128 ////////////////////////////////////////
    129 
    130 void WebGLContext::BindBuffer(GLenum target, WebGLBuffer* buffer) {
    131  FuncScope funcScope(*this, "bindBuffer");
    132  if (IsContextLost()) return;
    133  funcScope.mBindFailureGuard = true;
    134 
    135  if (buffer && !ValidateObject("buffer", *buffer)) return;
    136 
    137  const auto& slot = ValidateBufferSlot(target);
    138  if (!slot) return;
    139 
    140  if (buffer && !buffer->ValidateCanBindToTarget(target)) return;
    141 
    142  if (!IsBufferTargetLazilyBound(target)) {
    143    gl->fBindBuffer(target, buffer ? buffer->mGLName : 0);
    144  }
    145 
    146  *slot = buffer;
    147  if (buffer) {
    148    buffer->SetContentAfterBind(target);
    149  }
    150 
    151  funcScope.mBindFailureGuard = false;
    152 }
    153 
    154 ////////////////////////////////////////
    155 
    156 bool WebGLContext::ValidateIndexedBufferBinding(
    157    GLenum target, GLuint index, RefPtr<WebGLBuffer>** const out_genericBinding,
    158    IndexedBufferBinding** const out_indexedBinding) {
    159  *out_genericBinding = ValidateBufferSlot(target);
    160  if (!*out_genericBinding) return false;
    161 
    162  *out_indexedBinding = ValidateIndexedBufferSlot(target, index);
    163  if (!*out_indexedBinding) return false;
    164 
    165  if (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER &&
    166      mBoundTransformFeedback->mIsActive) {
    167    ErrorInvalidOperation(
    168        "Cannot update indexed buffer bindings on active"
    169        " transform feedback objects.");
    170    return false;
    171  }
    172 
    173  return true;
    174 }
    175 
    176 void WebGLContext::BindBufferRange(GLenum target, GLuint index,
    177                                   WebGLBuffer* buffer, uint64_t offset,
    178                                   uint64_t size) {
    179  FuncScope funcScope(*this, "bindBufferBase/Range");
    180  if (buffer && !ValidateObject("buffer", *buffer)) return;
    181  funcScope.mBindFailureGuard = true;
    182 
    183  RefPtr<WebGLBuffer>* genericBinding;
    184  IndexedBufferBinding* indexedBinding;
    185  if (!ValidateIndexedBufferBinding(target, index, &genericBinding,
    186                                    &indexedBinding)) {
    187    return;
    188  }
    189 
    190  if (buffer && !buffer->ValidateCanBindToTarget(target)) return;
    191 
    192  const auto& limits = Limits();
    193  auto err =
    194      CheckBindBufferRange(target, index, bool(buffer), offset, size, limits);
    195  if (err) return;
    196 
    197  ////
    198 
    199  bool needsPrebind = false;
    200  needsPrebind |= gl->IsANGLE();
    201 #ifdef XP_MACOSX
    202  needsPrebind = true;
    203 #endif
    204 
    205  if (gl->WorkAroundDriverBugs() && buffer && needsPrebind) {
    206    // BindBufferBase/Range will fail (on some drivers) if the buffer name has
    207    // never been bound. (GenBuffers makes a name, but BindBuffer initializes
    208    // that name as a real buffer object)
    209    gl->fBindBuffer(target, buffer->mGLName);
    210  }
    211 
    212  if (size) {
    213    gl->fBindBufferRange(target, index, buffer ? buffer->mGLName : 0, offset,
    214                         size);
    215  } else {
    216    gl->fBindBufferBase(target, index, buffer ? buffer->mGLName : 0);
    217  }
    218 
    219  if (buffer) {
    220    gl->fBindBuffer(target, 0);  // Reset generic.
    221  }
    222 
    223  ////
    224 
    225  *genericBinding = buffer;
    226  indexedBinding->mBufferBinding = buffer;
    227  indexedBinding->mRangeStart = offset;
    228  indexedBinding->mRangeSize = size;
    229 
    230  if (buffer) {
    231    buffer->SetContentAfterBind(target);
    232  }
    233 
    234  funcScope.mBindFailureGuard = false;
    235 }
    236 
    237 ////////////////////////////////////////
    238 
    239 void WebGLContext::BufferData(GLenum target, uint64_t dataLen,
    240                              const uint8_t* data, GLenum usage) const {
    241  // `data` may be null.
    242  const FuncScope funcScope(*this, "bufferData");
    243  if (IsContextLost()) return;
    244 
    245  const auto& buffer = ValidateBufferSelection(target);
    246  if (!buffer) return;
    247 
    248  buffer->BufferData(target, dataLen, data, usage);
    249 }
    250 
    251 void WebGLContext::UninitializedBufferData_SizeOnly(GLenum target,
    252                                                    uint64_t dataLen,
    253                                                    GLenum usage) const {
    254  const FuncScope funcScope(*this, "bufferData");
    255  if (IsContextLost()) return;
    256 
    257  const auto& buffer = ValidateBufferSelection(target);
    258  if (!buffer) return;
    259 
    260  buffer->BufferData(target, dataLen, nullptr, usage, true);
    261 }
    262 
    263 ////////////////////////////////////////
    264 
    265 void WebGLContext::BufferSubData(GLenum target, uint64_t dstByteOffset,
    266                                 uint64_t dataLen, const uint8_t* data,
    267                                 bool unsynchronized) const {
    268  MOZ_ASSERT(data || !dataLen);
    269  const FuncScope funcScope(*this, "bufferSubData");
    270  if (IsContextLost()) return;
    271 
    272  const auto& buffer = ValidateBufferSelection(target);
    273  if (!buffer) return;
    274  buffer->BufferSubData(target, dstByteOffset, dataLen, data, unsynchronized);
    275 }
    276 
    277 ////////////////////////////////////////
    278 
    279 RefPtr<WebGLBuffer> WebGLContext::CreateBuffer() {
    280  const FuncScope funcScope(*this, "createBuffer");
    281  if (IsContextLost()) return nullptr;
    282 
    283  GLuint buf = 0;
    284  gl->fGenBuffers(1, &buf);
    285 
    286  return new WebGLBuffer(this, buf);
    287 }
    288 
    289 }  // namespace mozilla