2025-04-27 07:49:33 -04:00

771 lines
27 KiB
NASM

;---------------------------Module-Header------------------------------;
; Module Name: cpybits.asm
;
; Copyright (c) 1992 Microsoft Corporation
;-----------------------------------------------------------------------;
page ,132
title DrvCopyBits Support
.386
ifndef DOS_PLATFORM
.model small,c
else
ifdef STD_CALL
.model small,c
else
.model small,pascal
endif; STD_CALL
endif; DOS_PLATFORM
assume ds:FLAT,es:FLAT,ss:FLAT
assume fs:nothing,gs:nothing
.xlist
include stdcall.inc ;calling convention cmacros
include i386\egavga.inc ;VGA register definitions
include i386\strucs.inc
.list
;-----------------------------------------------------------------------;
.data
; Reuse the work area from the dib conversion code.
extrn ajConvertBuffer:byte ;Buffer for converting to/from display
CJ_WORK_PLANE equ cj_max_scan+1 ;Width of each plane in ajConvertBuffer
.code
; ausLo16 is used to convert the low nibble of a byte into 4bpp packed pel
ausLo16 label word
dw 0000h ;0000
dw 0100h ;0001
dw 1000h ;0010
dw 1100h ;0011
dw 0001h ;0100
dw 0101h ;0101
dw 1001h ;0110
dw 1101h ;0111
dw 0010h ;1000
dw 0110h ;1001
dw 1010h ;1010
dw 1110h ;1011
dw 0011h ;1100
dw 0111h ;1101
dw 1011h ;1110
dw 1111h ;1111
; aulHi16 is used to convert the hi nibble of a byte into 4bpp packed pel
aulHi16 label dword
dd 00000000h ;0000
dd 01000000h ;0001
dd 10000000h ;0010
dd 11000000h ;0011
dd 00010000h ;0100
dd 01010000h ;0101
dd 10010000h ;0110
dd 11010000h ;0111
dd 00100000h ;1000
dd 01100000h ;1001
dd 10100000h ;1010
dd 11100000h ;1011
dd 00110000h ;1100
dd 01110000h ;1101
dd 10110000h ;1110
dd 11110000h ;1111
; ajRightMasks turns an exclusive bit position (0-7) into a mask of bits
; to alter for the right hand side of the blt
ajRightMasks label byte
db 11111111b ;0 should never be used
db 01111111b ;1
db 00111111b ;2
db 00011111b ;3
db 00001111b ;4
db 00000111b ;5
db 00000011b ;6
db 00000001b ;7
; ajLeftMasks turns a bit position (0-7) into a mask of bits to alter for
; the left hand side of the blt
ajLeftMasks label byte
db 11111111b ;0 should never be used
db 10000000b ;1
db 11000000b ;2
db 11100000b ;3
db 11110000b ;4
db 11111000b ;5
db 11111100b ;6
db 11111110b ;7
CB_4BPP_SCAN equ (CX_SCREEN_MAX / 2) ;# bytes for a 4bpp screen scan
;-----------------------------Public-Routine----------------------------;
; vConvertVGAScan
;
; Converts a VGA scan into a 4bpp format with a given phase alignment,
; and returns a pointer to the converted buffer.
;
; pdsurfsrc - pointer to source surface (must be VGA display memory)
; xSrc - X origin of the source
; ySrc - Y origin of the source
; pjDstBase - Base address of the destination
; xDst - X origin of the destination
; yDst - Y origin of the destination
; cxPels - Number of pels in X
; cyTotalScans - Number of scans in overall operation
; lDelta - Width in bytes of a destination scan
; iFormat - Format of destination
; pulXlate - Color translation vector
;-----------------------------------------------------------------------;
ProcName xxxvConvertVGA2DIB,vConvertVGA2DIB,44
xxxvConvertVGA2DIB proc uses esi edi ebx,\
pdsurfsrc :ptr DEVSURF, \
xSrc :dword, \
ySrc :dword, \
pjDstBase :dword, \
xDst :dword, \
yDst :dword, \
cxPels :dword, \
cyTotalScans :dword, \
lDelta :dword, \
iFormat :dword, \
pulXlate :dword
;-----------------------------------------------------------------------;
; Local variables and their meaning
;
; cjScreenCopy This is the number of bytes to copy from each scan
; into ajConvertBuffer.
; jLeftMask This is the left-hand side (lhs) mask used when copying
; the converted data to the destination
; jRightMask This is the right-hand side (lhs) mask used when copying
; the converted data to the destination
; cRightShift This is the number of bits that the converted data needs
; to be shifted right to align with the destination.
; cjRightShift This is the number of bytes which must be shifted right
; by cRightShift
; cCopy This is the number of full (e.g. not masked) bytes which
; must be copied to the destination
; pjWork Pointer to the work area where
; a) color converted data is written into
; b) bits are phase-aligned if needed
; c) data is read from for the final copy to the DIB
; pjSrc Address of scan 0 in memory
; pjDst Address of scan 0 in memory
; cyScans Number of scans to do in current bank
; ulScanWidth Offset from start of one scan to start of next
; ulBottomSrcScan Bottom scan line of source rectangle (non-inclusive)
;-----------------------------------------------------------------------;
local cjScreenCopy :dword
local jLeftMask :byte
local jRightMask :byte
local cRightShift :byte
local cjRightShift :dword
local cCopy :dword
local pfnXlate :ptr
local pjWork :ptr
local cjSkip :dword
local pjSrc :dword
local pjDst :dword
local cyScans :dword
local ulScanWidth :dword
local ulBottomSrcScan :dword
local ajColorConv[16]:byte
local ajWork[CB_4BPP_SCAN+4]:byte
local aj8bpp[CX_SCREEN_MAX+8]:byte
;----------------------------------------------------------------------;
; Loop through source banks, copying & converting one bank at a time.
; Calculate the bottom scan line of the source rectangle (non-inclusive).
mov eax,ySrc
add eax,cyTotalScans
mov ulBottomSrcScan,eax
mov ecx,pdsurfsrc ;point to source surface
mov eax,[ecx].dsurf_lNextScan
mov ulScanWidth,eax ;local copy of scan line width
; Map in the bank containing the top scan to fill, if it's not mapped in
; already.
mov eax,ySrc ;top scan line of source
cmp eax,[ecx].dsurf_rcl1WindowClip.yTop ;is fill top less than
; current bank?
jl short map_init_bank ;yes, map in proper bank
cmp eax,[ecx].dsurf_rcl1WindowClip.yBottom ;fill top greater than
; current bank?
jl short init_bank_mapped ;no, proper bank already mapped
map_init_bank:
; Map in the bank containing the top scan line of the fill.
ptrCall <dword ptr [ecx].dsurf_pfnBankControl>,<ecx,eax,JustifyTop>
init_bank_mapped:
bank_loop:
; Set the start address of the source bitmap.
; Note that the start of the bitmap will change each time through the
; bank loop, because the start of the bitmap is varied to map the
; desired scan line to the banking window.
mov eax,pdsurfsrc ;point to source surface
mov ebx,[eax].dsurf_pvBitmapStart ;start of scan 0 in bitmap
mov pjSrc,ebx
; Set the start address of the destination bitmap.
mov ebx,pjDstBase
mov pjDst,ebx
; Figure out how many scan lines we'll fill in the current bank.
mov ebx,ulBottomSrcScan ;bottom of destination rectangle
cmp ebx,[eax].dsurf_rcl1WindowClip.yBottom
;which comes first, the bottom of the
; dest rect or the bottom of the
; current bank?
jl short BottomScanSet ;fill bottom comes first, so draw to
; that; this is the last bank in fill
mov ebx,[eax].dsurf_rcl1WindowClip.yBottom
;bank bottom comes first; draw to
; bottom of bank
BottomScanSet:
sub ebx,ySrc ;# of scans to fill in bank
mov cyScans,ebx
push ebx ;remember # of scans in bank
call DoOneBank ;copy and convert within the current bank
pop ebx ;restore # of scans in bank
sub cyTotalScans,ebx ;count off this bank's scans from total
jz short banks_done ;no more scans; done
add yDst,ebx ;advance to the next destination scan
; to copy to
mov edi,pdsurfsrc
mov eax,[edi].dsurf_rcl1WindowClip.yBottom
mov ySrc,eax ;remember where the top of the bank
; we're about to map in is (same as
; bottom of bank we just did)
ptrCall <dword ptr [edi].dsurf_pfnBankControl>,<edi,eax,JustifyTop>
;map in the bank
jmp bank_loop ;fill the next bank
; Done.
align 4
banks_done:
cRet vConvertVGA2DIB
;----------------------------------------------------------------------;
; Copies and converts bits within a single bank.
align 4
DoOneBank:
cld
; Compute the number of bytes to copy from the screen, and the starting
; address of the source
mov eax,ySrc ;Compute addr of first source scan
mov ebx,xSrc
imul eax,ulScanWidth
mov ecx,ebx
shr ebx,3
add eax,ebx
add pjSrc,eax
; Compute the number of bytes to actually transfer from the screen
mov eax,cxPels ;Compute rhs
add eax,ecx
dec eax ;Make rhs inclusive
shr ecx,3 ;Compute byte of lhs
shr eax,3 ;Compute byte of rhs
sub eax,ecx ;Compute number of bytes for copy
inc eax ;(because rhs inclusive, always inc)
mov cjScreenCopy,eax
; Compute the address of the starting destination scan.
mov eax,yDst
imul lDelta
add pjDst,eax
; Set up for the preprocess loops and invoke the correct one. First make
; some assumptions about defaults
xor eax,eax
mov cRightShift,al ;No shifting needed
mov jLeftMask,al ;No left masking needed
mov jRightMask,al ;No right masking needed
lea eax,ajWork ;Intermediate work area
mov pjWork,eax
mov esi,cxPels
mov ebx,xSrc
mov edx,xDst
mov eax,iFormat
dec eax
jz preproc_1bpp
dec eax
jz preproc_4bpp
.errnz BMF_1BPP-1
.errnz BMF_4BPP-2
.errnz BMF_8BPP-3
; Destination is 8bpp. Copy will be phased aligned from the conversion buffer
; to the destination.
preproc_8bpp:
add pjDst,edx ;Offset to first pel in DIB
and ebx,7 ;Offset to first pel for final copy
mov cjSkip,ebx
mov cCopy,esi ;Number of bytes for final copy
lea eax,aj8bpp ;Intermediate work area
mov pjWork,eax
mov pfnXlate,offset FLAT:cvt_to_8bpp
jmp preproc_done
; Destination is 4bpp. Copy will either be phase aligned or be off by 4 in
; which case we will phase align the entire buffer before copying.
preproc_4bpp:
lea eax,[esi][edx] ;Compute rhs for later
test dl,1 ;Odd if left mask needed
jz @F
mov jLeftMask,11110000b
dec esi ;One less pel in inner loop
@@:
test al,1 ;Odd if right mask needed
jz @F
mov jRightMask,00001111b
dec esi ;One less pel in inner loop
@@:
and ebx,7 ;Offset for final copy is xSrc mod 8
; If the source and destination have different alignments, we'll have to
; compute phase alignment stuff.
mov eax,ebx
xor eax,edx
shr eax,1
jnc @F
mov eax,cjScreenCopy ;* 4 for size of data in buffer
shl eax,2
inc eax ;+ 1 to shift into last byte!
mov cjRightShift,eax
mov cRightShift,4 ;Shift entire buffer right 4 pels
inc ebx ;First pel just moved right
@@:
; Finish calculating the other parameters
shr edx,1 ;Offset to first pel in DIB
add pjDst,edx
shr ebx,1
mov cjSkip,ebx
shr esi,1
mov cCopy,esi ;# of inner bytes for final copy
mov eax,offset FLAT:copy_to_dest;Assume no color translation needed
cmp pulXlate,0
je @F
mov eax,offset FLAT:cvt_to_4bpp ;Addreess of color xlate routine
@@:
mov pfnXlate,eax
jmp preproc_done
; Destination is 1bpp. Copy most likely will require masking and phase
; alignment.
preproc_1bpp:
mov edi,00000007h ;A handy mask used a lot
xor ecx,ecx ;CL = lhs mask, CH = rhs mask
lea eax,[esi][edx] ;Compute rhs for later
test edx,edi ;See if partial byte
jz preproc_1bpp_done_lhs ;No partial lhs byte
mov ecx,edx
neg ecx
and ecx,edi ;CL = # bits in lhs, CH = 0
sub esi,ecx ;Compute # remaining bytes
mov cl,ajLeftMasks[ecx] ;Get lhs mask
jnc preproc_1bpp_done_lhs ;Didn't combine into one byte
and eax,edi ;Combine rhs mask with lhs mask
and cl,ajRightMasks[eax]
xor esi,esi ;No more bytes
xor eax,eax ;To show no rhs
jmp short preproc_1bpp_have_masks
preproc_1bpp_done_lhs:
and eax,edi ;See if partial rhs byte
jz preproc_1bpp_have_masks ;No partial rhs byte
mov ch,ajRightMasks[eax]
sub esi,eax ;Compute # remaining bytes
preproc_1bpp_have_masks:
mov jLeftMask,cl ;Set left and right masks
mov jRightMask,ch
shr esi,3 ;# of inner bytes for final copy
mov cCopy,esi
; Compute offset to first byte in destination DIB
mov eax,edx
shr eax,3
add pjDst,eax
; Compute phase alignment parameters
xor ecx,ecx ;Assume cjSkip is 0
and edx,edi
and ebx,edi
sub edx,ebx ;Determine phase alignment
jz preproc_finish_1bpp ;No phase alignment needed
; We're really shifting left, so we'll set it up to shift right a lot, and
; get the first byte of the final move from byte 1 of the work area.
adc ecx,ecx ;Set cjSkip = 0 or 1
and edx,edi ;3 LSBs is shift count
mov cRightShift,dl ;Phase for the shift
mov eax,cjScreenCopy ;Size of data in buffer
inc eax ;+ 1 to shift into last byte!
mov cjRightShift,eax
preproc_finish_1bpp:
mov cjSkip,ecx ;No skipping needed
mov esi,pulXlate ;Copy color translation table to the
lea edi,ajColorConv ; frame because we are out of regs.
mov ecx,16
@@:
lodsd
stosb
dec ecx
jnz @B
mov pfnXlate,offset FLAT:cvt_to_1bpp
preproc_done:
process_next_scan:
mov edi,offset FLAT:ajConvertBuffer
mov edx,EGA_BASE + GRAF_ADDR
mov eax,GRAF_READ_MAP
copy_planes_012:
mov esi,pjSrc ;ESI --> first Source byte
out dx,ax ;Set read plane
mov ecx,cjScreenCopy ;Set number of bytes to read
mov ebx,edi
rep movsb
lea edi,[ebx][CJ_WORK_PLANE];EDI --> next scan in convert buf
inc ah ;Set next read plane
mov esi,pjSrc ;ESI --> first Source byte
out dx,ax ;Set read plane
mov ecx,cjScreenCopy ;Set number of bytes to read
mov ebx,edi
rep movsb
lea edi,[ebx][CJ_WORK_PLANE];EDI --> next scan in convert buf
inc ah ;Set next read plane
mov esi,pjSrc ;ESI --> first Source byte
out dx,ax ;Set read plane
mov ecx,cjScreenCopy ;Set number of bytes to read
mov ebx,edi
rep movsb
lea edi,[ebx][CJ_WORK_PLANE];EDI --> next scan in convert buf
inc ah ;Set next read plane
copy_plane_3:
mov esi,pjSrc ;ESI --> first Source byte
out dx,ax ;Set read plane
mov ecx,cjScreenCopy ;Set number of bytes to read
mov ebx,edi
;-----------------------------------------------------------------------;
; [BUGFIX] - byte reads from plane 3 of video memory must be done twice
; on the VLB CL5434 or they don't always work
;-----------------------------------------------------------------------;
;---------------------------------------
; do a "movsb" with double reads
; was "rep movsb"
push eax
; any more bytes to copy?
next_byte:
dec ecx
jl done_movs
mov al,[esi]
mov al,[esi]
mov [edi],al
inc edi
inc esi
jmp next_byte
; done with "movsb"
done_movs:
sub ecx,ecx
pop eax
;---------------------------------------
; The scan has been read in from the VGA. Convert it into 4bpp format which
; will be needed for doing the color conversion.
lea edi,ajWork ;Convert dwords into here
mov esi,offset FLAT:ajConvertBuffer
mov ecx,cjScreenCopy ;# of source bytes to convert
cvt_next_src_byte:
xor eax,eax
mov al,[esi][CJ_WORK_PLANE*3] ;Get data for plane C3
mov ebx,eax
and ebx,00001111b
shr eax,4
mov edx,aulHi16[ebx*4]
or dx,ausLo16[eax*2]
shl edx,1
mov al,[esi][CJ_WORK_PLANE*2] ;Get data for plane C2
mov ebx,eax
and ebx,00001111b
shr eax,4
or edx,aulHi16[ebx*4]
or dx,ausLo16[eax*2]
shl edx,1
mov al,[esi][CJ_WORK_PLANE*1] ;Get data for plane C1
mov ebx,eax
and ebx,00001111b
shr eax,4
or edx,aulHi16[ebx*4]
or dx,ausLo16[eax*2]
shl edx,1
lodsb ;Get data for plane C0
mov ebx,eax
and ebx,00001111b
shr eax,4
or edx,aulHi16[ebx*4]
or dx,ausLo16[eax*2]
mov eax,edx
stosd ;8 pels down!
dec ecx
jnz cvt_next_src_byte
; Perform the format conversion
mov ecx,cjScreenCopy ;Set lopp count
lea esi,ajWork ;Set source pointer
mov edi,pjWork ;Set destination pointer
mov ebx,pulXlate ;Set color translate vector
xor eax,eax ;Init D31:D8 to 0
jmp pfnXlate ;Invoke correct conversion routine
; Convert from 4bpp to 8bpp with color translation
cvt_to_8bpp:
lodsb ;Get two nibbles worth
mov edx,eax
shr eax,4
and edx,00001111b
mov al,[ebx][eax*4]
stosb
mov al,[ebx][edx*4]
stosb
lodsb ;Get two nibbles worth
mov edx,eax
shr eax,4
and edx,00001111b
mov al,[ebx][eax*4]
stosb
mov al,[ebx][edx*4]
stosb
lodsb ;Get two nibbles worth
mov edx,eax
shr eax,4
and edx,00001111b
mov al,[ebx][eax*4]
stosb
mov al,[ebx][edx*4]
stosb
lodsb ;Get two nibbles worth
mov edx,eax
shr eax,4
and edx,00001111b
mov al,[ebx][eax*4]
stosb
mov al,[ebx][edx*4]
stosb
dec ecx
jnz cvt_to_8bpp
jmp copy_to_dest
; Convert from 4bpp to 4bpp with color translation.
cvt_to_4bpp:
lodsb ;Get two nibbles worth
mov edx,eax
shr eax,4
and edx,00001111b
mov al,[ebx][eax*4]
shl al,4
or al,[ebx][edx*4]
stosb
lodsb ;Get two nibbles worth
mov edx,eax
shr eax,4
and edx,00001111b
mov al,[ebx][eax*4]
shl al,4
or al,[ebx][edx*4]
stosb
lodsb ;Get two nibbles worth
mov edx,eax
shr eax,4
and edx,00001111b
mov al,[ebx][eax*4]
shl al,4
or al,[ebx][edx*4]
stosb
lodsb ;Get two nibbles worth
mov edx,eax
shr eax,4
and edx,00001111b
mov al,[ebx][eax*4]
shl al,4
or al,[ebx][edx*4]
stosb
dec ecx
jnz cvt_to_4bpp
jmp copy_to_dest
; Convert from 4bpp to 1bpp with color translation.
cvt_to_1bpp:
lodsb ;Get two nibbles worth
mov edx,eax
shr eax,4
and edx,00001111b
mov bl,ajColorConv[eax]
shl bl,1
or bl,ajColorConv[edx]
lodsb
mov edx,eax
shr eax,4
and edx,00001111b
shl bl,1
or bl,ajColorConv[eax]
shl bl,1
or bl,ajColorConv[edx]
lodsb ;Get two nibbles worth
mov edx,eax
shr eax,4
and edx,00001111b
shl bl,1
or bl,ajColorConv[eax]
shl bl,1
or bl,ajColorConv[edx]
lodsb ;Get two nibbles worth
mov edx,eax
shr eax,4
and edx,00001111b
shl bl,1
or bl,ajColorConv[eax]
shl bl,1
or bl,ajColorConv[edx]
mov al,bl
stosb
dec ecx
jnz cvt_to_1bpp
; Copy to the destination. This unfortunately may involve phase alignment
copy_to_dest:
movzx ecx,cRightShift
jecxz copy_aligned_to_dest
mov edi,pjWork
mov ebx,cjRightShift
phase_align_it:
mov ah,dl ;Get previous unused bits
mov al,byte ptr [edi]
mov dl,al
shr eax,cl
stosb
dec ebx
jnz phase_align_it
copy_aligned_to_dest:
mov esi,pjWork
add esi,cjSkip
mov edi,pjDst
mov dl,jLeftMask
or dl,dl
jz @F
lodsb
mov ah,byte ptr [edi]
xor ah,al
and ah,dl
xor al,ah
stosb
@@:
mov ecx,cCopy
rep movsb
mov dl,jRightMask
or dl,dl
jz @F
lodsb
mov ah,byte ptr [edi]
xor ah,al
and ah,dl
xor al,ah
stosb
@@:
mov eax,ulScanWidth
add pjSrc,eax
mov eax,lDelta
add pjDst,eax
dec cyScans
jnz process_next_scan
PLAIN_RET ;we're done with this bank
xxxvConvertVGA2DIB endp
end