Merge mozilla-central to autoland on a CLOSED TREE
[gecko.git] / dom / canvas / WebGLContextVertices.cpp
blobe50f5f1c3d335aa9cc6aa4b5cb86d371ddfc935e
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 "WebGLContext.h"
8 #include "GLContext.h"
9 #include "mozilla/Casting.h"
10 #include "mozilla/CheckedInt.h"
11 #include "WebGLBuffer.h"
12 #include "WebGLFramebuffer.h"
13 #include "WebGLProgram.h"
14 #include "WebGLRenderbuffer.h"
15 #include "WebGLShader.h"
16 #include "WebGLTexture.h"
17 #include "WebGLTypes.h"
18 #include "WebGLVertexArray.h"
20 #include "mozilla/ResultVariant.h"
22 namespace mozilla {
24 static bool ValidateAttribIndex(WebGLContext& webgl, GLuint index) {
25 bool valid = (index < webgl.MaxVertexAttribs());
27 if (!valid) {
28 if (index == GLuint(-1)) {
29 webgl.ErrorInvalidValue(
30 "-1 is not a valid `index`. This value"
31 " probably comes from a getAttribLocation()"
32 " call, where this return value -1 means"
33 " that the passed name didn't correspond to"
34 " an active attribute in the specified"
35 " program.");
36 } else {
37 webgl.ErrorInvalidValue(
38 "`index` must be less than"
39 " MAX_VERTEX_ATTRIBS.");
43 return valid;
46 ////////////////////////////////////////
48 void WebGLContext::VertexAttrib4T(GLuint index, const webgl::TypedQuad& src) {
49 const FuncScope funcScope(*this, "vertexAttrib[1234]u?[fi]v?");
50 if (IsContextLost()) return;
52 if (!ValidateAttribIndex(*this, index)) return;
54 ////
56 if (index || !gl->IsCompatibilityProfile()) {
57 switch (src.type) {
58 case webgl::AttribBaseType::Boolean:
59 case webgl::AttribBaseType::Float:
60 gl->fVertexAttrib4fv(index,
61 reinterpret_cast<const float*>(src.data.data()));
62 break;
63 case webgl::AttribBaseType::Int:
64 gl->fVertexAttribI4iv(
65 index, reinterpret_cast<const int32_t*>(src.data.data()));
66 break;
67 case webgl::AttribBaseType::Uint:
68 gl->fVertexAttribI4uiv(
69 index, reinterpret_cast<const uint32_t*>(src.data.data()));
70 break;
74 ////
76 mGenericVertexAttribTypes[index] = src.type;
77 mGenericVertexAttribTypeInvalidator.InvalidateCaches();
79 if (!index) {
80 memcpy(mGenericVertexAttrib0Data, src.data.data(),
81 sizeof(mGenericVertexAttrib0Data));
85 ////////////////////////////////////////
87 void WebGLContext::EnableVertexAttribArray(GLuint index) {
88 const FuncScope funcScope(*this, "enableVertexAttribArray");
89 if (IsContextLost()) return;
91 if (!ValidateAttribIndex(*this, index)) return;
93 gl->fEnableVertexAttribArray(index);
95 MOZ_ASSERT(mBoundVertexArray);
96 mBoundVertexArray->SetAttribIsArray(index, true);
99 void WebGLContext::DisableVertexAttribArray(GLuint index) {
100 const FuncScope funcScope(*this, "disableVertexAttribArray");
101 if (IsContextLost()) return;
103 if (!ValidateAttribIndex(*this, index)) return;
105 if (index || !gl->IsCompatibilityProfile()) {
106 gl->fDisableVertexAttribArray(index);
109 MOZ_ASSERT(mBoundVertexArray);
110 mBoundVertexArray->SetAttribIsArray(index, false);
113 Maybe<double> WebGLContext::GetVertexAttrib(GLuint index, GLenum pname) {
114 const FuncScope funcScope(*this, "getVertexAttrib");
115 if (IsContextLost()) return Nothing();
117 if (!ValidateAttribIndex(*this, index)) return Nothing();
119 MOZ_ASSERT(mBoundVertexArray);
120 auto ret = mBoundVertexArray->GetVertexAttrib(index, pname);
122 switch (pname) {
123 case LOCAL_GL_VERTEX_ATTRIB_ARRAY_INTEGER:
124 if (!IsWebGL2()) {
125 ret = Nothing();
127 break;
129 case LOCAL_GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
130 if (!IsWebGL2() &&
131 !IsExtensionEnabled(WebGLExtensionID::ANGLE_instanced_arrays)) {
132 ret = Nothing();
134 break;
137 if (!ret) {
138 ErrorInvalidEnumInfo("pname", pname);
140 return ret;
143 ////////////////////////////////////////
145 Result<webgl::VertAttribPointerCalculated, webgl::ErrorInfo>
146 CheckVertexAttribPointer(const bool isWebgl2,
147 const webgl::VertAttribPointerDesc& desc) {
148 if (desc.channels < 1 || desc.channels > 4) {
149 return Err(webgl::ErrorInfo{LOCAL_GL_INVALID_VALUE,
150 "Channel count `size` must be within [1,4]."});
153 ////
155 webgl::VertAttribPointerCalculated calc;
157 bool isTypeValid = true;
158 bool isPackedType = false;
159 uint8_t bytesPerType = 0;
160 switch (desc.type) {
161 // WebGL 1:
162 case LOCAL_GL_BYTE:
163 bytesPerType = 1;
164 calc.baseType = webgl::AttribBaseType::Int;
165 break;
166 case LOCAL_GL_UNSIGNED_BYTE:
167 bytesPerType = 1;
168 calc.baseType = webgl::AttribBaseType::Uint;
169 break;
171 case LOCAL_GL_SHORT:
172 bytesPerType = 2;
173 calc.baseType = webgl::AttribBaseType::Int;
174 break;
175 case LOCAL_GL_UNSIGNED_SHORT:
176 bytesPerType = 2;
177 calc.baseType = webgl::AttribBaseType::Uint;
178 break;
180 case LOCAL_GL_FLOAT:
181 bytesPerType = 4;
182 calc.baseType = webgl::AttribBaseType::Float;
183 break;
185 // WebGL 2:
186 case LOCAL_GL_INT:
187 isTypeValid = isWebgl2;
188 bytesPerType = 4;
189 calc.baseType = webgl::AttribBaseType::Int;
190 break;
191 case LOCAL_GL_UNSIGNED_INT:
192 isTypeValid = isWebgl2;
193 bytesPerType = 4;
194 calc.baseType = webgl::AttribBaseType::Uint;
195 break;
197 case LOCAL_GL_HALF_FLOAT:
198 isTypeValid = isWebgl2;
199 bytesPerType = 2;
200 calc.baseType = webgl::AttribBaseType::Float;
201 break;
203 case LOCAL_GL_INT_2_10_10_10_REV:
204 case LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV:
205 if (desc.channels != 4) {
206 return Err(webgl::ErrorInfo{LOCAL_GL_INVALID_OPERATION,
207 "Size must be 4 for this type."});
209 isTypeValid = isWebgl2;
210 bytesPerType = 4;
211 calc.baseType =
212 webgl::AttribBaseType::Float; // Invalid for intFunc:true.
213 isPackedType = true;
214 break;
216 default:
217 isTypeValid = false;
218 break;
220 if (desc.intFunc) {
221 isTypeValid = (calc.baseType != webgl::AttribBaseType::Float);
222 } else {
223 calc.baseType = webgl::AttribBaseType::Float;
225 if (!isTypeValid) {
226 const auto info =
227 nsPrintfCString("Bad `type`: %s", EnumString(desc.type).c_str());
228 return Err(webgl::ErrorInfo{LOCAL_GL_INVALID_ENUM, info.BeginReading()});
231 ////
233 calc.byteSize = bytesPerType;
234 if (!isPackedType) {
235 calc.byteSize *= desc.channels;
238 calc.byteStride =
239 desc.byteStrideOrZero ? desc.byteStrideOrZero : calc.byteSize;
241 // `alignment` should always be a power of two.
242 MOZ_ASSERT(IsPowerOfTwo(bytesPerType));
243 const auto typeAlignmentMask = bytesPerType - 1;
245 if (calc.byteStride & typeAlignmentMask ||
246 desc.byteOffset & typeAlignmentMask) {
247 return Err(
248 webgl::ErrorInfo{LOCAL_GL_INVALID_OPERATION,
249 "`stride` and `byteOffset` must satisfy the alignment"
250 " requirement of `type`."});
253 return calc;
256 void DoVertexAttribPointer(gl::GLContext& gl, const uint32_t index,
257 const webgl::VertAttribPointerDesc& desc) {
258 if (desc.intFunc) {
259 gl.fVertexAttribIPointer(index, desc.channels, desc.type,
260 desc.byteStrideOrZero,
261 reinterpret_cast<const void*>(desc.byteOffset));
262 } else {
263 gl.fVertexAttribPointer(index, desc.channels, desc.type, desc.normalized,
264 desc.byteStrideOrZero,
265 reinterpret_cast<const void*>(desc.byteOffset));
269 void WebGLContext::VertexAttribPointer(
270 const uint32_t index, const webgl::VertAttribPointerDesc& desc) {
271 if (IsContextLost()) return;
272 if (!ValidateAttribIndex(*this, index)) return;
274 const auto res = CheckVertexAttribPointer(IsWebGL2(), desc);
275 if (res.isErr()) {
276 const auto& err = res.inspectErr();
277 GenerateError(err.type, "%s", err.info.c_str());
278 return;
280 const auto& calc = res.inspect();
282 ////
284 const auto& buffer = mBoundArrayBuffer;
286 mBoundVertexArray->AttribPointer(index, buffer, desc, calc);
288 const ScopedLazyBind lazyBind(gl, LOCAL_GL_ARRAY_BUFFER, buffer);
289 DoVertexAttribPointer(*gl, index, desc);
292 ////////////////////////////////////////
294 void WebGLContext::VertexAttribDivisor(GLuint index, GLuint divisor) {
295 const FuncScope funcScope(*this, "vertexAttribDivisor");
296 if (IsContextLost()) return;
298 if (!ValidateAttribIndex(*this, index)) return;
300 MOZ_ASSERT(mBoundVertexArray);
301 mBoundVertexArray->AttribDivisor(index, divisor);
302 gl->fVertexAttribDivisor(index, divisor);
305 } // namespace mozilla