Bumping gaia.json for 3 gaia-central revision(s) a=gaia-bump
[gecko.git] / content / canvas / src / WebGLRenderbuffer.cpp
blob3f44ada579bedaa9644fab1dc7c0a11d2f74184e
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;
15 static GLenum
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;
24 static bool
25 SupportsDepthStencil(GLContext* gl) {
26 return gl->IsExtensionSupported(GLContext::EXT_packed_depth_stencil) ||
27 gl->IsExtensionSupported(GLContext::OES_packed_depth_stencil);
30 static bool
31 NeedsDepthStencilEmu(GLContext* gl, GLenum internalFormat) {
32 MOZ_ASSERT(internalFormat != LOCAL_GL_DEPTH_STENCIL);
33 if (internalFormat != LOCAL_GL_DEPTH24_STENCIL8)
34 return false;
36 return !SupportsDepthStencil(gl);
39 JSObject*
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)
46 , mPrimaryRB(0)
47 , mSecondaryRB(0)
48 , mInternalFormat(0)
49 , mInternalFormatForGL(0)
50 , mHasEverBeenBound(false)
51 , mImageDataStatus(WebGLImageDataStatus::NoImageData)
53 SetIsDOMBinding();
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);
63 void
64 WebGLRenderbuffer::Delete() {
65 mContext->MakeContextCurrent();
67 mContext->gl->fDeleteRenderbuffers(1, &mPrimaryRB);
68 if (mSecondaryRB)
69 mContext->gl->fDeleteRenderbuffers(1, &mSecondaryRB);
71 LinkedListElement<WebGLRenderbuffer>::removeFrom(mContext->mRenderbuffers);
74 int64_t
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
80 if (!primaryFormat) {
81 return 0;
84 int64_t secondarySize = 0;
85 if (mSecondaryRB) {
86 if (NeedsDepthStencilEmu(mContext->gl, primaryFormat)) {
87 primaryFormat = DepthStencilDepthFormat(mContext->gl);
88 secondarySize = 1*pixels; // STENCIL_INDEX8
89 } else {
90 secondarySize = 1*1*2; // 1x1xRGBA4
94 int64_t primarySize = 0;
95 switch (primaryFormat) {
96 case LOCAL_GL_STENCIL_INDEX8:
97 primarySize = 1 * pixels;
98 break;
99 case LOCAL_GL_RGBA4:
100 case LOCAL_GL_RGB5_A1:
101 case LOCAL_GL_RGB565:
102 case LOCAL_GL_DEPTH_COMPONENT16:
103 primarySize = 2 * pixels;
104 break;
105 case LOCAL_GL_RGB8:
106 case LOCAL_GL_DEPTH_COMPONENT24:
107 primarySize = 3*pixels;
108 break;
109 case LOCAL_GL_RGBA8:
110 case LOCAL_GL_DEPTH24_STENCIL8:
111 case LOCAL_GL_DEPTH_COMPONENT32:
112 primarySize = 4*pixels;
113 break;
114 default:
115 MOZ_ASSERT(false, "Unknown `primaryFormat`.");
116 break;
119 return primarySize + secondarySize;
122 void
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
135 * buffer.
137 mContext->gl->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mPrimaryRB);
140 void
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);
154 if (!mSecondaryRB) {
155 MOZ_ASSERT(!secondaryFormat);
156 return;
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);
165 } else {
166 gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, LOCAL_GL_RGBA4, 1, 1);
170 void
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);
175 return;
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);
188 GLint
189 WebGLRenderbuffer::GetRenderbufferParameter(GLenum target, GLenum pname) const {
190 GLContext* gl = mContext->gl;
192 switch (pname) {
193 case LOCAL_GL_RENDERBUFFER_STENCIL_SIZE: {
194 if (NeedsDepthStencilEmu(mContext->gl, InternalFormatForGL())) {
195 if (gl->WorkAroundDriverBugs() &&
196 gl->Renderer() == GLContext::RendererTegra)
198 return 8;
201 ScopedBindRenderbuffer autoRB(gl, mSecondaryRB);
203 GLint i = 0;
204 gl->fGetRenderbufferParameteriv(target, pname, &i);
205 return 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: {
216 GLint i = 0;
217 gl->fGetRenderbufferParameteriv(target, pname, &i);
218 return i;
222 MOZ_ASSERT(false, "This function should only be called with valid `pname`.");
223 return 0;
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)