;  depends on nasm

 global image_mult_buffer_mmx_x86asm
 global image_mult_buffers_mmx_x86asm

 global image_add_buffers_mmx_x86asm
 global image_add_buffer_mmx_x86asm

 global image_sub_buffer_mmx_x86asm

 global image_clear_buffer_mmx_x86asm_eq
 global image_clear_buffer_mmx_x86asm_from

 global image_get_cpuid

;  do not use the function from mmxlib, since that might be
;  unavailable even when mmx is available.	
;
;  void image_get_cpuid(int oper,int *cpuid1,int *cpuid2,int *cpuid3,int *a )
;
image_get_cpuid:
	push ebp
	mov ebp, esp
	pushf
	pop  eax
	mov  ecx, eax
	xor  eax, 200000h
	push eax
	popf
	pushf
	pop  eax
	xor  ecx, eax
	test ecx, 200000h
	jnz .ok

	xor eax,eax
	mov [ebp+12], eax	;  cpuid not supported
	mov [ebp+16], eax
	mov [ebp+20], eax

	leave
	ret

.ok:
	push ebx
 	mov eax, [ebp+8]
	cpuid
	push ebx
	mov ebx, [ebp+24]
	mov [ebx], eax
	pop ebx

	mov eax, [ebp+12]
	mov [eax], ebx

	mov eax, [ebp+16]
	mov [eax], edx

	mov eax, [ebp+20]
	mov [eax], ecx

	pop ebx
	leave
	ret


;  Clear an image to a solid color
;  void image_clear_buffer_mmx_x86asm_eq( char *d,
;                                         int npixels_div_8,
;                                         int colv );
image_clear_buffer_mmx_x86asm_eq:
	push ebp
	mov ebp, esp
	mov ecx, [ebp+12]
	mov eax, [ebp+16]
	;;  now in eax:	  00 xx
	shl eax, 8
	or eax, [ebp+16]
	;;  now in mm0:	  xx xx
	pinsrw mm0, eax, 0
	pinsrw mm0, eax, 1
	pinsrw mm0, eax, 2
	pinsrw mm0, eax, 3
	mov eax, [ebp+8]

	align 32
.loop:
	movq [eax], mm0
	add eax, 8

	movq [eax], mm0
	add eax, 8

	movq [eax], mm0
	add eax, 8		; 8

	dec ecx
	jnz .loop

	emms
	leave
	ret


image_clear_buffer_mmx_x86asm_from:
	push ebp
	mov ebp, esp
	mov eax, [ebp+8]
	mov ecx, [ebp+12]

	movq mm0, [eax]

	add eax, 8
	movq mm1, [eax]

	add eax, 8
	movq mm2, [eax]
	dec ecx
	add eax, 8

	align 32
.loop:
	movq [eax], mm0
	add eax, 8

	movq [eax], mm1
	add eax, 8

	movq [eax], mm2
	add eax, 8

	loopnz .loop, ecx

	emms
	leave
	ret


; Add two images
;
; void image_add_buffers_mmx_x86asm( char *d,
;		                     char *s1, char *s2,
;                                    int npixels_mult_3_div_8 )
;
image_add_buffers_mmx_x86asm:
	push ebp
	mov ebp, esp
	push ebx
	mov ebx, [ebp+8]
	mov eax, [ebp+12]
	mov edx, [ebp+16]
	mov ecx, [ebp+20]

	align 32
.loop:
	movq	mm0, [edx]
	add	edx, 8
	paddusb mm0, [eax]
	add	eax, 8
	movq	[ebx],mm0
	add	ebx, 8
	loopnz .loop,ecx

	emms
	pop ebx
	leave
	ret




; Multiply two images

; Add a fixed rgb value to an image
;
; void image_mult_buffers_mmx_x86asm( char *d, char *s1, char *s2,
;				      int npixels_div_4 )
;
image_mult_buffers_mmx_x86asm:
	push ebp
	mov ebp, esp
	push ebx
	mov ebx, [ebp+8]
	mov eax, [ebp+12]
	mov edx, [ebp+16]
	mov ecx, [ebp+20]

	pxor    mm4,mm4

	align 32
.loop:
	movd	  mm0, [eax]
	add	  eax, 4

	punpcklbw mm0,mm4
	movd      mm1, [edx]
	add	  edx, 4

	punpcklbw mm1,mm4

	pmullw	  mm0,mm1
	psrlw	  mm0, 8
	packuswb  mm0,mm0

	movd	  [ebx],mm0
	add	  ebx, 4

	loopnz .loop,ecx
		
	emms
	pop ebx
	leave
	ret


; Subtract a RGB-value value to an image
;
; void image_sub_buffer_mmx_x86asm( char *d, char *source, int npixels,
;	                             int rgbr, int gbrg, int brgb )
;
; edx				dest          ebp+8
; eax				source        ebp+12
; mm0				sourcedata    [eax]
; ecx				numpixels     ebp+16
; mm1				mult1 <rgbr>  ebp+20
; mm2				mult2 <gbrg>  ebp+24
; mm3				mult3 <brgb>  ebp+28
; mm4				null
;
; This funciton can be changed to do twice the amount of work per
; instruction, but it's all memory bound anyway, so there is no
; significant performance gain.
;
image_sub_buffer_mmx_x86asm:
	enter   0,0

	mov edx, [ebp+8]
	mov eax, [ebp+12]

	mov ecx, [ebp+16]

	movd	mm1,[ebp+20]	; rgb r
	movd	mm2,[ebp+24]	; gb rg
	movd	mm3,[ebp+28]	; b rgb

;	r g b r g b r g b r g b r g b r g  ...
;	0       4       8       12      16
;
;  int is 0:	 r b g r   
;	  4:	 g r b g  
; 	  8:	 b g r b
	align 32
.loop:
 	movd	  mm0,[eax]
	add	  eax,4
	psubusb	  mm0,mm1
 	movd	  [edx],mm0
	add	  edx,4


 	movd	  mm0,[eax]
	add	  eax,4
	psubusb	  mm0,mm2
 	movd	  [edx],mm0
	add	  edx,4

 	movd	  mm0,[eax]
	add	  eax,4
	psubusb	  mm0,mm3
 	movd	  [edx],mm0
	add	  edx,4

	loopnz .loop,ecx
	
	emms
	leave
	ret

; Add a RGB-value value to an image
;
; void image_add_buffer_mmx_x86asm( char *d, char *source, int npixels,
;	                             int rgbr, int gbrg, int brgb )
;
; edx				dest          ebp+8
; eax				source        ebp+12
; mm0				sourcedata    [eax]
; ecx				numpixels     ebp+16
; mm1				mult1 <rgbr>  ebp+20
; mm2				mult2 <gbrg>  ebp+24
; mm3				mult3 <brgb>  ebp+28
; mm4				null
;
; This funciton can be changed to do twice the amount of work per
; instruction, but it's all memory bound anyway, so there is no
; significant performance gain.
;
image_add_buffer_mmx_x86asm:
	enter   0,0

	mov edx, [ebp+8]
	mov eax, [ebp+12]

	mov ecx, [ebp+16]

	movd	mm1,[ebp+20]	; rgb r
	movd	mm2,[ebp+24]	; gb rg
	movd	mm3,[ebp+28]	; b rgb


;	r g b r g b r g b r g b r g b r g  ...
;	0       4       8       12      16
;
;  int is 0:	 r b g r   
;	  4:	 g r b g  
; 	  8:	 b g r b
	align 32
.loop:
 	movd	  mm0,[eax]	
	add	  eax,4		
	paddusb	  mm0,mm1	
 	movd	  [edx],mm0	
	add	  edx,4		

 	movd	  mm0,[eax]	
	add	  eax,4		
	paddusb	  mm0,mm2
 	movd	  [edx],mm0	
	add	  edx,4		

 	movd	  mm0,[eax]
	add	  eax,4		
	paddusb	  mm0,mm3
 	movd	  [edx],mm0
	add	  edx,4

	loopnz .loop,ecx
	
	emms
	leave
	ret
	
; Multiply an image with a fixed rgb value
;
; void image_mult_buffer_mmx_x86asm( char *d, char *source, int npixels, 
;	                             int rgbr, int gbrg, int brgb )
;
; eax				address       ebp+8
; mm0				sourcedata    [eax]
; ecx				numpixels     ebp+12
; mm1				mult1 <rgbr>  ebp+16
; mm2				mult2 <gbrg>  ebp+20
; mm3				mult3 <brgb>  ebp+24
; mm4				null
image_mult_buffer_mmx_x86asm:
	enter   0,0

	mov edx, [ebp+8]
	mov eax, [ebp+12]
	mov ecx, [ebp+16]

	pxor    mm4,mm4

	movd	mm1,[ebp+20]	; rgb r
	punpcklbw mm1, mm4

	movd	mm2,[ebp+24]	; gb rg
	punpcklbw mm2, mm4

	movd	mm3,[ebp+28]	; b rgb
	punpcklbw mm3, mm4



;	r g b r g b r g b r g b r g b r g  ...
;	0       4       8       12      16
;
;  int is 0:	 r b g r   
;	  4:	 g r b g  
; 	  8:	 b g r b
	align 32
.loop:
 	movd	  mm0,[eax]	
	add	  eax,4		
	punpcklbw mm0,mm4	
	pmullw	  mm0,mm1	
	psrlw	  mm0,8		
	packuswb  mm0,mm0	
 	movd	  [edx],mm0	
	add	  edx,4		


 	movd	  mm0,[eax]	
	add	  eax,4		
	punpcklbw mm0,mm4	
	pmullw	  mm0,mm2	
	psrlw	  mm0,8		
	packuswb  mm0,mm0	
 	movd	  [edx],mm0	
	add	  edx,4		

 	movd	  mm0,[eax]
	add	  eax,4		
	punpcklbw mm0,mm4
	pmullw	  mm0,mm3
	psrlw	  mm0,8
	packuswb  mm0,mm0
 	movd	  [edx],mm0
	add	  edx,4

	loopnz .loop,ecx
	
	emms
	leave
	ret
