Line data Source code
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 "WebGLRenderbuffer.h"
7 :
8 : #include "GLContext.h"
9 : #include "mozilla/dom/WebGLRenderingContextBinding.h"
10 : #include "ScopedGLHelpers.h"
11 : #include "WebGLContext.h"
12 : #include "WebGLStrongTypes.h"
13 : #include "WebGLTexture.h"
14 :
15 : namespace mozilla {
16 :
17 : static GLenum
18 0 : DepthFormatForDepthStencilEmu(gl::GLContext* gl)
19 : {
20 : // We might not be able to get 24-bit, so let's pretend!
21 0 : if (gl->IsGLES() && !gl->IsExtensionSupported(gl::GLContext::OES_depth24))
22 0 : return LOCAL_GL_DEPTH_COMPONENT16;
23 :
24 0 : return LOCAL_GL_DEPTH_COMPONENT24;
25 : }
26 :
27 : JSObject*
28 0 : WebGLRenderbuffer::WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto)
29 : {
30 0 : return dom::WebGLRenderbufferBinding::Wrap(cx, this, givenProto);
31 : }
32 :
33 : static GLuint
34 0 : DoCreateRenderbuffer(gl::GLContext* gl)
35 : {
36 0 : MOZ_ASSERT(gl->IsCurrent());
37 :
38 0 : GLuint ret = 0;
39 0 : gl->fGenRenderbuffers(1, &ret);
40 0 : return ret;
41 : }
42 :
43 : static bool
44 0 : EmulatePackedDepthStencil(gl::GLContext* gl)
45 : {
46 0 : return !gl->IsSupported(gl::GLFeature::packed_depth_stencil);
47 : }
48 :
49 0 : WebGLRenderbuffer::WebGLRenderbuffer(WebGLContext* webgl)
50 : : WebGLRefCountedObject(webgl)
51 0 : , mPrimaryRB( DoCreateRenderbuffer(webgl->gl) )
52 0 : , mEmulatePackedDepthStencil( EmulatePackedDepthStencil(webgl->gl) )
53 : , mSecondaryRB(0)
54 : , mFormat(nullptr)
55 : , mSamples(0)
56 : , mImageDataStatus(WebGLImageDataStatus::NoImageData)
57 0 : , mHasBeenBound(false)
58 : {
59 0 : mContext->mRenderbuffers.insertBack(this);
60 0 : }
61 :
62 : void
63 0 : WebGLRenderbuffer::Delete()
64 : {
65 0 : mContext->MakeContextCurrent();
66 :
67 0 : mContext->gl->fDeleteRenderbuffers(1, &mPrimaryRB);
68 0 : if (mSecondaryRB)
69 0 : mContext->gl->fDeleteRenderbuffers(1, &mSecondaryRB);
70 :
71 0 : LinkedListElement<WebGLRenderbuffer>::removeFrom(mContext->mRenderbuffers);
72 0 : }
73 :
74 : int64_t
75 0 : WebGLRenderbuffer::MemoryUsage() const
76 : {
77 : // If there is no defined format, we're not taking up any memory
78 0 : if (!mFormat)
79 0 : return 0;
80 :
81 0 : const auto bytesPerPixel = mFormat->format->estimatedBytesPerPixel;
82 0 : const int64_t pixels = int64_t(mWidth) * int64_t(mHeight);
83 :
84 0 : const int64_t totalSize = pixels * bytesPerPixel;
85 0 : return totalSize;
86 : }
87 :
88 : static GLenum
89 0 : DoRenderbufferStorageMaybeMultisample(gl::GLContext* gl, GLsizei samples,
90 : GLenum internalFormat, GLsizei width,
91 : GLsizei height)
92 : {
93 0 : MOZ_ASSERT_IF(samples >= 1, gl->IsSupported(gl::GLFeature::framebuffer_multisample));
94 :
95 : // Certain OpenGL ES renderbuffer formats may not exist on desktop OpenGL.
96 0 : switch (internalFormat) {
97 : case LOCAL_GL_RGBA4:
98 : case LOCAL_GL_RGB5_A1:
99 : // 16-bit RGBA formats are not supported on desktop GL.
100 0 : if (!gl->IsGLES())
101 0 : internalFormat = LOCAL_GL_RGBA8;
102 0 : break;
103 :
104 : case LOCAL_GL_RGB565:
105 : // RGB565 is not supported on desktop GL.
106 0 : if (!gl->IsGLES())
107 0 : internalFormat = LOCAL_GL_RGB8;
108 0 : break;
109 :
110 : case LOCAL_GL_DEPTH_COMPONENT16:
111 0 : if (!gl->IsGLES() || gl->IsExtensionSupported(gl::GLContext::OES_depth24))
112 0 : internalFormat = LOCAL_GL_DEPTH_COMPONENT24;
113 0 : else if (gl->IsSupported(gl::GLFeature::packed_depth_stencil))
114 0 : internalFormat = LOCAL_GL_DEPTH24_STENCIL8;
115 0 : break;
116 :
117 : case LOCAL_GL_DEPTH_STENCIL:
118 0 : MOZ_CRASH("GFX: GL_DEPTH_STENCIL is not valid here.");
119 : break;
120 :
121 : default:
122 0 : break;
123 : }
124 :
125 0 : gl::GLContext::LocalErrorScope errorScope(*gl);
126 :
127 0 : if (samples > 0) {
128 : gl->fRenderbufferStorageMultisample(LOCAL_GL_RENDERBUFFER, samples,
129 0 : internalFormat, width, height);
130 : } else {
131 0 : gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, internalFormat, width, height);
132 : }
133 :
134 0 : return errorScope.GetError();
135 : }
136 :
137 : GLenum
138 0 : WebGLRenderbuffer::DoRenderbufferStorage(uint32_t samples,
139 : const webgl::FormatUsageInfo* format,
140 : uint32_t width, uint32_t height)
141 : {
142 0 : MOZ_ASSERT(mContext->mBoundRenderbuffer == this);
143 :
144 0 : gl::GLContext* gl = mContext->gl;
145 0 : MOZ_ASSERT(samples <= 256); // Sanity check.
146 :
147 0 : GLenum primaryFormat = format->format->sizedFormat;
148 0 : GLenum secondaryFormat = 0;
149 :
150 0 : if (mEmulatePackedDepthStencil && primaryFormat == LOCAL_GL_DEPTH24_STENCIL8) {
151 0 : primaryFormat = DepthFormatForDepthStencilEmu(gl);
152 0 : secondaryFormat = LOCAL_GL_STENCIL_INDEX8;
153 : }
154 :
155 0 : gl->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mPrimaryRB);
156 0 : GLenum error = DoRenderbufferStorageMaybeMultisample(gl, samples, primaryFormat,
157 0 : width, height);
158 0 : if (error)
159 0 : return error;
160 :
161 0 : if (secondaryFormat) {
162 0 : if (!mSecondaryRB) {
163 0 : gl->fGenRenderbuffers(1, &mSecondaryRB);
164 : }
165 :
166 0 : gl->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mSecondaryRB);
167 0 : error = DoRenderbufferStorageMaybeMultisample(gl, samples, secondaryFormat,
168 0 : width, height);
169 0 : if (error)
170 0 : return error;
171 0 : } else if (mSecondaryRB) {
172 0 : gl->fDeleteRenderbuffers(1, &mSecondaryRB);
173 0 : mSecondaryRB = 0;
174 : }
175 :
176 0 : return 0;
177 : }
178 :
179 : void
180 0 : WebGLRenderbuffer::RenderbufferStorage(const char* funcName, uint32_t samples,
181 : GLenum internalFormat, uint32_t width,
182 : uint32_t height)
183 : {
184 0 : const auto usage = mContext->mFormatUsage->GetRBUsage(internalFormat);
185 0 : if (!usage) {
186 0 : mContext->ErrorInvalidEnum("%s: Invalid `internalFormat`: 0x%04x.", funcName,
187 0 : internalFormat);
188 0 : return;
189 : }
190 :
191 0 : if (width > mContext->mImplMaxRenderbufferSize ||
192 0 : height > mContext->mImplMaxRenderbufferSize)
193 : {
194 0 : mContext->ErrorInvalidValue("%s: Width or height exceeds maximum renderbuffer"
195 : " size.",
196 0 : funcName);
197 0 : return;
198 : }
199 :
200 0 : mContext->MakeContextCurrent();
201 :
202 0 : if (!usage->maxSamplesKnown) {
203 0 : const_cast<webgl::FormatUsageInfo*>(usage)->ResolveMaxSamples(mContext->gl);
204 : }
205 0 : MOZ_ASSERT(usage->maxSamplesKnown);
206 :
207 0 : if (samples > usage->maxSamples) {
208 0 : mContext->ErrorInvalidOperation("%s: `samples` is out of the valid range.", funcName);
209 0 : return;
210 : }
211 :
212 : // Validation complete.
213 :
214 0 : const GLenum error = DoRenderbufferStorage(samples, usage, width, height);
215 0 : if (error) {
216 0 : const char* errorName = mContext->ErrorName(error);
217 0 : mContext->GenerateWarning("%s generated error %s", funcName, errorName);
218 0 : return;
219 : }
220 :
221 0 : mSamples = samples;
222 0 : mFormat = usage;
223 0 : mWidth = width;
224 0 : mHeight = height;
225 0 : mImageDataStatus = WebGLImageDataStatus::UninitializedImageData;
226 :
227 0 : InvalidateStatusOfAttachedFBs(funcName);
228 : }
229 :
230 : void
231 0 : WebGLRenderbuffer::DoFramebufferRenderbuffer(FBTarget target, GLenum attachment) const
232 : {
233 0 : gl::GLContext* gl = mContext->gl;
234 :
235 0 : if (attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
236 0 : const GLuint stencilRB = (mSecondaryRB ? mSecondaryRB : mPrimaryRB);
237 0 : gl->fFramebufferRenderbuffer(target.get(), LOCAL_GL_DEPTH_ATTACHMENT,
238 0 : LOCAL_GL_RENDERBUFFER, mPrimaryRB);
239 0 : gl->fFramebufferRenderbuffer(target.get(), LOCAL_GL_STENCIL_ATTACHMENT,
240 0 : LOCAL_GL_RENDERBUFFER, stencilRB);
241 0 : return;
242 : }
243 :
244 0 : gl->fFramebufferRenderbuffer(target.get(), attachment,
245 0 : LOCAL_GL_RENDERBUFFER, mPrimaryRB);
246 : }
247 :
248 : GLint
249 0 : WebGLRenderbuffer::GetRenderbufferParameter(RBTarget target,
250 : RBParam pname) const
251 : {
252 0 : gl::GLContext* gl = mContext->gl;
253 :
254 0 : switch (pname.get()) {
255 : case LOCAL_GL_RENDERBUFFER_STENCIL_SIZE:
256 0 : if (!mFormat)
257 0 : return 0;
258 :
259 0 : if (!mFormat->format->s)
260 0 : return 0;
261 :
262 0 : return 8;
263 :
264 : case LOCAL_GL_RENDERBUFFER_SAMPLES:
265 : case LOCAL_GL_RENDERBUFFER_WIDTH:
266 : case LOCAL_GL_RENDERBUFFER_HEIGHT:
267 : case LOCAL_GL_RENDERBUFFER_RED_SIZE:
268 : case LOCAL_GL_RENDERBUFFER_GREEN_SIZE:
269 : case LOCAL_GL_RENDERBUFFER_BLUE_SIZE:
270 : case LOCAL_GL_RENDERBUFFER_ALPHA_SIZE:
271 : case LOCAL_GL_RENDERBUFFER_DEPTH_SIZE:
272 : {
273 0 : gl->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mPrimaryRB);
274 0 : GLint i = 0;
275 0 : gl->fGetRenderbufferParameteriv(target.get(), pname.get(), &i);
276 0 : return i;
277 : }
278 :
279 : case LOCAL_GL_RENDERBUFFER_INTERNAL_FORMAT:
280 : {
281 0 : GLenum ret = LOCAL_GL_RGBA4;
282 0 : if (mFormat) {
283 0 : ret = mFormat->format->sizedFormat;
284 :
285 0 : if (!mContext->IsWebGL2() && ret == LOCAL_GL_DEPTH24_STENCIL8) {
286 0 : ret = LOCAL_GL_DEPTH_STENCIL;
287 : }
288 : }
289 0 : return ret;
290 : }
291 : }
292 :
293 0 : MOZ_ASSERT(false, "This function should only be called with valid `pname`.");
294 : return 0;
295 : }
296 :
297 0 : NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLRenderbuffer)
298 :
299 0 : NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLRenderbuffer, AddRef)
300 0 : NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLRenderbuffer, Release)
301 :
302 : } // namespace mozilla
|