LuminanceNEON.cpp (3320B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include <arm_neon.h> 8 #include "LuminanceNEON.h" 9 10 using namespace mozilla::gfx; 11 12 /** 13 * Byte offsets of channels in a native packed gfxColor or cairo image surface. 14 */ 15 #ifdef IS_BIG_ENDIAN 16 # define GFX_ARGB32_OFFSET_A 0 17 # define GFX_ARGB32_OFFSET_R 1 18 # define GFX_ARGB32_OFFSET_G 2 19 # define GFX_ARGB32_OFFSET_B 3 20 #else 21 # define GFX_ARGB32_OFFSET_A 3 22 # define GFX_ARGB32_OFFSET_R 2 23 # define GFX_ARGB32_OFFSET_G 1 24 # define GFX_ARGB32_OFFSET_B 0 25 #endif 26 27 void ComputesRGBLuminanceMask_NEON(const uint8_t* aSourceData, 28 int32_t aSourceStride, uint8_t* aDestData, 29 int32_t aDestStride, const IntSize& aSize, 30 float aOpacity) { 31 int32_t redFactor = 55 * aOpacity; // 255 * 0.2125 * opacity 32 int32_t greenFactor = 183 * aOpacity; // 255 * 0.7154 * opacity 33 int32_t blueFactor = 18 * aOpacity; // 255 * 0.0721 34 const uint8_t* sourcePixel = aSourceData; 35 int32_t sourceOffset = aSourceStride - 4 * aSize.width; 36 uint8_t* destPixel = aDestData; 37 int32_t destOffset = aDestStride - aSize.width; 38 39 sourcePixel = aSourceData; 40 int32_t remainderWidth = aSize.width % 8; 41 int32_t roundedWidth = aSize.width - remainderWidth; 42 uint16x8_t temp; 43 uint8x8_t gray; 44 uint8x8_t redVector = vdup_n_u8(redFactor); 45 uint8x8_t greenVector = vdup_n_u8(greenFactor); 46 uint8x8_t blueVector = vdup_n_u8(blueFactor); 47 uint8x8_t fullBitVector = vdup_n_u8(255); 48 uint8x8_t oneVector = vdup_n_u8(1); 49 for (int32_t y = 0; y < aSize.height; y++) { 50 // Calculate luminance by neon with 8 pixels per loop 51 for (int32_t x = 0; x < roundedWidth; x += 8) { 52 uint8x8x4_t argb = vld4_u8(sourcePixel); 53 temp = vmull_u8(argb.val[GFX_ARGB32_OFFSET_R], 54 redVector); // temp = red * redFactor 55 temp = vmlal_u8(temp, argb.val[GFX_ARGB32_OFFSET_G], 56 greenVector); // temp += green * greenFactor 57 temp = vmlal_u8(temp, argb.val[GFX_ARGB32_OFFSET_B], 58 blueVector); // temp += blue * blueFactor 59 gray = vshrn_n_u16(temp, 8); // gray = temp >> 8 60 61 // Check alpha value 62 uint8x8_t alphaVector = 63 vtst_u8(argb.val[GFX_ARGB32_OFFSET_A], fullBitVector); 64 gray = vmul_u8(gray, vand_u8(alphaVector, oneVector)); 65 66 // Put the result to the 8 pixels 67 vst1_u8(destPixel, gray); 68 sourcePixel += 8 * 4; 69 destPixel += 8; 70 } 71 72 // Calculate the rest pixels of the line by cpu 73 for (int32_t x = 0; x < remainderWidth; x++) { 74 if (sourcePixel[GFX_ARGB32_OFFSET_A] > 0) { 75 *destPixel = (redFactor * sourcePixel[GFX_ARGB32_OFFSET_R] + 76 greenFactor * sourcePixel[GFX_ARGB32_OFFSET_G] + 77 blueFactor * sourcePixel[GFX_ARGB32_OFFSET_B]) >> 78 8; 79 } else { 80 *destPixel = 0; 81 } 82 sourcePixel += 4; 83 destPixel++; 84 } 85 sourcePixel += sourceOffset; 86 destPixel += destOffset; 87 } 88 }