Bug 1700051: part 26) Correct typo in comment of `mozInlineSpellWordUtil::BuildSoftTe...
[gecko.git] / dom / canvas / WebGLContextState.cpp
blobfae6436ea2739048d5384e557273c0ccf9aaadd0
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 "GLScreenBuffer.h"
10 #include "mozilla/Maybe.h"
11 #include "mozilla/Preferences.h"
12 #include "MozFramebuffer.h"
13 #include "nsString.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"
23 namespace mozilla {
25 void WebGLContext::SetEnabled(const char* const funcName, const GLenum cap,
26 const bool enabled) {
27 const FuncScope funcScope(*this, funcName);
28 if (IsContextLost()) return;
30 if (!ValidateCapabilityEnum(cap)) return;
32 const auto& slot = GetStateTrackingSlot(cap);
33 if (slot) {
34 *slot = enabled;
37 switch (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.
42 default:
43 // Non-lazy caps.
44 gl->SetEnabled(cap, enabled);
45 break;
49 bool WebGLContext::GetStencilBits(GLint* const out_stencilBits) const {
50 *out_stencilBits = 0;
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");
56 return false;
59 if (mBoundDrawFramebuffer->StencilAttachment().HasAttachment() ||
60 mBoundDrawFramebuffer->DepthStencilAttachment().HasAttachment()) {
61 *out_stencilBits = 8;
63 } else if (mOptions.stencil) {
64 *out_stencilBits = 8;
67 return true;
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) {
86 if (slotId == 0) {
87 ret = mDefaultFB_DrawBuffer0;
89 } else {
90 const auto& fb = *mBoundDrawFramebuffer;
91 if (fb.IsDrawBufferEnabled(slotId)) {
92 ret = LOCAL_GL_COLOR_ATTACHMENT0 + slotId;
95 return Some(ret);
99 if (IsExtensionEnabled(WebGLExtensionID::EXT_disjoint_timer_query)) {
100 switch (pname) {
101 case LOCAL_GL_TIMESTAMP_EXT: {
102 uint64_t val = 0;
103 if (Has64BitTimestamps()) {
104 gl->fGetInteger64v(pname, (GLint64*)&val);
105 } else {
106 gl->fGetIntegerv(pname, (GLint*)&val);
108 // TODO: JS doesn't support 64-bit integers. Be lossy and
109 // cast to double (53 bits)
110 return Some(val);
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));
121 default:
122 break;
126 if (IsWebGL2() ||
127 IsExtensionEnabled(WebGLExtensionID::OES_standard_derivatives)) {
128 if (pname == LOCAL_GL_FRAGMENT_SHADER_DERIVATIVE_HINT) {
129 GLint i = 0;
130 gl->fGetIntegerv(pname, &i);
131 return Some(i);
135 if (IsExtensionEnabled(WebGLExtensionID::EXT_texture_filter_anisotropic)) {
136 if (pname == LOCAL_GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT) {
137 GLfloat f = 0.f;
138 gl->fGetFloatv(pname, &f);
139 return Some(f);
143 if (IsExtensionEnabled(WebGLExtensionID::MOZ_debug)) {
144 if (pname == dom::MOZ_debug_Binding::DOES_INDEX_VALIDATION) {
145 return Some(mNeedsIndexValidation);
149 switch (pname) {
150 ////////////////////////////////
151 // Single-value params
153 // unsigned int
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: {
172 GLint i = 0;
173 gl->fGetIntegerv(pname, &i);
174 return Some(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))
186 return Nothing();
188 const auto implPI = ValidImplementationColorReadPI(usage);
190 GLenum ret;
191 if (pname == LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT) {
192 ret = implPI.format;
193 } else {
194 ret = implPI.type;
196 return Some(ret);
199 // int
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;
208 GLint refValue = 0;
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> {
218 if (!fb) {
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));
227 }();
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: {
237 GLint i = 0;
238 gl->fGetIntegerv(pname, &i);
239 return Some(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;
250 if (fb) {
251 if (!fb->IsCheckFramebufferStatusComplete()) return nullptr;
253 const auto& attachment = [&]() -> const auto& {
254 switch (pname) {
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();
265 default:
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;
277 switch (pname) {
278 case LOCAL_GL_DEPTH_BITS:
279 if (mOptions.depth) {
280 effFormat = webgl::EffectiveFormat::DEPTH24_STENCIL8;
282 break;
284 case LOCAL_GL_STENCIL_BITS:
285 if (mOptions.stencil) {
286 effFormat = webgl::EffectiveFormat::DEPTH24_STENCIL8;
288 break;
290 default:
291 if (mOptions.alpha) {
292 effFormat = webgl::EffectiveFormat::RGBA8;
294 break;
296 return webgl::GetFormat(effFormat);
297 }();
298 int32_t ret = 0;
299 if (format) {
300 switch (pname) {
301 case LOCAL_GL_RED_BITS:
302 ret = format->r;
303 break;
304 case LOCAL_GL_GREEN_BITS:
305 ret = format->g;
306 break;
307 case LOCAL_GL_BLUE_BITS:
308 ret = format->b;
309 break;
310 case LOCAL_GL_ALPHA_BITS:
311 ret = format->a;
312 break;
313 case LOCAL_GL_DEPTH_BITS:
314 ret = format->d;
315 break;
316 case LOCAL_GL_STENCIL_BITS:
317 ret = format->s;
318 break;
321 return Some(ret);
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);
358 // float
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: {
366 GLfloat f = 0.f;
367 gl->fGetFloatv(pname, &f);
368 return Some(f);
371 // bool
372 case LOCAL_GL_DEPTH_TEST:
373 return Some((bool)mDepthTestEnabled);
374 case LOCAL_GL_STENCIL_TEST:
375 return Some((bool)mStencilTestEnabled);
377 case LOCAL_GL_BLEND:
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: {
386 realGLboolean b = 0;
387 gl->fGetBooleanv(pname, &b);
388 return Some(bool(b));
391 default:
392 break;
395 ErrorInvalidEnumInfo("pname", pname);
396 return Nothing();
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) {
412 switch (cap) {
413 case LOCAL_GL_BLEND:
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:
422 return true;
423 case LOCAL_GL_RASTERIZER_DISCARD:
424 return IsWebGL2();
425 default:
426 ErrorInvalidEnumInfo("cap", cap);
427 return false;
431 realGLboolean* WebGLContext::GetStateTrackingSlot(GLenum cap) {
432 switch (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;
443 case LOCAL_GL_BLEND:
444 return &mBlendEnabled;
447 return nullptr;
450 } // namespace mozilla