content/canvas/src/WebGLContextUtils.cpp

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

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

mercurial