From: Heeyong Song Date: Thu, 3 Feb 2022 05:21:57 +0000 (+0900) Subject: Add stride to PixelBuffer X-Git-Tag: dali_2.1.17~1 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-adaptor.git;a=commitdiff_plain;h=ba1ebd3a50f1974bde8e180e1fc4ff4007528fe8 Add stride to PixelBuffer Change-Id: I9f7c46e63b78e186a2bb47deb63d35d5a5102f5f --- diff --git a/automated-tests/src/dali-adaptor-internal/utc-Dali-ImageOperations.cpp b/automated-tests/src/dali-adaptor-internal/utc-Dali-ImageOperations.cpp index e7414ff..6c54a62 100644 --- a/automated-tests/src/dali-adaptor-internal/utc-Dali-ImageOperations.cpp +++ b/automated-tests/src/dali-adaptor-internal/utc-Dali-ImageOperations.cpp @@ -402,7 +402,7 @@ int UtcDaliImageOperationsDownscaleBitmap(void) */ int UtcDaliImageOperationsDownscaleInPlacePow2RGB888(void) { - unsigned outWidth = -1, outHeight = -1; + unsigned outWidth = -1, outHeight = -1, outStride = -1; // Do downscaling to 1 x 1 so we can easily assert the value of the single pixel produced: @@ -410,26 +410,29 @@ int UtcDaliImageOperationsDownscaleInPlacePow2RGB888(void) unsigned char check_4x4[16 * 3] = { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff}; - Dali::Internal::Platform::DownscaleInPlacePow2RGB888(check_4x4, 4, 4, 1, 1, BoxDimensionTestBoth, outWidth, outHeight); + Dali::Internal::Platform::DownscaleInPlacePow2RGB888(check_4x4, 4, 4, 4, 1, 1, BoxDimensionTestBoth, outWidth, outHeight, outStride); DALI_TEST_EQUALS(outWidth, 1u, TEST_LOCATION); DALI_TEST_EQUALS(outHeight, 1u, TEST_LOCATION); + DALI_TEST_EQUALS(outStride, 1u, TEST_LOCATION); DALI_TEST_EQUALS(check_4x4[0], (unsigned char)0x7f, TEST_LOCATION); // Scale down a 16 pixel black image with a single white pixel to a 1/16th grey single pixel: unsigned char single_4x4[16 * 3] = { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - Dali::Internal::Platform::DownscaleInPlacePow2RGB888(single_4x4, 4, 4, 1, 1, BoxDimensionTestBoth, outWidth, outHeight); + Dali::Internal::Platform::DownscaleInPlacePow2RGB888(single_4x4, 4, 4, 4, 1, 1, BoxDimensionTestBoth, outWidth, outHeight, outStride); DALI_TEST_EQUALS(outWidth, 1u, TEST_LOCATION); DALI_TEST_EQUALS(outHeight, 1u, TEST_LOCATION); + DALI_TEST_EQUALS(outStride, 1u, TEST_LOCATION); DALI_TEST_EQUALS(single_4x4[0], (unsigned char)0xf, TEST_LOCATION); // Scale down a 16 pixel black image with a single white pixel to a 1/16th grey single pixel: // (white pixel at bottom-right of image) unsigned char single_4x4_2[16 * 3] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff}; - Dali::Internal::Platform::DownscaleInPlacePow2RGB888(single_4x4_2, 4, 4, 1, 1, BoxDimensionTestBoth, outWidth, outHeight); + Dali::Internal::Platform::DownscaleInPlacePow2RGB888(single_4x4_2, 4, 4, 4, 1, 1, BoxDimensionTestBoth, outWidth, outHeight, outStride); DALI_TEST_EQUALS(outWidth, 1u, TEST_LOCATION); DALI_TEST_EQUALS(outHeight, 1u, TEST_LOCATION); + DALI_TEST_EQUALS(outStride, 1u, TEST_LOCATION); DALI_TEST_EQUALS(single_4x4_2[0], (unsigned char)0xf, TEST_LOCATION); // Build a larger ~600 x ~600 uniform magenta image for tests which only test output dimensions: @@ -443,41 +446,50 @@ int UtcDaliImageOperationsDownscaleInPlacePow2RGB888(void) } // Scaling to 0 x 0 should stop at 1 x 1: - Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 352, 352, 0, 0, BoxDimensionTestBoth, outWidth, outHeight); + Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 352, 352, 352, 0, 0, BoxDimensionTestBoth, outWidth, outHeight, outStride); DALI_TEST_EQUALS(outWidth, 1u, TEST_LOCATION); DALI_TEST_EQUALS(outHeight, 1u, TEST_LOCATION); + DALI_TEST_CHECK(outStride == outWidth); // Scaling to 1 x 1 should hit 1 x 1: - Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 608, 608, 1, 1, BoxDimensionTestBoth, outWidth, outHeight); + Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 608, 608, 608, 1, 1, BoxDimensionTestBoth, outWidth, outHeight, outStride); DALI_TEST_EQUALS(outWidth, 1u, TEST_LOCATION); DALI_TEST_EQUALS(outHeight, 1u, TEST_LOCATION); + DALI_TEST_CHECK(outStride == outWidth); // Scaling to original dimensions should NOP: - Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 384, 384, 384, 384, BoxDimensionTestBoth, outWidth, outHeight); + Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 384, 384, 384, 384, 384, BoxDimensionTestBoth, outWidth, outHeight, outStride); DALI_TEST_EQUALS(outWidth, 384u, TEST_LOCATION); DALI_TEST_EQUALS(outHeight, 384u, TEST_LOCATION); + DALI_TEST_CHECK(outStride == outWidth); // More dimension tests: - Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 352, 352, 44, 11, BoxDimensionTestBoth, outWidth, outHeight); + Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 352, 352, 352, 44, 11, BoxDimensionTestBoth, outWidth, outHeight, outStride); DALI_TEST_EQUALS(outWidth, 44u, TEST_LOCATION); DALI_TEST_EQUALS(outHeight, 44u, TEST_LOCATION); + DALI_TEST_CHECK(outStride == outWidth); - Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 384, 384, 3, 48, BoxDimensionTestBoth, outWidth, outHeight); + Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 384, 384, 384, 3, 48, BoxDimensionTestBoth, outWidth, outHeight, outStride); DALI_TEST_EQUALS(outWidth, 48u, TEST_LOCATION); DALI_TEST_EQUALS(outHeight, 48u, TEST_LOCATION); + DALI_TEST_CHECK(outStride == outWidth); - Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 384, 384, 3, 3, BoxDimensionTestBoth, outWidth, outHeight); + Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 384, 384, 384, 3, 3, BoxDimensionTestBoth, outWidth, outHeight, outStride); DALI_TEST_CHECK(outWidth == 3u && outHeight == 3u); + DALI_TEST_CHECK(outStride == outWidth); - Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 320, 320, 5, 5, BoxDimensionTestBoth, outWidth, outHeight); + Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 320, 320, 320, 5, 5, BoxDimensionTestBoth, outWidth, outHeight, outStride); DALI_TEST_CHECK(outWidth == 5u && outHeight == 5u); + DALI_TEST_CHECK(outStride == outWidth); - Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 448, 448, 7, 7, BoxDimensionTestBoth, outWidth, outHeight); + Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 448, 448, 448, 7, 7, BoxDimensionTestBoth, outWidth, outHeight, outStride); DALI_TEST_CHECK(outWidth == 7u && outHeight == 7u); + DALI_TEST_CHECK(outStride == outWidth); - Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 352, 352, 11, 11, BoxDimensionTestBoth, outWidth, outHeight); + Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 352, 352, 352, 11, 11, BoxDimensionTestBoth, outWidth, outHeight, outStride); DALI_TEST_CHECK(outWidth == 11u && outHeight == 11u); + DALI_TEST_CHECK(outStride == outWidth); // Check that no pixel values were modified by the repeated averaging of identical pixels in tests above: unsigned int numNonMagenta = 0u; @@ -495,19 +507,22 @@ int UtcDaliImageOperationsDownscaleInPlacePow2RGB888(void) */ void TestDownscaleOutputsExpectedDimensionsRGBA8888(uint32_t pixels[], unsigned inputWidth, unsigned inputHeight, unsigned int desiredWidth, unsigned int desiredHeight, unsigned int expectedWidth, unsigned int expectedHeight, const char* const location) { - unsigned int resultingWidth = -1, resultingHeight = -1; + unsigned int resultingWidth = -1, resultingHeight = -1, resultingStride = -1; Dali::Internal::Platform::DownscaleInPlacePow2RGBA8888( reinterpret_cast(pixels), inputWidth, inputHeight, + inputWidth, desiredWidth, desiredHeight, BoxDimensionTestBoth, resultingWidth, - resultingHeight); + resultingHeight, + resultingStride); DALI_TEST_EQUALS(resultingWidth, expectedWidth, location); DALI_TEST_EQUALS(resultingHeight, expectedHeight, location); + DALI_TEST_EQUALS(resultingStride, expectedWidth, location); } /** @@ -515,19 +530,22 @@ void TestDownscaleOutputsExpectedDimensionsRGBA8888(uint32_t pixels[], unsigned */ void TestDownscaleOutputsExpectedDimensionsRGB565(uint16_t pixels[], unsigned inputWidth, unsigned inputHeight, unsigned int desiredWidth, unsigned int desiredHeight, unsigned int expectedWidth, unsigned int expectedHeight, const char* const location) { - unsigned int resultingWidth = -1, resultingHeight = -1; + unsigned int resultingWidth = -1, resultingHeight = -1, resultingStride = -1; Dali::Internal::Platform::DownscaleInPlacePow2RGB565( reinterpret_cast(pixels), inputWidth, inputHeight, + inputWidth, desiredWidth, desiredHeight, BoxDimensionTestBoth, resultingWidth, - resultingHeight); + resultingHeight, + resultingStride); DALI_TEST_EQUALS(resultingWidth, expectedWidth, location); DALI_TEST_EQUALS(resultingHeight, expectedHeight, location); + DALI_TEST_EQUALS(resultingStride, expectedWidth, location); } /** @@ -535,19 +553,22 @@ void TestDownscaleOutputsExpectedDimensionsRGB565(uint16_t pixels[], unsigned in */ void TestDownscaleOutputsExpectedDimensions2ComponentPair(uint8_t pixels[], unsigned inputWidth, unsigned inputHeight, unsigned int desiredWidth, unsigned int desiredHeight, unsigned int expectedWidth, unsigned int expectedHeight, const char* const location) { - unsigned int resultingWidth = -1, resultingHeight = -1; + unsigned int resultingWidth = -1, resultingHeight = -1, resultingStride = -1; Dali::Internal::Platform::DownscaleInPlacePow2ComponentPair( pixels, inputWidth, inputHeight, + inputWidth, desiredWidth, desiredHeight, BoxDimensionTestBoth, resultingWidth, - resultingHeight); + resultingHeight, + resultingStride); DALI_TEST_EQUALS(resultingWidth, expectedWidth, location); DALI_TEST_EQUALS(resultingHeight, expectedHeight, location); + DALI_TEST_EQUALS(resultingStride, expectedWidth, location); } /** @@ -555,19 +576,22 @@ void TestDownscaleOutputsExpectedDimensions2ComponentPair(uint8_t pixels[], unsi */ void TestDownscaleOutputsExpectedDimensionsSingleComponent(uint8_t pixels[], unsigned inputWidth, unsigned inputHeight, unsigned int desiredWidth, unsigned int desiredHeight, unsigned int expectedWidth, unsigned int expectedHeight, const char* const location) { - unsigned int resultingWidth = -1, resultingHeight = -1; + unsigned int resultingWidth = -1, resultingHeight = -1, resultingStride = -1; Dali::Internal::Platform::DownscaleInPlacePow2SingleBytePerPixel( pixels, inputWidth, inputHeight, + inputWidth, desiredWidth, desiredHeight, BoxDimensionTestBoth, resultingWidth, - resultingHeight); + resultingHeight, + resultingStride); DALI_TEST_EQUALS(resultingWidth, expectedWidth, location); DALI_TEST_EQUALS(resultingHeight, expectedHeight, location); + DALI_TEST_EQUALS(resultingStride, expectedWidth, location); } /** @@ -581,58 +605,68 @@ int UtcDaliImageOperationsDownscaleInPlacePow2RGBA8888(void) image[i] = 0xffffffff; } unsigned char* const pixels = reinterpret_cast(image); - unsigned int resultingWidth = -1, resultingHeight = -1; + unsigned int resultingWidth = -1, resultingHeight = -1, resultingStride = -1; // Test downscaling where the input size is an exact multiple of the desired size: // (We expect a perfect result here) - DownscaleInPlacePow2RGBA8888(pixels, 600, 600, 75, 75, BoxDimensionTestBoth, resultingWidth, resultingHeight); + DownscaleInPlacePow2RGBA8888(pixels, 600, 600, 600, 75, 75, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride); DALI_TEST_EQUALS(resultingWidth, 75u, TEST_LOCATION); DALI_TEST_EQUALS(resultingHeight, 75u, TEST_LOCATION); + DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION); - DownscaleInPlacePow2RGBA8888(pixels, 512, 512, 16, 16, BoxDimensionTestBoth, resultingWidth, resultingHeight); + DownscaleInPlacePow2RGBA8888(pixels, 512, 512, 512, 16, 16, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride); DALI_TEST_EQUALS(resultingWidth, 16u, TEST_LOCATION); DALI_TEST_EQUALS(resultingHeight, 16u, TEST_LOCATION); + DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION); - DownscaleInPlacePow2RGBA8888(pixels, 512, 64, 16, 2, BoxDimensionTestBoth, resultingWidth, resultingHeight); + DownscaleInPlacePow2RGBA8888(pixels, 512, 64, 512, 16, 2, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride); DALI_TEST_EQUALS(resultingWidth, 16u, TEST_LOCATION); DALI_TEST_EQUALS(resultingHeight, 2u, TEST_LOCATION); + DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION); - DownscaleInPlacePow2RGBA8888(pixels, 64, 1024, 4, 64, BoxDimensionTestBoth, resultingWidth, resultingHeight); + DownscaleInPlacePow2RGBA8888(pixels, 64, 1024, 64, 4, 64, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride); DALI_TEST_EQUALS(resultingWidth, 4u, TEST_LOCATION); DALI_TEST_EQUALS(resultingHeight, 64u, TEST_LOCATION); + DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION); // Test downscaling where the input size is slightly off being an exact multiple of the desired size: // (We expect a perfect match at the end because of rounding-down to an even width and height at each step) - DownscaleInPlacePow2RGBA8888(pixels, 601, 603, 75, 75, BoxDimensionTestBoth, resultingWidth, resultingHeight); + DownscaleInPlacePow2RGBA8888(pixels, 601, 603, 601, 75, 75, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride); DALI_TEST_EQUALS(resultingWidth, 75u, TEST_LOCATION); DALI_TEST_EQUALS(resultingHeight, 75u, TEST_LOCATION); + DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION); - DownscaleInPlacePow2RGBA8888(pixels, 736 + 1, 352 + 3, 23, 11, BoxDimensionTestBoth, resultingWidth, resultingHeight); + DownscaleInPlacePow2RGBA8888(pixels, 736 + 1, 352 + 3, 736 + 1, 23, 11, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride); DALI_TEST_EQUALS(resultingWidth, 23u, TEST_LOCATION); DALI_TEST_EQUALS(resultingHeight, 11u, TEST_LOCATION); + DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION); - DownscaleInPlacePow2RGBA8888(pixels, 384 + 3, 896 + 1, 3, 7, BoxDimensionTestBoth, resultingWidth, resultingHeight); + DownscaleInPlacePow2RGBA8888(pixels, 384 + 3, 896 + 1, 384 + 3, 3, 7, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride); DALI_TEST_EQUALS(resultingWidth, 3u, TEST_LOCATION); DALI_TEST_EQUALS(resultingHeight, 7u, TEST_LOCATION); + DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION); // Test downscales with source dimensions which are under a nice power of two by one: // The target is hit exactly due to losing spare columns or rows at each iteration: - DownscaleInPlacePow2RGBA8888(pixels, 63, 31, 7, 3, BoxDimensionTestBoth, resultingWidth, resultingHeight); + DownscaleInPlacePow2RGBA8888(pixels, 63, 31, 63, 7, 3, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride); DALI_TEST_EQUALS(resultingWidth, 7u, TEST_LOCATION); DALI_TEST_EQUALS(resultingHeight, 3u, TEST_LOCATION); + DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION); // Asking to downscale a bit smaller should stop at the dimensions of the last test as one more halving would go down to 3 x 1, which is too small. - DownscaleInPlacePow2RGBA8888(pixels, 63, 31, 4, 2, BoxDimensionTestBoth, resultingWidth, resultingHeight); + DownscaleInPlacePow2RGBA8888(pixels, 63, 31, 63, 4, 2, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride); DALI_TEST_EQUALS(resultingWidth, 7u, TEST_LOCATION); DALI_TEST_EQUALS(resultingHeight, 3u, TEST_LOCATION); + DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION); // Should stop at almost twice the requested dimensions: - DownscaleInPlacePow2RGBA8888(pixels, 15, 127, 4, 32, BoxDimensionTestBoth, resultingWidth, resultingHeight); + DownscaleInPlacePow2RGBA8888(pixels, 15, 127, 15, 4, 32, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride); DALI_TEST_EQUALS(resultingWidth, 7u, TEST_LOCATION); DALI_TEST_EQUALS(resultingHeight, 63u, TEST_LOCATION); + DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION); // Test downscales to 1 in one or both dimensions: // Parameters: input-x input-y, desired-x, desired-y, expected-x, expected-y @@ -678,22 +712,25 @@ int UtcDaliImageOperationsDownscaleInPlacePow2RGBA8888Nops(void) } const uint32_t imageHash = HashPixels(image, numPixels); unsigned char* const pixels = reinterpret_cast(image); - unsigned int resultingWidth = -1, resultingHeight = -1; + unsigned int resultingWidth = -1, resultingHeight = -1, resultingStride = -1; // Test downscales to the same size: // The point is just to be sure the downscale is a NOP in this case: - DownscaleInPlacePow2RGBA8888(pixels, 600, 600, 600, 600, BoxDimensionTestBoth, resultingWidth, resultingHeight); + DownscaleInPlacePow2RGBA8888(pixels, 600, 600, 600, 600, 600, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride); DALI_TEST_EQUALS(resultingWidth, 600u, TEST_LOCATION); DALI_TEST_EQUALS(resultingHeight, 600u, TEST_LOCATION); + DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION); - DownscaleInPlacePow2RGBA8888(pixels, 512, 128, 512, 128, BoxDimensionTestBoth, resultingWidth, resultingHeight); + DownscaleInPlacePow2RGBA8888(pixels, 512, 128, 512, 512, 128, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride); DALI_TEST_EQUALS(resultingWidth, 512u, TEST_LOCATION); DALI_TEST_EQUALS(resultingHeight, 128u, TEST_LOCATION); + DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION); - DownscaleInPlacePow2RGBA8888(pixels, 17, 1001, 17, 1001, BoxDimensionTestBoth, resultingWidth, resultingHeight); + DownscaleInPlacePow2RGBA8888(pixels, 17, 1001, 17, 17, 1001, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride); DALI_TEST_EQUALS(resultingWidth, 17u, TEST_LOCATION); DALI_TEST_EQUALS(resultingHeight, 1001u, TEST_LOCATION); + DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION); // Test downscales that request a larger size (we never upscale so these are NOPs too): // Parameters: input-x input-y, desired-x, desired-y, expected-x, expected-y @@ -714,8 +751,8 @@ int UtcDaliImageOperationsDownscaleInPlacePow2RGBA8888Nops(void) int UtcDaliImageOperationsDownscaleInPlacePow2RGB565(void) { // Test that calling with null and zero parameters doesn't blow up: - unsigned int outWidth, outHeight; - DownscaleInPlacePow2RGB565(0, 0, 0, 0, 0, BoxDimensionTestBoth, outWidth, outHeight); + unsigned int outWidth, outHeight, outStride; + DownscaleInPlacePow2RGB565(0, 0, 0, 0, 0, 0, BoxDimensionTestBoth, outWidth, outHeight, outStride); uint16_t image[608 * 608]; for(unsigned i = 0; i < sizeof(image) / sizeof(image[0]); ++i) @@ -754,8 +791,8 @@ int UtcDaliImageOperationsDownscaleInPlacePow2RGB565(void) int UtcDaliImageOperationsDownscaleInPlacePow2ComponentPair(void) { // Simple test that a null pointer does not get dereferenced in the function: - unsigned int outWidth, outHeight; - DownscaleInPlacePow2ComponentPair(0, 0, 0, 0, 0, BoxDimensionTestBoth, outWidth, outHeight); + unsigned int outWidth, outHeight, outStride; + DownscaleInPlacePow2ComponentPair(0, 0, 0, 0, 0, 0, BoxDimensionTestBoth, outWidth, outHeight, outStride); // Simple tests of dimensions output: @@ -793,8 +830,8 @@ int UtcDaliImageOperationsDownscaleInPlacePow2ComponentPair(void) int UtcDaliImageOperationsDownscaleInPlacePow2SingleBytePerPixel(void) { // Simple test that a null pointer does not get dereferenced in the function: - unsigned int outWidth, outHeight; - DownscaleInPlacePow2SingleBytePerPixel(0, 0, 0, 0, 0, BoxDimensionTestBoth, outWidth, outHeight); + unsigned int outWidth, outHeight, outStride; + DownscaleInPlacePow2SingleBytePerPixel(0, 0, 0, 0, 0, 0, BoxDimensionTestBoth, outWidth, outHeight, outStride); // Tests of output dimensions from downscaling: uint8_t image[608 * 608]; @@ -1298,7 +1335,7 @@ int UtcDaliImageOperationsPointSampleCheckerboardRGBA888(void) uint32_t outputImage[desiredWidth * desiredHeight]; - Dali::Internal::Platform::PointSample4BPP((const unsigned char*)&image->GetVector()[0], 256, 256, (unsigned char*)outputImage, desiredWidth, desiredHeight); + Dali::Internal::Platform::PointSample4BPP((const unsigned char*)&image->GetVector()[0], 256, 256, 256, (unsigned char*)outputImage, desiredWidth, desiredHeight); DALI_TEST_EQUALS(outputImage[0], (uint32_t)0xff0000ff, TEST_LOCATION); // < Red corner pixel DALI_TEST_EQUALS(outputImage[7], (uint32_t)0xff00ff00, TEST_LOCATION); // < Green corner pixel @@ -1367,7 +1404,7 @@ int UtcDaliImageOperationsPointSampleRGBA888PixelsCorrectColor(void) buffer.resize(outputBufferSize); uint32_t* outputImage = &buffer[0]; - Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, inputWidth, inputHeight, (unsigned char*)outputImage, desiredWidth, desiredHeight); + Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, inputWidth, inputHeight, inputWidth, (unsigned char*)outputImage, desiredWidth, desiredHeight); // Check that all the output pixels are the right color: const uint32_t reference = inputImage[inputWidth * inputHeight / 2]; @@ -1400,38 +1437,38 @@ int UtcDaliImageOperationsPointSampleRGBA888ScaleToSinglePixel(void) // Try several different starting image sizes: // 1x1 -> 1x1: - Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1, 1, (unsigned char*)&outputImage, desiredWidth, desiredHeight); + Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1, 1, 1, (unsigned char*)&outputImage, desiredWidth, desiredHeight); DALI_TEST_EQUALS(outputImage, inputImage[0], TEST_LOCATION); outputImage = 0; // Single-pixel wide tall stripe: - Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1, 1024, (unsigned char*)&outputImage, desiredWidth, desiredHeight); + Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1, 1024, 1, (unsigned char*)&outputImage, desiredWidth, desiredHeight); DALI_TEST_EQUALS(outputImage, inputImage[0], TEST_LOCATION); outputImage = 0; // Single-pixel tall, wide strip: - Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1024, 1, (unsigned char*)&outputImage, desiredWidth, desiredHeight); + Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1024, 1, 1024, (unsigned char*)&outputImage, desiredWidth, desiredHeight); DALI_TEST_EQUALS(outputImage, inputImage[0], TEST_LOCATION); outputImage = 0; // Square mid-size image: - Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 103, 103, (unsigned char*)&outputImage, desiredWidth, desiredHeight); + Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 103, 103, 103, (unsigned char*)&outputImage, desiredWidth, desiredHeight); DALI_TEST_EQUALS(outputImage, inputImage[0], TEST_LOCATION); outputImage = 0; // Wide mid-size image: - Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 313, 79, (unsigned char*)&outputImage, desiredWidth, desiredHeight); + Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 313, 79, 313, (unsigned char*)&outputImage, desiredWidth, desiredHeight); DALI_TEST_EQUALS(outputImage, inputImage[0], TEST_LOCATION); outputImage = 0; // Tall mid-size image: - Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 53, 467, (unsigned char*)&outputImage, desiredWidth, desiredHeight); + Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 53, 467, 53, (unsigned char*)&outputImage, desiredWidth, desiredHeight); DALI_TEST_EQUALS(outputImage, inputImage[0], TEST_LOCATION); outputImage = 0; // 0 x 0 input image (make sure output not written to): outputImage = 0xDEADBEEF; - Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 0, 0, (unsigned char*)&outputImage, desiredWidth, desiredHeight); + Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 0, 0, 0, (unsigned char*)&outputImage, desiredWidth, desiredHeight); DALI_TEST_EQUALS(outputImage, (uint32_t)0xDEADBEEF, TEST_LOCATION); outputImage = 0; @@ -1452,31 +1489,31 @@ int UtcDaliImageOperationsPointSampleRGBA888N(void) // Try several different starting image sizes: // 1x1 -> 1x1: - Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1, 1, (unsigned char*)outputImage, 0, 0); + Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1, 1, 1, (unsigned char*)outputImage, 0, 0); DALI_TEST_EQUALS(0xaaaaaaaa, outputImage[0], TEST_LOCATION); // Single-pixel wide tall stripe: - Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1, 102, (unsigned char*)outputImage, 0, 33); + Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1, 102, 1, (unsigned char*)outputImage, 0, 33); DALI_TEST_EQUALS(0xaaaaaaaa, outputImage[0], TEST_LOCATION); // Single-pixel tall, wide strip: - Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 102, 1, (unsigned char*)outputImage, 0, 67); + Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 102, 1, 102, (unsigned char*)outputImage, 0, 67); DALI_TEST_EQUALS(0xaaaaaaaa, outputImage[0], TEST_LOCATION); // Square mid-size image: - Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 103, 103, (unsigned char*)outputImage, 21, 0); + Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 103, 103, 103, (unsigned char*)outputImage, 21, 0); DALI_TEST_EQUALS(0xaaaaaaaa, outputImage[0], TEST_LOCATION); // Wide mid-size image to 0 height - Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 313, 79, (unsigned char*)outputImage, 99, 0); + Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 313, 79, 313, (unsigned char*)outputImage, 99, 0); DALI_TEST_EQUALS(0xaaaaaaaa, outputImage[0], TEST_LOCATION); // Tall mid-size image to 0 height, over width - Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 53, 46, (unsigned char*)outputImage, 9999, 0); + Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 53, 46, 53, (unsigned char*)outputImage, 9999, 0); DALI_TEST_EQUALS(0xaaaaaaaa, outputImage[0], TEST_LOCATION); // 0 x 0 input image: - Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 0, 0, (unsigned char*)outputImage, 200, 99); + Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 0, 0, 0, (unsigned char*)outputImage, 200, 99); DALI_TEST_EQUALS(0xaaaaaaaa, outputImage[0], TEST_LOCATION); END_TEST; diff --git a/automated-tests/src/dali-adaptor/utc-Dali-PixelBuffer.cpp b/automated-tests/src/dali-adaptor/utc-Dali-PixelBuffer.cpp index 9958472..bed76e1 100644 --- a/automated-tests/src/dali-adaptor/utc-Dali-PixelBuffer.cpp +++ b/automated-tests/src/dali-adaptor/utc-Dali-PixelBuffer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * Copyright (c) 2022 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -227,6 +227,7 @@ int UtcDaliPixelBufferConvert(void) DALI_TEST_CHECK(pixelData); DALI_TEST_EQUALS(pixelData.GetWidth(), 10, TEST_LOCATION); DALI_TEST_EQUALS(pixelData.GetHeight(), 10, TEST_LOCATION); + DALI_TEST_EQUALS(pixelData.GetStride(), 10, TEST_LOCATION); DALI_TEST_EQUALS(pixelData.GetPixelFormat(), Pixel::RGB565, TEST_LOCATION); // Try drawing it @@ -261,6 +262,7 @@ int UtcDaliPixelBufferGetWidth(void) FillCheckerboard(pixbuf); DALI_TEST_EQUALS(pixbuf.GetWidth(), 10, TEST_LOCATION); + DALI_TEST_EQUALS(pixbuf.GetStride(), 10, TEST_LOCATION); END_TEST; } diff --git a/dali/devel-api/adaptor-framework/pixel-buffer.cpp b/dali/devel-api/adaptor-framework/pixel-buffer.cpp index e5856c3..e033afa 100644 --- a/dali/devel-api/adaptor-framework/pixel-buffer.cpp +++ b/dali/devel-api/adaptor-framework/pixel-buffer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2022 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -84,6 +84,11 @@ unsigned int PixelBuffer::GetHeight() const return GetImplementation(*this).GetHeight(); } +unsigned int PixelBuffer::GetStride() const +{ + return GetImplementation(*this).GetStride(); +} + Pixel::Format PixelBuffer::GetPixelFormat() const { return GetImplementation(*this).GetPixelFormat(); diff --git a/dali/devel-api/adaptor-framework/pixel-buffer.h b/dali/devel-api/adaptor-framework/pixel-buffer.h index 9e6f58a..51c6739 100644 --- a/dali/devel-api/adaptor-framework/pixel-buffer.h +++ b/dali/devel-api/adaptor-framework/pixel-buffer.h @@ -2,7 +2,7 @@ #define DALI_PIXEL_BUFFER_H /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2022 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -157,6 +157,14 @@ public: unsigned int GetHeight() const; /** + * @brief Gets the stride of the buffer in pixels. + * + * @SINCE_2_1.17 + * @return The stride of the buffer in pixels. 0 means the buffer is tightly packed. + */ + unsigned int GetStride() const; + + /** * @brief Gets the pixel format. * * @SINCE_1_2.46 diff --git a/dali/internal/graphics/gles-impl/egl-graphics-controller.cpp b/dali/internal/graphics/gles-impl/egl-graphics-controller.cpp index 56c5f2d..84325ae 100644 --- a/dali/internal/graphics/gles-impl/egl-graphics-controller.cpp +++ b/dali/internal/graphics/gles-impl/egl-graphics-controller.cpp @@ -663,6 +663,8 @@ void EglGraphicsController::ProcessTextureUpdateQueue() } mGlAbstraction->PixelStorei(GL_UNPACK_ALIGNMENT, 1); + mGlAbstraction->PixelStorei(GL_UNPACK_ROW_LENGTH, info.srcStride); + mCurrentContext->BindTexture(bindTarget, texture->GetTextureTypeId(), texture->GetGLTexture()); if(!isSubImage) diff --git a/dali/internal/imaging/common/alpha-mask.cpp b/dali/internal/imaging/common/alpha-mask.cpp index 5205da5..9abdfec 100644 --- a/dali/internal/imaging/common/alpha-mask.cpp +++ b/dali/internal/imaging/common/alpha-mask.cpp @@ -51,9 +51,8 @@ void ApplyMaskToAlphaChannel(PixelBuffer& buffer, const PixelBuffer& mask) unsigned char* destBuffer = buffer.GetBuffer(); unsigned int destBytesPerPixel = Dali::Pixel::GetBytesPerPixel(buffer.GetPixelFormat()); - - int srcOffset = 0; - int destOffset = 0; + unsigned int srcStrideBytes = mask.GetStride() * srcBytesPerPixel; + unsigned int destStrideBytes = buffer.GetStride() * destBytesPerPixel; // if image is premultiplied, the other channels of the image need to multiply by alpha. if(buffer.IsAlphaPreMultiplied()) @@ -71,6 +70,9 @@ void ApplyMaskToAlphaChannel(PixelBuffer& buffer, const PixelBuffer& mask) { for(unsigned int row = 0; row < buffer.GetHeight(); ++row) { + int srcOffset = 0; + int destOffset = 0; + for(unsigned int col = 0; col < buffer.GetWidth(); ++col) { auto srcAlpha = srcBuffer[srcOffset + srcAlphaByteOffset] & srcAlphaMask; @@ -96,6 +98,8 @@ void ApplyMaskToAlphaChannel(PixelBuffer& buffer, const PixelBuffer& mask) srcOffset += srcBytesPerPixel; destOffset += destBytesPerPixel; } + srcBuffer += srcStrideBytes; + destBuffer += destStrideBytes; } } } @@ -103,6 +107,9 @@ void ApplyMaskToAlphaChannel(PixelBuffer& buffer, const PixelBuffer& mask) { for(unsigned int row = 0; row < buffer.GetHeight(); ++row) { + int srcOffset = 0; + int destOffset = 0; + for(unsigned int col = 0; col < buffer.GetWidth(); ++col) { unsigned char srcAlpha = srcBuffer[srcOffset + srcAlphaByteOffset] & srcAlphaMask; @@ -116,6 +123,8 @@ void ApplyMaskToAlphaChannel(PixelBuffer& buffer, const PixelBuffer& mask) srcOffset += srcBytesPerPixel; destOffset += destBytesPerPixel; } + srcBuffer += srcStrideBytes; + destBuffer += destStrideBytes; } } } @@ -136,12 +145,14 @@ PixelBufferPtr CreateNewMaskedBuffer(const PixelBuffer& buffer, const PixelBuffe srcAlphaMask = 0xFF; } - unsigned int srcBytesPerPixel = Dali::Pixel::GetBytesPerPixel(srcPixelFormat); unsigned char* srcBuffer = mask.GetBuffer(); + unsigned int srcBytesPerPixel = Dali::Pixel::GetBytesPerPixel(srcPixelFormat); + unsigned int srcStrideBytes = mask.GetStride() * srcBytesPerPixel; // Set up source color offsets Dali::Pixel::Format srcColorPixelFormat = buffer.GetPixelFormat(); unsigned int srcColorBytesPerPixel = Dali::Pixel::GetBytesPerPixel(srcColorPixelFormat); + unsigned int srcColorStrideBytes = buffer.GetStride() * srcColorBytesPerPixel; // Setup destination offsets Dali::Pixel::Format destPixelFormat = Dali::Pixel::RGBA8888; @@ -150,19 +161,20 @@ PixelBufferPtr CreateNewMaskedBuffer(const PixelBuffer& buffer, const PixelBuffe int destAlphaMask = 0; Dali::Pixel::GetAlphaOffsetAndMask(destPixelFormat, destAlphaByteOffset, destAlphaMask); - PixelBufferPtr newPixelBuffer = PixelBuffer::New(buffer.GetWidth(), buffer.GetHeight(), destPixelFormat); - unsigned char* destBuffer = newPixelBuffer->GetBuffer(); - unsigned char* oldBuffer = buffer.GetBuffer(); + PixelBufferPtr newPixelBuffer = PixelBuffer::New(buffer.GetWidth(), buffer.GetHeight(), destPixelFormat); + unsigned char* destBuffer = newPixelBuffer->GetBuffer(); + unsigned char* oldBuffer = buffer.GetBuffer(); + unsigned int destStrideBytes = newPixelBuffer->GetStride() * destBytesPerPixel; - int srcAlphaOffset = 0; - int srcColorOffset = 0; - int destOffset = 0; - bool hasAlpha = Dali::Pixel::HasAlpha(buffer.GetPixelFormat()); + bool hasAlpha = Dali::Pixel::HasAlpha(buffer.GetPixelFormat()); unsigned char destAlpha = 0; for(unsigned int row = 0; row < buffer.GetHeight(); ++row) { + int srcAlphaOffset = 0; + int srcColorOffset = 0; + int destOffset = 0; for(unsigned int col = 0; col < buffer.GetWidth(); ++col) { unsigned char srcAlpha = srcBuffer[srcAlphaOffset + srcAlphaByteOffset] & srcAlphaMask; @@ -186,6 +198,9 @@ PixelBufferPtr CreateNewMaskedBuffer(const PixelBuffer& buffer, const PixelBuffe srcAlphaOffset += srcBytesPerPixel; destOffset += destBytesPerPixel; } + oldBuffer += srcColorStrideBytes; + srcBuffer += srcStrideBytes; + destBuffer += destStrideBytes; } return newPixelBuffer; diff --git a/dali/internal/imaging/common/gaussian-blur.cpp b/dali/internal/imaging/common/gaussian-blur.cpp index c10c577..01b5b5b 100644 --- a/dali/internal/imaging/common/gaussian-blur.cpp +++ b/dali/internal/imaging/common/gaussian-blur.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2022 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,6 +15,7 @@ */ // EXTERNAL INCLUDES +#include #include #include @@ -32,6 +33,8 @@ void ConvoluteAndTranspose(unsigned char* inBuffer, unsigned char* outBuffer, const unsigned int bufferWidth, const unsigned int bufferHeight, + const unsigned int inBufferStride, + const unsigned int outBufferStride, const float blurRadius) { // Calculate the weights for gaussian blur @@ -73,7 +76,7 @@ void ConvoluteAndTranspose(unsigned char* inBuffer, for(unsigned int y = 0; y < bufferHeight; y++) { unsigned int targetPixelIndex = y; - unsigned int ioffset = y * bufferWidth; + unsigned int ioffset = y * inBufferStride; for(unsigned int x = 0; x < bufferWidth; x++) { float r = 0.0f, g = 0.0f, b = 0.0f, a = 0.0f; @@ -98,7 +101,7 @@ void ConvoluteAndTranspose(unsigned char* inBuffer, outBuffer[targetPixelIndex * 4 + 2] = std::max(0, std::min(static_cast(b + 0.5f), 255)); outBuffer[targetPixelIndex * 4 + 3] = std::max(0, std::min(static_cast(a + 0.5f), 255)); - targetPixelIndex += bufferHeight; + targetPixelIndex += outBufferStride; } } @@ -109,18 +112,24 @@ void PerformGaussianBlurRGBA(PixelBuffer& buffer, const float blurRadius) { unsigned int bufferWidth = buffer.GetWidth(); unsigned int bufferHeight = buffer.GetHeight(); + unsigned int bufferStride = buffer.GetStride(); + + if(bufferWidth == 0 || bufferHeight == 0 || bufferStride == 0 || buffer.GetPixelFormat() != Pixel::RGBA8888) + { + DALI_LOG_ERROR("Invalid buffer!\n"); + return; + } // Create a temporary buffer for the two-pass blur PixelBufferPtr softShadowImageBuffer = PixelBuffer::New(bufferWidth, bufferHeight, Pixel::RGBA8888); - memcpy(softShadowImageBuffer->GetBuffer(), buffer.GetBuffer(), 4u * bufferWidth * bufferHeight); // We perform the blur first but write its output image buffer transposed, so that we // can just do it in two passes. The first pass blurs horizontally and transposes, the // second pass does the same, but as the image is now transposed, it's really doing a // vertical blur. The second transposition makes the image the right way up again. This // is much faster than doing a 2D convolution. - ConvoluteAndTranspose(buffer.GetBuffer(), softShadowImageBuffer->GetBuffer(), bufferWidth, bufferHeight, blurRadius); - ConvoluteAndTranspose(softShadowImageBuffer->GetBuffer(), buffer.GetBuffer(), bufferHeight, bufferWidth, blurRadius); + ConvoluteAndTranspose(buffer.GetBuffer(), softShadowImageBuffer->GetBuffer(), bufferWidth, bufferHeight, bufferStride, bufferHeight, blurRadius); + ConvoluteAndTranspose(softShadowImageBuffer->GetBuffer(), buffer.GetBuffer(), bufferHeight, bufferWidth, bufferHeight, bufferStride, blurRadius); // On leaving scope, softShadowImageBuffer will get destroyed. } diff --git a/dali/internal/imaging/common/image-operations.cpp b/dali/internal/imaging/common/image-operations.cpp index 772d26f..360c9ad 100644 --- a/dali/internal/imaging/common/image-operations.cpp +++ b/dali/internal/imaging/common/image-operations.cpp @@ -57,7 +57,7 @@ const float RAD_315 = RAD_225 + Math::PI_2; ///< 315 degrees in radians; using Integration::Bitmap; using Integration::BitmapPtr; -typedef unsigned char PixelBuffer; +typedef uint8_t PixelBuffer; /** * @brief 4 byte pixel structure. @@ -505,6 +505,7 @@ ImageDimensions CalculateDesiredDimensions(unsigned int bitmapWidth, unsigned in * @param[in] pixelsIn The input buffer. * @param[in] widthIn The width of the input buffer. * @param[in] heightIn The height of the input buffer. + * @param[in] strideIn The stride of the input buffer. * @param[in] pixelSize The size of the pixel. * @param[out] pixelsOut The rotated output buffer. * @param[out] widthOut The width of the output buffer. @@ -515,6 +516,7 @@ ImageDimensions CalculateDesiredDimensions(unsigned int bitmapWidth, unsigned in bool Rotate90(const uint8_t* const pixelsIn, unsigned int widthIn, unsigned int heightIn, + unsigned int strideIn, unsigned int pixelSize, uint8_t*& pixelsOut, unsigned int& widthOut, @@ -525,6 +527,7 @@ bool Rotate90(const uint8_t* const pixelsIn, heightOut = widthIn; // Allocate memory for the rotated buffer. + // Output buffer is tightly packed pixelsOut = static_cast(malloc(widthOut * heightOut * pixelSize)); if(nullptr == pixelsOut) { @@ -538,7 +541,7 @@ bool Rotate90(const uint8_t* const pixelsIn, // Rotate the buffer. for(unsigned int y = 0u; y < heightIn; ++y) { - const unsigned int srcLineIndex = y * widthIn; + const unsigned int srcLineIndex = y * strideIn; const unsigned int dstX = y; for(unsigned int x = 0u; x < widthIn; ++x) { @@ -566,6 +569,7 @@ bool Rotate90(const uint8_t* const pixelsIn, * @param[in] pixelsIn The input buffer. * @param[in] widthIn The width of the input buffer. * @param[in] heightIn The height of the input buffer. + * @param[in] strideIn The stride of the input buffer. * @param[in] pixelSize The size of the pixel. * @param[out] pixelsOut The rotated output buffer. * @@ -574,10 +578,12 @@ bool Rotate90(const uint8_t* const pixelsIn, bool Rotate180(const uint8_t* const pixelsIn, unsigned int widthIn, unsigned int heightIn, + unsigned int strideIn, unsigned int pixelSize, uint8_t*& pixelsOut) { // Allocate memory for the rotated buffer. + // Output buffer is tightly packed pixelsOut = static_cast(malloc(widthIn * heightIn * pixelSize)); if(nullptr == pixelsOut) { @@ -588,7 +594,7 @@ bool Rotate180(const uint8_t* const pixelsIn, // Rotate the buffer. for(unsigned int y = 0u; y < heightIn; ++y) { - const unsigned int srcLineIndex = y * widthIn; + const unsigned int srcLineIndex = y * strideIn; const unsigned int dstY = heightIn - y - 1u; for(unsigned int x = 0u; x < widthIn; ++x) { @@ -616,6 +622,7 @@ bool Rotate180(const uint8_t* const pixelsIn, * @param[in] pixelsIn The input buffer. * @param[in] widthIn The width of the input buffer. * @param[in] heightIn The height of the input buffer. + * @param[in] strideIn The stride of the input buffer. * @param[in] pixelSize The size of the pixel. * @param[out] pixelsOut The rotated output buffer. * @param[out] widthOut The width of the output buffer. @@ -626,6 +633,7 @@ bool Rotate180(const uint8_t* const pixelsIn, bool Rotate270(const uint8_t* const pixelsIn, unsigned int widthIn, unsigned int heightIn, + unsigned int strideIn, unsigned int pixelSize, uint8_t*& pixelsOut, unsigned int& widthOut, @@ -636,6 +644,7 @@ bool Rotate270(const uint8_t* const pixelsIn, heightOut = widthIn; // Allocate memory for the rotated buffer. + // Output buffer is tightly packed pixelsOut = static_cast(malloc(widthOut * heightOut * pixelSize)); if(nullptr == pixelsOut) { @@ -649,7 +658,7 @@ bool Rotate270(const uint8_t* const pixelsIn, // Rotate the buffer. for(unsigned int y = 0u; y < heightIn; ++y) { - const unsigned int srcLineIndex = y * widthIn; + const unsigned int srcLineIndex = y * strideIn; const unsigned int dstX = widthOut - y - 1u; for(unsigned int x = 0u; x < widthIn; ++x) { @@ -675,6 +684,7 @@ bool Rotate270(const uint8_t* const pixelsIn, * * @param[in] srcBufferPtr Pointer to the input pixel buffer. * @param[in] srcWidth The width of the input pixel buffer. + * @param[in] srcStride The stride of the input pixel buffer. * @param[in] pixelSize The size of the pixel. * @param[in,out] dstPixelBuffer Pointer to the output pixel buffer. * @param[in] dstWidth The width of the output pixel buffer. @@ -684,6 +694,7 @@ bool Rotate270(const uint8_t* const pixelsIn, */ void HorizontalSkew(const uint8_t* const srcBufferPtr, int srcWidth, + int srcStride, unsigned int pixelSize, uint8_t*& dstBufferPtr, int dstWidth, @@ -703,7 +714,7 @@ void HorizontalSkew(const uint8_t* const srcBufferPtr, for(i = 0u; i < srcWidth; ++i) { // Loop through row pixels - const unsigned int srcIndex = pixelSize * (row * srcWidth + i); + const unsigned int srcIndex = pixelSize * (row * srcStride + i); unsigned char src[4u] = {0u, 0u, 0u, 0u}; for(unsigned int channel = 0u; channel < pixelSize; ++channel) @@ -766,6 +777,7 @@ void HorizontalSkew(const uint8_t* const srcBufferPtr, * @param[in] srcBufferPtr Pointer to the input pixel buffer. * @param[in] srcWidth The width of the input pixel buffer. * @param[in] srcHeight The height of the input pixel buffer. + * @param[in] srcStride The stride of the input pixel buffer. * @param[in] pixelSize The size of the pixel. * @param[in,out] dstPixelBuffer Pointer to the output pixel buffer. * @param[in] dstWidth The width of the output pixel buffer. @@ -777,6 +789,7 @@ void HorizontalSkew(const uint8_t* const srcBufferPtr, void VerticalSkew(const uint8_t* const srcBufferPtr, int srcWidth, int srcHeight, + int srcStride, unsigned int pixelSize, uint8_t*& dstBufferPtr, int dstWidth, @@ -803,7 +816,7 @@ void VerticalSkew(const uint8_t* const srcBufferPtr, for(i = 0; i < srcHeight; ++i) { // Loop through column pixels - const unsigned int srcIndex = pixelSize * (i * srcWidth + column); + const unsigned int srcIndex = pixelSize * (i * srcStride + column); unsigned char src[4u] = {0u, 0u, 0u, 0u}; for(unsigned int channel = 0u; channel < pixelSize; ++channel) @@ -932,6 +945,7 @@ Dali::Devel::PixelBuffer CropAndPadForFittingMode(Dali::Devel::PixelBuffer& bitm { const unsigned int inputWidth = bitmap.GetWidth(); const unsigned int inputHeight = bitmap.GetHeight(); + const unsigned int inputStride = bitmap.GetStride(); if(desiredDimensions.GetWidth() < 1u || desiredDimensions.GetHeight() < 1u) { @@ -984,7 +998,7 @@ Dali::Devel::PixelBuffer CropAndPadForFittingMode(Dali::Devel::PixelBuffer& bitm // Add some pre-calculated offsets to the bitmap pointers so this is not done within a loop. // The cropping is added to the source pointer, and the padding is added to the destination. const auto bytesPerPixel = Pixel::GetBytesPerPixel(pixelFormat); - const PixelBuffer* const sourcePixels = bitmap.GetBuffer() + ((((scanlinesToCrop / 2) * inputWidth) + (columnsToCrop / 2)) * bytesPerPixel); + const PixelBuffer* const sourcePixels = bitmap.GetBuffer() + ((((scanlinesToCrop / 2) * inputStride) + (columnsToCrop / 2)) * bytesPerPixel); PixelBuffer* const targetPixels = croppedBitmap.GetBuffer(); PixelBuffer* const targetPixelsActive = targetPixels + ((((scanlinesToPad / 2) * desiredWidth) + (columnsToPad / 2)) * bytesPerPixel); DALI_ASSERT_DEBUG(sourcePixels && targetPixels); @@ -992,7 +1006,7 @@ Dali::Devel::PixelBuffer CropAndPadForFittingMode(Dali::Devel::PixelBuffer& bitm // Copy the image data to the new bitmap. // Optimize to a single memcpy if the left and right edges don't need a crop or a pad. unsigned int outputSpan(desiredWidth * bytesPerPixel); - if(columnsToCrop == 0 && columnsToPad == 0) + if(columnsToCrop == 0 && columnsToPad == 0 && inputStride == inputWidth) { memcpy(targetPixelsActive, sourcePixels, (desiredHeight - scanlinesToPad) * outputSpan); } @@ -1000,7 +1014,7 @@ Dali::Devel::PixelBuffer CropAndPadForFittingMode(Dali::Devel::PixelBuffer& bitm { // The width needs to change (due to either a crop or a pad), so we copy a scanline at a time. // Precalculate any constants to optimize the inner loop. - const unsigned int inputSpan(inputWidth * bytesPerPixel); + const unsigned int inputSpan(inputStride * bytesPerPixel); const unsigned int copySpan((desiredWidth - columnsToPad) * bytesPerPixel); const unsigned int scanlinesToCopy(desiredHeight - scanlinesToPad); @@ -1078,6 +1092,7 @@ Dali::Devel::PixelBuffer DownscaleBitmap(Dali::Devel::PixelBuffer bitmap, // Source dimensions as loaded from resources (e.g. filesystem): auto bitmapWidth = bitmap.GetWidth(); auto bitmapHeight = bitmap.GetHeight(); + auto bitmapStride = bitmap.GetStride(); // Desired dimensions (the rectangle to fit the source image to): auto desiredWidth = desired.GetWidth(); auto desiredHeight = desired.GetHeight(); @@ -1092,8 +1107,8 @@ Dali::Devel::PixelBuffer DownscaleBitmap(Dali::Devel::PixelBuffer bitmap, auto pixelFormat = bitmap.GetPixelFormat(); // Do the fast power of 2 iterated box filter to get to roughly the right side if the filter mode requests that: - unsigned int shrunkWidth = -1, shrunkHeight = -1; - DownscaleInPlacePow2(bitmap.GetBuffer(), pixelFormat, bitmapWidth, bitmapHeight, desiredWidth, desiredHeight, fittingMode, samplingMode, shrunkWidth, shrunkHeight); + unsigned int shrunkWidth = -1, shrunkHeight = -1, outStride = -1; + DownscaleInPlacePow2(bitmap.GetBuffer(), pixelFormat, bitmapWidth, bitmapHeight, bitmapStride, desiredWidth, desiredHeight, fittingMode, samplingMode, shrunkWidth, shrunkHeight, outStride); // Work out the dimensions of the downscaled bitmap, given the scaling mode and desired dimensions: const ImageDimensions filteredDimensions = FitToScalingMode(ImageDimensions(desiredWidth, desiredHeight), ImageDimensions(shrunkWidth, shrunkHeight), fittingMode); @@ -1113,11 +1128,11 @@ Dali::Devel::PixelBuffer DownscaleBitmap(Dali::Devel::PixelBuffer bitmap, { if(samplingMode == SamplingMode::LINEAR || samplingMode == SamplingMode::BOX_THEN_LINEAR) { - LinearSample(bitmap.GetBuffer(), ImageDimensions(shrunkWidth, shrunkHeight), pixelFormat, outputBitmap.GetBuffer(), filteredDimensions); + LinearSample(bitmap.GetBuffer(), ImageDimensions(shrunkWidth, shrunkHeight), outStride, pixelFormat, outputBitmap.GetBuffer(), filteredDimensions); } else { - PointSample(bitmap.GetBuffer(), shrunkWidth, shrunkHeight, pixelFormat, outputBitmap.GetBuffer(), filteredWidth, filteredHeight); + PointSample(bitmap.GetBuffer(), shrunkWidth, shrunkHeight, outStride, pixelFormat, outputBitmap.GetBuffer(), filteredWidth, filteredHeight); } filtered = true; } @@ -1126,6 +1141,7 @@ Dali::Devel::PixelBuffer DownscaleBitmap(Dali::Devel::PixelBuffer bitmap, // Copy out the 2^x downscaled, box-filtered pixels if no secondary filter (point or linear) was applied: if(filtered == false && (shrunkWidth < bitmapWidth || shrunkHeight < bitmapHeight)) { + // The buffer is downscaled and it is tightly packed. We don't need to set a stride. outputBitmap = MakePixelBuffer(bitmap.GetBuffer(), pixelFormat, shrunkWidth, shrunkHeight); } } @@ -1195,11 +1211,13 @@ template< void DownscaleInPlacePow2Generic(unsigned char* const pixels, const unsigned int inputWidth, const unsigned int inputHeight, + const unsigned int inputStride, const unsigned int desiredWidth, const unsigned int desiredHeight, BoxDimensionTest dimensionTest, unsigned& outWidth, - unsigned& outHeight) + unsigned& outHeight, + unsigned& outStride) { if(pixels == 0) { @@ -1209,12 +1227,14 @@ void DownscaleInPlacePow2Generic(unsigned char* const pixels, // Scale the image until it would be smaller than desired, stopping if the // resulting height or width would be less than 1: - unsigned int scaledWidth = inputWidth, scaledHeight = inputHeight; + unsigned int scaledWidth = inputWidth, scaledHeight = inputHeight, stride = inputStride; while(ContinueScaling(dimensionTest, scaledWidth, scaledHeight, desiredWidth, desiredHeight)) { - const unsigned int lastWidth = scaledWidth; + const unsigned int lastWidth = scaledWidth; + const unsigned int lastStride = stride; scaledWidth >>= 1u; scaledHeight >>= 1u; + stride = scaledWidth; DALI_LOG_INFO(gImageOpsLogFilter, Dali::Integration::Log::Verbose, "Scaling to %u\t%u.\n", scaledWidth, scaledHeight); @@ -1224,8 +1244,8 @@ void DownscaleInPlacePow2Generic(unsigned char* const pixels, for(unsigned int y = 0; y <= lastScanlinePair; ++y) { // Scale two scanlines horizontally: - HalveScanlineInPlace(&pixels[y * 2 * lastWidth * BYTES_PER_PIXEL], lastWidth); - HalveScanlineInPlace(&pixels[(y * 2 + 1) * lastWidth * BYTES_PER_PIXEL], lastWidth); + HalveScanlineInPlace(&pixels[y * 2 * lastStride * BYTES_PER_PIXEL], lastWidth); + HalveScanlineInPlace(&pixels[(y * 2 + 1) * lastStride * BYTES_PER_PIXEL], lastWidth); // Scale vertical pairs of pixels while the last two scanlines are still warm in // the CPU cache(s): @@ -1233,8 +1253,8 @@ void DownscaleInPlacePow2Generic(unsigned char* const pixels, // images but even a 4k wide RGB888 image will use just 24kB of cache (4k pixels // * 3 Bpp * 2 scanlines) for two scanlines on the first iteration. AverageScanlines( - &pixels[y * 2 * lastWidth * BYTES_PER_PIXEL], - &pixels[(y * 2 + 1) * lastWidth * BYTES_PER_PIXEL], + &pixels[y * 2 * lastStride * BYTES_PER_PIXEL], + &pixels[(y * 2 + 1) * lastStride * BYTES_PER_PIXEL], &pixels[y * scaledWidth * BYTES_PER_PIXEL], scaledWidth); } @@ -1243,6 +1263,7 @@ void DownscaleInPlacePow2Generic(unsigned char* const pixels, ///@note: we could finish off with one of two mutually exclusive passes, one squashing horizontally as far as possible, and the other vertically, if we knew a following cpu point or bilinear filter would restore the desired aspect ratio. outWidth = scaledWidth; outHeight = scaledHeight; + outStride = stride; } } // namespace @@ -1511,15 +1532,18 @@ void DownscaleInPlacePow2(unsigned char* const pixels, Pixel::Format pixelFormat, unsigned int inputWidth, unsigned int inputHeight, + unsigned int inputStride, unsigned int desiredWidth, unsigned int desiredHeight, FittingMode::Type fittingMode, SamplingMode::Type samplingMode, unsigned& outWidth, - unsigned& outHeight) + unsigned& outHeight, + unsigned& outStride) { outWidth = inputWidth; outHeight = inputHeight; + outStride = inputStride; // Perform power of 2 iterated 4:1 box filtering if the requested filter mode requires it: if(samplingMode == SamplingMode::BOX || samplingMode == SamplingMode::BOX_THEN_NEAREST || samplingMode == SamplingMode::BOX_THEN_LINEAR) { @@ -1532,28 +1556,28 @@ void DownscaleInPlacePow2(unsigned char* const pixels, { case Pixel::RGBA8888: { - Internal::Platform::DownscaleInPlacePow2RGBA8888(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight); + Internal::Platform::DownscaleInPlacePow2RGBA8888(pixels, inputWidth, inputHeight, inputStride, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight, outStride); break; } case Pixel::RGB888: { - Internal::Platform::DownscaleInPlacePow2RGB888(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight); + Internal::Platform::DownscaleInPlacePow2RGB888(pixels, inputWidth, inputHeight, inputStride, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight, outStride); break; } case Pixel::RGB565: { - Internal::Platform::DownscaleInPlacePow2RGB565(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight); + Internal::Platform::DownscaleInPlacePow2RGB565(pixels, inputWidth, inputHeight, inputStride, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight, outStride); break; } case Pixel::LA88: { - Internal::Platform::DownscaleInPlacePow2ComponentPair(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight); + Internal::Platform::DownscaleInPlacePow2ComponentPair(pixels, inputWidth, inputHeight, inputStride, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight, outStride); break; } case Pixel::L8: case Pixel::A8: { - Internal::Platform::DownscaleInPlacePow2SingleBytePerPixel(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight); + Internal::Platform::DownscaleInPlacePow2SingleBytePerPixel(pixels, inputWidth, inputHeight, inputStride, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight, outStride); break; } default: @@ -1572,38 +1596,44 @@ void DownscaleInPlacePow2(unsigned char* const pixels, void DownscaleInPlacePow2RGB888(unsigned char* pixels, unsigned int inputWidth, unsigned int inputHeight, + unsigned int inputStride, unsigned int desiredWidth, unsigned int desiredHeight, BoxDimensionTest dimensionTest, unsigned& outWidth, - unsigned& outHeight) + unsigned& outHeight, + unsigned& outStride) { - DownscaleInPlacePow2Generic<3, HalveScanlineInPlaceRGB888, AverageScanlines3>(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight); + DownscaleInPlacePow2Generic<3, HalveScanlineInPlaceRGB888, AverageScanlines3>(pixels, inputWidth, inputHeight, inputStride, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight, outStride); } void DownscaleInPlacePow2RGBA8888(unsigned char* pixels, unsigned int inputWidth, unsigned int inputHeight, + unsigned int inputStride, unsigned int desiredWidth, unsigned int desiredHeight, BoxDimensionTest dimensionTest, unsigned& outWidth, - unsigned& outHeight) + unsigned& outHeight, + unsigned& outStride) { DALI_ASSERT_DEBUG(((reinterpret_cast(pixels) & 3u) == 0u) && "Pointer should be 4-byte aligned for performance on some platforms."); - DownscaleInPlacePow2Generic<4, HalveScanlineInPlaceRGBA8888, AverageScanlinesRGBA8888>(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight); + DownscaleInPlacePow2Generic<4, HalveScanlineInPlaceRGBA8888, AverageScanlinesRGBA8888>(pixels, inputWidth, inputHeight, inputStride, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight, outStride); } void DownscaleInPlacePow2RGB565(unsigned char* pixels, unsigned int inputWidth, unsigned int inputHeight, + unsigned int inputStride, unsigned int desiredWidth, unsigned int desiredHeight, BoxDimensionTest dimensionTest, unsigned int& outWidth, - unsigned int& outHeight) + unsigned int& outHeight, + unsigned int& outStride) { - DownscaleInPlacePow2Generic<2, HalveScanlineInPlaceRGB565, AverageScanlinesRGB565>(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight); + DownscaleInPlacePow2Generic<2, HalveScanlineInPlaceRGB565, AverageScanlinesRGB565>(pixels, inputWidth, inputHeight, inputStride, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight, outStride); } /** @@ -1614,25 +1644,29 @@ void DownscaleInPlacePow2RGB565(unsigned char* pixels, void DownscaleInPlacePow2ComponentPair(unsigned char* pixels, unsigned int inputWidth, unsigned int inputHeight, + unsigned int inputStride, unsigned int desiredWidth, unsigned int desiredHeight, BoxDimensionTest dimensionTest, unsigned& outWidth, - unsigned& outHeight) + unsigned& outHeight, + unsigned& outStride) { - DownscaleInPlacePow2Generic<2, HalveScanlineInPlace2Bytes, AverageScanlines2>(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight); + DownscaleInPlacePow2Generic<2, HalveScanlineInPlace2Bytes, AverageScanlines2>(pixels, inputWidth, inputHeight, inputStride, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight, outStride); } void DownscaleInPlacePow2SingleBytePerPixel(unsigned char* pixels, unsigned int inputWidth, unsigned int inputHeight, + unsigned int inputStride, unsigned int desiredWidth, unsigned int desiredHeight, BoxDimensionTest dimensionTest, unsigned int& outWidth, - unsigned int& outHeight) + unsigned int& outHeight, + unsigned int& outStride) { - DownscaleInPlacePow2Generic<1, HalveScanlineInPlace1Byte, AverageScanlines1>(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight); + DownscaleInPlacePow2Generic<1, HalveScanlineInPlace1Byte, AverageScanlines1>(pixels, inputWidth, inputHeight, inputStride, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight, outStride); } // Point sampling group below @@ -1650,12 +1684,13 @@ template inline void PointSampleAddressablePixels(const uint8_t* inPixels, unsigned int inputWidth, unsigned int inputHeight, + unsigned int inputStride, uint8_t* outPixels, unsigned int desiredWidth, unsigned int desiredHeight) { DALI_ASSERT_DEBUG(((desiredWidth <= inputWidth && desiredHeight <= inputHeight) || - outPixels >= inPixels + inputWidth * inputHeight * sizeof(PIXEL) || outPixels <= inPixels - desiredWidth * desiredHeight * sizeof(PIXEL)) && + outPixels >= inPixels + inputStride * inputHeight * sizeof(PIXEL) || outPixels <= inPixels - desiredWidth * desiredHeight * sizeof(PIXEL)) && "The input and output buffers must not overlap for an upscaling."); DALI_ASSERT_DEBUG(reinterpret_cast(inPixels) % sizeof(PIXEL) == 0 && "Pixel pointers need to be aligned to the size of the pixels (E.g., 4 bytes for RGBA, 2 bytes for RGB565, ...)."); DALI_ASSERT_DEBUG(reinterpret_cast(outPixels) % sizeof(PIXEL) == 0 && "Pixel pointers need to be aligned to the size of the pixels (E.g., 4 bytes for RGBA, 2 bytes for RGB565, ...)."); @@ -1674,11 +1709,11 @@ inline void PointSampleAddressablePixels(const uint8_t* inPixels, { // Round fixed point y coordinate to nearest integer: const unsigned int integerY = (inY + (1u << 15u)) >> 16u; - const PIXEL* const inScanline = &inAligned[inputWidth * integerY]; + const PIXEL* const inScanline = &inAligned[inputStride * integerY]; PIXEL* const outScanline = &outAligned[desiredWidth * outY]; DALI_ASSERT_DEBUG(integerY < inputHeight); - DALI_ASSERT_DEBUG(reinterpret_cast(inScanline) < (inPixels + inputWidth * inputHeight * sizeof(PIXEL))); + DALI_ASSERT_DEBUG(reinterpret_cast(inScanline) < (inPixels + inputStride * inputHeight * sizeof(PIXEL))); DALI_ASSERT_DEBUG(reinterpret_cast(outScanline) < (outPixels + desiredWidth * desiredHeight * sizeof(PIXEL))); unsigned int inX = 0; @@ -1701,33 +1736,36 @@ inline void PointSampleAddressablePixels(const uint8_t* inPixels, void PointSample4BPP(const unsigned char* inPixels, unsigned int inputWidth, unsigned int inputHeight, + unsigned int inputStride, unsigned char* outPixels, unsigned int desiredWidth, unsigned int desiredHeight) { - PointSampleAddressablePixels(inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight); + PointSampleAddressablePixels(inPixels, inputWidth, inputHeight, inputStride, outPixels, desiredWidth, desiredHeight); } // RGB565, LA88 void PointSample2BPP(const unsigned char* inPixels, unsigned int inputWidth, unsigned int inputHeight, + unsigned int inputStride, unsigned char* outPixels, unsigned int desiredWidth, unsigned int desiredHeight) { - PointSampleAddressablePixels(inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight); + PointSampleAddressablePixels(inPixels, inputWidth, inputHeight, inputStride, outPixels, desiredWidth, desiredHeight); } // L8, A8 void PointSample1BPP(const unsigned char* inPixels, unsigned int inputWidth, unsigned int inputHeight, + unsigned int inputStride, unsigned char* outPixels, unsigned int desiredWidth, unsigned int desiredHeight) { - PointSampleAddressablePixels(inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight); + PointSampleAddressablePixels(inPixels, inputWidth, inputHeight, inputStride, outPixels, desiredWidth, desiredHeight); } /* RGB888 @@ -1736,6 +1774,7 @@ void PointSample1BPP(const unsigned char* inPixels, void PointSample3BPP(const uint8_t* inPixels, unsigned int inputWidth, unsigned int inputHeight, + unsigned int inputStride, uint8_t* outPixels, unsigned int desiredWidth, unsigned int desiredHeight) @@ -1757,7 +1796,7 @@ void PointSample3BPP(const uint8_t* inPixels, for(unsigned int outY = 0; outY < desiredHeight; ++outY) { const unsigned int integerY = (inY + (1u << 15u)) >> 16u; - const uint8_t* const inScanline = &inPixels[inputWidth * integerY * BYTES_PER_PIXEL]; + const uint8_t* const inScanline = &inPixels[inputStride * integerY * BYTES_PER_PIXEL]; uint8_t* const outScanline = &outPixels[desiredWidth * outY * BYTES_PER_PIXEL]; unsigned int inX = 0; //< 16.16 fixed-point input image x-coord. @@ -1790,6 +1829,7 @@ void PointSample3BPP(const uint8_t* inPixels, void PointSample(const unsigned char* inPixels, unsigned int inputWidth, unsigned int inputHeight, + unsigned int inputStride, Pixel::Format pixelFormat, unsigned char* outPixels, unsigned int desiredWidth, @@ -1802,24 +1842,24 @@ void PointSample(const unsigned char* inPixels, { case Pixel::RGB888: { - PointSample3BPP(inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight); + PointSample3BPP(inPixels, inputWidth, inputHeight, inputStride, outPixels, desiredWidth, desiredHeight); break; } case Pixel::RGBA8888: { - PointSample4BPP(inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight); + PointSample4BPP(inPixels, inputWidth, inputHeight, inputStride, outPixels, desiredWidth, desiredHeight); break; } case Pixel::RGB565: case Pixel::LA88: { - PointSample2BPP(inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight); + PointSample2BPP(inPixels, inputWidth, inputHeight, inputStride, outPixels, desiredWidth, desiredHeight); break; } case Pixel::L8: case Pixel::A8: { - PointSample1BPP(inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight); + PointSample1BPP(inPixels, inputWidth, inputHeight, inputStride, outPixels, desiredWidth, desiredHeight); break; } default: @@ -1894,6 +1934,7 @@ template< bool DEBUG_ASSERT_ALIGNMENT> inline void LinearSampleGeneric(const unsigned char* __restrict__ inPixels, ImageDimensions inputDimensions, + unsigned int inputStride, unsigned char* __restrict__ outPixels, ImageDimensions desiredDimensions) { @@ -1902,7 +1943,7 @@ inline void LinearSampleGeneric(const unsigned char* __restrict__ inPixels, const unsigned int desiredWidth = desiredDimensions.GetWidth(); const unsigned int desiredHeight = desiredDimensions.GetHeight(); - DALI_ASSERT_DEBUG(((outPixels >= inPixels + inputWidth * inputHeight * sizeof(PIXEL)) || + DALI_ASSERT_DEBUG(((outPixels >= inPixels + inputStride * inputHeight * sizeof(PIXEL)) || (inPixels >= outPixels + desiredWidth * desiredHeight * sizeof(PIXEL))) && "Input and output buffers cannot overlap."); if(DEBUG_ASSERT_ALIGNMENT) @@ -1933,8 +1974,8 @@ inline void LinearSampleGeneric(const unsigned char* __restrict__ inPixels, DALI_ASSERT_DEBUG(integerY1 < inputHeight); DALI_ASSERT_DEBUG(integerY2 < inputHeight); - const PIXEL* const inScanline1 = &inAligned[inputWidth * integerY1]; - const PIXEL* const inScanline2 = &inAligned[inputWidth * integerY2]; + const PIXEL* const inScanline1 = &inAligned[inputStride * integerY1]; + const PIXEL* const inScanline2 = &inAligned[inputStride * integerY2]; unsigned int inX = 0; for(unsigned int outX = 0; outX < desiredWidth; ++outX) @@ -1966,46 +2007,52 @@ inline void LinearSampleGeneric(const unsigned char* __restrict__ inPixels, void LinearSample1BPP(const unsigned char* __restrict__ inPixels, ImageDimensions inputDimensions, + unsigned int inputStride, unsigned char* __restrict__ outPixels, ImageDimensions desiredDimensions) { - LinearSampleGeneric(inPixels, inputDimensions, outPixels, desiredDimensions); + LinearSampleGeneric(inPixels, inputDimensions, inputStride, outPixels, desiredDimensions); } void LinearSample2BPP(const unsigned char* __restrict__ inPixels, ImageDimensions inputDimensions, + unsigned int inputStride, unsigned char* __restrict__ outPixels, ImageDimensions desiredDimensions) { - LinearSampleGeneric(inPixels, inputDimensions, outPixels, desiredDimensions); + LinearSampleGeneric(inPixels, inputDimensions, inputStride, outPixels, desiredDimensions); } void LinearSampleRGB565(const unsigned char* __restrict__ inPixels, ImageDimensions inputDimensions, + unsigned int inputStride, unsigned char* __restrict__ outPixels, ImageDimensions desiredDimensions) { - LinearSampleGeneric(inPixels, inputDimensions, outPixels, desiredDimensions); + LinearSampleGeneric(inPixels, inputDimensions, inputStride, outPixels, desiredDimensions); } void LinearSample3BPP(const unsigned char* __restrict__ inPixels, ImageDimensions inputDimensions, + unsigned int inputStride, unsigned char* __restrict__ outPixels, ImageDimensions desiredDimensions) { - LinearSampleGeneric(inPixels, inputDimensions, outPixels, desiredDimensions); + LinearSampleGeneric(inPixels, inputDimensions, inputStride, outPixels, desiredDimensions); } void LinearSample4BPP(const unsigned char* __restrict__ inPixels, ImageDimensions inputDimensions, + unsigned int inputStride, unsigned char* __restrict__ outPixels, ImageDimensions desiredDimensions) { - LinearSampleGeneric(inPixels, inputDimensions, outPixels, desiredDimensions); + LinearSampleGeneric(inPixels, inputDimensions, inputStride, outPixels, desiredDimensions); } void Resample(const unsigned char* __restrict__ inPixels, ImageDimensions inputDimensions, + unsigned int inputStride, unsigned char* __restrict__ outPixels, ImageDimensions desiredDimensions, Resampler::Filter filterType, @@ -2089,7 +2136,7 @@ void Resample(const unsigned char* __restrict__ inPixels, samples[i].ResizeUninitialized(srcWidth); } - const int srcPitch = srcWidth * numChannels; + const int srcPitch = inputStride * numChannels; const int dstPitch = dstWidth * numChannels; int dstY = 0; @@ -2185,24 +2232,27 @@ void Resample(const unsigned char* __restrict__ inPixels, void LanczosSample4BPP(const unsigned char* __restrict__ inPixels, ImageDimensions inputDimensions, + unsigned int inputStride, unsigned char* __restrict__ outPixels, ImageDimensions desiredDimensions) { - Resample(inPixels, inputDimensions, outPixels, desiredDimensions, Resampler::LANCZOS4, 4, true); + Resample(inPixels, inputDimensions, inputStride, outPixels, desiredDimensions, Resampler::LANCZOS4, 4, true); } void LanczosSample1BPP(const unsigned char* __restrict__ inPixels, ImageDimensions inputDimensions, + unsigned int inputStride, unsigned char* __restrict__ outPixels, ImageDimensions desiredDimensions) { // For L8 images - Resample(inPixels, inputDimensions, outPixels, desiredDimensions, Resampler::LANCZOS4, 1, false); + Resample(inPixels, inputDimensions, inputStride, outPixels, desiredDimensions, Resampler::LANCZOS4, 1, false); } // Dispatch to a format-appropriate linear sampling function: void LinearSample(const unsigned char* __restrict__ inPixels, ImageDimensions inDimensions, + unsigned int inStride, Pixel::Format pixelFormat, unsigned char* __restrict__ outPixels, ImageDimensions outDimensions) @@ -2214,28 +2264,28 @@ void LinearSample(const unsigned char* __restrict__ inPixels, { case Pixel::RGB888: { - LinearSample3BPP(inPixels, inDimensions, outPixels, outDimensions); + LinearSample3BPP(inPixels, inDimensions, inStride, outPixels, outDimensions); break; } case Pixel::RGBA8888: { - LinearSample4BPP(inPixels, inDimensions, outPixels, outDimensions); + LinearSample4BPP(inPixels, inDimensions, inStride, outPixels, outDimensions); break; } case Pixel::L8: case Pixel::A8: { - LinearSample1BPP(inPixels, inDimensions, outPixels, outDimensions); + LinearSample1BPP(inPixels, inDimensions, inStride, outPixels, outDimensions); break; } case Pixel::LA88: { - LinearSample2BPP(inPixels, inDimensions, outPixels, outDimensions); + LinearSample2BPP(inPixels, inDimensions, inStride, outPixels, outDimensions); break; } case Pixel::RGB565: { - LinearSampleRGB565(inPixels, inDimensions, outPixels, outDimensions); + LinearSampleRGB565(inPixels, inDimensions, inStride, outPixels, outDimensions); break; } default: @@ -2253,6 +2303,7 @@ void LinearSample(const unsigned char* __restrict__ inPixels, void RotateByShear(const uint8_t* const pixelsIn, unsigned int widthIn, unsigned int heightIn, + unsigned int strideIn, unsigned int pixelSize, float radians, uint8_t*& pixelsOut, @@ -2273,6 +2324,7 @@ void RotateByShear(const uint8_t* const pixelsIn, fastRotationPerformed = Rotate90(pixelsIn, widthIn, heightIn, + strideIn, pixelSize, pixelsOut, widthOut, @@ -2297,6 +2349,7 @@ void RotateByShear(const uint8_t* const pixelsIn, fastRotationPerformed = Rotate180(pixelsIn, widthIn, heightIn, + strideIn, pixelSize, pixelsOut); @@ -2321,6 +2374,7 @@ void RotateByShear(const uint8_t* const pixelsIn, fastRotationPerformed = Rotate270(pixelsIn, widthIn, heightIn, + strideIn, pixelSize, pixelsOut, widthOut, @@ -2348,6 +2402,8 @@ void RotateByShear(const uint8_t* const pixelsIn, const uint8_t* const firstHorizontalSkewPixelsIn = fastRotationPerformed ? pixelsOut : pixelsIn; std::unique_ptr tmpPixelsInPtr((fastRotationPerformed ? pixelsOut : nullptr), free); + unsigned int stride = fastRotationPerformed ? widthOut : strideIn; + // Reset the input/output widthIn = widthOut; heightIn = heightOut; @@ -2386,7 +2442,7 @@ void RotateByShear(const uint8_t* const pixelsIn, const float shear = angleTangent * ((angleTangent >= 0.f) ? (0.5f + static_cast(y)) : (0.5f + static_cast(y) - static_cast(heightOut))); const int intShear = static_cast(floor(shear)); - HorizontalSkew(firstHorizontalSkewPixelsIn, widthIn, pixelSize, pixelsOut, widthOut, y, intShear, shear - static_cast(intShear)); + HorizontalSkew(firstHorizontalSkewPixelsIn, widthIn, stride, pixelSize, pixelsOut, widthOut, y, intShear, shear - static_cast(intShear)); } // Reset the 'pixel in' pointer with the output of the 'First Horizontal Skew' and free the memory allocated by the 'Fast Rotations'. @@ -2425,7 +2481,7 @@ void RotateByShear(const uint8_t* const pixelsIn, for(column = 0u; column < widthOut; ++column, offset -= angleSinus) { const int shear = static_cast(floor(offset)); - VerticalSkew(tmpPixelsInPtr.get(), tmpWidthIn, tmpHeightIn, pixelSize, pixelsOut, widthOut, heightOut, column, shear, offset - static_cast(shear)); + VerticalSkew(tmpPixelsInPtr.get(), tmpWidthIn, tmpHeightIn, tmpWidthIn, pixelSize, pixelsOut, widthOut, heightOut, column, shear, offset - static_cast(shear)); } // Reset the 'pixel in' pointer with the output of the 'Vertical Skew' and free the memory allocated by the 'First Horizontal Skew'. // Reset the input/output @@ -2460,7 +2516,7 @@ void RotateByShear(const uint8_t* const pixelsIn, for(unsigned int y = 0u; y < heightOut; ++y, offset += angleTangent) { const int shear = static_cast(floor(offset)); - HorizontalSkew(tmpPixelsInPtr.get(), tmpWidthIn, pixelSize, pixelsOut, widthOut, y, shear, offset - static_cast(shear)); + HorizontalSkew(tmpPixelsInPtr.get(), tmpWidthIn, tmpWidthIn, pixelSize, pixelsOut, widthOut, y, shear, offset - static_cast(shear)); } // The deleter of the tmpPixelsInPtr unique pointer is called freeing the memory allocated by the 'Vertical Skew'. @@ -2470,6 +2526,7 @@ void RotateByShear(const uint8_t* const pixelsIn, void HorizontalShear(const uint8_t* const pixelsIn, unsigned int widthIn, unsigned int heightIn, + unsigned int strideIn, unsigned int pixelSize, float radians, uint8_t*& pixelsOut, @@ -2510,7 +2567,7 @@ void HorizontalShear(const uint8_t* const pixelsIn, const float shear = radians * ((radians >= 0.f) ? (0.5f + static_cast(y)) : (0.5f + static_cast(y) - static_cast(heightOut))); const int intShear = static_cast(floor(shear)); - HorizontalSkew(pixelsIn, widthIn, pixelSize, pixelsOut, widthOut, y, intShear, shear - static_cast(intShear)); + HorizontalSkew(pixelsIn, widthIn, strideIn, pixelSize, pixelsOut, widthOut, y, intShear, shear - static_cast(intShear)); } } diff --git a/dali/internal/imaging/common/image-operations.h b/dali/internal/imaging/common/image-operations.h index d1105ad..fd330a0 100644 --- a/dali/internal/imaging/common/image-operations.h +++ b/dali/internal/imaging/common/image-operations.h @@ -107,21 +107,25 @@ Dali::Devel::PixelBuffer DownscaleBitmap(Dali::Devel::PixelBuffer bitmap, * @param[in] pixelFormat The format of the image pointed at by pixels. * @param[in] inputWidth The width of the input image. * @param[in] inputHeight The height of the input image. + * @param[in] inputStride The stride of the input image. * @param[in] desiredWidth The width the client is requesting. * @param[in] desiredHeight The height the client is requesting. * @param[out] outWidth The resulting width after downscaling. * @param[out] outHeight The resulting height after downscaling. + * @param[out] outStride The resulting stride after downscaling. */ void DownscaleInPlacePow2(unsigned char* const pixels, Pixel::Format pixelFormat, unsigned int inputWidth, unsigned int inputHeight, + unsigned int inputStride, unsigned int desiredWidth, unsigned int desiredHeight, FittingMode::Type fittingMode, SamplingMode::Type samplingMode, unsigned& outWidth, - unsigned& outHeight); + unsigned& outHeight, + unsigned& outStride); /** * @brief Destructive in-place downscaling by a power of 2 factor. @@ -132,19 +136,23 @@ void DownscaleInPlacePow2(unsigned char* const pixels, * @param[in,out] pixels The buffer both to read from and write the result to. * @param[in] inputWidth The width of the input image. * @param[in] inputHeight The height of the input image. + * @param[in] inputStride The stride of the input image. * @param[in] desiredWidth The width the client is requesting. * @param[in] desiredHeight The height the client is requesting. * @param[out] outWidth The resulting width after downscaling. * @param[out] outHeight The resulting height after downscaling. + * @param[out] outStride The resulting stride after downscaling. */ void DownscaleInPlacePow2RGB888(unsigned char* pixels, unsigned int inputWidth, unsigned int inputHeight, + unsigned int inputStride, unsigned int desiredWidth, unsigned int desiredHeight, BoxDimensionTest dimensionTest, unsigned int& outWidth, - unsigned int& outHeight); + unsigned int& outHeight, + unsigned int& outStride); /** * @copydoc DownscaleInPlacePow2RGB888 @@ -152,11 +160,13 @@ void DownscaleInPlacePow2RGB888(unsigned char* pixels, void DownscaleInPlacePow2RGBA8888(unsigned char* pixels, unsigned int inputWidth, unsigned int inputHeight, + unsigned int inputStride, unsigned int desiredWidth, unsigned int desiredHeight, BoxDimensionTest dimensionTest, unsigned int& outWidth, - unsigned int& outHeight); + unsigned int& outHeight, + unsigned int& outStride); /** * @copydoc DownscaleInPlacePow2RGB888 @@ -166,11 +176,13 @@ void DownscaleInPlacePow2RGBA8888(unsigned char* pixels, void DownscaleInPlacePow2RGB565(unsigned char* pixels, unsigned int inputWidth, unsigned int inputHeight, + unsigned int inputStride, unsigned int desiredWidth, unsigned int desiredHeight, BoxDimensionTest dimensionTest, unsigned int& outWidth, - unsigned int& outHeight); + unsigned int& outHeight, + unsigned int& outStride); /** * @copydoc DownscaleInPlacePow2RGB888 @@ -180,11 +192,13 @@ void DownscaleInPlacePow2RGB565(unsigned char* pixels, void DownscaleInPlacePow2ComponentPair(unsigned char* pixels, unsigned int inputWidth, unsigned int inputHeight, + unsigned int inputStride, unsigned int desiredWidth, unsigned int desiredHeight, BoxDimensionTest dimensionTest, unsigned int& outWidth, - unsigned int& outHeight); + unsigned int& outHeight, + unsigned int& outStride); /** * @copydoc DownscaleInPlacePow2RGB888 @@ -194,11 +208,13 @@ void DownscaleInPlacePow2ComponentPair(unsigned char* pixels, void DownscaleInPlacePow2SingleBytePerPixel(unsigned char* pixels, unsigned int inputWidth, unsigned int inputHeight, + unsigned int inputStride, unsigned int desiredWidth, unsigned int desiredHeight, BoxDimensionTest dimensionTest, unsigned int& outWidth, - unsigned int& outHeight); + unsigned int& outHeight, + unsigned int& outStride); /** * @brief Rescales an input image into the exact output dimensions passed-in. @@ -211,6 +227,7 @@ void DownscaleInPlacePow2SingleBytePerPixel(unsigned char* pixels, void PointSample(const unsigned char* inPixels, unsigned int inputWidth, unsigned int inputHeight, + unsigned int inputStride, Pixel::Format pixelFormat, unsigned char* outPixels, unsigned int desiredWidth, @@ -224,6 +241,7 @@ void PointSample(const unsigned char* inPixels, void PointSample4BPP(const unsigned char* inPixels, unsigned int inputWidth, unsigned int inputHeight, + unsigned int inputStride, unsigned char* outPixels, unsigned int desiredWidth, unsigned int desiredHeight); @@ -236,6 +254,7 @@ void PointSample4BPP(const unsigned char* inPixels, void PointSample3BPP(const unsigned char* inPixels, unsigned int inputWidth, unsigned int inputHeight, + unsigned int inputStride, unsigned char* outPixels, unsigned int desiredWidth, unsigned int desiredHeight); @@ -248,6 +267,7 @@ void PointSample3BPP(const unsigned char* inPixels, void PointSample2BPP(const unsigned char* inPixels, unsigned int inputWidth, unsigned int inputHeight, + unsigned int inputStride, unsigned char* outPixels, unsigned int desiredWidth, unsigned int desiredHeight); @@ -260,6 +280,7 @@ void PointSample2BPP(const unsigned char* inPixels, void PointSample1BPP(const unsigned char* inPixels, unsigned int inputWidth, unsigned int inputHeight, + unsigned int inputStride, unsigned char* outPixels, unsigned int desiredWidth, unsigned int desiredHeight); @@ -274,6 +295,7 @@ void PointSample1BPP(const unsigned char* inPixels, */ void LinearSample(const unsigned char* __restrict__ inPixels, ImageDimensions inDimensions, + unsigned int inStride, Pixel::Format pixelFormat, unsigned char* __restrict__ outPixels, ImageDimensions outDimensions); @@ -285,6 +307,7 @@ void LinearSample(const unsigned char* __restrict__ inPixels, */ void LinearSample1BPP(const unsigned char* __restrict__ inPixels, ImageDimensions inputDimensions, + unsigned int inputStride, unsigned char* __restrict__ outPixels, ImageDimensions desiredDimensions); @@ -295,6 +318,7 @@ void LinearSample1BPP(const unsigned char* __restrict__ inPixels, */ void LinearSample2BPP(const unsigned char* __restrict__ inPixels, ImageDimensions inputDimensions, + unsigned int inputStride, unsigned char* __restrict__ outPixels, ImageDimensions desiredDimensions); @@ -305,6 +329,7 @@ void LinearSample2BPP(const unsigned char* __restrict__ inPixels, */ void LinearSampleRGB565(const unsigned char* __restrict__ inPixels, ImageDimensions inputDimensions, + unsigned int inputStride, unsigned char* __restrict__ outPixels, ImageDimensions desiredDimensions); @@ -315,6 +340,7 @@ void LinearSampleRGB565(const unsigned char* __restrict__ inPixels, */ void LinearSample3BPP(const unsigned char* __restrict__ inPixels, ImageDimensions inputDimensions, + unsigned int inputStride, unsigned char* __restrict__ outPixels, ImageDimensions desiredDimensions); @@ -326,6 +352,7 @@ void LinearSample3BPP(const unsigned char* __restrict__ inPixels, */ void LinearSample4BPP(const unsigned char* __restrict__ inPixels, ImageDimensions inputDimensions, + unsigned int inputStride, unsigned char* __restrict__ outPixels, ImageDimensions desiredDimensions); @@ -337,11 +364,13 @@ void LinearSample4BPP(const unsigned char* __restrict__ inPixels, * * @param[in] inPixels Pointer to the input image buffer. * @param[in] inputDimensions The input dimensions of the image. + * @param[in] inputStride The input stride of the image. * @param[out] outPixels Pointer to the output image buffer. * @param[in] desiredDimensions The output dimensions of the image. */ void LanczosSample4BPP(const unsigned char* __restrict__ inPixels, ImageDimensions inputDimensions, + unsigned int inputStride, unsigned char* __restrict__ outPixels, ImageDimensions desiredDimensions); @@ -353,11 +382,13 @@ void LanczosSample4BPP(const unsigned char* __restrict__ inPixels, * * @param[in] inPixels Pointer to the input image buffer. * @param[in] inputDimensions The input dimensions of the image. + * @param[in] inputStride The input stride of the image. * @param[out] outPixels Pointer to the output image buffer. * @param[in] desiredDimensions The output dimensions of the image. */ void LanczosSample1BPP(const unsigned char* __restrict__ inPixels, ImageDimensions inputDimensions, + unsigned int inputStride, unsigned char* __restrict__ outPixels, ImageDimensions desiredDimensions); @@ -369,11 +400,13 @@ void LanczosSample1BPP(const unsigned char* __restrict__ inPixels, * * @param[in] inPixels Pointer to the input image buffer. * @param[in] inputDimensions The input dimensions of the image. + * @param[in] inputStride The input stride of the image. * @param[out] outPixels Pointer to the output image buffer. * @param[in] desiredDimensions The output dimensions of the image. */ void Resample(const unsigned char* __restrict__ inPixels, ImageDimensions inputDimensions, + unsigned int inputStride, unsigned char* __restrict__ outPixels, ImageDimensions desiredDimensions, Resampler::Filter filterType, @@ -391,6 +424,7 @@ void Resample(const unsigned char* __restrict__ inPixels, * @param[in] pixelsIn The input buffer. * @param[in] widthIn The width of the input buffer. * @param[in] heightIn The height of the input buffer. + * @param[in] strideIn The stride of the input buffer. * @param[in] pixelSize The size of the pixel. * @param[in] radians The rotation angle in radians. * @param[out] pixelsOut The rotated output buffer. @@ -400,6 +434,7 @@ void Resample(const unsigned char* __restrict__ inPixels, void RotateByShear(const uint8_t* const pixelsIn, unsigned int widthIn, unsigned int heightIn, + unsigned int strideIn, unsigned int pixelSize, float radians, uint8_t*& pixelsOut, @@ -418,6 +453,7 @@ void RotateByShear(const uint8_t* const pixelsIn, * @param[in] pixelsIn The input buffer. * @param[in] widthIn The width of the input buffer. * @param[in] heightIn The height of the input buffer. + * @param[in] strideIn The stride of the input buffer. * @param[in] pixelSize The size of the pixel. * @param[in] radians The shear angle in radians. * @param[out] pixelsOut The rotated output buffer. @@ -427,6 +463,7 @@ void RotateByShear(const uint8_t* const pixelsIn, void HorizontalShear(const uint8_t* const pixelsIn, unsigned int widthIn, unsigned int heightIn, + unsigned int strideIn, unsigned int pixelSize, float radians, uint8_t*& pixelsOut, diff --git a/dali/internal/imaging/common/pixel-buffer-impl.cpp b/dali/internal/imaging/common/pixel-buffer-impl.cpp index 4ff2250..f2594ac 100644 --- a/dali/internal/imaging/common/pixel-buffer-impl.cpp +++ b/dali/internal/imaging/common/pixel-buffer-impl.cpp @@ -47,12 +47,14 @@ PixelBuffer::PixelBuffer(unsigned char* buffer, unsigned int bufferSize, unsigned int width, unsigned int height, + unsigned int stride, Dali::Pixel::Format pixelFormat) : mMetadata(), mBuffer(buffer), mBufferSize(bufferSize), mWidth(width), mHeight(height), + mStride(stride ? stride : width), mPixelFormat(pixelFormat), mPreMultiplied(false) { @@ -73,16 +75,17 @@ PixelBufferPtr PixelBuffer::New(unsigned int width, { buffer = static_cast(malloc(bufferSize)); } - return new PixelBuffer(buffer, bufferSize, width, height, pixelFormat); + return new PixelBuffer(buffer, bufferSize, width, height, width, pixelFormat); } PixelBufferPtr PixelBuffer::New(unsigned char* buffer, unsigned int bufferSize, unsigned int width, unsigned int height, + unsigned int stride, Dali::Pixel::Format pixelFormat) { - return new PixelBuffer(buffer, bufferSize, width, height, pixelFormat); + return new PixelBuffer(buffer, bufferSize, width, height, stride, pixelFormat); } Dali::PixelData PixelBuffer::Convert(PixelBuffer& pixelBuffer) @@ -91,12 +94,14 @@ Dali::PixelData PixelBuffer::Convert(PixelBuffer& pixelBuffer) pixelBuffer.mBufferSize, pixelBuffer.mWidth, pixelBuffer.mHeight, + pixelBuffer.mStride, pixelBuffer.mPixelFormat, Dali::PixelData::FREE); pixelBuffer.mBuffer = NULL; pixelBuffer.mWidth = 0; pixelBuffer.mHeight = 0; pixelBuffer.mBufferSize = 0; + pixelBuffer.mStride = 0; return pixelData; } @@ -111,6 +116,11 @@ unsigned int PixelBuffer::GetHeight() const return mHeight; } +uint32_t PixelBuffer::GetStride() const +{ + return mStride; +} + Dali::Pixel::Format PixelBuffer::GetPixelFormat() const { return mPixelFormat; @@ -141,7 +151,7 @@ Dali::PixelData PixelBuffer::CreatePixelData() const memcpy(destBuffer, mBuffer, mBufferSize); } - Dali::PixelData pixelData = Dali::PixelData::New(destBuffer, mBufferSize, mWidth, mHeight, mPixelFormat, Dali::PixelData::FREE); + Dali::PixelData pixelData = Dali::PixelData::New(destBuffer, mBufferSize, mWidth, mHeight, mStride, mPixelFormat, Dali::PixelData::FREE); return pixelData; } @@ -201,6 +211,7 @@ void PixelBuffer::TakeOwnershipOfBuffer(PixelBuffer& pixelBuffer) mBufferSize = pixelBuffer.mBufferSize; mWidth = pixelBuffer.mWidth; mHeight = pixelBuffer.mHeight; + mStride = pixelBuffer.mStride; mPixelFormat = pixelBuffer.mPixelFormat; } @@ -271,6 +282,7 @@ bool PixelBuffer::Rotate(Degree angle) Platform::RotateByShear(mBuffer, mWidth, mHeight, + mStride, pixelSize, radians, pixelsOut, @@ -289,6 +301,7 @@ bool PixelBuffer::Rotate(Degree angle) mBuffer = pixelsOut; pixelsOut = nullptr; mBufferSize = mWidth * mHeight * pixelSize; + mStride = mWidth; // The buffer is tightly packed. } return success; @@ -327,8 +340,8 @@ PixelBufferPtr PixelBuffer::NewCrop(const PixelBuffer& inBuffer, uint16_t x, uin { PixelBufferPtr outBuffer = PixelBuffer::New(cropDimensions.GetWidth(), cropDimensions.GetHeight(), inBuffer.GetPixelFormat()); int bytesPerPixel = Pixel::GetBytesPerPixel(inBuffer.mPixelFormat); - int srcStride = inBuffer.mWidth * bytesPerPixel; - int destStride = cropDimensions.GetWidth() * bytesPerPixel; + int srcStride = inBuffer.mStride * bytesPerPixel; + int destStride = cropDimensions.GetWidth() * bytesPerPixel; // The destination buffer is tightly packed // Clamp crop to right edge if(x + cropDimensions.GetWidth() > inBuffer.mWidth) @@ -409,7 +422,7 @@ PixelBufferPtr PixelBuffer::NewResize(const PixelBuffer& inBuffer, ImageDimensio inBuffer.mPixelFormat == Pixel::RGBA8888 || inBuffer.mPixelFormat == Pixel::BGRA8888) { - Dali::Internal::Platform::Resample(inBuffer.mBuffer, inDimensions, outBuffer->GetBuffer(), outDimensions, filterType, bytesPerPixel, hasAlpha); + Dali::Internal::Platform::Resample(inBuffer.mBuffer, inDimensions, inBuffer.mStride, outBuffer->GetBuffer(), outDimensions, filterType, bytesPerPixel, hasAlpha); } else { @@ -443,8 +456,9 @@ void PixelBuffer::MultiplyColorByAlpha() // must be skipped in such case if(Pixel::GetBytesPerPixel(mPixelFormat) && Pixel::HasAlpha(mPixelFormat)) { - unsigned char* pixel = mBuffer; - const unsigned int bufferSize = mWidth * mHeight; + unsigned char* pixel = mBuffer; + const unsigned int strideBytes = mStride * bytesPerPixel; + const unsigned int widthBytes = mWidth * bytesPerPixel; // Collect all valid channel list before lookup whole buffer std::vector validChannelList; @@ -458,32 +472,35 @@ void PixelBuffer::MultiplyColorByAlpha() if(DALI_LIKELY(!validChannelList.empty())) { - for(unsigned int i = 0; i < bufferSize; ++i) + for(unsigned int y = 0; y < mHeight; y++) { - unsigned int alpha = ReadChannel(pixel, mPixelFormat, Adaptor::ALPHA); - if(alpha < 255) + for(unsigned int x = 0; x < widthBytes; x += bytesPerPixel) { - // If alpha is 255, we don't need to change color. Skip current pixel - // But if alpha is not 255, we should change color. - if(alpha > 0) + unsigned int alpha = ReadChannel(&pixel[x], mPixelFormat, Adaptor::ALPHA); + if(alpha < 255) { - for(const Channel& channel : validChannelList) + // If alpha is 255, we don't need to change color. Skip current pixel + // But if alpha is not 255, we should change color. + if(alpha > 0) { - auto color = ReadChannel(pixel, mPixelFormat, channel); - WriteChannel(pixel, mPixelFormat, channel, color * alpha / 255); + for(const Channel& channel : validChannelList) + { + auto color = ReadChannel(&pixel[x], mPixelFormat, channel); + WriteChannel(&pixel[x], mPixelFormat, channel, color * alpha / 255); + } + } + else + { + // If alpha is 0, just set all pixel as zero. + memset(&pixel[x], 0, bytesPerPixel); } - } - else - { - // If alpha is 0, just set all pixel as zero. - memset(pixel, 0, bytesPerPixel); } } - pixel += bytesPerPixel; + pixel += strideBytes; } } + mPreMultiplied = true; } - mPreMultiplied = true; } bool PixelBuffer::IsAlphaPreMultiplied() const @@ -493,30 +510,33 @@ bool PixelBuffer::IsAlphaPreMultiplied() const uint32_t PixelBuffer::GetBrightness() const { - uint32_t brightness = 0; - + uint32_t brightness = 0; uint32_t bytesPerPixel = Pixel::GetBytesPerPixel(mPixelFormat); - if(bytesPerPixel) + + if(bytesPerPixel && mWidth && mHeight) { - unsigned char* pixel = mBuffer; - const uint32_t bufferSize = mWidth * mHeight; + unsigned char* pixel = mBuffer; + const uint32_t strideBytes = mStride * bytesPerPixel; + const uint32_t widthBytes = mWidth * bytesPerPixel; + const uint32_t bufferSize = mWidth * mHeight; - if(bufferSize) // avoid division by zero to calculate brightness - { - uint64_t red = 0; - uint64_t green = 0; - uint64_t blue = 0; + uint64_t red = 0; + uint64_t green = 0; + uint64_t blue = 0; - for(uint32_t i = 0; i < bufferSize; ++i) + for(unsigned int y = 0; y < mHeight; y++) + { + for(unsigned int x = 0; x < widthBytes; x += bytesPerPixel) { - red += ReadChannel(pixel, mPixelFormat, Adaptor::RED); - green += ReadChannel(pixel, mPixelFormat, Adaptor::GREEN); - blue += ReadChannel(pixel, mPixelFormat, Adaptor::BLUE); - pixel += bytesPerPixel; + red += ReadChannel(&pixel[x], mPixelFormat, Adaptor::RED); + green += ReadChannel(&pixel[x], mPixelFormat, Adaptor::GREEN); + blue += ReadChannel(&pixel[x], mPixelFormat, Adaptor::BLUE); } - // http://www.w3.org/TR/AERT#color-contrast - brightness = (red * BRIGHTNESS_CONSTANT_R + green * BRIGHTNESS_CONSTANT_G + blue * BRIGHTNESS_CONSTANT_B) / (1000uLL * bufferSize); + pixel += strideBytes; } + + // http://www.w3.org/TR/AERT#color-contrast + brightness = (red * BRIGHTNESS_CONSTANT_R + green * BRIGHTNESS_CONSTANT_G + blue * BRIGHTNESS_CONSTANT_B) / (1000uLL * bufferSize); } return brightness; diff --git a/dali/internal/imaging/common/pixel-buffer-impl.h b/dali/internal/imaging/common/pixel-buffer-impl.h index da25097..6e02f3c 100644 --- a/dali/internal/imaging/common/pixel-buffer-impl.h +++ b/dali/internal/imaging/common/pixel-buffer-impl.h @@ -2,7 +2,7 @@ #define DALI_INTERNAL_ADAPTOR_PIXEL_BUFFER_H /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2022 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -60,13 +60,14 @@ public: * @param [in] bufferSize The size of the buffer in bytes * @param [in] width Buffer width in pixels * @param [in] height Buffer height in pixels + * @param [in] stride Buffer stride in pixels, 0 means the buffer is tightly packed * @param [in] pixelFormat The pixel format - * @param [in] releaseFunction The function used to release the memory. */ static PixelBufferPtr New(unsigned char* buffer, unsigned int bufferSize, unsigned int width, unsigned int height, + unsigned int stride, Pixel::Format pixelFormat); /** @@ -85,12 +86,14 @@ public: * @param [in] bufferSize The size of the buffer in bytes * @param [in] width Buffer width in pixels * @param [in] height Buffer height in pixels + * @param [in] stride Buffer stride in pixels, 0 means the buffer is tightly packed * @param [in] pixelFormat The pixel format */ PixelBuffer(unsigned char* buffer, unsigned int bufferSize, unsigned int width, unsigned int height, + unsigned int stride, Pixel::Format pixelFormat); protected: @@ -115,6 +118,12 @@ public: unsigned int GetHeight() const; /** + * @brief Gets the stride of the buffer in pixels. + * @return The stride of the buffer in pixels. 0 means the buffer is tightly packed. + */ + unsigned int GetStride() const; + + /** * Get the pixel format * @return The pixel format */ @@ -281,10 +290,11 @@ private: private: std::unique_ptr mMetadata; ///< Metadata fields - unsigned char* mBuffer; ///< The raw pixel data - unsigned int mBufferSize; ///< Buffer sized in bytes - unsigned int mWidth; ///< Buffer width in pixels - unsigned int mHeight; ///< Buffer height in pixels + uint8_t* mBuffer; ///< The raw pixel data + uint32_t mBufferSize; ///< Buffer sized in bytes + uint32_t mWidth; ///< Buffer width in pixels + uint32_t mHeight; ///< Buffer height in pixels + uint32_t mStride; ///< Buffer stride in bytes, 0 means the buffer is tightly packed Pixel::Format mPixelFormat; ///< Pixel format bool mPreMultiplied; ///< PreMultiplied }; diff --git a/dali/internal/text/text-abstraction/cairo-renderer.cpp b/dali/internal/text/text-abstraction/cairo-renderer.cpp index 0735798..dd11c76 100644 --- a/dali/internal/text/text-abstraction/cairo-renderer.cpp +++ b/dali/internal/text/text-abstraction/cairo-renderer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2022 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -896,6 +896,7 @@ Devel::PixelBuffer RenderTextCairo(const TextAbstraction::TextRenderer::Paramete Dali::Internal::Platform::RotateByShear(data.buffer, data.width, data.height, + data.width, pixelSize, radians, pixelsOut, diff --git a/dali/internal/text/text-abstraction/plugin/font-client-utils.cpp b/dali/internal/text/text-abstraction/plugin/font-client-utils.cpp index 3f9743f..869609c 100644 --- a/dali/internal/text/text-abstraction/plugin/font-client-utils.cpp +++ b/dali/internal/text/text-abstraction/plugin/font-client-utils.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2022 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -154,6 +154,7 @@ void ConvertBitmap(TextAbstraction::FontClient::GlyphBufferData& data, unsigned { Dali::Internal::Platform::LanczosSample4BPP(srcBuffer, inputDimensions, + srcWidth, data.buffer, desiredDimensions); } @@ -224,6 +225,7 @@ void ConvertBitmap(TextAbstraction::FontClient::GlyphBufferData& data, FT_Bitmap Dali::Internal::Platform::HorizontalShear(pixelsIn, width, height, + width, 1u, -TextAbstraction::FontClient::DEFAULT_ITALIC_ANGLE, pixelsOut,