From 50ff266ef29cffbf57565fad9c5f75426a8aba97 Mon Sep 17 00:00:00 2001 From: David McPaul Date: Mon, 25 Jan 2010 21:53:56 +0000 Subject: [PATCH] Add SSE versions of YUV2RGB converters for earlier x86 cpus git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@35290 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../media/plugins/ffmpeg/gfx_conv_mmx.cpp | 53 ++++ .../media/plugins/ffmpeg/gfx_conv_mmx.h | 2 + src/add-ons/media/plugins/ffmpeg/gfx_util.cpp | 5 + src/add-ons/media/plugins/ffmpeg/yuvrgb.nasm | 288 +++++++++++++++--- 4 files changed, 303 insertions(+), 45 deletions(-) diff --git a/src/add-ons/media/plugins/ffmpeg/gfx_conv_mmx.cpp b/src/add-ons/media/plugins/ffmpeg/gfx_conv_mmx.cpp index ff6bb07a26..3a8aa9d12a 100644 --- a/src/add-ons/media/plugins/ffmpeg/gfx_conv_mmx.cpp +++ b/src/add-ons/media/plugins/ffmpeg/gfx_conv_mmx.cpp @@ -3,6 +3,8 @@ extern "C" void _Convert_YUV420P_RGBA32_SSE2(void *fromYPtr, void *fromUPtr, void *fromVPtr, void *toPtr, int width); extern "C" void _Convert_YUV422_RGBA32_SSE2(void *fromYPtr, void *toPtr, int width); +extern "C" void _Convert_YUV420P_RGBA32_SSE(void *fromYPtr, void *fromUPtr, void *fromVPtr, void *toPtr, int width); +extern "C" void _Convert_YUV422_RGBA32_SSE(void *fromYPtr, void *toPtr, int width); void gfx_conv_null_mmx(AVFrame *in, AVFrame *out, int width, int height) { memcpy(out->data[0], in->data[0], height * in->linesize[0]); @@ -88,3 +90,54 @@ void gfx_conv_yuv422p_rgba32_sse2(AVFrame *in, AVFrame *out, int width, int heig gfx_conv_YCbCr422_RGB32_c(in, out, width, height); } } + +// Planar YUV420 +void gfx_conv_yuv420p_rgba32_sse(AVFrame *in, AVFrame *out, int width, int height) +{ + // in and out buffers must be aligned to 16 bytes, in should be as ffmpeg allocates it + if ((off_t)out->data[0] % 16 == 0) { + + uint8 *ybase = (uint8 *)in->data[0]; + uint8 *ubase = (uint8 *)in->data[1]; + uint8 *vbase = (uint8 *)in->data[2]; + uint8 *rgbbase = (uint8 *)out->data[0]; + + int yBaseInc = in->linesize[0]; + int uBaseInc = in->linesize[1]; + int vBaseInc = in->linesize[2]; + int rgbBaseInc = out->linesize[0]; + + for (int i=0;idata[0] % 16 == 0) { + + uint8 *ybase = (uint8 *)in->data[0]; + uint8 *rgbbase = (uint8 *)out->data[0]; + + for (int i = 0; i <= height; i++) { + _Convert_YUV422_RGBA32_SSE(ybase, rgbbase, width); + ybase += in->linesize[0]; + rgbbase += out->linesize[0]; + } + } else { + gfx_conv_YCbCr422_RGB32_c(in, out, width, height); + } +} diff --git a/src/add-ons/media/plugins/ffmpeg/gfx_conv_mmx.h b/src/add-ons/media/plugins/ffmpeg/gfx_conv_mmx.h index 7d82d08c30..6454c6c8c6 100644 --- a/src/add-ons/media/plugins/ffmpeg/gfx_conv_mmx.h +++ b/src/add-ons/media/plugins/ffmpeg/gfx_conv_mmx.h @@ -15,5 +15,7 @@ void gfx_conv_yuv410p_rgb32_mmx(AVFrame *in, AVFrame *out, int width, int height void gfx_conv_yuv411p_rgb32_mmx(AVFrame *in, AVFrame *out, int width, int height); void gfx_conv_yuv420p_rgba32_sse2(AVFrame *in, AVFrame *out, int width, int height); void gfx_conv_yuv422p_rgba32_sse2(AVFrame *in, AVFrame *out, int width, int height); +void gfx_conv_yuv420p_rgba32_sse(AVFrame *in, AVFrame *out, int width, int height); +void gfx_conv_yuv422p_rgba32_sse(AVFrame *in, AVFrame *out, int width, int height); #endif diff --git a/src/add-ons/media/plugins/ffmpeg/gfx_util.cpp b/src/add-ons/media/plugins/ffmpeg/gfx_util.cpp index f9e6e1a87f..2706cee654 100644 --- a/src/add-ons/media/plugins/ffmpeg/gfx_util.cpp +++ b/src/add-ons/media/plugins/ffmpeg/gfx_util.cpp @@ -49,6 +49,9 @@ CPUCapabilities cpu; if (cpu.HasSSE2() && width % 8 == 0 && height % 2 == 0) { TRACE("resolve_colorspace: gfx_conv_yuv420p_rgba32_sse2\n"); return gfx_conv_yuv420p_rgba32_sse2; + } else if (cpu.HasSSE1() && width % 4 == 0 && height % 2 == 0) { + TRACE("resolve_colorspace: gfx_conv_yuv420p_rgba32_sse\n"); + return gfx_conv_yuv420p_rgba32_sse; } else { TRACE("resolve_colorspace: gfx_conv_YCbCr420p_RGB32_c\n"); return gfx_conv_YCbCr420p_RGB32_c; @@ -58,6 +61,8 @@ CPUCapabilities cpu; if (pixelFormat == PIX_FMT_YUV422P || pixelFormat == PIX_FMT_YUVJ422P) { if (cpu.HasSSE2() && width % 8 == 0) { return gfx_conv_yuv422p_rgba32_sse2; + } else if (cpu.HasSSE1() && width % 4 == 0) { + return gfx_conv_yuv422p_rgba32_sse; } else { return gfx_conv_YCbCr422_RGB32_c; } diff --git a/src/add-ons/media/plugins/ffmpeg/yuvrgb.nasm b/src/add-ons/media/plugins/ffmpeg/yuvrgb.nasm index 70e7d9bd32..0cabc75c4a 100644 --- a/src/add-ons/media/plugins/ffmpeg/yuvrgb.nasm +++ b/src/add-ons/media/plugins/ffmpeg/yuvrgb.nasm @@ -1,5 +1,5 @@ ; -; Copyright (C) 2009 David McPaul +; Copyright (C) 2009-2010 David McPaul ; ; All rights reserved. Distributed under the terms of the MIT License. ; @@ -34,7 +34,7 @@ %endmacro ; conversion code -%macro yuv2rgb 0 +%macro yuv2rgbsse2 0 ; u = u - 128 ; v = v - 128 ; r = y + v + v >> 2 + v >> 3 + v >> 5 @@ -47,51 +47,116 @@ movdqa xmm7, [Const128] ; loads a constant using data cache (slower on first fetch but then cached) psubsw xmm1,xmm7 ; u = u - 128 psubsw xmm2,xmm7 ; v = v - 128 -; load r,g,b with y +; load r,b with y movdqa xmm3,xmm0 ; r = y - pshufd xmm4,xmm0, 0xE4 ; g = y - movdqa xmm5,xmm0 ; b = y -; r = r + v + v >> 2 + v >> 3 + v >> 5 - paddsw xmm3, xmm2 ; add v to r - movdqa xmm6, xmm2 ; move v to scratch - psraw xmm6,2 ; divide by 4 - paddsw xmm3, xmm6 ; and add to r - psraw xmm6,1 ; divide by 2 - paddsw xmm3, xmm6 ; and add to r - psraw xmm6,2 ; divide by 4 - paddsw xmm3, xmm6 ; and add to r - -; g = y - u >> 2 - u >> 4 - u >> 5 - v >> 1 - v >> 3 - v >> 4 - v >> 5 - movdqa xmm6,xmm1 ; move u to scratch - psraw xmm6,2 ; divide by 4 - psubsw xmm4,xmm6 ; subtract from g - psraw xmm6,2 ; divide by 4 - psubsw xmm4,xmm6 ; subtract from g - psraw xmm6,1 ; divide by 2 - psubsw xmm4,xmm6 ; subtract from g + pshufd xmm5,xmm0, 0xE4 ; b = y + +; r = y + v + v >> 2 + v >> 3 + v >> 5 + paddsw xmm3, xmm2 ; add v to r + movdqa xmm7, xmm1 ; move u to scratch + pshufd xmm6, xmm2, 0xE4 ; move v to scratch + + psraw xmm6,2 ; divide v by 4 + paddsw xmm3, xmm6 ; and add to r + psraw xmm6,1 ; divide v by 2 + paddsw xmm3, xmm6 ; and add to r + psraw xmm6,2 ; divide v by 4 + paddsw xmm3, xmm6 ; and add to r - movdqa xmm6,xmm2 ; move v to scratch - psraw xmm6,1 ; divide by 2 - psubsw xmm4,xmm6 ; subtract from g - psraw xmm6,2 ; divide by 4 - psubsw xmm4,xmm6 ; subtract from g - psraw xmm6,1 ; divide by 2 - psubsw xmm4,xmm6 ; subtract from g - psraw xmm6,1 ; divide by 2 - psubsw xmm4,xmm6 ; subtract from g ; b = y + u + u >> 1 + u >> 2 + u >> 6 paddsw xmm5, xmm1 ; add u to b - movdqa xmm6, xmm1 ; move u to scratch - psraw xmm6,1 ; divide by 2 - paddsw xmm5, xmm6 ; and add to b - psraw xmm6,1 ; divide by 2 - paddsw xmm5, xmm6 ; and add to b - psraw xmm6,4 ; divide by 32 - paddsw xmm5, xmm6 ; and add to b + psraw xmm7,1 ; divide u by 2 + paddsw xmm5, xmm7 ; and add to b + psraw xmm7,1 ; divide u by 2 + paddsw xmm5, xmm7 ; and add to b + psraw xmm7,4 ; divide u by 32 + paddsw xmm5, xmm7 ; and add to b + +; g = y - u >> 2 - u >> 4 - u >> 5 - v >> 1 - v >> 3 - v >> 4 - v >> 5 + movdqa xmm7,xmm2 ; move v to scratch + pshufd xmm6,xmm1, 0xE4 ; move u to scratch + movdqa xmm4,xmm0 ; g = y + + psraw xmm6,2 ; divide u by 4 + psubsw xmm4,xmm6 ; subtract from g + psraw xmm6,2 ; divide u by 4 + psubsw xmm4,xmm6 ; subtract from g + psraw xmm6,1 ; divide u by 2 + psubsw xmm4,xmm6 ; subtract from g + + psraw xmm7,1 ; divide v by 2 + psubsw xmm4,xmm7 ; subtract from g + psraw xmm7,2 ; divide v by 4 + psubsw xmm4,xmm7 ; subtract from g + psraw xmm7,1 ; divide v by 2 + psubsw xmm4,xmm7 ; subtract from g + psraw xmm7,1 ; divide v by 2 + psubsw xmm4,xmm7 ; subtract from g +%endmacro + +; conversion code +%macro yuv2rgbsse 0 +; u = u - 128 +; v = v - 128 +; r = y + v + v >> 2 + v >> 3 + v >> 5 +; g = y - (u >> 2 + u >> 4 + u >> 5) - (v >> 1 + v >> 3 + v >> 4 + v >> 5) +; b = y + u + u >> 1 + u >> 2 + u >> 6 +; subtract 16 from y + movq mm7, [Const16] ; loads a constant using data cache (slower on first fetch but then cached) + psubsw mm0,mm7 ; y = y - 16 +; subtract 128 from u and v + movq mm7, [Const128] ; loads a constant using data cache (slower on first fetch but then cached) + psubsw mm1,mm7 ; u = u - 128 + psubsw mm2,mm7 ; v = v - 128 +; load r,g,b with y + movq mm3,mm0 ; r = y + pshufw mm5,mm0, 0xE4 ; b = y + +; r = r + v + v >> 2 + v >> 3 + v >> 5 + paddsw mm3, mm2 ; add v to r + movq mm7, mm1 ; move u to scratch + pshufw mm6, mm2, 0xE4 ; move v to scratch + + psraw mm6,2 ; divide v by 4 + paddsw mm3, mm6 ; and add to r + psraw mm6,1 ; divide v by 2 + paddsw mm3, mm6 ; and add to r + psraw mm6,2 ; divide v by 4 + paddsw mm3, mm6 ; and add to r + +; b = y + u + u >> 1 + u >> 2 + u >> 6 + paddsw mm5, mm1 ; add u to b + psraw mm7,1 ; divide u by 2 + paddsw mm5, mm7 ; and add to b + psraw mm7,1 ; divide u by 2 + paddsw mm5, mm7 ; and add to b + psraw mm7,4 ; divide u by 32 + paddsw mm5, mm7 ; and add to b + +; g = y - u >> 2 - u >> 4 - u >> 5 - v >> 1 - v >> 3 - v >> 4 - v >> 5 + movq mm7,mm2 ; move v to scratch + pshufw mm6,mm1, 0xE4 ; move u to scratch + movq mm4,mm0 ; g = y + + psraw mm6,2 ; divide u by 4 + psubsw mm4,mm6 ; subtract from g + psraw mm6,2 ; divide u by 4 + psubsw mm4,mm6 ; subtract from g + psraw mm6,1 ; divide u by 2 + psubsw mm4,mm6 ; subtract from g + + psraw mm7,1 ; divide v by 2 + psubsw mm4,mm7 ; subtract from g + psraw mm7,2 ; divide v by 4 + psubsw mm4,mm7 ; subtract from g + psraw mm7,1 ; divide v by 2 + psubsw mm4,mm7 ; subtract from g + psraw mm7,1 ; divide v by 2 + psubsw mm4,mm7 ; subtract from g %endmacro ; outputer -%macro rgba32output 0 +%macro rgba32sse2output 0 ; clamp values pxor xmm7,xmm7 packuswb xmm3,xmm7 ; clamp to 0,255 and pack R to 8 bit per pixel @@ -108,6 +173,24 @@ movntdq [edi+16], xmm0 ; output second 4 pixels bypassing cache %endmacro +; outputer +%macro rgba32sseoutput 0 +; clamp values + pxor mm7,mm7 + packuswb mm3,mm7 ; clamp to 0,255 and pack R to 8 bit per pixel + packuswb mm4,mm7 ; clamp to 0,255 and pack G to 8 bit per pixel + packuswb mm5,mm7 ; clamp to 0,255 and pack B to 8 bit per pixel +; convert to bgra32 packed + punpcklbw mm5,mm4 ; bgbgbgbgbgbgbgbg + movq mm0, mm5 ; save bg values + punpcklbw mm3,mm7 ; r0r0r0r0 + punpcklwd mm5,mm3 ; lower half bgr0bgr0 + punpckhwd mm0,mm3 ; upper half bgr0bgr0 +; write to output ptr + movq [edi], mm5 ; output first 2 pixels + movq [edi+8], mm0 ; output second 2 pixels +%endmacro + SECTION .data align=16 Const16 dw 16 @@ -153,7 +236,6 @@ cglobal Convert_YUV422_RGBA32_SSE2 mov esi, [fromPtr] mov edi, [toPtr] mov ecx, [width] - prefetchnta [esi] ; hint that we will be loading our data outside of cache ; loop width / 8 times shr ecx,3 test ecx,ecx @@ -181,9 +263,9 @@ REPEATLOOP: ; loop over width / 8 pshuflw xmm2,xmm2, 0xF5 ; copy v values pshufhw xmm2,xmm2, 0xF5 ; to get v0v0 -yuv2rgb +yuv2rgbsse2 -rgba32output +rgba32sse2output ; endloop add edi,32 @@ -238,9 +320,9 @@ REPEATLOOP1: ; loop over width / 8 pshuflw xmm2,xmm2, 0xA0 ; copy v values pshufhw xmm2,xmm2, 0xA0 ; to get v0v0 -yuv2rgb +yuv2rgbsse2 -rgba32output +rgba32sse2output ; endloop add edi,32 @@ -260,4 +342,120 @@ ENDLOOP1: pop ebp ret +cglobal Convert_YUV422_RGBA32_SSE +; reserve variables + push ebp + mov ebp, esp + push edi + push esi + push ecx + + mov esi, [fromPtr] + mov ecx, [width] + mov edi, [toPtr] +; loop width / 4 times + shr ecx,2 + test ecx,ecx + jng ENDLOOP2 +REPEATLOOP2: ; loop over width / 4 + +; YUV422 packed inputer + movq mm0, [esi] ; should have yuyv yuyv + pshufw mm1, mm0, 0xE4 ; copy to mm1 + movq mm2, mm0 ; copy to mm2 +; extract y + pxor mm7,mm7 ; 0000000000000000 + pcmpeqb mm6,mm6 ; ffffffffffffffff + punpckhbw mm6,mm7 ; interleave mm7 into mm6 ff00ff00ff00ff00 + pand mm0, mm6 ; clear all but y values leaving y0y0 etc +; extract u and duplicate so each u in yuyv becomes 0u0u + psrld mm6,8 ; 00ff0000 00ff0000 + pand mm1, mm6 ; clear all yv values leaving 0u00 etc + psrld mm1,8 ; rotate u to get u000 + pshufw mm1,mm1, 0xA0 ; copy u values to get u0u0 (SSE not MMX) +; extract v + pslld mm6,16 ; 000000ff000000ff + pand mm2, mm6 ; clear all yu values leaving 000v etc + psrld mm2,8 ; rotate v to get 00v0 + pshufw mm2,mm2, 0xF5 ; copy v values to get v0v0 (SSE not MMX) + +yuv2rgbsse + +rgba32sseoutput + + ; endloop + add edi,16 + add esi,8 + sub ecx, 1 ; apparently sub is better than dec + jnz REPEATLOOP2 +ENDLOOP2: +; Cleanup + emms ; reset mmx regs back to float + pop ecx + pop esi + pop edi + mov esp, ebp + pop ebp + ret + +cglobal Convert_YUV420P_RGBA32_SSE +; reserve variables + push ebp + mov ebp, esp + push edi + push esi + push ecx + push eax + push ebx + + mov esi, [fromYPtr] + mov eax, [fromUPtr] + mov ebx, [fromVPtr] + mov edi, [toPtr1] + mov ecx, [width1] +; loop width / 4 times + shr ecx,2 + test ecx,ecx + jng ENDLOOP3 +REPEATLOOP3: ; loop over width / 4 +; YUV420 Planar inputer + movq mm0, [esi] ; fetch 4 y values (8 bit) yyyy0000 + movd mm1, [eax] ; fetch 2 u values (8 bit) uu000000 + movd mm2, [ebx] ; fetch 2 v values (8 bit) vv000000 + +; extract y + pxor mm7,mm7 ; 0000000000000000 + punpcklbw mm0,mm7 ; interleave xmm7 into xmm0 y0y0y0y +; extract u and duplicate so each becomes 0u0u + punpcklbw mm1,mm7 ; interleave xmm7 into xmm1 u0u00000 + punpcklwd mm1,mm7 ; interleave again u000u000 + pshufw mm1,mm1, 0xA0 ; copy u values to get u0u0 +; extract v + punpcklbw mm2,mm7 ; interleave xmm7 into xmm1 v0v00000 + punpcklwd mm2,mm7 ; interleave again v000v000 + pshufw mm2,mm2, 0xA0 ; copy v values to get v0v0 + +yuv2rgbsse + +rgba32sseoutput + +; endloop + add edi,16 + add esi,4 + add eax,2 + add ebx,2 + sub ecx, 1 ; apparently sub is better than dec + jnz REPEATLOOP3 +ENDLOOP3: +; Cleanup + emms + pop ebx + pop eax + pop ecx + pop esi + pop edi + mov esp, ebp + pop ebp + ret + SECTION .note.GNU-stack noalloc noexec nowrite progbits