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 "WebGLFormats.h"
11 #include "WebGLFramebuffer.h"
12 #include "WebGLRenderbuffer.h"
13 #include "WebGLTexture.h"
17 void WebGLContext::Clear(GLbitfield mask
) {
18 const FuncScope
funcScope(*this, "clear");
19 if (IsContextLost()) return;
21 uint32_t m
= mask
& (LOCAL_GL_COLOR_BUFFER_BIT
| LOCAL_GL_DEPTH_BUFFER_BIT
|
22 LOCAL_GL_STENCIL_BUFFER_BIT
);
23 if (mask
!= m
) return ErrorInvalidValue("Invalid mask bits.");
26 GenerateWarning("Calling gl.clear(0) has no effect.");
27 } else if (mRasterizerDiscardEnabled
) {
29 "Calling gl.clear() with RASTERIZER_DISCARD enabled has no effects.");
32 if (mask
& LOCAL_GL_COLOR_BUFFER_BIT
&& mBoundDrawFramebuffer
) {
33 for (const auto& cur
: mBoundDrawFramebuffer
->ColorDrawBuffers()) {
34 const auto imageInfo
= cur
->GetImageInfo();
35 if (!imageInfo
|| !imageInfo
->mFormat
) continue;
37 if (imageInfo
->mFormat
->format
->baseType
!=
38 webgl::TextureBaseType::Float
) {
39 ErrorInvalidOperation(
40 "Color draw buffers must be floating-point"
41 " or fixed-point. (normalized (u)ints)");
47 if (!BindCurFBForDraw()) return;
49 auto driverMask
= mask
;
50 if (!mBoundDrawFramebuffer
) {
51 if (mNeedsFakeNoDepth
) {
52 driverMask
&= ~LOCAL_GL_DEPTH_BUFFER_BIT
;
54 if (mNeedsFakeNoStencil
) {
55 driverMask
&= ~LOCAL_GL_STENCIL_BUFFER_BIT
;
59 const ScopedDrawCallWrapper
wrapper(*this);
60 gl
->fClear(driverMask
);
63 static GLfloat
GLClampFloat(GLfloat val
) {
64 if (val
< 0.0) return 0.0;
66 if (val
> 1.0) return 1.0;
71 void WebGLContext::ClearColor(GLfloat r
, GLfloat g
, GLfloat b
, GLfloat a
) {
72 const FuncScope
funcScope(*this, "clearColor");
73 if (IsContextLost()) return;
75 if (IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_float
)) {
76 MOZ_ASSERT(IsExtensionExplicit(WebGLExtensionID::EXT_color_buffer_float
));
78 } else if (IsExtensionEnabled(
79 WebGLExtensionID::EXT_color_buffer_half_float
) ||
80 IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float
)) {
82 (IsExtensionExplicit(WebGLExtensionID::EXT_color_buffer_half_float
) ||
83 IsExtensionExplicit(WebGLExtensionID::WEBGL_color_buffer_float
));
84 const bool wouldHaveClamped
=
85 (r
!= GLClampFloat(r
) || g
!= GLClampFloat(g
) || b
!= GLClampFloat(b
) ||
86 a
!= GLClampFloat(a
));
87 if (!explict
&& wouldHaveClamped
) {
88 if (IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float
)) {
89 WarnIfImplicit(WebGLExtensionID::EXT_color_buffer_half_float
);
90 } else if (IsExtensionEnabled(
91 WebGLExtensionID::WEBGL_color_buffer_float
)) {
92 WarnIfImplicit(WebGLExtensionID::WEBGL_color_buffer_float
);
102 gl
->fClearColor(r
, g
, b
, a
);
104 mColorClearValue
[0] = r
;
105 mColorClearValue
[1] = g
;
106 mColorClearValue
[2] = b
;
107 mColorClearValue
[3] = a
;
110 void WebGLContext::ClearDepth(GLclampf v
) {
111 const FuncScope
funcScope(*this, "clearDepth");
112 if (IsContextLost()) return;
114 mDepthClearValue
= GLClampFloat(v
);
115 gl
->fClearDepth(mDepthClearValue
);
118 void WebGLContext::ClearStencil(GLint v
) {
119 const FuncScope
funcScope(*this, "clearStencil");
120 if (IsContextLost()) return;
122 mStencilClearValue
= v
;
123 gl
->fClearStencil(v
);
126 void WebGLContext::ColorMask(const Maybe
<GLuint
> i
, const uint8_t mask
) {
127 const FuncScope
funcScope(*this, "colorMask");
128 if (IsContextLost()) return;
132 IsExtensionEnabled(WebGLExtensionID::OES_draw_buffers_indexed
));
133 const auto limit
= MaxValidDrawBuffers();
135 ErrorInvalidValue("`index` (%u) must be < %s (%u)", *i
,
136 "MAX_DRAW_BUFFERS", limit
);
140 mColorWriteMask0
= mask
;
142 mColorWriteMaskNonzero
[*i
] = bool(mask
);
144 mColorWriteMask0
= mask
;
146 mColorWriteMaskNonzero
.set();
148 mColorWriteMaskNonzero
.reset();
152 DoColorMask(i
, mask
);
155 void WebGLContext::DepthMask(WebGLboolean b
) {
156 const FuncScope
funcScope(*this, "depthMask");
157 if (IsContextLost()) return;
163 void WebGLContext::DrawBuffers(const std::vector
<GLenum
>& buffers
) {
164 const FuncScope
funcScope(*this, "drawBuffers");
165 if (IsContextLost()) return;
167 if (mBoundDrawFramebuffer
) {
168 mBoundDrawFramebuffer
->DrawBuffers(buffers
);
173 // "If the GL is bound to the default framebuffer, then `n` must be 1 and the
174 // constant must be BACK or NONE. [...] If DrawBuffers is supplied with a
175 // constant other than BACK and NONE, or with a value of `n` other than 1,
176 // the error INVALID_OPERATION is generated."
177 if (buffers
.size() != 1) {
178 ErrorInvalidOperation(
179 "For the default framebuffer, `buffers` must have a"
184 switch (buffers
[0]) {
190 ErrorInvalidOperation(
191 "For the default framebuffer, `buffers[0]` must be"
196 mDefaultFB_DrawBuffer0
= buffers
[0];
197 // Don't actually set it.
200 void WebGLContext::StencilMaskSeparate(GLenum face
, GLuint mask
) {
201 const FuncScope
funcScope(*this, "stencilMaskSeparate");
202 if (IsContextLost()) return;
204 if (!ValidateFaceEnum(face
)) return;
207 case LOCAL_GL_FRONT_AND_BACK
:
208 mStencilWriteMaskFront
= mask
;
209 mStencilWriteMaskBack
= mask
;
212 mStencilWriteMaskFront
= mask
;
215 mStencilWriteMaskBack
= mask
;
219 gl
->fStencilMaskSeparate(face
, mask
);
222 } // namespace mozilla