diff --git a/gfx/2d/Swizzle.cpp b/gfx/2d/Swizzle.cpp index 7dcc5745d57d..6844b5813dbb 100644 --- a/gfx/2d/Swizzle.cpp +++ b/gfx/2d/Swizzle.cpp @@ -41,10 +41,6 @@ namespace gfx { #define FORMAT_CASE(aSrcFormat, aDstFormat, ...) \ FORMAT_CASE_EXPR(aSrcFormat, aDstFormat, FORMAT_CASE_CALL(__VA_ARGS__)) -#define FORMAT_CASE_ROW(aSrcFormat, aDstFormat, ...) \ - case FORMAT_KEY(aSrcFormat, aDstFormat): \ - return &__VA_ARGS__; - /** * Constexpr functions for analyzing format attributes in templates. */ @@ -118,15 +114,6 @@ void Premultiply_SSE2(const uint8_t*, int32_t, uint8_t*, int32_t, IntSize); Premultiply_SSE2) -template -void PremultiplyRow_SSE2(const uint8_t*, uint8_t*, int32_t); - -# define PREMULTIPLY_ROW_SSE2(aSrcFormat, aDstFormat) \ - FORMAT_CASE_ROW( \ - aSrcFormat, aDstFormat, \ - PremultiplyRow_SSE2) - template void Unpremultiply_SSE2(const uint8_t*, int32_t, uint8_t*, int32_t, IntSize); @@ -142,29 +129,6 @@ void Swizzle_SSE2(const uint8_t*, int32_t, uint8_t*, int32_t, IntSize); Swizzle_SSE2) -template -void SwizzleRow_SSE2(const uint8_t*, uint8_t*, int32_t); - -# define SWIZZLE_ROW_SSE2(aSrcFormat, aDstFormat) \ - FORMAT_CASE_ROW( \ - aSrcFormat, aDstFormat, \ - SwizzleRow_SSE2) - -template -void UnpackRowRGB24_SSSE3(const uint8_t*, uint8_t*, int32_t); - -#define UNPACK_ROW_RGB_SSSE3(aDstFormat) \ - FORMAT_CASE_ROW(SurfaceFormat::R8G8B8, aDstFormat, \ - UnpackRowRGB24_SSSE3) - -template -void UnpackRowRGB24_AVX2(const uint8_t*, uint8_t*, int32_t); - -#define UNPACK_ROW_RGB_AVX2(aDstFormat) \ - FORMAT_CASE_ROW(SurfaceFormat::R8G8B8, aDstFormat, \ - UnpackRowRGB24_AVX2) - #endif #ifdef USE_NEON @@ -180,15 +144,6 @@ void Premultiply_NEON(const uint8_t*, int32_t, uint8_t*, int32_t, IntSize); Premultiply_NEON) -template -void PremultiplyRow_NEON(const uint8_t*, uint8_t*, int32_t); - -# define PREMULTIPLY_ROW_NEON(aSrcFormat, aDstFormat) \ - FORMAT_CASE_ROW( \ - aSrcFormat, aDstFormat, \ - PremultiplyRow_NEON) - template void Unpremultiply_NEON(const uint8_t*, int32_t, uint8_t*, int32_t, IntSize); @@ -204,14 +159,6 @@ void Swizzle_NEON(const uint8_t*, int32_t, uint8_t*, int32_t, IntSize); Swizzle_NEON) -template -void SwizzleRow_NEON(const uint8_t*, uint8_t*, int32_t); - -# define SWIZZLE_ROW_NEON(aSrcFormat, aDstFormat) \ - FORMAT_CASE_ROW( \ - aSrcFormat, aDstFormat, \ - SwizzleRow_NEON) #endif /** @@ -224,65 +171,51 @@ void SwizzleRow_NEON(const uint8_t*, uint8_t*, int32_t); // 2-component vectors. Otherwise, an approximation if divide-by-255 is used // which is faster than an actual division. These optimizations are also used // for the SSE2 and NEON implementations. -template -static void PremultiplyChunkFallback(const uint8_t*& aSrc, uint8_t*& aDst, - int32_t aLength) { - const uint8_t* end = aSrc + 4 * aLength; - do { - // Load and process 1 entire pixel at a time. - uint32_t color = *reinterpret_cast(aSrc); - - uint32_t a = aSrcAShift ? color >> aSrcAShift : color & 0xFF; - - // Isolate the R and B components. - uint32_t rb = (color >> aSrcRGBShift) & 0x00FF00FF; - // Swap the order of R and B if necessary. - if (aSwapRB) { - rb = (rb >> 16) | (rb << 16); - } - // Approximate the multiply by alpha and divide by 255 which is - // essentially: - // c = c*a + 255; c = (c + (c >> 8)) >> 8; - // However, we omit the final >> 8 to fold it with the final shift into - // place depending on desired output format. - rb = rb * a + 0x00FF00FF; - rb = (rb + ((rb >> 8) & 0x00FF00FF)) & 0xFF00FF00; - - // Use same approximation as above, but G is shifted 8 bits left. - // Alpha is left out and handled separately. - uint32_t g = color & (0xFF00 << aSrcRGBShift); - g = g * a + (0xFF00 << aSrcRGBShift); - g = (g + (g >> 8)) & (0xFF0000 << aSrcRGBShift); - - // The above math leaves RGB shifted left by 8 bits. - // Shift them right if required for the output format. - // then combine them back together to produce output pixel. - // Add the alpha back on if the output format is not opaque. - *reinterpret_cast(aDst) = - (rb >> (8 - aDstRGBShift)) | (g >> (8 + aSrcRGBShift - aDstRGBShift)) | - (aOpaqueAlpha ? 0xFF << aDstAShift : a << aDstAShift); - - aSrc += 4; - aDst += 4; - } while (aSrc < end); -} - -template -static void PremultiplyRowFallback(const uint8_t* aSrc, uint8_t* aDst, - int32_t aLength) { - PremultiplyChunkFallback(aSrc, aDst, aLength); -} - template static void PremultiplyFallback(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst, int32_t aDstGap, IntSize aSize) { for (int32_t height = aSize.height; height > 0; height--) { - PremultiplyChunkFallback(aSrc, aDst, aSize.width); + const uint8_t* end = aSrc + 4 * aSize.width; + do { + // Load and process 1 entire pixel at a time. + uint32_t color = *reinterpret_cast(aSrc); + + uint32_t a = aSrcAShift ? color >> aSrcAShift : color & 0xFF; + + // Isolate the R and B components. + uint32_t rb = (color >> aSrcRGBShift) & 0x00FF00FF; + // Swap the order of R and B if necessary. + if (aSwapRB) { + rb = (rb >> 16) | (rb << 16); + } + // Approximate the multiply by alpha and divide by 255 which is + // essentially: + // c = c*a + 255; c = (c + (c >> 8)) >> 8; + // However, we omit the final >> 8 to fold it with the final shift into + // place depending on desired output format. + rb = rb * a + 0x00FF00FF; + rb = (rb + ((rb >> 8) & 0x00FF00FF)) & 0xFF00FF00; + + // Use same approximation as above, but G is shifted 8 bits left. + // Alpha is left out and handled separately. + uint32_t g = color & (0xFF00 << aSrcRGBShift); + g = g * a + (0xFF00 << aSrcRGBShift); + g = (g + (g >> 8)) & (0xFF0000 << aSrcRGBShift); + + // The above math leaves RGB shifted left by 8 bits. + // Shift them right if required for the output format. + // then combine them back together to produce output pixel. + // Add the alpha back on if the output format is not opaque. + *reinterpret_cast(aDst) = + (rb >> (8 - aDstRGBShift)) | + (g >> (8 + aSrcRGBShift - aDstRGBShift)) | + (aOpaqueAlpha ? 0xFF << aDstAShift : a << aDstAShift); + + aSrc += 4; + aDst += 4; + } while (aSrc < end); + aSrc += aSrcGap; aDst += aDstGap; } @@ -304,22 +237,6 @@ static void PremultiplyFallback(const uint8_t* aSrc, int32_t aSrcGap, PREMULTIPLY_FALLBACK_CASE(aSrcFormat, SurfaceFormat::A8R8G8B8) \ PREMULTIPLY_FALLBACK_CASE(aSrcFormat, SurfaceFormat::X8R8G8B8) -#define PREMULTIPLY_ROW_FALLBACK_CASE(aSrcFormat, aDstFormat) \ - FORMAT_CASE_ROW(aSrcFormat, aDstFormat, \ - PremultiplyRowFallback< \ - ShouldSwapRB(aSrcFormat, aDstFormat), \ - ShouldForceOpaque(aSrcFormat, aDstFormat), \ - RGBBitShift(aSrcFormat), AlphaBitShift(aSrcFormat), \ - RGBBitShift(aDstFormat), AlphaBitShift(aDstFormat)>) - -#define PREMULTIPLY_ROW_FALLBACK(aSrcFormat) \ - PREMULTIPLY_ROW_FALLBACK_CASE(aSrcFormat, SurfaceFormat::B8G8R8A8) \ - PREMULTIPLY_ROW_FALLBACK_CASE(aSrcFormat, SurfaceFormat::B8G8R8X8) \ - PREMULTIPLY_ROW_FALLBACK_CASE(aSrcFormat, SurfaceFormat::R8G8B8A8) \ - PREMULTIPLY_ROW_FALLBACK_CASE(aSrcFormat, SurfaceFormat::R8G8B8X8) \ - PREMULTIPLY_ROW_FALLBACK_CASE(aSrcFormat, SurfaceFormat::A8R8G8B8) \ - PREMULTIPLY_ROW_FALLBACK_CASE(aSrcFormat, SurfaceFormat::X8R8G8B8) - // If rows are tightly packed, and the size of the total area will fit within // the precision range of a single row, then process all the data as if it was // a single row. @@ -406,50 +323,6 @@ bool PremultiplyData(const uint8_t* aSrc, int32_t aSrcStride, return false; } -SwizzleRowFn PremultiplyRow(SurfaceFormat aSrcFormat, - SurfaceFormat aDstFormat) { -#ifdef USE_SSE2 - if (mozilla::supports_sse2()) switch (FORMAT_KEY(aSrcFormat, aDstFormat)) { - PREMULTIPLY_ROW_SSE2(SurfaceFormat::B8G8R8A8, SurfaceFormat::B8G8R8A8) - PREMULTIPLY_ROW_SSE2(SurfaceFormat::B8G8R8A8, SurfaceFormat::B8G8R8X8) - PREMULTIPLY_ROW_SSE2(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8A8) - PREMULTIPLY_ROW_SSE2(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8X8) - PREMULTIPLY_ROW_SSE2(SurfaceFormat::R8G8B8A8, SurfaceFormat::R8G8B8A8) - PREMULTIPLY_ROW_SSE2(SurfaceFormat::R8G8B8A8, SurfaceFormat::R8G8B8X8) - PREMULTIPLY_ROW_SSE2(SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8A8) - PREMULTIPLY_ROW_SSE2(SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8X8) - default: - break; - } -#endif - -#ifdef USE_NEON - if (mozilla::supports_neon()) switch (FORMAT_KEY(aSrcFormat, aDstFormat)) { - PREMULTIPLY_ROW_NEON(SurfaceFormat::B8G8R8A8, SurfaceFormat::B8G8R8A8) - PREMULTIPLY_ROW_NEON(SurfaceFormat::B8G8R8A8, SurfaceFormat::B8G8R8X8) - PREMULTIPLY_ROW_NEON(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8A8) - PREMULTIPLY_ROW_NEON(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8X8) - PREMULTIPLY_ROW_NEON(SurfaceFormat::R8G8B8A8, SurfaceFormat::R8G8B8A8) - PREMULTIPLY_ROW_NEON(SurfaceFormat::R8G8B8A8, SurfaceFormat::R8G8B8X8) - PREMULTIPLY_ROW_NEON(SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8A8) - PREMULTIPLY_ROW_NEON(SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8X8) - default: - break; - } -#endif - - switch (FORMAT_KEY(aSrcFormat, aDstFormat)) { - PREMULTIPLY_ROW_FALLBACK(SurfaceFormat::B8G8R8A8) - PREMULTIPLY_ROW_FALLBACK(SurfaceFormat::R8G8B8A8) - PREMULTIPLY_ROW_FALLBACK(SurfaceFormat::A8R8G8B8) - default: - break; - } - - MOZ_ASSERT_UNREACHABLE("Unsupported premultiply formats"); - return nullptr; -} - /** * Unpremultiplying */ @@ -584,54 +457,39 @@ bool UnpremultiplyData(const uint8_t* aSrc, int32_t aSrcStride, // Fallback swizzle implementation that uses shifting and masking to reorder // pixels. -template -static void SwizzleChunkFallback(const uint8_t*& aSrc, uint8_t*& aDst, - int32_t aLength) { - const uint8_t* end = aSrc + 4 * aLength; - do { - uint32_t rgba = *reinterpret_cast(aSrc); - - if (aSwapRB) { - // Handle R and B swaps by exchanging words and masking. - uint32_t rb = - ((rgba << 16) | (rgba >> 16)) & (0x00FF00FF << aSrcRGBShift); - uint32_t ga = rgba & ((0xFF << aSrcAShift) | (0xFF00 << aSrcRGBShift)); - rgba = rb | ga; - } - - // If src and dst shifts differ, rotate left or right to move RGB into - // place, i.e. ARGB -> RGBA or ARGB -> RGBA. - if (aDstRGBShift > aSrcRGBShift) { - rgba = (rgba << 8) | (aOpaqueAlpha ? 0x000000FF : rgba >> 24); - } else if (aSrcRGBShift > aDstRGBShift) { - rgba = (rgba >> 8) | (aOpaqueAlpha ? 0xFF000000 : rgba << 24); - } else if (aOpaqueAlpha) { - rgba |= 0xFF << aDstAShift; - } - - *reinterpret_cast(aDst) = rgba; - - aSrc += 4; - aDst += 4; - } while (aSrc < end); -} - -template -static void SwizzleRowFallback(const uint8_t* aSrc, uint8_t* aDst, - int32_t aLength) { - SwizzleChunkFallback(aSrc, aDst, aLength); -} - template static void SwizzleFallback(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst, int32_t aDstGap, IntSize aSize) { for (int32_t height = aSize.height; height > 0; height--) { - SwizzleChunkFallback(aSrc, aDst, aSize.width); + const uint8_t* end = aSrc + 4 * aSize.width; + do { + uint32_t rgba = *reinterpret_cast(aSrc); + + if (aSwapRB) { + // Handle R and B swaps by exchanging words and masking. + uint32_t rb = + ((rgba << 16) | (rgba >> 16)) & (0x00FF00FF << aSrcRGBShift); + uint32_t ga = rgba & ((0xFF << aSrcAShift) | (0xFF00 << aSrcRGBShift)); + rgba = rb | ga; + } + + // If src and dst shifts differ, rotate left or right to move RGB into + // place, i.e. ARGB -> RGBA or ARGB -> RGBA. + if (aDstRGBShift > aSrcRGBShift) { + rgba = (rgba << 8) | (aOpaqueAlpha ? 0x000000FF : rgba >> 24); + } else if (aSrcRGBShift > aDstRGBShift) { + rgba = (rgba >> 8) | (aOpaqueAlpha ? 0xFF000000 : rgba << 24); + } else if (aOpaqueAlpha) { + rgba |= 0xFF << aDstAShift; + } + + *reinterpret_cast(aDst) = rgba; + + aSrc += 4; + aDst += 4; + } while (aSrc < end); + aSrc += aSrcGap; aDst += aDstGap; } @@ -645,14 +503,6 @@ static void SwizzleFallback(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst, RGBBitShift(aSrcFormat), AlphaBitShift(aSrcFormat), \ RGBBitShift(aDstFormat), AlphaBitShift(aDstFormat)>) -#define SWIZZLE_ROW_FALLBACK(aSrcFormat, aDstFormat) \ - FORMAT_CASE_ROW( \ - aSrcFormat, aDstFormat, \ - SwizzleRowFallback) - // Fast-path for matching formats. static void SwizzleCopy(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst, int32_t aDstGap, IntSize aSize, int32_t aBPP) { @@ -667,39 +517,26 @@ static void SwizzleCopy(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst, } // Fast-path for conversions that swap all bytes. -template -static void SwizzleChunkSwap(const uint8_t*& aSrc, uint8_t*& aDst, - int32_t aLength) { - const uint8_t* end = aSrc + 4 * aLength; - do { - // Use an endian swap to move the bytes, i.e. BGRA -> ARGB. - uint32_t rgba = *reinterpret_cast(aSrc); -#if MOZ_LITTLE_ENDIAN - rgba = NativeEndian::swapToBigEndian(rgba); -#else - rgba = NativeEndian::swapToLittleEndian(rgba); -#endif - if (aOpaqueAlpha) { - rgba |= 0xFF << aDstAShift; - } - *reinterpret_cast(aDst) = rgba; - aSrc += 4; - aDst += 4; - } while (aSrc < end); -} - -template -static void SwizzleRowSwap(const uint8_t* aSrc, uint8_t* aDst, - int32_t aLength) { - SwizzleChunkSwap(aSrc, aDst, aLength); -} - template static void SwizzleSwap(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst, int32_t aDstGap, IntSize aSize) { for (int32_t height = aSize.height; height > 0; height--) { - SwizzleChunkSwap(aSrc, aDst, - aSize.width); + const uint8_t* end = aSrc + 4 * aSize.width; + do { + // Use an endian swap to move the bytes, i.e. BGRA -> ARGB. + uint32_t rgba = *reinterpret_cast(aSrc); +#if MOZ_LITTLE_ENDIAN + rgba = NativeEndian::swapToBigEndian(rgba); +#else + rgba = NativeEndian::swapToLittleEndian(rgba); +#endif + if (aOpaqueAlpha) { + rgba |= 0xFF << aDstAShift; + } + *reinterpret_cast(aDst) = rgba; + aSrc += 4; + aDst += 4; + } while (aSrc < end); aSrc += aSrcGap; aDst += aDstGap; } @@ -711,61 +548,34 @@ static void SwizzleSwap(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst, SwizzleSwap) -#define SWIZZLE_ROW_SWAP(aSrcFormat, aDstFormat) \ - FORMAT_CASE_ROW( \ - aSrcFormat, aDstFormat, \ - SwizzleRowSwap) - // Fast-path for conversions that force alpha to opaque. -template -static void SwizzleChunkOpaqueUpdate(uint8_t*& aBuffer, int32_t aLength) { - const uint8_t* end = aBuffer + 4 * aLength; - do { - uint32_t rgba = *reinterpret_cast(aBuffer); - // Just add on the alpha bits to the source. - rgba |= 0xFF << aDstAShift; - *reinterpret_cast(aBuffer) = rgba; - aBuffer += 4; - } while (aBuffer < end); -} - -template -static void SwizzleChunkOpaqueCopy(const uint8_t*& aSrc, uint8_t* aDst, - int32_t aLength) { - const uint8_t* end = aSrc + 4 * aLength; - do { - uint32_t rgba = *reinterpret_cast(aSrc); - // Just add on the alpha bits to the source. - rgba |= 0xFF << aDstAShift; - *reinterpret_cast(aDst) = rgba; - aSrc += 4; - aDst += 4; - } while (aSrc < end); -} - -template -static void SwizzleRowOpaque(const uint8_t* aSrc, uint8_t* aDst, - int32_t aLength) { - if (aSrc == aDst) { - SwizzleChunkOpaqueUpdate(aDst, aLength); - } else { - SwizzleChunkOpaqueCopy(aSrc, aDst, aLength); - } -} - template static void SwizzleOpaque(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst, int32_t aDstGap, IntSize aSize) { if (aSrc == aDst) { // Modifying in-place, so just write out the alpha. for (int32_t height = aSize.height; height > 0; height--) { - SwizzleChunkOpaqueUpdate(aDst, aSize.width); + const uint8_t* end = aDst + 4 * aSize.width; + do { + // ORing directly onto destination memory profiles faster than writing + // individually to the alpha byte and also profiles equivalently to a + // SSE2 implementation. + *reinterpret_cast(aDst) |= 0xFF << aDstAShift; + aDst += 4; + } while (aDst < end); aDst += aDstGap; } } else { for (int32_t height = aSize.height; height > 0; height--) { - SwizzleChunkOpaqueCopy(aSrc, aDst, aSize.width); + const uint8_t* end = aSrc + 4 * aSize.width; + do { + uint32_t rgba = *reinterpret_cast(aSrc); + // Just add on the alpha bits to the source. + rgba |= 0xFF << aDstAShift; + *reinterpret_cast(aDst) = rgba; + aSrc += 4; + aDst += 4; + } while (aSrc < end); aSrc += aSrcGap; aDst += aDstGap; } @@ -775,10 +585,6 @@ static void SwizzleOpaque(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst, #define SWIZZLE_OPAQUE(aSrcFormat, aDstFormat) \ FORMAT_CASE(aSrcFormat, aDstFormat, SwizzleOpaque) -#define SWIZZLE_ROW_OPAQUE(aSrcFormat, aDstFormat) \ - FORMAT_CASE_ROW(aSrcFormat, aDstFormat, \ - SwizzleRowOpaque) - // Packing of 32-bit formats to RGB565. template static void PackToRGB565(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst, @@ -872,31 +678,6 @@ static void PackToA8(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst, PACK_ALPHA_CASE(SurfaceFormat::R8G8B8A8, aDstFormat, aPackFunc) \ PACK_ALPHA_CASE(SurfaceFormat::A8R8G8B8, aDstFormat, aPackFunc) -template -void UnpackRowRGB24(const uint8_t* aSrc, uint8_t* aDst, int32_t aLength) { - // Because we are expanding, we can only process the data back to front in - // case we are performing this in place. - const uint8_t* src = aSrc + 3 * (aLength - 1); - uint8_t* dst = aDst + 4 * (aLength - 1); - while (src >= aSrc) { - uint8_t r = src[aSwapRB ? 2 : 0]; - uint8_t g = src[1]; - uint8_t b = src[aSwapRB ? 0 : 2]; - - dst[0] = r; - dst[1] = g; - dst[2] = b; - dst[3] = 0xFF; - - src -= 3; - dst -= 4; - } -} - -#define UNPACK_ROW_RGB(aDstFormat) \ - FORMAT_CASE_ROW(SurfaceFormat::R8G8B8, aDstFormat, \ - UnpackRowRGB24) - bool SwizzleData(const uint8_t* aSrc, int32_t aSrcStride, SurfaceFormat aSrcFormat, uint8_t* aDst, int32_t aDstStride, SurfaceFormat aDstFormat, const IntSize& aSize) { @@ -999,83 +780,5 @@ bool SwizzleData(const uint8_t* aSrc, int32_t aSrcStride, return false; } -SwizzleRowFn SwizzleRow(SurfaceFormat aSrcFormat, SurfaceFormat aDstFormat) { -#ifdef USE_SSE2 - if (mozilla::supports_avx2()) switch (FORMAT_KEY(aSrcFormat, aDstFormat)) { - UNPACK_ROW_RGB_AVX2(SurfaceFormat::R8G8B8X8) - UNPACK_ROW_RGB_AVX2(SurfaceFormat::R8G8B8A8) - UNPACK_ROW_RGB_AVX2(SurfaceFormat::B8G8R8X8) - UNPACK_ROW_RGB_AVX2(SurfaceFormat::B8G8R8A8) - default: - break; - } - - if (mozilla::supports_ssse3()) switch (FORMAT_KEY(aSrcFormat, aDstFormat)) { - UNPACK_ROW_RGB_SSSE3(SurfaceFormat::R8G8B8X8) - UNPACK_ROW_RGB_SSSE3(SurfaceFormat::R8G8B8A8) - UNPACK_ROW_RGB_SSSE3(SurfaceFormat::B8G8R8X8) - UNPACK_ROW_RGB_SSSE3(SurfaceFormat::B8G8R8A8) - default: - break; - } - - if (mozilla::supports_sse2()) switch (FORMAT_KEY(aSrcFormat, aDstFormat)) { - SWIZZLE_ROW_SSE2(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8A8) - SWIZZLE_ROW_SSE2(SurfaceFormat::B8G8R8X8, SurfaceFormat::R8G8B8X8) - SWIZZLE_ROW_SSE2(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8X8) - SWIZZLE_ROW_SSE2(SurfaceFormat::B8G8R8X8, SurfaceFormat::R8G8B8A8) - SWIZZLE_ROW_SSE2(SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8A8) - SWIZZLE_ROW_SSE2(SurfaceFormat::R8G8B8X8, SurfaceFormat::B8G8R8X8) - SWIZZLE_ROW_SSE2(SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8X8) - SWIZZLE_ROW_SSE2(SurfaceFormat::R8G8B8X8, SurfaceFormat::B8G8R8A8) - default: - break; - } -#endif - -#ifdef USE_NEON - if (mozilla::supports_neon()) switch (FORMAT_KEY(aSrcFormat, aDstFormat)) { - SWIZZLE_ROW_NEON(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8A8) - SWIZZLE_ROW_NEON(SurfaceFormat::B8G8R8X8, SurfaceFormat::R8G8B8X8) - SWIZZLE_ROW_NEON(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8X8) - SWIZZLE_ROW_NEON(SurfaceFormat::B8G8R8X8, SurfaceFormat::R8G8B8A8) - SWIZZLE_ROW_NEON(SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8A8) - SWIZZLE_ROW_NEON(SurfaceFormat::R8G8B8X8, SurfaceFormat::B8G8R8X8) - SWIZZLE_ROW_NEON(SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8X8) - SWIZZLE_ROW_NEON(SurfaceFormat::R8G8B8X8, SurfaceFormat::B8G8R8A8) - default: - break; - } -#endif - - switch (FORMAT_KEY(aSrcFormat, aDstFormat)) { - SWIZZLE_ROW_FALLBACK(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8A8) - SWIZZLE_ROW_FALLBACK(SurfaceFormat::B8G8R8X8, SurfaceFormat::R8G8B8X8) - SWIZZLE_ROW_FALLBACK(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8X8) - SWIZZLE_ROW_FALLBACK(SurfaceFormat::B8G8R8X8, SurfaceFormat::R8G8B8A8) - - SWIZZLE_ROW_FALLBACK(SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8A8) - SWIZZLE_ROW_FALLBACK(SurfaceFormat::R8G8B8X8, SurfaceFormat::B8G8R8X8) - SWIZZLE_ROW_FALLBACK(SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8X8) - SWIZZLE_ROW_FALLBACK(SurfaceFormat::R8G8B8X8, SurfaceFormat::B8G8R8A8) - - SWIZZLE_ROW_OPAQUE(SurfaceFormat::B8G8R8A8, SurfaceFormat::B8G8R8X8) - SWIZZLE_ROW_OPAQUE(SurfaceFormat::B8G8R8X8, SurfaceFormat::B8G8R8A8) - SWIZZLE_ROW_OPAQUE(SurfaceFormat::R8G8B8A8, SurfaceFormat::R8G8B8X8) - SWIZZLE_ROW_OPAQUE(SurfaceFormat::R8G8B8X8, SurfaceFormat::R8G8B8A8) - - UNPACK_ROW_RGB(SurfaceFormat::R8G8B8X8) - UNPACK_ROW_RGB(SurfaceFormat::R8G8B8A8) - UNPACK_ROW_RGB(SurfaceFormat::B8G8R8X8) - UNPACK_ROW_RGB(SurfaceFormat::B8G8R8A8) - - default: - break; - } - - MOZ_ASSERT_UNREACHABLE("Unsupported swizzle formats"); - return nullptr; -} - } // namespace gfx } // namespace mozilla diff --git a/gfx/2d/Swizzle.h b/gfx/2d/Swizzle.h index 44b4073ee66f..a52471d5d66e 100644 --- a/gfx/2d/Swizzle.h +++ b/gfx/2d/Swizzle.h @@ -41,22 +41,6 @@ GFX2D_API bool SwizzleData(const uint8_t* aSrc, int32_t aSrcStride, int32_t aDstStride, SurfaceFormat aDstFormat, const IntSize& aSize); -/** - * Swizzles source and writes it to destination. Source and destination may be - * the same to swizzle in-place. - */ -typedef void (*SwizzleRowFn)(const uint8_t* aSrc, uint8_t* aDst, int32_t aLength); - -/** - * Get a function pointer to perform premultiplication between two formats. - */ -GFX2D_API SwizzleRowFn PremultiplyRow(SurfaceFormat aSrcFormat, SurfaceFormat aDstFormat); - -/** - * Get a function pointer to perform swizzling between two formats. - */ -GFX2D_API SwizzleRowFn SwizzleRow(SurfaceFormat aSrcFormat, SurfaceFormat aDstFormat); - } // namespace gfx } // namespace mozilla diff --git a/gfx/2d/SwizzleAVX2.cpp b/gfx/2d/SwizzleAVX2.cpp deleted file mode 100644 index 177124d8a988..000000000000 --- a/gfx/2d/SwizzleAVX2.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "Swizzle.h" - -#include -#include - -namespace mozilla { -namespace gfx { - -template -void UnpackRowRGB24_SSSE3(const uint8_t*, uint8_t*, int32_t); - -template -void UnpackRowRGB24_AVX2(const uint8_t* aSrc, uint8_t* aDst, int32_t aLength) { - // Because this implementation will read an additional 8 bytes of data that - // is ignored and masked over, we cannot use the accelerated version for the - // last 1-8 bytes to guarantee we don't access memory outside the buffer. - if (aLength < 9) { - UnpackRowRGB24_SSSE3(aSrc, aDst, aLength); - return; - } - - // Because we are expanding, we can only process the data back to front in - // case we are performing this in place. - int32_t alignedRow = (aLength - 1) & ~7; - int32_t remainder = aLength - alignedRow; - - const uint8_t* src = aSrc + alignedRow * 3; - uint8_t* dst = aDst + alignedRow * 4; - - // Handle any 1-8 remaining pixels. - UnpackRowRGB24_SSSE3(src, dst, remainder); - - // Used to shuffle the two final 32-bit words which we ignore into the last - // 32-bit word of each 128-bit lane, such that - // RGBR GBRG BRGB RGBR GBRG BRGB RGBR GBRG - // BRGB RGBR GBRG BRGB ZZZZ ZZZZ ZZZZ ZZZZ - // becomes - // RGBR GBRG BRGB RGBR GBRG BRGB ZZZZ ZZZZ - // RGBR GBRG BRGB RGBR GBRG BRGB ZZZZ ZZZZ - const __m256i discardMask = _mm256_set_epi32(7, 5, 4, 3, 6, 2, 1, 0); - - // Used to shuffle 8-bit words within a 128-bit lane, such that we transform - // RGBR GBRG BRGB RGBR GBRG BRGB ZZZZ ZZZZ - // into - // RGBZ RGBZ RGBZ RGBZ RGBZ RGBZ RGBZ RGBZ - // or - // BGRZ BGRZ BGRZ BGRZ BGRZ BGRZ BGRZ BGRZ - const __m256i colorMask = - aSwapRB ? _mm256_set_epi8(15, 9, 10, 11, 14, 6, 7, 8, 13, 3, 4, 5, 12, 0, - 1, 2, 15, 9, 10, 11, 14, 6, 7, 8, 13, 3, 4, 5, - 12, 0, 1, 2) - : _mm256_set_epi8(15, 11, 10, 9, 14, 8, 7, 6, 13, 5, 4, 3, 12, 2, - 1, 0, 15, 11, 10, 9, 14, 8, 7, 6, 13, 5, 4, 3, - 12, 2, 1, 0); - - // Used to transform RGBZ/BGRZ to RGBX/BGRX, or force the alpha opaque. - const __m256i alphaMask = _mm256_set1_epi32(0xFF000000); - - // Process all 8-pixel chunks as one vector. - src -= 8 * 3; - dst -= 8 * 4; - while (src >= aSrc) { - __m256i px = _mm256_loadu_si256(reinterpret_cast(src)); - px = _mm256_permutevar8x32_epi32(px, discardMask); - px = _mm256_shuffle_epi8(px, colorMask); - px = _mm256_or_si256(px, alphaMask); - _mm256_storeu_si256(reinterpret_cast<__m256i*>(dst), px); - src -= 8 * 3; - dst -= 8 * 4; - } -} - -// Force instantiation of swizzle variants here. -template void UnpackRowRGB24_AVX2(const uint8_t*, uint8_t*, int32_t); -template void UnpackRowRGB24_AVX2(const uint8_t*, uint8_t*, int32_t); - -} // namespace gfx -} // namespace mozilla diff --git a/gfx/2d/SwizzleNEON.cpp b/gfx/2d/SwizzleNEON.cpp index 5e56a5ffe834..0926e6b4f71c 100644 --- a/gfx/2d/SwizzleNEON.cpp +++ b/gfx/2d/SwizzleNEON.cpp @@ -85,36 +85,6 @@ PremultiplyVector_NEON(const uint16x8_t& aSrc) { return vsriq_n_u16(ga, rb, 8); } -template -static MOZ_ALWAYS_INLINE void PremultiplyChunk_NEON(const uint8_t*& aSrc, - uint8_t*& aDst, - int32_t aAlignedRow, - int32_t aRemainder) { - // Process all 4-pixel chunks as one vector. - for (const uint8_t* end = aSrc + aAlignedRow; aSrc < end;) { - uint16x8_t px = vld1q_u16(reinterpret_cast(aSrc)); - px = PremultiplyVector_NEON(px); - vst1q_u16(reinterpret_cast(aDst), px); - aSrc += 4 * 4; - aDst += 4 * 4; - } - - // Handle any 1-3 remaining pixels. - if (aRemainder) { - uint16x8_t px = LoadRemainder_NEON(aSrc, aRemainder); - px = PremultiplyVector_NEON(px); - StoreRemainder_NEON(aDst, aRemainder, px); - } -} - -template -void PremultiplyRow_NEON(const uint8_t* aSrc, uint8_t* aDst, int32_t aLength) { - int32_t alignedRow = 4 * (aLength & ~3); - int32_t remainder = aLength & 3; - PremultiplyChunk_NEON(aSrc, aDst, alignedRow, - remainder); -} - template void Premultiply_NEON(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst, int32_t aDstGap, IntSize aSize) { @@ -125,22 +95,28 @@ void Premultiply_NEON(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst, aDstGap += 4 * remainder; for (int32_t height = aSize.height; height > 0; height--) { - PremultiplyChunk_NEON(aSrc, aDst, alignedRow, - remainder); + // Process all 4-pixel chunks as one vector. + for (const uint8_t* end = aSrc + alignedRow; aSrc < end;) { + uint16x8_t px = vld1q_u16(reinterpret_cast(aSrc)); + px = PremultiplyVector_NEON(px); + vst1q_u16(reinterpret_cast(aDst), px); + aSrc += 4 * 4; + aDst += 4 * 4; + } + + // Handle any 1-3 remaining pixels. + if (remainder) { + uint16x8_t px = LoadRemainder_NEON(aSrc, remainder); + px = PremultiplyVector_NEON(px); + StoreRemainder_NEON(aDst, remainder, px); + } + aSrc += aSrcGap; aDst += aDstGap; } } // Force instantiation of premultiply variants here. -template void PremultiplyRow_NEON(const uint8_t*, uint8_t*, - int32_t); -template void PremultiplyRow_NEON(const uint8_t*, uint8_t*, - int32_t); -template void PremultiplyRow_NEON(const uint8_t*, uint8_t*, - int32_t); -template void PremultiplyRow_NEON(const uint8_t*, uint8_t*, - int32_t); template void Premultiply_NEON(const uint8_t*, int32_t, uint8_t*, int32_t, IntSize); template void Premultiply_NEON(const uint8_t*, int32_t, uint8_t*, @@ -282,7 +258,7 @@ template void Unpremultiply_NEON(const uint8_t*, int32_t, uint8_t*, // Swizzle a vector of 4 pixels providing swaps and opaquifying. template -static MOZ_ALWAYS_INLINE uint16x8_t SwizzleVector_NEON(const uint16x8_t& aSrc) { +MOZ_ALWAYS_INLINE uint16x8_t SwizzleVector_NEON(const uint16x8_t& aSrc) { // Swap R and B, then add to G and A (forced to 255): // (((src>>16) | (src << 16)) & 0x00FF00FF) | // ((src | 0xFF000000) & ~0x00FF00FF) @@ -299,7 +275,7 @@ static MOZ_ALWAYS_INLINE uint16x8_t SwizzleVector_NEON(const uint16x8_t& aSrc) { // Optimized implementations for when there is no R and B swap. template<> -static MOZ_ALWAYS_INLINE uint16x8_t +MOZ_ALWAYS_INLINE uint16x8_t SwizzleVector_NEON(const uint16x8_t& aSrc) { // Force alpha to 255. @@ -307,42 +283,13 @@ SwizzleVector_NEON(const uint16x8_t& aSrc) } template<> -static MOZ_ALWAYS_INLINE uint16x8_t +MOZ_ALWAYS_INLINE uint16x8_t SwizzleVector_NEON(const uint16x8_t& aSrc) { return aSrc; } #endif -template -static MOZ_ALWAYS_INLINE void SwizzleChunk_NEON(const uint8_t*& aSrc, - uint8_t*& aDst, - int32_t aAlignedRow, - int32_t aRemainder) { - // Process all 4-pixel chunks as one vector. - for (const uint8_t* end = aSrc + aAlignedRow; aSrc < end;) { - uint16x8_t px = vld1q_u16(reinterpret_cast(aSrc)); - px = SwizzleVector_NEON(px); - vst1q_u16(reinterpret_cast(aDst), px); - aSrc += 4 * 4; - aDst += 4 * 4; - } - - // Handle any 1-3 remaining pixels. - if (aRemainder) { - uint16x8_t px = LoadRemainder_NEON(aSrc, aRemainder); - px = SwizzleVector_NEON(px); - StoreRemainder_NEON(aDst, aRemainder, px); - } -} - -template -void SwizzleRow_NEON(const uint8_t* aSrc, uint8_t* aDst, int32_t aLength) { - int32_t alignedRow = 4 * (aLength & ~3); - int32_t remainder = aLength & 3; - SwizzleChunk_NEON(aSrc, aDst, alignedRow, remainder); -} - template void Swizzle_NEON(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst, int32_t aDstGap, IntSize aSize) { @@ -353,16 +300,28 @@ void Swizzle_NEON(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst, aDstGap += 4 * remainder; for (int32_t height = aSize.height; height > 0; height--) { - SwizzleChunk_NEON(aSrc, aDst, alignedRow, - remainder); + // Process all 4-pixel chunks as one vector. + for (const uint8_t* end = aSrc + alignedRow; aSrc < end;) { + uint16x8_t px = vld1q_u16(reinterpret_cast(aSrc)); + px = SwizzleVector_NEON(px); + vst1q_u16(reinterpret_cast(aDst), px); + aSrc += 4 * 4; + aDst += 4 * 4; + } + + // Handle any 1-3 remaining pixels. + if (remainder) { + uint16x8_t px = LoadRemainder_NEON(aSrc, remainder); + px = SwizzleVector_NEON(px); + StoreRemainder_NEON(aDst, remainder, px); + } + aSrc += aSrcGap; aDst += aDstGap; } } // Force instantiation of swizzle variants here. -template void SwizzleRow_NEON(const uint8_t*, uint8_t*, int32_t); -template void SwizzleRow_NEON(const uint8_t*, uint8_t*, int32_t); template void Swizzle_NEON(const uint8_t*, int32_t, uint8_t*, int32_t, IntSize); template void Swizzle_NEON(const uint8_t*, int32_t, uint8_t*, diff --git a/gfx/2d/SwizzleSSE2.cpp b/gfx/2d/SwizzleSSE2.cpp index 38e016809531..12d742dd730d 100644 --- a/gfx/2d/SwizzleSSE2.cpp +++ b/gfx/2d/SwizzleSSE2.cpp @@ -88,38 +88,6 @@ static MOZ_ALWAYS_INLINE __m128i PremultiplyVector_SSE2(const __m128i& aSrc) { return _mm_or_si128(rb, ga); } -// Premultiply vector of aAlignedRow + aRemainder pixels. -template -static MOZ_ALWAYS_INLINE void PremultiplyChunk_SSE2(const uint8_t*& aSrc, - uint8_t*& aDst, - int32_t aAlignedRow, - int32_t aRemainder) { - // Process all 4-pixel chunks as one vector. - for (const uint8_t* end = aSrc + aAlignedRow; aSrc < end;) { - __m128i px = _mm_loadu_si128(reinterpret_cast(aSrc)); - px = PremultiplyVector_SSE2(px); - _mm_storeu_si128(reinterpret_cast<__m128i*>(aDst), px); - aSrc += 4 * 4; - aDst += 4 * 4; - } - - // Handle any 1-3 remaining pixels. - if (aRemainder) { - __m128i px = LoadRemainder_SSE2(aSrc, aRemainder); - px = PremultiplyVector_SSE2(px); - StoreRemainder_SSE2(aDst, aRemainder, px); - } -} - -// Premultiply vector of aLength pixels. -template -void PremultiplyRow_SSE2(const uint8_t* aSrc, uint8_t* aDst, int32_t aLength) { - int32_t alignedRow = 4 * (aLength & ~3); - int32_t remainder = aLength & 3; - PremultiplyChunk_SSE2(aSrc, aDst, alignedRow, - remainder); -} - template void Premultiply_SSE2(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst, int32_t aDstGap, IntSize aSize) { @@ -130,22 +98,28 @@ void Premultiply_SSE2(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst, aDstGap += 4 * remainder; for (int32_t height = aSize.height; height > 0; height--) { - PremultiplyChunk_SSE2(aSrc, aDst, alignedRow, - remainder); + // Process all 4-pixel chunks as one vector. + for (const uint8_t* end = aSrc + alignedRow; aSrc < end;) { + __m128i px = _mm_loadu_si128(reinterpret_cast(aSrc)); + px = PremultiplyVector_SSE2(px); + _mm_storeu_si128(reinterpret_cast<__m128i*>(aDst), px); + aSrc += 4 * 4; + aDst += 4 * 4; + } + + // Handle any 1-3 remaining pixels. + if (remainder) { + __m128i px = LoadRemainder_SSE2(aSrc, remainder); + px = PremultiplyVector_SSE2(px); + StoreRemainder_SSE2(aDst, remainder, px); + } + aSrc += aSrcGap; aDst += aDstGap; } } // Force instantiation of premultiply variants here. -template void PremultiplyRow_SSE2(const uint8_t*, uint8_t*, - int32_t); -template void PremultiplyRow_SSE2(const uint8_t*, uint8_t*, - int32_t); -template void PremultiplyRow_SSE2(const uint8_t*, uint8_t*, - int32_t); -template void PremultiplyRow_SSE2(const uint8_t*, uint8_t*, - int32_t); template void Premultiply_SSE2(const uint8_t*, int32_t, uint8_t*, int32_t, IntSize); template void Premultiply_SSE2(const uint8_t*, int32_t, uint8_t*, @@ -319,35 +293,6 @@ SwizzleVector_SSE2(const __m128i& aSrc) } #endif -template -static MOZ_ALWAYS_INLINE void SwizzleChunk_SSE2(const uint8_t*& aSrc, - uint8_t*& aDst, - int32_t aAlignedRow, - int32_t aRemainder) { - // Process all 4-pixel chunks as one vector. - for (const uint8_t* end = aSrc + aAlignedRow; aSrc < end;) { - __m128i px = _mm_loadu_si128(reinterpret_cast(aSrc)); - px = SwizzleVector_SSE2(px); - _mm_storeu_si128(reinterpret_cast<__m128i*>(aDst), px); - aSrc += 4 * 4; - aDst += 4 * 4; - } - - // Handle any 1-3 remaining pixels. - if (aRemainder) { - __m128i px = LoadRemainder_SSE2(aSrc, aRemainder); - px = SwizzleVector_SSE2(px); - StoreRemainder_SSE2(aDst, aRemainder, px); - } -} - -template -void SwizzleRow_SSE2(const uint8_t* aSrc, uint8_t* aDst, int32_t aLength) { - int32_t alignedRow = 4 * (aLength & ~3); - int32_t remainder = aLength & 3; - SwizzleChunk_SSE2(aSrc, aDst, alignedRow, remainder); -} - template void Swizzle_SSE2(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst, int32_t aDstGap, IntSize aSize) { @@ -358,15 +303,28 @@ void Swizzle_SSE2(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst, aDstGap += 4 * remainder; for (int32_t height = aSize.height; height > 0; height--) { - SwizzleChunk_SSE2(aSrc, aDst, alignedRow, remainder); + // Process all 4-pixel chunks as one vector. + for (const uint8_t* end = aSrc + alignedRow; aSrc < end;) { + __m128i px = _mm_loadu_si128(reinterpret_cast(aSrc)); + px = SwizzleVector_SSE2(px); + _mm_storeu_si128(reinterpret_cast<__m128i*>(aDst), px); + aSrc += 4 * 4; + aDst += 4 * 4; + } + + // Handle any 1-3 remaining pixels. + if (remainder) { + __m128i px = LoadRemainder_SSE2(aSrc, remainder); + px = SwizzleVector_SSE2(px); + StoreRemainder_SSE2(aDst, remainder, px); + } + aSrc += aSrcGap; aDst += aDstGap; } } // Force instantiation of swizzle variants here. -template void SwizzleRow_SSE2(const uint8_t*, uint8_t*, int32_t); -template void SwizzleRow_SSE2(const uint8_t*, uint8_t*, int32_t); template void Swizzle_SSE2(const uint8_t*, int32_t, uint8_t*, int32_t, IntSize); template void Swizzle_SSE2(const uint8_t*, int32_t, uint8_t*, diff --git a/gfx/2d/SwizzleSSSE3.cpp b/gfx/2d/SwizzleSSSE3.cpp deleted file mode 100644 index bd0ca3b3b6ba..000000000000 --- a/gfx/2d/SwizzleSSSE3.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "Swizzle.h" - -#include -#include - -namespace mozilla { -namespace gfx { - -template -void UnpackRowRGB24(const uint8_t*, uint8_t*, int32_t); - -template -void UnpackRowRGB24_SSSE3(const uint8_t* aSrc, uint8_t* aDst, int32_t aLength) { - // Because this implementation will read an additional 4 bytes of data that - // is ignored and masked over, we cannot use the accelerated version for the - // last 1-4 bytes to guarantee we don't access memory outside the buffer. - if (aLength < 5) { - UnpackRowRGB24(aSrc, aDst, aLength); - return; - } - - // Because we are expanding, we can only process the data back to front in - // case we are performing this in place. - int32_t alignedRow = (aLength - 1) & ~3; - int32_t remainder = aLength - alignedRow; - - const uint8_t* src = aSrc + alignedRow * 3; - uint8_t* dst = aDst + alignedRow * 4; - - // Handle 1-4 remaining pixels. - UnpackRowRGB24(src, dst, remainder); - - __m128i mask; - if (aSwapRB) { - mask = _mm_set_epi8(15, 9, 10, 11, 14, 6, 7, 8, 13, 3, 4, 5, 12, 0, 1, 2); - } else { - mask = _mm_set_epi8(15, 11, 10, 9, 14, 8, 7, 6, 13, 5, 4, 3, 12, 2, 1, 0); - } - - __m128i alpha = _mm_set1_epi32(0xFF000000); - - // Process all 4-pixel chunks as one vector. - src -= 4 * 3; - dst -= 4 * 4; - while (src >= aSrc) { - __m128i px = _mm_loadu_si128(reinterpret_cast(src)); - px = _mm_shuffle_epi8(px, mask); - px = _mm_or_si128(px, alpha); - _mm_storeu_si128(reinterpret_cast<__m128i*>(dst), px); - src -= 4 * 3; - dst -= 4 * 4; - } -} - -// Force instantiation of swizzle variants here. -template void UnpackRowRGB24_SSSE3(const uint8_t*, uint8_t*, int32_t); -template void UnpackRowRGB24_SSSE3(const uint8_t*, uint8_t*, int32_t); - -} // namespace gfx -} // namespace mozilla diff --git a/gfx/2d/moz.build b/gfx/2d/moz.build index 627cb6172ee6..b9e6e3a7a6a8 100644 --- a/gfx/2d/moz.build +++ b/gfx/2d/moz.build @@ -145,9 +145,7 @@ if CONFIG['INTEL_ARCHITECTURE']: 'FilterProcessingSSE2.cpp', 'ImageScalingSSE2.cpp', 'ssse3-scaler.c', - 'SwizzleAVX2.cpp', 'SwizzleSSE2.cpp', - 'SwizzleSSSE3.cpp', ] DEFINES['USE_SSE2'] = True # The file uses SSE2 intrinsics, so it needs special compile flags on some @@ -155,9 +153,7 @@ if CONFIG['INTEL_ARCHITECTURE']: SOURCES['BlurSSE2.cpp'].flags += CONFIG['SSE2_FLAGS'] SOURCES['FilterProcessingSSE2.cpp'].flags += CONFIG['SSE2_FLAGS'] SOURCES['ImageScalingSSE2.cpp'].flags += CONFIG['SSE2_FLAGS'] - SOURCES['SwizzleAVX2.cpp'].flags += ['-mavx2'] SOURCES['SwizzleSSE2.cpp'].flags += CONFIG['SSE2_FLAGS'] - SOURCES['SwizzleSSSE3.cpp'].flags += CONFIG['SSSE3_FLAGS'] SOURCES['ssse3-scaler.c'].flags += CONFIG['SSSE3_FLAGS'] elif CONFIG['CPU_ARCH'].startswith('mips'): SOURCES += [ diff --git a/gfx/tests/gtest/TestSwizzle.cpp b/gfx/tests/gtest/TestSwizzle.cpp index 778c23872330..de26c558d0b8 100644 --- a/gfx/tests/gtest/TestSwizzle.cpp +++ b/gfx/tests/gtest/TestSwizzle.cpp @@ -45,34 +45,6 @@ TEST(Moz2D, PremultiplyData) EXPECT_TRUE(ArrayEqual(out, check_argb)); } -TEST(Moz2D, PremultiplyRow) -{ - const uint8_t in_bgra[5 * 4] = { - 255, 255, 0, 255, // verify 255 alpha leaves RGB unchanged - 0, 0, 255, 255, - 0, 255, 255, 0, // verify 0 alpha zeroes out RGB - 0, 0, 0, 0, - 255, 0, 0, 128, // verify that 255 RGB maps to alpha - }; - uint8_t out[5 * 4]; - const uint8_t check_bgra[5 * 4] = { - 255, 255, 0, 255, 0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 128, - }; - // check swizzled output - const uint8_t check_rgba[5 * 4] = { - 0, 255, 255, 255, 255, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, - }; - - SwizzleRowFn func = - PremultiplyRow(SurfaceFormat::B8G8R8A8, SurfaceFormat::B8G8R8A8); - func(in_bgra, out, 5); - EXPECT_TRUE(ArrayEqual(out, check_bgra)); - - func = PremultiplyRow(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8A8); - func(in_bgra, out, 5); - EXPECT_TRUE(ArrayEqual(out, check_rgba)); -} - TEST(Moz2D, UnpremultiplyData) { const uint8_t in_bgra[5 * 4] = { @@ -183,68 +155,3 @@ TEST(Moz2D, SwizzleData) SurfaceFormat::R5G6B5_UINT16, IntSize(5, 1)); EXPECT_TRUE(ArrayEqual(out16, check_16)); } - -TEST(Moz2D, SwizzleRow) -{ - const uint8_t in_bgra[5 * 4] = { - 253, 254, 0, 255, 0, 0, 255, 255, 0, 0, 0, 0, 1, 2, 3, 64, 127, 0, 9, 128, - - }; - uint8_t out[5 * 4]; - // check swaps - const uint8_t check_rgba[5 * 4] = { - 0, 254, 253, 255, 255, 0, 0, 255, 0, 0, 0, 0, 3, 2, 1, 64, 9, 0, 127, 128, - }; - // check opaquifying - const uint8_t check_rgbx[5 * 4] = { - 0, 254, 253, 255, 255, 0, 0, 255, 0, 0, - 0, 255, 3, 2, 1, 255, 9, 0, 127, 255, - }; - // check unpacking - uint8_t out_unpack[16 * 4]; - const uint8_t in_rgb[16 * 3] = { - 0, 254, 253, 255, 0, 0, 0, 0, 0, 3, 2, 1, - 9, 0, 127, 4, 5, 6, 9, 8, 7, 10, 11, 12, - 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, - }; - const uint8_t check_unpack_rgbx[16 * 4] = { - 0, 254, 253, 255, 255, 0, 0, 255, 0, 0, 0, 255, 3, 2, 1, 255, - 9, 0, 127, 255, 4, 5, 6, 255, 9, 8, 7, 255, 10, 11, 12, 255, - 13, 14, 15, 255, 16, 17, 18, 255, 19, 20, 21, 255, 22, 23, 24, 255, - 25, 26, 27, 255, 28, 29, 30, 255, 31, 32, 33, 255, 34, 35, 36, 255, - }; - const uint8_t check_unpack_bgrx[16 * 4] = { - 253, 254, 0, 255, 0, 0, 255, 255, 0, 0, 0, 255, 1, 2, 3, 255, - 127, 0, 9, 255, 6, 5, 4, 255, 7, 8, 9, 255, 12, 11, 10, 255, - 15, 14, 13, 255, 18, 17, 16, 255, 21, 20, 19, 255, 24, 23, 22, 255, - 27, 26, 25, 255, 30, 29, 28, 255, 33, 32, 31, 255, 36, 35, 34, 255, - }; - - SwizzleRowFn func = - SwizzleRow(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8A8); - func(in_bgra, out, 5); - EXPECT_TRUE(ArrayEqual(out, check_rgba)); - - func = SwizzleRow(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8X8); - func(in_bgra, out, 5); - EXPECT_TRUE(ArrayEqual(out, check_rgbx)); - - func = SwizzleRow(SurfaceFormat::R8G8B8, SurfaceFormat::B8G8R8X8); - func(in_rgb, out_unpack, 16); - EXPECT_TRUE(ArrayEqual(out_unpack, check_unpack_bgrx)); - - memset(out_unpack, 0xE5, sizeof(out_unpack)); - memcpy(out_unpack, in_rgb, sizeof(in_rgb)); - func(out_unpack, out_unpack, 16); - EXPECT_TRUE(ArrayEqual(out_unpack, check_unpack_bgrx)); - - func = SwizzleRow(SurfaceFormat::R8G8B8, SurfaceFormat::R8G8B8X8); - func(in_rgb, out_unpack, 16); - EXPECT_TRUE(ArrayEqual(out_unpack, check_unpack_rgbx)); - - memset(out_unpack, 0xE5, sizeof(out_unpack)); - memcpy(out_unpack, in_rgb, sizeof(in_rgb)); - func(out_unpack, out_unpack, 16); - EXPECT_TRUE(ArrayEqual(out_unpack, check_unpack_rgbx)); -} diff --git a/image/DownscalingFilter.h b/image/DownscalingFilter.h index 41d796f45057..6a2b93c69d5b 100644 --- a/image/DownscalingFilter.h +++ b/image/DownscalingFilter.h @@ -78,10 +78,6 @@ class DownscalingFilter final : public SurfaceFilter { MOZ_CRASH(); return nullptr; } - uint8_t* DoAdvanceRowFromBuffer(const uint8_t* aInputRow) override { - MOZ_CRASH(); - return nullptr; - } uint8_t* DoAdvanceRow() override { MOZ_CRASH(); return nullptr; @@ -210,7 +206,7 @@ class DownscalingFilter final : public SurfaceFilter { return GetRowPointer(); } - uint8_t* DoAdvanceRowFromBuffer(const uint8_t* aInputRow) override { + uint8_t* DoAdvanceRow() override { if (mInputRow >= mInputSize.height) { NS_WARNING("Advancing DownscalingFilter past the end of the input"); return nullptr; @@ -230,7 +226,7 @@ class DownscalingFilter final : public SurfaceFilter { if (mInputRow == inputRowToRead) { MOZ_RELEASE_ASSERT(mRowsInWindow < mWindowCapacity, "Need more rows than capacity!"); - mXFilter.ConvolveHorizontally(aInputRow, mWindow[mRowsInWindow++], + mXFilter.ConvolveHorizontally(mRowBuffer.get(), mWindow[mRowsInWindow++], mHasAlpha); } @@ -253,10 +249,6 @@ class DownscalingFilter final : public SurfaceFilter { return mInputRow < mInputSize.height ? GetRowPointer() : nullptr; } - uint8_t* DoAdvanceRow() override { - return DoAdvanceRowFromBuffer(mRowBuffer.get()); - } - private: uint8_t* GetRowPointer() const { return mRowBuffer.get(); } diff --git a/image/SurfaceFilters.h b/image/SurfaceFilters.h index b19eba7b6389..a3aff1e6955c 100644 --- a/image/SurfaceFilters.h +++ b/image/SurfaceFilters.h @@ -20,7 +20,6 @@ #include "mozilla/Maybe.h" #include "mozilla/UniquePtr.h" #include "mozilla/gfx/2D.h" -#include "mozilla/gfx/Swizzle.h" #include "skia/src/core/SkBlitRow.h" #include "DownscalingFilter.h" @@ -30,83 +29,6 @@ namespace mozilla { namespace image { -////////////////////////////////////////////////////////////////////////////// -// SwizzleFilter -////////////////////////////////////////////////////////////////////////////// - -template -class SwizzleFilter; - -/** - * A configuration struct for SwizzleFilter. - */ -struct SwizzleConfig { - template - using Filter = SwizzleFilter; - gfx::SurfaceFormat mInFormat; - gfx::SurfaceFormat mOutFormat; - bool mPremultiplyAlpha; -}; - -/** - * SwizzleFilter performs premultiplication, swizzling and unpacking on - * rows written to it. It can use accelerated methods to perform these - * operations if supported on the platform. - * - * The 'Next' template parameter specifies the next filter in the chain. - */ -template -class SwizzleFilter final : public SurfaceFilter { - public: - SwizzleFilter() : mSwizzleFn(nullptr) {} - - template - nsresult Configure(const SwizzleConfig& aConfig, const Rest&... aRest) { - nsresult rv = mNext.Configure(aRest...); - if (NS_FAILED(rv)) { - return rv; - } - - if (aConfig.mPremultiplyAlpha) { - mSwizzleFn = gfx::PremultiplyRow(aConfig.mInFormat, aConfig.mOutFormat); - } else { - mSwizzleFn = gfx::SwizzleRow(aConfig.mInFormat, aConfig.mOutFormat); - } - - if (!mSwizzleFn) { - return NS_ERROR_INVALID_ARG; - } - - ConfigureFilter(mNext.InputSize(), sizeof(uint32_t)); - return NS_OK; - } - - Maybe TakeInvalidRect() override { - return mNext.TakeInvalidRect(); - } - - protected: - uint8_t* DoResetToFirstRow() override { return mNext.ResetToFirstRow(); } - - uint8_t* DoAdvanceRowFromBuffer(const uint8_t* aInputRow) override { - uint8_t* rowPtr = mNext.CurrentRowPointer(); - if (!rowPtr) { - return nullptr; // We already got all the input rows we expect. - } - - mSwizzleFn(aInputRow, rowPtr, mNext.InputSize().width); - return mNext.AdvanceRow(); - } - - uint8_t* DoAdvanceRow() override { - return DoAdvanceRowFromBuffer(mNext.CurrentRowPointer()); - } - - Next mNext; /// The next SurfaceFilter in the chain. - - gfx::SwizzleRowFn mSwizzleFn; -}; - ////////////////////////////////////////////////////////////////////////////// // ColorManagementFilter ////////////////////////////////////////////////////////////////////////////// @@ -158,14 +80,10 @@ class ColorManagementFilter final : public SurfaceFilter { protected: uint8_t* DoResetToFirstRow() override { return mNext.ResetToFirstRow(); } - uint8_t* DoAdvanceRowFromBuffer(const uint8_t* aInputRow) override { - qcms_transform_data(mTransform, aInputRow, mNext.CurrentRowPointer(), - mNext.InputSize().width); - return mNext.AdvanceRow(); - } - uint8_t* DoAdvanceRow() override { - return DoAdvanceRowFromBuffer(mNext.CurrentRowPointer()); + uint8_t* rowPtr = mNext.CurrentRowPointer(); + qcms_transform_data(mTransform, rowPtr, rowPtr, mNext.InputSize().width); + return mNext.AdvanceRow(); } Next mNext; /// The next SurfaceFilter in the chain. @@ -264,11 +182,6 @@ class DeinterlacingFilter final : public SurfaceFilter { return GetRowPointer(mOutputRow); } - uint8_t* DoAdvanceRowFromBuffer(const uint8_t* aInputRow) override { - CopyInputRow(aInputRow); - return DoAdvanceRow(); - } - uint8_t* DoAdvanceRow() override { if (mPass >= 4) { return nullptr; // We already finished all passes. @@ -725,11 +638,6 @@ class BlendAnimationFilter final : public SurfaceFilter { return nullptr; // We're done. } - uint8_t* DoAdvanceRowFromBuffer(const uint8_t* aInputRow) override { - CopyInputRow(aInputRow); - return DoAdvanceRow(); - } - uint8_t* DoAdvanceRow() override { uint8_t* rowPtr = nullptr; @@ -1004,11 +912,6 @@ class RemoveFrameRectFilter final : public SurfaceFilter { return nullptr; // We're done. } - uint8_t* DoAdvanceRowFromBuffer(const uint8_t* aInputRow) override { - CopyInputRow(aInputRow); - return DoAdvanceRow(); - } - uint8_t* DoAdvanceRow() override { uint8_t* rowPtr = nullptr; @@ -1194,11 +1097,6 @@ class ADAM7InterpolatingFilter final : public SurfaceFilter { return mCurrentRow.get(); } - uint8_t* DoAdvanceRowFromBuffer(const uint8_t* aInputRow) override { - CopyInputRow(aInputRow); - return DoAdvanceRow(); - } - uint8_t* DoAdvanceRow() override { MOZ_ASSERT(0 < mPass && mPass <= 7, "Invalid pass"); diff --git a/image/SurfacePipe.cpp b/image/SurfacePipe.cpp index 1fbb25470d40..f5595e2d5c7b 100644 --- a/image/SurfacePipe.cpp +++ b/image/SurfacePipe.cpp @@ -36,11 +36,6 @@ uint8_t* AbstractSurfaceSink::DoResetToFirstRow() { return GetRowPointer(); } -uint8_t* AbstractSurfaceSink::DoAdvanceRowFromBuffer(const uint8_t* aInputRow) { - CopyInputRow(aInputRow); - return DoAdvanceRow(); -} - uint8_t* AbstractSurfaceSink::DoAdvanceRow() { if (mRow >= uint32_t(InputSize().height)) { return nullptr; diff --git a/image/SurfacePipe.h b/image/SurfacePipe.h index 7bcadf050b39..224680f29c0e 100644 --- a/image/SurfacePipe.h +++ b/image/SurfacePipe.h @@ -127,19 +127,6 @@ class SurfaceFilter { return mRowPointer; } - /** - * Called by WriteBuffer() to advance this filter to the next row, if the - * supplied row is a full row. - * - * @return a pointer to the buffer for the next row, or nullptr to indicate - * that we've finished the entire surface. - */ - uint8_t* AdvanceRow(const uint8_t* aInputRow) { - mCol = 0; - mRowPointer = DoAdvanceRowFromBuffer(aInputRow); - return mRowPointer; - } - /// @return a pointer to the buffer for the current row. uint8_t* CurrentRowPointer() const { return mRowPointer; } @@ -282,22 +269,7 @@ class SurfaceFilter { */ template WriteState WriteBuffer(const PixelType* aSource) { - MOZ_ASSERT(mPixelSize == 1 || mPixelSize == 4); - MOZ_ASSERT_IF(mPixelSize == 1, sizeof(PixelType) == sizeof(uint8_t)); - MOZ_ASSERT_IF(mPixelSize == 4, sizeof(PixelType) == sizeof(uint32_t)); - - if (IsSurfaceFinished()) { - return WriteState::FINISHED; // Already done. - } - - if (MOZ_UNLIKELY(!aSource)) { - NS_WARNING("Passed a null pointer to WriteBuffer"); - return WriteState::FAILURE; - } - - AdvanceRow(reinterpret_cast(aSource)); - return IsSurfaceFinished() ? WriteState::FINISHED - : WriteState::NEED_MORE_DATA; + return WriteBuffer(aSource, 0, mInputSize.width); } /** @@ -468,16 +440,6 @@ class SurfaceFilter { */ virtual uint8_t* DoResetToFirstRow() = 0; - /** - * Called by AdvanceRow() to actually advance this filter to the next row. - * - * @param aInputRow The input row supplied by the decoder. - * - * @return a pointer to the buffer for the next row, or nullptr to indicate - * that we've finished the entire surface. - */ - virtual uint8_t* DoAdvanceRowFromBuffer(const uint8_t* aInputRow) = 0; - /** * Called by AdvanceRow() to actually advance this filter to the next row. * @@ -508,20 +470,6 @@ class SurfaceFilter { ResetToFirstRow(); } - /** - * Called by subclasses' DoAdvanceRowFromBuffer() methods to copy a decoder - * supplied row buffer into its internal row pointer. Ideally filters at the - * top of the filter pipeline are able to consume the decoder row buffer - * directly without the extra copy prior to performing its transformation. - * - * @param aInputRow The input row supplied by the decoder. - */ - void CopyInputRow(const uint8_t* aInputRow) { - MOZ_ASSERT(aInputRow); - MOZ_ASSERT(mCol == 0); - memcpy(mRowPointer, aInputRow, mPixelSize * mInputSize.width); - } - private: /** * An internal method used to implement WritePixelBlocks. This method writes @@ -771,7 +719,6 @@ class AbstractSurfaceSink : public SurfaceFilter { protected: uint8_t* DoResetToFirstRow() final; - uint8_t* DoAdvanceRowFromBuffer(const uint8_t* aInputRow) final; uint8_t* DoAdvanceRow() final; virtual uint8_t* GetRowPointer() const = 0; diff --git a/image/SurfacePipeFactory.h b/image/SurfacePipeFactory.h index 52c67ca61765..403cd6afbdc1 100644 --- a/image/SurfacePipeFactory.h +++ b/image/SurfacePipeFactory.h @@ -59,9 +59,6 @@ enum class SurfacePipeFlags { // result in a better user experience for // progressive display but which may be more // computationally expensive. - - PREMULTIPLY_ALPHA = 1 << 4, // If set, we want to premultiply the alpha - // channel and the individual color channels. }; MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(SurfacePipeFlags) @@ -91,9 +88,8 @@ class SurfacePipeFactory { static Maybe CreateSurfacePipe( Decoder* aDecoder, const nsIntSize& aInputSize, const nsIntSize& aOutputSize, const nsIntRect& aFrameRect, - gfx::SurfaceFormat aInFormat, gfx::SurfaceFormat aOutFormat, - const Maybe& aAnimParams, qcms_transform* aTransform, - SurfacePipeFlags aFlags) { + gfx::SurfaceFormat aFormat, const Maybe& aAnimParams, + qcms_transform* aTransform, SurfacePipeFlags aFlags) { const bool deinterlace = bool(aFlags & SurfacePipeFlags::DEINTERLACE); const bool flipVertically = bool(aFlags & SurfacePipeFlags::FLIP_VERTICALLY); @@ -104,46 +100,6 @@ class SurfacePipeFactory { nsIntRect(0, 0, aInputSize.width, aInputSize.height)); const bool blendAnimation = aAnimParams.isSome(); const bool colorManagement = aTransform != nullptr; - const bool premultiplyAlpha = - bool(aFlags & SurfacePipeFlags::PREMULTIPLY_ALPHA); - - // Early swizzles are for unpacking RGB or forcing RGBA/BGRA to RGBX/BGRX. - // We should never want to premultiply in either case, but the image's - // alpha channel will always be opaque. - bool earlySwizzle = aInFormat == gfx::SurfaceFormat::R8G8B8 || - ((aInFormat == gfx::SurfaceFormat::R8G8B8A8 && - aOutFormat == gfx::SurfaceFormat::R8G8B8X8) || - (aInFormat == gfx::SurfaceFormat::B8G8R8A8 && - aOutFormat == gfx::SurfaceFormat::B8G8R8X8)); - - // Late swizzles are for premultiplying RGBA/BGRA and/or possible converting - // between RGBA and BGRA. It must happen after color management. - bool lateSwizzle = ((aInFormat == gfx::SurfaceFormat::R8G8B8A8 && - aOutFormat == gfx::SurfaceFormat::B8G8R8A8) || - (aInFormat == gfx::SurfaceFormat::B8G8R8A8 && - aOutFormat == gfx::SurfaceFormat::R8G8B8A8)) || - premultiplyAlpha; - - MOZ_ASSERT(aInFormat == gfx::SurfaceFormat::R8G8B8 || - aInFormat == gfx::SurfaceFormat::R8G8B8A8 || - aInFormat == gfx::SurfaceFormat::R8G8B8X8 || - aInFormat == gfx::SurfaceFormat::B8G8R8A8 || - aInFormat == gfx::SurfaceFormat::B8G8R8X8); - - MOZ_ASSERT(aOutFormat == gfx::SurfaceFormat::R8G8B8A8 || - aOutFormat == gfx::SurfaceFormat::R8G8B8X8 || - aOutFormat == gfx::SurfaceFormat::B8G8R8A8 || - aOutFormat == gfx::SurfaceFormat::B8G8R8X8); - - if (earlySwizzle && lateSwizzle) { - MOZ_ASSERT_UNREACHABLE("Early and late swizzles not supported"); - return Nothing(); - } - - if (!earlySwizzle && !lateSwizzle && aInFormat != aOutFormat) { - MOZ_ASSERT_UNREACHABLE("Need to swizzle, but not configured to"); - return Nothing(); - } // Don't interpolate if we're sure we won't show this surface to the user // until it's completely decoded. The final pass of an ADAM7 image doesn't @@ -168,402 +124,129 @@ class SurfacePipeFactory { ADAM7InterpolatingConfig interpolatingConfig; RemoveFrameRectConfig removeFrameRectConfig{aFrameRect}; BlendAnimationConfig blendAnimationConfig{aDecoder}; - DownscalingConfig downscalingConfig{aInputSize, aOutFormat}; + DownscalingConfig downscalingConfig{aInputSize, aFormat}; ColorManagementConfig colorManagementConfig{aTransform}; - SwizzleConfig swizzleConfig{aInFormat, aOutFormat, premultiplyAlpha}; - SurfaceConfig surfaceConfig{aDecoder, aOutputSize, aOutFormat, - flipVertically, aAnimParams}; + SurfaceConfig surfaceConfig{aDecoder, aOutputSize, aFormat, flipVertically, + aAnimParams}; Maybe pipe; - if (earlySwizzle) { - if (colorManagement) { - if (downscale) { - MOZ_ASSERT(!blendAnimation); - if (removeFrameRect) { - if (deinterlace) { - pipe = MakePipe(swizzleConfig, deinterlacingConfig, - removeFrameRectConfig, downscalingConfig, - colorManagementConfig, surfaceConfig); - } else if (adam7Interpolate) { - pipe = MakePipe(swizzleConfig, interpolatingConfig, - removeFrameRectConfig, downscalingConfig, - colorManagementConfig, surfaceConfig); - } else { // (deinterlace and adam7Interpolate are false) - pipe = MakePipe(swizzleConfig, removeFrameRectConfig, - downscalingConfig, colorManagementConfig, - surfaceConfig); - } - } else { // (removeFrameRect is false) - if (deinterlace) { - pipe = MakePipe(swizzleConfig, deinterlacingConfig, - downscalingConfig, colorManagementConfig, - surfaceConfig); - } else if (adam7Interpolate) { - pipe = MakePipe(swizzleConfig, interpolatingConfig, - downscalingConfig, colorManagementConfig, - surfaceConfig); - } else { // (deinterlace and adam7Interpolate are false) - pipe = MakePipe(swizzleConfig, downscalingConfig, - colorManagementConfig, surfaceConfig); - } + if (colorManagement) { + if (downscale) { + MOZ_ASSERT(!blendAnimation); + if (removeFrameRect) { + if (deinterlace) { + pipe = MakePipe(deinterlacingConfig, removeFrameRectConfig, + downscalingConfig, colorManagementConfig, + surfaceConfig); + } else if (adam7Interpolate) { + pipe = MakePipe(interpolatingConfig, removeFrameRectConfig, + downscalingConfig, colorManagementConfig, + surfaceConfig); + } else { // (deinterlace and adam7Interpolate are false) + pipe = MakePipe(removeFrameRectConfig, downscalingConfig, + colorManagementConfig, surfaceConfig); } - } else { // (downscale is false) - if (blendAnimation) { - if (deinterlace) { - pipe = MakePipe(swizzleConfig, deinterlacingConfig, - colorManagementConfig, blendAnimationConfig, - surfaceConfig); - } else if (adam7Interpolate) { - pipe = MakePipe(swizzleConfig, interpolatingConfig, - colorManagementConfig, blendAnimationConfig, - surfaceConfig); - } else { // (deinterlace and adam7Interpolate are false) - pipe = MakePipe(swizzleConfig, colorManagementConfig, - blendAnimationConfig, surfaceConfig); - } - } else if (removeFrameRect) { - if (deinterlace) { - pipe = MakePipe(swizzleConfig, deinterlacingConfig, - colorManagementConfig, removeFrameRectConfig, - surfaceConfig); - } else if (adam7Interpolate) { - pipe = MakePipe(swizzleConfig, interpolatingConfig, - colorManagementConfig, removeFrameRectConfig, - surfaceConfig); - } else { // (deinterlace and adam7Interpolate are false) - pipe = MakePipe(swizzleConfig, colorManagementConfig, - removeFrameRectConfig, surfaceConfig); - } - } else { // (blendAnimation and removeFrameRect is false) - if (deinterlace) { - pipe = MakePipe(swizzleConfig, deinterlacingConfig, - colorManagementConfig, surfaceConfig); - } else if (adam7Interpolate) { - pipe = MakePipe(swizzleConfig, interpolatingConfig, - colorManagementConfig, surfaceConfig); - } else { // (deinterlace and adam7Interpolate are false) - pipe = - MakePipe(swizzleConfig, colorManagementConfig, surfaceConfig); - } + } else { // (removeFrameRect is false) + if (deinterlace) { + pipe = MakePipe(deinterlacingConfig, downscalingConfig, + colorManagementConfig, surfaceConfig); + } else if (adam7Interpolate) { + pipe = MakePipe(interpolatingConfig, downscalingConfig, + colorManagementConfig, surfaceConfig); + } else { // (deinterlace and adam7Interpolate are false) + pipe = MakePipe(downscalingConfig, colorManagementConfig, + surfaceConfig); } } - } else { // (colorManagement is false) - if (downscale) { - MOZ_ASSERT(!blendAnimation); - if (removeFrameRect) { - if (deinterlace) { - pipe = MakePipe(swizzleConfig, deinterlacingConfig, - removeFrameRectConfig, downscalingConfig, - surfaceConfig); - } else if (adam7Interpolate) { - pipe = MakePipe(swizzleConfig, interpolatingConfig, - removeFrameRectConfig, downscalingConfig, - surfaceConfig); - } else { // (deinterlace and adam7Interpolate are false) - pipe = MakePipe(swizzleConfig, removeFrameRectConfig, - downscalingConfig, surfaceConfig); - } - } else { // (removeFrameRect is false) - if (deinterlace) { - pipe = MakePipe(swizzleConfig, deinterlacingConfig, - downscalingConfig, surfaceConfig); - } else if (adam7Interpolate) { - pipe = MakePipe(swizzleConfig, interpolatingConfig, - downscalingConfig, surfaceConfig); - } else { // (deinterlace and adam7Interpolate are false) - pipe = MakePipe(swizzleConfig, downscalingConfig, surfaceConfig); - } + } else { // (downscale is false) + if (blendAnimation) { + if (deinterlace) { + pipe = MakePipe(deinterlacingConfig, colorManagementConfig, + blendAnimationConfig, surfaceConfig); + } else if (adam7Interpolate) { + pipe = MakePipe(interpolatingConfig, colorManagementConfig, + blendAnimationConfig, surfaceConfig); + } else { // (deinterlace and adam7Interpolate are false) + pipe = MakePipe(colorManagementConfig, blendAnimationConfig, + surfaceConfig); } - } else { // (downscale is false) - if (blendAnimation) { - if (deinterlace) { - pipe = MakePipe(swizzleConfig, deinterlacingConfig, - blendAnimationConfig, surfaceConfig); - } else if (adam7Interpolate) { - pipe = MakePipe(swizzleConfig, interpolatingConfig, - blendAnimationConfig, surfaceConfig); - } else { // (deinterlace and adam7Interpolate are false) - pipe = - MakePipe(swizzleConfig, blendAnimationConfig, surfaceConfig); - } - } else if (removeFrameRect) { - if (deinterlace) { - pipe = MakePipe(swizzleConfig, deinterlacingConfig, - removeFrameRectConfig, surfaceConfig); - } else if (adam7Interpolate) { - pipe = MakePipe(swizzleConfig, interpolatingConfig, - removeFrameRectConfig, surfaceConfig); - } else { // (deinterlace and adam7Interpolate are false) - pipe = - MakePipe(swizzleConfig, removeFrameRectConfig, surfaceConfig); - } - } else { // (blendAnimation and removeFrameRect is false) - if (deinterlace) { - pipe = - MakePipe(swizzleConfig, deinterlacingConfig, surfaceConfig); - } else if (adam7Interpolate) { - pipe = - MakePipe(swizzleConfig, interpolatingConfig, surfaceConfig); - } else { // (deinterlace and adam7Interpolate are false) - pipe = MakePipe(swizzleConfig, surfaceConfig); - } + } else if (removeFrameRect) { + if (deinterlace) { + pipe = MakePipe(deinterlacingConfig, colorManagementConfig, + removeFrameRectConfig, surfaceConfig); + } else if (adam7Interpolate) { + pipe = MakePipe(interpolatingConfig, colorManagementConfig, + removeFrameRectConfig, surfaceConfig); + } else { // (deinterlace and adam7Interpolate are false) + pipe = MakePipe(colorManagementConfig, removeFrameRectConfig, + surfaceConfig); + } + } else { // (blendAnimation and removeFrameRect is false) + if (deinterlace) { + pipe = MakePipe(deinterlacingConfig, colorManagementConfig, + surfaceConfig); + } else if (adam7Interpolate) { + pipe = MakePipe(interpolatingConfig, colorManagementConfig, + surfaceConfig); + } else { // (deinterlace and adam7Interpolate are false) + pipe = MakePipe(colorManagementConfig, surfaceConfig); } } } - } else if (lateSwizzle) { - if (colorManagement) { - if (downscale) { - MOZ_ASSERT(!blendAnimation); - if (removeFrameRect) { - if (deinterlace) { - pipe = MakePipe(deinterlacingConfig, removeFrameRectConfig, - downscalingConfig, colorManagementConfig, - swizzleConfig, surfaceConfig); - } else if (adam7Interpolate) { - pipe = MakePipe(interpolatingConfig, removeFrameRectConfig, - downscalingConfig, colorManagementConfig, - swizzleConfig, surfaceConfig); - } else { // (deinterlace and adam7Interpolate are false) - pipe = - MakePipe(removeFrameRectConfig, downscalingConfig, - colorManagementConfig, swizzleConfig, surfaceConfig); - } - } else { // (removeFrameRect is false) - if (deinterlace) { - pipe = - MakePipe(deinterlacingConfig, downscalingConfig, - colorManagementConfig, swizzleConfig, surfaceConfig); - } else if (adam7Interpolate) { - pipe = - MakePipe(interpolatingConfig, downscalingConfig, - colorManagementConfig, swizzleConfig, surfaceConfig); - } else { // (deinterlace and adam7Interpolate are false) - pipe = MakePipe(downscalingConfig, colorManagementConfig, - swizzleConfig, surfaceConfig); - } + } else { // (colorManagement is false) + if (downscale) { + MOZ_ASSERT(!blendAnimation); + if (removeFrameRect) { + if (deinterlace) { + pipe = MakePipe(deinterlacingConfig, removeFrameRectConfig, + downscalingConfig, surfaceConfig); + } else if (adam7Interpolate) { + pipe = MakePipe(interpolatingConfig, removeFrameRectConfig, + downscalingConfig, surfaceConfig); + } else { // (deinterlace and adam7Interpolate are false) + pipe = MakePipe(removeFrameRectConfig, downscalingConfig, + surfaceConfig); } - } else { // (downscale is false) - if (blendAnimation) { - if (deinterlace) { - pipe = - MakePipe(deinterlacingConfig, colorManagementConfig, - swizzleConfig, blendAnimationConfig, surfaceConfig); - } else if (adam7Interpolate) { - pipe = MakePipe(interpolatingConfig, colorManagementConfig, - swizzleConfig, blendAnimationConfig, - swizzleConfig, surfaceConfig); - } else { // (deinterlace and adam7Interpolate are false) - pipe = MakePipe(colorManagementConfig, swizzleConfig, - blendAnimationConfig, surfaceConfig); - } - } else if (removeFrameRect) { - if (deinterlace) { - pipe = - MakePipe(deinterlacingConfig, colorManagementConfig, - swizzleConfig, removeFrameRectConfig, surfaceConfig); - } else if (adam7Interpolate) { - pipe = - MakePipe(interpolatingConfig, colorManagementConfig, - swizzleConfig, removeFrameRectConfig, surfaceConfig); - } else { // (deinterlace and adam7Interpolate are false) - pipe = MakePipe(colorManagementConfig, swizzleConfig, - removeFrameRectConfig, surfaceConfig); - } - } else { // (blendAnimation and removeFrameRect is false) - if (deinterlace) { - pipe = MakePipe(deinterlacingConfig, colorManagementConfig, - swizzleConfig, surfaceConfig); - } else if (adam7Interpolate) { - pipe = MakePipe(interpolatingConfig, colorManagementConfig, - swizzleConfig, surfaceConfig); - } else { // (deinterlace and adam7Interpolate are false) - pipe = - MakePipe(colorManagementConfig, swizzleConfig, surfaceConfig); - } + } else { // (removeFrameRect is false) + if (deinterlace) { + pipe = + MakePipe(deinterlacingConfig, downscalingConfig, surfaceConfig); + } else if (adam7Interpolate) { + pipe = + MakePipe(interpolatingConfig, downscalingConfig, surfaceConfig); + } else { // (deinterlace and adam7Interpolate are false) + pipe = MakePipe(downscalingConfig, surfaceConfig); } } - } else { // (colorManagement is false) - if (downscale) { - MOZ_ASSERT(!blendAnimation); - if (removeFrameRect) { - if (deinterlace) { - pipe = MakePipe(deinterlacingConfig, swizzleConfig, - removeFrameRectConfig, downscalingConfig, - surfaceConfig); - } else if (adam7Interpolate) { - pipe = MakePipe(interpolatingConfig, swizzleConfig, - removeFrameRectConfig, downscalingConfig, - surfaceConfig); - } else { // (deinterlace and adam7Interpolate are false) - pipe = MakePipe(swizzleConfig, removeFrameRectConfig, - downscalingConfig, surfaceConfig); - } - } else { // (removeFrameRect is false) - if (deinterlace) { - pipe = MakePipe(deinterlacingConfig, downscalingConfig, - swizzleConfig, surfaceConfig); - } else if (adam7Interpolate) { - pipe = MakePipe(interpolatingConfig, downscalingConfig, - swizzleConfig, surfaceConfig); - } else { // (deinterlace and adam7Interpolate are false) - pipe = MakePipe(downscalingConfig, swizzleConfig, surfaceConfig); - } + } else { // (downscale is false) + if (blendAnimation) { + if (deinterlace) { + pipe = MakePipe(deinterlacingConfig, blendAnimationConfig, + surfaceConfig); + } else if (adam7Interpolate) { + pipe = MakePipe(interpolatingConfig, blendAnimationConfig, + surfaceConfig); + } else { // (deinterlace and adam7Interpolate are false) + pipe = MakePipe(blendAnimationConfig, surfaceConfig); } - } else { // (downscale is false) - if (blendAnimation) { - if (deinterlace) { - pipe = MakePipe(deinterlacingConfig, swizzleConfig, - blendAnimationConfig, surfaceConfig); - } else if (adam7Interpolate) { - pipe = MakePipe(interpolatingConfig, swizzleConfig, - blendAnimationConfig, surfaceConfig); - } else { // (deinterlace and adam7Interpolate are false) - pipe = - MakePipe(swizzleConfig, blendAnimationConfig, surfaceConfig); - } - } else if (removeFrameRect) { - if (deinterlace) { - pipe = MakePipe(deinterlacingConfig, swizzleConfig, - removeFrameRectConfig, surfaceConfig); - } else if (adam7Interpolate) { - pipe = MakePipe(interpolatingConfig, swizzleConfig, - removeFrameRectConfig, surfaceConfig); - } else { // (deinterlace and adam7Interpolate are false) - pipe = - MakePipe(swizzleConfig, removeFrameRectConfig, surfaceConfig); - } - } else { // (blendAnimation and removeFrameRect is false) - if (deinterlace) { - pipe = - MakePipe(deinterlacingConfig, swizzleConfig, surfaceConfig); - } else if (adam7Interpolate) { - pipe = - MakePipe(interpolatingConfig, swizzleConfig, surfaceConfig); - } else { // (deinterlace and adam7Interpolate are false) - pipe = MakePipe(swizzleConfig, surfaceConfig); - } + } else if (removeFrameRect) { + if (deinterlace) { + pipe = MakePipe(deinterlacingConfig, removeFrameRectConfig, + surfaceConfig); + } else if (adam7Interpolate) { + pipe = MakePipe(interpolatingConfig, removeFrameRectConfig, + surfaceConfig); + } else { // (deinterlace and adam7Interpolate are false) + pipe = MakePipe(removeFrameRectConfig, surfaceConfig); } - } - } - } else { // (earlySwizzle and lateSwizzle are false) - if (colorManagement) { - if (downscale) { - MOZ_ASSERT(!blendAnimation); - if (removeFrameRect) { - if (deinterlace) { - pipe = MakePipe(deinterlacingConfig, removeFrameRectConfig, - downscalingConfig, colorManagementConfig, - surfaceConfig); - } else if (adam7Interpolate) { - pipe = MakePipe(interpolatingConfig, removeFrameRectConfig, - downscalingConfig, colorManagementConfig, - surfaceConfig); - } else { // (deinterlace and adam7Interpolate are false) - pipe = MakePipe(removeFrameRectConfig, downscalingConfig, - colorManagementConfig, surfaceConfig); - } - } else { // (removeFrameRect is false) - if (deinterlace) { - pipe = MakePipe(deinterlacingConfig, downscalingConfig, - colorManagementConfig, surfaceConfig); - } else if (adam7Interpolate) { - pipe = MakePipe(interpolatingConfig, downscalingConfig, - colorManagementConfig, surfaceConfig); - } else { // (deinterlace and adam7Interpolate are false) - pipe = MakePipe(downscalingConfig, colorManagementConfig, - surfaceConfig); - } - } - } else { // (downscale is false) - if (blendAnimation) { - if (deinterlace) { - pipe = MakePipe(deinterlacingConfig, colorManagementConfig, - blendAnimationConfig, surfaceConfig); - } else if (adam7Interpolate) { - pipe = MakePipe(interpolatingConfig, colorManagementConfig, - blendAnimationConfig, surfaceConfig); - } else { // (deinterlace and adam7Interpolate are false) - pipe = MakePipe(colorManagementConfig, blendAnimationConfig, - surfaceConfig); - } - } else if (removeFrameRect) { - if (deinterlace) { - pipe = MakePipe(deinterlacingConfig, colorManagementConfig, - removeFrameRectConfig, surfaceConfig); - } else if (adam7Interpolate) { - pipe = MakePipe(interpolatingConfig, colorManagementConfig, - removeFrameRectConfig, surfaceConfig); - } else { // (deinterlace and adam7Interpolate are false) - pipe = MakePipe(colorManagementConfig, removeFrameRectConfig, - surfaceConfig); - } - } else { // (blendAnimation and removeFrameRect is false) - if (deinterlace) { - pipe = MakePipe(deinterlacingConfig, colorManagementConfig, - surfaceConfig); - } else if (adam7Interpolate) { - pipe = MakePipe(interpolatingConfig, colorManagementConfig, - surfaceConfig); - } else { // (deinterlace and adam7Interpolate are false) - pipe = MakePipe(colorManagementConfig, surfaceConfig); - } - } - } - } else { // (colorManagement is false) - if (downscale) { - MOZ_ASSERT(!blendAnimation); - if (removeFrameRect) { - if (deinterlace) { - pipe = MakePipe(deinterlacingConfig, removeFrameRectConfig, - downscalingConfig, surfaceConfig); - } else if (adam7Interpolate) { - pipe = MakePipe(interpolatingConfig, removeFrameRectConfig, - downscalingConfig, surfaceConfig); - } else { // (deinterlace and adam7Interpolate are false) - pipe = MakePipe(removeFrameRectConfig, downscalingConfig, - surfaceConfig); - } - } else { // (removeFrameRect is false) - if (deinterlace) { - pipe = MakePipe(deinterlacingConfig, downscalingConfig, - surfaceConfig); - } else if (adam7Interpolate) { - pipe = MakePipe(interpolatingConfig, downscalingConfig, - surfaceConfig); - } else { // (deinterlace and adam7Interpolate are false) - pipe = MakePipe(downscalingConfig, surfaceConfig); - } - } - } else { // (downscale is false) - if (blendAnimation) { - if (deinterlace) { - pipe = MakePipe(deinterlacingConfig, blendAnimationConfig, - surfaceConfig); - } else if (adam7Interpolate) { - pipe = MakePipe(interpolatingConfig, blendAnimationConfig, - surfaceConfig); - } else { // (deinterlace and adam7Interpolate are false) - pipe = MakePipe(blendAnimationConfig, surfaceConfig); - } - } else if (removeFrameRect) { - if (deinterlace) { - pipe = MakePipe(deinterlacingConfig, removeFrameRectConfig, - surfaceConfig); - } else if (adam7Interpolate) { - pipe = MakePipe(interpolatingConfig, removeFrameRectConfig, - surfaceConfig); - } else { // (deinterlace and adam7Interpolate are false) - pipe = MakePipe(removeFrameRectConfig, surfaceConfig); - } - } else { // (blendAnimation and removeFrameRect is false) - if (deinterlace) { - pipe = MakePipe(deinterlacingConfig, surfaceConfig); - } else if (adam7Interpolate) { - pipe = MakePipe(interpolatingConfig, surfaceConfig); - } else { // (deinterlace and adam7Interpolate are false) - pipe = MakePipe(surfaceConfig); - } + } else { // (blendAnimation and removeFrameRect is false) + if (deinterlace) { + pipe = MakePipe(deinterlacingConfig, surfaceConfig); + } else if (adam7Interpolate) { + pipe = MakePipe(interpolatingConfig, surfaceConfig); + } else { // (deinterlace and adam7Interpolate are false) + pipe = MakePipe(surfaceConfig); } } } diff --git a/image/decoders/nsGIFDecoder2.cpp b/image/decoders/nsGIFDecoder2.cpp index 2772605436ae..e02a81b8237f 100644 --- a/image/decoders/nsGIFDecoder2.cpp +++ b/image/decoders/nsGIFDecoder2.cpp @@ -193,8 +193,8 @@ nsresult nsGIFDecoder2::BeginImageFrame(const IntRect& aFrameRect, } Maybe pipe = SurfacePipeFactory::CreateSurfacePipe( - this, Size(), OutputSize(), aFrameRect, format, format, animParams, - mTransform, pipeFlags); + this, Size(), OutputSize(), aFrameRect, format, animParams, mTransform, + pipeFlags); mCurrentFrameIndex = mGIFStruct.images_decoded; if (!pipe) { diff --git a/image/decoders/nsIconDecoder.cpp b/image/decoders/nsIconDecoder.cpp index 3ec890cb8f91..5e3bb24a039e 100644 --- a/image/decoders/nsIconDecoder.cpp +++ b/image/decoders/nsIconDecoder.cpp @@ -68,7 +68,6 @@ LexerTransition nsIconDecoder::ReadHeader( MOZ_ASSERT(!mImageData, "Already have a buffer allocated?"); Maybe pipe = SurfacePipeFactory::CreateSurfacePipe( this, Size(), OutputSize(), FullFrame(), SurfaceFormat::B8G8R8A8, - SurfaceFormat::B8G8R8A8, /* aAnimParams */ Nothing(), mTransform, SurfacePipeFlags()); if (!pipe) { return Transition::TerminateFailure(); diff --git a/image/decoders/nsJPEGDecoder.cpp b/image/decoders/nsJPEGDecoder.cpp index 23b8ff371b29..d43363279581 100644 --- a/image/decoders/nsJPEGDecoder.cpp +++ b/image/decoders/nsJPEGDecoder.cpp @@ -357,8 +357,7 @@ LexerTransition nsJPEGDecoder::ReadJPEGData( Maybe pipe = SurfacePipeFactory::CreateSurfacePipe( this, Size(), OutputSize(), FullFrame(), SurfaceFormat::B8G8R8X8, - SurfaceFormat::B8G8R8X8, Nothing(), pipeTransform, - SurfacePipeFlags()); + Nothing(), pipeTransform, SurfacePipeFlags()); if (!pipe) { mState = JPEG_ERROR; MOZ_LOG(sJPEGDecoderAccountingLog, LogLevel::Debug, diff --git a/image/decoders/nsPNGDecoder.cpp b/image/decoders/nsPNGDecoder.cpp index 749dc196f3a2..90772130567c 100644 --- a/image/decoders/nsPNGDecoder.cpp +++ b/image/decoders/nsPNGDecoder.cpp @@ -116,7 +116,6 @@ nsPNGDecoder::nsPNGDecoder(RasterImage* aImage) mFrameIsHidden(false), mDisablePremultipliedAlpha(false), mGotInfoCallback(false), - mUsePipeTransform(false), mNumFrames(0) {} nsPNGDecoder::~nsPNGDecoder() { @@ -213,29 +212,9 @@ nsresult nsPNGDecoder::CreateFrame(const FrameInfo& aFrameInfo) { pipeFlags |= SurfacePipeFlags::PROGRESSIVE_DISPLAY; } - SurfaceFormat inFormat; - if (mTransform && !mUsePipeTransform) { - // QCMS will output in the correct format. - inFormat = mFormat; - } else if (transparency == TransparencyType::eAlpha) { - // We are outputting directly as RGBA, so we need to swap at this step. - inFormat = SurfaceFormat::R8G8B8A8; - } else { - // We have no alpha channel, so we need to unpack from RGB to BGRA. - inFormat = SurfaceFormat::R8G8B8; - } - - // Only apply premultiplication if the frame has true alpha. If we ever - // support downscaling animated images, we will need to premultiply for frame - // rect transparency when downscaling as well. - if (transparency == TransparencyType::eAlpha && !mDisablePremultipliedAlpha) { - pipeFlags |= SurfacePipeFlags::PREMULTIPLY_ALPHA; - } - - qcms_transform* pipeTransform = mUsePipeTransform ? mTransform : nullptr; Maybe pipe = SurfacePipeFactory::CreateSurfacePipe( - this, Size(), OutputSize(), aFrameInfo.mFrameRect, inFormat, mFormat, - animParams, pipeTransform, pipeFlags); + this, Size(), OutputSize(), aFrameInfo.mFrameRect, mFormat, animParams, + /*aTransform*/ nullptr, pipeFlags); if (!pipe) { mPipe = SurfacePipe(); @@ -434,7 +413,8 @@ static void PNGDoGammaCorrection(png_structp png_ptr, png_infop info_ptr) { // Adapted from http://www.littlecms.com/pngchrm.c example code static qcms_profile* PNGGetColorProfile(png_structp png_ptr, png_infop info_ptr, - int color_type, uint32_t* intent) { + int color_type, qcms_data_type* inType, + uint32_t* intent) { qcms_profile* profile = nullptr; *intent = QCMS_INTENT_PERCEPTUAL; // Our default @@ -512,6 +492,24 @@ static qcms_profile* PNGGetColorProfile(png_structp png_ptr, png_infop info_ptr, } } + if (profile) { + uint32_t profileSpace = qcms_profile_get_color_space(profile); + if (profileSpace == icSigGrayData) { + if (color_type & PNG_COLOR_MASK_ALPHA) { + *inType = QCMS_DATA_GRAYA_8; + } else { + *inType = QCMS_DATA_GRAY_8; + } + } else { + if (color_type & PNG_COLOR_MASK_ALPHA || + png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { + *inType = QCMS_DATA_RGBA_8; + } else { + *inType = QCMS_DATA_RGB_8; + } + } + } + return profile; } @@ -592,13 +590,14 @@ void nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr) { // We only need to extract the color profile for non-metadata decodes. It is // fairly expensive to read the profile and create the transform so we should // avoid it if not necessary. + qcms_data_type inType = QCMS_DATA_RGBA_8; uint32_t intent = -1; uint32_t pIntent; if (!decoder->IsMetadataDecode()) { if (decoder->mCMSMode != eCMSMode_Off) { intent = gfxPlatform::GetRenderingIntent(); decoder->mInProfile = - PNGGetColorProfile(png_ptr, info_ptr, color_type, &pIntent); + PNGGetColorProfile(png_ptr, info_ptr, color_type, &inType, &pIntent); // If we're not mandating an intent, use the one from the image. if (intent == uint32_t(-1)) { intent = pIntent; @@ -649,7 +648,6 @@ void nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr) { } #endif - auto transparency = decoder->GetTransparencyType(frameRect); if (decoder->IsMetadataDecode()) { // If we are animated then the first frame rect is either: // 1) the whole image if the IDAT chunk is part of the animation @@ -658,6 +656,7 @@ void nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr) { // PostHasTransparency in the metadata decode if we need to. So it's // okay to pass IntRect(0, 0, width, height) here for animated images; // they will call with the proper first frame rect in the full decode. + auto transparency = decoder->GetTransparencyType(frameRect); decoder->PostHasTransparencyIfNeeded(transparency); // We have the metadata we're looking for, so stop here, before we allocate @@ -666,47 +665,23 @@ void nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr) { } if (decoder->mInProfile && gfxPlatform::GetCMSOutputProfile()) { - qcms_data_type inType; qcms_data_type outType; - uint32_t profileSpace = qcms_profile_get_color_space(decoder->mInProfile); - decoder->mUsePipeTransform = profileSpace != icSigGrayData; - if (decoder->mUsePipeTransform) { - // If the transform happens with SurfacePipe, it will be in RGBA if we - // have an alpha channel, because the swizzle and premultiplication - // happens after color management. Otherwise it will be in BGRA because - // the swizzle happens at the start. - if (transparency == TransparencyType::eAlpha) { - inType = QCMS_DATA_RGBA_8; - outType = QCMS_DATA_RGBA_8; - } else { - inType = QCMS_DATA_BGRA_8; - outType = QCMS_DATA_BGRA_8; - } + if (color_type & PNG_COLOR_MASK_ALPHA || num_trans) { + outType = QCMS_DATA_RGBA_8; } else { - if (color_type & PNG_COLOR_MASK_ALPHA) { - inType = QCMS_DATA_GRAYA_8; - outType = QCMS_DATA_BGRA_8; - } else { - inType = QCMS_DATA_GRAY_8; - outType = QCMS_DATA_BGRA_8; - } + outType = QCMS_DATA_RGB_8; } decoder->mTransform = qcms_transform_create( decoder->mInProfile, inType, gfxPlatform::GetCMSOutputProfile(), outType, (qcms_intent)intent); } else if (decoder->mCMSMode == eCMSMode_All) { - // If the transform happens with SurfacePipe, it will be in RGBA if we - // have an alpha channel, because the swizzle and premultiplication - // happens after color management. Otherwise it will be in BGRA because - // the swizzle happens at the start. - if (transparency == TransparencyType::eAlpha) { + if (color_type & PNG_COLOR_MASK_ALPHA || num_trans) { decoder->mTransform = gfxPlatform::GetCMSRGBATransform(); } else { - decoder->mTransform = gfxPlatform::GetCMSBGRATransform(); + decoder->mTransform = gfxPlatform::GetCMSRGBTransform(); } - decoder->mUsePipeTransform = true; } #ifdef PNG_APNG_SUPPORTED @@ -728,8 +703,8 @@ void nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr) { } #endif - if (decoder->mTransform && !decoder->mUsePipeTransform) { - uint32_t bpp[] = {0, 3, 4}; + if (decoder->mTransform && (channels <= 2 || isInterlaced)) { + uint32_t bpp[] = {0, 3, 4, 3, 4}; decoder->mCMSLine = static_cast(malloc(bpp[channels] * frameRect.Width())); if (!decoder->mCMSLine) { @@ -765,6 +740,29 @@ void nsPNGDecoder::PostInvalidationIfNeeded() { Some(invalidRect->mOutputSpaceRect)); } +static NextPixel PackRGBPixelAndAdvance(uint8_t*& aRawPixelInOut) { + const uint32_t pixel = gfxPackedPixel(0xFF, aRawPixelInOut[0], + aRawPixelInOut[1], aRawPixelInOut[2]); + aRawPixelInOut += 3; + return AsVariant(pixel); +} + +static NextPixel PackRGBAPixelAndAdvance(uint8_t*& aRawPixelInOut) { + const uint32_t pixel = gfxPackedPixel(aRawPixelInOut[3], aRawPixelInOut[0], + aRawPixelInOut[1], aRawPixelInOut[2]); + aRawPixelInOut += 4; + return AsVariant(pixel); +} + +static NextPixel PackUnpremultipliedRGBAPixelAndAdvance( + uint8_t*& aRawPixelInOut) { + const uint32_t pixel = + gfxPackedPixelNoPreMultiply(aRawPixelInOut[3], aRawPixelInOut[0], + aRawPixelInOut[1], aRawPixelInOut[2]); + aRawPixelInOut += 4; + return AsVariant(pixel); +} + void nsPNGDecoder::row_callback(png_structp png_ptr, png_bytep new_row, png_uint_32 row_num, int pass) { /* libpng comments: @@ -849,16 +847,38 @@ void nsPNGDecoder::WriteRow(uint8_t* aRow) { uint32_t width = uint32_t(mFrameRect.Width()); // Apply color management to the row, if necessary, before writing it out. - // This is only needed for grayscale images. - if (mTransform && !mUsePipeTransform) { - MOZ_ASSERT(mCMSLine); - qcms_transform_data(mTransform, rowToWrite, mCMSLine, width); - rowToWrite = mCMSLine; + if (mTransform) { + if (mCMSLine) { + qcms_transform_data(mTransform, rowToWrite, mCMSLine, width); + + // Copy alpha over. + if (HasAlphaChannel()) { + for (uint32_t i = 0; i < width; ++i) { + mCMSLine[4 * i + 3] = rowToWrite[mChannels * i + mChannels - 1]; + } + } + + rowToWrite = mCMSLine; + } else { + qcms_transform_data(mTransform, rowToWrite, rowToWrite, width); + } } // Write this row to the SurfacePipe. - DebugOnly result = - mPipe.WriteBuffer(reinterpret_cast(rowToWrite)); + DebugOnly result; + if (HasAlphaChannel()) { + if (mDisablePremultipliedAlpha) { + result = mPipe.WritePixelsToRow( + [&] { return PackUnpremultipliedRGBAPixelAndAdvance(rowToWrite); }); + } else { + result = mPipe.WritePixelsToRow( + [&] { return PackRGBAPixelAndAdvance(rowToWrite); }); + } + } else { + result = mPipe.WritePixelsToRow( + [&] { return PackRGBPixelAndAdvance(rowToWrite); }); + } + MOZ_ASSERT(WriteState(result) != WriteState::FAILURE); PostInvalidationIfNeeded(); diff --git a/image/decoders/nsPNGDecoder.h b/image/decoders/nsPNGDecoder.h index f042afe99e7b..4ed454fea2b3 100644 --- a/image/decoders/nsPNGDecoder.h +++ b/image/decoders/nsPNGDecoder.h @@ -11,7 +11,6 @@ #include "png.h" #include "StreamingLexer.h" #include "SurfacePipe.h" -#include "mozilla/gfx/Swizzle.h" namespace mozilla { namespace image { @@ -102,7 +101,6 @@ class nsPNGDecoder : public Decoder { bool mFrameIsHidden; bool mDisablePremultipliedAlpha; bool mGotInfoCallback; - bool mUsePipeTransform; struct AnimFrameInfo { AnimFrameInfo(); diff --git a/image/decoders/nsWebPDecoder.cpp b/image/decoders/nsWebPDecoder.cpp index 737975a4f391..9fbbad654c04 100644 --- a/image/decoders/nsWebPDecoder.cpp +++ b/image/decoders/nsWebPDecoder.cpp @@ -210,7 +210,7 @@ nsresult nsWebPDecoder::CreateFrame(const nsIntRect& aFrameRect) { } WebPInitDecBuffer(&mBuffer); - mBuffer.colorspace = MODE_BGRA; + mBuffer.colorspace = MODE_RGBA; mDecoder = WebPINewDecoder(&mBuffer); if (!mDecoder) { @@ -220,16 +220,7 @@ nsresult nsWebPDecoder::CreateFrame(const nsIntRect& aFrameRect) { return NS_ERROR_FAILURE; } - // WebP doesn't guarantee that the alpha generated matches the hint in the - // header, so we always need to claim the input is BGRA. If the output is - // BGRX, swizzling will mask off the alpha channel. - SurfaceFormat inFormat = SurfaceFormat::B8G8R8A8; - SurfacePipeFlags pipeFlags = SurfacePipeFlags(); - if (mFormat == SurfaceFormat::B8G8R8A8 && - !(GetSurfaceFlags() & SurfaceFlags::NO_PREMULTIPLY_ALPHA)) { - pipeFlags |= SurfacePipeFlags::PREMULTIPLY_ALPHA; - } Maybe animParams; if (!IsFirstFrameDecode()) { @@ -237,8 +228,8 @@ nsresult nsWebPDecoder::CreateFrame(const nsIntRect& aFrameRect) { } Maybe pipe = SurfacePipeFactory::CreateSurfacePipe( - this, Size(), OutputSize(), aFrameRect, inFormat, mFormat, animParams, - mTransform, pipeFlags); + this, Size(), OutputSize(), aFrameRect, mFormat, animParams, + /*aTransform*/ nullptr, pipeFlags); if (!pipe) { MOZ_LOG(sWebPLog, LogLevel::Error, ("[this=%p] nsWebPDecoder::CreateFrame -- no pipe\n", this)); @@ -290,7 +281,7 @@ void nsWebPDecoder::ApplyColorProfile(const char* aProfile, size_t aLength) { ("[this=%p] nsWebPDecoder::ApplyColorProfile -- not tagged, use " "sRGB transform\n", this)); - mTransform = gfxPlatform::GetCMSBGRATransform(); + mTransform = gfxPlatform::GetCMSRGBATransform(); return; } @@ -320,9 +311,9 @@ void nsWebPDecoder::ApplyColorProfile(const char* aProfile, size_t aLength) { } // Create the color management transform. - mTransform = qcms_transform_create(mInProfile, QCMS_DATA_BGRA_8, + mTransform = qcms_transform_create(mInProfile, QCMS_DATA_RGBA_8, gfxPlatform::GetCMSOutputProfile(), - QCMS_DATA_BGRA_8, (qcms_intent)intent); + QCMS_DATA_RGBA_8, (qcms_intent)intent); MOZ_LOG(sWebPLog, LogLevel::Debug, ("[this=%p] nsWebPDecoder::ApplyColorProfile -- use tagged " "transform\n", @@ -467,9 +458,43 @@ LexerResult nsWebPDecoder::ReadSingle(const uint8_t* aData, size_t aLength, return LexerResult(TerminalState::FAILURE); } + const bool noPremultiply = + bool(GetSurfaceFlags() & SurfaceFlags::NO_PREMULTIPLY_ALPHA); + for (int row = mLastRow; row < lastRow; row++) { - uint32_t* src = reinterpret_cast(rowStart + row * stride); - WriteState result = mPipe.WriteBuffer(src); + uint8_t* src = rowStart + row * stride; + if (mTransform) { + qcms_transform_data(mTransform, src, src, width); + } + + WriteState result; + if (mFormat == SurfaceFormat::B8G8R8A8) { + if (noPremultiply) { + result = + mPipe.WritePixelsToRow([&]() -> NextPixel { + const uint32_t pixel = + gfxPackedPixelNoPreMultiply(src[3], src[0], src[1], src[2]); + src += 4; + return AsVariant(pixel); + }); + } else { + result = + mPipe.WritePixelsToRow([&]() -> NextPixel { + const uint32_t pixel = + gfxPackedPixel(src[3], src[0], src[1], src[2]); + src += 4; + return AsVariant(pixel); + }); + } + } else { + // We are producing a surface without transparency. Ignore the alpha + // channel provided to us by the library. + result = mPipe.WritePixelsToRow([&]() -> NextPixel { + const uint32_t pixel = gfxPackedPixel(0xFF, src[0], src[1], src[2]); + src += 4; + return AsVariant(pixel); + }); + } Maybe invalidRect = mPipe.TakeInvalidRect(); if (invalidRect) { diff --git a/image/test/gtest/Common.cpp b/image/test/gtest/Common.cpp index f36295a8d02a..00fca643e284 100644 --- a/image/test/gtest/Common.cpp +++ b/image/test/gtest/Common.cpp @@ -167,6 +167,11 @@ bool IsSolidColor(SourceSurface* aSurface, BGRAColor aColor, aColor, aFuzz); } +bool IsSolidPalettedColor(Decoder* aDecoder, uint8_t aColor) { + RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef(); + return PalettedRectIsSolidColor(aDecoder, currentFrame->GetRect(), aColor); +} + bool RowsAreSolidColor(SourceSurface* aSurface, int32_t aStartRow, int32_t aRowCount, BGRAColor aColor, uint8_t aFuzz /* = 0 */) { @@ -175,6 +180,15 @@ bool RowsAreSolidColor(SourceSurface* aSurface, int32_t aStartRow, aSurface, IntRect(0, aStartRow, size.width, aRowCount), aColor, aFuzz); } +bool PalettedRowsAreSolidColor(Decoder* aDecoder, int32_t aStartRow, + int32_t aRowCount, uint8_t aColor) { + RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef(); + IntRect frameRect = currentFrame->GetRect(); + IntRect solidColorRect(frameRect.X(), aStartRow, frameRect.Width(), + aRowCount); + return PalettedRectIsSolidColor(aDecoder, solidColorRect, aColor); +} + bool RectIsSolidColor(SourceSurface* aSurface, const IntRect& aRect, BGRAColor aColor, uint8_t aFuzz /* = 0 */) { IntSize surfaceSize = aSurface->GetSize(); @@ -214,6 +228,42 @@ bool RectIsSolidColor(SourceSurface* aSurface, const IntRect& aRect, return true; } +bool PalettedRectIsSolidColor(Decoder* aDecoder, const IntRect& aRect, + uint8_t aColor) { + RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef(); + uint8_t* imageData; + uint32_t imageLength; + currentFrame->GetImageData(&imageData, &imageLength); + ASSERT_TRUE_OR_RETURN(imageData, false); + + // Clamp to the frame rect. If any pixels outside the frame rect are included, + // we immediately fail, because such pixels don't have any "color" in the + // sense this function measures - they're transparent, and that doesn't + // necessarily correspond to any color palette index at all. + IntRect frameRect = currentFrame->GetRect(); + ASSERT_EQ_OR_RETURN(imageLength, uint32_t(frameRect.Area()), false); + IntRect rect = aRect.Intersect(frameRect); + ASSERT_EQ_OR_RETURN(rect.Area(), aRect.Area(), false); + + // Translate |rect| by |frameRect.TopLeft()| to reflect the fact that the + // frame rect's offset doesn't actually mean anything in terms of the + // in-memory representation of the surface. The image data starts at the upper + // left corner of the frame rect, in other words. + rect -= frameRect.TopLeft(); + + // Walk through the image data and make sure that the entire rect has the + // palette index |aColor|. + int32_t rowLength = frameRect.Width(); + for (int32_t row = rect.Y(); row < rect.YMost(); ++row) { + for (int32_t col = rect.X(); col < rect.XMost(); ++col) { + int32_t i = row * rowLength + col; + ASSERT_EQ_OR_RETURN(aColor, imageData[i], false); + } + } + + return true; +} + bool RowHasPixels(SourceSurface* aSurface, int32_t aRow, const vector& aPixels) { ASSERT_GE_OR_RETURN(aRow, 0, false); @@ -322,20 +372,93 @@ void CheckGeneratedSurface(SourceSurface* aSurface, const IntRect& aRect, aOuterColor, aFuzz)); } +void CheckGeneratedPalettedImage(Decoder* aDecoder, const IntRect& aRect) { + RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef(); + IntSize imageSize = currentFrame->GetSize(); + + // This diagram shows how the surface is divided into regions that the code + // below tests for the correct content. The output rect is the bounds of the + // region labeled 'C'. + // + // +---------------------------+ + // | A | + // +---------+--------+--------+ + // | B | C | D | + // +---------+--------+--------+ + // | E | + // +---------------------------+ + + // Check that the output rect itself is all 255's. (Region 'C'.) + EXPECT_TRUE(PalettedRectIsSolidColor(aDecoder, aRect, 255)); + + // Check that the area above the output rect is all 0's. (Region 'A'.) + EXPECT_TRUE(PalettedRectIsSolidColor( + aDecoder, IntRect(0, 0, imageSize.width, aRect.Y()), 0)); + + // Check that the area to the left of the output rect is all 0's. (Region + // 'B'.) + EXPECT_TRUE(PalettedRectIsSolidColor( + aDecoder, IntRect(0, aRect.Y(), aRect.X(), aRect.YMost()), 0)); + + // Check that the area to the right of the output rect is all 0's. (Region + // 'D'.) + const int32_t widthOnRight = imageSize.width - aRect.XMost(); + EXPECT_TRUE(PalettedRectIsSolidColor( + aDecoder, IntRect(aRect.XMost(), aRect.Y(), widthOnRight, aRect.YMost()), + 0)); + + // Check that the area below the output rect is transparent. (Region 'E'.) + const int32_t heightBelow = imageSize.height - aRect.YMost(); + EXPECT_TRUE(PalettedRectIsSolidColor( + aDecoder, IntRect(0, aRect.YMost(), imageSize.width, heightBelow), 0)); +} + void CheckWritePixels(Decoder* aDecoder, SurfaceFilter* aFilter, const Maybe& aOutputRect /* = Nothing() */, const Maybe& aInputRect /* = Nothing() */, const Maybe& aInputWriteRect /* = Nothing() */, const Maybe& aOutputWriteRect /* = Nothing() */, uint8_t aFuzz /* = 0 */) { - CheckTransformedWritePixels(aDecoder, aFilter, BGRAColor::Green(), - BGRAColor::Green(), aOutputRect, aInputRect, - aInputWriteRect, aOutputWriteRect, aFuzz); + IntRect outputRect = aOutputRect.valueOr(IntRect(0, 0, 100, 100)); + IntRect inputRect = aInputRect.valueOr(IntRect(0, 0, 100, 100)); + IntRect inputWriteRect = aInputWriteRect.valueOr(inputRect); + IntRect outputWriteRect = aOutputWriteRect.valueOr(outputRect); + + // Fill the image. + int32_t count = 0; + auto result = aFilter->WritePixels([&] { + ++count; + return AsVariant(BGRAColor::Green().AsPixel()); + }); + EXPECT_EQ(WriteState::FINISHED, result); + EXPECT_EQ(inputWriteRect.Width() * inputWriteRect.Height(), count); + + AssertCorrectPipelineFinalState(aFilter, inputRect, outputRect); + + // Attempt to write more data and make sure nothing changes. + const int32_t oldCount = count; + result = aFilter->WritePixels([&] { + ++count; + return AsVariant(BGRAColor::Green().AsPixel()); + }); + EXPECT_EQ(oldCount, count); + EXPECT_EQ(WriteState::FINISHED, result); + EXPECT_TRUE(aFilter->IsSurfaceFinished()); + Maybe invalidRect = aFilter->TakeInvalidRect(); + EXPECT_TRUE(invalidRect.isNothing()); + + // Attempt to advance to the next row and make sure nothing changes. + aFilter->AdvanceRow(); + EXPECT_TRUE(aFilter->IsSurfaceFinished()); + invalidRect = aFilter->TakeInvalidRect(); + EXPECT_TRUE(invalidRect.isNothing()); + + // Check that the generated image is correct. + CheckGeneratedImage(aDecoder, outputWriteRect, aFuzz); } -void CheckTransformedWritePixels( - Decoder* aDecoder, SurfaceFilter* aFilter, const BGRAColor& aInputColor, - const BGRAColor& aOutputColor, +void CheckPalettedWritePixels( + Decoder* aDecoder, SurfaceFilter* aFilter, const Maybe& aOutputRect /* = Nothing() */, const Maybe& aInputRect /* = Nothing() */, const Maybe& aInputWriteRect /* = Nothing() */, @@ -348,9 +471,9 @@ void CheckTransformedWritePixels( // Fill the image. int32_t count = 0; - auto result = aFilter->WritePixels([&] { + auto result = aFilter->WritePixels([&] { ++count; - return AsVariant(aInputColor.AsPixel()); + return AsVariant(uint8_t(255)); }); EXPECT_EQ(WriteState::FINISHED, result); EXPECT_EQ(inputWriteRect.Width() * inputWriteRect.Height(), count); @@ -359,9 +482,9 @@ void CheckTransformedWritePixels( // Attempt to write more data and make sure nothing changes. const int32_t oldCount = count; - result = aFilter->WritePixels([&] { + result = aFilter->WritePixels([&] { ++count; - return AsVariant(aInputColor.AsPixel()); + return AsVariant(uint8_t(255)); }); EXPECT_EQ(oldCount, count); EXPECT_EQ(WriteState::FINISHED, result); @@ -377,9 +500,15 @@ void CheckTransformedWritePixels( // Check that the generated image is correct. RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef(); - RefPtr surface = currentFrame->GetSourceSurface(); - CheckGeneratedSurface(surface, outputWriteRect, aOutputColor, - BGRAColor::Transparent(), aFuzz); + uint8_t* imageData; + uint32_t imageLength; + currentFrame->GetImageData(&imageData, &imageLength); + ASSERT_TRUE(imageData != nullptr); + ASSERT_EQ(outputWriteRect.Width() * outputWriteRect.Height(), + int32_t(imageLength)); + for (uint32_t i = 0; i < imageLength; ++i) { + ASSERT_EQ(uint8_t(255), imageData[i]); + } } /////////////////////////////////////////////////////////////////////////////// diff --git a/image/test/gtest/Common.h b/image/test/gtest/Common.h index 59be591c673f..57c546f0414e 100644 --- a/image/test/gtest/Common.h +++ b/image/test/gtest/Common.h @@ -158,6 +158,12 @@ already_AddRefed LoadFile(const char* aRelativePath); bool IsSolidColor(gfx::SourceSurface* aSurface, BGRAColor aColor, uint8_t aFuzz = 0); +/** + * @returns true if every pixel of @aDecoder's surface has the palette index + * specified by @aColor. + */ +bool IsSolidPalettedColor(Decoder* aDecoder, uint8_t aColor); + /** * @returns true if every pixel in the range of rows specified by @aStartRow and * @aRowCount of @aSurface is @aColor. @@ -169,6 +175,13 @@ bool IsSolidColor(gfx::SourceSurface* aSurface, BGRAColor aColor, bool RowsAreSolidColor(gfx::SourceSurface* aSurface, int32_t aStartRow, int32_t aRowCount, BGRAColor aColor, uint8_t aFuzz = 0); +/** + * @returns true if every pixel in the range of rows specified by @aStartRow and + * @aRowCount of @aDecoder's surface has the palette index specified by @aColor. + */ +bool PalettedRowsAreSolidColor(Decoder* aDecoder, int32_t aStartRow, + int32_t aRowCount, uint8_t aColor); + /** * @returns true if every pixel in the rect specified by @aRect is @aColor. * @@ -179,6 +192,13 @@ bool RowsAreSolidColor(gfx::SourceSurface* aSurface, int32_t aStartRow, bool RectIsSolidColor(gfx::SourceSurface* aSurface, const gfx::IntRect& aRect, BGRAColor aColor, uint8_t aFuzz = 0); +/** + * @returns true if every pixel in the rect specified by @aRect has the palette + * index specified by @aColor. + */ +bool PalettedRectIsSolidColor(Decoder* aDecoder, const gfx::IntRect& aRect, + uint8_t aColor); + /** * @returns true if the pixels in @aRow of @aSurface match the pixels given in * @aPixels. @@ -224,9 +244,9 @@ class CountResumes : public IResumable { * that requires a decoder to initialize or to allocate surfaces but doesn't * actually need the decoder to do any decoding. * - * XXX(seth): We only need this because SurfaceSink defer to the decoder for - * surface allocation. Once all decoders use SurfacePipe we won't need to do - * that anymore and we can remove this function. + * XXX(seth): We only need this because SurfaceSink and PalettedSurfaceSink + * defer to the decoder for surface allocation. Once all decoders use + * SurfacePipe we won't need to do that anymore and we can remove this function. */ already_AddRefed CreateTrivialDecoder(); @@ -329,6 +349,19 @@ void CheckGeneratedSurface(gfx::SourceSurface* aSurface, const BGRAColor& aInnerColor, const BGRAColor& aOuterColor, uint8_t aFuzz = 0); +/** + * Checks a generated paletted image for correctness. Reports any unexpected + * deviation from the expected image as GTest failures. + * + * @param aDecoder The decoder which contains the image. The decoder's current + * frame will be checked. + * @param aRect The region in the space of the output surface that the filter + * pipeline will actually write to. It's expected that pixels in + * this region have a palette index of 255, while pixels outside + * this region have a palette index of 0. + */ +void CheckGeneratedPalettedImage(Decoder* aDecoder, const gfx::IntRect& aRect); + /** * Tests the result of calling WritePixels() using the provided SurfaceFilter * pipeline. The pipeline must be a normal (i.e., non-paletted) pipeline. @@ -366,13 +399,11 @@ void CheckWritePixels(Decoder* aDecoder, SurfaceFilter* aFilter, /** * Tests the result of calling WritePixels() using the provided SurfaceFilter - * pipeline. Allows for control over the input color to write, and the expected - * output color. + * pipeline. The pipeline must be a paletted pipeline. * @see CheckWritePixels() for documentation of the arguments. */ -void CheckTransformedWritePixels( - Decoder* aDecoder, SurfaceFilter* aFilter, const BGRAColor& aInputColor, - const BGRAColor& aOutputColor, +void CheckPalettedWritePixels( + Decoder* aDecoder, SurfaceFilter* aFilter, const Maybe& aOutputRect = Nothing(), const Maybe& aInputRect = Nothing(), const Maybe& aInputWriteRect = Nothing(), diff --git a/image/test/gtest/TestSwizzleFilter.cpp b/image/test/gtest/TestSwizzleFilter.cpp deleted file mode 100644 index cf775e88b9d3..000000000000 --- a/image/test/gtest/TestSwizzleFilter.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "gtest/gtest.h" - -#include "mozilla/gfx/2D.h" -#include "Common.h" -#include "Decoder.h" -#include "DecoderFactory.h" -#include "SurfaceFilters.h" -#include "SurfacePipe.h" - -using namespace mozilla; -using namespace mozilla::gfx; -using namespace mozilla::image; - -template -void WithSwizzleFilter(const IntSize& aSize, SurfaceFormat aInputFormat, - SurfaceFormat aOutputFormat, bool aPremultiplyAlpha, - Func aFunc) { - RefPtr decoder = CreateTrivialDecoder(); - ASSERT_TRUE(decoder != nullptr); - - WithFilterPipeline( - decoder, std::forward(aFunc), - SwizzleConfig{aInputFormat, aOutputFormat, aPremultiplyAlpha}, - SurfaceConfig{decoder, aSize, aOutputFormat, false}); -} - -TEST(ImageSwizzleFilter, WritePixels_RGBA_to_BGRA) -{ - WithSwizzleFilter( - IntSize(100, 100), SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8A8, - false, [](Decoder* aDecoder, SurfaceFilter* aFilter) { - CheckTransformedWritePixels(aDecoder, aFilter, BGRAColor::Blue(), - BGRAColor::Red()); - }); -} - -TEST(ImageSwizzleFilter, WritePixels_RGBA_to_Premultiplied_BGRA) -{ - WithSwizzleFilter( - IntSize(100, 100), SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8A8, true, - [](Decoder* aDecoder, SurfaceFilter* aFilter) { - CheckTransformedWritePixels( - aDecoder, aFilter, BGRAColor(0x26, 0x00, 0x00, 0x7F, true), - BGRAColor(0x00, 0x00, 0x26, 0x7F), Nothing(), Nothing(), Nothing(), - Nothing(), /* aFuzz */ 1); - }); -} - -TEST(ImageSwizzleFilter, WritePixels_RGBA_to_BGRX) -{ - WithSwizzleFilter( - IntSize(100, 100), SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8X8, - false, [](Decoder* aDecoder, SurfaceFilter* aFilter) { - CheckTransformedWritePixels(aDecoder, aFilter, - BGRAColor(0x26, 0x00, 0x00, 0x7F, true), - BGRAColor(0x00, 0x00, 0x26, 0xFF)); - }); -} - -TEST(ImageSwizzleFilter, WritePixels_RGBA_to_Premultiplied_BGRX) -{ - WithSwizzleFilter( - IntSize(100, 100), SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8X8, true, - [](Decoder* aDecoder, SurfaceFilter* aFilter) { - CheckTransformedWritePixels(aDecoder, aFilter, - BGRAColor(0x26, 0x00, 0x00, 0x7F, true), - BGRAColor(0x00, 0x00, 0x13, 0xFF)); - }); -} - -TEST(ImageSwizzleFilter, WritePixels_RGBA_to_RGBX) -{ - WithSwizzleFilter( - IntSize(100, 100), SurfaceFormat::R8G8B8A8, SurfaceFormat::R8G8B8X8, - false, [](Decoder* aDecoder, SurfaceFilter* aFilter) { - CheckTransformedWritePixels(aDecoder, aFilter, - BGRAColor(0x00, 0x00, 0x26, 0x7F, true), - BGRAColor(0x00, 0x00, 0x26, 0xFF)); - }); -} - -TEST(ImageSwizzleFilter, WritePixels_RGBA_to_Premultiplied_RGRX) -{ - WithSwizzleFilter( - IntSize(100, 100), SurfaceFormat::R8G8B8A8, SurfaceFormat::R8G8B8X8, true, - [](Decoder* aDecoder, SurfaceFilter* aFilter) { - CheckTransformedWritePixels(aDecoder, aFilter, - BGRAColor(0x00, 0x00, 0x26, 0x7F, true), - BGRAColor(0x00, 0x00, 0x13, 0xFF)); - }); -} - -TEST(ImageSwizzleFilter, WritePixels_BGRA_to_BGRX) -{ - WithSwizzleFilter( - IntSize(100, 100), SurfaceFormat::B8G8R8A8, SurfaceFormat::B8G8R8X8, - false, [](Decoder* aDecoder, SurfaceFilter* aFilter) { - CheckTransformedWritePixels(aDecoder, aFilter, - BGRAColor(0x10, 0x26, 0x00, 0x7F, true), - BGRAColor(0x10, 0x26, 0x00, 0xFF)); - }); -} - -TEST(ImageSwizzleFilter, WritePixels_BGRA_to_Premultiplied_BGRA) -{ - WithSwizzleFilter( - IntSize(100, 100), SurfaceFormat::B8G8R8A8, SurfaceFormat::B8G8R8A8, true, - [](Decoder* aDecoder, SurfaceFilter* aFilter) { - CheckTransformedWritePixels( - aDecoder, aFilter, BGRAColor(0x10, 0x26, 0x00, 0x7F, true), - BGRAColor(0x10, 0x26, 0x00, 0x7F), Nothing(), Nothing(), Nothing(), - Nothing(), /* aFuzz */ 1); - }); -} diff --git a/image/test/gtest/moz.build b/image/test/gtest/moz.build index bd677f5e430e..14343d8fb86f 100644 --- a/image/test/gtest/moz.build +++ b/image/test/gtest/moz.build @@ -19,7 +19,6 @@ UNIFIED_SOURCES = [ 'TestRemoveFrameRectFilter.cpp', 'TestStreamingLexer.cpp', 'TestSurfaceSink.cpp', - 'TestSwizzleFilter.cpp', ] # skip the test on windows10-aarch64, aarch64 due to 1544961 diff --git a/image/test/reftest/ico/cur/reftest.list b/image/test/reftest/ico/cur/reftest.list index 0d80ad2f10d8..635136506bcb 100644 --- a/image/test/reftest/ico/cur/reftest.list +++ b/image/test/reftest/ico/cur/reftest.list @@ -1,4 +1,4 @@ # ICO BMP and PNG mixed tests -fuzzy(1-1,67-67) == wrapper.html?pointer.cur wrapper.html?pointer.png +== wrapper.html?pointer.cur wrapper.html?pointer.png diff --git a/image/test/reftest/ico/ico-bmp-32bpp/reftest.list b/image/test/reftest/ico/ico-bmp-32bpp/reftest.list index 3da8a291871f..e05355a2bf05 100644 --- a/image/test/reftest/ico/ico-bmp-32bpp/reftest.list +++ b/image/test/reftest/ico/ico-bmp-32bpp/reftest.list @@ -19,4 +19,4 @@ == ico-size-256x256-32bpp.ico ico-size-256x256-32bpp.png == ico-partial-transparent-32bpp.ico ico-partial-transparent-32bpp.png == ico-transparent-32bpp.ico ico-transparent-32bpp.png -fuzzy(1-1,81-81) == ico-not-square-transparent-32bpp.ico ico-not-square-transparent-32bpp.png +== ico-not-square-transparent-32bpp.ico ico-not-square-transparent-32bpp.png diff --git a/image/test/reftest/ico/ico-mixed/reftest.list b/image/test/reftest/ico/ico-mixed/reftest.list index 9ae81786a5f3..36134e40ab55 100644 --- a/image/test/reftest/ico/ico-mixed/reftest.list +++ b/image/test/reftest/ico/ico-mixed/reftest.list @@ -1,3 +1,3 @@ # ICO BMP and PNG mixed tests -fuzzy(1-1,407-407) == mixed-bmp-png.ico mixed-bmp-png48.png +== mixed-bmp-png.ico mixed-bmp-png48.png diff --git a/image/test/reftest/ico/ico-png/reftest.list b/image/test/reftest/ico/ico-png/reftest.list index 595bd244f00d..002d0e4f3295 100644 --- a/image/test/reftest/ico/ico-png/reftest.list +++ b/image/test/reftest/ico/ico-png/reftest.list @@ -25,5 +25,5 @@ == wrapper.html?xcrn0g04.ico about:blank # Test ICO PNG transparency -fuzzy(1-1,29-29) == transparent-png.ico transparent-png.png +== transparent-png.ico transparent-png.png diff --git a/image/test/reftest/pngsuite-background/reftest.list b/image/test/reftest/pngsuite-background/reftest.list index 54e1817bd864..7f677b8ee9a6 100644 --- a/image/test/reftest/pngsuite-background/reftest.list +++ b/image/test/reftest/pngsuite-background/reftest.list @@ -5,18 +5,18 @@ # identically and thus share common reference HTML files. # bgai4a08 - 8 bit grayscale, alpha, no background chunk, interlaced -fuzzy(1-2,0-1024) == wrapper.html?bgai4a08.png bg__4a08.html +fuzzy-if(cocoaWidget||skiaContent,0-1,0-1024) == wrapper.html?bgai4a08.png bg__4a08.html # bgai4a16 - 16 bit grayscale, alpha, no background chunk, interlaced -fuzzy(1-2,0-1024) == wrapper.html?bgai4a16.png bg__4a16.html +fuzzy-if(cocoaWidget||skiaContent,0-1,0-1024) == wrapper.html?bgai4a16.png bg__4a16.html # bgan6a08 - 3x8 bits rgb color, alpha, no background chunk -fuzzy(1-2,0-1024) == wrapper.html?bgan6a08.png bg__6a08.html +fuzzy-if(cocoaWidget||skiaContent,0-1,0-1024) == wrapper.html?bgan6a08.png bg__6a08.html # bgan6a16 - 3x16 bits rgb color, alpha, no background chunk -fuzzy(1-2,0-1024) == wrapper.html?bgan6a16.png bg__6a16.html +fuzzy-if(cocoaWidget||skiaContent,0-1,0-1024) == wrapper.html?bgan6a16.png bg__6a16.html # bgbn4a08 - 8 bit grayscale, alpha, black background chunk -fuzzy(1-2,0-1024) == wrapper.html?bgbn4a08.png bg__4a08.html +fuzzy-if(cocoaWidget||skiaContent,0-1,0-1024) == wrapper.html?bgbn4a08.png bg__4a08.html # bggn4a16 - 16 bit grayscale, alpha, gray background chunk -fuzzy(1-2,0-1024) == wrapper.html?bggn4a16.png bg__4a16.html +fuzzy-if(cocoaWidget||skiaContent,0-1,0-1024) == wrapper.html?bggn4a16.png bg__4a16.html # bgwn6a08 - 3x8 bits rgb color, alpha, white background chunk -fuzzy(1-2,0-1024) == wrapper.html?bgwn6a08.png bg__6a08.html +fuzzy-if(cocoaWidget||skiaContent,0-1,0-1024) == wrapper.html?bgwn6a08.png bg__6a08.html # bgyn6a16 - 3x16 bits rgb color, alpha, yellow background chunk -fuzzy(1-2,0-1024) == wrapper.html?bgyn6a16.png bg__6a16.html +fuzzy-if(cocoaWidget||skiaContent,0-1,0-1024) == wrapper.html?bgyn6a16.png bg__6a16.html diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list index 0c1efd4d39a1..78f6eaf9c891 100644 --- a/layout/reftests/bugs/reftest.list +++ b/layout/reftests/bugs/reftest.list @@ -318,7 +318,7 @@ fuzzy-if(Android,0-3,0-50) fuzzy-if(skiaContent,0-1,0-133) == 273681-1.html 2736 == 283686-2.html 283686-2-ref.html == 283686-3.html about:blank == 289384-1.xhtml 289384-ref.xhtml -random-if(d2d) fuzzy(0-1,0-16) fuzzy-if(Android,0-8,0-1439) fuzzy-if(webrender,0-9,0-2024) HTTP == 289480.html#top 289480-ref.html # basically-verbatim acid2 test, HTTP for a 404 page -- bug 578114 for the d2d failures +random-if(d2d) fuzzy-if(Android,0-8,0-1439) fuzzy-if(webrender,0-9,0-2024) HTTP == 289480.html#top 289480-ref.html # basically-verbatim acid2 test, HTTP for a 404 page -- bug 578114 for the d2d failures == 290129-1.html 290129-1-ref.html == 291078-1.html 291078-1-ref.html == 291078-2.html 291078-2-ref.html