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 "GLScreenBuffer.h"
10 #include "mozilla/Maybe.h"
11 #include "mozilla/Preferences.h"
12 #include "MozFramebuffer.h"
14 #include "WebGLBuffer.h"
15 #include "WebGLContextUtils.h"
16 #include "WebGLFramebuffer.h"
17 #include "WebGLProgram.h"
18 #include "WebGLRenderbuffer.h"
19 #include "WebGLShader.h"
20 #include "WebGLTexture.h"
21 #include "WebGLVertexArray.h"
25 void WebGLContext::SetEnabled(const char* const funcName
, const GLenum cap
,
27 const FuncScope
funcScope(*this, funcName
);
28 if (IsContextLost()) return;
30 if (!ValidateCapabilityEnum(cap
)) return;
32 const auto& slot
= GetStateTrackingSlot(cap
);
38 case LOCAL_GL_DEPTH_TEST
:
39 case LOCAL_GL_STENCIL_TEST
:
40 break; // Lazily applied, so don't tell GL yet or we will desync.
44 gl
->SetEnabled(cap
, enabled
);
49 bool WebGLContext::GetStencilBits(GLint
* const out_stencilBits
) const {
51 if (mBoundDrawFramebuffer
) {
52 if (!mBoundDrawFramebuffer
->IsCheckFramebufferStatusComplete()) {
53 // Error, we don't know which stencil buffer's bits to use
54 ErrorInvalidFramebufferOperation(
55 "getParameter: framebuffer has two stencil buffers bound");
59 if (mBoundDrawFramebuffer
->StencilAttachment().HasAttachment() ||
60 mBoundDrawFramebuffer
->DepthStencilAttachment().HasAttachment()) {
63 } else if (mOptions
.stencil
) {
70 Maybe
<double> WebGLContext::GetParameter(const GLenum pname
) {
71 const FuncScope
funcScope(*this, "getParameter");
72 if (IsContextLost()) return {};
74 if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers
)) {
75 if (pname
== LOCAL_GL_MAX_COLOR_ATTACHMENTS
) {
76 return Some(MaxValidDrawBuffers());
78 } else if (pname
== LOCAL_GL_MAX_DRAW_BUFFERS
) {
79 return Some(MaxValidDrawBuffers());
81 } else if (pname
>= LOCAL_GL_DRAW_BUFFER0
&&
82 pname
< GLenum(LOCAL_GL_DRAW_BUFFER0
+ MaxValidDrawBuffers())) {
83 const auto slotId
= pname
- LOCAL_GL_DRAW_BUFFER0
;
84 GLenum ret
= LOCAL_GL_NONE
;
85 if (!mBoundDrawFramebuffer
) {
87 ret
= mDefaultFB_DrawBuffer0
;
90 const auto& fb
= *mBoundDrawFramebuffer
;
91 if (fb
.IsDrawBufferEnabled(slotId
)) {
92 ret
= LOCAL_GL_COLOR_ATTACHMENT0
+ slotId
;
99 if (IsExtensionEnabled(WebGLExtensionID::EXT_disjoint_timer_query
)) {
101 case LOCAL_GL_TIMESTAMP_EXT
: {
103 if (Has64BitTimestamps()) {
104 gl
->fGetInteger64v(pname
, (GLint64
*)&val
);
106 gl
->fGetIntegerv(pname
, (GLint
*)&val
);
108 // TODO: JS doesn't support 64-bit integers. Be lossy and
109 // cast to double (53 bits)
113 case LOCAL_GL_GPU_DISJOINT_EXT
: {
114 realGLboolean val
= false; // Not disjoint by default.
115 if (gl
->IsExtensionSupported(gl::GLContext::EXT_disjoint_timer_query
)) {
116 gl
->fGetBooleanv(pname
, &val
);
118 return Some(bool(val
));
127 IsExtensionEnabled(WebGLExtensionID::OES_standard_derivatives
)) {
128 if (pname
== LOCAL_GL_FRAGMENT_SHADER_DERIVATIVE_HINT
) {
130 gl
->fGetIntegerv(pname
, &i
);
135 if (IsExtensionEnabled(WebGLExtensionID::EXT_texture_filter_anisotropic
)) {
136 if (pname
== LOCAL_GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT
) {
138 gl
->fGetFloatv(pname
, &f
);
143 if (IsExtensionEnabled(WebGLExtensionID::MOZ_debug
)) {
144 if (pname
== dom::MOZ_debug_Binding::DOES_INDEX_VALIDATION
) {
145 return Some(mNeedsIndexValidation
);
150 ////////////////////////////////
151 // Single-value params
154 case LOCAL_GL_CULL_FACE_MODE
:
155 case LOCAL_GL_FRONT_FACE
:
156 case LOCAL_GL_ACTIVE_TEXTURE
:
157 case LOCAL_GL_STENCIL_FUNC
:
158 case LOCAL_GL_STENCIL_FAIL
:
159 case LOCAL_GL_STENCIL_PASS_DEPTH_FAIL
:
160 case LOCAL_GL_STENCIL_PASS_DEPTH_PASS
:
161 case LOCAL_GL_STENCIL_BACK_FUNC
:
162 case LOCAL_GL_STENCIL_BACK_FAIL
:
163 case LOCAL_GL_STENCIL_BACK_PASS_DEPTH_FAIL
:
164 case LOCAL_GL_STENCIL_BACK_PASS_DEPTH_PASS
:
165 case LOCAL_GL_DEPTH_FUNC
:
166 case LOCAL_GL_BLEND_SRC_RGB
:
167 case LOCAL_GL_BLEND_SRC_ALPHA
:
168 case LOCAL_GL_BLEND_DST_RGB
:
169 case LOCAL_GL_BLEND_DST_ALPHA
:
170 case LOCAL_GL_BLEND_EQUATION_RGB
:
171 case LOCAL_GL_BLEND_EQUATION_ALPHA
: {
173 gl
->fGetIntegerv(pname
, &i
);
177 case LOCAL_GL_GENERATE_MIPMAP_HINT
:
178 return Some(mGenerateMipmapHint
);
180 case LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT
:
181 case LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE
: {
182 const webgl::FormatUsageInfo
* usage
;
183 uint32_t width
, height
;
184 if (!BindCurFBForColorRead(&usage
, &width
, &height
,
185 LOCAL_GL_INVALID_OPERATION
))
188 const auto implPI
= ValidImplementationColorReadPI(usage
);
191 if (pname
== LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT
) {
200 case LOCAL_GL_STENCIL_REF
:
201 case LOCAL_GL_STENCIL_BACK_REF
: {
202 GLint stencilBits
= 0;
203 if (!GetStencilBits(&stencilBits
)) return Nothing();
205 // Assuming stencils have 8 bits
206 const GLint stencilMask
= (1 << stencilBits
) - 1;
209 gl
->fGetIntegerv(pname
, &refValue
);
211 return Some(refValue
& stencilMask
);
214 case LOCAL_GL_SAMPLE_BUFFERS
:
215 case LOCAL_GL_SAMPLES
: {
216 const auto& fb
= mBoundDrawFramebuffer
;
217 auto samples
= [&]() -> Maybe
<uint32_t> {
219 if (!EnsureDefaultFB()) return Nothing();
220 return Some(mDefaultFB
->mSamples
);
223 if (!fb
->IsCheckFramebufferStatusComplete()) return Some(0);
225 DoBindFB(fb
, LOCAL_GL_FRAMEBUFFER
);
226 return Some(gl
->GetIntAs
<uint32_t>(LOCAL_GL_SAMPLES
));
228 if (samples
&& pname
== LOCAL_GL_SAMPLE_BUFFERS
) {
229 samples
= Some(uint32_t(bool(samples
.value())));
231 if (!samples
) return Nothing();
232 return Some(samples
.value());
235 case LOCAL_GL_STENCIL_CLEAR_VALUE
:
236 case LOCAL_GL_SUBPIXEL_BITS
: {
238 gl
->fGetIntegerv(pname
, &i
);
242 case LOCAL_GL_RED_BITS
:
243 case LOCAL_GL_GREEN_BITS
:
244 case LOCAL_GL_BLUE_BITS
:
245 case LOCAL_GL_ALPHA_BITS
:
246 case LOCAL_GL_DEPTH_BITS
:
247 case LOCAL_GL_STENCIL_BITS
: {
248 const auto format
= [&]() -> const webgl::FormatInfo
* {
249 const auto& fb
= mBoundDrawFramebuffer
;
251 if (!fb
->IsCheckFramebufferStatusComplete()) return nullptr;
253 const auto& attachment
= [&]() -> const auto& {
255 case LOCAL_GL_DEPTH_BITS
:
256 if (fb
->DepthStencilAttachment().HasAttachment())
257 return fb
->DepthStencilAttachment();
258 return fb
->DepthAttachment();
260 case LOCAL_GL_STENCIL_BITS
:
261 if (fb
->DepthStencilAttachment().HasAttachment())
262 return fb
->DepthStencilAttachment();
263 return fb
->StencilAttachment();
266 return fb
->ColorAttachment0();
271 const auto imageInfo
= attachment
.GetImageInfo();
272 if (!imageInfo
) return nullptr;
273 return imageInfo
->mFormat
->format
;
276 auto effFormat
= webgl::EffectiveFormat::RGB8
;
278 case LOCAL_GL_DEPTH_BITS
:
279 if (mOptions
.depth
) {
280 effFormat
= webgl::EffectiveFormat::DEPTH24_STENCIL8
;
284 case LOCAL_GL_STENCIL_BITS
:
285 if (mOptions
.stencil
) {
286 effFormat
= webgl::EffectiveFormat::DEPTH24_STENCIL8
;
291 if (mOptions
.alpha
) {
292 effFormat
= webgl::EffectiveFormat::RGBA8
;
296 return webgl::GetFormat(effFormat
);
301 case LOCAL_GL_RED_BITS
:
304 case LOCAL_GL_GREEN_BITS
:
307 case LOCAL_GL_BLUE_BITS
:
310 case LOCAL_GL_ALPHA_BITS
:
313 case LOCAL_GL_DEPTH_BITS
:
316 case LOCAL_GL_STENCIL_BITS
:
324 case LOCAL_GL_MAX_RENDERBUFFER_SIZE
:
325 return Some(mGLMaxRenderbufferSize
);
327 case LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS
:
328 return Some(mGLMaxVertexTextureImageUnits
);
330 case LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS
:
331 return Some(mGLMaxFragmentTextureImageUnits
);
333 case LOCAL_GL_MAX_VERTEX_UNIFORM_VECTORS
:
334 return Some(mGLMaxVertexUniformVectors
);
336 case LOCAL_GL_MAX_FRAGMENT_UNIFORM_VECTORS
:
337 return Some(mGLMaxFragmentUniformVectors
);
339 case LOCAL_GL_MAX_VARYING_VECTORS
:
340 return Some(mGLMaxFragmentInputVectors
);
342 // unsigned int. here we may have to return very large values like 2^32-1
343 // that can't be represented as javascript integer values. We just return
344 // them as doubles and javascript doesn't care.
345 case LOCAL_GL_STENCIL_BACK_VALUE_MASK
:
346 return Some(mStencilValueMaskBack
);
347 // pass as FP value to allow large values such as 2^32-1.
349 case LOCAL_GL_STENCIL_BACK_WRITEMASK
:
350 return Some(mStencilWriteMaskBack
);
352 case LOCAL_GL_STENCIL_VALUE_MASK
:
353 return Some(mStencilValueMaskFront
);
355 case LOCAL_GL_STENCIL_WRITEMASK
:
356 return Some(mStencilWriteMaskFront
);
359 case LOCAL_GL_LINE_WIDTH
:
360 return Some((double)mLineWidth
);
362 case LOCAL_GL_DEPTH_CLEAR_VALUE
:
363 case LOCAL_GL_POLYGON_OFFSET_FACTOR
:
364 case LOCAL_GL_POLYGON_OFFSET_UNITS
:
365 case LOCAL_GL_SAMPLE_COVERAGE_VALUE
: {
367 gl
->fGetFloatv(pname
, &f
);
372 case LOCAL_GL_DEPTH_TEST
:
373 return Some((bool)mDepthTestEnabled
);
374 case LOCAL_GL_STENCIL_TEST
:
375 return Some((bool)mStencilTestEnabled
);
378 case LOCAL_GL_CULL_FACE
:
379 case LOCAL_GL_DITHER
:
380 case LOCAL_GL_POLYGON_OFFSET_FILL
:
381 case LOCAL_GL_SCISSOR_TEST
:
382 case LOCAL_GL_SAMPLE_COVERAGE_INVERT
:
383 case LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE
:
384 case LOCAL_GL_SAMPLE_COVERAGE
:
385 case LOCAL_GL_DEPTH_WRITEMASK
: {
387 gl
->fGetBooleanv(pname
, &b
);
388 return Some(bool(b
));
395 ErrorInvalidEnumInfo("pname", pname
);
399 bool WebGLContext::IsEnabled(GLenum cap
) {
400 const FuncScope
funcScope(*this, "isEnabled");
401 if (IsContextLost()) return false;
403 if (!ValidateCapabilityEnum(cap
)) return false;
405 const auto& slot
= GetStateTrackingSlot(cap
);
406 if (slot
) return *slot
;
408 return gl
->fIsEnabled(cap
);
411 bool WebGLContext::ValidateCapabilityEnum(GLenum cap
) {
414 case LOCAL_GL_CULL_FACE
:
415 case LOCAL_GL_DEPTH_TEST
:
416 case LOCAL_GL_DITHER
:
417 case LOCAL_GL_POLYGON_OFFSET_FILL
:
418 case LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE
:
419 case LOCAL_GL_SAMPLE_COVERAGE
:
420 case LOCAL_GL_SCISSOR_TEST
:
421 case LOCAL_GL_STENCIL_TEST
:
423 case LOCAL_GL_RASTERIZER_DISCARD
:
426 ErrorInvalidEnumInfo("cap", cap
);
431 realGLboolean
* WebGLContext::GetStateTrackingSlot(GLenum cap
) {
433 case LOCAL_GL_DEPTH_TEST
:
434 return &mDepthTestEnabled
;
435 case LOCAL_GL_DITHER
:
436 return &mDitherEnabled
;
437 case LOCAL_GL_RASTERIZER_DISCARD
:
438 return &mRasterizerDiscardEnabled
;
439 case LOCAL_GL_SCISSOR_TEST
:
440 return &mScissorTestEnabled
;
441 case LOCAL_GL_STENCIL_TEST
:
442 return &mStencilTestEnabled
;
444 return &mBlendEnabled
;
450 } // namespace mozilla