--- a/dom/canvas/TexUnpackBlob.cpp
+++ b/dom/canvas/TexUnpackBlob.cpp
@@ -14,16 +14,34 @@
#include "nsLayoutUtils.h"
#include "WebGLContext.h"
#include "WebGLTexelConversions.h"
#include "WebGLTexture.h"
namespace mozilla {
namespace webgl {
+TexUnpackBlob::TexUnpackBlob(const WebGLContext* webgl, uint32_t alignment,
+ uint32_t rowLength, uint32_t imageHeight, uint32_t width,
+ uint32_t height, uint32_t depth, bool hasData)
+ : mAlignment(alignment)
+ , mRowLength(rowLength)
+ , mImageHeight(imageHeight)
+
+ , mSkipPixels(webgl->mPixelStore_UnpackSkipPixels)
+ , mSkipRows(webgl->mPixelStore_UnpackSkipRows)
+ , mSkipImages(webgl->mPixelStore_UnpackSkipImages)
+
+ , mWidth(width)
+ , mHeight(height)
+ , mDepth(depth)
+
+ , mHasData(hasData)
+{ }
+
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)
{
if (isSubImage) {
return DoTexSubImage(gl, target, level, xOffset, yOffset, zOffset, width, height,
depth, dui->ToPacking(), data);
@@ -43,42 +61,30 @@ TexUnpackBlob::OriginsForDOM(WebGLContex
// Thus y-flip would give us bottom-left.
*out_dst = webgl->mPixelStore_FlipY ? gl::OriginPos::BottomLeft
: gl::OriginPos::TopLeft;
}
//////////////////////////////////////////////////////////////////////////////////////////
// TexUnpackBytes
-bool
-TexUnpackBytes::ValidateUnpack(WebGLContext* webgl, const char* funcName, bool isFunc3D,
- const webgl::PackingInfo& pi)
+static uint32_t
+FallbackOnZero(uint32_t val, uint32_t fallback)
{
- if (!mBytes)
- return true;
+ return (val ? val : fallback);
+}
- 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 (mByteCount < bytesNeeded.value()) {
- webgl->ErrorInvalidOperation("%s: Provided buffer is too small. (needs %u, has"
- " %u)",
- funcName, bytesNeeded.value(), mByteCount);
- return false;
- }
-
- return true;
-}
+TexUnpackBytes::TexUnpackBytes(const WebGLContext* webgl, uint32_t width, uint32_t height,
+ uint32_t depth, const void* bytes)
+ : TexUnpackBlob(webgl, webgl->mPixelStore_UnpackAlignment,
+ FallbackOnZero(webgl->mPixelStore_UnpackRowLength, width),
+ FallbackOnZero(webgl->mPixelStore_UnpackImageHeight, height),
+ width, height, depth, bool(bytes))
+ , mBytes(bytes)
+{ }
static bool
UnpackFormatHasAlpha(GLenum unpackFormat)
{
switch (unpackFormat) {
case LOCAL_GL_ALPHA:
case LOCAL_GL_LUMINANCE_ALPHA:
case LOCAL_GL_RGBA:
@@ -131,21 +137,21 @@ FormatFromPacking(const webgl::PackingIn
case LOCAL_GL_RGB: return WebGLTexelFormat::RGB32F;
case LOCAL_GL_RGBA: return WebGLTexelFormat::RGBA32F;
}
}
return WebGLTexelFormat::FormatNotSupportingAnyConversion;
}
-void
+bool
TexUnpackBytes::TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName,
WebGLTexture* tex, TexImageTarget target, GLint level,
const webgl::DriverUnpackInfo* dui, GLint xOffset,
- GLint yOffset, GLint zOffset, GLenum* const out_glError)
+ GLint yOffset, GLint zOffset, GLenum* const out_error) const
{
WebGLContext* webgl = tex->mContext;
gl::GLContext* gl = webgl->gl;
const void* uploadBytes = mBytes;
UniqueBuffer tempBuffer;
do {
@@ -162,122 +168,150 @@ TexUnpackBytes::TexOrSubImage(bool isSub
bool needsAlphaPremult = webgl->mPixelStore_PremultiplyAlpha;
if (!UnpackFormatHasAlpha(pi.format))
needsAlphaPremult = false;
if (!needsYFlip && !needsAlphaPremult)
break;
+ ////////////
// This is literally the worst.
+
+ if (mSkipPixels || mSkipRows || mSkipImages ||
+ mRowLength != mWidth ||
+ mImageHeight != mHeight)
+ {
+ webgl->ErrorInvalidOperation("%s: FLIP_Y and PREMULTIPLY_ALPHA are"
+ " incompatible with WebGL 2's new UNPACK_*"
+ " settings.",
+ funcName);
+ return false;
+ }
+
+ if (mDepth != 1) {
+ webgl->ErrorInvalidOperation("%s: FLIP_Y and PREMULTIPLY_ALPHA are"
+ " incompatible with 3D textures.",
+ funcName);
+ return false;
+ }
+
webgl->GenerateWarning("%s: Uploading ArrayBuffers with FLIP_Y or"
" PREMULTIPLY_ALPHA is slow.",
funcName);
- tempBuffer = malloc(mByteCount);
- if (!tempBuffer) {
- *out_glError = LOCAL_GL_OUT_OF_MEMORY;
- return;
+ const auto bytesPerPixel = webgl::BytesPerPixel(pi);
+
+ const auto bytesPerRow = CheckedUint32(mRowLength) * bytesPerPixel;
+ const auto rowStride = RoundUpToMultipleOf(bytesPerRow, mAlignment);
+ const auto imageStride = rowStride * mImageHeight;
+
+ if (!imageStride.isValid()) {
+ webgl->ErrorOutOfMemory("%s: Invalid calculation during"
+ " FLIP_Y/PREMULTIPLY_ALPHA handling.",
+ funcName);
+ return false;
}
- const auto bytesPerPixel = webgl::BytesPerPixel(pi);
- const auto rowByteAlignment = webgl->mPixelStore_UnpackAlignment;
-
- const size_t bytesPerRow = bytesPerPixel * mWidth;
- const size_t rowStride = RoundUpToMultipleOf(bytesPerRow, rowByteAlignment);
+ tempBuffer = malloc(imageStride.value());
+ if (!tempBuffer) {
+ webgl->ErrorOutOfMemory("%s: OOM during FLIP_Y/PREMULTIPLY_ALPHA handling.",
+ funcName);
+ return false;
+ }
if (!needsAlphaPremult) {
MOZ_ASSERT(needsYFlip);
const uint8_t* src = (const uint8_t*)mBytes;
- const uint8_t* const srcEnd = src + rowStride * mHeight;
+ const uint8_t* const srcEnd = src + rowStride.value() * mHeight;
- uint8_t* dst = (uint8_t*)tempBuffer.get() + rowStride * (mHeight - 1);
+ uint8_t* dst = (uint8_t*)tempBuffer.get() + rowStride.value() * (mHeight - 1);
while (src != srcEnd) {
- memcpy(dst, src, bytesPerRow);
- src += rowStride;
- dst -= rowStride;
+ memcpy(dst, src, bytesPerRow.value());
+ src += rowStride.value();
+ dst -= rowStride.value();
}
uploadBytes = tempBuffer.get();
break;
}
const auto texelFormat = FormatFromPacking(pi);
if (texelFormat == WebGLTexelFormat::FormatNotSupportingAnyConversion) {
MOZ_ASSERT(false, "Bad texelFormat from pi.");
- *out_glError = LOCAL_GL_OUT_OF_MEMORY;
- return;
+ webgl->ErrorOutOfMemory("%s: FormatFromPacking failed during"
+ " PREMULTIPLY_ALPHA handling.",
+ funcName);
+ return false;
}
const auto srcOrigin = gl::OriginPos::BottomLeft;
const auto dstOrigin = (needsYFlip ? gl::OriginPos::TopLeft
: gl::OriginPos::BottomLeft);
const bool srcPremultiplied = false;
const bool dstPremultiplied = needsAlphaPremult; // Always true here.
// And go!:
MOZ_ASSERT(srcOrigin != dstOrigin || srcPremultiplied != dstPremultiplied);
bool unused_wasTrivial;
if (!ConvertImage(mWidth, mHeight,
- mBytes, rowStride, srcOrigin, texelFormat, srcPremultiplied,
- tempBuffer.get(), rowStride, dstOrigin, texelFormat,
+ mBytes, rowStride.value(), srcOrigin, texelFormat,
+ srcPremultiplied,
+ tempBuffer.get(), rowStride.value(), dstOrigin, texelFormat,
dstPremultiplied, &unused_wasTrivial))
{
MOZ_ASSERT(false, "ConvertImage failed unexpectedly.");
- *out_glError = LOCAL_GL_OUT_OF_MEMORY;
- return;
+ webgl->ErrorOutOfMemory("%s: ConvertImage failed during PREMULTIPLY_ALPHA"
+ " handling.",
+ funcName);
+ return false;
}
uploadBytes = tempBuffer.get();
} while (false);
- GLenum error = DoTexOrSubImage(isSubImage, gl, target, level, dui, xOffset, yOffset,
- zOffset, mWidth, mHeight, mDepth, uploadBytes);
- *out_glError = error;
+ *out_error = DoTexOrSubImage(isSubImage, gl, target, level, dui, xOffset, yOffset,
+ zOffset, mWidth, mHeight, mDepth, uploadBytes);
+ return true;
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// TexUnpackImage
-TexUnpackImage::TexUnpackImage(const RefPtr<layers::Image>& image, bool isAlphaPremult)
- : TexUnpackBlob(image->GetSize().width, image->GetSize().height, 1, true)
+TexUnpackImage::TexUnpackImage(const WebGLContext* webgl, uint32_t imageHeight,
+ uint32_t width, uint32_t height, uint32_t depth,
+ const RefPtr<layers::Image>& image, bool isAlphaPremult)
+ : TexUnpackBlob(webgl, 0, image->GetSize().width, imageHeight, width, height, depth,
+ true)
, mImage(image)
, mIsAlphaPremult(isAlphaPremult)
{ }
-TexUnpackImage::~TexUnpackImage()
-{ }
-
-void
+bool
TexUnpackImage::TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName,
WebGLTexture* tex, TexImageTarget target, GLint level,
const webgl::DriverUnpackInfo* dui, GLint xOffset,
- GLint yOffset, GLint zOffset, GLenum* const out_glError)
+ GLint yOffset, GLint zOffset, GLenum* const out_error) const
{
MOZ_ASSERT_IF(needsRespec, !isSubImage);
- *out_glError = 0;
WebGLContext* webgl = tex->mContext;
gl::GLContext* gl = webgl->GL();
gl->MakeCurrent();
if (needsRespec) {
- GLenum error = DoTexOrSubImage(isSubImage, gl, target.get(), level, dui, xOffset,
- yOffset, zOffset, mWidth, mHeight, mDepth,
- nullptr);
- if (error) {
- MOZ_ASSERT(!error);
- *out_glError = LOCAL_GL_OUT_OF_MEMORY;
- return;
- }
+ *out_error = DoTexOrSubImage(isSubImage, gl, target.get(), level, dui, xOffset,
+ yOffset, zOffset, mWidth, mHeight, mDepth,
+ nullptr);
+ return true;
}
do {
if (dui->unpackFormat != LOCAL_GL_RGB && dui->unpackFormat != LOCAL_GL_RGBA)
break;
if (dui->unpackType != LOCAL_GL_UNSIGNED_BYTE)
break;
@@ -304,39 +338,55 @@ TexUnpackImage::TexOrSubImage(bool isSub
const gfx::IntSize destSize(mWidth, mHeight);
if (!gl->BlitHelper()->BlitImageToFramebuffer(mImage, destSize, scopedFB.FB(),
dstOrigin))
{
break;
}
- return; // Blitting was successful, so we're done!
+ // Blitting was successful, so we're done!
+ *out_error = 0;
+ return true;
} while (false);
webgl->GenerateWarning("%s: Failed to hit GPU-copy fast-path. Falling back to CPU"
" upload.",
funcName);
RefPtr<SourceSurface> surface = mImage->GetAsSourceSurface();
if (!surface) {
- *out_glError = LOCAL_GL_OUT_OF_MEMORY;
- return;
+ webgl->ErrorOutOfMemory("%s: GetAsSourceSurface failed after blit failed for"
+ " TexUnpackImage.",
+ funcName);
+ return false;
}
- TexUnpackSurface surfBlob(surface, mIsAlphaPremult);
+ TexUnpackSurface surfBlob(webgl, mImageHeight, mWidth, mHeight, mDepth, surface,
+ mIsAlphaPremult);
- surfBlob.TexOrSubImage(isSubImage, needsRespec, funcName, tex, target, level, dui,
- xOffset, yOffset, zOffset, out_glError);
+ return surfBlob.TexOrSubImage(isSubImage, needsRespec, funcName, tex, target, level,
+ dui, xOffset, yOffset, zOffset, out_error);
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// TexUnpackSurface
+TexUnpackSurface::TexUnpackSurface(const WebGLContext* webgl, uint32_t imageHeight,
+ uint32_t width, uint32_t height, uint32_t depth,
+ gfx::SourceSurface* surf, bool isAlphaPremult)
+ : TexUnpackBlob(webgl, 0, surf->GetSize().width, imageHeight, width, height, depth,
+ true)
+ , mSurf(surf)
+ , mIsAlphaPremult(isAlphaPremult)
+{ }
+
+//////////
+
static bool
GuessAlignment(const void* data, size_t bytesPerRow, size_t stride, size_t maxAlignment,
size_t* const out_alignment)
{
size_t alignmentGuess = maxAlignment;
while (alignmentGuess) {
size_t guessStride = RoundUpToMultipleOf(bytesPerRow, alignmentGuess);
if (guessStride == stride &&
@@ -740,88 +790,68 @@ TexUnpackSurface::ConvertSurface(WebGLCo
*out_convertedAlignment = dstAlignment;
*out_wasTrivial = wasTrivial;
return true;
}
////////////////////
-TexUnpackSurface::TexUnpackSurface(const RefPtr<gfx::SourceSurface>& surf,
- bool isAlphaPremult)
- : TexUnpackBlob(surf->GetSize().width, surf->GetSize().height, 1, true)
- , mSurf(surf)
- , mIsAlphaPremult(isAlphaPremult)
-{ }
-
-TexUnpackSurface::~TexUnpackSurface()
-{ }
-
-void
+bool
TexUnpackSurface::TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName,
WebGLTexture* tex, TexImageTarget target, GLint level,
const webgl::DriverUnpackInfo* dui, GLint xOffset,
- GLint yOffset, GLint zOffset, GLenum* const out_glError)
+ GLint yOffset, GLint zOffset,
+ GLenum* const out_error) const
{
- *out_glError = 0;
-
WebGLContext* webgl = tex->mContext;
// MakeCurrent is a big mess in here, because mapping (and presumably unmapping) on
// OSX can lose our MakeCurrent. Therefore it's easiest to MakeCurrent just before we
// call into GL, instead of trying to keep MakeCurrent-ed.
RefPtr<gfx::DataSourceSurface> dataSurf = mSurf->GetDataSurface();
-
if (!dataSurf) {
// Since GetDataSurface didn't return error code, assume system
// is out of memory
- *out_glError = LOCAL_GL_OUT_OF_MEMORY;
- return;
+ webgl->ErrorOutOfMemory("%s: OOM in GetDataSurface for TexUnpackSurface.",
+ funcName);
+ return false;
}
- GLenum error;
if (UploadDataSurface(isSubImage, webgl, target, level, dui, xOffset, yOffset,
- zOffset, mWidth, mHeight, dataSurf, mIsAlphaPremult, &error))
+ zOffset, mWidth, mHeight, dataSurf, mIsAlphaPremult, out_error))
{
- return;
- }
- if (error == LOCAL_GL_OUT_OF_MEMORY) {
- *out_glError = LOCAL_GL_OUT_OF_MEMORY;
- return;
+ return true;
}
// CPU conversion. (++numCopies)
UniqueBuffer convertedBuffer;
uint8_t convertedAlignment;
bool wasTrivial;
bool outOfMemory;
if (!ConvertSurface(webgl, dui, dataSurf, mIsAlphaPremult, &convertedBuffer,
&convertedAlignment, &wasTrivial, &outOfMemory))
{
- if (outOfMemory) {
- *out_glError = LOCAL_GL_OUT_OF_MEMORY;
- } else {
- NS_ERROR("Failed to convert surface.");
- *out_glError = LOCAL_GL_OUT_OF_MEMORY;
- }
- return;
+ webgl->ErrorOutOfMemory("%s: %s in ConvertSurface for TexUnpackSurface.",
+ funcName, outOfMemory ? "OOM" : "Failure");
+ return false;
}
if (!wasTrivial) {
webgl->GenerateWarning("%s: Chosen format/type incured an expensive reformat:"
" 0x%04x/0x%04x",
funcName, dui->unpackFormat, dui->unpackType);
}
MOZ_ALWAYS_TRUE( webgl->gl->MakeCurrent() );
ScopedUnpackReset scopedReset(webgl);
webgl->gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, convertedAlignment);
- error = DoTexOrSubImage(isSubImage, webgl->gl, target.get(), level, dui, xOffset,
- yOffset, zOffset, mWidth, mHeight, mDepth,
- convertedBuffer.get());
- *out_glError = error;
+ *out_error = DoTexOrSubImage(isSubImage, webgl->gl, target.get(), level, dui, xOffset,
+ yOffset, zOffset, mWidth, mHeight, mDepth,
+ convertedBuffer.get());
+ return true;
}
} // namespace webgl
} // namespace mozilla
--- a/dom/canvas/WebGLTextureUpload.cpp
+++ b/dom/canvas/WebGLTextureUpload.cpp
@@ -50,16 +50,43 @@ namespace mozilla {
* CopyTexImage2D(texImageTarget, level, internalFormat, x, y, width, height, border)
* CopyTexImage3D - "Because the framebuffer is inhererntly two-dimensional, there is no
* CopyTexImage3D command."
* CopyTexSubImage2D(texImageTarget, level, xOffset, yOffset, x, y, width, height)
* CopyTexSubImage3D(texImageTarget, level, xOffset, yOffset, zOffset, x, y, width,
* height)
*/
+static bool
+ValidateExtents(WebGLContext* webgl, const char* funcName, GLsizei width, GLsizei height,
+ GLsizei depth, GLint border, uint32_t* const out_width,
+ uint32_t* const out_height, uint32_t* const out_depth)
+{
+ // Check border
+ if (border != 0) {
+ webgl->ErrorInvalidValue("%s: `border` must be 0.", funcName);
+ return false;
+ }
+
+ if (width < 0 || height < 0 || depth < 0) {
+ /* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
+ * "If wt and ht are the specified image width and height,
+ * and if either wt or ht are less than zero, then the error
+ * INVALID_VALUE is generated."
+ */
+ webgl->ErrorInvalidValue("%s: `width`/`height`/`depth` must be >= 0.", funcName);
+ return false;
+ }
+
+ *out_width = width;
+ *out_height = height;
+ *out_depth = depth;
+ return true;
+}
+
////////////////////////////////////////
// ArrayBufferView?
static inline bool
DoesJSTypeMatchUnpackType(GLenum unpackType, js::Scalar::Type jsType)
{
switch (unpackType) {
case LOCAL_GL_BYTE:
@@ -93,224 +120,401 @@ DoesJSTypeMatchUnpackType(GLenum unpackT
case LOCAL_GL_FLOAT:
return jsType == js::Scalar::Type::Float32;
default:
return false;
}
}
-static bool
-ValidateUnpackArrayType(WebGLContext* webgl, const char* funcName, GLenum unpackType,
- js::Scalar::Type jsType)
+bool
+WebGLContext::ValidateUnpackPixels(const char* funcName, uint32_t fullRows,
+ uint32_t tailPixels, const webgl::TexUnpackBlob* blob)
{
- if (DoesJSTypeMatchUnpackType(unpackType, jsType))
- return true;
+ const auto usedPixelsPerRow = CheckedUint32(blob->mSkipPixels) + blob->mWidth;
+ const auto usedRowsPerImage = CheckedUint32(blob->mSkipRows) + blob->mHeight;
+ const auto usedImages = CheckedUint32(blob->mSkipImages) + blob->mDepth;
- const auto& fua = webgl->mFormatUsage;
- const GLenum fakeUnpackFormat = LOCAL_GL_RGBA;
- if (!fua->AreUnpackEnumsValid(fakeUnpackFormat, unpackType)) {
- webgl->ErrorInvalidEnum("%s: Invalid unpack type: 0x%04x", funcName, unpackType);
+ if (!usedPixelsPerRow.isValid() ||
+ !usedRowsPerImage.isValid() ||
+ !usedImages.isValid())
+ {
+ ErrorOutOfMemory("%s: Invalid calculation for e.g. UNPACK_SKIP_PIXELS + width.",
+ funcName);
return false;
}
- webgl->ErrorInvalidOperation("%s: `pixels` be compatible with unpack `type`.",
- funcName);
+ //////
+
+ if (usedPixelsPerRow.value() > blob->mRowLength ||
+ usedRowsPerImage.value() > blob->mImageHeight)
+ {
+ ErrorInvalidOperation("%s: UNPACK_ROW_LENGTH or UNPACK_IMAGE_HEIGHT too small.",
+ funcName);
+ return false;
+ }
+
+ //////
+
+ auto fullRowsNeeded = (usedImages - 1) * blob->mImageHeight;
+ fullRowsNeeded += usedRowsPerImage - 1;
+
+ if (!fullRowsNeeded.isValid()) {
+ ErrorOutOfMemory("%s: Invalid calculation for required row count.",
+ funcName);
+ return false;
+ }
+
+ if (fullRows > fullRowsNeeded.value())
+ return true;
+
+ if (fullRows == fullRowsNeeded.value() && tailPixels >= usedPixelsPerRow.value())
+ return true;
+
+ ErrorInvalidOperation("%s: Desired upload requires more data than is available: (%u"
+ " rows plus %u pixels needed, %u rows plus %u pixels"
+ " available)",
+ funcName, fullRowsNeeded.value(), usedPixelsPerRow.value(),
+ fullRows, tailPixels);
return false;
}
static UniquePtr<webgl::TexUnpackBlob>
-UnpackBlobFromMaybeView(WebGLContext* webgl, const char* funcName, GLsizei width,
- GLsizei height, GLsizei depth, GLenum unpackType,
- const dom::Nullable<dom::ArrayBufferView>& maybeView)
+BlobFromView(WebGLContext* webgl, const char* funcName, uint32_t width, uint32_t height,
+ uint32_t depth, const webgl::PackingInfo& pi,
+ const dom::Nullable<dom::ArrayBufferView>& maybeView)
{
- size_t dataSize;
- const void* data;
- if (maybeView.IsNull()) {
- dataSize = 0;
- data = nullptr;
- } else {
+ const void* bytes = nullptr;
+ uint32_t byteCount = 0;
+
+ if (!maybeView.IsNull()) {
const auto& view = maybeView.Value();
- view.ComputeLengthAndData();
- data = view.DataAllowShared();
- dataSize = view.LengthAllowShared();
- js::Scalar::Type jsType = JS_GetArrayBufferViewType(view.Obj());
- if (!ValidateUnpackArrayType(webgl, funcName, unpackType, jsType))
+
+ const auto jsType = JS_GetArrayBufferViewType(view.Obj());
+ if (!DoesJSTypeMatchUnpackType(pi.type, jsType)) {
+ webgl->ErrorInvalidOperation("%s: `pixels` must be compatible with `type`.",
+ funcName);
return nullptr;
+ }
+
+ if (width && height && depth) {
+ view.ComputeLengthAndData();
+
+ bytes = view.DataAllowShared();
+ byteCount = view.LengthAllowShared();
+ }
}
- UniquePtr<webgl::TexUnpackBlob> ret;
- // Warning: Possibly shared memory. See bug 1225033.
- ret.reset(new webgl::TexUnpackBytes(width, height, depth, dataSize, data));
- return Move(ret);
+ UniquePtr<webgl::TexUnpackBlob> blob(new webgl::TexUnpackBytes(webgl, width, height,
+ depth, bytes));
+
+ //////
+
+ if (bytes) {
+ const auto bytesPerPixel = webgl::BytesPerPixel(pi);
+ const auto bytesPerRow = CheckedUint32(blob->mRowLength) * bytesPerPixel;
+ const auto rowStride = RoundUpToMultipleOf(bytesPerRow, blob->mAlignment);
+
+ const auto fullRows = byteCount / rowStride;
+ if (!fullRows.isValid()) {
+ webgl->ErrorOutOfMemory("%s: Unacceptable upload size calculated.");
+ return nullptr;
+ }
+
+ const auto bodyBytes = fullRows.value() * rowStride.value();
+ const auto tailPixels = (byteCount - bodyBytes) / bytesPerPixel;
+
+ if (!webgl->ValidateUnpackPixels(funcName, fullRows.value(), tailPixels,
+ blob.get()))
+ {
+ return nullptr;
+ }
+ }
+
+ //////
+
+ return Move(blob);
+}
+
+bool
+WebGLContext::ValidateUnpackInfo(const char* funcName, GLenum format, GLenum type,
+ webgl::PackingInfo* const out)
+{
+ if (!mFormatUsage->AreUnpackEnumsValid(format, type)) {
+ ErrorInvalidEnum("%s: Invalid unpack format/type: 0x%04x/0x%04x", funcName,
+ format, type);
+ return false;
+ }
+
+ out->format = format;
+ out->type = type;
+ return true;
}
void
WebGLTexture::TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarget target,
GLint level, GLenum internalFormat, GLint xOffset,
- GLint yOffset, GLint zOffset, GLsizei width, GLsizei height,
- GLsizei depth, GLint border, GLenum unpackFormat,
- GLenum unpackType,
+ GLint yOffset, GLint zOffset, GLsizei rawWidth,
+ GLsizei rawHeight, GLsizei rawDepth, GLint border,
+ GLenum unpackFormat, GLenum unpackType,
const dom::Nullable<dom::ArrayBufferView>& maybeView)
{
- UniquePtr<webgl::TexUnpackBlob> blob;
- blob = UnpackBlobFromMaybeView(mContext, funcName, width, height, depth, unpackType,
+ uint32_t width, height, depth;
+ if (!ValidateExtents(mContext, funcName, rawWidth, rawHeight, rawDepth, border,
+ &width, &height, &depth))
+ {
+ return;
+ }
+
+ webgl::PackingInfo pi;
+ if (!mContext->ValidateUnpackInfo(funcName, unpackFormat, unpackType, &pi))
+ return;
+
+ const auto blob = BlobFromView(mContext, funcName, width, height, depth, pi,
maybeView);
if (!blob)
return;
- TexOrSubImage(isSubImage, funcName, target, level, internalFormat, xOffset, yOffset,
- zOffset, border, unpackFormat, unpackType, blob.get());
+ TexOrSubImageBlob(isSubImage, funcName, target, level, internalFormat, xOffset,
+ yOffset, zOffset, pi, blob.get());
}
////////////////////////////////////////
// ImageData
-static UniquePtr<webgl::TexUnpackBlob>
-UnpackBlobFromImageData(WebGLContext* webgl, const char* funcName, GLenum unpackType,
- dom::ImageData* imageData, dom::Uint8ClampedArray* scopedArr)
+static already_AddRefed<gfx::SourceSurface>
+FromImageData(WebGLContext* webgl, const char* funcName, GLenum unpackType,
+ dom::ImageData* imageData, dom::Uint8ClampedArray* scopedArr)
{
- if (!imageData) {
- // Spec says to generate an INVALID_VALUE error
- webgl->ErrorInvalidValue("%s: null ImageData", funcName);
- return nullptr;
- }
-
DebugOnly<bool> inited = scopedArr->Init(imageData->GetDataObject());
MOZ_ASSERT(inited);
scopedArr->ComputeLengthAndData();
const DebugOnly<size_t> dataSize = scopedArr->Length();
const void* const data = scopedArr->Data();
const gfx::IntSize size(imageData->Width(), imageData->Height());
const size_t stride = size.width * 4;
const gfx::SurfaceFormat surfFormat = gfx::SurfaceFormat::R8G8B8A8;
MOZ_ASSERT(dataSize == stride * size.height);
uint8_t* wrappableData = (uint8_t*)data;
- const RefPtr<gfx::SourceSurface> surf =
+ RefPtr<gfx::SourceSurface> surf =
gfx::Factory::CreateWrappingDataSourceSurface(wrappableData,
stride,
size,
surfFormat);
+ if (!surf) {
+ webgl->ErrorOutOfMemory("%s: OOM in FromImageData.", funcName);
+ return nullptr;
+ }
- // WhatWG "HTML Living Standard" (30 October 2015):
- // "The getImageData(sx, sy, sw, sh) method [...] Pixels must be returned as
- // non-premultiplied alpha values."
- const bool surfIsAlphaPremult = false;
+ return surf.forget();
+}
- UniquePtr<webgl::TexUnpackBlob> ret;
- ret.reset(new webgl::TexUnpackSurface(surf, surfIsAlphaPremult));
- return Move(ret);
+bool
+WebGLContext::GetUnpackValuesForImage(const char* funcName, uint32_t srcImageWidth,
+ uint32_t srcImageHeight,
+ uint32_t* const out_rowLength,
+ uint32_t* const out_imageHeight)
+{
+ uint32_t rowLength = mPixelStore_UnpackRowLength;
+ if (!rowLength) {
+ rowLength = srcImageWidth;
+ } else if (rowLength != srcImageWidth) {
+ ErrorInvalidOperation("%s: UNPACK_ROW_LENGTH, if set, must be == width of"
+ " object.");
+ return false;
+ }
+
+ uint32_t imageHeight = mPixelStore_UnpackImageHeight;
+ if (!imageHeight) {
+ imageHeight = srcImageHeight;
+ } else if (imageHeight > srcImageHeight) {
+ ErrorInvalidOperation("%s: UNPACK_IMAGE_HEIGHT, if set, must be <= height of"
+ " object");
+ return false;
+ }
+
+ *out_rowLength = rowLength;
+ *out_imageHeight = imageHeight;
+ return true;
}
void
WebGLTexture::TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarget target,
GLint level, GLenum internalFormat, GLint xOffset,
GLint yOffset, GLint zOffset, GLenum unpackFormat,
GLenum unpackType, dom::ImageData* imageData)
{
+ webgl::PackingInfo pi;
+ if (!mContext->ValidateUnpackInfo(funcName, unpackFormat, unpackType, &pi))
+ return;
+
+ if (!imageData) {
+ // Spec says to generate an INVALID_VALUE error
+ mContext->ErrorInvalidValue("%s: Null ImageData.", funcName);
+ return;
+ }
+
+ // Eventually, these will be args.
+ const uint32_t width = imageData->Width();
+ const uint32_t height = imageData->Height();
+ const uint32_t depth = 1;
+
+ uint32_t rowLength, imageHeight;
+ if (!mContext->GetUnpackValuesForImage(funcName, imageData->Width(),
+ imageData->Height(), &rowLength, &imageHeight))
+ {
+ return;
+ }
+
dom::RootedTypedArray<dom::Uint8ClampedArray> scopedArr(
nsContentUtils::RootingCxForThread());
-
- UniquePtr<webgl::TexUnpackBlob> blob;
- blob = UnpackBlobFromImageData(mContext, funcName, unpackType, imageData, &scopedArr);
- if (!blob)
+ const RefPtr<gfx::SourceSurface> surf = FromImageData(mContext, funcName, unpackType,
+ imageData, &scopedArr);
+ if (!surf)
return;
- const GLint border = 0;
- TexOrSubImage(isSubImage, funcName, target, level, internalFormat, xOffset, yOffset,
- zOffset, border, unpackFormat, unpackType, blob.get());
+ // WhatWG "HTML Living Standard" (30 October 2015):
+ // "The getImageData(sx, sy, sw, sh) method [...] Pixels must be returned as
+ // non-premultiplied alpha values."
+ const bool surfIsAlphaPremult = false;
+
+ const webgl::TexUnpackSurface blob(mContext, imageHeight, width, height, depth, surf,
+ surfIsAlphaPremult);
+
+ const uint32_t fullRows = imageData->Height();
+ const uint32_t tailPixels = 0;
+ if (!mContext->ValidateUnpackPixels(funcName, fullRows, tailPixels, &blob))
+ return;
+
+ TexOrSubImageBlob(isSubImage, funcName, target, level, internalFormat, xOffset,
+ yOffset, zOffset, pi, &blob);
}
////////////////////////////////////////
// dom::Element
void
WebGLTexture::TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarget target,
GLint level, GLenum internalFormat, GLint xOffset,
GLint yOffset, GLint zOffset, GLenum unpackFormat,
GLenum unpackType, dom::Element* elem,
ErrorResult* const out_error)
{
+ webgl::PackingInfo pi;
+ if (!mContext->ValidateUnpackInfo(funcName, unpackFormat, unpackType, &pi))
+ return;
+
auto sfer = mContext->SurfaceFromElement(elem);
+ uint32_t elemWidth = 0;
+ uint32_t elemHeight = 0;
+ layers::Image* layersImage = nullptr;
+ if (!gfxPrefs::WebGLDisableDOMBlitUploads() && sfer.mLayersImage) {
+ layersImage = sfer.mLayersImage;
+ elemWidth = layersImage->GetSize().width;
+ elemHeight = layersImage->GetSize().height;
+ }
+
+ gfx::SourceSurface* surf = nullptr;
+ if (!layersImage && sfer.GetSourceSurface()) {
+ surf = sfer.GetSourceSurface();
+ elemWidth = surf->GetSize().width;
+ elemHeight = surf->GetSize().height;
+ }
+
+ // Eventually, these will be args.
+ const uint32_t width = elemWidth;
+ const uint32_t height = elemHeight;
+ const uint32_t depth = 1;
+
// While it's counter-intuitive, the shape of the SFEResult API means that we should
// try to pull out a surface first, and then, if we do pull out a surface, check
// CORS/write-only/etc..
- UniquePtr<webgl::TexUnpackBlob> blob;
- const bool isAlphaPremult = sfer.mIsPremultiplied;
-
- const auto& layersImage = sfer.mLayersImage;
- if (layersImage && !gfxPrefs::WebGLDisableDOMBlitUploads()) {
- blob.reset(new webgl::TexUnpackImage(layersImage, isAlphaPremult));
- } else if (sfer.GetSourceSurface()) {
- blob.reset(new webgl::TexUnpackSurface(sfer.GetSourceSurface(), isAlphaPremult));
+ if (!layersImage && !surf) {
+ webgl::TexUnpackBytes blob(mContext, width, height, depth, nullptr);
+ TexOrSubImageBlob(isSubImage, funcName, target, level, internalFormat, xOffset,
+ yOffset, zOffset, pi, &blob);
+ return;
}
- if (blob) {
- if (!sfer.mCORSUsed) {
- auto& srcPrincipal = sfer.mPrincipal;
- nsIPrincipal* dstPrincipal = mContext->GetCanvas()->NodePrincipal();
+ //////
- if (!dstPrincipal->Subsumes(srcPrincipal)) {
- mContext->GenerateWarning("%s: Cross-origin elements require CORS.",
- funcName);
- out_error->Throw(NS_ERROR_DOM_SECURITY_ERR);
- return;
- }
- }
+ if (!sfer.mCORSUsed) {
+ auto& srcPrincipal = sfer.mPrincipal;
+ nsIPrincipal* dstPrincipal = mContext->GetCanvas()->NodePrincipal();
- if (sfer.mIsWriteOnly) {
- // mIsWriteOnly defaults to true, and so will be true even if SFE merely
- // failed. Thus we must test mIsWriteOnly after successfully retrieving an
- // Image or SourceSurface.
- mContext->GenerateWarning("%s: Element is write-only, thus cannot be"
- " uploaded.",
+ if (!dstPrincipal->Subsumes(srcPrincipal)) {
+ mContext->GenerateWarning("%s: Cross-origin elements require CORS.",
funcName);
out_error->Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
- } else {
- mContext->GenerateWarning("%s: Failed to get data from DOM element. Implicit"
- " width and height for this upload will be zero.",
+ }
+
+ if (sfer.mIsWriteOnly) {
+ // mIsWriteOnly defaults to true, and so will be true even if SFE merely
+ // failed. Thus we must test mIsWriteOnly after successfully retrieving an
+ // Image or SourceSurface.
+ mContext->GenerateWarning("%s: Element is write-only, thus cannot be"
+ " uploaded.",
funcName);
+ out_error->Throw(NS_ERROR_DOM_SECURITY_ERR);
+ return;
+ }
+
+ //////
+ // Ok, we're good!
- const uint32_t width = 0;
- const uint32_t height = 0;
- const uint32_t depth = 1; // Implicit depth for DOM uploads is always 1.
- const size_t byteCount = 0;
- blob.reset(new webgl::TexUnpackBytes(width, height, depth, byteCount, nullptr));
+ uint32_t rowLength, imageHeight;
+ if (!mContext->GetUnpackValuesForImage(funcName, elemWidth, elemHeight, &rowLength,
+ &imageHeight))
+ {
+ return;
}
- MOZ_ASSERT(blob);
+
+ UniquePtr<const webgl::TexUnpackBlob> blob;
+ const bool isAlphaPremult = sfer.mIsPremultiplied;
- const GLint border = 0;
- TexOrSubImage(isSubImage, funcName, target, level, internalFormat, xOffset, yOffset,
- zOffset, border, unpackFormat, unpackType, blob.get());
+ if (layersImage) {
+ blob.reset(new webgl::TexUnpackImage(mContext, imageHeight, width, height, depth,
+ layersImage, isAlphaPremult));
+ } else {
+ MOZ_ASSERT(surf);
+ blob.reset(new webgl::TexUnpackSurface(mContext, imageHeight, width, height,
+ depth, surf, isAlphaPremult));
+ }
+
+ const uint32_t fullRows = elemHeight;
+ const uint32_t tailPixels = 0;
+ if (!mContext->ValidateUnpackPixels(funcName, fullRows, tailPixels, blob.get()))
+ return;
+
+ TexOrSubImageBlob(isSubImage, funcName, target, level, internalFormat, xOffset,
+ yOffset, zOffset, pi, blob.get());
}
//////////////////////////////////////////////////////////////////////////////////////////
void
-WebGLTexture::TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarget target,
- GLint level, GLenum internalFormat, GLint xOffset,
- GLint yOffset, GLint zOffset, GLint border,
- GLenum unpackFormat, GLenum unpackType,
- webgl::TexUnpackBlob* blob)
+WebGLTexture::TexOrSubImageBlob(bool isSubImage, const char* funcName,
+ TexImageTarget target, GLint level, GLenum internalFormat,
+ GLint xOffset, GLint yOffset, GLint zOffset,
+ const webgl::PackingInfo& pi,
+ const webgl::TexUnpackBlob* blob)
{
if (isSubImage) {
- TexSubImage(funcName, target, level, xOffset, yOffset, zOffset, unpackFormat,
- unpackType, blob);
+ TexSubImage(funcName, target, level, xOffset, yOffset, zOffset, pi, blob);
} else {
- TexImage(funcName, target, level, internalFormat, border, unpackFormat,
- unpackType, blob);
+ TexImage(funcName, target, level, internalFormat, pi, blob);
}
}
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
static bool
ValidateTexImage(WebGLContext* webgl, WebGLTexture* texture, const char* funcName,
@@ -329,51 +533,33 @@ ValidateTexImage(WebGLContext* webgl, We
}
WebGLTexture::ImageInfo& imageInfo = texture->ImageInfoAt(target, level);
*out_imageInfo = &imageInfo;
return true;
}
-
// For *TexImage*
bool
WebGLTexture::ValidateTexImageSpecification(const char* funcName, TexImageTarget target,
- GLint level, GLsizei width, GLsizei height,
- GLsizei depth, GLint border,
+ GLint level, uint32_t width, uint32_t height,
+ uint32_t depth,
WebGLTexture::ImageInfo** const out_imageInfo)
{
if (mImmutable) {
mContext->ErrorInvalidOperation("%s: Specified texture is immutable.", funcName);
return false;
}
// Do this early to validate `level`.
WebGLTexture::ImageInfo* imageInfo;
if (!ValidateTexImage(mContext, this, funcName, target, level, &imageInfo))
return false;
- // Check border
- if (border != 0) {
- mContext->ErrorInvalidValue("%s: `border` must be 0.", funcName);
- return false;
- }
-
- if (width < 0 || height < 0 || depth < 0) {
- /* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
- * "If wt and ht are the specified image width and height,
- * and if either wt or ht are less than zero, then the error
- * INVALID_VALUE is generated."
- */
- mContext->ErrorInvalidValue("%s: `width`/`height`/`depth` must be >= 0.",
- funcName);
- return false;
- }
-
if (mTarget == LOCAL_GL_TEXTURE_CUBE_MAP &&
width != height)
{
mContext->ErrorInvalidValue("%s: Cube map images must be square.", funcName);
return false;
}
/* GLES 3.0.4, p133-134:
@@ -414,19 +600,19 @@ WebGLTexture::ValidateTexImageSpecificat
default: // cube maps
MOZ_ASSERT(IsCubeMap());
maxWidthHeight = mContext->mImplMaxCubeMapTextureSize >> level;
maxDepth = 1;
break;
}
- if (uint32_t(width) > maxWidthHeight ||
- uint32_t(height) > maxWidthHeight ||
- uint32_t(depth) > maxDepth)
+ if (width > maxWidthHeight ||
+ height > maxWidthHeight ||
+ depth > maxDepth)
{
mContext->ErrorInvalidValue("%s: Requested size at this level is unsupported.",
funcName);
return false;
}
{
/* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
@@ -434,42 +620,40 @@ WebGLTexture::ValidateTexImageSpecificat
* height is not a power-of-two, the error INVALID_VALUE is
* generated."
*
* This restriction does not apply to GL ES Version 3.0+.
*/
bool requirePOT = (!mContext->IsWebGL2() && level != 0);
if (requirePOT) {
- if (!IsPowerOfTwo(uint32_t(width)) || !IsPowerOfTwo(uint32_t(height))) {
+ if (!IsPowerOfTwo(width) || !IsPowerOfTwo(height)) {
mContext->ErrorInvalidValue("%s: For level > 0, width and height must be"
" powers of two.",
funcName);
return false;
}
}
}
*out_imageInfo = imageInfo;
return true;
}
// For *TexSubImage*
bool
WebGLTexture::ValidateTexImageSelection(const char* funcName, TexImageTarget target,
GLint level, GLint xOffset, GLint yOffset,
- GLint zOffset, GLsizei width, GLsizei height,
- GLsizei depth,
+ GLint zOffset, uint32_t width, uint32_t height,
+ uint32_t depth,
WebGLTexture::ImageInfo** const out_imageInfo)
{
// The conformance test wants bad arg checks before imageInfo checks.
- if (xOffset < 0 || yOffset < 0 || zOffset < 0 ||
- width < 0 || height < 0 || depth < 0)
- {
- mContext->ErrorInvalidValue("%s: Offsets and dimensions must be >=0.", funcName);
+ if (xOffset < 0 || yOffset < 0 || zOffset < 0) {
+ mContext->ErrorInvalidValue("%s: Offsets must be >=0.", funcName);
return false;
}
WebGLTexture::ImageInfo* imageInfo;
if (!ValidateTexImage(mContext, this, funcName, target, level, &imageInfo))
return false;
if (!imageInfo->IsDefined()) {
@@ -713,18 +897,20 @@ DoTexSubImage(gl::GLContext* gl, TexImag
}
return errorScope.GetError();
}
static inline GLenum
DoCompressedTexImage(gl::GLContext* gl, TexImageTarget target, GLint level,
GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth,
- GLint border, GLsizei dataSize, const void* data)
+ GLsizei dataSize, const void* data)
{
+ const GLint border = 0;
+
gl::GLContext::LocalErrorScope errorScope(*gl);
if (Is3D(target)) {
gl->fCompressedTexImage3D(target.get(), level, internalFormat, width, height,
depth, border, dataSize, data);
} else {
MOZ_ASSERT(depth == 1);
gl->fCompressedTexImage2D(target.get(), level, internalFormat, width, height,
@@ -753,19 +939,20 @@ DoCompressedTexSubImage(gl::GLContext* g
height, sizedUnpackFormat, dataSize, data);
}
return errorScope.GetError();
}
static inline GLenum
DoCopyTexImage2D(gl::GLContext* gl, TexImageTarget target, GLint level,
- GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height,
- GLint border)
+ GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height)
{
+ const GLint border = 0;
+
gl::GLContext::LocalErrorScope errorScope(*gl);
MOZ_ASSERT(!Is3D(target));
gl->fCopyTexImage2D(target.get(), level, internalFormat, x, y, width, height,
border);
return errorScope.GetError();
}
@@ -923,21 +1110,20 @@ WebGLTexture::TexStorage(const char* fun
if (!width || !height || !depth) {
mContext->ErrorInvalidValue("%s: Dimensions must be non-zero.", funcName);
return;
}
const TexImageTarget testTarget = IsCubeMap() ? LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X
: target.get();
const GLint testLevel = 0;
- const GLint border = 0;
WebGLTexture::ImageInfo* testImageInfo;
if (!ValidateTexImageSpecification(funcName, testTarget, testLevel, width, height,
- depth, border, &testImageInfo))
+ depth, &testImageInfo))
{
return;
}
MOZ_ASSERT(testImageInfo);
mozilla::Unused << testImageInfo;
auto dstUsage = mContext->mFormatUsage->GetSizedTexUsage(sizedFormat);
if (!dstUsage) {
@@ -1010,100 +1196,70 @@ WebGLTexture::TexStorage(const char* fun
mImmutable = true;
}
////////////////////////////////////////
// Tex(Sub)Image
void
WebGLTexture::TexImage(const char* funcName, TexImageTarget target, GLint level,
- GLenum internalFormat, GLint border, GLenum unpackFormat,
- GLenum unpackType, webgl::TexUnpackBlob* blob)
+ GLenum internalFormat, const webgl::PackingInfo& pi,
+ const webgl::TexUnpackBlob* blob)
{
////////////////////////////////////
// Get dest info
WebGLTexture::ImageInfo* imageInfo;
if (!ValidateTexImageSpecification(funcName, target, level, blob->mWidth,
- blob->mHeight, blob->mDepth, border, &imageInfo))
+ blob->mHeight, blob->mDepth, &imageInfo))
{
return;
}
MOZ_ASSERT(imageInfo);
- const webgl::PackingInfo srcPacking = { unpackFormat, unpackType };
+ const auto& fua = mContext->mFormatUsage;
+ if (!fua->IsInternalFormatEnumValid(internalFormat)) {
+ mContext->ErrorInvalidValue("%s: Invalid internalformat: 0x%04x",
+ funcName, internalFormat);
+ return;
+ }
- const auto& fua = mContext->mFormatUsage;
auto dstUsage = fua->GetSizedTexUsage(internalFormat);
if (!dstUsage) {
- if (internalFormat != unpackFormat) {
- if (!fua->AreUnpackEnumsValid(unpackFormat, unpackType)) {
- mContext->ErrorInvalidEnum("%s: Invalid unpack format/type:"
- " 0x%04x/0x%04x",
- funcName, unpackFormat, unpackType);
- return;
- }
-
- if (!fua->IsInternalFormatEnumValid(internalFormat)) {
- mContext->ErrorInvalidValue("%s: Invalid internalformat: 0x%04x",
- funcName, internalFormat);
- return;
- }
-
+ if (internalFormat != pi.format) {
/* GL ES Version 3.0.4 - 3.8.3 Texture Image Specification
* "Specifying a combination of values for format, type, and
* internalformat that is not listed as a valid combination
* in tables 3.2 or 3.3 generates the error INVALID_OPERATION."
*/
mContext->ErrorInvalidOperation("%s: Unsized internalFormat must match"
" unpack format.",
funcName);
return;
}
- dstUsage = fua->GetUnsizedTexUsage(srcPacking);
+ dstUsage = fua->GetUnsizedTexUsage(pi);
}
if (!dstUsage) {
- if (!fua->IsInternalFormatEnumValid(internalFormat)) {
- mContext->ErrorInvalidValue("%s: Invalid internalformat: 0x%04x",
- funcName, internalFormat);
- return;
- }
-
- if (!fua->AreUnpackEnumsValid(unpackFormat, unpackType)) {
- mContext->ErrorInvalidEnum("%s: Invalid unpack format/type:"
- " 0x%04x/0x%04x",
- funcName, unpackFormat, unpackType);
- return;
- }
-
mContext->ErrorInvalidOperation("%s: Invalid internalformat/format/type:"
" 0x%04x/0x%04x/0x%04x",
- funcName, internalFormat, unpackFormat,
- unpackType);
+ funcName, internalFormat, pi.format, pi.type);
return;
}
const webgl::DriverUnpackInfo* driverUnpackInfo;
- if (!dstUsage->IsUnpackValid(srcPacking, &driverUnpackInfo)) {
+ if (!dstUsage->IsUnpackValid(pi, &driverUnpackInfo)) {
mContext->ErrorInvalidOperation("%s: Mismatched internalFormat and format/type:"
" 0x%04x and 0x%04x/0x%04x",
- funcName, internalFormat, unpackFormat,
- unpackType);
+ funcName, internalFormat, pi.format, pi.type);
return;
}
////////////////////////////////////
- // Get source info
- const bool isFunc3D = Is3D(target);
- if (!blob->ValidateUnpack(mContext, funcName, isFunc3D, srcPacking))
- return;
-
- ////////////////////////////////////
// Check that source and dest info are compatible
auto dstFormat = dstUsage->format;
if (!ValidateTargetForFormat(funcName, mContext, target, dstFormat))
return;
if (!mContext->IsWebGL2() && dstFormat->hasDepth) {
if (target != LOCAL_GL_TEXTURE_2D ||
@@ -1162,18 +1318,17 @@ WebGLTexture::TexImage(const char* funcN
// Update our specification data.
SetImageInfo(imageInfo, newImageInfo);
}
void
WebGLTexture::TexSubImage(const char* funcName, TexImageTarget target, GLint level,
GLint xOffset, GLint yOffset, GLint zOffset,
- GLenum unpackFormat, GLenum unpackType,
- webgl::TexUnpackBlob* blob)
+ const webgl::PackingInfo& pi, const webgl::TexUnpackBlob* blob)
{
////////////////////////////////////
// Get dest info
WebGLTexture::ImageInfo* imageInfo;
if (!ValidateTexImageSelection(funcName, target, level, xOffset, yOffset, zOffset,
blob->mWidth, blob->mHeight, blob->mDepth, &imageInfo))
{
@@ -1195,38 +1350,24 @@ WebGLTexture::TexSubImage(const char* fu
" format %s.",
funcName, dstFormat->name);
return;
}
////////////////////////////////////
// Get source info
- const webgl::PackingInfo srcPacking = { unpackFormat, unpackType };
const webgl::DriverUnpackInfo* driverUnpackInfo;
- if (!dstUsage->IsUnpackValid(srcPacking, &driverUnpackInfo)) {
- const auto& fua = mContext->mFormatUsage;
- if (!fua->AreUnpackEnumsValid(unpackFormat, unpackType)) {
- mContext->ErrorInvalidEnum("%s: Invalid unpack format/type:"
- " 0x%04x/0x%04x",
- funcName, unpackFormat, unpackType);
- return;
- }
-
+ if (!dstUsage->IsUnpackValid(pi, &driverUnpackInfo)) {
mContext->ErrorInvalidOperation("%s: Mismatched internalFormat and format/type:"
" %s and 0x%04x/0x%04x",
- funcName, dstFormat->name, unpackFormat,
- unpackType);
+ funcName, dstFormat->name, pi.format, pi.type);
return;
}
- const bool isFunc3D = Is3D(target);
- if (!blob->ValidateUnpack(mContext, funcName, isFunc3D, srcPacking))
- return;
-
////////////////////////////////////
// Do the thing!
mContext->gl->MakeCurrent();
bool uploadWillInitialize;
if (!EnsureImageDataInitializedForUpload(this, funcName, target, level, xOffset,
yOffset, zOffset, blob->mWidth,
@@ -1264,26 +1405,33 @@ WebGLTexture::TexSubImage(const char* fu
}
}
////////////////////////////////////////
// CompressedTex(Sub)Image
void
WebGLTexture::CompressedTexImage(const char* funcName, TexImageTarget target, GLint level,
- GLenum internalFormat, GLsizei width, GLsizei height,
- GLsizei depth, GLint border,
+ GLenum internalFormat, GLsizei rawWidth,
+ GLsizei rawHeight, GLsizei rawDepth, GLint border,
const dom::ArrayBufferView& view)
{
+ uint32_t width, height, depth;
+ if (!ValidateExtents(mContext, funcName, rawWidth, rawHeight, rawDepth, border,
+ &width, &height, &depth))
+ {
+ return;
+ }
+
////////////////////////////////////
// Get dest info
WebGLTexture::ImageInfo* imageInfo;
if (!ValidateTexImageSpecification(funcName, target, level, width, height, depth,
- border, &imageInfo))
+ &imageInfo))
{
return;
}
MOZ_ASSERT(imageInfo);
auto usage = mContext->mFormatUsage->GetSizedTexUsage(internalFormat);
if (!usage) {
mContext->ErrorInvalidEnum("%s: Invalid internalFormat: 0x%04x", funcName,
@@ -1325,17 +1473,17 @@ WebGLTexture::CompressedTexImage(const c
////////////////////////////////////
// Do the thing!
mContext->gl->MakeCurrent();
// Warning: Possibly shared memory. See bug 1225033.
GLenum error = DoCompressedTexImage(mContext->gl, target, level, internalFormat,
- width, height, depth, border, dataSize, data);
+ width, height, depth, dataSize, data);
if (error == LOCAL_GL_OUT_OF_MEMORY) {
mContext->ErrorOutOfMemory("%s: Ran out of memory during upload.", funcName);
return;
}
if (error) {
MOZ_RELEASE_ASSERT(false, "GFX: We should have caught all other errors.");
mContext->GenerateWarning("%s: Unexpected error during texture upload. Context"
" lost.",
@@ -1370,20 +1518,27 @@ IsSubImageBlockAligned(const webgl::Comp
return false;
return true;
}
void
WebGLTexture::CompressedTexSubImage(const char* funcName, TexImageTarget target,
GLint level, GLint xOffset, GLint yOffset,
- GLint zOffset, GLsizei width, GLsizei height,
- GLsizei depth, GLenum sizedUnpackFormat,
+ GLint zOffset, GLsizei rawWidth, GLsizei rawHeight,
+ GLsizei rawDepth, GLenum sizedUnpackFormat,
const dom::ArrayBufferView& view)
{
+ uint32_t width, height, depth;
+ if (!ValidateExtents(mContext, funcName, rawWidth, rawHeight, rawDepth, 0, &width,
+ &height, &depth))
+ {
+ return;
+ }
+
////////////////////////////////////
// Get dest info
WebGLTexture::ImageInfo* imageInfo;
if (!ValidateTexImageSelection(funcName, target, level, xOffset, yOffset, zOffset,
width, height, depth, &imageInfo))
{
return;
@@ -1693,29 +1848,34 @@ ScopedCopyTexImageSource::~ScopedCopyTex
gl->fDeleteRenderbuffers(1, &mRB);
}
////////////////////////////////////////////////////////////////////////////////
// There is no CopyTexImage3D.
void
WebGLTexture::CopyTexImage2D(TexImageTarget target, GLint level, GLenum internalFormat,
- GLint x, GLint y, GLsizei width, GLsizei height,
+ GLint x, GLint y, GLsizei rawWidth, GLsizei rawHeight,
GLint border)
{
const char funcName[] = "CopyTexImage2D";
- const uint8_t depth = 1;
-
////////////////////////////////////
// Get dest info
+ uint32_t width, height, depth;
+ if (!ValidateExtents(mContext, funcName, rawWidth, rawHeight, 1, border, &width,
+ &height, &depth))
+ {
+ return;
+ }
+
WebGLTexture::ImageInfo* imageInfo;
if (!ValidateTexImageSpecification(funcName, target, level, width, height, depth,
- border, &imageInfo))
+ &imageInfo))
{
return;
}
MOZ_ASSERT(imageInfo);
////////////////////////////////////
// Get source info
@@ -1795,18 +1955,18 @@ WebGLTexture::CopyTexImage2D(TexImageTar
uint32_t writeX, writeY;
uint32_t rwWidth, rwHeight;
Intersect(srcWidth, x, width, &readX, &writeX, &rwWidth);
Intersect(srcHeight, y, height, &readY, &writeY, &rwHeight);
GLenum error;
if (rwWidth == uint32_t(width) && rwHeight == uint32_t(height)) {
MOZ_ASSERT(dstUsage->idealUnpack);
- error = DoCopyTexImage2D(gl, target, level, dstUsage->idealUnpack->internalFormat, x, y, width, height,
- border);
+ error = DoCopyTexImage2D(gl, target, level, dstUsage->idealUnpack->internalFormat,
+ x, y, width, height);
} else {
// 1. Zero the texture data.
// 2. CopyTexSubImage the subrect.
const bool respecifyTexture = true;
const uint8_t zOffset = 0;
if (!ZeroTextureData(mContext, funcName, respecifyTexture, mGLName, target, level,
dstUsage, 0, 0, zOffset, width, height, depth))
@@ -1846,19 +2006,24 @@ WebGLTexture::CopyTexImage2D(TexImageTar
const bool isDataInitialized = true;
const ImageInfo newImageInfo(dstUsage, width, height, depth, isDataInitialized);
SetImageInfo(imageInfo, newImageInfo);
}
void
WebGLTexture::CopyTexSubImage(const char* funcName, TexImageTarget target, GLint level,
GLint xOffset, GLint yOffset, GLint zOffset, GLint x,
- GLint y, GLsizei width, GLsizei height)
+ GLint y, GLsizei rawWidth, GLsizei rawHeight)
{
- const GLsizei depth = 1;
+ uint32_t width, height, depth;
+ if (!ValidateExtents(mContext, funcName, rawWidth, rawHeight, 1, 0, &width,
+ &height, &depth))
+ {
+ return;
+ }
////////////////////////////////////
// Get dest info
WebGLTexture::ImageInfo* imageInfo;
if (!ValidateTexImageSelection(funcName, target, level, xOffset, yOffset, zOffset,
width, height, depth, &imageInfo))
{