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 "WebGLTransformFeedback.h"
13 #include "WebGLVertexArray.h"
17 RefPtr
<WebGLBuffer
>* WebGLContext::ValidateBufferSlot(GLenum target
) {
18 RefPtr
<WebGLBuffer
>* slot
= nullptr;
21 case LOCAL_GL_ARRAY_BUFFER
:
22 slot
= &mBoundArrayBuffer
;
25 case LOCAL_GL_ELEMENT_ARRAY_BUFFER
:
26 slot
= &(mBoundVertexArray
->mElementArrayBuffer
);
32 case LOCAL_GL_COPY_READ_BUFFER
:
33 slot
= &mBoundCopyReadBuffer
;
36 case LOCAL_GL_COPY_WRITE_BUFFER
:
37 slot
= &mBoundCopyWriteBuffer
;
40 case LOCAL_GL_PIXEL_PACK_BUFFER
:
41 slot
= &mBoundPixelPackBuffer
;
44 case LOCAL_GL_PIXEL_UNPACK_BUFFER
:
45 slot
= &mBoundPixelUnpackBuffer
;
48 case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER
:
49 slot
= &mBoundTransformFeedbackBuffer
;
52 case LOCAL_GL_UNIFORM_BUFFER
:
53 slot
= &mBoundUniformBuffer
;
59 ErrorInvalidEnumInfo("target", target
);
66 WebGLBuffer
* WebGLContext::ValidateBufferSelection(GLenum target
) const {
68 const_cast<WebGLContext
*>(this)->ValidateBufferSlot(target
);
69 if (!slot
) return nullptr;
70 const auto& buffer
= *slot
;
73 ErrorInvalidOperation("Buffer for `target` is null.");
77 if (target
== LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER
) {
78 if (mBoundTransformFeedback
->IsActiveAndNotPaused()) {
79 ErrorInvalidOperation(
80 "Cannot select TRANSFORM_FEEDBACK_BUFFER when"
81 " transform feedback is active and unpaused.");
84 const auto tfBuffers
= std::vector
<webgl::BufferAndIndex
>{{
88 if (!ValidateBuffersForTf(tfBuffers
)) return nullptr;
90 if (mBoundTransformFeedback
&& !ValidateBufferForNonTf(buffer
, target
))
97 IndexedBufferBinding
* WebGLContext::ValidateIndexedBufferSlot(GLenum target
,
99 decltype(mIndexedUniformBufferBindings
)* bindings
;
100 const char* maxIndexEnum
;
102 case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER
:
103 if (mBoundTransformFeedback
->mIsActive
&&
104 !mBoundTransformFeedback
->mIsPaused
) {
105 ErrorInvalidOperation("Transform feedback active and not paused.");
108 bindings
= &(mBoundTransformFeedback
->mIndexedBindings
);
109 maxIndexEnum
= "MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS";
112 case LOCAL_GL_UNIFORM_BUFFER
:
113 bindings
= &mIndexedUniformBufferBindings
;
114 maxIndexEnum
= "MAX_UNIFORM_BUFFER_BINDINGS";
118 ErrorInvalidEnumInfo("target", target
);
122 if (index
>= bindings
->size()) {
123 ErrorInvalidValue("`index` >= %s.", maxIndexEnum
);
127 return &(*bindings
)[index
];
130 ////////////////////////////////////////
132 void WebGLContext::BindBuffer(GLenum target
, WebGLBuffer
* buffer
) {
133 FuncScope
funcScope(*this, "bindBuffer");
134 if (IsContextLost()) return;
135 funcScope
.mBindFailureGuard
= true;
137 if (buffer
&& !ValidateObject("buffer", *buffer
)) return;
139 const auto& slot
= ValidateBufferSlot(target
);
142 if (buffer
&& !buffer
->ValidateCanBindToTarget(target
)) return;
144 if (!IsBufferTargetLazilyBound(target
)) {
145 gl
->fBindBuffer(target
, buffer
? buffer
->mGLName
: 0);
150 buffer
->SetContentAfterBind(target
);
153 funcScope
.mBindFailureGuard
= false;
156 ////////////////////////////////////////
158 bool WebGLContext::ValidateIndexedBufferBinding(
159 GLenum target
, GLuint index
, RefPtr
<WebGLBuffer
>** const out_genericBinding
,
160 IndexedBufferBinding
** const out_indexedBinding
) {
161 *out_genericBinding
= ValidateBufferSlot(target
);
162 if (!*out_genericBinding
) return false;
164 *out_indexedBinding
= ValidateIndexedBufferSlot(target
, index
);
165 if (!*out_indexedBinding
) return false;
167 if (target
== LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER
&&
168 mBoundTransformFeedback
->mIsActive
) {
169 ErrorInvalidOperation(
170 "Cannot update indexed buffer bindings on active"
171 " transform feedback objects.");
178 void WebGLContext::BindBufferRange(GLenum target
, GLuint index
,
179 WebGLBuffer
* buffer
, uint64_t offset
,
181 FuncScope
funcScope(*this, "bindBufferBase/Range");
182 if (buffer
&& !ValidateObject("buffer", *buffer
)) return;
183 funcScope
.mBindFailureGuard
= true;
185 RefPtr
<WebGLBuffer
>* genericBinding
;
186 IndexedBufferBinding
* indexedBinding
;
187 if (!ValidateIndexedBufferBinding(target
, index
, &genericBinding
,
192 if (buffer
&& !buffer
->ValidateCanBindToTarget(target
)) return;
194 const auto& limits
= Limits();
196 CheckBindBufferRange(target
, index
, bool(buffer
), offset
, size
, limits
);
201 bool needsPrebind
= false;
202 needsPrebind
|= gl
->IsANGLE();
207 if (gl
->WorkAroundDriverBugs() && buffer
&& needsPrebind
) {
208 // BindBufferBase/Range will fail (on some drivers) if the buffer name has
209 // never been bound. (GenBuffers makes a name, but BindBuffer initializes
210 // that name as a real buffer object)
211 gl
->fBindBuffer(target
, buffer
->mGLName
);
215 gl
->fBindBufferRange(target
, index
, buffer
? buffer
->mGLName
: 0, offset
,
218 gl
->fBindBufferBase(target
, index
, buffer
? buffer
->mGLName
: 0);
222 gl
->fBindBuffer(target
, 0); // Reset generic.
227 *genericBinding
= buffer
;
228 indexedBinding
->mBufferBinding
= buffer
;
229 indexedBinding
->mRangeStart
= offset
;
230 indexedBinding
->mRangeSize
= size
;
233 buffer
->SetContentAfterBind(target
);
236 funcScope
.mBindFailureGuard
= false;
239 ////////////////////////////////////////
241 void WebGLContext::BufferData(GLenum target
, uint64_t dataLen
,
242 const uint8_t* data
, GLenum usage
) const {
243 // `data` may be null.
244 const FuncScope
funcScope(*this, "bufferData");
245 if (IsContextLost()) return;
247 const auto& buffer
= ValidateBufferSelection(target
);
250 buffer
->BufferData(target
, dataLen
, data
, usage
);
253 ////////////////////////////////////////
255 void WebGLContext::BufferSubData(GLenum target
, uint64_t dstByteOffset
,
256 uint64_t dataLen
, const uint8_t* data
) const {
257 MOZ_ASSERT(data
|| !dataLen
);
258 const FuncScope
funcScope(*this, "bufferSubData");
259 if (IsContextLost()) return;
261 const auto& buffer
= ValidateBufferSelection(target
);
263 buffer
->BufferSubData(target
, dstByteOffset
, dataLen
, data
);
266 ////////////////////////////////////////
268 RefPtr
<WebGLBuffer
> WebGLContext::CreateBuffer() {
269 const FuncScope
funcScope(*this, "createBuffer");
270 if (IsContextLost()) return nullptr;
273 gl
->fGenBuffers(1, &buf
);
275 return new WebGLBuffer(this, buf
);
278 } // namespace mozilla