WebGLContextFramebufferOperations.cpp (6355B)
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/. */ 5 6 #include "GLContext.h" 7 #include "GLScreenBuffer.h" 8 #include "WebGLContext.h" 9 #include "WebGLFormats.h" 10 #include "WebGLFramebuffer.h" 11 #include "WebGLRenderbuffer.h" 12 #include "WebGLTexture.h" 13 14 namespace mozilla { 15 16 void WebGLContext::Clear(GLbitfield mask) { 17 const FuncScope funcScope(*this, "clear"); 18 if (IsContextLost()) return; 19 20 uint32_t m = mask & (LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT | 21 LOCAL_GL_STENCIL_BUFFER_BIT); 22 if (mask != m) return ErrorInvalidValue("Invalid mask bits."); 23 24 if (mask == 0) { 25 GenerateWarning("Calling gl.clear(0) has no effect."); 26 } else if (mRasterizerDiscardEnabled) { 27 GenerateWarning( 28 "Calling gl.clear() with RASTERIZER_DISCARD enabled has no effects."); 29 } 30 31 if (mask & LOCAL_GL_COLOR_BUFFER_BIT && mBoundDrawFramebuffer) { 32 for (const auto& cur : mBoundDrawFramebuffer->ColorDrawBuffers()) { 33 const auto imageInfo = cur->GetImageInfo(); 34 if (!imageInfo || !imageInfo->mFormat) continue; 35 36 if (imageInfo->mFormat->format->baseType != 37 webgl::TextureBaseType::Float) { 38 ErrorInvalidOperation( 39 "Color draw buffers must be floating-point" 40 " or fixed-point. (normalized (u)ints)"); 41 return; 42 } 43 } 44 } 45 46 if (!BindCurFBForDraw()) return; 47 48 auto driverMask = mask; 49 if (!mBoundDrawFramebuffer) { 50 if (mNeedsFakeNoDepth) { 51 driverMask &= ~LOCAL_GL_DEPTH_BUFFER_BIT; 52 } 53 if (mNeedsFakeNoStencil) { 54 driverMask &= ~LOCAL_GL_STENCIL_BUFFER_BIT; 55 } 56 } 57 58 const ScopedDrawCallWrapper wrapper(*this); 59 gl->fClear(driverMask); 60 } 61 62 static GLfloat GLClampFloat(GLfloat val) { 63 if (val < 0.0) return 0.0; 64 65 if (val > 1.0) return 1.0; 66 67 return val; 68 } 69 70 void WebGLContext::ClearColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) { 71 const FuncScope funcScope(*this, "clearColor"); 72 if (IsContextLost()) return; 73 74 if (IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_float)) { 75 MOZ_ASSERT(IsExtensionExplicit(WebGLExtensionID::EXT_color_buffer_float)); 76 77 } else if (IsExtensionEnabled( 78 WebGLExtensionID::EXT_color_buffer_half_float) || 79 IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float)) { 80 const bool explict = 81 (IsExtensionExplicit(WebGLExtensionID::EXT_color_buffer_half_float) || 82 IsExtensionExplicit(WebGLExtensionID::WEBGL_color_buffer_float)); 83 const bool wouldHaveClamped = 84 (r != GLClampFloat(r) || g != GLClampFloat(g) || b != GLClampFloat(b) || 85 a != GLClampFloat(a)); 86 if (!explict && wouldHaveClamped) { 87 if (IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float)) { 88 WarnIfImplicit(WebGLExtensionID::EXT_color_buffer_half_float); 89 } else if (IsExtensionEnabled( 90 WebGLExtensionID::WEBGL_color_buffer_float)) { 91 WarnIfImplicit(WebGLExtensionID::WEBGL_color_buffer_float); 92 } 93 } 94 } else { 95 r = GLClampFloat(r); 96 g = GLClampFloat(g); 97 b = GLClampFloat(b); 98 a = GLClampFloat(a); 99 } 100 101 gl->fClearColor(r, g, b, a); 102 103 mColorClearValue[0] = r; 104 mColorClearValue[1] = g; 105 mColorClearValue[2] = b; 106 mColorClearValue[3] = a; 107 } 108 109 void WebGLContext::ClearDepth(GLclampf v) { 110 const FuncScope funcScope(*this, "clearDepth"); 111 if (IsContextLost()) return; 112 113 mDepthClearValue = GLClampFloat(v); 114 gl->fClearDepth(mDepthClearValue); 115 } 116 117 void WebGLContext::ClearStencil(GLint v) { 118 const FuncScope funcScope(*this, "clearStencil"); 119 if (IsContextLost()) return; 120 121 mStencilClearValue = v; 122 gl->fClearStencil(v); 123 } 124 125 void WebGLContext::ColorMask(const Maybe<GLuint> i, const uint8_t mask) { 126 const FuncScope funcScope(*this, "colorMask"); 127 if (IsContextLost()) return; 128 129 if (i) { 130 MOZ_RELEASE_ASSERT( 131 IsExtensionEnabled(WebGLExtensionID::OES_draw_buffers_indexed)); 132 const auto limit = MaxValidDrawBuffers(); 133 if (*i >= limit) { 134 ErrorInvalidValue("`index` (%u) must be < %s (%u)", *i, 135 "MAX_DRAW_BUFFERS", limit); 136 return; 137 } 138 if (*i == 0) { 139 mColorWriteMask0 = mask; 140 } 141 mColorWriteMaskNonzero[*i] = bool(mask); 142 } else { 143 mColorWriteMask0 = mask; 144 if (mask) { 145 mColorWriteMaskNonzero.set(); 146 } else { 147 mColorWriteMaskNonzero.reset(); 148 } 149 } 150 151 DoColorMask(i, mask); 152 } 153 154 void WebGLContext::DepthMask(WebGLboolean b) { 155 const FuncScope funcScope(*this, "depthMask"); 156 if (IsContextLost()) return; 157 158 mDepthWriteMask = b; 159 gl->fDepthMask(b); 160 } 161 162 void WebGLContext::DrawBuffers(const std::vector<GLenum>& buffers) { 163 const FuncScope funcScope(*this, "drawBuffers"); 164 if (IsContextLost()) return; 165 166 if (mBoundDrawFramebuffer) { 167 mBoundDrawFramebuffer->DrawBuffers(buffers); 168 return; 169 } 170 171 // GLES 3.0.4 p186: 172 // "If the GL is bound to the default framebuffer, then `n` must be 1 and the 173 // constant must be BACK or NONE. [...] If DrawBuffers is supplied with a 174 // constant other than BACK and NONE, or with a value of `n` other than 1, 175 // the error INVALID_OPERATION is generated." 176 if (buffers.size() != 1) { 177 ErrorInvalidOperation( 178 "For the default framebuffer, `buffers` must have a" 179 " length of 1."); 180 return; 181 } 182 183 switch (buffers[0]) { 184 case LOCAL_GL_NONE: 185 case LOCAL_GL_BACK: 186 break; 187 188 default: 189 ErrorInvalidOperation( 190 "For the default framebuffer, `buffers[0]` must be" 191 " BACK or NONE."); 192 return; 193 } 194 195 mDefaultFB_DrawBuffer0 = buffers[0]; 196 // Don't actually set it. 197 } 198 199 void WebGLContext::StencilMaskSeparate(GLenum face, GLuint mask) { 200 const FuncScope funcScope(*this, "stencilMaskSeparate"); 201 if (IsContextLost()) return; 202 203 if (!ValidateFaceEnum(face)) return; 204 205 switch (face) { 206 case LOCAL_GL_FRONT_AND_BACK: 207 mStencilWriteMaskFront = mask; 208 mStencilWriteMaskBack = mask; 209 break; 210 case LOCAL_GL_FRONT: 211 mStencilWriteMaskFront = mask; 212 break; 213 case LOCAL_GL_BACK: 214 mStencilWriteMaskBack = mask; 215 break; 216 } 217 218 gl->fStencilMaskSeparate(face, mask); 219 } 220 221 } // namespace mozilla