mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 707460 - Fix WebGL framebuffer statuses and errors - r=jgilbert
This commit is contained in:
parent
249106d9ba
commit
0f5ca361a9
@ -1104,6 +1104,17 @@ WebGLContext::EnsureBackbufferClearedAsNeeded()
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
nsresult
|
||||
WebGLContext::DummyFramebufferOperation(const char *info)
|
||||
{
|
||||
WebGLenum status;
|
||||
CheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER, &status);
|
||||
if (status == LOCAL_GL_FRAMEBUFFER_COMPLETE)
|
||||
return NS_OK;
|
||||
else
|
||||
return ErrorInvalidFramebufferOperation("%s: incomplete framebuffer", info);
|
||||
}
|
||||
|
||||
// We use this timer for many things. Here are the things that it is activated for:
|
||||
// 1) If a script is using the MOZ_WEBGL_lose_context extension.
|
||||
// 2) If we are using EGL and _NOT ANGLE_, we query periodically to see if the
|
||||
|
@ -566,13 +566,16 @@ public:
|
||||
nsresult ErrorInvalidEnum(const char *fmt = 0, ...);
|
||||
nsresult ErrorInvalidOperation(const char *fmt = 0, ...);
|
||||
nsresult ErrorInvalidValue(const char *fmt = 0, ...);
|
||||
nsresult ErrorInvalidFramebufferOperation(const char *fmt = 0, ...);
|
||||
nsresult ErrorInvalidEnumInfo(const char *info, PRUint32 enumvalue) {
|
||||
return ErrorInvalidEnum("%s: invalid enum value 0x%x", info, enumvalue);
|
||||
}
|
||||
nsresult ErrorOutOfMemory(const char *fmt = 0, ...);
|
||||
|
||||
|
||||
const char *ErrorName(GLenum error);
|
||||
|
||||
nsresult DummyFramebufferOperation(const char *info);
|
||||
|
||||
WebGLTexture *activeBoundTextureForTarget(WebGLenum target) {
|
||||
return target == LOCAL_GL_TEXTURE_2D ? mBound2DTextures[mActiveTexture]
|
||||
: mBoundCubeMapTextures[mActiveTexture];
|
||||
@ -1939,31 +1942,6 @@ public:
|
||||
return mTextureCubeMapFace;
|
||||
}
|
||||
|
||||
bool IsIncompatibleWithAttachmentPoint() const
|
||||
{
|
||||
// textures can only be color textures in WebGL
|
||||
if (mTexturePtr)
|
||||
return mAttachmentPoint != LOCAL_GL_COLOR_ATTACHMENT0;
|
||||
|
||||
if (mRenderbufferPtr) {
|
||||
WebGLenum format = mRenderbufferPtr->InternalFormat();
|
||||
switch (mAttachmentPoint) {
|
||||
case LOCAL_GL_COLOR_ATTACHMENT0:
|
||||
return format != LOCAL_GL_RGB565 &&
|
||||
format != LOCAL_GL_RGB5_A1 &&
|
||||
format != LOCAL_GL_RGBA4;
|
||||
case LOCAL_GL_DEPTH_ATTACHMENT:
|
||||
return format != LOCAL_GL_DEPTH_COMPONENT16;
|
||||
case LOCAL_GL_STENCIL_ATTACHMENT:
|
||||
return format != LOCAL_GL_STENCIL_INDEX8;
|
||||
case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT:
|
||||
return format != LOCAL_GL_DEPTH_STENCIL;
|
||||
}
|
||||
}
|
||||
|
||||
return false; // no attachment at all, so no incompatibility
|
||||
}
|
||||
|
||||
bool HasUninitializedRenderbuffer() const {
|
||||
return mRenderbufferPtr && !mRenderbufferPtr->Initialized();
|
||||
}
|
||||
@ -1988,6 +1966,39 @@ public:
|
||||
otherRect &&
|
||||
thisRect->HasSameDimensionsAs(*otherRect);
|
||||
}
|
||||
|
||||
bool IsComplete() const {
|
||||
const WebGLRectangleObject *thisRect = RectangleObject();
|
||||
|
||||
if (!thisRect ||
|
||||
!thisRect->Width() ||
|
||||
!thisRect->Height())
|
||||
return false;
|
||||
|
||||
if (mTexturePtr)
|
||||
return mAttachmentPoint == LOCAL_GL_COLOR_ATTACHMENT0;
|
||||
|
||||
if (mRenderbufferPtr) {
|
||||
WebGLenum format = mRenderbufferPtr->InternalFormat();
|
||||
switch (mAttachmentPoint) {
|
||||
case LOCAL_GL_COLOR_ATTACHMENT0:
|
||||
return format == LOCAL_GL_RGB565 ||
|
||||
format == LOCAL_GL_RGB5_A1 ||
|
||||
format == LOCAL_GL_RGBA4;
|
||||
case LOCAL_GL_DEPTH_ATTACHMENT:
|
||||
return format == LOCAL_GL_DEPTH_COMPONENT16;
|
||||
case LOCAL_GL_STENCIL_ATTACHMENT:
|
||||
return format == LOCAL_GL_STENCIL_INDEX8;
|
||||
case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT:
|
||||
return format == LOCAL_GL_DEPTH_STENCIL;
|
||||
default:
|
||||
NS_ABORT(); // should have been validated earlier
|
||||
}
|
||||
}
|
||||
|
||||
NS_ABORT(); // should never get there
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class WebGLFramebuffer
|
||||
@ -2135,50 +2146,23 @@ public:
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool CheckAndInitializeRenderbuffers()
|
||||
{
|
||||
if (HasBadAttachments()) {
|
||||
mContext->SynthesizeGLError(LOCAL_GL_INVALID_FRAMEBUFFER_OPERATION);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mColorAttachment.HasUninitializedRenderbuffer() ||
|
||||
mDepthAttachment.HasUninitializedRenderbuffer() ||
|
||||
mStencilAttachment.HasUninitializedRenderbuffer() ||
|
||||
mDepthStencilAttachment.HasUninitializedRenderbuffer())
|
||||
{
|
||||
InitializeRenderbuffers();
|
||||
}
|
||||
|
||||
return true;
|
||||
bool HasIncompleteAttachment() const {
|
||||
return (mColorAttachment.IsDefined() && !mColorAttachment.IsComplete()) ||
|
||||
(mDepthAttachment.IsDefined() && !mDepthAttachment.IsComplete()) ||
|
||||
(mStencilAttachment.IsDefined() && !mStencilAttachment.IsComplete()) ||
|
||||
(mDepthStencilAttachment.IsDefined() && !mDepthStencilAttachment.IsComplete());
|
||||
}
|
||||
|
||||
bool HasBadAttachments() const {
|
||||
if (mColorAttachment.IsIncompatibleWithAttachmentPoint() ||
|
||||
mDepthAttachment.IsIncompatibleWithAttachmentPoint() ||
|
||||
mStencilAttachment.IsIncompatibleWithAttachmentPoint() ||
|
||||
mDepthStencilAttachment.IsIncompatibleWithAttachmentPoint())
|
||||
{
|
||||
// some attachment is incompatible with its attachment point
|
||||
return true;
|
||||
}
|
||||
bool HasDepthStencilConflict() const {
|
||||
return int(mDepthAttachment.IsDefined()) +
|
||||
int(mStencilAttachment.IsDefined()) +
|
||||
int(mDepthStencilAttachment.IsDefined()) >= 2;
|
||||
}
|
||||
|
||||
if (int(mDepthAttachment.IsDefined()) +
|
||||
int(mStencilAttachment.IsDefined()) +
|
||||
int(mDepthStencilAttachment.IsDefined()) >= 2)
|
||||
{
|
||||
// has at least two among Depth, Stencil, DepthStencil
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mDepthAttachment.IsDefined() && !mDepthAttachment.HasSameDimensionsAs(mColorAttachment))
|
||||
return true;
|
||||
if (mStencilAttachment.IsDefined() && !mStencilAttachment.HasSameDimensionsAs(mColorAttachment))
|
||||
return true;
|
||||
if (mDepthStencilAttachment.IsDefined() && !mDepthStencilAttachment.HasSameDimensionsAs(mColorAttachment))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
bool HasAttachmentsOfMismatchedDimensions() const {
|
||||
return (mDepthAttachment.IsDefined() && !mDepthAttachment.HasSameDimensionsAs(mColorAttachment)) ||
|
||||
(mStencilAttachment.IsDefined() && !mStencilAttachment.HasSameDimensionsAs(mColorAttachment)) ||
|
||||
(mDepthStencilAttachment.IsDefined() && !mDepthStencilAttachment.HasSameDimensionsAs(mColorAttachment));
|
||||
}
|
||||
|
||||
const WebGLFramebufferAttachment& ColorAttachment() const {
|
||||
@ -2238,15 +2222,32 @@ public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIWEBGLFRAMEBUFFER
|
||||
|
||||
protected:
|
||||
|
||||
// protected because WebGLContext should only call InitializeRenderbuffers
|
||||
void InitializeRenderbuffers()
|
||||
bool CheckAndInitializeRenderbuffers()
|
||||
{
|
||||
// enforce WebGL section 6.5 which is WebGL-specific, hence OpenGL itself would not
|
||||
// generate the INVALID_FRAMEBUFFER_OPERATION that we need here
|
||||
if (HasDepthStencilConflict())
|
||||
return false;
|
||||
|
||||
if (!mColorAttachment.HasUninitializedRenderbuffer() &&
|
||||
!mDepthAttachment.HasUninitializedRenderbuffer() &&
|
||||
!mStencilAttachment.HasUninitializedRenderbuffer() &&
|
||||
!mDepthStencilAttachment.HasUninitializedRenderbuffer())
|
||||
return true;
|
||||
|
||||
// ensure INVALID_FRAMEBUFFER_OPERATION in zero-size case
|
||||
const WebGLRectangleObject *rect = mColorAttachment.RectangleObject();
|
||||
if (!rect ||
|
||||
!rect->Width() ||
|
||||
!rect->Height())
|
||||
return false;
|
||||
|
||||
mContext->MakeContextCurrent();
|
||||
|
||||
if (mContext->gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER) != LOCAL_GL_FRAMEBUFFER_COMPLETE)
|
||||
return;
|
||||
WebGLenum status;
|
||||
mContext->CheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER, &status);
|
||||
if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE)
|
||||
return false;
|
||||
|
||||
PRUint32 mask = 0;
|
||||
|
||||
@ -2265,7 +2266,6 @@ protected:
|
||||
mask |= LOCAL_GL_STENCIL_BUFFER_BIT;
|
||||
}
|
||||
|
||||
const WebGLRectangleObject *rect = mColorAttachment.RectangleObject();
|
||||
mContext->ForceClearFramebufferWithDefaultValues(mask, nsIntRect(0, 0, rect->Width(), rect->Height()));
|
||||
|
||||
if (mColorAttachment.HasUninitializedRenderbuffer())
|
||||
@ -2279,6 +2279,8 @@ protected:
|
||||
|
||||
if (mDepthStencilAttachment.HasUninitializedRenderbuffer())
|
||||
mDepthStencilAttachment.Renderbuffer()->SetInitialized(true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
WebGLuint mGLName;
|
||||
|
@ -686,8 +686,16 @@ WebGLContext::CheckFramebufferStatus(WebGLenum target, WebGLenum *retval)
|
||||
if (target != LOCAL_GL_FRAMEBUFFER)
|
||||
return ErrorInvalidEnum("checkFramebufferStatus: target must be FRAMEBUFFER");
|
||||
|
||||
if (mBoundFramebuffer && mBoundFramebuffer->HasBadAttachments())
|
||||
if (!mBoundFramebuffer)
|
||||
*retval = LOCAL_GL_FRAMEBUFFER_COMPLETE;
|
||||
else if(mBoundFramebuffer->HasDepthStencilConflict())
|
||||
*retval = LOCAL_GL_FRAMEBUFFER_UNSUPPORTED;
|
||||
else if(!mBoundFramebuffer->ColorAttachment().IsDefined())
|
||||
*retval = LOCAL_GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
|
||||
else if(mBoundFramebuffer->HasIncompleteAttachment())
|
||||
*retval = LOCAL_GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
|
||||
else if(mBoundFramebuffer->HasAttachmentsOfMismatchedDimensions())
|
||||
*retval = LOCAL_GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
|
||||
else
|
||||
*retval = gl->fCheckFramebufferStatus(target);
|
||||
|
||||
@ -710,7 +718,7 @@ WebGLContext::Clear(PRUint32 mask)
|
||||
|
||||
if (mBoundFramebuffer) {
|
||||
if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers())
|
||||
return NS_OK;
|
||||
return ErrorInvalidFramebufferOperation("clear: incomplete framebuffer");
|
||||
} else {
|
||||
// no FBO is bound, so we are clearing the backbuffer here
|
||||
EnsureBackbufferClearedAsNeeded();
|
||||
@ -861,7 +869,7 @@ WebGLContext::CopyTexSubImage2D_base(WebGLenum target,
|
||||
|| y+height <= 0)
|
||||
{
|
||||
// we are completely outside of range, can exit now with buffer filled with zeros
|
||||
return NS_OK;
|
||||
return DummyFramebufferOperation(info);
|
||||
}
|
||||
|
||||
GLint actual_x = clamped(x, 0, framebufferWidth);
|
||||
@ -946,8 +954,9 @@ WebGLContext::CopyTexImage2D(WebGLenum target,
|
||||
return ErrorInvalidOperation("copyTexImage2D: texture format requires an alpha channel "
|
||||
"but the framebuffer doesn't have one");
|
||||
|
||||
if (mBoundFramebuffer && !mBoundFramebuffer->CheckAndInitializeRenderbuffers())
|
||||
return NS_OK;
|
||||
if (mBoundFramebuffer)
|
||||
if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers())
|
||||
return ErrorInvalidFramebufferOperation("copyTexImage2D: incomplete framebuffer");
|
||||
|
||||
WebGLTexture *tex = activeBoundTextureForTarget(target);
|
||||
if (!tex)
|
||||
@ -1053,8 +1062,9 @@ WebGLContext::CopyTexSubImage2D(WebGLenum target,
|
||||
return ErrorInvalidOperation("copyTexSubImage2D: texture format requires an alpha channel "
|
||||
"but the framebuffer doesn't have one");
|
||||
|
||||
if (mBoundFramebuffer && !mBoundFramebuffer->CheckAndInitializeRenderbuffers())
|
||||
return NS_OK;
|
||||
if (mBoundFramebuffer)
|
||||
if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers())
|
||||
return ErrorInvalidFramebufferOperation("copyTexSubImage2D: incomplete framebuffer");
|
||||
|
||||
return CopyTexSubImage2D_base(target, level, format, xoffset, yoffset, x, y, width, height, true);
|
||||
}
|
||||
@ -1588,7 +1598,7 @@ WebGLContext::DrawArrays(GLenum mode, WebGLint first, WebGLsizei count)
|
||||
|
||||
if (mBoundFramebuffer) {
|
||||
if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers())
|
||||
return NS_OK;
|
||||
return ErrorInvalidFramebufferOperation("drawArrays: incomplete framebuffer");
|
||||
} else {
|
||||
EnsureBackbufferClearedAsNeeded();
|
||||
}
|
||||
@ -1699,7 +1709,7 @@ WebGLContext::DrawElements(WebGLenum mode, WebGLsizei count, WebGLenum type, Web
|
||||
|
||||
if (mBoundFramebuffer) {
|
||||
if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers())
|
||||
return NS_OK;
|
||||
return ErrorInvalidFramebufferOperation("drawElements: incomplete framebuffer");
|
||||
} else {
|
||||
EnsureBackbufferClearedAsNeeded();
|
||||
}
|
||||
@ -3372,7 +3382,7 @@ WebGLContext::ReadPixels_base(WebGLint x, WebGLint y, WebGLsizei width, WebGLsiz
|
||||
if (mBoundFramebuffer) {
|
||||
// prevent readback of arbitrary video memory through uninitialized renderbuffers!
|
||||
if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers())
|
||||
return NS_OK;
|
||||
return ErrorInvalidFramebufferOperation("readPixels: incomplete framebuffer");
|
||||
} else {
|
||||
EnsureBackbufferClearedAsNeeded();
|
||||
}
|
||||
@ -3380,7 +3390,7 @@ WebGLContext::ReadPixels_base(WebGLint x, WebGLint y, WebGLsizei width, WebGLsiz
|
||||
|
||||
// If we won't be reading any pixels anyways, just skip the actual reading
|
||||
if (width == 0 || height == 0)
|
||||
return NS_OK;
|
||||
return DummyFramebufferOperation("readPixels");
|
||||
|
||||
if (CanvasUtils::CheckSaneSubrectSize(x, y, width, height, framebufferWidth, framebufferHeight)) {
|
||||
// the easy case: we're not reading out-of-range pixels
|
||||
@ -3403,7 +3413,7 @@ WebGLContext::ReadPixels_base(WebGLint x, WebGLint y, WebGLsizei width, WebGLsiz
|
||||
|| y+height <= 0)
|
||||
{
|
||||
// we are completely outside of range, can exit now with buffer filled with zeros
|
||||
return NS_OK;
|
||||
return DummyFramebufferOperation("readPixels");
|
||||
}
|
||||
|
||||
// compute the parameters of the subrect we're actually going to call glReadPixels on
|
||||
@ -3568,7 +3578,7 @@ WebGLContext::RenderbufferStorage(WebGLenum target, WebGLenum internalformat, We
|
||||
GLenum error = LOCAL_GL_NO_ERROR;
|
||||
UpdateWebGLErrorAndClearGLError(&error);
|
||||
if (error) {
|
||||
LogMessageIfVerbose("bufferData generated error %s", ErrorName(error));
|
||||
LogMessageIfVerbose("renderbufferStorage generated error %s", ErrorName(error));
|
||||
return NS_OK;
|
||||
}
|
||||
} else {
|
||||
|
@ -197,6 +197,17 @@ WebGLContext::ErrorInvalidValue(const char *fmt, ...)
|
||||
return SynthesizeGLError(LOCAL_GL_INVALID_VALUE);
|
||||
}
|
||||
|
||||
nsresult
|
||||
WebGLContext::ErrorInvalidFramebufferOperation(const char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
LogMessageIfVerbose(fmt, va);
|
||||
va_end(va);
|
||||
|
||||
return SynthesizeGLError(LOCAL_GL_INVALID_FRAMEBUFFER_OPERATION);
|
||||
}
|
||||
|
||||
nsresult
|
||||
WebGLContext::ErrorOutOfMemory(const char *fmt, ...)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user