summaryrefslogtreecommitdiffstats
path: root/dom/canvas/WebGL2ContextBuffers.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/canvas/WebGL2ContextBuffers.cpp')
-rw-r--r--dom/canvas/WebGL2ContextBuffers.cpp150
1 files changed, 150 insertions, 0 deletions
diff --git a/dom/canvas/WebGL2ContextBuffers.cpp b/dom/canvas/WebGL2ContextBuffers.cpp
new file mode 100644
index 0000000000..ebbda995ee
--- /dev/null
+++ b/dom/canvas/WebGL2ContextBuffers.cpp
@@ -0,0 +1,150 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "WebGL2Context.h"
+
+#include "ClientWebGLContext.h"
+#include "GLContext.h"
+#include "WebGLBuffer.h"
+#include "WebGLTransformFeedback.h"
+
+namespace mozilla {
+
+// -------------------------------------------------------------------------
+// Buffer objects
+
+void WebGL2Context::CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
+ uint64_t readOffset, uint64_t writeOffset,
+ uint64_t size) const {
+ const FuncScope funcScope(*this, "copyBufferSubData");
+ if (IsContextLost()) return;
+
+ const auto& readBuffer = ValidateBufferSelection(readTarget);
+ if (!readBuffer) return;
+
+ const auto& writeBuffer = ValidateBufferSelection(writeTarget);
+ if (!writeBuffer) return;
+
+ if (!CheckedInt<GLintptr>(readOffset).isValid() ||
+ !CheckedInt<GLintptr>(writeOffset).isValid() ||
+ !CheckedInt<GLsizeiptr>(size).isValid())
+ return ErrorOutOfMemory("offset or size too large for platform.");
+
+ const auto fnValidateOffsetSize = [&](const char* info, WebGLintptr offset,
+ const WebGLBuffer* buffer) {
+ const auto neededBytes = CheckedInt<uint64_t>(offset) + size;
+ if (!neededBytes.isValid() || neededBytes.value() > buffer->ByteLength()) {
+ ErrorInvalidValue("Invalid %s range.", info);
+ return false;
+ }
+ return true;
+ };
+
+ if (!fnValidateOffsetSize("read", readOffset, readBuffer) ||
+ !fnValidateOffsetSize("write", writeOffset, writeBuffer)) {
+ return;
+ }
+
+ if (readBuffer == writeBuffer) {
+ const bool separate =
+ (readOffset + size <= writeOffset || writeOffset + size <= readOffset);
+ if (!separate) {
+ ErrorInvalidValue(
+ "Ranges [readOffset, readOffset + size) and"
+ " [writeOffset, writeOffset + size) overlap.");
+ return;
+ }
+ }
+
+ const auto& readType = readBuffer->Content();
+ const auto& writeType = writeBuffer->Content();
+ MOZ_ASSERT(readType != WebGLBuffer::Kind::Undefined);
+ MOZ_ASSERT(writeType != WebGLBuffer::Kind::Undefined);
+ if (writeType != readType) {
+ ErrorInvalidOperation(
+ "Can't copy %s data to %s data.",
+ (readType == WebGLBuffer::Kind::OtherData) ? "other" : "element",
+ (writeType == WebGLBuffer::Kind::OtherData) ? "other" : "element");
+ return;
+ }
+
+ const ScopedLazyBind readBind(gl, readTarget, readBuffer);
+ const ScopedLazyBind writeBind(gl, writeTarget, writeBuffer);
+ gl->fCopyBufferSubData(readTarget, writeTarget, readOffset, writeOffset,
+ size);
+
+ writeBuffer->ResetLastUpdateFenceId();
+}
+
+bool WebGL2Context::GetBufferSubData(GLenum target, uint64_t srcByteOffset,
+ const Range<uint8_t>& dest) const {
+ const FuncScope funcScope(*this, "getBufferSubData");
+ if (IsContextLost()) return false;
+
+ const auto& buffer = ValidateBufferSelection(target);
+ if (!buffer) return false;
+
+ const auto byteLen = dest.length();
+ if (!buffer->ValidateRange(srcByteOffset, byteLen)) return false;
+
+ ////
+
+ if (!CheckedInt<GLintptr>(srcByteOffset).isValid() ||
+ !CheckedInt<GLsizeiptr>(byteLen).isValid()) {
+ ErrorOutOfMemory("offset or size too large for platform.");
+ return false;
+ }
+ const GLsizeiptr glByteLen(byteLen);
+
+ ////
+
+ switch (buffer->mUsage) {
+ case LOCAL_GL_STATIC_READ:
+ case LOCAL_GL_STREAM_READ:
+ case LOCAL_GL_DYNAMIC_READ:
+ if (mCompletedFenceId < buffer->mLastUpdateFenceId) {
+ GenerateWarning(
+ "Reading from a buffer without checking for previous"
+ " command completion likely causes pipeline stalls."
+ " Please use FenceSync.");
+ }
+ break;
+ default:
+ GenerateWarning(
+ "Reading from a buffer with usage other than *_READ"
+ " causes pipeline stalls. Copy through a STREAM_READ buffer.");
+ break;
+ }
+
+ ////
+
+ const ScopedLazyBind readBind(gl, target, buffer);
+
+ if (byteLen) {
+ const bool isTF = (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER);
+ GLenum mapTarget = target;
+ if (isTF) {
+ gl->fBindTransformFeedback(LOCAL_GL_TRANSFORM_FEEDBACK, mEmptyTFO);
+ gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, buffer->mGLName);
+ mapTarget = LOCAL_GL_ARRAY_BUFFER;
+ }
+
+ const auto mappedBytes = gl->fMapBufferRange(
+ mapTarget, srcByteOffset, glByteLen, LOCAL_GL_MAP_READ_BIT);
+ memcpy(dest.begin().get(), mappedBytes, dest.length());
+ gl->fUnmapBuffer(mapTarget);
+
+ if (isTF) {
+ const GLuint vbo = (mBoundArrayBuffer ? mBoundArrayBuffer->mGLName : 0);
+ gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, vbo);
+ const GLuint tfo =
+ (mBoundTransformFeedback ? mBoundTransformFeedback->mGLName : 0);
+ gl->fBindTransformFeedback(LOCAL_GL_TRANSFORM_FEEDBACK, tfo);
+ }
+ }
+ return true;
+}
+
+} // namespace mozilla