Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 "WebGL2Context.h"
7 :
8 : #include "GLContext.h"
9 : #include "WebGLBuffer.h"
10 : #include "WebGLTransformFeedback.h"
11 :
12 : namespace mozilla {
13 :
14 : // -------------------------------------------------------------------------
15 : // Buffer objects
16 :
17 : void
18 0 : WebGL2Context::CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
19 : GLintptr readOffset, GLintptr writeOffset,
20 : GLsizeiptr size)
21 : {
22 0 : const char funcName[] = "copyBufferSubData";
23 0 : if (IsContextLost())
24 0 : return;
25 :
26 0 : const auto& readBuffer = ValidateBufferSelection(funcName, readTarget);
27 0 : if (!readBuffer)
28 0 : return;
29 :
30 0 : const auto& writeBuffer = ValidateBufferSelection(funcName, writeTarget);
31 0 : if (!writeBuffer)
32 0 : return;
33 :
34 0 : if (!ValidateNonNegative(funcName, "readOffset", readOffset) ||
35 0 : !ValidateNonNegative(funcName, "writeOffset", writeOffset) ||
36 0 : !ValidateNonNegative(funcName, "size", size))
37 : {
38 0 : return;
39 : }
40 :
41 : const auto fnValidateOffsetSize = [&](const char* info, GLintptr offset,
42 0 : const WebGLBuffer* buffer)
43 : {
44 0 : const auto neededBytes = CheckedInt<size_t>(offset) + size;
45 0 : if (!neededBytes.isValid() || neededBytes.value() > buffer->ByteLength()) {
46 0 : ErrorInvalidValue("%s: Invalid %s range.", funcName, info);
47 0 : return false;
48 : }
49 0 : return true;
50 0 : };
51 :
52 0 : if (!fnValidateOffsetSize("read", readOffset, readBuffer) ||
53 0 : !fnValidateOffsetSize("write", writeOffset, writeBuffer))
54 : {
55 0 : return;
56 : }
57 :
58 0 : if (readBuffer == writeBuffer) {
59 0 : MOZ_ASSERT((CheckedInt<WebGLsizeiptr>(readOffset) + size).isValid());
60 0 : MOZ_ASSERT((CheckedInt<WebGLsizeiptr>(writeOffset) + size).isValid());
61 :
62 0 : const bool separate = (readOffset + size <= writeOffset ||
63 0 : writeOffset + size <= readOffset);
64 0 : if (!separate) {
65 0 : ErrorInvalidValue("%s: ranges [readOffset, readOffset + size) and"
66 : " [writeOffset, writeOffset + size) overlap",
67 0 : funcName);
68 0 : return;
69 : }
70 : }
71 :
72 0 : const auto& readType = readBuffer->Content();
73 0 : const auto& writeType = writeBuffer->Content();
74 0 : MOZ_ASSERT(readType != WebGLBuffer::Kind::Undefined);
75 0 : MOZ_ASSERT(writeType != WebGLBuffer::Kind::Undefined);
76 0 : if (writeType != readType) {
77 0 : ErrorInvalidOperation("%s: Can't copy %s data to %s data.",
78 : funcName,
79 0 : (readType == WebGLBuffer::Kind::OtherData) ? "other"
80 : : "element",
81 0 : (writeType == WebGLBuffer::Kind::OtherData) ? "other"
82 0 : : "element");
83 0 : return;
84 : }
85 :
86 0 : gl->MakeCurrent();
87 0 : const ScopedLazyBind readBind(gl, readTarget, readBuffer);
88 0 : const ScopedLazyBind writeBind(gl, writeTarget, writeBuffer);
89 0 : gl->fCopyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size);
90 : }
91 :
92 : void
93 0 : WebGL2Context::GetBufferSubData(GLenum target, GLintptr srcByteOffset,
94 : const dom::ArrayBufferView& dstData, GLuint dstElemOffset,
95 : GLuint dstElemCountOverride)
96 : {
97 0 : const char funcName[] = "getBufferSubData";
98 0 : if (IsContextLost())
99 0 : return;
100 :
101 0 : if (!ValidateNonNegative(funcName, "srcByteOffset", srcByteOffset))
102 0 : return;
103 :
104 : uint8_t* bytes;
105 : size_t byteLen;
106 0 : if (!ValidateArrayBufferView(funcName, dstData, dstElemOffset, dstElemCountOverride,
107 : &bytes, &byteLen))
108 : {
109 0 : return;
110 : }
111 :
112 : ////
113 :
114 0 : const auto& buffer = ValidateBufferSelection(funcName, target);
115 0 : if (!buffer)
116 0 : return;
117 :
118 0 : if (!buffer->ValidateRange(funcName, srcByteOffset, byteLen))
119 0 : return;
120 :
121 : ////
122 :
123 0 : if (!CheckedInt<GLsizeiptr>(byteLen).isValid()) {
124 0 : ErrorOutOfMemory("%s: Size too large.", funcName);
125 0 : return;
126 : }
127 0 : const GLsizeiptr glByteLen(byteLen);
128 :
129 : ////
130 :
131 0 : gl->MakeCurrent();
132 0 : const ScopedLazyBind readBind(gl, target, buffer);
133 :
134 0 : if (byteLen) {
135 0 : const bool isTF = (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER);
136 0 : GLenum mapTarget = target;
137 0 : if (isTF) {
138 0 : gl->fBindTransformFeedback(LOCAL_GL_TRANSFORM_FEEDBACK, mEmptyTFO);
139 0 : gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, buffer->mGLName);
140 0 : mapTarget = LOCAL_GL_ARRAY_BUFFER;
141 : }
142 :
143 0 : const auto mappedBytes = gl->fMapBufferRange(mapTarget, srcByteOffset, glByteLen,
144 0 : LOCAL_GL_MAP_READ_BIT);
145 0 : memcpy(bytes, mappedBytes, byteLen);
146 0 : gl->fUnmapBuffer(mapTarget);
147 :
148 0 : if (isTF) {
149 0 : const GLuint vbo = (mBoundArrayBuffer ? mBoundArrayBuffer->mGLName : 0);
150 0 : gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, vbo);
151 0 : const GLuint tfo = (mBoundTransformFeedback ? mBoundTransformFeedback->mGLName
152 0 : : 0);
153 0 : gl->fBindTransformFeedback(LOCAL_GL_TRANSFORM_FEEDBACK, tfo);
154 : }
155 : }
156 : }
157 :
158 : } // namespace mozilla
|