no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / dom / canvas / WebGLContextState.cpp
blobf81e590436fd082e90ffb3240700b7f77b354614
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 GLenum cap, const Maybe<GLuint> i,
26 const bool enabled) {
27 const FuncScope funcScope(*this, "enable(i)/disable(i)");
28 if (IsContextLost()) return;
30 if (!ValidateCapabilityEnum(cap)) return;
32 if (i) {
33 if (cap != LOCAL_GL_BLEND) {
34 ErrorInvalidEnumArg("cap", cap);
35 return;
38 const auto limit = MaxValidDrawBuffers();
39 if (*i >= limit) {
40 ErrorInvalidValue("`index` (%u) must be < %s (%u)", *i,
41 "MAX_DRAW_BUFFERS", limit);
42 return;
46 const auto slot = GetStateTrackingSlot(cap, i ? *i : 0);
47 if (slot) {
48 *slot = enabled;
49 } else if (cap == LOCAL_GL_BLEND) {
50 if (i) {
51 mBlendEnabled[*i] = enabled;
52 } else {
53 if (enabled) {
54 mBlendEnabled.set();
55 } else {
56 mBlendEnabled.reset();
61 switch (cap) {
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.
66 default:
67 // Non-lazy caps.
68 if (i) {
69 if (enabled) {
70 gl->fEnablei(cap, *i);
71 } else {
72 gl->fDisablei(cap, *i);
74 } else {
75 gl->SetEnabled(cap, enabled);
77 break;
81 bool WebGLContext::GetStencilBits(GLint* const out_stencilBits) const {
82 *out_stencilBits = 0;
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");
88 return false;
91 if (mBoundDrawFramebuffer->StencilAttachment().HasAttachment() ||
92 mBoundDrawFramebuffer->DepthStencilAttachment().HasAttachment()) {
93 *out_stencilBits = 8;
95 } else if (mOptions.stencil) {
96 *out_stencilBits = 8;
99 return true;
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) {
118 if (slotId == 0) {
119 ret = mDefaultFB_DrawBuffer0;
121 } else {
122 const auto& fb = *mBoundDrawFramebuffer;
123 const auto& bs = fb.DrawBufferEnabled();
124 if (bs[slotId]) {
125 ret = LOCAL_GL_COLOR_ATTACHMENT0 + slotId;
128 return Some(ret);
132 if (IsExtensionEnabled(WebGLExtensionID::EXT_disjoint_timer_query)) {
133 switch (pname) {
134 case LOCAL_GL_TIMESTAMP_EXT: {
135 uint64_t val = 0;
136 if (Has64BitTimestamps()) {
137 gl->fGetInteger64v(pname, (GLint64*)&val);
138 } else {
139 gl->fGetIntegerv(pname, (GLint*)&val);
141 // TODO: JS doesn't support 64-bit integers. Be lossy and
142 // cast to double (53 bits)
143 return Some(val);
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));
154 default:
155 break;
159 if (IsWebGL2() ||
160 IsExtensionEnabled(WebGLExtensionID::OES_standard_derivatives)) {
161 if (pname == LOCAL_GL_FRAGMENT_SHADER_DERIVATIVE_HINT) {
162 GLint i = 0;
163 gl->fGetIntegerv(pname, &i);
164 return Some(i);
168 if (IsExtensionEnabled(WebGLExtensionID::EXT_texture_filter_anisotropic)) {
169 if (pname == LOCAL_GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT) {
170 GLfloat f = 0.f;
171 gl->fGetFloatv(pname, &f);
172 return Some(f);
176 if (IsExtensionEnabled(WebGLExtensionID::MOZ_debug)) {
177 if (pname == dom::MOZ_debug_Binding::DOES_INDEX_VALIDATION) {
178 return Some(mNeedsIndexValidation);
182 switch (pname) {
183 ////////////////////////////////
184 // Single-value params
186 // unsigned int
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: {
205 GLint i = 0;
206 gl->fGetIntegerv(pname, &i);
207 return Some(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))
219 return Nothing();
221 const auto implPI = ValidImplementationColorReadPI(usage);
223 GLenum ret;
224 if (pname == LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT) {
225 ret = implPI.format;
226 } else {
227 ret = implPI.type;
229 return Some(ret);
232 // int
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;
241 GLint refValue = 0;
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> {
251 if (!fb) {
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));
260 }();
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: {
270 GLint i = 0;
271 gl->fGetIntegerv(pname, &i);
272 return Some(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;
283 if (fb) {
284 if (!fb->IsCheckFramebufferStatusComplete()) return nullptr;
286 const auto& attachment = [&]() -> const auto& {
287 switch (pname) {
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();
298 default:
299 return fb->ColorAttachment0();
301 }();
303 const auto imageInfo = attachment.GetImageInfo();
304 if (!imageInfo) return nullptr;
305 return imageInfo->mFormat->format;
308 auto effFormat = webgl::EffectiveFormat::RGB8;
309 switch (pname) {
310 case LOCAL_GL_DEPTH_BITS:
311 if (mOptions.depth) {
312 effFormat = webgl::EffectiveFormat::DEPTH24_STENCIL8;
314 break;
316 case LOCAL_GL_STENCIL_BITS:
317 if (mOptions.stencil) {
318 effFormat = webgl::EffectiveFormat::DEPTH24_STENCIL8;
320 break;
322 default:
323 if (mOptions.alpha) {
324 effFormat = webgl::EffectiveFormat::RGBA8;
326 break;
328 return webgl::GetFormat(effFormat);
329 }();
330 int32_t ret = 0;
331 if (format) {
332 switch (pname) {
333 case LOCAL_GL_RED_BITS:
334 ret = format->r;
335 break;
336 case LOCAL_GL_GREEN_BITS:
337 ret = format->g;
338 break;
339 case LOCAL_GL_BLUE_BITS:
340 ret = format->b;
341 break;
342 case LOCAL_GL_ALPHA_BITS:
343 ret = format->a;
344 break;
345 case LOCAL_GL_DEPTH_BITS:
346 ret = format->d;
347 break;
348 case LOCAL_GL_STENCIL_BITS:
349 ret = format->s;
350 break;
353 return Some(ret);
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);
393 // float
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: {
401 GLfloat f = 0.f;
402 gl->fGetFloatv(pname, &f);
403 return Some(f);
406 // bool
407 case LOCAL_GL_DEPTH_TEST:
408 return Some((bool)mDepthTestEnabled);
409 case LOCAL_GL_STENCIL_TEST:
410 return Some((bool)mStencilTestEnabled);
412 case LOCAL_GL_BLEND:
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: {
421 realGLboolean b = 0;
422 gl->fGetBooleanv(pname, &b);
423 return Some(bool(b));
426 default:
427 break;
430 ErrorInvalidEnumInfo("pname", pname);
431 return Nothing();
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) {
447 switch (cap) {
448 case LOCAL_GL_BLEND:
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:
457 return true;
458 case LOCAL_GL_RASTERIZER_DISCARD:
459 return IsWebGL2();
460 default:
461 ErrorInvalidEnumInfo("cap", cap);
462 return false;
466 bool* WebGLContext::GetStateTrackingSlot(GLenum cap, GLuint i) {
467 switch (cap) {
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;
480 return nullptr;
483 } // namespace mozilla