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"
12 using namespace mozilla
;
13 using namespace mozilla::gl
;
16 DepthStencilDepthFormat(GLContext
* gl
) {
17 // We might not be able to get 24-bit, so let's pretend!
18 if (gl
->IsGLES2() && !gl
->IsExtensionSupported(gl::GLContext::OES_depth24
))
19 return LOCAL_GL_DEPTH_COMPONENT16
;
21 return LOCAL_GL_DEPTH_COMPONENT24
;
25 SupportsDepthStencil(GLContext
* gl
) {
26 return gl
->IsExtensionSupported(GLContext::EXT_packed_depth_stencil
) ||
27 gl
->IsExtensionSupported(GLContext::OES_packed_depth_stencil
);
31 NeedsDepthStencilEmu(GLContext
* gl
, GLenum internalFormat
) {
32 MOZ_ASSERT(internalFormat
!= LOCAL_GL_DEPTH_STENCIL
);
33 if (internalFormat
!= LOCAL_GL_DEPTH24_STENCIL8
)
36 return !SupportsDepthStencil(gl
);
40 WebGLRenderbuffer::WrapObject(JSContext
*cx
, JS::Handle
<JSObject
*> scope
) {
41 return dom::WebGLRenderbufferBinding::Wrap(cx
, scope
, this);
44 WebGLRenderbuffer::WebGLRenderbuffer(WebGLContext
*context
)
45 : WebGLContextBoundObject(context
)
49 , mInternalFormatForGL(0)
50 , mHasEverBeenBound(false)
51 , mImageDataStatus(WebGLImageDataStatus::NoImageData
)
54 mContext
->MakeContextCurrent();
56 mContext
->gl
->fGenRenderbuffers(1, &mPrimaryRB
);
57 if (!SupportsDepthStencil(mContext
->gl
))
58 mContext
->gl
->fGenRenderbuffers(1, &mSecondaryRB
);
60 mContext
->mRenderbuffers
.insertBack(this);
64 WebGLRenderbuffer::Delete() {
65 mContext
->MakeContextCurrent();
67 mContext
->gl
->fDeleteRenderbuffers(1, &mPrimaryRB
);
69 mContext
->gl
->fDeleteRenderbuffers(1, &mSecondaryRB
);
71 LinkedListElement
<WebGLRenderbuffer
>::removeFrom(mContext
->mRenderbuffers
);
75 WebGLRenderbuffer::MemoryUsage() const {
76 int64_t pixels
= int64_t(Width()) * int64_t(Height());
78 GLenum primaryFormat
= InternalFormatForGL();
79 // If there is no defined format, we're not taking up any memory
84 int64_t secondarySize
= 0;
86 if (NeedsDepthStencilEmu(mContext
->gl
, primaryFormat
)) {
87 primaryFormat
= DepthStencilDepthFormat(mContext
->gl
);
88 secondarySize
= 1*pixels
; // STENCIL_INDEX8
90 secondarySize
= 1*1*2; // 1x1xRGBA4
94 int64_t primarySize
= 0;
95 switch (primaryFormat
) {
96 case LOCAL_GL_STENCIL_INDEX8
:
97 primarySize
= 1 * pixels
;
100 case LOCAL_GL_RGB5_A1
:
101 case LOCAL_GL_RGB565
:
102 case LOCAL_GL_DEPTH_COMPONENT16
:
103 primarySize
= 2 * pixels
;
106 case LOCAL_GL_DEPTH_COMPONENT24
:
107 primarySize
= 3*pixels
;
110 case LOCAL_GL_DEPTH24_STENCIL8
:
111 case LOCAL_GL_DEPTH_COMPONENT32
:
112 primarySize
= 4*pixels
;
115 MOZ_ASSERT(false, "Unknown `primaryFormat`.");
119 return primarySize
+ secondarySize
;
123 WebGLRenderbuffer::BindRenderbuffer() const {
124 /* Do this explicitly here, since the meaning changes for depth-stencil emu.
125 * Under normal circumstances, there's only one RB: `mPrimaryRB`.
126 * `mSecondaryRB` is used when we have to pretend that the renderbuffer is
127 * DEPTH_STENCIL, when it's actually one DEPTH buffer `mPrimaryRB` and one
128 * STENCIL buffer `mSecondaryRB`.
130 * In the DEPTH_STENCIL emulation case, we're actually juggling two RBs, but
131 * we can only bind one of them at a time. We choose to unconditionally bind
132 * the depth RB. When we need to ask about the stencil buffer (say, how many
133 * stencil bits we have), we temporarily bind the stencil RB, so that it
134 * looks like we're just asking the question of a combined DEPTH_STENCIL
137 mContext
->gl
->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER
, mPrimaryRB
);
141 WebGLRenderbuffer::RenderbufferStorage(GLenum internalFormat
, GLsizei width
, GLsizei height
) const {
142 GLContext
* gl
= mContext
->gl
;
144 GLenum primaryFormat
= internalFormat
;
145 GLenum secondaryFormat
= 0;
147 if (NeedsDepthStencilEmu(mContext
->gl
, primaryFormat
)) {
148 primaryFormat
= DepthStencilDepthFormat(gl
);
149 secondaryFormat
= LOCAL_GL_STENCIL_INDEX8
;
152 gl
->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER
, primaryFormat
, width
, height
);
155 MOZ_ASSERT(!secondaryFormat
);
158 // We can't leave the secondary RB unspecified either, since we should
159 // handle the case where we attach a non-depth-stencil RB to a
160 // depth-stencil attachment point, or attach this depth-stencil RB to a
161 // non-depth-stencil attachment point.
162 ScopedBindRenderbuffer
autoRB(gl
, mSecondaryRB
);
163 if (secondaryFormat
) {
164 gl
->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER
, secondaryFormat
, width
, height
);
166 gl
->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER
, LOCAL_GL_RGBA4
, 1, 1);
171 WebGLRenderbuffer::FramebufferRenderbuffer(GLenum attachment
) const {
172 GLContext
* gl
= mContext
->gl
;
173 if (attachment
!= LOCAL_GL_DEPTH_STENCIL_ATTACHMENT
) {
174 gl
->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER
, attachment
, LOCAL_GL_RENDERBUFFER
, mPrimaryRB
);
178 GLuint stencilRB
= mPrimaryRB
;
179 if (NeedsDepthStencilEmu(mContext
->gl
, InternalFormatForGL())) {
180 printf_stderr("DEV-ONLY: Using secondary buffer to emulate DepthStencil.\n");
181 MOZ_ASSERT(mSecondaryRB
);
182 stencilRB
= mSecondaryRB
;
184 gl
->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER
, LOCAL_GL_DEPTH_ATTACHMENT
, LOCAL_GL_RENDERBUFFER
, mPrimaryRB
);
185 gl
->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER
, LOCAL_GL_STENCIL_ATTACHMENT
, LOCAL_GL_RENDERBUFFER
, stencilRB
);
189 WebGLRenderbuffer::GetRenderbufferParameter(GLenum target
, GLenum pname
) const {
190 GLContext
* gl
= mContext
->gl
;
193 case LOCAL_GL_RENDERBUFFER_STENCIL_SIZE
: {
194 if (NeedsDepthStencilEmu(mContext
->gl
, InternalFormatForGL())) {
195 if (gl
->WorkAroundDriverBugs() &&
196 gl
->Renderer() == GLContext::RendererTegra
)
201 ScopedBindRenderbuffer
autoRB(gl
, mSecondaryRB
);
204 gl
->fGetRenderbufferParameteriv(target
, pname
, &i
);
207 // Fall through otherwise.
209 case LOCAL_GL_RENDERBUFFER_WIDTH
:
210 case LOCAL_GL_RENDERBUFFER_HEIGHT
:
211 case LOCAL_GL_RENDERBUFFER_RED_SIZE
:
212 case LOCAL_GL_RENDERBUFFER_GREEN_SIZE
:
213 case LOCAL_GL_RENDERBUFFER_BLUE_SIZE
:
214 case LOCAL_GL_RENDERBUFFER_ALPHA_SIZE
:
215 case LOCAL_GL_RENDERBUFFER_DEPTH_SIZE
: {
217 gl
->fGetRenderbufferParameteriv(target
, pname
, &i
);
222 MOZ_ASSERT(false, "This function should only be called with valid `pname`.");
227 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLRenderbuffer
)
229 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLRenderbuffer
, AddRef
)
230 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLRenderbuffer
, Release
)