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"
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/Casting.h"
24 static bool ValidateAttribIndex(WebGLContext
& webgl
, GLuint index
) {
25 bool valid
= (index
< webgl
.MaxVertexAttribs());
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"
37 webgl
.ErrorInvalidValue(
38 "`index` must be less than"
39 " MAX_VERTEX_ATTRIBS.");
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;
56 if (index
|| !gl
->IsCompatibilityProfile()) {
58 case webgl::AttribBaseType::Boolean
:
59 case webgl::AttribBaseType::Float
:
60 gl
->fVertexAttrib4fv(index
, reinterpret_cast<const float*>(src
.data
));
62 case webgl::AttribBaseType::Int
:
63 gl
->fVertexAttribI4iv(index
,
64 reinterpret_cast<const int32_t*>(src
.data
));
66 case webgl::AttribBaseType::Uint
:
67 gl
->fVertexAttribI4uiv(index
,
68 reinterpret_cast<const uint32_t*>(src
.data
));
75 mGenericVertexAttribTypes
[index
] = src
.type
;
76 mGenericVertexAttribTypeInvalidator
.InvalidateCaches();
79 memcpy(mGenericVertexAttrib0Data
, src
.data
,
80 sizeof(mGenericVertexAttrib0Data
));
84 ////////////////////////////////////////
86 void WebGLContext::EnableVertexAttribArray(GLuint index
) {
87 const FuncScope
funcScope(*this, "enableVertexAttribArray");
88 if (IsContextLost()) return;
90 if (!ValidateAttribIndex(*this, index
)) return;
92 gl
->fEnableVertexAttribArray(index
);
94 MOZ_ASSERT(mBoundVertexArray
);
95 mBoundVertexArray
->SetAttribIsArray(index
, true);
98 void WebGLContext::DisableVertexAttribArray(GLuint index
) {
99 const FuncScope
funcScope(*this, "disableVertexAttribArray");
100 if (IsContextLost()) return;
102 if (!ValidateAttribIndex(*this, index
)) return;
104 if (index
|| !gl
->IsCompatibilityProfile()) {
105 gl
->fDisableVertexAttribArray(index
);
108 MOZ_ASSERT(mBoundVertexArray
);
109 mBoundVertexArray
->SetAttribIsArray(index
, false);
112 Maybe
<double> WebGLContext::GetVertexAttrib(GLuint index
, GLenum pname
) {
113 const FuncScope
funcScope(*this, "getVertexAttrib");
114 if (IsContextLost()) return Nothing();
116 if (!ValidateAttribIndex(*this, index
)) return Nothing();
118 MOZ_ASSERT(mBoundVertexArray
);
119 auto ret
= mBoundVertexArray
->GetVertexAttrib(index
, pname
);
122 case LOCAL_GL_VERTEX_ATTRIB_ARRAY_INTEGER
:
128 case LOCAL_GL_VERTEX_ATTRIB_ARRAY_DIVISOR
:
130 !IsExtensionEnabled(WebGLExtensionID::ANGLE_instanced_arrays
)) {
137 ErrorInvalidEnumInfo("pname", pname
);
142 ////////////////////////////////////////
144 Result
<webgl::VertAttribPointerCalculated
, webgl::ErrorInfo
>
145 CheckVertexAttribPointer(const bool isWebgl2
,
146 const webgl::VertAttribPointerDesc
& desc
) {
147 if (desc
.channels
< 1 || desc
.channels
> 4) {
148 return Err(webgl::ErrorInfo
{LOCAL_GL_INVALID_VALUE
,
149 "Channel count `size` must be within [1,4]."});
154 webgl::VertAttribPointerCalculated calc
;
156 bool isTypeValid
= true;
157 bool isPackedType
= false;
158 uint8_t bytesPerType
= 0;
163 calc
.baseType
= webgl::AttribBaseType::Int
;
165 case LOCAL_GL_UNSIGNED_BYTE
:
167 calc
.baseType
= webgl::AttribBaseType::Uint
;
172 calc
.baseType
= webgl::AttribBaseType::Int
;
174 case LOCAL_GL_UNSIGNED_SHORT
:
176 calc
.baseType
= webgl::AttribBaseType::Uint
;
181 calc
.baseType
= webgl::AttribBaseType::Float
;
186 isTypeValid
= isWebgl2
;
188 calc
.baseType
= webgl::AttribBaseType::Int
;
190 case LOCAL_GL_UNSIGNED_INT
:
191 isTypeValid
= isWebgl2
;
193 calc
.baseType
= webgl::AttribBaseType::Uint
;
196 case LOCAL_GL_HALF_FLOAT
:
197 isTypeValid
= isWebgl2
;
199 calc
.baseType
= webgl::AttribBaseType::Float
;
203 isTypeValid
= isWebgl2
;
205 calc
.baseType
= webgl::AttribBaseType::Float
;
208 case LOCAL_GL_INT_2_10_10_10_REV
:
209 case LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV
:
210 if (desc
.channels
!= 4) {
211 return Err(webgl::ErrorInfo
{LOCAL_GL_INVALID_OPERATION
,
212 "Size must be 4 for this type."});
214 isTypeValid
= isWebgl2
;
217 webgl::AttribBaseType::Float
; // Invalid for intFunc:true.
226 isTypeValid
= (calc
.baseType
!= webgl::AttribBaseType::Float
);
228 calc
.baseType
= webgl::AttribBaseType::Float
;
232 nsPrintfCString("Bad `type`: %s", EnumString(desc
.type
).c_str());
233 return Err(webgl::ErrorInfo
{LOCAL_GL_INVALID_ENUM
, info
.BeginReading()});
238 calc
.byteSize
= bytesPerType
;
240 calc
.byteSize
*= desc
.channels
;
244 desc
.byteStrideOrZero
? desc
.byteStrideOrZero
: calc
.byteSize
;
246 // `alignment` should always be a power of two.
247 MOZ_ASSERT(IsPowerOfTwo(bytesPerType
));
248 const auto typeAlignmentMask
= bytesPerType
- 1;
250 if (calc
.byteStride
& typeAlignmentMask
||
251 desc
.byteOffset
& typeAlignmentMask
) {
253 webgl::ErrorInfo
{LOCAL_GL_INVALID_OPERATION
,
254 "`stride` and `byteOffset` must satisfy the alignment"
255 " requirement of `type`."});
261 void DoVertexAttribPointer(gl::GLContext
& gl
, const uint32_t index
,
262 const webgl::VertAttribPointerDesc
& desc
) {
264 gl
.fVertexAttribIPointer(index
, desc
.channels
, desc
.type
,
265 desc
.byteStrideOrZero
,
266 reinterpret_cast<const void*>(desc
.byteOffset
));
268 gl
.fVertexAttribPointer(index
, desc
.channels
, desc
.type
, desc
.normalized
,
269 desc
.byteStrideOrZero
,
270 reinterpret_cast<const void*>(desc
.byteOffset
));
274 void WebGLContext::VertexAttribPointer(
275 const uint32_t index
, const webgl::VertAttribPointerDesc
& desc
) {
276 if (IsContextLost()) return;
277 if (!ValidateAttribIndex(*this, index
)) return;
279 const auto res
= CheckVertexAttribPointer(IsWebGL2(), desc
);
281 const auto& err
= res
.inspectErr();
282 GenerateError(err
.type
, "%s", err
.info
.c_str());
285 const auto& calc
= res
.inspect();
289 const auto& buffer
= mBoundArrayBuffer
;
291 mBoundVertexArray
->AttribPointer(index
, buffer
, desc
, calc
);
293 const ScopedLazyBind
lazyBind(gl
, LOCAL_GL_ARRAY_BUFFER
, buffer
);
294 DoVertexAttribPointer(*gl
, index
, desc
);
297 ////////////////////////////////////////
299 void WebGLContext::VertexAttribDivisor(GLuint index
, GLuint divisor
) {
300 const FuncScope
funcScope(*this, "vertexAttribDivisor");
301 if (IsContextLost()) return;
303 if (!ValidateAttribIndex(*this, index
)) return;
305 MOZ_ASSERT(mBoundVertexArray
);
306 mBoundVertexArray
->AttribDivisor(index
, divisor
);
307 gl
->fVertexAttribDivisor(index
, divisor
);
310 } // namespace mozilla