1 /* -*- Mode: C++; tab-width: 20; 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 "WebGLRenderbuffer.h"
9 #include "mozilla/dom/WebGLRenderingContextBinding.h"
10 #include "ScopedGLHelpers.h"
11 #include "WebGLContext.h"
12 #include "WebGLFormats.h"
13 #include "WebGLStrongTypes.h"
14 #include "WebGLTexture.h"
18 static GLenum
DepthFormatForDepthStencilEmu(gl::GLContext
* gl
) {
19 // We might not be able to get 24-bit, so let's pretend!
20 if (gl
->IsGLES() && !gl
->IsExtensionSupported(gl::GLContext::OES_depth24
))
21 return LOCAL_GL_DEPTH_COMPONENT16
;
23 return LOCAL_GL_DEPTH_COMPONENT24
;
26 static GLuint
DoCreateRenderbuffer(gl::GLContext
* gl
) {
28 gl
->fGenRenderbuffers(1, &ret
);
32 static bool EmulatePackedDepthStencil(gl::GLContext
* gl
) {
33 return !gl
->IsSupported(gl::GLFeature::packed_depth_stencil
);
36 WebGLRenderbuffer::WebGLRenderbuffer(WebGLContext
* webgl
)
37 : WebGLContextBoundObject(webgl
),
38 mPrimaryRB(DoCreateRenderbuffer(webgl
->gl
)),
39 mEmulatePackedDepthStencil(EmulatePackedDepthStencil(webgl
->gl
)),
41 // Bind our RB, or we might end up calling FramebufferRenderbuffer before we
42 // ever call BindRenderbuffer, since webgl.bindRenderbuffer doesn't actually
43 // call glBindRenderbuffer anymore.
44 mContext
->gl
->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER
, mPrimaryRB
);
45 mContext
->gl
->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER
, 0);
48 WebGLRenderbuffer::~WebGLRenderbuffer() {
49 mImageInfo
= webgl::ImageInfo();
51 if (!mContext
) return;
53 mContext
->gl
->fDeleteRenderbuffers(1, &mPrimaryRB
);
55 mContext
->gl
->fDeleteRenderbuffers(1, &mSecondaryRB
);
59 static GLenum
DoRenderbufferStorageMaybeMultisample(gl::GLContext
* gl
,
61 GLenum internalFormat
,
64 MOZ_ASSERT_IF(samples
>= 1,
65 gl
->IsSupported(gl::GLFeature::framebuffer_multisample
));
67 // Certain OpenGL ES renderbuffer formats may not exist on desktop OpenGL.
68 switch (internalFormat
) {
70 case LOCAL_GL_RGB5_A1
:
71 // 16-bit RGBA formats are not supported on desktop GL.
72 if (!gl
->IsGLES()) internalFormat
= LOCAL_GL_RGBA8
;
76 // RGB565 is not supported on desktop GL.
77 if (!gl
->IsGLES()) internalFormat
= LOCAL_GL_RGB8
;
80 case LOCAL_GL_DEPTH_COMPONENT16
:
81 if (!gl
->IsGLES() || gl
->IsExtensionSupported(gl::GLContext::OES_depth24
))
82 internalFormat
= LOCAL_GL_DEPTH_COMPONENT24
;
83 else if (gl
->IsSupported(gl::GLFeature::packed_depth_stencil
))
84 internalFormat
= LOCAL_GL_DEPTH24_STENCIL8
;
87 case LOCAL_GL_DEPTH_STENCIL
:
88 MOZ_CRASH("GFX: GL_DEPTH_STENCIL is not valid here.");
95 gl::GLContext::LocalErrorScope
errorScope(*gl
);
98 gl
->fRenderbufferStorageMultisample(LOCAL_GL_RENDERBUFFER
, samples
,
99 internalFormat
, width
, height
);
101 gl
->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER
, internalFormat
, width
,
105 return errorScope
.GetError();
108 GLenum
WebGLRenderbuffer::DoRenderbufferStorage(
109 uint32_t samples
, const webgl::FormatUsageInfo
* format
, uint32_t width
,
111 gl::GLContext
* gl
= mContext
->gl
;
112 MOZ_ASSERT(samples
<= 256); // Sanity check.
114 GLenum primaryFormat
= format
->format
->sizedFormat
;
115 GLenum secondaryFormat
= 0;
117 if (mEmulatePackedDepthStencil
&&
118 primaryFormat
== LOCAL_GL_DEPTH24_STENCIL8
) {
119 primaryFormat
= DepthFormatForDepthStencilEmu(gl
);
120 secondaryFormat
= LOCAL_GL_STENCIL_INDEX8
;
123 gl
->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER
, mPrimaryRB
);
124 GLenum error
= DoRenderbufferStorageMaybeMultisample(
125 gl
, samples
, primaryFormat
, width
, height
);
126 gl
->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER
, 0);
127 if (error
) return error
;
129 if (secondaryFormat
) {
131 gl
->fGenRenderbuffers(1, &mSecondaryRB
);
134 gl
->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER
, mSecondaryRB
);
135 error
= DoRenderbufferStorageMaybeMultisample(gl
, samples
, secondaryFormat
,
137 gl
->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER
, 0);
138 if (error
) return error
;
139 } else if (mSecondaryRB
) {
140 gl
->fDeleteRenderbuffers(1, &mSecondaryRB
);
147 void WebGLRenderbuffer::RenderbufferStorage(uint32_t samples
,
148 GLenum internalFormat
,
149 uint32_t width
, uint32_t height
) {
150 const auto usage
= mContext
->mFormatUsage
->GetRBUsage(internalFormat
);
152 mContext
->ErrorInvalidEnum("Invalid `internalFormat`: 0x%04x.",
157 if (width
> mContext
->mGLMaxRenderbufferSize
||
158 height
> mContext
->mGLMaxRenderbufferSize
) {
159 mContext
->ErrorInvalidValue(
160 "Width or height exceeds maximum renderbuffer"
165 const auto maxSamples
= usage
->MaxSamples(*mContext
->gl
);
166 if (samples
> maxSamples
) {
167 mContext
->ErrorInvalidOperation("`samples` is out of the valid range.");
171 // Validation complete.
173 const GLenum error
= DoRenderbufferStorage(samples
, usage
, width
, height
);
175 mContext
->GenerateWarning("Unexpected error %s", EnumString(error
).c_str());
176 if (error
== LOCAL_GL_OUT_OF_MEMORY
) {
184 mContext
->OnDataAllocCall();
186 const uint32_t depth
= 1;
187 auto uninitializedSlices
= Some(std::vector
<bool>(depth
, true));
189 usage
, width
, height
, depth
, std::move(uninitializedSlices
),
194 void WebGLRenderbuffer::DoFramebufferRenderbuffer(
195 const GLenum attachment
) const {
196 gl::GLContext
* gl
= mContext
->gl
;
198 if (attachment
== LOCAL_GL_DEPTH_STENCIL_ATTACHMENT
) {
199 const GLuint stencilRB
= (mSecondaryRB
? mSecondaryRB
: mPrimaryRB
);
200 gl
->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER
,
201 LOCAL_GL_DEPTH_ATTACHMENT
,
202 LOCAL_GL_RENDERBUFFER
, mPrimaryRB
);
203 gl
->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER
,
204 LOCAL_GL_STENCIL_ATTACHMENT
,
205 LOCAL_GL_RENDERBUFFER
, stencilRB
);
209 gl
->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER
, attachment
,
210 LOCAL_GL_RENDERBUFFER
, mPrimaryRB
);
213 GLint
WebGLRenderbuffer::GetRenderbufferParameter(RBParam pname
) const {
214 gl::GLContext
* gl
= mContext
->gl
;
216 switch (pname
.get()) {
217 case LOCAL_GL_RENDERBUFFER_STENCIL_SIZE
:
218 if (!mImageInfo
.mFormat
) return 0;
220 if (!mImageInfo
.mFormat
->format
->s
) return 0;
224 case LOCAL_GL_RENDERBUFFER_SAMPLES
:
225 case LOCAL_GL_RENDERBUFFER_WIDTH
:
226 case LOCAL_GL_RENDERBUFFER_HEIGHT
:
227 case LOCAL_GL_RENDERBUFFER_RED_SIZE
:
228 case LOCAL_GL_RENDERBUFFER_GREEN_SIZE
:
229 case LOCAL_GL_RENDERBUFFER_BLUE_SIZE
:
230 case LOCAL_GL_RENDERBUFFER_ALPHA_SIZE
:
231 case LOCAL_GL_RENDERBUFFER_DEPTH_SIZE
: {
232 gl
->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER
, mPrimaryRB
);
234 gl
->fGetRenderbufferParameteriv(LOCAL_GL_RENDERBUFFER
, pname
.get(), &i
);
235 gl
->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER
, 0);
239 case LOCAL_GL_RENDERBUFFER_INTERNAL_FORMAT
: {
240 GLenum ret
= LOCAL_GL_RGBA4
;
241 if (mImageInfo
.mFormat
) {
242 ret
= mImageInfo
.mFormat
->format
->sizedFormat
;
244 if (!mContext
->IsWebGL2() && ret
== LOCAL_GL_DEPTH24_STENCIL8
) {
245 ret
= LOCAL_GL_DEPTH_STENCIL
;
252 MOZ_ASSERT(false, "This function should only be called with valid `pname`.");
256 } // namespace mozilla