|
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) |