Leaked source code of windows server 2003
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.
 
 
 
 
 
 

2251 lines
74 KiB

;---------------------------Module-Header------------------------------;
; Module Name: monopat.asm
;
; Copyright (c) 1992-1993 Microsoft Corporation. All rights reserved.
;-----------------------------------------------------------------------;
;-----------------------------------------------------------------------;
; VOID vMonoPat(ppdev, culRcl, prcl, ulMix, prb, pptlBrush)
;
; Input:
;
; ppdev - surface on which to draw
; culRcl - number of rectangles
; prcl - pointer to rectangles
; ulMix - mix mode (i.e., ROP)
; prb - pointer to realized brush
; pptlBrush - brush alignment
;
; Draws two color patterns using the VGA hardware. If the ROP is a
; PATCOPY ROP, we can light 8 pixels on every word write to VGA memory.
;
; We special case black & white patterns because we can do slightly less
; initialization, and we can handle arbitrary ROPs (although if the ROP
; has to read video memory, we can only do 4 pixels on every read/write
; operation).
;
;-----------------------------------------------------------------------;
;
; NOTE: Assumes all rectangles have positive heights and widths. Will
; not work properly if this is not the case.
;
;-----------------------------------------------------------------------;
;-----------------------------------------------------------------------;
.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\egavga.inc
include i386\ropdefs.inc
.list
;-----------------------------------------------------------------------;
.code
; vTrgBlt is used for 2-pass ROPs:
EXTRNP vTrgBlt,24
.data
; Tables shared with vgablts.asm:
extrn jALUFuncTable: byte
extrn jInvertDest: byte
;-----------------------------------------------------------------------;
; Bits for drawing routine look-ups.
BLOCK_LEFT_EDGE equ 010000b
BLOCK_RIGHT_EDGE equ 001000b
BLOCK_MIDDLE_STARTS_UNALIGNED equ 000100b
BLOCK_NO_MIDDLE equ 000010b
BLOCK_MIDDLE_ENDS_UNALIGNED equ 000001b
;-----------------------------------------------------------------------;
; Table of drawing routines, with the look-up index a 5 bit field as
; follows:
;
; Bit 4 = 1 if a left edge must be drawn
; Bit 3 = 1 if a right edge must be drawn
; Bit 2 = 1 if middle block starts unaligned word-wise
; Bit 1 = 1 if no middle block
; Bit 0 = 1 if middle block is an odd number of bytes in length
align 4
gapfnSetTable label dword
dd dual_wide_00_w ;00000
dd dual_wide_01_w ;00001
dd 0 ;00010
dd 0 ;00011
dd dual_wide_11_w ;00100
dd dual_wide_10_w ;00101
dd 0 ;00110
dd 0 ;00111
dd Block_01000_w ;01000
dd Block_01001_w ;01001
dd dual_right_0_w ;01010
dd dual_right_1_w ;01011
dd Block_01100_w ;01100
dd Block_01101_w ;01101
dd dual_right_1_w ;01110
dd dual_right_0_w ;01111
dd Block_10000_w ;10000
dd Block_10001_w ;10001
dd dual_left_0_w ;10010
dd dual_left_0_w ;10011
dd Block_10100_w ;10100
dd Block_10101_w ;10101
dd dual_left_1_w ;10110
dd dual_left_1_w ;10111
dd Block_11000_w ;11000
dd Block_11001_w ;11001
dd Block_11010_w ;11010
dd 0 ;11011 - can never happen
dd Block_11100_w ;11100
dd Block_11101_w ;11101
dd Block_11110_w ;11110
dd 0 ;11111 - can never happen
gapfnROPTable label dword
dd dual_wide_00_rw ;00000
dd dual_wide_01_rw ;00001
dd 0 ;00010
dd 0 ;00011
dd dual_wide_11_rw ;00100
dd dual_wide_10_rw ;00101
dd 0 ;00110
dd 0 ;00111
dd Block_01000_rw ;01000
dd Block_01001_rw ;01001
dd dual_right_0_rw ;01010
dd dual_right_1_rw ;01011
dd Block_01100_rw ;01100
dd Block_01101_rw ;01101
dd dual_right_1_rw ;01110
dd dual_right_0_rw ;01111
dd Block_10000_rw ;10000
dd Block_10001_rw ;10001
dd dual_left_0_rw ;10010
dd dual_left_0_rw ;10011
dd Block_10100_rw ;10100
dd Block_10101_rw ;10101
dd dual_left_1_rw ;10110
dd dual_left_1_rw ;10111
dd Block_11000_rw ;11000
dd Block_11001_rw ;11001
dd Block_11010_rw ;11010
dd 0 ;11011 - can never happen
dd Block_11100_rw ;11100
dd Block_11101_rw ;11101
dd Block_11110_rw ;11110
dd 0 ;11111 - can never happen
gaulForceOffTable label dword
dd 0 ;ignored - there is no mix 0
dd 0
dd 0ffffffffh
dd 0ffffffffh
dd 0ffffffffh
dd 0ffffffffh
dd 0ffffffffh
dd 0ffffffffh
dd 0ffffffffh
dd 0ffffffffh
dd 0ffffffffh
dd 0
dd 0ffffffffh
dd 0ffffffffh
dd 0ffffffffh
dd 0ffffffffh
dd 0ffffffffh
gaulForceOnTable label dword
dd 0 ;ignored - there is no mix 0
dd 0
dd 0
dd 0
dd 0
dd 0
dd 0ffffffffh
dd 0
dd 0
dd 0
dd 0
dd 0
dd 0
dd 0
dd 0
dd 0
dd 0ffffffffh
gaulForceNotTable label dword
dd 0 ;ignored - there is no mix 0
dd 0
dd 0ffffffffh
dd 0ffffffffh
dd 0ffffffffh
dd 0
dd 0
dd 0
dd 0ffffffffh
dd 0
dd 0ffffffffh
dd 0
dd 0ffffffffh
dd 0
dd 0
dd 0
dd 0
;-----------------------------------------------------------------------;
.code
;-----------------------------------------------------------------------;
; Write thunks (for set ROPs)
;-----------------------------------------------------------------------;
Block_01000_w:
push offset dual_right_0_w
jmp dual_wide_00_w
Block_01001_w:
push offset dual_right_1_w
jmp dual_wide_01_w
Block_01100_w:
push offset dual_right_1_w
jmp dual_wide_11_w
Block_01101_w:
push offset dual_right_0_w
jmp dual_wide_10_w
Block_11000_w:
push offset dual_right_0_w
Block_10000_w:
push offset dual_left_0_w
jmp dual_wide_00_w
Block_11001_w:
push offset dual_right_1_w
Block_10001_w:
push offset dual_left_0_w
jmp dual_wide_01_w
Block_11100_w:
push offset dual_right_1_w
Block_10100_w:
push offset dual_left_1_w
jmp dual_wide_11_w
Block_11101_w:
push offset dual_right_0_w
Block_10101_w:
push offset dual_left_1_w
jmp dual_wide_10_w
Block_11010_w:
push offset dual_right_0_w
jmp dual_left_0_w
Block_11110_w:
push offset dual_right_1_w
jmp dual_left_1_w
;-----------------------------------------------------------------------;
; Read/write thunks (for arbitrary ROPs)
;-----------------------------------------------------------------------;
Block_01000_rw:
push offset dual_right_0_rw
jmp dual_wide_00_rw
Block_01001_rw:
push offset dual_right_1_rw
jmp dual_wide_01_rw
Block_01100_rw:
push offset dual_right_1_rw
jmp dual_wide_11_rw
Block_01101_rw:
push offset dual_right_0_rw
jmp dual_wide_10_rw
Block_11000_rw:
push offset dual_right_0_rw
Block_10000_rw:
push offset dual_left_0_rw
jmp dual_wide_00_rw
Block_11001_rw:
push offset dual_right_1_rw
Block_10001_rw:
push offset dual_left_0_rw
jmp dual_wide_01_rw
Block_11100_rw:
push offset dual_right_1_rw
Block_10100_rw:
push offset dual_left_1_rw
jmp dual_wide_11_rw
Block_11101_rw:
push offset dual_right_0_rw
Block_10101_rw:
push offset dual_left_1_rw
jmp dual_wide_10_rw
Block_11010_rw:
push offset dual_right_0_rw
jmp dual_left_0_rw
Block_11110_rw:
push offset dual_right_1_rw
jmp dual_left_1_rw
;-----------------------------------------------------------------------;
cProc vMonoPat,24,< \
uses esi edi ebx, \
ppdev: ptr PDEV, \
culRcl: dword, \
prcl: ptr RECTL, \
ulMix: dword, \
prb: ptr RBRUSH,\
pptlBrush: ptr POINTL >
; Variables used in block drawers:
local ppfnDraw: ptr ;pointer to array of draw routines
local pfnDraw: ptr ;pointer to draw routines
local yBrush: dword ;current y brush alignment
local yBrushOrg: dword ;original y brush alignment
local ulMiddleDest: dword ;bitmap offset to middle
local lMiddleDelta: dword ;delta from end of middle scan to next
local ulBlockHeight: dword ;# of scans to be drawn in block
local ulBlockHeightTmp: dword ;scratch copy of ulBlockHeight
local cwMiddle: dword ;# of words to be written in middle
local ulLeftDest: dword ;bitmap offset to left edge
local ulLeftMask: dword ;plane mask for left-edge drawing
local ulRightDest: dword ;bitmap offset to right edge
local ulRightMask: dword ;plane mask for right-edge drawing
local lDelta: dword ;delta between scans
local ulCurrentDestScan: dword ;current destination scan
local ulLastDestScan: dword ;last destination scan
local pulPattern: ptr ;pointer to working pattern buffer
; (to account for brush inversions)
local aulPatternBuffer[8]: dword ;pattern buffer
local pfnLoopTop: ptr ;points to desired loop top
mov esi,pptlBrush
mov edi,prb
mov ecx,[esi].ptl_y
mov yBrushOrg,ecx ;yBrushOrg = pptlBrush->y
mov ecx,[esi].ptl_x
mov eax,[edi].rb_xBrush
and ecx,7
cmp eax,ecx
jne dual_align_brush ;only align if we really have to
dual_done_align_brush:
test [edi].rb_fl,RBRUSH_2COLOR
jnz col2_colors
; Set VGA to read mode 1 and write mode 2:
mov esi,ppdev
mov edx,VGA_BASE + GRAF_ADDR
mov ah,byte ptr [esi].pdev_ulrm0_wmX[2]
or ah,M_COLOR_READ
mov al,GRAF_MODE
out dx,ax ;write mode 2 to expand pattern bits to
; 0 or 0ffh per plane, read mode 1 so
; we can read 0xFF from memory always,
; for ANDing (because Color Don't Care
; is all zeros)
;-----------------------------------------------------------------------;
; Handle only black/white patterns.
;-----------------------------------------------------------------------;
lea eax,[edi].rb_aulPattern
mov pulPattern,eax ;pulPattern = &pbr.rb_aulPattern[0]
lea eax,gapfnSetTable
mov ppfnDraw,eax ;ppfnDraw = gapfnSetTable
mov ecx,ulMix
and ecx,0fh
cmp ecx,R2_COPYPEN
jne bw_init_rop ;do some more work if not copy ROP
bw_done_init_rop:
call dual_draw_rectangles ;draw those puppies
; All done! Restore read mode 0, write mode 0:
mov esi,ppdev
mov edx,VGA_BASE + GRAF_ADDR
mov ah,byte ptr [esi].pdev_ulrm0_wmX[0]
mov al,GRAF_MODE
out dx,ax
; Enable all planes:
mov edx,VGA_BASE + SEQ_DATA
mov al,MM_ALL
out dx,al
cmp ulMix,R2_COPYPEN
jne short bw_enable_set_mode
cRet vMonoPat
; Set ALU function to Set mode (we don't have to bother if we had a
; COPYPEN ROP):
bw_enable_set_mode:
mov eax,GRAF_DATA_ROT + (DR_SET shl 8)
mov edx,VGA_BASE + GRAF_ADDR
out dx,ax
cRet vMonoPat
;-----------------------------------------------------------------------;
; Draw both black and white and 2 color rectangles.
;-----------------------------------------------------------------------;
public dual_draw_rectangles
dual_draw_rectangles::
mov edi,prcl ;edi = prcl
mov edx,ppdev
mov eax,[edi].yBottom
mov ebx,[edi].yTop
mov edx,[edx].pdev_lPlanarNextScan
mov lDelta,edx ;lDelta = ppdev->lPlanarNextScan
mov ulLastDestScan,eax ;ulLastDestScan = prcl->bottom
mov ulCurrentDestScan,ebx ;ulCurrentDestScan = prcl->top
mov ecx,edx
imul ecx,ebx
sub ebx,yBrushOrg
and ebx,7
mov yBrush,ebx ;yBrush = (prcl->top - pptlBrush->y) & 7
; (our current index into the pattern
; array)
mov ebx,[edi].xLeft
shr ebx,2
add ebx,ecx ;ebx = prcl->top * lDelta +
; (prcl->left >> 2)
; (offset into bitmap of left side)
mov eax,[edi].xRight
shr eax,2
add eax,ecx
mov ulRightDest,eax ;ulRightDest = prcl->top * lDelta +
; (prcl->right >> 2)
; (offset into bitmap of right side)
xor esi,esi ;zero our flags
mov ecx,[edi].xLeft
and ecx,3
jz short dual_done_left ;skip if we don't need a left edge
mov esi,0fh ;compute the plane mask for the left
shl esi,cl ; edge. we don't use a look-up table
mov ulLeftMask,esi ; 'cause it won't be in the cache.
mov esi,(BLOCK_LEFT_EDGE shr 2)
;set our flag (we soon shift left by 2)
mov ulLeftDest,ebx ;ulLeftDest = prcl->top * lDelta +
; (prcl->left >> 2)
inc ebx ;ebx = ulMiddleDest = ulLeftDest + 1
; (we have to adjust our offset to
; the first whole byte)
dual_done_left:
sub eax,ebx ;eax = cjMiddle =
; ulRightDest - ulMiddleDest
mov ulMiddleDest,ebx ;ulMiddleDest
.errnz (BLOCK_MIDDLE_STARTS_UNALIGNED shr 2) - 1
and ebx,1 ;set bit if middle doesn't start
or esi,ebx ; word aligned (remembering we'll
; soon shift flags left by 2)
mov ecx,[edi].xRight
and ecx,3
jz short dual_done_right ;skip if we don't need a right edge
mov ebx,0f0h ;compute the plane mask for the right
rol bl,cl ; edge. we don't use a look-up table
mov ulRightMask,ebx ; 'cause it won't be in the cache.
or esi,(BLOCK_RIGHT_EDGE shr 2)
;set our flag (we soon shift left by 2)
; If the count of whole bytes is negative, that means that the pattern
; starts and ends in the same quadpixel, so we do some more work:
cmp eax,0
jge short dual_done_right
; It starts and ends in the same quadpixel:
and esi,not (BLOCK_RIGHT_EDGE shr 2)
;turn off right edge
and ebx,ulLeftMask
mov ulLeftMask,ebx
xor eax,eax ;we do zero middle bytes
public dual_done_right
dual_done_right::
mov ebx,ppfnDraw
; We're going to do two 'adc esi,esi' instructions here, effectively
; shifting our flags left by 2, and setting the low bits:
.errnz (BLOCK_NO_MIDDLE shr 1) - 1
cmp eax,1 ;shift flags left one, and set low
adc esi,esi ; bit if we don't need to do a middle
.errnz (BLOCK_MIDDLE_ENDS_UNALIGNED) - 1
shr eax,1
adc esi,esi ;shift flags left one, and set low
; bit if the middle isn't an even
; number of bytes in length
mov cwMiddle,eax ;cwMiddle = cjMiddle / 2
sub edx,eax
sub edx,eax
mov lMiddleDelta,edx ;lMiddleDelta = lDelta - 2 * cwMiddle
mov eax,[ebx+esi*4]
mov pfnDraw,eax ;pointer to function that draws
; everything in the bank
mov ebx,ppdev
mov edi,[edi].yTop
cmp edi,[ebx].pdev_rcl1PlanarClip.yTop
jl short dual_map_init_bank
cmp edi,[ebx].pdev_rcl1PlanarClip.yBottom
jl short dual_init_bank_mapped
dual_map_init_bank:
ptrCall <dword ptr [ebx].pdev_pfnPlanarControl>, \
<ebx,edi,JustifyTop>
dual_init_bank_mapped:
mov eax,ulLastDestScan
mov ebx,[ebx].pdev_rcl1PlanarClip.yBottom
sub eax,ebx
sbb ecx,ecx
and ecx,eax
add ebx,ecx ;ebx = min(ulLastDestScan,
; ppdev->rcl1PlanarClip.yBottom)
mov ulCurrentDestScan,ebx
sub ebx,edi
mov ulBlockHeight,ebx ;ulBlockHeight = ebx - ulCurrentDestScan
; Draw everything in this bank:
call pfnDraw
dual_done_pfnDraw:
mov edi,ulCurrentDestScan
cmp edi,ulLastDestScan
jge short dual_next_rectangle
; Get the next bank:
mov ebx,ppdev
mov yBrush,esi ;make sure we record the new brush
; alignment
; Map the next bank into window.
; Note: EBX, ESI, and EDI are preserved, according to C calling conventions.
ptrCall <dword ptr [ebx].pdev_pfnPlanarControl>, \
<ebx,edi,JustifyTop>
jmp short dual_init_bank_mapped
;-----------------------------------------------------------------------;
; Done rectangle.
;-----------------------------------------------------------------------;
public dual_next_rectangle
dual_next_rectangle::
add prcl, size RECTL
dec culRcl
jg dual_draw_rectangles ;do more rectangles
PLAIN_RET ;return
;-----------------------------------------------------------------------;
; Handle x-brush alignment.
;-----------------------------------------------------------------------;
public dual_align_brush
dual_align_brush::
; Align the pattern on x. Remember it in the realized brush, because if
; the brush is used again, it's likely to have the same alignment...
mov [edi].rb_xBrush,ecx ;remember our new alignment
sub ecx,eax ;rotate pattern left by
; pptlBrush->x - prb->xBrush
; We keep each row of the pattern in the low word of each dword. If the
; bits are to appear on the screen as 01234567, the word of our pattern
; has the bits 32107654|76543210 -- we're in write mode 3, and when
; written as a word, this results in 3210 being written in the first
; byte, and 7654 in the second byte.
;
; For our funky plaanr format, we just rotate each byte of the word left by
; 'cl' to get the desired result.
rol byte ptr [edi][0].rb_aulPattern,cl ;0
rol byte ptr [edi][1].rb_aulPattern,cl
rol byte ptr [edi][4].rb_aulPattern,cl ;1
rol byte ptr [edi][5].rb_aulPattern,cl
rol byte ptr [edi][8].rb_aulPattern,cl ;2
rol byte ptr [edi][9].rb_aulPattern,cl
rol byte ptr [edi][12].rb_aulPattern,cl ;3
rol byte ptr [edi][13].rb_aulPattern,cl
rol byte ptr [edi][16].rb_aulPattern,cl ;4
rol byte ptr [edi][17].rb_aulPattern,cl
rol byte ptr [edi][20].rb_aulPattern,cl ;5
rol byte ptr [edi][21].rb_aulPattern,cl
rol byte ptr [edi][24].rb_aulPattern,cl ;6
rol byte ptr [edi][25].rb_aulPattern,cl
rol byte ptr [edi][28].rb_aulPattern,cl ;7
rol byte ptr [edi][29].rb_aulPattern,cl
jmp dual_done_align_brush
;-----------------------------------------------------------------------;
; Handle arbitrary ROPs for black/white patterns.
;-----------------------------------------------------------------------;
; Expect:
;
; ecx = ulMix
public bw_init_rop
bw_init_rop::
cmp jInvertDest[ecx],0
je short bw_set_that_ALU ;skip if don't need 2 passes
; For some ROPs, we have to invert the destination first, then do another
; operation (that is, it's a 2-pass ROP). We handle the inversion here:
cCall vTrgBlt,<ppdev, culRcl, prcl, R2_NOT, 0, 0>
mov ecx,ulMix
and ecx,0fh
bw_set_that_ALU:
mov ah,jALUFuncTable[ecx]
cmp ah,DR_SET
je short bw_that_ALU_is_set
;we're already in Set mode
mov edx,VGA_BASE + GRAF_ADDR
mov al,GRAF_DATA_ROT
out dx,ax ;set the ALU logical function
lea ebx,gapfnROPTable
mov ppfnDraw,ebx
bw_that_ALU_is_set:
lea esi,aulPatternBuffer
mov pulPattern,esi ;we're using the temporary buffer
mov ebx,gaulForceOffTable[ecx*4]
mov edx,gaulForceOnTable[ecx*4]
mov esi,gaulForceNotTable[ecx*4]
mov eax,[edi][0].rb_aulPattern ;0
and eax,ebx
or eax,edx
xor eax,esi
mov [aulPatternBuffer][0],eax
mov eax,[edi][4].rb_aulPattern ;1
and eax,ebx
or eax,edx
xor eax,esi
mov [aulPatternBuffer][4],eax
mov eax,[edi][8].rb_aulPattern ;2
and eax,ebx
or eax,edx
xor eax,esi
mov [aulPatternBuffer][8],eax
mov eax,[edi][12].rb_aulPattern ;3
and eax,ebx
or eax,edx
xor eax,esi
mov [aulPatternBuffer][12],eax
mov eax,[edi][16].rb_aulPattern ;4
and eax,ebx
or eax,edx
xor eax,esi
mov [aulPatternBuffer][16],eax
mov eax,[edi][20].rb_aulPattern ;5
and eax,ebx
or eax,edx
xor eax,esi
mov [aulPatternBuffer][20],eax
mov eax,[edi][24].rb_aulPattern ;6
and eax,ebx
or eax,edx
xor eax,esi
mov [aulPatternBuffer][24],eax
mov eax,[edi][28].rb_aulPattern ;7
and eax,ebx
or eax,edx
xor eax,esi
mov [aulPatternBuffer][28],eax
jmp bw_done_init_rop
;-----------------------------------------------------------------------;
; Handle 2-color patterns.
;-----------------------------------------------------------------------;
public col2_colors
col2_colors::
lea eax,[edi].rb_aulPattern
mov pulPattern,eax ;pulPattern = &pbr.rb_aulPattern[0]
lea eax,gapfnSetTable
mov ppfnDraw,eax ;ppfnDraw = gapfnSetTable
call col2_first_rectangle
; Restore VGA hardware to its default state:
mov edx,VGA_BASE + GRAF_DATA
mov al,0ffh
out dx,al ;enable all bits through the Bit Mask
mov esi,ppdev
dec edx ;point back to the Graphics Index reg
mov ah,byte ptr [esi].pdev_ulrm0_wmX[0]
;write mode 0 setting for Graphics Mode
mov al,GRAF_MODE
out dx,ax ;write mode 0, read mode 0
mov eax,GRAF_DATA_ROT + (DR_SET SHL 8)
out dx,ax ;replace mode, no rotate
mov edx,VGA_BASE + SEQ_DATA
mov al,MM_ALL
out dx,al ;enable all planes
cRet vMonoPat
;-----------------------------------------------------------------------;
; Handle first rectangle for 2-color patterns.
;-----------------------------------------------------------------------;
; We have to special case the first rectangle because we have to load
; the latches with the background color after mapping the bank but before
; doing any drawing.
public col2_first_rectangle
col2_first_rectangle::
mov edi,prcl ;edi = prcl
mov edx,ppdev
mov eax,[edi].yBottom
mov ebx,[edi].yTop
mov edx,[edx].pdev_lPlanarNextScan
mov lDelta,edx ;lDelta = ppdev->lPlanarNextScan
mov ulLastDestScan,eax ;ulLastDestScan = prcl->bottom
mov ulCurrentDestScan,ebx ;ulCurrentDestScan = prcl->top
mov ecx,edx
imul ecx,ebx
sub ebx,yBrushOrg
and ebx,7
mov yBrush,ebx ;yBrush = (prcl->top - pptlBrush->y) & 7
; (our current index into the pattern
; array)
mov ebx,[edi].xLeft
shr ebx,2
add ebx,ecx ;ebx = prcl->top * lDelta +
; (prcl->left >> 2)
; (offset into bitmap of left side)
mov eax,[edi].xRight
shr eax,2
add eax,ecx
mov ulRightDest,eax ;ulRightDest = prcl->top * lDelta +
; (prcl->right >> 2)
; (offset into bitmap of right side)
xor esi,esi ;zero our flags
mov ecx,[edi].xLeft
and ecx,3
jz short col2_done_left ;skip if we don't need a left edge
mov esi,0fh ;compute the plane mask for the left
shl esi,cl ; edge. we don't use a look-up table
mov ulLeftMask,esi ; 'cause it won't be in the cache.
mov esi,(BLOCK_LEFT_EDGE shr 2)
;set our flag (we soon shift left by 2)
mov ulLeftDest,ebx ;ulLeftDest = prcl->top * lDelta +
; (prcl->left >> 2)
inc ebx ;ebx = ulMiddleDest = ulLeftDest + 1
; (we have to adjust our offset to
; the first whole byte)
col2_done_left:
sub eax,ebx ;eax = cjMiddle =
; ulRightDest - ulMiddleDest
mov ulMiddleDest,ebx ;ulMiddleDest
.errnz (BLOCK_MIDDLE_STARTS_UNALIGNED shr 2) - 1
and ebx,1 ;set bit if middle doesn't start
or esi,ebx ; word aligned (remembering we'll
; soon shift flags left by 2)
mov ecx,[edi].xRight
and ecx,3
jz short col2_done_right ;skip if we don't need a right edge
mov ebx,0f0h ;compute the plane mask for the right
rol bl,cl ; edge. we don't use a look-up table
mov ulRightMask,ebx ; 'cause it won't be in the cache.
or esi,(BLOCK_RIGHT_EDGE shr 2)
;set our flag (we soon shift left by 2)
; If the count of whole bytes is negative, that means that the pattern
; starts and ends in the same quadpixel, so we do some more work:
cmp eax,0
jge short col2_done_right
; It starts and ends in the same quadpixel:
and esi,not (BLOCK_RIGHT_EDGE shr 2)
;turn off right edge
and ebx,ulLeftMask
mov ulLeftMask,ebx
xor eax,eax ;we do zero middle bytes
public col2_done_right
col2_done_right::
mov ebx,ppfnDraw
; We're going to do two 'adc esi,esi' instructions here, effectively
; shifting our flags left by 2, and setting the low bits:
.errnz (BLOCK_NO_MIDDLE shr 1) - 1
cmp eax,1 ;shift flags left one, and set low
adc esi,esi ; bit if we don't need to do a middle
.errnz (BLOCK_MIDDLE_ENDS_UNALIGNED) - 1
shr eax,1
mov cwMiddle,eax ;cwMiddle = cjMiddle / 2
adc esi,esi ;shift flags left one, and set low
; bit if the middle isn't an even
; number of bytes in length
sub edx,eax
sub edx,eax
mov lMiddleDelta,edx ;lMiddleDelta = lDelta - 2 * cwMiddle
mov eax,[ebx+esi*4]
mov pfnDraw,eax ;pointer to function that draws
; everything in the bank
mov ebx,ppdev
test esi,BLOCK_NO_MIDDLE
jz short col2_have_a_middle
;-----------------------------------------;
; Handle case where there isn't a whole quadpixel that will be overwritten
; by the pattern, and so we don't have a convenient place for loading the
; latches. For this case, we'll use off-screen memory.
mov esi,[ebx].pdev_pbceCache
mov eax,[esi].bce_yCache
cmp eax,[ebx].pdev_rcl1PlanarClip.yTop
jl short col2_no_middle_map_brush_bank
cmp eax,[ebx].pdev_rcl1PlanarClip.yBottom
jl short col2_no_middle_brush_bank_mapped
col2_no_middle_map_brush_bank:
ptrCall <dword ptr [ebx].pdev_pfnPlanarControl>, \
<ebx,eax,JustifyBottom>
col2_no_middle_brush_bank_mapped:
mov ecx,prb ;ecx = prb
mov esi,[esi].bce_ulCache
add esi,[ebx].pdev_pvBitmapStart
mov eax,[ecx].rb_ulBkColor
mov [esi],al
mov al,[esi] ;latches now laoded with bk color
mov edi,[edi].yTop
cmp edi,[ebx].pdev_rcl1PlanarClip.yTop
jl short col2_no_middle_map_init_bank
cmp edi,[ebx].pdev_rcl1PlanarClip.yBottom
jl col2_latches_loaded
col2_no_middle_map_init_bank:
ptrCall <dword ptr [ebx].pdev_pfnPlanarControl>, \
<ebx,edi,JustifyTop>
mov ecx,prb ;reload ecx = prb
jmp col2_latches_loaded
;-----------------------------------------;
col2_have_a_middle:
mov edi,[edi].yTop
cmp edi,[ebx].pdev_rcl1PlanarClip.yTop
jl short col2_map_init_bank
cmp edi,[ebx].pdev_rcl1PlanarClip.yBottom
jl short col2_init_bank_mapped
col2_map_init_bank:
ptrCall <dword ptr [ebx].pdev_pfnPlanarControl>, \
<ebx,edi,JustifyTop>
col2_init_bank_mapped:
mov ecx,prb ;ecx = prb
mov esi,ulMiddleDest
add esi,[ebx].pdev_pvBitmapStart
;pointer to the first whole quadpixel
; that will be overwritten by the
; pattern, and so which is a great
; place to use to load the latches
mov eax,[ecx].rb_ulBkColor
mov [esi],al
mov al,[esi] ;latches now loaded with bk color
; Set VGA to read mode 0 and write mode 2:
col2_latches_loaded:
; ebx = ppdev
; ecx = prb
; edi = top line of rectangle
mov esi,ppdev
mov edx,VGA_BASE + GRAF_ADDR
mov ah,byte ptr [esi].pdev_ulrm0_wmX[2]
mov al,GRAF_MODE
out dx,ax
mov eax,GRAF_DATA_ROT + (DR_XOR SHL 8)
out dx,ax ;XOR to flip latched data to make ~bk
mov ah,byte ptr [ecx].rb_ulBkColor
xor ah,byte ptr [ecx].rb_ulFgColor
mov al,GRAF_BIT_MASK
out dx,ax ;pass through common fg & bk bits
; unchanged from bk color in latches;
; non-common bits come from XOR in the
; ALUs, flipped from the bk to the fg
; state if the glyph bit for the pixel
; in that plane is 1, still in bk state
; if the glyph bit for that plane is 0
; All done hardware initialization. Do rest of this boring stuff:
mov eax,ulLastDestScan
mov ebx,[ebx].pdev_rcl1PlanarClip.yBottom
sub eax,ebx
sbb ecx,ecx
and ecx,eax
add ebx,ecx ;ebx = min(ulLastDestScan,
; ppdev->rcl1PlanarClip.yBottom)
mov ulCurrentDestScan,ebx
sub ebx,edi
mov ulBlockHeight,ebx ;ulBlockHeight = ebx - ulCurrentDestScan
; Draw everything in this bank:
CALL_AND_JUMP pfnDraw,dual_done_pfnDraw
;=======================================================================;
;========================= Set Block Drawers ===========================;
;=======================================================================;
;-----------------------------------------------------------------------;
; dual_wide_11_w
;
; Draws middle words with 1 leading byte and 1 trailing byte.
;
; Input:
; ppdev - pointer to physical device structure
; ulBlockHeight - # of scans to draw
; lMiddleDelta - distance from end of current scan to start of next
; ulMiddleDest - offset in bitmap at which to start drawing
; yBrush - current y brush alignment
; cwMiddle - # of words to draw on each scan
;
; Output:
; esi - new y brush alignment
; ulMiddleDest - new bitmap offset
;-----------------------------------------------------------------------;
public dual_wide_11_w
dual_wide_11_w::
; 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
; Calculate full start addresses:
mov edi,ppdev
mov ebx,ulBlockHeight
mov ulBlockHeightTmp,ebx
mov ebx,pulPattern
mov edx,lMiddleDelta
add edx,2 ;account for first and last
; bytes
mov esi,yBrush
mov edi,[edi].pdev_pvBitmapStart
add edi,ulMiddleDest
inc edi ;align to word
; EBX = pointer to start of pattern
; EDX = offset from end of scan to start of next
; ESI = current offset into pattern
; EDI = target address to which to write
dual_wide_11_w_loop:
; We aim to overdrive.
mov eax,[ebx+esi * 4] ;load pattern for this scan
mov [edi-1],ah ;write the first byte
mov ecx,cwMiddle
dec ecx ;account for first and last
; bytes
rep stosw ;light 8 pels on every write
inc esi ;advance to next scan of pattern
and esi,7
mov [edi],al ;write that last byte
add edi,edx ;advance to next scan
dec ulBlockHeightTmp
jnz short dual_wide_11_w_loop
; get ready for next time:
mov ecx,ppdev
sub edi,[ecx].pdev_pvBitmapStart
dec edi ;undo our word alignment
mov ulMiddleDest,edi
PLAIN_RET
;-----------------------------------------------------------------------;
; dual_wide_10_w
;
; Draws middle words with 1 leading byte and 0 trailing bytes.
;
; Input:
; ppdev - pointer to physical device structure
; ulBlockHeight - # of scans to draw
; lMiddleDelta - distance from end of current scan to start of next
; ulMiddleDest - offset in bitmap at which to start drawing
; yBrush - current y brush alignment
; cwMiddle - # of words to draw on each scan
;
; Output:
; esi - new y brush alignment
; ulMiddleDest - new bitmap offset
;-----------------------------------------------------------------------;
public dual_wide_10_w
dual_wide_10_w::
; 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
; Calculate full start addresses:
mov edi,ppdev
mov ebx,ulBlockHeight
mov ulBlockHeightTmp,ebx
mov ebx,pulPattern
mov edx,lMiddleDelta
mov esi,yBrush
mov edi,[edi].pdev_pvBitmapStart
add edi,ulMiddleDest
inc edi ;align to word
; EBX = pointer to start of pattern
; EDX = offset from end of scan to start of next
; ESI = current offset into pattern
; EDI = target address to which to write
dual_wide_10_w_loop:
mov eax,[ebx+esi * 4] ;load pattern for this scan
mov [edi-1],ah ;write the first byte
mov ecx,cwMiddle
rep stosw ;light 8 pels on every write
inc esi ;advance to next scan of pattern
and esi,7
add edi,edx ;advance to next scan
dec ulBlockHeightTmp
jnz short dual_wide_10_w_loop
; get ready for next time:
mov ecx,ppdev
sub edi,[ecx].pdev_pvBitmapStart
dec edi ;undo our word alignment
mov ulMiddleDest,edi
PLAIN_RET
;-----------------------------------------------------------------------;
; dual_wide_01_w
;
; Draws middle words with 0 leading bytes and 1 trailing byte.
;
; Input:
; ppdev - pointer to physical device structure
; ulBlockHeight - # of scans to draw
; lMiddleDelta - distance from end of current scan to start of next
; ulMiddleDest - offset in bitmap at which to start drawing
; yBrush - current y brush alignment
; cwMiddle - # of words to draw on each scan
;
; Output:
; esi - new y brush alignment
; ulMiddleDest - new bitmap offset
;-----------------------------------------------------------------------;
public dual_wide_01_w
dual_wide_01_w::
; 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
; Calculate full start addresses:
mov edi,ppdev
mov ebx,ulBlockHeight
mov ulBlockHeightTmp,ebx
mov ebx,pulPattern
mov edx,lMiddleDelta
mov esi,yBrush
mov edi,[edi].pdev_pvBitmapStart
add edi,ulMiddleDest
; EBX = pointer to start of pattern
; EDX = offset from end of scan to start of next
; ESI = current offset into pattern
; EDI = target address to which to write
dual_wide_01_w_loop:
mov eax,[ebx+esi*4] ;load pattern for this scan
mov ecx,cwMiddle
rep stosw ;light 8 pels on every write
inc esi ;advance to next scan of pattern
and esi,7
mov [edi],al ;write that last byte
add edi,edx ;advance to next scan
dec ulBlockHeightTmp
jnz short dual_wide_01_w_loop
; get ready for next time:
mov ecx,ppdev
sub edi,[ecx].pdev_pvBitmapStart
mov ulMiddleDest,edi
PLAIN_RET
;-----------------------------------------------------------------------;
; dual_wide_00_w
;
; Draws middle words with 0 leading bytes and 1 trailing byte.
;
; Input:
; ppdev - pointer to physical device structure
; ulBlockHeight - # of scans to draw
; lMiddleDelta - distance from end of current scan to start of next
; ulMiddleDest - offset in bitmap at which to start drawing
; yBrush - current y brush alignment
; cwMiddle - # of words to draw on each scan
;
; Output:
; esi - new y brush alignment
; ulMiddleDest - new bitmap offset
;-----------------------------------------------------------------------;
public dual_wide_00_w
dual_wide_00_w::
; 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
; Calculate full start addresses:
mov edi,ppdev
mov ebx,ulBlockHeight
mov ulBlockHeightTmp,ebx
mov ebx,pulPattern
mov edx,lMiddleDelta
mov esi,yBrush
mov edi,[edi].pdev_pvBitmapStart
add edi,ulMiddleDest
; EBX = pointer to start of pattern
; EDX = offset from end of scan to start of next
; ESI = current offset into pattern
; EDI = target address to which to write
dual_wide_00_w_loop:
mov eax,[ebx+esi*4] ;load pattern for this scan
mov ecx,cwMiddle
rep stosw ;light 8 pels on every write
inc esi ;advance to next scan of pattern
and esi,7
add edi,edx ;advance to next scan
dec ulBlockHeightTmp
jnz short dual_wide_00_w_loop
; get ready for next time:
mov ecx,ppdev
sub edi,[ecx].pdev_pvBitmapStart
mov ulMiddleDest,edi
PLAIN_RET
;-----------------------------------------------------------------------;
; dual_left_1_w
;
; Draws a left edge when the next byte is not word aligned.
;
; Input:
; ppdev - pointer to physical device structure
; ulBlockHeight - # of scans to draw
; lDelta - distance from end of current scan to start of next
; ulLeftDest - offset in bitmap at which to start drawing
; yBrush - current y brush alignment
;
; Output:
; esi - new y brush alignment
; ulLeftDest - new bitmap offset
;-----------------------------------------------------------------------;
public dual_left_1_w
dual_left_1_w::
; Set left mask by disabling some planes:
mov edx,VGA_BASE + SEQ_DATA
mov eax,ulLeftMask
out dx,al
; Calculate full start addresses:
mov edi,ppdev
mov ebx,ulBlockHeight
mov ecx,pulPattern
mov edx,lDelta
mov esi,yBrush
mov edi,[edi].pdev_pvBitmapStart
add edi,ulLeftDest
; EBX = count of loop iterations
; ECX = pointer to start of pattern
; EDX = offset to next scan
; ESI = current offset into pattern
; EDI = target address to which to write
dual_left_1_w_loop:
mov eax,[ecx+esi*4] ;load pattern for this scan
mov [edi],al ;write the low byte
inc esi ;advance to next scan of pattern
and esi,7
add edi,edx ;advance to next scan
dec ebx
jnz short dual_left_1_w_loop
; get ready for next time:
mov ecx,ppdev
sub edi,[ecx].pdev_pvBitmapStart
mov ulLeftDest,edi
PLAIN_RET
;-----------------------------------------------------------------------;
; dual_left_0_w
;
; Draws a left edge when the next byte is word aligned.
;
; Input:
; ppdev - pointer to physical device structure
; ulBlockHeight - # of scans to draw
; lDelta - distance from end of current scan to start of next
; ulLeftDest - offset in bitmap at which to start drawing
; yBrush - current y brush alignment
;
; Output:
; esi - new y brush alignment
; ulLeftDest - new bitmap offset
;-----------------------------------------------------------------------;
public dual_left_0_w
dual_left_0_w::
; Set left mask by disabling some planes:
mov edx,VGA_BASE + SEQ_DATA
mov eax,ulLeftMask
out dx,al
; Calculate full start addresses:
mov edi,ppdev
mov ebx,ulBlockHeight
mov ecx,pulPattern
mov edx,lDelta
mov esi,yBrush
mov edi,[edi].pdev_pvBitmapStart
add edi,ulLeftDest
; EBX = count of loop iterations
; ECX = pointer to start of pattern
; EDX = offset to next scan
; ESI = current offset into pattern
; EDI = target address to which to write
dual_left_0_w_loop:
mov eax,[ecx+esi*4] ;load pattern for this scan
mov [edi],ah ;write the high byte
inc esi ;advance to next scan of pattern
and esi,7
add edi,edx ;advance to next scan
dec ebx
jnz short dual_left_0_w_loop
; get ready for next time:
mov ecx,ppdev
sub edi,[ecx].pdev_pvBitmapStart
mov ulLeftDest,edi
PLAIN_RET
;-----------------------------------------------------------------------;
; dual_right_1_w
;
; Draws a right edge when not word aligned.
;
; Input:
; ppdev - pointer to physical device structure
; ulBlockHeight - # of scans to draw
; lDelta - distance from end of current scan to start of next
; ulRightDest - offset in bitmap at which to start drawing
; yBrush - current y brush alignment
;
; Output:
; esi - new y brush alignment
; ulRightDest - new bitmap offset
;-----------------------------------------------------------------------;
public dual_right_1_w
dual_right_1_w::
; Set right mask by disabling some planes:
mov edx,VGA_BASE + SEQ_DATA
mov eax,ulRightMask
out dx,al
; Calculate full start addresses:
mov edi,ppdev
mov ebx,ulBlockHeight
mov ecx,pulPattern
mov edx,lDelta
mov esi,yBrush
mov edi,[edi].pdev_pvBitmapStart
add edi,ulRightDest
; EBX = count of loop iterations
; ECX = pointer to start of pattern
; EDX = offset to next scan
; ESI = current offset into pattern
; EDI = target address to which to write
dual_right_1_w_loop:
mov eax,[ecx+esi*4] ;load pattern for this scan
mov [edi],ah ;write the high byte
inc esi ;advance to next scan of pattern
and esi,7
add edi,edx ;advance to next scan
dec ebx
jnz short dual_right_1_w_loop
; get ready for next time:
mov ecx,ppdev
sub edi,[ecx].pdev_pvBitmapStart
mov ulRightDest,edi
PLAIN_RET
;-----------------------------------------------------------------------;
; dual_right_0_w
;
; Draws a right edge when word aligned.
;
; Input:
; ppdev - pointer to physical device structure
; ulBlockHeight - # of scans to draw
; lDelta - distance from end of current scan to start of next
; ulRightDest - offset in bitmap at which to start drawing
; yBrush - current y brush alignment
;
; Output:
; esi - new y brush alignment
; ulRightDest - new bitmap offset
;-----------------------------------------------------------------------;
public dual_right_0_w
dual_right_0_w::
; Set right mask by disabling some planes:
mov edx,VGA_BASE + SEQ_DATA
mov eax,ulRightMask
out dx,al
; Calculate full start addresses:
mov edi,ppdev
mov ebx,ulBlockHeight
mov ecx,pulPattern
mov edx,lDelta
mov esi,yBrush
mov edi,[edi].pdev_pvBitmapStart
add edi,ulRightDest
; EBX = count of loop iterations
; ECX = pointer to start of pattern
; EDX = offset to next scan
; ESI = current offset into pattern
; EDI = target address to which to write
dual_right_0_w_loop:
mov eax,[ecx+esi*4] ;load pattern for this scan
mov [edi],al ;write the low byte
inc esi ;advance to next scan of pattern
and esi,7
add edi,edx ;advance to next scan
dec ebx
jnz short dual_right_0_w_loop
; get ready for next time:
mov ecx,ppdev
sub edi,[ecx].pdev_pvBitmapStart
mov ulRightDest,edi
PLAIN_RET
;=======================================================================;
;========================= ROP Block Drawers ===========================;
;=======================================================================;
;-----------------------------------------------------------------------;
; dual_wide_11_rw
;
; Draws middle words with 1 leading byte and 1 trailing byte.
;
; Input:
; ppdev - pointer to physical device structure
; ulBlockHeight - # of scans to draw
; lMiddleDelta - distance from end of current scan to start of next
; ulMiddleDest - offset in bitmap at which to start drawing
; yBrush - current y brush alignment
; cwMiddle - # of words to draw on each scan
;
; Output:
; esi - new y brush alignment
; ulMiddleDest - new bitmap offset
;-----------------------------------------------------------------------;
public dual_wide_11_rw
dual_wide_11_rw::
; 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
mov edi,ppdev
mov edx,ulBlockHeight
mov ulBlockHeightTmp,edx
mov edx,pulPattern ;load those registers
mov edi,[edi].pdev_pvBitmapStart
add edi,ulMiddleDest
mov esi,yBrush
mov ebx,cwMiddle
mov eax,[edx+esi*4] ;load pattern for this scan
inc esi
and esi,7
; EAX = pattern for this scan
; EBX = count of loop iterations
; EDX = pointer to start of pattern
; ESI = current offset into pattern
; EDI = target address to which to write
dual_wide_11_rw_loop:
and [edi],ah
and [edi+1],al
add edi,2 ;the write will overlap this
dec ebx
jnz short dual_wide_11_rw_loop
add edi,lMiddleDelta
dec ulBlockHeightTmp
jz short dual_wide_11_rw_done
mov eax,[edx+esi*4] ;load pattern for this scan
inc esi
and esi,7
mov ebx,cwMiddle
jmp dual_wide_11_rw_loop
dual_wide_11_rw_done:
mov ecx,ppdev
sub edi,[ecx].pdev_pvBitmapStart
mov ulMiddleDest,edi
PLAIN_RET
;-----------------------------------------------------------------------;
; dual_wide_10_rw
;
; Draws middle words with 1 leading byte and 0 trailing bytes.
;
; Input:
; ppdev - pointer to physical device structure
; ulBlockHeight - # of scans to draw
; lMiddleDelta - distance from end of current scan to start of next
; ulMiddleDest - offset in bitmap at which to start drawing
; yBrush - current y brush alignment
; cwMiddle - # of words to draw on each scan
;
; Output:
; esi - new y brush alignment
; ulMiddleDest - new bitmap offset
;-----------------------------------------------------------------------;
public dual_wide_10_rw
dual_wide_10_rw::
; 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
mov edi,ppdev
mov edx,ulBlockHeight
mov ulBlockHeightTmp,edx
mov edx,pulPattern ;load those registers
mov edi,[edi].pdev_pvBitmapStart
add edi,ulMiddleDest
mov esi,yBrush
mov ebx,cwMiddle
mov eax,[edx+esi*4] ;load pattern for this scan
inc esi
and esi,7
or ebx,ebx ;have to watch for zero words
jz short dual_wide_10_rw_only_one_byte
mov pfnLoopTop,offset dual_wide_10_rw_loop
; EAX = pattern for this scan
; EBX = count of loop iterations
; EDX = pointer to start of pattern
; ESI = current offset into pattern
; EDI = target address to which to write
dual_wide_10_rw_loop:
and [edi],ah
and [edi+1],al
add edi,2 ;the write will overlap this
dec ebx
jnz short dual_wide_10_rw_loop
dual_wide_10_rw_odd_byte:
and [edi],ah ;write that odd byte
add edi,lMiddleDelta
dec ulBlockHeightTmp
jz short dual_wide_10_rw_done
mov eax,[edx+esi*4] ;load pattern for this scan
inc esi
and esi,7
mov ebx,cwMiddle
jmp pfnLoopTop
dual_wide_10_rw_only_one_byte:
mov pfnLoopTop,offset dual_wide_10_rw_odd_byte
jmp short dual_wide_10_rw_odd_byte
dual_wide_10_rw_done:
mov ecx,ppdev
sub edi,[ecx].pdev_pvBitmapStart
mov ulMiddleDest,edi
PLAIN_RET
;-----------------------------------------------------------------------;
; dual_wide_01_rw
;
; Draws middle words with 0 leading bytes and 1 trailing byte.
;
; Input:
; ppdev - pointer to physical device structure
; ulBlockHeight - # of scans to draw
; lMiddleDelta - distance from end of current scan to start of next
; ulMiddleDest - offset in bitmap at which to start drawing
; yBrush - current y brush alignment
; cwMiddle - # of words to draw on each scan
;
; Output:
; esi - new y brush alignment
; ulMiddleDest - new bitmap offset
;-----------------------------------------------------------------------;
public dual_wide_01_rw
dual_wide_01_rw::
; 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
mov edi,ppdev
mov edx,ulBlockHeight
mov ulBlockHeightTmp,edx
mov edx,pulPattern ;load those registers
mov edi,[edi].pdev_pvBitmapStart
add edi,ulMiddleDest
mov esi,yBrush
mov ebx,cwMiddle
mov eax,[edx+esi*4] ;load pattern for this scan
inc esi
and esi,7
or ebx,ebx
jz short dual_wide_01_rw_only_one_byte
mov pfnLoopTop,offset dual_wide_01_rw_loop
; EAX = pattern for this scan
; EBX = count of loop iterations
; EDX = pointer to start of pattern
; ESI = current offset into pattern
; EDI = target address to which to write
dual_wide_01_rw_loop:
and [edi],al
and [edi+1],ah
add edi,2 ;the write will overlap this
dec ebx
jnz short dual_wide_01_rw_loop
dual_wide_01_rw_odd_byte:
and [edi],al ;write that odd byte
add edi,lMiddleDelta
dec ulBlockHeightTmp
jz short dual_wide_01_rw_done
mov eax,[edx+esi*4] ;load pattern for this scan
inc esi
and esi,7
mov ebx,cwMiddle
jmp pfnLoopTop
dual_wide_01_rw_only_one_byte:
mov pfnLoopTop,offset dual_wide_01_rw_odd_byte
jmp short dual_wide_01_rw_odd_byte
dual_wide_01_rw_done:
mov ecx,ppdev
sub edi,[ecx].pdev_pvBitmapStart
mov ulMiddleDest,edi
PLAIN_RET
;-----------------------------------------------------------------------;
; dual_wide_00_rw
;
; Draws middle words with 0 leading bytes and 0 trailing bytes.
;
; Input:
; ppdev - pointer to physical device structure
; ulBlockHeight - # of scans to draw
; lMiddleDelta - distance from end of current scan to start of next
; ulMiddleDest - offset in bitmap at which to start drawing
; yBrush - current y brush alignment
; cwMiddle - # of words to draw on each scan
;
; Output:
; esi - new y brush alignment
; ulMiddleDest - new bitmap offset
;-----------------------------------------------------------------------;
public dual_wide_00_rw
dual_wide_00_rw::
; 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
mov edi,ppdev
mov edx,ulBlockHeight
mov ulBlockHeightTmp,edx
mov edx,pulPattern ;load those registers
mov edi,[edi].pdev_pvBitmapStart
add edi,ulMiddleDest
mov esi,yBrush
dual_wide_00_rw_scan_loop:
mov ebx,cwMiddle
mov eax,[edx+esi*4] ;load pattern for this scan
inc esi
and esi,7
; EAX = pattern for this scan
; EBX = count of loop iterations
; EDX = pointer to start of pattern
; ESI = current offset into pattern
; EDI = target address to which to write
dual_wide_00_rw_loop:
and [edi],al
and [edi+1],ah
add edi,2 ;the write will overlap this
dec ebx
jnz short dual_wide_00_rw_loop
add edi,lMiddleDelta
dec ulBlockHeightTmp
jnz dual_wide_00_rw_scan_loop
mov ecx,ppdev
sub edi,[ecx].pdev_pvBitmapStart
mov ulMiddleDest,edi
PLAIN_RET
;-----------------------------------------------------------------------;
; dual_left_1_rw
;
; Draws a left edge when the next byte is not word aligned.
;
; Input:
; ppdev - pointer to physical device structure
; ulBlockHeight - # of scans to draw
; lDelta - distance from end of current scan to start of next
; ulLeftDest - offset in bitmap at which to start drawing
; yBrush - current y brush alignment
;
; Output:
; esi - new y brush alignment
; ulLeftDest - new bitmap offset
;-----------------------------------------------------------------------;
public dual_left_1_rw
dual_left_1_rw::
; Set left mask by disabling some planes:
mov edx,VGA_BASE + SEQ_DATA
mov eax,ulLeftMask
out dx,al
; Calculate full start addresses:
mov edi,ppdev
mov ebx,ulBlockHeight
mov ecx,pulPattern
mov edx,lDelta
mov esi,yBrush
mov edi,[edi].pdev_pvBitmapStart
add edi,ulLeftDest
; EBX = count of loop iterations
; ECX = pointer to start of pattern
; EDX = offset to next scan
; ESI = current offset into pattern
; EDI = target address to which to write
dual_left_1_rw_loop:
mov eax,[ecx+esi*4] ;load pattern for this scan
and [edi],al ;write the low byte
inc esi ;advance to next scan of pattern
and esi,7
add edi,edx ;advance to next scan
dec ebx
jnz short dual_left_1_rw_loop
; get ready for next time:
mov ecx,ppdev
sub edi,[ecx].pdev_pvBitmapStart
mov ulLeftDest,edi
PLAIN_RET
;-----------------------------------------------------------------------;
; dual_left_0_rw
;
; Draws a left edge when the next byte is word aligned.
;
; Input:
; ppdev - pointer to physical device structure
; ulBlockHeight - # of scans to draw
; lDelta - distance from end of current scan to start of next
; ulLeftDest - offset in bitmap at which to start drawing
; yBrush - current y brush alignment
;
; Output:
; esi - new y brush alignment
; ulLeftDest - new bitmap offset
;-----------------------------------------------------------------------;
public dual_left_0_rw
dual_left_0_rw::
; Set left mask by disabling some planes:
mov edx,VGA_BASE + SEQ_DATA
mov eax,ulLeftMask
out dx,al
; Calculate full start addresses:
mov edi,ppdev
mov ebx,ulBlockHeight
mov ecx,pulPattern
mov edx,lDelta
mov esi,yBrush
mov edi,[edi].pdev_pvBitmapStart
add edi,ulLeftDest
; EBX = count of loop iterations
; ECX = pointer to start of pattern
; EDX = offset to next scan
; ESI = current offset into pattern
; EDI = target address to which to write
dual_left_0_rw_loop:
mov eax,[ecx+esi*4] ;load pattern for this scan
and [edi],ah ;write the high byte
inc esi ;advance to next scan of pattern
and esi,7
add edi,edx ;advance to next scan
dec ebx
jnz short dual_left_0_rw_loop
; get ready for next time:
mov ecx,ppdev
sub edi,[ecx].pdev_pvBitmapStart
mov ulLeftDest,edi
PLAIN_RET
;-----------------------------------------------------------------------;
; dual_right_1_rw
;
; Draws a right edge when not word aligned.
;
; Input:
; ppdev - pointer to physical device structure
; ulBlockHeight - # of scans to draw
; lDelta - distance from end of current scan to start of next
; ulRightDest - offset in bitmap at which to start drawing
; yBrush - current y brush alignment
;
; Output:
; esi - new y brush alignment
; ulRightDest - new bitmap offset
;-----------------------------------------------------------------------;
public dual_right_1_rw
dual_right_1_rw::
; Set right mask by disabling some planes:
mov edx,VGA_BASE + SEQ_DATA
mov eax,ulRightMask
out dx,al
; Calculate full start addresses:
mov edi,ppdev
mov ebx,ulBlockHeight
mov ecx,pulPattern
mov edx,lDelta
mov esi,yBrush
mov edi,[edi].pdev_pvBitmapStart
add edi,ulRightDest
; EBX = count of loop iterations
; ECX = pointer to start of pattern
; EDX = offset to next scan
; ESI = current offset into pattern
; EDI = target address to which to write
dual_right_1_rw_loop:
mov eax,[ecx+esi*4] ;load pattern for this scan
and [edi],ah ;write the high byte
inc esi ;advance to next scan of pattern
and esi,7
add edi,edx ;advance to next scan
dec ebx
jnz short dual_right_1_rw_loop
; get ready for next time:
mov ecx,ppdev
sub edi,[ecx].pdev_pvBitmapStart
mov ulRightDest,edi
PLAIN_RET
;-----------------------------------------------------------------------;
; dual_right_0_rw
;
; Draws a right edge when word aligned.
;
; Input:
; ppdev - pointer to physical device structure
; ulBlockHeight - # of scans to draw
; lDelta - distance from end of current scan to start of next
; ulRightDest - offset in bitmap at which to start drawing
; yBrush - current y brush alignment
;
; Output:
; esi - new y brush alignment
; ulRightDest - new bitmap offset
;-----------------------------------------------------------------------;
public dual_right_0_rw
dual_right_0_rw::
; Set right mask by disabling some planes:
mov edx,VGA_BASE + SEQ_DATA
mov eax,ulRightMask
out dx,al
; Calculate full start addresses:
mov edi,ppdev
mov ebx,ulBlockHeight
mov ecx,pulPattern
mov edx,lDelta
mov esi,yBrush
mov edi,[edi].pdev_pvBitmapStart
add edi,ulRightDest
; EBX = count of loop iterations
; ECX = pointer to start of pattern
; EDX = offset to next scan
; ESI = current offset into pattern
; EDI = target address to which to write
dual_right_0_rw_loop:
mov eax,[ecx+esi*4] ;load pattern for this scan
and [edi],al ;write the low byte
inc esi ;advance to next scan of pattern
and esi,7
add edi,edx ;advance to next scan
dec ebx
jnz short dual_right_0_rw_loop
; get ready for next time:
mov ecx,ppdev
sub edi,[ecx].pdev_pvBitmapStart
mov ulRightDest,edi
PLAIN_RET
;-----------------------------------------------------------------------;
endProc vMonoPat
;-----------------------------------------------------------------------;
; BOOL b2ColorBrush(pjBits, pjFgColor, pjBkColor)
;
; Determines if the 8x8x8bpp packed brush pointed to by pjBits has only
; two colors, and if so returns the 1bpp bitmap.
;
; Returns:
; eax = 1 if two (or one) color brush, 0 otherwise
; pjBits = pointer to packed 1bpp bitmap if a 2-color brush
; *pjFgColor = foreground color for returned 1bpp bitmap (i.e.,
; used to color-expand '1' bits)
; *pjBkColor = backgroun color for returned 1bpp bitmap (i.e.,
; used to color-expand '0' bits)
;-----------------------------------------------------------------------;
cProc b2ColorBrush,12,< \
uses esi edi ebx, \
pjBits: ptr BYTE, \
pjFgColor: ptr BYTE, \
pjBkColor: ptr BYTE >
; al = first color
; ah = second color
; ecx = number of unrolled loops
mov esi,pjBits
mov ecx,(BRUSH_SIZE shr 1)
mov al,[esi]
b2col_find_2nd_color_loop:
mov ah,[esi+1]
cmp ah,al
jne short b2col_find_consecutive_2nd_color_loop_part_1
add esi,2
dec ecx
jz short b2col_is_2_colors ;actually, it's only one color
mov ah,[esi]
cmp ah,al
jne short b2col_find_consecutive_2nd_color_loop_part_2
jmp short b2col_find_2nd_color_loop
;------------------------------------;
b2col_find_consecutive_1st_color_loop_part_1:
add esi,2
dec ecx
jz short b2col_is_2_colors
mov bl,[esi]
cmp bl,ah
je short b2col_find_consecutive_2nd_color_loop_part_2
cmp bl,al
jne short b2col_isnt_2_colors
b2col_find_consecutive_1st_color_loop_part_2:
mov bl,[esi+1]
cmp bl,ah
je short b2col_find_consecutive_2nd_color_loop_part_1
cmp bl,al
je short b2col_find_consecutive_1st_color_loop_part_1
xor eax,eax
cRet b2ColorBrush ;return FALSE
;------------------------------------;
b2col_find_consecutive_2nd_color_loop_part_1:
add esi,2
dec ecx
jz short b2col_is_2_colors
mov bl,[esi]
cmp bl,al
je short b2col_find_consecutive_1st_color_loop_part_2
cmp bl,ah
jne short b2col_isnt_2_colors
b2col_find_consecutive_2nd_color_loop_part_2:
mov bl,[esi+1]
cmp bl,al
je short b2col_find_consecutive_1st_color_loop_part_1
cmp bl,ah
je short b2col_find_consecutive_2nd_color_loop_part_1
b2col_isnt_2_colors:
xor eax,eax
cRet b2ColorBrush ;return FALSE
;------------------------------------;
public b2col_is_2_colors
b2col_is_2_colors::
; Here, we want the color with the lesser value to be in 'al', and the
; other to be in 'ah'.
cmp al,ah
jb short b2col_ordered_colors
xchg al,ah
b2col_ordered_colors:
mov ecx,(BRUSH_SIZE shr 3)
mov esi,pjBits
mov edi,esi
; Colors matching 'al' will get mapped to '1' bits, and colors matching
; 'ah' will get mapped to '0' bits:
b2col_monochrome_bitmap_loop:
cmp [esi+7],ah
adc bl,bl
cmp [esi+6],ah
adc bl,bl
cmp [esi+5],ah
adc bl,bl
cmp [esi+4],ah
adc bl,bl
cmp [esi+3],ah
adc bl,bl
cmp [esi+2],ah
adc bl,bl
cmp [esi+1],ah
adc bl,bl
cmp [esi],ah
adc bl,bl
; At this point, where the 8 bytes of the bitmap were ordered 0 1 2 3 4 5 6 7,
; we've got the monochrome byte in 'bl' ordered 7 6 5 4 3 2 1 0. We want
; the word ordered '3 2 1 0 7 6 5 4 | 7 6 5 4 3 2 1 0' where the lower 4 bits
; of every bit are the planes mask, and the upper 4 bits are ordered to
; facilitate easy rotating.
;
; The word is actually written into a dword in the destination buffer.
mov bh,bl
ror bh,4
mov [edi],ebx ;save this dword of monochrome bitmap
add edi,4
add esi,8
dec ecx
jnz b2col_monochrome_bitmap_loop
; Aside: because of the way this is written, if the two colors are black
; and white (i.e., 0x00 and 0xff), the foreground color will be black (0x00),
; and the background will be white (0xff).
mov esi,pjFgColor
mov edi,pjBkColor
mov [esi],al ;save foreground color
mov [edi],ah ;save background color
mov eax,1
cRet b2ColorBrush
endProc b2ColorBrush
end