2018-11-30 22:52:05 +03:00
|
|
|
|
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
2012-05-21 15:12:37 +04:00
|
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2010-05-18 08:04:22 +04:00
|
|
|
|
|
2009-09-03 04:47:49 +04:00
|
|
|
|
#include "WebGLContext.h"
|
2014-08-22 20:55:00 +04:00
|
|
|
|
|
2017-11-30 14:40:57 +03:00
|
|
|
|
#include <algorithm>
|
2021-08-27 04:47:14 +03:00
|
|
|
|
#include <bitset>
|
2015-07-15 03:37:28 +03:00
|
|
|
|
#include <queue>
|
2020-01-09 01:19:16 +03:00
|
|
|
|
#include <regex>
|
2015-07-15 03:37:28 +03:00
|
|
|
|
|
2012-10-17 23:11:51 +04:00
|
|
|
|
#include "AccessCheck.h"
|
2020-01-09 01:19:14 +03:00
|
|
|
|
#include "CompositableHost.h"
|
2019-02-08 01:35:50 +03:00
|
|
|
|
#include "gfxConfig.h"
|
2009-09-03 04:47:49 +04:00
|
|
|
|
#include "gfxContext.h"
|
2014-11-14 07:03:50 +03:00
|
|
|
|
#include "gfxCrashReporterUtils.h"
|
2019-07-02 19:45:22 +03:00
|
|
|
|
#include "gfxEnv.h"
|
2009-09-03 04:47:49 +04:00
|
|
|
|
#include "gfxPattern.h"
|
2018-01-07 20:35:00 +03:00
|
|
|
|
#include "MozFramebuffer.h"
|
2014-11-14 07:03:50 +03:00
|
|
|
|
#include "GLBlitHelper.h"
|
2013-09-04 16:14:52 +04:00
|
|
|
|
#include "GLContext.h"
|
2014-11-14 07:03:50 +03:00
|
|
|
|
#include "GLContextProvider.h"
|
2014-01-02 19:17:29 +04:00
|
|
|
|
#include "GLReadTexImageHelper.h"
|
2015-07-15 03:37:28 +03:00
|
|
|
|
#include "GLScreenBuffer.h"
|
2014-11-14 07:03:50 +03:00
|
|
|
|
#include "ImageContainer.h"
|
|
|
|
|
#include "ImageEncoder.h"
|
|
|
|
|
#include "Layers.h"
|
2015-10-22 23:04:35 +03:00
|
|
|
|
#include "LayerUserData.h"
|
2014-11-14 07:03:50 +03:00
|
|
|
|
#include "mozilla/dom/BindingUtils.h"
|
2020-11-23 19:21:38 +03:00
|
|
|
|
#include "mozilla/dom/Document.h"
|
2015-10-12 06:21:03 +03:00
|
|
|
|
#include "mozilla/dom/Event.h"
|
2014-11-14 07:03:50 +03:00
|
|
|
|
#include "mozilla/dom/HTMLVideoElement.h"
|
|
|
|
|
#include "mozilla/dom/ImageData.h"
|
2016-05-12 02:45:43 +03:00
|
|
|
|
#include "mozilla/dom/WebGLContextEvent.h"
|
2014-11-14 07:03:50 +03:00
|
|
|
|
#include "mozilla/EnumeratedArrayCycleCollection.h"
|
2020-01-09 01:19:16 +03:00
|
|
|
|
#include "mozilla/EnumeratedRange.h"
|
2020-09-28 01:18:23 +03:00
|
|
|
|
#include "mozilla/gfx/gfxVars.h"
|
2011-07-07 06:00:02 +04:00
|
|
|
|
#include "mozilla/Preferences.h"
|
2014-11-14 07:03:50 +03:00
|
|
|
|
#include "mozilla/ProcessPriorityManager.h"
|
2021-09-11 05:11:11 +03:00
|
|
|
|
#include "mozilla/ResultVariant.h"
|
2016-07-22 20:26:05 +03:00
|
|
|
|
#include "mozilla/ScopeExit.h"
|
2012-06-06 11:40:02 +04:00
|
|
|
|
#include "mozilla/Services.h"
|
2019-07-26 04:10:23 +03:00
|
|
|
|
#include "mozilla/StaticPrefs_webgl.h"
|
2020-06-25 23:42:49 +03:00
|
|
|
|
#include "mozilla/SVGObserverUtils.h"
|
2011-09-20 00:08:56 +04:00
|
|
|
|
#include "mozilla/Telemetry.h"
|
2014-11-14 07:03:50 +03:00
|
|
|
|
#include "nsContentUtils.h"
|
|
|
|
|
#include "nsDisplayList.h"
|
|
|
|
|
#include "nsError.h"
|
|
|
|
|
#include "nsIClassInfoImpl.h"
|
|
|
|
|
#include "nsIWidget.h"
|
|
|
|
|
#include "nsServiceManagerUtils.h"
|
2020-01-09 01:19:14 +03:00
|
|
|
|
#include "SharedSurfaceGL.h"
|
2014-11-14 07:03:50 +03:00
|
|
|
|
#include "prenv.h"
|
|
|
|
|
#include "ScopedGLHelpers.h"
|
2016-02-25 02:54:50 +03:00
|
|
|
|
#include "VRManagerChild.h"
|
2020-01-09 01:19:14 +03:00
|
|
|
|
#include "mozilla/layers/CompositorBridgeChild.h"
|
2018-09-28 22:25:21 +03:00
|
|
|
|
#include "mozilla/layers/ImageBridgeChild.h"
|
2016-02-25 02:54:50 +03:00
|
|
|
|
#include "mozilla/layers/TextureClientSharedSurface.h"
|
2017-10-28 13:07:27 +03:00
|
|
|
|
#include "mozilla/layers/WebRenderUserData.h"
|
|
|
|
|
#include "mozilla/layers/WebRenderCanvasRenderer.h"
|
2015-07-15 03:37:28 +03:00
|
|
|
|
|
|
|
|
|
// Local
|
|
|
|
|
#include "CanvasUtils.h"
|
2020-01-09 01:19:14 +03:00
|
|
|
|
#include "ClientWebGLContext.h"
|
|
|
|
|
#include "HostWebGLContext.h"
|
2014-11-14 07:03:50 +03:00
|
|
|
|
#include "WebGLBuffer.h"
|
2020-01-09 01:19:14 +03:00
|
|
|
|
#include "WebGLChild.h"
|
2014-11-14 07:03:50 +03:00
|
|
|
|
#include "WebGLContextLossHandler.h"
|
|
|
|
|
#include "WebGLContextUtils.h"
|
|
|
|
|
#include "WebGLExtensions.h"
|
2018-09-28 02:38:23 +03:00
|
|
|
|
#include "WebGLFormats.h"
|
2014-11-14 07:03:50 +03:00
|
|
|
|
#include "WebGLFramebuffer.h"
|
|
|
|
|
#include "WebGLMemoryTracker.h"
|
|
|
|
|
#include "WebGLObjectModel.h"
|
2015-07-15 03:37:28 +03:00
|
|
|
|
#include "WebGLProgram.h"
|
2014-11-14 07:03:50 +03:00
|
|
|
|
#include "WebGLQuery.h"
|
|
|
|
|
#include "WebGLSampler.h"
|
2015-07-15 03:37:28 +03:00
|
|
|
|
#include "WebGLShader.h"
|
2020-01-09 01:19:16 +03:00
|
|
|
|
#include "WebGLShaderValidator.h"
|
2016-06-23 12:01:36 +03:00
|
|
|
|
#include "WebGLSync.h"
|
2014-11-26 05:00:06 +03:00
|
|
|
|
#include "WebGLTransformFeedback.h"
|
2020-01-09 01:19:23 +03:00
|
|
|
|
#include "WebGLValidateStrings.h"
|
2014-11-14 07:03:50 +03:00
|
|
|
|
#include "WebGLVertexArray.h"
|
2012-08-21 08:06:46 +04:00
|
|
|
|
|
2016-02-19 04:59:24 +03:00
|
|
|
|
#ifdef MOZ_WIDGET_COCOA
|
|
|
|
|
# include "nsCocoaFeatures.h"
|
|
|
|
|
#endif
|
|
|
|
|
|
2016-06-21 06:38:47 +03:00
|
|
|
|
#ifdef XP_WIN
|
|
|
|
|
# include "WGLLibrary.h"
|
|
|
|
|
#endif
|
|
|
|
|
|
2015-07-15 03:37:28 +03:00
|
|
|
|
// Generated
|
|
|
|
|
#include "mozilla/dom/WebGLRenderingContextBinding.h"
|
|
|
|
|
|
|
|
|
|
namespace mozilla {
|
2013-05-27 18:12:13 +04:00
|
|
|
|
|
2012-08-01 22:58:44 +04:00
|
|
|
|
WebGLContextOptions::WebGLContextOptions() {
|
|
|
|
|
// Set default alpha state based on preference.
|
2019-06-29 00:56:43 +03:00
|
|
|
|
alpha = !StaticPrefs::webgl_default_no_alpha();
|
|
|
|
|
antialias = StaticPrefs::webgl_default_antialias();
|
2012-08-01 22:58:44 +04:00
|
|
|
|
}
|
|
|
|
|
|
2018-06-23 02:47:02 +03:00
|
|
|
|
bool WebGLContextOptions::operator==(const WebGLContextOptions& r) const {
|
|
|
|
|
bool eq = true;
|
|
|
|
|
eq &= (alpha == r.alpha);
|
|
|
|
|
eq &= (depth == r.depth);
|
|
|
|
|
eq &= (stencil == r.stencil);
|
|
|
|
|
eq &= (premultipliedAlpha == r.premultipliedAlpha);
|
|
|
|
|
eq &= (antialias == r.antialias);
|
|
|
|
|
eq &= (preserveDrawingBuffer == r.preserveDrawingBuffer);
|
|
|
|
|
eq &= (failIfMajorPerformanceCaveat == r.failIfMajorPerformanceCaveat);
|
2019-11-16 00:32:15 +03:00
|
|
|
|
eq &= (xrCompatible == r.xrCompatible);
|
2018-06-23 02:47:02 +03:00
|
|
|
|
eq &= (powerPreference == r.powerPreference);
|
|
|
|
|
return eq;
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-09 01:19:23 +03:00
|
|
|
|
static std::list<WebGLContext*> sWebglLru;
|
|
|
|
|
|
2020-02-19 00:08:00 +03:00
|
|
|
|
WebGLContext::LruPosition::LruPosition() : mItr(sWebglLru.end()) {} // NOLINT
|
2020-01-09 01:19:23 +03:00
|
|
|
|
|
|
|
|
|
WebGLContext::LruPosition::LruPosition(WebGLContext& context)
|
|
|
|
|
: mItr(sWebglLru.insert(sWebglLru.end(), &context)) {}
|
|
|
|
|
|
|
|
|
|
void WebGLContext::LruPosition::reset() {
|
|
|
|
|
const auto end = sWebglLru.end();
|
|
|
|
|
if (mItr != end) {
|
|
|
|
|
sWebglLru.erase(mItr);
|
|
|
|
|
mItr = end;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-09 01:19:16 +03:00
|
|
|
|
WebGLContext::WebGLContext(HostWebGLContext& host,
|
|
|
|
|
const webgl::InitContextDesc& desc)
|
|
|
|
|
: gl(mGL_OnlyClearInDestroyResourcesAndContext), // const reference
|
|
|
|
|
mHost(&host),
|
|
|
|
|
mResistFingerprinting(desc.resistFingerprinting),
|
|
|
|
|
mOptions(desc.options),
|
2020-01-09 01:19:23 +03:00
|
|
|
|
mPrincipalKey(desc.principalKey),
|
2019-06-29 00:56:43 +03:00
|
|
|
|
mMaxPerfWarnings(StaticPrefs::webgl_perf_max_warnings()),
|
2018-04-13 16:01:28 +03:00
|
|
|
|
mMaxAcceptableFBStatusInvals(
|
2019-06-29 00:56:43 +03:00
|
|
|
|
StaticPrefs::webgl_perf_max_acceptable_fb_status_invals()),
|
2018-04-13 16:01:28 +03:00
|
|
|
|
mContextLossHandler(this),
|
2020-01-09 01:19:23 +03:00
|
|
|
|
mMaxWarnings(StaticPrefs::webgl_max_warnings_per_context()),
|
2019-06-29 00:56:43 +03:00
|
|
|
|
mAllowFBInvalidation(StaticPrefs::webgl_allow_fb_invalidation()),
|
2020-01-09 01:19:16 +03:00
|
|
|
|
mMsaaSamples((uint8_t)StaticPrefs::webgl_msaa_samples()),
|
|
|
|
|
mRequestedSize(desc.size) {
|
|
|
|
|
host.mContext = this;
|
2020-01-09 01:19:26 +03:00
|
|
|
|
const FuncScope funcScope(*this, "<Create>");
|
2016-06-03 11:18:56 +03:00
|
|
|
|
}
|
|
|
|
|
|
2020-01-09 01:19:16 +03:00
|
|
|
|
WebGLContext::~WebGLContext() { DestroyResourcesAndContext(); }
|
|
|
|
|
|
2010-07-19 09:01:14 +04:00
|
|
|
|
void WebGLContext::DestroyResourcesAndContext() {
|
|
|
|
|
if (!gl) return;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
|
2017-12-19 05:30:56 +03:00
|
|
|
|
mDefaultFB = nullptr;
|
|
|
|
|
mResolvedDefaultFB = nullptr;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
|
2011-12-04 23:15:42 +04:00
|
|
|
|
mBound2DTextures.Clear();
|
|
|
|
|
mBoundCubeMapTextures.Clear();
|
2014-10-14 03:42:20 +04:00
|
|
|
|
mBound3DTextures.Clear();
|
2015-11-25 07:15:29 +03:00
|
|
|
|
mBound2DArrayTextures.Clear();
|
2015-06-09 03:18:19 +03:00
|
|
|
|
mBoundSamplers.Clear();
|
2012-07-30 18:20:58 +04:00
|
|
|
|
mBoundArrayBuffer = nullptr;
|
2014-12-05 10:04:55 +03:00
|
|
|
|
mBoundCopyReadBuffer = nullptr;
|
|
|
|
|
mBoundCopyWriteBuffer = nullptr;
|
|
|
|
|
mBoundPixelPackBuffer = nullptr;
|
|
|
|
|
mBoundPixelUnpackBuffer = nullptr;
|
2018-03-30 02:43:58 +03:00
|
|
|
|
mBoundTransformFeedbackBuffer = nullptr;
|
2014-12-05 10:04:55 +03:00
|
|
|
|
mBoundUniformBuffer = nullptr;
|
2012-07-30 18:20:58 +04:00
|
|
|
|
mCurrentProgram = nullptr;
|
2015-01-16 02:40:39 +03:00
|
|
|
|
mActiveProgramLinkInfo = nullptr;
|
2015-01-13 02:05:21 +03:00
|
|
|
|
mBoundDrawFramebuffer = nullptr;
|
|
|
|
|
mBoundReadFramebuffer = nullptr;
|
2013-06-28 01:07:21 +04:00
|
|
|
|
mBoundVertexArray = nullptr;
|
|
|
|
|
mDefaultVertexArray = nullptr;
|
2014-11-26 05:00:06 +03:00
|
|
|
|
mBoundTransformFeedback = nullptr;
|
|
|
|
|
mDefaultTransformFeedback = nullptr;
|
|
|
|
|
|
2016-10-04 04:33:52 +03:00
|
|
|
|
mQuerySlot_SamplesPassed = nullptr;
|
|
|
|
|
mQuerySlot_TFPrimsWritten = nullptr;
|
|
|
|
|
mQuerySlot_TimeElapsed = nullptr;
|
|
|
|
|
|
2016-09-10 07:02:54 +03:00
|
|
|
|
mIndexedUniformBufferBindings.clear();
|
2014-12-05 10:04:55 +03:00
|
|
|
|
|
2016-06-03 11:18:56 +03:00
|
|
|
|
//////
|
2018-11-30 13:46:48 +03:00
|
|
|
|
|
2016-12-29 11:08:39 +03:00
|
|
|
|
if (mEmptyTFO) {
|
|
|
|
|
gl->fDeleteTransformFeedbacks(1, &mEmptyTFO);
|
|
|
|
|
mEmptyTFO = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//////
|
|
|
|
|
|
2016-07-21 11:12:15 +03:00
|
|
|
|
if (mFakeVertexAttrib0BufferObject) {
|
2011-02-25 01:17:34 +03:00
|
|
|
|
gl->fDeleteBuffers(1, &mFakeVertexAttrib0BufferObject);
|
2016-07-21 11:12:15 +03:00
|
|
|
|
mFakeVertexAttrib0BufferObject = 0;
|
|
|
|
|
}
|
2011-02-25 01:17:34 +03:00
|
|
|
|
|
2013-11-05 13:35:50 +04:00
|
|
|
|
// disable all extensions except "WEBGL_lose_context". see bug #927969
|
|
|
|
|
// spec: http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2
|
2014-04-26 06:34:07 +04:00
|
|
|
|
for (size_t i = 0; i < size_t(WebGLExtensionID::Max); ++i) {
|
2013-11-05 13:35:50 +04:00
|
|
|
|
WebGLExtensionID extension = WebGLExtensionID(i);
|
2020-01-09 01:19:16 +03:00
|
|
|
|
if (extension == WebGLExtensionID::WEBGL_lose_context) continue;
|
2013-11-05 13:35:50 +04:00
|
|
|
|
mExtensions[extension] = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-19 09:01:14 +04:00
|
|
|
|
// We just got rid of everything, so the context had better
|
|
|
|
|
// have been going away.
|
2020-01-09 01:19:16 +03:00
|
|
|
|
if (gl::GLContext::ShouldSpew()) {
|
2012-06-11 19:25:06 +04:00
|
|
|
|
printf_stderr("--- WebGL context destroyed: %p\n", gl.get());
|
2016-06-07 02:29:08 +03:00
|
|
|
|
}
|
2010-07-19 09:01:14 +04:00
|
|
|
|
|
2016-07-21 11:12:15 +03:00
|
|
|
|
MOZ_ASSERT(gl);
|
2017-12-19 05:30:56 +03:00
|
|
|
|
gl->MarkDestroyed();
|
2016-07-21 11:12:15 +03:00
|
|
|
|
mGL_OnlyClearInDestroyResourcesAndContext = nullptr;
|
|
|
|
|
MOZ_ASSERT(!gl);
|
2009-09-03 04:47:49 +04:00
|
|
|
|
}
|
|
|
|
|
|
2020-06-15 21:25:55 +03:00
|
|
|
|
void ClientWebGLContext::MarkCanvasDirty() {
|
2021-12-10 05:57:54 +03:00
|
|
|
|
if (!mCanvasElement && !mOffscreenCanvas) return;
|
2011-03-28 03:59:47 +04:00
|
|
|
|
|
2022-01-24 18:31:14 +03:00
|
|
|
|
mFrameCaptureState = FrameCaptureState::DIRTY;
|
2015-09-17 06:37:05 +03:00
|
|
|
|
|
2021-12-10 02:13:23 +03:00
|
|
|
|
if (mIsCanvasDirty) return;
|
|
|
|
|
mIsCanvasDirty = true;
|
|
|
|
|
|
2021-12-10 05:57:54 +03:00
|
|
|
|
if (mCanvasElement) {
|
|
|
|
|
SVGObserverUtils::InvalidateDirectRenderingObservers(mCanvasElement);
|
|
|
|
|
mCanvasElement->InvalidateCanvasContent(nullptr);
|
2021-12-10 05:57:55 +03:00
|
|
|
|
} else if (mOffscreenCanvas) {
|
|
|
|
|
mOffscreenCanvas->QueueCommitToCompositor();
|
2021-12-10 05:57:54 +03:00
|
|
|
|
}
|
2009-09-03 04:47:49 +04:00
|
|
|
|
}
|
|
|
|
|
|
2015-10-12 06:21:03 +03:00
|
|
|
|
void WebGLContext::OnMemoryPressure() {
|
|
|
|
|
bool shouldLoseContext = mLoseContextOnMemoryPressure;
|
|
|
|
|
|
|
|
|
|
if (!mCanLoseContextInForeground &&
|
|
|
|
|
ProcessPriorityManager::CurrentProcessIsForeground()) {
|
|
|
|
|
shouldLoseContext = false;
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-09 01:19:16 +03:00
|
|
|
|
if (shouldLoseContext) LoseContext();
|
2015-10-12 06:21:03 +03:00
|
|
|
|
}
|
|
|
|
|
|
2018-11-30 13:46:48 +03:00
|
|
|
|
// --
|
2015-05-21 18:51:49 +03:00
|
|
|
|
|
2016-06-21 06:28:57 +03:00
|
|
|
|
bool WebGLContext::CreateAndInitGL(
|
|
|
|
|
bool forceEnabled, std::vector<FailureReason>* const out_failReasons) {
|
2020-01-09 01:19:26 +03:00
|
|
|
|
const FuncScope funcScope(*this, "<Create>");
|
|
|
|
|
|
2018-11-11 20:44:13 +03:00
|
|
|
|
// WebGL2 is separately blocked:
|
2019-07-12 05:34:19 +03:00
|
|
|
|
if (IsWebGL2() && !forceEnabled) {
|
2017-03-02 23:48:12 +03:00
|
|
|
|
FailureReason reason;
|
2020-09-28 01:18:23 +03:00
|
|
|
|
if (!gfx::gfxVars::AllowWebgl2()) {
|
2020-10-01 11:14:12 +03:00
|
|
|
|
reason.info =
|
|
|
|
|
"AllowWebgl2:false restricts context creation on this system.";
|
2017-03-02 23:48:12 +03:00
|
|
|
|
out_failReasons->push_back(reason);
|
|
|
|
|
GenerateWarning("%s", reason.info.BeginReading());
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
}
|
2017-03-02 23:48:12 +03:00
|
|
|
|
|
2017-03-09 23:30:01 +03:00
|
|
|
|
gl::CreateContextFlags flags = (gl::CreateContextFlags::NO_VALIDATION |
|
|
|
|
|
gl::CreateContextFlags::PREFER_ROBUSTNESS);
|
2016-06-22 22:47:03 +03:00
|
|
|
|
bool tryNativeGL = true;
|
|
|
|
|
bool tryANGLE = false;
|
|
|
|
|
|
2016-06-21 06:43:06 +03:00
|
|
|
|
if (forceEnabled) {
|
2016-06-22 22:47:03 +03:00
|
|
|
|
flags |= gl::CreateContextFlags::FORCE_ENABLE_HARDWARE;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-20 00:49:01 +03:00
|
|
|
|
if (StaticPrefs::webgl_cgl_multithreaded()) {
|
|
|
|
|
flags |= gl::CreateContextFlags::PREFER_MULTITHREADED;
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-22 22:47:03 +03:00
|
|
|
|
if (IsWebGL2()) {
|
|
|
|
|
flags |= gl::CreateContextFlags::PREFER_ES3;
|
2019-11-11 16:09:32 +03:00
|
|
|
|
} else {
|
|
|
|
|
// Request and prefer ES2 context for WebGL1.
|
|
|
|
|
flags |= gl::CreateContextFlags::PREFER_EXACT_VERSION;
|
|
|
|
|
|
|
|
|
|
if (!StaticPrefs::webgl_1_allow_core_profiles()) {
|
|
|
|
|
flags |= gl::CreateContextFlags::REQUIRE_COMPAT_PROFILE;
|
|
|
|
|
}
|
2016-06-22 22:47:03 +03:00
|
|
|
|
}
|
|
|
|
|
|
2019-06-25 04:09:25 +03:00
|
|
|
|
{
|
2019-07-02 19:45:22 +03:00
|
|
|
|
auto powerPref = mOptions.powerPreference;
|
|
|
|
|
|
|
|
|
|
// If "Use hardware acceleration when available" option is disabled:
|
2020-01-09 01:19:16 +03:00
|
|
|
|
if (!gfx::gfxConfig::IsEnabled(gfx::Feature::HW_COMPOSITING)) {
|
2019-07-02 19:45:22 +03:00
|
|
|
|
powerPref = dom::WebGLPowerPreference::Low_power;
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-21 07:00:07 +03:00
|
|
|
|
const auto overrideVal = StaticPrefs::webgl_power_preference_override();
|
|
|
|
|
if (overrideVal > 0) {
|
|
|
|
|
powerPref = dom::WebGLPowerPreference::High_performance;
|
|
|
|
|
} else if (overrideVal < 0) {
|
2019-07-02 19:45:22 +03:00
|
|
|
|
powerPref = dom::WebGLPowerPreference::Low_power;
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-21 07:00:07 +03:00
|
|
|
|
if (powerPref == dom::WebGLPowerPreference::High_performance) {
|
2019-06-25 04:09:25 +03:00
|
|
|
|
flags |= gl::CreateContextFlags::HIGH_POWER;
|
|
|
|
|
}
|
2019-02-08 01:35:50 +03:00
|
|
|
|
}
|
|
|
|
|
|
2020-09-28 01:18:23 +03:00
|
|
|
|
if (!gfx::gfxVars::WebglAllowCoreProfile()) {
|
2017-11-24 11:51:37 +03:00
|
|
|
|
flags |= gl::CreateContextFlags::REQUIRE_COMPAT_PROFILE;
|
|
|
|
|
}
|
2018-06-28 23:09:16 +03:00
|
|
|
|
|
|
|
|
|
// --
|
|
|
|
|
|
2016-06-22 22:47:03 +03:00
|
|
|
|
const bool useEGL = PR_GetEnv("MOZ_WEBGL_FORCE_EGL");
|
|
|
|
|
|
|
|
|
|
#ifdef XP_WIN
|
2016-09-12 12:39:54 +03:00
|
|
|
|
tryNativeGL = false;
|
|
|
|
|
tryANGLE = true;
|
2016-06-22 22:47:03 +03:00
|
|
|
|
|
2019-06-29 00:56:43 +03:00
|
|
|
|
if (StaticPrefs::webgl_disable_wgl()) {
|
2016-06-22 22:47:03 +03:00
|
|
|
|
tryNativeGL = false;
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-29 00:56:43 +03:00
|
|
|
|
if (StaticPrefs::webgl_disable_angle() ||
|
|
|
|
|
PR_GetEnv("MOZ_WEBGL_FORCE_OPENGL") || useEGL) {
|
2016-06-22 22:47:03 +03:00
|
|
|
|
tryNativeGL = true;
|
|
|
|
|
tryANGLE = false;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (tryNativeGL && !forceEnabled) {
|
2016-06-21 06:28:57 +03:00
|
|
|
|
FailureReason reason;
|
2020-09-28 01:18:23 +03:00
|
|
|
|
if (!gfx::gfxVars::WebglAllowWindowsNativeGl()) {
|
2020-10-01 11:14:12 +03:00
|
|
|
|
reason.info =
|
|
|
|
|
"WebglAllowWindowsNativeGl:false restricts context creation on this "
|
|
|
|
|
"system.";
|
2016-06-21 06:28:57 +03:00
|
|
|
|
|
|
|
|
|
out_failReasons->push_back(reason);
|
|
|
|
|
|
2016-12-10 02:48:22 +03:00
|
|
|
|
GenerateWarning("%s", reason.info.BeginReading());
|
2016-06-22 22:47:03 +03:00
|
|
|
|
tryNativeGL = false;
|
2016-06-21 06:28:57 +03:00
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
}
|
2016-06-21 06:28:57 +03:00
|
|
|
|
|
2018-06-28 23:09:16 +03:00
|
|
|
|
// --
|
2018-11-30 13:46:48 +03:00
|
|
|
|
|
2021-07-30 18:30:52 +03:00
|
|
|
|
using fnCreateT = decltype(gl::GLContextProviderEGL::CreateHeadless);
|
2020-06-15 21:25:55 +03:00
|
|
|
|
const auto fnCreate = [&](fnCreateT* const pfnCreate,
|
2018-06-28 23:09:16 +03:00
|
|
|
|
const char* const info) {
|
|
|
|
|
nsCString failureId;
|
2020-06-15 21:25:55 +03:00
|
|
|
|
const RefPtr<gl::GLContext> gl = pfnCreate({flags}, &failureId);
|
2018-06-28 23:09:16 +03:00
|
|
|
|
if (!gl) {
|
|
|
|
|
out_failReasons->push_back(WebGLContext::FailureReason(failureId, info));
|
|
|
|
|
}
|
|
|
|
|
return gl;
|
|
|
|
|
};
|
2018-11-30 13:46:48 +03:00
|
|
|
|
|
2018-06-28 23:09:16 +03:00
|
|
|
|
const auto newGL = [&]() -> RefPtr<gl::GLContext> {
|
|
|
|
|
if (tryNativeGL) {
|
|
|
|
|
if (useEGL)
|
2020-06-15 21:25:55 +03:00
|
|
|
|
return fnCreate(&gl::GLContextProviderEGL::CreateHeadless, "useEGL");
|
2018-11-30 13:46:48 +03:00
|
|
|
|
|
2018-06-28 23:09:16 +03:00
|
|
|
|
const auto ret =
|
2020-06-15 21:25:55 +03:00
|
|
|
|
fnCreate(&gl::GLContextProvider::CreateHeadless, "tryNativeGL");
|
2013-04-22 15:15:59 +04:00
|
|
|
|
if (ret) return ret;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
}
|
|
|
|
|
|
2018-06-28 23:09:16 +03:00
|
|
|
|
if (tryANGLE) {
|
2020-06-15 21:25:55 +03:00
|
|
|
|
return fnCreate(&gl::GLContextProviderEGL::CreateHeadless, "tryANGLE");
|
2018-11-30 13:46:48 +03:00
|
|
|
|
}
|
2018-06-28 23:09:16 +03:00
|
|
|
|
return nullptr;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
}();
|
|
|
|
|
|
2018-06-28 23:09:16 +03:00
|
|
|
|
if (!newGL) {
|
|
|
|
|
out_failReasons->push_back(
|
|
|
|
|
FailureReason("FEATURE_FAILURE_WEBGL_EXHAUSTED_DRIVERS",
|
|
|
|
|
"Exhausted GL driver options."));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2016-06-21 06:28:57 +03:00
|
|
|
|
|
2018-06-28 23:09:16 +03:00
|
|
|
|
// --
|
|
|
|
|
|
|
|
|
|
FailureReason reason;
|
2016-06-21 06:28:57 +03:00
|
|
|
|
|
2018-06-28 23:09:16 +03:00
|
|
|
|
mGL_OnlyClearInDestroyResourcesAndContext = newGL;
|
|
|
|
|
MOZ_RELEASE_ASSERT(gl);
|
|
|
|
|
if (!InitAndValidateGL(&reason)) {
|
|
|
|
|
DestroyResourcesAndContext();
|
|
|
|
|
MOZ_RELEASE_ASSERT(!gl);
|
2016-06-21 06:28:57 +03:00
|
|
|
|
|
2018-06-28 23:09:16 +03:00
|
|
|
|
// The fail reason here should be specific enough for now.
|
|
|
|
|
out_failReasons->push_back(reason);
|
|
|
|
|
return false;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
}
|
2016-06-21 06:28:57 +03:00
|
|
|
|
|
2020-07-02 04:42:21 +03:00
|
|
|
|
const auto val = StaticPrefs::webgl_debug_incomplete_tex_color();
|
|
|
|
|
if (val) {
|
|
|
|
|
mIncompleteTexOverride.reset(new gl::Texture(*gl));
|
|
|
|
|
const gl::ScopedBindTexture autoBind(gl, mIncompleteTexOverride->name);
|
|
|
|
|
const auto heapVal = std::make_unique<uint32_t>(val);
|
2020-07-04 12:38:43 +03:00
|
|
|
|
gl->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_RGBA, 1, 1, 0,
|
|
|
|
|
LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, heapVal.get());
|
2020-07-02 04:42:21 +03:00
|
|
|
|
}
|
|
|
|
|
|
2018-06-28 23:09:16 +03:00
|
|
|
|
return true;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
}
|
2016-06-21 06:28:57 +03:00
|
|
|
|
|
2018-06-28 23:09:16 +03:00
|
|
|
|
// Fallback for resizes:
|
|
|
|
|
|
2018-07-27 07:46:33 +03:00
|
|
|
|
bool WebGLContext::EnsureDefaultFB() {
|
2017-12-19 05:30:56 +03:00
|
|
|
|
if (mDefaultFB) {
|
2020-01-09 01:19:26 +03:00
|
|
|
|
MOZ_ASSERT(*uvec2::FromSize(mDefaultFB->mSize) == mRequestedSize);
|
2018-06-28 23:09:16 +03:00
|
|
|
|
return true;
|
2014-08-28 03:16:22 +04:00
|
|
|
|
}
|
|
|
|
|
|
2017-12-19 05:30:56 +03:00
|
|
|
|
const bool depthStencil = mOptions.depth || mOptions.stencil;
|
2020-01-09 01:19:16 +03:00
|
|
|
|
auto attemptSize = gfx::IntSize{mRequestedSize.x, mRequestedSize.y};
|
2017-12-19 05:30:56 +03:00
|
|
|
|
|
|
|
|
|
while (attemptSize.width || attemptSize.height) {
|
|
|
|
|
attemptSize.width = std::max(attemptSize.width, 1);
|
|
|
|
|
attemptSize.height = std::max(attemptSize.height, 1);
|
|
|
|
|
|
|
|
|
|
[&]() {
|
|
|
|
|
if (mOptions.antialias) {
|
|
|
|
|
MOZ_ASSERT(!mDefaultFB);
|
2020-01-09 01:19:16 +03:00
|
|
|
|
mDefaultFB = gl::MozFramebuffer::Create(gl, attemptSize, mMsaaSamples,
|
|
|
|
|
depthStencil);
|
2017-12-19 05:30:56 +03:00
|
|
|
|
if (mDefaultFB) return;
|
|
|
|
|
if (mOptionsFrozen) return;
|
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
|
2017-12-19 05:30:56 +03:00
|
|
|
|
MOZ_ASSERT(!mDefaultFB);
|
2020-01-09 01:19:16 +03:00
|
|
|
|
mDefaultFB = gl::MozFramebuffer::Create(gl, attemptSize, 0, depthStencil);
|
2017-12-19 05:30:56 +03:00
|
|
|
|
}();
|
2014-08-28 03:16:22 +04:00
|
|
|
|
|
2017-12-22 04:14:54 +03:00
|
|
|
|
if (mDefaultFB) break;
|
2014-08-28 03:16:22 +04:00
|
|
|
|
|
2017-12-19 05:30:56 +03:00
|
|
|
|
attemptSize.width /= 2;
|
|
|
|
|
attemptSize.height /= 2;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
}
|
2014-08-28 03:16:22 +04:00
|
|
|
|
|
2017-12-19 05:30:56 +03:00
|
|
|
|
if (!mDefaultFB) {
|
2018-07-27 07:46:33 +03:00
|
|
|
|
GenerateWarning("Backbuffer resize failed. Losing context.");
|
2020-01-09 01:19:16 +03:00
|
|
|
|
LoseContext();
|
2018-06-28 23:09:16 +03:00
|
|
|
|
return false;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
}
|
|
|
|
|
|
2017-12-19 05:30:56 +03:00
|
|
|
|
mDefaultFB_IsInvalid = true;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
|
2020-01-09 01:19:26 +03:00
|
|
|
|
const auto actualSize = *uvec2::FromSize(mDefaultFB->mSize);
|
2020-01-09 01:19:16 +03:00
|
|
|
|
if (actualSize != mRequestedSize) {
|
2014-08-28 03:16:22 +04:00
|
|
|
|
GenerateWarning(
|
2020-01-09 01:19:16 +03:00
|
|
|
|
"Requested size %ux%u was too large, but resize"
|
|
|
|
|
" to %ux%u succeeded.",
|
|
|
|
|
mRequestedSize.x, mRequestedSize.y, actualSize.x, actualSize.y);
|
2014-08-28 03:16:22 +04:00
|
|
|
|
}
|
2020-01-09 01:19:16 +03:00
|
|
|
|
mRequestedSize = actualSize;
|
2014-08-28 03:16:22 +04:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-09 01:19:16 +03:00
|
|
|
|
void WebGLContext::Resize(uvec2 requestedSize) {
|
|
|
|
|
// Zero-sized surfaces can cause problems.
|
|
|
|
|
if (!requestedSize.x) {
|
|
|
|
|
requestedSize.x = 1;
|
|
|
|
|
}
|
|
|
|
|
if (!requestedSize.y) {
|
|
|
|
|
requestedSize.y = 1;
|
2012-09-27 18:13:45 +04:00
|
|
|
|
}
|
2012-08-03 01:28:02 +04:00
|
|
|
|
|
2020-01-09 01:19:16 +03:00
|
|
|
|
// Kill our current default fb(s), for later lazy allocation.
|
|
|
|
|
mRequestedSize = requestedSize;
|
|
|
|
|
mDefaultFB = nullptr;
|
|
|
|
|
mResetLayer = true; // New size means new Layer.
|
|
|
|
|
}
|
2014-11-14 07:03:50 +03:00
|
|
|
|
|
2020-01-09 01:19:16 +03:00
|
|
|
|
UniquePtr<webgl::FormatUsageAuthority> WebGLContext::CreateFormatUsage(
|
|
|
|
|
gl::GLContext* gl) const {
|
|
|
|
|
return webgl::FormatUsageAuthority::CreateForWebGL1(gl);
|
|
|
|
|
}
|
2011-05-19 14:49:18 +04:00
|
|
|
|
|
2020-01-09 01:19:16 +03:00
|
|
|
|
/*static*/
|
|
|
|
|
RefPtr<WebGLContext> WebGLContext::Create(HostWebGLContext& host,
|
|
|
|
|
const webgl::InitContextDesc& desc,
|
|
|
|
|
webgl::InitContextResult* const out) {
|
2021-12-31 03:56:07 +03:00
|
|
|
|
AUTO_PROFILER_LABEL("WebGLContext::Create", GRAPHICS);
|
2020-01-09 01:19:16 +03:00
|
|
|
|
nsCString failureId = "FEATURE_FAILURE_WEBGL_UNKOWN"_ns;
|
|
|
|
|
const bool forceEnabled = StaticPrefs::webgl_force_enabled();
|
|
|
|
|
ScopedGfxFeatureReporter reporter("WebGL", forceEnabled);
|
2014-08-28 03:16:22 +04:00
|
|
|
|
|
2020-01-09 01:19:16 +03:00
|
|
|
|
auto res = [&]() -> Result<RefPtr<WebGLContext>, std::string> {
|
|
|
|
|
bool disabled = StaticPrefs::webgl_disabled();
|
2014-08-28 03:16:22 +04:00
|
|
|
|
|
2020-01-09 01:19:16 +03:00
|
|
|
|
// TODO: When we have software webgl support we should use that instead.
|
|
|
|
|
disabled |= gfxPlatform::InSafeMode();
|
2013-10-31 17:52:24 +04:00
|
|
|
|
|
2020-01-09 01:19:16 +03:00
|
|
|
|
if (disabled) {
|
|
|
|
|
if (gfxPlatform::InSafeMode()) {
|
|
|
|
|
failureId = "FEATURE_FAILURE_WEBGL_SAFEMODE"_ns;
|
|
|
|
|
} else {
|
|
|
|
|
failureId = "FEATURE_FAILURE_WEBGL_DISABLED"_ns;
|
|
|
|
|
}
|
|
|
|
|
return Err("WebGL is currently disabled.");
|
2015-03-19 05:55:44 +03:00
|
|
|
|
}
|
|
|
|
|
|
2020-01-09 01:19:16 +03:00
|
|
|
|
// Alright, now let's start trying.
|
2010-06-10 02:07:12 +04:00
|
|
|
|
|
2020-01-09 01:19:16 +03:00
|
|
|
|
RefPtr<WebGLContext> webgl;
|
|
|
|
|
if (desc.isWebgl2) {
|
|
|
|
|
webgl = new WebGL2Context(host, desc);
|
2016-07-29 21:28:51 +03:00
|
|
|
|
} else {
|
2020-01-09 01:19:16 +03:00
|
|
|
|
webgl = new WebGLContext(host, desc);
|
2014-08-27 13:15:40 +04:00
|
|
|
|
}
|
|
|
|
|
|
2020-01-09 01:19:16 +03:00
|
|
|
|
MOZ_ASSERT(!webgl->gl);
|
|
|
|
|
std::vector<FailureReason> failReasons;
|
|
|
|
|
if (!webgl->CreateAndInitGL(forceEnabled, &failReasons)) {
|
|
|
|
|
nsCString text("WebGL creation failed: ");
|
|
|
|
|
for (const auto& cur : failReasons) {
|
|
|
|
|
// Don't try to accumulate using an empty key if |cur.key| is empty.
|
|
|
|
|
if (cur.key.IsEmpty()) {
|
|
|
|
|
Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_FAILURE_ID,
|
|
|
|
|
"FEATURE_FAILURE_REASON_UNKNOWN"_ns);
|
|
|
|
|
} else {
|
|
|
|
|
Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_FAILURE_ID, cur.key);
|
|
|
|
|
}
|
2016-05-12 02:45:43 +03:00
|
|
|
|
|
2021-03-30 02:35:29 +03:00
|
|
|
|
const auto str = nsPrintfCString("\n* %s (%s)", cur.info.BeginReading(),
|
|
|
|
|
cur.key.BeginReading());
|
|
|
|
|
text.Append(str);
|
2020-01-09 01:19:16 +03:00
|
|
|
|
}
|
|
|
|
|
failureId = "FEATURE_FAILURE_REASON"_ns;
|
|
|
|
|
return Err(text.BeginReading());
|
2015-05-21 18:51:49 +03:00
|
|
|
|
}
|
2020-01-09 01:19:16 +03:00
|
|
|
|
MOZ_ASSERT(webgl->gl);
|
|
|
|
|
|
|
|
|
|
if (desc.options.failIfMajorPerformanceCaveat) {
|
|
|
|
|
if (webgl->gl->IsWARP()) {
|
|
|
|
|
failureId = "FEATURE_FAILURE_WEBGL_PERF_WARP"_ns;
|
|
|
|
|
return Err(
|
|
|
|
|
"failIfMajorPerformanceCaveat: Driver is not"
|
|
|
|
|
" hardware-accelerated.");
|
2018-11-30 13:46:48 +03:00
|
|
|
|
}
|
|
|
|
|
|
2020-01-09 01:19:16 +03:00
|
|
|
|
#ifdef XP_WIN
|
|
|
|
|
if (webgl->gl->GetContextType() == gl::GLContextType::WGL &&
|
|
|
|
|
!gl::sWGLLib.HasDXInterop2()) {
|
|
|
|
|
failureId = "FEATURE_FAILURE_WEBGL_DXGL_INTEROP2"_ns;
|
2020-12-07 08:35:57 +03:00
|
|
|
|
return Err("failIfMajorPerformanceCaveat: WGL without DXGLInterop2.");
|
2020-01-09 01:19:16 +03:00
|
|
|
|
}
|
|
|
|
|
#endif
|
2018-11-30 13:46:48 +03:00
|
|
|
|
}
|
2015-05-21 18:51:49 +03:00
|
|
|
|
|
2020-01-09 01:19:16 +03:00
|
|
|
|
const FuncScope funcScope(*webgl, "getContext/restoreContext");
|
2016-06-21 06:38:47 +03:00
|
|
|
|
|
2020-01-09 01:19:16 +03:00
|
|
|
|
MOZ_ASSERT(!webgl->mDefaultFB);
|
|
|
|
|
if (!webgl->EnsureDefaultFB()) {
|
2020-01-09 01:19:23 +03:00
|
|
|
|
MOZ_ASSERT(!webgl->mDefaultFB);
|
|
|
|
|
MOZ_ASSERT(webgl->IsContextLost());
|
2020-01-09 01:19:16 +03:00
|
|
|
|
failureId = "FEATURE_FAILURE_WEBGL_BACKBUFFER"_ns;
|
|
|
|
|
return Err("Initializing WebGL backbuffer failed.");
|
|
|
|
|
}
|
2017-12-22 04:14:54 +03:00
|
|
|
|
|
2020-01-09 01:19:16 +03:00
|
|
|
|
return webgl;
|
|
|
|
|
}();
|
|
|
|
|
if (res.isOk()) {
|
|
|
|
|
failureId = "SUCCESS"_ns;
|
2010-08-07 09:09:18 +04:00
|
|
|
|
}
|
2020-01-09 01:19:16 +03:00
|
|
|
|
Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_FAILURE_ID, failureId);
|
2010-08-07 09:09:18 +04:00
|
|
|
|
|
2020-01-09 01:19:16 +03:00
|
|
|
|
if (!res.isOk()) {
|
|
|
|
|
out->error = res.unwrapErr();
|
|
|
|
|
return nullptr;
|
2016-06-07 02:29:08 +03:00
|
|
|
|
}
|
2020-01-09 01:19:16 +03:00
|
|
|
|
const auto webgl = res.unwrap();
|
2010-08-07 09:09:18 +04:00
|
|
|
|
|
2014-10-09 03:37:30 +04:00
|
|
|
|
// Update our internal stuff:
|
2020-01-09 01:19:16 +03:00
|
|
|
|
webgl->FinishInit();
|
|
|
|
|
|
|
|
|
|
reporter.SetSuccessful();
|
|
|
|
|
if (gl::GLContext::ShouldSpew()) {
|
|
|
|
|
printf_stderr("--- WebGL context created: %p\n", webgl.get());
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-14 04:23:06 +03:00
|
|
|
|
// -
|
|
|
|
|
|
|
|
|
|
const auto UploadableSdTypes = [&]() {
|
|
|
|
|
webgl::EnumMask<layers::SurfaceDescriptor::Type> types;
|
2021-12-15 04:54:21 +03:00
|
|
|
|
types[layers::SurfaceDescriptor::TSurfaceDescriptorBuffer] = true;
|
2021-01-14 04:23:06 +03:00
|
|
|
|
if (webgl->gl->IsANGLE()) {
|
|
|
|
|
types[layers::SurfaceDescriptor::TSurfaceDescriptorD3D10] = true;
|
|
|
|
|
types[layers::SurfaceDescriptor::TSurfaceDescriptorDXGIYCbCr] = true;
|
|
|
|
|
}
|
|
|
|
|
if (kIsMacOS) {
|
|
|
|
|
types[layers::SurfaceDescriptor::TSurfaceDescriptorMacIOSurface] = true;
|
|
|
|
|
}
|
2022-01-19 05:13:48 +03:00
|
|
|
|
if (kIsAndroid) {
|
|
|
|
|
types[layers::SurfaceDescriptor::TSurfaceTextureDescriptor] = true;
|
|
|
|
|
}
|
2021-01-14 04:23:06 +03:00
|
|
|
|
return types;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// -
|
|
|
|
|
|
2020-01-09 01:19:16 +03:00
|
|
|
|
out->options = webgl->mOptions;
|
|
|
|
|
out->limits = *webgl->mLimits;
|
2021-01-14 04:23:06 +03:00
|
|
|
|
out->uploadableSdTypes = UploadableSdTypes();
|
2018-06-28 23:09:16 +03:00
|
|
|
|
|
2020-01-09 01:19:16 +03:00
|
|
|
|
return webgl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void WebGLContext::FinishInit() {
|
2018-06-28 23:09:16 +03:00
|
|
|
|
mOptions.antialias &= bool(mDefaultFB->mSamples);
|
2015-03-12 04:23:56 +03:00
|
|
|
|
|
2017-12-19 05:30:56 +03:00
|
|
|
|
if (!mOptions.alpha) {
|
|
|
|
|
// We always have alpha.
|
|
|
|
|
mNeedsFakeNoAlpha = true;
|
|
|
|
|
}
|
2015-09-24 22:21:05 +03:00
|
|
|
|
|
2017-12-19 05:30:56 +03:00
|
|
|
|
if (mOptions.depth || mOptions.stencil) {
|
|
|
|
|
// We always have depth+stencil if we have either.
|
|
|
|
|
if (!mOptions.depth) {
|
|
|
|
|
mNeedsFakeNoDepth = true;
|
2014-10-09 03:37:30 +04:00
|
|
|
|
}
|
2017-12-19 05:30:56 +03:00
|
|
|
|
if (!mOptions.stencil) {
|
2015-03-12 04:23:56 +03:00
|
|
|
|
mNeedsFakeNoStencil = true;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
2014-08-28 03:16:22 +04:00
|
|
|
|
|
2017-12-22 14:42:04 +03:00
|
|
|
|
mNeedsFakeNoStencil_UserFBs = false;
|
|
|
|
|
#ifdef MOZ_WIDGET_COCOA
|
|
|
|
|
if (!nsCocoaFeatures::IsAtLeastVersion(10, 12) &&
|
2020-01-09 01:19:16 +03:00
|
|
|
|
gl->Vendor() == gl::GLVendor::Intel) {
|
2017-12-22 14:42:04 +03:00
|
|
|
|
mNeedsFakeNoStencil_UserFBs = true;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2017-12-19 05:30:56 +03:00
|
|
|
|
mResetLayer = true;
|
|
|
|
|
mOptionsFrozen = true;
|
2014-10-23 01:17:02 +04:00
|
|
|
|
|
2016-06-01 00:44:46 +03:00
|
|
|
|
//////
|
|
|
|
|
// Initial setup.
|
|
|
|
|
|
2017-08-11 04:01:04 +03:00
|
|
|
|
gl->mImplicitMakeCurrent = true;
|
2021-08-24 02:59:26 +03:00
|
|
|
|
gl->mElideDuplicateBindFramebuffers = true;
|
2014-10-09 03:37:30 +04:00
|
|
|
|
|
2017-12-19 05:30:56 +03:00
|
|
|
|
const auto& size = mDefaultFB->mSize;
|
|
|
|
|
|
2017-01-10 22:15:00 +03:00
|
|
|
|
mViewportX = mViewportY = 0;
|
2017-12-19 05:30:56 +03:00
|
|
|
|
mViewportWidth = size.width;
|
|
|
|
|
mViewportHeight = size.height;
|
|
|
|
|
gl->fViewport(mViewportX, mViewportY, mViewportWidth, mViewportHeight);
|
2014-10-09 03:37:30 +04:00
|
|
|
|
|
2019-01-26 03:55:57 +03:00
|
|
|
|
mScissorRect = {0, 0, size.width, size.height};
|
|
|
|
|
mScissorRect.Apply(*gl);
|
2011-12-20 03:47:54 +04:00
|
|
|
|
|
2016-06-01 00:44:46 +03:00
|
|
|
|
//////
|
|
|
|
|
// Check everything
|
2015-07-02 02:19:09 +03:00
|
|
|
|
|
2016-06-01 00:44:46 +03:00
|
|
|
|
AssertCachedBindings();
|
|
|
|
|
AssertCachedGlobalState();
|
2013-02-14 03:26:24 +04:00
|
|
|
|
|
2016-06-01 00:44:46 +03:00
|
|
|
|
mShouldPresent = true;
|
|
|
|
|
|
|
|
|
|
//////
|
2014-05-22 06:03:09 +04:00
|
|
|
|
|
2017-07-13 21:26:00 +03:00
|
|
|
|
gl->ResetSyncCallCount("WebGLContext Initialization");
|
2020-01-09 01:19:23 +03:00
|
|
|
|
LoseLruContextIfLimitExceeded();
|
2020-01-09 01:19:14 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void WebGLContext::SetCompositableHost(
|
|
|
|
|
RefPtr<layers::CompositableHost>& aCompositableHost) {
|
|
|
|
|
mCompositableHost = aCompositableHost;
|
2009-09-03 04:47:49 +04:00
|
|
|
|
}
|
|
|
|
|
|
2020-01-09 01:19:23 +03:00
|
|
|
|
void WebGLContext::LoseLruContextIfLimitExceeded() {
|
|
|
|
|
const auto maxContexts = std::max(1u, StaticPrefs::webgl_max_contexts());
|
|
|
|
|
const auto maxContextsPerPrincipal =
|
|
|
|
|
std::max(1u, StaticPrefs::webgl_max_contexts_per_principal());
|
2015-10-12 06:21:03 +03:00
|
|
|
|
|
2012-08-03 01:28:02 +04:00
|
|
|
|
// it's important to update the index on a new context before losing old
|
|
|
|
|
// contexts, otherwise new unused contexts would all have index 0 and we
|
|
|
|
|
// couldn't distinguish older ones when choosing which one to lose first.
|
2020-01-09 01:19:23 +03:00
|
|
|
|
BumpLru();
|
2018-11-30 13:46:48 +03:00
|
|
|
|
|
2020-01-09 01:19:23 +03:00
|
|
|
|
{
|
|
|
|
|
size_t forPrincipal = 0;
|
|
|
|
|
for (const auto& context : sWebglLru) {
|
|
|
|
|
if (context->mPrincipalKey == mPrincipalKey) {
|
|
|
|
|
forPrincipal += 1;
|
|
|
|
|
}
|
2012-08-03 01:28:02 +04:00
|
|
|
|
}
|
|
|
|
|
|
2020-01-09 01:19:23 +03:00
|
|
|
|
while (forPrincipal > maxContextsPerPrincipal) {
|
|
|
|
|
const auto text = nsPrintfCString(
|
|
|
|
|
"Exceeded %u live WebGL contexts for this principal, losing the "
|
|
|
|
|
"least recently used one.",
|
|
|
|
|
maxContextsPerPrincipal);
|
|
|
|
|
mHost->JsWarning(ToString(text));
|
|
|
|
|
|
|
|
|
|
for (const auto& context : sWebglLru) {
|
|
|
|
|
if (context->mPrincipalKey == mPrincipalKey) {
|
|
|
|
|
MOZ_ASSERT(context != this);
|
|
|
|
|
context->LoseContext(webgl::ContextLossReason::None);
|
|
|
|
|
forPrincipal -= 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2017-11-30 14:40:57 +03:00
|
|
|
|
}
|
2012-08-03 01:28:02 +04:00
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
}
|
|
|
|
|
|
2020-01-09 01:19:23 +03:00
|
|
|
|
auto total = sWebglLru.size();
|
|
|
|
|
while (total > maxContexts) {
|
2020-01-09 01:19:16 +03:00
|
|
|
|
const auto text = nsPrintfCString(
|
|
|
|
|
"Exceeded %u live WebGL contexts, losing the least "
|
|
|
|
|
"recently used one.",
|
2020-01-09 01:19:23 +03:00
|
|
|
|
maxContexts);
|
|
|
|
|
mHost->JsWarning(ToString(text));
|
|
|
|
|
|
|
|
|
|
const auto& context = sWebglLru.front();
|
|
|
|
|
MOZ_ASSERT(context != this);
|
|
|
|
|
context->LoseContext(webgl::ContextLossReason::None);
|
|
|
|
|
total -= 1;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
}
|
2015-10-12 06:21:03 +03:00
|
|
|
|
}
|
|
|
|
|
|
2018-10-17 07:18:15 +03:00
|
|
|
|
// -
|
2013-02-14 03:26:24 +04:00
|
|
|
|
|
2018-10-17 07:18:15 +03:00
|
|
|
|
namespace webgl {
|
2011-05-20 23:53:53 +04:00
|
|
|
|
|
2018-10-17 07:18:15 +03:00
|
|
|
|
ScopedPrepForResourceClear::ScopedPrepForResourceClear(
|
|
|
|
|
const WebGLContext& webgl_)
|
|
|
|
|
: webgl(webgl_) {
|
|
|
|
|
const auto& gl = webgl.gl;
|
2014-10-02 04:05:34 +04:00
|
|
|
|
|
2018-10-17 07:18:15 +03:00
|
|
|
|
if (webgl.mScissorTestEnabled) {
|
|
|
|
|
gl->fDisable(LOCAL_GL_SCISSOR_TEST);
|
2011-05-20 23:53:53 +04:00
|
|
|
|
}
|
2018-10-17 07:18:15 +03:00
|
|
|
|
if (webgl.mRasterizerDiscardEnabled) {
|
|
|
|
|
gl->fDisable(LOCAL_GL_RASTERIZER_DISCARD);
|
2011-05-20 23:53:53 +04:00
|
|
|
|
}
|
|
|
|
|
|
2018-10-17 07:18:15 +03:00
|
|
|
|
// "The clear operation always uses the front stencil write mask
|
|
|
|
|
// when clearing the stencil buffer."
|
2022-03-24 22:39:06 +03:00
|
|
|
|
webgl.DoColorMask(Some(0), 0b1111);
|
2018-10-17 07:18:15 +03:00
|
|
|
|
gl->fDepthMask(true);
|
|
|
|
|
gl->fStencilMaskSeparate(LOCAL_GL_FRONT, 0xffffffff);
|
2011-05-20 23:53:53 +04:00
|
|
|
|
|
2018-10-17 07:18:15 +03:00
|
|
|
|
gl->fClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
|
|
|
|
gl->fClearDepth(1.0f); // Depth formats are always cleared to 1.0f, not 0.0f.
|
|
|
|
|
gl->fClearStencil(0);
|
|
|
|
|
}
|
2013-08-23 04:11:40 +04:00
|
|
|
|
|
2018-10-17 07:18:15 +03:00
|
|
|
|
ScopedPrepForResourceClear::~ScopedPrepForResourceClear() {
|
|
|
|
|
const auto& gl = webgl.gl;
|
2011-05-20 23:53:53 +04:00
|
|
|
|
|
2018-10-17 07:18:15 +03:00
|
|
|
|
if (webgl.mScissorTestEnabled) {
|
2013-02-14 03:26:24 +04:00
|
|
|
|
gl->fEnable(LOCAL_GL_SCISSOR_TEST);
|
2017-12-20 12:55:50 +03:00
|
|
|
|
}
|
2018-10-17 07:18:15 +03:00
|
|
|
|
if (webgl.mRasterizerDiscardEnabled) {
|
2013-08-23 04:11:40 +04:00
|
|
|
|
gl->fEnable(LOCAL_GL_RASTERIZER_DISCARD);
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-24 22:39:06 +03:00
|
|
|
|
webgl.DoColorMask(Some(0), webgl.mColorWriteMask0);
|
2018-10-17 07:18:15 +03:00
|
|
|
|
gl->fDepthMask(webgl.mDepthWriteMask);
|
|
|
|
|
gl->fStencilMaskSeparate(LOCAL_GL_FRONT, webgl.mStencilWriteMaskFront);
|
2011-05-20 23:53:53 +04:00
|
|
|
|
|
2018-10-17 07:18:15 +03:00
|
|
|
|
gl->fClearColor(webgl.mColorClearValue[0], webgl.mColorClearValue[1],
|
|
|
|
|
webgl.mColorClearValue[2], webgl.mColorClearValue[3]);
|
|
|
|
|
gl->fClearDepth(webgl.mDepthClearValue);
|
|
|
|
|
gl->fClearStencil(webgl.mStencilClearValue);
|
2011-05-20 23:53:53 +04:00
|
|
|
|
}
|
|
|
|
|
|
2018-10-17 07:18:15 +03:00
|
|
|
|
} // namespace webgl
|
|
|
|
|
|
|
|
|
|
// -
|
|
|
|
|
|
2020-01-09 01:19:23 +03:00
|
|
|
|
void WebGLContext::OnEndOfFrame() {
|
2019-06-29 00:56:43 +03:00
|
|
|
|
if (StaticPrefs::webgl_perf_spew_frame_allocs()) {
|
2017-06-22 21:32:00 +03:00
|
|
|
|
GeneratePerfWarning("[webgl.perf.spew-frame-allocs] %" PRIu64
|
|
|
|
|
" data allocations this frame.",
|
|
|
|
|
mDataAllocGLCallCount);
|
|
|
|
|
}
|
|
|
|
|
mDataAllocGLCallCount = 0;
|
2017-07-13 21:26:00 +03:00
|
|
|
|
gl->ResetSyncCallCount("WebGLContext PresentScreenBuffer");
|
2020-01-09 01:19:23 +03:00
|
|
|
|
|
2020-06-15 21:25:55 +03:00
|
|
|
|
mDrawCallsSinceLastFlush = 0;
|
|
|
|
|
|
2020-01-09 01:19:23 +03:00
|
|
|
|
BumpLru();
|
2017-06-22 21:32:00 +03:00
|
|
|
|
}
|
|
|
|
|
|
2020-04-07 21:48:13 +03:00
|
|
|
|
void WebGLContext::BlitBackbufferToCurDriverFB(
|
2022-02-11 22:49:56 +03:00
|
|
|
|
WebGLFramebuffer* const srcAsWebglFb,
|
2022-02-21 20:33:09 +03:00
|
|
|
|
const gl::MozFramebuffer* const srcAsMozFb, bool srcIsBGRA) const {
|
2022-03-24 22:39:06 +03:00
|
|
|
|
// BlitFramebuffer ignores ColorMask().
|
2017-12-20 12:55:50 +03:00
|
|
|
|
|
2017-12-19 05:30:56 +03:00
|
|
|
|
if (mScissorTestEnabled) {
|
|
|
|
|
gl->fDisable(LOCAL_GL_SCISSOR_TEST);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[&]() {
|
2022-02-11 22:49:56 +03:00
|
|
|
|
// If a MozFramebuffer is supplied, ensure that a WebGLFramebuffer is not
|
|
|
|
|
// used since it might not have completeness info, while the MozFramebuffer
|
|
|
|
|
// can still supply the needed information.
|
|
|
|
|
MOZ_ASSERT(!(srcAsMozFb && srcAsWebglFb));
|
|
|
|
|
const auto* mozFb = srcAsMozFb ? srcAsMozFb : mDefaultFB.get();
|
|
|
|
|
GLuint fbo = 0;
|
|
|
|
|
gfx::IntSize size;
|
|
|
|
|
if (srcAsWebglFb) {
|
|
|
|
|
fbo = srcAsWebglFb->mGLName;
|
|
|
|
|
const auto* info = srcAsWebglFb->GetCompletenessInfo();
|
|
|
|
|
MOZ_ASSERT(info);
|
|
|
|
|
size = gfx::IntSize(info->width, info->height);
|
|
|
|
|
} else {
|
|
|
|
|
fbo = mozFb->mFB;
|
|
|
|
|
size = mozFb->mSize;
|
|
|
|
|
}
|
2017-12-19 05:30:56 +03:00
|
|
|
|
|
2022-02-21 20:33:09 +03:00
|
|
|
|
// If no format conversion is necessary, then attempt to directly blit
|
|
|
|
|
// between framebuffers. Otherwise, if we need to convert to RGBA from
|
|
|
|
|
// the source format, then we will need to use the texture blit path
|
|
|
|
|
// below.
|
|
|
|
|
if (!srcIsBGRA) {
|
|
|
|
|
if (gl->IsSupported(gl::GLFeature::framebuffer_blit)) {
|
|
|
|
|
gl->fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER, fbo);
|
|
|
|
|
gl->fBlitFramebuffer(0, 0, size.width, size.height, 0, 0, size.width,
|
|
|
|
|
size.height, LOCAL_GL_COLOR_BUFFER_BIT,
|
|
|
|
|
LOCAL_GL_NEAREST);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (mDefaultFB->mSamples &&
|
|
|
|
|
gl->IsExtensionSupported(
|
|
|
|
|
gl::GLContext::APPLE_framebuffer_multisample)) {
|
|
|
|
|
gl->fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER, fbo);
|
|
|
|
|
gl->fResolveMultisampleFramebufferAPPLE();
|
|
|
|
|
return;
|
|
|
|
|
}
|
2017-12-19 05:30:56 +03:00
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
|
2022-02-11 22:49:56 +03:00
|
|
|
|
GLuint colorTex = 0;
|
|
|
|
|
if (srcAsWebglFb) {
|
|
|
|
|
const auto& attach = srcAsWebglFb->ColorAttachment0();
|
|
|
|
|
MOZ_ASSERT(attach.Texture());
|
|
|
|
|
colorTex = attach.Texture()->mGLName;
|
|
|
|
|
} else {
|
|
|
|
|
colorTex = mozFb->ColorTex();
|
|
|
|
|
}
|
2022-03-24 23:35:57 +03:00
|
|
|
|
|
2022-03-24 22:39:06 +03:00
|
|
|
|
// DrawBlit handles ColorMask itself.
|
2022-02-21 20:33:09 +03:00
|
|
|
|
gl->BlitHelper()->DrawBlitTextureToFramebuffer(
|
|
|
|
|
colorTex, size, size, LOCAL_GL_TEXTURE_2D, srcIsBGRA);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
}();
|
|
|
|
|
|
2016-06-21 06:28:57 +03:00
|
|
|
|
if (mScissorTestEnabled) {
|
2017-12-19 05:30:56 +03:00
|
|
|
|
gl->fEnable(LOCAL_GL_SCISSOR_TEST);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
}
|
2017-12-19 05:30:56 +03:00
|
|
|
|
}
|
|
|
|
|
|
2020-02-15 07:15:03 +03:00
|
|
|
|
// -
|
|
|
|
|
|
|
|
|
|
template <typename T, typename... Args>
|
|
|
|
|
constexpr auto MakeArray(Args... args) -> std::array<T, sizeof...(Args)> {
|
|
|
|
|
return {{static_cast<T>(args)...}};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// -
|
|
|
|
|
|
2013-02-14 03:26:24 +04:00
|
|
|
|
// For an overview of how WebGL compositing works, see:
|
|
|
|
|
// https://wiki.mozilla.org/Platform/GFX/WebGL/Compositing
|
2022-02-21 20:33:09 +03:00
|
|
|
|
bool WebGLContext::PresentInto(gl::SwapChain& swapChain) {
|
2020-06-15 21:25:55 +03:00
|
|
|
|
OnEndOfFrame();
|
2013-02-21 23:54:25 +04:00
|
|
|
|
|
2022-02-21 20:33:09 +03:00
|
|
|
|
if (!ValidateAndInitFB(nullptr)) return false;
|
2020-06-08 23:35:38 +03:00
|
|
|
|
|
2020-06-15 21:25:55 +03:00
|
|
|
|
{
|
2022-04-29 00:38:28 +03:00
|
|
|
|
auto presenter = swapChain.Acquire(mDefaultFB->mSize);
|
2020-06-15 21:25:55 +03:00
|
|
|
|
if (!presenter) {
|
|
|
|
|
GenerateWarning("Swap chain surface creation failed.");
|
|
|
|
|
LoseContext();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2020-06-08 23:35:38 +03:00
|
|
|
|
|
2020-06-15 21:25:55 +03:00
|
|
|
|
const auto destFb = presenter->Fb();
|
|
|
|
|
gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, destFb);
|
2020-06-11 01:21:07 +03:00
|
|
|
|
|
2022-02-21 20:33:09 +03:00
|
|
|
|
BlitBackbufferToCurDriverFB();
|
2020-06-11 01:21:07 +03:00
|
|
|
|
|
2020-06-15 21:25:55 +03:00
|
|
|
|
if (!mOptions.preserveDrawingBuffer) {
|
|
|
|
|
if (gl->IsSupported(gl::GLFeature::invalidate_framebuffer)) {
|
2022-02-21 20:33:09 +03:00
|
|
|
|
gl->fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER, mDefaultFB->mFB);
|
2020-06-15 21:25:55 +03:00
|
|
|
|
constexpr auto attachments = MakeArray<GLenum>(
|
|
|
|
|
LOCAL_GL_COLOR_ATTACHMENT0, LOCAL_GL_DEPTH_STENCIL_ATTACHMENT);
|
|
|
|
|
gl->fInvalidateFramebuffer(LOCAL_GL_READ_FRAMEBUFFER,
|
|
|
|
|
attachments.size(), attachments.data());
|
|
|
|
|
}
|
2022-02-21 20:33:09 +03:00
|
|
|
|
mDefaultFB_IsInvalid = true;
|
2020-06-15 21:25:55 +03:00
|
|
|
|
}
|
2020-06-11 09:37:38 +03:00
|
|
|
|
|
2020-06-15 21:25:55 +03:00
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
if (!mOptions.alpha) {
|
|
|
|
|
gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, destFb);
|
|
|
|
|
uint32_t pixel = 0xffbadbad;
|
|
|
|
|
gl->fReadPixels(0, 0, 1, 1, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE,
|
|
|
|
|
&pixel);
|
|
|
|
|
MOZ_ASSERT((pixel & 0xff000000) == 0xff000000);
|
2020-06-11 19:44:20 +03:00
|
|
|
|
}
|
2020-06-15 21:25:55 +03:00
|
|
|
|
#endif
|
2020-06-11 09:37:38 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-15 21:26:00 +03:00
|
|
|
|
bool WebGLContext::PresentIntoXR(gl::SwapChain& swapChain,
|
|
|
|
|
const gl::MozFramebuffer& fb) {
|
|
|
|
|
OnEndOfFrame();
|
|
|
|
|
|
2022-04-29 00:38:28 +03:00
|
|
|
|
auto presenter = swapChain.Acquire(fb.mSize);
|
2020-06-15 21:26:00 +03:00
|
|
|
|
if (!presenter) {
|
|
|
|
|
GenerateWarning("Swap chain surface creation failed.");
|
|
|
|
|
LoseContext();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const auto destFb = presenter->Fb();
|
|
|
|
|
gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, destFb);
|
|
|
|
|
|
2022-02-11 22:49:56 +03:00
|
|
|
|
BlitBackbufferToCurDriverFB(nullptr, &fb);
|
2020-06-15 21:26:00 +03:00
|
|
|
|
|
|
|
|
|
// https://immersive-web.github.io/webxr/#opaque-framebuffer
|
|
|
|
|
// Opaque framebuffers will always be cleared regardless of the
|
|
|
|
|
// associated WebGL context’s preserveDrawingBuffer value.
|
|
|
|
|
if (gl->IsSupported(gl::GLFeature::invalidate_framebuffer)) {
|
|
|
|
|
gl->fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER, fb.mFB);
|
|
|
|
|
constexpr auto attachments = MakeArray<GLenum>(
|
|
|
|
|
LOCAL_GL_COLOR_ATTACHMENT0, LOCAL_GL_DEPTH_STENCIL_ATTACHMENT);
|
|
|
|
|
gl->fInvalidateFramebuffer(LOCAL_GL_READ_FRAMEBUFFER, attachments.size(),
|
|
|
|
|
attachments.data());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-21 20:33:09 +03:00
|
|
|
|
// Initialize a swap chain's surface factory given the desired surface type.
|
|
|
|
|
void InitSwapChain(gl::GLContext& gl, gl::SwapChain& swapChain,
|
|
|
|
|
const layers::TextureType consumerType) {
|
|
|
|
|
if (!swapChain.mFactory) {
|
|
|
|
|
auto typedFactory = gl::SurfaceFactory::Create(&gl, consumerType);
|
|
|
|
|
if (typedFactory) {
|
|
|
|
|
swapChain.mFactory = std::move(typedFactory);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!swapChain.mFactory) {
|
|
|
|
|
NS_WARNING("Failed to make an ideal SurfaceFactory.");
|
|
|
|
|
swapChain.mFactory = MakeUnique<gl::SurfaceFactory_Basic>(gl);
|
|
|
|
|
}
|
|
|
|
|
MOZ_ASSERT(swapChain.mFactory);
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-17 21:56:16 +03:00
|
|
|
|
void WebGLContext::Present(WebGLFramebuffer* const xrFb,
|
|
|
|
|
const layers::TextureType consumerType,
|
|
|
|
|
const bool webvr) {
|
2020-06-15 21:25:55 +03:00
|
|
|
|
const FuncScope funcScope(*this, "<Present>");
|
|
|
|
|
if (IsContextLost()) return;
|
2020-06-11 09:37:35 +03:00
|
|
|
|
|
2020-06-17 21:56:16 +03:00
|
|
|
|
auto swapChain = webvr ? &mWebVRSwapChain : &mSwapChain;
|
|
|
|
|
if (xrFb) {
|
2022-02-11 22:49:56 +03:00
|
|
|
|
swapChain = &xrFb->mSwapChain;
|
2020-06-17 21:56:16 +03:00
|
|
|
|
}
|
2020-06-15 21:26:00 +03:00
|
|
|
|
const gl::MozFramebuffer* maybeFB = nullptr;
|
2020-06-17 21:56:16 +03:00
|
|
|
|
if (xrFb) {
|
2022-02-11 22:49:56 +03:00
|
|
|
|
swapChain = &xrFb->mSwapChain;
|
2020-06-17 21:56:16 +03:00
|
|
|
|
maybeFB = xrFb->mOpaque.get();
|
2020-06-15 21:25:58 +03:00
|
|
|
|
} else {
|
|
|
|
|
mResolvedDefaultFB = nullptr;
|
|
|
|
|
}
|
2020-06-15 21:25:55 +03:00
|
|
|
|
|
2022-02-21 20:33:09 +03:00
|
|
|
|
InitSwapChain(*gl, *swapChain, consumerType);
|
2020-04-07 21:48:13 +03:00
|
|
|
|
|
2020-06-15 21:26:00 +03:00
|
|
|
|
if (maybeFB) {
|
|
|
|
|
(void)PresentIntoXR(*swapChain, *maybeFB);
|
|
|
|
|
} else {
|
2022-02-21 20:33:09 +03:00
|
|
|
|
(void)PresentInto(*swapChain);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void WebGLContext::CopyToSwapChain(WebGLFramebuffer* const srcFb,
|
|
|
|
|
const layers::TextureType consumerType,
|
|
|
|
|
const webgl::SwapChainOptions& options) {
|
|
|
|
|
const FuncScope funcScope(*this, "<CopyToSwapChain>");
|
|
|
|
|
if (IsContextLost()) return;
|
|
|
|
|
|
|
|
|
|
OnEndOfFrame();
|
|
|
|
|
|
|
|
|
|
if (!srcFb) return;
|
|
|
|
|
const auto* info = srcFb->GetCompletenessInfo();
|
|
|
|
|
if (!info) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
gfx::IntSize size(info->width, info->height);
|
|
|
|
|
|
|
|
|
|
InitSwapChain(*gl, srcFb->mSwapChain, consumerType);
|
|
|
|
|
|
2022-04-29 00:38:28 +03:00
|
|
|
|
auto presenter = srcFb->mSwapChain.Acquire(size);
|
2022-02-21 20:33:09 +03:00
|
|
|
|
if (!presenter) {
|
|
|
|
|
GenerateWarning("Swap chain surface creation failed.");
|
|
|
|
|
LoseContext();
|
|
|
|
|
return;
|
2020-06-15 21:26:00 +03:00
|
|
|
|
}
|
2022-02-21 20:33:09 +03:00
|
|
|
|
|
|
|
|
|
const ScopedFBRebinder saveFB(this);
|
|
|
|
|
|
|
|
|
|
const auto destFb = presenter->Fb();
|
|
|
|
|
gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, destFb);
|
|
|
|
|
|
|
|
|
|
BlitBackbufferToCurDriverFB(srcFb, nullptr, options.bgra);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void WebGLContext::EndOfFrame() {
|
|
|
|
|
const FuncScope funcScope(*this, "<EndOfFrame>");
|
|
|
|
|
if (IsContextLost()) return;
|
|
|
|
|
|
|
|
|
|
OnEndOfFrame();
|
2020-06-15 21:25:55 +03:00
|
|
|
|
}
|
2020-04-07 21:48:13 +03:00
|
|
|
|
|
2020-06-15 21:25:55 +03:00
|
|
|
|
Maybe<layers::SurfaceDescriptor> WebGLContext::GetFrontBuffer(
|
2020-06-17 21:56:16 +03:00
|
|
|
|
WebGLFramebuffer* const xrFb, const bool webvr) {
|
|
|
|
|
auto swapChain = webvr ? &mWebVRSwapChain : &mSwapChain;
|
|
|
|
|
if (xrFb) {
|
2022-02-11 22:49:56 +03:00
|
|
|
|
swapChain = &xrFb->mSwapChain;
|
2020-04-07 21:48:13 +03:00
|
|
|
|
}
|
2020-06-15 21:25:58 +03:00
|
|
|
|
const auto& front = swapChain->FrontBuffer();
|
2020-06-15 21:25:55 +03:00
|
|
|
|
if (!front) return {};
|
2020-06-11 09:37:36 +03:00
|
|
|
|
|
2020-06-15 21:25:55 +03:00
|
|
|
|
return front->ToSurfaceDescriptor();
|
|
|
|
|
}
|
2020-06-11 01:21:04 +03:00
|
|
|
|
|
2021-05-06 03:22:42 +03:00
|
|
|
|
Maybe<uvec2> WebGLContext::FrontBufferSnapshotInto(
|
|
|
|
|
const Maybe<Range<uint8_t>> maybeDest) {
|
2020-06-15 21:25:55 +03:00
|
|
|
|
const auto& front = mSwapChain.FrontBuffer();
|
2021-05-06 03:22:42 +03:00
|
|
|
|
if (!front) return {};
|
|
|
|
|
const auto& size = front->mDesc.size;
|
|
|
|
|
const auto ret = Some(*uvec2::FromSize(size));
|
|
|
|
|
if (!maybeDest) return ret;
|
|
|
|
|
const auto& dest = *maybeDest;
|
2020-06-08 23:36:14 +03:00
|
|
|
|
|
2020-06-15 21:25:55 +03:00
|
|
|
|
// -
|
2020-04-07 21:48:13 +03:00
|
|
|
|
|
2020-07-09 21:31:12 +03:00
|
|
|
|
front->WaitForBufferOwnership();
|
2020-06-15 21:25:55 +03:00
|
|
|
|
front->LockProd();
|
|
|
|
|
front->ProducerReadAcquire();
|
|
|
|
|
auto reset = MakeScopeExit([&] {
|
|
|
|
|
front->ProducerReadRelease();
|
|
|
|
|
front->UnlockProd();
|
|
|
|
|
});
|
2020-04-07 21:48:13 +03:00
|
|
|
|
|
2020-06-15 21:25:55 +03:00
|
|
|
|
// -
|
2020-04-07 21:48:13 +03:00
|
|
|
|
|
2020-06-15 21:25:55 +03:00
|
|
|
|
gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, 1);
|
|
|
|
|
if (IsWebGL2()) {
|
|
|
|
|
gl->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH, 0);
|
|
|
|
|
gl->fPixelStorei(LOCAL_GL_PACK_SKIP_PIXELS, 0);
|
|
|
|
|
gl->fPixelStorei(LOCAL_GL_PACK_SKIP_ROWS, 0);
|
2020-01-09 01:19:14 +03:00
|
|
|
|
}
|
|
|
|
|
|
2020-06-15 21:25:55 +03:00
|
|
|
|
// -
|
2020-01-09 01:19:14 +03:00
|
|
|
|
|
2020-06-15 21:25:55 +03:00
|
|
|
|
const auto readFbWas = mBoundReadFramebuffer;
|
|
|
|
|
const auto pboWas = mBoundPixelPackBuffer;
|
2020-01-09 01:19:14 +03:00
|
|
|
|
|
2020-06-15 21:25:55 +03:00
|
|
|
|
GLenum fbTarget = LOCAL_GL_READ_FRAMEBUFFER;
|
|
|
|
|
if (!IsWebGL2()) {
|
|
|
|
|
fbTarget = LOCAL_GL_FRAMEBUFFER;
|
2020-06-11 02:43:35 +03:00
|
|
|
|
}
|
2020-06-15 21:25:55 +03:00
|
|
|
|
auto reset2 = MakeScopeExit([&] {
|
|
|
|
|
DoBindFB(readFbWas, fbTarget);
|
|
|
|
|
if (pboWas) {
|
|
|
|
|
BindBuffer(LOCAL_GL_PIXEL_PACK_BUFFER, pboWas);
|
|
|
|
|
}
|
|
|
|
|
});
|
2020-06-08 23:34:15 +03:00
|
|
|
|
|
2021-09-18 04:23:58 +03:00
|
|
|
|
gl->fBindFramebuffer(fbTarget, front->mFb ? front->mFb->mFB : 0);
|
2021-04-21 04:03:32 +03:00
|
|
|
|
if (pboWas) {
|
|
|
|
|
BindBuffer(LOCAL_GL_PIXEL_PACK_BUFFER, nullptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// -
|
|
|
|
|
|
2020-07-22 01:56:52 +03:00
|
|
|
|
const size_t stride = size.width * 4;
|
2021-05-06 03:22:42 +03:00
|
|
|
|
const size_t srcByteCount = stride * size.height;
|
|
|
|
|
const auto dstByteCount = dest.length();
|
|
|
|
|
if (srcByteCount != dstByteCount) {
|
|
|
|
|
gfxCriticalError() << "FrontBufferSnapshotInto: srcByteCount:"
|
|
|
|
|
<< srcByteCount << " != dstByteCount:" << dstByteCount;
|
|
|
|
|
return {};
|
|
|
|
|
}
|
2020-07-22 01:56:52 +03:00
|
|
|
|
gl->fReadPixels(0, 0, size.width, size.height, LOCAL_GL_RGBA,
|
|
|
|
|
LOCAL_GL_UNSIGNED_BYTE, dest.begin().get());
|
2020-06-11 01:21:02 +03:00
|
|
|
|
|
2021-05-06 03:22:42 +03:00
|
|
|
|
return ret;
|
2020-06-15 21:25:55 +03:00
|
|
|
|
}
|
2020-01-09 01:19:14 +03:00
|
|
|
|
|
2020-06-17 21:56:16 +03:00
|
|
|
|
void WebGLContext::ClearVRSwapChain() { mWebVRSwapChain.ClearPool(); }
|
|
|
|
|
|
2020-06-15 21:25:55 +03:00
|
|
|
|
// ------------------------
|
2020-01-09 01:19:14 +03:00
|
|
|
|
|
2020-06-15 21:25:55 +03:00
|
|
|
|
RefPtr<gfx::DataSourceSurface> GetTempSurface(const gfx::IntSize& aSize,
|
|
|
|
|
gfx::SurfaceFormat& aFormat) {
|
|
|
|
|
uint32_t stride =
|
|
|
|
|
gfx::GetAlignedStride<8>(aSize.width, BytesPerPixel(aFormat));
|
|
|
|
|
return gfx::Factory::CreateDataSourceSurfaceWithStride(aSize, aFormat,
|
|
|
|
|
stride);
|
2012-01-25 01:12:31 +04:00
|
|
|
|
}
|
|
|
|
|
|
2016-10-04 04:33:52 +03:00
|
|
|
|
void WebGLContext::DummyReadFramebufferOperation() {
|
2015-12-15 03:11:59 +03:00
|
|
|
|
if (!mBoundReadFramebuffer) return; // Infallible.
|
2018-11-30 13:46:48 +03:00
|
|
|
|
|
2016-10-04 04:33:52 +03:00
|
|
|
|
const auto status = mBoundReadFramebuffer->CheckFramebufferStatus();
|
2016-07-17 20:37:00 +03:00
|
|
|
|
if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
|
|
|
|
|
ErrorInvalidFramebufferOperation("Framebuffer must be complete.");
|
2018-11-30 13:46:48 +03:00
|
|
|
|
}
|
2016-07-17 20:37:00 +03:00
|
|
|
|
}
|
|
|
|
|
|
2014-11-14 07:03:50 +03:00
|
|
|
|
bool WebGLContext::Has64BitTimestamps() const {
|
|
|
|
|
// 'sync' provides glGetInteger64v either by supporting ARB_sync, GL3+, or
|
2016-07-17 20:37:00 +03:00
|
|
|
|
// GLES3+.
|
2020-01-09 01:19:16 +03:00
|
|
|
|
return gl->IsSupported(gl::GLFeature::sync);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
}
|
2014-06-03 01:40:15 +04:00
|
|
|
|
|
2020-01-09 01:19:16 +03:00
|
|
|
|
static bool CheckContextLost(gl::GLContext* gl, bool* const out_isGuilty) {
|
2014-06-03 01:40:15 +04:00
|
|
|
|
MOZ_ASSERT(gl);
|
|
|
|
|
|
2018-11-27 07:23:19 +03:00
|
|
|
|
const auto resetStatus = gl->fGetGraphicsResetStatus();
|
2014-06-03 01:40:15 +04:00
|
|
|
|
if (resetStatus == LOCAL_GL_NO_ERROR) {
|
|
|
|
|
*out_isGuilty = false;
|
2013-02-14 03:26:24 +04:00
|
|
|
|
return false;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
}
|
|
|
|
|
|
2014-06-03 01:40:15 +04:00
|
|
|
|
// Assume guilty unless we find otherwise!
|
|
|
|
|
bool isGuilty = true;
|
|
|
|
|
switch (resetStatus) {
|
|
|
|
|
case LOCAL_GL_INNOCENT_CONTEXT_RESET_ARB:
|
2018-11-27 07:23:19 +03:00
|
|
|
|
case LOCAL_GL_PURGED_CONTEXT_RESET_NV:
|
2014-06-03 01:40:15 +04:00
|
|
|
|
// Either nothing wrong, or not our fault.
|
|
|
|
|
isGuilty = false;
|
|
|
|
|
break;
|
|
|
|
|
case LOCAL_GL_GUILTY_CONTEXT_RESET_ARB:
|
|
|
|
|
NS_WARNING(
|
|
|
|
|
"WebGL content on the page definitely caused the graphics"
|
|
|
|
|
" card to reset.");
|
|
|
|
|
break;
|
|
|
|
|
case LOCAL_GL_UNKNOWN_CONTEXT_RESET_ARB:
|
|
|
|
|
NS_WARNING(
|
|
|
|
|
"WebGL content on the page might have caused the graphics"
|
|
|
|
|
" card to reset");
|
2018-11-27 07:23:19 +03:00
|
|
|
|
// If we can't tell, assume not-guilty.
|
|
|
|
|
// Todo: Implement max number of "unknown" resets per document or time.
|
|
|
|
|
isGuilty = false;
|
2014-06-03 01:40:15 +04:00
|
|
|
|
break;
|
|
|
|
|
default:
|
2018-11-27 07:23:19 +03:00
|
|
|
|
gfxCriticalError() << "Unexpected glGetGraphicsResetStatus: "
|
|
|
|
|
<< gfx::hexa(resetStatus);
|
2014-06-03 01:40:15 +04:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isGuilty) {
|
|
|
|
|
NS_WARNING(
|
|
|
|
|
"WebGL context on this page is considered guilty, and will"
|
|
|
|
|
" not be restored.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*out_isGuilty = isGuilty;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-22 20:55:00 +04:00
|
|
|
|
void WebGLContext::RunContextLossTimer() { mContextLossHandler.RunTimer(); }
|
|
|
|
|
|
2012-01-05 01:12:03 +04:00
|
|
|
|
// We use this timer for many things. Here are the things that it is activated
|
|
|
|
|
// for:
|
|
|
|
|
// 1) If a script is using the MOZ_WEBGL_lose_context extension.
|
|
|
|
|
// 2) If we are using EGL and _NOT ANGLE_, we query periodically to see if the
|
|
|
|
|
// CONTEXT_LOST_WEBGL error has been triggered.
|
|
|
|
|
// 3) If we are using ANGLE, or anything that supports ARB_robustness, query the
|
|
|
|
|
// GPU periodically to see if the reset status bit has been set.
|
|
|
|
|
// In all of these situations, we use this timer to send the script context lost
|
|
|
|
|
// and restored events asynchronously. For example, if it triggers a context
|
|
|
|
|
// loss, the webglcontextlost event will be sent to it the next time the
|
|
|
|
|
// robustness timer fires.
|
|
|
|
|
// Note that this timer mechanism is not used unless one of these 3 criteria are
|
|
|
|
|
// met.
|
|
|
|
|
// At a bare minimum, from context lost to context restores, it would take 3
|
|
|
|
|
// full timer iterations: detection, webglcontextlost, webglcontextrestored.
|
2020-01-09 01:19:16 +03:00
|
|
|
|
void WebGLContext::CheckForContextLoss() {
|
|
|
|
|
bool isGuilty = true;
|
|
|
|
|
const auto isContextLost = CheckContextLost(gl, &isGuilty);
|
|
|
|
|
if (!isContextLost) return;
|
2014-06-03 01:40:15 +04:00
|
|
|
|
|
2020-01-09 01:19:16 +03:00
|
|
|
|
mWebGLError = LOCAL_GL_CONTEXT_LOST;
|
2014-06-03 01:40:15 +04:00
|
|
|
|
|
2020-01-09 01:19:16 +03:00
|
|
|
|
auto reason = webgl::ContextLossReason::None;
|
|
|
|
|
if (isGuilty) {
|
|
|
|
|
reason = webgl::ContextLossReason::Guilty;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
}
|
2020-01-09 01:19:16 +03:00
|
|
|
|
LoseContext(reason);
|
2011-10-27 00:00:44 +04:00
|
|
|
|
}
|
|
|
|
|
|
2020-01-09 01:19:16 +03:00
|
|
|
|
void WebGLContext::LoseContext(const webgl::ContextLossReason reason) {
|
|
|
|
|
printf_stderr("WebGL(%p)::LoseContext(%u)\n", this,
|
|
|
|
|
static_cast<uint32_t>(reason));
|
|
|
|
|
mIsContextLost = true;
|
2020-07-22 01:56:52 +03:00
|
|
|
|
mLruPosition = {};
|
2020-01-09 01:19:16 +03:00
|
|
|
|
mHost->OnContextLoss(reason);
|
2011-10-27 00:00:44 +04:00
|
|
|
|
}
|
|
|
|
|
|
2014-09-10 05:40:51 +04:00
|
|
|
|
void WebGLContext::DidRefresh() {
|
|
|
|
|
if (gl) {
|
|
|
|
|
gl->FlushIfHeavyGLCallsSinceLastFlush();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-19 05:30:56 +03:00
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2020-01-09 01:19:16 +03:00
|
|
|
|
uvec2 WebGLContext::DrawingBufferSize() {
|
|
|
|
|
const FuncScope funcScope(*this, "width/height");
|
|
|
|
|
if (IsContextLost()) return {};
|
2016-05-27 04:07:52 +03:00
|
|
|
|
|
2020-01-09 01:19:16 +03:00
|
|
|
|
if (!EnsureDefaultFB()) return {};
|
2015-11-24 06:27:13 +03:00
|
|
|
|
|
2020-01-09 01:19:26 +03:00
|
|
|
|
return *uvec2::FromSize(mDefaultFB->mSize);
|
2017-12-19 05:30:56 +03:00
|
|
|
|
}
|
2015-11-25 07:15:29 +03:00
|
|
|
|
|
2019-01-23 20:53:43 +03:00
|
|
|
|
bool WebGLContext::ValidateAndInitFB(const WebGLFramebuffer* const fb,
|
|
|
|
|
const GLenum incompleteFbError) {
|
|
|
|
|
if (fb) return fb->ValidateAndInitAttachments(incompleteFbError);
|
2015-11-25 07:15:29 +03:00
|
|
|
|
|
2018-07-27 07:46:33 +03:00
|
|
|
|
if (!EnsureDefaultFB()) return false;
|
2015-11-25 07:15:29 +03:00
|
|
|
|
|
2017-12-19 05:30:56 +03:00
|
|
|
|
if (mDefaultFB_IsInvalid) {
|
2018-10-17 07:18:15 +03:00
|
|
|
|
// Clear it!
|
2017-12-19 05:30:56 +03:00
|
|
|
|
gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mDefaultFB->mFB);
|
2018-10-17 07:18:15 +03:00
|
|
|
|
const webgl::ScopedPrepForResourceClear scopedPrep(*this);
|
|
|
|
|
if (!mOptions.alpha) {
|
|
|
|
|
gl->fClearColor(0, 0, 0, 1);
|
2017-12-19 05:30:56 +03:00
|
|
|
|
}
|
|
|
|
|
const GLbitfield bits = LOCAL_GL_COLOR_BUFFER_BIT |
|
|
|
|
|
LOCAL_GL_DEPTH_BUFFER_BIT |
|
|
|
|
|
LOCAL_GL_STENCIL_BUFFER_BIT;
|
2018-10-17 07:18:15 +03:00
|
|
|
|
gl->fClear(bits);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
|
2017-12-19 05:30:56 +03:00
|
|
|
|
mDefaultFB_IsInvalid = false;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
}
|
2017-12-19 05:30:56 +03:00
|
|
|
|
return true;
|
2015-08-04 00:34:46 +03:00
|
|
|
|
}
|
|
|
|
|
|
2017-12-19 05:30:56 +03:00
|
|
|
|
void WebGLContext::DoBindFB(const WebGLFramebuffer* const fb,
|
|
|
|
|
const GLenum target) const {
|
|
|
|
|
const GLenum driverFB = fb ? fb->mGLName : mDefaultFB->mFB;
|
|
|
|
|
gl->fBindFramebuffer(target, driverFB);
|
|
|
|
|
}
|
2014-10-02 04:05:34 +04:00
|
|
|
|
|
2018-07-27 07:46:33 +03:00
|
|
|
|
bool WebGLContext::BindCurFBForDraw() {
|
2017-12-19 05:30:56 +03:00
|
|
|
|
const auto& fb = mBoundDrawFramebuffer;
|
2018-07-27 07:46:33 +03:00
|
|
|
|
if (!ValidateAndInitFB(fb)) return false;
|
2016-12-21 10:31:22 +03:00
|
|
|
|
|
2017-12-19 05:30:56 +03:00
|
|
|
|
DoBindFB(fb);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-27 07:46:33 +03:00
|
|
|
|
bool WebGLContext::BindCurFBForColorRead(
|
|
|
|
|
const webgl::FormatUsageInfo** const out_format, uint32_t* const out_width,
|
2019-01-23 20:53:43 +03:00
|
|
|
|
uint32_t* const out_height, const GLenum incompleteFbError) {
|
2017-12-19 05:30:56 +03:00
|
|
|
|
const auto& fb = mBoundReadFramebuffer;
|
|
|
|
|
|
|
|
|
|
if (fb) {
|
2019-01-23 20:53:43 +03:00
|
|
|
|
if (!ValidateAndInitFB(fb, incompleteFbError)) return false;
|
2018-07-27 07:46:33 +03:00
|
|
|
|
if (!fb->ValidateForColorRead(out_format, out_width, out_height))
|
2017-12-19 05:30:56 +03:00
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, fb->mGLName);
|
|
|
|
|
return true;
|
2015-09-24 22:21:05 +03:00
|
|
|
|
}
|
2017-12-19 05:30:56 +03:00
|
|
|
|
|
2018-07-27 07:46:33 +03:00
|
|
|
|
if (!BindDefaultFBForRead()) return false;
|
2017-12-19 05:30:56 +03:00
|
|
|
|
|
|
|
|
|
if (mDefaultFB_ReadBuffer == LOCAL_GL_NONE) {
|
2018-07-27 07:46:33 +03:00
|
|
|
|
ErrorInvalidOperation(
|
|
|
|
|
"Can't read from backbuffer when readBuffer mode is NONE.");
|
2017-12-19 05:30:56 +03:00
|
|
|
|
return false;
|
2015-03-12 04:23:56 +03:00
|
|
|
|
}
|
2017-12-19 05:30:56 +03:00
|
|
|
|
|
|
|
|
|
auto effFormat = mOptions.alpha ? webgl::EffectiveFormat::RGBA8
|
|
|
|
|
: webgl::EffectiveFormat::RGB8;
|
|
|
|
|
|
|
|
|
|
*out_format = mFormatUsage->GetUsage(effFormat);
|
|
|
|
|
MOZ_ASSERT(*out_format);
|
|
|
|
|
|
|
|
|
|
*out_width = mDefaultFB->mSize.width;
|
|
|
|
|
*out_height = mDefaultFB->mSize.height;
|
|
|
|
|
return true;
|
2014-10-02 04:05:34 +04:00
|
|
|
|
}
|
|
|
|
|
|
2018-07-27 07:46:33 +03:00
|
|
|
|
bool WebGLContext::BindDefaultFBForRead() {
|
|
|
|
|
if (!ValidateAndInitFB(nullptr)) return false;
|
2017-12-19 05:30:56 +03:00
|
|
|
|
|
|
|
|
|
if (!mDefaultFB->mSamples) {
|
|
|
|
|
gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mDefaultFB->mFB);
|
|
|
|
|
return true;
|
2015-09-24 22:21:05 +03:00
|
|
|
|
}
|
2017-12-19 05:30:56 +03:00
|
|
|
|
|
|
|
|
|
if (!mResolvedDefaultFB) {
|
|
|
|
|
mResolvedDefaultFB =
|
2020-01-09 01:19:16 +03:00
|
|
|
|
gl::MozFramebuffer::Create(gl, mDefaultFB->mSize, 0, false);
|
2017-12-19 05:30:56 +03:00
|
|
|
|
if (!mResolvedDefaultFB) {
|
2018-07-27 07:46:33 +03:00
|
|
|
|
gfxCriticalNote << FuncName() << ": Failed to create mResolvedDefaultFB.";
|
2017-12-19 05:30:56 +03:00
|
|
|
|
return false;
|
2015-03-12 04:23:56 +03:00
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
}
|
2016-12-21 10:31:22 +03:00
|
|
|
|
|
2017-12-19 05:30:56 +03:00
|
|
|
|
gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mResolvedDefaultFB->mFB);
|
|
|
|
|
BlitBackbufferToCurDriverFB();
|
|
|
|
|
|
|
|
|
|
gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mResolvedDefaultFB->mFB);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-24 22:39:06 +03:00
|
|
|
|
void WebGLContext::DoColorMask(Maybe<GLuint> i, const uint8_t bitmask) const {
|
|
|
|
|
if (!IsExtensionEnabled(WebGLExtensionID::OES_draw_buffers_indexed)) {
|
|
|
|
|
i = Nothing();
|
|
|
|
|
}
|
|
|
|
|
const auto bs = std::bitset<4>(bitmask);
|
|
|
|
|
if (i) {
|
|
|
|
|
gl->fColorMaski(*i, bs[0], bs[1], bs[2], bs[3]);
|
|
|
|
|
} else {
|
|
|
|
|
gl->fColorMask(bs[0], bs[1], bs[2], bs[3]);
|
2017-12-20 12:55:50 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-19 05:30:56 +03:00
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
ScopedDrawCallWrapper::ScopedDrawCallWrapper(WebGLContext& webgl)
|
|
|
|
|
: mWebGL(webgl) {
|
2021-08-27 04:47:14 +03:00
|
|
|
|
uint8_t driverColorMask0 = mWebGL.mColorWriteMask0;
|
2017-12-19 05:30:56 +03:00
|
|
|
|
bool driverDepthTest = mWebGL.mDepthTestEnabled;
|
|
|
|
|
bool driverStencilTest = mWebGL.mStencilTestEnabled;
|
2017-12-22 14:42:04 +03:00
|
|
|
|
const auto& fb = mWebGL.mBoundDrawFramebuffer;
|
|
|
|
|
if (!fb) {
|
2017-12-19 05:30:56 +03:00
|
|
|
|
if (mWebGL.mDefaultFB_DrawBuffer0 == LOCAL_GL_NONE) {
|
2021-08-27 04:47:14 +03:00
|
|
|
|
driverColorMask0 = 0; // Is this well-optimized enough for depth-first
|
2021-11-16 11:07:30 +03:00
|
|
|
|
// rendering?
|
2017-12-22 14:42:04 +03:00
|
|
|
|
} else {
|
2021-08-27 04:47:14 +03:00
|
|
|
|
driverColorMask0 &= ~(uint8_t(mWebGL.mNeedsFakeNoAlpha) << 3);
|
2017-12-19 05:30:56 +03:00
|
|
|
|
}
|
|
|
|
|
driverDepthTest &= !mWebGL.mNeedsFakeNoDepth;
|
|
|
|
|
driverStencilTest &= !mWebGL.mNeedsFakeNoStencil;
|
|
|
|
|
} else {
|
|
|
|
|
if (mWebGL.mNeedsFakeNoStencil_UserFBs &&
|
2018-10-17 07:18:15 +03:00
|
|
|
|
fb->DepthAttachment().HasAttachment() &&
|
2017-12-19 05:30:56 +03:00
|
|
|
|
!fb->StencilAttachment().HasAttachment()) {
|
|
|
|
|
driverStencilTest = false;
|
2016-12-21 10:31:22 +03:00
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
}
|
|
|
|
|
|
2017-12-19 05:30:56 +03:00
|
|
|
|
const auto& gl = mWebGL.gl;
|
2022-03-24 22:39:06 +03:00
|
|
|
|
mWebGL.DoColorMask(Some(0), driverColorMask0);
|
2017-12-19 05:30:56 +03:00
|
|
|
|
if (mWebGL.mDriverDepthTest != driverDepthTest) {
|
|
|
|
|
// "When disabled, the depth comparison and subsequent possible updates to
|
2018-11-30 13:46:48 +03:00
|
|
|
|
// the
|
2017-12-19 05:30:56 +03:00
|
|
|
|
// depth buffer value are bypassed and the fragment is passed to the next
|
|
|
|
|
// operation." [GLES 3.0.5, p177]
|
|
|
|
|
mWebGL.mDriverDepthTest = driverDepthTest;
|
|
|
|
|
gl->SetEnabled(LOCAL_GL_DEPTH_TEST, mWebGL.mDriverDepthTest);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
}
|
2017-12-19 05:30:56 +03:00
|
|
|
|
if (mWebGL.mDriverStencilTest != driverStencilTest) {
|
|
|
|
|
// "When disabled, the stencil test and associated modifications are not
|
|
|
|
|
// made, and
|
|
|
|
|
// the fragment is always passed." [GLES 3.0.5, p175]
|
|
|
|
|
mWebGL.mDriverStencilTest = driverStencilTest;
|
|
|
|
|
gl->SetEnabled(LOCAL_GL_STENCIL_TEST, mWebGL.mDriverStencilTest);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
}
|
2014-10-02 04:05:34 +04:00
|
|
|
|
}
|
2015-02-25 01:09:09 +03:00
|
|
|
|
|
2017-12-19 05:30:56 +03:00
|
|
|
|
ScopedDrawCallWrapper::~ScopedDrawCallWrapper() {
|
|
|
|
|
if (mWebGL.mBoundDrawFramebuffer) return;
|
2016-02-19 04:59:24 +03:00
|
|
|
|
|
2017-12-19 05:30:56 +03:00
|
|
|
|
mWebGL.mResolvedDefaultFB = nullptr;
|
|
|
|
|
mWebGL.mShouldPresent = true;
|
2016-12-24 05:54:04 +03:00
|
|
|
|
}
|
|
|
|
|
|
2019-01-26 03:55:57 +03:00
|
|
|
|
// -
|
|
|
|
|
|
|
|
|
|
void WebGLContext::ScissorRect::Apply(gl::GLContext& gl) const {
|
|
|
|
|
gl.fScissor(x, y, w, h);
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-25 07:15:29 +03:00
|
|
|
|
////////////////////////////////////////
|
|
|
|
|
|
2016-09-10 07:02:54 +03:00
|
|
|
|
IndexedBufferBinding::IndexedBufferBinding() : mRangeStart(0), mRangeSize(0) {}
|
|
|
|
|
|
|
|
|
|
uint64_t IndexedBufferBinding::ByteCount() const {
|
|
|
|
|
if (!mBufferBinding) return 0;
|
|
|
|
|
|
|
|
|
|
uint64_t bufferSize = mBufferBinding->ByteLength();
|
|
|
|
|
if (!mRangeSize) // BindBufferBase
|
|
|
|
|
return bufferSize;
|
|
|
|
|
|
|
|
|
|
if (mRangeStart >= bufferSize) return 0;
|
|
|
|
|
bufferSize -= mRangeStart;
|
|
|
|
|
|
|
|
|
|
return std::min(bufferSize, mRangeSize);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////
|
|
|
|
|
|
2019-06-17 09:40:27 +03:00
|
|
|
|
ScopedFBRebinder::~ScopedFBRebinder() {
|
2016-09-09 01:56:58 +03:00
|
|
|
|
const auto fnName = [&](WebGLFramebuffer* fb) {
|
|
|
|
|
return fb ? fb->mGLName : 0;
|
|
|
|
|
};
|
2018-11-30 13:46:48 +03:00
|
|
|
|
|
2019-06-17 09:40:27 +03:00
|
|
|
|
const auto& gl = mWebGL->gl;
|
2016-09-09 01:56:58 +03:00
|
|
|
|
if (mWebGL->IsWebGL2()) {
|
2019-06-17 09:40:27 +03:00
|
|
|
|
gl->fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER,
|
|
|
|
|
fnName(mWebGL->mBoundDrawFramebuffer));
|
|
|
|
|
gl->fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER,
|
|
|
|
|
fnName(mWebGL->mBoundReadFramebuffer));
|
2016-09-09 01:56:58 +03:00
|
|
|
|
} else {
|
|
|
|
|
MOZ_ASSERT(mWebGL->mBoundDrawFramebuffer == mWebGL->mBoundReadFramebuffer);
|
2019-06-17 09:40:27 +03:00
|
|
|
|
gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER,
|
|
|
|
|
fnName(mWebGL->mBoundDrawFramebuffer));
|
2016-09-09 01:56:58 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-26 23:38:56 +03:00
|
|
|
|
////////////////////
|
|
|
|
|
|
2020-02-26 03:44:26 +03:00
|
|
|
|
void DoBindBuffer(gl::GLContext& gl, const GLenum target,
|
|
|
|
|
const WebGLBuffer* const buffer) {
|
|
|
|
|
gl.fBindBuffer(target, buffer ? buffer->mGLName : 0);
|
2016-09-26 23:38:56 +03:00
|
|
|
|
}
|
|
|
|
|
|
2015-11-25 07:15:29 +03:00
|
|
|
|
////////////////////////////////////////
|
|
|
|
|
|
2017-02-28 02:24:14 +03:00
|
|
|
|
bool Intersect(const int32_t srcSize, const int32_t read0,
|
|
|
|
|
const int32_t readSize, int32_t* const out_intRead0,
|
|
|
|
|
int32_t* const out_intWrite0, int32_t* const out_intSize) {
|
|
|
|
|
MOZ_ASSERT(srcSize >= 0);
|
|
|
|
|
MOZ_ASSERT(readSize >= 0);
|
|
|
|
|
const auto read1 = int64_t(read0) + readSize;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
|
2017-02-28 02:24:14 +03:00
|
|
|
|
int32_t intRead0 = read0; // Clearly doesn't need validation.
|
|
|
|
|
int64_t intWrite0 = 0;
|
|
|
|
|
int64_t intSize = readSize;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
|
2017-02-28 02:24:14 +03:00
|
|
|
|
if (read1 <= 0 || read0 >= srcSize) {
|
|
|
|
|
// Disjoint ranges.
|
|
|
|
|
intSize = 0;
|
|
|
|
|
} else {
|
|
|
|
|
if (read0 < 0) {
|
|
|
|
|
const auto diff = int64_t(0) - read0;
|
|
|
|
|
MOZ_ASSERT(diff >= 0);
|
|
|
|
|
intRead0 = 0;
|
|
|
|
|
intWrite0 = diff;
|
|
|
|
|
intSize -= diff;
|
|
|
|
|
}
|
|
|
|
|
if (read1 > srcSize) {
|
|
|
|
|
const auto diff = int64_t(read1) - srcSize;
|
|
|
|
|
MOZ_ASSERT(diff >= 0);
|
|
|
|
|
intSize -= diff;
|
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
|
2017-02-28 02:24:14 +03:00
|
|
|
|
if (!CheckedInt<int32_t>(intWrite0).isValid() ||
|
|
|
|
|
!CheckedInt<int32_t>(intSize).isValid()) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
}
|
2017-02-28 02:24:14 +03:00
|
|
|
|
|
|
|
|
|
*out_intRead0 = intRead0;
|
|
|
|
|
*out_intWrite0 = intWrite0;
|
|
|
|
|
*out_intSize = intSize;
|
|
|
|
|
return true;
|
2015-11-25 07:15:29 +03:00
|
|
|
|
}
|
|
|
|
|
|
2017-10-21 01:40:12 +03:00
|
|
|
|
// --
|
|
|
|
|
|
|
|
|
|
uint64_t AvailGroups(const uint64_t totalAvailItems,
|
|
|
|
|
const uint64_t firstItemOffset, const uint32_t groupSize,
|
|
|
|
|
const uint32_t groupStride) {
|
|
|
|
|
MOZ_ASSERT(groupSize && groupStride);
|
|
|
|
|
MOZ_ASSERT(groupSize <= groupStride);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
|
2017-10-21 01:40:12 +03:00
|
|
|
|
if (totalAvailItems <= firstItemOffset) return 0;
|
|
|
|
|
const size_t availItems = totalAvailItems - firstItemOffset;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
|
2017-10-21 01:40:12 +03:00
|
|
|
|
size_t availGroups = availItems / groupStride;
|
|
|
|
|
const size_t tailItems = availItems % groupStride;
|
|
|
|
|
if (tailItems >= groupSize) {
|
|
|
|
|
availGroups += 1;
|
|
|
|
|
}
|
|
|
|
|
return availGroups;
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-25 07:15:29 +03:00
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2018-07-27 07:46:33 +03:00
|
|
|
|
const char* WebGLContext::FuncName() const {
|
|
|
|
|
const char* ret;
|
|
|
|
|
if (MOZ_LIKELY(mFuncScope)) {
|
|
|
|
|
ret = mFuncScope->mFuncName;
|
|
|
|
|
} else {
|
2021-01-14 04:23:06 +03:00
|
|
|
|
NS_WARNING("FuncScope not on stack!");
|
|
|
|
|
ret = "<unknown function>";
|
2018-07-27 07:46:33 +03:00
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// -
|
|
|
|
|
|
|
|
|
|
WebGLContext::FuncScope::FuncScope(const WebGLContext& webgl,
|
|
|
|
|
const char* const funcName)
|
|
|
|
|
: mWebGL(webgl), mFuncName(bool(mWebGL.mFuncScope) ? nullptr : funcName) {
|
2020-01-09 01:19:16 +03:00
|
|
|
|
if (!mFuncName) return;
|
2018-07-27 07:46:33 +03:00
|
|
|
|
mWebGL.mFuncScope = this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WebGLContext::FuncScope::~FuncScope() {
|
2020-01-09 01:19:16 +03:00
|
|
|
|
if (mBindFailureGuard) {
|
|
|
|
|
gfxCriticalError() << "mBindFailureGuard failure: Early exit from "
|
|
|
|
|
<< mWebGL.FuncName();
|
|
|
|
|
}
|
2018-07-27 07:46:33 +03:00
|
|
|
|
|
2020-01-09 01:19:16 +03:00
|
|
|
|
if (!mFuncName) return;
|
2018-07-27 07:46:33 +03:00
|
|
|
|
mWebGL.mFuncScope = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --
|
|
|
|
|
|
2020-06-03 03:49:45 +03:00
|
|
|
|
bool ClientWebGLContext::IsXRCompatible() const { return mXRCompatible; }
|
2018-07-27 07:46:33 +03:00
|
|
|
|
|
2020-01-16 00:18:00 +03:00
|
|
|
|
already_AddRefed<dom::Promise> ClientWebGLContext::MakeXRCompatible(
|
|
|
|
|
ErrorResult& aRv) {
|
2019-11-16 00:32:15 +03:00
|
|
|
|
const FuncScope funcScope(*this, "MakeXRCompatible");
|
2021-12-24 02:52:08 +03:00
|
|
|
|
nsCOMPtr<nsIGlobalObject> global = GetParentObject();
|
2019-11-16 00:32:15 +03:00
|
|
|
|
if (!global) {
|
2020-02-03 23:19:11 +03:00
|
|
|
|
aRv.ThrowInvalidAccessError(
|
|
|
|
|
"Using a WebGL context that is not attached to either a canvas or an "
|
|
|
|
|
"OffscreenCanvas");
|
2019-11-16 00:32:15 +03:00
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
2020-01-09 01:19:16 +03:00
|
|
|
|
RefPtr<dom::Promise> promise = dom::Promise::Create(global, aRv);
|
2019-11-16 00:32:15 +03:00
|
|
|
|
NS_ENSURE_TRUE(!aRv.Failed(), nullptr);
|
|
|
|
|
|
|
|
|
|
if (IsContextLost()) {
|
2020-02-03 23:37:32 +03:00
|
|
|
|
promise->MaybeRejectWithInvalidStateError(
|
2019-11-16 00:32:15 +03:00
|
|
|
|
"Can not make context XR compatible when context is already lost.");
|
|
|
|
|
return promise.forget();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO: Bug 1580258 - WebGLContext.MakeXRCompatible needs to switch to
|
|
|
|
|
// the device connected to the XR hardware
|
2020-01-09 01:19:16 +03:00
|
|
|
|
// This should update `options` and lose+restore the context.
|
2020-06-03 03:49:45 +03:00
|
|
|
|
mXRCompatible = true;
|
2019-11-16 00:32:15 +03:00
|
|
|
|
promise->MaybeResolveWithUndefined();
|
|
|
|
|
return promise.forget();
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-27 07:46:33 +03:00
|
|
|
|
// --
|
|
|
|
|
|
2020-07-22 01:57:01 +03:00
|
|
|
|
webgl::AvailabilityRunnable& ClientWebGLContext::EnsureAvailabilityRunnable()
|
|
|
|
|
const {
|
2018-02-21 04:34:25 +03:00
|
|
|
|
if (!mAvailabilityRunnable) {
|
2020-07-22 01:57:01 +03:00
|
|
|
|
mAvailabilityRunnable = new webgl::AvailabilityRunnable(this);
|
|
|
|
|
auto forgettable = mAvailabilityRunnable;
|
|
|
|
|
NS_DispatchToCurrentThread(forgettable.forget());
|
2018-11-30 13:46:48 +03:00
|
|
|
|
}
|
2020-07-22 01:57:01 +03:00
|
|
|
|
return *mAvailabilityRunnable;
|
2018-02-21 04:34:25 +03:00
|
|
|
|
}
|
|
|
|
|
|
2020-07-22 01:57:01 +03:00
|
|
|
|
webgl::AvailabilityRunnable::AvailabilityRunnable(
|
|
|
|
|
const ClientWebGLContext* const webgl)
|
2021-12-10 05:57:54 +03:00
|
|
|
|
: DiscardableRunnable("webgl::AvailabilityRunnable"), mWebGL(webgl) {}
|
2018-02-21 04:34:25 +03:00
|
|
|
|
|
|
|
|
|
webgl::AvailabilityRunnable::~AvailabilityRunnable() {
|
|
|
|
|
MOZ_ASSERT(mQueries.empty());
|
|
|
|
|
MOZ_ASSERT(mSyncs.empty());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nsresult webgl::AvailabilityRunnable::Run() {
|
|
|
|
|
for (const auto& cur : mQueries) {
|
2020-07-22 01:57:01 +03:00
|
|
|
|
if (!cur) continue;
|
2018-02-21 04:34:25 +03:00
|
|
|
|
cur->mCanBeAvailable = true;
|
|
|
|
|
}
|
|
|
|
|
mQueries.clear();
|
|
|
|
|
|
|
|
|
|
for (const auto& cur : mSyncs) {
|
2020-07-22 01:57:01 +03:00
|
|
|
|
if (!cur) continue;
|
2018-02-21 04:34:25 +03:00
|
|
|
|
cur->mCanBeAvailable = true;
|
|
|
|
|
}
|
|
|
|
|
mSyncs.clear();
|
|
|
|
|
|
2020-07-22 01:57:01 +03:00
|
|
|
|
if (mWebGL) {
|
|
|
|
|
mWebGL->mAvailabilityRunnable = nullptr;
|
|
|
|
|
}
|
2018-02-21 04:34:25 +03:00
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-09 01:19:16 +03:00
|
|
|
|
// -
|
|
|
|
|
|
2021-01-14 04:23:06 +03:00
|
|
|
|
void WebGLContext::GenerateErrorImpl(const GLenum errOrWarning,
|
2020-01-09 01:19:16 +03:00
|
|
|
|
const std::string& text) const {
|
2021-01-14 04:23:06 +03:00
|
|
|
|
auto err = errOrWarning;
|
|
|
|
|
bool isPerfWarning = false;
|
|
|
|
|
if (err == webgl::kErrorPerfWarning) {
|
|
|
|
|
err = 0;
|
|
|
|
|
isPerfWarning = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (err && mFuncScope && mFuncScope->mBindFailureGuard) {
|
2020-01-09 01:19:16 +03:00
|
|
|
|
gfxCriticalError() << "mBindFailureGuard failure: Generating error "
|
|
|
|
|
<< EnumString(err) << ": " << text;
|
|
|
|
|
}
|
2021-01-14 04:23:06 +03:00
|
|
|
|
|
2020-01-09 01:19:16 +03:00
|
|
|
|
/* ES2 section 2.5 "GL Errors" states that implementations can have
|
|
|
|
|
* multiple 'flags', as errors might be caught in different parts of
|
|
|
|
|
* a distributed implementation.
|
|
|
|
|
* We're signing up as a distributed implementation here, with
|
|
|
|
|
* separate flags for WebGL and the underlying GLContext.
|
|
|
|
|
*/
|
|
|
|
|
if (!mWebGLError) mWebGLError = err;
|
|
|
|
|
|
2020-01-09 01:19:23 +03:00
|
|
|
|
if (!mHost) return; // Impossible?
|
|
|
|
|
|
2021-01-14 04:23:06 +03:00
|
|
|
|
// -
|
|
|
|
|
|
|
|
|
|
const auto ShouldWarn = [&]() {
|
|
|
|
|
if (isPerfWarning) {
|
|
|
|
|
return ShouldGeneratePerfWarnings();
|
|
|
|
|
}
|
|
|
|
|
return ShouldGenerateWarnings();
|
|
|
|
|
};
|
|
|
|
|
if (!ShouldWarn()) return;
|
|
|
|
|
|
|
|
|
|
// -
|
|
|
|
|
|
|
|
|
|
auto* pNumWarnings = &mWarningCount;
|
|
|
|
|
const char* warningsType = "warnings";
|
|
|
|
|
if (isPerfWarning) {
|
|
|
|
|
pNumWarnings = &mNumPerfWarnings;
|
|
|
|
|
warningsType = "perf warnings";
|
|
|
|
|
}
|
2020-01-09 01:19:23 +03:00
|
|
|
|
|
2021-01-14 04:23:06 +03:00
|
|
|
|
if (isPerfWarning) {
|
|
|
|
|
const auto perfText = std::string("WebGL perf warning: ") + text;
|
|
|
|
|
mHost->JsWarning(perfText);
|
|
|
|
|
} else {
|
|
|
|
|
mHost->JsWarning(text);
|
|
|
|
|
}
|
|
|
|
|
*pNumWarnings += 1;
|
2020-01-09 01:19:23 +03:00
|
|
|
|
|
2021-01-14 04:23:06 +03:00
|
|
|
|
if (!ShouldWarn()) {
|
|
|
|
|
const auto& msg = nsPrintfCString(
|
|
|
|
|
"After reporting %i, no further %s will be reported for this WebGL "
|
|
|
|
|
"context.",
|
|
|
|
|
int(*pNumWarnings), warningsType);
|
|
|
|
|
mHost->JsWarning(ToString(msg));
|
2020-01-09 01:19:16 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// -
|
|
|
|
|
|
|
|
|
|
Maybe<std::string> WebGLContext::GetString(const GLenum pname) const {
|
|
|
|
|
const WebGLContext::FuncScope funcScope(*this, "getParameter");
|
|
|
|
|
if (IsContextLost()) return {};
|
|
|
|
|
|
2020-08-27 03:16:24 +03:00
|
|
|
|
const auto FromRaw = [](const char* const raw) -> Maybe<std::string> {
|
|
|
|
|
if (!raw) return {};
|
|
|
|
|
return Some(std::string(raw));
|
|
|
|
|
};
|
|
|
|
|
|
2020-01-09 01:19:16 +03:00
|
|
|
|
switch (pname) {
|
|
|
|
|
case LOCAL_GL_EXTENSIONS: {
|
|
|
|
|
if (!gl->IsCoreProfile()) {
|
|
|
|
|
const auto rawExt = (const char*)gl->fGetString(LOCAL_GL_EXTENSIONS);
|
2020-08-27 03:16:24 +03:00
|
|
|
|
return FromRaw(rawExt);
|
2020-01-09 01:19:16 +03:00
|
|
|
|
}
|
|
|
|
|
std::string ret;
|
|
|
|
|
const auto& numExts = gl->GetIntAs<GLuint>(LOCAL_GL_NUM_EXTENSIONS);
|
|
|
|
|
for (GLuint i = 0; i < numExts; i++) {
|
|
|
|
|
const auto rawExt =
|
|
|
|
|
(const char*)gl->fGetStringi(LOCAL_GL_EXTENSIONS, i);
|
2020-08-27 03:16:24 +03:00
|
|
|
|
if (!rawExt) continue;
|
|
|
|
|
|
2020-01-09 01:19:16 +03:00
|
|
|
|
if (i > 0) {
|
|
|
|
|
ret += " ";
|
|
|
|
|
}
|
|
|
|
|
ret += rawExt;
|
|
|
|
|
}
|
|
|
|
|
return Some(std::move(ret));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case LOCAL_GL_RENDERER:
|
|
|
|
|
case LOCAL_GL_VENDOR:
|
|
|
|
|
case LOCAL_GL_VERSION: {
|
|
|
|
|
const auto raw = (const char*)gl->fGetString(pname);
|
2020-08-27 03:16:24 +03:00
|
|
|
|
return FromRaw(raw);
|
2020-01-09 01:19:16 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case dom::MOZ_debug_Binding::WSI_INFO: {
|
|
|
|
|
nsCString info;
|
|
|
|
|
gl->GetWSIInfo(&info);
|
|
|
|
|
return Some(std::string(info.BeginReading()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
ErrorInvalidEnumArg("pname", pname);
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ---------------------------------
|
|
|
|
|
|
|
|
|
|
Maybe<webgl::IndexedName> webgl::ParseIndexed(const std::string& str) {
|
|
|
|
|
static const std::regex kRegex("(.*)\\[([0-9]+)\\]");
|
|
|
|
|
|
|
|
|
|
std::smatch match;
|
|
|
|
|
if (!std::regex_match(str, match, kRegex)) return {};
|
|
|
|
|
|
|
|
|
|
const auto index = std::stoull(match[2]);
|
|
|
|
|
return Some(webgl::IndexedName{match[1], index});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ExplodeName("foo.bar[3].x") -> ["foo", ".", "bar", "[", "3", "]", ".", "x"]
|
|
|
|
|
static std::vector<std::string> ExplodeName(const std::string& str) {
|
|
|
|
|
std::vector<std::string> ret;
|
|
|
|
|
|
|
|
|
|
static const std::regex kSep("[.[\\]]");
|
|
|
|
|
|
|
|
|
|
auto itr = std::regex_token_iterator<decltype(str.begin())>(
|
|
|
|
|
str.begin(), str.end(), kSep, {-1, 0});
|
|
|
|
|
const auto end = decltype(itr)();
|
|
|
|
|
|
|
|
|
|
for (; itr != end; ++itr) {
|
|
|
|
|
const auto& part = itr->str();
|
|
|
|
|
if (part.size()) {
|
|
|
|
|
ret.push_back(part);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-
|
|
|
|
|
|
2020-01-09 01:19:23 +03:00
|
|
|
|
//#define DUMP_MakeLinkResult
|
|
|
|
|
|
2020-01-09 01:19:16 +03:00
|
|
|
|
webgl::LinkActiveInfo GetLinkActiveInfo(
|
|
|
|
|
gl::GLContext& gl, const GLuint prog, const bool webgl2,
|
|
|
|
|
const std::unordered_map<std::string, std::string>& nameUnmap) {
|
|
|
|
|
webgl::LinkActiveInfo ret;
|
|
|
|
|
[&]() {
|
|
|
|
|
const auto fnGetProgramui = [&](const GLenum pname) {
|
|
|
|
|
GLint ret = 0;
|
|
|
|
|
gl.fGetProgramiv(prog, pname, &ret);
|
|
|
|
|
return static_cast<uint32_t>(ret);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
std::vector<char> stringBuffer(1);
|
|
|
|
|
const auto fnEnsureCapacity = [&](const GLenum pname) {
|
|
|
|
|
const auto maxWithNull = fnGetProgramui(pname);
|
|
|
|
|
if (maxWithNull > stringBuffer.size()) {
|
|
|
|
|
stringBuffer.resize(maxWithNull);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
fnEnsureCapacity(LOCAL_GL_ACTIVE_ATTRIBUTE_MAX_LENGTH);
|
|
|
|
|
fnEnsureCapacity(LOCAL_GL_ACTIVE_UNIFORM_MAX_LENGTH);
|
|
|
|
|
if (webgl2) {
|
|
|
|
|
fnEnsureCapacity(LOCAL_GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH);
|
|
|
|
|
fnEnsureCapacity(LOCAL_GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// -
|
|
|
|
|
|
|
|
|
|
const auto fnUnmapName = [&](const std::string& mappedName) {
|
|
|
|
|
const auto parts = ExplodeName(mappedName);
|
|
|
|
|
|
|
|
|
|
std::ostringstream ret;
|
|
|
|
|
for (const auto& part : parts) {
|
|
|
|
|
const auto maybe = MaybeFind(nameUnmap, part);
|
|
|
|
|
if (maybe) {
|
|
|
|
|
ret << *maybe;
|
|
|
|
|
} else {
|
|
|
|
|
ret << part;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return ret.str();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// -
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
const auto count = fnGetProgramui(LOCAL_GL_ACTIVE_ATTRIBUTES);
|
|
|
|
|
ret.activeAttribs.reserve(count);
|
2020-01-09 01:19:23 +03:00
|
|
|
|
for (const auto i : IntegerRange(count)) {
|
2020-01-09 01:19:16 +03:00
|
|
|
|
GLsizei lengthWithoutNull = 0;
|
|
|
|
|
GLint elemCount = 0; // `size`
|
|
|
|
|
GLenum elemType = 0; // `type`
|
|
|
|
|
gl.fGetActiveAttrib(prog, i, stringBuffer.size(), &lengthWithoutNull,
|
|
|
|
|
&elemCount, &elemType, stringBuffer.data());
|
|
|
|
|
if (!elemType) {
|
|
|
|
|
const auto error = gl.fGetError();
|
|
|
|
|
if (error != LOCAL_GL_CONTEXT_LOST) {
|
|
|
|
|
gfxCriticalError() << "Failed to do glGetActiveAttrib: " << error;
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const auto mappedName =
|
|
|
|
|
std::string(stringBuffer.data(), lengthWithoutNull);
|
|
|
|
|
const auto userName = fnUnmapName(mappedName);
|
|
|
|
|
|
|
|
|
|
auto loc = gl.fGetAttribLocation(prog, mappedName.c_str());
|
|
|
|
|
if (mappedName.find("gl_") == 0) {
|
|
|
|
|
// Bug 1328559: Appears problematic on ANGLE and OSX, but not Linux or
|
|
|
|
|
// Win+GL.
|
|
|
|
|
loc = -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef DUMP_MakeLinkResult
|
|
|
|
|
printf_stderr("[attrib %u/%u] @%i %s->%s\n", i, count, loc,
|
|
|
|
|
userName.c_str(), mappedName.c_str());
|
|
|
|
|
#endif
|
|
|
|
|
webgl::ActiveAttribInfo info;
|
|
|
|
|
info.elemType = elemType;
|
|
|
|
|
info.elemCount = elemCount;
|
|
|
|
|
info.name = userName;
|
|
|
|
|
info.location = loc;
|
2020-02-26 03:44:26 +03:00
|
|
|
|
info.baseType = webgl::ToAttribBaseType(info.elemType);
|
2020-01-09 01:19:16 +03:00
|
|
|
|
ret.activeAttribs.push_back(std::move(info));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// -
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
const auto count = fnGetProgramui(LOCAL_GL_ACTIVE_UNIFORMS);
|
|
|
|
|
ret.activeUniforms.reserve(count);
|
|
|
|
|
|
|
|
|
|
std::vector<GLint> blockIndexList(count, -1);
|
|
|
|
|
std::vector<GLint> blockOffsetList(count, -1);
|
|
|
|
|
std::vector<GLint> blockArrayStrideList(count, -1);
|
|
|
|
|
std::vector<GLint> blockMatrixStrideList(count, -1);
|
|
|
|
|
std::vector<GLint> blockIsRowMajorList(count, 0);
|
|
|
|
|
|
2020-02-21 06:11:23 +03:00
|
|
|
|
if (webgl2 && count) {
|
2020-01-09 01:19:16 +03:00
|
|
|
|
std::vector<GLuint> activeIndices;
|
|
|
|
|
activeIndices.reserve(count);
|
2020-01-09 01:19:23 +03:00
|
|
|
|
for (const auto i : IntegerRange(count)) {
|
2020-01-09 01:19:16 +03:00
|
|
|
|
activeIndices.push_back(i);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gl.fGetActiveUniformsiv(
|
|
|
|
|
prog, activeIndices.size(), activeIndices.data(),
|
|
|
|
|
LOCAL_GL_UNIFORM_BLOCK_INDEX, blockIndexList.data());
|
|
|
|
|
|
|
|
|
|
gl.fGetActiveUniformsiv(prog, activeIndices.size(),
|
|
|
|
|
activeIndices.data(), LOCAL_GL_UNIFORM_OFFSET,
|
|
|
|
|
blockOffsetList.data());
|
|
|
|
|
|
|
|
|
|
gl.fGetActiveUniformsiv(
|
|
|
|
|
prog, activeIndices.size(), activeIndices.data(),
|
|
|
|
|
LOCAL_GL_UNIFORM_ARRAY_STRIDE, blockArrayStrideList.data());
|
|
|
|
|
|
|
|
|
|
gl.fGetActiveUniformsiv(
|
|
|
|
|
prog, activeIndices.size(), activeIndices.data(),
|
|
|
|
|
LOCAL_GL_UNIFORM_MATRIX_STRIDE, blockMatrixStrideList.data());
|
|
|
|
|
|
|
|
|
|
gl.fGetActiveUniformsiv(
|
|
|
|
|
prog, activeIndices.size(), activeIndices.data(),
|
|
|
|
|
LOCAL_GL_UNIFORM_IS_ROW_MAJOR, blockIsRowMajorList.data());
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-09 01:19:23 +03:00
|
|
|
|
for (const auto i : IntegerRange(count)) {
|
2020-01-09 01:19:16 +03:00
|
|
|
|
GLsizei lengthWithoutNull = 0;
|
|
|
|
|
GLint elemCount = 0; // `size`
|
|
|
|
|
GLenum elemType = 0; // `type`
|
|
|
|
|
gl.fGetActiveUniform(prog, i, stringBuffer.size(), &lengthWithoutNull,
|
|
|
|
|
&elemCount, &elemType, stringBuffer.data());
|
|
|
|
|
if (!elemType) {
|
|
|
|
|
const auto error = gl.fGetError();
|
|
|
|
|
if (error != LOCAL_GL_CONTEXT_LOST) {
|
|
|
|
|
gfxCriticalError() << "Failed to do glGetActiveUniform: " << error;
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
auto mappedName = std::string(stringBuffer.data(), lengthWithoutNull);
|
|
|
|
|
|
|
|
|
|
// Get true name
|
|
|
|
|
|
|
|
|
|
auto baseMappedName = mappedName;
|
|
|
|
|
|
|
|
|
|
const bool isArray = [&]() {
|
|
|
|
|
const auto maybe = webgl::ParseIndexed(mappedName);
|
|
|
|
|
if (maybe) {
|
|
|
|
|
MOZ_ASSERT(maybe->index == 0);
|
|
|
|
|
baseMappedName = std::move(maybe->name);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}();
|
|
|
|
|
|
|
|
|
|
const auto userName = fnUnmapName(mappedName);
|
|
|
|
|
|
|
|
|
|
// -
|
|
|
|
|
|
|
|
|
|
webgl::ActiveUniformInfo info;
|
|
|
|
|
info.elemType = elemType;
|
|
|
|
|
info.elemCount = static_cast<uint32_t>(elemCount);
|
|
|
|
|
info.name = userName;
|
|
|
|
|
info.block_index = blockIndexList[i];
|
|
|
|
|
info.block_offset = blockOffsetList[i];
|
|
|
|
|
info.block_arrayStride = blockArrayStrideList[i];
|
|
|
|
|
info.block_matrixStride = blockMatrixStrideList[i];
|
|
|
|
|
info.block_isRowMajor = bool(blockIsRowMajorList[i]);
|
|
|
|
|
|
|
|
|
|
#ifdef DUMP_MakeLinkResult
|
|
|
|
|
printf_stderr("[uniform %u/%u] %s->%s\n", i + 1, count,
|
|
|
|
|
userName.c_str(), mappedName.c_str());
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// Get uniform locations
|
|
|
|
|
{
|
|
|
|
|
auto locName = baseMappedName;
|
|
|
|
|
const auto baseLength = locName.size();
|
|
|
|
|
for (const auto i : IntegerRange(info.elemCount)) {
|
|
|
|
|
if (isArray) {
|
|
|
|
|
locName.erase(
|
|
|
|
|
baseLength); // Erase previous [N], but retain capacity.
|
|
|
|
|
locName += '[';
|
|
|
|
|
locName += std::to_string(i);
|
|
|
|
|
locName += ']';
|
|
|
|
|
}
|
|
|
|
|
const auto loc = gl.fGetUniformLocation(prog, locName.c_str());
|
|
|
|
|
if (loc != -1) {
|
|
|
|
|
info.locByIndex[i] = static_cast<uint32_t>(loc);
|
|
|
|
|
#ifdef DUMP_MakeLinkResult
|
|
|
|
|
printf_stderr(" [%u] @%i\n", i, loc);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} // anon
|
|
|
|
|
|
|
|
|
|
ret.activeUniforms.push_back(std::move(info));
|
|
|
|
|
} // for i
|
|
|
|
|
} // anon
|
|
|
|
|
|
|
|
|
|
if (webgl2) {
|
|
|
|
|
// -------------------------------------
|
|
|
|
|
// active uniform blocks
|
|
|
|
|
{
|
|
|
|
|
const auto count = fnGetProgramui(LOCAL_GL_ACTIVE_UNIFORM_BLOCKS);
|
|
|
|
|
ret.activeUniformBlocks.reserve(count);
|
|
|
|
|
|
2020-01-09 01:19:23 +03:00
|
|
|
|
for (const auto i : IntegerRange(count)) {
|
2020-01-09 01:19:16 +03:00
|
|
|
|
GLsizei lengthWithoutNull = 0;
|
|
|
|
|
gl.fGetActiveUniformBlockName(prog, i, stringBuffer.size(),
|
|
|
|
|
&lengthWithoutNull,
|
|
|
|
|
stringBuffer.data());
|
|
|
|
|
const auto mappedName =
|
|
|
|
|
std::string(stringBuffer.data(), lengthWithoutNull);
|
|
|
|
|
const auto userName = fnUnmapName(mappedName);
|
|
|
|
|
|
|
|
|
|
// -
|
|
|
|
|
|
|
|
|
|
auto info = webgl::ActiveUniformBlockInfo{userName};
|
|
|
|
|
GLint val = 0;
|
|
|
|
|
|
|
|
|
|
gl.fGetActiveUniformBlockiv(prog, i, LOCAL_GL_UNIFORM_BLOCK_DATA_SIZE,
|
|
|
|
|
&val);
|
|
|
|
|
info.dataSize = static_cast<uint32_t>(val);
|
|
|
|
|
|
|
|
|
|
gl.fGetActiveUniformBlockiv(
|
|
|
|
|
prog, i, LOCAL_GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &val);
|
|
|
|
|
info.activeUniformIndices.resize(val);
|
|
|
|
|
gl.fGetActiveUniformBlockiv(
|
|
|
|
|
prog, i, LOCAL_GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES,
|
|
|
|
|
reinterpret_cast<GLint*>(info.activeUniformIndices.data()));
|
|
|
|
|
|
|
|
|
|
gl.fGetActiveUniformBlockiv(
|
|
|
|
|
prog, i, LOCAL_GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER,
|
|
|
|
|
&val);
|
|
|
|
|
info.referencedByVertexShader = bool(val);
|
|
|
|
|
|
|
|
|
|
gl.fGetActiveUniformBlockiv(
|
|
|
|
|
prog, i, LOCAL_GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER,
|
|
|
|
|
&val);
|
|
|
|
|
info.referencedByFragmentShader = bool(val);
|
|
|
|
|
|
|
|
|
|
ret.activeUniformBlocks.push_back(std::move(info));
|
|
|
|
|
} // for i
|
|
|
|
|
} // anon
|
|
|
|
|
|
|
|
|
|
// -------------------------------------
|
|
|
|
|
// active tf varyings
|
|
|
|
|
{
|
|
|
|
|
const auto count = fnGetProgramui(LOCAL_GL_TRANSFORM_FEEDBACK_VARYINGS);
|
|
|
|
|
ret.activeTfVaryings.reserve(count);
|
|
|
|
|
|
2020-01-09 01:19:23 +03:00
|
|
|
|
for (const auto i : IntegerRange(count)) {
|
2020-01-09 01:19:16 +03:00
|
|
|
|
GLsizei lengthWithoutNull = 0;
|
|
|
|
|
GLsizei elemCount = 0; // `size`
|
|
|
|
|
GLenum elemType = 0; // `type`
|
|
|
|
|
gl.fGetTransformFeedbackVarying(prog, i, stringBuffer.size(),
|
|
|
|
|
&lengthWithoutNull, &elemCount,
|
|
|
|
|
&elemType, stringBuffer.data());
|
|
|
|
|
const auto mappedName =
|
|
|
|
|
std::string(stringBuffer.data(), lengthWithoutNull);
|
|
|
|
|
const auto userName = fnUnmapName(mappedName);
|
|
|
|
|
|
|
|
|
|
ret.activeTfVaryings.push_back(
|
|
|
|
|
{elemType, static_cast<uint32_t>(elemCount), userName});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} // if webgl2
|
|
|
|
|
}();
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-22 01:56:52 +03:00
|
|
|
|
nsCString ToCString(const std::string& s) {
|
|
|
|
|
return nsCString(s.data(), s.size());
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-09 01:19:16 +03:00
|
|
|
|
webgl::CompileResult WebGLContext::GetCompileResult(
|
|
|
|
|
const WebGLShader& shader) const {
|
|
|
|
|
webgl::CompileResult ret;
|
|
|
|
|
[&]() {
|
2020-01-09 01:19:23 +03:00
|
|
|
|
ret.pending = false;
|
2020-01-09 01:19:16 +03:00
|
|
|
|
const auto& info = shader.CompileResults();
|
|
|
|
|
if (!info) return;
|
|
|
|
|
if (!info->mValid) {
|
2020-07-22 01:56:52 +03:00
|
|
|
|
ret.log = info->mInfoLog.c_str();
|
2020-01-09 01:19:16 +03:00
|
|
|
|
return;
|
|
|
|
|
}
|
2020-07-22 01:56:52 +03:00
|
|
|
|
// TODO: These could be large and should be made fallible.
|
|
|
|
|
ret.translatedSource = ToCString(info->mObjectCode);
|
|
|
|
|
ret.log = ToCString(shader.CompileLog());
|
2020-01-09 01:19:16 +03:00
|
|
|
|
if (!shader.IsCompiled()) return;
|
|
|
|
|
ret.success = true;
|
|
|
|
|
}();
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
webgl::LinkResult WebGLContext::GetLinkResult(const WebGLProgram& prog) const {
|
|
|
|
|
webgl::LinkResult ret;
|
|
|
|
|
[&]() {
|
2020-01-09 01:19:23 +03:00
|
|
|
|
ret.pending = false; // Link status polling not yet implemented.
|
2020-07-22 01:56:52 +03:00
|
|
|
|
ret.log = ToCString(prog.LinkLog());
|
2020-01-09 01:19:16 +03:00
|
|
|
|
const auto& info = prog.LinkInfo();
|
|
|
|
|
if (!info) return;
|
|
|
|
|
ret.success = true;
|
|
|
|
|
ret.active = info->active;
|
|
|
|
|
ret.tfBufferMode = info->transformFeedbackBufferMode;
|
|
|
|
|
}();
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// -
|
|
|
|
|
|
|
|
|
|
GLint WebGLContext::GetFragDataLocation(const WebGLProgram& prog,
|
|
|
|
|
const std::string& userName) const {
|
2020-01-09 01:19:23 +03:00
|
|
|
|
const auto err = CheckGLSLVariableName(IsWebGL2(), userName);
|
|
|
|
|
if (err) {
|
|
|
|
|
GenerateError(err->type, "%s", err->info.c_str());
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-09 01:19:16 +03:00
|
|
|
|
const auto& info = prog.LinkInfo();
|
|
|
|
|
if (!info) return -1;
|
|
|
|
|
const auto& nameMap = info->nameMap;
|
|
|
|
|
|
2020-01-09 01:19:23 +03:00
|
|
|
|
const auto parts = ExplodeName(userName);
|
|
|
|
|
|
|
|
|
|
std::ostringstream ret;
|
|
|
|
|
for (const auto& part : parts) {
|
|
|
|
|
const auto maybe = MaybeFind(nameMap, part);
|
|
|
|
|
if (maybe) {
|
|
|
|
|
ret << *maybe;
|
|
|
|
|
} else {
|
|
|
|
|
ret << part;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
const auto mappedName = ret.str();
|
|
|
|
|
|
2021-08-12 04:35:15 +03:00
|
|
|
|
if (gl->WorkAroundDriverBugs() && gl->IsMesa()) {
|
|
|
|
|
// Mesa incorrectly generates INVALID_OPERATION for gl_ prefixes here.
|
|
|
|
|
if (mappedName.find("gl_") == 0) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-09 01:19:16 +03:00
|
|
|
|
return gl->fGetFragDataLocation(prog.mGLName, mappedName.c_str());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// -
|
|
|
|
|
|
|
|
|
|
WebGLContextBoundObject::WebGLContextBoundObject(WebGLContext* webgl)
|
|
|
|
|
: mContext(webgl) {}
|
|
|
|
|
|
2022-02-12 05:20:42 +03:00
|
|
|
|
// -
|
|
|
|
|
|
|
|
|
|
Result<webgl::ExplicitPixelPackingState, std::string>
|
|
|
|
|
webgl::ExplicitPixelPackingState::ForUseWith(
|
|
|
|
|
const webgl::PixelPackingState& stateOrZero, const GLenum target,
|
|
|
|
|
const uvec3& subrectSize, const webgl::PackingInfo& pi,
|
|
|
|
|
const Maybe<size_t> bytesPerRowStrideOverride) {
|
|
|
|
|
auto state = stateOrZero;
|
|
|
|
|
|
|
|
|
|
if (!IsTexTarget3D(target)) {
|
|
|
|
|
state.skipImages = 0;
|
|
|
|
|
state.imageHeight = 0;
|
|
|
|
|
}
|
|
|
|
|
if (!state.rowLength) {
|
|
|
|
|
state.rowLength = subrectSize.x;
|
|
|
|
|
}
|
|
|
|
|
if (!state.imageHeight) {
|
|
|
|
|
state.imageHeight = subrectSize.y;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// -
|
|
|
|
|
|
|
|
|
|
const auto mpii = PackingInfoInfo::For(pi);
|
|
|
|
|
if (!mpii) {
|
|
|
|
|
const auto text =
|
|
|
|
|
nsPrintfCString("Invalid pi: { 0x%x, 0x%x}", pi.format, pi.type);
|
|
|
|
|
return Err(mozilla::ToString(text));
|
|
|
|
|
}
|
|
|
|
|
const auto pii = *mpii;
|
|
|
|
|
const auto bytesPerPixel = pii.BytesPerPixel();
|
|
|
|
|
|
|
|
|
|
const auto ElemsPerRowStride = [&]() {
|
|
|
|
|
// GLES 3.0.6 p116:
|
|
|
|
|
// p: `Elem*` pointer to the first element of the first row
|
|
|
|
|
// N: row number, starting at 0
|
|
|
|
|
// l: groups (pixels) per row
|
|
|
|
|
// n: elements per group (pixel) in [1,2,3,4]
|
|
|
|
|
// s: bytes per element in [1,2,4,8]
|
|
|
|
|
// a: UNPACK_ALIGNMENT in [1,2,4,8]
|
|
|
|
|
// Pointer to first element of Nth row: p + N*k
|
|
|
|
|
// k(s>=a): n*l
|
|
|
|
|
// k(s<a): a/s * ceil(s*n*l/a)
|
|
|
|
|
const auto n__elemsPerPixel = pii.elementsPerPixel;
|
|
|
|
|
const auto l__pixelsPerRow = state.rowLength;
|
|
|
|
|
const auto a__alignment = state.alignmentInTypeElems;
|
|
|
|
|
const auto s__bytesPerElem = pii.bytesPerElement;
|
|
|
|
|
|
|
|
|
|
const auto nl = CheckedInt<size_t>(n__elemsPerPixel) * l__pixelsPerRow;
|
|
|
|
|
auto k__elemsPerRowStride = nl;
|
|
|
|
|
if (s__bytesPerElem < a__alignment) {
|
|
|
|
|
// k = a/s * ceil(s*n*l/a)
|
|
|
|
|
k__elemsPerRowStride =
|
|
|
|
|
a__alignment / s__bytesPerElem *
|
|
|
|
|
((nl * s__bytesPerElem + a__alignment - 1) / a__alignment);
|
|
|
|
|
}
|
|
|
|
|
return k__elemsPerRowStride;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// -
|
|
|
|
|
|
|
|
|
|
if (bytesPerRowStrideOverride) { // E.g. HTMLImageElement
|
|
|
|
|
const size_t bytesPerRowStrideRequired = *bytesPerRowStrideOverride;
|
|
|
|
|
// We have to reverse-engineer an ALIGNMENT and ROW_LENGTH for this.
|
|
|
|
|
|
|
|
|
|
// GL does this in elems not bytes, so we should too.
|
|
|
|
|
MOZ_RELEASE_ASSERT(bytesPerRowStrideRequired % pii.bytesPerElement == 0);
|
|
|
|
|
const auto elemsPerRowStrideRequired =
|
|
|
|
|
bytesPerRowStrideRequired / pii.bytesPerElement;
|
|
|
|
|
|
|
|
|
|
state.rowLength = bytesPerRowStrideRequired / bytesPerPixel;
|
|
|
|
|
state.alignmentInTypeElems = 8;
|
|
|
|
|
while (true) {
|
|
|
|
|
const auto elemPerRowStride = ElemsPerRowStride();
|
|
|
|
|
if (elemPerRowStride.isValid() &&
|
|
|
|
|
elemPerRowStride.value() == elemsPerRowStrideRequired) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
state.alignmentInTypeElems /= 2;
|
|
|
|
|
if (!state.alignmentInTypeElems) {
|
|
|
|
|
const auto text = nsPrintfCString(
|
|
|
|
|
"No valid alignment found: pi: { 0x%x, 0x%x},"
|
|
|
|
|
" bytesPerRowStrideRequired: %zu",
|
|
|
|
|
pi.format, pi.type, bytesPerRowStrideRequired);
|
|
|
|
|
return Err(mozilla::ToString(text));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// -
|
|
|
|
|
|
|
|
|
|
const auto usedPixelsPerRow =
|
|
|
|
|
CheckedInt<size_t>(state.skipPixels) + subrectSize.x;
|
|
|
|
|
if (!usedPixelsPerRow.isValid() ||
|
|
|
|
|
usedPixelsPerRow.value() > state.rowLength) {
|
|
|
|
|
return Err("UNPACK_SKIP_PIXELS + width > UNPACK_ROW_LENGTH.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (subrectSize.y > state.imageHeight) {
|
|
|
|
|
return Err("height > UNPACK_IMAGE_HEIGHT.");
|
|
|
|
|
}
|
|
|
|
|
// The spec doesn't bound SKIP_ROWS + height <= IMAGE_HEIGHT, unfortunately.
|
|
|
|
|
|
|
|
|
|
// -
|
|
|
|
|
|
|
|
|
|
auto metrics = Metrics{};
|
|
|
|
|
|
|
|
|
|
metrics.usedSize = subrectSize;
|
|
|
|
|
metrics.bytesPerPixel = BytesPerPixel(pi);
|
|
|
|
|
|
|
|
|
|
// -
|
|
|
|
|
|
|
|
|
|
const auto elemsPerRowStride = ElemsPerRowStride();
|
|
|
|
|
const auto bytesPerRowStride = pii.bytesPerElement * elemsPerRowStride;
|
|
|
|
|
if (!bytesPerRowStride.isValid()) {
|
|
|
|
|
return Err("ROW_LENGTH or width too large for packing.");
|
|
|
|
|
}
|
|
|
|
|
metrics.bytesPerRowStride = bytesPerRowStride.value();
|
|
|
|
|
|
|
|
|
|
// -
|
|
|
|
|
|
|
|
|
|
const auto firstImageTotalRows =
|
|
|
|
|
CheckedInt<size_t>(state.skipRows) + metrics.usedSize.y;
|
|
|
|
|
const auto totalImages =
|
|
|
|
|
CheckedInt<size_t>(state.skipImages) + metrics.usedSize.z;
|
|
|
|
|
auto totalRows = CheckedInt<size_t>(0);
|
|
|
|
|
if (metrics.usedSize.y && metrics.usedSize.z) {
|
|
|
|
|
totalRows = firstImageTotalRows + state.imageHeight * (totalImages - 1);
|
|
|
|
|
}
|
|
|
|
|
if (!totalRows.isValid()) {
|
|
|
|
|
return Err(
|
|
|
|
|
"SKIP_ROWS, height, IMAGE_HEIGHT, SKIP_IMAGES, or depth too large for "
|
|
|
|
|
"packing.");
|
|
|
|
|
}
|
|
|
|
|
metrics.totalRows = totalRows.value();
|
|
|
|
|
|
|
|
|
|
// -
|
|
|
|
|
|
|
|
|
|
const auto totalBytesStrided = totalRows * metrics.bytesPerRowStride;
|
|
|
|
|
if (!totalBytesStrided.isValid()) {
|
|
|
|
|
return Err("Total byte count too large for packing.");
|
|
|
|
|
}
|
|
|
|
|
metrics.totalBytesStrided = totalBytesStrided.value();
|
|
|
|
|
|
|
|
|
|
metrics.totalBytesUsed = metrics.totalBytesStrided;
|
|
|
|
|
if (metrics.usedSize.x && metrics.usedSize.y && metrics.usedSize.z) {
|
|
|
|
|
const auto usedBytesPerRow =
|
|
|
|
|
usedPixelsPerRow.value() * metrics.bytesPerPixel;
|
|
|
|
|
metrics.totalBytesUsed -= metrics.bytesPerRowStride;
|
|
|
|
|
metrics.totalBytesUsed += usedBytesPerRow;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// -
|
|
|
|
|
|
|
|
|
|
return {{state, metrics}};
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-15 03:37:28 +03:00
|
|
|
|
} // namespace mozilla
|