зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1281098 - Fix UNPACK_ handling. - r=jrmuizel
MozReview-Commit-ID: Au9eiKSxquJ
This commit is contained in:
Родитель
ed42e5fb40
Коммит
8a6d29efd0
|
@ -19,6 +19,24 @@
|
|||
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,
|
||||
|
@ -48,32 +66,20 @@ TexUnpackBlob::OriginsForDOM(WebGLContext* webgl, gl::OriginPos* const out_src,
|
|||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// 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;
|
||||
|
||||
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;
|
||||
return (val ? val : fallback);
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -136,11 +142,11 @@ FormatFromPacking(const webgl::PackingInfo& pi)
|
|||
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;
|
||||
|
@ -167,35 +173,63 @@ TexUnpackBytes::TexOrSubImage(bool isSubImage, bool needsRespec, const char* fun
|
|||
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();
|
||||
|
@ -205,8 +239,10 @@ TexUnpackBytes::TexOrSubImage(bool isSubImage, bool needsRespec, const char* fun
|
|||
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;
|
||||
|
@ -220,44 +256,46 @@ TexUnpackBytes::TexOrSubImage(bool isSubImage, bool needsRespec, const char* fun
|
|||
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,
|
||||
*out_error = DoTexOrSubImage(isSubImage, gl, target, level, dui, xOffset, yOffset,
|
||||
zOffset, mWidth, mHeight, mDepth, uploadBytes);
|
||||
*out_glError = error;
|
||||
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;
|
||||
|
||||
|
@ -265,14 +303,10 @@ TexUnpackImage::TexOrSubImage(bool isSubImage, bool needsRespec, const char* fun
|
|||
gl->MakeCurrent();
|
||||
|
||||
if (needsRespec) {
|
||||
GLenum error = DoTexOrSubImage(isSubImage, gl, target.get(), level, dui, xOffset,
|
||||
*out_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;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
do {
|
||||
|
@ -309,7 +343,9 @@ TexUnpackImage::TexOrSubImage(bool isSubImage, bool needsRespec, const char* fun
|
|||
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"
|
||||
|
@ -318,20 +354,34 @@ TexUnpackImage::TexOrSubImage(bool isSubImage, bool needsRespec, const char* fun
|
|||
|
||||
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)
|
||||
|
@ -745,24 +795,13 @@ TexUnpackSurface::ConvertSurface(WebGLContext* webgl, const webgl::DriverUnpackI
|
|||
|
||||
////////////////////
|
||||
|
||||
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
|
||||
|
@ -770,23 +809,18 @@ TexUnpackSurface::TexOrSubImage(bool isSubImage, bool needsRespec, const char* f
|
|||
// 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)
|
||||
|
@ -798,13 +832,9 @@ TexUnpackSurface::TexOrSubImage(bool isSubImage, bool needsRespec, const char* f
|
|||
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) {
|
||||
|
@ -817,10 +847,10 @@ TexUnpackSurface::TexOrSubImage(bool isSubImage, bool needsRespec, const char* f
|
|||
ScopedUnpackReset scopedReset(webgl);
|
||||
webgl->gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, convertedAlignment);
|
||||
|
||||
error = DoTexOrSubImage(isSubImage, webgl->gl, target.get(), level, dui, xOffset,
|
||||
*out_error = DoTexOrSubImage(isSubImage, webgl->gl, target.get(), level, dui, xOffset,
|
||||
yOffset, zOffset, mWidth, mHeight, mDepth,
|
||||
convertedBuffer.get());
|
||||
*out_glError = error;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace webgl
|
||||
|
|
|
@ -47,30 +47,30 @@ struct DriverUnpackInfo;
|
|||
class TexUnpackBlob
|
||||
{
|
||||
public:
|
||||
const GLsizei mWidth;
|
||||
const GLsizei mHeight;
|
||||
const GLsizei mDepth;
|
||||
const uint32_t mAlignment;
|
||||
const uint32_t mRowLength;
|
||||
const uint32_t mImageHeight;
|
||||
const uint32_t mSkipPixels;
|
||||
const uint32_t mSkipRows;
|
||||
const uint32_t mSkipImages;
|
||||
const uint32_t mWidth;
|
||||
const uint32_t mHeight;
|
||||
const uint32_t mDepth;
|
||||
const bool mHasData;
|
||||
|
||||
protected:
|
||||
TexUnpackBlob(GLsizei width, GLsizei height, GLsizei depth, bool hasData)
|
||||
: mWidth(width)
|
||||
, mHeight(height)
|
||||
, mDepth(depth)
|
||||
, mHasData(hasData)
|
||||
{ }
|
||||
TexUnpackBlob(const WebGLContext* webgl, uint32_t alignment, uint32_t rowLength,
|
||||
uint32_t imageHeight, uint32_t width, uint32_t height, uint32_t depth,
|
||||
bool hasData);
|
||||
|
||||
public:
|
||||
virtual ~TexUnpackBlob() { }
|
||||
|
||||
virtual bool ValidateUnpack(WebGLContext* webgl, const char* funcName, bool isFunc3D,
|
||||
const webgl::PackingInfo& pi) = 0;
|
||||
|
||||
virtual void TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName,
|
||||
virtual bool 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) = 0;
|
||||
GLenum* const out_error) const = 0;
|
||||
|
||||
static void OriginsForDOM(WebGLContext* webgl, gl::OriginPos* const out_src,
|
||||
gl::OriginPos* const out_dst);
|
||||
|
@ -79,24 +79,16 @@ public:
|
|||
class TexUnpackBytes : public TexUnpackBlob
|
||||
{
|
||||
public:
|
||||
const size_t mByteCount;
|
||||
const void* const mBytes;
|
||||
|
||||
TexUnpackBytes(GLsizei width, GLsizei height, GLsizei depth, size_t byteCount,
|
||||
const void* bytes)
|
||||
: TexUnpackBlob(width, height, depth, bool(bytes))
|
||||
, mByteCount(byteCount)
|
||||
, mBytes(bytes)
|
||||
{ }
|
||||
TexUnpackBytes(const WebGLContext* webgl, uint32_t width, uint32_t height,
|
||||
uint32_t depth, const void* bytes);
|
||||
|
||||
virtual bool ValidateUnpack(WebGLContext* webgl, const char* funcName, bool isFunc3D,
|
||||
const webgl::PackingInfo& pi) override;
|
||||
|
||||
virtual void TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName,
|
||||
virtual bool 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) override;
|
||||
GLenum* const out_error) const override;
|
||||
};
|
||||
|
||||
class TexUnpackImage : public TexUnpackBlob
|
||||
|
@ -105,20 +97,15 @@ public:
|
|||
const RefPtr<layers::Image> mImage;
|
||||
const bool mIsAlphaPremult;
|
||||
|
||||
TexUnpackImage(const RefPtr<layers::Image>& image, bool isAlphaPremult);
|
||||
virtual ~TexUnpackImage() override;
|
||||
TexUnpackImage(const WebGLContext* webgl, uint32_t imageHeight, uint32_t width,
|
||||
uint32_t height, uint32_t depth, const RefPtr<layers::Image>& image,
|
||||
bool isAlphaPremult);
|
||||
|
||||
virtual bool ValidateUnpack(WebGLContext* webgl, const char* funcName, bool isFunc3D,
|
||||
const webgl::PackingInfo& pi) override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName,
|
||||
virtual bool 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) override;
|
||||
GLenum* const out_error) const override;
|
||||
};
|
||||
|
||||
class TexUnpackSurface : public TexUnpackBlob
|
||||
|
@ -127,20 +114,15 @@ public:
|
|||
const RefPtr<gfx::SourceSurface> mSurf;
|
||||
const bool mIsAlphaPremult;
|
||||
|
||||
TexUnpackSurface(const RefPtr<gfx::SourceSurface>& surf, bool isAlphaPremult);
|
||||
virtual ~TexUnpackSurface() override;
|
||||
TexUnpackSurface(const WebGLContext* webgl, uint32_t imageHeight, uint32_t width,
|
||||
uint32_t height, uint32_t depth, gfx::SourceSurface* surf,
|
||||
bool isAlphaPremult);
|
||||
|
||||
virtual bool ValidateUnpack(WebGLContext* webgl, const char* funcName, bool isFunc3D,
|
||||
const webgl::PackingInfo& pi) override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName,
|
||||
virtual bool 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) override;
|
||||
GLenum* const out_error) const override;
|
||||
|
||||
protected:
|
||||
static bool ConvertSurface(WebGLContext* webgl, const webgl::DriverUnpackInfo* dui,
|
||||
|
|
|
@ -940,7 +940,13 @@ public:
|
|||
&elem, &out_error);
|
||||
}
|
||||
|
||||
//////
|
||||
// WebGLTextureUpload.cpp
|
||||
public:
|
||||
bool ValidateUnpackPixels(const char* funcName, uint32_t fullRows,
|
||||
uint32_t tailPixels, const webgl::TexUnpackBlob* blob);
|
||||
|
||||
protected:
|
||||
bool ValidateTexImageSpecification(const char* funcName, uint8_t funcDims,
|
||||
GLenum texImageTarget, GLint level,
|
||||
GLsizei width, GLsizei height, GLsizei depth,
|
||||
|
@ -956,6 +962,13 @@ public:
|
|||
WebGLTexture** const out_texture,
|
||||
WebGLTexture::ImageInfo** const out_imageInfo);
|
||||
|
||||
bool GetUnpackValuesForImage(const char* funcName, uint32_t srcImageWidth,
|
||||
uint32_t srcImageHeight, uint32_t* const out_rowLength,
|
||||
uint32_t* const out_imageHeight);
|
||||
|
||||
bool ValidateUnpackInfo(const char* funcName, GLenum format, GLenum type,
|
||||
webgl::PackingInfo* const out);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Vertices Feature (WebGLContextVertices.cpp)
|
||||
public:
|
||||
|
|
|
@ -237,31 +237,34 @@ public:
|
|||
dom::Element* elem, ErrorResult* const out_error);
|
||||
|
||||
protected:
|
||||
void 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);
|
||||
void 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);
|
||||
|
||||
bool 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);
|
||||
bool 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);
|
||||
|
||||
bool ValidateUnpack(const char* funcName, const webgl::TexUnpackBlob* blob,
|
||||
bool isFunc3D, const webgl::PackingInfo& srcPI) const;
|
||||
public:
|
||||
void TexStorage(const char* funcName, TexTarget target, GLsizei levels,
|
||||
GLenum sizedFormat, GLsizei width, GLsizei height, GLsizei depth);
|
||||
protected:
|
||||
void 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);
|
||||
void TexSubImage(const char* funcName, TexImageTarget target, GLint level,
|
||||
GLint xOffset, GLint yOffset, GLint zOffset, GLenum unpackFormat,
|
||||
GLenum unpackType, webgl::TexUnpackBlob* blob);
|
||||
GLint xOffset, GLint yOffset, GLint zOffset,
|
||||
const webgl::PackingInfo& pi, const webgl::TexUnpackBlob* blob);
|
||||
public:
|
||||
void CompressedTexImage(const char* funcName, TexImageTarget target, GLint level,
|
||||
GLenum internalFormat, GLsizei width, GLsizei height,
|
||||
|
|
|
@ -55,6 +55,33 @@ namespace mozilla {
|
|||
* 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?
|
||||
|
||||
|
@ -98,82 +125,165 @@ DoesJSTypeMatchUnpackType(GLenum unpackType, js::Scalar::Type jsType)
|
|||
}
|
||||
}
|
||||
|
||||
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);
|
||||
return false;
|
||||
}
|
||||
|
||||
webgl->ErrorInvalidOperation("%s: `pixels` be compatible with unpack `type`.",
|
||||
if (!usedPixelsPerRow.isValid() ||
|
||||
!usedRowsPerImage.isValid() ||
|
||||
!usedImages.isValid())
|
||||
{
|
||||
ErrorOutOfMemory("%s: Invalid calculation for e.g. UNPACK_SKIP_PIXELS + width.",
|
||||
funcName);
|
||||
return false;
|
||||
}
|
||||
|
||||
//////
|
||||
|
||||
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,
|
||||
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;
|
||||
}
|
||||
|
||||
UniquePtr<webgl::TexUnpackBlob> ret;
|
||||
// Warning: Possibly shared memory. See bug 1225033.
|
||||
ret.reset(new webgl::TexUnpackBytes(width, height, depth, dataSize, data));
|
||||
return Move(ret);
|
||||
if (width && height && depth) {
|
||||
view.ComputeLengthAndData();
|
||||
|
||||
bytes = view.DataAllowShared();
|
||||
byteCount = view.LengthAllowShared();
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
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);
|
||||
|
||||
|
@ -189,20 +299,46 @@ UnpackBlobFromImageData(WebGLContext* webgl, const char* funcName, GLenum unpack
|
|||
|
||||
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
|
||||
|
@ -211,17 +347,50 @@ WebGLTexture::TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarge
|
|||
GLint yOffset, GLint zOffset, GLenum unpackFormat,
|
||||
GLenum unpackType, dom::ImageData* imageData)
|
||||
{
|
||||
dom::RootedTypedArray<dom::Uint8ClampedArray> scopedArr(
|
||||
nsContentUtils::RootingCxForThread());
|
||||
|
||||
UniquePtr<webgl::TexUnpackBlob> blob;
|
||||
blob = UnpackBlobFromImageData(mContext, funcName, unpackType, imageData, &scopedArr);
|
||||
if (!blob)
|
||||
webgl::PackingInfo pi;
|
||||
if (!mContext->ValidateUnpackInfo(funcName, unpackFormat, unpackType, &pi))
|
||||
return;
|
||||
|
||||
const GLint border = 0;
|
||||
TexOrSubImage(isSubImage, funcName, target, level, internalFormat, xOffset, yOffset,
|
||||
zOffset, border, unpackFormat, unpackType, blob.get());
|
||||
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());
|
||||
const RefPtr<gfx::SourceSurface> surf = FromImageData(mContext, funcName, unpackType,
|
||||
imageData, &scopedArr);
|
||||
if (!surf)
|
||||
return;
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
|
@ -234,22 +403,45 @@ WebGLTexture::TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarge
|
|||
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();
|
||||
|
@ -272,40 +464,52 @@ WebGLTexture::TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarge
|
|||
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.",
|
||||
funcName);
|
||||
|
||||
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));
|
||||
//////
|
||||
// Ok, we're good!
|
||||
|
||||
uint32_t rowLength, imageHeight;
|
||||
if (!mContext->GetUnpackValuesForImage(funcName, elemWidth, elemHeight, &rowLength,
|
||||
&imageHeight))
|
||||
{
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(blob);
|
||||
|
||||
const GLint border = 0;
|
||||
TexOrSubImage(isSubImage, funcName, target, level, internalFormat, xOffset, yOffset,
|
||||
zOffset, border, unpackFormat, unpackType, blob.get());
|
||||
UniquePtr<const webgl::TexUnpackBlob> blob;
|
||||
const bool isAlphaPremult = sfer.mIsPremultiplied;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -334,12 +538,11 @@ ValidateTexImage(WebGLContext* webgl, WebGLTexture* texture, const char* funcNam
|
|||
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) {
|
||||
|
@ -352,23 +555,6 @@ WebGLTexture::ValidateTexImageSpecification(const char* funcName, TexImageTarget
|
|||
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)
|
||||
{
|
||||
|
@ -419,9 +605,9 @@ WebGLTexture::ValidateTexImageSpecification(const char* funcName, TexImageTarget
|
|||
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);
|
||||
|
@ -439,7 +625,7 @@ WebGLTexture::ValidateTexImageSpecification(const char* funcName, TexImageTarget
|
|||
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);
|
||||
|
@ -456,15 +642,13 @@ WebGLTexture::ValidateTexImageSpecification(const char* funcName, TexImageTarget
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -718,8 +902,10 @@ DoTexSubImage(gl::GLContext* gl, TexImageTarget target, GLint level, GLint xOffs
|
|||
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)) {
|
||||
|
@ -758,9 +944,10 @@ DoCompressedTexSubImage(gl::GLContext* gl, TexImageTarget target, GLint level,
|
|||
|
||||
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));
|
||||
|
@ -928,11 +1115,10 @@ WebGLTexture::TexStorage(const char* funcName, TexTarget target, GLsizei levels,
|
|||
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;
|
||||
}
|
||||
|
@ -1015,39 +1201,30 @@ WebGLTexture::TexStorage(const char* funcName, TexTarget target, GLsizei levels,
|
|||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
auto dstUsage = fua->GetSizedTexUsage(internalFormat);
|
||||
if (!dstUsage) {
|
||||
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
|
||||
|
@ -1059,45 +1236,24 @@ WebGLTexture::TexImage(const char* funcName, TexImageTarget target, GLint level,
|
|||
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;
|
||||
|
@ -1167,8 +1323,7 @@ WebGLTexture::TexImage(const char* funcName, TexImageTarget target, GLint level,
|
|||
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
|
||||
|
@ -1200,28 +1355,14 @@ WebGLTexture::TexSubImage(const char* funcName, TexImageTarget target, GLint lev
|
|||
////////////////////////////////////
|
||||
// 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!
|
||||
|
||||
|
@ -1269,16 +1410,23 @@ WebGLTexture::TexSubImage(const char* funcName, TexImageTarget target, GLint lev
|
|||
|
||||
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;
|
||||
}
|
||||
|
@ -1330,7 +1478,7 @@ WebGLTexture::CompressedTexImage(const char* funcName, TexImageTarget target, GL
|
|||
|
||||
// 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;
|
||||
|
@ -1375,10 +1523,17 @@ IsSubImageBlockAligned(const webgl::CompressedFormatInfo* compression,
|
|||
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
|
||||
|
||||
|
@ -1698,19 +1853,24 @@ ScopedCopyTexImageSource::~ScopedCopyTexImageSource()
|
|||
// 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;
|
||||
}
|
||||
|
@ -1800,8 +1960,8 @@ WebGLTexture::CopyTexImage2D(TexImageTarget target, GLint level, GLenum internal
|
|||
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.
|
||||
|
@ -1851,9 +2011,14 @@ WebGLTexture::CopyTexImage2D(TexImageTarget target, GLint level, GLenum internal
|
|||
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
|
||||
|
|
Загрузка…
Ссылка в новой задаче