--- a/dom/canvas/TexUnpackBlob.cpp
+++ b/dom/canvas/TexUnpackBlob.cpp
@@ -186,64 +186,103 @@ TexUnpackBlob::ConvertIfNeeded(WebGLCont
//////
const auto srcOrigin = (webgl->mPixelStore_FlipY ? gl::OriginPos::TopLeft
: gl::OriginPos::BottomLeft);
const auto dstOrigin = gl::OriginPos::BottomLeft;
const bool isDstPremult = webgl->mPixelStore_PremultiplyAlpha;
const auto pi = dstDUI->ToPacking();
- const auto dstFormat = FormatForPackingInfo(pi);
const auto dstBPP = webgl::BytesPerPixel(pi);
const auto dstWidthBytes = CheckedUint32(dstBPP) * mWidth;
const auto dstRowLengthBytes = CheckedUint32(dstBPP) * mRowLength;
const auto dstAlignment = mAlignment;
const auto dstStride = RoundUpToMultipleOf(dstRowLengthBytes, dstAlignment);
//////
const auto dstTotalRows = CheckedUint32(mDepth - 1) * mImageHeight + mHeight;
+ const auto dstUsedSizeExceptLastRow = (dstTotalRows - 1) * dstStride;
- const auto dstSize = skipBytes + (dstTotalRows - 1) * dstStride + dstWidthBytes;
+ const auto dstSize = skipBytes + dstUsedSizeExceptLastRow + dstWidthBytes;
if (!dstSize.isValid()) {
webgl->ErrorOutOfMemory("%s: Invalid dstSize calculation during conversion.",
funcName);
return false;
}
//////
- bool needsConvert = (srcOrigin != dstOrigin ||
- srcFormat != dstFormat ||
- srcStride != dstStride.value());
+ const auto dstFormat = FormatForPackingInfo(pi);
- if (UnpackFormatHasAlpha(dstDUI->unpackFormat)) {
- needsConvert |= (mIsSrcPremult != isDstPremult);
+ bool premultMatches = (mIsSrcPremult == isDstPremult);
+ if (!UnpackFormatHasAlpha(dstDUI->unpackFormat)) {
+ premultMatches = true;
}
- if (!needsConvert)
- return true;
+ const bool needsPixelConversion = (srcFormat != dstFormat || !premultMatches);
+ const bool originsMatch = (srcOrigin == dstOrigin);
+
+ MOZ_ASSERT_IF(!needsPixelConversion, srcBPP == dstBPP);
- ////////////
- // Ugh, ok, fine!
-
- webgl->GenerateWarning("%s: Incurred CPU data conversion, which is slow.",
- funcName);
+ if (!needsPixelConversion &&
+ originsMatch &&
+ srcStride == dstStride.value())
+ {
+ // No conversion needed!
+ return true;
+ }
//////
+ // We need some sort of conversion, so create the dest buffer.
*out_anchoredBuffer = calloc(1, dstSize.value());
- if (!out_anchoredBuffer->get()) {
+ *out_bytes = out_anchoredBuffer->get();
+ if (!*out_bytes) {
webgl->ErrorOutOfMemory("%s: Unable to allocate buffer during conversion.",
funcName);
return false;
}
- const auto dstBegin = (uint8_t*)out_anchoredBuffer->get() + skipBytes;
+ const auto dstBegin = (uint8_t*)(*out_bytes) + skipBytes;
+
+ //////
+ // Row conversion
+
+ if (!needsPixelConversion) {
+ webgl->GenerateWarning("%s: Incurred CPU row conversion, which is slow.",
+ funcName);
+
+ const uint8_t* srcRow = srcBegin;
+ uint8_t* dstRow = dstBegin;
+ const auto widthBytes = dstWidthBytes.value();
+ ptrdiff_t dstCopyStride = dstStride.value();
+
+ if (!originsMatch) {
+ dstRow += dstUsedSizeExceptLastRow.value();
+ dstCopyStride = -dstCopyStride;
+ }
+
+ for (uint32_t i = 0; i < dstTotalRows.value(); i++) {
+ memcpy(dstRow, srcRow, widthBytes);
+ srcRow += srcStride;
+ dstRow += dstCopyStride;
+ }
+ return true;
+ }
+
+ ////////////
+ // Pixel conversion.
+
+ MOZ_ASSERT(srcFormat != WebGLTexelFormat::FormatNotSupportingAnyConversion);
+ MOZ_ASSERT(dstFormat != WebGLTexelFormat::FormatNotSupportingAnyConversion);
+
+ webgl->GenerateWarning("%s: Incurred CPU pixel conversion, which is very slow.",
+ funcName);
//////
// And go!:
bool wasTrivial;
if (!ConvertImage(mWidth, dstTotalRows.value(),
srcBegin, srcStride, srcOrigin, srcFormat, mIsSrcPremult,
dstBegin, dstStride.value(), dstOrigin, dstFormat, isDstPremult,
@@ -254,17 +293,16 @@ TexUnpackBlob::ConvertIfNeeded(WebGLCont
}
if (!wasTrivial) {
webgl->GenerateWarning("%s: Chosen format/type incurred an expensive reformat:"
" 0x%04x/0x%04x",
funcName, dstDUI->unpackFormat, dstDUI->unpackType);
}
- *out_bytes = out_anchoredBuffer->get();
return true;
}
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)
{
@@ -292,25 +330,26 @@ 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_error) const
{
WebGLContext* webgl = tex->mContext;
const auto pi = dui->ToPacking();
- const auto format = FormatForPackingInfo(pi);
const auto bytesPerPixel = webgl::BytesPerPixel(pi);
const auto bytesPerRow = CheckedUint32(mRowLength) * bytesPerPixel;
const auto rowStride = RoundUpToMultipleOf(bytesPerRow, mAlignment);
if (!rowStride.isValid()) {
MOZ_CRASH("Should be checked earlier.");
}
+ const auto format = FormatForPackingInfo(pi);
+
const void* uploadBytes;
UniqueBuffer tempBuffer;
if (!ConvertIfNeeded(webgl, funcName, mBytes, rowStride.value(), bytesPerPixel,
format, dui, &uploadBytes, &tempBuffer))
{
return false;
}