--- a/dom/canvas/OffscreenCanvas.cpp
+++ b/dom/canvas/OffscreenCanvas.cpp
@@ -220,24 +220,17 @@ already_AddRefed<ImageBitmap>
OffscreenCanvas::TransferToImageBitmap(ErrorResult& aRv)
{
nsCOMPtr<nsIGlobalObject> globalObject = GetGlobalObject();
RefPtr<ImageBitmap> result = ImageBitmap::CreateFromOffscreenCanvas(globalObject, *this, aRv);
if (aRv.Failed()) {
return nullptr;
}
- // Clear the content.
- if ((mCurrentContextType == CanvasContextType::WebGL1 ||
- mCurrentContextType == CanvasContextType::WebGL2))
- {
- WebGLContext* webGL = static_cast<WebGLContext*>(mCurrentContext.get());
- webGL->ClearScreen();
- }
-
+ // TODO: Clear the content?
return result.forget();
}
already_AddRefed<Promise>
OffscreenCanvas::ToBlob(JSContext* aCx,
const nsAString& aType,
JS::Handle<JS::Value> aParams,
ErrorResult& aRv)
--- a/dom/canvas/WebGL2ContextFramebuffers.cpp
+++ b/dom/canvas/WebGL2ContextFramebuffers.cpp
@@ -35,39 +35,28 @@ WebGL2Context::BlitFramebuffer(GLint src
break;
default:
ErrorInvalidEnumInfo("blitFramebuffer: Bad `filter`:", filter);
return;
}
////
- const auto& readFB = mBoundReadFramebuffer;
- if (readFB &&
- !readFB->ValidateAndInitAttachments("blitFramebuffer's READ_FRAMEBUFFER"))
+ if (!ValidateAndInitFB("blitFramebuffer: READ_FRAMEBUFFER", mBoundReadFramebuffer) ||
+ !ValidateAndInitFB("blitFramebuffer: DRAW_FRAMEBUFFER", mBoundDrawFramebuffer))
{
return;
}
- const auto& drawFB = mBoundDrawFramebuffer;
- if (drawFB &&
- !drawFB->ValidateAndInitAttachments("blitFramebuffer's DRAW_FRAMEBUFFER"))
- {
- return;
- }
-
- ////
-
- if (!mBoundReadFramebuffer) {
- ClearBackbufferIfNeeded();
- }
+ DoBindFB(mBoundReadFramebuffer, LOCAL_GL_READ_FRAMEBUFFER);
+ DoBindFB(mBoundDrawFramebuffer, LOCAL_GL_DRAW_FRAMEBUFFER);
WebGLFramebuffer::BlitFramebuffer(this,
- readFB, srcX0, srcY0, srcX1, srcY1,
- drawFB, dstX0, dstY0, dstX1, dstY1,
+ srcX0, srcY0, srcX1, srcY1,
+ dstX0, dstY0, dstX1, dstY1,
mask, filter);
}
void
WebGL2Context::FramebufferTextureLayer(GLenum target, GLenum attachment,
WebGLTexture* texture, GLint level, GLint layer)
{
const char funcName[] = "framebufferTextureLayer";
@@ -165,33 +154,35 @@ WebGLContext::ValidateInvalidateFramebuf
{
if (IsContextLost())
return false;
if (!ValidateFramebufferTarget(target, funcName))
return false;
const WebGLFramebuffer* fb;
- bool isDefaultFB;
+ bool isDefaultFB = false;
switch (target) {
case LOCAL_GL_FRAMEBUFFER:
case LOCAL_GL_DRAW_FRAMEBUFFER:
fb = mBoundDrawFramebuffer;
- isDefaultFB = gl->Screen()->IsDrawFramebufferDefault();
break;
case LOCAL_GL_READ_FRAMEBUFFER:
fb = mBoundReadFramebuffer;
- isDefaultFB = gl->Screen()->IsReadFramebufferDefault();
break;
default:
MOZ_CRASH("GFX: Bad target.");
}
+ if (!ValidateAndInitFB(funcName, fb))
+ return false;
+ DoBindFB(fb, target);
+
*out_glNumAttachments = attachments.Length();
*out_glAttachments = attachments.Elements();
if (fb) {
for (const auto& attachment : attachments) {
if (!ValidateFramebufferAttachmentEnum(this, funcName, attachment))
return false;
}
@@ -225,23 +216,19 @@ WebGLContext::ValidateInvalidateFramebuf
*out_glNumAttachments = scopedVector->size();
*out_glAttachments = scopedVector->data();
}
}
////
if (!fb) {
- ClearBackbufferIfNeeded();
-
- // Don't do more validation after these.
- Invalidate();
- mShouldPresent = true;
+ mDefaultFB_IsInvalid = true;
+ mResolvedDefaultFB = nullptr;
}
-
return true;
}
void
WebGL2Context::InvalidateFramebuffer(GLenum target,
const dom::Sequence<GLenum>& attachments,
ErrorResult& rv)
{
@@ -326,12 +313,12 @@ WebGL2Context::ReadBuffer(GLenum mode)
nsCString enumName;
EnumName(mode, &enumName);
ErrorInvalidOperation("%s: If READ_FRAMEBUFFER is null, `mode` must be BACK or"
" NONE. Was %s.",
funcName, enumName.BeginReading());
return;
}
- gl->Screen()->SetReadBuffer(mode);
+ mDefaultFB_ReadBuffer = mode;
}
} // namespace mozilla
--- a/dom/canvas/WebGL2ContextMRTs.cpp
+++ b/dom/canvas/WebGL2ContextMRTs.cpp
@@ -57,21 +57,21 @@ WebGL2Context::ValidateClearBuffer(const
if (availElemCount < requiredElements) {
ErrorInvalidValue("%s: Not enough elements. Require %zu. Given %zu.",
funcName, requiredElements, availElemCount);
return false;
}
////
+ if (!BindCurFBForDraw(funcName))
+ return false;
+
const auto& fb = mBoundDrawFramebuffer;
if (fb) {
- if (!fb->ValidateAndInitAttachments(funcName))
- return false;
-
if (!fb->ValidateClearBufferType(funcName, buffer, drawBuffer, funcType))
return false;
} else if (buffer == LOCAL_GL_COLOR) {
if (drawBuffer != 0)
return true;
if (mDefaultFB_DrawBuffer0 == LOCAL_GL_NONE)
return true;
@@ -105,16 +105,23 @@ WebGL2Context::ClearBufferfv(GLenum buff
}
if (!ValidateClearBuffer(funcName, buffer, drawBuffer, src.elemCount, srcElemOffset,
LOCAL_GL_FLOAT))
{
return;
}
+ if (!mBoundDrawFramebuffer &&
+ buffer == LOCAL_GL_DEPTH &&
+ mNeedsFakeNoDepth)
+ {
+ return;
+ }
+
ScopedDrawCallWrapper wrapper(*this);
const auto ptr = src.elemBytes + srcElemOffset;
gl->fClearBufferfv(buffer, drawBuffer, ptr);
}
void
WebGL2Context::ClearBufferiv(GLenum buffer, GLint drawBuffer, const Int32Arr& src,
GLuint srcElemOffset)
@@ -131,16 +138,23 @@ WebGL2Context::ClearBufferiv(GLenum buff
}
if (!ValidateClearBuffer(funcName, buffer, drawBuffer, src.elemCount, srcElemOffset,
LOCAL_GL_INT))
{
return;
}
+ if (!mBoundDrawFramebuffer &&
+ buffer == LOCAL_GL_STENCIL &&
+ mNeedsFakeNoStencil)
+ {
+ return;
+ }
+
ScopedDrawCallWrapper wrapper(*this);
const auto ptr = src.elemBytes + srcElemOffset;
gl->fClearBufferiv(buffer, drawBuffer, ptr);
}
void
WebGL2Context::ClearBufferuiv(GLenum buffer, GLint drawBuffer, const Uint32Arr& src,
GLuint srcElemOffset)
@@ -174,13 +188,23 @@ WebGL2Context::ClearBufferfi(GLenum buff
return;
if (buffer != LOCAL_GL_DEPTH_STENCIL)
return ErrorInvalidEnum("%s: buffer must be DEPTH_STENCIL.", funcName);
if (!ValidateClearBuffer(funcName, buffer, drawBuffer, 2, 0, 0))
return;
+ auto driverDepth = depth;
+ auto driverStencil = stencil;
+ if (!mBoundDrawFramebuffer) {
+ if (mNeedsFakeNoDepth) {
+ driverDepth = 1.0f;
+ } else if (mNeedsFakeNoStencil) {
+ driverStencil = 0;
+ }
+ }
+
ScopedDrawCallWrapper wrapper(*this);
- gl->fClearBufferfi(buffer, drawBuffer, depth, stencil);
+ gl->fClearBufferfi(buffer, drawBuffer, driverDepth, driverStencil);
}
} // namespace mozilla
--- a/dom/canvas/WebGL2ContextState.cpp
+++ b/dom/canvas/WebGL2ContextState.cpp
@@ -40,17 +40,17 @@ WebGL2Context::GetParameter(JSContext* c
case LOCAL_GL_TRANSFORM_FEEDBACK_ACTIVE:
return JS::BooleanValue(mBoundTransformFeedback->mIsActive);
case LOCAL_GL_TRANSFORM_FEEDBACK_PAUSED:
return JS::BooleanValue(mBoundTransformFeedback->mIsPaused);
/* GLenum */
case LOCAL_GL_READ_BUFFER: {
if (!mBoundReadFramebuffer)
- return JS::Int32Value(gl->Screen()->GetReadBufferMode());
+ return JS::Int32Value(mDefaultFB_ReadBuffer);
if (!mBoundReadFramebuffer->ColorReadBuffer())
return JS::Int32Value(LOCAL_GL_NONE);
return JS::Int32Value(mBoundReadFramebuffer->ColorReadBuffer()->mAttachmentPoint);
}
case LOCAL_GL_FRAGMENT_SHADER_DERIVATIVE_HINT:
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -9,16 +9,17 @@
#include <queue>
#include "AccessCheck.h"
#include "gfxContext.h"
#include "gfxCrashReporterUtils.h"
#include "gfxPattern.h"
#include "gfxPrefs.h"
#include "gfxUtils.h"
+#include "gfx/gl/MozFramebuffer.h"
#include "GLBlitHelper.h"
#include "GLContext.h"
#include "GLContextProvider.h"
#include "GLReadTexImageHelper.h"
#include "GLScreenBuffer.h"
#include "ImageContainer.h"
#include "ImageEncoder.h"
#include "Layers.h"
@@ -114,42 +115,31 @@ WebGLContext::WebGLContext()
, mMaxAcceptableFBStatusInvals(gfxPrefs::WebGLMaxAcceptableFBStatusInvals())
, mDataAllocGLCallCount(0)
, mBypassShaderValidation(false)
, mEmptyTFO(0)
, mContextLossHandler(this)
, mNeedsFakeNoAlpha(false)
, mNeedsFakeNoDepth(false)
, mNeedsFakeNoStencil(false)
- , mNeedsEmulatedLoneDepthStencil(false)
, mAllowFBInvalidation(gfxPrefs::WebGLFBInvalidation())
+ , mMsaaSamples(gfxPrefs::WebGLMsaaSamples())
{
mGeneration = 0;
mInvalidated = false;
mCapturedFrameInvalidated = false;
mShouldPresent = true;
mResetLayer = true;
mOptionsFrozen = false;
mDisableExtensions = false;
mIsMesa = false;
mEmitContextLostErrorOnce = false;
mWebGLError = 0;
mUnderlyingGLError = 0;
- mActiveTexture = 0;
-
- mStencilRefFront = 0;
- mStencilRefBack = 0;
- mStencilValueMaskFront = 0;
- mStencilValueMaskBack = 0;
- mStencilWriteMaskFront = 0;
- mStencilWriteMaskBack = 0;
- mDepthWriteMask = 0;
- mStencilClearValue = 0;
- mDepthClearValue = 0;
mContextLostErrorSet = false;
mViewportX = 0;
mViewportY = 0;
mViewportWidth = 0;
mViewportHeight = 0;
mDitherEnabled = 1;
@@ -207,16 +197,19 @@ ClearLinkedList(LinkedList<T>& list)
}
void
WebGLContext::DestroyResourcesAndContext()
{
if (!gl)
return;
+ mDefaultFB = nullptr;
+ mResolvedDefaultFB = nullptr;
+
mBound2DTextures.Clear();
mBoundCubeMapTextures.Clear();
mBound3DTextures.Clear();
mBound2DArrayTextures.Clear();
mBoundSamplers.Clear();
mBoundArrayBuffer = nullptr;
mBoundCopyReadBuffer = nullptr;
mBoundCopyWriteBuffer = nullptr;
@@ -290,16 +283,17 @@ WebGLContext::DestroyResourcesAndContext
// We just got rid of everything, so the context had better
// have been going away.
if (GLContext::ShouldSpew()) {
printf_stderr("--- WebGL context destroyed: %p\n", gl.get());
}
MOZ_ASSERT(gl);
+ gl->MarkDestroyed();
mGL_OnlyClearInDestroyResourcesAndContext = nullptr;
MOZ_ASSERT(!gl);
}
void
WebGLContext::Invalidate()
{
if (!mCanvasElement)
@@ -393,28 +387,16 @@ WebGLContext::SetContextOptions(JSContex
// aren't the same as what they were originally.
return NS_ERROR_FAILURE;
}
mOptions = newOpts;
return NS_OK;
}
-int32_t
-WebGLContext::GetWidth() const
-{
- return mWidth;
-}
-
-int32_t
-WebGLContext::GetHeight() const
-{
- return mHeight;
-}
-
/* So there are a number of points of failure here. We might fail based
* on EGL vs. WGL, or we might fail to alloc a too-large size, or we
* might not be able to create a context with a certain combo of context
* creation attribs.
*
* We don't want to test the complete fallback matrix. (for now, at
* least) Instead, attempt creation in this order:
* 1. By platform API. (e.g. EGL vs. WGL)
@@ -481,64 +463,34 @@ HasAcceleratedLayers(const nsCOMPtr<nsIG
return false;
}
static void
PopulateCapFallbackQueue(const gl::SurfaceCaps& baseCaps,
std::queue<gl::SurfaceCaps>* out_fallbackCaps)
{
out_fallbackCaps->push(baseCaps);
-
- // Dropping antialias drops our quality, but not our correctness.
- // The user basically doesn't have to handle if this fails, they
- // just get reduced quality.
- if (baseCaps.antialias) {
- gl::SurfaceCaps nextCaps(baseCaps);
- nextCaps.antialias = false;
- PopulateCapFallbackQueue(nextCaps, out_fallbackCaps);
- }
-
- // If we have to drop one of depth or stencil, we'd prefer to keep
- // depth. However, the client app will need to handle if this
- // doesn't work.
- if (baseCaps.stencil) {
- gl::SurfaceCaps nextCaps(baseCaps);
- nextCaps.stencil = false;
- PopulateCapFallbackQueue(nextCaps, out_fallbackCaps);
- }
-
- if (baseCaps.depth) {
- gl::SurfaceCaps nextCaps(baseCaps);
- nextCaps.depth = false;
- PopulateCapFallbackQueue(nextCaps, out_fallbackCaps);
- }
}
static gl::SurfaceCaps
BaseCaps(const WebGLContextOptions& options, WebGLContext* webgl)
{
gl::SurfaceCaps baseCaps;
baseCaps.color = true;
- baseCaps.alpha = options.alpha;
- baseCaps.antialias = options.antialias;
- baseCaps.depth = options.depth;
+ baseCaps.alpha = true;
+ baseCaps.antialias = false;
+ baseCaps.depth = false;
+ baseCaps.stencil = false;
baseCaps.premultAlpha = options.premultipliedAlpha;
baseCaps.preserve = options.preserveDrawingBuffer;
- baseCaps.stencil = options.stencil;
-
- if (!baseCaps.alpha)
+
+ if (!baseCaps.alpha) {
baseCaps.premultAlpha = true;
-
- // we should really have this behind a
- // |gfxPlatform::GetPlatform()->GetScreenDepth() == 16| check, but
- // for now it's just behind a pref for testing/evaluation.
- baseCaps.bpp16 = gfxPrefs::WebGLPrefer16bpp();
-
- // Done with baseCaps construction.
+ }
if (!gfxPrefs::WebGLForceMSAA()) {
const nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
nsCString blocklistId;
if (IsFeatureInBlacklist(gfxInfo, nsIGfxInfo::FEATURE_WEBGL_MSAA, &blocklistId)) {
webgl->GenerateWarning("Disallowing antialiased backbuffers due"
" to blacklisting.");
@@ -767,67 +719,78 @@ WebGLContext::CreateAndInitGL(bool force
if (CreateAndInitGLWith(CreateGLWithDefault, baseCaps, flags, out_failReasons))
return true;
}
//////
if (tryANGLE) {
- // Force enable alpha channel to make sure ANGLE use correct framebuffer formart
- gl::SurfaceCaps& angleCaps = const_cast<gl::SurfaceCaps&>(baseCaps);
+ // Force enable alpha channel to make sure ANGLE use correct framebuffer format
+ auto angleCaps = baseCaps;
angleCaps.alpha = true;
return CreateAndInitGLWith(CreateGLWithANGLE, angleCaps, flags, out_failReasons);
}
//////
out_failReasons->push_back(FailureReason("FEATURE_FAILURE_WEBGL_EXHAUSTED_DRIVERS",
"Exhausted GL driver options."));
return false;
}
// Fallback for resizes:
+
bool
-WebGLContext::ResizeBackbuffer(uint32_t requestedWidth,
- uint32_t requestedHeight)
+WebGLContext::EnsureDefaultFB() const
{
- uint32_t width = requestedWidth;
- uint32_t height = requestedHeight;
-
- bool resized = false;
- while (width || height) {
- width = width ? width : 1;
- height = height ? height : 1;
-
- gfx::IntSize curSize(width, height);
- if (gl->ResizeOffscreen(curSize)) {
- resized = true;
- break;
- }
-
- width /= 2;
- height /= 2;
+ if (mDefaultFB) {
+ MOZ_ASSERT(mDefaultFB->mSize == mRequestedSize);
+ return true;
}
- if (!resized)
+ const bool depthStencil = mOptions.depth || mOptions.stencil;
+ auto attemptSize = mRequestedSize;
+
+ 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);
+ mDefaultFB = MozFramebuffer::Create(gl, attemptSize, mMsaaSamples,
+ depthStencil);
+ if (mDefaultFB)
+ return;
+ if (mOptionsFrozen)
+ return;
+ }
+
+ MOZ_ASSERT(!mDefaultFB);
+ mDefaultFB = MozFramebuffer::Create(gl, attemptSize, 0, depthStencil);
+ }();
+
+ if (mDefaultFB)
+ break;
+
+ attemptSize.width /= 2;
+ attemptSize.height /= 2;
+ }
+
+ if (!mDefaultFB)
return false;
- mWidth = gl->OffscreenSize().width;
- mHeight = gl->OffscreenSize().height;
- MOZ_ASSERT((uint32_t)mWidth == width);
- MOZ_ASSERT((uint32_t)mHeight == height);
-
- if (width != requestedWidth ||
- height != requestedHeight)
- {
+ mDefaultFB_IsInvalid = true;
+
+ if (mDefaultFB->mSize != mRequestedSize) {
GenerateWarning("Requested size %dx%d was too large, but resize"
" to %dx%d succeeded.",
- requestedWidth, requestedHeight,
- width, height);
+ mRequestedSize.width, mRequestedSize.height,
+ mDefaultFB->mSize.width, mDefaultFB->mSize.height);
}
return true;
}
void
WebGLContext::ThrowEvent_WebGLContextCreationError(const nsACString& text)
{
RefPtr<EventTarget> target = mCanvasElement;
@@ -882,46 +845,38 @@ WebGLContext::SetDimensions(int32_t sign
if (width == 0)
width = 1;
if (height == 0)
height = 1;
// If we already have a gl context, then we just need to resize it
if (gl) {
- if ((uint32_t)mWidth == width &&
- (uint32_t)mHeight == height)
+ if (uint32_t(mRequestedSize.width) == width &&
+ uint32_t(mRequestedSize.height) == height)
{
return NS_OK;
}
if (IsContextLost())
return NS_OK;
// If we've already drawn, we should commit the current buffer.
PresentScreenBuffer();
if (IsContextLost()) {
GenerateWarning("WebGL context was lost due to swap failure.");
return NS_OK;
}
- // ResizeOffscreen scraps the current prod buffer before making a new one.
- if (!ResizeBackbuffer(width, height)) {
- GenerateWarning("WebGL context failed to resize.");
- ForceLoseContext();
- return NS_OK;
- }
-
- // everything's good, we're done here
+ // Kill our current default fb(s), for later lazy allocation.
+ mRequestedSize = {width, height};
+ mDefaultFB = nullptr;
+
mResetLayer = true;
- mBackbufferNeedsClear = true;
-
- gl->ResetSyncCallCount("Existing WebGLContext resized.");
-
return NS_OK;
}
nsCString failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_UNKOWN");
auto autoTelemetry = mozilla::MakeScopeExit([&] {
Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_FAILURE_ID,
failureId);
});
@@ -1038,121 +993,83 @@ WebGLContext::SetDimensions(int32_t sign
failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_DXGL_INTEROP2");
const nsLiteralCString text("Caveat: WGL without DXGLInterop2.");
ThrowEvent_WebGLContextCreationError(text);
return NS_ERROR_FAILURE;
}
#endif
}
- if (!ResizeBackbuffer(width, height)) {
+ MOZ_ASSERT(!mDefaultFB);
+ mRequestedSize = {width, height};
+ if (!EnsureDefaultFB()) {
failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_BACKBUFFER");
const nsLiteralCString text("Initializing WebGL backbuffer failed.");
ThrowEvent_WebGLContextCreationError(text);
return NS_ERROR_FAILURE;
}
if (GLContext::ShouldSpew()) {
printf_stderr("--- WebGL context created: %p\n", gl.get());
}
+ // Update our internal stuff:
+ mOptions.antialias = bool(mDefaultFB->mSamples);
+
+ if (!mOptions.alpha) {
+ // We always have alpha.
+ mNeedsFakeNoAlpha = true;
+ }
+
+ if (mOptions.depth || mOptions.stencil) {
+ // We always have depth+stencil if we have either.
+ if (!mOptions.depth) {
+ mNeedsFakeNoDepth = true;
+ }
+ if (!mOptions.stencil) {
+ mNeedsFakeNoStencil = true;
+ }
+ }
+
mResetLayer = true;
mOptionsFrozen = true;
- // Update our internal stuff:
- if (gl->WorkAroundDriverBugs()) {
- if (!mOptions.alpha && gl->Caps().alpha)
- mNeedsFakeNoAlpha = true;
-
- if (!mOptions.depth && gl->Caps().depth)
- mNeedsFakeNoDepth = true;
-
- if (!mOptions.stencil && gl->Caps().stencil)
- mNeedsFakeNoStencil = true;
-
-#ifdef MOZ_WIDGET_COCOA
- if (!nsCocoaFeatures::IsAtLeastVersion(10, 12) &&
- gl->Vendor() == GLVendor::Intel)
- {
- mNeedsEmulatedLoneDepthStencil = true;
- }
-#endif
- }
-
- // Update mOptions.
- if (!gl->Caps().depth)
- mOptions.depth = false;
-
- if (!gl->Caps().stencil)
- mOptions.stencil = false;
-
- mOptions.antialias = gl->Caps().antialias;
-
//////
// Initial setup.
gl->mImplicitMakeCurrent = true;
- gl->fViewport(0, 0, mWidth, mHeight);
+ const auto& size = mDefaultFB->mSize;
+
mViewportX = mViewportY = 0;
- mViewportWidth = mWidth;
- mViewportHeight = mHeight;
-
- gl->fScissor(0, 0, mWidth, mHeight);
- gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
+ mViewportWidth = size.width;
+ mViewportHeight = size.height;
+ gl->fViewport(mViewportX, mViewportY, mViewportWidth, mViewportHeight);
+
+ gl->fScissor(0, 0, size.width, size.height);
//////
// Check everything
AssertCachedBindings();
AssertCachedGlobalState();
- MOZ_ASSERT(gl->Caps().color);
-
- MOZ_ASSERT_IF(!mNeedsFakeNoAlpha, gl->Caps().alpha == mOptions.alpha);
- MOZ_ASSERT_IF(mNeedsFakeNoAlpha, !mOptions.alpha && gl->Caps().alpha);
-
- MOZ_ASSERT_IF(!mNeedsFakeNoDepth, gl->Caps().depth == mOptions.depth);
- MOZ_ASSERT_IF(mNeedsFakeNoDepth, !mOptions.depth && gl->Caps().depth);
-
- MOZ_ASSERT_IF(!mNeedsFakeNoStencil, gl->Caps().stencil == mOptions.stencil);
- MOZ_ASSERT_IF(mNeedsFakeNoStencil, !mOptions.stencil && gl->Caps().stencil);
-
- MOZ_ASSERT(gl->Caps().antialias == mOptions.antialias);
- MOZ_ASSERT(gl->Caps().preserve == mOptions.preserveDrawingBuffer);
-
- //////
- // Clear immediately, because we need to present the cleared initial buffer
- mBackbufferNeedsClear = true;
- ClearBackbufferIfNeeded();
-
mShouldPresent = true;
//////
reporter.SetSuccessful();
failureId = NS_LITERAL_CSTRING("SUCCESS");
gl->ResetSyncCallCount("WebGLContext Initialization");
return NS_OK;
}
void
-WebGLContext::ClearBackbufferIfNeeded()
-{
- if (!mBackbufferNeedsClear)
- return;
-
- ClearScreen();
-
- mBackbufferNeedsClear = false;
-}
-
-void
WebGLContext::LoseOldestWebGLContextIfLimitExceeded()
{
const auto maxWebGLContexts = gfxPrefs::WebGLMaxContexts();
auto maxWebGLContextsPerPrincipal = gfxPrefs::WebGLMaxContextsPerPrincipal();
// maxWebGLContextsPerPrincipal must be less than maxWebGLContexts
MOZ_ASSERT(maxWebGLContextsPerPrincipal <= maxWebGLContexts);
maxWebGLContextsPerPrincipal = std::min(maxWebGLContextsPerPrincipal, maxWebGLContexts);
@@ -1398,18 +1315,18 @@ WebGLContext::InitializeCanvasRenderer(n
// the invalidation state to indicate that the canvas is up to date.
data.mPreTransCallback = WebGLContextUserData::PreTransactionCallback;
data.mPreTransCallbackData = this;
data.mDidTransCallback = WebGLContextUserData::DidTransactionCallback;
data.mDidTransCallbackData = this;
}
data.mGLContext = gl;
- data.mSize = nsIntSize(mWidth, mHeight);
- data.mHasAlpha = gl->Caps().alpha;
+ data.mSize = DrawingBufferSize();
+ data.mHasAlpha = mOptions.alpha;
data.mIsGLAlphaPremult = IsPremultAlpha() || !data.mHasAlpha;
aRenderer->Initialize(data);
aRenderer->SetDirty();
return true;
}
layers::LayersBackend
@@ -1501,55 +1418,33 @@ WebGLContext::MozGetUnderlyingParamStrin
default:
return NS_ERROR_INVALID_ARG;
}
return NS_OK;
}
void
-WebGLContext::ClearScreen()
-{
- ScopedBindFramebuffer autoFB(gl, 0);
-
- const bool changeDrawBuffers = (mDefaultFB_DrawBuffer0 != LOCAL_GL_BACK);
- if (changeDrawBuffers) {
- gl->Screen()->SetDrawBuffer(LOCAL_GL_BACK);
- }
-
- GLbitfield bufferBits = LOCAL_GL_COLOR_BUFFER_BIT;
- if (mOptions.depth)
- bufferBits |= LOCAL_GL_DEPTH_BUFFER_BIT;
- if (mOptions.stencil)
- bufferBits |= LOCAL_GL_STENCIL_BUFFER_BIT;
-
- ForceClearFramebufferWithDefaultValues(bufferBits, mNeedsFakeNoAlpha);
-
- if (changeDrawBuffers) {
- gl->Screen()->SetDrawBuffer(mDefaultFB_DrawBuffer0);
- }
-}
-
-void
-WebGLContext::ForceClearFramebufferWithDefaultValues(GLbitfield clearBits,
- bool fakeNoAlpha)
+WebGLContext::ForceClearFramebufferWithDefaultValues(const GLbitfield clearBits,
+ const bool fakeNoAlpha) const
{
const bool initializeColorBuffer = bool(clearBits & LOCAL_GL_COLOR_BUFFER_BIT);
const bool initializeDepthBuffer = bool(clearBits & LOCAL_GL_DEPTH_BUFFER_BIT);
const bool initializeStencilBuffer = bool(clearBits & LOCAL_GL_STENCIL_BUFFER_BIT);
// Fun GL fact: No need to worry about the viewport here, glViewport is just
// setting up a coordinates transformation, it doesn't affect glClear at all.
AssertCachedGlobalState();
// Prepare GL state for clearing.
gl->fDisable(LOCAL_GL_SCISSOR_TEST);
if (initializeColorBuffer) {
gl->fColorMask(1, 1, 1, 1);
+ mDriverColorMask = 0x0f;
if (fakeNoAlpha) {
gl->fClearColor(0.0f, 0.0f, 0.0f, 1.0f);
} else {
gl->fClearColor(0.0f, 0.0f, 0.0f, 0.0f);
}
}
@@ -1578,20 +1473,16 @@ WebGLContext::ForceClearFramebufferWithD
gl->fEnable(LOCAL_GL_SCISSOR_TEST);
if (mRasterizerDiscardEnabled) {
gl->fEnable(LOCAL_GL_RASTERIZER_DISCARD);
}
// Restore GL state after clearing.
if (initializeColorBuffer) {
- gl->fColorMask(mColorWriteMask[0],
- mColorWriteMask[1],
- mColorWriteMask[2],
- mColorWriteMask[3]);
gl->fClearColor(mColorClearValue[0],
mColorClearValue[1],
mColorClearValue[2],
mColorClearValue[3]);
}
if (initializeDepthBuffer) {
gl->fDepthMask(mDepthWriteMask);
@@ -1611,41 +1502,91 @@ WebGLContext::OnEndOfFrame() const
if (gfxPrefs::WebGLSpewFrameAllocs()) {
GeneratePerfWarning("[webgl.perf.spew-frame-allocs] %" PRIu64 " data allocations this frame.",
mDataAllocGLCallCount);
}
mDataAllocGLCallCount = 0;
gl->ResetSyncCallCount("WebGLContext PresentScreenBuffer");
}
+void
+WebGLContext::BlitBackbufferToCurDriverFB() const
+{
+ if (mScissorTestEnabled) {
+ gl->fDisable(LOCAL_GL_SCISSOR_TEST);
+ }
+
+ [&]() {
+ const auto& size = mDefaultFB->mSize;
+
+ if (gl->IsSupported(GLFeature::framebuffer_blit)) {
+ gl->fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER, mDefaultFB->mFB);
+ 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(GLContext::APPLE_framebuffer_multisample))
+ {
+ gl->fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER, mDefaultFB->mFB);
+ gl->fResolveMultisampleFramebufferAPPLE();
+ return;
+ }
+
+ gl->BlitHelper()->DrawBlitTextureToFramebuffer(mDefaultFB->ColorTex(), size,
+ size);
+ }();
+
+ if (mScissorTestEnabled) {
+ gl->fEnable(LOCAL_GL_SCISSOR_TEST);
+ }
+}
+
// For an overview of how WebGL compositing works, see:
// https://wiki.mozilla.org/Platform/GFX/WebGL/Compositing
bool
WebGLContext::PresentScreenBuffer()
{
- if (IsContextLost()) {
+ if (IsContextLost())
+ return false;
+
+ if (!mShouldPresent)
+ return false;
+
+ if (!ValidateAndInitFB("Present", nullptr))
return false;
- }
-
- if (!mShouldPresent) {
+
+ const auto& screen = gl->Screen();
+ if (screen->Size() != mDefaultFB->mSize &&
+ !screen->Resize(mDefaultFB->mSize))
+ {
+ GenerateWarning("screen->Resize failed. Losing context.");
+ ForceLoseContext();
return false;
}
- MOZ_ASSERT(!mBackbufferNeedsClear);
-
- GLScreenBuffer* screen = gl->Screen();
- MOZ_ASSERT(screen);
+
+ gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
+ BlitBackbufferToCurDriverFB();
if (!screen->PublishFrame(screen->Size())) {
+ GenerateWarning("PublishFrame failed. Losing context.");
ForceLoseContext();
return false;
}
if (!mOptions.preserveDrawingBuffer) {
- mBackbufferNeedsClear = true;
+ if (gl->IsSupported(gl::GLFeature::invalidate_framebuffer)) {
+ gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mDefaultFB->mFB);
+ const GLenum attachments[] = { LOCAL_GL_COLOR_ATTACHMENT0 };
+ gl->fInvalidateFramebuffer(LOCAL_GL_FRAMEBUFFER, 1, attachments);
+ }
+ mDefaultFB_IsInvalid = true;
}
+ mResolvedDefaultFB = nullptr;
mShouldPresent = false;
OnEndOfFrame();
return true;
}
// Prepare the context for capture before compositing
@@ -1742,17 +1683,17 @@ CheckContextLost(GLContext* gl, bool* co
*out_isGuilty = isGuilty;
return true;
}
bool
WebGLContext::TryToRestoreContext()
{
- if (NS_FAILED(SetDimensions(mWidth, mHeight)))
+ if (NS_FAILED(SetDimensions(mRequestedSize.width, mRequestedSize.height)))
return false;
return true;
}
void
WebGLContext::RunContextLossTimer()
{
@@ -1954,41 +1895,28 @@ WebGLContext::ForceRestoreContext()
}
already_AddRefed<mozilla::gfx::SourceSurface>
WebGLContext::GetSurfaceSnapshot(gfxAlphaType* const out_alphaType)
{
if (!gl)
return nullptr;
+ if (!BindDefaultFBForRead("GetSurfaceSnapshot"))
+ return nullptr;
+
const auto surfFormat = mOptions.alpha ? SurfaceFormat::B8G8R8A8
: SurfaceFormat::B8G8R8X8;
+ const auto& size = mDefaultFB->mSize;
RefPtr<DataSourceSurface> surf;
- surf = Factory::CreateDataSourceSurfaceWithStride(IntSize(mWidth, mHeight),
- surfFormat,
- mWidth * 4);
+ surf = Factory::CreateDataSourceSurfaceWithStride(size, surfFormat, size.width * 4);
if (NS_WARN_IF(!surf))
return nullptr;
- {
- ScopedBindFramebuffer autoFB(gl, 0);
- ClearBackbufferIfNeeded();
-
- // Save, override, then restore glReadBuffer.
- const GLenum readBufferMode = gl->Screen()->GetReadBufferMode();
-
- if (readBufferMode != LOCAL_GL_BACK) {
- gl->Screen()->SetReadBuffer(LOCAL_GL_BACK);
- }
- ReadPixelsIntoDataSurface(gl, surf);
-
- if (readBufferMode != LOCAL_GL_BACK) {
- gl->Screen()->SetReadBuffer(readBufferMode);
- }
- }
+ ReadPixelsIntoDataSurface(gl, surf);
gfxAlphaType alphaType;
if (!mOptions.alpha) {
alphaType = gfxAlphaType::Opaque;
} else if (mOptions.premultipliedAlpha) {
alphaType = gfxAlphaType::Premult;
} else {
alphaType = gfxAlphaType::NonPremult;
@@ -2000,138 +1928,211 @@ WebGLContext::GetSurfaceSnapshot(gfxAlph
// Expects Opaque or Premult
if (alphaType == gfxAlphaType::NonPremult) {
gfxUtils::PremultiplyDataSurface(surf, surf);
}
}
RefPtr<DrawTarget> dt =
Factory::CreateDrawTarget(gfxPlatform::GetPlatform()->GetSoftwareBackend(),
- IntSize(mWidth, mHeight),
- SurfaceFormat::B8G8R8A8);
+ size, SurfaceFormat::B8G8R8A8);
if (!dt)
return nullptr;
- dt->SetTransform(Matrix::Translation(0.0, mHeight).PreScale(1.0, -1.0));
-
- dt->DrawSurface(surf,
- Rect(0, 0, mWidth, mHeight),
- Rect(0, 0, mWidth, mHeight),
- DrawSurfaceOptions(),
+ dt->SetTransform(Matrix::Translation(0.0, size.height).PreScale(1.0, -1.0));
+
+ const gfx::Rect rect{0, 0, float(size.width), float(size.height)};
+ dt->DrawSurface(surf, rect, rect, DrawSurfaceOptions(),
DrawOptions(1.0f, CompositionOp::OP_SOURCE));
return dt->Snapshot();
}
void
WebGLContext::DidRefresh()
{
if (gl) {
gl->FlushIfHeavyGLCallsSinceLastFlush();
}
}
+////////////////////////////////////////////////////////////////////////////////
+
+gfx::IntSize
+WebGLContext::DrawingBufferSize() const
+{
+ const gfx::IntSize zeros{0, 0};
+ if (IsContextLost())
+ return zeros;
+
+ if (!EnsureDefaultFB())
+ return zeros;
+
+ return mDefaultFB->mSize;
+}
+
bool
-WebGLContext::ValidateCurFBForRead(const char* funcName,
- const webgl::FormatUsageInfo** const out_format,
- uint32_t* const out_width, uint32_t* const out_height)
+WebGLContext::ValidateAndInitFB(const char* const funcName,
+ const WebGLFramebuffer* const fb)
+{
+ if (fb)
+ return fb->ValidateAndInitAttachments(funcName);
+
+ if (!EnsureDefaultFB()) {
+ GenerateWarning("%s: Lazy resize failed. Losing context.", funcName);
+ ForceLoseContext();
+ return false;
+ }
+
+ if (mDefaultFB_IsInvalid) {
+ gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mDefaultFB->mFB);
+ const GLbitfield bits = LOCAL_GL_COLOR_BUFFER_BIT |
+ LOCAL_GL_DEPTH_BUFFER_BIT |
+ LOCAL_GL_STENCIL_BUFFER_BIT;
+ const bool fakeNoAlpha = !mOptions.alpha;
+ ForceClearFramebufferWithDefaultValues(bits, fakeNoAlpha);
+ mDefaultFB_IsInvalid = false;
+ }
+ return true;
+}
+
+void
+WebGLContext::DoBindFB(const WebGLFramebuffer* const fb, const GLenum target) const
+{
+ const GLenum driverFB = fb ? fb->mGLName : mDefaultFB->mFB;
+ gl->fBindFramebuffer(target, driverFB);
+}
+
+bool
+WebGLContext::BindCurFBForDraw(const char* const funcName)
{
- if (!mBoundReadFramebuffer) {
- const GLenum readBufferMode = gl->Screen()->GetReadBufferMode();
- if (readBufferMode == LOCAL_GL_NONE) {
- ErrorInvalidOperation("%s: Can't read from backbuffer when readBuffer mode is"
- " NONE.",
- funcName);
+ const auto& fb = mBoundDrawFramebuffer;
+ if (!ValidateAndInitFB(funcName, fb))
+ return false;
+
+ DoBindFB(fb);
+ return true;
+}
+
+bool
+WebGLContext::BindCurFBForColorRead(const char* const funcName,
+ const webgl::FormatUsageInfo** const out_format,
+ uint32_t* const out_width,
+ uint32_t* const out_height)
+{
+ const auto& fb = mBoundReadFramebuffer;
+
+ if (fb) {
+ if (!ValidateAndInitFB(funcName, fb))
+ return false;
+ if (!fb->ValidateForColorRead(funcName, out_format, out_width, out_height))
+ return false;
+
+ gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, fb->mGLName);
+ return true;
+ }
+
+ if (!BindDefaultFBForRead(funcName))
+ return false;
+
+ if (mDefaultFB_ReadBuffer == LOCAL_GL_NONE) {
+ ErrorInvalidOperation("%s: Can't read from backbuffer when readBuffer mode is"
+ " NONE.",
+ funcName);
+ return false;
+ }
+
+ 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;
+}
+
+bool
+WebGLContext::BindDefaultFBForRead(const char* const funcName)
+{
+ if (!ValidateAndInitFB(funcName, nullptr))
+ return false;
+
+ if (!mDefaultFB->mSamples) {
+ gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mDefaultFB->mFB);
+ return true;
+ }
+
+ if (!mResolvedDefaultFB) {
+ mResolvedDefaultFB = MozFramebuffer::Create(gl, mDefaultFB->mSize, 0, false);
+ if (!mResolvedDefaultFB) {
+ gfxCriticalNote << funcName << ": Failed to create mResolvedDefaultFB.";
return false;
}
-
- ClearBackbufferIfNeeded();
-
- // FIXME - here we're assuming that the default framebuffer is backed by
- // UNSIGNED_BYTE that might not always be true, say if we had a 16bpp default
- // framebuffer.
- auto effFormat = mOptions.alpha ? webgl::EffectiveFormat::RGBA8
- : webgl::EffectiveFormat::RGB8;
-
- *out_format = mFormatUsage->GetUsage(effFormat);
- MOZ_ASSERT(*out_format);
-
- *out_width = mWidth;
- *out_height = mHeight;
- return true;
}
- return mBoundReadFramebuffer->ValidateForRead(funcName, out_format, out_width,
- out_height);
+ gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mResolvedDefaultFB->mFB);
+ BlitBackbufferToCurDriverFB();
+
+ gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mResolvedDefaultFB->mFB);
+ return true;
}
////////////////////////////////////////////////////////////////////////////////
-WebGLContext::ScopedDrawCallWrapper::ScopedDrawCallWrapper(WebGLContext& webgl)
+ScopedDrawCallWrapper::ScopedDrawCallWrapper(WebGLContext& webgl)
: mWebGL(webgl)
- , mFakeNoAlpha(ShouldFakeNoAlpha(webgl))
- , mFakeNoDepth(ShouldFakeNoDepth(webgl))
- , mFakeNoStencil(ShouldFakeNoStencil(webgl))
{
+ uint8_t driverColorMask = mWebGL.mColorWriteMask;
+ bool driverDepthTest = mWebGL.mDepthTestEnabled;
+ bool driverStencilTest = mWebGL.mStencilTestEnabled;
if (!mWebGL.mBoundDrawFramebuffer) {
- mWebGL.ClearBackbufferIfNeeded();
+ if (mWebGL.mDefaultFB_DrawBuffer0 == LOCAL_GL_NONE) {
+ driverColorMask = 0; // Is this well-optimized enough for depth-first
+ // rendering?
+ } else {
+ driverColorMask &= ~(uint8_t(mWebGL.mNeedsFakeNoAlpha) << 3);
+ }
+ driverDepthTest &= !mWebGL.mNeedsFakeNoDepth;
+ driverStencilTest &= !mWebGL.mNeedsFakeNoStencil;
}
- if (mFakeNoAlpha) {
- mWebGL.gl->fColorMask(mWebGL.mColorWriteMask[0],
- mWebGL.mColorWriteMask[1],
- mWebGL.mColorWriteMask[2],
- false);
+ const auto& gl = mWebGL.gl;
+ if (mWebGL.mDriverColorMask != driverColorMask) {
+ mWebGL.mDriverColorMask = driverColorMask;
+ gl->fColorMask(bool(mWebGL.mDriverColorMask & (1 << 0)),
+ bool(mWebGL.mDriverColorMask & (1 << 1)),
+ bool(mWebGL.mDriverColorMask & (1 << 2)),
+ bool(mWebGL.mDriverColorMask & (1 << 3)));
}
- if (mFakeNoDepth) {
- mWebGL.gl->fDisable(LOCAL_GL_DEPTH_TEST);
+ if (mWebGL.mDriverDepthTest != driverDepthTest) {
+ // "When disabled, the depth comparison and subsequent possible updates to the
+ // 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);
}
- if (mFakeNoStencil) {
- mWebGL.gl->fDisable(LOCAL_GL_STENCIL_TEST);
+ 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);
}
}
-WebGLContext::ScopedDrawCallWrapper::~ScopedDrawCallWrapper()
+ScopedDrawCallWrapper::~ScopedDrawCallWrapper()
{
- if (mFakeNoAlpha) {
- mWebGL.gl->fColorMask(mWebGL.mColorWriteMask[0],
- mWebGL.mColorWriteMask[1],
- mWebGL.mColorWriteMask[2],
- mWebGL.mColorWriteMask[3]);
- }
- if (mFakeNoDepth) {
- mWebGL.gl->fEnable(LOCAL_GL_DEPTH_TEST);
- }
- if (mFakeNoStencil) {
- MOZ_ASSERT(mWebGL.mStencilTestEnabled);
- mWebGL.gl->fEnable(LOCAL_GL_STENCIL_TEST);
- }
-
- if (!mWebGL.mBoundDrawFramebuffer) {
- mWebGL.Invalidate();
- mWebGL.mShouldPresent = true;
- }
-}
-
-/*static*/ bool
-WebGLContext::ScopedDrawCallWrapper::HasDepthButNoStencil(const WebGLFramebuffer* fb)
-{
- const auto& depth = fb->DepthAttachment();
- const auto& stencil = fb->StencilAttachment();
- return depth.IsDefined() && !stencil.IsDefined();
-}
-
-////
-
-void
-WebGLContext::OnBeforeReadCall()
-{
- if (!mBoundReadFramebuffer) {
- ClearBackbufferIfNeeded();
- }
+ if (mWebGL.mBoundDrawFramebuffer)
+ return;
+
+ mWebGL.mResolvedDefaultFB = nullptr;
+
+ mWebGL.Invalidate();
+ mWebGL.mShouldPresent = true;
}
////////////////////////////////////////
IndexedBufferBinding::IndexedBufferBinding()
: mRangeStart(0)
, mRangeSize(0)
{ }
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -62,16 +62,17 @@ class nsIDocShell;
#define LOCAL_GL_CONTEXT_LOST_WEBGL 0x9242
#define LOCAL_GL_MAX_CLIENT_WAIT_TIMEOUT_WEBGL 0x9247
#define LOCAL_GL_UNPACK_COLORSPACE_CONVERSION_WEBGL 0x9243
#define LOCAL_GL_UNPACK_FLIP_Y_WEBGL 0x9240
#define LOCAL_GL_UNPACK_PREMULTIPLY_ALPHA_WEBGL 0x9241
namespace mozilla {
class ScopedCopyTexImageSource;
+class ScopedDrawCallWrapper;
class ScopedResolveTexturesForDraw;
class ScopedUnpackReset;
class WebGLActiveInfo;
class WebGLBuffer;
class WebGLExtensionBase;
class WebGLFramebuffer;
class WebGLProgram;
class WebGLQuery;
@@ -93,16 +94,20 @@ struct WebGLContextAttributes;
template<typename> struct Nullable;
} // namespace dom
namespace gfx {
class SourceSurface;
class VRLayerChild;
} // namespace gfx
+namespace gl {
+class MozFramebuffer;
+} // namespace gl
+
namespace webgl {
struct LinkedProgramInfo;
class ShaderValidator;
class TexUnpackBlob;
struct UniformInfo;
struct UniformBlockInfo;
} // namespace webgl
@@ -268,19 +273,19 @@ struct TexImageSourceAdapter final : pub
////////////////////////////////////////////////////////////////////////////////
class WebGLContext
: public nsIDOMWebGLRenderingContext
, public nsICanvasRenderingContextInternal
, public nsSupportsWeakReference
, public WebGLContextUnchecked
- , public WebGLRectangleObject
, public nsWrapperCache
{
+ friend class ScopedDrawCallWrapper;
friend class ScopedDrawHelper;
friend class ScopedDrawWithTransformFeedback;
friend class ScopedFBRebinder;
friend class WebGL2Context;
friend class WebGLContextUserData;
friend class WebGLExtensionCompressedTextureASTC;
friend class WebGLExtensionCompressedTextureATC;
friend class WebGLExtensionCompressedTextureES3;
@@ -332,18 +337,18 @@ public:
virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override = 0;
NS_DECL_NSIDOMWEBGLRENDERINGCONTEXT
virtual void OnVisibilityChange() override;
virtual void OnMemoryPressure() override;
// nsICanvasRenderingContextInternal
- virtual int32_t GetWidth() const override;
- virtual int32_t GetHeight() const override;
+ virtual int32_t GetWidth() const override { return DrawingBufferWidth(); }
+ virtual int32_t GetHeight() const override { return DrawingBufferHeight(); }
NS_IMETHOD SetDimensions(int32_t width, int32_t height) override;
NS_IMETHOD InitializeWithDrawTarget(nsIDocShell*,
NotNull<gfx::DrawTarget*>) override
{
return NS_ERROR_NOT_IMPLEMENTED;
}
@@ -376,32 +381,32 @@ public:
* before it is destroyed.
*/
virtual void DidRefresh() override;
NS_IMETHOD Redraw(const gfxRect&) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
- void SynthesizeGLError(GLenum err);
- void SynthesizeGLError(GLenum err, const char* fmt, ...) MOZ_FORMAT_PRINTF(3, 4);
+ void SynthesizeGLError(GLenum err) const;
+ void SynthesizeGLError(GLenum err, const char* fmt, ...) const MOZ_FORMAT_PRINTF(3, 4);
- void ErrorInvalidEnum(const char* fmt = 0, ...) MOZ_FORMAT_PRINTF(2, 3);
- void ErrorInvalidOperation(const char* fmt = 0, ...) MOZ_FORMAT_PRINTF(2, 3);
- void ErrorInvalidValue(const char* fmt = 0, ...) MOZ_FORMAT_PRINTF(2, 3);
- void ErrorInvalidFramebufferOperation(const char* fmt = 0, ...) MOZ_FORMAT_PRINTF(2, 3);
- void ErrorInvalidEnumInfo(const char* info, GLenum enumValue);
+ void ErrorInvalidEnum(const char* fmt = 0, ...) const MOZ_FORMAT_PRINTF(2, 3);
+ void ErrorInvalidOperation(const char* fmt = 0, ...) const MOZ_FORMAT_PRINTF(2, 3);
+ void ErrorInvalidValue(const char* fmt = 0, ...) const MOZ_FORMAT_PRINTF(2, 3);
+ void ErrorInvalidFramebufferOperation(const char* fmt = 0, ...) const MOZ_FORMAT_PRINTF(2, 3);
+ void ErrorInvalidEnumInfo(const char* info, GLenum enumValue) const;
void ErrorInvalidEnumInfo(const char* info, const char* funcName,
- GLenum enumValue);
- void ErrorOutOfMemory(const char* fmt = 0, ...) MOZ_FORMAT_PRINTF(2, 3);
- void ErrorImplementationBug(const char* fmt = 0, ...) MOZ_FORMAT_PRINTF(2, 3);
+ GLenum enumValue) const;
+ void ErrorOutOfMemory(const char* fmt = 0, ...) const MOZ_FORMAT_PRINTF(2, 3);
+ void ErrorImplementationBug(const char* fmt = 0, ...) const MOZ_FORMAT_PRINTF(2, 3);
- void ErrorInvalidEnumArg(const char* funcName, const char* argName, GLenum val);
+ void ErrorInvalidEnumArg(const char* funcName, const char* argName, GLenum val) const;
- const char* ErrorName(GLenum error);
+ static const char* ErrorName(GLenum error);
/**
* Return displayable name for GLenum.
* This version is like gl::GLenumToStr but with out the GL_ prefix to
* keep consistency with how errors are reported from WebGL.
* Returns hex formatted version of glenum if glenum is unknown.
*/
static void EnumName(GLenum val, nsCString* out_name);
@@ -472,41 +477,39 @@ public:
// a number that increments every time we have an event that causes
// all context resources to be lost.
uint32_t Generation() const { return mGeneration.value(); }
// This is similar to GLContext::ClearSafely, but tries to minimize the
// amount of work it does.
// It only clears the buffers we specify, and can reset its state without
// first having to query anything, as WebGL knows its state at all times.
- void ForceClearFramebufferWithDefaultValues(GLbitfield bufferBits, bool fakeNoAlpha);
-
- // Calls ForceClearFramebufferWithDefaultValues() for the Context's 'screen'.
- void ClearScreen();
- void ClearBackbufferIfNeeded();
+ void ForceClearFramebufferWithDefaultValues(GLbitfield bufferBits,
+ bool fakeNoAlpha) const;
void RunContextLossTimer();
void UpdateContextLossStatus();
void EnqueueUpdateContextLossStatus();
bool TryToRestoreContext();
- void AssertCachedBindings();
- void AssertCachedGlobalState();
+ void AssertCachedBindings() const;
+ void AssertCachedGlobalState() const;
dom::HTMLCanvasElement* GetCanvas() const { return mCanvasElement; }
nsIDocument* GetOwnerDoc() const;
// WebIDL WebGLRenderingContext API
void Commit();
void GetCanvas(Nullable<dom::OwningHTMLCanvasElementOrOffscreenCanvas>& retval);
- GLsizei DrawingBufferWidth() const { return IsContextLost() ? 0 : mWidth; }
- GLsizei DrawingBufferHeight() const {
- return IsContextLost() ? 0 : mHeight;
- }
+private:
+ gfx::IntSize DrawingBufferSize() const;
+public:
+ GLsizei DrawingBufferWidth() const { return DrawingBufferSize().width; }
+ GLsizei DrawingBufferHeight() const { return DrawingBufferSize().height; }
layers::LayersBackend GetCompositorBackendType() const;
void
GetContextAttributes(dom::Nullable<dom::WebGLContextAttributes>& retval);
bool IsContextLost() const { return mContextStatus != ContextNotLost; }
void GetSupportedExtensions(dom::Nullable< nsTArray<nsString> >& retval,
@@ -981,17 +984,17 @@ public:
JS::MutableHandleValue retval, const char* funcName = nullptr);
// -----------------------------------------------------------------------------
// State and State Requests (WebGLContextState.cpp)
public:
void Disable(GLenum cap);
void Enable(GLenum cap);
- bool GetStencilBits(GLint* const out_stencilBits);
+ bool GetStencilBits(GLint* const out_stencilBits) const;
bool GetChannelBits(const char* funcName, GLenum pname, GLint* const out_val);
virtual JS::Value GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv);
void GetParameter(JSContext* cx, GLenum pname,
JS::MutableHandle<JS::Value> retval, ErrorResult& rv)
{
retval.set(GetParameter(cx, pname, rv));
}
@@ -1438,30 +1441,30 @@ protected:
bool mResetLayer;
bool mOptionsFrozen;
bool mDisableExtensions;
bool mIsMesa;
bool mLoseContextOnMemoryPressure;
bool mCanLoseContextInForeground;
bool mRestoreWhenVisible;
bool mShouldPresent;
- bool mBackbufferNeedsClear;
bool mDisableFragHighP;
template<typename WebGLObjectType>
void DeleteWebGLObjectsArray(nsTArray<WebGLObjectType>& array);
GLuint mActiveTexture;
GLenum mDefaultFB_DrawBuffer0;
+ GLenum mDefaultFB_ReadBuffer;
// glGetError sources:
bool mEmitContextLostErrorOnce;
- GLenum mWebGLError;
- GLenum mUnderlyingGLError;
- GLenum GetAndFlushUnderlyingGLErrors();
+ mutable GLenum mWebGLError;
+ mutable GLenum mUnderlyingGLError;
+ GLenum GetAndFlushUnderlyingGLErrors() const;
bool mBypassShaderValidation;
webgl::ShaderValidator* CreateShaderValidator(GLenum shaderType) const;
// some GL constants
uint32_t mGLMaxTextureUnits;
@@ -1580,18 +1583,16 @@ public:
{ }
};
protected:
bool InitWebGL2(FailureReason* const out_failReason);
bool CreateAndInitGL(bool forceEnabled,
std::vector<FailureReason>* const out_failReasons);
- bool ResizeBackbuffer(uint32_t width, uint32_t height);
-
typedef already_AddRefed<gl::GLContext> FnCreateGL_T(const gl::SurfaceCaps& caps,
gl::CreateContextFlags flags,
WebGLContext* webgl,
std::vector<FailureReason>* const out_failReasons);
bool CreateAndInitGLWith(FnCreateGL_T fnCreateGL, const gl::SurfaceCaps& baseCaps,
gl::CreateContextFlags flags,
std::vector<FailureReason>* const out_failReasons);
@@ -1657,20 +1658,16 @@ protected:
uint32_t byteLength,
WebGLTexImageFunc func,
WebGLTexDimensions dims);
bool ValidateUniformLocationForProgram(WebGLUniformLocation* location,
WebGLProgram* program,
const char* funcName);
- bool ValidateCurFBForRead(const char* funcName,
- const webgl::FormatUsageInfo** const out_format,
- uint32_t* const out_width, uint32_t* const out_height);
-
bool HasDrawBuffers() const {
return IsWebGL2() ||
IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers);
}
WebGLRefPtr<WebGLBuffer>* ValidateBufferSlot(const char* funcName, GLenum target);
public:
WebGLBuffer* ValidateBufferSelection(const char* funcName, GLenum target);
@@ -1933,17 +1930,17 @@ protected:
JSObject* GetVertexAttribUint32Array(JSContext* cx, GLuint index);
GLint mStencilRefFront;
GLint mStencilRefBack;
GLuint mStencilValueMaskFront;
GLuint mStencilValueMaskBack;
GLuint mStencilWriteMaskFront;
GLuint mStencilWriteMaskBack;
- realGLboolean mColorWriteMask[4];
+ uint8_t mColorWriteMask; // bitmask
realGLboolean mDepthWriteMask;
GLfloat mColorClearValue[4];
GLint mStencilClearValue;
GLfloat mDepthClearValue;
GLint mViewportX;
GLint mViewportY;
GLsizei mViewportWidth;
@@ -1957,96 +1954,66 @@ protected:
bool mLastLossWasSimulated;
ContextStatus mContextStatus;
bool mContextLostErrorSet;
// Used for some hardware (particularly Tegra 2 and 4) that likes to
// be Flushed while doing hundreds of draw calls.
int mDrawCallsSinceLastFlush;
- int mAlreadyGeneratedWarnings;
+ mutable int mAlreadyGeneratedWarnings;
int mMaxWarnings;
bool mAlreadyWarnedAboutFakeVertexAttrib0;
bool ShouldGenerateWarnings() const;
bool ShouldGeneratePerfWarnings() const {
return mNumPerfWarnings < mMaxPerfWarnings;
}
uint64_t mLastUseIndex;
bool mNeedsFakeNoAlpha;
bool mNeedsFakeNoDepth;
bool mNeedsFakeNoStencil;
- bool mNeedsEmulatedLoneDepthStencil;
+
+ mutable uint8_t mDriverColorMask;
+ bool mDriverDepthTest;
+ bool mDriverStencilTest;
bool mNeedsIndexValidation;
const bool mAllowFBInvalidation;
bool Has64BitTimestamps() const;
- struct ScopedDrawCallWrapper final {
- WebGLContext& mWebGL;
- const bool mFakeNoAlpha;
- const bool mFakeNoDepth;
- const bool mFakeNoStencil;
+ // --
- static bool ShouldFakeNoAlpha(WebGLContext& webgl) {
- // We should only be doing this if we're about to draw to the backbuffer, but
- // the backbuffer needs to have this fake-no-alpha workaround.
- return !webgl.mBoundDrawFramebuffer &&
- webgl.mNeedsFakeNoAlpha &&
- webgl.mColorWriteMask[3] != false;
- }
+ const uint8_t mMsaaSamples;
+ gfx::IntSize mRequestedSize;
+ mutable UniquePtr<gl::MozFramebuffer> mDefaultFB;
+ mutable bool mDefaultFB_IsInvalid;
+ mutable UniquePtr<gl::MozFramebuffer> mResolvedDefaultFB;
- static bool ShouldFakeNoDepth(WebGLContext& webgl) {
- // We should only be doing this if we're about to draw to the backbuffer.
- return !webgl.mBoundDrawFramebuffer &&
- webgl.mNeedsFakeNoDepth &&
- webgl.mDepthTestEnabled;
- }
-
- static bool HasDepthButNoStencil(const WebGLFramebuffer* fb);
-
- static bool ShouldFakeNoStencil(WebGLContext& webgl) {
- if (!webgl.mStencilTestEnabled)
- return false;
+ // --
- if (!webgl.mBoundDrawFramebuffer) {
- if (webgl.mNeedsFakeNoStencil)
- return true;
-
- if (webgl.mNeedsEmulatedLoneDepthStencil &&
- webgl.mOptions.depth && !webgl.mOptions.stencil)
- {
- return true;
- }
-
- return false;
- }
+ bool EnsureDefaultFB() const;
+ bool ValidateAndInitFB(const char* funcName, const WebGLFramebuffer* fb);
+ void DoBindFB(const WebGLFramebuffer* fb, GLenum target = LOCAL_GL_FRAMEBUFFER) const;
- if (webgl.mNeedsEmulatedLoneDepthStencil &&
- HasDepthButNoStencil(webgl.mBoundDrawFramebuffer))
- {
- return true;
- }
-
- return false;
- }
+ bool BindCurFBForDraw(const char* funcName);
+ bool BindCurFBForColorRead(const char* funcName,
+ const webgl::FormatUsageInfo** out_format,
+ uint32_t* out_width, uint32_t* out_height);
+ void BlitBackbufferToCurDriverFB() const;
+ bool BindDefaultFBForRead(const char* funcName);
- ////
+ // --
- explicit ScopedDrawCallWrapper(WebGLContext& webgl);
- ~ScopedDrawCallWrapper();
- };
-
- void OnBeforeReadCall();
-
+public:
void LoseOldestWebGLContextIfLimitExceeded();
void UpdateLastUseIndex();
template <typename WebGLObjectType>
JS::Value WebGLObjectAsJSValue(JSContext* cx, const WebGLObjectType*,
ErrorResult& rv) const;
template <typename WebGLObjectType>
JSObject* WebGLObjectAsJSObject(JSContext* cx, const WebGLObjectType*,
@@ -2058,18 +2025,18 @@ protected:
// these objects at high frequency. Having WebGLContext's hold one such object seems fine,
// because WebGLContext objects only go away during GC, which shouldn't happen too frequently.
// If in the future GC becomes much more frequent, we may have to revisit then (maybe use a timer).
ForceDiscreteGPUHelperCGL mForceDiscreteGPUHelper;
#endif
public:
// console logging helpers
- void GenerateWarning(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3);
- void GenerateWarning(const char* fmt, va_list ap) MOZ_FORMAT_PRINTF(2, 0);
+ void GenerateWarning(const char* fmt, ...) const MOZ_FORMAT_PRINTF(2, 3);
+ void GenerateWarning(const char* fmt, va_list ap) const MOZ_FORMAT_PRINTF(2, 0);
void GeneratePerfWarning(const char* fmt, ...) const MOZ_FORMAT_PRINTF(2, 3);
public:
UniquePtr<webgl::FormatUsageAuthority> mFormatUsage;
virtual UniquePtr<webgl::FormatUsageAuthority>
CreateFormatUsage(gl::GLContext* gl) const = 0;
@@ -2185,16 +2152,27 @@ Intersect(int32_t srcSize, int32_t read0
int32_t* out_intWrite0, int32_t* out_intSize);
uint64_t
AvailGroups(uint64_t totalAvailItems, uint64_t firstItemOffset, uint32_t groupSize,
uint32_t groupStride);
////
+class ScopedDrawCallWrapper final
+{
+public:
+ WebGLContext& mWebGL;
+
+ explicit ScopedDrawCallWrapper(WebGLContext& webgl);
+ ~ScopedDrawCallWrapper();
+};
+
+////
+
void
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& callback,
const std::vector<IndexedBufferBinding>& field,
const char* name, uint32_t flags = 0);
void
ImplCycleCollectionUnlink(std::vector<IndexedBufferBinding>& field);
--- a/dom/canvas/WebGLContextDraw.cpp
+++ b/dom/canvas/WebGLContextDraw.cpp
@@ -1,16 +1,17 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
#include "WebGLContext.h"
#include "GeckoProfiler.h"
+#include "gfx/gl/MozFramebuffer.h"
#include "GLContext.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/UniquePtrExtensions.h"
#include "nsPrintfCString.h"
#include "WebGLBuffer.h"
#include "WebGLContextUtils.h"
#include "WebGLFramebuffer.h"
#include "WebGLProgram.h"
@@ -94,33 +95,20 @@ WebGLTexture::IsFeedback(WebGLContext* w
ScopedResolveTexturesForDraw::ScopedResolveTexturesForDraw(WebGLContext* webgl,
const char* funcName,
bool* const out_error)
: mWebGL(webgl)
{
MOZ_ASSERT(mWebGL->gl->IsCurrent());
- if (!mWebGL->mActiveProgramLinkInfo) {
- mWebGL->ErrorInvalidOperation("%s: The current program is not linked.", funcName);
- *out_error = true;
- return;
- }
-
const std::vector<const WebGLFBAttachPoint*>* attachList = nullptr;
const auto& fb = mWebGL->mBoundDrawFramebuffer;
if (fb) {
- if (!fb->ValidateAndInitAttachments(funcName)) {
- *out_error = true;
- return;
- }
-
attachList = &(fb->ResolvedCompleteData()->texDrawBuffers);
- } else {
- webgl->ClearBackbufferIfNeeded();
}
MOZ_ASSERT(mWebGL->mActiveProgramLinkInfo);
const auto& uniformSamplers = mWebGL->mActiveProgramLinkInfo->uniformSamplers;
for (const auto& uniform : uniformSamplers) {
const auto& texList = *(uniform->mSamplerTexList);
for (const auto& texUnit : uniform->mSamplerValues) {
@@ -250,42 +238,41 @@ public:
ScopedDrawHelper(WebGLContext* const webgl, const char* const funcName,
const GLenum mode, const Maybe<uint32_t>& lastRequiredVertex,
const uint32_t instanceCount, bool* const out_error)
: mWebGL(webgl)
, mDidFake(false)
{
MOZ_ASSERT(mWebGL->gl->IsCurrent());
+ if (!mWebGL->BindCurFBForDraw(funcName)) {
+ *out_error = true;
+ return;
+ }
+
if (!mWebGL->ValidateDrawModeEnum(mode, funcName)) {
*out_error = true;
return;
}
if (!mWebGL->ValidateStencilParamsForDrawCall()) {
*out_error = true;
return;
}
- ////
-
- if (mWebGL->mBoundDrawFramebuffer) {
- if (!mWebGL->mBoundDrawFramebuffer->ValidateAndInitAttachments(funcName)) {
- *out_error = true;
- return;
- }
- } else {
- mWebGL->ClearBackbufferIfNeeded();
+ if (!mWebGL->mActiveProgramLinkInfo) {
+ mWebGL->ErrorInvalidOperation("%s: The current program is not linked.", funcName);
+ *out_error = true;
+ return;
}
+ const auto& linkInfo = mWebGL->mActiveProgramLinkInfo;
////
// Check UBO sizes.
- const auto& linkInfo = mWebGL->mActiveProgramLinkInfo;
-
for (const auto& cur : linkInfo->uniformBlocks) {
const auto& dataSize = cur->mDataSize;
const auto& binding = cur->mBinding;
if (!binding) {
mWebGL->ErrorInvalidOperation("%s: Buffer for uniform block is null.",
funcName);
*out_error = true;
return;
@@ -520,30 +507,30 @@ WebGLContext::DrawArrays_check(const cha
void
WebGLContext::DrawArraysInstanced(GLenum mode, GLint first, GLsizei vertCount,
GLsizei instanceCount, const char* const funcName)
{
AUTO_PROFILER_LABEL("WebGLContext::DrawArraysInstanced", GRAPHICS);
if (IsContextLost())
return;
- bool error = false;
- ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
- if (error)
- return;
-
Maybe<uint32_t> lastVert;
if (!DrawArrays_check(funcName, first, vertCount, instanceCount, &lastVert))
return;
+ bool error = false;
const ScopedDrawHelper scopedHelper(this, funcName, mode, lastVert, instanceCount,
&error);
if (error)
return;
+ const ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
+ if (error)
+ return;
+
const ScopedDrawWithTransformFeedback scopedTF(this, funcName, mode, vertCount,
instanceCount, &error);
if (error)
return;
{
ScopedDrawCallWrapper wrapper(*this);
if (vertCount && instanceCount) {
@@ -676,33 +663,33 @@ void
WebGLContext::DrawElementsInstanced(GLenum mode, GLsizei indexCount, GLenum type,
WebGLintptr byteOffset, GLsizei instanceCount,
const char* const funcName)
{
AUTO_PROFILER_LABEL("WebGLContext::DrawElementsInstanced", GRAPHICS);
if (IsContextLost())
return;
- bool error = false;
- ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
- if (error)
- return;
-
Maybe<uint32_t> lastVert;
if (!DrawElements_check(funcName, indexCount, type, byteOffset, instanceCount,
&lastVert))
{
return;
}
+ bool error = false;
const ScopedDrawHelper scopedHelper(this, funcName, mode, lastVert, instanceCount,
&error);
if (error)
return;
+ const ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
+ if (error)
+ return;
+
{
ScopedDrawCallWrapper wrapper(*this);
{
UniquePtr<gl::GLContext::LocalErrorScope> errorScope;
if (gl->IsANGLE()) {
errorScope.reset(new gl::GLContext::LocalErrorScope(*gl));
}
@@ -754,18 +741,18 @@ WebGLContext::Draw_cleanup(const char* f
const auto& drawBuffers = mBoundDrawFramebuffer->ColorDrawBuffers();
for (const auto& cur : drawBuffers) {
if (!cur->IsDefined())
continue;
cur->Size(&destWidth, &destHeight);
break;
}
} else {
- destWidth = mWidth;
- destHeight = mHeight;
+ destWidth = mDefaultFB->mSize.width;
+ destHeight = mDefaultFB->mSize.height;
}
if (mViewportWidth > int32_t(destWidth) ||
mViewportHeight > int32_t(destHeight))
{
if (!mAlreadyWarnedAboutViewportLargerThanDest) {
GenerateWarning("%s: Drawing to a destination rect smaller than the viewport"
" rect. (This warning will only be given once)",
--- a/dom/canvas/WebGLContextFramebufferOperations.cpp
+++ b/dom/canvas/WebGLContextFramebufferOperations.cpp
@@ -25,20 +25,17 @@ WebGLContext::Clear(GLbitfield mask)
return ErrorInvalidValue("%s: invalid mask bits", funcName);
if (mask == 0) {
GenerateWarning("Calling gl.clear(0) has no effect.");
} else if (mRasterizerDiscardEnabled) {
GenerateWarning("Calling gl.clear() with RASTERIZER_DISCARD enabled has no effects.");
}
- if (mBoundDrawFramebuffer) {
- if (!mBoundDrawFramebuffer->ValidateAndInitAttachments(funcName))
- return;
-
+ if (mask & LOCAL_GL_COLOR_BUFFER_BIT && mBoundDrawFramebuffer) {
if (mask & LOCAL_GL_COLOR_BUFFER_BIT) {
for (const auto& cur : mBoundDrawFramebuffer->ColorDrawBuffers()) {
if (!cur->IsDefined())
continue;
switch (cur->Format()->format->componentType) {
case webgl::ComponentType::Float:
case webgl::ComponentType::NormInt:
@@ -50,18 +47,31 @@ WebGLContext::Clear(GLbitfield mask)
" or fixed-point. (normalized (u)ints)",
funcName);
return;
}
}
}
}
- ScopedDrawCallWrapper wrapper(*this);
- gl->fClear(mask);
+ if (!BindCurFBForDraw(funcName))
+ return;
+
+ auto driverMask = mask;
+ if (!mBoundDrawFramebuffer) {
+ if (mNeedsFakeNoDepth) {
+ driverMask &= ~LOCAL_GL_DEPTH_BUFFER_BIT;
+ }
+ if (mNeedsFakeNoStencil) {
+ driverMask &= ~LOCAL_GL_STENCIL_BUFFER_BIT;
+ }
+ }
+
+ const ScopedDrawCallWrapper wrapper(*this);
+ gl->fClear(driverMask);
}
static GLfloat
GLClampFloat(GLfloat val)
{
if (val < 0.0)
return 0.0;
@@ -116,21 +126,21 @@ WebGLContext::ClearStencil(GLint v)
}
void
WebGLContext::ColorMask(WebGLboolean r, WebGLboolean g, WebGLboolean b, WebGLboolean a)
{
if (IsContextLost())
return;
- mColorWriteMask[0] = r;
- mColorWriteMask[1] = g;
- mColorWriteMask[2] = b;
- mColorWriteMask[3] = a;
gl->fColorMask(r, g, b, a);
+ mColorWriteMask = uint8_t(bool(r)) << 0 |
+ uint8_t(bool(g)) << 1 |
+ uint8_t(bool(b)) << 2 |
+ uint8_t(bool(a)) << 3;
}
void
WebGLContext::DepthMask(WebGLboolean b)
{
if (IsContextLost())
return;
@@ -170,17 +180,17 @@ WebGLContext::DrawBuffers(const dom::Seq
default:
ErrorInvalidOperation("%s: For the default framebuffer, `buffers[0]` must be"
" BACK or NONE.",
funcName);
return;
}
mDefaultFB_DrawBuffer0 = buffers[0];
- gl->Screen()->SetDrawBuffer(buffers[0]);
+ // Don't actually set it.
}
void
WebGLContext::StencilMask(GLuint mask)
{
if (IsContextLost())
return;
--- a/dom/canvas/WebGLContextGL.cpp
+++ b/dom/canvas/WebGLContextGL.cpp
@@ -1556,17 +1556,17 @@ WebGLContext::ReadPixelsImpl(GLint x, GL
const uint32_t width(rawWidth);
const uint32_t height(rawHeight);
//////
const webgl::FormatUsageInfo* srcFormat;
uint32_t srcWidth;
uint32_t srcHeight;
- if (!ValidateCurFBForRead("readPixels", &srcFormat, &srcWidth, &srcHeight))
+ if (!BindCurFBForColorRead("readPixels", &srcFormat, &srcWidth, &srcHeight))
return;
//////
const webgl::PackingInfo pi = {packFormat, packType};
if (!ValidateReadPixelsFormatAndType(srcFormat, pi, gl, this))
return;
@@ -1601,18 +1601,16 @@ WebGLContext::ReadPixelsImpl(GLint x, GL
{
ErrorOutOfMemory("readPixels: Bad subrect selection.");
return;
}
////////////////
// Now that the errors are out of the way, on to actually reading!
- OnBeforeReadCall();
-
if (!rwWidth || !rwHeight) {
// Disjoint rects, so we're done already.
DummyReadFramebufferOperation("readPixels");
return;
}
if (uint32_t(rwWidth) == width &&
uint32_t(rwHeight) == height)
--- a/dom/canvas/WebGLContextState.cpp
+++ b/dom/canvas/WebGLContextState.cpp
@@ -55,17 +55,17 @@ WebGLContext::Enable(GLenum cap)
{
*trackingSlot = 1;
}
gl->fEnable(cap);
}
bool
-WebGLContext::GetStencilBits(GLint* const out_stencilBits)
+WebGLContext::GetStencilBits(GLint* const out_stencilBits) const
{
*out_stencilBits = 0;
if (mBoundDrawFramebuffer) {
if (mBoundDrawFramebuffer->StencilAttachment().IsDefined() &&
mBoundDrawFramebuffer->DepthStencilAttachment().IsDefined())
{
// Error, we don't know which stencil buffer's bits to use
ErrorInvalidFramebufferOperation("getParameter: framebuffer has two stencil buffers bound");
@@ -185,17 +185,17 @@ WebGLContext::GetParameter(JSContext* cx
return JS::Int32Value(mGLMaxDrawBuffers);
} else if (pname >= LOCAL_GL_DRAW_BUFFER0 &&
pname < GLenum(LOCAL_GL_DRAW_BUFFER0 + mGLMaxDrawBuffers))
{
GLint ret = LOCAL_GL_NONE;
if (!mBoundDrawFramebuffer) {
if (pname == LOCAL_GL_DRAW_BUFFER0) {
- ret = gl->Screen()->GetDrawBufferMode();
+ ret = mDefaultFB_DrawBuffer0;
}
} else {
gl->fGetIntegerv(pname, &ret);
}
return JS::Int32Value(ret);
}
}
@@ -337,17 +337,17 @@ WebGLContext::GetParameter(JSContext* cx
case LOCAL_GL_GENERATE_MIPMAP_HINT:
return JS::NumberValue(mGenerateMipmapHint);
case LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT:
case LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE: {
const webgl::FormatUsageInfo* usage;
uint32_t width, height;
- if (!ValidateCurFBForRead(funcName, &usage, &width, &height))
+ if (!BindCurFBForColorRead(funcName, &usage, &width, &height))
return JS::NullValue();
const auto implPI = ValidImplementationColorReadPI(usage);
GLenum ret;
if (pname == LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT) {
ret = implPI.format;
} else {
--- a/dom/canvas/WebGLContextUtils.cpp
+++ b/dom/canvas/WebGLContextUtils.cpp
@@ -51,28 +51,28 @@ StringValue(JSContext* cx, const char* c
rv.Throw(NS_ERROR_OUT_OF_MEMORY);
return JS::NullValue();
}
return JS::StringValue(str);
}
void
-WebGLContext::GenerateWarning(const char* fmt, ...)
+WebGLContext::GenerateWarning(const char* fmt, ...) const
{
va_list ap;
va_start(ap, fmt);
GenerateWarning(fmt, ap);
va_end(ap);
}
void
-WebGLContext::GenerateWarning(const char* fmt, va_list ap)
+WebGLContext::GenerateWarning(const char* fmt, va_list ap) const
{
if (!ShouldGenerateWarnings())
return;
mAlreadyGeneratedWarnings++;
char buf[1024];
VsprintfLiteral(buf, fmt, ap);
@@ -141,131 +141,131 @@ WebGLContext::GeneratePerfWarning(const
JS_ReportWarningASCII(cx,
"WebGL: After reporting %u, no further perf warnings will"
" be reported for this WebGL context.",
uint32_t(mNumPerfWarnings));
}
}
void
-WebGLContext::SynthesizeGLError(GLenum err)
+WebGLContext::SynthesizeGLError(GLenum err) const
{
/* 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;
}
void
-WebGLContext::SynthesizeGLError(GLenum err, const char* fmt, ...)
+WebGLContext::SynthesizeGLError(GLenum err, const char* fmt, ...) const
{
va_list va;
va_start(va, fmt);
GenerateWarning(fmt, va);
va_end(va);
return SynthesizeGLError(err);
}
void
-WebGLContext::ErrorInvalidEnum(const char* fmt, ...)
+WebGLContext::ErrorInvalidEnum(const char* fmt, ...) const
{
va_list va;
va_start(va, fmt);
GenerateWarning(fmt, va);
va_end(va);
return SynthesizeGLError(LOCAL_GL_INVALID_ENUM);
}
void
-WebGLContext::ErrorInvalidEnumInfo(const char* info, GLenum enumValue)
+WebGLContext::ErrorInvalidEnumInfo(const char* info, GLenum enumValue) const
{
nsCString name;
EnumName(enumValue, &name);
return ErrorInvalidEnum("%s: invalid enum value %s", info, name.BeginReading());
}
void
WebGLContext::ErrorInvalidEnumInfo(const char* info, const char* funcName,
- GLenum enumValue)
+ GLenum enumValue) const
{
nsCString name;
EnumName(enumValue, &name);
ErrorInvalidEnum("%s: %s: Invalid enum: 0x%04x (%s).", funcName, info,
enumValue, name.BeginReading());
}
void
-WebGLContext::ErrorInvalidOperation(const char* fmt, ...)
+WebGLContext::ErrorInvalidOperation(const char* fmt, ...) const
{
va_list va;
va_start(va, fmt);
GenerateWarning(fmt, va);
va_end(va);
return SynthesizeGLError(LOCAL_GL_INVALID_OPERATION);
}
void
-WebGLContext::ErrorInvalidValue(const char* fmt, ...)
+WebGLContext::ErrorInvalidValue(const char* fmt, ...) const
{
va_list va;
va_start(va, fmt);
GenerateWarning(fmt, va);
va_end(va);
return SynthesizeGLError(LOCAL_GL_INVALID_VALUE);
}
void
-WebGLContext::ErrorInvalidFramebufferOperation(const char* fmt, ...)
+WebGLContext::ErrorInvalidFramebufferOperation(const char* fmt, ...) const
{
va_list va;
va_start(va, fmt);
GenerateWarning(fmt, va);
va_end(va);
return SynthesizeGLError(LOCAL_GL_INVALID_FRAMEBUFFER_OPERATION);
}
void
-WebGLContext::ErrorOutOfMemory(const char* fmt, ...)
+WebGLContext::ErrorOutOfMemory(const char* fmt, ...) const
{
va_list va;
va_start(va, fmt);
GenerateWarning(fmt, va);
va_end(va);
return SynthesizeGLError(LOCAL_GL_OUT_OF_MEMORY);
}
void
-WebGLContext::ErrorImplementationBug(const char* fmt, ...)
+WebGLContext::ErrorImplementationBug(const char* fmt, ...) const
{
const nsPrintfCString warning("Implementation bug, please file at %s! %s",
"https://bugzilla.mozilla.org/", fmt);
va_list va;
va_start(va, fmt);
GenerateWarning(warning.BeginReading(), va);
va_end(va);
MOZ_ASSERT(false, "WebGLContext::ErrorImplementationBug");
NS_ERROR("WebGLContext::ErrorImplementationBug");
return SynthesizeGLError(LOCAL_GL_OUT_OF_MEMORY);
}
-const char*
+/*static*/ const char*
WebGLContext::ErrorName(GLenum error)
{
switch(error) {
case LOCAL_GL_INVALID_ENUM:
return "INVALID_ENUM";
case LOCAL_GL_INVALID_OPERATION:
return "INVALID_OPERATION";
case LOCAL_GL_INVALID_VALUE:
@@ -620,17 +620,18 @@ WebGLContext::EnumName(GLenum val, nsCSt
*out_name = name;
return;
}
*out_name = nsPrintfCString("<enum 0x%04x>", val);
}
void
-WebGLContext::ErrorInvalidEnumArg(const char* funcName, const char* argName, GLenum val)
+WebGLContext::ErrorInvalidEnumArg(const char* funcName, const char* argName,
+ GLenum val) const
{
nsCString enumName;
EnumName(val, &enumName);
ErrorInvalidEnum("%s: Bad `%s`: %s", funcName, argName, enumName.BeginReading());
}
bool
IsCompressedTextureFormat(GLenum format)
@@ -671,17 +672,17 @@ IsCompressedTextureFormat(GLenum format)
bool
IsTextureFormatCompressed(TexInternalFormat format)
{
return IsCompressedTextureFormat(format.get());
}
GLenum
-WebGLContext::GetAndFlushUnderlyingGLErrors()
+WebGLContext::GetAndFlushUnderlyingGLErrors() const
{
// Get and clear GL error in ALL cases.
GLenum error = gl->fGetError();
// Only store in mUnderlyingGLError if is hasn't already recorded an
// error.
if (!mUnderlyingGLError)
mUnderlyingGLError = error;
@@ -734,41 +735,26 @@ AssertMaskedUintParamCorrect(gl::GLConte
#else
void
AssertUintParamCorrect(gl::GLContext*, GLenum, GLuint)
{
}
#endif
void
-WebGLContext::AssertCachedBindings()
+WebGLContext::AssertCachedBindings() const
{
#ifdef DEBUG
GetAndFlushUnderlyingGLErrors();
if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::OES_vertex_array_object)) {
GLuint bound = mBoundVertexArray ? mBoundVertexArray->GLName() : 0;
AssertUintParamCorrect(gl, LOCAL_GL_VERTEX_ARRAY_BINDING, bound);
}
- // Framebuffers
- if (IsWebGL2()) {
- GLuint bound = mBoundDrawFramebuffer ? mBoundDrawFramebuffer->mGLName
- : 0;
- AssertUintParamCorrect(gl, LOCAL_GL_DRAW_FRAMEBUFFER_BINDING, bound);
-
- bound = mBoundReadFramebuffer ? mBoundReadFramebuffer->mGLName : 0;
- AssertUintParamCorrect(gl, LOCAL_GL_READ_FRAMEBUFFER_BINDING, bound);
- } else {
- MOZ_ASSERT(mBoundDrawFramebuffer == mBoundReadFramebuffer);
- GLuint bound = mBoundDrawFramebuffer ? mBoundDrawFramebuffer->mGLName
- : 0;
- AssertUintParamCorrect(gl, LOCAL_GL_FRAMEBUFFER_BINDING, bound);
- }
-
GLint stencilBits = 0;
if (GetStencilBits(&stencilBits)) { // Depends on current draw framebuffer.
const GLuint stencilRefMask = (1 << stencilBits) - 1;
AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_REF, stencilRefMask, mStencilRefFront);
AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_REF, stencilRefMask, mStencilRefBack);
}
@@ -799,37 +785,28 @@ WebGLContext::AssertCachedBindings()
MOZ_ASSERT(!GetAndFlushUnderlyingGLErrors());
#endif
// We do not check the renderbuffer binding, because we never rely on it matching.
}
void
-WebGLContext::AssertCachedGlobalState()
+WebGLContext::AssertCachedGlobalState() const
{
#ifdef DEBUG
GetAndFlushUnderlyingGLErrors();
////////////////
// Draw state
- MOZ_ASSERT(gl->fIsEnabled(LOCAL_GL_DEPTH_TEST) == mDepthTestEnabled);
MOZ_ASSERT(gl->fIsEnabled(LOCAL_GL_DITHER) == mDitherEnabled);
MOZ_ASSERT_IF(IsWebGL2(),
gl->fIsEnabled(LOCAL_GL_RASTERIZER_DISCARD) == mRasterizerDiscardEnabled);
MOZ_ASSERT(gl->fIsEnabled(LOCAL_GL_SCISSOR_TEST) == mScissorTestEnabled);
- MOZ_ASSERT(gl->fIsEnabled(LOCAL_GL_STENCIL_TEST) == mStencilTestEnabled);
-
- realGLboolean colorWriteMask[4] = {0, 0, 0, 0};
- gl->fGetBooleanv(LOCAL_GL_COLOR_WRITEMASK, colorWriteMask);
- MOZ_ASSERT(colorWriteMask[0] == mColorWriteMask[0] &&
- colorWriteMask[1] == mColorWriteMask[1] &&
- colorWriteMask[2] == mColorWriteMask[2] &&
- colorWriteMask[3] == mColorWriteMask[3]);
GLfloat colorClearValue[4] = {0.0f, 0.0f, 0.0f, 0.0f};
gl->fGetFloatv(LOCAL_GL_COLOR_CLEAR_VALUE, colorClearValue);
MOZ_ASSERT(IsCacheCorrect(mColorClearValue[0], colorClearValue[0]) &&
IsCacheCorrect(mColorClearValue[1], colorClearValue[1]) &&
IsCacheCorrect(mColorClearValue[2], colorClearValue[2]) &&
IsCacheCorrect(mColorClearValue[3], colorClearValue[3]));
--- a/dom/canvas/WebGLContextValidate.cpp
+++ b/dom/canvas/WebGLContextValidate.cpp
@@ -415,25 +415,23 @@ WebGLContext::InitAndValidateGL(FailureR
mDisableExtensions = gfxPrefs::WebGLDisableExtensions();
mLoseContextOnMemoryPressure = gfxPrefs::WebGLLoseContextOnMemoryPressure();
mCanLoseContextInForeground = gfxPrefs::WebGLCanLoseContextInForeground();
mRestoreWhenVisible = gfxPrefs::WebGLRestoreWhenVisible();
// These are the default values, see 6.2 State tables in the
// OpenGL ES 2.0.25 spec.
- mColorWriteMask[0] = 1;
- mColorWriteMask[1] = 1;
- mColorWriteMask[2] = 1;
- mColorWriteMask[3] = 1;
- mDepthWriteMask = 1;
+ mColorWriteMask = 0x0f;
+ mDriverColorMask = mColorWriteMask;
mColorClearValue[0] = 0.f;
mColorClearValue[1] = 0.f;
mColorClearValue[2] = 0.f;
mColorClearValue[3] = 0.f;
+ mDepthWriteMask = true;
mDepthClearValue = 1.f;
mStencilClearValue = 0;
mStencilRefFront = 0;
mStencilRefBack = 0;
mLineWidth = 1.0;
/*
@@ -456,23 +454,28 @@ WebGLContext::InitAndValidateGL(FailureR
AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_VALUE_MASK, mStencilValueMaskFront);
AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_VALUE_MASK, mStencilValueMaskBack);
AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_WRITEMASK, mStencilWriteMaskFront);
AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_WRITEMASK, mStencilWriteMaskBack);
mDitherEnabled = true;
mRasterizerDiscardEnabled = false;
mScissorTestEnabled = false;
+
mDepthTestEnabled = 0;
+ mDriverDepthTest = false;
mStencilTestEnabled = 0;
+ mDriverStencilTest = false;
+
mGenerateMipmapHint = LOCAL_GL_DONT_CARE;
// Bindings, etc.
mActiveTexture = 0;
mDefaultFB_DrawBuffer0 = LOCAL_GL_BACK;
+ mDefaultFB_ReadBuffer = LOCAL_GL_BACK;
mEmitContextLostErrorOnce = true;
mWebGLError = LOCAL_GL_NO_ERROR;
mUnderlyingGLError = LOCAL_GL_NO_ERROR;
mBound2DTextures.Clear();
mBoundCubeMapTextures.Clear();
mBound3DTextures.Clear();
--- a/dom/canvas/WebGLFramebuffer.cpp
+++ b/dom/canvas/WebGLFramebuffer.cpp
@@ -884,17 +884,17 @@ WebGLFramebuffer::PrecheckFramebufferSta
return LOCAL_GL_FRAMEBUFFER_COMPLETE;
}
////////////////////////////////////////
// Validation
bool
-WebGLFramebuffer::ValidateAndInitAttachments(const char* funcName)
+WebGLFramebuffer::ValidateAndInitAttachments(const char* funcName) const
{
MOZ_ASSERT(mContext->mBoundDrawFramebuffer == this ||
mContext->mBoundReadFramebuffer == this);
const auto fbStatus = CheckFramebufferStatus(funcName);
if (fbStatus == LOCAL_GL_FRAMEBUFFER_COMPLETE)
return true;
@@ -937,23 +937,21 @@ WebGLFramebuffer::ValidateClearBufferTyp
funcName, attachType, funcType);
return false;
}
return true;
}
bool
-WebGLFramebuffer::ValidateForRead(const char* funcName,
- const webgl::FormatUsageInfo** const out_format,
- uint32_t* const out_width, uint32_t* const out_height)
+WebGLFramebuffer::ValidateForColorRead(const char* funcName,
+ const webgl::FormatUsageInfo** const out_format,
+ uint32_t* const out_width,
+ uint32_t* const out_height) const
{
- if (!ValidateAndInitAttachments(funcName))
- return false;
-
if (!mColorReadBuffer) {
mContext->ErrorInvalidOperation("%s: READ_BUFFER must not be NONE.", funcName);
return false;
}
if (!mColorReadBuffer->IsDefined()) {
mContext->ErrorInvalidOperation("%s: The READ_BUFFER attachment is not defined.",
funcName);
@@ -1180,17 +1178,17 @@ WebGLFramebuffer::RefreshResolvedData()
mResolvedCompleteData.reset(new ResolvedData(*this));
}
}
////////////////////////////////////////////////////////////////////////////////
// Entrypoints
FBStatus
-WebGLFramebuffer::CheckFramebufferStatus(const char* funcName)
+WebGLFramebuffer::CheckFramebufferStatus(const char* const funcName) const
{
if (IsResolvedComplete())
return LOCAL_GL_FRAMEBUFFER_COMPLETE;
// Ok, let's try to resolve it!
nsCString statusInfo;
FBStatus ret = PrecheckFramebufferStatus(&statusInfo);
@@ -1646,25 +1644,26 @@ GetBackbufferFormats(const WebGLContext*
if (options.stencil) {
*out_stencil = webgl::GetFormat(webgl::EffectiveFormat::STENCIL_INDEX8);
}
}
}
/*static*/ void
WebGLFramebuffer::BlitFramebuffer(WebGLContext* webgl,
- const WebGLFramebuffer* srcFB, GLint srcX0, GLint srcY0,
- GLint srcX1, GLint srcY1,
- const WebGLFramebuffer* dstFB, GLint dstX0, GLint dstY0,
- GLint dstX1, GLint dstY1,
+ GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
+ GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter)
{
const char funcName[] = "blitFramebuffer";
const auto& gl = webgl->gl;
+ const auto& srcFB = webgl->mBoundReadFramebuffer;
+ const auto& dstFB = webgl->mBoundDrawFramebuffer;
+
////
// Collect data
const auto fnGetDepthAndStencilAttach = [](const WebGLFramebuffer* fb,
const WebGLFBAttachPoint** const out_depth,
const WebGLFBAttachPoint** const out_stencil)
{
*out_depth = nullptr;
@@ -1923,18 +1922,17 @@ WebGLFramebuffer::BlitFramebuffer(WebGLC
}
} else if (!srcFB && !dstFB) {
webgl->ErrorInvalidOperation("%s: Feedback with default framebuffer.", funcName);
return;
}
////
- webgl->OnBeforeReadCall();
- WebGLContext::ScopedDrawCallWrapper wrapper(*webgl);
+ const ScopedDrawCallWrapper wrapper(*webgl);
gl->fBlitFramebuffer(srcX0, srcY0, srcX1, srcY1,
dstX0, dstY0, dstX1, dstY1,
mask, filter);
}
////////////////////////////////////////////////////////////////////////////////
// Goop.
--- a/dom/canvas/WebGLFramebuffer.h
+++ b/dom/canvas/WebGLFramebuffer.h
@@ -190,17 +190,17 @@ protected:
// IsFeedback
std::vector<const WebGLFBAttachPoint*> texDrawBuffers; // Non-null
std::set<WebGLFBAttachPoint::Ordered> drawSet;
std::set<WebGLFBAttachPoint::Ordered> readSet;
explicit ResolvedData(const WebGLFramebuffer& parent);
};
- UniquePtr<const ResolvedData> mResolvedCompleteData;
+ mutable UniquePtr<const ResolvedData> mResolvedCompleteData;
////
public:
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLFramebuffer)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLFramebuffer)
WebGLFramebuffer(WebGLContext* webgl, GLuint fbo);
@@ -231,23 +231,23 @@ protected:
void ResolveAttachments() const;
void RefreshDrawBuffers() const;
void RefreshReadBuffer() const;
bool ResolveAttachmentData(const char* funcName) const;
public:
void DetachTexture(const char* funcName, const WebGLTexture* tex);
void DetachRenderbuffer(const char* funcName, const WebGLRenderbuffer* rb);
- bool ValidateAndInitAttachments(const char* funcName);
+ bool ValidateAndInitAttachments(const char* funcName) const;
bool ValidateClearBufferType(const char* funcName, GLenum buffer, uint32_t drawBuffer,
GLenum funcType) const;
- bool ValidateForRead(const char* info,
- const webgl::FormatUsageInfo** const out_format,
- uint32_t* const out_width, uint32_t* const out_height);
+ bool ValidateForColorRead(const char* funcName,
+ const webgl::FormatUsageInfo** out_format,
+ uint32_t* out_width, uint32_t* out_height) const;
////////////////
// Getters
#define GETTER(X) const decltype(m##X)& X() const { return m##X; }
GETTER(DepthAttachment)
GETTER(StencilAttachment)
@@ -263,33 +263,31 @@ public:
bool IsResolvedComplete() const { return bool(mResolvedCompleteData); }
void InvalidateFramebufferStatus(const char* funcName);
void RefreshResolvedData();
////////////////
// WebGL funcs
- FBStatus CheckFramebufferStatus(const char* funcName);
+ FBStatus CheckFramebufferStatus(const char* funcName) const;
void FramebufferRenderbuffer(const char* funcName, GLenum attachment, GLenum rbtarget,
WebGLRenderbuffer* rb);
void FramebufferTexture2D(const char* funcName, GLenum attachment,
GLenum texImageTarget, WebGLTexture* tex, GLint level);
void FramebufferTextureLayer(const char* funcName, GLenum attachment,
WebGLTexture* tex, GLint level, GLint layer);
void DrawBuffers(const char* funcName, const dom::Sequence<GLenum>& buffers);
void ReadBuffer(const char* funcName, GLenum attachPoint);
JS::Value GetAttachmentParameter(const char* funcName, JSContext* cx, GLenum target,
GLenum attachment, GLenum pname,
ErrorResult* const out_error);
static void BlitFramebuffer(WebGLContext* webgl,
- const WebGLFramebuffer* src, GLint srcX0, GLint srcY0,
- GLint srcX1, GLint srcY1,
- const WebGLFramebuffer* dst, GLint dstX0, GLint dstY0,
- GLint dstX1, GLint dstY1,
+ GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
+ GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter);
};
} // namespace mozilla
#endif // WEBGL_FRAMEBUFFER_H_
--- a/dom/canvas/WebGLTextureUpload.cpp
+++ b/dom/canvas/WebGLTextureUpload.cpp
@@ -2116,18 +2116,18 @@ WebGLTexture::CopyTexImage2D(TexImageTar
MOZ_ASSERT(imageInfo);
////////////////////////////////////
// Get source info
const webgl::FormatUsageInfo* srcUsage;
uint32_t srcTotalWidth;
uint32_t srcTotalHeight;
- if (!mContext->ValidateCurFBForRead(funcName, &srcUsage, &srcTotalWidth,
- &srcTotalHeight))
+ if (!mContext->BindCurFBForColorRead(funcName, &srcUsage, &srcTotalWidth,
+ &srcTotalHeight))
{
return;
}
if (!ValidateCopyTexImageForFeedback(funcName, level))
return;
////////////////////////////////////
@@ -2150,18 +2150,16 @@ WebGLTexture::CopyTexImage2D(TexImageTar
}
if (!ValidateCopyTexImageFormats(mContext, funcName, srcFormat, dstFormat))
return;
////////////////////////////////////
// Do the thing!
- mContext->OnBeforeReadCall();
-
const bool isSubImage = false;
if (!DoCopyTexOrSubImage(mContext, funcName, isSubImage, this, target, level, x, y,
srcTotalWidth, srcTotalHeight, srcUsage, 0, 0, 0, width,
height, dstUsage))
{
return;
}
@@ -2210,18 +2208,18 @@ WebGLTexture::CopyTexSubImage(const char
}
////////////////////////////////////
// Get source info
const webgl::FormatUsageInfo* srcUsage;
uint32_t srcTotalWidth;
uint32_t srcTotalHeight;
- if (!mContext->ValidateCurFBForRead(funcName, &srcUsage, &srcTotalWidth,
- &srcTotalHeight))
+ if (!mContext->BindCurFBForColorRead(funcName, &srcUsage, &srcTotalWidth,
+ &srcTotalHeight))
{
return;
}
if (!ValidateCopyTexImageForFeedback(funcName, level, zOffset))
return;
////////////////////////////////////
@@ -2229,18 +2227,16 @@ WebGLTexture::CopyTexSubImage(const char
auto srcFormat = srcUsage->format;
if (!ValidateCopyTexImageFormats(mContext, funcName, srcFormat, dstFormat))
return;
////////////////////////////////////
// Do the thing!
- mContext->OnBeforeReadCall();
-
bool uploadWillInitialize;
if (!EnsureImageDataInitializedForUpload(this, funcName, target, level, xOffset,
yOffset, zOffset, width, height, depth,
imageInfo, &uploadWillInitialize))
{
return;
}
--- a/dom/canvas/moz.build
+++ b/dom/canvas/moz.build
@@ -196,16 +196,17 @@ LOCAL_INCLUDES += [
'/js/xpconnect/wrappers',
]
include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'
LOCAL_INCLUDES += [
'../workers',
+ '/', # Allow including relpaths from root.
'/dom/base',
'/dom/html',
'/dom/svg',
'/dom/workers',
'/dom/xul',
'/gfx/gl',
'/image',
'/js/xpconnect/src',
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -2515,18 +2515,16 @@ SplitByChar(const nsACString& str, const
out->push_back(nsCString(substr));
}
bool
GLContext::Readback(SharedSurface* src, gfx::DataSourceSurface* dest)
{
MOZ_ASSERT(src && dest);
MOZ_ASSERT(dest->GetSize() == src->mSize);
- MOZ_ASSERT(dest->GetFormat() == (src->mHasAlpha ? SurfaceFormat::B8G8R8A8
- : SurfaceFormat::B8G8R8X8));
if (!MakeCurrent()) {
return false;
}
SharedSurface* prev = GetLockedSurface();
const bool needsSwap = src != prev;
--- a/gfx/layers/CopyableCanvasRenderer.cpp
+++ b/gfx/layers/CopyableCanvasRenderer.cpp
@@ -150,18 +150,18 @@ CopyableCanvasRenderer::ReadbackSurface(
}
if (!frontbuffer) {
NS_WARNING("Null frame received.");
return nullptr;
}
IntSize readSize(frontbuffer->mSize);
- SurfaceFormat format =
- mOpaque ? SurfaceFormat::B8G8R8X8 : SurfaceFormat::B8G8R8A8;
+ SurfaceFormat format = frontbuffer->mHasAlpha ? SurfaceFormat::B8G8R8X8
+ : SurfaceFormat::B8G8R8A8;
bool needsPremult = frontbuffer->mHasAlpha && !mIsAlphaPremultiplied;
RefPtr<DataSourceSurface> resultSurf = GetTempSurface(readSize, format);
// There will already be a warning from inside of GetTempSurface, but
// it doesn't hurt to complain:
if (NS_WARN_IF(!resultSurf)) {
return nullptr;
}
--- a/gfx/layers/ShareableCanvasRenderer.cpp
+++ b/gfx/layers/ShareableCanvasRenderer.cpp
@@ -46,17 +46,16 @@ ShareableCanvasRenderer::Initialize(cons
if (mGLFrontbuffer) {
// The screen caps are irrelevant if we're using a separate frontbuffer.
caps = mGLFrontbuffer->mHasAlpha ? gl::SurfaceCaps::ForRGBA()
: gl::SurfaceCaps::ForRGB();
} else {
MOZ_ASSERT(screen);
caps = screen->mCaps;
}
- MOZ_ASSERT(caps.alpha == aData.mHasAlpha);
auto forwarder = GetForwarder();
mFlags = TextureFlags::ORIGIN_BOTTOM_LEFT;
if (!aData.mIsGLAlphaPremult) {
mFlags |= TextureFlags::NON_PREMULTIPLIED;
}
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -746,16 +746,17 @@ private:
DECL_GFX_PREF(Once, "webgl.force-layers-readback", WebGLForceLayersReadback, bool, false);
DECL_GFX_PREF(Live, "webgl.force-index-validation", WebGLForceIndexValidation, int32_t, 0);
DECL_GFX_PREF(Live, "webgl.lose-context-on-memory-pressure", WebGLLoseContextOnMemoryPressure, bool, false);
DECL_GFX_PREF(Live, "webgl.max-contexts", WebGLMaxContexts, uint32_t, 32);
DECL_GFX_PREF(Live, "webgl.max-contexts-per-principal", WebGLMaxContextsPerPrincipal, uint32_t, 16);
DECL_GFX_PREF(Live, "webgl.max-warnings-per-context", WebGLMaxWarningsPerContext, uint32_t, 32);
DECL_GFX_PREF(Live, "webgl.min_capability_mode", WebGLMinCapabilityMode, bool, false);
DECL_GFX_PREF(Live, "webgl.msaa-force", WebGLForceMSAA, bool, false);
+ DECL_GFX_PREF(Live, "webgl.msaa-samples", WebGLMsaaSamples, uint32_t, 4);
DECL_GFX_PREF(Live, "webgl.prefer-16bpp", WebGLPrefer16bpp, bool, false);
DECL_GFX_PREF(Live, "webgl.restore-context-when-visible", WebGLRestoreWhenVisible, bool, true);
DECL_GFX_PREF(Live, "webgl.allow-immediate-queries", WebGLImmediateQueries, bool, false);
DECL_GFX_PREF(Live, "webgl.allow-fb-invalidation", WebGLFBInvalidation, bool, false);
DECL_GFX_PREF(Live, "webgl.perf.max-warnings", WebGLMaxPerfWarnings, int32_t, 0);
DECL_GFX_PREF(Live, "webgl.perf.max-acceptable-fb-status-invals", WebGLMaxAcceptableFBStatusInvals, int32_t, 0);
DECL_GFX_PREF(Live, "webgl.perf.spew-frame-allocs", WebGLSpewFrameAllocs, bool, true);