1 /* -*- Mode: C++; tab-width: 20; 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/. */
6 #include "WebGLContext.h"
7 #include "WebGLRenderbuffer.h"
8 #include "WebGLTexture.h"
9 #include "mozilla/dom/WebGLRenderingContextBinding.h"
10 #include "GLContext.h"
11 #include "ScopedGLHelpers.h"
13 using namespace mozilla
;
14 using namespace mozilla::gl
;
17 DepthStencilDepthFormat(GLContext
* gl
) {
18 // We might not be able to get 24-bit, so let's pretend!
19 if (gl
->IsGLES() && !gl
->IsExtensionSupported(gl::GLContext::OES_depth24
))
20 return LOCAL_GL_DEPTH_COMPONENT16
;
22 return LOCAL_GL_DEPTH_COMPONENT24
;
26 SupportsDepthStencil(GLContext
* gl
) {
27 return gl
->IsExtensionSupported(GLContext::EXT_packed_depth_stencil
) ||
28 gl
->IsExtensionSupported(GLContext::OES_packed_depth_stencil
);
32 NeedsDepthStencilEmu(GLContext
* gl
, GLenum internalFormat
) {
33 MOZ_ASSERT(internalFormat
!= LOCAL_GL_DEPTH_STENCIL
);
34 if (internalFormat
!= LOCAL_GL_DEPTH24_STENCIL8
)
37 return !SupportsDepthStencil(gl
);
41 WebGLRenderbuffer::WrapObject(JSContext
*cx
) {
42 return dom::WebGLRenderbufferBinding::Wrap(cx
, this);
45 WebGLRenderbuffer::WebGLRenderbuffer(WebGLContext
*context
)
47 , WebGLContextBoundObject(context
)
51 , mInternalFormatForGL(0)
52 , mImageDataStatus(WebGLImageDataStatus::NoImageData
)
55 mContext
->MakeContextCurrent();
57 mContext
->gl
->fGenRenderbuffers(1, &mPrimaryRB
);
58 if (!SupportsDepthStencil(mContext
->gl
))
59 mContext
->gl
->fGenRenderbuffers(1, &mSecondaryRB
);
61 mContext
->mRenderbuffers
.insertBack(this);
65 WebGLRenderbuffer::Delete() {
66 mContext
->MakeContextCurrent();
68 mContext
->gl
->fDeleteRenderbuffers(1, &mPrimaryRB
);
70 mContext
->gl
->fDeleteRenderbuffers(1, &mSecondaryRB
);
72 LinkedListElement
<WebGLRenderbuffer
>::removeFrom(mContext
->mRenderbuffers
);
76 WebGLRenderbuffer::MemoryUsage() const {
77 int64_t pixels
= int64_t(Width()) * int64_t(Height());
79 GLenum primaryFormat
= InternalFormatForGL();
80 // If there is no defined format, we're not taking up any memory
85 int64_t secondarySize
= 0;
87 if (NeedsDepthStencilEmu(mContext
->gl
, primaryFormat
)) {
88 primaryFormat
= DepthStencilDepthFormat(mContext
->gl
);
89 secondarySize
= 1*pixels
; // STENCIL_INDEX8
91 secondarySize
= 1*1*2; // 1x1xRGBA4
95 int64_t primarySize
= 0;
96 switch (primaryFormat
) {
97 case LOCAL_GL_STENCIL_INDEX8
:
98 primarySize
= 1*pixels
;
101 case LOCAL_GL_RGB5_A1
:
102 case LOCAL_GL_RGB565
:
103 case LOCAL_GL_DEPTH_COMPONENT16
:
104 primarySize
= 2*pixels
;
107 case LOCAL_GL_DEPTH_COMPONENT24
:
108 primarySize
= 3*pixels
;
111 case LOCAL_GL_SRGB8_ALPHA8_EXT
:
112 case LOCAL_GL_DEPTH24_STENCIL8
:
113 case LOCAL_GL_DEPTH_COMPONENT32
:
114 primarySize
= 4*pixels
;
116 case LOCAL_GL_RGB16F
:
117 primarySize
= 2*3*pixels
;
119 case LOCAL_GL_RGBA16F
:
120 primarySize
= 2*4*pixels
;
122 case LOCAL_GL_RGB32F
:
123 primarySize
= 4*3*pixels
;
125 case LOCAL_GL_RGBA32F
:
126 primarySize
= 4*4*pixels
;
129 MOZ_ASSERT(false, "Unknown `primaryFormat`.");
133 return primarySize
+ secondarySize
;
137 WebGLRenderbuffer::BindRenderbuffer() const {
138 /* Do this explicitly here, since the meaning changes for depth-stencil emu.
139 * Under normal circumstances, there's only one RB: `mPrimaryRB`.
140 * `mSecondaryRB` is used when we have to pretend that the renderbuffer is
141 * DEPTH_STENCIL, when it's actually one DEPTH buffer `mPrimaryRB` and one
142 * STENCIL buffer `mSecondaryRB`.
144 * In the DEPTH_STENCIL emulation case, we're actually juggling two RBs, but
145 * we can only bind one of them at a time. We choose to unconditionally bind
146 * the depth RB. When we need to ask about the stencil buffer (say, how many
147 * stencil bits we have), we temporarily bind the stencil RB, so that it
148 * looks like we're just asking the question of a combined DEPTH_STENCIL
151 mContext
->gl
->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER
, mPrimaryRB
);
155 WebGLRenderbuffer::RenderbufferStorage(GLenum internalFormat
, GLsizei width
, GLsizei height
) const {
156 GLContext
* gl
= mContext
->gl
;
158 GLenum primaryFormat
= internalFormat
;
159 GLenum secondaryFormat
= 0;
161 if (NeedsDepthStencilEmu(mContext
->gl
, primaryFormat
)) {
162 primaryFormat
= DepthStencilDepthFormat(gl
);
163 secondaryFormat
= LOCAL_GL_STENCIL_INDEX8
;
166 gl
->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER
, primaryFormat
, width
, height
);
169 MOZ_ASSERT(!secondaryFormat
);
172 // We can't leave the secondary RB unspecified either, since we should
173 // handle the case where we attach a non-depth-stencil RB to a
174 // depth-stencil attachment point, or attach this depth-stencil RB to a
175 // non-depth-stencil attachment point.
176 ScopedBindRenderbuffer
autoRB(gl
, mSecondaryRB
);
177 if (secondaryFormat
) {
178 gl
->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER
, secondaryFormat
, width
, height
);
180 gl
->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER
, LOCAL_GL_RGBA4
, 1, 1);
185 WebGLRenderbuffer::FramebufferRenderbuffer(GLenum attachment
) const {
186 GLContext
* gl
= mContext
->gl
;
187 if (attachment
!= LOCAL_GL_DEPTH_STENCIL_ATTACHMENT
) {
188 gl
->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER
, attachment
, LOCAL_GL_RENDERBUFFER
, mPrimaryRB
);
192 GLuint stencilRB
= mPrimaryRB
;
193 if (NeedsDepthStencilEmu(mContext
->gl
, InternalFormatForGL())) {
194 printf_stderr("DEV-ONLY: Using secondary buffer to emulate DepthStencil.\n");
195 MOZ_ASSERT(mSecondaryRB
);
196 stencilRB
= mSecondaryRB
;
198 gl
->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER
, LOCAL_GL_DEPTH_ATTACHMENT
, LOCAL_GL_RENDERBUFFER
, mPrimaryRB
);
199 gl
->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER
, LOCAL_GL_STENCIL_ATTACHMENT
, LOCAL_GL_RENDERBUFFER
, stencilRB
);
203 WebGLRenderbuffer::GetRenderbufferParameter(GLenum target
, GLenum pname
) const {
204 GLContext
* gl
= mContext
->gl
;
207 case LOCAL_GL_RENDERBUFFER_STENCIL_SIZE
: {
208 if (NeedsDepthStencilEmu(mContext
->gl
, InternalFormatForGL())) {
209 if (gl
->WorkAroundDriverBugs() &&
210 gl
->Renderer() == GLRenderer::Tegra
)
215 ScopedBindRenderbuffer
autoRB(gl
, mSecondaryRB
);
218 gl
->fGetRenderbufferParameteriv(target
, pname
, &i
);
221 // Fall through otherwise.
223 case LOCAL_GL_RENDERBUFFER_WIDTH
:
224 case LOCAL_GL_RENDERBUFFER_HEIGHT
:
225 case LOCAL_GL_RENDERBUFFER_RED_SIZE
:
226 case LOCAL_GL_RENDERBUFFER_GREEN_SIZE
:
227 case LOCAL_GL_RENDERBUFFER_BLUE_SIZE
:
228 case LOCAL_GL_RENDERBUFFER_ALPHA_SIZE
:
229 case LOCAL_GL_RENDERBUFFER_DEPTH_SIZE
: {
231 gl
->fGetRenderbufferParameteriv(target
, pname
, &i
);
236 MOZ_ASSERT(false, "This function should only be called with valid `pname`.");
241 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLRenderbuffer
)
243 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLRenderbuffer
, AddRef
)
244 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLRenderbuffer
, Release
)