mirror of
https://github.com/ZDoom/qzdoom-gpl.git
synced 2024-11-17 01:32:19 +00:00
e2179d5c2d
SVN r184 (trunk)
537 lines
12 KiB
Text
537 lines
12 KiB
Text
;*
|
||
;* misc.nas
|
||
;* Miscellaneous assembly functions
|
||
;*
|
||
;*---------------------------------------------------------------------------
|
||
;* Copyright 1998-2006 Randy Heit
|
||
;* All rights reserved.
|
||
;*
|
||
;* Redistribution and use in source and binary forms, with or without
|
||
;* modification, are permitted provided that the following conditions
|
||
;* are met:
|
||
;*
|
||
;* 1. Redistributions of source code must retain the above copyright
|
||
;* notice, this list of conditions and the following disclaimer.
|
||
;* 2. Redistributions in binary form must reproduce the above copyright
|
||
;* notice, this list of conditions and the following disclaimer in the
|
||
;* documentation and/or other materials provided with the distribution.
|
||
;* 3. The name of the author may not be used to endorse or promote products
|
||
;* derived from this software without specific prior written permission.
|
||
;*
|
||
;* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||
;* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||
;* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||
;* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||
;* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||
;* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||
;* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||
;* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||
;* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||
;* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||
;*---------------------------------------------------------------------------
|
||
;*
|
||
|
||
BITS 32
|
||
|
||
%ifndef M_TARGET_LINUX
|
||
|
||
%define CheckMMX _CheckMMX
|
||
%define EndMMX _EndMMX
|
||
%define DoBlending_MMX _DoBlending_MMX
|
||
%define BestColor_MMX _BestColor_MMX
|
||
%define DoubleHoriz_MMX _DoubleHoriz_MMX
|
||
%define DoubleHorizVert_MMX _DoubleHorizVert_MMX
|
||
%define DoubleVert_ASM _DoubleVert_ASM
|
||
|
||
%endif
|
||
|
||
%ifdef M_TARGET_WATCOM
|
||
SEGMENT DATA PUBLIC ALIGN=16 CLASS=DATA USE32
|
||
SEGMENT DATA
|
||
%else
|
||
SECTION .data
|
||
%endif
|
||
|
||
Blending256:
|
||
dd 0x01000100,0x00000100
|
||
|
||
%ifdef M_TARGET_WATCOM
|
||
SEGMENT CODE PUBLIC ALIGN=16 CLASS=CODE USE32
|
||
SEGMENT CODE
|
||
%else
|
||
SECTION .text
|
||
%endif
|
||
|
||
;-----------------------------------------------------------
|
||
;
|
||
; CheckMMX
|
||
;
|
||
; Checks for the presence of MMX instructions on the
|
||
; current processor. This code is adapted from the samples
|
||
; in AMD's document entitled "AMD-K6<4B> MMX Processor
|
||
; Multimedia Extensions." Also fills in the vendor
|
||
; information string.
|
||
;
|
||
;-----------------------------------------------------------
|
||
|
||
GLOBAL CheckMMX
|
||
|
||
; void CheckMMX (struct CPUInfo *)
|
||
|
||
CheckMMX:
|
||
xor eax,eax
|
||
mov ecx,92/4
|
||
push ebx
|
||
push edi
|
||
mov edi,[esp+12]
|
||
rep stosd
|
||
sub edi,92
|
||
|
||
mov [edi+88],byte 32; Assume a 32-byte cache line
|
||
|
||
pushfd ; save EFLAGS
|
||
pop eax ; store EFLAGS in EAX
|
||
mov ebx,eax ; save in EBX for later testing
|
||
xor eax,0x00200000 ; toggle bit 21
|
||
push eax ; put to stack
|
||
popfd ; save changed EAX to EFLAGS
|
||
pushfd ; push EFLAGS to TOS
|
||
pop eax ; store EFLAGS in EAX
|
||
cmp eax,ebx ; see if bit 21 has changed
|
||
jz near .noid ; if no change, then no CPUID
|
||
|
||
; Get vendor ID
|
||
xor eax,eax
|
||
CPUID
|
||
mov [edi],ebx
|
||
mov [edi+4],edx
|
||
mov [edi+8],ecx
|
||
|
||
cmp ebx,0x68747541 ; 'htuA'
|
||
jne .notamd
|
||
cmp edx,0x69746e65 ; 'itne'
|
||
jne .notamd
|
||
cmp ecx,0x444d4163 ; 'DMAc'
|
||
jne .notamd
|
||
inc byte [edi+87]
|
||
.notamd
|
||
|
||
; Get features flags and other info
|
||
mov eax,1
|
||
CPUID
|
||
mov [edi+68],ebx ; Store brand index and other stuff
|
||
mov [edi+72],ecx ; Store extended feature flags
|
||
mov [edi+76],edx ; Store feature flags
|
||
|
||
test edx,(1<<19) ; If CLFLUSH instruction is supported,
|
||
jz .noclf
|
||
shl bh,3 ; get the real cache line size.
|
||
mov [edi+88],bh
|
||
|
||
.noclf mov bl,al ; Extract stepping
|
||
and bl,0x0F
|
||
mov [edi+64],bl
|
||
|
||
mov bl,ah ; Extract processor type
|
||
shr bl,4 ; (Valid for Intel only)
|
||
and bl,0x03
|
||
mov [edi+67],bl
|
||
|
||
shr al,4 ; Extract model and family
|
||
and ah,0x0F ; model in al and family in ah
|
||
cmp ah,15
|
||
jne .noex
|
||
|
||
mov ebx,eax ; Add extended model and family
|
||
shr ebx,12
|
||
and bl,0xF0
|
||
add ah,bh
|
||
or al,bl
|
||
|
||
.noex mov [edi+65],al
|
||
mov [edi+66],ah
|
||
|
||
; Check for processor brand string
|
||
mov eax,0x80000000
|
||
CPUID
|
||
cmp eax,0x80000001
|
||
je .feat2
|
||
jb near .noid
|
||
cmp eax,0x80000004
|
||
jb .feat2
|
||
cmp eax,0x80000005
|
||
jb .brand
|
||
|
||
; Get data L1 cache info
|
||
mov eax,0x80000005
|
||
CPUID
|
||
mov [edi+88],ecx
|
||
|
||
; Get processor brand string
|
||
.brand mov eax,0x80000002
|
||
CPUID
|
||
mov [edi+16],eax
|
||
mov [edi+20],ebx
|
||
mov [edi+24],ecx
|
||
mov [edi+28],edx
|
||
mov eax,0x80000003
|
||
CPUID
|
||
mov [edi+32],eax
|
||
mov [edi+36],ebx
|
||
mov [edi+40],ecx
|
||
mov [edi+44],edx
|
||
mov eax,0x80000004
|
||
CPUID
|
||
mov [edi+48],eax
|
||
mov [edi+52],ebx
|
||
mov [edi+56],ecx
|
||
mov [edi+60],edx
|
||
|
||
; Get AMD-specific feature flags
|
||
.feat2 cmp byte [edi+87],0
|
||
jz .noid
|
||
mov eax,0x80000001
|
||
CPUID
|
||
mov [edi+80],edx
|
||
|
||
mov bl,al ; Extract stepping
|
||
and bl,0x0F
|
||
mov [edi+84],bl
|
||
|
||
shr al,4 ; Extract model and family
|
||
and ah,0x0F ; model in al and family in ah
|
||
cmp ah,15
|
||
jne .noex2
|
||
|
||
mov ebx,eax ; Add extended model and family
|
||
shr ebx,12
|
||
and bl,0xF0
|
||
add ah,bh
|
||
or al,bl
|
||
|
||
.noex2 mov [edi+85],al
|
||
mov [edi+86],ah
|
||
|
||
.noid pop edi
|
||
pop ebx
|
||
ret
|
||
|
||
;-----------------------------------------------------------
|
||
;
|
||
; EndMMX
|
||
;
|
||
; Signal the end of MMX code for compilers that can't
|
||
; do inline assembly. Currently unused.
|
||
;
|
||
;-----------------------------------------------------------
|
||
|
||
GLOBAL EndMMX
|
||
|
||
EndMMX:
|
||
emms
|
||
ret
|
||
|
||
;-----------------------------------------------------------
|
||
;
|
||
; DoBlending_MMX
|
||
;
|
||
; MMX version of DoBlending
|
||
;
|
||
; (DWORD *from, DWORD *to, count, tor, tog, tob, toa)
|
||
;-----------------------------------------------------------
|
||
|
||
GLOBAL DoBlending_MMX
|
||
|
||
DoBlending_MMX:
|
||
pxor mm0,mm0 ; mm0 = 0
|
||
mov eax,[esp+4*4]
|
||
shl eax,16
|
||
mov edx,[esp+4*5]
|
||
shl edx,8
|
||
or eax,[esp+4*6]
|
||
or eax,edx
|
||
mov ecx,[esp+4*3] ; ecx = count
|
||
movd mm1,eax ; mm1 = 00000000 00RRGGBB
|
||
mov eax,[esp+4*7]
|
||
shl eax,16
|
||
mov edx,[esp+4*7]
|
||
shl edx,8
|
||
or eax,[esp+4*7]
|
||
or eax,edx
|
||
mov edx,[esp+4*2] ; edx = dest
|
||
movd mm6,eax ; mm6 = 00000000 00AAAAAA
|
||
punpcklbw mm1,mm0 ; mm1 = 000000RR 00GG00BB
|
||
movq mm7,[Blending256]
|
||
punpcklbw mm6,mm0 ; mm6 = 000000AA 00AA00AA
|
||
mov eax,[esp+4*1] ; eax = source
|
||
pmullw mm1,mm6 ; mm1 = 000000RR 00GG00BB (multiplied by alpha)
|
||
psubusw mm7,mm6 ; mm7 = 000000aa 00aa00aa (one minus alpha)
|
||
nop ; Does this actually pair on a Pentium?
|
||
|
||
; Do two colors per iteration: Count must be even.
|
||
|
||
.loop movq mm2,[eax] ; mm2 = 00r2g2b2 00r1g1b1
|
||
add eax,8
|
||
movq mm3,mm2 ; mm3 = 00r2g2b2 00r1g1b1
|
||
punpcklbw mm2,mm0 ; mm2 = 000000r1 00g100b1
|
||
movq mm4,mm1
|
||
punpckhbw mm3,mm0 ; mm3 = 000000r2 00g200b2
|
||
pmullw mm2,mm7 ; mm2 = 0000r1rr g1ggb1bb
|
||
add edx,8
|
||
pmullw mm3,mm7 ; mm3 = 0000r2rr g2ggb2bb
|
||
sub ecx,2
|
||
paddusw mm2,mm1
|
||
paddusw mm3,mm1
|
||
psrlw mm2,8
|
||
psrlw mm3,8
|
||
packuswb mm2,mm3 ; mm2 = 00r2g2b2 00r1g1b1
|
||
movq [edx-8],mm2
|
||
jnz .loop
|
||
|
||
emms
|
||
ret
|
||
|
||
;-----------------------------------------------------------
|
||
;
|
||
; BestColor_MMX
|
||
;
|
||
; Picks the closest matching color from a palette
|
||
;
|
||
; Passed FFRRGGBB and palette array in same format
|
||
; FF is the index of the first palette entry to consider
|
||
;
|
||
;-----------------------------------------------------------
|
||
|
||
GLOBAL BestColor_MMX
|
||
GLOBAL @BestColor_MMX@8
|
||
|
||
BestColor_MMX:
|
||
mov ecx,[esp+4]
|
||
mov edx,[esp+8]
|
||
@BestColor_MMX@8:
|
||
pxor mm0,mm0
|
||
movd mm1,ecx ; mm1 = color searching for
|
||
mov eax,257*257+257*257+257*257 ;eax = bestdist
|
||
push ebx
|
||
punpcklbw mm1,mm0
|
||
mov ebx,ecx ; ebx = best color
|
||
shr ecx,24 ; ecx = count
|
||
and ebx,0xffffff
|
||
push esi
|
||
push ebp
|
||
|
||
.loop movd mm2,[edx+ecx*4] ; mm2 = color considering now
|
||
inc ecx
|
||
punpcklbw mm2,mm0
|
||
movq mm3,mm1
|
||
psubsw mm3,mm2
|
||
pmullw mm3,mm3 ; mm3 = color distance squared
|
||
|
||
movd ebp,mm3 ; add the three components
|
||
psrlq mm3,32 ; into ebp to get the real
|
||
mov esi,ebp ; (squared) distance
|
||
shr esi,16
|
||
and ebp,0xffff
|
||
add ebp,esi
|
||
movd esi,mm3
|
||
add ebp,esi
|
||
|
||
jz .perf ; found a perfect match
|
||
cmp eax,ebp
|
||
jb .skip
|
||
mov eax,ebp
|
||
lea ebx,[ecx-1]
|
||
.skip cmp ecx,256
|
||
jne .loop
|
||
mov eax,ebx
|
||
pop ebp
|
||
pop esi
|
||
pop ebx
|
||
emms
|
||
ret
|
||
|
||
.perf lea eax,[ecx-1]
|
||
pop ebp
|
||
pop esi
|
||
pop ebx
|
||
emms
|
||
ret
|
||
|
||
;-----------------------------------------------------------
|
||
;
|
||
; DoubleHoriz_MMX
|
||
;
|
||
; Stretches an image horizontally using MMX instructions.
|
||
; The source image is assumed to occupy the right half
|
||
; of the destination image.
|
||
;
|
||
; height of source
|
||
; width of source
|
||
; dest pointer (at end of row)
|
||
; pitch
|
||
;
|
||
;-----------------------------------------------------------
|
||
|
||
GLOBAL DoubleHoriz_MMX
|
||
|
||
DoubleHoriz_MMX:
|
||
mov edx,[esp+8] ; edx = width
|
||
push edi
|
||
|
||
neg edx ; make edx negative so we can count up
|
||
mov edi,[esp+16] ; edi = dest pointer
|
||
|
||
sar edx,2 ; and make edx count groups of 4 pixels
|
||
push ebp
|
||
|
||
mov ebp,edx ; ebp = # of columns remaining in this row
|
||
push ebx
|
||
|
||
mov ebx,[esp+28] ; ebx = pitch
|
||
mov ecx,[esp+16] ; ecx = # of rows remaining
|
||
|
||
.loop movq mm0,[edi+ebp*4]
|
||
|
||
.loop2 movq mm1,mm0
|
||
punpcklbw mm0,mm0 ; double left 4 pixels
|
||
|
||
movq mm2,[edi+ebp*4+8]
|
||
punpckhbw mm1,mm1 ; double right 4 pixels
|
||
|
||
movq [edi+ebp*8],mm0 ; write left pixels
|
||
movq mm0,mm2
|
||
|
||
movq [edi+ebp*8+8],mm1 ; write right pixels
|
||
|
||
add ebp,2 ; increment counter
|
||
jnz .loop2 ; repeat until done with this row
|
||
|
||
|
||
add edi,ebx ; move edi to next row
|
||
dec ecx ; decrease row counter
|
||
|
||
mov ebp,edx ; prep ebp for next row
|
||
jnz .loop ; repeat until every row is done
|
||
|
||
emms
|
||
pop ebx
|
||
pop ebp
|
||
pop edi
|
||
ret
|
||
|
||
;-----------------------------------------------------------
|
||
;
|
||
; DoubleHorizVert_MMX
|
||
;
|
||
; Stretches an image horizontally and vertically using
|
||
; MMX instructions. The source image is assumed to occupy
|
||
; the right half of the destination image and to leave
|
||
; every other line unused for expansion.
|
||
;
|
||
; height of source
|
||
; width of source
|
||
; dest pointer (at end of row)
|
||
; pitch
|
||
;
|
||
;-----------------------------------------------------------
|
||
|
||
GLOBAL DoubleHorizVert_MMX
|
||
|
||
DoubleHorizVert_MMX:
|
||
mov edx,[esp+8] ; edx = width
|
||
push edi
|
||
|
||
neg edx ; make edx negative so we can count up
|
||
mov edi,[esp+16] ; edi = dest pointer
|
||
|
||
sar edx,2 ; and make edx count groups of 4 pixels
|
||
push ebp
|
||
|
||
mov ebp,edx ; ebp = # of columns remaining in this row
|
||
push ebx
|
||
|
||
mov ebx,[esp+28] ; ebx = pitch
|
||
mov ecx,[esp+16] ; ecx = # of rows remaining
|
||
|
||
push esi
|
||
lea esi,[edi+ebx]
|
||
|
||
.loop movq mm0,[edi+ebp*4] ; get 8 pixels
|
||
|
||
movq mm1,mm0
|
||
punpcklbw mm0,mm0 ; double left 4
|
||
|
||
punpckhbw mm1,mm1 ; double right 4
|
||
add ebp,2 ; increment counter
|
||
|
||
movq [edi+ebp*8-16],mm0 ; write them back out
|
||
|
||
movq [edi+ebp*8-8],mm1
|
||
|
||
movq [esi+ebp*8-16],mm0
|
||
|
||
movq [esi+ebp*8-8],mm1
|
||
|
||
jnz .loop ; repeat until done with this row
|
||
|
||
lea edi,[edi+ebx*2] ; move edi and esi to next row
|
||
lea esi,[esi+ebx*2]
|
||
|
||
dec ecx ; decrease row counter
|
||
mov ebp,edx ; prep ebp for next row
|
||
|
||
jnz .loop ; repeat until every row is done
|
||
|
||
emms
|
||
pop esi
|
||
pop ebx
|
||
pop ebp
|
||
pop edi
|
||
ret
|
||
|
||
;-----------------------------------------------------------
|
||
;
|
||
; DoubleVert_ASM
|
||
;
|
||
; Stretches an image vertically using regular x86
|
||
; instructions. The source image should be interleaved.
|
||
;
|
||
; height of source
|
||
; width of source
|
||
; source/dest pointer
|
||
; pitch
|
||
;
|
||
;-----------------------------------------------------------
|
||
|
||
GLOBAL DoubleVert_ASM
|
||
|
||
DoubleVert_ASM:
|
||
mov edx,[esp+16] ; edx = pitch
|
||
mov eax,[esp+4] ; eax = # of rows left
|
||
|
||
push esi
|
||
mov esi,[esp+16]
|
||
|
||
push edi
|
||
lea edi,[esi+edx]
|
||
|
||
shl edx,1 ; edx = pitch*2
|
||
mov ecx,[esp+16]
|
||
|
||
sub edx,ecx ; edx = dist from end of one line to start of next
|
||
shr ecx,2
|
||
|
||
.loop rep movsd
|
||
|
||
mov ecx,[esp+16]
|
||
add esi,edx
|
||
|
||
add edi,edx
|
||
shr ecx,2
|
||
|
||
dec eax
|
||
jnz .loop
|
||
|
||
pop edi
|
||
pop esi
|
||
ret
|