Bug 1892041 - Part 1: Update test262 features. r=spidermonkey-reviewers,dminor
[gecko.git] / dom / canvas / WebGLContextBuffers.cpp
blobd40e8bfd1eb999d228c3b7c94f87641ffe009963
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"
8 #include <limits>
10 #include "GLContext.h"
11 #include "WebGLBuffer.h"
12 #include "WebGLContext.h"
13 #include "WebGLTransformFeedback.h"
14 #include "WebGLVertexArray.h"
16 namespace mozilla {
18 RefPtr<WebGLBuffer>* WebGLContext::ValidateBufferSlot(GLenum target) {
19 RefPtr<WebGLBuffer>* slot = nullptr;
21 switch (target) {
22 case LOCAL_GL_ARRAY_BUFFER:
23 slot = &mBoundArrayBuffer;
24 break;
26 case LOCAL_GL_ELEMENT_ARRAY_BUFFER:
27 slot = &(mBoundVertexArray->mElementArrayBuffer);
28 break;
31 if (IsWebGL2()) {
32 switch (target) {
33 case LOCAL_GL_COPY_READ_BUFFER:
34 slot = &mBoundCopyReadBuffer;
35 break;
37 case LOCAL_GL_COPY_WRITE_BUFFER:
38 slot = &mBoundCopyWriteBuffer;
39 break;
41 case LOCAL_GL_PIXEL_PACK_BUFFER:
42 slot = &mBoundPixelPackBuffer;
43 break;
45 case LOCAL_GL_PIXEL_UNPACK_BUFFER:
46 slot = &mBoundPixelUnpackBuffer;
47 break;
49 case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
50 slot = &mBoundTransformFeedbackBuffer;
51 break;
53 case LOCAL_GL_UNIFORM_BUFFER:
54 slot = &mBoundUniformBuffer;
55 break;
59 if (!slot) {
60 ErrorInvalidEnumInfo("target", target);
61 return nullptr;
64 return slot;
67 WebGLBuffer* WebGLContext::ValidateBufferSelection(GLenum target) const {
68 const auto& slot =
69 const_cast<WebGLContext*>(this)->ValidateBufferSlot(target);
70 if (!slot) return nullptr;
71 const auto& buffer = *slot;
73 if (!buffer) {
74 ErrorInvalidOperation("Buffer for `target` is null.");
75 return nullptr;
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.");
83 return nullptr;
85 const auto tfBuffers = std::vector<webgl::BufferAndIndex>{{
86 {buffer},
87 }};
89 if (!ValidateBuffersForTf(tfBuffers)) return nullptr;
90 } else {
91 if (mBoundTransformFeedback && !ValidateBufferForNonTf(buffer, target))
92 return nullptr;
95 return buffer.get();
98 IndexedBufferBinding* WebGLContext::ValidateIndexedBufferSlot(GLenum target,
99 GLuint index) {
100 decltype(mIndexedUniformBufferBindings)* bindings;
101 const char* maxIndexEnum;
102 switch (target) {
103 case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
104 if (mBoundTransformFeedback->mIsActive &&
105 !mBoundTransformFeedback->mIsPaused) {
106 ErrorInvalidOperation("Transform feedback active and not paused.");
107 return nullptr;
109 bindings = &(mBoundTransformFeedback->mIndexedBindings);
110 maxIndexEnum = "MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS";
111 break;
113 case LOCAL_GL_UNIFORM_BUFFER:
114 bindings = &mIndexedUniformBufferBindings;
115 maxIndexEnum = "MAX_UNIFORM_BUFFER_BINDINGS";
116 break;
118 default:
119 ErrorInvalidEnumInfo("target", target);
120 return nullptr;
123 if (index >= bindings->size()) {
124 ErrorInvalidValue("`index` >= %s.", maxIndexEnum);
125 return nullptr;
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);
141 if (!slot) return;
143 if (buffer && !buffer->ValidateCanBindToTarget(target)) return;
145 if (!IsBufferTargetLazilyBound(target)) {
146 gl->fBindBuffer(target, buffer ? buffer->mGLName : 0);
149 *slot = buffer;
150 if (buffer) {
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.");
173 return false;
176 return true;
179 void WebGLContext::BindBufferRange(GLenum target, GLuint index,
180 WebGLBuffer* buffer, uint64_t offset,
181 uint64_t size) {
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,
189 &indexedBinding)) {
190 return;
193 if (buffer && !buffer->ValidateCanBindToTarget(target)) return;
195 const auto& limits = Limits();
196 auto err =
197 CheckBindBufferRange(target, index, bool(buffer), offset, size, limits);
198 if (err) return;
200 ////
202 bool needsPrebind = false;
203 needsPrebind |= gl->IsANGLE();
204 #ifdef XP_MACOSX
205 needsPrebind = true;
206 #endif
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);
215 if (size) {
216 gl->fBindBufferRange(target, index, buffer ? buffer->mGLName : 0, offset,
217 size);
218 } else {
219 gl->fBindBufferBase(target, index, buffer ? buffer->mGLName : 0);
222 if (buffer) {
223 gl->fBindBuffer(target, 0); // Reset generic.
226 ////
228 *genericBinding = buffer;
229 indexedBinding->mBufferBinding = buffer;
230 indexedBinding->mRangeStart = offset;
231 indexedBinding->mRangeSize = size;
233 if (buffer) {
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);
249 if (!buffer) return;
251 buffer->BufferData(target, dataLen, data, usage);
254 void WebGLContext::UninitializedBufferData_SizeOnly(GLenum target,
255 uint64_t dataLen,
256 GLenum usage) const {
257 const FuncScope funcScope(*this, "bufferData");
258 if (IsContextLost()) return;
260 const auto& buffer = ValidateBufferSelection(target);
261 if (!buffer) return;
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);
276 if (!buffer) return;
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;
286 GLuint buf = 0;
287 gl->fGenBuffers(1, &buf);
289 return new WebGLBuffer(this, buf);
292 } // namespace mozilla