/* ----------------------------------------------------------------------------- GSFramework Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. ----------------------------------------------------------------------------- */ #include "picture/pict.h" #if __PLATFORM_WINDOWS__ && __MMX__ #include "mmintrin.h" #endif using namespace GS; //------------------------------------------------------------------------------ static void mmx_yuv2rgb (uchar *py, uchar *pu, uchar *pv, uchar *image) { #if __PLATFORM_WINDOWS__ && __MMX__ static __m64 mmx_80w = {0x0080008000800080LL}; static __m64 mmx_U_green = {0xf37df37df37df37dLL}; static __m64 mmx_U_blue = {0x4093409340934093LL}; static __m64 mmx_V_red = {0x3312331233123312LL}; static __m64 mmx_V_green = {0xe5fce5fce5fce5fcLL}; static __m64 mmx_10w = {0x1010101010101010LL}; static __m64 mmx_00ffw = {0x00ff00ff00ff00ffLL}; static __m64 mmx_Y_coeff = {0x253f253f253f253fLL}; static __m64 mmx_A_unpack = {0xffffffffffffffffLL}; __asm { push esi pxor mm4, mm4 ; mm4 = 0 mov esi, pu movd mm0, [esi] ; mm0 = 00 00 00 00 u3 u2 u1 u0 mov esi, pv movd mm1, [esi] ; mm1 = 00 00 00 00 v3 v2 v1 v0 mov esi, py movq mm6, [esi] ; mm6 = Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 ; Multiply part of the conversion. punpcklbw mm0, mm4 ; mm0 = u3 u2 u1 u0 punpcklbw mm1, mm4 ; mm1 = v3 v2 v1 v0 psubsw mm0, mmx_80w ; u -= 128 psubsw mm1, mmx_80w ; v -= 128 psllw mm0, 3 ; promote precision psllw mm1, 3 ; promote precision movq mm2, mm0 ; mm2 = u3 u2 u1 u0 movq mm3, mm1 ; mm3 = v3 v2 v1 v0 pmulhw mm2, mmx_U_green ; mm2 = u * u_green pmulhw mm3, mmx_V_green ; mm3 = v * v_green pmulhw mm0, mmx_U_blue ; mm0 = chroma_b pmulhw mm1, mmx_V_red ; mm1 = chroma_r paddsw mm2, mm3 ; mm2 = chroma_g psubusb mm6, mmx_10w ; Y -= 16 movq mm7, mm6 ; mm7 = Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 pand mm6, mmx_00ffw ; mm6 = Y6 Y4 Y2 Y0 psrlw mm7, 8 ; mm7 = Y7 Y5 Y3 Y1 psllw mm6, 3 ; promote precision psllw mm7, 3 ; promote precision pmulhw mm6, mmx_Y_coeff ; mm6 = luma_rgb even pmulhw mm7, mmx_Y_coeff ; mm7 = luma_rgb odd ; Addition part of the conversion for even and odd pixels. movq mm3, mm0 ; mm3 = chroma_b movq mm4, mm1 ; mm4 = chroma_r movq mm5, mm2 ; mm5 = chroma_g paddsw mm0, mm6 ; mm0 = B6 B4 B2 B0 paddsw mm3, mm7 ; mm3 = B7 B5 B3 B1 paddsw mm1, mm6 ; mm1 = R6 R4 R2 R0 paddsw mm4, mm7 ; mm4 = R7 R5 R3 R1 paddsw mm2, mm6 ; mm2 = G6 G4 G2 G0 paddsw mm5, mm7 ; mm5 = G7 G5 G3 G1 packuswb mm0, mm0 ; saturate to 0-255 packuswb mm1, mm1 ; saturate to 0-255 packuswb mm2, mm2 ; saturate to 0-255 packuswb mm3, mm3 ; saturate to 0-255 packuswb mm4, mm4 ; saturate to 0-255 packuswb mm5, mm5 ; saturate to 0-255 punpcklbw mm0, mm3 ; mm0 = B7 B6 B5 B4 B3 B2 B1 B0 punpcklbw mm1, mm4 ; mm1 = R7 R6 R5 R4 R3 R2 R1 R0 punpcklbw mm2, mm5 ; mm2 = G7 G6 G5 G4 G3 G2 G1 G0 mov esi, image ;pxor mm3, mm3 movq mm3, mmx_A_unpack movq mm6, mm0 movq mm7, mm1 movq mm4, mm0 movq mm5, mm1 punpcklbw mm6, mm2 punpcklbw mm7, mm3 punpcklwd mm6, mm7 movq [esi], mm6 movq mm6, mm0 punpcklbw mm6, mm2 punpckhwd mm6, mm7 movq [esi + 8], mm6 punpckhbw mm4, mm2 punpckhbw mm5, mm3 punpcklwd mm4, mm5 movq [esi + 16], mm4 movq mm4, mm0 punpckhbw mm4, mm2 punpckhwd mm4, mm5 movq [esi + 24], mm4 pop esi emms } #endif } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ void Picture::YUV422toRGB32(uchar * const yuv_plane[3], uchar *rgb32, int width, int height, int dst_pitch, int dst_height) { // Default pitch if none specified. if (!dst_pitch) dst_pitch = width * 4; if (!dst_height) dst_height = height; // Target resolution. int c_width = dst_pitch / 4; if (width < c_width) c_width = width; if (height < dst_height) dst_height = height; #pragma omp parallel for for (int y = 0; y < dst_height; ++y) { uchar *p_out = rgb32 + dst_pitch * y, *p_yuv[3] = { yuv_plane[0] + width * y, yuv_plane[1] + (width / 2) * (y / 2), yuv_plane[2] + (width / 2) * (y / 2) }; // Convert scan line. for (int x = 0; x < c_width; x += 8) { mmx_yuv2rgb(p_yuv[0], p_yuv[1], p_yuv[2], p_out); p_yuv[0] += 8; p_yuv[1] += 4; p_yuv[2] += 4; p_out += 32; } } } void Picture::UnpackYCbCr(uchar *y, uchar *cb, uchar *cr) { if (!y || !cb || !cr || (GetBpp() != 32)) return; uchar *pdata = GetData(); for (uint n = 0; n < (GetHeight() * GetWidth()); ++n) { float r = (float)pdata[0], g = (float)pdata[1], b = (float)pdata[2]; *y++ = (uchar)( 0.2990f * r + 0.5870f * g + 0.1140f * b + 0.5f); *cb++ = (uchar)(-0.1687f * r - 0.3313f * g + 0.5000f * b + 128.f + 0.5f); *cr++ = (uchar)( 0.5000f * r - 0.4187f * g - 0.0813f * b + 128.f + 0.5f); pdata += 4; } } void Picture::PackYCbCr(uchar *y, uchar *cb, uchar *cr) { if (!y || !cb || !cr || (GetBpp() != 32)) return; uchar *pdata = GetData(); for (uint n = 0; n < (GetHeight() * GetWidth()); ++n) { float _y = (float)*y++, _cb = ((float)*cb++) - 128.f, _cr = ((float)*cr++) - 128.f; float r = _y + 1.402f * _cr; float g = _y - 0.34414f * _cb - 0.71414f * _cr; float b = _y + 1.77200f * _cb; if (r < 0) pdata[0] = 0; else if (r > 255.f) pdata[0] = 255; else pdata[0] = (uchar)r; if (g < 0) pdata[1] = 0; else if (g > 255.f) pdata[1] = 255; else pdata[1] = (uchar)g; if (b < 0) pdata[2] = 0; else if (b > 255.f) pdata[2] = 255; else pdata[2] = (uchar)b; pdata += 4; } } //------------------------------------------------------------------------------