You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1509 lines
50 KiB
1509 lines
50 KiB
|
|
;---------------------------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
|
|
|
|
|