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 "ClientWebGLContext.h"
10 #include "GLContext.h"
11 #include "WebGLBuffer.h"
12 #include "WebGLContext.h"
13 #include "WebGLTransformFeedback.h"
14 #include "WebGLVertexArray.h"
18 RefPtr
<WebGLBuffer
>* WebGLContext::ValidateBufferSlot(GLenum target
) {
19 RefPtr
<WebGLBuffer
>* slot
= nullptr;
22 case LOCAL_GL_ARRAY_BUFFER
:
23 slot
= &mBoundArrayBuffer
;
26 case LOCAL_GL_ELEMENT_ARRAY_BUFFER
:
27 slot
= &(mBoundVertexArray
->mElementArrayBuffer
);
33 case LOCAL_GL_COPY_READ_BUFFER
:
34 slot
= &mBoundCopyReadBuffer
;
37 case LOCAL_GL_COPY_WRITE_BUFFER
:
38 slot
= &mBoundCopyWriteBuffer
;
41 case LOCAL_GL_PIXEL_PACK_BUFFER
:
42 slot
= &mBoundPixelPackBuffer
;
45 case LOCAL_GL_PIXEL_UNPACK_BUFFER
:
46 slot
= &mBoundPixelUnpackBuffer
;
49 case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER
:
50 slot
= &mBoundTransformFeedbackBuffer
;
53 case LOCAL_GL_UNIFORM_BUFFER
:
54 slot
= &mBoundUniformBuffer
;
60 ErrorInvalidEnumInfo("target", target
);
67 WebGLBuffer
* WebGLContext::ValidateBufferSelection(GLenum target
) const {
69 const_cast<WebGLContext
*>(this)->ValidateBufferSlot(target
);
70 if (!slot
) return nullptr;
71 const auto& buffer
= *slot
;
74 ErrorInvalidOperation("Buffer for `target` is null.");
78 if (target
== LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER
) {
79 if (mBoundTransformFeedback
->IsActiveAndNotPaused()) {
80 ErrorInvalidOperation(
81 "Cannot select TRANSFORM_FEEDBACK_BUFFER when"
82 " transform feedback is active and unpaused.");
85 const auto tfBuffers
= std::vector
<webgl::BufferAndIndex
>{{
89 if (!ValidateBuffersForTf(tfBuffers
)) return nullptr;
91 if (mBoundTransformFeedback
&& !ValidateBufferForNonTf(buffer
, target
))
98 IndexedBufferBinding
* WebGLContext::ValidateIndexedBufferSlot(GLenum target
,
100 decltype(mIndexedUniformBufferBindings
)* bindings
;
101 const char* maxIndexEnum
;
103 case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER
:
104 if (mBoundTransformFeedback
->mIsActive
&&
105 !mBoundTransformFeedback
->mIsPaused
) {
106 ErrorInvalidOperation("Transform feedback active and not paused.");
109 bindings
= &(mBoundTransformFeedback
->mIndexedBindings
);
110 maxIndexEnum
= "MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS";
113 case LOCAL_GL_UNIFORM_BUFFER
:
114 bindings
= &mIndexedUniformBufferBindings
;
115 maxIndexEnum
= "MAX_UNIFORM_BUFFER_BINDINGS";
119 ErrorInvalidEnumInfo("target", target
);
123 if (index
>= bindings
->size()) {
124 ErrorInvalidValue("`index` >= %s.", maxIndexEnum
);
128 return &(*bindings
)[index
];
131 ////////////////////////////////////////
133 void WebGLContext::BindBuffer(GLenum target
, WebGLBuffer
* buffer
) {
134 FuncScope
funcScope(*this, "bindBuffer");
135 if (IsContextLost()) return;
136 funcScope
.mBindFailureGuard
= true;
138 if (buffer
&& !ValidateObject("buffer", *buffer
)) return;
140 const auto& slot
= ValidateBufferSlot(target
);
143 if (buffer
&& !buffer
->ValidateCanBindToTarget(target
)) return;
145 if (!IsBufferTargetLazilyBound(target
)) {
146 gl
->fBindBuffer(target
, buffer
? buffer
->mGLName
: 0);
151 buffer
->SetContentAfterBind(target
);
154 funcScope
.mBindFailureGuard
= false;
157 ////////////////////////////////////////
159 bool WebGLContext::ValidateIndexedBufferBinding(
160 GLenum target
, GLuint index
, RefPtr
<WebGLBuffer
>** const out_genericBinding
,
161 IndexedBufferBinding
** const out_indexedBinding
) {
162 *out_genericBinding
= ValidateBufferSlot(target
);
163 if (!*out_genericBinding
) return false;
165 *out_indexedBinding
= ValidateIndexedBufferSlot(target
, index
);
166 if (!*out_indexedBinding
) return false;
168 if (target
== LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER
&&
169 mBoundTransformFeedback
->mIsActive
) {
170 ErrorInvalidOperation(
171 "Cannot update indexed buffer bindings on active"
172 " transform feedback objects.");
179 void WebGLContext::BindBufferRange(GLenum target
, GLuint index
,
180 WebGLBuffer
* buffer
, uint64_t offset
,
182 FuncScope
funcScope(*this, "bindBufferBase/Range");
183 if (buffer
&& !ValidateObject("buffer", *buffer
)) return;
184 funcScope
.mBindFailureGuard
= true;
186 RefPtr
<WebGLBuffer
>* genericBinding
;
187 IndexedBufferBinding
* indexedBinding
;
188 if (!ValidateIndexedBufferBinding(target
, index
, &genericBinding
,
193 if (buffer
&& !buffer
->ValidateCanBindToTarget(target
)) return;
195 const auto& limits
= Limits();
197 CheckBindBufferRange(target
, index
, bool(buffer
), offset
, size
, limits
);
202 bool needsPrebind
= false;
203 needsPrebind
|= gl
->IsANGLE();
208 if (gl
->WorkAroundDriverBugs() && buffer
&& needsPrebind
) {
209 // BindBufferBase/Range will fail (on some drivers) if the buffer name has
210 // never been bound. (GenBuffers makes a name, but BindBuffer initializes
211 // that name as a real buffer object)
212 gl
->fBindBuffer(target
, buffer
->mGLName
);
216 gl
->fBindBufferRange(target
, index
, buffer
? buffer
->mGLName
: 0, offset
,
219 gl
->fBindBufferBase(target
, index
, buffer
? buffer
->mGLName
: 0);
223 gl
->fBindBuffer(target
, 0); // Reset generic.
228 *genericBinding
= buffer
;
229 indexedBinding
->mBufferBinding
= buffer
;
230 indexedBinding
->mRangeStart
= offset
;
231 indexedBinding
->mRangeSize
= size
;
234 buffer
->SetContentAfterBind(target
);
237 funcScope
.mBindFailureGuard
= false;
240 ////////////////////////////////////////
242 void WebGLContext::BufferData(GLenum target
, uint64_t dataLen
,
243 const uint8_t* data
, GLenum usage
) const {
244 // `data` may be null.
245 const FuncScope
funcScope(*this, "bufferData");
246 if (IsContextLost()) return;
248 const auto& buffer
= ValidateBufferSelection(target
);
251 buffer
->BufferData(target
, dataLen
, data
, usage
);
254 void WebGLContext::UninitializedBufferData_SizeOnly(GLenum target
,
256 GLenum usage
) const {
257 const FuncScope
funcScope(*this, "bufferData");
258 if (IsContextLost()) return;
260 const auto& buffer
= ValidateBufferSelection(target
);
263 buffer
->BufferData(target
, dataLen
, nullptr, usage
, true);
266 ////////////////////////////////////////
268 void WebGLContext::BufferSubData(GLenum target
, uint64_t dstByteOffset
,
269 uint64_t dataLen
, const uint8_t* data
,
270 bool unsynchronized
) const {
271 MOZ_ASSERT(data
|| !dataLen
);
272 const FuncScope
funcScope(*this, "bufferSubData");
273 if (IsContextLost()) return;
275 const auto& buffer
= ValidateBufferSelection(target
);
277 buffer
->BufferSubData(target
, dstByteOffset
, dataLen
, data
, unsynchronized
);
280 ////////////////////////////////////////
282 RefPtr
<WebGLBuffer
> WebGLContext::CreateBuffer() {
283 const FuncScope
funcScope(*this, "createBuffer");
284 if (IsContextLost()) return nullptr;
287 gl
->fGenBuffers(1, &buf
);
289 return new WebGLBuffer(this, buf
);
292 } // namespace mozilla