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/. */
6 #include "WebGL2Context.h"
8 #include "ClientWebGLContext.h"
10 #include "WebGLBuffer.h"
11 #include "WebGLTransformFeedback.h"
15 // -------------------------------------------------------------------------
18 void WebGL2Context::CopyBufferSubData(GLenum readTarget
, GLenum writeTarget
,
19 uint64_t readOffset
, uint64_t writeOffset
,
20 uint64_t size
) const {
21 const FuncScope
funcScope(*this, "copyBufferSubData");
22 if (IsContextLost()) return;
24 const auto& readBuffer
= ValidateBufferSelection(readTarget
);
25 if (!readBuffer
) return;
27 const auto& writeBuffer
= ValidateBufferSelection(writeTarget
);
28 if (!writeBuffer
) return;
30 if (!CheckedInt
<GLintptr
>(readOffset
).isValid() ||
31 !CheckedInt
<GLintptr
>(writeOffset
).isValid() ||
32 !CheckedInt
<GLsizeiptr
>(size
).isValid())
33 return ErrorOutOfMemory("offset or size too large for platform.");
35 const auto fnValidateOffsetSize
= [&](const char* info
, WebGLintptr offset
,
36 const WebGLBuffer
* buffer
) {
37 const auto neededBytes
= CheckedInt
<uint64_t>(offset
) + size
;
38 if (!neededBytes
.isValid() || neededBytes
.value() > buffer
->ByteLength()) {
39 ErrorInvalidValue("Invalid %s range.", info
);
45 if (!fnValidateOffsetSize("read", readOffset
, readBuffer
) ||
46 !fnValidateOffsetSize("write", writeOffset
, writeBuffer
)) {
50 if (readBuffer
== writeBuffer
) {
52 (readOffset
+ size
<= writeOffset
|| writeOffset
+ size
<= readOffset
);
55 "Ranges [readOffset, readOffset + size) and"
56 " [writeOffset, writeOffset + size) overlap.");
61 const auto& readType
= readBuffer
->Content();
62 const auto& writeType
= writeBuffer
->Content();
63 MOZ_ASSERT(readType
!= WebGLBuffer::Kind::Undefined
);
64 MOZ_ASSERT(writeType
!= WebGLBuffer::Kind::Undefined
);
65 if (writeType
!= readType
) {
66 ErrorInvalidOperation(
67 "Can't copy %s data to %s data.",
68 (readType
== WebGLBuffer::Kind::OtherData
) ? "other" : "element",
69 (writeType
== WebGLBuffer::Kind::OtherData
) ? "other" : "element");
73 const ScopedLazyBind
readBind(gl
, readTarget
, readBuffer
);
74 const ScopedLazyBind
writeBind(gl
, writeTarget
, writeBuffer
);
75 gl
->fCopyBufferSubData(readTarget
, writeTarget
, readOffset
, writeOffset
,
78 writeBuffer
->ResetLastUpdateFenceId();
81 bool WebGL2Context::GetBufferSubData(GLenum target
, uint64_t srcByteOffset
,
82 const Range
<uint8_t>& dest
) const {
83 const FuncScope
funcScope(*this, "getBufferSubData");
84 if (IsContextLost()) return false;
86 const auto& buffer
= ValidateBufferSelection(target
);
87 if (!buffer
) return false;
89 const auto byteLen
= dest
.length();
90 if (!buffer
->ValidateRange(srcByteOffset
, byteLen
)) return false;
94 if (!CheckedInt
<GLintptr
>(srcByteOffset
).isValid() ||
95 !CheckedInt
<GLsizeiptr
>(byteLen
).isValid()) {
96 ErrorOutOfMemory("offset or size too large for platform.");
99 const GLsizeiptr
glByteLen(byteLen
);
103 switch (buffer
->mUsage
) {
104 case LOCAL_GL_STATIC_READ
:
105 case LOCAL_GL_STREAM_READ
:
106 case LOCAL_GL_DYNAMIC_READ
:
107 if (mCompletedFenceId
< buffer
->mLastUpdateFenceId
) {
109 "Reading from a buffer without checking for previous"
110 " command completion likely causes pipeline stalls."
111 " Please use FenceSync.");
116 "Reading from a buffer with usage other than *_READ"
117 " causes pipeline stalls. Copy through a STREAM_READ buffer.");
123 const ScopedLazyBind
readBind(gl
, target
, buffer
);
126 const bool isTF
= (target
== LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER
);
127 GLenum mapTarget
= target
;
129 gl
->fBindTransformFeedback(LOCAL_GL_TRANSFORM_FEEDBACK
, mEmptyTFO
);
130 gl
->fBindBuffer(LOCAL_GL_ARRAY_BUFFER
, buffer
->mGLName
);
131 mapTarget
= LOCAL_GL_ARRAY_BUFFER
;
134 const auto mappedBytes
= gl
->fMapBufferRange(
135 mapTarget
, srcByteOffset
, glByteLen
, LOCAL_GL_MAP_READ_BIT
);
136 memcpy(dest
.begin().get(), mappedBytes
, dest
.length());
137 gl
->fUnmapBuffer(mapTarget
);
140 const GLuint vbo
= (mBoundArrayBuffer
? mBoundArrayBuffer
->mGLName
: 0);
141 gl
->fBindBuffer(LOCAL_GL_ARRAY_BUFFER
, vbo
);
143 (mBoundTransformFeedback
? mBoundTransformFeedback
->mGLName
: 0);
144 gl
->fBindTransformFeedback(LOCAL_GL_TRANSFORM_FEEDBACK
, tfo
);
150 } // namespace mozilla