|
|
;---------------------------Module-Header------------------------------; ; Module Name: scroll.asm ; ; Copyright (c) 1992-1993 Microsoft Corporation ;-----------------------------------------------------------------------;
;-----------------------------------------------------------------------; ; VOID vPlanarCopyBits(ppdev, prclDest, pptlSrc); ; ; Input: ; ; ppdev - surface on which to copy ; prcldest - pointer to destination rectangle ; pptlsrc - pointer to source upper left corner ; ; Performs accelerated SRCCOPY screen-to-screen blts. ; ;-----------------------------------------------------------------------; ; ; NOTE: This handles only quad-pixel aligned blits! ; ; NOTE: Assumes all rectangles have positive heights and widths. Will ; not work properly if this is not the case. ; ;-----------------------------------------------------------------------;
;-----------------------------------------------------------------------; ; Set LOOP_UNROLL_SHIFT to the log2 of the number of times you want loops in ; this module unrolled. For example, LOOP_UNROLL_SHIFT of 3 yields 2**3 = 8 ; times unrolling. This is the only thing you need to change to control ; unrolling.
LOOP_UNROLL_SHIFT equ 1
;-----------------------------------------------------------------------;
.386
.model small,c
assume cs:FLAT,ds:FLAT,es:FLAT,ss:FLAT assume fs:nothing,gs:nothing
.xlist include stdcall.inc ;calling convention cmacros include i386\strucs.inc include i386\driver.inc include i386\unroll.inc include i386\egavga.inc
.list
;-----------------------------------------------------------------------;
.code
EXTRNP bPuntScreenToScreenCopyBits,20
.data
; Bits for block copier tables:
BLOCK_RIGHT_TO_LEFT equ 4 BLOCK_LEFT_EDGE equ 2 BLOCK_RIGHT_EDGE equ 1
;-----------------------------------------------------------------------; ; Table of block copiers for various horizontal directions, with the ; look-up index a 3-bit field as follows: ; ; Bit 2 (BLOCK_RIGHT_TO_LEFT) = 1 if right-to-left copy ; Bit 1 (BLOCK_LEFT_EDGE) = 1 if left edge must be copied ; Bit 0 (BLOCK_RIGHT_EDGE) = 1 if right edge must be copied
align 4 MasterBlockTable label dword
dd copy_just_middle_block dd Block_WR dd Block_LW dd Block_LWR
dd copy_just_middle_block dd Block_RW dd Block_WL dd Block_RWL
align 4 TopToBottomLoopTable label dword dd 0 ;Not used - unbanked case dd top_to_bottom_1RW dd top_to_bottom_2RW dd top_to_bottom_2RW
align 4 BottomToTopLoopTable label dword dd 0 ;Not used - unbanked case dd bottom_to_top_1RW dd bottom_to_top_2RW dd bottom_to_top_2RW
align 4 SetUpForCopyDirection label dword dd left_to_right_top_to_bottom ;CD_RIGHTDOWN dd right_to_left_top_to_bottom ;CD_LEFTDOWN dd left_to_right_bottom_to_top ;CD_RIGHTUP dd right_to_left_bottom_to_top ;CD_LEFTUP
LeftMaskTable label dword dd 01111b dd 01100b
RightMaskTable label dword dd 00000b dd 00011b
;-----------------------------------------------------------------------;
.code
Block_WR: push offset copy_right_block jmp copy_middle_block
Block_LW: push offset copy_middle_block jmp copy_left_block
Block_LWR: push offset copy_right_block push offset copy_middle_block jmp copy_left_block
Block_RW: push offset copy_middle_block jmp copy_right_block
Block_WL: push offset copy_left_block jmp copy_middle_block
Block_RWL: push offset copy_left_block push offset copy_middle_block jmp copy_right_block
;-----------------------------------------------------------------------;
cProc vPlanarCopyBits,12,< \ uses esi edi ebx, \ ppdev: ptr PDEV, \ prclDest: ptr RECTL, \ pptlSrc: ptr POINTL >
; Variables used in block copiers:
local pfnCopyBlocks: ptr ;pointer to block copy routines
local ulMiddleSrc: dword ;bitmap offset to 1st source local ulMiddleDest: dword ;bitmap offset to 1st dest local lMiddleDelta: dword ;delta from end of middle scan to next local ulBlockHeight: dword ;number of scans to be copied in block local cjMiddle: dword ;number of bytes to be copied on scan
local ulLeftSrc: dword ;bitmap offset to left source byte edge local ulLeftDest: dword ;bitmap offset to left dest byte edge local ulRightSrc: dword ;bitmap offset to right source byte edge local ulRightDest: dword ;bitmap offset to right dest byte edge local lDelta: dword ;delta between scans
local ulLeftMask: dword ;byte mask for left-edge copies local ulRightMask: dword ;byte mask for right-edge copies
local rclDest[size RECTL]: byte ;left and right values always valid local ptlSrc[size POINTL]: byte ;x value always valid
local ulCurrentSrcScan: dword ;real current source scan local ulCurrentDestScan: dword ;real current destination scan local ulLastDestScan: dword ;last destination scan
; Set the bit mask to disable all bits, so we can copy through the latches:
mov edx,VGA_BASE + GRAF_ADDR mov eax,(0 shl 8) + GRAF_BIT_MASK out dx,ax
; Figure out which direction to do the copies:
mov esi,pptlSrc mov edi,prclDest mov eax,[esi].ptl_y cmp eax,[edi].yTop jl planar_bottom_to_top
mov eax,[esi].ptl_x cmp eax,[edi].xLeft jge short left_to_right_top_to_bottom ; CD_RIGHTDOWN jmp right_to_left_top_to_bottom ; CD_LEFTDOWN
planar_bottom_to_top: mov eax,[esi].ptl_x cmp eax,[edi].xLeft jge left_to_right_bottom_to_top ; CD_RIGHTUP jmp right_to_left_bottom_to_top ; CD_LEFTUP
all_done:
; Enable bit mask for all bits:
mov edx,VGA_BASE + GRAF_ADDR mov eax,(0ffh shl 8) + GRAF_BIT_MASK out dx,ax
; Enable writes to all planes and reset direction flag:
mov edx,VGA_BASE + SEQ_DATA mov al,MM_ALL out dx,al
cld
cRet vPlanarCopyBits
;=======================================================================; ;==================== Direction Dependent Setup ========================; ;=======================================================================;
;-----------------------------------------------------------------------; ; Set-up code for left-to-right, top-to-bottom copies. ; ; Input: ; esi - pptlSrc ; edi - prclDest ;-----------------------------------------------------------------------;
public left_to_right_top_to_bottom left_to_right_top_to_bottom::
; Need to set-up: ulMiddleSrc, ulMiddleDest, lMiddleDelta, cjMiddle ; ulLeftSrc, ulLeftDest, ulLeftMask ; lDelta ; ulRightSrc, ulRightDest, ulRightMask ; ulCurrentDestScan, ulLastDestScan ; pfnCopyBlocks ; ptlSrc.x, rclDest.left, rclDest.right
; lDelta = ppdev->lPlanarScan ; ulCurrentSrcScan = pptl->y ; ulLeftSrc = pptl->y * lDelta + (pptl->x >> 1) ; ulCurrentDestScan = prclDest->top ; ulLeftDest = prclDest->top * lDelta + (prclDest->left >> 1) ; ; ulMiddleSrc = ulLeftSrc ; ulMiddleDest = ulLeftDest ; ; cjMiddle = (prclDest->right >> 1) - (prclDest->left >> 1) ; if (prclDest->left & 3) ; ulLeftMask = LeftMaskTable[prclDest->left & 1] ; fl |= BLOCK_LEFT_EDGE ; ulMiddleSrc++ ; ulMiddleDest++ ; cjMiddle-- ; ; lMiddleDelta = lDelta - cjMiddle ; ; if (prclDest->right & 1) ; ulRightMask = RightMaskTable[prclDest->right & 1] ; fl |= BLOCK_RIGHT_EDGE ; ulRightSrc = ulMiddleSrc + cjMiddle ; ulRightDest = ulMiddleDest + cjMiddle
mov edx,ppdev mov eax,[edi].yBottom mov edx,[edx].pdev_lPlanarNextScan ;edx = lDelta mov ulLastDestScan,eax ;ulLastDestScan = prclDest->bottom
mov ecx,[esi].ptl_y mov eax,edx mov ulCurrentSrcScan,ecx ;ulCurrentSrcScan = pptlSrc->y imul eax,ecx mov ecx,[esi].ptl_x mov ptlSrc.ptl_x,ecx ;ptlSrc.x = pptlSrc->x shr ecx,1 add eax,ecx ;eax = ulLeftSrc = pptlSrc->y * ; lDelta + (pptlSrc->x >> 1)
xor esi,esi ;initialize flags
mov ecx,[edi].yTop mov ebx,edx mov ulCurrentDestScan,ecx ;ulCurrentDestScan = prclDest->top imul ebx,ecx mov ecx,[edi].xLeft mov rclDest.xLeft,ecx ;rclDest.left = prclDest->left shr ecx,1 add ebx,ecx ;ebx = ulLeftDest = prclDest->top * ; lDelta + (prclDest->left >> 1)
mov edi,[edi].xRight mov rclDest.xRight,edi shr edi,1 sub edi,ecx ;cjMiddle = (prclDest->right >> 1) - ; (prclDest->left >> 1)
mov ecx,rclDest.xLeft and ecx,1 jz short l_t_done_left_edge ;skip if we don't need a left edge
or esi,BLOCK_LEFT_EDGE mov ecx,LeftMaskTable[ecx*4] mov ulLeftMask,ecx ;ulLeftMask = ; LeftMaskTable[prclDest->left & 1]
mov ulLeftSrc,eax ;ulLeftSrc mov ulLeftDest,ebx ;ulLeftDest inc eax inc ebx dec edi
l_t_done_left_edge: mov ulMiddleSrc,eax ;ulMiddleSrc mov ulMiddleDest,ebx ;ulMiddleDest
mov ecx,rclDest.xRight and ecx,1 jz short l_t_done_right_edge ;skip if we don't need a right edge
or esi,BLOCK_RIGHT_EDGE mov ecx,RightMaskTable[ecx*4] mov ulRightMask,ecx ;ulRightMask = ; RightMaskTable[prclDest->right & 1]
add eax,edi add ebx,edi mov ulRightSrc,eax ;ulRightSrc = ulMiddleSrc + cjMiddle mov ulRightDest,ebx ;ulRightDest = ulMiddleDest + cjMiddle
; We special case here blits that are less than 2 pels wide and begin and end ; in the same 4-pel quadruple:
cmp edi,0 jge l_t_done_right_edge
; We make sure the 'middle' count of bytes is zero (we'll just let the code ; fall through the 'middle' copy code), turn off the right-edge flag, and ; give ulLeftMask the composite mask:
inc edi xor esi,BLOCK_RIGHT_EDGE and ecx,ulLeftMask mov ulLeftMask,ecx
l_t_done_right_edge: mov cjMiddle,edi ;cjMiddle
mov lDelta,edx ;lDelta = ppdev->lPlanarNextScan sub edx,edi mov lMiddleDelta,edx ;lMiddleDelta = lDelta - cjMiddle
mov ebx,ppdev mov eax,MasterBlockTable[esi*4] mov pfnCopyBlocks,eax ;copy blocks between video memory
; Branch to the appropriate top-to-bottom bank enumeration loop:
mov eax,[ebx].pdev_vbtPlanarType jmp TopToBottomLoopTable[eax*4]
;-----------------------------------------------------------------------; ; Set-up code for right-to-left, top-to-bottom copies. ; ; Input: ; esi - pptlSrc ; edi - prclDest ;-----------------------------------------------------------------------;
public right_to_left_top_to_bottom right_to_left_top_to_bottom::
std ;copy middle blocks right-to-left
mov edx,ppdev mov eax,[edi].yBottom mov edx,[edx].pdev_lPlanarNextScan ;edx = lDelta mov ulLastDestScan,eax ;ulLastDestScan = prclDest->bottom
mov ecx,[esi].ptl_y mov eax,edx mov ulCurrentSrcScan,ecx ;ulCurrentSrcScan = pptlSrc->y imul eax,ecx mov ecx,[esi].ptl_x mov ptlSrc.ptl_x,ecx ;ptlSrc.x = pptlSrc->x add ecx,[edi].xRight sub ecx,[edi].xLeft shr ecx,1 add eax,ecx ;eax = ulRightSrc = pptlSrc->y * ; lDelta + (pptlSrc->x + ; prclDest->right - prclDest->left) / 2
mov esi,BLOCK_RIGHT_TO_LEFT ;initialize flags
mov ecx,[edi].yTop mov ebx,edx mov ulCurrentDestScan,ecx ;ulCurrentDestScan = prclDest->top imul ebx,ecx mov ecx,[edi].xRight mov rclDest.xRight,ecx ;rclDest.right = prclDest->right shr ecx,1 add ebx,ecx ;ebx = ulRightDest = prclDest->top * ; lDelta + prclDest->right / 2
mov edi,[edi].xLeft mov rclDest.xLeft,edi shr edi,1 neg edi add edi,ecx ;cjMiddle = prclDest->right / 2 - ; prclDest->left / 2
mov ecx,rclDest.xRight and ecx,1 jz short r_t_done_right_edge ;skip if we don't need a right edge
or esi,BLOCK_RIGHT_EDGE mov ecx,RightMaskTable[ecx*4] mov ulRightMask,ecx ;ulRightMask = ; RightMaskTable[prclDest->right & 1]
mov ulRightSrc,eax ;ulRightSrc mov ulRightDest,ebx ;ulRightDest
r_t_done_right_edge: dec eax dec ebx mov ulMiddleSrc,eax ;ulMiddleSrc mov ulMiddleDest,ebx ;ulMiddleDest
mov ecx,rclDest.xLeft and ecx,1 jz short r_t_done_left_edge ;skip if we don't need a right edge or esi,BLOCK_LEFT_EDGE mov ecx,LeftMaskTable[ecx*4] mov ulLeftMask,ecx ;ulLeftMask = ; LeftMaskTable[prclDest->left & 1]
dec edi ;adjust middle block length because ; we're effectively doing one less ; middle byte
sub eax,edi sub ebx,edi mov ulLeftSrc,eax ;ulLeftSrc = ulMiddleSrc - cjMiddle mov ulLeftDest,ebx ;ulLeftDest = ulMiddleDest - cjMiddle
; We special case here blits that are less than 2 pels wide and begin and end ; in the same 4-pel quadruple:
cmp edi,0 jge r_t_done_left_edge
; We make sure the 'middle' count of bytes is zero (we'll just let the code ; fall through the 'middle' copy code), turn off the right-edge flag, and ; give ulRightMask the composite mask:
inc edi xor esi,BLOCK_LEFT_EDGE and ecx,ulRightMask mov ulRightMask,ecx
r_t_done_left_edge: mov cjMiddle,edi ;cjMiddle
mov lDelta,edx ;lDelta = ppdev->lPlanarNextScan add edx,edi mov lMiddleDelta,edx ;lMiddleDelta = lDelta + cjMiddle
mov ebx,ppdev mov eax,MasterBlockTable[esi*4] mov pfnCopyBlocks,eax ;copy blocks between video memory
; Branch to the appropriate top-to-bottom bank enumeration loop:
mov eax,[ebx].pdev_vbtPlanarType jmp TopToBottomLoopTable[eax*4]
;-----------------------------------------------------------------------; ; Set-up code for left-to-right, bottom-to-top copies. ; ; Input: ; esi - pptlSrc ; edi - prclDest ;-----------------------------------------------------------------------;
public left_to_right_bottom_to_top left_to_right_bottom_to_top::
mov edx,ppdev mov eax,[edi].yTop mov edx,[edx].pdev_lPlanarNextScan ;edx = lDelta mov ulLastDestScan,eax ;ulLastDestScan = prclDest->top
mov ecx,[esi].ptl_y add ecx,[edi].yBottom sub ecx,[edi].yTop mov eax,edx mov ulCurrentSrcScan,ecx ;ulCurrentSrcScan = pptlSrc->y + ; (prclDest->bottom - prclDest->top) dec ecx imul eax,ecx mov ecx,[esi].ptl_x mov ptlSrc.ptl_x,ecx ;ptlSrc.x = pptlSrc->x shr ecx,1 add eax,ecx ;eax = ulLeftSrc = (ulCurrentSrcScan - 1) ; * lDelta + (pptlSrc->x >> 1)
xor esi,esi ;initialize flags
mov ecx,[edi].yBottom mov ebx,edx mov ulCurrentDestScan,ecx ;ulCurrentDestScan = prclDest->bottom dec ecx imul ebx,ecx mov ecx,[edi].xLeft mov rclDest.xLeft,ecx ;rclDest.left = prclDest->left shr ecx,1 add ebx,ecx ;ebx = ulLeftDest = (prclDest->bottom - 1) ; * lDelta + (prclDest->left >> 1)
mov edi,[edi].xRight mov rclDest.xRight,edi shr edi,1 sub edi,ecx ;cjMiddle = (prclDest->right >> 1) - ; (prclDest->left >> 1)
mov ecx,rclDest.xLeft and ecx,1 jz short l_b_done_left_edge ;skip if we don't need a left edge
or esi,BLOCK_LEFT_EDGE mov ecx,LeftMaskTable[ecx*4] mov ulLeftMask,ecx ;ulLeftMask = ; LeftMaskTable[prclDest->left & 3]
mov ulLeftSrc,eax ;ulLeftSrc mov ulLeftDest,ebx ;ulLeftDest inc eax inc ebx dec edi
l_b_done_left_edge: mov ulMiddleSrc,eax ;ulMiddleSrc mov ulMiddleDest,ebx ;ulMiddleDest
mov ecx,rclDest.xRight and ecx,1 jz short l_b_done_right_edge ;skip if we don't need a right edge
or esi,BLOCK_RIGHT_EDGE mov ecx,RightMaskTable[ecx*4] mov ulRightMask,ecx ;ulRightMask = ; RightMaskTable[prclDest->right & 1]
add eax,edi add ebx,edi mov ulRightSrc,eax ;ulRightSrc = ulMiddleSrc + cjMiddle mov ulRightDest,ebx ;ulRightDest = ulMiddleDest + cjMiddle
; We special case here blits that are less than 2 pels wide and begin and end ; in the same 4-pel quadruple:
cmp edi,0 jge l_b_done_right_edge
; We make sure the 'middle' count of bytes is zero (we'll just let the code ; fall through the 'middle' copy code), turn off the right-edge flag, and ; give ulLeftMask the composite mask:
inc edi xor esi,BLOCK_RIGHT_EDGE and ecx,ulLeftMask mov ulLeftMask,ecx
l_b_done_right_edge: mov cjMiddle,edi ;cjMiddle
neg edx mov lDelta,edx ;lDelta = -ppdev->lPlanarNextScan sub edx,edi mov lMiddleDelta,edx ;lMiddleDelta = lDelta - cjMiddle
mov ebx,ppdev mov eax,MasterBlockTable[esi*4] mov pfnCopyBlocks,eax ;copy blocks between video memory
; Branch to the appropriate top-to-bottom bank enumeration loop:
mov eax,[ebx].pdev_vbtPlanarType jmp BottomToTopLoopTable[eax*4]
;-----------------------------------------------------------------------; ; Set-up code for right-to-left, bottom-to-top copies. ; ; Input: ; esi - pptlSrc ; edi - prclDest ;-----------------------------------------------------------------------;
public right_to_left_bottom_to_top right_to_left_bottom_to_top::
std ;copy middle blocks right-to-left
mov edx,ppdev mov eax,[edi].yTop mov edx,[edx].pdev_lPlanarNextScan ;edx = lDelta mov ulLastDestScan,eax ;ulLastDestScan = prclDest->top
mov ecx,[esi].ptl_y add ecx,[edi].yBottom sub ecx,[edi].yTop mov eax,edx mov ulCurrentSrcScan,ecx ;ulCurrentSrcScan = pptlSrc->y + ; (prclDest->bottom - prclDest->top) dec ecx imul eax,ecx mov ecx,[esi].ptl_x mov ptlSrc.ptl_x,ecx ;ptlSrc.x = pptlSrc->x add ecx,[edi].xRight sub ecx,[edi].xLeft shr ecx,1 add eax,ecx ;eax = ulRightSrc = (ulCurrentSrcScan ; - 1) * lDelta + (pptlSrc->x + ; prclDest->right - prclDest->left) / 2
mov esi,BLOCK_RIGHT_TO_LEFT ;initialize flags
mov ecx,[edi].yBottom mov ebx,edx mov ulCurrentDestScan,ecx ;ulCurrentDestScan = prclDest->bottom dec ecx imul ebx,ecx mov ecx,[edi].xRight mov rclDest.xRight,ecx ;rclDest.right = prclDest->right shr ecx,1 add ebx,ecx ;ebx = ulRightDest = (ulCurrentDestScan ; - 1) * lDelta + prclDest->right / 2
mov edi,[edi].xLeft mov rclDest.xLeft,edi shr edi,1 neg edi add edi,ecx ;cjMiddle = prclDest->right / 2 - ; prclDest->left / 2
mov ecx,rclDest.xRight and ecx,1 jz short r_b_done_right_edge ;skip if we don't need a right edge
or esi,BLOCK_RIGHT_EDGE mov ecx,RightMaskTable[ecx*4] mov ulRightMask,ecx ;ulRightMask = ; RightMaskTable[prclDest->right & 1]
mov ulRightSrc,eax ;ulRightSrc mov ulRightDest,ebx ;ulRightDest
r_b_done_right_edge: dec eax dec ebx mov ulMiddleSrc,eax ;ulMiddleSrc mov ulMiddleDest,ebx ;ulMiddleDest
mov ecx,rclDest.xLeft and ecx,1 jz short r_b_done_left_edge ;skip if we don't need a right edge
or esi,BLOCK_LEFT_EDGE mov ecx,LeftMaskTable[ecx*4] mov ulLeftMask,ecx ;ulLeftMask = ; LeftMaskTable[prclDest->left & 1]
dec edi ;adjust middle block length because ; we're effectively doing one less ; middle byte
sub eax,edi sub ebx,edi mov ulLeftSrc,eax ;ulLeftSrc = ulMiddleSrc - cjMiddle mov ulLeftDest,ebx ;ulLeftDest = ulMiddleDest - cjMiddle
; We special case here blits that are less than 2 pels wide and begin and end ; in the same 4-pel quadruple:
cmp edi,0 jge r_b_done_left_edge
; We make sure the 'middle' count of bytes is zero (we'll just let the code ; fall through the 'middle' copy code), turn off the right-edge flag, and ; give ulRightMask the composite mask:
inc edi xor esi,BLOCK_LEFT_EDGE and ecx,ulRightMask mov ulRightMask,ecx
r_b_done_left_edge: mov cjMiddle,edi ;cjMiddle
neg edx mov lDelta,edx ;lDelta = -ppdev->lPlanarNextScan add edx,edi mov lMiddleDelta,edx ;lMiddleDelta = lDelta + cjMiddle
mov ebx,ppdev mov eax,MasterBlockTable[esi*4] mov pfnCopyBlocks,eax ;copy blocks between video memory
; Branch to the appropriate top-to-bottom bank enumeration loop:
mov eax,[ebx].pdev_vbtPlanarType jmp BottomToTopLoopTable[eax*4]
;=======================================================================; ;============================= Banking =================================; ;=======================================================================;
;-----------------------------------------------------------------------; ; Banking for 1 R/W adapters, top to bottom. ; ; Input: ; ulCurrentSrcScan ; ulCurrentDestScan ; ulLastDestScan ; Plus some other stuff for split rasters and block copiers ;-----------------------------------------------------------------------; public top_to_bottom_1RW top_to_bottom_1RW::
; LATER: Should check to see if there's any chance that the source and ; destination overlap in the same window, so that we can use planar ; copies -- otherwise, it's faster to directly call of to ; bPuntScreenToScreenCopyBits
; We're going top to bottom. Map in the source and dest, top-justified.
mov ebx,ppdev mov edi,ulCurrentDestScan
cmp edi,[ebx].pdev_rcl1PlanarClip.yTop jl short top_1RW_map_init_bank
cmp edi,[ebx].pdev_rcl1PlanarClip.yBottom jl short top_1RW_init_bank_mapped
top_1RW_map_init_bank:
; Map bank containing the top destination scan line into window. ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
ptrCall <dword ptr [ebx].pdev_pfnPlanarControl>, \ <ebx,edi,JustifyTop>
top_1RW_init_bank_mapped:
mov eax,ulCurrentSrcScan cmp eax,[ebx].pdev_rcl1PlanarClip.yBottom
jl short top_1RW_do_planar_copy
; ulCurrentSrcScan >= ppdev->rcl1PlanarClip.bottom, which means that ; the window can't overlap the source and destination at all. We'll ; have to use an intermediate temporary buffer:
; ebx = ppdev ; eax = ulCurrentSrcScan ; edi = ulCurrentDestScan
mov ptlSrc.ptl_y,eax ;ptlSrc.y = ulCurrentSrcScan mov rclDest.yTop,edi ;rclDest.top = ulCurrentDestScan
mov esi,[ebx].pdev_rcl1PlanarClip.yBottom mov eax,ulLastDestScan sub eax,esi sbb ecx,ecx and ecx,eax add esi,ecx mov rclDest.yBottom,esi ;rclDest.bottom = min(ulLastDestScan, ; ppdev->pdev_rcl1PlanarClip.bottom)
; Enable bit mask for all bits:
mov edx,VGA_BASE + GRAF_ADDR mov eax,(0ffh shl 8) + GRAF_BIT_MASK out dx,ax
; Enable writes to all planes and reset direction flag:
mov edx,VGA_BASE + SEQ_DATA mov al,MM_ALL out dx,al
pushfd cld
; Call our routine that copies bits the slow way, preserving EBX, ESI and EDI ; according to C calling conventions:
lea ecx,rclDest lea edx,ptlSrc
cCall bPuntScreenToScreenCopyBits,<ebx,0,0,ecx,edx>
popfd
; Set the bit mask to disable all bits, so we can copy through latches again:
mov edx,VGA_BASE + GRAF_ADDR mov eax,(000h shl 8) + GRAF_BIT_MASK out dx,ax
; Update our position variables:
mov ulCurrentDestScan,esi ;ulCurrentDestScan = rclDest.bottom
sub esi,edi ;ulBlockHeight = rclDest.bottom - ; rclDest.top
add ulCurrentSrcScan,esi ;ulCurrentSrcScan += ulBlockHeight
; We have to adjust the offsets for all our block copiers, according to the ; number of scans we copied:
mov edx,lDelta imul edx,esi ;edx = lDelta * ulBlockHeight add ulLeftSrc,edx add ulLeftDest,edx add ulMiddleSrc,edx add ulMiddleDest,edx add ulRightSrc,edx add ulRightDest,edx
jmp short top_1RW_see_if_done
top_1RW_do_planar_copy:
; ebx = ppdev ; eax = ulCurrentSrcScan ; edi = ulCurrentDestScan
mov ebx,[ebx].pdev_rcl1PlanarClip.yBottom sub ebx,eax ;ebx = ppdev->rcl1PlanarClip.bottom - ; ulCurrentSrcScan ;ebx is the available number of scans ; we have in the source
mov edx,ulLastDestScan sub edx,edi ;edx = ulLastDestScan - ulCurrentDestScan ;edx is the available number of scans ; in the destination
; (Because the source starts lower in the window than the destination, ; the bottom of the bank always limits the source number of scans before ; it does the destination.)
sub ebx,edx sbb ecx,ecx and ecx,ebx add edx,ecx ;edx = min(source available, ; destination available) mov ulBlockHeight,edx
add eax,edx ;We have to adjust our current scans add edi,edx mov ulCurrentSrcScan,eax mov ulCurrentDestScan,edi
; Now copy the puppy:
call pfnCopyBlocks
; See if we're done:
top_1RW_see_if_done: mov edi,ulCurrentDestScan cmp edi,ulLastDestScan jge all_done
mov ebx,ppdev
; Map bank containing the top destination scan line into window. ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
ptrCall <dword ptr [ebx].pdev_pfnPlanarControl>, \ <ebx,edi,JustifyTop>
jmp top_1RW_init_bank_mapped
;-----------------------------------------------------------------------; ; Banking for 1 R/W adapters, bottom to top. ; ; Input: ; ulCurrentSrcScan - Actually, 1 more current source scan ; ulCurrentDestScan - Actually, 1 more current destination scan ; ulLastDestScan ; Plus some other stuff for split rasters and block copiers ;-----------------------------------------------------------------------; public bottom_to_top_1RW bottom_to_top_1RW::
; We're going top to bottom. Map in the source and dest, top-justified.
mov ebx,ppdev mov edi,ulCurrentDestScan
cmp edi,[ebx].pdev_rcl1PlanarClip.yTop jle short bot_1RW_map_init_bank
cmp edi,[ebx].pdev_rcl1PlanarClip.yBottom jle short bot_1RW_init_bank_mapped
bot_1RW_map_init_bank:
; Map bank containing the top destination scan line into window. ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
dec edi ptrCall <dword ptr [ebx].pdev_pfnPlanarControl>, \ <ebx,edi,JustifyTop> inc edi
bot_1RW_init_bank_mapped:
mov eax,ulCurrentSrcScan cmp eax,[ebx].pdev_rcl1PlanarClip.yTop
jg short bot_1RW_do_planar_copy
; ulCurrentSrcScan <= ppdev->rcl1PlanarClip.top, which means that ; the window can't overlap the source and destination at all. We'll ; have to use an intermediate temporary buffer:
; ebx = ppdev ; eax = ulCurrentSrcScan ; edi = ulCurrentDestScan
mov esi,[ebx].pdev_rcl1PlanarClip.yTop mov edx,ulLastDestScan cmp esi,edx jg @F mov esi,edx @@: mov rclDest.yTop,esi ;rclDest.top = max(ulLastDestScan, ; ppdev->rcl1PlanarClip.top)
mov rclDest.yBottom,edi ;rclDest.bottom = ulCurrentDestScan add eax,esi sub eax,edi mov ptlSrc.ptl_y,eax ;ptlSrc.y = ulCurrentSrcScan - ; (rclDest.bottom - rclDest.top)
; Enable bit mask for all bits:
mov edx,VGA_BASE + GRAF_ADDR mov eax,(0ffh shl 8) + GRAF_BIT_MASK out dx,ax
; Enable writes to all planes and reset direction flag:
mov edx,VGA_BASE + SEQ_DATA mov al,MM_ALL out dx,al
pushfd cld
; Call our routine that copies bits the slow way, preserving EBX, ESI and EDI ; according to C calling conventions:
lea ecx,rclDest lea edx,ptlSrc
cCall bPuntScreenToScreenCopyBits,<ebx,0,0,ecx,edx>
popfd
; Set the bit mask to disable all bits, so we can copy through latches again:
mov edx,VGA_BASE + GRAF_ADDR mov eax,(000h shl 8) + GRAF_BIT_MASK out dx,ax
; Update our position variables:
mov ulCurrentDestScan,esi ;ulCurrentDestScan = rclDest.top
sub edi,esi ;ulBlockHeight = rclDest.bottom - ; rclDest.top
sub ulCurrentSrcScan,edi ;ulCurrentSrcScan -= ulBlockHeight
; We have to adjust the offsets for all our block copiers, according to the ; number of scans we copied:
mov edx,lDelta imul edx,edi ;edx = lDelta * ulBlockHeight add ulLeftSrc,edx add ulLeftDest,edx add ulMiddleSrc,edx add ulMiddleDest,edx add ulRightSrc,edx add ulRightDest,edx
jmp short bot_1RW_see_if_done
bot_1RW_do_planar_copy:
; ebx = ppdev ; eax = ulCurrentSrcScan ; edi = ulCurrentDestScan
sub eax,[ebx].pdev_rcl1PlanarClip.yTop ;eax = ulCurrentSrcScan - ; ppdev->rcl1PlanarClip.top
sub edi,ulLastDestScan ;edi = ulCurrentDestScan - ulLastDestScan ;edi is the available number of scans ; in the destination
; (Because the source starts higher in the window than the destination, ; the bottom of the bank always limits the source number of scans before ; it does the destination.)
sub eax,edi sbb ecx,ecx and ecx,eax add edi,ecx ;edi = min(source available, ; destination available)
mov ulBlockHeight,edi
sub ulCurrentSrcScan,edi ;We have to adjust our current scans sub ulCurrentDestScan,edi
; Now copy the puppy:
call pfnCopyBlocks
; See if we're done:
bot_1RW_see_if_done: mov edi,ulCurrentDestScan cmp edi,ulLastDestScan jle all_done
mov ebx,ppdev
; Map bank containing the top destination scan line into window. ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
dec edi ptrCall <dword ptr [ebx].pdev_pfnPlanarControl>, \ <ebx,edi,JustifyTop> inc edi
jmp bot_1RW_init_bank_mapped
;-----------------------------------------------------------------------; ; Banking for 1R/1W or 2R/W adapters, top to bottom. ; ; Input: ; ulCurrentSrcScan ; ulCurrentDestScan ; ulLastDestScan ; Plus some other stuff for split rasters and block copiers ;-----------------------------------------------------------------------; public top_to_bottom_2RW top_to_bottom_2RW::
; We're going top to bottom. Map in the destination, top-justified.
mov ebx,ppdev mov edi,ulCurrentDestScan mov esi,ulCurrentSrcScan
cmp edi,[ebx].pdev_rcl2PlanarClipD.yTop jl short top_2RW_map_init_dest_bank
cmp edi,[ebx].pdev_rcl2PlanarClipD.yBottom jl short top_2RW_init_dest_bank_mapped
top_2RW_map_init_dest_bank:
; Map bank containing the top destination scan line into window. ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
ptrCall <dword ptr [ebx].pdev_pfnPlanarControl2>, \ <ebx,edi,JustifyTop,MapDestBank>
top_2RW_init_dest_bank_mapped:
cmp esi,[ebx].pdev_rcl2PlanarClipS.yTop jl short top_2RW_map_init_src_bank
cmp esi,[ebx].pdev_rcl2PlanarClipS.yBottom jl short top_2RW_main_loop
top_2RW_map_init_src_bank:
; Map bank containing the top source scan line into window. ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
ptrCall <dword ptr [ebx].pdev_pfnPlanarControl2>, \ <ebx,esi,JustifyTop,MapSourceBank>
top_2RW_main_loop: mov ecx,[ebx].pdev_rcl2PlanarClipD.yBottom mov edx,ulLastDestScan
sub ecx,edx sbb eax,eax and eax,ecx add edx,eax ;edx = min(ulLastDestScan, ; ppdev->rcl2PlanarClipD.bottom)
mov ecx,[ebx].pdev_rcl2PlanarClipS.yBottom
sub edx,edi ;edx = available scans in destination ; bank sub ecx,esi ;ecx = available scans in source bank
sub ecx,edx sbb eax,eax and eax,ecx add edx,eax
mov ulBlockHeight,edx ;ulBlockHeight = min(source available, ; dest available)
add esi,edx ;adjust our currents scans accordingly add edi,edx mov ulCurrentSrcScan,esi mov ulCurrentDestScan,edi
; Do the actual copy:
call pfnCopyBlocks
mov edi,ulCurrentDestScan ;check if done cmp edi,ulLastDestScan jge all_done
mov ebx,ppdev
; We'll have to map a new source bank, destination bank, or both:
mov esi,ulCurrentSrcScan cmp edi,[ebx].pdev_rcl2PlanarClipD.yBottom jl short top_2RW_map_next_src_bank
; Map bank containing the top destination scan line into window. ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
ptrCall <dword ptr [ebx].pdev_pfnPlanarControl2>, \ <ebx,edi,JustifyTop,MapDestBank>
cmp esi,[ebx].pdev_rcl2PlanarClipS.yBottom jl short top_2RW_main_loop
top_2RW_map_next_src_bank:
; Map bank containing the top source scan line into window. ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
ptrCall <dword ptr [ebx].pdev_pfnPlanarControl2>, \ <ebx,esi,JustifyTop,MapSourceBank>
jmp short top_2RW_main_loop
;-----------------------------------------------------------------------; ; Banking for 1R/1W or 2R/W adapters, bottom to top. ; ; Input: ; ulCurrentSrcScan ; ulCurrentDestScan ; ulLastDestScan ; Plus some other stuff for split rasters and block copiers ;-----------------------------------------------------------------------; public bottom_to_top_2RW bottom_to_top_2RW::
; We're going bottom to top. Map in the destination, bottom-justified.
mov ebx,ppdev mov edi,ulCurrentDestScan ; 1 more than actual destination scan mov esi,ulCurrentSrcScan ; 1 more than actual source scan
cmp edi,[ebx].pdev_rcl2PlanarClipD.yTop jle short bot_2RW_map_init_dest_bank
cmp edi,[ebx].pdev_rcl2PlanarClipD.yBottom jle short bot_2RW_init_dest_bank_mapped
bot_2RW_map_init_dest_bank:
; Map bank containing the top destination scan line into window. ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
dec edi ptrCall <dword ptr [ebx].pdev_pfnPlanarControl2>, \ <ebx,edi,JustifyBottom,MapDestBank> inc edi
bot_2RW_init_dest_bank_mapped:
cmp esi,[ebx].pdev_rcl2PlanarClipS.yTop jle short bot_2RW_map_init_src_bank
cmp esi,[ebx].pdev_rcl2PlanarClipS.yBottom jle short bot_2RW_main_loop
bot_2RW_map_init_src_bank:
; Map bank containing the top source scan line into window. ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
dec esi ptrCall <dword ptr [ebx].pdev_pfnPlanarControl2>, \ <ebx,esi,JustifyBottom,MapSourceBank> inc esi
bot_2RW_main_loop: mov ecx,[ebx].pdev_rcl2PlanarClipD.yTop mov edx,ulLastDestScan
cmp edx,ecx jg @F mov edx,ecx ;edx = max(ulLastDestScan, @@: ; ppdev->rcl2PlanarClipD.top)
sub edi,edx ;edi = available scans in destination ; bank sub esi,[ebx].pdev_rcl2PlanarClipS.yTop ;esi = available scans in source bank
sub esi,edi sbb eax,eax and eax,esi add edi,eax
mov ulBlockHeight,edi ;ulBlockHeight = min(source available, ; dest available)
sub ulCurrentSrcScan,edi ;adjust our current scans sub ulCurrentDestScan,edi
; Do the actual copy:
call pfnCopyBlocks
mov edi,ulCurrentDestScan ;check if done cmp edi,ulLastDestScan jle all_done
mov ebx,ppdev
; We'll have to map a new source bank, destination bank, or both:
mov esi,ulCurrentSrcScan cmp edi,[ebx].pdev_rcl2PlanarClipD.yTop jg short bot_2RW_map_next_src_bank
; Map bank containing the top destination scan line into window. ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
dec edi ptrCall <dword ptr [ebx].pdev_pfnPlanarControl2>, \ <ebx,edi,JustifyBottom,MapDestBank> inc edi
cmp esi,[ebx].pdev_rcl2PlanarClipS.yTop jg short bot_2RW_main_loop
bot_2RW_map_next_src_bank:
; Map bank containing the top source scan line into window. ; Note: EBX, ESI, and EDI preserved, according to C calling conventions.
dec esi ptrCall <dword ptr [ebx].pdev_pfnPlanarControl2>, \ <ebx,esi,JustifyBottom,MapSourceBank> inc esi
jmp short bot_2RW_main_loop
;=======================================================================; ;=========================== Block Copiers =============================; ;=======================================================================;
;-----------------------------------------------------------------------; ; Input: ; Direction flag - set to the appropriate direction ; ulMiddleSrc - offset in bitmap to source ; ulMiddleDest - offset in bitmap to destination ; lMiddleDelta - distance from end of current scan to start of next ; ulBlockHeight - # of scans to copy ; cjMiddle - # of planar bytes to copy on every scan ; ; Output: ; Advances ulMiddleSrc and ulMiddleDest to next strip ;-----------------------------------------------------------------------;
public copy_middle_block copy_middle_block::
; We only have to reset which planes are enabled if we do edges too:
mov edx,VGA_BASE + SEQ_DATA mov al,MM_ALL out dx,al
copy_just_middle_block::
; Calculate full start addresses:
mov edi,ppdev mov eax,cjMiddle mov ebx,ulBlockHeight mov edx,lMiddleDelta mov esi,[edi].pdev_pvBitmapStart2WindowS mov edi,[edi].pdev_pvBitmapStart2WindowD add esi,ulMiddleSrc add edi,ulMiddleDest
SET_UP_UNROLL_VARS ebx,ecx,ebx,pfnCopyMiddleEntry, \ LOOP_UNROLL_SHIFT
jmp ecx
UNROLL_LOOP_ENTRY_TABLE pfnCopyMiddleEntry,MIDDLE, \ LOOP_UNROLL_COUNT
COPY_MIDDLE macro ENTRY_LABEL,ENTRY_INDEX &ENTRY_LABEL&ENTRY_INDEX&: mov ecx,eax rep movsb add esi,edx add edi,edx endm ;-----------------------------------;
; EAX = # of bytes to copy ; EBX = count of unrolled loop iterations ; EDX = offset from end of one scan's fill to start of next ; ESI = source address from which to copy ; EDI = target address to which to copy
middle_loop: UNROLL_LOOP COPY_MIDDLE,MIDDLE,LOOP_UNROLL_COUNT dec ebx jnz middle_loop
; get ready for next time:
mov ecx,ppdev sub esi,[ecx].pdev_pvBitmapStart2WindowS sub edi,[ecx].pdev_pvBitmapStart2WindowD mov ulMiddleSrc,esi mov ulMiddleDest,edi
PLAIN_RET
;-----------------------------------------------------------------------; ; Input: ; ulLeftSrc - offset in bitmap to source ; ulLeftDest - offset in bitmap to destination ; lDelta - distance from between planar scans ; ulBlockHeight - # of scans to copy ; ; Output: ; Advances ulLeftSrc and ulLeftDest to next strip ;-----------------------------------------------------------------------;
public copy_left_block copy_left_block::
; Set left mask by disabling some planes:
mov edx,VGA_BASE + SEQ_DATA mov eax,ulLeftMask out dx,al
; Calculate full start addresses:
mov ecx,ppdev mov ebx,ulBlockHeight mov edx,lDelta mov esi,[ecx].pdev_pvBitmapStart2WindowS mov edi,[ecx].pdev_pvBitmapStart2WindowD add esi,ulLeftSrc add edi,ulLeftDest
SET_UP_UNROLL_VARS ebx,eax,ebx,pfnCopyLeftEntry, \ LOOP_UNROLL_SHIFT
jmp eax
UNROLL_LOOP_ENTRY_TABLE pfnCopyLeftEntry,LEFT, \ LOOP_UNROLL_COUNT
COPY_LEFT macro ENTRY_LABEL,ENTRY_INDEX &ENTRY_LABEL&ENTRY_INDEX&: mov al,[esi] mov [edi],al add esi,edx add edi,edx endm ;-----------------------------------;
; EBX = count of unrolled loop iterations ; EDX = offset from one scan to next ; ESI = source address from which to copy ; EDI = target address to which to copy
left_loop: UNROLL_LOOP COPY_LEFT,LEFT,LOOP_UNROLL_COUNT dec ebx jnz left_loop
; get ready for next time:
sub esi,[ecx].pdev_pvBitmapStart2WindowS sub edi,[ecx].pdev_pvBitmapStart2WindowD mov ulLeftSrc,esi mov ulLeftDest,edi
PLAIN_RET
;-----------------------------------------------------------------------; ; Input: ; ulRightSrc - offset in bitmap to source ; ulRightDest - offset in bitmap to destination ; lDelta - distance from between planar scans ; ulBlockHeight - # of scans to copy ; ; Output: ; Advances ulRightSrc and ulRightDest to next strip ;-----------------------------------------------------------------------;
public copy_right_block copy_right_block::
; Set right mask by disabling some planes:
mov edx,VGA_BASE + SEQ_DATA mov eax,ulRightMask out dx,al
; Calculate full start addresses:
mov ecx,ppdev mov ebx,ulBlockHeight mov edx,lDelta mov esi,[ecx].pdev_pvBitmapStart2WindowS mov edi,[ecx].pdev_pvBitmapStart2WindowD add esi,ulRightSrc add edi,ulRightDest
SET_UP_UNROLL_VARS ebx,eax,ebx,pfnCopyRightEntry, \ LOOP_UNROLL_SHIFT
jmp eax
UNROLL_LOOP_ENTRY_TABLE pfnCopyRightEntry,RIGHT, \ LOOP_UNROLL_COUNT
COPY_RIGHT macro ENTRY_LABEL,ENTRY_INDEX &ENTRY_LABEL&ENTRY_INDEX&: mov al,[esi] mov [edi],al add esi,edx add edi,edx endm ;-----------------------------------;
; EBX = count of unrolled loop iterations ; EDX = offset from one scan to next ; ESI = source address from which to copy ; EDI = target address to which to copy
right_loop: UNROLL_LOOP COPY_RIGHT,RIGHT,LOOP_UNROLL_COUNT dec ebx jnz right_loop
; get ready for next time:
sub esi,[ecx].pdev_pvBitmapStart2WindowS sub edi,[ecx].pdev_pvBitmapStart2WindowD mov ulRightSrc,esi mov ulRightDest,edi
PLAIN_RET
;-----------------------------------------------------------------------;
endProc vPlanarCopyBits
end
|