|
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
|
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 "WebGLContext.h" |
|
7 #include "WebGLTexture.h" |
|
8 #include "WebGLRenderbuffer.h" |
|
9 #include "WebGLFramebuffer.h" |
|
10 #include "GLContext.h" |
|
11 |
|
12 using namespace mozilla; |
|
13 |
|
14 void |
|
15 WebGLContext::Clear(GLbitfield mask) |
|
16 { |
|
17 if (IsContextLost()) |
|
18 return; |
|
19 |
|
20 MakeContextCurrent(); |
|
21 |
|
22 uint32_t m = mask & (LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT | LOCAL_GL_STENCIL_BUFFER_BIT); |
|
23 if (mask != m) |
|
24 return ErrorInvalidValue("clear: invalid mask bits"); |
|
25 |
|
26 if (mask == 0) { |
|
27 GenerateWarning("Calling gl.clear(0) has no effect."); |
|
28 } else if (mRasterizerDiscardEnabled) { |
|
29 GenerateWarning("Calling gl.clear() with RASTERIZER_DISCARD enabled has no effects."); |
|
30 } |
|
31 |
|
32 if (mBoundFramebuffer) { |
|
33 if (!mBoundFramebuffer->CheckAndInitializeAttachments()) |
|
34 return ErrorInvalidFramebufferOperation("clear: incomplete framebuffer"); |
|
35 |
|
36 gl->fClear(mask); |
|
37 return; |
|
38 } else { |
|
39 ClearBackbufferIfNeeded(); |
|
40 } |
|
41 |
|
42 // Ok, we're clearing the default framebuffer/screen. |
|
43 |
|
44 gl->fClear(mask); |
|
45 |
|
46 Invalidate(); |
|
47 mShouldPresent = true; |
|
48 } |
|
49 |
|
50 static GLclampf |
|
51 GLClampFloat(GLclampf val) |
|
52 { |
|
53 if (val < 0.0) |
|
54 return 0.0; |
|
55 |
|
56 if (val > 1.0) |
|
57 return 1.0; |
|
58 |
|
59 return val; |
|
60 } |
|
61 |
|
62 void |
|
63 WebGLContext::ClearColor(GLclampf r, GLclampf g, |
|
64 GLclampf b, GLclampf a) |
|
65 { |
|
66 if (IsContextLost()) |
|
67 return; |
|
68 |
|
69 MakeContextCurrent(); |
|
70 mColorClearValue[0] = GLClampFloat(r); |
|
71 mColorClearValue[1] = GLClampFloat(g); |
|
72 mColorClearValue[2] = GLClampFloat(b); |
|
73 mColorClearValue[3] = GLClampFloat(a); |
|
74 gl->fClearColor(r, g, b, a); |
|
75 } |
|
76 |
|
77 void |
|
78 WebGLContext::ClearDepth(GLclampf v) |
|
79 { |
|
80 if (IsContextLost()) |
|
81 return; |
|
82 |
|
83 MakeContextCurrent(); |
|
84 mDepthClearValue = GLClampFloat(v); |
|
85 gl->fClearDepth(v); |
|
86 } |
|
87 |
|
88 void |
|
89 WebGLContext::ClearStencil(GLint v) |
|
90 { |
|
91 if (IsContextLost()) |
|
92 return; |
|
93 |
|
94 MakeContextCurrent(); |
|
95 mStencilClearValue = v; |
|
96 gl->fClearStencil(v); |
|
97 } |
|
98 |
|
99 void |
|
100 WebGLContext::ColorMask(WebGLboolean r, WebGLboolean g, WebGLboolean b, WebGLboolean a) |
|
101 { |
|
102 if (IsContextLost()) |
|
103 return; |
|
104 |
|
105 MakeContextCurrent(); |
|
106 mColorWriteMask[0] = r; |
|
107 mColorWriteMask[1] = g; |
|
108 mColorWriteMask[2] = b; |
|
109 mColorWriteMask[3] = a; |
|
110 gl->fColorMask(r, g, b, a); |
|
111 } |
|
112 |
|
113 void |
|
114 WebGLContext::DepthMask(WebGLboolean b) |
|
115 { |
|
116 if (IsContextLost()) |
|
117 return; |
|
118 |
|
119 MakeContextCurrent(); |
|
120 mDepthWriteMask = b; |
|
121 gl->fDepthMask(b); |
|
122 } |
|
123 |
|
124 void |
|
125 WebGLContext::DrawBuffers(const dom::Sequence<GLenum>& buffers) |
|
126 { |
|
127 if (IsContextLost()) |
|
128 return; |
|
129 |
|
130 const size_t buffersLength = buffers.Length(); |
|
131 |
|
132 if (buffersLength == 0) { |
|
133 return ErrorInvalidValue("drawBuffers: invalid <buffers> (buffers must not be empty)"); |
|
134 } |
|
135 |
|
136 if (mBoundFramebuffer == 0) |
|
137 { |
|
138 // OK: we are rendering in the default framebuffer |
|
139 |
|
140 /* EXT_draw_buffers : |
|
141 If the GL is bound to the default framebuffer, then <buffersLength> must be 1 |
|
142 and the constant must be BACK or NONE. When draw buffer zero is |
|
143 BACK, color values are written into the sole buffer for single- |
|
144 buffered contexts, or into the back buffer for double-buffered |
|
145 contexts. If DrawBuffersEXT is supplied with a constant other than |
|
146 BACK and NONE, the error INVALID_OPERATION is generated. |
|
147 */ |
|
148 if (buffersLength != 1) { |
|
149 return ErrorInvalidValue("drawBuffers: invalid <buffers> (main framebuffer: buffers.length must be 1)"); |
|
150 } |
|
151 |
|
152 MakeContextCurrent(); |
|
153 |
|
154 if (buffers[0] == LOCAL_GL_NONE) { |
|
155 const GLenum drawBuffersCommand = LOCAL_GL_NONE; |
|
156 gl->fDrawBuffers(1, &drawBuffersCommand); |
|
157 return; |
|
158 } |
|
159 else if (buffers[0] == LOCAL_GL_BACK) { |
|
160 const GLenum drawBuffersCommand = LOCAL_GL_COLOR_ATTACHMENT0; |
|
161 gl->fDrawBuffers(1, &drawBuffersCommand); |
|
162 return; |
|
163 } |
|
164 return ErrorInvalidOperation("drawBuffers: invalid operation (main framebuffer: buffers[0] must be GL_NONE or GL_BACK)"); |
|
165 } |
|
166 |
|
167 // OK: we are rendering in a framebuffer object |
|
168 |
|
169 if (buffersLength > size_t(mGLMaxDrawBuffers)) { |
|
170 /* EXT_draw_buffers : |
|
171 The maximum number of draw buffers is implementation-dependent. The |
|
172 number of draw buffers supported can be queried by calling |
|
173 GetIntegerv with the symbolic constant MAX_DRAW_BUFFERS_EXT. An |
|
174 INVALID_VALUE error is generated if <buffersLength> is greater than |
|
175 MAX_DRAW_BUFFERS_EXT. |
|
176 */ |
|
177 return ErrorInvalidValue("drawBuffers: invalid <buffers> (buffers.length > GL_MAX_DRAW_BUFFERS)"); |
|
178 } |
|
179 |
|
180 for (uint32_t i = 0; i < buffersLength; i++) |
|
181 { |
|
182 /* EXT_draw_buffers : |
|
183 If the GL is bound to a draw framebuffer object, the <i>th buffer listed |
|
184 in <bufs> must be COLOR_ATTACHMENT<i>_EXT or NONE. Specifying a |
|
185 buffer out of order, BACK, or COLOR_ATTACHMENT<m>_EXT where <m> is |
|
186 greater than or equal to the value of MAX_COLOR_ATTACHMENTS_EXT, |
|
187 will generate the error INVALID_OPERATION. |
|
188 */ |
|
189 /* WEBGL_draw_buffers : |
|
190 The value of the MAX_COLOR_ATTACHMENTS_WEBGL parameter must be greater than or equal to that of the MAX_DRAW_BUFFERS_WEBGL parameter. |
|
191 */ |
|
192 if (buffers[i] != LOCAL_GL_NONE && |
|
193 buffers[i] != GLenum(LOCAL_GL_COLOR_ATTACHMENT0 + i)) { |
|
194 return ErrorInvalidOperation("drawBuffers: invalid operation (buffers[i] must be GL_NONE or GL_COLOR_ATTACHMENTi)"); |
|
195 } |
|
196 } |
|
197 |
|
198 MakeContextCurrent(); |
|
199 |
|
200 gl->fDrawBuffers(buffersLength, buffers.Elements()); |
|
201 } |
|
202 |
|
203 void |
|
204 WebGLContext::StencilMask(GLuint mask) |
|
205 { |
|
206 if (IsContextLost()) |
|
207 return; |
|
208 |
|
209 mStencilWriteMaskFront = mask; |
|
210 mStencilWriteMaskBack = mask; |
|
211 |
|
212 MakeContextCurrent(); |
|
213 gl->fStencilMask(mask); |
|
214 } |
|
215 |
|
216 void |
|
217 WebGLContext::StencilMaskSeparate(GLenum face, GLuint mask) |
|
218 { |
|
219 if (IsContextLost()) |
|
220 return; |
|
221 |
|
222 if (!ValidateFaceEnum(face, "stencilMaskSeparate: face")) |
|
223 return; |
|
224 |
|
225 switch (face) { |
|
226 case LOCAL_GL_FRONT_AND_BACK: |
|
227 mStencilWriteMaskFront = mask; |
|
228 mStencilWriteMaskBack = mask; |
|
229 break; |
|
230 case LOCAL_GL_FRONT: |
|
231 mStencilWriteMaskFront = mask; |
|
232 break; |
|
233 case LOCAL_GL_BACK: |
|
234 mStencilWriteMaskBack = mask; |
|
235 break; |
|
236 } |
|
237 |
|
238 MakeContextCurrent(); |
|
239 gl->fStencilMaskSeparate(face, mask); |
|
240 } |
|
241 |
|
242 |
|
243 |
|
244 |