1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/canvas/src/WebGLContextFramebufferOperations.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,244 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "WebGLContext.h" 1.10 +#include "WebGLTexture.h" 1.11 +#include "WebGLRenderbuffer.h" 1.12 +#include "WebGLFramebuffer.h" 1.13 +#include "GLContext.h" 1.14 + 1.15 +using namespace mozilla; 1.16 + 1.17 +void 1.18 +WebGLContext::Clear(GLbitfield mask) 1.19 +{ 1.20 + if (IsContextLost()) 1.21 + return; 1.22 + 1.23 + MakeContextCurrent(); 1.24 + 1.25 + uint32_t m = mask & (LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT | LOCAL_GL_STENCIL_BUFFER_BIT); 1.26 + if (mask != m) 1.27 + return ErrorInvalidValue("clear: invalid mask bits"); 1.28 + 1.29 + if (mask == 0) { 1.30 + GenerateWarning("Calling gl.clear(0) has no effect."); 1.31 + } else if (mRasterizerDiscardEnabled) { 1.32 + GenerateWarning("Calling gl.clear() with RASTERIZER_DISCARD enabled has no effects."); 1.33 + } 1.34 + 1.35 + if (mBoundFramebuffer) { 1.36 + if (!mBoundFramebuffer->CheckAndInitializeAttachments()) 1.37 + return ErrorInvalidFramebufferOperation("clear: incomplete framebuffer"); 1.38 + 1.39 + gl->fClear(mask); 1.40 + return; 1.41 + } else { 1.42 + ClearBackbufferIfNeeded(); 1.43 + } 1.44 + 1.45 + // Ok, we're clearing the default framebuffer/screen. 1.46 + 1.47 + gl->fClear(mask); 1.48 + 1.49 + Invalidate(); 1.50 + mShouldPresent = true; 1.51 +} 1.52 + 1.53 +static GLclampf 1.54 +GLClampFloat(GLclampf val) 1.55 +{ 1.56 + if (val < 0.0) 1.57 + return 0.0; 1.58 + 1.59 + if (val > 1.0) 1.60 + return 1.0; 1.61 + 1.62 + return val; 1.63 +} 1.64 + 1.65 +void 1.66 +WebGLContext::ClearColor(GLclampf r, GLclampf g, 1.67 + GLclampf b, GLclampf a) 1.68 +{ 1.69 + if (IsContextLost()) 1.70 + return; 1.71 + 1.72 + MakeContextCurrent(); 1.73 + mColorClearValue[0] = GLClampFloat(r); 1.74 + mColorClearValue[1] = GLClampFloat(g); 1.75 + mColorClearValue[2] = GLClampFloat(b); 1.76 + mColorClearValue[3] = GLClampFloat(a); 1.77 + gl->fClearColor(r, g, b, a); 1.78 +} 1.79 + 1.80 +void 1.81 +WebGLContext::ClearDepth(GLclampf v) 1.82 +{ 1.83 + if (IsContextLost()) 1.84 + return; 1.85 + 1.86 + MakeContextCurrent(); 1.87 + mDepthClearValue = GLClampFloat(v); 1.88 + gl->fClearDepth(v); 1.89 +} 1.90 + 1.91 +void 1.92 +WebGLContext::ClearStencil(GLint v) 1.93 +{ 1.94 + if (IsContextLost()) 1.95 + return; 1.96 + 1.97 + MakeContextCurrent(); 1.98 + mStencilClearValue = v; 1.99 + gl->fClearStencil(v); 1.100 +} 1.101 + 1.102 +void 1.103 +WebGLContext::ColorMask(WebGLboolean r, WebGLboolean g, WebGLboolean b, WebGLboolean a) 1.104 +{ 1.105 + if (IsContextLost()) 1.106 + return; 1.107 + 1.108 + MakeContextCurrent(); 1.109 + mColorWriteMask[0] = r; 1.110 + mColorWriteMask[1] = g; 1.111 + mColorWriteMask[2] = b; 1.112 + mColorWriteMask[3] = a; 1.113 + gl->fColorMask(r, g, b, a); 1.114 +} 1.115 + 1.116 +void 1.117 +WebGLContext::DepthMask(WebGLboolean b) 1.118 +{ 1.119 + if (IsContextLost()) 1.120 + return; 1.121 + 1.122 + MakeContextCurrent(); 1.123 + mDepthWriteMask = b; 1.124 + gl->fDepthMask(b); 1.125 +} 1.126 + 1.127 +void 1.128 +WebGLContext::DrawBuffers(const dom::Sequence<GLenum>& buffers) 1.129 +{ 1.130 + if (IsContextLost()) 1.131 + return; 1.132 + 1.133 + const size_t buffersLength = buffers.Length(); 1.134 + 1.135 + if (buffersLength == 0) { 1.136 + return ErrorInvalidValue("drawBuffers: invalid <buffers> (buffers must not be empty)"); 1.137 + } 1.138 + 1.139 + if (mBoundFramebuffer == 0) 1.140 + { 1.141 + // OK: we are rendering in the default framebuffer 1.142 + 1.143 + /* EXT_draw_buffers : 1.144 + If the GL is bound to the default framebuffer, then <buffersLength> must be 1 1.145 + and the constant must be BACK or NONE. When draw buffer zero is 1.146 + BACK, color values are written into the sole buffer for single- 1.147 + buffered contexts, or into the back buffer for double-buffered 1.148 + contexts. If DrawBuffersEXT is supplied with a constant other than 1.149 + BACK and NONE, the error INVALID_OPERATION is generated. 1.150 + */ 1.151 + if (buffersLength != 1) { 1.152 + return ErrorInvalidValue("drawBuffers: invalid <buffers> (main framebuffer: buffers.length must be 1)"); 1.153 + } 1.154 + 1.155 + MakeContextCurrent(); 1.156 + 1.157 + if (buffers[0] == LOCAL_GL_NONE) { 1.158 + const GLenum drawBuffersCommand = LOCAL_GL_NONE; 1.159 + gl->fDrawBuffers(1, &drawBuffersCommand); 1.160 + return; 1.161 + } 1.162 + else if (buffers[0] == LOCAL_GL_BACK) { 1.163 + const GLenum drawBuffersCommand = LOCAL_GL_COLOR_ATTACHMENT0; 1.164 + gl->fDrawBuffers(1, &drawBuffersCommand); 1.165 + return; 1.166 + } 1.167 + return ErrorInvalidOperation("drawBuffers: invalid operation (main framebuffer: buffers[0] must be GL_NONE or GL_BACK)"); 1.168 + } 1.169 + 1.170 + // OK: we are rendering in a framebuffer object 1.171 + 1.172 + if (buffersLength > size_t(mGLMaxDrawBuffers)) { 1.173 + /* EXT_draw_buffers : 1.174 + The maximum number of draw buffers is implementation-dependent. The 1.175 + number of draw buffers supported can be queried by calling 1.176 + GetIntegerv with the symbolic constant MAX_DRAW_BUFFERS_EXT. An 1.177 + INVALID_VALUE error is generated if <buffersLength> is greater than 1.178 + MAX_DRAW_BUFFERS_EXT. 1.179 + */ 1.180 + return ErrorInvalidValue("drawBuffers: invalid <buffers> (buffers.length > GL_MAX_DRAW_BUFFERS)"); 1.181 + } 1.182 + 1.183 + for (uint32_t i = 0; i < buffersLength; i++) 1.184 + { 1.185 + /* EXT_draw_buffers : 1.186 + If the GL is bound to a draw framebuffer object, the <i>th buffer listed 1.187 + in <bufs> must be COLOR_ATTACHMENT<i>_EXT or NONE. Specifying a 1.188 + buffer out of order, BACK, or COLOR_ATTACHMENT<m>_EXT where <m> is 1.189 + greater than or equal to the value of MAX_COLOR_ATTACHMENTS_EXT, 1.190 + will generate the error INVALID_OPERATION. 1.191 + */ 1.192 + /* WEBGL_draw_buffers : 1.193 + The value of the MAX_COLOR_ATTACHMENTS_WEBGL parameter must be greater than or equal to that of the MAX_DRAW_BUFFERS_WEBGL parameter. 1.194 + */ 1.195 + if (buffers[i] != LOCAL_GL_NONE && 1.196 + buffers[i] != GLenum(LOCAL_GL_COLOR_ATTACHMENT0 + i)) { 1.197 + return ErrorInvalidOperation("drawBuffers: invalid operation (buffers[i] must be GL_NONE or GL_COLOR_ATTACHMENTi)"); 1.198 + } 1.199 + } 1.200 + 1.201 + MakeContextCurrent(); 1.202 + 1.203 + gl->fDrawBuffers(buffersLength, buffers.Elements()); 1.204 +} 1.205 + 1.206 +void 1.207 +WebGLContext::StencilMask(GLuint mask) 1.208 +{ 1.209 + if (IsContextLost()) 1.210 + return; 1.211 + 1.212 + mStencilWriteMaskFront = mask; 1.213 + mStencilWriteMaskBack = mask; 1.214 + 1.215 + MakeContextCurrent(); 1.216 + gl->fStencilMask(mask); 1.217 +} 1.218 + 1.219 +void 1.220 +WebGLContext::StencilMaskSeparate(GLenum face, GLuint mask) 1.221 +{ 1.222 + if (IsContextLost()) 1.223 + return; 1.224 + 1.225 + if (!ValidateFaceEnum(face, "stencilMaskSeparate: face")) 1.226 + return; 1.227 + 1.228 + switch (face) { 1.229 + case LOCAL_GL_FRONT_AND_BACK: 1.230 + mStencilWriteMaskFront = mask; 1.231 + mStencilWriteMaskBack = mask; 1.232 + break; 1.233 + case LOCAL_GL_FRONT: 1.234 + mStencilWriteMaskFront = mask; 1.235 + break; 1.236 + case LOCAL_GL_BACK: 1.237 + mStencilWriteMaskBack = mask; 1.238 + break; 1.239 + } 1.240 + 1.241 + MakeContextCurrent(); 1.242 + gl->fStencilMaskSeparate(face, mask); 1.243 +} 1.244 + 1.245 + 1.246 + 1.247 +