Bumping gaia.json for 2 gaia revision(s) a=gaia-bump
[gecko.git] / dom / canvas / WebGLRenderbuffer.cpp
blob48dca59a9ee1b2800f30eeddaabcfda6758b4388
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;
16 static GLenum
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;
25 static bool
26 SupportsDepthStencil(GLContext* gl) {
27 return gl->IsExtensionSupported(GLContext::EXT_packed_depth_stencil) ||
28 gl->IsExtensionSupported(GLContext::OES_packed_depth_stencil);
31 static bool
32 NeedsDepthStencilEmu(GLContext* gl, GLenum internalFormat) {
33 MOZ_ASSERT(internalFormat != LOCAL_GL_DEPTH_STENCIL);
34 if (internalFormat != LOCAL_GL_DEPTH24_STENCIL8)
35 return false;
37 return !SupportsDepthStencil(gl);
40 JSObject*
41 WebGLRenderbuffer::WrapObject(JSContext *cx) {
42 return dom::WebGLRenderbufferBinding::Wrap(cx, this);
45 WebGLRenderbuffer::WebGLRenderbuffer(WebGLContext *context)
46 : WebGLBindableName()
47 , WebGLContextBoundObject(context)
48 , mPrimaryRB(0)
49 , mSecondaryRB(0)
50 , mInternalFormat(0)
51 , mInternalFormatForGL(0)
52 , mImageDataStatus(WebGLImageDataStatus::NoImageData)
54 SetIsDOMBinding();
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);
64 void
65 WebGLRenderbuffer::Delete() {
66 mContext->MakeContextCurrent();
68 mContext->gl->fDeleteRenderbuffers(1, &mPrimaryRB);
69 if (mSecondaryRB)
70 mContext->gl->fDeleteRenderbuffers(1, &mSecondaryRB);
72 LinkedListElement<WebGLRenderbuffer>::removeFrom(mContext->mRenderbuffers);
75 int64_t
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
81 if (!primaryFormat) {
82 return 0;
85 int64_t secondarySize = 0;
86 if (mSecondaryRB) {
87 if (NeedsDepthStencilEmu(mContext->gl, primaryFormat)) {
88 primaryFormat = DepthStencilDepthFormat(mContext->gl);
89 secondarySize = 1*pixels; // STENCIL_INDEX8
90 } else {
91 secondarySize = 1*1*2; // 1x1xRGBA4
95 int64_t primarySize = 0;
96 switch (primaryFormat) {
97 case LOCAL_GL_STENCIL_INDEX8:
98 primarySize = 1*pixels;
99 break;
100 case LOCAL_GL_RGBA4:
101 case LOCAL_GL_RGB5_A1:
102 case LOCAL_GL_RGB565:
103 case LOCAL_GL_DEPTH_COMPONENT16:
104 primarySize = 2*pixels;
105 break;
106 case LOCAL_GL_RGB8:
107 case LOCAL_GL_DEPTH_COMPONENT24:
108 primarySize = 3*pixels;
109 break;
110 case LOCAL_GL_RGBA8:
111 case LOCAL_GL_SRGB8_ALPHA8_EXT:
112 case LOCAL_GL_DEPTH24_STENCIL8:
113 case LOCAL_GL_DEPTH_COMPONENT32:
114 primarySize = 4*pixels;
115 break;
116 case LOCAL_GL_RGB16F:
117 primarySize = 2*3*pixels;
118 break;
119 case LOCAL_GL_RGBA16F:
120 primarySize = 2*4*pixels;
121 break;
122 case LOCAL_GL_RGB32F:
123 primarySize = 4*3*pixels;
124 break;
125 case LOCAL_GL_RGBA32F:
126 primarySize = 4*4*pixels;
127 break;
128 default:
129 MOZ_ASSERT(false, "Unknown `primaryFormat`.");
130 break;
133 return primarySize + secondarySize;
136 void
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
149 * buffer.
151 mContext->gl->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mPrimaryRB);
154 void
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);
168 if (!mSecondaryRB) {
169 MOZ_ASSERT(!secondaryFormat);
170 return;
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);
179 } else {
180 gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, LOCAL_GL_RGBA4, 1, 1);
184 void
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);
189 return;
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);
202 GLint
203 WebGLRenderbuffer::GetRenderbufferParameter(GLenum target, GLenum pname) const {
204 GLContext* gl = mContext->gl;
206 switch (pname) {
207 case LOCAL_GL_RENDERBUFFER_STENCIL_SIZE: {
208 if (NeedsDepthStencilEmu(mContext->gl, InternalFormatForGL())) {
209 if (gl->WorkAroundDriverBugs() &&
210 gl->Renderer() == GLRenderer::Tegra)
212 return 8;
215 ScopedBindRenderbuffer autoRB(gl, mSecondaryRB);
217 GLint i = 0;
218 gl->fGetRenderbufferParameteriv(target, pname, &i);
219 return 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: {
230 GLint i = 0;
231 gl->fGetRenderbufferParameteriv(target, pname, &i);
232 return i;
236 MOZ_ASSERT(false, "This function should only be called with valid `pname`.");
237 return 0;
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)