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
This commit is contained in:
David McPaul
2010-01-25 21:53:56 +00:00
parent 72570e2e14
commit 50ff266ef2
4 changed files with 303 additions and 45 deletions
@@ -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;i<height;i+=2) {
_Convert_YUV420P_RGBA32_SSE(ybase, ubase, vbase, rgbbase, width); // First Y row
ybase += yBaseInc;
rgbbase += rgbBaseInc;
_Convert_YUV420P_RGBA32_SSE(ybase, ubase, vbase, rgbbase, width); // Second Y row but same u and v row
ybase += yBaseInc;
ubase += uBaseInc;
vbase += vBaseInc;
rgbbase += rgbBaseInc;
}
} else {
gfx_conv_YCbCr420p_RGB32_c(in, out, width, height);
}
}
// Packed YUV422
void gfx_conv_yuv422p_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 *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);
}
}
@@ -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
@@ -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;
}
+243 -45
View File
@@ -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