Merge mozilla-central to autoland on a CLOSED TREE
[gecko.git] / dom / canvas / WebGL2ContextFramebuffers.cpp
blob7056c83d03a0c6e175ae5e2a4a2eb09ac26dca7e
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/. */
6 #include "WebGL2Context.h"
8 #include "GLContext.h"
9 #include "GLScreenBuffer.h"
10 #include "mozilla/CheckedInt.h"
11 #include "WebGLContextUtils.h"
12 #include "WebGLFormats.h"
13 #include "WebGLFramebuffer.h"
15 namespace mozilla {
17 void WebGL2Context::BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1,
18 GLint srcY1, GLint dstX0, GLint dstY0,
19 GLint dstX1, GLint dstY1, GLbitfield mask,
20 GLenum filter) {
21 const FuncScope funcScope(*this, "blitFramebuffer");
22 if (IsContextLost()) return;
24 const GLbitfield validBits = LOCAL_GL_COLOR_BUFFER_BIT |
25 LOCAL_GL_DEPTH_BUFFER_BIT |
26 LOCAL_GL_STENCIL_BUFFER_BIT;
27 if ((mask | validBits) != validBits) {
28 ErrorInvalidValue("Invalid bit set in mask.");
29 return;
32 switch (filter) {
33 case LOCAL_GL_NEAREST:
34 case LOCAL_GL_LINEAR:
35 break;
36 default:
37 ErrorInvalidEnumInfo("filter", filter);
38 return;
41 // --
43 const auto fnLikelyOverflow = [](GLint p0, GLint p1) {
44 auto checked = CheckedInt<GLint>(p1) - p0;
45 checked = -checked; // And check the negation!
46 return !checked.isValid();
49 if (fnLikelyOverflow(srcX0, srcX1) || fnLikelyOverflow(srcY0, srcY1) ||
50 fnLikelyOverflow(dstX0, dstX1) || fnLikelyOverflow(dstY0, dstY1)) {
51 ErrorInvalidValue("Likely-to-overflow large ranges are forbidden.");
52 return;
55 // --
57 if (!ValidateAndInitFB(mBoundReadFramebuffer) ||
58 !ValidateAndInitFB(mBoundDrawFramebuffer)) {
59 return;
62 DoBindFB(mBoundReadFramebuffer, LOCAL_GL_READ_FRAMEBUFFER);
63 DoBindFB(mBoundDrawFramebuffer, LOCAL_GL_DRAW_FRAMEBUFFER);
65 WebGLFramebuffer::BlitFramebuffer(this, srcX0, srcY0, srcX1, srcY1, dstX0,
66 dstY0, dstX1, dstY1, mask, filter);
69 ////
71 static bool ValidateBackbufferAttachmentEnum(WebGLContext* webgl,
72 GLenum attachment) {
73 switch (attachment) {
74 case LOCAL_GL_COLOR:
75 case LOCAL_GL_DEPTH:
76 case LOCAL_GL_STENCIL:
77 return true;
79 default:
80 webgl->ErrorInvalidEnumInfo("attachment", attachment);
81 return false;
85 static bool ValidateFramebufferAttachmentEnum(WebGLContext* webgl,
86 GLenum attachment) {
87 switch (attachment) {
88 case LOCAL_GL_DEPTH_ATTACHMENT:
89 case LOCAL_GL_STENCIL_ATTACHMENT:
90 case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT:
91 return true;
94 if (attachment < LOCAL_GL_COLOR_ATTACHMENT0) {
95 webgl->ErrorInvalidEnumInfo("attachment", attachment);
96 return false;
99 if (attachment > webgl->LastColorAttachmentEnum()) {
100 // That these errors have different types is ridiculous.
101 webgl->ErrorInvalidOperation("Too-large LOCAL_GL_COLOR_ATTACHMENTn.");
102 return false;
105 return true;
108 bool WebGLContext::ValidateInvalidateFramebuffer(
109 GLenum target, const Range<const GLenum>& attachments,
110 std::vector<GLenum>* const scopedVector,
111 GLsizei* const out_glNumAttachments,
112 const GLenum** const out_glAttachments) {
113 if (IsContextLost()) return false;
115 if (!ValidateFramebufferTarget(target)) return false;
117 const WebGLFramebuffer* fb;
118 bool isDefaultFB = false;
119 switch (target) {
120 case LOCAL_GL_FRAMEBUFFER:
121 case LOCAL_GL_DRAW_FRAMEBUFFER:
122 fb = mBoundDrawFramebuffer;
123 break;
125 case LOCAL_GL_READ_FRAMEBUFFER:
126 fb = mBoundReadFramebuffer;
127 break;
129 default:
130 MOZ_CRASH("GFX: Bad target.");
133 if (fb) {
134 const auto fbStatus = fb->CheckFramebufferStatus();
135 if (fbStatus != LOCAL_GL_FRAMEBUFFER_COMPLETE)
136 return false; // Not an error, but don't run forward to driver either.
137 } else {
138 if (!EnsureDefaultFB()) return false;
140 DoBindFB(fb, target);
142 *out_glNumAttachments = attachments.length();
143 *out_glAttachments = attachments.begin().get();
145 if (fb) {
146 for (const auto& attachment : attachments) {
147 if (!ValidateFramebufferAttachmentEnum(this, attachment)) return false;
149 } else {
150 for (const auto& attachment : attachments) {
151 if (!ValidateBackbufferAttachmentEnum(this, attachment)) return false;
154 if (!isDefaultFB) {
155 MOZ_ASSERT(scopedVector->empty());
156 scopedVector->reserve(attachments.length());
157 for (const auto& attachment : attachments) {
158 switch (attachment) {
159 case LOCAL_GL_COLOR:
160 scopedVector->push_back(LOCAL_GL_COLOR_ATTACHMENT0);
161 break;
163 case LOCAL_GL_DEPTH:
164 scopedVector->push_back(LOCAL_GL_DEPTH_ATTACHMENT);
165 break;
167 case LOCAL_GL_STENCIL:
168 scopedVector->push_back(LOCAL_GL_STENCIL_ATTACHMENT);
169 break;
171 default:
172 MOZ_CRASH();
175 *out_glNumAttachments = scopedVector->size();
176 *out_glAttachments = scopedVector->data();
180 ////
182 return true;
185 void WebGL2Context::InvalidateFramebuffer(
186 GLenum target, const Range<const GLenum>& attachments) {
187 const FuncScope funcScope(*this, "invalidateFramebuffer");
189 std::vector<GLenum> scopedVector;
190 GLsizei glNumAttachments;
191 const GLenum* glAttachments;
192 if (!ValidateInvalidateFramebuffer(target, attachments, &scopedVector,
193 &glNumAttachments, &glAttachments)) {
194 return;
197 ////
199 // Some drivers (like OSX 10.9 GL) just don't support invalidate_framebuffer.
200 const bool useFBInvalidation =
201 (mAllowFBInvalidation &&
202 gl->IsSupported(gl::GLFeature::invalidate_framebuffer));
203 if (useFBInvalidation) {
204 gl->fInvalidateFramebuffer(target, glNumAttachments, glAttachments);
205 return;
208 // Use clear instead?
209 // No-op for now.
212 void WebGL2Context::InvalidateSubFramebuffer(
213 GLenum target, const Range<const GLenum>& attachments, GLint x, GLint y,
214 GLsizei width, GLsizei height) {
215 const FuncScope funcScope(*this, "invalidateSubFramebuffer");
217 std::vector<GLenum> scopedVector;
218 GLsizei glNumAttachments;
219 const GLenum* glAttachments;
220 if (!ValidateInvalidateFramebuffer(target, attachments, &scopedVector,
221 &glNumAttachments, &glAttachments)) {
222 return;
225 if (!ValidateNonNegative("width", width) ||
226 !ValidateNonNegative("height", height)) {
227 return;
230 ////
232 // Some drivers (like OSX 10.9 GL) just don't support invalidate_framebuffer.
233 const bool useFBInvalidation =
234 (mAllowFBInvalidation &&
235 gl->IsSupported(gl::GLFeature::invalidate_framebuffer));
236 if (useFBInvalidation) {
237 gl->fInvalidateSubFramebuffer(target, glNumAttachments, glAttachments, x, y,
238 width, height);
239 return;
242 // Use clear instead?
243 // No-op for now.
246 void WebGL2Context::ReadBuffer(GLenum mode) {
247 const FuncScope funcScope(*this, "readBuffer");
248 if (IsContextLost()) return;
250 if (mBoundReadFramebuffer) {
251 mBoundReadFramebuffer->ReadBuffer(mode);
252 return;
255 // Operating on the default framebuffer.
256 if (mode != LOCAL_GL_NONE && mode != LOCAL_GL_BACK) {
257 nsCString enumName;
258 EnumName(mode, &enumName);
259 ErrorInvalidOperation(
260 "If READ_FRAMEBUFFER is null, `mode` must be BACK or"
261 " NONE. Was %s.",
262 enumName.BeginReading());
263 return;
266 mDefaultFB_ReadBuffer = mode;
269 } // namespace mozilla