/* * img_rgb_packed.c - RGB packed image format conversion routines * Written by Andrew Church * * This file is part of transcode, a video stream processing tool. * transcode is free software, distributable under the terms of the GNU * General Public License (version 2 or later). See the file COPYING * for details. */ #include "ac.h" #include "imgconvert.h" #include "img_internal.h" /*************************************************************************/ /*************************************************************************/ /* Standard C implementations */ /*************************************************************************/ /* Identity transformations, all work when src==dest */ static int rgb_copy(uint8_t **src, uint8_t **dest, int width, int height) { ac_memcpy(dest[0], src[0], width*height*3); return 1; } static int rgba_copy(uint8_t **src, uint8_t **dest, int width, int height) { ac_memcpy(dest[0], src[0], width*height*4); return 1; } static int gray8_copy(uint8_t **src, uint8_t **dest, int width, int height) { ac_memcpy(dest[0], src[0], width*height); return 1; } /*************************************************************************/ /* Conversions between various 32-bit formats, all usable when src==dest */ /* RGBA<->ABGR and ARGB<->BGRA: reverse byte order */ static int rgba_swapall(uint8_t **src, uint8_t **dest, int width, int height) { uint32_t *srcp = (uint32_t *)src[0]; uint32_t *destp = (uint32_t *)dest[0]; int i; for (i = 0; i < width*height; i++) { /* This shortcut works regardless of CPU endianness */ destp[i] = srcp[i] >> 24 | (srcp[i] & 0x00FF0000) >> 8 | (srcp[i] & 0x0000FF00) << 8 | srcp[i] << 24; } return 1; } /* RGBA<->BGRA: swap bytes 0 and 2 */ static int rgba_swap02(uint8_t **src, uint8_t **dest, int width, int height) { int i; for (i = 0; i < width*height; i++) { uint8_t tmp = src[0][i*4+2]; dest[0][i*4+2] = src[0][i*4 ]; dest[0][i*4 ] = tmp; dest[0][i*4+1] = src[0][i*4+1]; dest[0][i*4+3] = src[0][i*4+3]; } return 1; } /* ARGB<->ABGR: swap bytes 1 and 3 */ static int rgba_swap13(uint8_t **src, uint8_t **dest, int width, int height) { int i; for (i = 0; i < width*height; i++) { uint8_t tmp = src[0][i*4+3]; dest[0][i*4+3] = src[0][i*4+1]; dest[0][i*4+1] = tmp; dest[0][i*4 ] = src[0][i*4 ]; dest[0][i*4+2] = src[0][i*4+2]; } return 1; } /* RGBA->ARGB and BGRA->ABGR: alpha moves from byte 3 to byte 0 */ static int rgba_alpha30(uint8_t **src, uint8_t **dest, int width, int height) { int i; for (i = 0; i < width*height; i++) { uint8_t tmp = src[0][i*4+3]; dest[0][i*4+3] = src[0][i*4+2]; dest[0][i*4+2] = src[0][i*4+1]; dest[0][i*4+1] = src[0][i*4 ]; dest[0][i*4 ] = tmp; } return 1; } /* ARGB->RGBA and ABGR->BGRA: alpha moves from byte 0 to byte 3 */ static int rgba_alpha03(uint8_t **src, uint8_t **dest, int width, int height) { int i; for (i = 0; i < width*height; i++) { uint8_t tmp = src[0][i*4 ]; dest[0][i*4 ] = src[0][i*4+1]; dest[0][i*4+1] = src[0][i*4+2]; dest[0][i*4+2] = src[0][i*4+3]; dest[0][i*4+3] = tmp; } return 1; } /*************************************************************************/ static int rgb24_bgr24(uint8_t **src, uint8_t **dest, int width, int height) { int i; for (i = 0; i < width*height; i++) { dest[0][i*3 ] = src[0][i*3+2]; dest[0][i*3+1] = src[0][i*3+1]; dest[0][i*3+2] = src[0][i*3 ]; } return 1; } static int rgb24_rgba32(uint8_t **src, uint8_t **dest, int width, int height) { int i; for (i = 0; i < width*height; i++) { dest[0][i*4 ] = src[0][i*3 ]; dest[0][i*4+1] = src[0][i*3+1]; dest[0][i*4+2] = src[0][i*3+2]; dest[0][i*4+3] = 0; } return 1; } static int rgb24_abgr32(uint8_t **src, uint8_t **dest, int width, int height) { int i; for (i = 0; i < width*height; i++) { dest[0][i*4 ] = 0; dest[0][i*4+1] = src[0][i*3+2]; dest[0][i*4+2] = src[0][i*3+1]; dest[0][i*4+3] = src[0][i*3 ]; } return 1; } static int rgb24_argb32(uint8_t **src, uint8_t **dest, int width, int height) { int i; for (i = 0; i < width*height; i++) { dest[0][i*4 ] = 0; dest[0][i*4+1] = src[0][i*3 ]; dest[0][i*4+2] = src[0][i*3+1]; dest[0][i*4+3] = src[0][i*3+2]; } return 1; } static int rgb24_bgra32(uint8_t **src, uint8_t **dest, int width, int height) { int i; for (i = 0; i < width*height; i++) { dest[0][i*4 ] = src[0][i*3+2]; dest[0][i*4+1] = src[0][i*3+1]; dest[0][i*4+2] = src[0][i*3 ]; dest[0][i*4+3] = 0; } return 1; } static int rgb24_gray8(uint8_t **src, uint8_t **dest, int width, int height) { int i; for (i = 0; i < width*height; i++) { /* Use the Y part of a YUV transformation, scaled to 0..255 */ int r = src[0][i*3 ]; int g = src[0][i*3+1]; int b = src[0][i*3+2]; dest[0][i] = (19595*r + 38470*g + 7471*b + 32768) >> 16; } return 1; } static int bgr24_gray8(uint8_t **src, uint8_t **dest, int width, int height) { int i; for (i = 0; i < width*height; i++) { /* Use the Y part of a YUV transformation, scaled to 0..255 */ int r = src[0][i*3+2]; int g = src[0][i*3+1]; int b = src[0][i*3 ]; dest[0][i] = (19595*r + 38470*g + 7471*b + 32768) >> 16; } return 1; } /*************************************************************************/ static int rgba32_rgb24(uint8_t **src, uint8_t **dest, int width, int height) { int i; for (i = 0; i < width*height; i++) { dest[0][i*3 ] = src[0][i*4 ]; dest[0][i*3+1] = src[0][i*4+1]; dest[0][i*3+2] = src[0][i*4+2]; } return 1; } static int bgra32_rgb24(uint8_t **src, uint8_t **dest, int width, int height) { int i; for (i = 0; i < width*height; i++) { dest[0][i*3 ] = src[0][i*4+2]; dest[0][i*3+1] = src[0][i*4+1]; dest[0][i*3+2] = src[0][i*4 ]; } return 1; } static int rgba32_gray8(uint8_t **src, uint8_t **dest, int width, int height) { int i; for (i = 0; i < width*height; i++) { /* Use the Y part of a YUV transformation, scaled to 0..255 */ int r = src[0][i*4 ]; int g = src[0][i*4+1]; int b = src[0][i*4+2]; dest[0][i] = (19595*r + 38470*g + 7471*b + 32768) >> 16; } return 1; } static int bgra32_gray8(uint8_t **src, uint8_t **dest, int width, int height) { int i; for (i = 0; i < width*height; i++) { /* Use the Y part of a YUV transformation, scaled to 0..255 */ int r = src[0][i*4+2]; int g = src[0][i*4+1]; int b = src[0][i*4 ]; dest[0][i] = (19595*r + 38470*g + 7471*b + 32768) >> 16; } return 1; } /*************************************************************************/ static int argb32_rgb24(uint8_t **src, uint8_t **dest, int width, int height) { int i; for (i = 0; i < width*height; i++) { dest[0][i*3 ] = src[0][i*4+1]; dest[0][i*3+1] = src[0][i*4+2]; dest[0][i*3+2] = src[0][i*4+3]; } return 1; } static int abgr32_rgb24(uint8_t **src, uint8_t **dest, int width, int height) { int i; for (i = 0; i < width*height; i++) { dest[0][i*3 ] = src[0][i*4+3]; dest[0][i*3+1] = src[0][i*4+2]; dest[0][i*3+2] = src[0][i*4+1]; } return 1; } static int argb32_gray8(uint8_t **src, uint8_t **dest, int width, int height) { int i; for (i = 0; i < width*height; i++) { /* Use the Y part of a YUV transformation, scaled to 0..255 */ int r = src[0][i*4+1]; int g = src[0][i*4+2]; int b = src[0][i*4+3]; dest[0][i] = (19595*r + 38470*g + 7471*b + 32768) >> 16; } return 1; } static int abgr32_gray8(uint8_t **src, uint8_t **dest, int width, int height) { int i; for (i = 0; i < width*height; i++) { /* Use the Y part of a YUV transformation, scaled to 0..255 */ int r = src[0][i*4+3]; int g = src[0][i*4+2]; int b = src[0][i*4+1]; dest[0][i] = (19595*r + 38470*g + 7471*b + 32768) >> 16; } return 1; } /*************************************************************************/ static int gray8_rgb24(uint8_t **src, uint8_t **dest, int width, int height) { int i; for (i = 0; i < width*height; i++) { dest[0][i*3 ] = src[0][i]; dest[0][i*3+1] = src[0][i]; dest[0][i*3+2] = src[0][i]; } return 1; } static int gray8_rgba32(uint8_t **src, uint8_t **dest, int width, int height) { int i; for (i = 0; i < width*height; i++) { dest[0][i*4 ] = src[0][i]; dest[0][i*4+1] = src[0][i]; dest[0][i*4+2] = src[0][i]; dest[0][i*4+3] = 0; } return 1; } static int gray8_argb32(uint8_t **src, uint8_t **dest, int width, int height) { int i; for (i = 0; i < width*height; i++) { dest[0][i*4 ] = 0; dest[0][i*4+1] = src[0][i]; dest[0][i*4+2] = src[0][i]; dest[0][i*4+3] = src[0][i]; } return 1; } /*************************************************************************/ /*************************************************************************/ #if defined(ARCH_X86) || defined(ARCH_X86_64) #define DEFINE_MASK_DATA #include "img_x86_common.h" /*************************************************************************/ /* Basic assembly routines */ /* RGBA<->ABGR and ARGB<->BGRA: reverse byte order */ static int rgba_swapall_x86(uint8_t **src, uint8_t **dest, int width, int height) { ASM_REV32_X86(width*height); return 1; } /* RGBA<->BGRA: swap bytes 0 and 2 */ static int rgba_swap02_x86(uint8_t **src, uint8_t **dest, int width, int height) { ASM_SWAP32_02_X86(width*height); return 1; } /* ARGB<->ABGR: swap bytes 1 and 3 */ static int rgba_swap13_x86(uint8_t **src, uint8_t **dest, int width, int height) { ASM_SWAP32_13_X86(width*height); return 1; } /* RGBA->ARGB and BGRA->ABGR: alpha moves from byte 3 to byte 0 */ static int rgba_alpha30_x86(uint8_t **src, uint8_t **dest, int width, int height) { ASM_ROL32_X86(width*height); return 1; } /* ARGB->RGBA and ABGR->BGRA: alpha moves from byte 0 to byte 3 */ static int rgba_alpha03_x86(uint8_t **src, uint8_t **dest, int width, int height) { ASM_ROR32_X86(width*height); return 1; } /*************************************************************************/ /* MMX routines */ #if defined(HAVE_ASM_MMX) && defined(ARCH_X86) /* i.e. not x86_64 */ /* RGBA<->ABGR and ARGB<->BGRA: reverse byte order */ static int rgba_swapall_mmx(uint8_t **src, uint8_t **dest, int width, int height) { ASM_REV32_MMX(width*height); return 1; } /* RGBA<->BGRA: swap bytes 0 and 2 */ static int rgba_swap02_mmx(uint8_t **src, uint8_t **dest, int width, int height) { ASM_SWAP32_02_MMX(width*height); return 1; } /* ARGB<->ABGR: swap bytes 1 and 3 */ static int rgba_swap13_mmx(uint8_t **src, uint8_t **dest, int width, int height) { ASM_SWAP32_13_MMX(width*height); return 1; } /* RGBA->ARGB and BGRA->ABGR: alpha moves from byte 3 to byte 0 */ static int rgba_alpha30_mmx(uint8_t **src, uint8_t **dest, int width, int height) { ASM_ROL32_MMX(width*height); return 1; } /* ARGB->RGBA and ABGR->BGRA: alpha moves from byte 0 to byte 3 */ static int rgba_alpha03_mmx(uint8_t **src, uint8_t **dest, int width, int height) { ASM_ROR32_MMX(width*height); return 1; } #endif /* HAVE_ASM_MMX && ARCH_X86 */ /*************************************************************************/ /* SSE2 routines */ #if defined(HAVE_ASM_SSE2) static const struct { uint32_t n[4]; } __attribute__((aligned(16))) rgb_bgr_data = {{ 0xFF0000FF, 0x00FF0000, 0x0000FF00, 0x00000000 }}; #define SHIFT_RBSWAP \ "movdqa %%xmm6, %%xmm2 # XMM2: low bytes mask \n\ pand %%xmm0, %%xmm2 # XMM2: R/B bytes \n\ pshuflw $0xB1, %%xmm2, %%xmm2 # XMM2: swap R and B (low quad) \n\ pand %%xmm7, %%xmm0 # XMM0: G bytes \n\ pshufhw $0xB1, %%xmm2, %%xmm2 # XMM2: swap R and B (high quad)\n\ por %%xmm2, %%xmm0 # XMM0: data now in BGRA32 \n" #define SHIFT_AFIRST \ "pslldq $1, %%xmm0 # XMM0: move A first \n" #define SHIFT_ALAST \ "psrldq $1, %%xmm0 # XMM0: move A last \n" #define RGB24TO32(ROFS,GOFS,BOFS,AOFS,SHIFT) \ asm("pcmpeqd %%xmm5, %%xmm5 \n\ movdqa %%xmm5, %%xmm6 \n\ psrldq $13, %%xmm5 # XMM5: 24-bit mask \n\ movdqa %%xmm6, %%xmm7 \n\ psrlw $8, %%xmm6 # XMM6: low bytes mask \n\ psllw $8, %%xmm7 # XMM7: high bytes mask \n"\ SIMD_LOOP_WRAPPER( \ /* blocksize */ 4, \ /* push_regs */ "", \ /* pop_regs */ "", \ /* small_loop */ \ "lea ("ECX","ECX",2),"EDX" \n\ movb -3("ESI","EDX"), %%al \n\ movb %%al, ("#ROFS"-4)("EDI","ECX",4) \n\ movb -2("ESI","EDX"), %%al \n\ movb %%al, ("#GOFS"-4)("EDI","ECX",4) \n\ movb -1("ESI","EDX"), %%al \n\ movb %%al, ("#BOFS"-4)("EDI","ECX",4) \n\ movb $0, ("#AOFS"-4)("EDI","ECX",4)", \ /* main_loop */ \ "lea ("ECX","ECX",2),"EDX" \n\ # We can't just movdqu, because we might run over the edge \n\ movd -12("ESI","EDX"), %%xmm1 \n\ movq -8("ESI","EDX"), %%xmm0 \n\ pshufd $0xD3, %%xmm0, %%xmm0 # shift left by 4 bytes \n\ por %%xmm1, %%xmm0 # XMM0: original RGB24 data \n\ pshufd $0xF3, %%xmm5, %%xmm2 # XMM2: pixel 1 mask \n\ movdqa %%xmm5, %%xmm1 # XMM1: pixel 0 mask \n\ pshufd $0xCF, %%xmm5, %%xmm3 # XMM3: pixel 2 mask \n\ pand %%xmm0, %%xmm1 # XMM1: pixel 0 \n\ pslldq $1, %%xmm0 \n\ pand %%xmm0, %%xmm2 # XMM2: pixel 1 \n\ pshufd $0x3F, %%xmm5, %%xmm4 # XMM4: pixel 3 mask \n\ por %%xmm2, %%xmm1 # XMM1: pixels 0 and 1 \n\ pslldq $1, %%xmm0 \n\ pand %%xmm0, %%xmm3 # XMM3: pixel 2 \n\ por %%xmm3, %%xmm1 # XMM1: pixels 0, 1, and 2 \n\ pslldq $1, %%xmm0 \n\ pand %%xmm4, %%xmm0 # XMM0: pixel 3 \n\ por %%xmm1, %%xmm0 # XMM0: RGBA32 data \n\ "SHIFT" # shift bytes to target position\n\ movdqu %%xmm0, -16("EDI","ECX",4)", \ /* emms */ "emms") \ : /* no outputs */ \ : "S" (src[0]), "D" (dest[0]), "c" (width*height), \ "d" (&rgb_bgr_data), "m" (rgb_bgr_data) \ : "eax"); #define RGB32TO24(ROFS,GOFS,BOFS,AOFS,SHIFT) \ asm("pcmpeqd %%xmm5, %%xmm5 \n\ movdqa %%xmm5, %%xmm6 \n\ psrldq $13, %%xmm5 # 24-bit mask \n\ movdqa %%xmm6, %%xmm7 \n\ psrlw $8, %%xmm6 # low bytes mask \n\ psllw $8, %%xmm7 # high bytes mask \n"\ SIMD_LOOP_WRAPPER( \ /* blocksize */ 4, \ /* push_regs */ "", \ /* pop_regs */ "", \ /* small_loop */ \ "lea ("ECX","ECX",2),"EDX" \n\ movb ("#ROFS"-4)("ESI","ECX",4), %%al \n\ movb %%al, -3("EDI","EDX") \n\ movb ("#GOFS"-4)("ESI","ECX",4), %%al \n\ movb %%al, -2("EDI","EDX") \n\ movb ("#BOFS"-4)("ESI","ECX",4), %%al \n\ movb %%al, -1("EDI","EDX")", \ /* main_loop */ \ "lea ("ECX","ECX",2),"EDX" \n\ movdqu -16("ESI","ECX",4), %%xmm0 \n\ "SHIFT" # shift source data to RGBA \n\ pshufd $0xF3, %%xmm5, %%xmm1 # XMM1: pixel 1 mask \n\ pshufd $0xCF, %%xmm5, %%xmm2 # XMM2: pixel 2 mask \n\ pshufd $0x3F, %%xmm5, %%xmm3 # XMM3: pixel 3 mask \n\ pand %%xmm0, %%xmm3 # XMM3: pixel 3 \n\ psrldq $1, %%xmm3 \n\ pand %%xmm0, %%xmm2 # XMM2: pixel 2 \n\ por %%xmm3, %%xmm2 # XMM2: pixels 2 and 3 \n\ psrldq $1, %%xmm2 \n\ pand %%xmm0, %%xmm1 # XMM1: pixel 1 \n\ pand %%xmm5, %%xmm0 # XMM0: pixel 0 \n\ por %%xmm2, %%xmm1 # XMM1: pixels 1, 2, and 3 \n\ psrldq $1, %%xmm1 \n\ por %%xmm1, %%xmm0 # XMM0: RGB24 data \n\ # We can't just movdqu, because we might run over the edge \n\ movd %%xmm0, -12("EDI","EDX") # store low 4 bytes \n\ pshufd $0xF9, %%xmm0, %%xmm0 # shift right 4 bytes \n\ movq %%xmm0, -8("EDI","EDX") # store high 8 bytes \n",\ /* emms */ "emms") \ : /* no outputs */ \ : "S" (src[0]), "D" (dest[0]), "c" (width*height), \ "d" (&rgb_bgr_data), "m" (rgb_bgr_data) \ : "eax"); /* RGBA<->ABGR and ARGB<->BGRA: reverse byte order */ static int rgba_swapall_sse2(uint8_t **src, uint8_t **dest, int width, int height) { ASM_REV32_SSE2(width*height); return 1; } /* RGBA<->BGRA: swap bytes 0 and 2 */ static int rgba_swap02_sse2(uint8_t **src, uint8_t **dest, int width, int height) { ASM_SWAP32_02_SSE2(width*height); return 1; } /* ARGB<->ABGR: swap bytes 1 and 3 */ static int rgba_swap13_sse2(uint8_t **src, uint8_t **dest, int width, int height) { ASM_SWAP32_13_SSE2(width*height); return 1; } /* RGBA->ARGB and BGRA->ABGR: alpha moves from byte 3 to byte 0 */ static int rgba_alpha30_sse2(uint8_t **src, uint8_t **dest, int width, int height) { ASM_ROL32_SSE2(width*height); return 1; } /* ARGB->RGBA and ABGR->BGRA: alpha moves from byte 0 to byte 3 */ static int rgba_alpha03_sse2(uint8_t **src, uint8_t **dest, int width, int height) { ASM_ROR32_SSE2(width*height); return 1; } /* RGB<->BGR */ static int rgb24_bgr24_sse2(uint8_t **src, uint8_t **dest, int width, int height) { asm("movdqa ("EDX"), %%xmm5 # byte 0 mask \n\ pshufd $0xD2, %%xmm5, %%xmm6 # byte 1 mask \n\ pshufd $0xC9, %%xmm5, %%xmm7 # byte 2 mask \n" SIMD_LOOP_WRAPPER( /* blocksize */ 4, /* push_regs */ "", /* pop_regs */ "", /* small_loop */ "lea ("ECX","ECX",2),"EDX" \n\ movb -3("ESI","EDX"), %%al \n\ movb -2("ESI","EDX"), %%ah \n\ movb %%ah, -2("EDI","EDX") \n\ movb -1("ESI","EDX"), %%ah \n\ movb %%ah, -3("EDI","EDX") \n\ movb %%al, -1("EDI","EDX")", /* main_loop */ "lea ("ECX","ECX",2),"EDX" \n\ # We can't just movdqu, because we might run over the edge \n\ movd -12("ESI","EDX"), %%xmm1 \n\ movq -8("ESI","EDX"), %%xmm0 \n\ pshufd $0xD3, %%xmm0, %%xmm0 # shift left by 4 bytes \n\ por %%xmm1, %%xmm0 # XMM0: original data \n\ movdqa %%xmm5, %%xmm2 \n\ movdqa %%xmm6, %%xmm3 \n\ movdqa %%xmm7, %%xmm4 \n\ pand %%xmm0, %%xmm2 # XMM2: byte 0 \n\ pslldq $2, %%xmm2 # shift to byte 2 position \n\ pand %%xmm0, %%xmm3 # XMM3: byte 1 \n\ pand %%xmm0, %%xmm4 # XMM4: byte 2 \n\ psrldq $2, %%xmm4 # shift to byte 0 position \n\ por %%xmm2, %%xmm3 \n\ por %%xmm4, %%xmm3 # XMM3: reversed data \n\ movd %%xmm3, -12("EDI","EDX") # avoid running over the edge \n\ pshufd $0xF9, %%xmm3, %%xmm3 # shift right by 4 bytes \n\ movq %%xmm3, -8("EDI","EDX")", /* emms */ "emms") : /* no outputs */ : "S" (src[0]), "D" (dest[0]), "c" (width*height), "d" (&rgb_bgr_data), "m" (rgb_bgr_data) : "eax"); return 1; } /* RGB->RGBA */ static int rgb24_rgba32_sse2(uint8_t **src, uint8_t **dest, int width, int height) { RGB24TO32(0,1,2,3, ""); return 1; } /* RGB->ABGR */ static int rgb24_abgr32_sse2(uint8_t **src, uint8_t **dest, int width, int height) { RGB24TO32(3,2,1,0, SHIFT_RBSWAP SHIFT_AFIRST); return 1; } /* RGB->ARGB */ static int rgb24_argb32_sse2(uint8_t **src, uint8_t **dest, int width, int height) { RGB24TO32(1,2,3,0, SHIFT_AFIRST); return 1; } /* RGB->BGRA */ static int rgb24_bgra32_sse2(uint8_t **src, uint8_t **dest, int width, int height) { RGB24TO32(2,1,0,3, SHIFT_RBSWAP); return 1; } /* RGBA->RGB */ static int rgba32_rgb24_sse2(uint8_t **src, uint8_t **dest, int width, int height) { RGB32TO24(0,1,2,3, ""); return 1; } /* ABGR->RGB */ static int abgr32_rgb24_sse2(uint8_t **src, uint8_t **dest, int width, int height) { RGB32TO24(3,2,1,0, SHIFT_ALAST SHIFT_RBSWAP); return 1; } /* ARGB->RGB */ static int argb32_rgb24_sse2(uint8_t **src, uint8_t **dest, int width, int height) { RGB32TO24(1,2,3,0, SHIFT_ALAST); return 1; } /* BGRA->RGB */ static int bgra32_rgb24_sse2(uint8_t **src, uint8_t **dest, int width, int height) { RGB32TO24(2,1,0,3, SHIFT_RBSWAP); return 1; } /*************************************************************************/ #define R_GRAY 19595 #define G_GRAY 38470 #define B_GRAY 7471 #define INIT_GRAY8 \ "pxor %%xmm4, %%xmm4 # XMM4: all 0's \n\ movl %3, %%eax \n\ movd %%eax, %%xmm5 \n\ pshuflw $0x00, %%xmm5, %%xmm5 \n\ pshufd $0x00, %%xmm5, %%xmm5 # XMM5: R->gray constant \n\ movl %4, %%eax \n\ movd %%eax, %%xmm6 \n\ pshuflw $0x00, %%xmm6, %%xmm6 \n\ pshufd $0x00, %%xmm6, %%xmm6 # XMM6: G->gray constant \n\ movl %5, %%eax \n\ movd %%eax, %%xmm7 \n\ pshuflw $0x00, %%xmm7, %%xmm7 \n\ pshufd $0x00, %%xmm7, %%xmm7 # XMM7: B->gray constant \n\ pcmpeqd %%xmm3, %%xmm3 \n\ psllw $15, %%xmm3 \n\ psrlw $8, %%xmm3 # XMM3: 0x0080*8 (for rounding) \n" #define SINGLE_GRAY8(idx,ofsR,ofsG,ofsB) \ "movzbl "#ofsR"("ESI","idx"), %%eax # retrieve red byte \n\ imull %3, %%eax # multiply by red->gray factor \n\ movzbl "#ofsG"("ESI","idx"), %%edx # retrieve green byte \n\ imull %4, %%edx # multiply by green->gray factor\n\ addl %%edx, %%eax # add to total \n\ movzbl "#ofsB"("ESI","idx"), %%edx # retrieve blue byte \n\ imull %5, %%edx # multiply by blue->gray factor \n\ addl %%edx, %%eax # add to total \n\ addl $0x8000, %%eax # round \n\ shrl $16, %%eax # shift back down \n\ movb %%al, -1("EDI","ECX") # and store \n" #define STORE_GRAY8 \ "psllw $8, %%xmm0 # XMM0: add 8 bits of precision \n\ pmulhuw %%xmm5, %%xmm0 # XMM0: r7 r6 r5 r4 r3 r2 r1 r0 \n\ psllw $8, %%xmm1 # XMM1: add 8 bits of precision \n\ pmulhuw %%xmm6, %%xmm1 # XMM1: g7 g6 g5 g4 g3 g2 g1 g0 \n\ paddw %%xmm3, %%xmm0 # XMM0: add rounding constant \n\ psllw $8, %%xmm2 # XMM2: add 8 bits of precision \n\ pmulhuw %%xmm7, %%xmm2 # XMM2: b7 b6 b5 b4 b3 b2 b1 b0 \n\ paddw %%xmm1, %%xmm0 # XMM0: add green part \n\ paddw %%xmm2, %%xmm0 # XMM0: add blue part \n\ psrlw $8, %%xmm0 # XMM0: shift back to bytes \n\ packuswb %%xmm4, %%xmm0 # XMM0: gray7..gray0 packed \n\ movq %%xmm0, -8("EDI","ECX") \n" #define ASM_RGB24_GRAY(ofsR,ofsG,ofsB,load) \ asm(INIT_GRAY8 \ PUSH(EBX)" \n\ lea ("ECX","ECX",2),"EBX" \n"\ SIMD_LOOP_WRAPPER( \ /* blocksize */ 8, \ /* push_regs */ "", \ /* pop_regs */ "", \ /* small_loop */ SINGLE_GRAY8(EBX, ofsR,ofsG,ofsB) "subl $3, %%ebx;",\ /* main_loop */ load(4) STORE_GRAY8 "subl $24, %%ebx;", \ /* emms */ "emms") \ POP(EBX) \ : /* no outputs */ \ : "S" (src[0]), "D" (dest[0]), "c" (width*height), \ "i" (R_GRAY), "i" (G_GRAY), "i" (B_GRAY) \ : "eax", "edx" COMMA_FAKE_PUSH_REG \ ) #define ASM_RGB32_GRAY(ofsR,ofsG,ofsB,load) \ asm(INIT_GRAY8 \ SIMD_LOOP_WRAPPER( \ /* blocksize */ 8, \ /* push_regs */ "", \ /* pop_regs */ "", \ /* small_loop */ SINGLE_GRAY8(ECX",4", ofsR,ofsG,ofsB), \ /* main_loop */ load(4) STORE_GRAY8, \ /* emms */ "emms") \ : /* no outputs */ \ : "S" (src[0]), "D" (dest[0]), "c" (width*height), \ "i" (R_GRAY), "i" (G_GRAY), "i" (B_GRAY) \ : "eax", "edx") static int rgb24_gray8_sse2(uint8_t **src, uint8_t **dest, int width, int height) { ASM_RGB24_GRAY(-3,-2,-1, SSE2_LOAD_RGB24); return 1; } static int bgr24_gray8_sse2(uint8_t **src, uint8_t **dest, int width, int height) { ASM_RGB24_GRAY(-1,-2,-3, SSE2_LOAD_BGR24); return 1; } static int rgba32_gray8_sse2(uint8_t **src, uint8_t **dest, int width, int height) { ASM_RGB32_GRAY(-4,-3,-2, SSE2_LOAD_RGBA32); return 1; } static int bgra32_gray8_sse2(uint8_t **src, uint8_t **dest, int width, int height) { ASM_RGB32_GRAY(-2,-3,-4, SSE2_LOAD_BGRA32); return 1; } static int argb32_gray8_sse2(uint8_t **src, uint8_t **dest, int width, int height) { ASM_RGB32_GRAY(-3,-2,-1, SSE2_LOAD_ARGB32); return 1; } static int abgr32_gray8_sse2(uint8_t **src, uint8_t **dest, int width, int height) { ASM_RGB32_GRAY(-1,-2,-3, SSE2_LOAD_ABGR32); return 1; } /*************************************************************************/ static int gray8_rgb24_sse2(uint8_t **src, uint8_t **dest, int width, int height) { asm("# Store all 0's in XMM4 \n\ pxor %%xmm4, %%xmm4 \n\ # Generate mask in XMM7 to select bytes 0,3,6,9 of an XMM register\n\ pcmpeqd %%xmm7, %%xmm7 # XMM7: all 1's \n\ psrlw $8, %%xmm7 # XMM7: 0x00FF * 8 \n\ pcmpeqd %%xmm6, %%xmm6 # XMM6: all 1's \n\ psllw $8, %%xmm6 # XMM6: 0xFF00 * 8 \n\ pslldq $8, %%xmm6 \n\ psrldq $8, %%xmm7 \n\ por %%xmm6, %%xmm7 # XMM7: 0xFF00*4, 0x00FF*4 \n\ pshufd $0xCC, %%xmm7, %%xmm7 # XMM7: {0xFF00*2, 0x00FF*2} * 2\n\ pshuflw $0xC0, %%xmm7, %%xmm7 # XMM7.l: FF0000FF00FF00FF \n\ psrldq $4, %%xmm7 # XMM7: 0x00000000FF00FF00 \n\ # 00FF00FFFF0000FF \n\ pshufd $0xEC, %%xmm7, %%xmm7 # XMM7: 0x00000000FF00FF00 \n\ # 00000000FF0000FF \n\ pshuflw $0x24, %%xmm7, %%xmm7 # XMM7.l: 00FF0000FF0000FF \n\ pshufhw $0xFC, %%xmm7, %%xmm7 # XMM7.h: 000000000000FF00 \n\ # Load ECX*3 into EDX ahead of time \n\ lea ("ECX","ECX",2), "EDX" \n" SIMD_LOOP_WRAPPER( /* blocksize */ 4, /* push_regs */ "", /* pop_regs */ "", /* small_loop */ "\ movb -1("ESI","ECX"), %%al # retrieve gray byte \n\ movb %%al, -3("EDI","EDX") # and store 3 times \n\ movb %%al, -2("EDI","EDX") \n\ movb %%al, -1("EDI","EDX") \n\ subl $3, %%edx \n", /* main_loop */ "\ movd -4("ESI","ECX"), %%xmm0 # XMM0: G3..G0 \n\ pshufd $0xCC, %%xmm0, %%xmm0 # XMM0: {0,0,0,0,G3..G0} * 2 \n\ pshuflw $0x50, %%xmm0, %%xmm0 # X0.l: G3 G2 G3 G2 G1 G0 G1 G0 \n\ pshufhw $0x55, %%xmm0, %%xmm0 # X0.h: G3 G2 G3 G2 G3 G2 G3 G2 \n\ pand %%xmm7, %%xmm0 # XMM0: ------3--2--1--0 \n\ movdqa %%xmm0, %%xmm1 # XMM1: ------3--2--1--0 \n\ pslldq $1, %%xmm1 # XMM1: -----3--2--1--0- \n\ movdqa %%xmm0, %%xmm2 # XMM2: ------3--2--1--0 \n\ pslldq $2, %%xmm2 # XMM2: ----3--2--1--0-- \n\ por %%xmm1, %%xmm0 # XMM0: -----33-22-11-00 \n\ por %%xmm2, %%xmm0 # XMM0: ----333222111000 \n\ movd %%xmm0, -12("EDI","EDX") \n\ pshufd $0xC9, %%xmm0, %%xmm0 \n\ movq %%xmm0, -8("EDI","EDX") \n\ subl $12, %%edx \n", /* emms */ "emms") : /* no outputs */ : "S" (src[0]), "D" (dest[0]), "c" (width*height) : "eax", "edx"); return 1; } static int gray8_rgba32_sse2(uint8_t **src, uint8_t **dest, int width, int height) { asm("pxor %%xmm4, %%xmm4 # XMM4: all 0's \n" SIMD_LOOP_WRAPPER( /* blocksize */ 4, /* push_regs */ "", /* pop_regs */ "", /* small_loop */ "\ movb -1("ESI","ECX"), %%al # retrieve gray byte \n\ movb %%al, -4("EDI","ECX",4) # and store 3 times \n\ movb %%al, -3("EDI","ECX",4) \n\ movb %%al, -2("EDI","ECX",4) \n\ movb $0, -1("EDI","ECX",4) # clear A byte \n", /* main_loop */ "\ movd -4("ESI","ECX"), %%xmm0 # XMM0: 00 00 00 00 G3 G2 G1 G0 \n\ movdqa %%xmm0, %%xmm1 # XMM1: 00 00 00 00 G3 G2 G1 G0 \n\ punpcklbw %%xmm0, %%xmm0 # XMM0: G3 G3 G2 G2 G1 G1 G0 G0 \n\ punpcklbw %%xmm4, %%xmm1 # XMM1: 00 G3 00 G2 00 G1 00 G0 \n\ punpcklbw %%xmm1, %%xmm0 # XMM0: 0GGG3 0GGG2 0GGG1 0GGG0 \n\ movdqu %%xmm0, -16("EDI","ECX",4) \n", /* emms */ "emms") : /* no outputs */ : "S" (src[0]), "D" (dest[0]), "c" (width*height) : "eax"); return 1; } static int gray8_argb32_sse2(uint8_t **src, uint8_t **dest, int width, int height) { asm("pxor %%xmm4, %%xmm4 # XMM4: all 0's \n" SIMD_LOOP_WRAPPER( /* blocksize */ 4, /* push_regs */ "", /* pop_regs */ "", /* small_loop */ "\ movb -1("ESI","ECX"), %%al # retrieve gray byte \n\ movb %%al, -3("EDI","ECX",4) # and store 3 times \n\ movb %%al, -2("EDI","ECX",4) \n\ movb %%al, -1("EDI","ECX",4) \n\ movb $0, -4("EDI","ECX",4) # clear A byte \n", /* main_loop */ "\ movd -4("ESI","ECX"), %%xmm0 # XMM0: 00 00 00 00 G3 G2 G1 G0 \n\ movdqa %%xmm4, %%xmm1 # XMM1: 00 00 00 00 00 00 00 00 \n\ punpcklbw %%xmm0, %%xmm1 # XMM1: G3 00 G2 00 G1 00 G0 00 \n\ punpcklbw %%xmm0, %%xmm0 # XMM0: G3 G3 G2 G2 G1 G1 G0 G0 \n\ punpcklbw %%xmm0, %%xmm1 # XMM0: GGG03 GGG02 GGG01 GGG00 \n\ movdqu %%xmm1, -16("EDI","ECX",4) \n", /* emms */ "emms") : /* no outputs */ : "S" (src[0]), "D" (dest[0]), "c" (width*height) : "eax"); return 1; } #endif /* HAVE_ASM_SSE2 */ /*************************************************************************/ #endif /* ARCH_X86 || ARCH_X86_64 */ /*************************************************************************/ /*************************************************************************/ /* Initialization */ int ac_imgconvert_init_rgb_packed(int accel) { if (!register_conversion(IMG_RGB24, IMG_RGB24, rgb_copy) || !register_conversion(IMG_RGB24, IMG_BGR24, rgb24_bgr24) || !register_conversion(IMG_RGB24, IMG_RGBA32, rgb24_rgba32) || !register_conversion(IMG_RGB24, IMG_ABGR32, rgb24_abgr32) || !register_conversion(IMG_RGB24, IMG_ARGB32, rgb24_argb32) || !register_conversion(IMG_RGB24, IMG_BGRA32, rgb24_bgra32) || !register_conversion(IMG_RGB24, IMG_GRAY8, rgb24_gray8) || !register_conversion(IMG_BGR24, IMG_BGR24, rgb_copy) || !register_conversion(IMG_BGR24, IMG_RGB24, rgb24_bgr24) || !register_conversion(IMG_BGR24, IMG_RGBA32, rgb24_bgra32) || !register_conversion(IMG_BGR24, IMG_ABGR32, rgb24_argb32) || !register_conversion(IMG_BGR24, IMG_ARGB32, rgb24_abgr32) || !register_conversion(IMG_BGR24, IMG_BGRA32, rgb24_rgba32) || !register_conversion(IMG_BGR24, IMG_GRAY8, bgr24_gray8) || !register_conversion(IMG_RGBA32, IMG_RGB24, rgba32_rgb24) || !register_conversion(IMG_RGBA32, IMG_BGR24, bgra32_rgb24) || !register_conversion(IMG_RGBA32, IMG_RGBA32, rgba_copy) || !register_conversion(IMG_RGBA32, IMG_ABGR32, rgba_swapall) || !register_conversion(IMG_RGBA32, IMG_ARGB32, rgba_alpha30) || !register_conversion(IMG_RGBA32, IMG_BGRA32, rgba_swap02) || !register_conversion(IMG_RGBA32, IMG_GRAY8, rgba32_gray8) || !register_conversion(IMG_ABGR32, IMG_RGB24, abgr32_rgb24) || !register_conversion(IMG_ABGR32, IMG_BGR24, argb32_rgb24) || !register_conversion(IMG_ABGR32, IMG_RGBA32, rgba_swapall) || !register_conversion(IMG_ABGR32, IMG_ABGR32, rgba_copy) || !register_conversion(IMG_ABGR32, IMG_ARGB32, rgba_swap13) || !register_conversion(IMG_ABGR32, IMG_BGRA32, rgba_alpha03) || !register_conversion(IMG_ABGR32, IMG_GRAY8, abgr32_gray8) || !register_conversion(IMG_ARGB32, IMG_RGB24, argb32_rgb24) || !register_conversion(IMG_ARGB32, IMG_BGR24, abgr32_rgb24) || !register_conversion(IMG_ARGB32, IMG_RGBA32, rgba_alpha03) || !register_conversion(IMG_ARGB32, IMG_ABGR32, rgba_swap13) || !register_conversion(IMG_ARGB32, IMG_ARGB32, rgba_copy) || !register_conversion(IMG_ARGB32, IMG_BGRA32, rgba_swapall) || !register_conversion(IMG_ARGB32, IMG_GRAY8, argb32_gray8) || !register_conversion(IMG_BGRA32, IMG_RGB24, bgra32_rgb24) || !register_conversion(IMG_BGRA32, IMG_BGR24, rgba32_rgb24) || !register_conversion(IMG_BGRA32, IMG_RGBA32, rgba_swap02) || !register_conversion(IMG_BGRA32, IMG_ABGR32, rgba_alpha30) || !register_conversion(IMG_BGRA32, IMG_ARGB32, rgba_swapall) || !register_conversion(IMG_BGRA32, IMG_BGRA32, rgba_copy) || !register_conversion(IMG_BGRA32, IMG_GRAY8, bgra32_gray8) || !register_conversion(IMG_GRAY8, IMG_RGB24, gray8_rgb24) || !register_conversion(IMG_GRAY8, IMG_BGR24, gray8_rgb24) || !register_conversion(IMG_GRAY8, IMG_RGBA32, gray8_rgba32) || !register_conversion(IMG_GRAY8, IMG_ABGR32, gray8_argb32) || !register_conversion(IMG_GRAY8, IMG_ARGB32, gray8_argb32) || !register_conversion(IMG_GRAY8, IMG_BGRA32, gray8_rgba32) || !register_conversion(IMG_GRAY8, IMG_GRAY8, gray8_copy) ) { return 0; } #if defined(ARCH_X86) || defined(ARCH_X86_64) if (accel & (AC_IA32ASM | AC_AMD64ASM)) { if (!register_conversion(IMG_RGBA32, IMG_ABGR32, rgba_swapall_x86) || !register_conversion(IMG_RGBA32, IMG_ARGB32, rgba_alpha30_x86) || !register_conversion(IMG_RGBA32, IMG_BGRA32, rgba_swap02_x86) || !register_conversion(IMG_ABGR32, IMG_RGBA32, rgba_swapall_x86) || !register_conversion(IMG_ABGR32, IMG_ARGB32, rgba_swap13_x86) || !register_conversion(IMG_ABGR32, IMG_BGRA32, rgba_alpha03_x86) || !register_conversion(IMG_ARGB32, IMG_RGBA32, rgba_alpha03_x86) || !register_conversion(IMG_ARGB32, IMG_ABGR32, rgba_swap13_x86) || !register_conversion(IMG_ARGB32, IMG_BGRA32, rgba_swapall_x86) || !register_conversion(IMG_BGRA32, IMG_RGBA32, rgba_swap02_x86) || !register_conversion(IMG_BGRA32, IMG_ABGR32, rgba_alpha30_x86) || !register_conversion(IMG_BGRA32, IMG_ARGB32, rgba_swapall_x86) ) { return 0; } } #if defined(HAVE_ASM_MMX) && defined(ARCH_X86) if (accel & AC_MMX) { if (!register_conversion(IMG_RGBA32, IMG_ABGR32, rgba_swapall_mmx) || !register_conversion(IMG_RGBA32, IMG_ARGB32, rgba_alpha30_mmx) || !register_conversion(IMG_RGBA32, IMG_BGRA32, rgba_swap02_mmx) || !register_conversion(IMG_ABGR32, IMG_RGBA32, rgba_swapall_mmx) || !register_conversion(IMG_ABGR32, IMG_ARGB32, rgba_swap13_mmx) || !register_conversion(IMG_ABGR32, IMG_BGRA32, rgba_alpha03_mmx) || !register_conversion(IMG_ARGB32, IMG_RGBA32, rgba_alpha03_mmx) || !register_conversion(IMG_ARGB32, IMG_ABGR32, rgba_swap13_mmx) || !register_conversion(IMG_ARGB32, IMG_BGRA32, rgba_swapall_mmx) || !register_conversion(IMG_BGRA32, IMG_RGBA32, rgba_swap02_mmx) || !register_conversion(IMG_BGRA32, IMG_ABGR32, rgba_alpha30_mmx) || !register_conversion(IMG_BGRA32, IMG_ARGB32, rgba_swapall_mmx) ) { return 0; } } #endif #if defined(HAVE_ASM_SSE2) if (accel & AC_SSE2) { if (!register_conversion(IMG_RGB24, IMG_BGR24, rgb24_bgr24_sse2) || !register_conversion(IMG_RGB24, IMG_RGBA32, rgb24_rgba32_sse2) || !register_conversion(IMG_RGB24, IMG_ABGR32, rgb24_abgr32_sse2) || !register_conversion(IMG_RGB24, IMG_ARGB32, rgb24_argb32_sse2) || !register_conversion(IMG_RGB24, IMG_BGRA32, rgb24_bgra32_sse2) || !register_conversion(IMG_RGB24, IMG_GRAY8, rgb24_gray8_sse2) || !register_conversion(IMG_BGR24, IMG_RGB24, rgb24_bgr24_sse2) || !register_conversion(IMG_BGR24, IMG_RGBA32, rgb24_bgra32_sse2) || !register_conversion(IMG_BGR24, IMG_ABGR32, rgb24_argb32_sse2) || !register_conversion(IMG_BGR24, IMG_ARGB32, rgb24_abgr32_sse2) || !register_conversion(IMG_BGR24, IMG_BGRA32, rgb24_rgba32_sse2) || !register_conversion(IMG_BGR24, IMG_GRAY8, bgr24_gray8_sse2) || !register_conversion(IMG_RGBA32, IMG_RGB24, rgba32_rgb24_sse2) || !register_conversion(IMG_RGBA32, IMG_BGR24, bgra32_rgb24_sse2) || !register_conversion(IMG_RGBA32, IMG_ABGR32, rgba_swapall_sse2) || !register_conversion(IMG_RGBA32, IMG_ARGB32, rgba_alpha30_sse2) || !register_conversion(IMG_RGBA32, IMG_BGRA32, rgba_swap02_sse2) || !register_conversion(IMG_RGBA32, IMG_GRAY8, rgba32_gray8_sse2) || !register_conversion(IMG_ABGR32, IMG_RGB24, abgr32_rgb24_sse2) || !register_conversion(IMG_ABGR32, IMG_BGR24, argb32_rgb24_sse2) || !register_conversion(IMG_ABGR32, IMG_RGBA32, rgba_swapall_sse2) || !register_conversion(IMG_ABGR32, IMG_ARGB32, rgba_swap13_sse2) || !register_conversion(IMG_ABGR32, IMG_BGRA32, rgba_alpha03_sse2) || !register_conversion(IMG_ABGR32, IMG_GRAY8, abgr32_gray8_sse2) || !register_conversion(IMG_ARGB32, IMG_RGB24, argb32_rgb24_sse2) || !register_conversion(IMG_ARGB32, IMG_BGR24, abgr32_rgb24_sse2) || !register_conversion(IMG_ARGB32, IMG_RGBA32, rgba_alpha03_sse2) || !register_conversion(IMG_ARGB32, IMG_ABGR32, rgba_swap13_sse2) || !register_conversion(IMG_ARGB32, IMG_BGRA32, rgba_swapall_sse2) || !register_conversion(IMG_ARGB32, IMG_GRAY8, argb32_gray8_sse2) || !register_conversion(IMG_BGRA32, IMG_RGB24, bgra32_rgb24_sse2) || !register_conversion(IMG_BGRA32, IMG_BGR24, rgba32_rgb24_sse2) || !register_conversion(IMG_BGRA32, IMG_RGBA32, rgba_swap02_sse2) || !register_conversion(IMG_BGRA32, IMG_ABGR32, rgba_alpha30_sse2) || !register_conversion(IMG_BGRA32, IMG_ARGB32, rgba_swapall_sse2) || !register_conversion(IMG_BGRA32, IMG_GRAY8, bgra32_gray8_sse2) || !register_conversion(IMG_GRAY8, IMG_RGB24, gray8_rgb24_sse2) || !register_conversion(IMG_GRAY8, IMG_BGR24, gray8_rgb24_sse2) || !register_conversion(IMG_GRAY8, IMG_RGBA32, gray8_rgba32_sse2) || !register_conversion(IMG_GRAY8, IMG_ABGR32, gray8_argb32_sse2) || !register_conversion(IMG_GRAY8, IMG_ARGB32, gray8_argb32_sse2) || !register_conversion(IMG_GRAY8, IMG_BGRA32, gray8_rgba32_sse2) ) { return 0; } } #endif #endif /* ARCH_X86 || ARCH_X86_64 */ return 1; } /*************************************************************************/ /* * Local variables: * c-file-style: "stroustrup" * c-file-offsets: ((case-label . *) (statement-case-intro . *)) * indent-tabs-mode: nil * End: * * vim: expandtab shiftwidth=4: */