--- a/dom/canvas/TexUnpackBlob.cpp
+++ b/dom/canvas/TexUnpackBlob.cpp
@@ -18,120 +18,48 @@
namespace mozilla {
namespace webgl {
static GLenum
DoTexOrSubImage(bool isSubImage, gl::GLContext* gl, TexImageTarget target, GLint level,
const DriverUnpackInfo* dui, GLint xOffset, GLint yOffset, GLint zOffset,
GLsizei width, GLsizei height, GLsizei depth, const void* data)
{
- auto internalFormat = dui->internalFormat;
- auto unpackFormat = dui->unpackFormat;
- auto unpackType = dui->unpackType;
-
if (isSubImage) {
return DoTexSubImage(gl, target, level, xOffset, yOffset, zOffset, width, height,
- depth, unpackFormat, unpackType, data);
+ depth, dui->ToPacking(), data);
} else {
- return DoTexImage(gl, target, level, internalFormat, width, height, depth,
- unpackFormat, unpackType, data);
+ return DoTexImage(gl, target, level, dui, width, height, depth, data);
}
}
//////////////////////////////////////////////////////////////////////////////////////////
// TexUnpackBuffer
-static bool
-GetPackedSizeForUnpack(uint32_t bytesPerPixel, uint8_t rowByteAlignment,
- uint32_t maybeStridePixelsPerRow, uint32_t maybeStrideRowsPerImage,
- uint32_t skipPixelsPerRow, uint32_t skipRowsPerImage,
- uint32_t skipImages, uint32_t usedPixelsPerRow,
- uint32_t usedRowsPerImage, uint32_t usedImages,
- uint32_t* const out_packedBytes)
-{
- MOZ_RELEASE_ASSERT(rowByteAlignment != 0);
-
- if (!usedPixelsPerRow || !usedRowsPerImage || !usedImages) {
- *out_packedBytes = 0;
- return true;
- }
- // Now we know there's at least one image.
-
- CheckedUint32 pixelsPerRow = CheckedUint32(skipPixelsPerRow) + usedPixelsPerRow;
- CheckedUint32 rowsPerImage = CheckedUint32(skipRowsPerImage) + usedRowsPerImage;
- CheckedUint32 images = CheckedUint32(skipImages) + usedImages;
-
- MOZ_ASSERT_IF(maybeStridePixelsPerRow,
- (pixelsPerRow.isValid() &&
- maybeStridePixelsPerRow >= pixelsPerRow.value()));
-
- MOZ_ASSERT_IF(maybeStrideRowsPerImage,
- (rowsPerImage.isValid() &&
- maybeStrideRowsPerImage >= rowsPerImage.value()));
-
- CheckedUint32 stridePixelsPerRow = maybeStridePixelsPerRow ? maybeStridePixelsPerRow
- : pixelsPerRow;
- CheckedUint32 strideRowsPerImage = maybeStrideRowsPerImage ? maybeStrideRowsPerImage
- : rowsPerImage;
-
- CheckedUint32 strideBytesPerRow = bytesPerPixel * stridePixelsPerRow;
- strideBytesPerRow = RoundUpToMultipleOf(strideBytesPerRow, rowByteAlignment);
-
- CheckedUint32 strideBytesPerImage = strideBytesPerRow * strideRowsPerImage;
-
- CheckedUint32 lastRowBytes = CheckedUint32(bytesPerPixel) * pixelsPerRow;
- CheckedUint32 lastImageBytes = strideBytesPerRow * (rowsPerImage - 1) + lastRowBytes;
-
- CheckedUint32 packedBytes = strideBytesPerImage * (images - 1) + lastImageBytes;
-
- if (!packedBytes.isValid())
- return false;
-
- *out_packedBytes = packedBytes.value();
- return true;
-}
-
-////////////////////
-
bool
TexUnpackBytes::ValidateUnpack(WebGLContext* webgl, const char* funcName, bool isFunc3D,
const webgl::PackingInfo& pi)
{
if (!mBytes)
return true;
- const auto bytesPerPixel = webgl::BytesPerPixel(pi);
- const auto rowByteAlignment = webgl->mPixelStore_UnpackAlignment;
- const auto maybeStridePixelsPerRow = webgl->mPixelStore_UnpackRowLength;
- const auto maybeStrideRowsPerImage = webgl->mPixelStore_UnpackImageHeight;
- const auto skipPixelsPerRow = webgl->mPixelStore_UnpackSkipPixels;
- const auto skipRowsPerImage = webgl->mPixelStore_UnpackSkipRows;
- const auto skipImages = isFunc3D ? webgl->mPixelStore_UnpackSkipImages
- : 0;
- const auto usedPixelsPerRow = mWidth;
- const auto usedRowsPerImage = mHeight;
- const auto usedImages = mDepth;
-
- uint32_t bytesNeeded;
- if (!GetPackedSizeForUnpack(bytesPerPixel, rowByteAlignment,
- maybeStridePixelsPerRow, maybeStrideRowsPerImage,
- skipPixelsPerRow, skipRowsPerImage, skipImages,
- usedPixelsPerRow, usedRowsPerImage, usedImages,
- &bytesNeeded))
- {
+ const auto bytesPerPixel = webgl::BytesPerPixel(pi);
+ const auto bytesNeeded = webgl->GetUnpackSize(isFunc3D, mWidth, mHeight, mDepth,
+ bytesPerPixel);
+ if (!bytesNeeded.isValid()) {
webgl->ErrorInvalidOperation("%s: Overflow while computing the needed buffer"
" size.",
funcName);
return false;
}
- if (bytesNeeded > mByteCount) {
+ if (mByteCount < bytesNeeded.value()) {
webgl->ErrorInvalidOperation("%s: Provided buffer is too small. (needs %u, has"
" %u)",
- funcName, bytesNeeded, mByteCount);
+ funcName, bytesNeeded.value(), mByteCount);
return false;
}
return true;
}
static bool
UnpackFormatHasAlpha(GLenum unpackFormat)
@@ -281,17 +209,16 @@ TexUnpackBytes::TexOrSubImage(bool isSub
dstPremultiplied))
{
MOZ_ASSERT(false, "ConvertImage failed unexpectedly.");
*out_glError = LOCAL_GL_OUT_OF_MEMORY;
return;
}
uploadBytes = tempBuffer.get();
- break;
} while (false);
GLenum error = DoTexOrSubImage(isSubImage, gl, target, level, dui, xOffset, yOffset,
zOffset, mWidth, mHeight, mDepth, uploadBytes);
*out_glError = error;
}
////////////////////////////////////////////////////////////////////////////////
--- a/dom/canvas/WebGL2ContextFramebuffers.cpp
+++ b/dom/canvas/WebGL2ContextFramebuffers.cpp
@@ -310,19 +310,16 @@ WebGL2Context::FramebufferTextureLayer(G
"MAX_ARRAY_TEXTURE_LAYERS");
}
break;
default:
return ErrorInvalidOperation("framebufferTextureLayer: texture must be an "
"existing 3D texture, or a 2D texture array.");
}
- } else {
- return ErrorInvalidOperation("framebufferTextureLayer: texture must be an "
- "existing 3D texture, or a 2D texture array.");
}
WebGLFramebuffer* fb;
switch (target) {
case LOCAL_GL_FRAMEBUFFER:
case LOCAL_GL_DRAW_FRAMEBUFFER:
fb = mBoundDrawFramebuffer;
break;
@@ -345,58 +342,61 @@ WebGL2Context::FramebufferTextureLayer(G
JS::Value
WebGL2Context::GetFramebufferAttachmentParameter(JSContext* cx,
GLenum target,
GLenum attachment,
GLenum pname,
ErrorResult& out_error)
{
+ const char funcName[] = "getFramebufferAttachmentParameter";
+
if (IsContextLost())
return JS::NullValue();
// OpenGL ES 3.0.4 (August 27, 2014) 6.1. QUERYING GL STATE 240
// "getFramebufferAttachmentParamter returns information about attachments of a bound
// framebuffer object. target must be DRAW_FRAMEBUFFER, READ_FRAMEBUFFER, or
// FRAMEBUFFER."
- if (!ValidateFramebufferTarget(target, "getFramebufferAttachmentParameter"))
+ if (!ValidateFramebufferTarget(target, funcName))
return JS::NullValue();
// FRAMEBUFFER is equivalent to DRAW_FRAMEBUFFER.
if (target == LOCAL_GL_FRAMEBUFFER)
target = LOCAL_GL_DRAW_FRAMEBUFFER;
WebGLFramebuffer* boundFB = nullptr;
switch (target) {
case LOCAL_GL_DRAW_FRAMEBUFFER: boundFB = mBoundDrawFramebuffer; break;
case LOCAL_GL_READ_FRAMEBUFFER: boundFB = mBoundReadFramebuffer; break;
}
if (boundFB) {
- return boundFB->GetAttachmentParameter(cx, target, attachment, pname, &out_error);
+ return boundFB->GetAttachmentParameter(funcName, cx, target, attachment, pname,
+ &out_error);
}
////////////////
// Handle default FB
// If the default framebuffer is bound to target, then attachment must be BACK,
// identifying the color buffer; DEPTH, identifying the depth buffer; or STENCIL,
// identifying the stencil buffer.
switch (attachment) {
case LOCAL_GL_BACK:
case LOCAL_GL_DEPTH:
case LOCAL_GL_STENCIL:
case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT:
break;
default:
- ErrorInvalidEnum("getFramebufferAttachmentParameter: Can only query "
- "attachment BACK, DEPTH, or STENCIL from default "
- "framebuffer");
+ ErrorInvalidEnum("%s: Can only query attachment BACK, DEPTH, or STENCIL from"
+ " default framebuffer.",
+ funcName);
return JS::NullValue();
}
switch (pname) {
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
return JS::Int32Value(LOCAL_GL_FRAMEBUFFER_DEFAULT);
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
@@ -610,17 +610,17 @@ WebGL2Context::InvalidateSubFramebuffer(
void
WebGL2Context::ReadBuffer(GLenum mode)
{
if (IsContextLost())
return;
const bool isColorAttachment = (mode >= LOCAL_GL_COLOR_ATTACHMENT0 &&
- mode <= LastColorAttachment());
+ mode <= LastColorAttachmentEnum());
if (mode != LOCAL_GL_NONE && mode != LOCAL_GL_BACK && !isColorAttachment) {
ErrorInvalidEnum("readBuffer: `mode` must be one of NONE, BACK, or "
"COLOR_ATTACHMENTi. Was %s",
EnumName(mode));
return;
}
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -1268,89 +1268,57 @@ WebGLContext::MozGetUnderlyingParamStrin
}
return NS_OK;
}
void
WebGLContext::ClearScreen()
{
- bool colorAttachmentsMask[WebGLContext::kMaxColorAttachments] = {false};
-
MakeContextCurrent();
ScopedBindFramebuffer autoFB(gl, 0);
- GLbitfield clearMask = LOCAL_GL_COLOR_BUFFER_BIT;
+ const bool changeDrawBuffers = (mDefaultFB_DrawBuffer0 != LOCAL_GL_BACK);
+ if (changeDrawBuffers) {
+ const GLenum back = LOCAL_GL_BACK;
+ gl->fDrawBuffers(1, &back);
+ }
+
+ GLbitfield bufferBits = LOCAL_GL_COLOR_BUFFER_BIT;
if (mOptions.depth)
- clearMask |= LOCAL_GL_DEPTH_BUFFER_BIT;
+ bufferBits |= LOCAL_GL_DEPTH_BUFFER_BIT;
if (mOptions.stencil)
- clearMask |= LOCAL_GL_STENCIL_BUFFER_BIT;
+ bufferBits |= LOCAL_GL_STENCIL_BUFFER_BIT;
+
+ ForceClearFramebufferWithDefaultValues(bufferBits, mNeedsFakeNoAlpha);
- colorAttachmentsMask[0] = true;
-
- ForceClearFramebufferWithDefaultValues(mNeedsFakeNoAlpha, clearMask,
- colorAttachmentsMask);
+ if (changeDrawBuffers) {
+ gl->fDrawBuffers(1, &mDefaultFB_DrawBuffer0);
+ }
}
void
-WebGLContext::ForceClearFramebufferWithDefaultValues(bool fakeNoAlpha, GLbitfield mask,
- const bool colorAttachmentsMask[kMaxColorAttachments])
+WebGLContext::ForceClearFramebufferWithDefaultValues(GLbitfield clearBits,
+ bool fakeNoAlpha)
{
MakeContextCurrent();
- bool initializeColorBuffer = 0 != (mask & LOCAL_GL_COLOR_BUFFER_BIT);
- bool initializeDepthBuffer = 0 != (mask & LOCAL_GL_DEPTH_BUFFER_BIT);
- bool initializeStencilBuffer = 0 != (mask & LOCAL_GL_STENCIL_BUFFER_BIT);
- bool drawBuffersIsEnabled = IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers);
- bool shouldOverrideDrawBuffers = false;
- bool usingDefaultFrameBuffer = !mBoundDrawFramebuffer;
-
- GLenum currentDrawBuffers[WebGLContext::kMaxColorAttachments];
+ 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.
AssertCachedState(); // Can't check cached bindings, as we could
// have a different FB bound temporarily.
// Prepare GL state for clearing.
gl->fDisable(LOCAL_GL_SCISSOR_TEST);
if (initializeColorBuffer) {
-
- if (drawBuffersIsEnabled) {
-
- GLenum drawBuffersCommand[WebGLContext::kMaxColorAttachments] = { LOCAL_GL_NONE };
-
- for (int32_t i = 0; i < mGLMaxDrawBuffers; i++) {
- GLint temp;
- gl->fGetIntegerv(LOCAL_GL_DRAW_BUFFER0 + i, &temp);
- currentDrawBuffers[i] = temp;
-
- if (colorAttachmentsMask[i]) {
- drawBuffersCommand[i] = LOCAL_GL_COLOR_ATTACHMENT0 + i;
- }
- if (currentDrawBuffers[i] != drawBuffersCommand[i])
- shouldOverrideDrawBuffers = true;
- }
-
- // When clearing the default framebuffer, we must be clearing only
- // GL_BACK, and nothing else, or else gl may return an error. We will
- // only use the first element of currentDrawBuffers in this case.
- if (usingDefaultFrameBuffer) {
- gl->Screen()->SetDrawBuffer(LOCAL_GL_BACK);
- if (currentDrawBuffers[0] == LOCAL_GL_COLOR_ATTACHMENT0)
- currentDrawBuffers[0] = LOCAL_GL_BACK;
- shouldOverrideDrawBuffers = false;
- }
- // calling draw buffers can cause resolves on adreno drivers so
- // we try to avoid calling it
- if (shouldOverrideDrawBuffers)
- gl->fDrawBuffers(mGLMaxDrawBuffers, drawBuffersCommand);
- }
-
gl->fColorMask(1, 1, 1, 1);
if (fakeNoAlpha) {
gl->fClearColor(0.0f, 0.0f, 0.0f, 1.0f);
} else {
gl->fClearColor(0.0f, 0.0f, 0.0f, 0.0f);
}
}
@@ -1368,37 +1336,28 @@ WebGLContext::ForceClearFramebufferWithD
gl->fClearStencil(0);
}
if (mRasterizerDiscardEnabled) {
gl->fDisable(LOCAL_GL_RASTERIZER_DISCARD);
}
// Do the clear!
- gl->fClear(mask);
+ gl->fClear(clearBits);
// And reset!
if (mScissorTestEnabled)
gl->fEnable(LOCAL_GL_SCISSOR_TEST);
if (mRasterizerDiscardEnabled) {
gl->fEnable(LOCAL_GL_RASTERIZER_DISCARD);
}
// Restore GL state after clearing.
if (initializeColorBuffer) {
-
- if (drawBuffersIsEnabled) {
- if (usingDefaultFrameBuffer) {
- gl->Screen()->SetDrawBuffer(currentDrawBuffers[0]);
- } else if (shouldOverrideDrawBuffers) {
- gl->fDrawBuffers(mGLMaxDrawBuffers, currentDrawBuffers);
- }
- }
-
gl->fColorMask(mColorWriteMask[0],
mColorWriteMask[1],
mColorWriteMask[2],
mColorWriteMask[3]);
gl->fClearColor(mColorClearValue[0],
mColorClearValue[1],
mColorClearValue[2],
mColorClearValue[3]);
@@ -1788,28 +1747,16 @@ WebGLContext::GetSurfaceSnapshot(bool* o
void
WebGLContext::DidRefresh()
{
if (gl) {
gl->FlushIfHeavyGLCallsSinceLastFlush();
}
}
-size_t
-RoundUpToMultipleOf(size_t value, size_t multiple)
-{
- return ((value + multiple - 1) / multiple) * multiple;
-}
-
-CheckedUint32
-RoundedToNextMultipleOf(CheckedUint32 value, CheckedUint32 multiple)
-{
- return ((value + multiple - 1) / multiple) * multiple;
-}
-
bool
WebGLContext::ValidateCurFBForRead(const char* funcName,
const webgl::FormatUsageInfo** const out_format,
uint32_t* const out_width, uint32_t* const out_height)
{
if (!mBoundReadFramebuffer) {
ClearBackbufferIfNeeded();
@@ -1993,19 +1940,17 @@ ZeroTextureData(WebGLContext* webgl, con
return false;
return true;
}
const auto driverUnpackInfo = usage->idealUnpack;
MOZ_RELEASE_ASSERT(driverUnpackInfo);
- const auto unpackFormat = driverUnpackInfo->unpackFormat;
- const auto unpackType = driverUnpackInfo->unpackType;
- const webgl::PackingInfo packing = { unpackFormat, unpackType };
+ const webgl::PackingInfo packing = driverUnpackInfo->ToPacking();
const auto bytesPerPixel = webgl::BytesPerPixel(packing);
CheckedUint32 checkedByteCount = bytesPerPixel;
checkedByteCount *= width;
checkedByteCount *= height;
checkedByteCount *= depth;
@@ -2016,31 +1961,76 @@ ZeroTextureData(WebGLContext* webgl, con
UniqueBuffer zeros = calloc(1, byteCount);
if (!zeros)
return false;
GLenum error;
if (respecifyTexture) {
MOZ_RELEASE_ASSERT(!xOffset && !yOffset && !zOffset);
-
- const auto internalFormat = driverUnpackInfo->internalFormat;
- error = DoTexImage(gl, target, level, internalFormat, width, height, depth,
- unpackFormat, unpackType, zeros.get());
+ error = DoTexImage(gl, target, level, driverUnpackInfo, width, height, depth,
+ zeros.get());
} else {
error = DoTexSubImage(gl, target, level, xOffset, yOffset, zOffset, width, height,
- depth, unpackFormat, unpackType, zeros.get());
+ depth, packing, zeros.get());
}
if (error)
return false;
return true;
}
////////////////////////////////////////////////////////////////////////////////
+
+CheckedUint32
+WebGLContext::GetUnpackSize(bool isFunc3D, uint32_t width, uint32_t height,
+ uint32_t depth, uint8_t bytesPerPixel)
+{
+ if (!width || !height || !depth)
+ return 0;
+
+ ////////////////
+
+ const auto& maybeRowLength = mPixelStore_UnpackRowLength;
+ const auto& maybeImageHeight = mPixelStore_UnpackImageHeight;
+
+ const auto usedPixelsPerRow = CheckedUint32(mPixelStore_UnpackSkipPixels) + width;
+ const auto stridePixelsPerRow = (maybeRowLength ? CheckedUint32(maybeRowLength)
+ : usedPixelsPerRow);
+
+ const auto usedRowsPerImage = CheckedUint32(mPixelStore_UnpackSkipRows) + height;
+ const auto strideRowsPerImage = (maybeImageHeight ? CheckedUint32(maybeImageHeight)
+ : usedRowsPerImage);
+
+ const uint32_t skipImages = (isFunc3D ? mPixelStore_UnpackSkipImages
+ : 0);
+ const CheckedUint32 usedImages = CheckedUint32(skipImages) + depth;
+
+ ////////////////
+
+ CheckedUint32 strideBytesPerRow = bytesPerPixel * stridePixelsPerRow;
+ strideBytesPerRow = RoundUpToMultipleOf(strideBytesPerRow,
+ mPixelStore_UnpackAlignment);
+
+ const CheckedUint32 strideBytesPerImage = strideBytesPerRow * strideRowsPerImage;
+
+ ////////////////
+
+ CheckedUint32 usedBytesPerRow = bytesPerPixel * usedPixelsPerRow;
+ // Don't round this to the alignment, since alignment here is really just used for
+ // establishing stride, particularly in WebGL 1, where you can't set ROW_LENGTH.
+
+ CheckedUint32 totalBytes = strideBytesPerImage * (usedImages - 1);
+ totalBytes += strideBytesPerRow * (usedRowsPerImage - 1);
+ totalBytes += usedBytesPerRow;
+
+ return totalBytes;
+}
+
+////////////////////////////////////////////////////////////////////////////////
// XPCOM goop
NS_IMPL_CYCLE_COLLECTING_ADDREF(WebGLContext)
NS_IMPL_CYCLE_COLLECTING_RELEASE(WebGLContext)
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLContext,
mCanvasElement,
mOffscreenCanvas,
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -209,16 +209,19 @@ class WebGLContext
UNPACK_PREMULTIPLY_ALPHA_WEBGL = 0x9241,
CONTEXT_LOST_WEBGL = 0x9242,
UNPACK_COLORSPACE_CONVERSION_WEBGL = 0x9243,
BROWSER_DEFAULT_WEBGL = 0x9244,
UNMASKED_VENDOR_WEBGL = 0x9245,
UNMASKED_RENDERER_WEBGL = 0x9246
};
+ static const uint32_t kMinMaxColorAttachments = 4;
+ static const uint32_t kMinMaxDrawBuffers = 4;
+
public:
WebGLContext();
protected:
virtual ~WebGLContext();
public:
MOZ_DECLARE_WEAKREFERENCE_TYPENAME(WebGLContext)
@@ -351,24 +354,21 @@ public:
bool IsPreservingDrawingBuffer() const { return mOptions.preserveDrawingBuffer; }
bool PresentScreenBuffer();
// a number that increments every time we have an event that causes
// all context resources to be lost.
uint32_t Generation() { return mGeneration.value(); }
- static const size_t kMaxColorAttachments = 16;
-
// 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(bool fakeNoAlpha, GLbitfield mask,
- const bool colorAttachmentsMask[kMaxColorAttachments]);
+ void ForceClearFramebufferWithDefaultValues(GLbitfield bufferBits, bool fakeNoAlpha);
// Calls ForceClearFramebufferWithDefaultValues() for the Context's 'screen'.
void ClearScreen();
void ClearBackbufferIfNeeded();
bool MinCapabilityMode() const { return mMinCapability; }
void RunContextLossTimer();
@@ -1090,16 +1090,17 @@ protected:
bool mShouldPresent;
bool mBackbufferNeedsClear;
bool mDisableFragHighP;
template<typename WebGLObjectType>
void DeleteWebGLObjectsArray(nsTArray<WebGLObjectType>& array);
GLuint mActiveTexture;
+ GLenum mDefaultFB_DrawBuffer0;
// glGetError sources:
bool mEmitContextLostErrorOnce;
GLenum mWebGLError;
GLenum mUnderlyingGLError;
GLenum GetAndFlushUnderlyingGLErrors();
bool mBypassShaderValidation;
@@ -1109,22 +1110,34 @@ protected:
// some GL constants
int32_t mGLMaxVertexAttribs;
int32_t mGLMaxTextureUnits;
int32_t mGLMaxTextureImageUnits;
int32_t mGLMaxVertexTextureImageUnits;
int32_t mGLMaxVaryingVectors;
int32_t mGLMaxFragmentUniformVectors;
int32_t mGLMaxVertexUniformVectors;
- int32_t mGLMaxColorAttachments;
- int32_t mGLMaxDrawBuffers;
uint32_t mGLMaxTransformFeedbackSeparateAttribs;
GLuint mGLMaxUniformBufferBindings;
GLsizei mGLMaxSamples;
+ // What is supported:
+ uint32_t mGLMaxColorAttachments;
+ uint32_t mGLMaxDrawBuffers;
+ // What we're allowing:
+ uint32_t mImplMaxColorAttachments;
+ uint32_t mImplMaxDrawBuffers;
+
+public:
+ GLenum LastColorAttachmentEnum() const {
+ return LOCAL_GL_COLOR_ATTACHMENT0 + mImplMaxColorAttachments - 1;
+ }
+
+protected:
+
// Texture sizes are often not actually the GL values. Let's be explicit that these
// are implementation limits.
uint32_t mImplMaxTextureSize;
uint32_t mImplMaxCubeMapTextureSize;
uint32_t mImplMax3DTextureSize;
uint32_t mImplMaxArrayTextureLayers;
uint32_t mImplMaxRenderbufferSize;
@@ -1371,20 +1384,16 @@ protected:
nsTArray<WebGLRefPtr<WebGLTexture> > mBound2DArrayTextures;
nsTArray<WebGLRefPtr<WebGLSampler> > mBoundSamplers;
void ResolveTexturesForDraw() const;
WebGLRefPtr<WebGLProgram> mCurrentProgram;
RefPtr<const webgl::LinkedProgramInfo> mActiveProgramLinkInfo;
- GLenum LastColorAttachment() const {
- return LOCAL_GL_COLOR_ATTACHMENT0 + mGLMaxColorAttachments - 1;
- }
-
bool ValidateFramebufferTarget(GLenum target, const char* const info);
WebGLRefPtr<WebGLFramebuffer> mBoundDrawFramebuffer;
WebGLRefPtr<WebGLFramebuffer> mBoundReadFramebuffer;
WebGLRefPtr<WebGLRenderbuffer> mBoundRenderbuffer;
WebGLRefPtr<WebGLTransformFeedback> mBoundTransformFeedback;
WebGLRefPtr<WebGLVertexArray> mBoundVertexArray;
@@ -1411,16 +1420,19 @@ protected:
uint32_t mPixelStore_UnpackSkipRows;
uint32_t mPixelStore_UnpackSkipPixels;
uint32_t mPixelStore_UnpackAlignment;
uint32_t mPixelStore_PackRowLength;
uint32_t mPixelStore_PackSkipRows;
uint32_t mPixelStore_PackSkipPixels;
uint32_t mPixelStore_PackAlignment;
+ CheckedUint32 GetUnpackSize(bool isFunc3D, uint32_t width, uint32_t height,
+ uint32_t depth, uint8_t bytesPerPixel);
+
CheckedUint32 GetPackSize(uint32_t width, uint32_t height, uint8_t bytesPerPixel,
CheckedUint32* const out_startOffset,
CheckedUint32* const out_rowStride);
GLenum mPixelStore_ColorspaceConversion;
bool mPixelStore_FlipY;
bool mPixelStore_PremultiplyAlpha;
@@ -1567,16 +1579,17 @@ public:
// Friend list
friend class ScopedCopyTexImageSource;
friend class ScopedResolveTexturesForDraw;
friend class ScopedUnpackReset;
friend class webgl::TexUnpackBytes;
friend class webgl::TexUnpackSurface;
friend class WebGLTexture;
+ friend class WebGLFBAttachPoint;
friend class WebGLFramebuffer;
friend class WebGLRenderbuffer;
friend class WebGLProgram;
friend class WebGLQuery;
friend class WebGLBuffer;
friend class WebGLSampler;
friend class WebGLShader;
friend class WebGLSync;
--- a/dom/canvas/WebGLContextDraw.cpp
+++ b/dom/canvas/WebGLContextDraw.cpp
@@ -825,25 +825,33 @@ WebGLContext::FakeBlackTexture::FakeBlac
mGL->fTexParameteri(target.get(), LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_NEAREST);
mGL->fTexParameteri(target.get(), LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_NEAREST);
// We allocate our zeros on the heap, and we overallocate (16 bytes instead of 4) to
// minimize the risk of running into a driver bug in texImage2D, as it is a bit
// unusual maybe to create 1x1 textures, and the stack may not have the alignment that
// TexImage2D expects.
- UniqueBuffer zeros = moz_xcalloc(1, 16);
+
+ const webgl::DriverUnpackInfo dui = {texFormat, texFormat, LOCAL_GL_UNSIGNED_BYTE};
+ UniqueBuffer zeros = moz_xcalloc(1, 16); // Infallible allocation.
+
if (target == LOCAL_GL_TEXTURE_CUBE_MAP) {
for (int i = 0; i < 6; ++i) {
- DoTexImage(mGL, LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, texFormat, 1, 1,
- 1, texFormat, LOCAL_GL_UNSIGNED_BYTE, zeros.get());
+ const TexImageTarget curTarget = LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + i;
+ const GLenum error = DoTexImage(mGL, curTarget.get(), 0, &dui, 1, 1, 1,
+ zeros.get());
+ if (error)
+ MOZ_CRASH("Unexpected error during FakeBlack creation.");
}
} else {
- DoTexImage(mGL, target.get(), 0, texFormat, 1, 1, 1, texFormat,
- LOCAL_GL_UNSIGNED_BYTE, zeros.get());
+ const GLenum error = DoTexImage(mGL, target.get(), 0, &dui, 1, 1, 1,
+ zeros.get());
+ if (error)
+ MOZ_CRASH("Unexpected error during FakeBlack creation.");
}
}
WebGLContext::FakeBlackTexture::~FakeBlackTexture()
{
mGL->MakeCurrent();
mGL->fDeleteTextures(1, &mGLName);
}
--- a/dom/canvas/WebGLContextFramebufferOperations.cpp
+++ b/dom/canvas/WebGLContextFramebufferOperations.cpp
@@ -132,81 +132,85 @@ WebGLContext::DepthMask(WebGLboolean b)
MakeContextCurrent();
mDepthWriteMask = b;
gl->fDepthMask(b);
}
void
WebGLContext::DrawBuffers(const dom::Sequence<GLenum>& buffers)
{
+ const char funcName[] = "drawBuffers";
if (IsContextLost())
return;
- const size_t buffersLength = buffers.Length();
-
- if (!buffersLength) {
- return ErrorInvalidValue("drawBuffers: invalid <buffers> (buffers must not be empty)");
- }
-
if (!mBoundDrawFramebuffer) {
- // OK: we are rendering in the default framebuffer
-
- /* EXT_draw_buffers :
- If the GL is bound to the default framebuffer, then <buffersLength> must be 1
- and the constant must be BACK or NONE. When draw buffer zero is
- BACK, color values are written into the sole buffer for single-
- buffered contexts, or into the back buffer for double-buffered
- contexts. If DrawBuffersEXT is supplied with a constant other than
- BACK and NONE, the error INVALID_OPERATION is generated.
- */
- if (buffersLength != 1) {
- return ErrorInvalidValue("drawBuffers: invalid <buffers> (main framebuffer: buffers.length must be 1)");
+ // GLES 3.0.4 p186:
+ // "If the GL is bound to the default framebuffer, then `n` must be 1 and the
+ // constant must be BACK or NONE. [...] If DrawBuffers is supplied with a
+ // constant other than BACK and NONE, or with a value of `n` other than 1, the
+ // error INVALID_OPERATION is generated."
+ if (buffers.Length() != 1) {
+ ErrorInvalidOperation("%s: For the default framebuffer, `buffers` must have a"
+ " length of 1.",
+ funcName);
+ return;
}
- if (buffers[0] == LOCAL_GL_NONE || buffers[0] == LOCAL_GL_BACK) {
- gl->Screen()->SetDrawBuffer(buffers[0]);
+ switch (buffers[0]) {
+ case LOCAL_GL_NONE:
+ case LOCAL_GL_BACK:
+ break;
+
+ default:
+ ErrorInvalidOperation("%s: For the default framebuffer, `buffers[0]` must be"
+ " BACK or NONE.",
+ funcName);
return;
}
- return ErrorInvalidOperation("drawBuffers: invalid operation (main framebuffer: buffers[0] must be GL_NONE or GL_BACK)");
+
+ mDefaultFB_DrawBuffer0 = buffers[0];
+ gl->Screen()->SetDrawBuffer(buffers[0]);
+ return;
}
- // OK: we are rendering in a framebuffer object
+ // Framebuffer object (not default framebuffer)
- if (buffersLength > size_t(mGLMaxDrawBuffers)) {
- /* EXT_draw_buffers :
- The maximum number of draw buffers is implementation-dependent. The
- number of draw buffers supported can be queried by calling
- GetIntegerv with the symbolic constant MAX_DRAW_BUFFERS_EXT. An
- INVALID_VALUE error is generated if <buffersLength> is greater than
- MAX_DRAW_BUFFERS_EXT.
- */
- return ErrorInvalidValue("drawBuffers: invalid <buffers> (buffers.length > GL_MAX_DRAW_BUFFERS)");
+ if (buffers.Length() > mImplMaxDrawBuffers) {
+ // "An INVALID_VALUE error is generated if `n` is greater than MAX_DRAW_BUFFERS."
+ ErrorInvalidValue("%s: `buffers` must have a length <= MAX_DRAW_BUFFERS.",
+ funcName);
+ return;
}
- for (uint32_t i = 0; i < buffersLength; i++)
- {
- /* EXT_draw_buffers :
- If the GL is bound to a draw framebuffer object, the <i>th buffer listed
- in <bufs> must be COLOR_ATTACHMENT<i>_EXT or NONE. Specifying a
- buffer out of order, BACK, or COLOR_ATTACHMENT<m>_EXT where <m> is
- greater than or equal to the value of MAX_COLOR_ATTACHMENTS_EXT,
- will generate the error INVALID_OPERATION.
- */
- /* WEBGL_draw_buffers :
- The value of the MAX_COLOR_ATTACHMENTS_WEBGL parameter must be greater than or equal to that of the MAX_DRAW_BUFFERS_WEBGL parameter.
- */
+ for (size_t i = 0; i < buffers.Length(); i++) {
+ // "If the GL is bound to a draw framebuffer object, the `i`th buffer listed in
+ // bufs must be COLOR_ATTACHMENTi or NONE. Specifying a buffer out of order,
+ // BACK, or COLOR_ATTACHMENTm where `m` is greater than or equal to the value of
+ // MAX_COLOR_ATTACHMENTS, will generate the error INVALID_OPERATION.
+
+ // WEBGL_draw_buffers:
+ // "The value of the MAX_COLOR_ATTACHMENTS_WEBGL parameter must be greater than or
+ // equal to that of the MAX_DRAW_BUFFERS_WEBGL parameter."
+ // This means that if buffers.Length() isn't larger than MaxDrawBuffers, it won't
+ // be larger than MaxColorAttachments.
if (buffers[i] != LOCAL_GL_NONE &&
- buffers[i] != GLenum(LOCAL_GL_COLOR_ATTACHMENT0 + i)) {
- return ErrorInvalidOperation("drawBuffers: invalid operation (buffers[i] must be GL_NONE or GL_COLOR_ATTACHMENTi)");
+ buffers[i] != LOCAL_GL_COLOR_ATTACHMENT0 + i)
+ {
+ ErrorInvalidOperation("%s: `buffers[i]` must be NONE or COLOR_ATTACHMENTi.",
+ funcName);
+ return;
}
}
MakeContextCurrent();
+ gl->fDrawBuffers(buffers.Length(), buffers.Elements());
- gl->fDrawBuffers(buffersLength, buffers.Elements());
+ const GLenum* begin = buffers.Elements();
+ const GLenum* end = begin + buffers.Length();
+ mBoundDrawFramebuffer->mDrawBuffers.assign(begin, end);
}
void
WebGLContext::StencilMask(GLuint mask)
{
if (IsContextLost())
return;
--- a/dom/canvas/WebGLContextGL.cpp
+++ b/dom/canvas/WebGLContextGL.cpp
@@ -703,20 +703,22 @@ JSUint32Value(uint32_t val)
JS::Value
WebGLContext::GetFramebufferAttachmentParameter(JSContext* cx,
GLenum target,
GLenum attachment,
GLenum pname,
ErrorResult& rv)
{
+ const char funcName[] = "getFramebufferAttachmentParameter";
+
if (IsContextLost())
return JS::NullValue();
- if (!ValidateFramebufferTarget(target, "getFramebufferAttachmentParameter"))
+ if (!ValidateFramebufferTarget(target, funcName))
return JS::NullValue();
WebGLFramebuffer* fb;
switch (target) {
case LOCAL_GL_FRAMEBUFFER:
case LOCAL_GL_DRAW_FRAMEBUFFER:
fb = mBoundDrawFramebuffer;
break;
@@ -724,155 +726,83 @@ WebGLContext::GetFramebufferAttachmentPa
case LOCAL_GL_READ_FRAMEBUFFER:
fb = mBoundReadFramebuffer;
break;
default:
MOZ_CRASH("Bad target.");
}
- if (!fb) {
- // This isn't actually true. GLES 3.0.4, p240: "If the default framebuffer[...]".
- ErrorInvalidOperation("getFramebufferAttachmentParameter: cannot query"
- " framebuffer 0.");
- return JS::NullValue();
- }
-
- if (!ValidateFramebufferAttachment(fb, attachment,
- "getFramebufferAttachmentParameter"))
- {
+ if (fb)
+ return fb->GetAttachmentParameter(funcName, cx, target, attachment, pname, &rv);
+
+ ////////////////////////////////////
+
+ if (!IsWebGL2()) {
+ ErrorInvalidOperation("%s: Querying against the default framebuffer is not"
+ " allowed in WebGL 1.",
+ funcName);
return JS::NullValue();
}
- if (IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers) &&
- attachment >= LOCAL_GL_COLOR_ATTACHMENT0 &&
- attachment <= LOCAL_GL_COLOR_ATTACHMENT15)
- {
- fb->EnsureColorAttachPoints(attachment - LOCAL_GL_COLOR_ATTACHMENT0);
+ switch (attachment) {
+ case LOCAL_GL_COLOR:
+ case LOCAL_GL_DEPTH:
+ case LOCAL_GL_STENCIL:
+ break;
+
+ default:
+ ErrorInvalidEnum("%s: For the default framebuffer, can only query COLOR, DEPTH,"
+ " or STENCIL.",
+ funcName);
+ return JS::NullValue();
}
- MakeContextCurrent();
-
- const WebGLFBAttachPoint& fba = fb->GetAttachPoint(attachment);
-
switch (pname) {
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
- if (fba.Renderbuffer())
- return JSUint32Value(LOCAL_GL_RENDERBUFFER);
-
- if (fba.Texture())
- return JSUint32Value(LOCAL_GL_TEXTURE);
-
- return JSUint32Value(LOCAL_GL_NONE);
+ return JS::Int32Value(LOCAL_GL_FRAMEBUFFER_DEFAULT);
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
- if (fba.Renderbuffer())
- return WebGLObjectAsJSValue(cx, fba.Renderbuffer(), rv);
-
- if (fba.Texture())
- return WebGLObjectAsJSValue(cx, fba.Texture(), rv);
-
return JS::NullValue();
- }
-
-
- const bool hasAttachments = (fba.Renderbuffer() || fba.Texture());
-
- switch (pname) {
- case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT:
- if (!hasAttachments)
- return MissingAttachmentCausesInvalidOp(this);
-
- if (!IsWebGL2() && !IsExtensionEnabled(WebGLExtensionID::EXT_sRGB))
- break;
-
- if (!fba.IsDefined())
- return JSUint32Value(LOCAL_GL_LINEAR);
-
- if (fba.IsDefined()) {
- if (fba.Format()->format->isSRGB)
- return JSUint32Value(LOCAL_GL_SRGB_EXT);
- }
-
- return JSUint32Value(LOCAL_GL_LINEAR);
+
+ ////////////////
+
+ case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
+ case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
+ case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
+ if (attachment == LOCAL_GL_COLOR)
+ return JS::Int32Value(8);
+ return JS::Int32Value(0);
+
+ case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
+ if (attachment == LOCAL_GL_COLOR)
+ return JS::Int32Value(mOptions.alpha ? 8 : 0);
+ return JS::Int32Value(0);
+
+ case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
+ if (attachment == LOCAL_GL_DEPTH)
+ return JS::Int32Value(mOptions.depth ? 24 : 0);
+ return JS::Int32Value(0);
+
+ case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
+ if (attachment == LOCAL_GL_STENCIL)
+ return JS::Int32Value(mOptions.stencil ? 8 : 0);
+ return JS::Int32Value(0);
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
- if (!hasAttachments)
- return MissingAttachmentCausesInvalidOp(this);
-
- if (!IsWebGL2() &&
- !IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float) &&
- !IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float))
- {
- break;
- }
-
- if (!fba.IsDefined())
- return JSUint32Value(LOCAL_GL_LINEAR);
-
- if (attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
- ErrorInvalidOperation("getFramebufferAttachmentParameter: Cannot get component"
- " type of a depth-stencil attachment.");
- return JS::NullValue();
- }
-
- switch (fba.Format()->format->componentType) {
- case webgl::ComponentType::Int:
- return JSUint32Value(LOCAL_GL_INT);
-
- case webgl::ComponentType::UInt:
- return JSUint32Value(LOCAL_GL_UNSIGNED_INT);
-
- case webgl::ComponentType::NormInt:
- return JSUint32Value(LOCAL_GL_SIGNED_NORMALIZED);
-
- case webgl::ComponentType::NormUInt:
- return JSUint32Value(LOCAL_GL_UNSIGNED_NORMALIZED);
-
- case webgl::ComponentType::Float:
- return JSUint32Value(LOCAL_GL_FLOAT);
-
- case webgl::ComponentType::None:
- return JSUint32Value(LOCAL_GL_NONE);
- }
- // Exhaustive switch means nothing's left.
-
- case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
- if (!hasAttachments)
- return MissingAttachmentCausesInvalidOp(this);
-
- if (!fba.Texture())
- break;
-
- return JSUint32Value(fba.MipLevel());
-
- case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
- if (!hasAttachments)
- return MissingAttachmentCausesInvalidOp(this);
-
- if (!fba.Texture())
- break;
-
- switch (fba.ImageTarget().get()) {
- case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
- case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
- case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
- case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
- case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
- case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
- return JSUint32Value(fba.ImageTarget().get());
- }
-
- return JSUint32Value(0);
-
- default:
- break;
+ if (attachment == LOCAL_GL_STENCIL)
+ return JS::Int32Value(LOCAL_GL_UNSIGNED_INT);
+ else
+ return JS::Int32Value(LOCAL_GL_UNSIGNED_NORMALIZED);
+
+ case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
+ return JS::Int32Value(LOCAL_GL_LINEAR);
}
- ErrorInvalidEnumInfo("getFramebufferAttachmentParameter: pname", pname);
+ ErrorInvalidEnum("%s: Invalid pname: 0x%04x", funcName, pname);
return JS::NullValue();
}
JS::Value
WebGLContext::GetRenderbufferParameter(GLenum target, GLenum pname)
{
if (IsContextLost())
return JS::NullValue();
--- a/dom/canvas/WebGLContextState.cpp
+++ b/dom/canvas/WebGLContextState.cpp
@@ -139,23 +139,23 @@ WebGLContext::GetParameter(JSContext* cx
default:
// Return the real value; we're not overriding this one
break;
}
}
if (IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers)) {
if (pname == LOCAL_GL_MAX_COLOR_ATTACHMENTS) {
- return JS::Int32Value(mGLMaxColorAttachments);
+ return JS::Int32Value(mImplMaxColorAttachments);
} else if (pname == LOCAL_GL_MAX_DRAW_BUFFERS) {
- return JS::Int32Value(mGLMaxDrawBuffers);
+ return JS::Int32Value(mImplMaxDrawBuffers);
} else if (pname >= LOCAL_GL_DRAW_BUFFER0 &&
- pname < GLenum(LOCAL_GL_DRAW_BUFFER0 + mGLMaxDrawBuffers))
+ pname < GLenum(LOCAL_GL_DRAW_BUFFER0 + mImplMaxDrawBuffers))
{
GLint iv = 0;
gl->fGetIntegerv(pname, &iv);
if (mBoundDrawFramebuffer)
return JS::Int32Value(iv);
const GLint index = (pname - LOCAL_GL_DRAW_BUFFER0);
--- a/dom/canvas/WebGLContextUtils.cpp
+++ b/dom/canvas/WebGLContextUtils.cpp
@@ -736,20 +736,30 @@ WebGLContext::AssertCachedBindings()
void
WebGLContext::AssertCachedState()
{
#ifdef DEBUG
MakeContextCurrent();
GetAndFlushUnderlyingGLErrors();
- // extensions
- if (IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers)) {
- AssertUintParamCorrect(gl, LOCAL_GL_MAX_COLOR_ATTACHMENTS, mGLMaxColorAttachments);
- AssertUintParamCorrect(gl, LOCAL_GL_MAX_DRAW_BUFFERS, mGLMaxDrawBuffers);
+ ////////////////
+
+ AssertUintParamCorrect(gl, LOCAL_GL_MAX_COLOR_ATTACHMENTS, mGLMaxColorAttachments);
+ AssertUintParamCorrect(gl, LOCAL_GL_MAX_DRAW_BUFFERS, mGLMaxDrawBuffers);
+
+ if (IsWebGL2() ||
+ IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers))
+ {
+ MOZ_ASSERT(mImplMaxColorAttachments == std::min(mGLMaxColorAttachments,
+ mGLMaxDrawBuffers));
+ MOZ_ASSERT(mImplMaxDrawBuffers == mGLMaxDrawBuffers);
+ } else {
+ MOZ_ASSERT(mImplMaxColorAttachments == 1);
+ MOZ_ASSERT(mImplMaxDrawBuffers == 1);
}
// 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);
--- a/dom/canvas/WebGLContextValidate.cpp
+++ b/dom/canvas/WebGLContextValidate.cpp
@@ -255,20 +255,16 @@ WebGLContext::ValidateDrawModeEnum(GLenu
return true;
default:
ErrorInvalidEnumInfo(info, mode);
return false;
}
}
-/**
- * Return true if the framebuffer attachment is valid. Attachment must
- * be one of depth/stencil/depth_stencil/color attachment.
- */
bool
WebGLContext::ValidateFramebufferAttachment(const WebGLFramebuffer* fb, GLenum attachment,
const char* funcName)
{
if (!fb) {
switch (attachment) {
case LOCAL_GL_COLOR:
case LOCAL_GL_DEPTH:
@@ -284,18 +280,21 @@ WebGLContext::ValidateFramebufferAttachm
if (attachment == LOCAL_GL_DEPTH_ATTACHMENT ||
attachment == LOCAL_GL_STENCIL_ATTACHMENT ||
attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
{
return true;
}
- if (attachment >= LOCAL_GL_COLOR_ATTACHMENT0 && attachment <= LastColorAttachment())
+ if (attachment >= LOCAL_GL_COLOR_ATTACHMENT0 &&
+ attachment <= LastColorAttachmentEnum())
+ {
return true;
+ }
ErrorInvalidEnum("%s: attachment: invalid enum value 0x%x.", funcName,
attachment);
return false;
}
/**
* Return true if pname is valid for GetSamplerParameter calls.
@@ -700,16 +699,18 @@ WebGLContext::InitAndValidateGL()
AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_WRITEMASK, mStencilWriteMaskBack);
mDitherEnabled = true;
mRasterizerDiscardEnabled = false;
mScissorTestEnabled = false;
// Bindings, etc.
mActiveTexture = 0;
+ mDefaultFB_DrawBuffer0 = LOCAL_GL_BACK;
+
mEmitContextLostErrorOnce = true;
mWebGLError = LOCAL_GL_NO_ERROR;
mUnderlyingGLError = LOCAL_GL_NO_ERROR;
mBound2DTextures.Clear();
mBoundCubeMapTextures.Clear();
mBound3DTextures.Clear();
mBound2DArrayTextures.Clear();
@@ -786,33 +787,54 @@ WebGLContext::InitAndValidateGL()
gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS, &mGLMaxTextureImageUnits);
gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &mGLMaxVertexTextureImageUnits);
if (!gl->GetPotentialInteger(LOCAL_GL_MAX_SAMPLES, (GLint*)&mGLMaxSamples))
mGLMaxSamples = 1;
}
- const auto fnFloor = [](uint32_t& val) {
+ // If we don't support a target, its max size is 0. We should only floor-to-POT if the
+ // value if it's non-zero. (NB log2(0) is -Inf, so zero isn't an integer power-of-two)
+ const auto fnFloorPOTIfSupported = [](uint32_t& val) {
if (val) {
val = FloorPOT(val);
}
};
- fnFloor(mImplMaxTextureSize);
- fnFloor(mImplMaxCubeMapTextureSize);
- fnFloor(mImplMaxRenderbufferSize);
+ fnFloorPOTIfSupported(mImplMaxTextureSize);
+ fnFloorPOTIfSupported(mImplMaxCubeMapTextureSize);
+ fnFloorPOTIfSupported(mImplMaxRenderbufferSize);
- fnFloor(mImplMax3DTextureSize);
- fnFloor(mImplMaxArrayTextureLayers);
+ fnFloorPOTIfSupported(mImplMax3DTextureSize);
+ fnFloorPOTIfSupported(mImplMaxArrayTextureLayers);
////////////////
mGLMaxColorAttachments = 1;
mGLMaxDrawBuffers = 1;
+ gl->GetPotentialInteger(LOCAL_GL_MAX_COLOR_ATTACHMENTS,
+ (GLint*)&mGLMaxColorAttachments);
+ gl->GetPotentialInteger(LOCAL_GL_MAX_DRAW_BUFFERS, (GLint*)&mGLMaxDrawBuffers);
+
+ if (MinCapabilityMode()) {
+ mGLMaxColorAttachments = std::min(mGLMaxColorAttachments,
+ kMinMaxColorAttachments);
+ mGLMaxDrawBuffers = std::min(mGLMaxDrawBuffers, kMinMaxDrawBuffers);
+ }
+
+ if (IsWebGL2()) {
+ mImplMaxColorAttachments = mGLMaxColorAttachments;
+ mImplMaxDrawBuffers = std::min(mGLMaxDrawBuffers, mImplMaxColorAttachments);
+ } else {
+ mImplMaxColorAttachments = 1;
+ mImplMaxDrawBuffers = 1;
+ }
+
+ ////////////////
if (MinCapabilityMode()) {
mGLMaxFragmentUniformVectors = MINVALUE_GL_MAX_FRAGMENT_UNIFORM_VECTORS;
mGLMaxVertexUniformVectors = MINVALUE_GL_MAX_VERTEX_UNIFORM_VECTORS;
mGLMaxVaryingVectors = MINVALUE_GL_MAX_VARYING_VECTORS;
} else {
if (gl->IsSupported(gl::GLFeature::ES2_compatibility)) {
gl->fGetIntegerv(LOCAL_GL_MAX_FRAGMENT_UNIFORM_VECTORS, &mGLMaxFragmentUniformVectors);
--- a/dom/canvas/WebGLExtensionColorBufferFloat.cpp
+++ b/dom/canvas/WebGLExtensionColorBufferFloat.cpp
@@ -26,18 +26,18 @@ WebGLExtensionColorBufferFloat::WebGLExt
auto usage = fua->EditUsage(effFormat);
usage->isRenderable = true;
fua->AddRBFormat(sizedFormat, usage);
};
#define FOO(x) fnUpdateUsage(LOCAL_GL_ ## x, webgl::EffectiveFormat::x)
+ // The extension doesn't actually add RGB32F; only RGBA32F.
FOO(RGBA32F);
- FOO(RGB32F);
#undef FOO
}
WebGLExtensionColorBufferFloat::~WebGLExtensionColorBufferFloat()
{
}
--- a/dom/canvas/WebGLExtensionDrawBuffers.cpp
+++ b/dom/canvas/WebGLExtensionDrawBuffers.cpp
@@ -15,36 +15,22 @@
namespace mozilla {
WebGLExtensionDrawBuffers::WebGLExtensionDrawBuffers(WebGLContext* webgl)
: WebGLExtensionBase(webgl)
{
MOZ_ASSERT(IsSupported(webgl), "Don't construct extension if unsupported.");
- GLint maxColorAttachments = 0;
- GLint maxDrawBuffers = 0;
-
- webgl->MakeContextCurrent();
- gl::GLContext* gl = webgl->GL();
-
- gl->fGetIntegerv(LOCAL_GL_MAX_COLOR_ATTACHMENTS, &maxColorAttachments);
- gl->fGetIntegerv(LOCAL_GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
-
- // WEBGL_draw_buffers specifications don't give a maximal value reachable by MAX_COLOR_ATTACHMENTS.
- maxColorAttachments = std::min(maxColorAttachments, GLint(WebGLContext::kMaxColorAttachments));
-
- if (webgl->MinCapabilityMode())
- maxColorAttachments = std::min(maxColorAttachments, GLint(kMinColorAttachments));
-
- // WEBGL_draw_buffers specifications request MAX_COLOR_ATTACHMENTS >= MAX_DRAW_BUFFERS.
- maxDrawBuffers = std::min(maxDrawBuffers, GLint(maxColorAttachments));
-
- webgl->mGLMaxColorAttachments = maxColorAttachments;
- webgl->mGLMaxDrawBuffers = maxDrawBuffers;
+ // WEBGL_draw_buffers:
+ // "The value of the MAX_COLOR_ATTACHMENTS_WEBGL parameter must be greater than or
+ // equal to that of the MAX_DRAW_BUFFERS_WEBGL parameter."
+ webgl->mImplMaxColorAttachments = webgl->mGLMaxColorAttachments;
+ webgl->mImplMaxDrawBuffers = std::min(webgl->mGLMaxDrawBuffers,
+ webgl->mImplMaxColorAttachments);
}
WebGLExtensionDrawBuffers::~WebGLExtensionDrawBuffers()
{
}
void
WebGLExtensionDrawBuffers::DrawBuffersWEBGL(const dom::Sequence<GLenum>& buffers)
@@ -60,29 +46,21 @@ WebGLExtensionDrawBuffers::DrawBuffersWE
bool
WebGLExtensionDrawBuffers::IsSupported(const WebGLContext* webgl)
{
gl::GLContext* gl = webgl->GL();
if (!gl->IsSupported(gl::GLFeature::draw_buffers))
return false;
- GLint supportedColorAttachments = 0;
- GLint supportedDrawBuffers = 0;
-
- webgl->MakeContextCurrent();
-
- gl->fGetIntegerv(LOCAL_GL_MAX_COLOR_ATTACHMENTS, &supportedColorAttachments);
- gl->fGetIntegerv(LOCAL_GL_MAX_COLOR_ATTACHMENTS, &supportedDrawBuffers);
-
// WEBGL_draw_buffers requires at least 4 color attachments.
- if (size_t(supportedColorAttachments) < kMinColorAttachments)
+ if (webgl->mGLMaxDrawBuffers < webgl->kMinMaxDrawBuffers ||
+ webgl->mGLMaxColorAttachments < webgl->kMinMaxColorAttachments)
+ {
return false;
-
- if (size_t(supportedDrawBuffers) < kMinDrawBuffers)
- return false;
+ }
return true;
}
IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionDrawBuffers, WEBGL_draw_buffers)
} // namespace mozilla
--- a/dom/canvas/WebGLExtensionSRGB.cpp
+++ b/dom/canvas/WebGLExtensionSRGB.cpp
@@ -22,36 +22,33 @@ WebGLExtensionSRGB::WebGLExtensionSRGB(W
// Desktop OpenGL requires the following to be enabled in order to
// support sRGB operations on framebuffers.
gl->MakeCurrent();
gl->fEnable(LOCAL_GL_FRAMEBUFFER_SRGB_EXT);
}
auto& fua = webgl->mFormatUsage;
- webgl::FormatUsageInfo* usage;
- webgl::PackingInfo pi;
- webgl::DriverUnpackInfo dui;
+ const auto fnAdd = [&fua](webgl::EffectiveFormat effFormat, GLenum unpackFormat)
+ {
+ auto usage = fua->EditUsage(webgl::EffectiveFormat::SRGB8);
+ usage->isFilterable = true;
- usage = fua->EditUsage(webgl::EffectiveFormat::SRGB8);
- usage->isRenderable = false;
- usage->isFilterable = true;
- pi = {LOCAL_GL_SRGB, LOCAL_GL_UNSIGNED_BYTE};
- dui = {LOCAL_GL_SRGB, LOCAL_GL_SRGB, LOCAL_GL_UNSIGNED_BYTE};
- fua->AddUnsizedTexFormat(pi, usage);
- usage->AddUnpack(pi, dui);
+ const webgl::DriverUnpackInfo dui = {unpackFormat, unpackFormat,
+ LOCAL_GL_UNSIGNED_BYTE};
+ const auto pi = dui.ToPacking();
+ fua->AddUnsizedTexFormat(pi, usage);
+ usage->AddUnpack(pi, dui);
+ };
- usage = fua->EditUsage(webgl::EffectiveFormat::SRGB8_ALPHA8);
+ fnAdd(webgl::EffectiveFormat::SRGB8, LOCAL_GL_SRGB);
+ fnAdd(webgl::EffectiveFormat::SRGB8_ALPHA8, LOCAL_GL_SRGB_ALPHA);
+
+ auto usage = fua->EditUsage(webgl::EffectiveFormat::SRGB8_ALPHA8);
usage->isRenderable = true;
- usage->isFilterable = true;
- pi = {LOCAL_GL_SRGB_ALPHA, LOCAL_GL_UNSIGNED_BYTE};
- dui = {LOCAL_GL_SRGB_ALPHA, LOCAL_GL_SRGB_ALPHA, LOCAL_GL_UNSIGNED_BYTE};
- fua->AddUnsizedTexFormat(pi, usage);
- usage->AddUnpack(pi, dui);
-
fua->AddRBFormat(LOCAL_GL_SRGB8_ALPHA8, usage);
}
WebGLExtensionSRGB::~WebGLExtensionSRGB()
{
}
bool
--- a/dom/canvas/WebGLExtensions.h
+++ b/dom/canvas/WebGLExtensions.h
@@ -284,24 +284,16 @@ class WebGLExtensionDrawBuffers
public:
explicit WebGLExtensionDrawBuffers(WebGLContext*);
virtual ~WebGLExtensionDrawBuffers();
void DrawBuffersWEBGL(const dom::Sequence<GLenum>& buffers);
static bool IsSupported(const WebGLContext*);
- static const size_t kMinColorAttachments = 4;
- static const size_t kMinDrawBuffers = 4;
- /*
- WEBGL_draw_buffers does not give a minal value for GL_MAX_DRAW_BUFFERS. But, we request
- for GL_MAX_DRAW_BUFFERS = 4 at least to be able to use all requested color attachments.
- See DrawBuffersWEBGL in WebGLExtensionDrawBuffers.cpp inner comments for more informations.
- */
-
DECL_WEBGL_EXTENSION_GOOP
};
class WebGLExtensionVertexArray
: public WebGLExtensionBase
{
public:
explicit WebGLExtensionVertexArray(WebGLContext* webgl);
--- a/dom/canvas/WebGLFormats.cpp
+++ b/dom/canvas/WebGLFormats.cpp
@@ -235,18 +235,18 @@ InitFormatInfo()
AddFormatInfo(FOO(RGBA16UI ), 8, UnsizedFormat::RGBA, false, ComponentType::UInt );
AddFormatInfo(FOO(RGBA32I ), 16, UnsizedFormat::RGBA, false, ComponentType::Int );
AddFormatInfo(FOO(RGBA32UI ), 16, UnsizedFormat::RGBA, false, ComponentType::UInt );
// GLES 3.0.4, p133, table 3.14
AddFormatInfo(FOO(DEPTH_COMPONENT16 ), 2, UnsizedFormat::D , false, ComponentType::NormUInt);
AddFormatInfo(FOO(DEPTH_COMPONENT24 ), 3, UnsizedFormat::D , false, ComponentType::NormUInt);
AddFormatInfo(FOO(DEPTH_COMPONENT32F), 4, UnsizedFormat::D , false, ComponentType::Float);
- AddFormatInfo(FOO(DEPTH24_STENCIL8 ), 4, UnsizedFormat::DS, false, ComponentType::None);
- AddFormatInfo(FOO(DEPTH32F_STENCIL8 ), 5, UnsizedFormat::DS, false, ComponentType::None);
+ AddFormatInfo(FOO(DEPTH24_STENCIL8 ), 4, UnsizedFormat::DS, false, ComponentType::Special);
+ AddFormatInfo(FOO(DEPTH32F_STENCIL8 ), 5, UnsizedFormat::DS, false, ComponentType::Special);
// GLES 3.0.4, p205-206, "Required Renderbuffer Formats"
AddFormatInfo(FOO(STENCIL_INDEX8), 1, UnsizedFormat::S, false, ComponentType::UInt);
// GLES 3.0.4, p147, table 3.19
// GLES 3.0.4 p286+ $C.1 "ETC Compressed Texture Image Formats"
AddFormatInfo(FOO(COMPRESSED_RGB8_ETC2 ), 0, UnsizedFormat::RGB , false, ComponentType::NormUInt);
AddFormatInfo(FOO(COMPRESSED_SRGB8_ETC2 ), 0, UnsizedFormat::RGB , true , ComponentType::NormUInt);
@@ -285,24 +285,24 @@ InitFormatInfo()
#define FOO(x) EffectiveFormat::x, #x, 0
// GLES 3.0.4, p128, table 3.12.
AddFormatInfo(FOO(Luminance8Alpha8), 2, UnsizedFormat::LA, false, ComponentType::NormUInt);
AddFormatInfo(FOO(Luminance8 ), 1, UnsizedFormat::L , false, ComponentType::NormUInt);
AddFormatInfo(FOO(Alpha8 ), 1, UnsizedFormat::A , false, ComponentType::NormUInt);
// OES_texture_float
- AddFormatInfo(FOO(Luminance32FAlpha32F), 2, UnsizedFormat::LA, false, ComponentType::Float);
- AddFormatInfo(FOO(Luminance32F ), 1, UnsizedFormat::L , false, ComponentType::Float);
- AddFormatInfo(FOO(Alpha32F ), 1, UnsizedFormat::A , false, ComponentType::Float);
+ AddFormatInfo(FOO(Luminance32FAlpha32F), 8, UnsizedFormat::LA, false, ComponentType::Float);
+ AddFormatInfo(FOO(Luminance32F ), 4, UnsizedFormat::L , false, ComponentType::Float);
+ AddFormatInfo(FOO(Alpha32F ), 4, UnsizedFormat::A , false, ComponentType::Float);
// OES_texture_half_float
- AddFormatInfo(FOO(Luminance16FAlpha16F), 2, UnsizedFormat::LA, false, ComponentType::Float);
- AddFormatInfo(FOO(Luminance16F ), 1, UnsizedFormat::L , false, ComponentType::Float);
- AddFormatInfo(FOO(Alpha16F ), 1, UnsizedFormat::A , false, ComponentType::Float);
+ AddFormatInfo(FOO(Luminance16FAlpha16F), 4, UnsizedFormat::LA, false, ComponentType::Float);
+ AddFormatInfo(FOO(Luminance16F ), 2, UnsizedFormat::L , false, ComponentType::Float);
+ AddFormatInfo(FOO(Alpha16F ), 2, UnsizedFormat::A , false, ComponentType::Float);
#undef FOO
}
//////////////////////////////////////////////////////////////////////////////////////////
bool gAreFormatTablesInitialized = false;
--- a/dom/canvas/WebGLFormats.h
+++ b/dom/canvas/WebGLFormats.h
@@ -158,22 +158,23 @@ enum class UnsizedFormat : uint8_t {
A,
D,
S,
DS,
};
// GLES 3.0.4 p114 Table 3.4, p240
enum class ComponentType : uint8_t {
- None, // DEPTH24_STENCIL8
+ None,
Int, // RGBA32I
UInt, // RGBA32UI, STENCIL_INDEX8
NormInt, // RGBA8_SNORM
NormUInt, // RGBA8, DEPTH_COMPONENT16
Float, // RGBA32F
+ Special, // DEPTH24_STENCIL8
};
enum class CompressionFamily : uint8_t {
ETC1,
ES3, // ETC2 or EAC
ATC,
S3TC,
PVRTC,
@@ -221,16 +222,20 @@ struct PackingInfo
}
};
struct DriverUnpackInfo
{
GLenum internalFormat;
GLenum unpackFormat;
GLenum unpackType;
+
+ PackingInfo ToPacking() const {
+ return {unpackFormat, unpackType};
+ }
};
//////////////////////////////////////////////////////////////////////////////////////////
const FormatInfo* GetFormat(EffectiveFormat format);
uint8_t BytesPerPixel(const PackingInfo& packing);
/*
GLint ComponentSize(const FormatInfo* format, GLenum component);
--- a/dom/canvas/WebGLFramebuffer.cpp
+++ b/dom/canvas/WebGLFramebuffer.cpp
@@ -10,18 +10,17 @@
#include "WebGLContext.h"
#include "WebGLContextUtils.h"
#include "WebGLExtensions.h"
#include "WebGLRenderbuffer.h"
#include "WebGLTexture.h"
namespace mozilla {
-WebGLFBAttachPoint::WebGLFBAttachPoint(WebGLFramebuffer* fb,
- FBAttachment attachmentPoint)
+WebGLFBAttachPoint::WebGLFBAttachPoint(WebGLFramebuffer* fb, GLenum attachmentPoint)
: mFB(fb)
, mAttachmentPoint(attachmentPoint)
, mTexImageTarget(LOCAL_GL_NONE)
{ }
WebGLFBAttachPoint::~WebGLFBAttachPoint()
{
MOZ_ASSERT(!mRenderbufferPtr);
@@ -229,48 +228,41 @@ WebGLFBAttachPoint::IsComplete() const
return false;
auto formatUsage = Format();
if (!formatUsage->isRenderable)
return false;
auto format = formatUsage->format;
- if (mAttachmentPoint >= LOCAL_GL_COLOR_ATTACHMENT0 &&
- mAttachmentPoint <= FBAttachment(LOCAL_GL_COLOR_ATTACHMENT0 - 1 +
- WebGLContext::kMaxColorAttachments))
- {
- return format->isColorFormat;
- }
-
if (mAttachmentPoint == LOCAL_GL_DEPTH_ATTACHMENT)
return format->hasDepth && !format->hasStencil;
if (mAttachmentPoint == LOCAL_GL_STENCIL_ATTACHMENT)
return !format->hasDepth && format->hasStencil;
if (mAttachmentPoint == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
return format->hasDepth && format->hasStencil;
- MOZ_CRASH("Invalid WebGL attachment point?");
+ MOZ_ASSERT(mAttachmentPoint >= LOCAL_GL_COLOR_ATTACHMENT0);
+ return format->isColorFormat;
}
void
-WebGLFBAttachPoint::FinalizeAttachment(gl::GLContext* gl,
- FBAttachment attachmentLoc) const
+WebGLFBAttachPoint::FinalizeAttachment(gl::GLContext* gl, GLenum attachment) const
{
if (!HasImage()) {
- switch (attachmentLoc.get()) {
+ switch (attachment) {
case LOCAL_GL_DEPTH_ATTACHMENT:
case LOCAL_GL_STENCIL_ATTACHMENT:
case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT:
break;
default:
- gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, attachmentLoc.get(),
+ gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, attachment,
LOCAL_GL_RENDERBUFFER, 0);
break;
}
return;
}
MOZ_ASSERT(HasImage());
@@ -285,115 +277,146 @@ WebGLFBAttachPoint::FinalizeAttachment(g
switch (imageTarget) {
case LOCAL_GL_TEXTURE_2D:
case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
- if (attachmentLoc == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
+ if (attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT,
imageTarget, glName, mipLevel);
- gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT,
- imageTarget, glName, mipLevel);
+ gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
+ LOCAL_GL_STENCIL_ATTACHMENT, imageTarget,
+ glName, mipLevel);
} else {
- gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, attachmentLoc.get(),
- imageTarget, glName, mipLevel);
+ gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, attachment, imageTarget,
+ glName, mipLevel);
}
break;
case LOCAL_GL_TEXTURE_2D_ARRAY:
case LOCAL_GL_TEXTURE_3D:
- if (attachmentLoc == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
+ if (attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
gl->fFramebufferTextureLayer(LOCAL_GL_FRAMEBUFFER,
- LOCAL_GL_DEPTH_ATTACHMENT,
- glName, mipLevel, layer);
+ LOCAL_GL_DEPTH_ATTACHMENT, glName, mipLevel,
+ layer);
gl->fFramebufferTextureLayer(LOCAL_GL_FRAMEBUFFER,
- LOCAL_GL_STENCIL_ATTACHMENT,
- glName, mipLevel, layer);
+ LOCAL_GL_STENCIL_ATTACHMENT, glName,
+ mipLevel, layer);
} else {
- gl->fFramebufferTextureLayer(LOCAL_GL_FRAMEBUFFER, attachmentLoc.get(),
- glName, mipLevel, layer);
+ gl->fFramebufferTextureLayer(LOCAL_GL_FRAMEBUFFER, attachment, glName,
+ mipLevel, layer);
}
break;
}
return ;
}
if (Renderbuffer()) {
- Renderbuffer()->FramebufferRenderbuffer(attachmentLoc);
+ Renderbuffer()->FramebufferRenderbuffer(attachment);
return;
}
MOZ_CRASH();
}
JS::Value
-WebGLFBAttachPoint::GetParameter(WebGLContext* context, GLenum target, GLenum attachment,
- GLenum pname)
+WebGLFBAttachPoint::GetParameter(const char* funcName, WebGLContext* webgl, JSContext* cx,
+ GLenum target, GLenum attachment, GLenum pname,
+ ErrorResult* const out_error)
{
- WebGLTexture* tex = Texture();
+ const bool hasAttachment = (mTexturePtr || mRenderbufferPtr);
+ if (!hasAttachment) {
+ switch (pname) {
+ case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
+ return JS::Int32Value(LOCAL_GL_NONE);
+
+ case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
+ return JS::NullValue();
+
+ default:
+ webgl->ErrorInvalidOperation("%s: No attachment at %s.", funcName,
+ webgl->EnumName(attachment));
+ return JS::NullValue();
+ }
+ }
bool isPNameValid = false;
switch (pname) {
+ case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
+ return JS::Int32Value(mTexturePtr ? LOCAL_GL_TEXTURE
+ : LOCAL_GL_RENDERBUFFER);
+
+ case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
+ return (mTexturePtr ? webgl->WebGLObjectAsJSValue(cx, mTexturePtr.get(),
+ *out_error)
+ : webgl->WebGLObjectAsJSValue(cx, mRenderbufferPtr.get(),
+ *out_error));
+ ////////////////
+
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
+ isPNameValid = true;
+ break;
+
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
+ MOZ_ASSERT(attachment != LOCAL_GL_DEPTH_STENCIL_ATTACHMENT);
isPNameValid = true;
break;
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
- if (tex->mContext->IsWebGL2() ||
- tex->mContext->IsExtensionEnabled(WebGLExtensionID::EXT_sRGB))
+ if (webgl->IsWebGL2() ||
+ webgl->IsExtensionEnabled(WebGLExtensionID::EXT_sRGB))
{
isPNameValid = true;
}
break;
+ ////////////////
+
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
- if (tex) {
+ if (mTexturePtr)
return JS::Int32Value(MipLevel());
- }
break;
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
- if (tex) {
- int32_t face = 0;
- if (tex->Target() == LOCAL_GL_TEXTURE_CUBE_MAP) {
+ if (mTexturePtr) {
+ GLenum face = 0;
+ if (mTexturePtr->Target() == LOCAL_GL_TEXTURE_CUBE_MAP) {
face = ImageTarget().get();
}
return JS::Int32Value(face);
}
break;
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER:
- if (tex) {
+ if (mTexturePtr) {
int32_t layer = 0;
- if (tex->Target() == LOCAL_GL_TEXTURE_2D_ARRAY ||
- tex->Target() == LOCAL_GL_TEXTURE_3D)
+ if (ImageTarget() == LOCAL_GL_TEXTURE_2D_ARRAY ||
+ ImageTarget() == LOCAL_GL_TEXTURE_3D)
{
layer = Layer();
}
return JS::Int32Value(layer);
}
break;
}
if (!isPNameValid) {
- context->ErrorInvalidEnum("getFramebufferParameter: Invalid combination of "
- "attachment and pname.");
+ webgl->ErrorInvalidEnum("%s: Invalid pname: 0x%04x", funcName, pname);
return JS::NullValue();
}
- gl::GLContext* gl = tex->mContext->GL();
+ gl::GLContext* gl = webgl->GL();
gl->MakeCurrent();
GLint ret = 0;
gl->fGetFramebufferAttachmentParameteriv(target, attachment, pname, &ret);
return JS::Int32Value(ret);
}
////////////////////////////////////////////////////////////////////////////////
@@ -403,67 +426,77 @@ WebGLFramebuffer::WebGLFramebuffer(WebGL
: WebGLContextBoundObject(webgl)
, mGLName(fbo)
, mIsKnownFBComplete(false)
, mReadBufferMode(LOCAL_GL_COLOR_ATTACHMENT0)
, mColorAttachment0(this, LOCAL_GL_COLOR_ATTACHMENT0)
, mDepthAttachment(this, LOCAL_GL_DEPTH_ATTACHMENT)
, mStencilAttachment(this, LOCAL_GL_STENCIL_ATTACHMENT)
, mDepthStencilAttachment(this, LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
+ , mDrawBuffers(1, LOCAL_GL_COLOR_ATTACHMENT0)
#ifdef ANDROID
, mIsFB(false)
#endif
-
{
mContext->mFramebuffers.insertBack(this);
}
void
WebGLFramebuffer::Delete()
{
mColorAttachment0.Clear();
mDepthAttachment.Clear();
mStencilAttachment.Clear();
mDepthStencilAttachment.Clear();
- const size_t moreColorAttachmentCount = mMoreColorAttachments.Length();
- for (size_t i = 0; i < moreColorAttachmentCount; i++) {
- mMoreColorAttachments[i].Clear();
+ for (auto& cur : mMoreColorAttachments) {
+ cur.Clear();
}
mContext->MakeContextCurrent();
mContext->gl->fDeleteFramebuffers(1, &mGLName);
+
LinkedListElement<WebGLFramebuffer>::removeFrom(mContext->mFramebuffers);
#ifdef ANDROID
mIsFB = false;
#endif
}
void
-WebGLFramebuffer::FramebufferRenderbuffer(FBAttachment attachPointEnum,
- RBTarget rbtarget,
+WebGLFramebuffer::FramebufferRenderbuffer(GLenum attachment, RBTarget rbtarget,
WebGLRenderbuffer* rb)
{
MOZ_ASSERT(mContext->mBoundDrawFramebuffer == this ||
mContext->mBoundReadFramebuffer == this);
if (!mContext->ValidateObjectAllowNull("framebufferRenderbuffer: renderbuffer", rb))
return;
- // `attachPoint` is validated by ValidateFramebufferAttachment().
- WebGLFBAttachPoint& attachPoint = GetAttachPoint(attachPointEnum);
- attachPoint.SetRenderbuffer(rb);
+ // `attachPointEnum` is validated by ValidateFramebufferAttachment().
+
+ const auto fnAttach = [this, rb](GLenum attachment) {
+ const auto attachPoint = this->GetAttachPoint(attachment);
+ MOZ_ASSERT(attachPoint);
+
+ attachPoint->SetRenderbuffer(rb);
+ };
+
+ if (mContext->IsWebGL2() && attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
+ fnAttach(LOCAL_GL_DEPTH_ATTACHMENT);
+ fnAttach(LOCAL_GL_STENCIL_ATTACHMENT);
+ } else {
+ fnAttach(attachment);
+ }
InvalidateFramebufferStatus();
}
void
-WebGLFramebuffer::FramebufferTexture2D(FBAttachment attachPointEnum,
- TexImageTarget texImageTarget,
+WebGLFramebuffer::FramebufferTexture2D(GLenum attachment, TexImageTarget texImageTarget,
WebGLTexture* tex, GLint level)
{
MOZ_ASSERT(mContext->mBoundDrawFramebuffer == this ||
mContext->mBoundReadFramebuffer == this);
if (!mContext->ValidateObjectAllowNull("framebufferTexture2D: texture", tex))
return;
@@ -472,66 +505,97 @@ WebGLFramebuffer::FramebufferTexture2D(F
bool isTexTarget2D = texImageTarget == LOCAL_GL_TEXTURE_2D;
if (isTexture2D != isTexTarget2D) {
mContext->ErrorInvalidOperation("framebufferTexture2D: Mismatched"
" texture and texture target.");
return;
}
}
- WebGLFBAttachPoint& attachPoint = GetAttachPoint(attachPointEnum);
- attachPoint.SetTexImage(tex, texImageTarget, level);
+ const auto fnAttach = [this, tex, texImageTarget, level](GLenum attachment) {
+ const auto attachPoint = this->GetAttachPoint(attachment);
+ MOZ_ASSERT(attachPoint);
+
+ attachPoint->SetTexImage(tex, texImageTarget, level);
+ };
+
+ if (mContext->IsWebGL2() && attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
+ fnAttach(LOCAL_GL_DEPTH_ATTACHMENT);
+ fnAttach(LOCAL_GL_STENCIL_ATTACHMENT);
+ } else {
+ fnAttach(attachment);
+ }
InvalidateFramebufferStatus();
}
void
-WebGLFramebuffer::FramebufferTextureLayer(FBAttachment attachment, WebGLTexture* tex,
+WebGLFramebuffer::FramebufferTextureLayer(GLenum attachment, WebGLTexture* tex,
GLint level, GLint layer)
{
MOZ_ASSERT(mContext->mBoundDrawFramebuffer == this ||
mContext->mBoundReadFramebuffer == this);
- MOZ_ASSERT(tex);
+
+ const TexImageTarget texImageTarget = (tex ? tex->Target().get()
+ : LOCAL_GL_TEXTURE_2D);
+
+ const auto fnAttach = [this, tex, texImageTarget, level, layer](GLenum attachment) {
+ const auto attachPoint = this->GetAttachPoint(attachment);
+ MOZ_ASSERT(attachPoint);
- WebGLFBAttachPoint& attachPoint = GetAttachPoint(attachment);
- TexImageTarget texImageTarget = tex->Target().get();
- attachPoint.SetTexImageLayer(tex, texImageTarget, level, layer);
+ attachPoint->SetTexImageLayer(tex, texImageTarget, level, layer);
+ };
+
+ if (mContext->IsWebGL2() && attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
+ fnAttach(LOCAL_GL_DEPTH_ATTACHMENT);
+ fnAttach(LOCAL_GL_STENCIL_ATTACHMENT);
+ } else {
+ fnAttach(attachment);
+ }
InvalidateFramebufferStatus();
}
-WebGLFBAttachPoint&
-WebGLFramebuffer::GetAttachPoint(FBAttachment attachPoint)
+WebGLFBAttachPoint*
+WebGLFramebuffer::GetAttachPoint(GLenum attachPoint)
{
- switch (attachPoint.get()) {
+ switch (attachPoint) {
case LOCAL_GL_COLOR_ATTACHMENT0:
- return mColorAttachment0;
+ return &mColorAttachment0;
case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT:
- return mDepthStencilAttachment;
+ return &mDepthStencilAttachment;
case LOCAL_GL_DEPTH_ATTACHMENT:
- return mDepthAttachment;
+ return &mDepthAttachment;
case LOCAL_GL_STENCIL_ATTACHMENT:
- return mStencilAttachment;
+ return &mStencilAttachment;
default:
break;
}
- if (attachPoint >= LOCAL_GL_COLOR_ATTACHMENT1) {
- size_t colorAttachmentId = attachPoint.get() - LOCAL_GL_COLOR_ATTACHMENT0;
- if (colorAttachmentId < (size_t)mContext->mGLMaxColorAttachments) {
- EnsureColorAttachPoints(colorAttachmentId);
- return mMoreColorAttachments[colorAttachmentId - 1];
+ const auto lastCAEnum = mContext->LastColorAttachmentEnum();
+ if (attachPoint < LOCAL_GL_COLOR_ATTACHMENT1 ||
+ attachPoint > lastCAEnum)
+ {
+ return nullptr;
+ }
+
+ if (!mMoreColorAttachments.size()) {
+ for (GLenum cur = LOCAL_GL_COLOR_ATTACHMENT1; cur <= lastCAEnum; cur++) {
+ mMoreColorAttachments.push_back(WebGLFBAttachPoint(this, cur));
}
}
+ MOZ_ASSERT(LOCAL_GL_COLOR_ATTACHMENT0 + mMoreColorAttachments.size() == lastCAEnum);
- MOZ_CRASH("bad `attachPoint` validation");
+ const size_t offset = attachPoint - LOCAL_GL_COLOR_ATTACHMENT1;
+ MOZ_ASSERT(offset <= mMoreColorAttachments.size());
+ return &mMoreColorAttachments[offset];
}
void
WebGLFramebuffer::DetachTexture(const WebGLTexture* tex)
{
if (mColorAttachment0.Texture() == tex)
mColorAttachment0.Clear();
@@ -539,20 +603,19 @@ WebGLFramebuffer::DetachTexture(const We
mDepthAttachment.Clear();
if (mStencilAttachment.Texture() == tex)
mStencilAttachment.Clear();
if (mDepthStencilAttachment.Texture() == tex)
mDepthStencilAttachment.Clear();
- const size_t moreColorAttachmentCount = mMoreColorAttachments.Length();
- for (size_t i = 0; i < moreColorAttachmentCount; i++) {
- if (mMoreColorAttachments[i].Texture() == tex)
- mMoreColorAttachments[i].Clear();
+ for (auto& cur : mMoreColorAttachments) {
+ if (cur.Texture() == tex)
+ cur.Clear();
}
}
void
WebGLFramebuffer::DetachRenderbuffer(const WebGLRenderbuffer* rb)
{
if (mColorAttachment0.Renderbuffer() == rb)
mColorAttachment0.Clear();
@@ -561,36 +624,34 @@ WebGLFramebuffer::DetachRenderbuffer(con
mDepthAttachment.Clear();
if (mStencilAttachment.Renderbuffer() == rb)
mStencilAttachment.Clear();
if (mDepthStencilAttachment.Renderbuffer() == rb)
mDepthStencilAttachment.Clear();
- const size_t moreColorAttachmentCount = mMoreColorAttachments.Length();
- for (size_t i = 0; i < moreColorAttachmentCount; i++) {
- if (mMoreColorAttachments[i].Renderbuffer() == rb)
- mMoreColorAttachments[i].Clear();
+ for (auto& cur : mMoreColorAttachments) {
+ if (cur.Renderbuffer() == rb)
+ cur.Clear();
}
}
bool
WebGLFramebuffer::HasDefinedAttachments() const
{
bool hasAttachments = false;
hasAttachments |= mColorAttachment0.IsDefined();
hasAttachments |= mDepthAttachment.IsDefined();
hasAttachments |= mStencilAttachment.IsDefined();
hasAttachments |= mDepthStencilAttachment.IsDefined();
- const size_t moreColorAttachmentCount = mMoreColorAttachments.Length();
- for (size_t i = 0; i < moreColorAttachmentCount; i++) {
- hasAttachments |= mMoreColorAttachments[i].IsDefined();
+ for (const auto& cur : mMoreColorAttachments) {
+ hasAttachments |= cur.IsDefined();
}
return hasAttachments;
}
static bool
IsIncomplete(const WebGLFBAttachPoint& cur)
{
@@ -602,19 +663,18 @@ WebGLFramebuffer::HasIncompleteAttachmen
{
bool hasIncomplete = false;
hasIncomplete |= IsIncomplete(mColorAttachment0);
hasIncomplete |= IsIncomplete(mDepthAttachment);
hasIncomplete |= IsIncomplete(mStencilAttachment);
hasIncomplete |= IsIncomplete(mDepthStencilAttachment);
- const size_t moreColorAttachmentCount = mMoreColorAttachments.Length();
- for (size_t i = 0; i < moreColorAttachmentCount; i++) {
- hasIncomplete |= IsIncomplete(mMoreColorAttachments[i]);
+ for (const auto& cur : mMoreColorAttachments) {
+ hasIncomplete |= IsIncomplete(cur);
}
return hasIncomplete;
}
static bool
MatchOrReplaceSize(const WebGLFBAttachPoint& cur, uint32_t* const out_width,
uint32_t* const out_height)
@@ -647,19 +707,18 @@ WebGLFramebuffer::AllImageRectsMatch() c
uint32_t height = 0;
bool imageRectsMatch = true;
imageRectsMatch &= MatchOrReplaceSize(mColorAttachment0, &width, &height);
imageRectsMatch &= MatchOrReplaceSize(mDepthAttachment, &width, &height);
imageRectsMatch &= MatchOrReplaceSize(mStencilAttachment, &width, &height);
imageRectsMatch &= MatchOrReplaceSize(mDepthStencilAttachment, &width, &height);
- const size_t moreColorAttachmentCount = mMoreColorAttachments.Length();
- for (size_t i = 0; i < moreColorAttachmentCount; i++) {
- imageRectsMatch &= MatchOrReplaceSize(mMoreColorAttachments[i], &width, &height);
+ for (const auto& cur : mMoreColorAttachments) {
+ imageRectsMatch &= MatchOrReplaceSize(cur, &width, &height);
}
return imageRectsMatch;
}
FBStatus
WebGLFramebuffer::PrecheckFramebufferStatus() const
{
@@ -737,107 +796,106 @@ WebGLFramebuffer::CheckAndInitializeAtta
{
MOZ_ASSERT(mContext->mBoundDrawFramebuffer == this ||
mContext->mBoundReadFramebuffer == this);
if (CheckFramebufferStatus() != LOCAL_GL_FRAMEBUFFER_COMPLETE)
return false;
// Cool! We've checked out ok. Just need to initialize.
- const size_t moreColorAttachmentCount = mMoreColorAttachments.Length();
// Check if we need to initialize anything
{
bool hasUninitializedAttachments = false;
- if (mColorAttachment0.HasImage())
+ if (mColorAttachment0.HasImage() && IsDrawBuffer(0))
hasUninitializedAttachments |= mColorAttachment0.HasUninitializedImageData();
+
+ size_t i = 1;
+ for (const auto& cur : mMoreColorAttachments) {
+ if (cur.HasImage() && IsDrawBuffer(i))
+ hasUninitializedAttachments |= cur.HasUninitializedImageData();
+
+ ++i;
+ }
+
if (mDepthAttachment.HasImage())
hasUninitializedAttachments |= mDepthAttachment.HasUninitializedImageData();
if (mStencilAttachment.HasImage())
hasUninitializedAttachments |= mStencilAttachment.HasUninitializedImageData();
if (mDepthStencilAttachment.HasImage())
hasUninitializedAttachments |= mDepthStencilAttachment.HasUninitializedImageData();
- for (size_t i = 0; i < moreColorAttachmentCount; i++) {
- if (mMoreColorAttachments[i].HasImage())
- hasUninitializedAttachments |= mMoreColorAttachments[i].HasUninitializedImageData();
- }
-
if (!hasUninitializedAttachments)
return true;
}
// Get buffer-bit-mask and color-attachment-mask-list
- uint32_t mask = 0;
- bool colorAttachmentsMask[WebGLContext::kMaxColorAttachments] = { false };
- MOZ_ASSERT(1 + moreColorAttachmentCount <= WebGLContext::kMaxColorAttachments);
+ uint32_t clearBits = 0;
+ std::vector<GLenum> tempDrawBuffers(1 + mMoreColorAttachments.size(), LOCAL_GL_NONE);
+
+ if (mColorAttachment0.HasUninitializedImageData() && IsDrawBuffer(0)) {
+ clearBits |= LOCAL_GL_COLOR_BUFFER_BIT;
+ tempDrawBuffers[0] = LOCAL_GL_COLOR_ATTACHMENT0;
+ }
- if (mColorAttachment0.HasUninitializedImageData()) {
- colorAttachmentsMask[0] = true;
- mask |= LOCAL_GL_COLOR_BUFFER_BIT;
+ size_t i = 1;
+ for (const auto& cur : mMoreColorAttachments) {
+ if (cur.HasUninitializedImageData() && IsDrawBuffer(i)) {
+ clearBits |= LOCAL_GL_COLOR_BUFFER_BIT;
+ tempDrawBuffers[i] = LOCAL_GL_COLOR_ATTACHMENT0 + i;
+ }
+
+ ++i;
}
if (mDepthAttachment.HasUninitializedImageData() ||
mDepthStencilAttachment.HasUninitializedImageData())
{
- mask |= LOCAL_GL_DEPTH_BUFFER_BIT;
+ clearBits |= LOCAL_GL_DEPTH_BUFFER_BIT;
}
if (mStencilAttachment.HasUninitializedImageData() ||
mDepthStencilAttachment.HasUninitializedImageData())
{
- mask |= LOCAL_GL_STENCIL_BUFFER_BIT;
+ clearBits |= LOCAL_GL_STENCIL_BUFFER_BIT;
}
- for (size_t i = 0; i < moreColorAttachmentCount; i++) {
- if (mMoreColorAttachments[i].HasUninitializedImageData()) {
- colorAttachmentsMask[1 + i] = true;
- mask |= LOCAL_GL_COLOR_BUFFER_BIT;
- }
- }
+ mContext->MakeContextCurrent();
+
+ mContext->gl->fDrawBuffers(tempDrawBuffers.size(), tempDrawBuffers.data());
// Clear!
- mContext->ForceClearFramebufferWithDefaultValues(false, mask, colorAttachmentsMask);
+ mContext->ForceClearFramebufferWithDefaultValues(clearBits, false);
+
+ mContext->gl->fDrawBuffers(mDrawBuffers.size(), mDrawBuffers.data());
// Mark all the uninitialized images as initialized.
- if (mColorAttachment0.HasUninitializedImageData())
- mColorAttachment0.SetImageDataStatus(WebGLImageDataStatus::InitializedImageData);
if (mDepthAttachment.HasUninitializedImageData())
mDepthAttachment.SetImageDataStatus(WebGLImageDataStatus::InitializedImageData);
if (mStencilAttachment.HasUninitializedImageData())
mStencilAttachment.SetImageDataStatus(WebGLImageDataStatus::InitializedImageData);
if (mDepthStencilAttachment.HasUninitializedImageData())
mDepthStencilAttachment.SetImageDataStatus(WebGLImageDataStatus::InitializedImageData);
- for (size_t i = 0; i < moreColorAttachmentCount; i++) {
- if (mMoreColorAttachments[i].HasUninitializedImageData())
- mMoreColorAttachments[i].SetImageDataStatus(WebGLImageDataStatus::InitializedImageData);
+ if (mColorAttachment0.HasUninitializedImageData() && IsDrawBuffer(0)) {
+ mColorAttachment0.SetImageDataStatus(WebGLImageDataStatus::InitializedImageData);
+ }
+
+ i = 1;
+ for (auto& cur : mMoreColorAttachments) {
+ if (cur.HasUninitializedImageData() && IsDrawBuffer(i))
+ cur.SetImageDataStatus(WebGLImageDataStatus::InitializedImageData);
+
+ ++i;
}
return true;
}
-void WebGLFramebuffer::EnsureColorAttachPoints(size_t colorAttachmentId)
-{
- size_t maxColorAttachments = mContext->mGLMaxColorAttachments;
-
- MOZ_ASSERT(colorAttachmentId < maxColorAttachments);
-
- if (colorAttachmentId < ColorAttachmentCount())
- return;
-
- while (ColorAttachmentCount() < maxColorAttachments) {
- GLenum nextAttachPoint = LOCAL_GL_COLOR_ATTACHMENT0 + ColorAttachmentCount();
- mMoreColorAttachments.AppendElement(WebGLFBAttachPoint(this, nextAttachPoint));
- }
-
- MOZ_ASSERT(ColorAttachmentCount() == maxColorAttachments);
-}
-
static void
FinalizeDrawAndReadBuffers(gl::GLContext* gl, bool isColorBufferDefined)
{
MOZ_ASSERT(gl, "Expected a valid GLContext ptr.");
// GLES don't support DrawBuffer()/ReadBuffer.
// According to http://www.opengl.org/wiki/Framebuffer_Object
//
// Each draw buffers must either specify color attachment points that have images
@@ -877,19 +935,18 @@ WebGLFramebuffer::FinalizeAttachments()
LOCAL_GL_RENDERBUFFER, 0);
// Call finalize.
mColorAttachment0.FinalizeAttachment(gl, LOCAL_GL_COLOR_ATTACHMENT0);
mDepthAttachment.FinalizeAttachment(gl, LOCAL_GL_DEPTH_ATTACHMENT);
mStencilAttachment.FinalizeAttachment(gl, LOCAL_GL_STENCIL_ATTACHMENT);
mDepthStencilAttachment.FinalizeAttachment(gl, LOCAL_GL_DEPTH_STENCIL_ATTACHMENT);
- const size_t moreColorAttachmentCount = mMoreColorAttachments.Length();
- for (size_t i = 0; i < moreColorAttachmentCount; i++) {
- GLenum attachPoint = LOCAL_GL_COLOR_ATTACHMENT0 + 1 + i;
+ for (size_t i = 0; i < mMoreColorAttachments.size(); i++) {
+ GLenum attachPoint = LOCAL_GL_COLOR_ATTACHMENT1 + i;
mMoreColorAttachments[i].FinalizeAttachment(gl, attachPoint);
}
FinalizeDrawAndReadBuffers(gl, mColorAttachment0.IsDefined());
}
bool
WebGLFramebuffer::ValidateForRead(const char* funcName,
@@ -903,26 +960,25 @@ WebGLFramebuffer::ValidateForRead(const
}
if (mReadBufferMode == LOCAL_GL_NONE) {
mContext->ErrorInvalidOperation("%s: Read buffer mode must not be"
" NONE.", funcName);
return false;
}
- const auto& attachPoint = GetAttachPoint(mReadBufferMode);
-
- if (!attachPoint.IsDefined()) {
- mContext->ErrorInvalidOperation("%s: THe attachment specified for reading is"
+ const auto attachPoint = GetAttachPoint(mReadBufferMode);
+ if (!attachPoint || !attachPoint->IsDefined()) {
+ mContext->ErrorInvalidOperation("%s: The attachment specified for reading is"
" null.", funcName);
return false;
}
- *out_format = attachPoint.Format();
- attachPoint.Size(out_width, out_height);
+ *out_format = attachPoint->Format();
+ attachPoint->Size(out_width, out_height);
return true;
}
static bool
AttachmentsDontMatch(const WebGLFBAttachPoint& a, const WebGLFBAttachPoint& b)
{
if (a.Texture()) {
return (a.Texture() != b.Texture());
@@ -931,101 +987,53 @@ AttachmentsDontMatch(const WebGLFBAttach
if (a.Renderbuffer()) {
return (a.Renderbuffer() != b.Renderbuffer());
}
return false;
}
JS::Value
-WebGLFramebuffer::GetAttachmentParameter(JSContext* cx, GLenum target, GLenum attachment,
+WebGLFramebuffer::GetAttachmentParameter(const char* funcName, JSContext* cx,
+ GLenum target, GLenum attachment,
GLenum pname, ErrorResult* const out_error)
{
- // "If a framebuffer object is bound to target, then attachment must be one of the
- // attachment points of the framebuffer listed in table 4.6."
- switch (attachment) {
- case LOCAL_GL_DEPTH_ATTACHMENT:
- case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT:
- break;
-
- case LOCAL_GL_STENCIL_ATTACHMENT:
- // "If attachment is DEPTH_STENCIL_ATTACHMENT, and different objects are bound to
- // the depth and stencil attachment points of target, the query will fail and
- // generate an INVALID_OPERATION error. If the same object is bound to both
- // attachment points, information about that object will be returned."
-
- // Does this mean it has to be the same level or layer? Because the queries are
- // independent of level or layer.
- if (AttachmentsDontMatch(DepthAttachment(), StencilAttachment())) {
- mContext->ErrorInvalidOperation("getFramebufferAttachmentParameter: "
- "DEPTH_ATTACHMENT and STENCIL_ATTACHMENT "
- "have different objects bound.");
- return JS::NullValue();
- }
- break;
-
- default:
- if (attachment < LOCAL_GL_COLOR_ATTACHMENT0 ||
- attachment > mContext->LastColorAttachment())
- {
- mContext->ErrorInvalidEnum("getFramebufferAttachmentParameter: Can only "
- "query COLOR_ATTACHMENTi, DEPTH_ATTACHMENT, "
- "DEPTH_STENCIL_ATTACHMENT, or STENCIL_ATTACHMENT "
- "on framebuffer.");
- return JS::NullValue();
- }
- }
-
- if (attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT &&
- pname == LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE)
- {
- mContext->ErrorInvalidOperation("getFramebufferAttachmentParameter: Querying "
- "FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE against "
- "DEPTH_STENCIL_ATTACHMENT is an error.");
+ auto attachPoint = GetAttachPoint(attachment);
+ if (!attachPoint) {
+ mContext->ErrorInvalidEnum("%s: Can only query COLOR_ATTACHMENTi,"
+ " DEPTH_ATTACHMENT, DEPTH_STENCIL_ATTACHMENT, or"
+ " STENCIL_ATTACHMENT for a framebuffer.",
+ funcName);
return JS::NullValue();
}
- GLenum objectType = LOCAL_GL_NONE;
- auto& fba = GetAttachPoint(attachment);
- if (fba.Texture()) {
- objectType = LOCAL_GL_TEXTURE;
- } else if (fba.Renderbuffer()) {
- objectType = LOCAL_GL_RENDERBUFFER;
- }
+ if (mContext->IsWebGL2() && attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
+ // There are a couple special rules for this one.
- switch (pname) {
- case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
- return JS::Int32Value(objectType);
-
- case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
- if (objectType == LOCAL_GL_NONE) {
+ if (pname == LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE) {
+ mContext->ErrorInvalidOperation("%s: Querying"
+ " FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE"
+ " against DEPTH_STENCIL_ATTACHMENT is an"
+ " error.",
+ funcName);
return JS::NullValue();
}
- if (objectType == LOCAL_GL_RENDERBUFFER) {
- const WebGLRenderbuffer* rb = fba.Renderbuffer();
- return mContext->WebGLObjectAsJSValue(cx, rb, *out_error);
+ if (AttachmentsDontMatch(DepthAttachment(), StencilAttachment())) {
+ mContext->ErrorInvalidOperation("%s: DEPTH_ATTACHMENT and STENCIL_ATTACHMENT"
+ " have different objects bound.",
+ funcName);
+ return JS::NullValue();
}
- /* If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is TEXTURE, then */
- if (objectType == LOCAL_GL_TEXTURE) {
- const WebGLTexture* tex = fba.Texture();
- return mContext->WebGLObjectAsJSValue(cx, tex, *out_error);
- }
- break;
+ attachPoint = GetAttachPoint(LOCAL_GL_DEPTH_ATTACHMENT);
}
- if (objectType == LOCAL_GL_NONE) {
- mContext->ErrorInvalidOperation("getFramebufferAttachmentParameter: No "
- "attachment at %s",
- mContext->EnumName(attachment));
- return JS::NullValue();
- }
-
- return fba.GetParameter(mContext, target, attachment, pname);
+ return attachPoint->GetParameter(funcName, mContext, cx, target, attachment, pname,
+ out_error);
}
////////////////////////////////////////////////////////////////////////////////
// Goop.
JSObject*
WebGLFramebuffer::WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto)
{
@@ -1043,16 +1051,37 @@ ImplCycleCollectionTraverse(nsCycleColle
mozilla::WebGLFBAttachPoint& field,
const char* name,
uint32_t flags = 0)
{
CycleCollectionNoteChild(callback, field.Texture(), name, flags);
CycleCollectionNoteChild(callback, field.Renderbuffer(), name, flags);
}
+template<typename T>
+inline void
+ImplCycleCollectionUnlink(std::vector<T>& field)
+{
+ for (auto& cur : field) {
+ cur.Unlink();
+ }
+}
+
+template<typename T>
+inline void
+ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& callback,
+ std::vector<T>& field,
+ const char* name,
+ uint32_t flags = 0)
+{
+ for (auto& cur : field) {
+ ImplCycleCollectionTraverse(callback, cur, name, flags);
+ }
+}
+
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLFramebuffer,
mColorAttachment0,
mDepthAttachment,
mStencilAttachment,
mDepthStencilAttachment,
mMoreColorAttachments)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLFramebuffer, AddRef)
--- a/dom/canvas/WebGLFramebuffer.h
+++ b/dom/canvas/WebGLFramebuffer.h
@@ -24,26 +24,26 @@ class WebGLTexture;
namespace gl {
class GLContext;
} // namespace gl
class WebGLFBAttachPoint
{
public:
WebGLFramebuffer* const mFB;
+ const GLenum mAttachmentPoint;
private:
WebGLRefPtr<WebGLTexture> mTexturePtr;
WebGLRefPtr<WebGLRenderbuffer> mRenderbufferPtr;
- FBAttachment mAttachmentPoint;
TexImageTarget mTexImageTarget;
GLint mTexImageLayer;
GLint mTexImageLevel;
public:
- WebGLFBAttachPoint(WebGLFramebuffer* fb, FBAttachment attachmentPoint);
+ WebGLFBAttachPoint(WebGLFramebuffer* fb, GLenum attachmentPoint);
~WebGLFBAttachPoint();
void Unlink();
bool IsDefined() const;
bool IsDeleteRequested() const;
const webgl::FormatUsageInfo* Format() const;
@@ -84,21 +84,21 @@ public:
void SetImageDataStatus(WebGLImageDataStatus x);
void Size(uint32_t* const out_width, uint32_t* const out_height) const;
//const WebGLRectangleObject& RectangleObject() const;
bool HasImage() const;
bool IsComplete() const;
- void FinalizeAttachment(gl::GLContext* gl,
- FBAttachment attachmentLoc) const;
+ void FinalizeAttachment(gl::GLContext* gl, GLenum attachmentLoc) const;
- JS::Value GetParameter(WebGLContext* context, GLenum target, GLenum attachment,
- GLenum pname);
+ JS::Value GetParameter(const char* funcName, WebGLContext* webgl, JSContext* cx,
+ GLenum target, GLenum attachment, GLenum pname,
+ ErrorResult* const out_error);
void OnBackingStoreRespecified() const;
};
class WebGLFramebuffer final
: public nsWrapperCache
, public WebGLRefCountedObject<WebGLFramebuffer>
, public LinkedListElement<WebGLFramebuffer>
@@ -117,17 +117,26 @@ private:
GLenum mReadBufferMode;
// No need to chase pointers for the oft-used color0.
WebGLFBAttachPoint mColorAttachment0;
WebGLFBAttachPoint mDepthAttachment;
WebGLFBAttachPoint mStencilAttachment;
WebGLFBAttachPoint mDepthStencilAttachment;
- nsTArray<WebGLFBAttachPoint> mMoreColorAttachments;
+ std::vector<WebGLFBAttachPoint> mMoreColorAttachments;
+
+ std::vector<GLenum> mDrawBuffers;
+
+ bool IsDrawBuffer(size_t n) const {
+ if (n < mDrawBuffers.size())
+ return bool(mDrawBuffers[n]);
+
+ return false;
+ }
#ifdef ANDROID
// Bug 1140459: Some drivers (including our test slaves!) don't
// give reasonable answers for IsRenderbuffer, maybe others.
// This shows up on Android 2.3 emulator.
//
// So we track the `is a Framebuffer` state ourselves.
bool mIsFB;
@@ -141,24 +150,21 @@ private:
DeleteOnce();
}
const WebGLRectangleObject& GetAnyRectObject() const;
public:
void Delete();
- void FramebufferRenderbuffer(FBAttachment attachment, RBTarget rbtarget,
+ void FramebufferRenderbuffer(GLenum attachment, RBTarget rbtarget,
WebGLRenderbuffer* rb);
-
- void FramebufferTexture2D(FBAttachment attachment,
- TexImageTarget texImageTarget, WebGLTexture* tex,
- GLint level);
-
- void FramebufferTextureLayer(FBAttachment attachment, WebGLTexture* tex, GLint level,
+ void FramebufferTexture2D(GLenum attachment, TexImageTarget texImageTarget,
+ WebGLTexture* tex, GLint level);
+ void FramebufferTextureLayer(GLenum attachment, WebGLTexture* tex, GLint level,
GLint layer);
bool HasDefinedAttachments() const;
bool HasIncompleteAttachments() const;
bool AllImageRectsMatch() const;
FBStatus PrecheckFramebufferStatus() const;
FBStatus CheckFramebufferStatus() const;
@@ -166,39 +172,38 @@ public:
GetFormatForAttachment(const WebGLFBAttachPoint& attachment) const;
bool HasDepthStencilConflict() const {
return int(mDepthAttachment.IsDefined()) +
int(mStencilAttachment.IsDefined()) +
int(mDepthStencilAttachment.IsDefined()) >= 2;
}
- size_t ColorAttachmentCount() const {
- return 1 + mMoreColorAttachments.Length();
- }
const WebGLFBAttachPoint& ColorAttachment(size_t colorAttachmentId) const {
- MOZ_ASSERT(colorAttachmentId < ColorAttachmentCount());
+ MOZ_ASSERT(colorAttachmentId < 1 + mMoreColorAttachments.size());
return colorAttachmentId ? mMoreColorAttachments[colorAttachmentId - 1]
: mColorAttachment0;
}
const WebGLFBAttachPoint& DepthAttachment() const {
return mDepthAttachment;
}
const WebGLFBAttachPoint& StencilAttachment() const {
return mStencilAttachment;
}
const WebGLFBAttachPoint& DepthStencilAttachment() const {
return mDepthStencilAttachment;
}
- WebGLFBAttachPoint& GetAttachPoint(FBAttachment attachPointEnum);
+protected:
+ WebGLFBAttachPoint* GetAttachPoint(GLenum attachment); // Fallible
+public:
void DetachTexture(const WebGLTexture* tex);
void DetachRenderbuffer(const WebGLRenderbuffer* rb);
WebGLContext* GetParentObject() const {
return mContext;
}
@@ -209,28 +214,24 @@ public:
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLFramebuffer)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLFramebuffer)
// mask mirrors glClear.
bool HasCompletePlanes(GLbitfield mask);
bool CheckAndInitializeAttachments();
- bool CheckColorAttachmentNumber(FBAttachment attachment,
- const char* funcName) const;
-
- void EnsureColorAttachPoints(size_t colorAttachmentId);
-
void InvalidateFramebufferStatus() const {
mIsKnownFBComplete = false;
}
bool ValidateForRead(const char* info,
const webgl::FormatUsageInfo** const out_format,
uint32_t* const out_width, uint32_t* const out_height);
- JS::Value GetAttachmentParameter(JSContext* cx, GLenum target, GLenum attachment,
- GLenum pname, ErrorResult* const out_error);
+ JS::Value GetAttachmentParameter(const char* funcName, JSContext* cx, GLenum target,
+ GLenum attachment, GLenum pname,
+ ErrorResult* const out_error);
};
} // namespace mozilla
#endif // WEBGL_FRAMEBUFFER_H_
--- a/dom/canvas/WebGLRenderbuffer.cpp
+++ b/dom/canvas/WebGLRenderbuffer.cpp
@@ -215,21 +215,21 @@ WebGLRenderbuffer::RenderbufferStorage(G
mHeight = height;
mImageDataStatus = WebGLImageDataStatus::UninitializedImageData;
mIsUsingSecondary = bool(secondaryFormat);
InvalidateStatusOfAttachedFBs();
}
void
-WebGLRenderbuffer::FramebufferRenderbuffer(FBAttachment attachment) const
+WebGLRenderbuffer::FramebufferRenderbuffer(GLenum attachment) const
{
gl::GLContext* gl = mContext->gl;
if (attachment != LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
- gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, attachment.get(),
+ gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, attachment,
LOCAL_GL_RENDERBUFFER, mPrimaryRB);
return;
}
GLuint stencilRB = mPrimaryRB;
if (mIsUsingSecondary) {
MOZ_ASSERT(mSecondaryRB);
stencilRB = mSecondaryRB;
--- a/dom/canvas/WebGLRenderbuffer.h
+++ b/dom/canvas/WebGLRenderbuffer.h
@@ -54,17 +54,17 @@ public:
WebGLContext* GetParentObject() const {
return mContext;
}
void BindRenderbuffer() const;
void RenderbufferStorage(GLsizei samples, const webgl::FormatUsageInfo* format,
GLsizei width, GLsizei height);
- void FramebufferRenderbuffer(FBAttachment attachment) const;
+ void FramebufferRenderbuffer(GLenum attachment) const;
// Only handles a subset of `pname`s.
GLint GetRenderbufferParameter(RBTarget target, RBParam pname) const;
virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLRenderbuffer)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLRenderbuffer)
--- a/dom/canvas/WebGLStrongTypes.h
+++ b/dom/canvas/WebGLStrongTypes.h
@@ -142,17 +142,16 @@ public:
MOZ_ASSERT(IsValueLegal(mValue));
}
GLenum get() const {
MOZ_ASSERT(mValue != NonexistantGLenum);
return mValue;
}
-
bool operator==(const StrongGLenum& other) const {
return get() == other.get();
}
bool operator!=(const StrongGLenum& other) const {
return get() != other.get();
}
@@ -396,38 +395,16 @@ STRONG_GLENUM_BEGIN(FBTarget)
STRONG_GLENUM_VALUE(FRAMEBUFFER),
STRONG_GLENUM_END(FBTarget)
STRONG_GLENUM_BEGIN(RBTarget)
STRONG_GLENUM_VALUE(NONE),
STRONG_GLENUM_VALUE(RENDERBUFFER),
STRONG_GLENUM_END(RBTarget)
-STRONG_GLENUM_BEGIN(FBAttachment)
- STRONG_GLENUM_VALUE(DEPTH_STENCIL_ATTACHMENT),
- STRONG_GLENUM_VALUE(COLOR_ATTACHMENT0),
- STRONG_GLENUM_VALUE(COLOR_ATTACHMENT1),
- STRONG_GLENUM_VALUE(COLOR_ATTACHMENT2),
- STRONG_GLENUM_VALUE(COLOR_ATTACHMENT3),
- STRONG_GLENUM_VALUE(COLOR_ATTACHMENT4),
- STRONG_GLENUM_VALUE(COLOR_ATTACHMENT5),
- STRONG_GLENUM_VALUE(COLOR_ATTACHMENT6),
- STRONG_GLENUM_VALUE(COLOR_ATTACHMENT7),
- STRONG_GLENUM_VALUE(COLOR_ATTACHMENT8),
- STRONG_GLENUM_VALUE(COLOR_ATTACHMENT9),
- STRONG_GLENUM_VALUE(COLOR_ATTACHMENT10),
- STRONG_GLENUM_VALUE(COLOR_ATTACHMENT11),
- STRONG_GLENUM_VALUE(COLOR_ATTACHMENT12),
- STRONG_GLENUM_VALUE(COLOR_ATTACHMENT13),
- STRONG_GLENUM_VALUE(COLOR_ATTACHMENT14),
- STRONG_GLENUM_VALUE(COLOR_ATTACHMENT15),
- STRONG_GLENUM_VALUE(DEPTH_ATTACHMENT),
- STRONG_GLENUM_VALUE(STENCIL_ATTACHMENT),
-STRONG_GLENUM_END(FBAttachment)
-
STRONG_GLENUM_BEGIN(FBStatus)
STRONG_GLENUM_VALUE(FRAMEBUFFER_COMPLETE),
STRONG_GLENUM_VALUE(FRAMEBUFFER_INCOMPLETE_ATTACHMENT),
STRONG_GLENUM_VALUE(FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT),
STRONG_GLENUM_VALUE(FRAMEBUFFER_INCOMPLETE_DIMENSIONS),
STRONG_GLENUM_VALUE(FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER),
STRONG_GLENUM_VALUE(FRAMEBUFFER_INCOMPLETE_READ_BUFFER),
STRONG_GLENUM_VALUE(FRAMEBUFFER_UNSUPPORTED),
--- a/dom/canvas/WebGLTexture.h
+++ b/dom/canvas/WebGLTexture.h
@@ -403,23 +403,23 @@ TexImageTargetForTargetAndFace(TexTarget
MOZ_CRASH();
}
}
already_AddRefed<mozilla::layers::Image>
ImageFromVideo(dom::HTMLVideoElement* elem);
GLenum
-DoTexImage(gl::GLContext* gl, TexImageTarget target, GLint level, GLenum internalFormat,
- GLsizei width, GLsizei height, GLsizei depth, GLenum unpackFormat,
- GLenum unpackType, const void* data);
+DoTexImage(gl::GLContext* gl, TexImageTarget target, GLint level,
+ const webgl::DriverUnpackInfo* dui, GLsizei width, GLsizei height,
+ GLsizei depth, const void* data);
GLenum
DoTexSubImage(gl::GLContext* gl, TexImageTarget target, GLint level, GLint xOffset,
GLint yOffset, GLint zOffset, GLsizei width, GLsizei height,
- GLsizei depth, GLenum unpackFormat, GLenum unpackType, const void* data);
+ GLsizei depth, const webgl::PackingInfo& pi, const void* data);
GLenum
DoCompressedTexSubImage(gl::GLContext* gl, TexImageTarget target, GLint level,
GLint xOffset, GLint yOffset, GLint zOffset, GLsizei width,
GLsizei height, GLsizei depth, GLenum sizedUnpackFormat,
GLsizei dataSize, const void* data);
} // namespace mozilla
--- a/dom/canvas/WebGLTextureUpload.cpp
+++ b/dom/canvas/WebGLTextureUpload.cpp
@@ -666,51 +666,51 @@ Is3D(TexImageTarget target)
return true;
default:
MOZ_CRASH("bad target");
}
}
GLenum
-DoTexImage(gl::GLContext* gl, TexImageTarget target, GLint level, GLenum internalFormat,
- GLsizei width, GLsizei height, GLsizei depth, GLenum unpackFormat,
- GLenum unpackType, const void* data)
+DoTexImage(gl::GLContext* gl, TexImageTarget target, GLint level,
+ const webgl::DriverUnpackInfo* dui, GLsizei width, GLsizei height,
+ GLsizei depth, const void* data)
{
const GLint border = 0;
gl::GLContext::LocalErrorScope errorScope(*gl);
if (Is3D(target)) {
- gl->fTexImage3D(target.get(), level, internalFormat, width, height, depth,
- border, unpackFormat, unpackType, data);
+ gl->fTexImage3D(target.get(), level, dui->internalFormat, width, height, depth,
+ border, dui->unpackFormat, dui->unpackType, data);
} else {
MOZ_ASSERT(depth == 1);
- gl->fTexImage2D(target.get(), level, internalFormat, width, height, border,
- unpackFormat, unpackType, data);
+ gl->fTexImage2D(target.get(), level, dui->internalFormat, width, height, border,
+ dui->unpackFormat, dui->unpackType, data);
}
return errorScope.GetError();
}
GLenum
DoTexSubImage(gl::GLContext* gl, TexImageTarget target, GLint level, GLint xOffset,
GLint yOffset, GLint zOffset, GLsizei width, GLsizei height, GLsizei depth,
- GLenum unpackFormat, GLenum unpackType, const void* data)
+ const webgl::PackingInfo& pi, const void* data)
{
gl::GLContext::LocalErrorScope errorScope(*gl);
if (Is3D(target)) {
gl->fTexSubImage3D(target.get(), level, xOffset, yOffset, zOffset, width, height,
- depth, unpackFormat, unpackType, data);
+ depth, pi.format, pi.type, data);
} else {
MOZ_ASSERT(zOffset == 0);
MOZ_ASSERT(depth == 1);
gl->fTexSubImage2D(target.get(), level, xOffset, yOffset, width, height,
- unpackFormat, unpackType, data);
+ pi.format, pi.type, data);
}
return errorScope.GetError();
}
static inline GLenum
DoCompressedTexImage(gl::GLContext* gl, TexImageTarget target, GLint level,
GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth,
--- a/dom/canvas/test/webgl-conformance/conformance/resources/webgl-test-utils.js
+++ b/dom/canvas/test/webgl-conformance/conformance/resources/webgl-test-utils.js
@@ -630,41 +630,16 @@ function create3DContextWithWrapperThatT
}
wrap.getError = function() {
return context.getError();
};
return wrap;
};
/**
- * Tests that an evaluated expression generates a specific GL error.
- * @param {!WebGLContext} gl The WebGLContext to use.
- * @param {number} glError The expected gl error.
- * @param {string} evalSTr The string to evaluate.
- */
-var shouldGenerateGLError = function(gl, glError, evalStr) {
- var exception;
- try {
- eval(evalStr);
- } catch (e) {
- exception = e;
- }
- if (exception) {
- testFailed(evalStr + " threw exception " + exception);
- } else {
- var err = gl.getError();
- if (err != glError) {
- testFailed(evalStr + " expected: " + getGLErrorAsString(gl, glError) + ". Was " + getGLErrorAsString(gl, err) + ".");
- } else {
- testPassed(evalStr + " was expected value: " + getGLErrorAsString(gl, glError) + ".");
- }
- }
-};
-
-/**
* Tests that the first error GL returns is the specified error.
* @param {!WebGLContext} gl The WebGLContext to use.
* @param {number} glError The expected gl error.
* @param {string} opt_msg
*/
var glErrorShouldBe = function(gl, glError, opt_msg) {
opt_msg = opt_msg || "";
var err = gl.getError();
@@ -673,19 +648,19 @@ var glErrorShouldBe = function(gl, glErr
". Was " + getGLErrorAsString(gl, err) + " : " + opt_msg);
} else {
testPassed("getError was expected value: " +
getGLErrorAsString(gl, glError) + " : " + opt_msg);
}
};
/**
- * Tests that the first error GL returns is the specified error.
+ * Tests that the first error GL returns is in the specified error list.
* @param {!WebGLContext} gl The WebGLContext to use.
- * @param {number} glError The expected gl error.
+ * @param {!Array.<number>} expectedErrorList The list of expected gl errors.
* @param {string} opt_msg
*/
var glErrorShouldBeIn = function(gl, expectedErrorList, opt_msg) {
opt_msg = opt_msg || "";
var expectedErrorStrList = [];
var expectedErrorSet = {};
@@ -703,16 +678,56 @@ var glErrorShouldBeIn = function(gl, exp
testPassed("getError was in expected values: " + expectedErrorStr + " : " + opt_msg);
} else {
testFailed("getError expected: " + expectedErrorStr +
". Was " + getGLErrorAsString(gl, actualError) + " : " + opt_msg);
}
};
/**
+ * Tests that an evaluated expression generates a specific GL error.
+ * @param {!WebGLContext} gl The WebGLContext to use.
+ * @param {number} glError The expected gl error.
+ * @param {string} evalSTr The string to evaluate.
+ */
+var shouldGenerateGLError = function(gl, glError, evalStr) {
+ var exception;
+ try {
+ eval(evalStr);
+ } catch (e) {
+ exception = e;
+ }
+ if (exception) {
+ testFailed(evalStr + " threw exception " + exception);
+ } else {
+ glErrorShouldBe(gl, glError, evalStr);
+ }
+};
+
+/**
+ * Tests that an evaluated expression generates a GL error from a list.
+ * @param {!WebGLContext} gl The WebGLContext to use.
+ * @param {!Array.<number>} expectedErrorList The list of expected gl errors.
+ * @param {string} evalSTr The string to evaluate.
+ */
+var shouldGenerateGLErrorIn = function(gl, expectedErrorList, evalStr) {
+ var exception;
+ try {
+ eval(evalStr);
+ } catch (e) {
+ exception = e;
+ }
+ if (exception) {
+ testFailed(evalStr + " threw exception " + exception);
+ } else {
+ glErrorShouldBeIn(gl, expectedErrorList, evalStr);
+ }
+};
+
+/**
* Links a WebGL program, throws if there are errors.
* @param {!WebGLContext} gl The WebGLContext to use.
* @param {!WebGLProgram} program The WebGLProgram to link.
* @param {function(string): void) opt_errorCallback callback for errors.
*/
var linkProgram = function(gl, program, opt_errorCallback) {
errFn = opt_errorCallback || testFailed;
// Link the program
--- a/gfx/gl/ScopedGLHelpers.cpp
+++ b/gfx/gl/ScopedGLHelpers.cpp
@@ -331,51 +331,51 @@ ScopedFramebufferForRenderbuffer::Unwrap
/* ScopedViewportRect *********************************************************/
ScopedViewportRect::ScopedViewportRect(GLContext* aGL,
GLint x, GLint y,
GLsizei width, GLsizei height)
: ScopedGLWrapper<ScopedViewportRect>(aGL)
{
- mGL->fGetIntegerv(LOCAL_GL_VIEWPORT, mSavedViewportRect);
- mGL->fViewport(x, y, width, height);
+ mGL->fGetIntegerv(LOCAL_GL_VIEWPORT, mSavedViewportRect);
+ mGL->fViewport(x, y, width, height);
}
void ScopedViewportRect::UnwrapImpl()
{
- mGL->fViewport(mSavedViewportRect[0],
- mSavedViewportRect[1],
- mSavedViewportRect[2],
- mSavedViewportRect[3]);
+ mGL->fViewport(mSavedViewportRect[0],
+ mSavedViewportRect[1],
+ mSavedViewportRect[2],
+ mSavedViewportRect[3]);
}
/* ScopedScissorRect **********************************************************/
ScopedScissorRect::ScopedScissorRect(GLContext* aGL,
GLint x, GLint y,
GLsizei width, GLsizei height)
: ScopedGLWrapper<ScopedScissorRect>(aGL)
{
- mGL->fGetIntegerv(LOCAL_GL_SCISSOR_BOX, mSavedScissorRect);
- mGL->fScissor(x, y, width, height);
+ mGL->fGetIntegerv(LOCAL_GL_SCISSOR_BOX, mSavedScissorRect);
+ mGL->fScissor(x, y, width, height);
}
ScopedScissorRect::ScopedScissorRect(GLContext* aGL)
: ScopedGLWrapper<ScopedScissorRect>(aGL)
{
- mGL->fGetIntegerv(LOCAL_GL_SCISSOR_BOX, mSavedScissorRect);
+ mGL->fGetIntegerv(LOCAL_GL_SCISSOR_BOX, mSavedScissorRect);
}
void ScopedScissorRect::UnwrapImpl()
{
- mGL->fScissor(mSavedScissorRect[0],
- mSavedScissorRect[1],
- mSavedScissorRect[2],
- mSavedScissorRect[3]);
+ mGL->fScissor(mSavedScissorRect[0],
+ mSavedScissorRect[1],
+ mSavedScissorRect[2],
+ mSavedScissorRect[3]);
}
/* ScopedVertexAttribPointer **************************************************/
ScopedVertexAttribPointer::ScopedVertexAttribPointer(GLContext* aGL,
GLuint index,
GLint size,
GLenum type,
@@ -557,17 +557,17 @@ ScopedUnpackAlignment::ScopedUnpackAlign
scopedVal == 4 ||
scopedVal == 8);
gl->fGetIntegerv(LOCAL_GL_UNPACK_ALIGNMENT, &mOldVal);
if (scopedVal != mOldVal) {
gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, scopedVal);
} else {
- // Don't try to re-set it during unwrap.
+ // Don't try to re-set it during unwrap.
mOldVal = 0;
}
}
void
ScopedUnpackAlignment::UnwrapImpl() {
// Check that we're not falling out of scope after the current context changed.
MOZ_ASSERT(mGL->IsCurrent());