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

651 lines
24 KiB
NASM

;---------------------------Module-Header------------------------------;
;
; Module Name: dfb2pat.asm
;
; Copyright (c) 1994 Microsoft Corporation
;
;-----------------------------------------------------------------------;
;
; VOID vClrPatDFB(PDEVSURF pdsurfDst,
; ULONG cRect,
; RECTL * prclDst,
; MIX ulMix,
; BRUSHINST *pBrush,
; PPOINTL pBrushOrg);
;
; The parameter list must match up with vClrPatBlt
;
; Performs accelerated fills to a DFB.
;
; pdsurfDst = pointer to dest surface
; cRect = count of rectangles to fill
; prclDst = pointer to array of rectangles describing target area of DFB
; ulMix = mix rop with which to fill
; pBrush = pointer to the brush instance
; pBrushOrg = pointer to where to start in brush
;
;-----------------------------------------------------------------------;
;
; Note: Assumes the destination rectangle has a positive height and width.
; Will not work properly if this is not the case.
;
;-----------------------------------------------------------------------;
.386
.model small,c
assume ds:FLAT,es:FLAT,ss:FLAT
assume fs:nothing,gs:nothing
.xlist
include stdcall.inc ;calling convention cmacros
include i386\egavga.inc
include i386\strucs.inc
include i386\ropdefs.inc
include i386\display.inc ; Display specific structures
.list
;-----------------------------------------------------------------------;
.data
extrn jForceOffTable:byte ;see vgablts.asm
extrn jForceOnTable:byte ;see vgablts.asm
extrn jNotTable:byte ;see vgablts.asm
extrn dfbfill_jLeftMasks:dword ;see dfbfill.asm
extrn dfbfill_jRightMasks:dword ;see dfbfill.asm
dfbpat_pfnScanHandlers label dword
dd patfill_dfb_scan_00
dd patfill_dfb_scan_01
dd patfill_dfb_scan_10
dd patfill_dfb_scan_11
;-----------------------------------------------------------------------;
.code
_TEXT$01 SEGMENT DWORD USE32 PUBLIC 'CODE'
ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
;-----------------------------------------------------------------------;
cProc vClrPatDFB,24,< \
uses esi edi ebx, \
pdsurfDst: ptr DEVSURF, \
cRect: dword, \
prclDst: ptr RECTL, \
ulMix: dword, \
pBrush: ptr oem_brush_def, \
pBrushOrg: ptr POINTL >
local pfnDrawScans:dword ;ptr to correct scan drawing function
local pDst:dword ;pointer to drawing dst start address
local ulBytesPerDstPlane:dword ;# of bytes on one mono plan scan of DFB
local ulColor:dword ;color of pattern
local ulPatternOrgY:dword ;Local copy of the pattern offset Y
local iPatY:dword ;y index into pattern
local RotatedPat[32]:byte ;Aligned pattern buffer
local sDfbInfo[size DFBBLT]:byte
TRAILING_PARTIAL equ 01h ;partial trailing word should be copied
LEADING_PARTIAL equ 02h ;partial leading word should be copied
PLANE_0_BIT equ 01h ;which bit of ulColor should go on plane 0
PLANE_1_BIT equ 02h ;which bit of ulColor should go on plane 1
PLANE_2_BIT equ 04h ;which bit of ulColor should go on plane 2
PLANE_3_BIT equ 08h ;which bit of ulColor should go on plane 3
;-----------------------------------------------------------------------;
;-----------------------------------------------------------------------;
; Make sure there's something to draw; clip enumerations can be empty.
;-----------------------------------------------------------------------;
cmp cRect,0 ;any more rects to fill?
je dfbpat_exit ;no, we're done
;
; Set up for the desired raster op.
;
sub ebx,ebx ;ignore any background mix; we're only
mov bl,byte ptr ulMix ; concerned with the foreground in this
; module
cmp ebx,R2_NOP ;is this NOP?
jz dfbpat_exit ;yes, we're done
mov esi,pBrush ;point to the brush
;-----------------------------------------------------------------------;
; Set up variables that are constant for the entire time we're in this
; module.
;-----------------------------------------------------------------------;
mov edx,pBrushOrg ;point to the brush origin
mov ecx,[edx].ptl_y
and ecx,7 ;just to be safe
mov ulPatternOrgY,ecx
mov ecx,[edx].ptl_x
and ecx,7 ;eax mod 8
;We are now going to make a copy of our rotated copy of our pattern.
;The reason that we do this is because we may be called with several
;rectangles and we don't really want to rotate the pattern data for
;each rectangle. We copy this rectangle to be double high so that
;we can incorperate our Y offest later without having to worry
;about running off the end of the pattern.
lea edi,RotatedPat ;Pattern Dest
; mov esi,[esi + oem_brush_pmono] ;Pattern Src
add esi,oem_brush_C0 ;Pattern Src
or ecx,ecx
jnz rotate_pattern_ROP
; Since there is no rotation we just need to expand our pattern
; to be double tall.
INDEX=0
DSTINDEX=0
rept 8
mov eax,[esi+INDEX]
mov [edi+DSTINDEX],eax
INDEX=INDEX+4
DSTINDEX=DSTINDEX+4
endm ;-----------------
jmp copy_masks
rotate_pattern_ROP:
mov ch,4 ;Loop count
shift_pattern_loop_ROP:
INDEX=0
rept 8 ;patterns are 8x8 planar (4*8)
mov al,[esi+INDEX] ;load bytes for shift
ror al,cl ;shift into position
mov [edi+INDEX],al ;save result
INDEX=INDEX+1
endm ;-----------------
add edi,8
add esi,8
dec ch
jnz shift_pattern_loop_ROP
copy_masks:
dfbpat_outer_loop:
;-----------------------------------------------------------------------;
; Set up various variables for the copy.
;
; At this point, EBX = pptlSrc, EDI = pdsurfDst.
;-----------------------------------------------------------------------;
mov edi,pdsurfDst ;point to surface to fill (DFB)
mov esi,prclDst ;point to rectangle to fill
mov ecx,[esi].yTop
add ecx,8 ;this and the fact that ulPatternOrgY
; is always less than 8 mean that...
sub ecx,ulPatternOrgY ;... this is always positive
and ecx,7
mov iPatY,ecx
sub ecx,ecx ;accumulate copy control flags
mov eax,[esi].xLeft ;first, check for partial-dword edges
and eax,11111b ;left edge pixel alignment
jz short @F ;whole byte, don't need leading mask
or ecx,LEADING_PARTIAL ;do need leading mask
@@:
mov edx,dfbfill_jLeftMasks[eax*4] ;mask to apply to source to clip
mov sDfbInfo.LeftMask,edx ;remember mask
not edx
mov sDfbInfo.NotLeftMask,edx ;remember mask
mov eax,[esi].xRight
and eax,11111b ;right edge pixel alignment
jz short @F ;whole byte, don't need trailing mask
or ecx,TRAILING_PARTIAL ;do need trailing mask
@@:
mov edx,dfbfill_jRightMasks[eax*4] ;mask to apply to source to clip
mov sDfbInfo.RightMask,edx ;remember mask
not edx
mov sDfbInfo.NotRightMask,edx ;remember mask
dfbpat_detect_partials::
mov sDfbInfo.DstWidth,0 ;overwritten if any whole dwords
;now, see if there are only partial
; dwords, or maybe even only one partial
mov eax,[esi].xLeft
add eax,11111b
and eax,not 11111b ;round left up to nearest dword
mov edx,[esi].xRight
cmp eax,edx ;if left (rounded up) >= right
jge short dfbpat_one_partial_only ; only one dword
and edx,not 11111b ;round right down to nearest dword
sub edx,eax ;# of pixels, rounded to nearest dword
; boundaries (not counting partials)
ja short dfbpat_check_whole_dwords ;there's at least one whole dword
;there are no whole dwords
; there are two partial
; dwords, which is exactly what
; we're already set up to do
jmp short dfbpat_set_copy_control_flags
dfbpat_one_partial_only:: ;only one, partial dword, so construct a
; single mask and set up to do just
; one, partial dword
mov eax,sDfbInfo.LeftMask
and eax,sDfbInfo.RightMask ;intersect the masks
mov sDfbInfo.LeftMask,eax
not eax
mov sDfbInfo.NotLeftMask,eax
mov ecx,LEADING_PARTIAL ;only one partial dword, which we'll
; treat as leading
jmp short dfbpat_set_copy_control_flags ;the copy control flags are set
dfbpat_check_whole_dwords::
;finally, calculate the number of whole
; dwords we'll process
shr edx,5 ;num_pixels/32
mov sDfbInfo.DstWidth,edx ;save count of whole dwords
dfbpat_set_copy_control_flags::
mov edx,dfbpat_pfnScanHandlers[ecx*4] ;proper drawing handler
mov pfnDrawScans,edx
;-----------------------------------------------------------------------;
; Set up the offsets to the next source and destination scans.
;
; At this point, EBX = pptlSrc, ESI = prclDst, EDI = pdsurfDst.
;-----------------------------------------------------------------------;
mov edx,sDfbInfo.DstWidth ;# of dwords across dest rectangle
shl edx,2 ;# of bytes across dest rectangle
mov eax,[edi].dsurf_lNextScan ;# of bytes across 1 scan of dest
sub eax,edx ;offset from end of scan 1 to start of scan 2
mov sDfbInfo.DstDelta,eax
;-----------------------------------------------------------------------;
; At this point, ESI = prclDst, EDI = pdsurfDst
;-----------------------------------------------------------------------;
mov eax,[edi].dsurf_lNextPlane
mov ulBytesPerDstPlane,eax
mov eax,[esi].yTop ;top scan of copy
imul eax,[edi].dsurf_lNextScan ;offset of starting scan line
mov edx,[esi].xLeft ;left dest X coordinate
add edx,31 ;round up to dword
and edx,not 31
shr edx,3 ;left dest byte offset in row
add eax,edx ;initial offset in dest bitmap
add eax,[edi].dsurf_pvBitmapStart ;initial dest bitmap address
mov pDst,eax ;remember where to start drawing
;-----------------------------------------------------------------------;
; At this point, EDI = pdsurfDst
;-----------------------------------------------------------------------;
; Calculate the # of scans to do
mov ebx,[esi].yBottom ;bottom of destination rectangle
sub ebx,[esi].yTop ;# of scans to copy
mov sDfbInfo.BurstCountLeft,ebx
;-----------------------------------------------------------------------;
; Copy to the screen in bursts of BurstCountLeft scans.
;-----------------------------------------------------------------------;
dfbpat_proceed_with_copy::
;-----------------------------------------------------------------------;
; Copy the DFB scans
;-----------------------------------------------------------------------;
dfbpat_plane_0_scan:
lea esi,sDfbInfo ;points to parameters
mov edi,pDst
lea eax,RotatedPat[SIZE_PATTERN*0]
mov ebx,iPatY
call pfnDrawScans
dfbpat_plane_1_scan:
mov eax,ulBytesPerDstPlane
add pDst,eax ;dst scan mod 4 now == 1
lea esi,sDfbInfo ;points to parameters
mov edi,pDst
lea eax,RotatedPat[SIZE_PATTERN*1]
mov ebx,iPatY
call pfnDrawScans
dfbpat_plane_2_scan:
mov eax,ulBytesPerDstPlane
add pDst,eax ;dst scan mod 4 now == 2
lea esi,sDfbInfo ;points to parameters
mov edi,pDst
lea eax,RotatedPat[SIZE_PATTERN*2]
mov ebx,iPatY
call pfnDrawScans
dfbpat_plane_3_scan:
mov eax,ulBytesPerDstPlane
add pDst,eax ;dst scan mod 4 now == 3
lea esi,sDfbInfo ;points to parameters
mov edi,pDst
lea eax,RotatedPat[SIZE_PATTERN*3]
mov ebx,iPatY
call pfnDrawScans
add prclDst,(size RECTL) ;point to the next rectangle, if there is one
dec cRect
jnz dfbpat_outer_loop
dfbpat_exit:
cRet vClrPatDFB ;done!
endProc vClrPatDFB
;-----------------------------------------------------------------------;
; Fill n scans, no leading partial, no trailing partial
;
; esi->BurstCountLeft: # scans to do
; esi->DstWidth: # whole words
; esi->DstDelta: distance from end of one dst line to start of next
;
; registers used *esi: ptr to structure of parameters
; *edi: pDst
; *eax: ulColor
; ebx: index into pattern
; ecx: esi->DstWidth (temp "disposable" copy)
;-----------------------------------------------------------------------;
patfill_dfb_scan_00 proc near
local pattern:dword
local temp_count:dword
mov ecx,[esi].BurstCountLeft
mov temp_count,ecx
mov pattern,eax
@@: ; burst loop (do each scan)
mov eax,pattern
mov cl,[eax+ebx] ;get pattern byte
inc ebx ;increment to next scan's pattern
and ebx,SIZE_PATTERN-1
mov al,cl ;copy cl to all 4 bytes of eax
mov ah,cl
ror eax,16
mov al,cl
mov ah,cl
; main loop
mov ecx,[esi].DstWidth ;load DstWidth (will get trashed)
rep stosd ;copy DWORDs (destroy CX)
; set up for next scan
add edi,[esi].DstDelta ;inc to next scan
dec temp_count ;dec BurstCountLeft
jg @B ;if any left, loop
ret ;bye
patfill_dfb_scan_00 endp
;-----------------------------------------------------------------------;
; Fill n scans, 0 leading partial, 1 trailing partial
;
; esi->BurstCountLeft: # scans to do
; esi->DstWidth: # whole words
; esi->DstDelta: distance from end of one dst line to start of next
;
; registers used *esi: ptr to structure of parameters
; *edi: pDst
; *eax: ulColor
; ebx: index into pattern
; ecx: esi->DstWidth (temp "disposable" copy)
; edx: saved bits for leading/trailing
;-----------------------------------------------------------------------;
patfill_dfb_scan_01 proc near
local pattern:dword
local temp_count:dword
mov ecx,[esi].BurstCountLeft
mov temp_count,ecx
mov pattern,eax
@@: ; burst loop (do each scan)
mov eax,pattern
mov cl,[eax+ebx] ;get pattern byte
inc ebx ;increment to next scan's pattern
and ebx,SIZE_PATTERN-1
mov al,cl ;copy cl to all 4 bytes of eax
mov ah,cl
ror eax,16
mov al,cl
mov ah,cl
; main loop
mov ecx,[esi].DstWidth ;load DstWidth (will get trashed)
rep stosd ;copy DWORDs (destroy CX)
; trailing partial dword
push eax ;save color for main loop
mov edx,[edi] ;get leading dst dword
and edx,[esi].NotRightMask ;remove bits that will be filled
and eax,[esi].RightMask ;remove bits that won't be filled
or edx,eax ;combine dwords
mov [edi],edx ;write leading dword
pop eax ;restore color for main loop
; set up for next scan
add edi,[esi].DstDelta ;inc to next scan
dec temp_count ;dec BurstCountLeft
jg @B ;if any left, loop
ret ;bye
patfill_dfb_scan_01 endp
;-----------------------------------------------------------------------;
; Fill n scans, 1 leading partial, 0 trailing partial
;
; esi->BurstCountLeft: # scans to do
; esi->DstWidth: # whole words
; esi->DstDelta: distance from end of one dst line to start of next
;
; registers used *esi: ptr to structure of parameters
; *edi: pDst
; *eax: ulColor
; ebx: index into pattern
; ecx: esi->DstWidth (temp "disposable" copy)
; edx: saved bits for leading/trailing
;-----------------------------------------------------------------------;
patfill_dfb_scan_10 proc near
local pattern:dword
local temp_count:dword
mov ecx,[esi].BurstCountLeft
mov temp_count,ecx
mov pattern,eax
@@: ; burst loop (do each scan)
mov eax,pattern
mov cl,[eax+ebx] ;get pattern byte
inc ebx ;increment to next scan's pattern
and ebx,SIZE_PATTERN-1
mov al,cl ;copy cl to all 4 bytes of eax
mov ah,cl
ror eax,16
mov al,cl
mov ah,cl
; leading partial dword
push eax ;save color for main loop
mov edx,[edi-4] ;get leading dst dword
and edx,[esi].NotLeftMask ;remove bits that will be filled
and eax,[esi].LeftMask ;remove bits that won't be filled
or edx,eax ;combine dwords
mov [edi-4],edx ;write leading dword
pop eax ;restore color for main loop
; main loop
mov ecx,[esi].DstWidth ;load DstWidth (will get trashed)
rep stosd ;copy DWORDs (destroy CX)
; set up for next scan
add edi,[esi].DstDelta ;inc to next scan
dec temp_count ;dec BurstCountLeft
jg @B ;if any left, loop
ret ;bye
patfill_dfb_scan_10 endp
;-----------------------------------------------------------------------;
; Fill n scans, 1 leading partial, 1 trailing partial
;
; esi->BurstCountLeft: # scans to do
; esi->DstWidth: # whole words
; esi->DstDelta: distance from end of one dst line to start of next
;
; registers used *esi: ptr to structure of parameters
; *edi: pDst
; *eax: ulColor
; ebx: index into pattern
; ecx: esi->DstWidth (temp "disposable" copy)
; edx: saved bits for leading/trailing
;-----------------------------------------------------------------------;
patfill_dfb_scan_11 proc near
local pattern:dword
local temp_count:dword
mov ecx,[esi].BurstCountLeft
mov temp_count,ecx
mov pattern,eax
@@: ; burst loop (do each scan)
mov eax,pattern
mov cl,[eax+ebx] ;get pattern byte
inc ebx ;increment to next scan's pattern
and ebx,SIZE_PATTERN-1
mov al,cl ;copy cl to all 4 bytes of eax
mov ah,cl
ror eax,16
mov al,cl
mov ah,cl
; leading partial dword
push eax ;save color for main loop
mov edx,[edi-4] ;get leading dst dword
and edx,[esi].NotLeftMask ;remove bits that will be filled
and eax,[esi].LeftMask ;remove bits that won't be filled
or edx,eax ;combine dwords
mov [edi-4],edx ;write leading dword
pop eax ;restore color for main loop
; main loop
mov ecx,[esi].DstWidth ;load DstWidth (will get trashed)
rep stosd ;copy DWORDs (destroy CX)
; trailing partial dword
push eax ;save color for main loop
mov edx,[edi] ;get leading dst dword
and edx,[esi].NotRightMask ;remove bits that will be filled
and eax,[esi].RightMask ;remove bits that won't be filled
or edx,eax ;combine dwords
mov [edi],edx ;write leading dword
pop eax ;restore color for main loop
; set up for next scan
add edi,[esi].DstDelta ;inc to next scan
dec temp_count ;dec BurstCountLeft
jg @B ;if any left, loop
ret ;bye
patfill_dfb_scan_11 endp
public patfill_dfb_scan_00
public patfill_dfb_scan_01
public patfill_dfb_scan_10
public patfill_dfb_scan_11
public dfbpat_detect_partials
public dfbpat_one_partial_only
public dfbpat_check_whole_dwords
public dfbpat_set_copy_control_flags
public dfbpat_proceed_with_copy
_TEXT$01 ends
end