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 GLenum cap
, const Maybe
<GLuint
> i
,
27 const FuncScope
funcScope(*this, "enable(i)/disable(i)");
28 if (IsContextLost()) return;
30 if (!ValidateCapabilityEnum(cap
)) return;
33 if (cap
!= LOCAL_GL_BLEND
) {
34 ErrorInvalidEnumArg("cap", cap
);
38 const auto limit
= MaxValidDrawBuffers();
40 ErrorInvalidValue("`index` (%u) must be < %s (%u)", *i
,
41 "MAX_DRAW_BUFFERS", limit
);
46 const auto slot
= GetStateTrackingSlot(cap
, i
? *i
: 0);
49 } else if (cap
== LOCAL_GL_BLEND
) {
51 mBlendEnabled
[*i
] = enabled
;
56 mBlendEnabled
.reset();
62 case LOCAL_GL_DEPTH_TEST
:
63 case LOCAL_GL_STENCIL_TEST
:
64 break; // Lazily applied, so don't tell GL yet or we will desync.
70 gl
->fEnablei(cap
, *i
);
72 gl
->fDisablei(cap
, *i
);
75 gl
->SetEnabled(cap
, enabled
);
81 bool WebGLContext::GetStencilBits(GLint
* const out_stencilBits
) const {
83 if (mBoundDrawFramebuffer
) {
84 if (!mBoundDrawFramebuffer
->IsCheckFramebufferStatusComplete()) {
85 // Error, we don't know which stencil buffer's bits to use
86 ErrorInvalidFramebufferOperation(
87 "getParameter: framebuffer has two stencil buffers bound");
91 if (mBoundDrawFramebuffer
->StencilAttachment().HasAttachment() ||
92 mBoundDrawFramebuffer
->DepthStencilAttachment().HasAttachment()) {
95 } else if (mOptions
.stencil
) {
102 Maybe
<double> WebGLContext::GetParameter(const GLenum pname
) {
103 const FuncScope
funcScope(*this, "getParameter");
104 if (IsContextLost()) return {};
106 if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers
)) {
107 if (pname
== LOCAL_GL_MAX_COLOR_ATTACHMENTS
) {
108 return Some(MaxValidDrawBuffers());
110 } else if (pname
== LOCAL_GL_MAX_DRAW_BUFFERS
) {
111 return Some(MaxValidDrawBuffers());
113 } else if (pname
>= LOCAL_GL_DRAW_BUFFER0
&&
114 pname
< GLenum(LOCAL_GL_DRAW_BUFFER0
+ MaxValidDrawBuffers())) {
115 const auto slotId
= pname
- LOCAL_GL_DRAW_BUFFER0
;
116 GLenum ret
= LOCAL_GL_NONE
;
117 if (!mBoundDrawFramebuffer
) {
119 ret
= mDefaultFB_DrawBuffer0
;
122 const auto& fb
= *mBoundDrawFramebuffer
;
123 const auto& bs
= fb
.DrawBufferEnabled();
125 ret
= LOCAL_GL_COLOR_ATTACHMENT0
+ slotId
;
132 if (IsExtensionEnabled(WebGLExtensionID::EXT_disjoint_timer_query
)) {
134 case LOCAL_GL_TIMESTAMP_EXT
: {
136 if (Has64BitTimestamps()) {
137 gl
->fGetInteger64v(pname
, (GLint64
*)&val
);
139 gl
->fGetIntegerv(pname
, (GLint
*)&val
);
141 // TODO: JS doesn't support 64-bit integers. Be lossy and
142 // cast to double (53 bits)
146 case LOCAL_GL_GPU_DISJOINT_EXT
: {
147 realGLboolean val
= false; // Not disjoint by default.
148 if (gl
->IsExtensionSupported(gl::GLContext::EXT_disjoint_timer_query
)) {
149 gl
->fGetBooleanv(pname
, &val
);
151 return Some(bool(val
));
160 IsExtensionEnabled(WebGLExtensionID::OES_standard_derivatives
)) {
161 if (pname
== LOCAL_GL_FRAGMENT_SHADER_DERIVATIVE_HINT
) {
163 gl
->fGetIntegerv(pname
, &i
);
168 if (IsExtensionEnabled(WebGLExtensionID::EXT_texture_filter_anisotropic
)) {
169 if (pname
== LOCAL_GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT
) {
171 gl
->fGetFloatv(pname
, &f
);
176 if (IsExtensionEnabled(WebGLExtensionID::MOZ_debug
)) {
177 if (pname
== dom::MOZ_debug_Binding::DOES_INDEX_VALIDATION
) {
178 return Some(mNeedsIndexValidation
);
183 ////////////////////////////////
184 // Single-value params
187 case LOCAL_GL_CULL_FACE_MODE
:
188 case LOCAL_GL_FRONT_FACE
:
189 case LOCAL_GL_ACTIVE_TEXTURE
:
190 case LOCAL_GL_STENCIL_FUNC
:
191 case LOCAL_GL_STENCIL_FAIL
:
192 case LOCAL_GL_STENCIL_PASS_DEPTH_FAIL
:
193 case LOCAL_GL_STENCIL_PASS_DEPTH_PASS
:
194 case LOCAL_GL_STENCIL_BACK_FUNC
:
195 case LOCAL_GL_STENCIL_BACK_FAIL
:
196 case LOCAL_GL_STENCIL_BACK_PASS_DEPTH_FAIL
:
197 case LOCAL_GL_STENCIL_BACK_PASS_DEPTH_PASS
:
198 case LOCAL_GL_DEPTH_FUNC
:
199 case LOCAL_GL_BLEND_SRC_RGB
:
200 case LOCAL_GL_BLEND_SRC_ALPHA
:
201 case LOCAL_GL_BLEND_DST_RGB
:
202 case LOCAL_GL_BLEND_DST_ALPHA
:
203 case LOCAL_GL_BLEND_EQUATION_RGB
:
204 case LOCAL_GL_BLEND_EQUATION_ALPHA
: {
206 gl
->fGetIntegerv(pname
, &i
);
210 case LOCAL_GL_GENERATE_MIPMAP_HINT
:
211 return Some(mGenerateMipmapHint
);
213 case LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT
:
214 case LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE
: {
215 const webgl::FormatUsageInfo
* usage
;
216 uint32_t width
, height
;
217 if (!BindCurFBForColorRead(&usage
, &width
, &height
,
218 LOCAL_GL_INVALID_OPERATION
))
221 const auto implPI
= ValidImplementationColorReadPI(usage
);
224 if (pname
== LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT
) {
233 case LOCAL_GL_STENCIL_REF
:
234 case LOCAL_GL_STENCIL_BACK_REF
: {
235 GLint stencilBits
= 0;
236 if (!GetStencilBits(&stencilBits
)) return Nothing();
238 // Assuming stencils have 8 bits
239 const GLint stencilMask
= (1 << stencilBits
) - 1;
242 gl
->fGetIntegerv(pname
, &refValue
);
244 return Some(refValue
& stencilMask
);
247 case LOCAL_GL_SAMPLE_BUFFERS
:
248 case LOCAL_GL_SAMPLES
: {
249 const auto& fb
= mBoundDrawFramebuffer
;
250 auto samples
= [&]() -> Maybe
<uint32_t> {
252 if (!EnsureDefaultFB()) return Nothing();
253 return Some(mDefaultFB
->mSamples
);
256 if (!fb
->IsCheckFramebufferStatusComplete()) return Some(0);
258 DoBindFB(fb
, LOCAL_GL_FRAMEBUFFER
);
259 return Some(gl
->GetIntAs
<uint32_t>(LOCAL_GL_SAMPLES
));
261 if (samples
&& pname
== LOCAL_GL_SAMPLE_BUFFERS
) {
262 samples
= Some(uint32_t(bool(samples
.value())));
264 if (!samples
) return Nothing();
265 return Some(samples
.value());
268 case LOCAL_GL_STENCIL_CLEAR_VALUE
:
269 case LOCAL_GL_SUBPIXEL_BITS
: {
271 gl
->fGetIntegerv(pname
, &i
);
275 case LOCAL_GL_RED_BITS
:
276 case LOCAL_GL_GREEN_BITS
:
277 case LOCAL_GL_BLUE_BITS
:
278 case LOCAL_GL_ALPHA_BITS
:
279 case LOCAL_GL_DEPTH_BITS
:
280 case LOCAL_GL_STENCIL_BITS
: {
281 const auto format
= [&]() -> const webgl::FormatInfo
* {
282 const auto& fb
= mBoundDrawFramebuffer
;
284 if (!fb
->IsCheckFramebufferStatusComplete()) return nullptr;
286 const auto& attachment
= [&]() -> const auto& {
288 case LOCAL_GL_DEPTH_BITS
:
289 if (fb
->DepthStencilAttachment().HasAttachment())
290 return fb
->DepthStencilAttachment();
291 return fb
->DepthAttachment();
293 case LOCAL_GL_STENCIL_BITS
:
294 if (fb
->DepthStencilAttachment().HasAttachment())
295 return fb
->DepthStencilAttachment();
296 return fb
->StencilAttachment();
299 return fb
->ColorAttachment0();
303 const auto imageInfo
= attachment
.GetImageInfo();
304 if (!imageInfo
) return nullptr;
305 return imageInfo
->mFormat
->format
;
308 auto effFormat
= webgl::EffectiveFormat::RGB8
;
310 case LOCAL_GL_DEPTH_BITS
:
311 if (mOptions
.depth
) {
312 effFormat
= webgl::EffectiveFormat::DEPTH24_STENCIL8
;
316 case LOCAL_GL_STENCIL_BITS
:
317 if (mOptions
.stencil
) {
318 effFormat
= webgl::EffectiveFormat::DEPTH24_STENCIL8
;
323 if (mOptions
.alpha
) {
324 effFormat
= webgl::EffectiveFormat::RGBA8
;
328 return webgl::GetFormat(effFormat
);
333 case LOCAL_GL_RED_BITS
:
336 case LOCAL_GL_GREEN_BITS
:
339 case LOCAL_GL_BLUE_BITS
:
342 case LOCAL_GL_ALPHA_BITS
:
345 case LOCAL_GL_DEPTH_BITS
:
348 case LOCAL_GL_STENCIL_BITS
:
356 case LOCAL_GL_MAX_RENDERBUFFER_SIZE
:
357 return Some(mGLMaxRenderbufferSize
);
359 case LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS
:
360 return Some(mGLMaxVertexTextureImageUnits
);
362 case LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS
:
363 return Some(mGLMaxFragmentTextureImageUnits
);
365 case LOCAL_GL_MAX_VERTEX_UNIFORM_VECTORS
:
366 return Some(mGLMaxVertexUniformVectors
);
368 case LOCAL_GL_MAX_FRAGMENT_UNIFORM_VECTORS
:
369 return Some(mGLMaxFragmentUniformVectors
);
371 case LOCAL_GL_MAX_VARYING_VECTORS
:
372 return Some(mGLMaxFragmentInputVectors
);
374 // unsigned int. here we may have to return very large values like 2^32-1
375 // that can't be represented as javascript integer values. We just return
376 // them as doubles and javascript doesn't care.
377 case LOCAL_GL_STENCIL_BACK_VALUE_MASK
:
378 return Some(mStencilValueMaskBack
);
379 // pass as FP value to allow large values such as 2^32-1.
381 case LOCAL_GL_STENCIL_BACK_WRITEMASK
:
382 return Some(mStencilWriteMaskBack
);
384 case LOCAL_GL_STENCIL_VALUE_MASK
:
385 return Some(mStencilValueMaskFront
);
387 case LOCAL_GL_STENCIL_WRITEMASK
:
388 return Some(mStencilWriteMaskFront
);
390 case LOCAL_GL_COLOR_WRITEMASK
:
391 return Some(mColorWriteMask0
);
394 case LOCAL_GL_LINE_WIDTH
:
395 return Some((double)mLineWidth
);
397 case LOCAL_GL_DEPTH_CLEAR_VALUE
:
398 case LOCAL_GL_POLYGON_OFFSET_FACTOR
:
399 case LOCAL_GL_POLYGON_OFFSET_UNITS
:
400 case LOCAL_GL_SAMPLE_COVERAGE_VALUE
: {
402 gl
->fGetFloatv(pname
, &f
);
407 case LOCAL_GL_DEPTH_TEST
:
408 return Some((bool)mDepthTestEnabled
);
409 case LOCAL_GL_STENCIL_TEST
:
410 return Some((bool)mStencilTestEnabled
);
413 case LOCAL_GL_CULL_FACE
:
414 case LOCAL_GL_DITHER
:
415 case LOCAL_GL_POLYGON_OFFSET_FILL
:
416 case LOCAL_GL_SCISSOR_TEST
:
417 case LOCAL_GL_SAMPLE_COVERAGE_INVERT
:
418 case LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE
:
419 case LOCAL_GL_SAMPLE_COVERAGE
:
420 case LOCAL_GL_DEPTH_WRITEMASK
: {
422 gl
->fGetBooleanv(pname
, &b
);
423 return Some(bool(b
));
430 ErrorInvalidEnumInfo("pname", pname
);
434 bool WebGLContext::IsEnabled(GLenum cap
) {
435 const FuncScope
funcScope(*this, "isEnabled");
436 if (IsContextLost()) return false;
438 if (!ValidateCapabilityEnum(cap
)) return false;
440 const auto& slot
= GetStateTrackingSlot(cap
, 0);
441 if (slot
) return *slot
;
443 return gl
->fIsEnabled(cap
);
446 bool WebGLContext::ValidateCapabilityEnum(GLenum cap
) {
449 case LOCAL_GL_CULL_FACE
:
450 case LOCAL_GL_DEPTH_TEST
:
451 case LOCAL_GL_DITHER
:
452 case LOCAL_GL_POLYGON_OFFSET_FILL
:
453 case LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE
:
454 case LOCAL_GL_SAMPLE_COVERAGE
:
455 case LOCAL_GL_SCISSOR_TEST
:
456 case LOCAL_GL_STENCIL_TEST
:
458 case LOCAL_GL_RASTERIZER_DISCARD
:
461 ErrorInvalidEnumInfo("cap", cap
);
466 bool* WebGLContext::GetStateTrackingSlot(GLenum cap
, GLuint i
) {
468 case LOCAL_GL_DEPTH_TEST
:
469 return &mDepthTestEnabled
;
470 case LOCAL_GL_DITHER
:
471 return &mDitherEnabled
;
472 case LOCAL_GL_RASTERIZER_DISCARD
:
473 return &mRasterizerDiscardEnabled
;
474 case LOCAL_GL_SCISSOR_TEST
:
475 return &mScissorTestEnabled
;
476 case LOCAL_GL_STENCIL_TEST
:
477 return &mStencilTestEnabled
;
483 } // namespace mozilla