tor-browser

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

WebGL2ContextBuffers.cpp (6010B)


      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 "WebGL2Context.h"
      9 #include "WebGLBuffer.h"
     10 #include "WebGLTransformFeedback.h"
     11 
     12 namespace mozilla {
     13 
     14 // -------------------------------------------------------------------------
     15 // Buffer objects
     16 
     17 void WebGL2Context::CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
     18                                      uint64_t readOffset, uint64_t writeOffset,
     19                                      uint64_t size) const {
     20  const FuncScope funcScope(*this, "copyBufferSubData");
     21  if (IsContextLost()) return;
     22 
     23  const auto& readBuffer = ValidateBufferSelection(readTarget);
     24  if (!readBuffer) return;
     25 
     26  const auto& writeBuffer = ValidateBufferSelection(writeTarget);
     27  if (!writeBuffer) return;
     28 
     29  if (!CheckedInt<GLintptr>(readOffset).isValid() ||
     30      !CheckedInt<GLintptr>(writeOffset).isValid() ||
     31      !CheckedInt<GLsizeiptr>(size).isValid())
     32    return ErrorOutOfMemory("offset or size too large for platform.");
     33 
     34  const auto fnValidateOffsetSize = [&](const char* info, WebGLintptr offset,
     35                                        const WebGLBuffer* buffer) {
     36    const auto neededBytes = CheckedInt<uint64_t>(offset) + size;
     37    if (!neededBytes.isValid() || neededBytes.value() > buffer->ByteLength()) {
     38      ErrorInvalidValue("Invalid %s range.", info);
     39      return false;
     40    }
     41    return true;
     42  };
     43 
     44  if (!fnValidateOffsetSize("read", readOffset, readBuffer) ||
     45      !fnValidateOffsetSize("write", writeOffset, writeBuffer)) {
     46    return;
     47  }
     48 
     49  if (readBuffer == writeBuffer) {
     50    const bool separate =
     51        (readOffset + size <= writeOffset || writeOffset + size <= readOffset);
     52    if (!separate) {
     53      ErrorInvalidValue(
     54          "Ranges [readOffset, readOffset + size) and"
     55          " [writeOffset, writeOffset + size) overlap.");
     56      return;
     57    }
     58  }
     59 
     60  const auto& readType = readBuffer->Content();
     61  const auto& writeType = writeBuffer->Content();
     62  MOZ_ASSERT(readType != WebGLBuffer::Kind::Undefined);
     63  MOZ_ASSERT(writeType != WebGLBuffer::Kind::Undefined);
     64  if (writeType != readType) {
     65    ErrorInvalidOperation(
     66        "Can't copy %s data to %s data.",
     67        (readType == WebGLBuffer::Kind::OtherData) ? "other" : "element",
     68        (writeType == WebGLBuffer::Kind::OtherData) ? "other" : "element");
     69    return;
     70  }
     71 
     72  const ScopedLazyBind readBind(gl, readTarget, readBuffer);
     73  const ScopedLazyBind writeBind(gl, writeTarget, writeBuffer);
     74  gl->fCopyBufferSubData(readTarget, writeTarget, readOffset, writeOffset,
     75                         size);
     76 
     77  writeBuffer->ResetLastUpdateFenceId();
     78 }
     79 
     80 bool WebGL2Context::GetBufferSubData(GLenum target, uint64_t srcByteOffset,
     81                                     const Range<uint8_t>& dest,
     82                                     uint64_t numRows, uint64_t rowDataWidth,
     83                                     uint64_t srcStride,
     84                                     uint64_t destStride) const {
     85  const FuncScope funcScope(*this, "getBufferSubData");
     86  if (IsContextLost()) return false;
     87 
     88  const auto& buffer = ValidateBufferSelection(target);
     89  if (!buffer) return false;
     90 
     91  uint64_t srcLen =
     92      numRows > 0 ? srcStride * (numRows - 1) + rowDataWidth : dest.length();
     93  uint64_t destLen =
     94      numRows > 0 ? destStride * (numRows - 1) + rowDataWidth : dest.length();
     95  if (!buffer->ValidateRange(srcByteOffset, srcLen)) return false;
     96  if (rowDataWidth > srcStride || rowDataWidth > destStride ||
     97      destLen > dest.length()) {
     98    ErrorInvalidValue("Destination is outside buffer.");
     99    return false;
    100  }
    101 
    102  ////
    103 
    104  if (!CheckedInt<GLintptr>(srcByteOffset).isValid() ||
    105      !CheckedInt<GLsizeiptr>(srcLen).isValid()) {
    106    ErrorOutOfMemory("Offset or size too large for platform.");
    107    return false;
    108  }
    109  const GLsizeiptr glByteLen(srcLen);
    110 
    111  ////
    112 
    113  switch (buffer->mUsage) {
    114    case LOCAL_GL_STATIC_READ:
    115    case LOCAL_GL_STREAM_READ:
    116    case LOCAL_GL_DYNAMIC_READ:
    117      if (mCompletedFenceId < buffer->mLastUpdateFenceId) {
    118        GenerateWarning(
    119            "Reading from a buffer without checking for previous"
    120            " command completion likely causes pipeline stalls."
    121            " Please use FenceSync.");
    122      }
    123      break;
    124    default:
    125      GenerateWarning(
    126          "Reading from a buffer with usage other than *_READ"
    127          " causes pipeline stalls. Copy through a STREAM_READ buffer.");
    128      break;
    129  }
    130 
    131  ////
    132 
    133  const ScopedLazyBind readBind(gl, target, buffer);
    134 
    135  if (srcLen) {
    136    const bool isTF = (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER);
    137    GLenum mapTarget = target;
    138    if (isTF) {
    139      gl->fBindTransformFeedback(LOCAL_GL_TRANSFORM_FEEDBACK, mEmptyTFO);
    140      gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, buffer->mGLName);
    141      mapTarget = LOCAL_GL_ARRAY_BUFFER;
    142    }
    143 
    144    const void* mappedBytes = gl->fMapBufferRange(
    145        mapTarget, srcByteOffset, glByteLen, LOCAL_GL_MAP_READ_BIT);
    146    if (numRows > 0 && (destStride != srcStride || rowDataWidth != srcStride)) {
    147      const uint8_t* srcRow = (const uint8_t*)mappedBytes;
    148      uint8_t* destRow = dest.begin().get();
    149      while (numRows > 0) {
    150        memcpy(destRow, srcRow, rowDataWidth);
    151        srcRow += srcStride;
    152        destRow += destStride;
    153        --numRows;
    154      }
    155    } else {
    156      memcpy(dest.begin().get(), mappedBytes, srcLen);
    157    }
    158    gl->fUnmapBuffer(mapTarget);
    159 
    160    if (isTF) {
    161      const GLuint vbo = (mBoundArrayBuffer ? mBoundArrayBuffer->mGLName : 0);
    162      gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, vbo);
    163      const GLuint tfo =
    164          (mBoundTransformFeedback ? mBoundTransformFeedback->mGLName : 0);
    165      gl->fBindTransformFeedback(LOCAL_GL_TRANSFORM_FEEDBACK, tfo);
    166    }
    167  }
    168  return true;
    169 }
    170 
    171 }  // namespace mozilla