Bug 1732219 - Add API for fetching the preview image. r=geckoview-reviewers,agi,mconley
[gecko.git] / dom / canvas / WebGLContextBuffers.cpp
blob3bab8742c010e8a9ab8b60316528e4ef304aaf67
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 "WebGLTransformFeedback.h"
13 #include "WebGLVertexArray.h"
15 namespace mozilla {
17 RefPtr<WebGLBuffer>* WebGLContext::ValidateBufferSlot(GLenum target) {
18 RefPtr<WebGLBuffer>* slot = nullptr;
20 switch (target) {
21 case LOCAL_GL_ARRAY_BUFFER:
22 slot = &mBoundArrayBuffer;
23 break;
25 case LOCAL_GL_ELEMENT_ARRAY_BUFFER:
26 slot = &(mBoundVertexArray->mElementArrayBuffer);
27 break;
30 if (IsWebGL2()) {
31 switch (target) {
32 case LOCAL_GL_COPY_READ_BUFFER:
33 slot = &mBoundCopyReadBuffer;
34 break;
36 case LOCAL_GL_COPY_WRITE_BUFFER:
37 slot = &mBoundCopyWriteBuffer;
38 break;
40 case LOCAL_GL_PIXEL_PACK_BUFFER:
41 slot = &mBoundPixelPackBuffer;
42 break;
44 case LOCAL_GL_PIXEL_UNPACK_BUFFER:
45 slot = &mBoundPixelUnpackBuffer;
46 break;
48 case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
49 slot = &mBoundTransformFeedbackBuffer;
50 break;
52 case LOCAL_GL_UNIFORM_BUFFER:
53 slot = &mBoundUniformBuffer;
54 break;
58 if (!slot) {
59 ErrorInvalidEnumInfo("target", target);
60 return nullptr;
63 return slot;
66 WebGLBuffer* WebGLContext::ValidateBufferSelection(GLenum target) const {
67 const auto& slot =
68 const_cast<WebGLContext*>(this)->ValidateBufferSlot(target);
69 if (!slot) return nullptr;
70 const auto& buffer = *slot;
72 if (!buffer) {
73 ErrorInvalidOperation("Buffer for `target` is null.");
74 return nullptr;
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.");
82 return nullptr;
84 const auto tfBuffers = std::vector<webgl::BufferAndIndex>{{
85 {buffer},
86 }};
88 if (!ValidateBuffersForTf(tfBuffers)) return nullptr;
89 } else {
90 if (mBoundTransformFeedback && !ValidateBufferForNonTf(buffer, target))
91 return nullptr;
94 return buffer.get();
97 IndexedBufferBinding* WebGLContext::ValidateIndexedBufferSlot(GLenum target,
98 GLuint index) {
99 decltype(mIndexedUniformBufferBindings)* bindings;
100 const char* maxIndexEnum;
101 switch (target) {
102 case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
103 if (mBoundTransformFeedback->mIsActive &&
104 !mBoundTransformFeedback->mIsPaused) {
105 ErrorInvalidOperation("Transform feedback active and not paused.");
106 return nullptr;
108 bindings = &(mBoundTransformFeedback->mIndexedBindings);
109 maxIndexEnum = "MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS";
110 break;
112 case LOCAL_GL_UNIFORM_BUFFER:
113 bindings = &mIndexedUniformBufferBindings;
114 maxIndexEnum = "MAX_UNIFORM_BUFFER_BINDINGS";
115 break;
117 default:
118 ErrorInvalidEnumInfo("target", target);
119 return nullptr;
122 if (index >= bindings->size()) {
123 ErrorInvalidValue("`index` >= %s.", maxIndexEnum);
124 return nullptr;
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);
140 if (!slot) return;
142 if (buffer && !buffer->ValidateCanBindToTarget(target)) return;
144 if (!IsBufferTargetLazilyBound(target)) {
145 gl->fBindBuffer(target, buffer ? buffer->mGLName : 0);
148 *slot = buffer;
149 if (buffer) {
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.");
172 return false;
175 return true;
178 void WebGLContext::BindBufferRange(GLenum target, GLuint index,
179 WebGLBuffer* buffer, uint64_t offset,
180 uint64_t size) {
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,
188 &indexedBinding)) {
189 return;
192 if (buffer && !buffer->ValidateCanBindToTarget(target)) return;
194 const auto& limits = Limits();
195 auto err =
196 CheckBindBufferRange(target, index, bool(buffer), offset, size, limits);
197 if (err) return;
199 ////
201 bool needsPrebind = false;
202 needsPrebind |= gl->IsANGLE();
203 #ifdef XP_MACOSX
204 needsPrebind = true;
205 #endif
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);
214 if (size) {
215 gl->fBindBufferRange(target, index, buffer ? buffer->mGLName : 0, offset,
216 size);
217 } else {
218 gl->fBindBufferBase(target, index, buffer ? buffer->mGLName : 0);
221 if (buffer) {
222 gl->fBindBuffer(target, 0); // Reset generic.
225 ////
227 *genericBinding = buffer;
228 indexedBinding->mBufferBinding = buffer;
229 indexedBinding->mRangeStart = offset;
230 indexedBinding->mRangeSize = size;
232 if (buffer) {
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);
248 if (!buffer) return;
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);
262 if (!buffer) return;
263 buffer->BufferSubData(target, dstByteOffset, dataLen, data);
266 ////////////////////////////////////////
268 RefPtr<WebGLBuffer> WebGLContext::CreateBuffer() {
269 const FuncScope funcScope(*this, "createBuffer");
270 if (IsContextLost()) return nullptr;
272 GLuint buf = 0;
273 gl->fGenBuffers(1, &buf);
275 return new WebGLBuffer(this, buf);
278 } // namespace mozilla