michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "WebGLContext.h" michael@0: #include "WebGLTexture.h" michael@0: #include "WebGLRenderbuffer.h" michael@0: #include "WebGLFramebuffer.h" michael@0: #include "GLContext.h" michael@0: michael@0: using namespace mozilla; michael@0: michael@0: void michael@0: WebGLContext::Clear(GLbitfield mask) michael@0: { michael@0: if (IsContextLost()) michael@0: return; michael@0: michael@0: MakeContextCurrent(); michael@0: michael@0: uint32_t m = mask & (LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT | LOCAL_GL_STENCIL_BUFFER_BIT); michael@0: if (mask != m) michael@0: return ErrorInvalidValue("clear: invalid mask bits"); michael@0: michael@0: if (mask == 0) { michael@0: GenerateWarning("Calling gl.clear(0) has no effect."); michael@0: } else if (mRasterizerDiscardEnabled) { michael@0: GenerateWarning("Calling gl.clear() with RASTERIZER_DISCARD enabled has no effects."); michael@0: } michael@0: michael@0: if (mBoundFramebuffer) { michael@0: if (!mBoundFramebuffer->CheckAndInitializeAttachments()) michael@0: return ErrorInvalidFramebufferOperation("clear: incomplete framebuffer"); michael@0: michael@0: gl->fClear(mask); michael@0: return; michael@0: } else { michael@0: ClearBackbufferIfNeeded(); michael@0: } michael@0: michael@0: // Ok, we're clearing the default framebuffer/screen. michael@0: michael@0: gl->fClear(mask); michael@0: michael@0: Invalidate(); michael@0: mShouldPresent = true; michael@0: } michael@0: michael@0: static GLclampf michael@0: GLClampFloat(GLclampf val) michael@0: { michael@0: if (val < 0.0) michael@0: return 0.0; michael@0: michael@0: if (val > 1.0) michael@0: return 1.0; michael@0: michael@0: return val; michael@0: } michael@0: michael@0: void michael@0: WebGLContext::ClearColor(GLclampf r, GLclampf g, michael@0: GLclampf b, GLclampf a) michael@0: { michael@0: if (IsContextLost()) michael@0: return; michael@0: michael@0: MakeContextCurrent(); michael@0: mColorClearValue[0] = GLClampFloat(r); michael@0: mColorClearValue[1] = GLClampFloat(g); michael@0: mColorClearValue[2] = GLClampFloat(b); michael@0: mColorClearValue[3] = GLClampFloat(a); michael@0: gl->fClearColor(r, g, b, a); michael@0: } michael@0: michael@0: void michael@0: WebGLContext::ClearDepth(GLclampf v) michael@0: { michael@0: if (IsContextLost()) michael@0: return; michael@0: michael@0: MakeContextCurrent(); michael@0: mDepthClearValue = GLClampFloat(v); michael@0: gl->fClearDepth(v); michael@0: } michael@0: michael@0: void michael@0: WebGLContext::ClearStencil(GLint v) michael@0: { michael@0: if (IsContextLost()) michael@0: return; michael@0: michael@0: MakeContextCurrent(); michael@0: mStencilClearValue = v; michael@0: gl->fClearStencil(v); michael@0: } michael@0: michael@0: void michael@0: WebGLContext::ColorMask(WebGLboolean r, WebGLboolean g, WebGLboolean b, WebGLboolean a) michael@0: { michael@0: if (IsContextLost()) michael@0: return; michael@0: michael@0: MakeContextCurrent(); michael@0: mColorWriteMask[0] = r; michael@0: mColorWriteMask[1] = g; michael@0: mColorWriteMask[2] = b; michael@0: mColorWriteMask[3] = a; michael@0: gl->fColorMask(r, g, b, a); michael@0: } michael@0: michael@0: void michael@0: WebGLContext::DepthMask(WebGLboolean b) michael@0: { michael@0: if (IsContextLost()) michael@0: return; michael@0: michael@0: MakeContextCurrent(); michael@0: mDepthWriteMask = b; michael@0: gl->fDepthMask(b); michael@0: } michael@0: michael@0: void michael@0: WebGLContext::DrawBuffers(const dom::Sequence& buffers) michael@0: { michael@0: if (IsContextLost()) michael@0: return; michael@0: michael@0: const size_t buffersLength = buffers.Length(); michael@0: michael@0: if (buffersLength == 0) { michael@0: return ErrorInvalidValue("drawBuffers: invalid (buffers must not be empty)"); michael@0: } michael@0: michael@0: if (mBoundFramebuffer == 0) michael@0: { michael@0: // OK: we are rendering in the default framebuffer michael@0: michael@0: /* EXT_draw_buffers : michael@0: If the GL is bound to the default framebuffer, then must be 1 michael@0: and the constant must be BACK or NONE. When draw buffer zero is michael@0: BACK, color values are written into the sole buffer for single- michael@0: buffered contexts, or into the back buffer for double-buffered michael@0: contexts. If DrawBuffersEXT is supplied with a constant other than michael@0: BACK and NONE, the error INVALID_OPERATION is generated. michael@0: */ michael@0: if (buffersLength != 1) { michael@0: return ErrorInvalidValue("drawBuffers: invalid (main framebuffer: buffers.length must be 1)"); michael@0: } michael@0: michael@0: MakeContextCurrent(); michael@0: michael@0: if (buffers[0] == LOCAL_GL_NONE) { michael@0: const GLenum drawBuffersCommand = LOCAL_GL_NONE; michael@0: gl->fDrawBuffers(1, &drawBuffersCommand); michael@0: return; michael@0: } michael@0: else if (buffers[0] == LOCAL_GL_BACK) { michael@0: const GLenum drawBuffersCommand = LOCAL_GL_COLOR_ATTACHMENT0; michael@0: gl->fDrawBuffers(1, &drawBuffersCommand); michael@0: return; michael@0: } michael@0: return ErrorInvalidOperation("drawBuffers: invalid operation (main framebuffer: buffers[0] must be GL_NONE or GL_BACK)"); michael@0: } michael@0: michael@0: // OK: we are rendering in a framebuffer object michael@0: michael@0: if (buffersLength > size_t(mGLMaxDrawBuffers)) { michael@0: /* EXT_draw_buffers : michael@0: The maximum number of draw buffers is implementation-dependent. The michael@0: number of draw buffers supported can be queried by calling michael@0: GetIntegerv with the symbolic constant MAX_DRAW_BUFFERS_EXT. An michael@0: INVALID_VALUE error is generated if is greater than michael@0: MAX_DRAW_BUFFERS_EXT. michael@0: */ michael@0: return ErrorInvalidValue("drawBuffers: invalid (buffers.length > GL_MAX_DRAW_BUFFERS)"); michael@0: } michael@0: michael@0: for (uint32_t i = 0; i < buffersLength; i++) michael@0: { michael@0: /* EXT_draw_buffers : michael@0: If the GL is bound to a draw framebuffer object, the th buffer listed michael@0: in must be COLOR_ATTACHMENT_EXT or NONE. Specifying a michael@0: buffer out of order, BACK, or COLOR_ATTACHMENT_EXT where is michael@0: greater than or equal to the value of MAX_COLOR_ATTACHMENTS_EXT, michael@0: will generate the error INVALID_OPERATION. michael@0: */ michael@0: /* WEBGL_draw_buffers : michael@0: The value of the MAX_COLOR_ATTACHMENTS_WEBGL parameter must be greater than or equal to that of the MAX_DRAW_BUFFERS_WEBGL parameter. michael@0: */ michael@0: if (buffers[i] != LOCAL_GL_NONE && michael@0: buffers[i] != GLenum(LOCAL_GL_COLOR_ATTACHMENT0 + i)) { michael@0: return ErrorInvalidOperation("drawBuffers: invalid operation (buffers[i] must be GL_NONE or GL_COLOR_ATTACHMENTi)"); michael@0: } michael@0: } michael@0: michael@0: MakeContextCurrent(); michael@0: michael@0: gl->fDrawBuffers(buffersLength, buffers.Elements()); michael@0: } michael@0: michael@0: void michael@0: WebGLContext::StencilMask(GLuint mask) michael@0: { michael@0: if (IsContextLost()) michael@0: return; michael@0: michael@0: mStencilWriteMaskFront = mask; michael@0: mStencilWriteMaskBack = mask; michael@0: michael@0: MakeContextCurrent(); michael@0: gl->fStencilMask(mask); michael@0: } michael@0: michael@0: void michael@0: WebGLContext::StencilMaskSeparate(GLenum face, GLuint mask) michael@0: { michael@0: if (IsContextLost()) michael@0: return; michael@0: michael@0: if (!ValidateFaceEnum(face, "stencilMaskSeparate: face")) michael@0: return; michael@0: michael@0: switch (face) { michael@0: case LOCAL_GL_FRONT_AND_BACK: michael@0: mStencilWriteMaskFront = mask; michael@0: mStencilWriteMaskBack = mask; michael@0: break; michael@0: case LOCAL_GL_FRONT: michael@0: mStencilWriteMaskFront = mask; michael@0: break; michael@0: case LOCAL_GL_BACK: michael@0: mStencilWriteMaskBack = mask; michael@0: break; michael@0: } michael@0: michael@0: MakeContextCurrent(); michael@0: gl->fStencilMaskSeparate(face, mask); michael@0: } michael@0: michael@0: michael@0: michael@0: