content/canvas/src/WebGLRenderbuffer.cpp

branch
TOR_BUG_9701
changeset 11
deefc01c0e14
equal deleted inserted replaced
-1:000000000000 0:7004f7b849ee
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/. */
5
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"
12
13 using namespace mozilla;
14 using namespace mozilla::gl;
15
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;
21
22 return LOCAL_GL_DEPTH_COMPONENT24;
23 }
24
25 static bool
26 SupportsDepthStencil(GLContext* gl) {
27 return gl->IsExtensionSupported(GLContext::EXT_packed_depth_stencil) ||
28 gl->IsExtensionSupported(GLContext::OES_packed_depth_stencil);
29 }
30
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;
36
37 return !SupportsDepthStencil(gl);
38 }
39
40 JSObject*
41 WebGLRenderbuffer::WrapObject(JSContext *cx) {
42 return dom::WebGLRenderbufferBinding::Wrap(cx, this);
43 }
44
45 WebGLRenderbuffer::WebGLRenderbuffer(WebGLContext *context)
46 : WebGLContextBoundObject(context)
47 , mPrimaryRB(0)
48 , mSecondaryRB(0)
49 , mInternalFormat(0)
50 , mInternalFormatForGL(0)
51 , mHasEverBeenBound(false)
52 , mImageDataStatus(WebGLImageDataStatus::NoImageData)
53 {
54 SetIsDOMBinding();
55 mContext->MakeContextCurrent();
56
57 mContext->gl->fGenRenderbuffers(1, &mPrimaryRB);
58 if (!SupportsDepthStencil(mContext->gl))
59 mContext->gl->fGenRenderbuffers(1, &mSecondaryRB);
60
61 mContext->mRenderbuffers.insertBack(this);
62 }
63
64 void
65 WebGLRenderbuffer::Delete() {
66 mContext->MakeContextCurrent();
67
68 mContext->gl->fDeleteRenderbuffers(1, &mPrimaryRB);
69 if (mSecondaryRB)
70 mContext->gl->fDeleteRenderbuffers(1, &mSecondaryRB);
71
72 LinkedListElement<WebGLRenderbuffer>::removeFrom(mContext->mRenderbuffers);
73 }
74
75 int64_t
76 WebGLRenderbuffer::MemoryUsage() const {
77 int64_t pixels = int64_t(Width()) * int64_t(Height());
78
79 GLenum primaryFormat = InternalFormatForGL();
80 // If there is no defined format, we're not taking up any memory
81 if (!primaryFormat) {
82 return 0;
83 }
84
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
92 }
93 }
94
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;
131 }
132
133 return primarySize + secondarySize;
134 }
135
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`.
143 *
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.
150 */
151 mContext->gl->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mPrimaryRB);
152 }
153
154 void
155 WebGLRenderbuffer::RenderbufferStorage(GLenum internalFormat, GLsizei width, GLsizei height) const {
156 GLContext* gl = mContext->gl;
157
158 GLenum primaryFormat = internalFormat;
159 GLenum secondaryFormat = 0;
160
161 if (NeedsDepthStencilEmu(mContext->gl, primaryFormat)) {
162 primaryFormat = DepthStencilDepthFormat(gl);
163 secondaryFormat = LOCAL_GL_STENCIL_INDEX8;
164 }
165
166 gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, primaryFormat, width, height);
167
168 if (!mSecondaryRB) {
169 MOZ_ASSERT(!secondaryFormat);
170 return;
171 }
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);
181 }
182 }
183
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;
190 }
191
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;
197 }
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);
200 }
201
202 GLint
203 WebGLRenderbuffer::GetRenderbufferParameter(GLenum target, GLenum pname) const {
204 GLContext* gl = mContext->gl;
205
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)
211 {
212 return 8;
213 }
214
215 ScopedBindRenderbuffer autoRB(gl, mSecondaryRB);
216
217 GLint i = 0;
218 gl->fGetRenderbufferParameteriv(target, pname, &i);
219 return i;
220 }
221 // Fall through otherwise.
222 }
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;
233 }
234 }
235
236 MOZ_ASSERT(false, "This function should only be called with valid `pname`.");
237 return 0;
238 }
239
240
241 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLRenderbuffer)
242
243 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLRenderbuffer, AddRef)
244 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLRenderbuffer, Release)

mercurial