Bug 1427668 - Move the webgl backbuffer into webgl. - r=daoshengmu

MozReview-Commit-ID: 2WpG7mfMRQ8
This commit is contained in:
Jeff Gilbert 2017-12-18 18:30:56 -08:00
Родитель 3f0aacfb10
Коммит df8e8db803
20 изменённых файлов: 526 добавлений и 577 удалений

Просмотреть файл

@ -225,14 +225,7 @@ OffscreenCanvas::TransferToImageBitmap(ErrorResult& aRv)
return nullptr; return nullptr;
} }
// Clear the content. // TODO: Clear the content?
if ((mCurrentContextType == CanvasContextType::WebGL1 ||
mCurrentContextType == CanvasContextType::WebGL2))
{
WebGLContext* webGL = static_cast<WebGLContext*>(mCurrentContext.get());
webGL->ClearScreen();
}
return result.forget(); return result.forget();
} }

Просмотреть файл

@ -40,29 +40,18 @@ WebGL2Context::BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY
//// ////
const auto& readFB = mBoundReadFramebuffer; if (!ValidateAndInitFB("blitFramebuffer: READ_FRAMEBUFFER", mBoundReadFramebuffer) ||
if (readFB && !ValidateAndInitFB("blitFramebuffer: DRAW_FRAMEBUFFER", mBoundDrawFramebuffer))
!readFB->ValidateAndInitAttachments("blitFramebuffer's READ_FRAMEBUFFER"))
{ {
return; return;
} }
const auto& drawFB = mBoundDrawFramebuffer; DoBindFB(mBoundReadFramebuffer, LOCAL_GL_READ_FRAMEBUFFER);
if (drawFB && DoBindFB(mBoundDrawFramebuffer, LOCAL_GL_DRAW_FRAMEBUFFER);
!drawFB->ValidateAndInitAttachments("blitFramebuffer's DRAW_FRAMEBUFFER"))
{
return;
}
////
if (!mBoundReadFramebuffer) {
ClearBackbufferIfNeeded();
}
WebGLFramebuffer::BlitFramebuffer(this, WebGLFramebuffer::BlitFramebuffer(this,
readFB, srcX0, srcY0, srcX1, srcY1, srcX0, srcY0, srcX1, srcY1,
drawFB, dstX0, dstY0, dstX1, dstY1, dstX0, dstY0, dstX1, dstY1,
mask, filter); mask, filter);
} }
@ -170,23 +159,25 @@ WebGLContext::ValidateInvalidateFramebuffer(const char* funcName, GLenum target,
return false; return false;
const WebGLFramebuffer* fb; const WebGLFramebuffer* fb;
bool isDefaultFB; bool isDefaultFB = false;
switch (target) { switch (target) {
case LOCAL_GL_FRAMEBUFFER: case LOCAL_GL_FRAMEBUFFER:
case LOCAL_GL_DRAW_FRAMEBUFFER: case LOCAL_GL_DRAW_FRAMEBUFFER:
fb = mBoundDrawFramebuffer; fb = mBoundDrawFramebuffer;
isDefaultFB = gl->Screen()->IsDrawFramebufferDefault();
break; break;
case LOCAL_GL_READ_FRAMEBUFFER: case LOCAL_GL_READ_FRAMEBUFFER:
fb = mBoundReadFramebuffer; fb = mBoundReadFramebuffer;
isDefaultFB = gl->Screen()->IsReadFramebufferDefault();
break; break;
default: default:
MOZ_CRASH("GFX: Bad target."); MOZ_CRASH("GFX: Bad target.");
} }
if (!ValidateAndInitFB(funcName, fb))
return false;
DoBindFB(fb, target);
*out_glNumAttachments = attachments.Length(); *out_glNumAttachments = attachments.Length();
*out_glAttachments = attachments.Elements(); *out_glAttachments = attachments.Elements();
@ -230,13 +221,9 @@ WebGLContext::ValidateInvalidateFramebuffer(const char* funcName, GLenum target,
//// ////
if (!fb) { if (!fb) {
ClearBackbufferIfNeeded(); mDefaultFB_IsInvalid = true;
mResolvedDefaultFB = nullptr;
// Don't do more validation after these.
Invalidate();
mShouldPresent = true;
} }
return true; return true;
} }
@ -331,7 +318,7 @@ WebGL2Context::ReadBuffer(GLenum mode)
return; return;
} }
gl->Screen()->SetReadBuffer(mode); mDefaultFB_ReadBuffer = mode;
} }
} // namespace mozilla } // namespace mozilla

Просмотреть файл

@ -62,11 +62,11 @@ WebGL2Context::ValidateClearBuffer(const char* funcName, GLenum buffer, GLint dr
//// ////
if (!BindCurFBForDraw(funcName))
return false;
const auto& fb = mBoundDrawFramebuffer; const auto& fb = mBoundDrawFramebuffer;
if (fb) { if (fb) {
if (!fb->ValidateAndInitAttachments(funcName))
return false;
if (!fb->ValidateClearBufferType(funcName, buffer, drawBuffer, funcType)) if (!fb->ValidateClearBufferType(funcName, buffer, drawBuffer, funcType))
return false; return false;
} else if (buffer == LOCAL_GL_COLOR) { } else if (buffer == LOCAL_GL_COLOR) {
@ -110,6 +110,13 @@ WebGL2Context::ClearBufferfv(GLenum buffer, GLint drawBuffer, const Float32Arr&
return; return;
} }
if (!mBoundDrawFramebuffer &&
buffer == LOCAL_GL_DEPTH &&
mNeedsFakeNoDepth)
{
return;
}
ScopedDrawCallWrapper wrapper(*this); ScopedDrawCallWrapper wrapper(*this);
const auto ptr = src.elemBytes + srcElemOffset; const auto ptr = src.elemBytes + srcElemOffset;
gl->fClearBufferfv(buffer, drawBuffer, ptr); gl->fClearBufferfv(buffer, drawBuffer, ptr);
@ -136,6 +143,13 @@ WebGL2Context::ClearBufferiv(GLenum buffer, GLint drawBuffer, const Int32Arr& sr
return; return;
} }
if (!mBoundDrawFramebuffer &&
buffer == LOCAL_GL_STENCIL &&
mNeedsFakeNoStencil)
{
return;
}
ScopedDrawCallWrapper wrapper(*this); ScopedDrawCallWrapper wrapper(*this);
const auto ptr = src.elemBytes + srcElemOffset; const auto ptr = src.elemBytes + srcElemOffset;
gl->fClearBufferiv(buffer, drawBuffer, ptr); gl->fClearBufferiv(buffer, drawBuffer, ptr);
@ -179,8 +193,18 @@ WebGL2Context::ClearBufferfi(GLenum buffer, GLint drawBuffer, GLfloat depth,
if (!ValidateClearBuffer(funcName, buffer, drawBuffer, 2, 0, 0)) if (!ValidateClearBuffer(funcName, buffer, drawBuffer, 2, 0, 0))
return; return;
auto driverDepth = depth;
auto driverStencil = stencil;
if (!mBoundDrawFramebuffer) {
if (mNeedsFakeNoDepth) {
driverDepth = 1.0f;
} else if (mNeedsFakeNoStencil) {
driverStencil = 0;
}
}
ScopedDrawCallWrapper wrapper(*this); ScopedDrawCallWrapper wrapper(*this);
gl->fClearBufferfi(buffer, drawBuffer, depth, stencil); gl->fClearBufferfi(buffer, drawBuffer, driverDepth, driverStencil);
} }
} // namespace mozilla } // namespace mozilla

Просмотреть файл

@ -45,7 +45,7 @@ WebGL2Context::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
/* GLenum */ /* GLenum */
case LOCAL_GL_READ_BUFFER: { case LOCAL_GL_READ_BUFFER: {
if (!mBoundReadFramebuffer) if (!mBoundReadFramebuffer)
return JS::Int32Value(gl->Screen()->GetReadBufferMode()); return JS::Int32Value(mDefaultFB_ReadBuffer);
if (!mBoundReadFramebuffer->ColorReadBuffer()) if (!mBoundReadFramebuffer->ColorReadBuffer())
return JS::Int32Value(LOCAL_GL_NONE); return JS::Int32Value(LOCAL_GL_NONE);

Просмотреть файл

@ -14,6 +14,7 @@
#include "gfxPattern.h" #include "gfxPattern.h"
#include "gfxPrefs.h" #include "gfxPrefs.h"
#include "gfxUtils.h" #include "gfxUtils.h"
#include "gfx/gl/MozFramebuffer.h"
#include "GLBlitHelper.h" #include "GLBlitHelper.h"
#include "GLContext.h" #include "GLContext.h"
#include "GLContextProvider.h" #include "GLContextProvider.h"
@ -119,8 +120,8 @@ WebGLContext::WebGLContext()
, mNeedsFakeNoAlpha(false) , mNeedsFakeNoAlpha(false)
, mNeedsFakeNoDepth(false) , mNeedsFakeNoDepth(false)
, mNeedsFakeNoStencil(false) , mNeedsFakeNoStencil(false)
, mNeedsEmulatedLoneDepthStencil(false)
, mAllowFBInvalidation(gfxPrefs::WebGLFBInvalidation()) , mAllowFBInvalidation(gfxPrefs::WebGLFBInvalidation())
, mMsaaSamples(gfxPrefs::WebGLMsaaSamples())
{ {
mGeneration = 0; mGeneration = 0;
mInvalidated = false; mInvalidated = false;
@ -134,17 +135,6 @@ WebGLContext::WebGLContext()
mWebGLError = 0; mWebGLError = 0;
mUnderlyingGLError = 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; mContextLostErrorSet = false;
mViewportX = 0; mViewportX = 0;
@ -212,6 +202,9 @@ WebGLContext::DestroyResourcesAndContext()
if (!gl) if (!gl)
return; return;
mDefaultFB = nullptr;
mResolvedDefaultFB = nullptr;
mBound2DTextures.Clear(); mBound2DTextures.Clear();
mBoundCubeMapTextures.Clear(); mBoundCubeMapTextures.Clear();
mBound3DTextures.Clear(); mBound3DTextures.Clear();
@ -295,6 +288,7 @@ WebGLContext::DestroyResourcesAndContext()
} }
MOZ_ASSERT(gl); MOZ_ASSERT(gl);
gl->MarkDestroyed();
mGL_OnlyClearInDestroyResourcesAndContext = nullptr; mGL_OnlyClearInDestroyResourcesAndContext = nullptr;
MOZ_ASSERT(!gl); MOZ_ASSERT(!gl);
} }
@ -398,18 +392,6 @@ WebGLContext::SetContextOptions(JSContext* cx, JS::Handle<JS::Value> options,
return NS_OK; 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 /* 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 * 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 * might not be able to create a context with a certain combo of context
@ -486,30 +468,6 @@ PopulateCapFallbackQueue(const gl::SurfaceCaps& baseCaps,
std::queue<gl::SurfaceCaps>* out_fallbackCaps) std::queue<gl::SurfaceCaps>* out_fallbackCaps)
{ {
out_fallbackCaps->push(baseCaps); 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 static gl::SurfaceCaps
@ -518,22 +476,16 @@ BaseCaps(const WebGLContextOptions& options, WebGLContext* webgl)
gl::SurfaceCaps baseCaps; gl::SurfaceCaps baseCaps;
baseCaps.color = true; baseCaps.color = true;
baseCaps.alpha = options.alpha; baseCaps.alpha = true;
baseCaps.antialias = options.antialias; baseCaps.antialias = false;
baseCaps.depth = options.depth; baseCaps.depth = false;
baseCaps.stencil = false;
baseCaps.premultAlpha = options.premultipliedAlpha; baseCaps.premultAlpha = options.premultipliedAlpha;
baseCaps.preserve = options.preserveDrawingBuffer; baseCaps.preserve = options.preserveDrawingBuffer;
baseCaps.stencil = options.stencil;
if (!baseCaps.alpha) if (!baseCaps.alpha) {
baseCaps.premultAlpha = true; 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()) { if (!gfxPrefs::WebGLForceMSAA()) {
const nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo(); const nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
@ -772,8 +724,8 @@ WebGLContext::CreateAndInitGL(bool forceEnabled,
////// //////
if (tryANGLE) { if (tryANGLE) {
// Force enable alpha channel to make sure ANGLE use correct framebuffer formart // Force enable alpha channel to make sure ANGLE use correct framebuffer format
gl::SurfaceCaps& angleCaps = const_cast<gl::SurfaceCaps&>(baseCaps); auto angleCaps = baseCaps;
angleCaps.alpha = true; angleCaps.alpha = true;
return CreateAndInitGLWith(CreateGLWithANGLE, angleCaps, flags, out_failReasons); return CreateAndInitGLWith(CreateGLWithANGLE, angleCaps, flags, out_failReasons);
} }
@ -786,43 +738,54 @@ WebGLContext::CreateAndInitGL(bool forceEnabled,
} }
// Fallback for resizes: // Fallback for resizes:
bool bool
WebGLContext::ResizeBackbuffer(uint32_t requestedWidth, WebGLContext::EnsureDefaultFB() const
uint32_t requestedHeight)
{ {
uint32_t width = requestedWidth; if (mDefaultFB) {
uint32_t height = requestedHeight; MOZ_ASSERT(mDefaultFB->mSize == mRequestedSize);
return true;
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 (!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; return false;
mWidth = gl->OffscreenSize().width; mDefaultFB_IsInvalid = true;
mHeight = gl->OffscreenSize().height;
MOZ_ASSERT((uint32_t)mWidth == width);
MOZ_ASSERT((uint32_t)mHeight == height);
if (width != requestedWidth || if (mDefaultFB->mSize != mRequestedSize) {
height != requestedHeight)
{
GenerateWarning("Requested size %dx%d was too large, but resize" GenerateWarning("Requested size %dx%d was too large, but resize"
" to %dx%d succeeded.", " to %dx%d succeeded.",
requestedWidth, requestedHeight, mRequestedSize.width, mRequestedSize.height,
width, height); mDefaultFB->mSize.width, mDefaultFB->mSize.height);
} }
return true; return true;
} }
@ -887,8 +850,8 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight)
// If we already have a gl context, then we just need to resize it // If we already have a gl context, then we just need to resize it
if (gl) { if (gl) {
if ((uint32_t)mWidth == width && if (uint32_t(mRequestedSize.width) == width &&
(uint32_t)mHeight == height) uint32_t(mRequestedSize.height) == height)
{ {
return NS_OK; return NS_OK;
} }
@ -904,19 +867,11 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight)
return NS_OK; return NS_OK;
} }
// ResizeOffscreen scraps the current prod buffer before making a new one. // Kill our current default fb(s), for later lazy allocation.
if (!ResizeBackbuffer(width, height)) { mRequestedSize = {width, height};
GenerateWarning("WebGL context failed to resize."); mDefaultFB = nullptr;
ForceLoseContext();
return NS_OK;
}
// everything's good, we're done here
mResetLayer = true; mResetLayer = true;
mBackbufferNeedsClear = true;
gl->ResetSyncCallCount("Existing WebGLContext resized.");
return NS_OK; return NS_OK;
} }
@ -1043,7 +998,9 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight)
#endif #endif
} }
if (!ResizeBackbuffer(width, height)) { MOZ_ASSERT(!mDefaultFB);
mRequestedSize = {width, height};
if (!EnsureDefaultFB()) {
failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_BACKBUFFER"); failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_BACKBUFFER");
const nsLiteralCString text("Initializing WebGL backbuffer failed."); const nsLiteralCString text("Initializing WebGL backbuffer failed.");
ThrowEvent_WebGLContextCreationError(text); ThrowEvent_WebGLContextCreationError(text);
@ -1054,50 +1011,40 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight)
printf_stderr("--- WebGL context created: %p\n", gl.get()); printf_stderr("--- WebGL context created: %p\n", gl.get());
} }
mResetLayer = true;
mOptionsFrozen = true;
// Update our internal stuff: // Update our internal stuff:
if (gl->WorkAroundDriverBugs()) { mOptions.antialias = bool(mDefaultFB->mSamples);
if (!mOptions.alpha && gl->Caps().alpha)
mNeedsFakeNoAlpha = true;
if (!mOptions.depth && gl->Caps().depth) if (!mOptions.alpha) {
mNeedsFakeNoDepth = true; // We always have alpha.
mNeedsFakeNoAlpha = 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 (mOptions.depth || mOptions.stencil) {
if (!gl->Caps().depth) // We always have depth+stencil if we have either.
mOptions.depth = false; if (!mOptions.depth) {
mNeedsFakeNoDepth = true;
}
if (!mOptions.stencil) {
mNeedsFakeNoStencil = true;
}
}
if (!gl->Caps().stencil) mResetLayer = true;
mOptions.stencil = false; mOptionsFrozen = true;
mOptions.antialias = gl->Caps().antialias;
////// //////
// Initial setup. // Initial setup.
gl->mImplicitMakeCurrent = true; 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); mViewportX = mViewportY = 0;
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 // Check everything
@ -1105,25 +1052,6 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight)
AssertCachedBindings(); AssertCachedBindings();
AssertCachedGlobalState(); 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; mShouldPresent = true;
////// //////
@ -1136,17 +1064,6 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight)
return NS_OK; return NS_OK;
} }
void
WebGLContext::ClearBackbufferIfNeeded()
{
if (!mBackbufferNeedsClear)
return;
ClearScreen();
mBackbufferNeedsClear = false;
}
void void
WebGLContext::LoseOldestWebGLContextIfLimitExceeded() WebGLContext::LoseOldestWebGLContextIfLimitExceeded()
{ {
@ -1403,8 +1320,8 @@ WebGLContext::InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
} }
data.mGLContext = gl; data.mGLContext = gl;
data.mSize = nsIntSize(mWidth, mHeight); data.mSize = DrawingBufferSize();
data.mHasAlpha = gl->Caps().alpha; data.mHasAlpha = mOptions.alpha;
data.mIsGLAlphaPremult = IsPremultAlpha() || !data.mHasAlpha; data.mIsGLAlphaPremult = IsPremultAlpha() || !data.mHasAlpha;
aRenderer->Initialize(data); aRenderer->Initialize(data);
@ -1506,31 +1423,8 @@ WebGLContext::MozGetUnderlyingParamString(uint32_t pname, nsAString& retval)
} }
void void
WebGLContext::ClearScreen() WebGLContext::ForceClearFramebufferWithDefaultValues(const GLbitfield clearBits,
{ const bool fakeNoAlpha) const
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)
{ {
const bool initializeColorBuffer = bool(clearBits & LOCAL_GL_COLOR_BUFFER_BIT); const bool initializeColorBuffer = bool(clearBits & LOCAL_GL_COLOR_BUFFER_BIT);
const bool initializeDepthBuffer = bool(clearBits & LOCAL_GL_DEPTH_BUFFER_BIT); const bool initializeDepthBuffer = bool(clearBits & LOCAL_GL_DEPTH_BUFFER_BIT);
@ -1545,6 +1439,7 @@ WebGLContext::ForceClearFramebufferWithDefaultValues(GLbitfield clearBits,
if (initializeColorBuffer) { if (initializeColorBuffer) {
gl->fColorMask(1, 1, 1, 1); gl->fColorMask(1, 1, 1, 1);
mDriverColorMask = 0x0f;
if (fakeNoAlpha) { if (fakeNoAlpha) {
gl->fClearColor(0.0f, 0.0f, 0.0f, 1.0f); gl->fClearColor(0.0f, 0.0f, 0.0f, 1.0f);
@ -1583,10 +1478,6 @@ WebGLContext::ForceClearFramebufferWithDefaultValues(GLbitfield clearBits,
// Restore GL state after clearing. // Restore GL state after clearing.
if (initializeColorBuffer) { if (initializeColorBuffer) {
gl->fColorMask(mColorWriteMask[0],
mColorWriteMask[1],
mColorWriteMask[2],
mColorWriteMask[3]);
gl->fClearColor(mColorClearValue[0], gl->fClearColor(mColorClearValue[0],
mColorClearValue[1], mColorClearValue[1],
mColorClearValue[2], mColorClearValue[2],
@ -1616,31 +1507,81 @@ WebGLContext::OnEndOfFrame() const
gl->ResetSyncCallCount("WebGLContext PresentScreenBuffer"); 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: // For an overview of how WebGL compositing works, see:
// https://wiki.mozilla.org/Platform/GFX/WebGL/Compositing // https://wiki.mozilla.org/Platform/GFX/WebGL/Compositing
bool bool
WebGLContext::PresentScreenBuffer() WebGLContext::PresentScreenBuffer()
{ {
if (IsContextLost()) { if (IsContextLost())
return false;
if (!mShouldPresent)
return false;
if (!ValidateAndInitFB("Present", nullptr))
return false;
const auto& screen = gl->Screen();
if (screen->Size() != mDefaultFB->mSize &&
!screen->Resize(mDefaultFB->mSize))
{
GenerateWarning("screen->Resize failed. Losing context.");
ForceLoseContext();
return false; return false;
} }
if (!mShouldPresent) { gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
return false; BlitBackbufferToCurDriverFB();
}
MOZ_ASSERT(!mBackbufferNeedsClear);
GLScreenBuffer* screen = gl->Screen();
MOZ_ASSERT(screen);
if (!screen->PublishFrame(screen->Size())) { if (!screen->PublishFrame(screen->Size())) {
GenerateWarning("PublishFrame failed. Losing context.");
ForceLoseContext(); ForceLoseContext();
return false; return false;
} }
if (!mOptions.preserveDrawingBuffer) { 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; mShouldPresent = false;
OnEndOfFrame(); OnEndOfFrame();
@ -1747,7 +1688,7 @@ CheckContextLost(GLContext* gl, bool* const out_isGuilty)
bool bool
WebGLContext::TryToRestoreContext() WebGLContext::TryToRestoreContext()
{ {
if (NS_FAILED(SetDimensions(mWidth, mHeight))) if (NS_FAILED(SetDimensions(mRequestedSize.width, mRequestedSize.height)))
return false; return false;
return true; return true;
@ -1959,31 +1900,18 @@ WebGLContext::GetSurfaceSnapshot(gfxAlphaType* const out_alphaType)
if (!gl) if (!gl)
return nullptr; return nullptr;
if (!BindDefaultFBForRead("GetSurfaceSnapshot"))
return nullptr;
const auto surfFormat = mOptions.alpha ? SurfaceFormat::B8G8R8A8 const auto surfFormat = mOptions.alpha ? SurfaceFormat::B8G8R8A8
: SurfaceFormat::B8G8R8X8; : SurfaceFormat::B8G8R8X8;
const auto& size = mDefaultFB->mSize;
RefPtr<DataSourceSurface> surf; RefPtr<DataSourceSurface> surf;
surf = Factory::CreateDataSourceSurfaceWithStride(IntSize(mWidth, mHeight), surf = Factory::CreateDataSourceSurfaceWithStride(size, surfFormat, size.width * 4);
surfFormat,
mWidth * 4);
if (NS_WARN_IF(!surf)) if (NS_WARN_IF(!surf))
return nullptr; return nullptr;
{ ReadPixelsIntoDataSurface(gl, surf);
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);
}
}
gfxAlphaType alphaType; gfxAlphaType alphaType;
if (!mOptions.alpha) { if (!mOptions.alpha) {
@ -2005,17 +1933,14 @@ WebGLContext::GetSurfaceSnapshot(gfxAlphaType* const out_alphaType)
RefPtr<DrawTarget> dt = RefPtr<DrawTarget> dt =
Factory::CreateDrawTarget(gfxPlatform::GetPlatform()->GetSoftwareBackend(), Factory::CreateDrawTarget(gfxPlatform::GetPlatform()->GetSoftwareBackend(),
IntSize(mWidth, mHeight), size, SurfaceFormat::B8G8R8A8);
SurfaceFormat::B8G8R8A8);
if (!dt) if (!dt)
return nullptr; return nullptr;
dt->SetTransform(Matrix::Translation(0.0, mHeight).PreScale(1.0, -1.0)); dt->SetTransform(Matrix::Translation(0.0, size.height).PreScale(1.0, -1.0));
dt->DrawSurface(surf, const gfx::Rect rect{0, 0, float(size.width), float(size.height)};
Rect(0, 0, mWidth, mHeight), dt->DrawSurface(surf, rect, rect, DrawSurfaceOptions(),
Rect(0, 0, mWidth, mHeight),
DrawSurfaceOptions(),
DrawOptions(1.0f, CompositionOp::OP_SOURCE)); DrawOptions(1.0f, CompositionOp::OP_SOURCE));
return dt->Snapshot(); return dt->Snapshot();
@ -2029,104 +1954,180 @@ WebGLContext::DidRefresh()
} }
} }
bool ////////////////////////////////////////////////////////////////////////////////
WebGLContext::ValidateCurFBForRead(const char* funcName,
const webgl::FormatUsageInfo** const out_format, gfx::IntSize
uint32_t* const out_width, uint32_t* const out_height) WebGLContext::DrawingBufferSize() const
{ {
if (!mBoundReadFramebuffer) { const gfx::IntSize zeros{0, 0};
const GLenum readBufferMode = gl->Screen()->GetReadBufferMode(); if (IsContextLost())
if (readBufferMode == LOCAL_GL_NONE) { return zeros;
ErrorInvalidOperation("%s: Can't read from backbuffer when readBuffer mode is"
" NONE.", if (!EnsureDefaultFB())
funcName); return zeros;
return mDefaultFB->mSize;
}
bool
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)
{
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; return false;
}
ClearBackbufferIfNeeded(); gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, fb->mGLName);
// 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 true;
} }
return mBoundReadFramebuffer->ValidateForRead(funcName, out_format, out_width, if (!BindDefaultFBForRead(funcName))
out_height); 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;
}
}
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) : 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) { 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) { const auto& gl = mWebGL.gl;
mWebGL.gl->fColorMask(mWebGL.mColorWriteMask[0], if (mWebGL.mDriverColorMask != driverColorMask) {
mWebGL.mColorWriteMask[1], mWebGL.mDriverColorMask = driverColorMask;
mWebGL.mColorWriteMask[2], gl->fColorMask(bool(mWebGL.mDriverColorMask & (1 << 0)),
false); bool(mWebGL.mDriverColorMask & (1 << 1)),
bool(mWebGL.mDriverColorMask & (1 << 2)),
bool(mWebGL.mDriverColorMask & (1 << 3)));
} }
if (mFakeNoDepth) { if (mWebGL.mDriverDepthTest != driverDepthTest) {
mWebGL.gl->fDisable(LOCAL_GL_DEPTH_TEST); // "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) { if (mWebGL.mDriverStencilTest != driverStencilTest) {
mWebGL.gl->fDisable(LOCAL_GL_STENCIL_TEST); // "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) { if (mWebGL.mBoundDrawFramebuffer)
mWebGL.gl->fColorMask(mWebGL.mColorWriteMask[0], return;
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.mResolvedDefaultFB = nullptr;
mWebGL.Invalidate();
mWebGL.mShouldPresent = true;
}
}
/*static*/ bool mWebGL.Invalidate();
WebGLContext::ScopedDrawCallWrapper::HasDepthButNoStencil(const WebGLFramebuffer* fb) mWebGL.mShouldPresent = true;
{
const auto& depth = fb->DepthAttachment();
const auto& stencil = fb->StencilAttachment();
return depth.IsDefined() && !stencil.IsDefined();
}
////
void
WebGLContext::OnBeforeReadCall()
{
if (!mBoundReadFramebuffer) {
ClearBackbufferIfNeeded();
}
} }
//////////////////////////////////////// ////////////////////////////////////////

Просмотреть файл

@ -67,6 +67,7 @@ class nsIDocShell;
namespace mozilla { namespace mozilla {
class ScopedCopyTexImageSource; class ScopedCopyTexImageSource;
class ScopedDrawCallWrapper;
class ScopedResolveTexturesForDraw; class ScopedResolveTexturesForDraw;
class ScopedUnpackReset; class ScopedUnpackReset;
class WebGLActiveInfo; class WebGLActiveInfo;
@ -98,6 +99,10 @@ class SourceSurface;
class VRLayerChild; class VRLayerChild;
} // namespace gfx } // namespace gfx
namespace gl {
class MozFramebuffer;
} // namespace gl
namespace webgl { namespace webgl {
struct LinkedProgramInfo; struct LinkedProgramInfo;
class ShaderValidator; class ShaderValidator;
@ -273,9 +278,9 @@ class WebGLContext
, public nsICanvasRenderingContextInternal , public nsICanvasRenderingContextInternal
, public nsSupportsWeakReference , public nsSupportsWeakReference
, public WebGLContextUnchecked , public WebGLContextUnchecked
, public WebGLRectangleObject
, public nsWrapperCache , public nsWrapperCache
{ {
friend class ScopedDrawCallWrapper;
friend class ScopedDrawHelper; friend class ScopedDrawHelper;
friend class ScopedDrawWithTransformFeedback; friend class ScopedDrawWithTransformFeedback;
friend class ScopedFBRebinder; friend class ScopedFBRebinder;
@ -337,8 +342,8 @@ public:
virtual void OnMemoryPressure() override; virtual void OnMemoryPressure() override;
// nsICanvasRenderingContextInternal // nsICanvasRenderingContextInternal
virtual int32_t GetWidth() const override; virtual int32_t GetWidth() const override { return DrawingBufferWidth(); }
virtual int32_t GetHeight() const override; virtual int32_t GetHeight() const override { return DrawingBufferHeight(); }
NS_IMETHOD SetDimensions(int32_t width, int32_t height) override; NS_IMETHOD SetDimensions(int32_t width, int32_t height) override;
NS_IMETHOD InitializeWithDrawTarget(nsIDocShell*, NS_IMETHOD InitializeWithDrawTarget(nsIDocShell*,
@ -381,22 +386,22 @@ public:
return NS_ERROR_NOT_IMPLEMENTED; return NS_ERROR_NOT_IMPLEMENTED;
} }
void SynthesizeGLError(GLenum err); void SynthesizeGLError(GLenum err) const;
void SynthesizeGLError(GLenum err, const char* fmt, ...) MOZ_FORMAT_PRINTF(3, 4); 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 ErrorInvalidEnum(const char* fmt = 0, ...) const MOZ_FORMAT_PRINTF(2, 3);
void ErrorInvalidOperation(const char* fmt = 0, ...) MOZ_FORMAT_PRINTF(2, 3); void ErrorInvalidOperation(const char* fmt = 0, ...) const MOZ_FORMAT_PRINTF(2, 3);
void ErrorInvalidValue(const char* fmt = 0, ...) MOZ_FORMAT_PRINTF(2, 3); void ErrorInvalidValue(const char* fmt = 0, ...) const MOZ_FORMAT_PRINTF(2, 3);
void ErrorInvalidFramebufferOperation(const char* fmt = 0, ...) MOZ_FORMAT_PRINTF(2, 3); void ErrorInvalidFramebufferOperation(const char* fmt = 0, ...) const MOZ_FORMAT_PRINTF(2, 3);
void ErrorInvalidEnumInfo(const char* info, GLenum enumValue); void ErrorInvalidEnumInfo(const char* info, GLenum enumValue) const;
void ErrorInvalidEnumInfo(const char* info, const char* funcName, void ErrorInvalidEnumInfo(const char* info, const char* funcName,
GLenum enumValue); GLenum enumValue) const;
void ErrorOutOfMemory(const char* fmt = 0, ...) MOZ_FORMAT_PRINTF(2, 3); void ErrorOutOfMemory(const char* fmt = 0, ...) const MOZ_FORMAT_PRINTF(2, 3);
void ErrorImplementationBug(const char* fmt = 0, ...) 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. * Return displayable name for GLenum.
@ -477,11 +482,8 @@ public:
// amount of work it does. // amount of work it does.
// It only clears the buffers we specify, and can reset its state without // 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. // first having to query anything, as WebGL knows its state at all times.
void ForceClearFramebufferWithDefaultValues(GLbitfield bufferBits, bool fakeNoAlpha); void ForceClearFramebufferWithDefaultValues(GLbitfield bufferBits,
bool fakeNoAlpha) const;
// Calls ForceClearFramebufferWithDefaultValues() for the Context's 'screen'.
void ClearScreen();
void ClearBackbufferIfNeeded();
void RunContextLossTimer(); void RunContextLossTimer();
void UpdateContextLossStatus(); void UpdateContextLossStatus();
@ -489,8 +491,8 @@ public:
bool TryToRestoreContext(); bool TryToRestoreContext();
void AssertCachedBindings(); void AssertCachedBindings() const;
void AssertCachedGlobalState(); void AssertCachedGlobalState() const;
dom::HTMLCanvasElement* GetCanvas() const { return mCanvasElement; } dom::HTMLCanvasElement* GetCanvas() const { return mCanvasElement; }
nsIDocument* GetOwnerDoc() const; nsIDocument* GetOwnerDoc() const;
@ -498,10 +500,11 @@ public:
// WebIDL WebGLRenderingContext API // WebIDL WebGLRenderingContext API
void Commit(); void Commit();
void GetCanvas(Nullable<dom::OwningHTMLCanvasElementOrOffscreenCanvas>& retval); void GetCanvas(Nullable<dom::OwningHTMLCanvasElementOrOffscreenCanvas>& retval);
GLsizei DrawingBufferWidth() const { return IsContextLost() ? 0 : mWidth; } private:
GLsizei DrawingBufferHeight() const { gfx::IntSize DrawingBufferSize() const;
return IsContextLost() ? 0 : mHeight; public:
} GLsizei DrawingBufferWidth() const { return DrawingBufferSize().width; }
GLsizei DrawingBufferHeight() const { return DrawingBufferSize().height; }
layers::LayersBackend GetCompositorBackendType() const; layers::LayersBackend GetCompositorBackendType() const;
@ -986,7 +989,7 @@ public:
public: public:
void Disable(GLenum cap); void Disable(GLenum cap);
void Enable(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); bool GetChannelBits(const char* funcName, GLenum pname, GLint* const out_val);
virtual JS::Value GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv); virtual JS::Value GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv);
@ -1443,7 +1446,6 @@ protected:
bool mCanLoseContextInForeground; bool mCanLoseContextInForeground;
bool mRestoreWhenVisible; bool mRestoreWhenVisible;
bool mShouldPresent; bool mShouldPresent;
bool mBackbufferNeedsClear;
bool mDisableFragHighP; bool mDisableFragHighP;
template<typename WebGLObjectType> template<typename WebGLObjectType>
@ -1451,12 +1453,13 @@ protected:
GLuint mActiveTexture; GLuint mActiveTexture;
GLenum mDefaultFB_DrawBuffer0; GLenum mDefaultFB_DrawBuffer0;
GLenum mDefaultFB_ReadBuffer;
// glGetError sources: // glGetError sources:
bool mEmitContextLostErrorOnce; bool mEmitContextLostErrorOnce;
GLenum mWebGLError; mutable GLenum mWebGLError;
GLenum mUnderlyingGLError; mutable GLenum mUnderlyingGLError;
GLenum GetAndFlushUnderlyingGLErrors(); GLenum GetAndFlushUnderlyingGLErrors() const;
bool mBypassShaderValidation; bool mBypassShaderValidation;
@ -1585,8 +1588,6 @@ protected:
bool CreateAndInitGL(bool forceEnabled, bool CreateAndInitGL(bool forceEnabled,
std::vector<FailureReason>* const out_failReasons); 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, typedef already_AddRefed<gl::GLContext> FnCreateGL_T(const gl::SurfaceCaps& caps,
gl::CreateContextFlags flags, gl::CreateContextFlags flags,
WebGLContext* webgl, WebGLContext* webgl,
@ -1662,10 +1663,6 @@ protected:
WebGLProgram* program, WebGLProgram* program,
const char* funcName); 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 { bool HasDrawBuffers() const {
return IsWebGL2() || return IsWebGL2() ||
IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers); IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers);
@ -1938,7 +1935,7 @@ protected:
GLuint mStencilValueMaskBack; GLuint mStencilValueMaskBack;
GLuint mStencilWriteMaskFront; GLuint mStencilWriteMaskFront;
GLuint mStencilWriteMaskBack; GLuint mStencilWriteMaskBack;
realGLboolean mColorWriteMask[4]; uint8_t mColorWriteMask; // bitmask
realGLboolean mDepthWriteMask; realGLboolean mDepthWriteMask;
GLfloat mColorClearValue[4]; GLfloat mColorClearValue[4];
GLint mStencilClearValue; GLint mStencilClearValue;
@ -1962,7 +1959,7 @@ protected:
// be Flushed while doing hundreds of draw calls. // be Flushed while doing hundreds of draw calls.
int mDrawCallsSinceLastFlush; int mDrawCallsSinceLastFlush;
int mAlreadyGeneratedWarnings; mutable int mAlreadyGeneratedWarnings;
int mMaxWarnings; int mMaxWarnings;
bool mAlreadyWarnedAboutFakeVertexAttrib0; bool mAlreadyWarnedAboutFakeVertexAttrib0;
@ -1977,7 +1974,10 @@ protected:
bool mNeedsFakeNoAlpha; bool mNeedsFakeNoAlpha;
bool mNeedsFakeNoDepth; bool mNeedsFakeNoDepth;
bool mNeedsFakeNoStencil; bool mNeedsFakeNoStencil;
bool mNeedsEmulatedLoneDepthStencil;
mutable uint8_t mDriverColorMask;
bool mDriverDepthTest;
bool mDriverStencilTest;
bool mNeedsIndexValidation; bool mNeedsIndexValidation;
@ -1985,63 +1985,30 @@ protected:
bool Has64BitTimestamps() const; bool Has64BitTimestamps() const;
struct ScopedDrawCallWrapper final { // --
WebGLContext& mWebGL;
const bool mFakeNoAlpha;
const bool mFakeNoDepth;
const bool mFakeNoStencil;
static bool ShouldFakeNoAlpha(WebGLContext& webgl) { const uint8_t mMsaaSamples;
// We should only be doing this if we're about to draw to the backbuffer, but gfx::IntSize mRequestedSize;
// the backbuffer needs to have this fake-no-alpha workaround. mutable UniquePtr<gl::MozFramebuffer> mDefaultFB;
return !webgl.mBoundDrawFramebuffer && mutable bool mDefaultFB_IsInvalid;
webgl.mNeedsFakeNoAlpha && mutable UniquePtr<gl::MozFramebuffer> mResolvedDefaultFB;
webgl.mColorWriteMask[3] != false;
}
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); bool EnsureDefaultFB() const;
bool ValidateAndInitFB(const char* funcName, const WebGLFramebuffer* fb);
void DoBindFB(const WebGLFramebuffer* fb, GLenum target = LOCAL_GL_FRAMEBUFFER) const;
static bool ShouldFakeNoStencil(WebGLContext& webgl) { bool BindCurFBForDraw(const char* funcName);
if (!webgl.mStencilTestEnabled) bool BindCurFBForColorRead(const char* funcName,
return false; const webgl::FormatUsageInfo** out_format,
uint32_t* out_width, uint32_t* out_height);
void BlitBackbufferToCurDriverFB() const;
bool BindDefaultFBForRead(const char* funcName);
if (!webgl.mBoundDrawFramebuffer) { // --
if (webgl.mNeedsFakeNoStencil)
return true;
if (webgl.mNeedsEmulatedLoneDepthStencil &&
webgl.mOptions.depth && !webgl.mOptions.stencil)
{
return true;
}
return false;
}
if (webgl.mNeedsEmulatedLoneDepthStencil &&
HasDepthButNoStencil(webgl.mBoundDrawFramebuffer))
{
return true;
}
return false;
}
////
explicit ScopedDrawCallWrapper(WebGLContext& webgl);
~ScopedDrawCallWrapper();
};
void OnBeforeReadCall();
public:
void LoseOldestWebGLContextIfLimitExceeded(); void LoseOldestWebGLContextIfLimitExceeded();
void UpdateLastUseIndex(); void UpdateLastUseIndex();
@ -2063,8 +2030,8 @@ protected:
public: public:
// console logging helpers // console logging helpers
void GenerateWarning(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3); void GenerateWarning(const char* fmt, ...) const MOZ_FORMAT_PRINTF(2, 3);
void GenerateWarning(const char* fmt, va_list ap) MOZ_FORMAT_PRINTF(2, 0); 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); void GeneratePerfWarning(const char* fmt, ...) const MOZ_FORMAT_PRINTF(2, 3);
@ -2190,6 +2157,17 @@ AvailGroups(uint64_t totalAvailItems, uint64_t firstItemOffset, uint32_t groupSi
//// ////
class ScopedDrawCallWrapper final
{
public:
WebGLContext& mWebGL;
explicit ScopedDrawCallWrapper(WebGLContext& webgl);
~ScopedDrawCallWrapper();
};
////
void void
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& callback, ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& callback,
const std::vector<IndexedBufferBinding>& field, const std::vector<IndexedBufferBinding>& field,

Просмотреть файл

@ -6,6 +6,7 @@
#include "WebGLContext.h" #include "WebGLContext.h"
#include "GeckoProfiler.h" #include "GeckoProfiler.h"
#include "gfx/gl/MozFramebuffer.h"
#include "GLContext.h" #include "GLContext.h"
#include "mozilla/CheckedInt.h" #include "mozilla/CheckedInt.h"
#include "mozilla/UniquePtrExtensions.h" #include "mozilla/UniquePtrExtensions.h"
@ -99,23 +100,10 @@ ScopedResolveTexturesForDraw::ScopedResolveTexturesForDraw(WebGLContext* webgl,
{ {
MOZ_ASSERT(mWebGL->gl->IsCurrent()); 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 std::vector<const WebGLFBAttachPoint*>* attachList = nullptr;
const auto& fb = mWebGL->mBoundDrawFramebuffer; const auto& fb = mWebGL->mBoundDrawFramebuffer;
if (fb) { if (fb) {
if (!fb->ValidateAndInitAttachments(funcName)) {
*out_error = true;
return;
}
attachList = &(fb->ResolvedCompleteData()->texDrawBuffers); attachList = &(fb->ResolvedCompleteData()->texDrawBuffers);
} else {
webgl->ClearBackbufferIfNeeded();
} }
MOZ_ASSERT(mWebGL->mActiveProgramLinkInfo); MOZ_ASSERT(mWebGL->mActiveProgramLinkInfo);
@ -255,6 +243,11 @@ public:
{ {
MOZ_ASSERT(mWebGL->gl->IsCurrent()); MOZ_ASSERT(mWebGL->gl->IsCurrent());
if (!mWebGL->BindCurFBForDraw(funcName)) {
*out_error = true;
return;
}
if (!mWebGL->ValidateDrawModeEnum(mode, funcName)) { if (!mWebGL->ValidateDrawModeEnum(mode, funcName)) {
*out_error = true; *out_error = true;
return; return;
@ -265,22 +258,16 @@ public:
return; return;
} }
//// if (!mWebGL->mActiveProgramLinkInfo) {
mWebGL->ErrorInvalidOperation("%s: The current program is not linked.", funcName);
if (mWebGL->mBoundDrawFramebuffer) { *out_error = true;
if (!mWebGL->mBoundDrawFramebuffer->ValidateAndInitAttachments(funcName)) { return;
*out_error = true;
return;
}
} else {
mWebGL->ClearBackbufferIfNeeded();
} }
const auto& linkInfo = mWebGL->mActiveProgramLinkInfo;
//// ////
// Check UBO sizes. // Check UBO sizes.
const auto& linkInfo = mWebGL->mActiveProgramLinkInfo;
for (const auto& cur : linkInfo->uniformBlocks) { for (const auto& cur : linkInfo->uniformBlocks) {
const auto& dataSize = cur->mDataSize; const auto& dataSize = cur->mDataSize;
const auto& binding = cur->mBinding; const auto& binding = cur->mBinding;
@ -525,20 +512,20 @@ WebGLContext::DrawArraysInstanced(GLenum mode, GLint first, GLsizei vertCount,
if (IsContextLost()) if (IsContextLost())
return; return;
bool error = false;
ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
if (error)
return;
Maybe<uint32_t> lastVert; Maybe<uint32_t> lastVert;
if (!DrawArrays_check(funcName, first, vertCount, instanceCount, &lastVert)) if (!DrawArrays_check(funcName, first, vertCount, instanceCount, &lastVert))
return; return;
bool error = false;
const ScopedDrawHelper scopedHelper(this, funcName, mode, lastVert, instanceCount, const ScopedDrawHelper scopedHelper(this, funcName, mode, lastVert, instanceCount,
&error); &error);
if (error) if (error)
return; return;
const ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
if (error)
return;
const ScopedDrawWithTransformFeedback scopedTF(this, funcName, mode, vertCount, const ScopedDrawWithTransformFeedback scopedTF(this, funcName, mode, vertCount,
instanceCount, &error); instanceCount, &error);
if (error) if (error)
@ -681,11 +668,6 @@ WebGLContext::DrawElementsInstanced(GLenum mode, GLsizei indexCount, GLenum type
if (IsContextLost()) if (IsContextLost())
return; return;
bool error = false;
ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
if (error)
return;
Maybe<uint32_t> lastVert; Maybe<uint32_t> lastVert;
if (!DrawElements_check(funcName, indexCount, type, byteOffset, instanceCount, if (!DrawElements_check(funcName, indexCount, type, byteOffset, instanceCount,
&lastVert)) &lastVert))
@ -693,11 +675,16 @@ WebGLContext::DrawElementsInstanced(GLenum mode, GLsizei indexCount, GLenum type
return; return;
} }
bool error = false;
const ScopedDrawHelper scopedHelper(this, funcName, mode, lastVert, instanceCount, const ScopedDrawHelper scopedHelper(this, funcName, mode, lastVert, instanceCount,
&error); &error);
if (error) if (error)
return; return;
const ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
if (error)
return;
{ {
ScopedDrawCallWrapper wrapper(*this); ScopedDrawCallWrapper wrapper(*this);
{ {
@ -759,8 +746,8 @@ WebGLContext::Draw_cleanup(const char* funcName)
break; break;
} }
} else { } else {
destWidth = mWidth; destWidth = mDefaultFB->mSize.width;
destHeight = mHeight; destHeight = mDefaultFB->mSize.height;
} }
if (mViewportWidth > int32_t(destWidth) || if (mViewportWidth > int32_t(destWidth) ||

Просмотреть файл

@ -30,10 +30,7 @@ WebGLContext::Clear(GLbitfield mask)
GenerateWarning("Calling gl.clear() with RASTERIZER_DISCARD enabled has no effects."); GenerateWarning("Calling gl.clear() with RASTERIZER_DISCARD enabled has no effects.");
} }
if (mBoundDrawFramebuffer) { if (mask & LOCAL_GL_COLOR_BUFFER_BIT && mBoundDrawFramebuffer) {
if (!mBoundDrawFramebuffer->ValidateAndInitAttachments(funcName))
return;
if (mask & LOCAL_GL_COLOR_BUFFER_BIT) { if (mask & LOCAL_GL_COLOR_BUFFER_BIT) {
for (const auto& cur : mBoundDrawFramebuffer->ColorDrawBuffers()) { for (const auto& cur : mBoundDrawFramebuffer->ColorDrawBuffers()) {
if (!cur->IsDefined()) if (!cur->IsDefined())
@ -55,8 +52,21 @@ WebGLContext::Clear(GLbitfield mask)
} }
} }
ScopedDrawCallWrapper wrapper(*this); if (!BindCurFBForDraw(funcName))
gl->fClear(mask); 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 static GLfloat
@ -121,11 +131,11 @@ WebGLContext::ColorMask(WebGLboolean r, WebGLboolean g, WebGLboolean b, WebGLboo
if (IsContextLost()) if (IsContextLost())
return; return;
mColorWriteMask[0] = r;
mColorWriteMask[1] = g;
mColorWriteMask[2] = b;
mColorWriteMask[3] = a;
gl->fColorMask(r, g, b, 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 void
@ -175,7 +185,7 @@ WebGLContext::DrawBuffers(const dom::Sequence<GLenum>& buffers)
} }
mDefaultFB_DrawBuffer0 = buffers[0]; mDefaultFB_DrawBuffer0 = buffers[0];
gl->Screen()->SetDrawBuffer(buffers[0]); // Don't actually set it.
} }
void void

Просмотреть файл

@ -1561,7 +1561,7 @@ WebGLContext::ReadPixelsImpl(GLint x, GLint y, GLsizei rawWidth, GLsizei rawHeig
const webgl::FormatUsageInfo* srcFormat; const webgl::FormatUsageInfo* srcFormat;
uint32_t srcWidth; uint32_t srcWidth;
uint32_t srcHeight; uint32_t srcHeight;
if (!ValidateCurFBForRead("readPixels", &srcFormat, &srcWidth, &srcHeight)) if (!BindCurFBForColorRead("readPixels", &srcFormat, &srcWidth, &srcHeight))
return; return;
////// //////
@ -1606,8 +1606,6 @@ WebGLContext::ReadPixelsImpl(GLint x, GLint y, GLsizei rawWidth, GLsizei rawHeig
//////////////// ////////////////
// Now that the errors are out of the way, on to actually reading! // Now that the errors are out of the way, on to actually reading!
OnBeforeReadCall();
if (!rwWidth || !rwHeight) { if (!rwWidth || !rwHeight) {
// Disjoint rects, so we're done already. // Disjoint rects, so we're done already.
DummyReadFramebufferOperation("readPixels"); DummyReadFramebufferOperation("readPixels");

Просмотреть файл

@ -60,7 +60,7 @@ WebGLContext::Enable(GLenum cap)
} }
bool bool
WebGLContext::GetStencilBits(GLint* const out_stencilBits) WebGLContext::GetStencilBits(GLint* const out_stencilBits) const
{ {
*out_stencilBits = 0; *out_stencilBits = 0;
if (mBoundDrawFramebuffer) { if (mBoundDrawFramebuffer) {
@ -190,7 +190,7 @@ WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
GLint ret = LOCAL_GL_NONE; GLint ret = LOCAL_GL_NONE;
if (!mBoundDrawFramebuffer) { if (!mBoundDrawFramebuffer) {
if (pname == LOCAL_GL_DRAW_BUFFER0) { if (pname == LOCAL_GL_DRAW_BUFFER0) {
ret = gl->Screen()->GetDrawBufferMode(); ret = mDefaultFB_DrawBuffer0;
} }
} else { } else {
gl->fGetIntegerv(pname, &ret); gl->fGetIntegerv(pname, &ret);
@ -342,7 +342,7 @@ WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
case LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE: { case LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE: {
const webgl::FormatUsageInfo* usage; const webgl::FormatUsageInfo* usage;
uint32_t width, height; uint32_t width, height;
if (!ValidateCurFBForRead(funcName, &usage, &width, &height)) if (!BindCurFBForColorRead(funcName, &usage, &width, &height))
return JS::NullValue(); return JS::NullValue();
const auto implPI = ValidImplementationColorReadPI(usage); const auto implPI = ValidImplementationColorReadPI(usage);

Просмотреть файл

@ -56,7 +56,7 @@ StringValue(JSContext* cx, const char* chars, ErrorResult& rv)
} }
void void
WebGLContext::GenerateWarning(const char* fmt, ...) WebGLContext::GenerateWarning(const char* fmt, ...) const
{ {
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
@ -67,7 +67,7 @@ WebGLContext::GenerateWarning(const char* fmt, ...)
} }
void void
WebGLContext::GenerateWarning(const char* fmt, va_list ap) WebGLContext::GenerateWarning(const char* fmt, va_list ap) const
{ {
if (!ShouldGenerateWarnings()) if (!ShouldGenerateWarnings())
return; return;
@ -146,7 +146,7 @@ WebGLContext::GeneratePerfWarning(const char* fmt, ...) const
} }
void void
WebGLContext::SynthesizeGLError(GLenum err) WebGLContext::SynthesizeGLError(GLenum err) const
{ {
/* ES2 section 2.5 "GL Errors" states that implementations can have /* ES2 section 2.5 "GL Errors" states that implementations can have
* multiple 'flags', as errors might be caught in different parts of * multiple 'flags', as errors might be caught in different parts of
@ -159,7 +159,7 @@ WebGLContext::SynthesizeGLError(GLenum err)
} }
void void
WebGLContext::SynthesizeGLError(GLenum err, const char* fmt, ...) WebGLContext::SynthesizeGLError(GLenum err, const char* fmt, ...) const
{ {
va_list va; va_list va;
va_start(va, fmt); va_start(va, fmt);
@ -170,7 +170,7 @@ WebGLContext::SynthesizeGLError(GLenum err, const char* fmt, ...)
} }
void void
WebGLContext::ErrorInvalidEnum(const char* fmt, ...) WebGLContext::ErrorInvalidEnum(const char* fmt, ...) const
{ {
va_list va; va_list va;
va_start(va, fmt); va_start(va, fmt);
@ -181,7 +181,7 @@ WebGLContext::ErrorInvalidEnum(const char* fmt, ...)
} }
void void
WebGLContext::ErrorInvalidEnumInfo(const char* info, GLenum enumValue) WebGLContext::ErrorInvalidEnumInfo(const char* info, GLenum enumValue) const
{ {
nsCString name; nsCString name;
EnumName(enumValue, &name); EnumName(enumValue, &name);
@ -191,7 +191,7 @@ WebGLContext::ErrorInvalidEnumInfo(const char* info, GLenum enumValue)
void void
WebGLContext::ErrorInvalidEnumInfo(const char* info, const char* funcName, WebGLContext::ErrorInvalidEnumInfo(const char* info, const char* funcName,
GLenum enumValue) GLenum enumValue) const
{ {
nsCString name; nsCString name;
EnumName(enumValue, &name); EnumName(enumValue, &name);
@ -201,7 +201,7 @@ WebGLContext::ErrorInvalidEnumInfo(const char* info, const char* funcName,
} }
void void
WebGLContext::ErrorInvalidOperation(const char* fmt, ...) WebGLContext::ErrorInvalidOperation(const char* fmt, ...) const
{ {
va_list va; va_list va;
va_start(va, fmt); va_start(va, fmt);
@ -212,7 +212,7 @@ WebGLContext::ErrorInvalidOperation(const char* fmt, ...)
} }
void void
WebGLContext::ErrorInvalidValue(const char* fmt, ...) WebGLContext::ErrorInvalidValue(const char* fmt, ...) const
{ {
va_list va; va_list va;
va_start(va, fmt); va_start(va, fmt);
@ -223,7 +223,7 @@ WebGLContext::ErrorInvalidValue(const char* fmt, ...)
} }
void void
WebGLContext::ErrorInvalidFramebufferOperation(const char* fmt, ...) WebGLContext::ErrorInvalidFramebufferOperation(const char* fmt, ...) const
{ {
va_list va; va_list va;
va_start(va, fmt); va_start(va, fmt);
@ -234,7 +234,7 @@ WebGLContext::ErrorInvalidFramebufferOperation(const char* fmt, ...)
} }
void void
WebGLContext::ErrorOutOfMemory(const char* fmt, ...) WebGLContext::ErrorOutOfMemory(const char* fmt, ...) const
{ {
va_list va; va_list va;
va_start(va, fmt); va_start(va, fmt);
@ -245,7 +245,7 @@ WebGLContext::ErrorOutOfMemory(const char* fmt, ...)
} }
void void
WebGLContext::ErrorImplementationBug(const char* fmt, ...) WebGLContext::ErrorImplementationBug(const char* fmt, ...) const
{ {
const nsPrintfCString warning("Implementation bug, please file at %s! %s", const nsPrintfCString warning("Implementation bug, please file at %s! %s",
"https://bugzilla.mozilla.org/", fmt); "https://bugzilla.mozilla.org/", fmt);
@ -260,7 +260,7 @@ WebGLContext::ErrorImplementationBug(const char* fmt, ...)
return SynthesizeGLError(LOCAL_GL_OUT_OF_MEMORY); return SynthesizeGLError(LOCAL_GL_OUT_OF_MEMORY);
} }
const char* /*static*/ const char*
WebGLContext::ErrorName(GLenum error) WebGLContext::ErrorName(GLenum error)
{ {
switch(error) { switch(error) {
@ -625,7 +625,8 @@ WebGLContext::EnumName(GLenum val, nsCString* out_name)
} }
void void
WebGLContext::ErrorInvalidEnumArg(const char* funcName, const char* argName, GLenum val) WebGLContext::ErrorInvalidEnumArg(const char* funcName, const char* argName,
GLenum val) const
{ {
nsCString enumName; nsCString enumName;
EnumName(val, &enumName); EnumName(val, &enumName);
@ -676,7 +677,7 @@ IsTextureFormatCompressed(TexInternalFormat format)
} }
GLenum GLenum
WebGLContext::GetAndFlushUnderlyingGLErrors() WebGLContext::GetAndFlushUnderlyingGLErrors() const
{ {
// Get and clear GL error in ALL cases. // Get and clear GL error in ALL cases.
GLenum error = gl->fGetError(); GLenum error = gl->fGetError();
@ -739,7 +740,7 @@ AssertUintParamCorrect(gl::GLContext*, GLenum, GLuint)
#endif #endif
void void
WebGLContext::AssertCachedBindings() WebGLContext::AssertCachedBindings() const
{ {
#ifdef DEBUG #ifdef DEBUG
GetAndFlushUnderlyingGLErrors(); GetAndFlushUnderlyingGLErrors();
@ -749,21 +750,6 @@ WebGLContext::AssertCachedBindings()
AssertUintParamCorrect(gl, LOCAL_GL_VERTEX_ARRAY_BINDING, bound); 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; GLint stencilBits = 0;
if (GetStencilBits(&stencilBits)) { // Depends on current draw framebuffer. if (GetStencilBits(&stencilBits)) { // Depends on current draw framebuffer.
const GLuint stencilRefMask = (1 << stencilBits) - 1; const GLuint stencilRefMask = (1 << stencilBits) - 1;
@ -804,7 +790,7 @@ WebGLContext::AssertCachedBindings()
} }
void void
WebGLContext::AssertCachedGlobalState() WebGLContext::AssertCachedGlobalState() const
{ {
#ifdef DEBUG #ifdef DEBUG
GetAndFlushUnderlyingGLErrors(); GetAndFlushUnderlyingGLErrors();
@ -812,19 +798,10 @@ WebGLContext::AssertCachedGlobalState()
//////////////// ////////////////
// Draw state // Draw state
MOZ_ASSERT(gl->fIsEnabled(LOCAL_GL_DEPTH_TEST) == mDepthTestEnabled);
MOZ_ASSERT(gl->fIsEnabled(LOCAL_GL_DITHER) == mDitherEnabled); MOZ_ASSERT(gl->fIsEnabled(LOCAL_GL_DITHER) == mDitherEnabled);
MOZ_ASSERT_IF(IsWebGL2(), MOZ_ASSERT_IF(IsWebGL2(),
gl->fIsEnabled(LOCAL_GL_RASTERIZER_DISCARD) == mRasterizerDiscardEnabled); gl->fIsEnabled(LOCAL_GL_RASTERIZER_DISCARD) == mRasterizerDiscardEnabled);
MOZ_ASSERT(gl->fIsEnabled(LOCAL_GL_SCISSOR_TEST) == mScissorTestEnabled); 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}; GLfloat colorClearValue[4] = {0.0f, 0.0f, 0.0f, 0.0f};
gl->fGetFloatv(LOCAL_GL_COLOR_CLEAR_VALUE, colorClearValue); gl->fGetFloatv(LOCAL_GL_COLOR_CLEAR_VALUE, colorClearValue);

Просмотреть файл

@ -420,15 +420,13 @@ WebGLContext::InitAndValidateGL(FailureReason* const out_failReason)
// These are the default values, see 6.2 State tables in the // These are the default values, see 6.2 State tables in the
// OpenGL ES 2.0.25 spec. // OpenGL ES 2.0.25 spec.
mColorWriteMask[0] = 1; mColorWriteMask = 0x0f;
mColorWriteMask[1] = 1; mDriverColorMask = mColorWriteMask;
mColorWriteMask[2] = 1;
mColorWriteMask[3] = 1;
mDepthWriteMask = 1;
mColorClearValue[0] = 0.f; mColorClearValue[0] = 0.f;
mColorClearValue[1] = 0.f; mColorClearValue[1] = 0.f;
mColorClearValue[2] = 0.f; mColorClearValue[2] = 0.f;
mColorClearValue[3] = 0.f; mColorClearValue[3] = 0.f;
mDepthWriteMask = true;
mDepthClearValue = 1.f; mDepthClearValue = 1.f;
mStencilClearValue = 0; mStencilClearValue = 0;
mStencilRefFront = 0; mStencilRefFront = 0;
@ -461,13 +459,18 @@ WebGLContext::InitAndValidateGL(FailureReason* const out_failReason)
mDitherEnabled = true; mDitherEnabled = true;
mRasterizerDiscardEnabled = false; mRasterizerDiscardEnabled = false;
mScissorTestEnabled = false; mScissorTestEnabled = false;
mDepthTestEnabled = 0; mDepthTestEnabled = 0;
mDriverDepthTest = false;
mStencilTestEnabled = 0; mStencilTestEnabled = 0;
mDriverStencilTest = false;
mGenerateMipmapHint = LOCAL_GL_DONT_CARE; mGenerateMipmapHint = LOCAL_GL_DONT_CARE;
// Bindings, etc. // Bindings, etc.
mActiveTexture = 0; mActiveTexture = 0;
mDefaultFB_DrawBuffer0 = LOCAL_GL_BACK; mDefaultFB_DrawBuffer0 = LOCAL_GL_BACK;
mDefaultFB_ReadBuffer = LOCAL_GL_BACK;
mEmitContextLostErrorOnce = true; mEmitContextLostErrorOnce = true;
mWebGLError = LOCAL_GL_NO_ERROR; mWebGLError = LOCAL_GL_NO_ERROR;

Просмотреть файл

@ -889,7 +889,7 @@ WebGLFramebuffer::PrecheckFramebufferStatus(nsCString* const out_info) const
// Validation // Validation
bool bool
WebGLFramebuffer::ValidateAndInitAttachments(const char* funcName) WebGLFramebuffer::ValidateAndInitAttachments(const char* funcName) const
{ {
MOZ_ASSERT(mContext->mBoundDrawFramebuffer == this || MOZ_ASSERT(mContext->mBoundDrawFramebuffer == this ||
mContext->mBoundReadFramebuffer == this); mContext->mBoundReadFramebuffer == this);
@ -942,13 +942,11 @@ WebGLFramebuffer::ValidateClearBufferType(const char* funcName, GLenum buffer,
} }
bool bool
WebGLFramebuffer::ValidateForRead(const char* funcName, WebGLFramebuffer::ValidateForColorRead(const char* funcName,
const webgl::FormatUsageInfo** const out_format, const webgl::FormatUsageInfo** const out_format,
uint32_t* const out_width, uint32_t* const out_height) uint32_t* const out_width,
uint32_t* const out_height) const
{ {
if (!ValidateAndInitAttachments(funcName))
return false;
if (!mColorReadBuffer) { if (!mColorReadBuffer) {
mContext->ErrorInvalidOperation("%s: READ_BUFFER must not be NONE.", funcName); mContext->ErrorInvalidOperation("%s: READ_BUFFER must not be NONE.", funcName);
return false; return false;
@ -1185,7 +1183,7 @@ WebGLFramebuffer::RefreshResolvedData()
// Entrypoints // Entrypoints
FBStatus FBStatus
WebGLFramebuffer::CheckFramebufferStatus(const char* funcName) WebGLFramebuffer::CheckFramebufferStatus(const char* const funcName) const
{ {
if (IsResolvedComplete()) if (IsResolvedComplete())
return LOCAL_GL_FRAMEBUFFER_COMPLETE; return LOCAL_GL_FRAMEBUFFER_COMPLETE;
@ -1651,15 +1649,16 @@ GetBackbufferFormats(const WebGLContext* webgl,
/*static*/ void /*static*/ void
WebGLFramebuffer::BlitFramebuffer(WebGLContext* webgl, WebGLFramebuffer::BlitFramebuffer(WebGLContext* webgl,
const WebGLFramebuffer* srcFB, GLint srcX0, GLint srcY0, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
const WebGLFramebuffer* dstFB, GLint dstX0, GLint dstY0,
GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter) GLbitfield mask, GLenum filter)
{ {
const char funcName[] = "blitFramebuffer"; const char funcName[] = "blitFramebuffer";
const auto& gl = webgl->gl; const auto& gl = webgl->gl;
const auto& srcFB = webgl->mBoundReadFramebuffer;
const auto& dstFB = webgl->mBoundDrawFramebuffer;
//// ////
// Collect data // Collect data
@ -1928,8 +1927,7 @@ WebGLFramebuffer::BlitFramebuffer(WebGLContext* webgl,
//// ////
webgl->OnBeforeReadCall(); const ScopedDrawCallWrapper wrapper(*webgl);
WebGLContext::ScopedDrawCallWrapper wrapper(*webgl);
gl->fBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, gl->fBlitFramebuffer(srcX0, srcY0, srcX1, srcY1,
dstX0, dstY0, dstX1, dstY1, dstX0, dstY0, dstX1, dstY1,
mask, filter); mask, filter);

Просмотреть файл

@ -195,7 +195,7 @@ protected:
explicit ResolvedData(const WebGLFramebuffer& parent); explicit ResolvedData(const WebGLFramebuffer& parent);
}; };
UniquePtr<const ResolvedData> mResolvedCompleteData; mutable UniquePtr<const ResolvedData> mResolvedCompleteData;
//// ////
@ -236,13 +236,13 @@ protected:
public: public:
void DetachTexture(const char* funcName, const WebGLTexture* tex); void DetachTexture(const char* funcName, const WebGLTexture* tex);
void DetachRenderbuffer(const char* funcName, const WebGLRenderbuffer* rb); 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, bool ValidateClearBufferType(const char* funcName, GLenum buffer, uint32_t drawBuffer,
GLenum funcType) const; GLenum funcType) const;
bool ValidateForRead(const char* info, bool ValidateForColorRead(const char* funcName,
const webgl::FormatUsageInfo** const out_format, const webgl::FormatUsageInfo** out_format,
uint32_t* const out_width, uint32_t* const out_height); uint32_t* out_width, uint32_t* out_height) const;
//////////////// ////////////////
// Getters // Getters
@ -268,7 +268,7 @@ public:
//////////////// ////////////////
// WebGL funcs // WebGL funcs
FBStatus CheckFramebufferStatus(const char* funcName); FBStatus CheckFramebufferStatus(const char* funcName) const;
void FramebufferRenderbuffer(const char* funcName, GLenum attachment, GLenum rbtarget, void FramebufferRenderbuffer(const char* funcName, GLenum attachment, GLenum rbtarget,
WebGLRenderbuffer* rb); WebGLRenderbuffer* rb);
void FramebufferTexture2D(const char* funcName, GLenum attachment, void FramebufferTexture2D(const char* funcName, GLenum attachment,
@ -283,10 +283,8 @@ public:
ErrorResult* const out_error); ErrorResult* const out_error);
static void BlitFramebuffer(WebGLContext* webgl, static void BlitFramebuffer(WebGLContext* webgl,
const WebGLFramebuffer* src, GLint srcX0, GLint srcY0, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
const WebGLFramebuffer* dst, GLint dstX0, GLint dstY0,
GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter); GLbitfield mask, GLenum filter);
}; };

Просмотреть файл

@ -2121,8 +2121,8 @@ WebGLTexture::CopyTexImage2D(TexImageTarget target, GLint level, GLenum internal
const webgl::FormatUsageInfo* srcUsage; const webgl::FormatUsageInfo* srcUsage;
uint32_t srcTotalWidth; uint32_t srcTotalWidth;
uint32_t srcTotalHeight; uint32_t srcTotalHeight;
if (!mContext->ValidateCurFBForRead(funcName, &srcUsage, &srcTotalWidth, if (!mContext->BindCurFBForColorRead(funcName, &srcUsage, &srcTotalWidth,
&srcTotalHeight)) &srcTotalHeight))
{ {
return; return;
} }
@ -2155,8 +2155,6 @@ WebGLTexture::CopyTexImage2D(TexImageTarget target, GLint level, GLenum internal
//////////////////////////////////// ////////////////////////////////////
// Do the thing! // Do the thing!
mContext->OnBeforeReadCall();
const bool isSubImage = false; const bool isSubImage = false;
if (!DoCopyTexOrSubImage(mContext, funcName, isSubImage, this, target, level, x, y, if (!DoCopyTexOrSubImage(mContext, funcName, isSubImage, this, target, level, x, y,
srcTotalWidth, srcTotalHeight, srcUsage, 0, 0, 0, width, srcTotalWidth, srcTotalHeight, srcUsage, 0, 0, 0, width,
@ -2215,8 +2213,8 @@ WebGLTexture::CopyTexSubImage(const char* funcName, TexImageTarget target, GLint
const webgl::FormatUsageInfo* srcUsage; const webgl::FormatUsageInfo* srcUsage;
uint32_t srcTotalWidth; uint32_t srcTotalWidth;
uint32_t srcTotalHeight; uint32_t srcTotalHeight;
if (!mContext->ValidateCurFBForRead(funcName, &srcUsage, &srcTotalWidth, if (!mContext->BindCurFBForColorRead(funcName, &srcUsage, &srcTotalWidth,
&srcTotalHeight)) &srcTotalHeight))
{ {
return; return;
} }
@ -2234,8 +2232,6 @@ WebGLTexture::CopyTexSubImage(const char* funcName, TexImageTarget target, GLint
//////////////////////////////////// ////////////////////////////////////
// Do the thing! // Do the thing!
mContext->OnBeforeReadCall();
bool uploadWillInitialize; bool uploadWillInitialize;
if (!EnsureImageDataInitializedForUpload(this, funcName, target, level, xOffset, if (!EnsureImageDataInitializedForUpload(this, funcName, target, level, xOffset,
yOffset, zOffset, width, height, depth, yOffset, zOffset, width, height, depth,

Просмотреть файл

@ -201,6 +201,7 @@ include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul' FINAL_LIBRARY = 'xul'
LOCAL_INCLUDES += [ LOCAL_INCLUDES += [
'../workers', '../workers',
'/', # Allow including relpaths from root.
'/dom/base', '/dom/base',
'/dom/html', '/dom/html',
'/dom/svg', '/dom/svg',

Просмотреть файл

@ -2520,8 +2520,6 @@ GLContext::Readback(SharedSurface* src, gfx::DataSourceSurface* dest)
{ {
MOZ_ASSERT(src && dest); MOZ_ASSERT(src && dest);
MOZ_ASSERT(dest->GetSize() == src->mSize); MOZ_ASSERT(dest->GetSize() == src->mSize);
MOZ_ASSERT(dest->GetFormat() == (src->mHasAlpha ? SurfaceFormat::B8G8R8A8
: SurfaceFormat::B8G8R8X8));
if (!MakeCurrent()) { if (!MakeCurrent()) {
return false; return false;

Просмотреть файл

@ -155,8 +155,8 @@ CopyableCanvasRenderer::ReadbackSurface()
} }
IntSize readSize(frontbuffer->mSize); IntSize readSize(frontbuffer->mSize);
SurfaceFormat format = SurfaceFormat format = frontbuffer->mHasAlpha ? SurfaceFormat::B8G8R8X8
mOpaque ? SurfaceFormat::B8G8R8X8 : SurfaceFormat::B8G8R8A8; : SurfaceFormat::B8G8R8A8;
bool needsPremult = frontbuffer->mHasAlpha && !mIsAlphaPremultiplied; bool needsPremult = frontbuffer->mHasAlpha && !mIsAlphaPremultiplied;
RefPtr<DataSourceSurface> resultSurf = GetTempSurface(readSize, format); RefPtr<DataSourceSurface> resultSurf = GetTempSurface(readSize, format);

Просмотреть файл

@ -51,7 +51,6 @@ ShareableCanvasRenderer::Initialize(const CanvasInitializeData& aData)
MOZ_ASSERT(screen); MOZ_ASSERT(screen);
caps = screen->mCaps; caps = screen->mCaps;
} }
MOZ_ASSERT(caps.alpha == aData.mHasAlpha);
auto forwarder = GetForwarder(); auto forwarder = GetForwarder();

Просмотреть файл

@ -755,6 +755,7 @@ private:
DECL_GFX_PREF(Live, "webgl.max-warnings-per-context", WebGLMaxWarningsPerContext, uint32_t, 32); 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.min_capability_mode", WebGLMinCapabilityMode, bool, false);
DECL_GFX_PREF(Live, "webgl.msaa-force", WebGLForceMSAA, 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.prefer-16bpp", WebGLPrefer16bpp, bool, false);
DECL_GFX_PREF(Live, "webgl.restore-context-when-visible", WebGLRestoreWhenVisible, bool, true); 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-immediate-queries", WebGLImmediateQueries, bool, false);