void JSGlobalObjectInspectorController::reportAPIException(ExecState* exec, Exception* exception) { if (isTerminatedExecutionException(exception)) return; ErrorHandlingScope errorScope(exec->vm()); RefPtr<ScriptCallStack> callStack = createScriptCallStackFromException(exec, exception, ScriptCallStack::maxCallStackSizeToCapture); if (includesNativeCallStackWhenReportingExceptions()) appendAPIBacktrace(callStack.get()); // FIXME: <http://webkit.org/b/115087> Web Inspector: Should not evaluate JavaScript handling exceptions // If this is a custom exception object, call toString on it to try and get a nice string representation for the exception. String errorMessage = exception->value().toString(exec)->value(exec); exec->clearException(); if (JSGlobalObjectConsoleClient::logToSystemConsole()) { if (callStack->size()) { const ScriptCallFrame& callFrame = callStack->at(0); ConsoleClient::printConsoleMessage(MessageSource::JS, MessageType::Log, MessageLevel::Error, errorMessage, callFrame.sourceURL(), callFrame.lineNumber(), callFrame.columnNumber()); } else ConsoleClient::printConsoleMessage(MessageSource::JS, MessageType::Log, MessageLevel::Error, errorMessage, String(), 0, 0); } m_consoleAgent->addMessageToConsole(std::make_unique<ConsoleMessage>(MessageSource::JS, MessageType::Log, MessageLevel::Error, errorMessage, callStack)); }
void WebGLBuffer::BufferData(GLenum target, size_t size, const void* data, GLenum usage) { const char funcName[] = "bufferData"; if (!ValidateBufferUsageEnum(mContext, funcName, usage)) return; if (mNumActiveTFOs) { mContext->ErrorInvalidOperation("%s: Buffer is bound to an active transform" " feedback object.", funcName); return; } const auto& gl = mContext->gl; gl->MakeCurrent(); const ScopedLazyBind lazyBind(gl, target, this); mContext->InvalidateBufferFetching(); #ifdef XP_MACOSX // bug 790879 if (gl->WorkAroundDriverBugs() && size > INT32_MAX) { mContext->ErrorOutOfMemory("%s: Allocation size too large.", funcName); return; } #endif const bool sizeChanges = (size != ByteLength()); if (sizeChanges) { gl::GLContext::LocalErrorScope errorScope(*gl); gl->fBufferData(target, size, data, usage); const auto error = errorScope.GetError(); if (error) { MOZ_ASSERT(error == LOCAL_GL_OUT_OF_MEMORY); mContext->ErrorOutOfMemory("%s: Error from driver: 0x%04x", funcName, error); return; } } else { gl->fBufferData(target, size, data, usage); } mUsage = usage; mByteLength = size; // Warning: Possibly shared memory. See bug 1225033. if (!ElementArrayCacheBufferData(data, size)) { mByteLength = 0; mContext->ErrorOutOfMemory("%s: Failed update index buffer cache.", funcName); } }
void WebGLContext::AssertCachedBindings() const { #ifdef DEBUG gl::GLContext::LocalErrorScope errorScope(*gl); if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::OES_vertex_array_object)) { AssertUintParamCorrect(gl, LOCAL_GL_VERTEX_ARRAY_BINDING, mBoundVertexArray->mGLName); } GLint stencilBits = 0; if (GetStencilBits(&stencilBits)) { // Depends on current draw framebuffer. const GLuint stencilRefMask = (1 << stencilBits) - 1; AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_REF, stencilRefMask, mStencilRefFront); AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_REF, stencilRefMask, mStencilRefBack); } // Program GLuint bound = mCurrentProgram ? mCurrentProgram->mGLName : 0; AssertUintParamCorrect(gl, LOCAL_GL_CURRENT_PROGRAM, bound); // Textures GLenum activeTexture = mActiveTexture + LOCAL_GL_TEXTURE0; AssertUintParamCorrect(gl, LOCAL_GL_ACTIVE_TEXTURE, activeTexture); WebGLTexture* curTex = ActiveBoundTextureForTarget(LOCAL_GL_TEXTURE_2D); bound = curTex ? curTex->mGLName : 0; AssertUintParamCorrect(gl, LOCAL_GL_TEXTURE_BINDING_2D, bound); curTex = ActiveBoundTextureForTarget(LOCAL_GL_TEXTURE_CUBE_MAP); bound = curTex ? curTex->mGLName : 0; AssertUintParamCorrect(gl, LOCAL_GL_TEXTURE_BINDING_CUBE_MAP, bound); // Buffers bound = mBoundArrayBuffer ? mBoundArrayBuffer->mGLName : 0; AssertUintParamCorrect(gl, LOCAL_GL_ARRAY_BUFFER_BINDING, bound); MOZ_ASSERT(mBoundVertexArray); WebGLBuffer* curBuff = mBoundVertexArray->mElementArrayBuffer; bound = curBuff ? curBuff->mGLName : 0; AssertUintParamCorrect(gl, LOCAL_GL_ELEMENT_ARRAY_BUFFER_BINDING, bound); MOZ_ASSERT(!gl::GLContext::IsBadCallError(errorScope.GetError())); #endif // We do not check the renderbuffer binding, because we never rely on it // matching. }
static GLenum DoRenderbufferStorageMaybeMultisample(gl::GLContext* gl, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height) { MOZ_ASSERT_IF(samples >= 1, gl->IsSupported(gl::GLFeature::framebuffer_multisample)); // Certain OpenGL ES renderbuffer formats may not exist on desktop OpenGL. switch (internalFormat) { case LOCAL_GL_RGBA4: case LOCAL_GL_RGB5_A1: // 16-bit RGBA formats are not supported on desktop GL. if (!gl->IsGLES()) internalFormat = LOCAL_GL_RGBA8; break; case LOCAL_GL_RGB565: // RGB565 is not supported on desktop GL. if (!gl->IsGLES()) internalFormat = LOCAL_GL_RGB8; break; case LOCAL_GL_DEPTH_COMPONENT16: if (!gl->IsGLES() || gl->IsExtensionSupported(gl::GLContext::OES_depth24)) internalFormat = LOCAL_GL_DEPTH_COMPONENT24; else if (gl->IsSupported(gl::GLFeature::packed_depth_stencil)) internalFormat = LOCAL_GL_DEPTH24_STENCIL8; break; case LOCAL_GL_DEPTH_STENCIL: MOZ_CRASH("GFX: GL_DEPTH_STENCIL is not valid here."); break; default: break; } gl::GLContext::LocalErrorScope errorScope(*gl); if (samples > 0) { gl->fRenderbufferStorageMultisample(LOCAL_GL_RENDERBUFFER, samples, internalFormat, width, height); } else { gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, internalFormat, width, height); } return errorScope.GetError(); }
JSObject* throwTerminatedExecutionException(ExecState* exec) { VM& vm = exec->vm(); ErrorHandlingScope errorScope(vm); return vm.throwException(exec, createTerminatedExecutionException(&vm)); }
JSObject* throwStackOverflowError(ExecState* exec) { VM& vm = exec->vm(); ErrorHandlingScope errorScope(vm); return vm.throwException(exec, createStackOverflowError(exec)); }
bool TexUnpackImage::TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName, WebGLTexture* tex, TexImageTarget target, GLint level, const webgl::DriverUnpackInfo* dui, GLint xOffset, GLint yOffset, GLint zOffset, const webgl::PackingInfo& pi, GLenum* const out_error) const { MOZ_ASSERT_IF(needsRespec, !isSubImage); WebGLContext* webgl = tex->mContext; gl::GLContext* gl = webgl->GL(); gl->MakeCurrent(); if (needsRespec) { *out_error = DoTexOrSubImage(isSubImage, gl, target.get(), level, dui, xOffset, yOffset, zOffset, mWidth, mHeight, mDepth, nullptr); if (*out_error) return true; } const char* fallbackReason; do { if (mDepth != 1) { fallbackReason = "depth is not 1"; break; } if (webgl->mPixelStore_UnpackSkipPixels || webgl->mPixelStore_UnpackSkipRows || webgl->mPixelStore_UnpackSkipImages) { fallbackReason = "non-zero UNPACK_SKIP_* not yet supported"; break; } const auto fnHasPremultMismatch = [&]() { if (mSrcAlphaType == gfxAlphaType::Opaque) return false; const bool srcIsPremult = (mSrcAlphaType == gfxAlphaType::Premult); const auto& dstIsPremult = webgl->mPixelStore_PremultiplyAlpha; if (srcIsPremult == dstIsPremult) return false; if (dstIsPremult) { fallbackReason = "UNPACK_PREMULTIPLY_ALPHA_WEBGL is not true"; } else { fallbackReason = "UNPACK_PREMULTIPLY_ALPHA_WEBGL is not false"; } return true; }; if (fnHasPremultMismatch()) break; if (dui->unpackFormat != LOCAL_GL_RGB && dui->unpackFormat != LOCAL_GL_RGBA) { fallbackReason = "`format` is not RGB or RGBA"; break; } if (dui->unpackType != LOCAL_GL_UNSIGNED_BYTE) { fallbackReason = "`type` is not UNSIGNED_BYTE"; break; } gl::ScopedFramebuffer scopedFB(gl); gl::ScopedBindFramebuffer bindFB(gl, scopedFB.FB()); { gl::GLContext::LocalErrorScope errorScope(*gl); gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, target.get(), tex->mGLName, level); if (errorScope.GetError()) { fallbackReason = "bug: failed to attach to FB for blit"; break; } } const GLenum status = gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) { fallbackReason = "bug: failed to confirm FB for blit"; break; } const gfx::IntSize destSize(mWidth, mHeight); const auto dstOrigin = (webgl->mPixelStore_FlipY ? gl::OriginPos::TopLeft : gl::OriginPos::BottomLeft); if (!gl->BlitHelper()->BlitImageToFramebuffer(mImage, destSize, scopedFB.FB(), dstOrigin)) { fallbackReason = "likely bug: failed to blit"; break; } // Blitting was successful, so we're done! *out_error = 0; return true; } while (false); const nsPrintfCString perfMsg("%s: Failed to hit GPU-copy fast-path: %s (src type %u)", funcName, fallbackReason, uint32_t(mImage->GetFormat())); if (webgl->mPixelStore_RequireFastPath) { webgl->ErrorInvalidOperation("%s", perfMsg.BeginReading()); return false; } webgl->GeneratePerfWarning("%s Falling back to CPU upload.", perfMsg.BeginReading()); const RefPtr<gfx::SourceSurface> surf = mImage->GetAsSourceSurface(); RefPtr<gfx::DataSourceSurface> dataSurf; if (surf) { // WARNING: OSX can lose our MakeCurrent here. dataSurf = surf->GetDataSurface(); } if (!dataSurf) { webgl->ErrorOutOfMemory("%s: GetAsSourceSurface or GetDataSurface failed after" " blit failed for TexUnpackImage.", funcName); return false; } const TexUnpackSurface surfBlob(webgl, target, mWidth, mHeight, mDepth, dataSurf, mSrcAlphaType); return surfBlob.TexOrSubImage(isSubImage, needsRespec, funcName, tex, target, level, dui, xOffset, yOffset, zOffset, pi, out_error); }
bool TexUnpackImage::TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName, WebGLTexture* tex, TexImageTarget target, GLint level, const webgl::DriverUnpackInfo* dui, GLint xOffset, GLint yOffset, GLint zOffset, GLenum* const out_error) const { MOZ_ASSERT_IF(needsRespec, !isSubImage); WebGLContext* webgl = tex->mContext; gl::GLContext* gl = webgl->GL(); gl->MakeCurrent(); if (needsRespec) { *out_error = DoTexOrSubImage(isSubImage, gl, target.get(), level, dui, xOffset, yOffset, zOffset, mWidth, mHeight, mDepth, nullptr); if (*out_error) return false; } do { if (mDepth != 1) break; const bool isDstPremult = webgl->mPixelStore_PremultiplyAlpha; if (mIsSrcPremult != isDstPremult) break; if (dui->unpackFormat != LOCAL_GL_RGB && dui->unpackFormat != LOCAL_GL_RGBA) break; if (dui->unpackType != LOCAL_GL_UNSIGNED_BYTE) break; gl::ScopedFramebuffer scopedFB(gl); gl::ScopedBindFramebuffer bindFB(gl, scopedFB.FB()); { gl::GLContext::LocalErrorScope errorScope(*gl); gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, target.get(), tex->mGLName, level); if (errorScope.GetError()) break; } const GLenum status = gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) break; const gfx::IntSize destSize(mWidth, mHeight); const auto dstOrigin = (webgl->mPixelStore_FlipY ? gl::OriginPos::TopLeft : gl::OriginPos::BottomLeft); if (!gl->BlitHelper()->BlitImageToFramebuffer(mImage, destSize, scopedFB.FB(), dstOrigin)) { break; } // Blitting was successful, so we're done! *out_error = 0; return true; } while (false); webgl->GenerateWarning("%s: Failed to hit GPU-copy fast-path. Falling back to CPU" " upload.", funcName); const RefPtr<gfx::SourceSurface> surf = mImage->GetAsSourceSurface(); RefPtr<gfx::DataSourceSurface> dataSurf; if (surf) { // WARNING: OSX can lose our MakeCurrent here. dataSurf = surf->GetDataSurface(); } if (!dataSurf) { webgl->ErrorOutOfMemory("%s: GetAsSourceSurface or GetDataSurface failed after" " blit failed for TexUnpackImage.", funcName); return false; } const TexUnpackSurface surfBlob(webgl, target, mWidth, mHeight, mDepth, dataSurf, mIsSrcPremult); return surfBlob.TexOrSubImage(isSubImage, needsRespec, funcName, tex, target, level, dui, xOffset, yOffset, zOffset, out_error); }
void TexUnpackImage::TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName, WebGLTexture* tex, TexImageTarget target, GLint level, const webgl::DriverUnpackInfo* dui, GLint xOffset, GLint yOffset, GLint zOffset, GLenum* const out_glError) { MOZ_ASSERT_IF(needsRespec, !isSubImage); *out_glError = 0; WebGLContext* webgl = tex->mContext; gl::GLContext* gl = webgl->GL(); gl->MakeCurrent(); if (needsRespec) { GLenum error = DoTexOrSubImage(isSubImage, gl, target.get(), level, dui, xOffset, yOffset, zOffset, mWidth, mHeight, mDepth, nullptr); if (error) { MOZ_ASSERT(!error); *out_glError = LOCAL_GL_OUT_OF_MEMORY; return; } } do { if (dui->unpackFormat != LOCAL_GL_RGB && dui->unpackFormat != LOCAL_GL_RGBA) break; if (dui->unpackType != LOCAL_GL_UNSIGNED_BYTE) break; gl::ScopedFramebuffer scopedFB(gl); gl::ScopedBindFramebuffer bindFB(gl, scopedFB.FB()); { gl::GLContext::LocalErrorScope errorScope(*gl); gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, target.get(), tex->mGLName, level); if (errorScope.GetError()) break; } const GLenum status = gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) break; gl::OriginPos srcOrigin, dstOrigin; OriginsForDOM(webgl, &srcOrigin, &dstOrigin); const gfx::IntSize destSize(mWidth, mHeight); if (!gl->BlitHelper()->BlitImageToFramebuffer(mImage, destSize, scopedFB.FB(), dstOrigin)) { break; } return; // Blitting was successful, so we're done! } while (false); TexUnpackSurface surfBlob(mImage->GetAsSourceSurface(), mIsAlphaPremult); surfBlob.TexOrSubImage(isSubImage, needsRespec, funcName, tex, target, level, dui, xOffset, yOffset, zOffset, out_glError); }
void WebGLBuffer::BufferData(GLenum target, size_t size, const void* data, GLenum usage) { // Careful: data.Length() could conceivably be any uint32_t, but GLsizeiptr // is like intptr_t. if (!CheckedInt<GLsizeiptr>(size).isValid()) return mContext->ErrorOutOfMemory("bad size"); if (!ValidateBufferUsageEnum(mContext, usage)) return; #ifdef XP_MACOSX // bug 790879 if (mContext->gl->WorkAroundDriverBugs() && size > INT32_MAX) { mContext->ErrorOutOfMemory("Allocation size too large."); return; } #endif const void* uploadData = data; UniqueBuffer newIndexCache; if (target == LOCAL_GL_ELEMENT_ARRAY_BUFFER && mContext->mNeedsIndexValidation) { newIndexCache = malloc(size); if (!newIndexCache) { mContext->ErrorOutOfMemory("Failed to alloc index cache."); return; } memcpy(newIndexCache.get(), data, size); uploadData = newIndexCache.get(); } const auto& gl = mContext->gl; const ScopedLazyBind lazyBind(gl, target, this); const bool sizeChanges = (size != ByteLength()); if (sizeChanges) { gl::GLContext::LocalErrorScope errorScope(*gl); gl->fBufferData(target, size, uploadData, usage); const auto error = errorScope.GetError(); if (error) { MOZ_ASSERT(error == LOCAL_GL_OUT_OF_MEMORY); mContext->ErrorOutOfMemory("Error from driver: 0x%04x", error); return; } } else { gl->fBufferData(target, size, uploadData, usage); } mContext->OnDataAllocCall(); mUsage = usage; mByteLength = size; mFetchInvalidator.InvalidateCaches(); mIndexCache = std::move(newIndexCache); if (mIndexCache) { if (!mIndexRanges.empty()) { mContext->GeneratePerfWarning("[%p] Invalidating %u ranges.", this, uint32_t(mIndexRanges.size())); mIndexRanges.clear(); } } ResetLastUpdateFenceId(); }
void WebGLContext::AssertCachedGlobalState() const { #ifdef DEBUG gl::GLContext::LocalErrorScope errorScope(*gl); //////////////// // Draw state MOZ_ASSERT(gl->fIsEnabled(LOCAL_GL_DITHER) == mDitherEnabled); MOZ_ASSERT_IF(IsWebGL2(), gl->fIsEnabled(LOCAL_GL_RASTERIZER_DISCARD) == mRasterizerDiscardEnabled); MOZ_ASSERT(gl->fIsEnabled(LOCAL_GL_SCISSOR_TEST) == mScissorTestEnabled); // Cannot trivially check COLOR_CLEAR_VALUE, since in old GL versions glGet // may clamp based on whether the current framebuffer is floating-point or // not. This also means COLOR_CLEAR_VALUE save+restore is dangerous! realGLboolean depthWriteMask = 0; gl->fGetBooleanv(LOCAL_GL_DEPTH_WRITEMASK, &depthWriteMask); MOZ_ASSERT(depthWriteMask == mDepthWriteMask); GLfloat depthClearValue = 0.0f; gl->fGetFloatv(LOCAL_GL_DEPTH_CLEAR_VALUE, &depthClearValue); MOZ_ASSERT(IsCacheCorrect(mDepthClearValue, depthClearValue)); const int maxStencilBits = 8; const GLuint maxStencilBitsMask = (1 << maxStencilBits) - 1; AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_CLEAR_VALUE, maxStencilBitsMask, mStencilClearValue); // GLES 3.0.4, $4.1.4, p177: // [...] the front and back stencil mask are both set to the value `2^s - // 1`, where `s` is greater than or equal to the number of bits in the // deepest stencil buffer supported by the GL implementation. AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_VALUE_MASK, maxStencilBitsMask, mStencilValueMaskFront); AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_VALUE_MASK, maxStencilBitsMask, mStencilValueMaskBack); AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_WRITEMASK, maxStencilBitsMask, mStencilWriteMaskFront); AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_WRITEMASK, maxStencilBitsMask, mStencilWriteMaskBack); // Viewport GLint int4[4] = {0, 0, 0, 0}; gl->fGetIntegerv(LOCAL_GL_VIEWPORT, int4); MOZ_ASSERT(int4[0] == mViewportX && int4[1] == mViewportY && int4[2] == mViewportWidth && int4[3] == mViewportHeight); AssertUintParamCorrect(gl, LOCAL_GL_PACK_ALIGNMENT, mPixelStore_PackAlignment); AssertUintParamCorrect(gl, LOCAL_GL_UNPACK_ALIGNMENT, mPixelStore_UnpackAlignment); if (IsWebGL2()) { AssertUintParamCorrect(gl, LOCAL_GL_UNPACK_IMAGE_HEIGHT, mPixelStore_UnpackImageHeight); AssertUintParamCorrect(gl, LOCAL_GL_UNPACK_SKIP_IMAGES, mPixelStore_UnpackSkipImages); AssertUintParamCorrect(gl, LOCAL_GL_UNPACK_ROW_LENGTH, mPixelStore_UnpackRowLength); AssertUintParamCorrect(gl, LOCAL_GL_UNPACK_SKIP_ROWS, mPixelStore_UnpackSkipRows); AssertUintParamCorrect(gl, LOCAL_GL_UNPACK_SKIP_PIXELS, mPixelStore_UnpackSkipPixels); AssertUintParamCorrect(gl, LOCAL_GL_PACK_ROW_LENGTH, mPixelStore_PackRowLength); AssertUintParamCorrect(gl, LOCAL_GL_PACK_SKIP_ROWS, mPixelStore_PackSkipRows); AssertUintParamCorrect(gl, LOCAL_GL_PACK_SKIP_PIXELS, mPixelStore_PackSkipPixels); } MOZ_ASSERT(!gl::GLContext::IsBadCallError(errorScope.GetError())); #endif }