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/ResultVariant.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
,
61 reinterpret_cast<const float*>(src
.data
.data()));
63 case webgl::AttribBaseType::Int
:
64 gl
->fVertexAttribI4iv(
65 index
, reinterpret_cast<const int32_t*>(src
.data
.data()));
67 case webgl::AttribBaseType::Uint
:
68 gl
->fVertexAttribI4uiv(
69 index
, reinterpret_cast<const uint32_t*>(src
.data
.data()));
76 mGenericVertexAttribTypes
[index
] = src
.type
;
77 mGenericVertexAttribTypeInvalidator
.InvalidateCaches();
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
);
123 case LOCAL_GL_VERTEX_ATTRIB_ARRAY_INTEGER
:
129 case LOCAL_GL_VERTEX_ATTRIB_ARRAY_DIVISOR
:
131 !IsExtensionEnabled(WebGLExtensionID::ANGLE_instanced_arrays
)) {
138 ErrorInvalidEnumInfo("pname", pname
);
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]."});
155 webgl::VertAttribPointerCalculated calc
;
157 bool isTypeValid
= true;
158 bool isPackedType
= false;
159 uint8_t bytesPerType
= 0;
164 calc
.baseType
= webgl::AttribBaseType::Int
;
166 case LOCAL_GL_UNSIGNED_BYTE
:
168 calc
.baseType
= webgl::AttribBaseType::Uint
;
173 calc
.baseType
= webgl::AttribBaseType::Int
;
175 case LOCAL_GL_UNSIGNED_SHORT
:
177 calc
.baseType
= webgl::AttribBaseType::Uint
;
182 calc
.baseType
= webgl::AttribBaseType::Float
;
187 isTypeValid
= isWebgl2
;
189 calc
.baseType
= webgl::AttribBaseType::Int
;
191 case LOCAL_GL_UNSIGNED_INT
:
192 isTypeValid
= isWebgl2
;
194 calc
.baseType
= webgl::AttribBaseType::Uint
;
197 case LOCAL_GL_HALF_FLOAT
:
198 isTypeValid
= isWebgl2
;
200 calc
.baseType
= webgl::AttribBaseType::Float
;
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
;
212 webgl::AttribBaseType::Float
; // Invalid for intFunc:true.
221 isTypeValid
= (calc
.baseType
!= webgl::AttribBaseType::Float
);
223 calc
.baseType
= webgl::AttribBaseType::Float
;
227 nsPrintfCString("Bad `type`: %s", EnumString(desc
.type
).c_str());
228 return Err(webgl::ErrorInfo
{LOCAL_GL_INVALID_ENUM
, info
.BeginReading()});
233 calc
.byteSize
= bytesPerType
;
235 calc
.byteSize
*= desc
.channels
;
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
) {
248 webgl::ErrorInfo
{LOCAL_GL_INVALID_OPERATION
,
249 "`stride` and `byteOffset` must satisfy the alignment"
250 " requirement of `type`."});
256 void DoVertexAttribPointer(gl::GLContext
& gl
, const uint32_t index
,
257 const webgl::VertAttribPointerDesc
& desc
) {
259 gl
.fVertexAttribIPointer(index
, desc
.channels
, desc
.type
,
260 desc
.byteStrideOrZero
,
261 reinterpret_cast<const void*>(desc
.byteOffset
));
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
);
276 const auto& err
= res
.inspectErr();
277 GenerateError(err
.type
, "%s", err
.info
.c_str());
280 const auto& calc
= res
.inspect();
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