1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/canvas/src/WebGLContextGL.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,4115 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "WebGLContext.h" 1.10 +#include "WebGLContextUtils.h" 1.11 +#include "WebGLBuffer.h" 1.12 +#include "WebGLVertexAttribData.h" 1.13 +#include "WebGLShader.h" 1.14 +#include "WebGLProgram.h" 1.15 +#include "WebGLUniformLocation.h" 1.16 +#include "WebGLFramebuffer.h" 1.17 +#include "WebGLRenderbuffer.h" 1.18 +#include "WebGLShaderPrecisionFormat.h" 1.19 +#include "WebGLTexture.h" 1.20 +#include "WebGLExtensions.h" 1.21 +#include "WebGLVertexArray.h" 1.22 + 1.23 +#include "nsString.h" 1.24 +#include "nsDebug.h" 1.25 + 1.26 +#include "gfxContext.h" 1.27 +#include "gfxPlatform.h" 1.28 +#include "GLContext.h" 1.29 + 1.30 +#include "nsContentUtils.h" 1.31 +#include "nsError.h" 1.32 +#include "nsLayoutUtils.h" 1.33 + 1.34 +#include "CanvasUtils.h" 1.35 +#include "gfxUtils.h" 1.36 + 1.37 +#include "jsfriendapi.h" 1.38 + 1.39 +#include "WebGLTexelConversions.h" 1.40 +#include "WebGLValidateStrings.h" 1.41 +#include <algorithm> 1.42 + 1.43 +// needed to check if current OS is lower than 10.7 1.44 +#if defined(MOZ_WIDGET_COCOA) 1.45 +#include "nsCocoaFeatures.h" 1.46 +#endif 1.47 + 1.48 +#include "mozilla/dom/BindingUtils.h" 1.49 +#include "mozilla/dom/ImageData.h" 1.50 +#include "mozilla/dom/ToJSValue.h" 1.51 +#include "mozilla/Endian.h" 1.52 + 1.53 +using namespace mozilla; 1.54 +using namespace mozilla::dom; 1.55 +using namespace mozilla::gl; 1.56 +using namespace mozilla::gfx; 1.57 + 1.58 +static bool BaseTypeAndSizeFromUniformType(GLenum uType, GLenum *baseType, GLint *unitSize); 1.59 + 1.60 +const WebGLRectangleObject* 1.61 +WebGLContext::CurValidFBRectObject() const 1.62 +{ 1.63 + const WebGLRectangleObject* rect = nullptr; 1.64 + 1.65 + if (mBoundFramebuffer) { 1.66 + // We don't really need to ask the driver. 1.67 + // Use 'precheck' to just check that our internal state looks good. 1.68 + GLenum precheckStatus = mBoundFramebuffer->PrecheckFramebufferStatus(); 1.69 + if (precheckStatus == LOCAL_GL_FRAMEBUFFER_COMPLETE) 1.70 + rect = &mBoundFramebuffer->RectangleObject(); 1.71 + } else { 1.72 + rect = static_cast<const WebGLRectangleObject*>(this); 1.73 + } 1.74 + 1.75 + return rect; 1.76 +} 1.77 + 1.78 +// 1.79 +// WebGL API 1.80 +// 1.81 + 1.82 +void 1.83 +WebGLContext::ActiveTexture(GLenum texture) 1.84 +{ 1.85 + if (IsContextLost()) 1.86 + return; 1.87 + 1.88 + if (texture < LOCAL_GL_TEXTURE0 || 1.89 + texture >= LOCAL_GL_TEXTURE0 + uint32_t(mGLMaxTextureUnits)) 1.90 + { 1.91 + return ErrorInvalidEnum( 1.92 + "ActiveTexture: texture unit %d out of range. " 1.93 + "Accepted values range from TEXTURE0 to TEXTURE0 + %d. " 1.94 + "Notice that TEXTURE0 != 0.", 1.95 + texture, mGLMaxTextureUnits); 1.96 + } 1.97 + 1.98 + MakeContextCurrent(); 1.99 + mActiveTexture = texture - LOCAL_GL_TEXTURE0; 1.100 + gl->fActiveTexture(texture); 1.101 +} 1.102 + 1.103 +void 1.104 +WebGLContext::AttachShader(WebGLProgram *program, WebGLShader *shader) 1.105 +{ 1.106 + if (IsContextLost()) 1.107 + return; 1.108 + 1.109 + if (!ValidateObject("attachShader: program", program) || 1.110 + !ValidateObject("attachShader: shader", shader)) 1.111 + return; 1.112 + 1.113 + // Per GLSL ES 2.0, we can only have one of each type of shader 1.114 + // attached. This renders the next test somewhat moot, but we'll 1.115 + // leave it for when we support more than one shader of each type. 1.116 + if (program->HasAttachedShaderOfType(shader->ShaderType())) 1.117 + return ErrorInvalidOperation("attachShader: only one of each type of shader may be attached to a program"); 1.118 + 1.119 + if (!program->AttachShader(shader)) 1.120 + return ErrorInvalidOperation("attachShader: shader is already attached"); 1.121 +} 1.122 + 1.123 + 1.124 +void 1.125 +WebGLContext::BindAttribLocation(WebGLProgram *prog, GLuint location, 1.126 + const nsAString& name) 1.127 +{ 1.128 + if (IsContextLost()) 1.129 + return; 1.130 + 1.131 + if (!ValidateObject("bindAttribLocation: program", prog)) 1.132 + return; 1.133 + 1.134 + GLuint progname = prog->GLName(); 1.135 + 1.136 + if (!ValidateGLSLVariableName(name, "bindAttribLocation")) 1.137 + return; 1.138 + 1.139 + if (!ValidateAttribIndex(location, "bindAttribLocation")) 1.140 + return; 1.141 + 1.142 + NS_LossyConvertUTF16toASCII cname(name); 1.143 + nsCString mappedName; 1.144 + prog->MapIdentifier(cname, &mappedName); 1.145 + 1.146 + MakeContextCurrent(); 1.147 + gl->fBindAttribLocation(progname, location, mappedName.get()); 1.148 +} 1.149 + 1.150 +void 1.151 +WebGLContext::BindFramebuffer(GLenum target, WebGLFramebuffer *wfb) 1.152 +{ 1.153 + if (IsContextLost()) 1.154 + return; 1.155 + 1.156 + if (target != LOCAL_GL_FRAMEBUFFER) 1.157 + return ErrorInvalidEnum("bindFramebuffer: target must be GL_FRAMEBUFFER"); 1.158 + 1.159 + if (!ValidateObjectAllowDeletedOrNull("bindFramebuffer", wfb)) 1.160 + return; 1.161 + 1.162 + // silently ignore a deleted frame buffer 1.163 + if (wfb && wfb->IsDeleted()) 1.164 + return; 1.165 + 1.166 + MakeContextCurrent(); 1.167 + 1.168 + if (!wfb) { 1.169 + gl->fBindFramebuffer(target, 0); 1.170 + } else { 1.171 + GLuint framebuffername = wfb->GLName(); 1.172 + gl->fBindFramebuffer(target, framebuffername); 1.173 + wfb->SetHasEverBeenBound(true); 1.174 + } 1.175 + 1.176 + mBoundFramebuffer = wfb; 1.177 +} 1.178 + 1.179 +void 1.180 +WebGLContext::BindRenderbuffer(GLenum target, WebGLRenderbuffer *wrb) 1.181 +{ 1.182 + if (IsContextLost()) 1.183 + return; 1.184 + 1.185 + if (target != LOCAL_GL_RENDERBUFFER) 1.186 + return ErrorInvalidEnumInfo("bindRenderbuffer: target", target); 1.187 + 1.188 + if (!ValidateObjectAllowDeletedOrNull("bindRenderbuffer", wrb)) 1.189 + return; 1.190 + 1.191 + // silently ignore a deleted buffer 1.192 + if (wrb && wrb->IsDeleted()) 1.193 + return; 1.194 + 1.195 + if (wrb) 1.196 + wrb->SetHasEverBeenBound(true); 1.197 + 1.198 + MakeContextCurrent(); 1.199 + 1.200 + // Sometimes we emulate renderbuffers (depth-stencil emu), so there's not 1.201 + // always a 1-1 mapping from `wrb` to GL name. Just have `wrb` handle it. 1.202 + if (wrb) { 1.203 + wrb->BindRenderbuffer(); 1.204 + } else { 1.205 + gl->fBindRenderbuffer(target, 0); 1.206 + } 1.207 + 1.208 + mBoundRenderbuffer = wrb; 1.209 +} 1.210 + 1.211 +void 1.212 +WebGLContext::BindTexture(GLenum target, WebGLTexture *newTex) 1.213 +{ 1.214 + if (IsContextLost()) 1.215 + return; 1.216 + 1.217 + if (!ValidateObjectAllowDeletedOrNull("bindTexture", newTex)) 1.218 + return; 1.219 + 1.220 + // silently ignore a deleted texture 1.221 + if (newTex && newTex->IsDeleted()) 1.222 + return; 1.223 + 1.224 + WebGLRefPtr<WebGLTexture>* currentTexPtr = nullptr; 1.225 + 1.226 + if (target == LOCAL_GL_TEXTURE_2D) { 1.227 + currentTexPtr = &mBound2DTextures[mActiveTexture]; 1.228 + } else if (target == LOCAL_GL_TEXTURE_CUBE_MAP) { 1.229 + currentTexPtr = &mBoundCubeMapTextures[mActiveTexture]; 1.230 + } else { 1.231 + return ErrorInvalidEnumInfo("bindTexture: target", target); 1.232 + } 1.233 + 1.234 + WebGLTextureFakeBlackStatus currentTexFakeBlackStatus = WebGLTextureFakeBlackStatus::NotNeeded; 1.235 + if (*currentTexPtr) { 1.236 + currentTexFakeBlackStatus = (*currentTexPtr)->ResolvedFakeBlackStatus(); 1.237 + } 1.238 + WebGLTextureFakeBlackStatus newTexFakeBlackStatus = WebGLTextureFakeBlackStatus::NotNeeded; 1.239 + if (newTex) { 1.240 + newTexFakeBlackStatus = newTex->ResolvedFakeBlackStatus(); 1.241 + } 1.242 + 1.243 + *currentTexPtr = newTex; 1.244 + 1.245 + if (currentTexFakeBlackStatus != newTexFakeBlackStatus) { 1.246 + SetFakeBlackStatus(WebGLContextFakeBlackStatus::Unknown); 1.247 + } 1.248 + 1.249 + MakeContextCurrent(); 1.250 + 1.251 + if (newTex) 1.252 + newTex->Bind(target); 1.253 + else 1.254 + gl->fBindTexture(target, 0 /* == texturename */); 1.255 +} 1.256 + 1.257 +void WebGLContext::BlendEquation(GLenum mode) 1.258 +{ 1.259 + if (IsContextLost()) 1.260 + return; 1.261 + 1.262 + if (!ValidateBlendEquationEnum(mode, "blendEquation: mode")) 1.263 + return; 1.264 + 1.265 + MakeContextCurrent(); 1.266 + gl->fBlendEquation(mode); 1.267 +} 1.268 + 1.269 +void WebGLContext::BlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) 1.270 +{ 1.271 + if (IsContextLost()) 1.272 + return; 1.273 + 1.274 + if (!ValidateBlendEquationEnum(modeRGB, "blendEquationSeparate: modeRGB") || 1.275 + !ValidateBlendEquationEnum(modeAlpha, "blendEquationSeparate: modeAlpha")) 1.276 + return; 1.277 + 1.278 + MakeContextCurrent(); 1.279 + gl->fBlendEquationSeparate(modeRGB, modeAlpha); 1.280 +} 1.281 + 1.282 +void WebGLContext::BlendFunc(GLenum sfactor, GLenum dfactor) 1.283 +{ 1.284 + if (IsContextLost()) 1.285 + return; 1.286 + 1.287 + if (!ValidateBlendFuncSrcEnum(sfactor, "blendFunc: sfactor") || 1.288 + !ValidateBlendFuncDstEnum(dfactor, "blendFunc: dfactor")) 1.289 + return; 1.290 + 1.291 + if (!ValidateBlendFuncEnumsCompatibility(sfactor, dfactor, "blendFuncSeparate: srcRGB and dstRGB")) 1.292 + return; 1.293 + 1.294 + MakeContextCurrent(); 1.295 + gl->fBlendFunc(sfactor, dfactor); 1.296 +} 1.297 + 1.298 +void 1.299 +WebGLContext::BlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, 1.300 + GLenum srcAlpha, GLenum dstAlpha) 1.301 +{ 1.302 + if (IsContextLost()) 1.303 + return; 1.304 + 1.305 + if (!ValidateBlendFuncSrcEnum(srcRGB, "blendFuncSeparate: srcRGB") || 1.306 + !ValidateBlendFuncSrcEnum(srcAlpha, "blendFuncSeparate: srcAlpha") || 1.307 + !ValidateBlendFuncDstEnum(dstRGB, "blendFuncSeparate: dstRGB") || 1.308 + !ValidateBlendFuncDstEnum(dstAlpha, "blendFuncSeparate: dstAlpha")) 1.309 + return; 1.310 + 1.311 + // note that we only check compatibity for the RGB enums, no need to for the Alpha enums, see 1.312 + // "Section 6.8 forgetting to mention alpha factors?" thread on the public_webgl mailing list 1.313 + if (!ValidateBlendFuncEnumsCompatibility(srcRGB, dstRGB, "blendFuncSeparate: srcRGB and dstRGB")) 1.314 + return; 1.315 + 1.316 + MakeContextCurrent(); 1.317 + gl->fBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha); 1.318 +} 1.319 + 1.320 +GLenum 1.321 +WebGLContext::CheckFramebufferStatus(GLenum target) 1.322 +{ 1.323 + if (IsContextLost()) 1.324 + return LOCAL_GL_FRAMEBUFFER_UNSUPPORTED; 1.325 + 1.326 + if (target != LOCAL_GL_FRAMEBUFFER) { 1.327 + ErrorInvalidEnum("checkFramebufferStatus: target must be FRAMEBUFFER"); 1.328 + return 0; 1.329 + } 1.330 + 1.331 + if (!mBoundFramebuffer) 1.332 + return LOCAL_GL_FRAMEBUFFER_COMPLETE; 1.333 + 1.334 + return mBoundFramebuffer->CheckFramebufferStatus(); 1.335 +} 1.336 + 1.337 +void 1.338 +WebGLContext::CopyTexSubImage2D_base(GLenum target, 1.339 + GLint level, 1.340 + GLenum internalformat, 1.341 + GLint xoffset, 1.342 + GLint yoffset, 1.343 + GLint x, 1.344 + GLint y, 1.345 + GLsizei width, 1.346 + GLsizei height, 1.347 + bool sub) 1.348 +{ 1.349 + const WebGLRectangleObject* framebufferRect = CurValidFBRectObject(); 1.350 + GLsizei framebufferWidth = framebufferRect ? framebufferRect->Width() : 0; 1.351 + GLsizei framebufferHeight = framebufferRect ? framebufferRect->Height() : 0; 1.352 + 1.353 + const char* info = sub ? "copyTexSubImage2D" : "copyTexImage2D"; 1.354 + WebGLTexImageFunc func = sub ? WebGLTexImageFunc::CopyTexSubImage : WebGLTexImageFunc::CopyTexImage; 1.355 + 1.356 + // TODO: This changes with color_buffer_float. Reassess when the 1.357 + // patch lands. 1.358 + if (!ValidateTexImage(2, target, level, internalformat, 1.359 + xoffset, yoffset, 0, 1.360 + width, height, 0, 1.361 + 0, internalformat, LOCAL_GL_UNSIGNED_BYTE, 1.362 + func)) 1.363 + { 1.364 + return; 1.365 + } 1.366 + 1.367 + MakeContextCurrent(); 1.368 + 1.369 + WebGLTexture *tex = activeBoundTextureForTarget(target); 1.370 + 1.371 + if (!tex) 1.372 + return ErrorInvalidOperation("%s: no texture is bound to this target"); 1.373 + 1.374 + if (CanvasUtils::CheckSaneSubrectSize(x, y, width, height, framebufferWidth, framebufferHeight)) { 1.375 + if (sub) 1.376 + gl->fCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height); 1.377 + else 1.378 + gl->fCopyTexImage2D(target, level, internalformat, x, y, width, height, 0); 1.379 + } else { 1.380 + 1.381 + // the rect doesn't fit in the framebuffer 1.382 + 1.383 + /*** first, we initialize the texture as black ***/ 1.384 + 1.385 + // first, compute the size of the buffer we should allocate to initialize the texture as black 1.386 + 1.387 + if (!ValidateTexInputData(LOCAL_GL_UNSIGNED_BYTE, -1, func)) 1.388 + return; 1.389 + 1.390 + uint32_t texelSize = GetBitsPerTexel(internalformat, LOCAL_GL_UNSIGNED_BYTE) / 8; 1.391 + 1.392 + CheckedUint32 checked_neededByteLength = 1.393 + GetImageSize(height, width, texelSize, mPixelStoreUnpackAlignment); 1.394 + 1.395 + if (!checked_neededByteLength.isValid()) 1.396 + return ErrorInvalidOperation("%s: integer overflow computing the needed buffer size", info); 1.397 + 1.398 + uint32_t bytesNeeded = checked_neededByteLength.value(); 1.399 + 1.400 + // now that the size is known, create the buffer 1.401 + 1.402 + // We need some zero pages, because GL doesn't guarantee the 1.403 + // contents of a texture allocated with nullptr data. 1.404 + // Hopefully calloc will just mmap zero pages here. 1.405 + void* tempZeroData = calloc(1, bytesNeeded); 1.406 + if (!tempZeroData) 1.407 + return ErrorOutOfMemory("%s: could not allocate %d bytes (for zero fill)", info, bytesNeeded); 1.408 + 1.409 + // now initialize the texture as black 1.410 + 1.411 + if (sub) 1.412 + gl->fTexSubImage2D(target, level, 0, 0, width, height, 1.413 + internalformat, LOCAL_GL_UNSIGNED_BYTE, tempZeroData); 1.414 + else 1.415 + gl->fTexImage2D(target, level, internalformat, width, height, 1.416 + 0, internalformat, LOCAL_GL_UNSIGNED_BYTE, tempZeroData); 1.417 + free(tempZeroData); 1.418 + 1.419 + // if we are completely outside of the framebuffer, we can exit now with our black texture 1.420 + if ( x >= framebufferWidth 1.421 + || x+width <= 0 1.422 + || y >= framebufferHeight 1.423 + || y+height <= 0) 1.424 + { 1.425 + // we are completely outside of range, can exit now with buffer filled with zeros 1.426 + return DummyFramebufferOperation(info); 1.427 + } 1.428 + 1.429 + GLint actual_x = clamped(x, 0, framebufferWidth); 1.430 + GLint actual_x_plus_width = clamped(x + width, 0, framebufferWidth); 1.431 + GLsizei actual_width = actual_x_plus_width - actual_x; 1.432 + GLint actual_xoffset = xoffset + actual_x - x; 1.433 + 1.434 + GLint actual_y = clamped(y, 0, framebufferHeight); 1.435 + GLint actual_y_plus_height = clamped(y + height, 0, framebufferHeight); 1.436 + GLsizei actual_height = actual_y_plus_height - actual_y; 1.437 + GLint actual_yoffset = yoffset + actual_y - y; 1.438 + 1.439 + gl->fCopyTexSubImage2D(target, level, actual_xoffset, actual_yoffset, actual_x, actual_y, actual_width, actual_height); 1.440 + } 1.441 +} 1.442 + 1.443 +void 1.444 +WebGLContext::CopyTexImage2D(GLenum target, 1.445 + GLint level, 1.446 + GLenum internalformat, 1.447 + GLint x, 1.448 + GLint y, 1.449 + GLsizei width, 1.450 + GLsizei height, 1.451 + GLint border) 1.452 +{ 1.453 + if (IsContextLost()) 1.454 + return; 1.455 + 1.456 + // copyTexImage2D only generates textures with type = UNSIGNED_BYTE 1.457 + const WebGLTexImageFunc func = WebGLTexImageFunc::CopyTexImage; 1.458 + const GLenum format = internalformat; // WebGL/ES Format 1.459 + const GLenum type = LOCAL_GL_UNSIGNED_BYTE; // WebGL/ES Format 1.460 + 1.461 + if (!ValidateTexImage(2, target, level, format, 1.462 + 0, 0, 0, 1.463 + width, height, 0, 1.464 + border, format, type, 1.465 + func)) 1.466 + { 1.467 + return; 1.468 + } 1.469 + 1.470 + if (mBoundFramebuffer) { 1.471 + if (!mBoundFramebuffer->CheckAndInitializeAttachments()) 1.472 + return ErrorInvalidFramebufferOperation("copyTexImage2D: incomplete framebuffer"); 1.473 + 1.474 + GLenum readPlaneBits = LOCAL_GL_COLOR_BUFFER_BIT; 1.475 + if (!mBoundFramebuffer->HasCompletePlanes(readPlaneBits)) { 1.476 + return ErrorInvalidOperation("copyTexImage2D: Read source attachment doesn't have the" 1.477 + " correct color/depth/stencil type."); 1.478 + } 1.479 + } else { 1.480 + ClearBackbufferIfNeeded(); 1.481 + } 1.482 + 1.483 + bool texFormatRequiresAlpha = format == LOCAL_GL_RGBA || 1.484 + format == LOCAL_GL_ALPHA || 1.485 + format == LOCAL_GL_LUMINANCE_ALPHA; 1.486 + bool fboFormatHasAlpha = mBoundFramebuffer ? mBoundFramebuffer->ColorAttachment(0).HasAlpha() 1.487 + : bool(gl->GetPixelFormat().alpha > 0); 1.488 + if (texFormatRequiresAlpha && !fboFormatHasAlpha) 1.489 + return ErrorInvalidOperation("copyTexImage2D: texture format requires an alpha channel " 1.490 + "but the framebuffer doesn't have one"); 1.491 + 1.492 + // check if the memory size of this texture may change with this call 1.493 + bool sizeMayChange = true; 1.494 + WebGLTexture* tex = activeBoundTextureForTarget(target); 1.495 + if (tex->HasImageInfoAt(target, level)) { 1.496 + const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(target, level); 1.497 + 1.498 + sizeMayChange = width != imageInfo.Width() || 1.499 + height != imageInfo.Height() || 1.500 + format != imageInfo.WebGLFormat() || 1.501 + type != imageInfo.WebGLType(); 1.502 + } 1.503 + 1.504 + if (sizeMayChange) 1.505 + GetAndFlushUnderlyingGLErrors(); 1.506 + 1.507 + CopyTexSubImage2D_base(target, level, format, 0, 0, x, y, width, height, false); 1.508 + 1.509 + if (sizeMayChange) { 1.510 + GLenum error = GetAndFlushUnderlyingGLErrors(); 1.511 + if (error) { 1.512 + GenerateWarning("copyTexImage2D generated error %s", ErrorName(error)); 1.513 + return; 1.514 + } 1.515 + } 1.516 + 1.517 + tex->SetImageInfo(target, level, width, height, format, type, 1.518 + WebGLImageDataStatus::InitializedImageData); 1.519 +} 1.520 + 1.521 +void 1.522 +WebGLContext::CopyTexSubImage2D(GLenum target, 1.523 + GLint level, 1.524 + GLint xoffset, 1.525 + GLint yoffset, 1.526 + GLint x, 1.527 + GLint y, 1.528 + GLsizei width, 1.529 + GLsizei height) 1.530 +{ 1.531 + if (IsContextLost()) 1.532 + return; 1.533 + 1.534 + switch (target) { 1.535 + case LOCAL_GL_TEXTURE_2D: 1.536 + case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X: 1.537 + case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X: 1.538 + case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y: 1.539 + case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: 1.540 + case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z: 1.541 + case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: 1.542 + break; 1.543 + default: 1.544 + return ErrorInvalidEnumInfo("copyTexSubImage2D: target", target); 1.545 + } 1.546 + 1.547 + if (level < 0) 1.548 + return ErrorInvalidValue("copyTexSubImage2D: level may not be negative"); 1.549 + 1.550 + GLsizei maxTextureSize = MaxTextureSizeForTarget(target); 1.551 + if (!(maxTextureSize >> level)) 1.552 + return ErrorInvalidValue("copyTexSubImage2D: 2^level exceeds maximum texture size"); 1.553 + 1.554 + if (width < 0 || height < 0) 1.555 + return ErrorInvalidValue("copyTexSubImage2D: width and height may not be negative"); 1.556 + 1.557 + if (xoffset < 0 || yoffset < 0) 1.558 + return ErrorInvalidValue("copyTexSubImage2D: xoffset and yoffset may not be negative"); 1.559 + 1.560 + WebGLTexture *tex = activeBoundTextureForTarget(target); 1.561 + if (!tex) 1.562 + return ErrorInvalidOperation("copyTexSubImage2D: no texture bound to this target"); 1.563 + 1.564 + if (!tex->HasImageInfoAt(target, level)) 1.565 + return ErrorInvalidOperation("copyTexSubImage2D: no texture image previously defined for this level and face"); 1.566 + 1.567 + const WebGLTexture::ImageInfo &imageInfo = tex->ImageInfoAt(target, level); 1.568 + GLsizei texWidth = imageInfo.Width(); 1.569 + GLsizei texHeight = imageInfo.Height(); 1.570 + 1.571 + if (xoffset + width > texWidth || xoffset + width < 0) 1.572 + return ErrorInvalidValue("copyTexSubImage2D: xoffset+width is too large"); 1.573 + 1.574 + if (yoffset + height > texHeight || yoffset + height < 0) 1.575 + return ErrorInvalidValue("copyTexSubImage2D: yoffset+height is too large"); 1.576 + 1.577 + GLenum webGLFormat = imageInfo.WebGLFormat(); 1.578 + if (IsGLDepthFormat(webGLFormat) || IsGLDepthStencilFormat(webGLFormat)) 1.579 + return ErrorInvalidOperation("copyTexSubImage2D: a base internal format of DEPTH_COMPONENT or DEPTH_STENCIL isn't supported"); 1.580 + 1.581 + if (mBoundFramebuffer) { 1.582 + if (!mBoundFramebuffer->CheckAndInitializeAttachments()) 1.583 + return ErrorInvalidFramebufferOperation("copyTexSubImage2D: incomplete framebuffer"); 1.584 + 1.585 + GLenum readPlaneBits = LOCAL_GL_COLOR_BUFFER_BIT; 1.586 + if (!mBoundFramebuffer->HasCompletePlanes(readPlaneBits)) { 1.587 + return ErrorInvalidOperation("copyTexSubImage2D: Read source attachment doesn't have the" 1.588 + " correct color/depth/stencil type."); 1.589 + } 1.590 + } else { 1.591 + ClearBackbufferIfNeeded(); 1.592 + } 1.593 + 1.594 + bool texFormatRequiresAlpha = FormatHasAlpha(webGLFormat); 1.595 + bool fboFormatHasAlpha = mBoundFramebuffer ? mBoundFramebuffer->ColorAttachment(0).HasAlpha() 1.596 + : bool(gl->GetPixelFormat().alpha > 0); 1.597 + 1.598 + if (texFormatRequiresAlpha && !fboFormatHasAlpha) 1.599 + return ErrorInvalidOperation("copyTexSubImage2D: texture format requires an alpha channel " 1.600 + "but the framebuffer doesn't have one"); 1.601 + 1.602 + if (imageInfo.HasUninitializedImageData()) { 1.603 + tex->DoDeferredImageInitialization(target, level); 1.604 + } 1.605 + 1.606 + return CopyTexSubImage2D_base(target, level, webGLFormat, xoffset, yoffset, x, y, width, height, true); 1.607 +} 1.608 + 1.609 + 1.610 +already_AddRefed<WebGLProgram> 1.611 +WebGLContext::CreateProgram() 1.612 +{ 1.613 + if (IsContextLost()) 1.614 + return nullptr; 1.615 + nsRefPtr<WebGLProgram> globj = new WebGLProgram(this); 1.616 + return globj.forget(); 1.617 +} 1.618 + 1.619 +already_AddRefed<WebGLShader> 1.620 +WebGLContext::CreateShader(GLenum type) 1.621 +{ 1.622 + if (IsContextLost()) 1.623 + return nullptr; 1.624 + 1.625 + if (type != LOCAL_GL_VERTEX_SHADER && 1.626 + type != LOCAL_GL_FRAGMENT_SHADER) 1.627 + { 1.628 + ErrorInvalidEnumInfo("createShader: type", type); 1.629 + return nullptr; 1.630 + } 1.631 + 1.632 + nsRefPtr<WebGLShader> shader = new WebGLShader(this, type); 1.633 + return shader.forget(); 1.634 +} 1.635 + 1.636 +void 1.637 +WebGLContext::CullFace(GLenum face) 1.638 +{ 1.639 + if (IsContextLost()) 1.640 + return; 1.641 + 1.642 + if (!ValidateFaceEnum(face, "cullFace")) 1.643 + return; 1.644 + 1.645 + MakeContextCurrent(); 1.646 + gl->fCullFace(face); 1.647 +} 1.648 + 1.649 +void 1.650 +WebGLContext::DeleteFramebuffer(WebGLFramebuffer* fbuf) 1.651 +{ 1.652 + if (IsContextLost()) 1.653 + return; 1.654 + 1.655 + if (!ValidateObjectAllowDeletedOrNull("deleteFramebuffer", fbuf)) 1.656 + return; 1.657 + 1.658 + if (!fbuf || fbuf->IsDeleted()) 1.659 + return; 1.660 + 1.661 + fbuf->RequestDelete(); 1.662 + 1.663 + if (mBoundFramebuffer == fbuf) 1.664 + BindFramebuffer(LOCAL_GL_FRAMEBUFFER, 1.665 + static_cast<WebGLFramebuffer*>(nullptr)); 1.666 +} 1.667 + 1.668 +void 1.669 +WebGLContext::DeleteRenderbuffer(WebGLRenderbuffer *rbuf) 1.670 +{ 1.671 + if (IsContextLost()) 1.672 + return; 1.673 + 1.674 + if (!ValidateObjectAllowDeletedOrNull("deleteRenderbuffer", rbuf)) 1.675 + return; 1.676 + 1.677 + if (!rbuf || rbuf->IsDeleted()) 1.678 + return; 1.679 + 1.680 + if (mBoundFramebuffer) 1.681 + mBoundFramebuffer->DetachRenderbuffer(rbuf); 1.682 + 1.683 + // Invalidate framebuffer status cache 1.684 + rbuf->NotifyFBsStatusChanged(); 1.685 + 1.686 + if (mBoundRenderbuffer == rbuf) 1.687 + BindRenderbuffer(LOCAL_GL_RENDERBUFFER, 1.688 + static_cast<WebGLRenderbuffer*>(nullptr)); 1.689 + 1.690 + rbuf->RequestDelete(); 1.691 +} 1.692 + 1.693 +void 1.694 +WebGLContext::DeleteTexture(WebGLTexture *tex) 1.695 +{ 1.696 + if (IsContextLost()) 1.697 + return; 1.698 + 1.699 + if (!ValidateObjectAllowDeletedOrNull("deleteTexture", tex)) 1.700 + return; 1.701 + 1.702 + if (!tex || tex->IsDeleted()) 1.703 + return; 1.704 + 1.705 + if (mBoundFramebuffer) 1.706 + mBoundFramebuffer->DetachTexture(tex); 1.707 + 1.708 + // Invalidate framebuffer status cache 1.709 + tex->NotifyFBsStatusChanged(); 1.710 + 1.711 + GLuint activeTexture = mActiveTexture; 1.712 + for (int32_t i = 0; i < mGLMaxTextureUnits; i++) { 1.713 + if ((tex->Target() == LOCAL_GL_TEXTURE_2D && mBound2DTextures[i] == tex) || 1.714 + (tex->Target() == LOCAL_GL_TEXTURE_CUBE_MAP && mBoundCubeMapTextures[i] == tex)) 1.715 + { 1.716 + ActiveTexture(LOCAL_GL_TEXTURE0 + i); 1.717 + BindTexture(tex->Target(), static_cast<WebGLTexture*>(nullptr)); 1.718 + } 1.719 + } 1.720 + ActiveTexture(LOCAL_GL_TEXTURE0 + activeTexture); 1.721 + 1.722 + tex->RequestDelete(); 1.723 +} 1.724 + 1.725 +void 1.726 +WebGLContext::DeleteProgram(WebGLProgram *prog) 1.727 +{ 1.728 + if (IsContextLost()) 1.729 + return; 1.730 + 1.731 + if (!ValidateObjectAllowDeletedOrNull("deleteProgram", prog)) 1.732 + return; 1.733 + 1.734 + if (!prog || prog->IsDeleted()) 1.735 + return; 1.736 + 1.737 + prog->RequestDelete(); 1.738 +} 1.739 + 1.740 +void 1.741 +WebGLContext::DeleteShader(WebGLShader *shader) 1.742 +{ 1.743 + if (IsContextLost()) 1.744 + return; 1.745 + 1.746 + if (!ValidateObjectAllowDeletedOrNull("deleteShader", shader)) 1.747 + return; 1.748 + 1.749 + if (!shader || shader->IsDeleted()) 1.750 + return; 1.751 + 1.752 + shader->RequestDelete(); 1.753 +} 1.754 + 1.755 +void 1.756 +WebGLContext::DetachShader(WebGLProgram *program, WebGLShader *shader) 1.757 +{ 1.758 + if (IsContextLost()) 1.759 + return; 1.760 + 1.761 + if (!ValidateObject("detachShader: program", program) || 1.762 + // it's valid to attempt to detach a deleted shader, since it's 1.763 + // still a shader 1.764 + !ValidateObjectAllowDeleted("detashShader: shader", shader)) 1.765 + return; 1.766 + 1.767 + if (!program->DetachShader(shader)) 1.768 + return ErrorInvalidOperation("detachShader: shader is not attached"); 1.769 +} 1.770 + 1.771 +void 1.772 +WebGLContext::DepthFunc(GLenum func) 1.773 +{ 1.774 + if (IsContextLost()) 1.775 + return; 1.776 + 1.777 + if (!ValidateComparisonEnum(func, "depthFunc")) 1.778 + return; 1.779 + 1.780 + MakeContextCurrent(); 1.781 + gl->fDepthFunc(func); 1.782 +} 1.783 + 1.784 +void 1.785 +WebGLContext::DepthRange(GLfloat zNear, GLfloat zFar) 1.786 +{ 1.787 + if (IsContextLost()) 1.788 + return; 1.789 + 1.790 + if (zNear > zFar) 1.791 + return ErrorInvalidOperation("depthRange: the near value is greater than the far value!"); 1.792 + 1.793 + MakeContextCurrent(); 1.794 + gl->fDepthRange(zNear, zFar); 1.795 +} 1.796 + 1.797 +void 1.798 +WebGLContext::FramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum rbtarget, WebGLRenderbuffer *wrb) 1.799 +{ 1.800 + if (IsContextLost()) 1.801 + return; 1.802 + 1.803 + if (!mBoundFramebuffer) 1.804 + return ErrorInvalidOperation("framebufferRenderbuffer: cannot modify framebuffer 0"); 1.805 + 1.806 + return mBoundFramebuffer->FramebufferRenderbuffer(target, attachment, rbtarget, wrb); 1.807 +} 1.808 + 1.809 +void 1.810 +WebGLContext::FramebufferTexture2D(GLenum target, 1.811 + GLenum attachment, 1.812 + GLenum textarget, 1.813 + WebGLTexture *tobj, 1.814 + GLint level) 1.815 +{ 1.816 + if (IsContextLost()) 1.817 + return; 1.818 + 1.819 + if (!mBoundFramebuffer) 1.820 + return ErrorInvalidOperation("framebufferRenderbuffer: cannot modify framebuffer 0"); 1.821 + 1.822 + return mBoundFramebuffer->FramebufferTexture2D(target, attachment, textarget, tobj, level); 1.823 +} 1.824 + 1.825 +void 1.826 +WebGLContext::FrontFace(GLenum mode) 1.827 +{ 1.828 + if (IsContextLost()) 1.829 + return; 1.830 + 1.831 + switch (mode) { 1.832 + case LOCAL_GL_CW: 1.833 + case LOCAL_GL_CCW: 1.834 + break; 1.835 + default: 1.836 + return ErrorInvalidEnumInfo("frontFace: mode", mode); 1.837 + } 1.838 + 1.839 + MakeContextCurrent(); 1.840 + gl->fFrontFace(mode); 1.841 +} 1.842 + 1.843 +already_AddRefed<WebGLActiveInfo> 1.844 +WebGLContext::GetActiveAttrib(WebGLProgram *prog, uint32_t index) 1.845 +{ 1.846 + if (IsContextLost()) 1.847 + return nullptr; 1.848 + 1.849 + if (!ValidateObject("getActiveAttrib: program", prog)) 1.850 + return nullptr; 1.851 + 1.852 + MakeContextCurrent(); 1.853 + 1.854 + GLint len = 0; 1.855 + GLuint progname = prog->GLName();; 1.856 + gl->fGetProgramiv(progname, LOCAL_GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &len); 1.857 + if (len == 0) 1.858 + return nullptr; 1.859 + 1.860 + nsAutoArrayPtr<char> name(new char[len]); 1.861 + GLint attrsize = 0; 1.862 + GLuint attrtype = 0; 1.863 + 1.864 + gl->fGetActiveAttrib(progname, index, len, &len, &attrsize, &attrtype, name); 1.865 + if (attrsize == 0 || attrtype == 0) { 1.866 + return nullptr; 1.867 + } 1.868 + 1.869 + nsCString reverseMappedName; 1.870 + prog->ReverseMapIdentifier(nsDependentCString(name), &reverseMappedName); 1.871 + 1.872 + nsRefPtr<WebGLActiveInfo> retActiveInfo = 1.873 + new WebGLActiveInfo(attrsize, attrtype, reverseMappedName); 1.874 + return retActiveInfo.forget(); 1.875 +} 1.876 + 1.877 +void 1.878 +WebGLContext::GenerateMipmap(GLenum target) 1.879 +{ 1.880 + if (IsContextLost()) 1.881 + return; 1.882 + 1.883 + if (!ValidateTextureTargetEnum(target, "generateMipmap")) 1.884 + return; 1.885 + 1.886 + WebGLTexture *tex = activeBoundTextureForTarget(target); 1.887 + 1.888 + if (!tex) 1.889 + return ErrorInvalidOperation("generateMipmap: No texture is bound to this target."); 1.890 + 1.891 + GLenum imageTarget = (target == LOCAL_GL_TEXTURE_2D) ? LOCAL_GL_TEXTURE_2D 1.892 + : LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X; 1.893 + if (!tex->HasImageInfoAt(imageTarget, 0)) 1.894 + { 1.895 + return ErrorInvalidOperation("generateMipmap: Level zero of texture is not defined."); 1.896 + } 1.897 + 1.898 + if (!tex->IsFirstImagePowerOfTwo()) 1.899 + return ErrorInvalidOperation("generateMipmap: Level zero of texture does not have power-of-two width and height."); 1.900 + 1.901 + GLenum webGLFormat = tex->ImageInfoAt(imageTarget, 0).WebGLFormat(); 1.902 + if (IsTextureFormatCompressed(webGLFormat)) 1.903 + return ErrorInvalidOperation("generateMipmap: Texture data at level zero is compressed."); 1.904 + 1.905 + if (IsExtensionEnabled(WebGLExtensionID::WEBGL_depth_texture) && 1.906 + (IsGLDepthFormat(webGLFormat) || IsGLDepthStencilFormat(webGLFormat))) 1.907 + { 1.908 + return ErrorInvalidOperation("generateMipmap: " 1.909 + "A texture that has a base internal format of " 1.910 + "DEPTH_COMPONENT or DEPTH_STENCIL isn't supported"); 1.911 + } 1.912 + 1.913 + if (!tex->AreAllLevel0ImageInfosEqual()) 1.914 + return ErrorInvalidOperation("generateMipmap: The six faces of this cube map have different dimensions, format, or type."); 1.915 + 1.916 + tex->SetGeneratedMipmap(); 1.917 + 1.918 + MakeContextCurrent(); 1.919 + 1.920 + if (gl->WorkAroundDriverBugs()) { 1.921 + // bug 696495 - to work around failures in the texture-mips.html test on various drivers, we 1.922 + // set the minification filter before calling glGenerateMipmap. This should not carry a significant performance 1.923 + // overhead so we do it unconditionally. 1.924 + // 1.925 + // note that the choice of GL_NEAREST_MIPMAP_NEAREST really matters. See Chromium bug 101105. 1.926 + gl->fTexParameteri(target, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_NEAREST_MIPMAP_NEAREST); 1.927 + gl->fGenerateMipmap(target); 1.928 + gl->fTexParameteri(target, LOCAL_GL_TEXTURE_MIN_FILTER, tex->MinFilter()); 1.929 + } else { 1.930 + gl->fGenerateMipmap(target); 1.931 + } 1.932 +} 1.933 + 1.934 +already_AddRefed<WebGLActiveInfo> 1.935 +WebGLContext::GetActiveUniform(WebGLProgram *prog, uint32_t index) 1.936 +{ 1.937 + if (IsContextLost()) 1.938 + return nullptr; 1.939 + 1.940 + if (!ValidateObject("getActiveUniform: program", prog)) 1.941 + return nullptr; 1.942 + 1.943 + MakeContextCurrent(); 1.944 + 1.945 + GLint len = 0; 1.946 + GLuint progname = prog->GLName(); 1.947 + gl->fGetProgramiv(progname, LOCAL_GL_ACTIVE_UNIFORM_MAX_LENGTH, &len); 1.948 + if (len == 0) 1.949 + return nullptr; 1.950 + 1.951 + nsAutoArrayPtr<char> name(new char[len]); 1.952 + 1.953 + GLint usize = 0; 1.954 + GLuint utype = 0; 1.955 + 1.956 + gl->fGetActiveUniform(progname, index, len, &len, &usize, &utype, name); 1.957 + if (len == 0 || usize == 0 || utype == 0) { 1.958 + return nullptr; 1.959 + } 1.960 + 1.961 + nsCString reverseMappedName; 1.962 + prog->ReverseMapIdentifier(nsDependentCString(name), &reverseMappedName); 1.963 + 1.964 + // OpenGL ES 2.0 specifies that if foo is a uniform array, GetActiveUniform returns its name as "foo[0]". 1.965 + // See section 2.10 page 35 in the OpenGL ES 2.0.24 specification: 1.966 + // 1.967 + // > If the active uniform is an array, the uniform name returned in name will always 1.968 + // > be the name of the uniform array appended with "[0]". 1.969 + // 1.970 + // There is no such requirement in the OpenGL (non-ES) spec and indeed we have OpenGL implementations returning 1.971 + // "foo" instead of "foo[0]". So, when implementing WebGL on top of desktop OpenGL, we must check if the 1.972 + // returned name ends in [0], and if it doesn't, append that. 1.973 + // 1.974 + // In principle we don't need to do that on OpenGL ES, but this is such a tricky difference between the ES and non-ES 1.975 + // specs that it seems probable that some ES implementers will overlook it. Since the work-around is quite cheap, 1.976 + // we do it unconditionally. 1.977 + if (usize > 1 && reverseMappedName.CharAt(reverseMappedName.Length()-1) != ']') 1.978 + reverseMappedName.AppendLiteral("[0]"); 1.979 + 1.980 + nsRefPtr<WebGLActiveInfo> retActiveInfo = 1.981 + new WebGLActiveInfo(usize, utype, reverseMappedName); 1.982 + return retActiveInfo.forget(); 1.983 +} 1.984 + 1.985 +void 1.986 +WebGLContext::GetAttachedShaders(WebGLProgram *prog, 1.987 + Nullable< nsTArray<WebGLShader*> > &retval) 1.988 +{ 1.989 + retval.SetNull(); 1.990 + if (IsContextLost()) 1.991 + return; 1.992 + 1.993 + if (!ValidateObjectAllowNull("getAttachedShaders", prog)) 1.994 + return; 1.995 + 1.996 + MakeContextCurrent(); 1.997 + 1.998 + if (!prog) { 1.999 + retval.SetNull(); 1.1000 + ErrorInvalidValue("getAttachedShaders: invalid program"); 1.1001 + } else if (prog->AttachedShaders().Length() == 0) { 1.1002 + retval.SetValue().TruncateLength(0); 1.1003 + } else { 1.1004 + retval.SetValue().AppendElements(prog->AttachedShaders()); 1.1005 + } 1.1006 +} 1.1007 + 1.1008 +GLint 1.1009 +WebGLContext::GetAttribLocation(WebGLProgram *prog, const nsAString& name) 1.1010 +{ 1.1011 + if (IsContextLost()) 1.1012 + return -1; 1.1013 + 1.1014 + if (!ValidateObject("getAttribLocation: program", prog)) 1.1015 + return -1; 1.1016 + 1.1017 + if (!ValidateGLSLVariableName(name, "getAttribLocation")) 1.1018 + return -1; 1.1019 + 1.1020 + NS_LossyConvertUTF16toASCII cname(name); 1.1021 + nsCString mappedName; 1.1022 + prog->MapIdentifier(cname, &mappedName); 1.1023 + 1.1024 + GLuint progname = prog->GLName(); 1.1025 + 1.1026 + MakeContextCurrent(); 1.1027 + return gl->fGetAttribLocation(progname, mappedName.get()); 1.1028 +} 1.1029 + 1.1030 +JS::Value 1.1031 +WebGLContext::GetBufferParameter(GLenum target, GLenum pname) 1.1032 +{ 1.1033 + if (IsContextLost()) 1.1034 + return JS::NullValue(); 1.1035 + 1.1036 + if (target != LOCAL_GL_ARRAY_BUFFER && target != LOCAL_GL_ELEMENT_ARRAY_BUFFER) { 1.1037 + ErrorInvalidEnumInfo("getBufferParameter: target", target); 1.1038 + return JS::NullValue(); 1.1039 + } 1.1040 + 1.1041 + MakeContextCurrent(); 1.1042 + 1.1043 + switch (pname) { 1.1044 + case LOCAL_GL_BUFFER_SIZE: 1.1045 + case LOCAL_GL_BUFFER_USAGE: 1.1046 + { 1.1047 + GLint i = 0; 1.1048 + gl->fGetBufferParameteriv(target, pname, &i); 1.1049 + if (pname == LOCAL_GL_BUFFER_SIZE) { 1.1050 + return JS::Int32Value(i); 1.1051 + } 1.1052 + 1.1053 + MOZ_ASSERT(pname == LOCAL_GL_BUFFER_USAGE); 1.1054 + return JS::NumberValue(uint32_t(i)); 1.1055 + } 1.1056 + break; 1.1057 + 1.1058 + default: 1.1059 + ErrorInvalidEnumInfo("getBufferParameter: parameter", pname); 1.1060 + } 1.1061 + 1.1062 + return JS::NullValue(); 1.1063 +} 1.1064 + 1.1065 +JS::Value 1.1066 +WebGLContext::GetFramebufferAttachmentParameter(JSContext* cx, 1.1067 + GLenum target, 1.1068 + GLenum attachment, 1.1069 + GLenum pname, 1.1070 + ErrorResult& rv) 1.1071 +{ 1.1072 + if (IsContextLost()) 1.1073 + return JS::NullValue(); 1.1074 + 1.1075 + if (target != LOCAL_GL_FRAMEBUFFER) { 1.1076 + ErrorInvalidEnumInfo("getFramebufferAttachmentParameter: target", target); 1.1077 + return JS::NullValue(); 1.1078 + } 1.1079 + 1.1080 + if (!mBoundFramebuffer) { 1.1081 + ErrorInvalidOperation("getFramebufferAttachmentParameter: cannot query framebuffer 0"); 1.1082 + return JS::NullValue(); 1.1083 + } 1.1084 + 1.1085 + if (attachment != LOCAL_GL_DEPTH_ATTACHMENT && 1.1086 + attachment != LOCAL_GL_STENCIL_ATTACHMENT && 1.1087 + attachment != LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) 1.1088 + { 1.1089 + if (IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers)) 1.1090 + { 1.1091 + if (attachment < LOCAL_GL_COLOR_ATTACHMENT0 || 1.1092 + attachment >= GLenum(LOCAL_GL_COLOR_ATTACHMENT0 + mGLMaxColorAttachments)) 1.1093 + { 1.1094 + ErrorInvalidEnumInfo("getFramebufferAttachmentParameter: attachment", attachment); 1.1095 + return JS::NullValue(); 1.1096 + } 1.1097 + 1.1098 + mBoundFramebuffer->EnsureColorAttachments(attachment - LOCAL_GL_COLOR_ATTACHMENT0); 1.1099 + } 1.1100 + else if (attachment != LOCAL_GL_COLOR_ATTACHMENT0) 1.1101 + { 1.1102 + ErrorInvalidEnumInfo("getFramebufferAttachmentParameter: attachment", attachment); 1.1103 + return JS::NullValue(); 1.1104 + } 1.1105 + } 1.1106 + 1.1107 + MakeContextCurrent(); 1.1108 + 1.1109 + const WebGLFramebuffer::Attachment& fba = mBoundFramebuffer->GetAttachment(attachment); 1.1110 + 1.1111 + if (fba.Renderbuffer()) { 1.1112 + switch (pname) { 1.1113 + case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT: 1.1114 + if (IsExtensionEnabled(WebGLExtensionID::EXT_sRGB)) { 1.1115 + const GLenum internalFormat = fba.Renderbuffer()->InternalFormat(); 1.1116 + return (internalFormat == LOCAL_GL_SRGB_EXT || 1.1117 + internalFormat == LOCAL_GL_SRGB_ALPHA_EXT || 1.1118 + internalFormat == LOCAL_GL_SRGB8_ALPHA8_EXT) ? 1.1119 + JS::NumberValue(uint32_t(LOCAL_GL_SRGB_EXT)) : 1.1120 + JS::NumberValue(uint32_t(LOCAL_GL_LINEAR)); 1.1121 + } 1.1122 + break; 1.1123 + 1.1124 + case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: 1.1125 + return JS::NumberValue(uint32_t(LOCAL_GL_RENDERBUFFER)); 1.1126 + 1.1127 + case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: 1.1128 + return WebGLObjectAsJSValue(cx, fba.Renderbuffer(), rv); 1.1129 + 1.1130 + case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: { 1.1131 + if (!IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float) && 1.1132 + !IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float)) 1.1133 + { 1.1134 + break; 1.1135 + } 1.1136 + 1.1137 + if (attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) { 1.1138 + ErrorInvalidOperation("getFramebufferAttachmentParameter: Cannot get component" 1.1139 + " type of a depth-stencil attachment."); 1.1140 + return JS::NullValue(); 1.1141 + } 1.1142 + 1.1143 + if (!fba.IsComplete()) 1.1144 + return JS::NumberValue(uint32_t(LOCAL_GL_NONE)); 1.1145 + 1.1146 + uint32_t ret = LOCAL_GL_NONE; 1.1147 + switch (fba.Renderbuffer()->InternalFormat()) { 1.1148 + case LOCAL_GL_RGBA4: 1.1149 + case LOCAL_GL_RGB5_A1: 1.1150 + case LOCAL_GL_RGB565: 1.1151 + case LOCAL_GL_SRGB8_ALPHA8: 1.1152 + ret = LOCAL_GL_UNSIGNED_NORMALIZED; 1.1153 + break; 1.1154 + case LOCAL_GL_RGB16F: 1.1155 + case LOCAL_GL_RGBA16F: 1.1156 + case LOCAL_GL_RGB32F: 1.1157 + case LOCAL_GL_RGBA32F: 1.1158 + ret = LOCAL_GL_FLOAT; 1.1159 + break; 1.1160 + case LOCAL_GL_DEPTH_COMPONENT16: 1.1161 + case LOCAL_GL_STENCIL_INDEX8: 1.1162 + ret = LOCAL_GL_UNSIGNED_INT; 1.1163 + break; 1.1164 + default: 1.1165 + MOZ_ASSERT(false, "Unhandled RB component type."); 1.1166 + break; 1.1167 + } 1.1168 + return JS::NumberValue(uint32_t(ret)); 1.1169 + } 1.1170 + } 1.1171 + 1.1172 + ErrorInvalidEnumInfo("getFramebufferAttachmentParameter: pname", pname); 1.1173 + return JS::NullValue(); 1.1174 + } else if (fba.Texture()) { 1.1175 + switch (pname) { 1.1176 + case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT: 1.1177 + if (IsExtensionEnabled(WebGLExtensionID::EXT_sRGB)) { 1.1178 + const GLenum webGLFormat = 1.1179 + fba.Texture()->ImageInfoBase().WebGLFormat(); 1.1180 + return (webGLFormat == LOCAL_GL_SRGB || 1.1181 + webGLFormat == LOCAL_GL_SRGB_ALPHA) ? 1.1182 + JS::NumberValue(uint32_t(LOCAL_GL_SRGB)) : 1.1183 + JS::NumberValue(uint32_t(LOCAL_GL_LINEAR)); 1.1184 + } 1.1185 + break; 1.1186 + 1.1187 + case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: 1.1188 + return JS::NumberValue(uint32_t(LOCAL_GL_TEXTURE)); 1.1189 + 1.1190 + case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: 1.1191 + return WebGLObjectAsJSValue(cx, fba.Texture(), rv); 1.1192 + 1.1193 + case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL: 1.1194 + return JS::Int32Value(fba.TexImageLevel()); 1.1195 + 1.1196 + case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE: { 1.1197 + GLenum face = fba.TexImageTarget(); 1.1198 + if (face == LOCAL_GL_TEXTURE_2D) 1.1199 + face = 0; 1.1200 + return JS::Int32Value(face); 1.1201 + } 1.1202 + 1.1203 + case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: { 1.1204 + if (!IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float) && 1.1205 + !IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float)) 1.1206 + { 1.1207 + break; 1.1208 + } 1.1209 + 1.1210 + if (attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) { 1.1211 + ErrorInvalidOperation("getFramebufferAttachmentParameter: cannot component" 1.1212 + " type of depth-stencil attachments."); 1.1213 + return JS::NullValue(); 1.1214 + } 1.1215 + 1.1216 + if (!fba.IsComplete()) 1.1217 + return JS::NumberValue(uint32_t(LOCAL_GL_NONE)); 1.1218 + 1.1219 + uint32_t ret = LOCAL_GL_NONE; 1.1220 + GLenum type = fba.Texture()->ImageInfoAt(fba.TexImageTarget(), 1.1221 + fba.TexImageLevel()).WebGLType(); 1.1222 + switch (type) { 1.1223 + case LOCAL_GL_UNSIGNED_BYTE: 1.1224 + case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4: 1.1225 + case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1: 1.1226 + case LOCAL_GL_UNSIGNED_SHORT_5_6_5: 1.1227 + ret = LOCAL_GL_UNSIGNED_NORMALIZED; 1.1228 + break; 1.1229 + case LOCAL_GL_FLOAT: 1.1230 + case LOCAL_GL_HALF_FLOAT_OES: 1.1231 + ret = LOCAL_GL_FLOAT; 1.1232 + break; 1.1233 + case LOCAL_GL_UNSIGNED_SHORT: 1.1234 + case LOCAL_GL_UNSIGNED_INT: 1.1235 + ret = LOCAL_GL_UNSIGNED_INT; 1.1236 + break; 1.1237 + default: 1.1238 + MOZ_ASSERT(false, "Unhandled RB component type."); 1.1239 + break; 1.1240 + } 1.1241 + return JS::NumberValue(uint32_t(ret)); 1.1242 + } 1.1243 + } 1.1244 + 1.1245 + ErrorInvalidEnumInfo("getFramebufferAttachmentParameter: pname", pname); 1.1246 + return JS::NullValue(); 1.1247 + } else { 1.1248 + switch (pname) { 1.1249 + case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: 1.1250 + return JS::NumberValue(uint32_t(LOCAL_GL_NONE)); 1.1251 + 1.1252 + default: 1.1253 + ErrorInvalidEnumInfo("getFramebufferAttachmentParameter: pname", pname); 1.1254 + return JS::NullValue(); 1.1255 + } 1.1256 + } 1.1257 + 1.1258 + return JS::NullValue(); 1.1259 +} 1.1260 + 1.1261 +JS::Value 1.1262 +WebGLContext::GetRenderbufferParameter(GLenum target, GLenum pname) 1.1263 +{ 1.1264 + if (IsContextLost()) 1.1265 + return JS::NullValue(); 1.1266 + 1.1267 + if (target != LOCAL_GL_RENDERBUFFER) { 1.1268 + ErrorInvalidEnumInfo("getRenderbufferParameter: target", target); 1.1269 + return JS::NullValue(); 1.1270 + } 1.1271 + 1.1272 + if (!mBoundRenderbuffer) { 1.1273 + ErrorInvalidOperation("getRenderbufferParameter: no render buffer is bound"); 1.1274 + return JS::NullValue(); 1.1275 + } 1.1276 + 1.1277 + MakeContextCurrent(); 1.1278 + 1.1279 + switch (pname) { 1.1280 + case LOCAL_GL_RENDERBUFFER_WIDTH: 1.1281 + case LOCAL_GL_RENDERBUFFER_HEIGHT: 1.1282 + case LOCAL_GL_RENDERBUFFER_RED_SIZE: 1.1283 + case LOCAL_GL_RENDERBUFFER_GREEN_SIZE: 1.1284 + case LOCAL_GL_RENDERBUFFER_BLUE_SIZE: 1.1285 + case LOCAL_GL_RENDERBUFFER_ALPHA_SIZE: 1.1286 + case LOCAL_GL_RENDERBUFFER_DEPTH_SIZE: 1.1287 + case LOCAL_GL_RENDERBUFFER_STENCIL_SIZE: 1.1288 + { 1.1289 + // RB emulation means we have to ask the RB itself. 1.1290 + GLint i = mBoundRenderbuffer->GetRenderbufferParameter(target, pname); 1.1291 + return JS::Int32Value(i); 1.1292 + } 1.1293 + case LOCAL_GL_RENDERBUFFER_INTERNAL_FORMAT: 1.1294 + { 1.1295 + return JS::NumberValue(mBoundRenderbuffer->InternalFormat()); 1.1296 + } 1.1297 + default: 1.1298 + ErrorInvalidEnumInfo("getRenderbufferParameter: parameter", pname); 1.1299 + } 1.1300 + 1.1301 + return JS::NullValue(); 1.1302 +} 1.1303 + 1.1304 +already_AddRefed<WebGLTexture> 1.1305 +WebGLContext::CreateTexture() 1.1306 +{ 1.1307 + if (IsContextLost()) 1.1308 + return nullptr; 1.1309 + nsRefPtr<WebGLTexture> globj = new WebGLTexture(this); 1.1310 + return globj.forget(); 1.1311 +} 1.1312 + 1.1313 +static GLenum 1.1314 +GetAndClearError(GLenum* errorVar) 1.1315 +{ 1.1316 + MOZ_ASSERT(errorVar); 1.1317 + GLenum ret = *errorVar; 1.1318 + *errorVar = LOCAL_GL_NO_ERROR; 1.1319 + return ret; 1.1320 +} 1.1321 + 1.1322 +GLenum 1.1323 +WebGLContext::GetError() 1.1324 +{ 1.1325 + /* WebGL 1.0: Section 5.14.3: Setting and getting state: 1.1326 + * If the context's webgl context lost flag is set, returns 1.1327 + * CONTEXT_LOST_WEBGL the first time this method is called. 1.1328 + * Afterward, returns NO_ERROR until the context has been 1.1329 + * restored. 1.1330 + * 1.1331 + * WEBGL_lose_context: 1.1332 + * [When this extension is enabled: ] loseContext and 1.1333 + * restoreContext are allowed to generate INVALID_OPERATION errors 1.1334 + * even when the context is lost. 1.1335 + */ 1.1336 + 1.1337 + if (IsContextLost()) { 1.1338 + if (mEmitContextLostErrorOnce) { 1.1339 + mEmitContextLostErrorOnce = false; 1.1340 + return LOCAL_GL_CONTEXT_LOST; 1.1341 + } 1.1342 + // Don't return yet, since WEBGL_lose_contexts contradicts the 1.1343 + // original spec, and allows error generation while lost. 1.1344 + } 1.1345 + 1.1346 + GLenum err = GetAndClearError(&mWebGLError); 1.1347 + if (err != LOCAL_GL_NO_ERROR) 1.1348 + return err; 1.1349 + 1.1350 + if (IsContextLost()) 1.1351 + return LOCAL_GL_NO_ERROR; 1.1352 + 1.1353 + // Either no WebGL-side error, or it's already been cleared. 1.1354 + // UnderlyingGL-side errors, now. 1.1355 + 1.1356 + MakeContextCurrent(); 1.1357 + GetAndFlushUnderlyingGLErrors(); 1.1358 + 1.1359 + err = GetAndClearError(&mUnderlyingGLError); 1.1360 + return err; 1.1361 +} 1.1362 + 1.1363 +JS::Value 1.1364 +WebGLContext::GetProgramParameter(WebGLProgram *prog, GLenum pname) 1.1365 +{ 1.1366 + if (IsContextLost()) 1.1367 + return JS::NullValue(); 1.1368 + 1.1369 + if (!ValidateObjectAllowDeleted("getProgramParameter: program", prog)) 1.1370 + return JS::NullValue(); 1.1371 + 1.1372 + GLuint progname = prog->GLName(); 1.1373 + 1.1374 + MakeContextCurrent(); 1.1375 + 1.1376 + switch (pname) { 1.1377 + case LOCAL_GL_ATTACHED_SHADERS: 1.1378 + case LOCAL_GL_ACTIVE_UNIFORMS: 1.1379 + case LOCAL_GL_ACTIVE_ATTRIBUTES: 1.1380 + { 1.1381 + GLint i = 0; 1.1382 + gl->fGetProgramiv(progname, pname, &i); 1.1383 + return JS::Int32Value(i); 1.1384 + } 1.1385 + case LOCAL_GL_DELETE_STATUS: 1.1386 + return JS::BooleanValue(prog->IsDeleteRequested()); 1.1387 + case LOCAL_GL_LINK_STATUS: 1.1388 + { 1.1389 + return JS::BooleanValue(prog->LinkStatus()); 1.1390 + } 1.1391 + case LOCAL_GL_VALIDATE_STATUS: 1.1392 + { 1.1393 + GLint i = 0; 1.1394 +#ifdef XP_MACOSX 1.1395 + // See comment in ValidateProgram below. 1.1396 + if (gl->WorkAroundDriverBugs()) 1.1397 + i = 1; 1.1398 + else 1.1399 + gl->fGetProgramiv(progname, pname, &i); 1.1400 +#else 1.1401 + gl->fGetProgramiv(progname, pname, &i); 1.1402 +#endif 1.1403 + return JS::BooleanValue(bool(i)); 1.1404 + } 1.1405 + break; 1.1406 + 1.1407 + default: 1.1408 + ErrorInvalidEnumInfo("getProgramParameter: parameter", pname); 1.1409 + } 1.1410 + 1.1411 + return JS::NullValue(); 1.1412 +} 1.1413 + 1.1414 +void 1.1415 +WebGLContext::GetProgramInfoLog(WebGLProgram *prog, nsAString& retval) 1.1416 +{ 1.1417 + nsAutoCString s; 1.1418 + GetProgramInfoLog(prog, s); 1.1419 + if (s.IsVoid()) 1.1420 + retval.SetIsVoid(true); 1.1421 + else 1.1422 + CopyASCIItoUTF16(s, retval); 1.1423 +} 1.1424 + 1.1425 +void 1.1426 +WebGLContext::GetProgramInfoLog(WebGLProgram *prog, nsACString& retval) 1.1427 +{ 1.1428 + if (IsContextLost()) 1.1429 + { 1.1430 + retval.SetIsVoid(true); 1.1431 + return; 1.1432 + } 1.1433 + 1.1434 + if (!ValidateObject("getProgramInfoLog: program", prog)) { 1.1435 + retval.Truncate(); 1.1436 + return; 1.1437 + } 1.1438 + 1.1439 + GLuint progname = prog->GLName(); 1.1440 + 1.1441 + MakeContextCurrent(); 1.1442 + 1.1443 + GLint k = -1; 1.1444 + gl->fGetProgramiv(progname, LOCAL_GL_INFO_LOG_LENGTH, &k); 1.1445 + if (k == -1) { 1.1446 + // If GetProgramiv doesn't modify |k|, 1.1447 + // it's because there was a GL error. 1.1448 + // GetProgramInfoLog should return null on error. (Bug 746740) 1.1449 + retval.SetIsVoid(true); 1.1450 + return; 1.1451 + } 1.1452 + 1.1453 + if (k == 0) { 1.1454 + retval.Truncate(); 1.1455 + return; 1.1456 + } 1.1457 + 1.1458 + retval.SetCapacity(k); 1.1459 + gl->fGetProgramInfoLog(progname, k, &k, (char*) retval.BeginWriting()); 1.1460 + retval.SetLength(k); 1.1461 +} 1.1462 + 1.1463 +// here we have to support all pnames with both int and float params. 1.1464 +// See this discussion: 1.1465 +// https://www.khronos.org/webgl/public-mailing-list/archives/1008/msg00014.html 1.1466 +void WebGLContext::TexParameter_base(GLenum target, GLenum pname, 1.1467 + GLint *intParamPtr, 1.1468 + GLfloat *floatParamPtr) 1.1469 +{ 1.1470 + MOZ_ASSERT(intParamPtr || floatParamPtr); 1.1471 + 1.1472 + if (IsContextLost()) 1.1473 + return; 1.1474 + 1.1475 + GLint intParam = intParamPtr ? *intParamPtr : GLint(*floatParamPtr); 1.1476 + GLfloat floatParam = floatParamPtr ? *floatParamPtr : GLfloat(*intParamPtr); 1.1477 + 1.1478 + if (!ValidateTextureTargetEnum(target, "texParameter: target")) 1.1479 + return; 1.1480 + 1.1481 + WebGLTexture *tex = activeBoundTextureForTarget(target); 1.1482 + if (!tex) 1.1483 + return ErrorInvalidOperation("texParameter: no texture is bound to this target"); 1.1484 + 1.1485 + bool pnameAndParamAreIncompatible = false; 1.1486 + bool paramValueInvalid = false; 1.1487 + 1.1488 + switch (pname) { 1.1489 + case LOCAL_GL_TEXTURE_MIN_FILTER: 1.1490 + switch (intParam) { 1.1491 + case LOCAL_GL_NEAREST: 1.1492 + case LOCAL_GL_LINEAR: 1.1493 + case LOCAL_GL_NEAREST_MIPMAP_NEAREST: 1.1494 + case LOCAL_GL_LINEAR_MIPMAP_NEAREST: 1.1495 + case LOCAL_GL_NEAREST_MIPMAP_LINEAR: 1.1496 + case LOCAL_GL_LINEAR_MIPMAP_LINEAR: 1.1497 + tex->SetMinFilter(intParam); 1.1498 + break; 1.1499 + default: 1.1500 + pnameAndParamAreIncompatible = true; 1.1501 + } 1.1502 + break; 1.1503 + case LOCAL_GL_TEXTURE_MAG_FILTER: 1.1504 + switch (intParam) { 1.1505 + case LOCAL_GL_NEAREST: 1.1506 + case LOCAL_GL_LINEAR: 1.1507 + tex->SetMagFilter(intParam); 1.1508 + break; 1.1509 + default: 1.1510 + pnameAndParamAreIncompatible = true; 1.1511 + } 1.1512 + break; 1.1513 + case LOCAL_GL_TEXTURE_WRAP_S: 1.1514 + switch (intParam) { 1.1515 + case LOCAL_GL_CLAMP_TO_EDGE: 1.1516 + case LOCAL_GL_MIRRORED_REPEAT: 1.1517 + case LOCAL_GL_REPEAT: 1.1518 + tex->SetWrapS(intParam); 1.1519 + break; 1.1520 + default: 1.1521 + pnameAndParamAreIncompatible = true; 1.1522 + } 1.1523 + break; 1.1524 + case LOCAL_GL_TEXTURE_WRAP_T: 1.1525 + switch (intParam) { 1.1526 + case LOCAL_GL_CLAMP_TO_EDGE: 1.1527 + case LOCAL_GL_MIRRORED_REPEAT: 1.1528 + case LOCAL_GL_REPEAT: 1.1529 + tex->SetWrapT(intParam); 1.1530 + break; 1.1531 + default: 1.1532 + pnameAndParamAreIncompatible = true; 1.1533 + } 1.1534 + break; 1.1535 + case LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT: 1.1536 + if (IsExtensionEnabled(WebGLExtensionID::EXT_texture_filter_anisotropic)) { 1.1537 + if (floatParamPtr && floatParam < 1.f) 1.1538 + paramValueInvalid = true; 1.1539 + else if (intParamPtr && intParam < 1) 1.1540 + paramValueInvalid = true; 1.1541 + } 1.1542 + else 1.1543 + pnameAndParamAreIncompatible = true; 1.1544 + break; 1.1545 + default: 1.1546 + return ErrorInvalidEnumInfo("texParameter: pname", pname); 1.1547 + } 1.1548 + 1.1549 + if (pnameAndParamAreIncompatible) { 1.1550 + if (intParamPtr) 1.1551 + return ErrorInvalidEnum("texParameteri: pname %x and param %x (decimal %d) are mutually incompatible", 1.1552 + pname, intParam, intParam); 1.1553 + else 1.1554 + return ErrorInvalidEnum("texParameterf: pname %x and param %g are mutually incompatible", 1.1555 + pname, floatParam); 1.1556 + } else if (paramValueInvalid) { 1.1557 + if (intParamPtr) 1.1558 + return ErrorInvalidValue("texParameteri: pname %x and param %x (decimal %d) is invalid", 1.1559 + pname, intParam, intParam); 1.1560 + else 1.1561 + return ErrorInvalidValue("texParameterf: pname %x and param %g is invalid", 1.1562 + pname, floatParam); 1.1563 + } 1.1564 + 1.1565 + MakeContextCurrent(); 1.1566 + if (intParamPtr) 1.1567 + gl->fTexParameteri(target, pname, intParam); 1.1568 + else 1.1569 + gl->fTexParameterf(target, pname, floatParam); 1.1570 +} 1.1571 + 1.1572 +JS::Value 1.1573 +WebGLContext::GetTexParameter(GLenum target, GLenum pname) 1.1574 +{ 1.1575 + if (IsContextLost()) 1.1576 + return JS::NullValue(); 1.1577 + 1.1578 + MakeContextCurrent(); 1.1579 + 1.1580 + if (!ValidateTextureTargetEnum(target, "getTexParameter: target")) 1.1581 + return JS::NullValue(); 1.1582 + 1.1583 + if (!activeBoundTextureForTarget(target)) { 1.1584 + ErrorInvalidOperation("getTexParameter: no texture bound"); 1.1585 + return JS::NullValue(); 1.1586 + } 1.1587 + 1.1588 + switch (pname) { 1.1589 + case LOCAL_GL_TEXTURE_MIN_FILTER: 1.1590 + case LOCAL_GL_TEXTURE_MAG_FILTER: 1.1591 + case LOCAL_GL_TEXTURE_WRAP_S: 1.1592 + case LOCAL_GL_TEXTURE_WRAP_T: 1.1593 + { 1.1594 + GLint i = 0; 1.1595 + gl->fGetTexParameteriv(target, pname, &i); 1.1596 + return JS::NumberValue(uint32_t(i)); 1.1597 + } 1.1598 + case LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT: 1.1599 + if (IsExtensionEnabled(WebGLExtensionID::EXT_texture_filter_anisotropic)) { 1.1600 + GLfloat f = 0.f; 1.1601 + gl->fGetTexParameterfv(target, pname, &f); 1.1602 + return JS::DoubleValue(f); 1.1603 + } 1.1604 + 1.1605 + ErrorInvalidEnumInfo("getTexParameter: parameter", pname); 1.1606 + break; 1.1607 + 1.1608 + default: 1.1609 + ErrorInvalidEnumInfo("getTexParameter: parameter", pname); 1.1610 + } 1.1611 + 1.1612 + return JS::NullValue(); 1.1613 +} 1.1614 + 1.1615 +JS::Value 1.1616 +WebGLContext::GetUniform(JSContext* cx, WebGLProgram *prog, 1.1617 + WebGLUniformLocation *location) 1.1618 +{ 1.1619 + if (IsContextLost()) 1.1620 + return JS::NullValue(); 1.1621 + 1.1622 + if (!ValidateObject("getUniform: program", prog)) 1.1623 + return JS::NullValue(); 1.1624 + 1.1625 + if (!ValidateObject("getUniform: location", location)) 1.1626 + return JS::NullValue(); 1.1627 + 1.1628 + if (location->Program() != prog) { 1.1629 + ErrorInvalidValue("getUniform: this uniform location corresponds to another program"); 1.1630 + return JS::NullValue(); 1.1631 + } 1.1632 + 1.1633 + if (location->ProgramGeneration() != prog->Generation()) { 1.1634 + ErrorInvalidOperation("getUniform: this uniform location is obsolete since the program has been relinked"); 1.1635 + return JS::NullValue(); 1.1636 + } 1.1637 + 1.1638 + GLuint progname = prog->GLName(); 1.1639 + 1.1640 + MakeContextCurrent(); 1.1641 + 1.1642 + GLint uniforms = 0; 1.1643 + GLint uniformNameMaxLength = 0; 1.1644 + gl->fGetProgramiv(progname, LOCAL_GL_ACTIVE_UNIFORMS, &uniforms); 1.1645 + gl->fGetProgramiv(progname, LOCAL_GL_ACTIVE_UNIFORM_MAX_LENGTH, &uniformNameMaxLength); 1.1646 + 1.1647 + // we now need the type info to switch between fGetUniformfv and fGetUniformiv 1.1648 + // the only way to get that is to iterate through all active uniforms by index until 1.1649 + // one matches the given uniform location. 1.1650 + GLenum uniformType = 0; 1.1651 + nsAutoArrayPtr<GLchar> uniformName(new GLchar[uniformNameMaxLength]); 1.1652 + // this buffer has 16 more bytes to be able to store [index] at the end. 1.1653 + nsAutoArrayPtr<GLchar> uniformNameBracketIndex(new GLchar[uniformNameMaxLength + 16]); 1.1654 + 1.1655 + GLint index; 1.1656 + for (index = 0; index < uniforms; ++index) { 1.1657 + GLsizei length; 1.1658 + GLint size; 1.1659 + gl->fGetActiveUniform(progname, index, uniformNameMaxLength, &length, 1.1660 + &size, &uniformType, uniformName); 1.1661 + if (gl->fGetUniformLocation(progname, uniformName) == location->Location()) 1.1662 + break; 1.1663 + 1.1664 + // now we handle the case of array uniforms. In that case, fGetActiveUniform returned as 'size' 1.1665 + // the biggest index used plus one, so we need to loop over that. The 0 index has already been handled above, 1.1666 + // so we can start at one. For each index, we construct the string uniformName + "[" + index + "]". 1.1667 + if (size > 1) { 1.1668 + bool found_it = false; 1.1669 + if (uniformName[length - 1] == ']') { // if uniformName ends in [0] 1.1670 + // remove the [0] at the end 1.1671 + length -= 3; 1.1672 + uniformName[length] = 0; 1.1673 + } 1.1674 + for (GLint arrayIndex = 1; arrayIndex < size; arrayIndex++) { 1.1675 + sprintf(uniformNameBracketIndex.get(), "%s[%d]", uniformName.get(), arrayIndex); 1.1676 + if (gl->fGetUniformLocation(progname, uniformNameBracketIndex) == location->Location()) { 1.1677 + found_it = true; 1.1678 + break; 1.1679 + } 1.1680 + } 1.1681 + if (found_it) break; 1.1682 + } 1.1683 + } 1.1684 + 1.1685 + if (index == uniforms) { 1.1686 + GenerateWarning("getUniform: internal error: hit an OpenGL driver bug"); 1.1687 + return JS::NullValue(); 1.1688 + } 1.1689 + 1.1690 + GLenum baseType; 1.1691 + GLint unitSize; 1.1692 + if (!BaseTypeAndSizeFromUniformType(uniformType, &baseType, &unitSize)) { 1.1693 + GenerateWarning("getUniform: internal error: unknown uniform type 0x%x", uniformType); 1.1694 + return JS::NullValue(); 1.1695 + } 1.1696 + 1.1697 + // this should never happen 1.1698 + if (unitSize > 16) { 1.1699 + GenerateWarning("getUniform: internal error: unexpected uniform unit size %d", unitSize); 1.1700 + return JS::NullValue(); 1.1701 + } 1.1702 + 1.1703 + if (baseType == LOCAL_GL_FLOAT) { 1.1704 + GLfloat fv[16] = { GLfloat(0) }; 1.1705 + gl->fGetUniformfv(progname, location->Location(), fv); 1.1706 + if (unitSize == 1) { 1.1707 + return JS::DoubleValue(fv[0]); 1.1708 + } else { 1.1709 + JSObject* obj = Float32Array::Create(cx, this, unitSize, fv); 1.1710 + if (!obj) { 1.1711 + ErrorOutOfMemory("getUniform: out of memory"); 1.1712 + return JS::NullValue(); 1.1713 + } 1.1714 + return JS::ObjectOrNullValue(obj); 1.1715 + } 1.1716 + } else if (baseType == LOCAL_GL_INT) { 1.1717 + GLint iv[16] = { 0 }; 1.1718 + gl->fGetUniformiv(progname, location->Location(), iv); 1.1719 + if (unitSize == 1) { 1.1720 + return JS::Int32Value(iv[0]); 1.1721 + } else { 1.1722 + JSObject* obj = Int32Array::Create(cx, this, unitSize, iv); 1.1723 + if (!obj) { 1.1724 + ErrorOutOfMemory("getUniform: out of memory"); 1.1725 + return JS::NullValue(); 1.1726 + } 1.1727 + return JS::ObjectOrNullValue(obj); 1.1728 + } 1.1729 + } else if (baseType == LOCAL_GL_BOOL) { 1.1730 + GLint iv[16] = { 0 }; 1.1731 + gl->fGetUniformiv(progname, location->Location(), iv); 1.1732 + if (unitSize == 1) { 1.1733 + return JS::BooleanValue(iv[0] ? true : false); 1.1734 + } else { 1.1735 + bool uv[16]; 1.1736 + for (int k = 0; k < unitSize; k++) 1.1737 + uv[k] = iv[k]; 1.1738 + JS::Rooted<JS::Value> val(cx); 1.1739 + // Be careful: we don't want to convert all of |uv|! 1.1740 + if (!ToJSValue(cx, uv, unitSize, &val)) { 1.1741 + ErrorOutOfMemory("getUniform: out of memory"); 1.1742 + return JS::NullValue(); 1.1743 + } 1.1744 + return val; 1.1745 + } 1.1746 + } 1.1747 + 1.1748 + // Else preserving behavior, but I'm not sure this is correct per spec 1.1749 + return JS::UndefinedValue(); 1.1750 +} 1.1751 + 1.1752 +already_AddRefed<WebGLUniformLocation> 1.1753 +WebGLContext::GetUniformLocation(WebGLProgram *prog, const nsAString& name) 1.1754 +{ 1.1755 + if (IsContextLost()) 1.1756 + return nullptr; 1.1757 + 1.1758 + if (!ValidateObject("getUniformLocation: program", prog)) 1.1759 + return nullptr; 1.1760 + 1.1761 + if (!ValidateGLSLVariableName(name, "getUniformLocation")) 1.1762 + return nullptr; 1.1763 + 1.1764 + NS_LossyConvertUTF16toASCII cname(name); 1.1765 + nsCString mappedName; 1.1766 + prog->MapIdentifier(cname, &mappedName); 1.1767 + 1.1768 + GLuint progname = prog->GLName(); 1.1769 + MakeContextCurrent(); 1.1770 + GLint intlocation = gl->fGetUniformLocation(progname, mappedName.get()); 1.1771 + 1.1772 + nsRefPtr<WebGLUniformLocation> loc; 1.1773 + if (intlocation >= 0) { 1.1774 + WebGLUniformInfo info = prog->GetUniformInfoForMappedIdentifier(mappedName); 1.1775 + loc = new WebGLUniformLocation(this, 1.1776 + prog, 1.1777 + intlocation, 1.1778 + info); 1.1779 + } 1.1780 + return loc.forget(); 1.1781 +} 1.1782 + 1.1783 +void 1.1784 +WebGLContext::Hint(GLenum target, GLenum mode) 1.1785 +{ 1.1786 + if (IsContextLost()) 1.1787 + return; 1.1788 + 1.1789 + bool isValid = false; 1.1790 + 1.1791 + switch (target) { 1.1792 + case LOCAL_GL_GENERATE_MIPMAP_HINT: 1.1793 + isValid = true; 1.1794 + break; 1.1795 + case LOCAL_GL_FRAGMENT_SHADER_DERIVATIVE_HINT: 1.1796 + if (IsExtensionEnabled(WebGLExtensionID::OES_standard_derivatives)) 1.1797 + isValid = true; 1.1798 + break; 1.1799 + } 1.1800 + 1.1801 + if (!isValid) 1.1802 + return ErrorInvalidEnum("hint: invalid hint"); 1.1803 + 1.1804 + MakeContextCurrent(); 1.1805 + gl->fHint(target, mode); 1.1806 +} 1.1807 + 1.1808 +bool 1.1809 +WebGLContext::IsFramebuffer(WebGLFramebuffer *fb) 1.1810 +{ 1.1811 + if (IsContextLost()) 1.1812 + return false; 1.1813 + 1.1814 + return ValidateObjectAllowDeleted("isFramebuffer", fb) && 1.1815 + !fb->IsDeleted() && 1.1816 + fb->HasEverBeenBound(); 1.1817 +} 1.1818 + 1.1819 +bool 1.1820 +WebGLContext::IsProgram(WebGLProgram *prog) 1.1821 +{ 1.1822 + if (IsContextLost()) 1.1823 + return false; 1.1824 + 1.1825 + return ValidateObjectAllowDeleted("isProgram", prog) && !prog->IsDeleted(); 1.1826 +} 1.1827 + 1.1828 +bool 1.1829 +WebGLContext::IsRenderbuffer(WebGLRenderbuffer *rb) 1.1830 +{ 1.1831 + if (IsContextLost()) 1.1832 + return false; 1.1833 + 1.1834 + return ValidateObjectAllowDeleted("isRenderBuffer", rb) && 1.1835 + !rb->IsDeleted() && 1.1836 + rb->HasEverBeenBound(); 1.1837 +} 1.1838 + 1.1839 +bool 1.1840 +WebGLContext::IsShader(WebGLShader *shader) 1.1841 +{ 1.1842 + if (IsContextLost()) 1.1843 + return false; 1.1844 + 1.1845 + return ValidateObjectAllowDeleted("isShader", shader) && 1.1846 + !shader->IsDeleted(); 1.1847 +} 1.1848 + 1.1849 +bool 1.1850 +WebGLContext::IsTexture(WebGLTexture *tex) 1.1851 +{ 1.1852 + if (IsContextLost()) 1.1853 + return false; 1.1854 + 1.1855 + return ValidateObjectAllowDeleted("isTexture", tex) && 1.1856 + !tex->IsDeleted() && 1.1857 + tex->HasEverBeenBound(); 1.1858 +} 1.1859 + 1.1860 +// Try to bind an attribute that is an array to location 0: 1.1861 +bool WebGLContext::BindArrayAttribToLocation0(WebGLProgram *program) 1.1862 +{ 1.1863 + if (mBoundVertexArray->IsAttribArrayEnabled(0)) { 1.1864 + return false; 1.1865 + } 1.1866 + 1.1867 + GLint leastArrayLocation = -1; 1.1868 + 1.1869 + std::map<GLint, nsCString>::iterator itr; 1.1870 + for (itr = program->mActiveAttribMap.begin(); 1.1871 + itr != program->mActiveAttribMap.end(); 1.1872 + itr++) { 1.1873 + int32_t index = itr->first; 1.1874 + if (mBoundVertexArray->IsAttribArrayEnabled(index) && 1.1875 + index < leastArrayLocation) 1.1876 + { 1.1877 + leastArrayLocation = index; 1.1878 + } 1.1879 + } 1.1880 + 1.1881 + if (leastArrayLocation > 0) { 1.1882 + nsCString& attrName = program->mActiveAttribMap.find(leastArrayLocation)->second; 1.1883 + const char* attrNameCStr = attrName.get(); 1.1884 + gl->fBindAttribLocation(program->GLName(), 0, attrNameCStr); 1.1885 + return true; 1.1886 + } 1.1887 + return false; 1.1888 +} 1.1889 + 1.1890 +void 1.1891 +WebGLContext::LinkProgram(WebGLProgram *program) 1.1892 +{ 1.1893 + if (IsContextLost()) 1.1894 + return; 1.1895 + 1.1896 + if (!ValidateObject("linkProgram", program)) 1.1897 + return; 1.1898 + 1.1899 + InvalidateBufferFetching(); // we do it early in this function 1.1900 + // as some of the validation below changes program state 1.1901 + 1.1902 + GLuint progname = program->GLName(); 1.1903 + 1.1904 + if (!program->NextGeneration()) { 1.1905 + // XXX throw? 1.1906 + return; 1.1907 + } 1.1908 + 1.1909 + if (!program->HasBothShaderTypesAttached()) { 1.1910 + GenerateWarning("linkProgram: this program doesn't have both a vertex shader" 1.1911 + " and a fragment shader"); 1.1912 + program->SetLinkStatus(false); 1.1913 + return; 1.1914 + } 1.1915 + 1.1916 + // bug 777028 1.1917 + // Mesa can't handle more than 16 samplers per program, counting each array entry. 1.1918 + if (gl->WorkAroundDriverBugs() && 1.1919 + mIsMesa && 1.1920 + program->UpperBoundNumSamplerUniforms() > 16) 1.1921 + { 1.1922 + GenerateWarning("Programs with more than 16 samplers are disallowed on Mesa drivers " "to avoid a Mesa crasher."); 1.1923 + program->SetLinkStatus(false); 1.1924 + return; 1.1925 + } 1.1926 + 1.1927 + bool updateInfoSucceeded = false; 1.1928 + GLint ok = 0; 1.1929 + if (gl->WorkAroundDriverBugs() && 1.1930 + program->HasBadShaderAttached()) 1.1931 + { 1.1932 + // it's a common driver bug, caught by program-test.html, that linkProgram doesn't 1.1933 + // correctly preserve the state of an in-use program that has been attached a bad shader 1.1934 + // see bug 777883 1.1935 + ok = false; 1.1936 + } else { 1.1937 + MakeContextCurrent(); 1.1938 + gl->fLinkProgram(progname); 1.1939 + gl->fGetProgramiv(progname, LOCAL_GL_LINK_STATUS, &ok); 1.1940 + 1.1941 + if (ok) { 1.1942 + updateInfoSucceeded = program->UpdateInfo(); 1.1943 + program->SetLinkStatus(updateInfoSucceeded); 1.1944 + 1.1945 + if (BindArrayAttribToLocation0(program)) { 1.1946 + GenerateWarning("linkProgram: relinking program to make attrib0 an " 1.1947 + "array."); 1.1948 + gl->fLinkProgram(progname); 1.1949 + gl->fGetProgramiv(progname, LOCAL_GL_LINK_STATUS, &ok); 1.1950 + if (ok) { 1.1951 + updateInfoSucceeded = program->UpdateInfo(); 1.1952 + program->SetLinkStatus(updateInfoSucceeded); 1.1953 + } 1.1954 + } 1.1955 + } 1.1956 + } 1.1957 + 1.1958 + if (ok) { 1.1959 + // Bug 750527 1.1960 + if (gl->WorkAroundDriverBugs() && 1.1961 + updateInfoSucceeded && 1.1962 + gl->Vendor() == gl::GLVendor::NVIDIA) 1.1963 + { 1.1964 + if (program == mCurrentProgram) 1.1965 + gl->fUseProgram(progname); 1.1966 + } 1.1967 + } else { 1.1968 + program->SetLinkStatus(false); 1.1969 + 1.1970 + if (ShouldGenerateWarnings()) { 1.1971 + 1.1972 + // report shader/program infoLogs as warnings. 1.1973 + // note that shader compilation errors can be deferred to linkProgram, 1.1974 + // which is why we can't do anything in compileShader. In practice we could 1.1975 + // report in compileShader the translation errors generated by ANGLE, 1.1976 + // but it seems saner to keep a single way of obtaining shader infologs. 1.1977 + 1.1978 + nsAutoCString log; 1.1979 + 1.1980 + bool alreadyReportedShaderInfoLog = false; 1.1981 + 1.1982 + for (size_t i = 0; i < program->AttachedShaders().Length(); i++) { 1.1983 + 1.1984 + WebGLShader* shader = program->AttachedShaders()[i]; 1.1985 + 1.1986 + if (shader->CompileStatus()) 1.1987 + continue; 1.1988 + 1.1989 + const char *shaderTypeName = nullptr; 1.1990 + if (shader->ShaderType() == LOCAL_GL_VERTEX_SHADER) { 1.1991 + shaderTypeName = "vertex"; 1.1992 + } else if (shader->ShaderType() == LOCAL_GL_FRAGMENT_SHADER) { 1.1993 + shaderTypeName = "fragment"; 1.1994 + } else { 1.1995 + // should have been validated earlier 1.1996 + MOZ_ASSERT(false); 1.1997 + shaderTypeName = "<unknown>"; 1.1998 + } 1.1999 + 1.2000 + GetShaderInfoLog(shader, log); 1.2001 + 1.2002 + GenerateWarning("linkProgram: a %s shader used in this program failed to " 1.2003 + "compile, with this log:\n%s\n", 1.2004 + shaderTypeName, 1.2005 + log.get()); 1.2006 + alreadyReportedShaderInfoLog = true; 1.2007 + } 1.2008 + 1.2009 + if (!alreadyReportedShaderInfoLog) { 1.2010 + GetProgramInfoLog(program, log); 1.2011 + if (!log.IsEmpty()) { 1.2012 + GenerateWarning("linkProgram failed, with this log:\n%s\n", 1.2013 + log.get()); 1.2014 + } 1.2015 + } 1.2016 + } 1.2017 + } 1.2018 +} 1.2019 + 1.2020 +void 1.2021 +WebGLContext::PixelStorei(GLenum pname, GLint param) 1.2022 +{ 1.2023 + if (IsContextLost()) 1.2024 + return; 1.2025 + 1.2026 + switch (pname) { 1.2027 + case UNPACK_FLIP_Y_WEBGL: 1.2028 + mPixelStoreFlipY = (param != 0); 1.2029 + break; 1.2030 + case UNPACK_PREMULTIPLY_ALPHA_WEBGL: 1.2031 + mPixelStorePremultiplyAlpha = (param != 0); 1.2032 + break; 1.2033 + case UNPACK_COLORSPACE_CONVERSION_WEBGL: 1.2034 + if (param == LOCAL_GL_NONE || param == BROWSER_DEFAULT_WEBGL) 1.2035 + mPixelStoreColorspaceConversion = param; 1.2036 + else 1.2037 + return ErrorInvalidEnumInfo("pixelStorei: colorspace conversion parameter", param); 1.2038 + break; 1.2039 + case LOCAL_GL_PACK_ALIGNMENT: 1.2040 + case LOCAL_GL_UNPACK_ALIGNMENT: 1.2041 + if (param != 1 && 1.2042 + param != 2 && 1.2043 + param != 4 && 1.2044 + param != 8) 1.2045 + return ErrorInvalidValue("pixelStorei: invalid pack/unpack alignment value"); 1.2046 + if (pname == LOCAL_GL_PACK_ALIGNMENT) 1.2047 + mPixelStorePackAlignment = param; 1.2048 + else if (pname == LOCAL_GL_UNPACK_ALIGNMENT) 1.2049 + mPixelStoreUnpackAlignment = param; 1.2050 + MakeContextCurrent(); 1.2051 + gl->fPixelStorei(pname, param); 1.2052 + break; 1.2053 + default: 1.2054 + return ErrorInvalidEnumInfo("pixelStorei: parameter", pname); 1.2055 + } 1.2056 +} 1.2057 + 1.2058 +void 1.2059 +WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, 1.2060 + GLsizei height, GLenum format, 1.2061 + GLenum type, const Nullable<ArrayBufferView> &pixels, 1.2062 + ErrorResult& rv) 1.2063 +{ 1.2064 + if (IsContextLost()) 1.2065 + return; 1.2066 + 1.2067 + if (mCanvasElement->IsWriteOnly() && !nsContentUtils::IsCallerChrome()) { 1.2068 + GenerateWarning("readPixels: Not allowed"); 1.2069 + return rv.Throw(NS_ERROR_DOM_SECURITY_ERR); 1.2070 + } 1.2071 + 1.2072 + if (width < 0 || height < 0) 1.2073 + return ErrorInvalidValue("readPixels: negative size passed"); 1.2074 + 1.2075 + if (pixels.IsNull()) 1.2076 + return ErrorInvalidValue("readPixels: null destination buffer"); 1.2077 + 1.2078 + const WebGLRectangleObject* framebufferRect = CurValidFBRectObject(); 1.2079 + GLsizei framebufferWidth = framebufferRect ? framebufferRect->Width() : 0; 1.2080 + GLsizei framebufferHeight = framebufferRect ? framebufferRect->Height() : 0; 1.2081 + 1.2082 + uint32_t channels = 0; 1.2083 + 1.2084 + // Check the format param 1.2085 + switch (format) { 1.2086 + case LOCAL_GL_ALPHA: 1.2087 + channels = 1; 1.2088 + break; 1.2089 + case LOCAL_GL_RGB: 1.2090 + channels = 3; 1.2091 + break; 1.2092 + case LOCAL_GL_RGBA: 1.2093 + channels = 4; 1.2094 + break; 1.2095 + default: 1.2096 + return ErrorInvalidEnum("readPixels: Bad format"); 1.2097 + } 1.2098 + 1.2099 + uint32_t bytesPerPixel = 0; 1.2100 + int requiredDataType = 0; 1.2101 + 1.2102 + // Check the type param 1.2103 + bool isReadTypeValid = false; 1.2104 + bool isReadTypeFloat = false; 1.2105 + switch (type) { 1.2106 + case LOCAL_GL_UNSIGNED_BYTE: 1.2107 + isReadTypeValid = true; 1.2108 + bytesPerPixel = 1*channels; 1.2109 + requiredDataType = js::ArrayBufferView::TYPE_UINT8; 1.2110 + break; 1.2111 + case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4: 1.2112 + case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1: 1.2113 + case LOCAL_GL_UNSIGNED_SHORT_5_6_5: 1.2114 + isReadTypeValid = true; 1.2115 + bytesPerPixel = 2; 1.2116 + requiredDataType = js::ArrayBufferView::TYPE_UINT16; 1.2117 + break; 1.2118 + case LOCAL_GL_FLOAT: 1.2119 + if (IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float) || 1.2120 + IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float)) 1.2121 + { 1.2122 + isReadTypeValid = true; 1.2123 + isReadTypeFloat = true; 1.2124 + bytesPerPixel = 4*channels; 1.2125 + requiredDataType = js::ArrayBufferView::TYPE_FLOAT32; 1.2126 + } 1.2127 + break; 1.2128 + } 1.2129 + if (!isReadTypeValid) 1.2130 + return ErrorInvalidEnum("readPixels: Bad type", type); 1.2131 + 1.2132 + const ArrayBufferView& pixbuf = pixels.Value(); 1.2133 + int dataType = JS_GetArrayBufferViewType(pixbuf.Obj()); 1.2134 + 1.2135 + // Check the pixels param type 1.2136 + if (dataType != requiredDataType) 1.2137 + return ErrorInvalidOperation("readPixels: Mismatched type/pixels types"); 1.2138 + 1.2139 + // Check the pixels param size 1.2140 + CheckedUint32 checked_neededByteLength = 1.2141 + GetImageSize(height, width, bytesPerPixel, mPixelStorePackAlignment); 1.2142 + 1.2143 + CheckedUint32 checked_plainRowSize = CheckedUint32(width) * bytesPerPixel; 1.2144 + 1.2145 + CheckedUint32 checked_alignedRowSize = 1.2146 + RoundedToNextMultipleOf(checked_plainRowSize, mPixelStorePackAlignment); 1.2147 + 1.2148 + if (!checked_neededByteLength.isValid()) 1.2149 + return ErrorInvalidOperation("readPixels: integer overflow computing the needed buffer size"); 1.2150 + 1.2151 + // Compute length and data. Don't reenter after this point, lest the 1.2152 + // precomputed go out of sync with the instant length/data. 1.2153 + pixbuf.ComputeLengthAndData(); 1.2154 + 1.2155 + uint32_t dataByteLen = pixbuf.Length(); 1.2156 + if (checked_neededByteLength.value() > dataByteLen) 1.2157 + return ErrorInvalidOperation("readPixels: buffer too small"); 1.2158 + 1.2159 + void* data = pixbuf.Data(); 1.2160 + if (!data) { 1.2161 + ErrorOutOfMemory("readPixels: buffer storage is null. Did we run out of memory?"); 1.2162 + return rv.Throw(NS_ERROR_OUT_OF_MEMORY); 1.2163 + } 1.2164 + 1.2165 + bool isSourceTypeFloat = false; 1.2166 + if (mBoundFramebuffer && 1.2167 + mBoundFramebuffer->ColorAttachmentCount() && 1.2168 + mBoundFramebuffer->ColorAttachment(0).IsDefined()) 1.2169 + { 1.2170 + isSourceTypeFloat = mBoundFramebuffer->ColorAttachment(0).IsReadableFloat(); 1.2171 + } 1.2172 + 1.2173 + if (isReadTypeFloat != isSourceTypeFloat) 1.2174 + return ErrorInvalidOperation("readPixels: Invalid type floatness"); 1.2175 + 1.2176 + // Check the format and type params to assure they are an acceptable pair (as per spec) 1.2177 + switch (format) { 1.2178 + case LOCAL_GL_RGBA: { 1.2179 + switch (type) { 1.2180 + case LOCAL_GL_UNSIGNED_BYTE: 1.2181 + break; 1.2182 + case LOCAL_GL_FLOAT: 1.2183 + break; 1.2184 + default: 1.2185 + return ErrorInvalidOperation("readPixels: Invalid format/type pair"); 1.2186 + } 1.2187 + break; 1.2188 + } 1.2189 + default: 1.2190 + return ErrorInvalidOperation("readPixels: Invalid format/type pair"); 1.2191 + } 1.2192 + 1.2193 + MakeContextCurrent(); 1.2194 + 1.2195 + if (mBoundFramebuffer) { 1.2196 + // prevent readback of arbitrary video memory through uninitialized renderbuffers! 1.2197 + if (!mBoundFramebuffer->CheckAndInitializeAttachments()) 1.2198 + return ErrorInvalidFramebufferOperation("readPixels: incomplete framebuffer"); 1.2199 + 1.2200 + GLenum readPlaneBits = LOCAL_GL_COLOR_BUFFER_BIT; 1.2201 + if (!mBoundFramebuffer->HasCompletePlanes(readPlaneBits)) { 1.2202 + return ErrorInvalidOperation("readPixels: Read source attachment doesn't have the" 1.2203 + " correct color/depth/stencil type."); 1.2204 + } 1.2205 + } else { 1.2206 + ClearBackbufferIfNeeded(); 1.2207 + } 1.2208 + // Now that the errors are out of the way, on to actually reading 1.2209 + 1.2210 + // If we won't be reading any pixels anyways, just skip the actual reading 1.2211 + if (width == 0 || height == 0) 1.2212 + return DummyFramebufferOperation("readPixels"); 1.2213 + 1.2214 + if (CanvasUtils::CheckSaneSubrectSize(x, y, width, height, framebufferWidth, framebufferHeight)) { 1.2215 + // the easy case: we're not reading out-of-range pixels 1.2216 + gl->fReadPixels(x, y, width, height, format, type, data); 1.2217 + } else { 1.2218 + // the rectangle doesn't fit entirely in the bound buffer. We then have to set to zero the part 1.2219 + // of the buffer that correspond to out-of-range pixels. We don't want to rely on system OpenGL 1.2220 + // to do that for us, because passing out of range parameters to a buggy OpenGL implementation 1.2221 + // could conceivably allow to read memory we shouldn't be allowed to read. So we manually initialize 1.2222 + // the buffer to zero and compute the parameters to pass to OpenGL. We have to use an intermediate buffer 1.2223 + // to accomodate the potentially different strides (widths). 1.2224 + 1.2225 + // Zero the whole pixel dest area in the destination buffer. 1.2226 + memset(data, 0, checked_neededByteLength.value()); 1.2227 + 1.2228 + if ( x >= framebufferWidth 1.2229 + || x+width <= 0 1.2230 + || y >= framebufferHeight 1.2231 + || y+height <= 0) 1.2232 + { 1.2233 + // we are completely outside of range, can exit now with buffer filled with zeros 1.2234 + return DummyFramebufferOperation("readPixels"); 1.2235 + } 1.2236 + 1.2237 + // compute the parameters of the subrect we're actually going to call glReadPixels on 1.2238 + GLint subrect_x = std::max(x, 0); 1.2239 + GLint subrect_end_x = std::min(x+width, framebufferWidth); 1.2240 + GLsizei subrect_width = subrect_end_x - subrect_x; 1.2241 + 1.2242 + GLint subrect_y = std::max(y, 0); 1.2243 + GLint subrect_end_y = std::min(y+height, framebufferHeight); 1.2244 + GLsizei subrect_height = subrect_end_y - subrect_y; 1.2245 + 1.2246 + if (subrect_width < 0 || subrect_height < 0 || 1.2247 + subrect_width > width || subrect_height > height) 1.2248 + return ErrorInvalidOperation("readPixels: integer overflow computing clipped rect size"); 1.2249 + 1.2250 + // now we know that subrect_width is in the [0..width] interval, and same for heights. 1.2251 + 1.2252 + // now, same computation as above to find the size of the intermediate buffer to allocate for the subrect 1.2253 + // no need to check again for integer overflow here, since we already know the sizes aren't greater than before 1.2254 + uint32_t subrect_plainRowSize = subrect_width * bytesPerPixel; 1.2255 + // There are checks above to ensure that this doesn't overflow. 1.2256 + uint32_t subrect_alignedRowSize = 1.2257 + RoundedToNextMultipleOf(subrect_plainRowSize, mPixelStorePackAlignment).value(); 1.2258 + uint32_t subrect_byteLength = (subrect_height-1)*subrect_alignedRowSize + subrect_plainRowSize; 1.2259 + 1.2260 + // create subrect buffer, call glReadPixels, copy pixels into destination buffer, delete subrect buffer 1.2261 + GLubyte *subrect_data = new GLubyte[subrect_byteLength]; 1.2262 + gl->fReadPixels(subrect_x, subrect_y, subrect_width, subrect_height, format, type, subrect_data); 1.2263 + 1.2264 + // notice that this for loop terminates because we already checked that subrect_height is at most height 1.2265 + for (GLint y_inside_subrect = 0; y_inside_subrect < subrect_height; ++y_inside_subrect) { 1.2266 + GLint subrect_x_in_dest_buffer = subrect_x - x; 1.2267 + GLint subrect_y_in_dest_buffer = subrect_y - y; 1.2268 + memcpy(static_cast<GLubyte*>(data) 1.2269 + + checked_alignedRowSize.value() * (subrect_y_in_dest_buffer + y_inside_subrect) 1.2270 + + bytesPerPixel * subrect_x_in_dest_buffer, // destination 1.2271 + subrect_data + subrect_alignedRowSize * y_inside_subrect, // source 1.2272 + subrect_plainRowSize); // size 1.2273 + } 1.2274 + delete [] subrect_data; 1.2275 + } 1.2276 + 1.2277 + // if we're reading alpha, we may need to do fixup. Note that we don't allow 1.2278 + // GL_ALPHA to readpixels currently, but we had the code written for it already. 1.2279 + if (format == LOCAL_GL_ALPHA || 1.2280 + format == LOCAL_GL_RGBA) 1.2281 + { 1.2282 + bool needAlphaFixup; 1.2283 + if (mBoundFramebuffer) { 1.2284 + needAlphaFixup = !mBoundFramebuffer->ColorAttachment(0).HasAlpha(); 1.2285 + } else { 1.2286 + needAlphaFixup = gl->GetPixelFormat().alpha == 0; 1.2287 + } 1.2288 + 1.2289 + if (needAlphaFixup) { 1.2290 + if (format == LOCAL_GL_ALPHA && type == LOCAL_GL_UNSIGNED_BYTE) { 1.2291 + // this is easy; it's an 0xff memset per row 1.2292 + uint8_t *row = static_cast<uint8_t*>(data); 1.2293 + for (GLint j = 0; j < height; ++j) { 1.2294 + memset(row, 0xff, checked_plainRowSize.value()); 1.2295 + row += checked_alignedRowSize.value(); 1.2296 + } 1.2297 + } else if (format == LOCAL_GL_RGBA && type == LOCAL_GL_UNSIGNED_BYTE) { 1.2298 + // this is harder, we need to just set the alpha byte here 1.2299 + uint8_t *row = static_cast<uint8_t*>(data); 1.2300 + for (GLint j = 0; j < height; ++j) { 1.2301 + uint8_t *rowp = row; 1.2302 +#if MOZ_LITTLE_ENDIAN 1.2303 + // offset to get the alpha byte; we're always going to 1.2304 + // move by 4 bytes 1.2305 + rowp += 3; 1.2306 +#endif 1.2307 + uint8_t *endrowp = rowp + 4 * width; 1.2308 + while (rowp != endrowp) { 1.2309 + *rowp = 0xff; 1.2310 + rowp += 4; 1.2311 + } 1.2312 + 1.2313 + row += checked_alignedRowSize.value(); 1.2314 + } 1.2315 + } else if (format == LOCAL_GL_RGBA && type == LOCAL_GL_FLOAT) { 1.2316 + float* row = static_cast<float*>(data); 1.2317 + 1.2318 + for (GLint j = 0; j < height; ++j) { 1.2319 + float* pAlpha = row + 3; 1.2320 + float* pAlphaEnd = pAlpha + 4*width; 1.2321 + 1.2322 + while (pAlpha != pAlphaEnd) { 1.2323 + *pAlpha = 1.0f; 1.2324 + pAlpha += 4; 1.2325 + } 1.2326 + 1.2327 + row += checked_alignedRowSize.value(); 1.2328 + } 1.2329 + } else { 1.2330 + NS_WARNING("Unhandled case, how'd we get here?"); 1.2331 + return rv.Throw(NS_ERROR_FAILURE); 1.2332 + } 1.2333 + } 1.2334 + } 1.2335 +} 1.2336 + 1.2337 +void 1.2338 +WebGLContext::RenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) 1.2339 +{ 1.2340 + if (IsContextLost()) 1.2341 + return; 1.2342 + 1.2343 + if (!mBoundRenderbuffer) 1.2344 + return ErrorInvalidOperation("renderbufferStorage called on renderbuffer 0"); 1.2345 + 1.2346 + if (target != LOCAL_GL_RENDERBUFFER) 1.2347 + return ErrorInvalidEnumInfo("renderbufferStorage: target", target); 1.2348 + 1.2349 + if (width < 0 || height < 0) 1.2350 + return ErrorInvalidValue("renderbufferStorage: width and height must be >= 0"); 1.2351 + 1.2352 + if (width > mGLMaxRenderbufferSize || height > mGLMaxRenderbufferSize) 1.2353 + return ErrorInvalidValue("renderbufferStorage: width or height exceeds maximum renderbuffer size"); 1.2354 + 1.2355 + // certain OpenGL ES renderbuffer formats may not exist on desktop OpenGL 1.2356 + GLenum internalformatForGL = internalformat; 1.2357 + 1.2358 + switch (internalformat) { 1.2359 + case LOCAL_GL_RGBA4: 1.2360 + case LOCAL_GL_RGB5_A1: 1.2361 + // 16-bit RGBA formats are not supported on desktop GL 1.2362 + if (!gl->IsGLES()) internalformatForGL = LOCAL_GL_RGBA8; 1.2363 + break; 1.2364 + case LOCAL_GL_RGB565: 1.2365 + // the RGB565 format is not supported on desktop GL 1.2366 + if (!gl->IsGLES()) internalformatForGL = LOCAL_GL_RGB8; 1.2367 + break; 1.2368 + case LOCAL_GL_DEPTH_COMPONENT16: 1.2369 + if (!gl->IsGLES() || gl->IsExtensionSupported(gl::GLContext::OES_depth24)) 1.2370 + internalformatForGL = LOCAL_GL_DEPTH_COMPONENT24; 1.2371 + else if (gl->IsExtensionSupported(gl::GLContext::OES_packed_depth_stencil)) 1.2372 + internalformatForGL = LOCAL_GL_DEPTH24_STENCIL8; 1.2373 + break; 1.2374 + case LOCAL_GL_STENCIL_INDEX8: 1.2375 + break; 1.2376 + case LOCAL_GL_DEPTH_STENCIL: 1.2377 + // We emulate this in WebGLRenderbuffer if we don't have the requisite extension. 1.2378 + internalformatForGL = LOCAL_GL_DEPTH24_STENCIL8; 1.2379 + break; 1.2380 + case LOCAL_GL_SRGB8_ALPHA8_EXT: 1.2381 + break; 1.2382 + case LOCAL_GL_RGB16F: 1.2383 + case LOCAL_GL_RGBA16F: { 1.2384 + bool hasExtensions = IsExtensionEnabled(WebGLExtensionID::OES_texture_half_float) && 1.2385 + IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float); 1.2386 + if (!hasExtensions) 1.2387 + return ErrorInvalidEnumInfo("renderbufferStorage: internalformat", target); 1.2388 + break; 1.2389 + } 1.2390 + case LOCAL_GL_RGB32F: 1.2391 + case LOCAL_GL_RGBA32F: { 1.2392 + bool hasExtensions = IsExtensionEnabled(WebGLExtensionID::OES_texture_float) && 1.2393 + IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float); 1.2394 + if (!hasExtensions) 1.2395 + return ErrorInvalidEnumInfo("renderbufferStorage: internalformat", target); 1.2396 + break; 1.2397 + } 1.2398 + default: 1.2399 + return ErrorInvalidEnumInfo("renderbufferStorage: internalformat", internalformat); 1.2400 + } 1.2401 + 1.2402 + MakeContextCurrent(); 1.2403 + 1.2404 + bool sizeChanges = width != mBoundRenderbuffer->Width() || 1.2405 + height != mBoundRenderbuffer->Height() || 1.2406 + internalformat != mBoundRenderbuffer->InternalFormat(); 1.2407 + if (sizeChanges) { 1.2408 + // Invalidate framebuffer status cache 1.2409 + mBoundRenderbuffer->NotifyFBsStatusChanged(); 1.2410 + GetAndFlushUnderlyingGLErrors(); 1.2411 + mBoundRenderbuffer->RenderbufferStorage(internalformatForGL, width, height); 1.2412 + GLenum error = GetAndFlushUnderlyingGLErrors(); 1.2413 + if (error) { 1.2414 + GenerateWarning("renderbufferStorage generated error %s", ErrorName(error)); 1.2415 + return; 1.2416 + } 1.2417 + } else { 1.2418 + mBoundRenderbuffer->RenderbufferStorage(internalformatForGL, width, height); 1.2419 + } 1.2420 + 1.2421 + mBoundRenderbuffer->SetInternalFormat(internalformat); 1.2422 + mBoundRenderbuffer->SetInternalFormatForGL(internalformatForGL); 1.2423 + mBoundRenderbuffer->setDimensions(width, height); 1.2424 + mBoundRenderbuffer->SetImageDataStatus(WebGLImageDataStatus::UninitializedImageData); 1.2425 +} 1.2426 + 1.2427 +void 1.2428 +WebGLContext::Scissor(GLint x, GLint y, GLsizei width, GLsizei height) 1.2429 +{ 1.2430 + if (IsContextLost()) 1.2431 + return; 1.2432 + 1.2433 + if (width < 0 || height < 0) 1.2434 + return ErrorInvalidValue("scissor: negative size"); 1.2435 + 1.2436 + MakeContextCurrent(); 1.2437 + gl->fScissor(x, y, width, height); 1.2438 +} 1.2439 + 1.2440 +void 1.2441 +WebGLContext::StencilFunc(GLenum func, GLint ref, GLuint mask) 1.2442 +{ 1.2443 + if (IsContextLost()) 1.2444 + return; 1.2445 + 1.2446 + if (!ValidateComparisonEnum(func, "stencilFunc: func")) 1.2447 + return; 1.2448 + 1.2449 + mStencilRefFront = ref; 1.2450 + mStencilRefBack = ref; 1.2451 + mStencilValueMaskFront = mask; 1.2452 + mStencilValueMaskBack = mask; 1.2453 + 1.2454 + MakeContextCurrent(); 1.2455 + gl->fStencilFunc(func, ref, mask); 1.2456 +} 1.2457 + 1.2458 +void 1.2459 +WebGLContext::StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) 1.2460 +{ 1.2461 + if (IsContextLost()) 1.2462 + return; 1.2463 + 1.2464 + if (!ValidateFaceEnum(face, "stencilFuncSeparate: face") || 1.2465 + !ValidateComparisonEnum(func, "stencilFuncSeparate: func")) 1.2466 + return; 1.2467 + 1.2468 + switch (face) { 1.2469 + case LOCAL_GL_FRONT_AND_BACK: 1.2470 + mStencilRefFront = ref; 1.2471 + mStencilRefBack = ref; 1.2472 + mStencilValueMaskFront = mask; 1.2473 + mStencilValueMaskBack = mask; 1.2474 + break; 1.2475 + case LOCAL_GL_FRONT: 1.2476 + mStencilRefFront = ref; 1.2477 + mStencilValueMaskFront = mask; 1.2478 + break; 1.2479 + case LOCAL_GL_BACK: 1.2480 + mStencilRefBack = ref; 1.2481 + mStencilValueMaskBack = mask; 1.2482 + break; 1.2483 + } 1.2484 + 1.2485 + MakeContextCurrent(); 1.2486 + gl->fStencilFuncSeparate(face, func, ref, mask); 1.2487 +} 1.2488 + 1.2489 +void 1.2490 +WebGLContext::StencilOp(GLenum sfail, GLenum dpfail, GLenum dppass) 1.2491 +{ 1.2492 + if (IsContextLost()) 1.2493 + return; 1.2494 + 1.2495 + if (!ValidateStencilOpEnum(sfail, "stencilOp: sfail") || 1.2496 + !ValidateStencilOpEnum(dpfail, "stencilOp: dpfail") || 1.2497 + !ValidateStencilOpEnum(dppass, "stencilOp: dppass")) 1.2498 + return; 1.2499 + 1.2500 + MakeContextCurrent(); 1.2501 + gl->fStencilOp(sfail, dpfail, dppass); 1.2502 +} 1.2503 + 1.2504 +void 1.2505 +WebGLContext::StencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) 1.2506 +{ 1.2507 + if (IsContextLost()) 1.2508 + return; 1.2509 + 1.2510 + if (!ValidateFaceEnum(face, "stencilOpSeparate: face") || 1.2511 + !ValidateStencilOpEnum(sfail, "stencilOpSeparate: sfail") || 1.2512 + !ValidateStencilOpEnum(dpfail, "stencilOpSeparate: dpfail") || 1.2513 + !ValidateStencilOpEnum(dppass, "stencilOpSeparate: dppass")) 1.2514 + return; 1.2515 + 1.2516 + MakeContextCurrent(); 1.2517 + gl->fStencilOpSeparate(face, sfail, dpfail, dppass); 1.2518 +} 1.2519 + 1.2520 +nsresult 1.2521 +WebGLContext::SurfaceFromElementResultToImageSurface(nsLayoutUtils::SurfaceFromElementResult& res, 1.2522 + RefPtr<DataSourceSurface>& imageOut, WebGLTexelFormat *format) 1.2523 +{ 1.2524 + *format = WebGLTexelFormat::None; 1.2525 + 1.2526 + if (!res.mSourceSurface) 1.2527 + return NS_OK; 1.2528 + RefPtr<DataSourceSurface> data = res.mSourceSurface->GetDataSurface(); 1.2529 + if (!data) { 1.2530 + // SurfaceFromElement lied! 1.2531 + return NS_OK; 1.2532 + } 1.2533 + 1.2534 + if (!mPixelStorePremultiplyAlpha && res.mIsPremultiplied) { 1.2535 + data = gfxUtils::UnpremultiplyDataSurface(data); 1.2536 + } 1.2537 + 1.2538 + // We disallow loading cross-domain images and videos that have not been validated 1.2539 + // with CORS as WebGL textures. The reason for doing that is that timing 1.2540 + // attacks on WebGL shaders are able to retrieve approximations of the 1.2541 + // pixel values in WebGL textures; see bug 655987. 1.2542 + // 1.2543 + // To prevent a loophole where a Canvas2D would be used as a proxy to load 1.2544 + // cross-domain textures, we also disallow loading textures from write-only 1.2545 + // Canvas2D's. 1.2546 + 1.2547 + // part 1: check that the DOM element is same-origin, or has otherwise been 1.2548 + // validated for cross-domain use. 1.2549 + if (!res.mCORSUsed) { 1.2550 + bool subsumes; 1.2551 + nsresult rv = mCanvasElement->NodePrincipal()->Subsumes(res.mPrincipal, &subsumes); 1.2552 + if (NS_FAILED(rv) || !subsumes) { 1.2553 + GenerateWarning("It is forbidden to load a WebGL texture from a cross-domain element that has not been validated with CORS. " 1.2554 + "See https://developer.mozilla.org/en/WebGL/Cross-Domain_Textures"); 1.2555 + return NS_ERROR_DOM_SECURITY_ERR; 1.2556 + } 1.2557 + } 1.2558 + 1.2559 + // part 2: if the DOM element is write-only, it might contain 1.2560 + // cross-domain image data. 1.2561 + if (res.mIsWriteOnly) { 1.2562 + GenerateWarning("The canvas used as source for texImage2D here is tainted (write-only). It is forbidden " 1.2563 + "to load a WebGL texture from a tainted canvas. A Canvas becomes tainted for example " 1.2564 + "when a cross-domain image is drawn on it. " 1.2565 + "See https://developer.mozilla.org/en/WebGL/Cross-Domain_Textures"); 1.2566 + return NS_ERROR_DOM_SECURITY_ERR; 1.2567 + } 1.2568 + 1.2569 + // End of security checks, now we should be safe regarding cross-domain images 1.2570 + // Notice that there is never a need to mark the WebGL canvas as write-only, since we reject write-only/cross-domain 1.2571 + // texture sources in the first place. 1.2572 + 1.2573 + switch (data->GetFormat()) { 1.2574 + case SurfaceFormat::B8G8R8A8: 1.2575 + *format = WebGLTexelFormat::BGRA8; // careful, our ARGB means BGRA 1.2576 + break; 1.2577 + case SurfaceFormat::B8G8R8X8: 1.2578 + *format = WebGLTexelFormat::BGRX8; // careful, our RGB24 is not tightly packed. Whence BGRX8. 1.2579 + break; 1.2580 + case SurfaceFormat::A8: 1.2581 + *format = WebGLTexelFormat::A8; 1.2582 + break; 1.2583 + case SurfaceFormat::R5G6B5: 1.2584 + *format = WebGLTexelFormat::RGB565; 1.2585 + break; 1.2586 + default: 1.2587 + NS_ASSERTION(false, "Unsupported image format. Unimplemented."); 1.2588 + return NS_ERROR_NOT_IMPLEMENTED; 1.2589 + } 1.2590 + 1.2591 + imageOut = data; 1.2592 + 1.2593 + return NS_OK; 1.2594 +} 1.2595 + 1.2596 + 1.2597 + 1.2598 +void 1.2599 +WebGLContext::Uniform1i(WebGLUniformLocation *location_object, GLint a1) 1.2600 +{ 1.2601 + GLint location; 1.2602 + if (!ValidateUniformSetter("Uniform1i", location_object, location)) 1.2603 + return; 1.2604 + 1.2605 + // Only uniform1i can take sampler settings. 1.2606 + if (!ValidateSamplerUniformSetter("Uniform1i", location_object, a1)) 1.2607 + return; 1.2608 + 1.2609 + MakeContextCurrent(); 1.2610 + gl->fUniform1i(location, a1); 1.2611 +} 1.2612 + 1.2613 +void 1.2614 +WebGLContext::Uniform2i(WebGLUniformLocation *location_object, GLint a1, 1.2615 + GLint a2) 1.2616 +{ 1.2617 + GLint location; 1.2618 + if (!ValidateUniformSetter("Uniform2i", location_object, location)) 1.2619 + return; 1.2620 + 1.2621 + MakeContextCurrent(); 1.2622 + gl->fUniform2i(location, a1, a2); 1.2623 +} 1.2624 + 1.2625 +void 1.2626 +WebGLContext::Uniform3i(WebGLUniformLocation *location_object, GLint a1, 1.2627 + GLint a2, GLint a3) 1.2628 +{ 1.2629 + GLint location; 1.2630 + if (!ValidateUniformSetter("Uniform3i", location_object, location)) 1.2631 + return; 1.2632 + 1.2633 + MakeContextCurrent(); 1.2634 + gl->fUniform3i(location, a1, a2, a3); 1.2635 +} 1.2636 + 1.2637 +void 1.2638 +WebGLContext::Uniform4i(WebGLUniformLocation *location_object, GLint a1, 1.2639 + GLint a2, GLint a3, GLint a4) 1.2640 +{ 1.2641 + GLint location; 1.2642 + if (!ValidateUniformSetter("Uniform4i", location_object, location)) 1.2643 + return; 1.2644 + 1.2645 + MakeContextCurrent(); 1.2646 + gl->fUniform4i(location, a1, a2, a3, a4); 1.2647 +} 1.2648 + 1.2649 +void 1.2650 +WebGLContext::Uniform1f(WebGLUniformLocation *location_object, GLfloat a1) 1.2651 +{ 1.2652 + GLint location; 1.2653 + if (!ValidateUniformSetter("Uniform1f", location_object, location)) 1.2654 + return; 1.2655 + MakeContextCurrent(); 1.2656 + gl->fUniform1f(location, a1); 1.2657 +} 1.2658 + 1.2659 +void 1.2660 +WebGLContext::Uniform2f(WebGLUniformLocation *location_object, GLfloat a1, 1.2661 + GLfloat a2) 1.2662 +{ 1.2663 + GLint location; 1.2664 + if (!ValidateUniformSetter("Uniform2f", location_object, location)) 1.2665 + return; 1.2666 + MakeContextCurrent(); 1.2667 + gl->fUniform2f(location, a1, a2); 1.2668 +} 1.2669 + 1.2670 +void 1.2671 +WebGLContext::Uniform3f(WebGLUniformLocation *location_object, GLfloat a1, 1.2672 + GLfloat a2, GLfloat a3) 1.2673 +{ 1.2674 + GLint location; 1.2675 + if (!ValidateUniformSetter("Uniform3f", location_object, location)) 1.2676 + return; 1.2677 + MakeContextCurrent(); 1.2678 + gl->fUniform3f(location, a1, a2, a3); 1.2679 +} 1.2680 + 1.2681 +void 1.2682 +WebGLContext::Uniform4f(WebGLUniformLocation *location_object, GLfloat a1, 1.2683 + GLfloat a2, GLfloat a3, GLfloat a4) 1.2684 +{ 1.2685 + GLint location; 1.2686 + if (!ValidateUniformSetter("Uniform4f", location_object, location)) 1.2687 + return; 1.2688 + MakeContextCurrent(); 1.2689 + gl->fUniform4f(location, a1, a2, a3, a4); 1.2690 +} 1.2691 + 1.2692 +void 1.2693 +WebGLContext::Uniform1iv_base(WebGLUniformLocation *location_object, 1.2694 + uint32_t arrayLength, const GLint* data) 1.2695 +{ 1.2696 + uint32_t numElementsToUpload; 1.2697 + GLint location; 1.2698 + if (!ValidateUniformArraySetter("Uniform1iv", 1, location_object, location, 1.2699 + numElementsToUpload, arrayLength)) { 1.2700 + return; 1.2701 + } 1.2702 + 1.2703 + if (!ValidateSamplerUniformSetter("Uniform1iv", location_object, data[0])) 1.2704 + return; 1.2705 + 1.2706 + MakeContextCurrent(); 1.2707 + gl->fUniform1iv(location, numElementsToUpload, data); 1.2708 +} 1.2709 + 1.2710 +void 1.2711 +WebGLContext::Uniform2iv_base(WebGLUniformLocation *location_object, 1.2712 + uint32_t arrayLength, const GLint* data) 1.2713 +{ 1.2714 + uint32_t numElementsToUpload; 1.2715 + GLint location; 1.2716 + if (!ValidateUniformArraySetter("Uniform2iv", 2, location_object, location, 1.2717 + numElementsToUpload, arrayLength)) { 1.2718 + return; 1.2719 + } 1.2720 + 1.2721 + if (!ValidateSamplerUniformSetter("Uniform2iv", location_object, data[0]) || 1.2722 + !ValidateSamplerUniformSetter("Uniform2iv", location_object, data[1])) 1.2723 + { 1.2724 + return; 1.2725 + } 1.2726 + 1.2727 + MakeContextCurrent(); 1.2728 + gl->fUniform2iv(location, numElementsToUpload, data); 1.2729 +} 1.2730 + 1.2731 +void 1.2732 +WebGLContext::Uniform3iv_base(WebGLUniformLocation *location_object, 1.2733 + uint32_t arrayLength, const GLint* data) 1.2734 +{ 1.2735 + uint32_t numElementsToUpload; 1.2736 + GLint location; 1.2737 + if (!ValidateUniformArraySetter("Uniform3iv", 3, location_object, location, 1.2738 + numElementsToUpload, arrayLength)) { 1.2739 + return; 1.2740 + } 1.2741 + 1.2742 + if (!ValidateSamplerUniformSetter("Uniform3iv", location_object, data[0]) || 1.2743 + !ValidateSamplerUniformSetter("Uniform3iv", location_object, data[1]) || 1.2744 + !ValidateSamplerUniformSetter("Uniform3iv", location_object, data[2])) 1.2745 + { 1.2746 + return; 1.2747 + } 1.2748 + 1.2749 + MakeContextCurrent(); 1.2750 + gl->fUniform3iv(location, numElementsToUpload, data); 1.2751 +} 1.2752 + 1.2753 +void 1.2754 +WebGLContext::Uniform4iv_base(WebGLUniformLocation *location_object, 1.2755 + uint32_t arrayLength, const GLint* data) 1.2756 +{ 1.2757 + uint32_t numElementsToUpload; 1.2758 + GLint location; 1.2759 + if (!ValidateUniformArraySetter("Uniform4iv", 4, location_object, location, 1.2760 + numElementsToUpload, arrayLength)) { 1.2761 + return; 1.2762 + } 1.2763 + 1.2764 + if (!ValidateSamplerUniformSetter("Uniform4iv", location_object, data[0]) || 1.2765 + !ValidateSamplerUniformSetter("Uniform4iv", location_object, data[1]) || 1.2766 + !ValidateSamplerUniformSetter("Uniform4iv", location_object, data[2]) || 1.2767 + !ValidateSamplerUniformSetter("Uniform4iv", location_object, data[3])) 1.2768 + { 1.2769 + return; 1.2770 + } 1.2771 + 1.2772 + MakeContextCurrent(); 1.2773 + gl->fUniform4iv(location, numElementsToUpload, data); 1.2774 +} 1.2775 + 1.2776 +void 1.2777 +WebGLContext::Uniform1fv_base(WebGLUniformLocation *location_object, 1.2778 + uint32_t arrayLength, const GLfloat* data) 1.2779 +{ 1.2780 + uint32_t numElementsToUpload; 1.2781 + GLint location; 1.2782 + if (!ValidateUniformArraySetter("Uniform1fv", 1, location_object, location, 1.2783 + numElementsToUpload, arrayLength)) { 1.2784 + return; 1.2785 + } 1.2786 + MakeContextCurrent(); 1.2787 + gl->fUniform1fv(location, numElementsToUpload, data); 1.2788 +} 1.2789 + 1.2790 +void 1.2791 +WebGLContext::Uniform2fv_base(WebGLUniformLocation *location_object, 1.2792 + uint32_t arrayLength, const GLfloat* data) 1.2793 +{ 1.2794 + uint32_t numElementsToUpload; 1.2795 + GLint location; 1.2796 + if (!ValidateUniformArraySetter("Uniform2fv", 2, location_object, location, 1.2797 + numElementsToUpload, arrayLength)) { 1.2798 + return; 1.2799 + } 1.2800 + MakeContextCurrent(); 1.2801 + gl->fUniform2fv(location, numElementsToUpload, data); 1.2802 +} 1.2803 + 1.2804 +void 1.2805 +WebGLContext::Uniform3fv_base(WebGLUniformLocation *location_object, 1.2806 + uint32_t arrayLength, const GLfloat* data) 1.2807 +{ 1.2808 + uint32_t numElementsToUpload; 1.2809 + GLint location; 1.2810 + if (!ValidateUniformArraySetter("Uniform3fv", 3, location_object, location, 1.2811 + numElementsToUpload, arrayLength)) { 1.2812 + return; 1.2813 + } 1.2814 + MakeContextCurrent(); 1.2815 + gl->fUniform3fv(location, numElementsToUpload, data); 1.2816 +} 1.2817 + 1.2818 +void 1.2819 +WebGLContext::Uniform4fv_base(WebGLUniformLocation *location_object, 1.2820 + uint32_t arrayLength, const GLfloat* data) 1.2821 +{ 1.2822 + uint32_t numElementsToUpload; 1.2823 + GLint location; 1.2824 + if (!ValidateUniformArraySetter("Uniform4fv", 4, location_object, location, 1.2825 + numElementsToUpload, arrayLength)) { 1.2826 + return; 1.2827 + } 1.2828 + MakeContextCurrent(); 1.2829 + gl->fUniform4fv(location, numElementsToUpload, data); 1.2830 +} 1.2831 + 1.2832 +void 1.2833 +WebGLContext::UniformMatrix2fv_base(WebGLUniformLocation* location_object, 1.2834 + WebGLboolean aTranspose, uint32_t arrayLength, 1.2835 + const float* data) 1.2836 +{ 1.2837 + uint32_t numElementsToUpload; 1.2838 + GLint location; 1.2839 + if (!ValidateUniformMatrixArraySetter("UniformMatrix2fv", 2, location_object, location, 1.2840 + numElementsToUpload, arrayLength, aTranspose)) { 1.2841 + return; 1.2842 + } 1.2843 + MakeContextCurrent(); 1.2844 + gl->fUniformMatrix2fv(location, numElementsToUpload, false, data); 1.2845 +} 1.2846 + 1.2847 +void 1.2848 +WebGLContext::UniformMatrix3fv_base(WebGLUniformLocation* location_object, 1.2849 + WebGLboolean aTranspose, uint32_t arrayLength, 1.2850 + const float* data) 1.2851 +{ 1.2852 + uint32_t numElementsToUpload; 1.2853 + GLint location; 1.2854 + if (!ValidateUniformMatrixArraySetter("UniformMatrix3fv", 3, location_object, location, 1.2855 + numElementsToUpload, arrayLength, aTranspose)) { 1.2856 + return; 1.2857 + } 1.2858 + MakeContextCurrent(); 1.2859 + gl->fUniformMatrix3fv(location, numElementsToUpload, false, data); 1.2860 +} 1.2861 + 1.2862 +void 1.2863 +WebGLContext::UniformMatrix4fv_base(WebGLUniformLocation* location_object, 1.2864 + WebGLboolean aTranspose, uint32_t arrayLength, 1.2865 + const float* data) 1.2866 +{ 1.2867 + uint32_t numElementsToUpload; 1.2868 + GLint location; 1.2869 + if (!ValidateUniformMatrixArraySetter("UniformMatrix4fv", 4, location_object, location, 1.2870 + numElementsToUpload, arrayLength, aTranspose)) { 1.2871 + return; 1.2872 + } 1.2873 + MakeContextCurrent(); 1.2874 + gl->fUniformMatrix4fv(location, numElementsToUpload, false, data); 1.2875 +} 1.2876 + 1.2877 +void 1.2878 +WebGLContext::UseProgram(WebGLProgram *prog) 1.2879 +{ 1.2880 + if (IsContextLost()) 1.2881 + return; 1.2882 + 1.2883 + if (!ValidateObjectAllowNull("useProgram", prog)) 1.2884 + return; 1.2885 + 1.2886 + MakeContextCurrent(); 1.2887 + 1.2888 + InvalidateBufferFetching(); 1.2889 + 1.2890 + GLuint progname = prog ? prog->GLName() : 0; 1.2891 + 1.2892 + if (prog && !prog->LinkStatus()) 1.2893 + return ErrorInvalidOperation("useProgram: program was not linked successfully"); 1.2894 + 1.2895 + gl->fUseProgram(progname); 1.2896 + 1.2897 + mCurrentProgram = prog; 1.2898 +} 1.2899 + 1.2900 +void 1.2901 +WebGLContext::ValidateProgram(WebGLProgram *prog) 1.2902 +{ 1.2903 + if (IsContextLost()) 1.2904 + return; 1.2905 + 1.2906 + if (!ValidateObject("validateProgram", prog)) 1.2907 + return; 1.2908 + 1.2909 + MakeContextCurrent(); 1.2910 + 1.2911 +#ifdef XP_MACOSX 1.2912 + // see bug 593867 for NVIDIA and bug 657201 for ATI. The latter is confirmed with Mac OS 10.6.7 1.2913 + if (gl->WorkAroundDriverBugs()) { 1.2914 + GenerateWarning("validateProgram: implemented as a no-operation on Mac to work around crashes"); 1.2915 + return; 1.2916 + } 1.2917 +#endif 1.2918 + 1.2919 + GLuint progname = prog->GLName(); 1.2920 + gl->fValidateProgram(progname); 1.2921 +} 1.2922 + 1.2923 +already_AddRefed<WebGLFramebuffer> 1.2924 +WebGLContext::CreateFramebuffer() 1.2925 +{ 1.2926 + if (IsContextLost()) 1.2927 + return nullptr; 1.2928 + nsRefPtr<WebGLFramebuffer> globj = new WebGLFramebuffer(this); 1.2929 + return globj.forget(); 1.2930 +} 1.2931 + 1.2932 +already_AddRefed<WebGLRenderbuffer> 1.2933 +WebGLContext::CreateRenderbuffer() 1.2934 +{ 1.2935 + if (IsContextLost()) 1.2936 + return nullptr; 1.2937 + nsRefPtr<WebGLRenderbuffer> globj = new WebGLRenderbuffer(this); 1.2938 + return globj.forget(); 1.2939 +} 1.2940 + 1.2941 +void 1.2942 +WebGLContext::Viewport(GLint x, GLint y, GLsizei width, GLsizei height) 1.2943 +{ 1.2944 + if (IsContextLost()) 1.2945 + return; 1.2946 + 1.2947 + if (width < 0 || height < 0) 1.2948 + return ErrorInvalidValue("viewport: negative size"); 1.2949 + 1.2950 + MakeContextCurrent(); 1.2951 + gl->fViewport(x, y, width, height); 1.2952 + 1.2953 + mViewportX = x; 1.2954 + mViewportY = y; 1.2955 + mViewportWidth = width; 1.2956 + mViewportHeight = height; 1.2957 +} 1.2958 + 1.2959 +void 1.2960 +WebGLContext::CompileShader(WebGLShader *shader) 1.2961 +{ 1.2962 + if (IsContextLost()) 1.2963 + return; 1.2964 + 1.2965 + if (!ValidateObject("compileShader", shader)) 1.2966 + return; 1.2967 + 1.2968 + GLuint shadername = shader->GLName(); 1.2969 + 1.2970 + shader->SetCompileStatus(false); 1.2971 + 1.2972 + MakeContextCurrent(); 1.2973 + 1.2974 + ShShaderOutput targetShaderSourceLanguage = gl->IsGLES() ? SH_ESSL_OUTPUT : SH_GLSL_OUTPUT; 1.2975 + bool useShaderSourceTranslation = true; 1.2976 + 1.2977 + if (shader->NeedsTranslation() && mShaderValidation) { 1.2978 + ShHandle compiler = 0; 1.2979 + ShBuiltInResources resources; 1.2980 + memset(&resources, 0, sizeof(ShBuiltInResources)); 1.2981 + 1.2982 + resources.MaxVertexAttribs = mGLMaxVertexAttribs; 1.2983 + resources.MaxVertexUniformVectors = mGLMaxVertexUniformVectors; 1.2984 + resources.MaxVaryingVectors = mGLMaxVaryingVectors; 1.2985 + resources.MaxVertexTextureImageUnits = mGLMaxVertexTextureImageUnits; 1.2986 + resources.MaxCombinedTextureImageUnits = mGLMaxTextureUnits; 1.2987 + resources.MaxTextureImageUnits = mGLMaxTextureImageUnits; 1.2988 + resources.MaxFragmentUniformVectors = mGLMaxFragmentUniformVectors; 1.2989 + resources.MaxDrawBuffers = mGLMaxDrawBuffers; 1.2990 + 1.2991 + if (IsExtensionEnabled(WebGLExtensionID::EXT_frag_depth)) 1.2992 + resources.EXT_frag_depth = 1; 1.2993 + 1.2994 + if (IsExtensionEnabled(WebGLExtensionID::OES_standard_derivatives)) 1.2995 + resources.OES_standard_derivatives = 1; 1.2996 + 1.2997 + if (IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers)) 1.2998 + resources.EXT_draw_buffers = 1; 1.2999 + 1.3000 + // Tell ANGLE to allow highp in frag shaders. (unless disabled) 1.3001 + // If underlying GLES doesn't have highp in frag shaders, it should complain anyways. 1.3002 + resources.FragmentPrecisionHigh = mDisableFragHighP ? 0 : 1; 1.3003 + 1.3004 + if (gl->WorkAroundDriverBugs()) { 1.3005 +#ifdef XP_MACOSX 1.3006 + if (gl->Vendor() == gl::GLVendor::NVIDIA) { 1.3007 + // Work around bug 890432 1.3008 + resources.MaxExpressionComplexity = 1000; 1.3009 + } 1.3010 +#endif 1.3011 + } 1.3012 + 1.3013 + // We're storing an actual instance of StripComments because, if we don't, the 1.3014 + // cleanSource nsAString instance will be destroyed before the reference is 1.3015 + // actually used. 1.3016 + StripComments stripComments(shader->Source()); 1.3017 + const nsAString& cleanSource = Substring(stripComments.result().Elements(), stripComments.length()); 1.3018 + if (!ValidateGLSLString(cleanSource, "compileShader")) 1.3019 + return; 1.3020 + 1.3021 + // shaderSource() already checks that the source stripped of comments is in the 1.3022 + // 7-bit ASCII range, so we can skip the NS_IsAscii() check. 1.3023 + NS_LossyConvertUTF16toASCII sourceCString(cleanSource); 1.3024 + 1.3025 + if (gl->WorkAroundDriverBugs()) { 1.3026 + const uint32_t maxSourceLength = 0x3ffff; 1.3027 + if (sourceCString.Length() > maxSourceLength) 1.3028 + return ErrorInvalidValue("compileShader: source has more than %d characters", 1.3029 + maxSourceLength); 1.3030 + } 1.3031 + 1.3032 + const char *s = sourceCString.get(); 1.3033 + 1.3034 +#define WEBGL2_BYPASS_ANGLE 1.3035 +#ifdef WEBGL2_BYPASS_ANGLE 1.3036 + /* 1.3037 + * The bypass don't bring a full support for GLSL ES 3.0, but the main purpose 1.3038 + * is to natively bring gl_InstanceID (to do instanced rendering) and gl_FragData 1.3039 + * 1.3040 + * To remove the bypass code, just comment #define WEBGL2_BYPASS_ANGLE above 1.3041 + * 1.3042 + * To bypass angle, the context must be a WebGL 2 and the shader must have the 1.3043 + * following line at the very top : 1.3044 + * #version proto-200 1.3045 + * 1.3046 + * In this case, byPassANGLE == true and here is what we do : 1.3047 + * We create two shader source code: 1.3048 + * - one for the driver, that enable GL_EXT_gpu_shader4 1.3049 + * - one for the angle compilor, to get informations about vertex attributes 1.3050 + * and uniforms 1.3051 + */ 1.3052 + static const char *bypassPrefixSearch = "#version proto-200"; 1.3053 + static const char *bypassANGLEPrefix[2] = {"precision mediump float;\n" 1.3054 + "#define gl_VertexID 0\n" 1.3055 + "#define gl_InstanceID 0\n", 1.3056 + 1.3057 + "precision mediump float;\n" 1.3058 + "#extension GL_EXT_draw_buffers : enable\n" 1.3059 + "#define gl_PrimitiveID 0\n"}; 1.3060 + 1.3061 + const bool bypassANGLE = IsWebGL2() && (strstr(s, bypassPrefixSearch) != 0); 1.3062 + 1.3063 + const char *angleShaderCode = s; 1.3064 + nsTArray<char> bypassANGLEShaderCode; 1.3065 + nsTArray<char> bypassDriverShaderCode; 1.3066 + 1.3067 + if (bypassANGLE) { 1.3068 + const int bypassStage = (shader->ShaderType() == LOCAL_GL_FRAGMENT_SHADER) ? 1 : 0; 1.3069 + const char *originalShader = strstr(s, bypassPrefixSearch) + strlen(bypassPrefixSearch); 1.3070 + int originalShaderSize = strlen(s) - (originalShader - s); 1.3071 + int bypassShaderCodeSize = originalShaderSize + 4096 + 1; 1.3072 + 1.3073 + bypassANGLEShaderCode.SetLength(bypassShaderCodeSize); 1.3074 + strcpy(bypassANGLEShaderCode.Elements(), bypassANGLEPrefix[bypassStage]); 1.3075 + strcat(bypassANGLEShaderCode.Elements(), originalShader); 1.3076 + 1.3077 + bypassDriverShaderCode.SetLength(bypassShaderCodeSize); 1.3078 + strcpy(bypassDriverShaderCode.Elements(), "#extension GL_EXT_gpu_shader4 : enable\n"); 1.3079 + strcat(bypassDriverShaderCode.Elements(), originalShader); 1.3080 + 1.3081 + angleShaderCode = bypassANGLEShaderCode.Elements(); 1.3082 + } 1.3083 +#endif 1.3084 + 1.3085 + compiler = ShConstructCompiler((ShShaderType) shader->ShaderType(), 1.3086 + SH_WEBGL_SPEC, 1.3087 + targetShaderSourceLanguage, 1.3088 + &resources); 1.3089 + 1.3090 + int compileOptions = SH_ATTRIBUTES_UNIFORMS | 1.3091 + SH_ENFORCE_PACKING_RESTRICTIONS; 1.3092 + 1.3093 + if (resources.MaxExpressionComplexity > 0) { 1.3094 + compileOptions |= SH_LIMIT_EXPRESSION_COMPLEXITY; 1.3095 + } 1.3096 + 1.3097 + // We want to do this everywhere, but: 1.3098 +#ifndef XP_MACOSX // To do this on Mac, we need to do it only on Mac OSX > 10.6 as this 1.3099 + // causes the shader compiler in 10.6 to crash 1.3100 + compileOptions |= SH_CLAMP_INDIRECT_ARRAY_BOUNDS; 1.3101 +#endif 1.3102 + 1.3103 + if (useShaderSourceTranslation) { 1.3104 + compileOptions |= SH_OBJECT_CODE 1.3105 + | SH_MAP_LONG_VARIABLE_NAMES; 1.3106 + 1.3107 +#ifdef XP_MACOSX 1.3108 + if (gl->WorkAroundDriverBugs()) { 1.3109 + // Work around bug 665578 and bug 769810 1.3110 + if (gl->Vendor() == gl::GLVendor::ATI) { 1.3111 + compileOptions |= SH_EMULATE_BUILT_IN_FUNCTIONS; 1.3112 + } 1.3113 + 1.3114 + // Work around bug 735560 1.3115 + if (gl->Vendor() == gl::GLVendor::Intel) { 1.3116 + compileOptions |= SH_EMULATE_BUILT_IN_FUNCTIONS; 1.3117 + } 1.3118 + } 1.3119 +#endif 1.3120 + } 1.3121 + 1.3122 +#ifdef WEBGL2_BYPASS_ANGLE 1.3123 + if (!ShCompile(compiler, &angleShaderCode, 1, compileOptions)) { 1.3124 +#else 1.3125 + if (!ShCompile(compiler, &s, 1, compileOptions)) { 1.3126 +#endif 1.3127 + size_t lenWithNull = 0; 1.3128 + ShGetInfo(compiler, SH_INFO_LOG_LENGTH, &lenWithNull); 1.3129 + 1.3130 + if (!lenWithNull) { 1.3131 + // Error in ShGetInfo. 1.3132 + shader->SetTranslationFailure(NS_LITERAL_CSTRING("Internal error: failed to get shader info log")); 1.3133 + } else { 1.3134 + size_t len = lenWithNull - 1; 1.3135 + 1.3136 + nsAutoCString info; 1.3137 + info.SetLength(len); // Allocates len+1, for the null-term. 1.3138 + ShGetInfoLog(compiler, info.BeginWriting()); 1.3139 + 1.3140 + shader->SetTranslationFailure(info); 1.3141 + } 1.3142 + ShDestruct(compiler); 1.3143 + shader->SetCompileStatus(false); 1.3144 + return; 1.3145 + } 1.3146 + 1.3147 + size_t num_attributes = 0; 1.3148 + ShGetInfo(compiler, SH_ACTIVE_ATTRIBUTES, &num_attributes); 1.3149 + size_t num_uniforms = 0; 1.3150 + ShGetInfo(compiler, SH_ACTIVE_UNIFORMS, &num_uniforms); 1.3151 + size_t attrib_max_length = 0; 1.3152 + ShGetInfo(compiler, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, &attrib_max_length); 1.3153 + size_t uniform_max_length = 0; 1.3154 + ShGetInfo(compiler, SH_ACTIVE_UNIFORM_MAX_LENGTH, &uniform_max_length); 1.3155 + size_t mapped_max_length = 0; 1.3156 + ShGetInfo(compiler, SH_MAPPED_NAME_MAX_LENGTH, &mapped_max_length); 1.3157 + 1.3158 + shader->mAttribMaxNameLength = attrib_max_length; 1.3159 + 1.3160 + shader->mAttributes.Clear(); 1.3161 + shader->mUniforms.Clear(); 1.3162 + shader->mUniformInfos.Clear(); 1.3163 + 1.3164 + nsAutoArrayPtr<char> attribute_name(new char[attrib_max_length+1]); 1.3165 + nsAutoArrayPtr<char> uniform_name(new char[uniform_max_length+1]); 1.3166 + nsAutoArrayPtr<char> mapped_name(new char[mapped_max_length+1]); 1.3167 + 1.3168 + for (size_t i = 0; i < num_uniforms; i++) { 1.3169 + size_t length; 1.3170 + int size; 1.3171 + ShDataType type; 1.3172 + ShGetActiveUniform(compiler, (int)i, 1.3173 + &length, &size, &type, 1.3174 + uniform_name, 1.3175 + mapped_name); 1.3176 + if (useShaderSourceTranslation) { 1.3177 + shader->mUniforms.AppendElement(WebGLMappedIdentifier( 1.3178 + nsDependentCString(uniform_name), 1.3179 + nsDependentCString(mapped_name))); 1.3180 + } 1.3181 + 1.3182 + // we always query uniform info, regardless of useShaderSourceTranslation, 1.3183 + // as we need it to validate uniform setter calls, and it doesn't rely on 1.3184 + // shader translation. 1.3185 + char mappedNameLength = strlen(mapped_name); 1.3186 + char mappedNameLastChar = mappedNameLength > 1 1.3187 + ? mapped_name[mappedNameLength - 1] 1.3188 + : 0; 1.3189 + shader->mUniformInfos.AppendElement(WebGLUniformInfo( 1.3190 + size, 1.3191 + mappedNameLastChar == ']', 1.3192 + type)); 1.3193 + } 1.3194 + 1.3195 + if (useShaderSourceTranslation) { 1.3196 + 1.3197 + for (size_t i = 0; i < num_attributes; i++) { 1.3198 + size_t length; 1.3199 + int size; 1.3200 + ShDataType type; 1.3201 + ShGetActiveAttrib(compiler, (int)i, 1.3202 + &length, &size, &type, 1.3203 + attribute_name, 1.3204 + mapped_name); 1.3205 + shader->mAttributes.AppendElement(WebGLMappedIdentifier( 1.3206 + nsDependentCString(attribute_name), 1.3207 + nsDependentCString(mapped_name))); 1.3208 + } 1.3209 + 1.3210 + size_t lenWithNull = 0; 1.3211 + ShGetInfo(compiler, SH_OBJECT_CODE_LENGTH, &lenWithNull); 1.3212 + MOZ_ASSERT(lenWithNull >= 1); 1.3213 + size_t len = lenWithNull - 1; 1.3214 + 1.3215 + nsAutoCString translatedSrc; 1.3216 + translatedSrc.SetLength(len); // Allocates len+1, for the null-term. 1.3217 + ShGetObjectCode(compiler, translatedSrc.BeginWriting()); 1.3218 + 1.3219 + CopyASCIItoUTF16(translatedSrc, shader->mTranslatedSource); 1.3220 + 1.3221 + const char *ts = translatedSrc.get(); 1.3222 + 1.3223 +#ifdef WEBGL2_BYPASS_ANGLE 1.3224 + if (bypassANGLE) { 1.3225 + const char* driverShaderCode = bypassDriverShaderCode.Elements(); 1.3226 + gl->fShaderSource(shadername, 1, (const GLchar**) &driverShaderCode, nullptr); 1.3227 + } 1.3228 + else { 1.3229 + gl->fShaderSource(shadername, 1, &ts, nullptr); 1.3230 + } 1.3231 +#else 1.3232 + gl->fShaderSource(shadername, 1, &ts, nullptr); 1.3233 +#endif 1.3234 + } else { // not useShaderSourceTranslation 1.3235 + // we just pass the raw untranslated shader source. We then can't use ANGLE idenfier mapping. 1.3236 + // that's really bad, as that means we can't be 100% conformant. We should work towards always 1.3237 + // using ANGLE identifier mapping. 1.3238 + gl->fShaderSource(shadername, 1, &s, nullptr); 1.3239 + 1.3240 + CopyASCIItoUTF16(s, shader->mTranslatedSource); 1.3241 + } 1.3242 + 1.3243 + shader->SetTranslationSuccess(); 1.3244 + 1.3245 + ShDestruct(compiler); 1.3246 + 1.3247 + gl->fCompileShader(shadername); 1.3248 + GLint ok; 1.3249 + gl->fGetShaderiv(shadername, LOCAL_GL_COMPILE_STATUS, &ok); 1.3250 + shader->SetCompileStatus(ok); 1.3251 + } 1.3252 +} 1.3253 + 1.3254 +void 1.3255 +WebGLContext::CompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, 1.3256 + GLsizei width, GLsizei height, GLint border, 1.3257 + const ArrayBufferView& view) 1.3258 +{ 1.3259 + if (IsContextLost()) 1.3260 + return; 1.3261 + 1.3262 + const WebGLTexImageFunc func = WebGLTexImageFunc::CompTexImage; 1.3263 + 1.3264 + if (!ValidateTexImage(2, target, level, internalformat, 1.3265 + 0, 0, 0, width, height, 0, 1.3266 + border, internalformat, LOCAL_GL_UNSIGNED_BYTE, 1.3267 + func)) 1.3268 + { 1.3269 + return; 1.3270 + } 1.3271 + 1.3272 + view.ComputeLengthAndData(); 1.3273 + 1.3274 + uint32_t byteLength = view.Length(); 1.3275 + if (!ValidateCompTexImageDataSize(target, internalformat, width, height, byteLength, func)) { 1.3276 + return; 1.3277 + } 1.3278 + 1.3279 + if (!ValidateCompTexImageSize(target, level, internalformat, 0, 0, 1.3280 + width, height, width, height, func)) 1.3281 + { 1.3282 + return; 1.3283 + } 1.3284 + 1.3285 + MakeContextCurrent(); 1.3286 + gl->fCompressedTexImage2D(target, level, internalformat, width, height, border, byteLength, view.Data()); 1.3287 + WebGLTexture* tex = activeBoundTextureForTarget(target); 1.3288 + MOZ_ASSERT(tex); 1.3289 + tex->SetImageInfo(target, level, width, height, internalformat, LOCAL_GL_UNSIGNED_BYTE, 1.3290 + WebGLImageDataStatus::InitializedImageData); 1.3291 +} 1.3292 + 1.3293 +void 1.3294 +WebGLContext::CompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, 1.3295 + GLint yoffset, GLsizei width, GLsizei height, 1.3296 + GLenum format, const ArrayBufferView& view) 1.3297 +{ 1.3298 + if (IsContextLost()) 1.3299 + return; 1.3300 + 1.3301 + const WebGLTexImageFunc func = WebGLTexImageFunc::CompTexSubImage; 1.3302 + 1.3303 + if (!ValidateTexImage(2, target, 1.3304 + level, format, 1.3305 + xoffset, yoffset, 0, 1.3306 + width, height, 0, 1.3307 + 0, format, LOCAL_GL_UNSIGNED_BYTE, 1.3308 + func)) 1.3309 + { 1.3310 + return; 1.3311 + } 1.3312 + 1.3313 + WebGLTexture *tex = activeBoundTextureForTarget(target); 1.3314 + MOZ_ASSERT(tex); 1.3315 + WebGLTexture::ImageInfo& levelInfo = tex->ImageInfoAt(target, level); 1.3316 + 1.3317 + view.ComputeLengthAndData(); 1.3318 + 1.3319 + uint32_t byteLength = view.Length(); 1.3320 + if (!ValidateCompTexImageDataSize(target, format, width, height, byteLength, func)) 1.3321 + return; 1.3322 + 1.3323 + if (!ValidateCompTexImageSize(target, level, format, 1.3324 + xoffset, yoffset, 1.3325 + width, height, 1.3326 + levelInfo.Width(), levelInfo.Height(), 1.3327 + func)) 1.3328 + { 1.3329 + return; 1.3330 + } 1.3331 + 1.3332 + if (levelInfo.HasUninitializedImageData()) 1.3333 + tex->DoDeferredImageInitialization(target, level); 1.3334 + 1.3335 + MakeContextCurrent(); 1.3336 + gl->fCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, byteLength, view.Data()); 1.3337 +} 1.3338 + 1.3339 +JS::Value 1.3340 +WebGLContext::GetShaderParameter(WebGLShader *shader, GLenum pname) 1.3341 +{ 1.3342 + if (IsContextLost()) 1.3343 + return JS::NullValue(); 1.3344 + 1.3345 + if (!ValidateObject("getShaderParameter: shader", shader)) 1.3346 + return JS::NullValue(); 1.3347 + 1.3348 + GLuint shadername = shader->GLName(); 1.3349 + 1.3350 + MakeContextCurrent(); 1.3351 + 1.3352 + switch (pname) { 1.3353 + case LOCAL_GL_SHADER_TYPE: 1.3354 + { 1.3355 + GLint i = 0; 1.3356 + gl->fGetShaderiv(shadername, pname, &i); 1.3357 + return JS::NumberValue(uint32_t(i)); 1.3358 + } 1.3359 + break; 1.3360 + case LOCAL_GL_DELETE_STATUS: 1.3361 + return JS::BooleanValue(shader->IsDeleteRequested()); 1.3362 + break; 1.3363 + case LOCAL_GL_COMPILE_STATUS: 1.3364 + { 1.3365 + GLint i = 0; 1.3366 + gl->fGetShaderiv(shadername, pname, &i); 1.3367 + return JS::BooleanValue(bool(i)); 1.3368 + } 1.3369 + break; 1.3370 + default: 1.3371 + ErrorInvalidEnumInfo("getShaderParameter: parameter", pname); 1.3372 + } 1.3373 + 1.3374 + return JS::NullValue(); 1.3375 +} 1.3376 + 1.3377 +void 1.3378 +WebGLContext::GetShaderInfoLog(WebGLShader *shader, nsAString& retval) 1.3379 +{ 1.3380 + nsAutoCString s; 1.3381 + GetShaderInfoLog(shader, s); 1.3382 + if (s.IsVoid()) 1.3383 + retval.SetIsVoid(true); 1.3384 + else 1.3385 + CopyASCIItoUTF16(s, retval); 1.3386 +} 1.3387 + 1.3388 +void 1.3389 +WebGLContext::GetShaderInfoLog(WebGLShader *shader, nsACString& retval) 1.3390 +{ 1.3391 + if (IsContextLost()) 1.3392 + { 1.3393 + retval.SetIsVoid(true); 1.3394 + return; 1.3395 + } 1.3396 + 1.3397 + if (!ValidateObject("getShaderInfoLog: shader", shader)) 1.3398 + return; 1.3399 + 1.3400 + retval = shader->TranslationLog(); 1.3401 + if (!retval.IsVoid()) { 1.3402 + return; 1.3403 + } 1.3404 + 1.3405 + MakeContextCurrent(); 1.3406 + 1.3407 + GLuint shadername = shader->GLName(); 1.3408 + GLint k = -1; 1.3409 + gl->fGetShaderiv(shadername, LOCAL_GL_INFO_LOG_LENGTH, &k); 1.3410 + if (k == -1) { 1.3411 + // XXX GL Error? should never happen. 1.3412 + return; 1.3413 + } 1.3414 + 1.3415 + if (k == 0) { 1.3416 + retval.Truncate(); 1.3417 + return; 1.3418 + } 1.3419 + 1.3420 + retval.SetCapacity(k); 1.3421 + gl->fGetShaderInfoLog(shadername, k, &k, (char*) retval.BeginWriting()); 1.3422 + retval.SetLength(k); 1.3423 +} 1.3424 + 1.3425 +already_AddRefed<WebGLShaderPrecisionFormat> 1.3426 +WebGLContext::GetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype) 1.3427 +{ 1.3428 + if (IsContextLost()) 1.3429 + return nullptr; 1.3430 + 1.3431 + switch (shadertype) { 1.3432 + case LOCAL_GL_FRAGMENT_SHADER: 1.3433 + case LOCAL_GL_VERTEX_SHADER: 1.3434 + break; 1.3435 + default: 1.3436 + ErrorInvalidEnumInfo("getShaderPrecisionFormat: shadertype", shadertype); 1.3437 + return nullptr; 1.3438 + } 1.3439 + 1.3440 + switch (precisiontype) { 1.3441 + case LOCAL_GL_LOW_FLOAT: 1.3442 + case LOCAL_GL_MEDIUM_FLOAT: 1.3443 + case LOCAL_GL_HIGH_FLOAT: 1.3444 + case LOCAL_GL_LOW_INT: 1.3445 + case LOCAL_GL_MEDIUM_INT: 1.3446 + case LOCAL_GL_HIGH_INT: 1.3447 + break; 1.3448 + default: 1.3449 + ErrorInvalidEnumInfo("getShaderPrecisionFormat: precisiontype", precisiontype); 1.3450 + return nullptr; 1.3451 + } 1.3452 + 1.3453 + MakeContextCurrent(); 1.3454 + GLint range[2], precision; 1.3455 + 1.3456 + if (mDisableFragHighP && 1.3457 + shadertype == LOCAL_GL_FRAGMENT_SHADER && 1.3458 + (precisiontype == LOCAL_GL_HIGH_FLOAT || 1.3459 + precisiontype == LOCAL_GL_HIGH_INT)) 1.3460 + { 1.3461 + precision = 0; 1.3462 + range[0] = 0; 1.3463 + range[1] = 0; 1.3464 + } else { 1.3465 + gl->fGetShaderPrecisionFormat(shadertype, precisiontype, range, &precision); 1.3466 + } 1.3467 + 1.3468 + nsRefPtr<WebGLShaderPrecisionFormat> retShaderPrecisionFormat 1.3469 + = new WebGLShaderPrecisionFormat(this, range[0], range[1], precision); 1.3470 + return retShaderPrecisionFormat.forget(); 1.3471 +} 1.3472 + 1.3473 +void 1.3474 +WebGLContext::GetShaderSource(WebGLShader *shader, nsAString& retval) 1.3475 +{ 1.3476 + if (IsContextLost()) { 1.3477 + retval.SetIsVoid(true); 1.3478 + return; 1.3479 + } 1.3480 + 1.3481 + if (!ValidateObject("getShaderSource: shader", shader)) 1.3482 + return; 1.3483 + 1.3484 + retval.Assign(shader->Source()); 1.3485 +} 1.3486 + 1.3487 +void 1.3488 +WebGLContext::ShaderSource(WebGLShader *shader, const nsAString& source) 1.3489 +{ 1.3490 + if (IsContextLost()) 1.3491 + return; 1.3492 + 1.3493 + if (!ValidateObject("shaderSource: shader", shader)) 1.3494 + return; 1.3495 + 1.3496 + // We're storing an actual instance of StripComments because, if we don't, the 1.3497 + // cleanSource nsAString instance will be destroyed before the reference is 1.3498 + // actually used. 1.3499 + StripComments stripComments(source); 1.3500 + const nsAString& cleanSource = Substring(stripComments.result().Elements(), stripComments.length()); 1.3501 + if (!ValidateGLSLString(cleanSource, "compileShader")) 1.3502 + return; 1.3503 + 1.3504 + shader->SetSource(source); 1.3505 + 1.3506 + shader->SetNeedsTranslation(); 1.3507 +} 1.3508 + 1.3509 +void 1.3510 +WebGLContext::GetShaderTranslatedSource(WebGLShader *shader, nsAString& retval) 1.3511 +{ 1.3512 + if (IsContextLost()) { 1.3513 + retval.SetIsVoid(true); 1.3514 + return; 1.3515 + } 1.3516 + 1.3517 + if (!ValidateObject("getShaderTranslatedSource: shader", shader)) 1.3518 + return; 1.3519 + 1.3520 + retval.Assign(shader->TranslatedSource()); 1.3521 +} 1.3522 + 1.3523 +GLenum WebGLContext::CheckedTexImage2D(GLenum target, 1.3524 + GLint level, 1.3525 + GLenum internalFormat, 1.3526 + GLsizei width, 1.3527 + GLsizei height, 1.3528 + GLint border, 1.3529 + GLenum format, 1.3530 + GLenum type, 1.3531 + const GLvoid *data) 1.3532 +{ 1.3533 + MOZ_ASSERT(internalFormat == format); 1.3534 + WebGLTexture *tex = activeBoundTextureForTarget(target); 1.3535 + MOZ_ASSERT(tex != nullptr, "no texture bound"); 1.3536 + 1.3537 + bool sizeMayChange = true; 1.3538 + 1.3539 + if (tex->HasImageInfoAt(target, level)) { 1.3540 + const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(target, level); 1.3541 + sizeMayChange = width != imageInfo.Width() || 1.3542 + height != imageInfo.Height() || 1.3543 + format != imageInfo.WebGLFormat() || 1.3544 + type != imageInfo.WebGLType(); 1.3545 + } 1.3546 + 1.3547 + // Convert to format and type required by OpenGL 'driver'. 1.3548 + GLenum driverType = DriverTypeFromType(gl, type); 1.3549 + GLenum driverInternalFormat = LOCAL_GL_NONE; 1.3550 + GLenum driverFormat = LOCAL_GL_NONE; 1.3551 + DriverFormatsFromFormatAndType(gl, format, type, &driverInternalFormat, &driverFormat); 1.3552 + 1.3553 + if (sizeMayChange) { 1.3554 + GetAndFlushUnderlyingGLErrors(); 1.3555 + } 1.3556 + 1.3557 + gl->fTexImage2D(target, level, driverInternalFormat, width, height, border, driverFormat, driverType, data); 1.3558 + 1.3559 + GLenum error = LOCAL_GL_NO_ERROR; 1.3560 + if (sizeMayChange) { 1.3561 + error = GetAndFlushUnderlyingGLErrors(); 1.3562 + } 1.3563 + 1.3564 + return error; 1.3565 +} 1.3566 + 1.3567 +void 1.3568 +WebGLContext::TexImage2D_base(GLenum target, GLint level, GLenum internalformat, 1.3569 + GLsizei width, GLsizei height, GLsizei srcStrideOrZero, 1.3570 + GLint border, 1.3571 + GLenum format, GLenum type, 1.3572 + void* data, uint32_t byteLength, 1.3573 + int jsArrayType, // a TypedArray format enum, or -1 if not relevant 1.3574 + WebGLTexelFormat srcFormat, bool srcPremultiplied) 1.3575 +{ 1.3576 + const WebGLTexImageFunc func = WebGLTexImageFunc::TexImage; 1.3577 + 1.3578 + if (!ValidateTexImage(2, target, level, internalformat, 1.3579 + 0, 0, 0, 1.3580 + width, height, 0, 1.3581 + border, format, type, func)) 1.3582 + { 1.3583 + return; 1.3584 + } 1.3585 + 1.3586 + const bool isDepthTexture = format == LOCAL_GL_DEPTH_COMPONENT || 1.3587 + format == LOCAL_GL_DEPTH_STENCIL; 1.3588 + 1.3589 + if (isDepthTexture) { 1.3590 + if (data != nullptr || level != 0) 1.3591 + return ErrorInvalidOperation("texImage2D: " 1.3592 + "with format of DEPTH_COMPONENT or DEPTH_STENCIL, " 1.3593 + "data must be nullptr, " 1.3594 + "level must be zero"); 1.3595 + } 1.3596 + 1.3597 + if (!ValidateTexInputData(type, jsArrayType, func)) 1.3598 + return; 1.3599 + 1.3600 + WebGLTexelFormat dstFormat = GetWebGLTexelFormat(format, type); 1.3601 + WebGLTexelFormat actualSrcFormat = srcFormat == WebGLTexelFormat::Auto ? dstFormat : srcFormat; 1.3602 + 1.3603 + uint32_t srcTexelSize = WebGLTexelConversions::TexelBytesForFormat(actualSrcFormat); 1.3604 + 1.3605 + CheckedUint32 checked_neededByteLength = 1.3606 + GetImageSize(height, width, srcTexelSize, mPixelStoreUnpackAlignment); 1.3607 + 1.3608 + CheckedUint32 checked_plainRowSize = CheckedUint32(width) * srcTexelSize; 1.3609 + CheckedUint32 checked_alignedRowSize = 1.3610 + RoundedToNextMultipleOf(checked_plainRowSize.value(), mPixelStoreUnpackAlignment); 1.3611 + 1.3612 + if (!checked_neededByteLength.isValid()) 1.3613 + return ErrorInvalidOperation("texImage2D: integer overflow computing the needed buffer size"); 1.3614 + 1.3615 + uint32_t bytesNeeded = checked_neededByteLength.value(); 1.3616 + 1.3617 + if (byteLength && byteLength < bytesNeeded) 1.3618 + return ErrorInvalidOperation("texImage2D: not enough data for operation (need %d, have %d)", 1.3619 + bytesNeeded, byteLength); 1.3620 + 1.3621 + WebGLTexture *tex = activeBoundTextureForTarget(target); 1.3622 + 1.3623 + if (!tex) 1.3624 + return ErrorInvalidOperation("texImage2D: no texture is bound to this target"); 1.3625 + 1.3626 + MakeContextCurrent(); 1.3627 + 1.3628 + nsAutoArrayPtr<uint8_t> convertedData; 1.3629 + void* pixels = nullptr; 1.3630 + WebGLImageDataStatus imageInfoStatusIfSuccess = WebGLImageDataStatus::UninitializedImageData; 1.3631 + 1.3632 + if (byteLength) { 1.3633 + size_t srcStride = srcStrideOrZero ? srcStrideOrZero : checked_alignedRowSize.value(); 1.3634 + uint32_t dstTexelSize = GetBitsPerTexel(format, type) / 8; 1.3635 + size_t dstPlainRowSize = dstTexelSize * width; 1.3636 + size_t unpackAlignment = mPixelStoreUnpackAlignment; 1.3637 + size_t dstStride = ((dstPlainRowSize + unpackAlignment-1) / unpackAlignment) * unpackAlignment; 1.3638 + 1.3639 + if (actualSrcFormat == dstFormat && 1.3640 + srcPremultiplied == mPixelStorePremultiplyAlpha && 1.3641 + srcStride == dstStride && 1.3642 + !mPixelStoreFlipY) 1.3643 + { 1.3644 + // no conversion, no flipping, so we avoid copying anything and just pass the source pointer 1.3645 + pixels = data; 1.3646 + } 1.3647 + else 1.3648 + { 1.3649 + size_t convertedDataSize = height * dstStride; 1.3650 + convertedData = new uint8_t[convertedDataSize]; 1.3651 + ConvertImage(width, height, srcStride, dstStride, 1.3652 + static_cast<uint8_t*>(data), convertedData, 1.3653 + actualSrcFormat, srcPremultiplied, 1.3654 + dstFormat, mPixelStorePremultiplyAlpha, dstTexelSize); 1.3655 + pixels = reinterpret_cast<void*>(convertedData.get()); 1.3656 + } 1.3657 + imageInfoStatusIfSuccess = WebGLImageDataStatus::InitializedImageData; 1.3658 + } 1.3659 + 1.3660 + GLenum error = CheckedTexImage2D(target, level, internalformat, width, 1.3661 + height, border, format, type, pixels); 1.3662 + 1.3663 + if (error) { 1.3664 + GenerateWarning("texImage2D generated error %s", ErrorName(error)); 1.3665 + return; 1.3666 + } 1.3667 + 1.3668 + // in all of the code paths above, we should have either initialized data, 1.3669 + // or allocated data and left it uninitialized, but in any case we shouldn't 1.3670 + // have NoImageData at this point. 1.3671 + MOZ_ASSERT(imageInfoStatusIfSuccess != WebGLImageDataStatus::NoImageData); 1.3672 + 1.3673 + tex->SetImageInfo(target, level, width, height, format, type, imageInfoStatusIfSuccess); 1.3674 +} 1.3675 + 1.3676 +void 1.3677 +WebGLContext::TexImage2D(GLenum target, GLint level, 1.3678 + GLenum internalformat, GLsizei width, 1.3679 + GLsizei height, GLint border, GLenum format, 1.3680 + GLenum type, const Nullable<ArrayBufferView> &pixels, ErrorResult& rv) 1.3681 +{ 1.3682 + if (IsContextLost()) 1.3683 + return; 1.3684 + 1.3685 + void* data; 1.3686 + uint32_t length; 1.3687 + int jsArrayType; 1.3688 + if (pixels.IsNull()) { 1.3689 + data = nullptr; 1.3690 + length = 0; 1.3691 + jsArrayType = -1; 1.3692 + } else { 1.3693 + const ArrayBufferView& view = pixels.Value(); 1.3694 + view.ComputeLengthAndData(); 1.3695 + 1.3696 + data = view.Data(); 1.3697 + length = view.Length(); 1.3698 + jsArrayType = int(JS_GetArrayBufferViewType(view.Obj())); 1.3699 + } 1.3700 + 1.3701 + return TexImage2D_base(target, level, internalformat, width, height, 0, border, format, type, 1.3702 + data, length, jsArrayType, 1.3703 + WebGLTexelFormat::Auto, false); 1.3704 +} 1.3705 + 1.3706 +void 1.3707 +WebGLContext::TexImage2D(GLenum target, GLint level, 1.3708 + GLenum internalformat, GLenum format, 1.3709 + GLenum type, ImageData* pixels, ErrorResult& rv) 1.3710 +{ 1.3711 + if (IsContextLost()) 1.3712 + return; 1.3713 + 1.3714 + if (!pixels) { 1.3715 + // Spec says to generate an INVALID_VALUE error 1.3716 + return ErrorInvalidValue("texImage2D: null ImageData"); 1.3717 + } 1.3718 + 1.3719 + Uint8ClampedArray arr(pixels->GetDataObject()); 1.3720 + arr.ComputeLengthAndData(); 1.3721 + 1.3722 + return TexImage2D_base(target, level, internalformat, pixels->Width(), 1.3723 + pixels->Height(), 4*pixels->Width(), 0, 1.3724 + format, type, arr.Data(), arr.Length(), -1, 1.3725 + WebGLTexelFormat::RGBA8, false); 1.3726 +} 1.3727 + 1.3728 + 1.3729 +void 1.3730 +WebGLContext::TexSubImage2D_base(GLenum target, GLint level, 1.3731 + GLint xoffset, GLint yoffset, 1.3732 + GLsizei width, GLsizei height, GLsizei srcStrideOrZero, 1.3733 + GLenum format, GLenum type, 1.3734 + void* data, uint32_t byteLength, 1.3735 + int jsArrayType, 1.3736 + WebGLTexelFormat srcFormat, bool srcPremultiplied) 1.3737 +{ 1.3738 + const WebGLTexImageFunc func = WebGLTexImageFunc::TexSubImage; 1.3739 + 1.3740 + if (!ValidateTexImage(2, target, level, format, 1.3741 + xoffset, yoffset, 0, 1.3742 + width, height, 0, 1.3743 + 0, format, type, func)) 1.3744 + { 1.3745 + return; 1.3746 + } 1.3747 + 1.3748 + if (!ValidateTexInputData(type, jsArrayType, func)) 1.3749 + return; 1.3750 + 1.3751 + WebGLTexelFormat dstFormat = GetWebGLTexelFormat(format, type); 1.3752 + WebGLTexelFormat actualSrcFormat = srcFormat == WebGLTexelFormat::Auto ? dstFormat : srcFormat; 1.3753 + 1.3754 + uint32_t srcTexelSize = WebGLTexelConversions::TexelBytesForFormat(actualSrcFormat); 1.3755 + 1.3756 + if (width == 0 || height == 0) 1.3757 + return; // ES 2.0 says it has no effect, we better return right now 1.3758 + 1.3759 + CheckedUint32 checked_neededByteLength = 1.3760 + GetImageSize(height, width, srcTexelSize, mPixelStoreUnpackAlignment); 1.3761 + 1.3762 + CheckedUint32 checked_plainRowSize = CheckedUint32(width) * srcTexelSize; 1.3763 + 1.3764 + CheckedUint32 checked_alignedRowSize = 1.3765 + RoundedToNextMultipleOf(checked_plainRowSize.value(), mPixelStoreUnpackAlignment); 1.3766 + 1.3767 + if (!checked_neededByteLength.isValid()) 1.3768 + return ErrorInvalidOperation("texSubImage2D: integer overflow computing the needed buffer size"); 1.3769 + 1.3770 + uint32_t bytesNeeded = checked_neededByteLength.value(); 1.3771 + 1.3772 + if (byteLength < bytesNeeded) 1.3773 + return ErrorInvalidOperation("texSubImage2D: not enough data for operation (need %d, have %d)", bytesNeeded, byteLength); 1.3774 + 1.3775 + WebGLTexture *tex = activeBoundTextureForTarget(target); 1.3776 + const WebGLTexture::ImageInfo &imageInfo = tex->ImageInfoAt(target, level); 1.3777 + 1.3778 + if (imageInfo.HasUninitializedImageData()) 1.3779 + tex->DoDeferredImageInitialization(target, level); 1.3780 + 1.3781 + MakeContextCurrent(); 1.3782 + 1.3783 + size_t srcStride = srcStrideOrZero ? srcStrideOrZero : checked_alignedRowSize.value(); 1.3784 + uint32_t dstTexelSize = GetBitsPerTexel(format, type) / 8; 1.3785 + size_t dstPlainRowSize = dstTexelSize * width; 1.3786 + // There are checks above to ensure that this won't overflow. 1.3787 + size_t dstStride = RoundedToNextMultipleOf(dstPlainRowSize, mPixelStoreUnpackAlignment).value(); 1.3788 + 1.3789 + void* pixels = data; 1.3790 + nsAutoArrayPtr<uint8_t> convertedData; 1.3791 + 1.3792 + // no conversion, no flipping, so we avoid copying anything and just pass the source pointer 1.3793 + bool noConversion = (actualSrcFormat == dstFormat && 1.3794 + srcPremultiplied == mPixelStorePremultiplyAlpha && 1.3795 + srcStride == dstStride && 1.3796 + !mPixelStoreFlipY); 1.3797 + 1.3798 + if (!noConversion) { 1.3799 + size_t convertedDataSize = height * dstStride; 1.3800 + convertedData = new uint8_t[convertedDataSize]; 1.3801 + ConvertImage(width, height, srcStride, dstStride, 1.3802 + static_cast<const uint8_t*>(data), convertedData, 1.3803 + actualSrcFormat, srcPremultiplied, 1.3804 + dstFormat, mPixelStorePremultiplyAlpha, dstTexelSize); 1.3805 + pixels = reinterpret_cast<void*>(convertedData.get()); 1.3806 + } 1.3807 + 1.3808 + GLenum driverType = DriverTypeFromType(gl, type); 1.3809 + GLenum driverInternalFormat = LOCAL_GL_NONE; 1.3810 + GLenum driverFormat = LOCAL_GL_NONE; 1.3811 + DriverFormatsFromFormatAndType(gl, format, type, &driverInternalFormat, &driverFormat); 1.3812 + 1.3813 + gl->fTexSubImage2D(target, level, xoffset, yoffset, width, height, driverFormat, driverType, pixels); 1.3814 +} 1.3815 + 1.3816 +void 1.3817 +WebGLContext::TexSubImage2D(GLenum target, GLint level, 1.3818 + GLint xoffset, GLint yoffset, 1.3819 + GLsizei width, GLsizei height, 1.3820 + GLenum format, GLenum type, 1.3821 + const Nullable<ArrayBufferView> &pixels, 1.3822 + ErrorResult& rv) 1.3823 +{ 1.3824 + if (IsContextLost()) 1.3825 + return; 1.3826 + 1.3827 + if (pixels.IsNull()) 1.3828 + return ErrorInvalidValue("texSubImage2D: pixels must not be null!"); 1.3829 + 1.3830 + const ArrayBufferView& view = pixels.Value(); 1.3831 + view.ComputeLengthAndData(); 1.3832 + 1.3833 + return TexSubImage2D_base(target, level, xoffset, yoffset, 1.3834 + width, height, 0, format, type, 1.3835 + view.Data(), view.Length(), 1.3836 + JS_GetArrayBufferViewType(view.Obj()), 1.3837 + WebGLTexelFormat::Auto, false); 1.3838 +} 1.3839 + 1.3840 +void 1.3841 +WebGLContext::TexSubImage2D(GLenum target, GLint level, 1.3842 + GLint xoffset, GLint yoffset, 1.3843 + GLenum format, GLenum type, ImageData* pixels, 1.3844 + ErrorResult& rv) 1.3845 +{ 1.3846 + if (IsContextLost()) 1.3847 + return; 1.3848 + 1.3849 + if (!pixels) 1.3850 + return ErrorInvalidValue("texSubImage2D: pixels must not be null!"); 1.3851 + 1.3852 + Uint8ClampedArray arr(pixels->GetDataObject()); 1.3853 + arr.ComputeLengthAndData(); 1.3854 + 1.3855 + return TexSubImage2D_base(target, level, xoffset, yoffset, 1.3856 + pixels->Width(), pixels->Height(), 1.3857 + 4*pixels->Width(), format, type, 1.3858 + arr.Data(), arr.Length(), 1.3859 + -1, 1.3860 + WebGLTexelFormat::RGBA8, false); 1.3861 +} 1.3862 + 1.3863 +bool 1.3864 +WebGLContext::LoseContext() 1.3865 +{ 1.3866 + if (IsContextLost()) 1.3867 + return false; 1.3868 + 1.3869 + ForceLoseContext(); 1.3870 + 1.3871 + return true; 1.3872 +} 1.3873 + 1.3874 +bool 1.3875 +WebGLContext::RestoreContext() 1.3876 +{ 1.3877 + if (!IsContextLost() || !mAllowRestore) { 1.3878 + return false; 1.3879 + } 1.3880 + 1.3881 + ForceRestoreContext(); 1.3882 + 1.3883 + return true; 1.3884 +} 1.3885 + 1.3886 +bool 1.3887 +BaseTypeAndSizeFromUniformType(GLenum uType, GLenum *baseType, GLint *unitSize) 1.3888 +{ 1.3889 + switch (uType) { 1.3890 + case LOCAL_GL_INT: 1.3891 + case LOCAL_GL_INT_VEC2: 1.3892 + case LOCAL_GL_INT_VEC3: 1.3893 + case LOCAL_GL_INT_VEC4: 1.3894 + case LOCAL_GL_SAMPLER_2D: 1.3895 + case LOCAL_GL_SAMPLER_CUBE: 1.3896 + *baseType = LOCAL_GL_INT; 1.3897 + break; 1.3898 + case LOCAL_GL_FLOAT: 1.3899 + case LOCAL_GL_FLOAT_VEC2: 1.3900 + case LOCAL_GL_FLOAT_VEC3: 1.3901 + case LOCAL_GL_FLOAT_VEC4: 1.3902 + case LOCAL_GL_FLOAT_MAT2: 1.3903 + case LOCAL_GL_FLOAT_MAT3: 1.3904 + case LOCAL_GL_FLOAT_MAT4: 1.3905 + *baseType = LOCAL_GL_FLOAT; 1.3906 + break; 1.3907 + case LOCAL_GL_BOOL: 1.3908 + case LOCAL_GL_BOOL_VEC2: 1.3909 + case LOCAL_GL_BOOL_VEC3: 1.3910 + case LOCAL_GL_BOOL_VEC4: 1.3911 + *baseType = LOCAL_GL_BOOL; // pretend these are int 1.3912 + break; 1.3913 + default: 1.3914 + return false; 1.3915 + } 1.3916 + 1.3917 + switch (uType) { 1.3918 + case LOCAL_GL_INT: 1.3919 + case LOCAL_GL_FLOAT: 1.3920 + case LOCAL_GL_BOOL: 1.3921 + case LOCAL_GL_SAMPLER_2D: 1.3922 + case LOCAL_GL_SAMPLER_CUBE: 1.3923 + *unitSize = 1; 1.3924 + break; 1.3925 + case LOCAL_GL_INT_VEC2: 1.3926 + case LOCAL_GL_FLOAT_VEC2: 1.3927 + case LOCAL_GL_BOOL_VEC2: 1.3928 + *unitSize = 2; 1.3929 + break; 1.3930 + case LOCAL_GL_INT_VEC3: 1.3931 + case LOCAL_GL_FLOAT_VEC3: 1.3932 + case LOCAL_GL_BOOL_VEC3: 1.3933 + *unitSize = 3; 1.3934 + break; 1.3935 + case LOCAL_GL_INT_VEC4: 1.3936 + case LOCAL_GL_FLOAT_VEC4: 1.3937 + case LOCAL_GL_BOOL_VEC4: 1.3938 + *unitSize = 4; 1.3939 + break; 1.3940 + case LOCAL_GL_FLOAT_MAT2: 1.3941 + *unitSize = 4; 1.3942 + break; 1.3943 + case LOCAL_GL_FLOAT_MAT3: 1.3944 + *unitSize = 9; 1.3945 + break; 1.3946 + case LOCAL_GL_FLOAT_MAT4: 1.3947 + *unitSize = 16; 1.3948 + break; 1.3949 + default: 1.3950 + return false; 1.3951 + } 1.3952 + 1.3953 + return true; 1.3954 +} 1.3955 + 1.3956 + 1.3957 +WebGLTexelFormat mozilla::GetWebGLTexelFormat(GLenum internalformat, GLenum type) 1.3958 +{ 1.3959 + // 1.3960 + // WEBGL_depth_texture 1.3961 + if (internalformat == LOCAL_GL_DEPTH_COMPONENT) { 1.3962 + switch (type) { 1.3963 + case LOCAL_GL_UNSIGNED_SHORT: 1.3964 + return WebGLTexelFormat::D16; 1.3965 + case LOCAL_GL_UNSIGNED_INT: 1.3966 + return WebGLTexelFormat::D32; 1.3967 + } 1.3968 + 1.3969 + MOZ_CRASH("Invalid WebGL texture format/type?"); 1.3970 + } 1.3971 + 1.3972 + if (internalformat == LOCAL_GL_DEPTH_STENCIL) { 1.3973 + switch (type) { 1.3974 + case LOCAL_GL_UNSIGNED_INT_24_8_EXT: 1.3975 + return WebGLTexelFormat::D24S8; 1.3976 + } 1.3977 + 1.3978 + MOZ_CRASH("Invalid WebGL texture format/type?"); 1.3979 + } 1.3980 + 1.3981 + if (internalformat == LOCAL_GL_DEPTH_COMPONENT16) { 1.3982 + return WebGLTexelFormat::D16; 1.3983 + } 1.3984 + 1.3985 + if (internalformat == LOCAL_GL_DEPTH_COMPONENT32) { 1.3986 + return WebGLTexelFormat::D32; 1.3987 + } 1.3988 + 1.3989 + if (internalformat == LOCAL_GL_DEPTH24_STENCIL8) { 1.3990 + return WebGLTexelFormat::D24S8; 1.3991 + } 1.3992 + 1.3993 + if (type == LOCAL_GL_UNSIGNED_BYTE) { 1.3994 + switch (internalformat) { 1.3995 + case LOCAL_GL_RGBA: 1.3996 + case LOCAL_GL_SRGB_ALPHA_EXT: 1.3997 + return WebGLTexelFormat::RGBA8; 1.3998 + case LOCAL_GL_RGB: 1.3999 + case LOCAL_GL_SRGB_EXT: 1.4000 + return WebGLTexelFormat::RGB8; 1.4001 + case LOCAL_GL_ALPHA: 1.4002 + return WebGLTexelFormat::A8; 1.4003 + case LOCAL_GL_LUMINANCE: 1.4004 + return WebGLTexelFormat::R8; 1.4005 + case LOCAL_GL_LUMINANCE_ALPHA: 1.4006 + return WebGLTexelFormat::RA8; 1.4007 + } 1.4008 + 1.4009 + MOZ_CRASH("Invalid WebGL texture format/type?"); 1.4010 + } 1.4011 + 1.4012 + if (type == LOCAL_GL_FLOAT) { 1.4013 + // OES_texture_float 1.4014 + switch (internalformat) { 1.4015 + case LOCAL_GL_RGBA: 1.4016 + case LOCAL_GL_RGBA32F: 1.4017 + return WebGLTexelFormat::RGBA32F; 1.4018 + case LOCAL_GL_RGB: 1.4019 + case LOCAL_GL_RGB32F: 1.4020 + return WebGLTexelFormat::RGB32F; 1.4021 + case LOCAL_GL_ALPHA: 1.4022 + case LOCAL_GL_ALPHA32F_ARB: 1.4023 + return WebGLTexelFormat::A32F; 1.4024 + case LOCAL_GL_LUMINANCE: 1.4025 + case LOCAL_GL_LUMINANCE32F_ARB: 1.4026 + return WebGLTexelFormat::R32F; 1.4027 + case LOCAL_GL_LUMINANCE_ALPHA: 1.4028 + case LOCAL_GL_LUMINANCE_ALPHA32F_ARB: 1.4029 + return WebGLTexelFormat::RA32F; 1.4030 + } 1.4031 + 1.4032 + MOZ_CRASH("Invalid WebGL texture format/type?"); 1.4033 + } else if (type == LOCAL_GL_HALF_FLOAT_OES) { 1.4034 + // OES_texture_half_float 1.4035 + switch (internalformat) { 1.4036 + case LOCAL_GL_RGBA: 1.4037 + case LOCAL_GL_RGBA16F: 1.4038 + return WebGLTexelFormat::RGBA16F; 1.4039 + case LOCAL_GL_RGB: 1.4040 + case LOCAL_GL_RGB16F: 1.4041 + return WebGLTexelFormat::RGB16F; 1.4042 + case LOCAL_GL_ALPHA: 1.4043 + case LOCAL_GL_ALPHA16F_ARB: 1.4044 + return WebGLTexelFormat::A16F; 1.4045 + case LOCAL_GL_LUMINANCE: 1.4046 + case LOCAL_GL_LUMINANCE16F_ARB: 1.4047 + return WebGLTexelFormat::R16F; 1.4048 + case LOCAL_GL_LUMINANCE_ALPHA: 1.4049 + case LOCAL_GL_LUMINANCE_ALPHA16F_ARB: 1.4050 + return WebGLTexelFormat::RA16F; 1.4051 + default: 1.4052 + MOZ_ASSERT(false, "Coding mistake?! Should never reach this point."); 1.4053 + return WebGLTexelFormat::BadFormat; 1.4054 + } 1.4055 + } 1.4056 + 1.4057 + switch (type) { 1.4058 + case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4: 1.4059 + return WebGLTexelFormat::RGBA4444; 1.4060 + case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1: 1.4061 + return WebGLTexelFormat::RGBA5551; 1.4062 + case LOCAL_GL_UNSIGNED_SHORT_5_6_5: 1.4063 + return WebGLTexelFormat::RGB565; 1.4064 + default: 1.4065 + MOZ_ASSERT(false, "Coding mistake?! Should never reach this point."); 1.4066 + return WebGLTexelFormat::BadFormat; 1.4067 + } 1.4068 + 1.4069 + MOZ_CRASH("Invalid WebGL texture format/type?"); 1.4070 +} 1.4071 + 1.4072 +void 1.4073 +WebGLContext::BlendColor(GLclampf r, GLclampf g, GLclampf b, GLclampf a) { 1.4074 + if (IsContextLost()) 1.4075 + return; 1.4076 + MakeContextCurrent(); 1.4077 + gl->fBlendColor(r, g, b, a); 1.4078 +} 1.4079 + 1.4080 +void 1.4081 +WebGLContext::Flush() { 1.4082 + if (IsContextLost()) 1.4083 + return; 1.4084 + MakeContextCurrent(); 1.4085 + gl->fFlush(); 1.4086 +} 1.4087 + 1.4088 +void 1.4089 +WebGLContext::Finish() { 1.4090 + if (IsContextLost()) 1.4091 + return; 1.4092 + MakeContextCurrent(); 1.4093 + gl->fFinish(); 1.4094 +} 1.4095 + 1.4096 +void 1.4097 +WebGLContext::LineWidth(GLfloat width) { 1.4098 + if (IsContextLost()) 1.4099 + return; 1.4100 + MakeContextCurrent(); 1.4101 + gl->fLineWidth(width); 1.4102 +} 1.4103 + 1.4104 +void 1.4105 +WebGLContext::PolygonOffset(GLfloat factor, GLfloat units) { 1.4106 + if (IsContextLost()) 1.4107 + return; 1.4108 + MakeContextCurrent(); 1.4109 + gl->fPolygonOffset(factor, units); 1.4110 +} 1.4111 + 1.4112 +void 1.4113 +WebGLContext::SampleCoverage(GLclampf value, WebGLboolean invert) { 1.4114 + if (IsContextLost()) 1.4115 + return; 1.4116 + MakeContextCurrent(); 1.4117 + gl->fSampleCoverage(value, invert); 1.4118 +}