Make some image operation as bitwise operation + Reduce alpha-masking op 24/271624/4
authorEunki, Hong <eunkiki.hong@samsung.com>
Wed, 23 Feb 2022 12:50:05 +0000 (21:50 +0900)
committerEunki, Hong <eunkiki.hong@samsung.com>
Wed, 23 Feb 2022 16:36:39 +0000 (01:36 +0900)
Make some simple arithmetic (and computer don't friendly) operations as
2-bit bitwise (and computer friendly) operations.
+
Tiny optimizer when premultiply alpha image pixels

Change-Id: Iff1878d7a6709d54a59cea5cffd55c69cbb7b0cb
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
dali/internal/imaging/common/image-operations.cpp
dali/internal/imaging/common/image-operations.h
dali/internal/imaging/common/pixel-buffer-impl.cpp

index 0d29c47..d0c7f79 100644 (file)
@@ -1253,20 +1253,35 @@ void HalveScanlineInPlaceRGB888(unsigned char* const pixels, const unsigned int
 
   const unsigned int lastPair = EvenDown(width - 2);
 
-  for(unsigned int pixel = 0, outPixel = 0; pixel <= lastPair; pixel += 2, ++outPixel)
-  {
-    // Load all the byte pixel components we need:
-    const unsigned int c11 = pixels[pixel * 3];
-    const unsigned int c12 = pixels[pixel * 3 + 1];
-    const unsigned int c13 = pixels[pixel * 3 + 2];
-    const unsigned int c21 = pixels[pixel * 3 + 3];
-    const unsigned int c22 = pixels[pixel * 3 + 4];
-    const unsigned int c23 = pixels[pixel * 3 + 5];
-
-    // Save the averaged byte pixel components:
-    pixels[outPixel * 3]     = static_cast<unsigned char>(AverageComponent(c11, c21));
-    pixels[outPixel * 3 + 1] = static_cast<unsigned char>(AverageComponent(c12, c22));
-    pixels[outPixel * 3 + 2] = static_cast<unsigned char>(AverageComponent(c13, c23));
+  /**
+   * @code
+   *  for(unsigned int pixel = 0, outPixel = 0; pixel <= lastPair; pixel += 2, ++outPixel)
+   * {
+   *   // Load all the byte pixel components we need:
+   *   const unsigned int c11 = pixels[pixel * 3];
+   *   const unsigned int c12 = pixels[pixel * 3 + 1];
+   *   const unsigned int c13 = pixels[pixel * 3 + 2];
+   *   const unsigned int c21 = pixels[pixel * 3 + 3];
+   *   const unsigned int c22 = pixels[pixel * 3 + 4];
+   *   const unsigned int c23 = pixels[pixel * 3 + 5];
+   *
+   *   // Save the averaged byte pixel components:
+   *   pixels[outPixel * 3]     = static_cast<unsigned char>(AverageComponent(c11, c21));
+   *   pixels[outPixel * 3 + 1] = static_cast<unsigned char>(AverageComponent(c12, c22));
+   *   pixels[outPixel * 3 + 2] = static_cast<unsigned char>(AverageComponent(c13, c23));
+   * }
+   *   @endcode
+   */
+  //@ToDo : Fix here if we found that collect 12 bytes == 3 uint32_t with 4 colors, and calculate in one-operation
+  std::uint8_t* inPixelPtr  = pixels;
+  std::uint8_t* outPixelPtr = pixels;
+  for(std::uint32_t scanedPixelCount = 0; scanedPixelCount <= lastPair; scanedPixelCount += 2)
+  {
+    *(outPixelPtr + 0) = ((*(inPixelPtr + 0) ^ *(inPixelPtr + 3)) >> 1) + (*(inPixelPtr + 0) & *(inPixelPtr + 3));
+    *(outPixelPtr + 1) = ((*(inPixelPtr + 1) ^ *(inPixelPtr + 4)) >> 1) + (*(inPixelPtr + 1) & *(inPixelPtr + 4));
+    *(outPixelPtr + 2) = ((*(inPixelPtr + 2) ^ *(inPixelPtr + 5)) >> 1) + (*(inPixelPtr + 2) & *(inPixelPtr + 5));
+    inPixelPtr += 6;
+    outPixelPtr += 3;
   }
 }
 
@@ -1310,15 +1325,22 @@ void HalveScanlineInPlace2Bytes(unsigned char* const pixels, const unsigned int
 
   for(unsigned int pixel = 0, outPixel = 0; pixel <= lastPair; pixel += 2, ++outPixel)
   {
-    // Load all the byte pixel components we need:
-    const unsigned int c11 = pixels[pixel * 2];
-    const unsigned int c12 = pixels[pixel * 2 + 1];
-    const unsigned int c21 = pixels[pixel * 2 + 2];
-    const unsigned int c22 = pixels[pixel * 2 + 3];
-
-    // Save the averaged byte pixel components:
-    pixels[outPixel * 2]     = static_cast<unsigned char>(AverageComponent(c11, c21));
-    pixels[outPixel * 2 + 1] = static_cast<unsigned char>(AverageComponent(c12, c22));
+    /**
+     * @code
+     * // Load all the byte pixel components we need:
+     * const unsigned int c11 = pixels[pixel * 2];
+     * const unsigned int c12 = pixels[pixel * 2 + 1];
+     * const unsigned int c21 = pixels[pixel * 2 + 2];
+     * const unsigned int c22 = pixels[pixel * 2 + 3];
+     *
+     * // Save the averaged byte pixel components:
+     * pixels[outPixel * 2]     = static_cast<unsigned char>(AverageComponent(c11, c21));
+     * pixels[outPixel * 2 + 1] = static_cast<unsigned char>(AverageComponent(c12, c22));
+     * @endcode
+     */
+    // Note : We can assume that pixel is even number. So we can use | operation instead of + operation.
+    pixels[(outPixel << 1)]     = ((pixels[(pixel << 1)] ^ pixels[(pixel << 1) | 2]) >> 1) + (pixels[(pixel << 1)] & pixels[(pixel << 1) | 2]);
+    pixels[(outPixel << 1) | 1] = ((pixels[(pixel << 1) | 1] ^ pixels[(pixel << 1) | 3]) >> 1) + (pixels[(pixel << 1) | 1] & pixels[(pixel << 1) | 3]);
   }
 }
 
@@ -1330,12 +1352,18 @@ void HalveScanlineInPlace1Byte(unsigned char* const pixels, const unsigned int w
 
   for(unsigned int pixel = 0, outPixel = 0; pixel <= lastPair; pixel += 2, ++outPixel)
   {
-    // Load all the byte pixel components we need:
-    const unsigned int c1 = pixels[pixel];
-    const unsigned int c2 = pixels[pixel + 1];
-
-    // Save the averaged byte pixel component:
-    pixels[outPixel] = static_cast<unsigned char>(AverageComponent(c1, c2));
+    /**
+     * @code
+     * // Load all the byte pixel components we need:
+     * const unsigned int c1 = pixels[pixel];
+     * const unsigned int c2 = pixels[pixel + 1];
+     *
+     * // Save the averaged byte pixel component:
+     * pixels[outPixel] = static_cast<unsigned char>(AverageComponent(c1, c2));
+     * @endcode
+     */
+    // Note : We can assume that pixel is even number. So we can use | operation instead of + operation.
+    pixels[outPixel] = ((pixels[pixel] ^ pixels[pixel | 1]) >> 1) + (pixels[pixel] & pixels[pixel | 1]);
   }
 }
 
index 81a722c..dd8db98 100644 (file)
@@ -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.
@@ -542,13 +542,17 @@ inline unsigned int AverageComponent(unsigned int a, unsigned int b)
  **/
 inline uint32_t AveragePixelRGBA8888(uint32_t a, uint32_t b)
 {
-  const unsigned int avg =
-    ((AverageComponent((a & 0xff000000) >> 1u, (b & 0xff000000) >> 1u) << 1u) & 0xff000000) +
-    (AverageComponent(a & 0x00ff0000, b & 0x00ff0000) & 0x00ff0000) +
-    (AverageComponent(a & 0x0000ff00, b & 0x0000ff00) & 0x0000ff00) +
-    (AverageComponent(a & 0x000000ff, b & 0x000000ff));
-  return avg;
-  ///@ToDo: Optimise by trying return (((a ^ b) & 0xfefefefeUL) >> 1) + (a & b);
+  /**
+   * @code
+   * const unsigned int avg =
+   *   (AverageComponent((a & 0xff000000) >> 1u, (b & 0xff000000) >> 1u) << 1u) & 0xff000000) +
+   *   (AverageComponent(a & 0x00ff0000, b & 0x00ff0000) & 0x00ff0000) +
+   *   (AverageComponent(a & 0x0000ff00, b & 0x0000ff00) & 0x0000ff00) +
+   *   (AverageComponent(a & 0x000000ff, b & 0x000000ff);
+   * return avg;
+   * @endcode
+   */
+  return (((a ^ b) & 0xfefefefeu) >> 1) + (a & b);
   ///@ToDo: Optimise for ARM using the single ARMV6 instruction: UHADD8  R4, R0, R5. This is not Neon. It runs in the normal integer pipeline so there is no downside like a stall moving between integer and copro.
 }
 
@@ -560,11 +564,16 @@ inline uint32_t AveragePixelRGBA8888(uint32_t a, uint32_t b)
  **/
 inline uint32_t AveragePixelRGB565(uint32_t a, uint32_t b)
 {
-  const unsigned int avg =
-    (AverageComponent(a & 0xf800, b & 0xf800) & 0xf800) +
-    (AverageComponent(a & 0x7e0, b & 0x7e0) & 0x7e0) +
-    (AverageComponent(a & 0x1f, b & 0x1f));
-  return avg;
+  /**
+   * @code
+   * const unsigned int avg =
+   *   (AverageComponent(a & 0xf800, b & 0xf800) & 0xf800) +
+   *   (AverageComponent(a & 0x7e0, b & 0x7e0) & 0x7e0) +
+   *   (AverageComponent(a & 0x1f, b & 0x1f));
+   * return avg;
+   * @endcode
+   */
+  return (((a ^ b) & 0xf7deu) >> 1) + (a & b);
 }
 
 /** @return The weighted blend of two integers as a 16.16 fixed-point number, given a 0.16 fixed-point blending factor. */
index 6ed2e31..747dcb3 100644 (file)
@@ -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.
@@ -449,15 +449,26 @@ void PixelBuffer::MultiplyColorByAlpha()
     for(unsigned int i = 0; i < bufferSize; ++i)
     {
       unsigned int alpha = ReadChannel(pixel, mPixelFormat, Adaptor::ALPHA);
+      if(alpha < 255)
       {
-        auto red       = ReadChannel(pixel, mPixelFormat, Adaptor::RED);
-        auto green     = ReadChannel(pixel, mPixelFormat, Adaptor::GREEN);
-        auto blue      = ReadChannel(pixel, mPixelFormat, Adaptor::BLUE);
-        auto luminance = ReadChannel(pixel, mPixelFormat, Adaptor::LUMINANCE);
-        WriteChannel(pixel, mPixelFormat, Adaptor::RED, red * alpha / 255);
-        WriteChannel(pixel, mPixelFormat, Adaptor::GREEN, green * alpha / 255);
-        WriteChannel(pixel, mPixelFormat, Adaptor::BLUE, blue * alpha / 255);
-        WriteChannel(pixel, mPixelFormat, Adaptor::LUMINANCE, luminance * alpha / 255);
+        // 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 red       = ReadChannel(pixel, mPixelFormat, Adaptor::RED);
+          auto green     = ReadChannel(pixel, mPixelFormat, Adaptor::GREEN);
+          auto blue      = ReadChannel(pixel, mPixelFormat, Adaptor::BLUE);
+          auto luminance = ReadChannel(pixel, mPixelFormat, Adaptor::LUMINANCE);
+          WriteChannel(pixel, mPixelFormat, Adaptor::RED, red * alpha / 255);
+          WriteChannel(pixel, mPixelFormat, Adaptor::GREEN, green * alpha / 255);
+          WriteChannel(pixel, mPixelFormat, Adaptor::BLUE, blue * alpha / 255);
+          WriteChannel(pixel, mPixelFormat, Adaptor::LUMINANCE, luminance * alpha / 255);
+        }
+        else
+        {
+          // If alpha is 0, just set all pixel as zero.
+          memset(pixel, 0, bytesPerPixel);
+        }
       }
       pixel += bytesPerPixel;
     }