Line data Source code
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 "WebGL2Context.h"
7 :
8 : #include "GLContext.h"
9 : #include "GLScreenBuffer.h"
10 : #include "WebGLContextUtils.h"
11 : #include "WebGLFormats.h"
12 : #include "WebGLFramebuffer.h"
13 :
14 : namespace mozilla {
15 :
16 : void
17 0 : WebGL2Context::BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
18 : GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
19 : GLbitfield mask, GLenum filter)
20 : {
21 0 : if (IsContextLost())
22 0 : return;
23 :
24 : const GLbitfield validBits = LOCAL_GL_COLOR_BUFFER_BIT |
25 : LOCAL_GL_DEPTH_BUFFER_BIT |
26 0 : LOCAL_GL_STENCIL_BUFFER_BIT;
27 0 : if ((mask | validBits) != validBits) {
28 0 : ErrorInvalidValue("blitFramebuffer: Invalid bit set in mask.");
29 0 : return;
30 : }
31 :
32 0 : switch (filter) {
33 : case LOCAL_GL_NEAREST:
34 : case LOCAL_GL_LINEAR:
35 0 : break;
36 : default:
37 0 : ErrorInvalidEnumInfo("blitFramebuffer: Bad `filter`:", filter);
38 0 : return;
39 : }
40 :
41 : ////
42 :
43 0 : const auto& readFB = mBoundReadFramebuffer;
44 0 : if (readFB &&
45 0 : !readFB->ValidateAndInitAttachments("blitFramebuffer's READ_FRAMEBUFFER"))
46 : {
47 0 : return;
48 : }
49 :
50 0 : const auto& drawFB = mBoundDrawFramebuffer;
51 0 : if (drawFB &&
52 0 : !drawFB->ValidateAndInitAttachments("blitFramebuffer's DRAW_FRAMEBUFFER"))
53 : {
54 0 : return;
55 : }
56 :
57 : ////
58 :
59 0 : if (!mBoundReadFramebuffer) {
60 0 : ClearBackbufferIfNeeded();
61 : }
62 :
63 0 : WebGLFramebuffer::BlitFramebuffer(this,
64 : readFB, srcX0, srcY0, srcX1, srcY1,
65 : drawFB, dstX0, dstY0, dstX1, dstY1,
66 0 : mask, filter);
67 : }
68 :
69 : void
70 0 : WebGL2Context::FramebufferTextureLayer(GLenum target, GLenum attachment,
71 : WebGLTexture* texture, GLint level, GLint layer)
72 : {
73 0 : const char funcName[] = "framebufferTextureLayer";
74 0 : if (IsContextLost())
75 0 : return;
76 :
77 0 : if (!ValidateFramebufferTarget(target, funcName))
78 0 : return;
79 :
80 : WebGLFramebuffer* fb;
81 0 : switch (target) {
82 : case LOCAL_GL_FRAMEBUFFER:
83 : case LOCAL_GL_DRAW_FRAMEBUFFER:
84 0 : fb = mBoundDrawFramebuffer;
85 0 : break;
86 :
87 : case LOCAL_GL_READ_FRAMEBUFFER:
88 0 : fb = mBoundReadFramebuffer;
89 0 : break;
90 :
91 : default:
92 0 : MOZ_CRASH("GFX: Bad target.");
93 : }
94 :
95 0 : if (!fb)
96 0 : return ErrorInvalidOperation("%s: Cannot modify framebuffer 0.", funcName);
97 :
98 0 : fb->FramebufferTextureLayer(funcName, attachment, texture, level, layer);
99 : }
100 :
101 : JS::Value
102 0 : WebGL2Context::GetFramebufferAttachmentParameter(JSContext* cx,
103 : GLenum target,
104 : GLenum attachment,
105 : GLenum pname,
106 : ErrorResult& out_error)
107 : {
108 : return WebGLContext::GetFramebufferAttachmentParameter(cx, target, attachment, pname,
109 0 : out_error);
110 : }
111 :
112 : ////
113 :
114 : static bool
115 0 : ValidateBackbufferAttachmentEnum(WebGLContext* webgl, const char* funcName,
116 : GLenum attachment)
117 : {
118 0 : switch (attachment) {
119 : case LOCAL_GL_COLOR:
120 : case LOCAL_GL_DEPTH:
121 : case LOCAL_GL_STENCIL:
122 0 : return true;
123 :
124 : default:
125 : webgl->ErrorInvalidEnum("%s: attachment: invalid enum value 0x%x.",
126 0 : funcName, attachment);
127 0 : return false;
128 : }
129 : }
130 :
131 : static bool
132 0 : ValidateFramebufferAttachmentEnum(WebGLContext* webgl, const char* funcName,
133 : GLenum attachment)
134 : {
135 0 : switch (attachment) {
136 : case LOCAL_GL_DEPTH_ATTACHMENT:
137 : case LOCAL_GL_STENCIL_ATTACHMENT:
138 : case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT:
139 0 : return true;
140 : }
141 :
142 0 : if (attachment < LOCAL_GL_COLOR_ATTACHMENT0) {
143 : webgl->ErrorInvalidEnum("%s: attachment: invalid enum value 0x%x.",
144 0 : funcName, attachment);
145 0 : return false;
146 : }
147 :
148 0 : if (attachment > webgl->LastColorAttachmentEnum()) {
149 : // That these errors have different types is ridiculous.
150 : webgl->ErrorInvalidOperation("%s: Too-large LOCAL_GL_COLOR_ATTACHMENTn.",
151 0 : funcName);
152 0 : return false;
153 : }
154 :
155 0 : return true;
156 : }
157 :
158 : bool
159 0 : WebGLContext::ValidateInvalidateFramebuffer(const char* funcName, GLenum target,
160 : const dom::Sequence<GLenum>& attachments,
161 : ErrorResult* const out_rv,
162 : std::vector<GLenum>* const scopedVector,
163 : GLsizei* const out_glNumAttachments,
164 : const GLenum** const out_glAttachments)
165 : {
166 0 : if (IsContextLost())
167 0 : return false;
168 :
169 0 : gl->MakeCurrent();
170 :
171 0 : if (!ValidateFramebufferTarget(target, funcName))
172 0 : return false;
173 :
174 : const WebGLFramebuffer* fb;
175 : bool isDefaultFB;
176 0 : switch (target) {
177 : case LOCAL_GL_FRAMEBUFFER:
178 : case LOCAL_GL_DRAW_FRAMEBUFFER:
179 0 : fb = mBoundDrawFramebuffer;
180 0 : isDefaultFB = gl->Screen()->IsDrawFramebufferDefault();
181 0 : break;
182 :
183 : case LOCAL_GL_READ_FRAMEBUFFER:
184 0 : fb = mBoundReadFramebuffer;
185 0 : isDefaultFB = gl->Screen()->IsReadFramebufferDefault();
186 0 : break;
187 :
188 : default:
189 0 : MOZ_CRASH("GFX: Bad target.");
190 : }
191 :
192 0 : *out_glNumAttachments = attachments.Length();
193 0 : *out_glAttachments = attachments.Elements();
194 :
195 0 : if (fb) {
196 0 : for (const auto& attachment : attachments) {
197 0 : if (!ValidateFramebufferAttachmentEnum(this, funcName, attachment))
198 0 : return false;
199 : }
200 : } else {
201 0 : for (const auto& attachment : attachments) {
202 0 : if (!ValidateBackbufferAttachmentEnum(this, funcName, attachment))
203 0 : return false;
204 : }
205 :
206 0 : if (!isDefaultFB) {
207 0 : MOZ_ASSERT(scopedVector->empty());
208 0 : scopedVector->reserve(attachments.Length());
209 0 : for (const auto& attachment : attachments) {
210 0 : switch (attachment) {
211 : case LOCAL_GL_COLOR:
212 0 : scopedVector->push_back(LOCAL_GL_COLOR_ATTACHMENT0);
213 0 : break;
214 :
215 : case LOCAL_GL_DEPTH:
216 0 : scopedVector->push_back(LOCAL_GL_DEPTH_ATTACHMENT);
217 0 : break;
218 :
219 : case LOCAL_GL_STENCIL:
220 0 : scopedVector->push_back(LOCAL_GL_STENCIL_ATTACHMENT);
221 0 : break;
222 :
223 : default:
224 0 : MOZ_CRASH();
225 : }
226 : }
227 0 : *out_glNumAttachments = scopedVector->size();
228 0 : *out_glAttachments = scopedVector->data();
229 : }
230 : }
231 :
232 : ////
233 :
234 0 : if (!fb) {
235 0 : ClearBackbufferIfNeeded();
236 :
237 : // Don't do more validation after these.
238 0 : Invalidate();
239 0 : mShouldPresent = true;
240 : }
241 :
242 0 : return true;
243 : }
244 :
245 : void
246 0 : WebGL2Context::InvalidateFramebuffer(GLenum target,
247 : const dom::Sequence<GLenum>& attachments,
248 : ErrorResult& rv)
249 : {
250 0 : const char funcName[] = "invalidateSubFramebuffer";
251 :
252 0 : std::vector<GLenum> scopedVector;
253 : GLsizei glNumAttachments;
254 : const GLenum* glAttachments;
255 0 : if (!ValidateInvalidateFramebuffer(funcName, target, attachments, &rv, &scopedVector,
256 : &glNumAttachments, &glAttachments))
257 : {
258 0 : return;
259 : }
260 :
261 : ////
262 :
263 : // Some drivers (like OSX 10.9 GL) just don't support invalidate_framebuffer.
264 0 : const bool useFBInvalidation = (mAllowFBInvalidation &&
265 0 : gl->IsSupported(gl::GLFeature::invalidate_framebuffer));
266 0 : if (useFBInvalidation) {
267 0 : gl->fInvalidateFramebuffer(target, glNumAttachments, glAttachments);
268 0 : return;
269 : }
270 :
271 : // Use clear instead?
272 : // No-op for now.
273 : }
274 :
275 : void
276 0 : WebGL2Context::InvalidateSubFramebuffer(GLenum target, const dom::Sequence<GLenum>& attachments,
277 : GLint x, GLint y, GLsizei width, GLsizei height,
278 : ErrorResult& rv)
279 : {
280 0 : const char funcName[] = "invalidateSubFramebuffer";
281 :
282 0 : if (!ValidateNonNegative(funcName, "width", width) ||
283 0 : !ValidateNonNegative(funcName, "height", height))
284 : {
285 0 : return;
286 : }
287 :
288 0 : std::vector<GLenum> scopedVector;
289 : GLsizei glNumAttachments;
290 : const GLenum* glAttachments;
291 0 : if (!ValidateInvalidateFramebuffer(funcName, target, attachments, &rv, &scopedVector,
292 : &glNumAttachments, &glAttachments))
293 : {
294 0 : return;
295 : }
296 :
297 : ////
298 :
299 : // Some drivers (like OSX 10.9 GL) just don't support invalidate_framebuffer.
300 0 : const bool useFBInvalidation = (mAllowFBInvalidation &&
301 0 : gl->IsSupported(gl::GLFeature::invalidate_framebuffer));
302 0 : if (useFBInvalidation) {
303 0 : gl->fInvalidateSubFramebuffer(target, glNumAttachments, glAttachments, x, y,
304 0 : width, height);
305 0 : return;
306 : }
307 :
308 : // Use clear instead?
309 : // No-op for now.
310 : }
311 :
312 : void
313 0 : WebGL2Context::ReadBuffer(GLenum mode)
314 : {
315 0 : const char funcName[] = "readBuffer";
316 0 : if (IsContextLost())
317 0 : return;
318 :
319 0 : if (mBoundReadFramebuffer) {
320 0 : mBoundReadFramebuffer->ReadBuffer(funcName, mode);
321 0 : return;
322 : }
323 :
324 : // Operating on the default framebuffer.
325 0 : if (mode != LOCAL_GL_NONE &&
326 : mode != LOCAL_GL_BACK)
327 : {
328 0 : nsCString enumName;
329 0 : EnumName(mode, &enumName);
330 0 : ErrorInvalidOperation("%s: If READ_FRAMEBUFFER is null, `mode` must be BACK or"
331 : " NONE. Was %s.",
332 0 : funcName, enumName.BeginReading());
333 0 : return;
334 : }
335 :
336 0 : gl->Screen()->SetReadBuffer(mode);
337 : }
338 :
339 : } // namespace mozilla
|