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(WebGLboolean r
, WebGLboolean g
, WebGLboolean b
,
128 const FuncScope
funcScope(*this, "colorMask");
129 if (IsContextLost()) return;
131 mColorWriteMask
= uint8_t(bool(r
) << 0) | uint8_t(bool(g
) << 1) |
132 uint8_t(bool(b
) << 2) | uint8_t(bool(a
) << 3);
135 void WebGLContext::DepthMask(WebGLboolean b
) {
136 const FuncScope
funcScope(*this, "depthMask");
137 if (IsContextLost()) return;
143 void WebGLContext::DrawBuffers(const std::vector
<GLenum
>& buffers
) {
144 const FuncScope
funcScope(*this, "drawBuffers");
145 if (IsContextLost()) return;
147 if (mBoundDrawFramebuffer
) {
148 mBoundDrawFramebuffer
->DrawBuffers(buffers
);
153 // "If the GL is bound to the default framebuffer, then `n` must be 1 and the
154 // constant must be BACK or NONE. [...] If DrawBuffers is supplied with a
155 // constant other than BACK and NONE, or with a value of `n` other than 1,
156 // the error INVALID_OPERATION is generated."
157 if (buffers
.size() != 1) {
158 ErrorInvalidOperation(
159 "For the default framebuffer, `buffers` must have a"
164 switch (buffers
[0]) {
170 ErrorInvalidOperation(
171 "For the default framebuffer, `buffers[0]` must be"
176 mDefaultFB_DrawBuffer0
= buffers
[0];
177 // Don't actually set it.
180 void WebGLContext::StencilMaskSeparate(GLenum face
, GLuint mask
) {
181 const FuncScope
funcScope(*this, "stencilMaskSeparate");
182 if (IsContextLost()) return;
184 if (!ValidateFaceEnum(face
)) return;
187 case LOCAL_GL_FRONT_AND_BACK
:
188 mStencilWriteMaskFront
= mask
;
189 mStencilWriteMaskBack
= mask
;
192 mStencilWriteMaskFront
= mask
;
195 mStencilWriteMaskBack
= mask
;
199 gl
->fStencilMaskSeparate(face
, mask
);
202 } // namespace mozilla