content/canvas/src/WebGLContextUtils.cpp

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:ce8a632a210a
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 <stdarg.h>
7
8 #include "WebGLContext.h"
9 #include "GLContext.h"
10
11 #include "prprf.h"
12
13 #include "jsapi.h"
14 #include "nsIScriptSecurityManager.h"
15 #include "nsServiceManagerUtils.h"
16 #include "nsIVariant.h"
17 #include "nsCxPusher.h"
18
19 #include "nsIDOMEvent.h"
20 #include "nsIDOMDataContainerEvent.h"
21
22 #include "mozilla/Preferences.h"
23
24 using namespace mozilla;
25
26 namespace mozilla {
27
28 using namespace gl;
29
30 bool
31 IsGLDepthFormat(GLenum webGLFormat)
32 {
33 return (webGLFormat == LOCAL_GL_DEPTH_COMPONENT ||
34 webGLFormat == LOCAL_GL_DEPTH_COMPONENT16 ||
35 webGLFormat == LOCAL_GL_DEPTH_COMPONENT32);
36 }
37
38 bool
39 IsGLDepthStencilFormat(GLenum webGLFormat)
40 {
41 return (webGLFormat == LOCAL_GL_DEPTH_STENCIL ||
42 webGLFormat == LOCAL_GL_DEPTH24_STENCIL8);
43 }
44
45 bool
46 FormatHasAlpha(GLenum webGLFormat)
47 {
48 return webGLFormat == LOCAL_GL_RGBA ||
49 webGLFormat == LOCAL_GL_LUMINANCE_ALPHA ||
50 webGLFormat == LOCAL_GL_ALPHA ||
51 webGLFormat == LOCAL_GL_RGBA4 ||
52 webGLFormat == LOCAL_GL_RGB5_A1 ||
53 webGLFormat == LOCAL_GL_SRGB_ALPHA;
54 }
55
56 /**
57 * Convert WebGL/ES format and type into GL format and GL internal
58 * format valid for underlying driver.
59 */
60 void
61 DriverFormatsFromFormatAndType(GLContext* gl, GLenum webGLFormat, GLenum webGLType,
62 GLenum* out_driverInternalFormat, GLenum* out_driverFormat)
63 {
64 MOZ_ASSERT(out_driverInternalFormat, "out_driverInternalFormat can't be nullptr.");
65 MOZ_ASSERT(out_driverFormat, "out_driverFormat can't be nullptr.");
66 if (!out_driverInternalFormat || !out_driverFormat)
67 return;
68
69 // ES2 requires that format == internalformat; floating-point is
70 // indicated purely by the type that's loaded. For desktop GL, we
71 // have to specify a floating point internal format.
72 if (gl->IsGLES()) {
73 *out_driverInternalFormat = webGLFormat;
74 *out_driverFormat = webGLFormat;
75
76 return;
77 }
78
79 GLenum format = webGLFormat;
80 GLenum internalFormat = LOCAL_GL_NONE;
81
82 if (format == LOCAL_GL_DEPTH_COMPONENT) {
83 if (webGLType == LOCAL_GL_UNSIGNED_SHORT)
84 internalFormat = LOCAL_GL_DEPTH_COMPONENT16;
85 else if (webGLType == LOCAL_GL_UNSIGNED_INT)
86 internalFormat = LOCAL_GL_DEPTH_COMPONENT32;
87 } else if (format == LOCAL_GL_DEPTH_STENCIL) {
88 if (webGLType == LOCAL_GL_UNSIGNED_INT_24_8_EXT)
89 internalFormat = LOCAL_GL_DEPTH24_STENCIL8;
90 } else {
91 switch (webGLType) {
92 case LOCAL_GL_UNSIGNED_BYTE:
93 case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
94 case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
95 case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
96 internalFormat = format;
97 break;
98
99 case LOCAL_GL_FLOAT:
100 switch (format) {
101 case LOCAL_GL_RGBA:
102 internalFormat = LOCAL_GL_RGBA32F;
103 break;
104
105 case LOCAL_GL_RGB:
106 internalFormat = LOCAL_GL_RGB32F;
107 break;
108
109 case LOCAL_GL_ALPHA:
110 internalFormat = LOCAL_GL_ALPHA32F_ARB;
111 break;
112
113 case LOCAL_GL_LUMINANCE:
114 internalFormat = LOCAL_GL_LUMINANCE32F_ARB;
115 break;
116
117 case LOCAL_GL_LUMINANCE_ALPHA:
118 internalFormat = LOCAL_GL_LUMINANCE_ALPHA32F_ARB;
119 break;
120 }
121 break;
122
123 case LOCAL_GL_HALF_FLOAT_OES:
124 switch (format) {
125 case LOCAL_GL_RGBA:
126 internalFormat = LOCAL_GL_RGBA16F;
127 break;
128
129 case LOCAL_GL_RGB:
130 internalFormat = LOCAL_GL_RGB16F;
131 break;
132
133 case LOCAL_GL_ALPHA:
134 internalFormat = LOCAL_GL_ALPHA16F_ARB;
135 break;
136
137 case LOCAL_GL_LUMINANCE:
138 internalFormat = LOCAL_GL_LUMINANCE16F_ARB;
139 break;
140
141 case LOCAL_GL_LUMINANCE_ALPHA:
142 internalFormat = LOCAL_GL_LUMINANCE_ALPHA16F_ARB;
143 break;
144 }
145 break;
146
147 default:
148 break;
149 }
150
151 // Handle ES2 and GL differences when supporting sRGB internal formats. GL ES
152 // requires that format == internalformat, but GL will fail in this case.
153 // GL requires:
154 // format -> internalformat
155 // GL_RGB GL_SRGB_EXT
156 // GL_RGBA GL_SRGB_ALPHA_EXT
157 switch (format) {
158 case LOCAL_GL_SRGB:
159 internalFormat = format;
160 format = LOCAL_GL_RGB;
161 break;
162
163 case LOCAL_GL_SRGB_ALPHA:
164 internalFormat = format;
165 format = LOCAL_GL_RGBA;
166 break;
167 }
168 }
169
170 MOZ_ASSERT(format != LOCAL_GL_NONE && internalFormat != LOCAL_GL_NONE,
171 "Coding mistake -- bad format/type passed?");
172
173 *out_driverInternalFormat = internalFormat;
174 *out_driverFormat = format;
175 }
176
177 GLenum
178 DriverTypeFromType(GLContext* gl, GLenum webGLType)
179 {
180 if (gl->IsGLES())
181 return webGLType;
182
183 // convert type for half float if not on GLES2
184 GLenum type = webGLType;
185 if (type == LOCAL_GL_HALF_FLOAT_OES) {
186 if (gl->IsSupported(gl::GLFeature::texture_half_float)) {
187 return LOCAL_GL_HALF_FLOAT;
188 } else {
189 MOZ_ASSERT(gl->IsExtensionSupported(gl::GLContext::OES_texture_half_float));
190 }
191 }
192
193 return webGLType;
194 }
195
196 } // namespace mozilla
197
198 void
199 WebGLContext::GenerateWarning(const char *fmt, ...)
200 {
201 va_list ap;
202 va_start(ap, fmt);
203
204 GenerateWarning(fmt, ap);
205
206 va_end(ap);
207 }
208
209 void
210 WebGLContext::GenerateWarning(const char *fmt, va_list ap)
211 {
212 if (!ShouldGenerateWarnings())
213 return;
214
215 mAlreadyGeneratedWarnings++;
216
217 char buf[1024];
218 PR_vsnprintf(buf, 1024, fmt, ap);
219
220 // no need to print to stderr, as JS_ReportWarning takes care of this for us.
221
222 AutoJSContext cx;
223 JS_ReportWarning(cx, "WebGL: %s", buf);
224 if (!ShouldGenerateWarnings()) {
225 JS_ReportWarning(cx,
226 "WebGL: No further warnings will be reported for this WebGL context "
227 "(already reported %d warnings)", mAlreadyGeneratedWarnings);
228 }
229 }
230
231 bool
232 WebGLContext::ShouldGenerateWarnings() const
233 {
234 if (mMaxWarnings == -1) {
235 return true;
236 }
237
238 return mAlreadyGeneratedWarnings < mMaxWarnings;
239 }
240
241 CheckedUint32
242 WebGLContext::GetImageSize(GLsizei height,
243 GLsizei width,
244 uint32_t pixelSize,
245 uint32_t packOrUnpackAlignment)
246 {
247 CheckedUint32 checked_plainRowSize = CheckedUint32(width) * pixelSize;
248
249 // alignedRowSize = row size rounded up to next multiple of packAlignment
250 CheckedUint32 checked_alignedRowSize = RoundedToNextMultipleOf(checked_plainRowSize, packOrUnpackAlignment);
251
252 // if height is 0, we don't need any memory to store this; without this check, we'll get an overflow
253 CheckedUint32 checked_neededByteLength
254 = height <= 0 ? 0 : (height-1) * checked_alignedRowSize + checked_plainRowSize;
255
256 return checked_neededByteLength;
257 }
258
259 void
260 WebGLContext::SynthesizeGLError(GLenum err)
261 {
262 /* ES2 section 2.5 "GL Errors" states that implementations can have
263 * multiple 'flags', as errors might be caught in different parts of
264 * a distributed implementation.
265 * We're signing up as a distributed implementation here, with
266 * separate flags for WebGL and the underlying GLContext.
267 */
268 if (!mWebGLError)
269 mWebGLError = err;
270 }
271
272 void
273 WebGLContext::SynthesizeGLError(GLenum err, const char *fmt, ...)
274 {
275 va_list va;
276 va_start(va, fmt);
277 GenerateWarning(fmt, va);
278 va_end(va);
279
280 return SynthesizeGLError(err);
281 }
282
283 void
284 WebGLContext::ErrorInvalidEnum(const char *fmt, ...)
285 {
286 va_list va;
287 va_start(va, fmt);
288 GenerateWarning(fmt, va);
289 va_end(va);
290
291 return SynthesizeGLError(LOCAL_GL_INVALID_ENUM);
292 }
293
294 void
295 WebGLContext::ErrorInvalidEnumInfo(const char *info, GLenum enumvalue)
296 {
297 return ErrorInvalidEnum("%s: invalid enum value 0x%x", info, enumvalue);
298 }
299
300 void
301 WebGLContext::ErrorInvalidOperation(const char *fmt, ...)
302 {
303 va_list va;
304 va_start(va, fmt);
305 GenerateWarning(fmt, va);
306 va_end(va);
307
308 return SynthesizeGLError(LOCAL_GL_INVALID_OPERATION);
309 }
310
311 void
312 WebGLContext::ErrorInvalidValue(const char *fmt, ...)
313 {
314 va_list va;
315 va_start(va, fmt);
316 GenerateWarning(fmt, va);
317 va_end(va);
318
319 return SynthesizeGLError(LOCAL_GL_INVALID_VALUE);
320 }
321
322 void
323 WebGLContext::ErrorInvalidFramebufferOperation(const char *fmt, ...)
324 {
325 va_list va;
326 va_start(va, fmt);
327 GenerateWarning(fmt, va);
328 va_end(va);
329
330 return SynthesizeGLError(LOCAL_GL_INVALID_FRAMEBUFFER_OPERATION);
331 }
332
333 void
334 WebGLContext::ErrorOutOfMemory(const char *fmt, ...)
335 {
336 va_list va;
337 va_start(va, fmt);
338 GenerateWarning(fmt, va);
339 va_end(va);
340
341 return SynthesizeGLError(LOCAL_GL_OUT_OF_MEMORY);
342 }
343
344 const char *
345 WebGLContext::ErrorName(GLenum error)
346 {
347 switch(error) {
348 case LOCAL_GL_INVALID_ENUM:
349 return "INVALID_ENUM";
350 case LOCAL_GL_INVALID_OPERATION:
351 return "INVALID_OPERATION";
352 case LOCAL_GL_INVALID_VALUE:
353 return "INVALID_VALUE";
354 case LOCAL_GL_OUT_OF_MEMORY:
355 return "OUT_OF_MEMORY";
356 case LOCAL_GL_INVALID_FRAMEBUFFER_OPERATION:
357 return "INVALID_FRAMEBUFFER_OPERATION";
358 case LOCAL_GL_NO_ERROR:
359 return "NO_ERROR";
360 default:
361 MOZ_ASSERT(false);
362 return "[unknown WebGL error!]";
363 }
364 }
365
366 bool
367 WebGLContext::IsTextureFormatCompressed(GLenum format)
368 {
369 switch (format) {
370 case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
371 case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
372 case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
373 case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
374 case LOCAL_GL_ATC_RGB:
375 case LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA:
376 case LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA:
377 case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
378 case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
379 case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
380 case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
381 case LOCAL_GL_ETC1_RGB8_OES:
382 return true;
383 default:
384 return false;
385 }
386 }
387
388 GLenum
389 WebGLContext::GetAndFlushUnderlyingGLErrors()
390 {
391 // Get and clear GL error in ALL cases.
392 GLenum error = gl->GetAndClearError();
393
394 // Only store in mUnderlyingGLError if is hasn't already recorded an
395 // error.
396 if (!mUnderlyingGLError)
397 mUnderlyingGLError = error;
398
399 return error;
400 }

mercurial