/* -*- 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