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"
9 #include "GLScreenBuffer.h"
10 #include "mozilla/CheckedInt.h"
11 #include "WebGLContextUtils.h"
12 #include "WebGLFormats.h"
13 #include "WebGLFramebuffer.h"
17 void WebGL2Context::BlitFramebuffer(GLint srcX0
, GLint srcY0
, GLint srcX1
,
18 GLint srcY1
, GLint dstX0
, GLint dstY0
,
19 GLint dstX1
, GLint dstY1
, GLbitfield mask
,
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.");
33 case LOCAL_GL_NEAREST
:
37 ErrorInvalidEnumInfo("filter", filter
);
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.");
57 if (!ValidateAndInitFB(mBoundReadFramebuffer
) ||
58 !ValidateAndInitFB(mBoundDrawFramebuffer
)) {
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
);
71 static bool ValidateBackbufferAttachmentEnum(WebGLContext
* webgl
,
76 case LOCAL_GL_STENCIL
:
80 webgl
->ErrorInvalidEnumInfo("attachment", attachment
);
85 static bool ValidateFramebufferAttachmentEnum(WebGLContext
* webgl
,
88 case LOCAL_GL_DEPTH_ATTACHMENT
:
89 case LOCAL_GL_STENCIL_ATTACHMENT
:
90 case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT
:
94 if (attachment
< LOCAL_GL_COLOR_ATTACHMENT0
) {
95 webgl
->ErrorInvalidEnumInfo("attachment", attachment
);
99 if (attachment
> webgl
->LastColorAttachmentEnum()) {
100 // That these errors have different types is ridiculous.
101 webgl
->ErrorInvalidOperation("Too-large LOCAL_GL_COLOR_ATTACHMENTn.");
108 bool WebGLContext::ValidateInvalidateFramebuffer(
109 GLenum target
, const Span
<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;
120 case LOCAL_GL_FRAMEBUFFER
:
121 case LOCAL_GL_DRAW_FRAMEBUFFER
:
122 fb
= mBoundDrawFramebuffer
;
125 case LOCAL_GL_READ_FRAMEBUFFER
:
126 fb
= mBoundReadFramebuffer
;
130 MOZ_CRASH("GFX: Bad target.");
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.
138 if (!EnsureDefaultFB()) return false;
140 DoBindFB(fb
, target
);
142 *out_glNumAttachments
= AutoAssertCast(attachments
.size());
143 *out_glAttachments
= attachments
.data();
146 for (const auto& attachment
: attachments
) {
147 if (!ValidateFramebufferAttachmentEnum(this, attachment
)) return false;
150 for (const auto& attachment
: attachments
) {
151 if (!ValidateBackbufferAttachmentEnum(this, attachment
)) return false;
155 MOZ_ASSERT(scopedVector
->empty());
156 scopedVector
->reserve(attachments
.size());
157 for (const auto& attachment
: attachments
) {
158 switch (attachment
) {
160 scopedVector
->push_back(LOCAL_GL_COLOR_ATTACHMENT0
);
164 scopedVector
->push_back(LOCAL_GL_DEPTH_ATTACHMENT
);
167 case LOCAL_GL_STENCIL
:
168 scopedVector
->push_back(LOCAL_GL_STENCIL_ATTACHMENT
);
175 *out_glNumAttachments
= AutoAssertCast(scopedVector
->size());
176 *out_glAttachments
= scopedVector
->data();
185 void WebGL2Context::InvalidateFramebuffer(
186 GLenum target
, const Span
<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
)) {
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
);
208 // Use clear instead?
212 void WebGL2Context::InvalidateSubFramebuffer(
213 GLenum target
, const Span
<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
)) {
225 if (!ValidateNonNegative("width", width
) ||
226 !ValidateNonNegative("height", height
)) {
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
,
242 // Use clear instead?
246 void WebGL2Context::ReadBuffer(GLenum mode
) {
247 const FuncScope
funcScope(*this, "readBuffer");
248 if (IsContextLost()) return;
250 if (mBoundReadFramebuffer
) {
251 mBoundReadFramebuffer
->ReadBuffer(mode
);
255 // Operating on the default framebuffer.
256 if (mode
!= LOCAL_GL_NONE
&& mode
!= LOCAL_GL_BACK
) {
258 EnumName(mode
, &enumName
);
259 ErrorInvalidOperation(
260 "If READ_FRAMEBUFFER is null, `mode` must be BACK or"
262 enumName
.BeginReading());
266 mDefaultFB_ReadBuffer
= mode
;
269 } // namespace mozilla