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.cpp158
1 files changed, 158 insertions, 0 deletions
diff --git a/dom/canvas/WebGL2ContextBuffers.cpp b/dom/canvas/WebGL2ContextBuffers.cpp
new file mode 100644
index 000000000..f59fa08b8
--- /dev/null
+++ b/dom/canvas/WebGL2ContextBuffers.cpp
@@ -0,0 +1,158 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* 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 "GLContext.h"
+#include "WebGLBuffer.h"
+#include "WebGLTransformFeedback.h"
+
+namespace mozilla {
+
+// -------------------------------------------------------------------------
+// Buffer objects
+
+void
+WebGL2Context::CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
+ GLintptr readOffset, GLintptr writeOffset,
+ GLsizeiptr size)
+{
+ const char funcName[] = "copyBufferSubData";
+ if (IsContextLost())
+ return;
+
+ const auto& readBuffer = ValidateBufferSelection(funcName, readTarget);
+ if (!readBuffer)
+ return;
+
+ const auto& writeBuffer = ValidateBufferSelection(funcName, writeTarget);
+ if (!writeBuffer)
+ return;
+
+ if (!ValidateNonNegative(funcName, "readOffset", readOffset) ||
+ !ValidateNonNegative(funcName, "writeOffset", writeOffset) ||
+ !ValidateNonNegative(funcName, "size", size))
+ {
+ return;
+ }
+
+ const auto fnValidateOffsetSize = [&](const char* info, GLintptr offset,
+ const WebGLBuffer* buffer)
+ {
+ const auto neededBytes = CheckedInt<size_t>(offset) + size;
+ if (!neededBytes.isValid() || neededBytes.value() > buffer->ByteLength()) {
+ ErrorInvalidValue("%s: Invalid %s range.", funcName, info);
+ return false;
+ }
+ return true;
+ };
+
+ if (!fnValidateOffsetSize("read", readOffset, readBuffer) ||
+ !fnValidateOffsetSize("write", writeOffset, writeBuffer))
+ {
+ return;
+ }
+
+ if (readBuffer == writeBuffer) {
+ MOZ_ASSERT((CheckedInt<WebGLsizeiptr>(readOffset) + size).isValid());
+ MOZ_ASSERT((CheckedInt<WebGLsizeiptr>(writeOffset) + size).isValid());
+
+ const bool separate = (readOffset + size <= writeOffset ||
+ writeOffset + size <= readOffset);
+ if (!separate) {
+ ErrorInvalidValue("%s: ranges [readOffset, readOffset + size) and"
+ " [writeOffset, writeOffset + size) overlap",
+ funcName);
+ 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("%s: Can't copy %s data to %s data.",
+ funcName,
+ (readType == WebGLBuffer::Kind::OtherData) ? "other"
+ : "element",
+ (writeType == WebGLBuffer::Kind::OtherData) ? "other"
+ : "element");
+ return;
+ }
+
+ gl->MakeCurrent();
+ const ScopedLazyBind readBind(gl, readTarget, readBuffer);
+ const ScopedLazyBind writeBind(gl, writeTarget, writeBuffer);
+ gl->fCopyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size);
+}
+
+void
+WebGL2Context::GetBufferSubData(GLenum target, GLintptr srcByteOffset,
+ const dom::ArrayBufferView& dstData, GLuint dstElemOffset,
+ GLuint dstElemCountOverride)
+{
+ const char funcName[] = "getBufferSubData";
+ if (IsContextLost())
+ return;
+
+ if (!ValidateNonNegative(funcName, "srcByteOffset", srcByteOffset))
+ return;
+
+ uint8_t* bytes;
+ size_t byteLen;
+ if (!ValidateArrayBufferView(funcName, dstData, dstElemOffset, dstElemCountOverride,
+ &bytes, &byteLen))
+ {
+ return;
+ }
+
+ ////
+
+ const auto& buffer = ValidateBufferSelection(funcName, target);
+ if (!buffer)
+ return;
+
+ if (!buffer->ValidateRange(funcName, srcByteOffset, byteLen))
+ return;
+
+ ////
+
+ if (!CheckedInt<GLsizeiptr>(byteLen).isValid()) {
+ ErrorOutOfMemory("%s: Size too large.", funcName);
+ return;
+ }
+ const GLsizeiptr glByteLen(byteLen);
+
+ ////
+
+ gl->MakeCurrent();
+ 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(bytes, mappedBytes, byteLen);
+ 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);
+ }
+ }
+}
+
+} // namespace mozilla