forked from mirrors/gecko-dev
Bug 1751205 - Part 1. Add Swizzle/PremultiplyYFlipData helper methods. r=gfx-reviewers,lsalzman,jgilbert
These new methods do both swizzle/premultiply and a Y-flip operation. Differential Revision: https://phabricator.services.mozilla.com/D136503
This commit is contained in:
parent
b6ae4a0fca
commit
47af38389f
3 changed files with 235 additions and 0 deletions
|
|
@ -10,6 +10,7 @@
|
||||||
#include "Tools.h"
|
#include "Tools.h"
|
||||||
#include "mozilla/CheckedInt.h"
|
#include "mozilla/CheckedInt.h"
|
||||||
#include "mozilla/EndianUtils.h"
|
#include "mozilla/EndianUtils.h"
|
||||||
|
#include "mozilla/UniquePtr.h"
|
||||||
|
|
||||||
#ifdef USE_SSE2
|
#ifdef USE_SSE2
|
||||||
# include "mozilla/SSE.h"
|
# include "mozilla/SSE.h"
|
||||||
|
|
@ -19,6 +20,8 @@
|
||||||
# include "mozilla/arm.h"
|
# include "mozilla/arm.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace gfx {
|
namespace gfx {
|
||||||
|
|
||||||
|
|
@ -1187,6 +1190,92 @@ bool SwizzleData(const uint8_t* aSrc, int32_t aSrcStride,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool SwizzleYFlipDataInternal(const uint8_t* aSrc, int32_t aSrcStride,
|
||||||
|
SurfaceFormat aSrcFormat, uint8_t* aDst,
|
||||||
|
int32_t aDstStride,
|
||||||
|
SurfaceFormat aDstFormat,
|
||||||
|
const IntSize& aSize,
|
||||||
|
SwizzleRowFn aSwizzleFn) {
|
||||||
|
if (!aSwizzleFn) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Guarantee our width and height are both greater than zero.
|
||||||
|
if (aSize.IsEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unlike SwizzleData/PremultiplyData, we don't use the stride gaps directly,
|
||||||
|
// but we can use it to verify that the stride is valid for our width and
|
||||||
|
// format.
|
||||||
|
int32_t srcGap = GetStrideGap(aSize.width, aSrcFormat, aSrcStride);
|
||||||
|
int32_t dstGap = GetStrideGap(aSize.width, aDstFormat, aDstStride);
|
||||||
|
MOZ_ASSERT(srcGap >= 0 && dstGap >= 0);
|
||||||
|
if (srcGap < 0 || dstGap < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swapping/swizzling to a new buffer is trivial.
|
||||||
|
if (aSrc != aDst) {
|
||||||
|
const uint8_t* src = aSrc;
|
||||||
|
const uint8_t* srcEnd = aSrc + aSize.height * aSrcStride;
|
||||||
|
uint8_t* dst = aDst + (aSize.height - 1) * aDstStride;
|
||||||
|
while (src < srcEnd) {
|
||||||
|
aSwizzleFn(src, dst, aSize.width);
|
||||||
|
src += aSrcStride;
|
||||||
|
dst -= aDstStride;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aSrcStride != aDstStride) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we are swizzling in place, then we need a temporary row buffer.
|
||||||
|
UniquePtr<uint8_t[]> rowBuffer(new (std::nothrow) uint8_t[aDstStride]);
|
||||||
|
if (!rowBuffer) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swizzle and swap the top and bottom rows until we meet in the middle.
|
||||||
|
int32_t middleRow = aSize.height / 2;
|
||||||
|
uint8_t* top = aDst;
|
||||||
|
uint8_t* bottom = aDst + (aSize.height - 1) * aDstStride;
|
||||||
|
for (int32_t row = 0; row < middleRow; ++row) {
|
||||||
|
memcpy(rowBuffer.get(), bottom, aDstStride);
|
||||||
|
aSwizzleFn(top, bottom, aSize.width);
|
||||||
|
aSwizzleFn(rowBuffer.get(), top, aSize.width);
|
||||||
|
top += aDstStride;
|
||||||
|
bottom -= aDstStride;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is an odd numbered row, we haven't swizzled it yet.
|
||||||
|
if (aSize.height % 2 == 1) {
|
||||||
|
top = aDst + middleRow * aDstStride;
|
||||||
|
aSwizzleFn(top, top, aSize.width);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SwizzleYFlipData(const uint8_t* aSrc, int32_t aSrcStride,
|
||||||
|
SurfaceFormat aSrcFormat, uint8_t* aDst,
|
||||||
|
int32_t aDstStride, SurfaceFormat aDstFormat,
|
||||||
|
const IntSize& aSize) {
|
||||||
|
return SwizzleYFlipDataInternal(aSrc, aSrcStride, aSrcFormat, aDst,
|
||||||
|
aDstStride, aDstFormat, aSize,
|
||||||
|
SwizzleRow(aSrcFormat, aDstFormat));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PremultiplyYFlipData(const uint8_t* aSrc, int32_t aSrcStride,
|
||||||
|
SurfaceFormat aSrcFormat, uint8_t* aDst,
|
||||||
|
int32_t aDstStride, SurfaceFormat aDstFormat,
|
||||||
|
const IntSize& aSize) {
|
||||||
|
return SwizzleYFlipDataInternal(aSrc, aSrcStride, aSrcFormat, aDst,
|
||||||
|
aDstStride, aDstFormat, aSize,
|
||||||
|
PremultiplyRow(aSrcFormat, aDstFormat));
|
||||||
|
}
|
||||||
|
|
||||||
SwizzleRowFn SwizzleRow(SurfaceFormat aSrcFormat, SurfaceFormat aDstFormat) {
|
SwizzleRowFn SwizzleRow(SurfaceFormat aSrcFormat, SurfaceFormat aDstFormat) {
|
||||||
#ifdef USE_SSE2
|
#ifdef USE_SSE2
|
||||||
if (mozilla::supports_avx2()) switch (FORMAT_KEY(aSrcFormat, aDstFormat)) {
|
if (mozilla::supports_avx2()) switch (FORMAT_KEY(aSrcFormat, aDstFormat)) {
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,27 @@ GFX2D_API bool SwizzleData(const uint8_t* aSrc, int32_t aSrcStride,
|
||||||
int32_t aDstStride, SurfaceFormat aDstFormat,
|
int32_t aDstStride, SurfaceFormat aDstFormat,
|
||||||
const IntSize& aSize);
|
const IntSize& aSize);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flips rows of source and swizzles it to destination. Source and destination
|
||||||
|
* may be the same to swizzle in-place; this will fail if it cannot allocate a
|
||||||
|
* temporary buffer.
|
||||||
|
*/
|
||||||
|
GFX2D_API bool SwizzleYFlipData(const uint8_t* aSrc, int32_t aSrcStride,
|
||||||
|
SurfaceFormat aSrcFormat, uint8_t* aDst,
|
||||||
|
int32_t aDstStride, SurfaceFormat aDstFormat,
|
||||||
|
const IntSize& aSize);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flips rows of source and premultiplies/swizzles it to destination. Source and
|
||||||
|
* destination may be the same to premultiply/swizzle in-place; this will fail
|
||||||
|
* if it cannot allocate a temporary buffer.
|
||||||
|
*/
|
||||||
|
GFX2D_API bool PremultiplyYFlipData(const uint8_t* aSrc, int32_t aSrcStride,
|
||||||
|
SurfaceFormat aSrcFormat, uint8_t* aDst,
|
||||||
|
int32_t aDstStride,
|
||||||
|
SurfaceFormat aDstFormat,
|
||||||
|
const IntSize& aSize);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Swizzles source and writes it to destination. Source and destination may be
|
* Swizzles source and writes it to destination. Source and destination may be
|
||||||
* the same to swizzle in-place.
|
* the same to swizzle in-place.
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,75 @@ TEST(Moz2D, PremultiplyRow)
|
||||||
EXPECT_TRUE(ArrayEqual(out, check_argb));
|
EXPECT_TRUE(ArrayEqual(out, check_argb));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(Moz2D, PremultiplyYFlipData)
|
||||||
|
{
|
||||||
|
const uint8_t stride = 2 * 4;
|
||||||
|
const uint8_t in_bgra[6 * 4] = {
|
||||||
|
255, 255, 0, 255, // row 1: verify 255 alpha leaves RGB unchanged
|
||||||
|
0, 0, 255, 255,
|
||||||
|
0, 255, 255, 0, // row 2: verify 0 alpha zeroes out RGB
|
||||||
|
0, 0, 0, 0,
|
||||||
|
255, 0, 0, 128, // row 3: verify that 255 RGB maps to alpha
|
||||||
|
255, 255, 255, 128,
|
||||||
|
};
|
||||||
|
const uint8_t in_bgra_2[4 * 4] = {
|
||||||
|
255, 255, 0, 255, // row 1: verify 255 alpha leaves RGB unchanged
|
||||||
|
0, 0, 255, 255,
|
||||||
|
0, 255, 255, 0, // row 2: verify 0 alpha zeroes out RGB
|
||||||
|
0, 0, 0, 0,
|
||||||
|
};
|
||||||
|
const uint8_t in_bgra_3[2 * 4] = {
|
||||||
|
255, 0, 0, 128, // row 1: verify that 255 RGB maps to alpha
|
||||||
|
255, 255, 255, 128,
|
||||||
|
};
|
||||||
|
uint8_t out[6 * 4];
|
||||||
|
uint8_t out_2[4 * 4];
|
||||||
|
uint8_t out_3[2 * 4];
|
||||||
|
const uint8_t check_bgra[6 * 4] = {
|
||||||
|
128, 0, 0, 128, 128, 128, 128, 128, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 255, 255, 0, 255, 0, 0, 255, 255,
|
||||||
|
};
|
||||||
|
const uint8_t check_bgra_2[4 * 4] = {
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 0, 255, 0, 0, 255, 255,
|
||||||
|
};
|
||||||
|
const uint8_t check_bgra_3[2 * 4] = {
|
||||||
|
128, 0, 0, 128, 128, 128, 128, 128,
|
||||||
|
};
|
||||||
|
// check swizzled output
|
||||||
|
const uint8_t check_rgba[6 * 4] = {
|
||||||
|
0, 0, 128, 128, 128, 128, 128, 128, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 255,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Premultiply.
|
||||||
|
PremultiplyYFlipData(in_bgra, stride, SurfaceFormat::B8G8R8A8, out, stride,
|
||||||
|
SurfaceFormat::B8G8R8A8, IntSize(2, 3));
|
||||||
|
EXPECT_TRUE(ArrayEqual(out, check_bgra));
|
||||||
|
|
||||||
|
// Premultiply in-place with middle row.
|
||||||
|
memcpy(out, in_bgra, sizeof(out));
|
||||||
|
PremultiplyYFlipData(out, stride, SurfaceFormat::B8G8R8A8, out, stride,
|
||||||
|
SurfaceFormat::B8G8R8A8, IntSize(2, 3));
|
||||||
|
EXPECT_TRUE(ArrayEqual(out, check_bgra));
|
||||||
|
|
||||||
|
// Premultiply in-place without middle row.
|
||||||
|
memcpy(out_2, in_bgra_2, sizeof(out_2));
|
||||||
|
PremultiplyYFlipData(out_2, stride, SurfaceFormat::B8G8R8A8, out_2, stride,
|
||||||
|
SurfaceFormat::B8G8R8A8, IntSize(2, 2));
|
||||||
|
EXPECT_TRUE(ArrayEqual(out_2, check_bgra_2));
|
||||||
|
|
||||||
|
// Premultiply in-place only middle row.
|
||||||
|
memcpy(out_3, in_bgra_3, sizeof(out_3));
|
||||||
|
PremultiplyYFlipData(out_3, stride, SurfaceFormat::B8G8R8A8, out_3, stride,
|
||||||
|
SurfaceFormat::B8G8R8A8, IntSize(2, 1));
|
||||||
|
EXPECT_TRUE(ArrayEqual(out_3, check_bgra_3));
|
||||||
|
|
||||||
|
// Premultiply and swizzle with middle row.
|
||||||
|
PremultiplyYFlipData(in_bgra, stride, SurfaceFormat::B8G8R8A8, out, stride,
|
||||||
|
SurfaceFormat::R8G8B8A8, IntSize(2, 3));
|
||||||
|
EXPECT_TRUE(ArrayEqual(out, check_rgba));
|
||||||
|
}
|
||||||
|
|
||||||
TEST(Moz2D, UnpremultiplyData)
|
TEST(Moz2D, UnpremultiplyData)
|
||||||
{
|
{
|
||||||
const uint8_t in_bgra[5 * 4] = {
|
const uint8_t in_bgra[5 * 4] = {
|
||||||
|
|
@ -235,6 +304,62 @@ TEST(Moz2D, SwizzleData)
|
||||||
EXPECT_TRUE(ArrayEqual(out16, check_16));
|
EXPECT_TRUE(ArrayEqual(out16, check_16));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(Moz2D, SwizzleYFlipData)
|
||||||
|
{
|
||||||
|
const uint8_t stride = 2 * 4;
|
||||||
|
const uint8_t in_bgra[6 * 4] = {
|
||||||
|
255, 255, 0, 255, // row 1
|
||||||
|
0, 0, 255, 255, 0, 255, 255, 0, // row 2
|
||||||
|
0, 0, 0, 0, 255, 0, 0, 128, // row 3
|
||||||
|
255, 255, 255, 128,
|
||||||
|
};
|
||||||
|
const uint8_t in_bgra_2[4 * 4] = {
|
||||||
|
255, 255, 0, 255, // row 1
|
||||||
|
0, 0, 255, 255, 0, 255, 255, 0, // row 2
|
||||||
|
0, 0, 0, 0,
|
||||||
|
};
|
||||||
|
const uint8_t in_bgra_3[2 * 4] = {
|
||||||
|
255, 0, 0, 128, // row 1
|
||||||
|
255, 255, 255, 128,
|
||||||
|
};
|
||||||
|
uint8_t out[6 * 4];
|
||||||
|
uint8_t out_2[4 * 4];
|
||||||
|
uint8_t out_3[2 * 4];
|
||||||
|
const uint8_t check_rgba[6 * 4] = {
|
||||||
|
0, 0, 255, 128, 255, 255, 255, 128, 255, 255, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 255,
|
||||||
|
};
|
||||||
|
const uint8_t check_rgba_2[4 * 4] = {
|
||||||
|
255, 255, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 255,
|
||||||
|
};
|
||||||
|
const uint8_t check_rgba_3[2 * 4] = {
|
||||||
|
0, 0, 255, 128, 255, 255, 255, 128,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Swizzle.
|
||||||
|
SwizzleYFlipData(in_bgra, stride, SurfaceFormat::B8G8R8A8, out, stride,
|
||||||
|
SurfaceFormat::R8G8B8A8, IntSize(2, 3));
|
||||||
|
EXPECT_TRUE(ArrayEqual(out, check_rgba));
|
||||||
|
|
||||||
|
// Swizzle in-place with middle row.
|
||||||
|
memcpy(out, in_bgra, sizeof(out));
|
||||||
|
SwizzleYFlipData(out, stride, SurfaceFormat::B8G8R8A8, out, stride,
|
||||||
|
SurfaceFormat::R8G8B8A8, IntSize(2, 3));
|
||||||
|
EXPECT_TRUE(ArrayEqual(out, check_rgba));
|
||||||
|
|
||||||
|
// Swizzle in-place without middle row.
|
||||||
|
memcpy(out_2, in_bgra_2, sizeof(out_2));
|
||||||
|
SwizzleYFlipData(out_2, stride, SurfaceFormat::B8G8R8A8, out_2, stride,
|
||||||
|
SurfaceFormat::R8G8B8A8, IntSize(2, 2));
|
||||||
|
EXPECT_TRUE(ArrayEqual(out_2, check_rgba_2));
|
||||||
|
|
||||||
|
// Swizzle in-place only middle row.
|
||||||
|
memcpy(out_3, in_bgra_3, sizeof(out_3));
|
||||||
|
SwizzleYFlipData(out_3, stride, SurfaceFormat::B8G8R8A8, out_3, stride,
|
||||||
|
SurfaceFormat::R8G8B8A8, IntSize(2, 1));
|
||||||
|
EXPECT_TRUE(ArrayEqual(out_3, check_rgba_3));
|
||||||
|
}
|
||||||
|
|
||||||
TEST(Moz2D, SwizzleRow)
|
TEST(Moz2D, SwizzleRow)
|
||||||
{
|
{
|
||||||
const uint8_t in_bgra[5 * 4] = {
|
const uint8_t in_bgra[5 * 4] = {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue