130 lines
3.3 KiB
NASM
130 lines
3.3 KiB
NASM
; MMX RGB2YUV conversion function
|
|
; by Matt Ownby
|
|
; For MASM (Microschlop) only
|
|
|
|
; This function is equivalent to this C code from Intel:
|
|
;
|
|
; Y = (unsigned char) (((9798*R)+(19235*G)+(3736*B))/32768);
|
|
; U = (unsigned char) ((((-5537*R)+(-10878*G)+(16384*B))/32768) + 128);
|
|
; V = (unsigned char) ((((16384*R)+(-13729*G)+(-2664*B))/32768) + 128);
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
; C function prototype is:
|
|
|
|
; extern "C" void asm_rgb2yuv();
|
|
|
|
; This function is controlled through global variables (because I found that to be the fastest).
|
|
; To set the RGB values that you want converted, you write three 8-bit values (R, G, and B) to
|
|
; an array of 16-bit shorts (I found this to be the fastest).
|
|
; As far as you're concerned, the array you write to looks like this:
|
|
;
|
|
; extern "C" unsigned short asm_rgb2yuv_input[3];
|
|
;
|
|
; (it actually is 64-bits but the last element is ignored)
|
|
;
|
|
; Here's some example C code to set your input:
|
|
;
|
|
; unsigned char rgb[3] = { 255, 0, 0 }; // a red color for example (notice it's 8-bit!!)
|
|
; asm_rgb2yuv_input[0] = rgb[0];
|
|
; asm_rgb2yuv_input[1] = rgb[1];
|
|
; asm_rgb2yuv_input[2] = rgb[2];
|
|
; asm_rgb2yuv(); // do the calculation here
|
|
;
|
|
; OK after you've done your calculation, the 8-bit YUV results will be written to three global
|
|
; variables:
|
|
;
|
|
; extern "C" unsigned char asm_rgb2yuv_result_y;
|
|
; extern "C" unsigned char asm_rgb2yuv_result_u;
|
|
; extern "C" unsigned char asm_rgb2yuv_result_v;
|
|
;
|
|
; NOTE : these are actually 64-bits in size, but only the first byte matters.
|
|
; Also, you might want to change these to unsigned int for better cpu efficiency.
|
|
; I made them unsigned char to illustrate that they were 8-bit results.
|
|
;
|
|
; So to continue my C program example, you might do something like this
|
|
;
|
|
; printf("The results of that conversion are Y: %u, U: %u, V: %u\n",
|
|
; asm_rgb2yuv_result_y, asm_rgb2yuv_result_u, asm_rgb2yuv_result_v);
|
|
;
|
|
; I hope this all makes sense. Good luck!
|
|
; --Matt
|
|
;
|
|
; PS : This is my first attempt at MMX programming so if it is lousy, sorry :)
|
|
|
|
.486
|
|
.MMX
|
|
|
|
.model flat, c
|
|
|
|
.DATA
|
|
|
|
ALIGN 8
|
|
|
|
the_offset dq 0000008000000080h
|
|
ystuff_q dq 00000E984B232646h ; 9798, 19235, and 3736 from the equation
|
|
ustuff_q dq 00004000D582EA5Fh ; -5537, -10878, and 16384 from the equation
|
|
vstuff_q dq 0000F598CA5F4000h ; 16384, -13729, and -2664 from the equation
|
|
|
|
PUBLIC asm_rgb2yuv_input
|
|
asm_rgb2yuv_input dq 0
|
|
|
|
PUBLIC asm_rgb2yuv_result_y
|
|
asm_rgb2yuv_result_y dq 0
|
|
|
|
PUBLIC asm_rgb2yuv_result_u
|
|
asm_rgb2yuv_result_u dq 0
|
|
|
|
PUBLIC asm_rgb2yuv_result_v
|
|
asm_rgb2yuv_result_v dq 0
|
|
|
|
.CODE
|
|
|
|
PUBLIC asm_rgb2yuv
|
|
asm_rgb2yuv PROC NEAR
|
|
|
|
push ebp ; required to preserve ebp, I'm not sure where exactly it gets changed
|
|
|
|
;;;;;;;;;;;;;;;;;;;;
|
|
|
|
movq mm1, asm_rgb2yuv_input
|
|
movq mm7, the_offset
|
|
|
|
; Calculate Y
|
|
movq mm0, ystuff_q
|
|
pmaddwd mm0, mm1
|
|
movq mm2, mm0
|
|
psrlq mm2, 32
|
|
paddd mm0, mm2
|
|
psrad mm0, 15 ; divide by 32768
|
|
movq asm_rgb2yuv_result_y, mm0
|
|
|
|
; Calculate U
|
|
movq mm0, ustuff_q
|
|
pmaddwd mm0, mm1
|
|
movq mm2, mm0
|
|
psrlq mm2, 32
|
|
paddd mm0, mm2
|
|
psrad mm0, 15 ; divide by 32768
|
|
paddd mm0, mm7 ; add 128
|
|
movq asm_rgb2yuv_result_u, mm0
|
|
|
|
; Calculate V
|
|
movq mm0, vstuff_q
|
|
pmaddwd mm0, mm1
|
|
movq mm2, mm0
|
|
psrlq mm2, 32
|
|
paddd mm0, mm2
|
|
psrad mm0, 15 ; divide by 32768
|
|
paddd mm0, mm7 ; add 128
|
|
movq asm_rgb2yuv_result_v, mm0
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
emms
|
|
|
|
pop ebp
|
|
|
|
ret
|
|
asm_rgb2yuv ENDP
|
|
END
|