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.
 
 
 
 
 
 

2439 lines
76 KiB

;---------------------------Module-Header------------------------------;
; Module Name: fastline.asm
;
; This module goes completely overboard in trying to do fast lines.
; It handles only solid R2_COPYPEN unclipped lines.
;
; Unfortunately, I know of only 4 performance tricks:
;
; 1) Most VGAs can co-process the last write to video memory,
; so we employ a traditional Bresenham-style algorithm (as
; opposed to a run-length version) as this minimizes our
; set-up time, and we can do some work between video writes
; without any throughput penalty.
;
; 2) Most VGAs can do one aligned word write faster than two
; byte writes; consequently we derive a double-stepping DDA
; that does aligned word writes whenever possible (note that
; this only makes sense on x-major lines).
;
; 3) Planar mode can be used to speed up long horizontal lines,
; where the cost to switch from linear to planar mode is offset
; by the ability to light 8 pixels on every word write instead
; of 2.
;
; 4) Most lines have integer end-points, so we accelerate those.
;
; If you're not familiar with GIQ lines, this is not the code to start
; with.
;
; Copyright (c) 1992-1993 Microsoft Corporation
;-----------------------------------------------------------------------;
.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\egavga.inc
include i386\strucs.inc
include i386\driver.inc
include i386\lines.inc
.list
; Length of horizontal line needed before we'll do it in planar mode:
NUM_PELS_NEEDED_FOR_PLANAR_HORIZONTAL equ 64
; Line coordinates are given in 28.4 fixed point format:
F equ 16
FLOG2 equ 4
; The following values must match those in winddi.h!
PD_BEGINSUBPATH equ 00000001h
PD_ENDSUBPATH equ 00000002h
PD_RESETSTYLE equ 00000004h
PD_CLOSEFIGURE equ 00000008h
PD_BEZIERS equ 00000010h
PATHDATA struc
pd_flags dd ?
pd_count dd ?
pd_pptfx dd ?
PATHDATA ends
;-------------------------------------------------------------------------;
; I felt a compelling need to use 'ebp' as a 7th general register, and we
; have no nifty macros for dereferencing frame variables off 'esp'. So
; with this structure I am rolling my own stack frame:
STATE_MEM_SIZE equ 4 ;4 dwords
PROC_MEM_SIZE equ 6 ;6 dwords
STACK_FRAME struc
; State variables (don't add/delete fields without modifying STATE_MEM_SIZE!)
sf_ulOurEbp dd ? ;useful for debugging
sf_ulOriginalEbx dd ?
sf_ulOriginalEdi dd ?
sf_ulOriginalEsi dd ?
; Frame variables (feel free to add/delete fields):
sf_lDelta dd ? ;sign depends on going up or down
sf_pfnReturn dd ? ;where to jump after getting next bank
sf_pfnNextBank dd ? ;routine for getting the next bank
sf_y0 dd ? ;GIQ variables
sf_y1 dd ?
sf_x1 dd ?
sf_pjStart dd ? ;for remembering edi
sf_cAfterThisBank dd ? ;# of pixels to light after this bank
sf_ptlOrg db (size POINTL) dup (?)
;our origin for normalizing the line
sf_ptfxLast db (size POINTL) dup (?)
;the most recent point
sf_ptfxStartFigure db (size POINTL) dup (?)
;the figure's 1st point
sf_bMore dd ? ;more path records to get?
sf_pptfxEnd dd ? ;points to last point in record
sf_pptfx dd ? ;points to current point
sf_pd db (size PATHDATA) dup (?)
;pathdata structure
; Procedure variables (don't add/delete fields without modifying
; PROC_MEM_SIZE!)
sf_ulOriginalEbp dd ?
sf_ulOriginalReturn dd ?
sf_ppdev dd ?
sf_ppo dd ?
sf_lNextScan dd ?
sf_iColor dd ?
STACK_FRAME ends
.code
EXTRNP PATHOBJ_bEnum,8
ROUND_X_DOWN equ 01h
ROUND_Y_DOWN equ 02h
ROUND_SLOPE_ONE equ 04h
ROUND_X_AND_Y_DOWN equ (ROUND_X_DOWN + ROUND_Y_DOWN)
ROUND_X_DOWN_SLOPE_ONE equ (ROUND_X_DOWN + ROUND_SLOPE_ONE)
ROUND_Y_DOWN_SLOPE_ONE equ (ROUND_Y_DOWN + ROUND_SLOPE_ONE)
;--------------------------------Macro----------------------------------;
; GIQ flags
;
; This macros computes the start pixel, the number of pixels to
; be lit, and the initial error term given a GIQ line. The line must
; have already been normalized such that dM >= dN, dN >= 0.
;
; Input: eax - M0
; ebx - N0
; ecx - dM
; edx - dN
; Trashes:
; esi, ebp
; [esp].sf_ptlOrg.ptl_x, [esp].sf_ptlOrg.ptl_y
; Output:
; [esp].sf_x1 - x-coordinate of last pixel (exclusive)
; eax - x-coordinate of first pixel
; ebx - error term
; ecx - dM
; edx - dN
; edi - y-coordinate of first pixel
;-----------------------------------------------------------------------;
GIQ macro flags
local compute_x1, compute_error_term
; We normalize our coordinate system so that if the start point is
; (M0/F, N0/F), the origin is at (floor(M0/F), (N0/F)):
mov esi,eax
mov edi,ebx
sar esi,FLOG2
sar edi,FLOG2
mov [esp].sf_ptlOrg.ptl_x,esi
;ptlOrg.x = floor(M0 / F)
mov [esp].sf_ptlOrg.ptl_y,edi
;ptlOrg.y = floor(N0 / F)
; Calculate the correct [esp].sf_x1:
lea edi,[ebx + edx] ;edi = N1
and edi,F - 1
if (flags AND ROUND_X_DOWN)
if (flags AND ROUND_SLOPE_ONE)
cmp edi,8
sbb edi,-1
endif
cmp edi,1
sbb edi,8 ;N1 -= 8
else
sub edi,8 ;N1 -= 8
endif
sbb esi,esi
xor edi,esi
sub edi,esi ;N1 = ABS(N1)
lea ebp,[eax + ecx]
mov esi,ebp
sar ebp,FLOG2
and esi,F - 1
jz short @f ;special case for M1 == 0
cmp esi,edi ;cmp M1, N1
sbb ebp,-1 ;ebp is now one pixel past the actual
@@: ; end coordinate (note that it hasn't
; been affected by the origin shift)
compute_error_term:
; eax = M0
; ebx = N0
; ebp = x1
; ecx = dM
; edx = dN
and ebx,F - 1
mov [esp].sf_x1,ebp ;save x1
; Calculate our error term for x = 0.
;
; NOTE: Since this routine is used only for lines that are unclipped, we
; are guaranteed by our screen size that the values will be far less
; than 32 bits in significance, and so we don't worry about overflow.
; If this is used for clipped lines, these multiplies will have to
; be converted to give 64 bit results, because we can have 36 bits of
; significance!
lea edi,[ebx + 8] ;edi = N0 + 8
mov esi,ecx
imul esi,edi ;esi = dM * (N0 + 8)
mov edi,edx
; We have to special case when M0 is 0 -- we know x0 will be zero.
; So we jump ahead a bit to a place where 'eax' is assumed to contain
; x0 -- and it just so happens 'eax' is zero in this case:
and eax,F - 1
jz short @f
imul edi,eax ;edi = dN * M0
sub esi,edi
; Calculate the x-coordinate of the first pixel:
if (flags AND ROUND_X_DOWN)
if (flags AND ROUND_SLOPE_ONE)
cmp ebx,8
sbb ebx,-1
endif
cmp ebx,1
sbb ebx,8 ;N0 -= 8
else
sub ebx,8 ;N0 -= 8
endif
sbb edi,edi
xor ebx,edi
sub ebx,edi ;N0 = ABS(N0)
cmp eax,ebx
sbb eax,eax
not eax ;eax = -x0
; Now adjust the error term accordingly:
@@:
if (flags AND ROUND_Y_DOWN)
dec esi
endif
sar esi,FLOG2 ;esi = floor((N0 + 8) dM - M0 dN] / 16)
mov ebx,[esp].sf_ptlOrg.ptl_x
mov edi,[esp].sf_ptlOrg.ptl_y
sub ebx,eax ;ebx = ptlOrg.ptl_x + x0
and eax,edx
add eax,esi
sub eax,ecx ;eax = dN * x0 + initial error - dM
jl short @f ;if the error term >= 0, we have to
sub eax,ecx ; add 1 to the y position and subtract
inc edi ; dM off again
@@:
xchg eax,ebx
endm
;--------------------------------Macro----------------------------------;
; GIQR flags
;
; Same as above, except it handles flips about the line x = y.
;
; Input: eax - M0
; ebx - N0
; ecx - dM
; edx - dN
; Trashes:
; esi, ebp
; [esp].sf_ptlOrg.ptl_x, [esp].sf_ptlOrg.ptl_y
; Output:
; [esp].sf_y1 - y-coordinate of last pixel (exclusive)
; eax - x-coordinate of first pixel
; ebx - error term
; ecx - dM
; edx - dN
; edi - y-coordinate of first pixel
;-----------------------------------------------------------------------;
GIQR macro flags
; We normalize our coordinate system so that if the start point is
; (M0/F, N0/F), the origin is at (floor(M0/F), (N0/F)):
mov esi,eax
mov edi,ebx
sar esi,FLOG2
sar edi,FLOG2
mov [esp].sf_ptlOrg.ptl_x,esi
;ptlOrg.x = floor(M0 / F)
mov [esp].sf_ptlOrg.ptl_y,edi
;ptlOrg.y = floor(N0 / F)
; Calculate the correct [esp].sf_y1:
lea edi,[eax + ecx] ;edi = M1
and edi,F - 1
if (flags AND ROUND_Y_DOWN)
cmp edi,1
sbb edi,8 ;M1 -= 8
else
sub edi,8 ;M1 -= 8
endif
sbb esi,esi
xor edi,esi
sub edi,esi ;M1 = ABS(M1)
lea ebp,[ebx + edx]
mov esi,ebp
sar ebp,FLOG2
and esi,F - 1
jz short @f ;special case for N1 == 0
cmp esi,edi ;cmp N1, M1
sbb ebp,-1 ;ebp is now one pixel past the actual
@@: ; end coordinate (note that it hasn't
; been affected by the origin shift)
and eax,F - 1
mov [esp].sf_y1,ebp
; Calculate our error term for y = 0.
;
; NOTE: Since this routine is used only for lines that are unclipped, we
; are guaranteed by our screen size that the values will be far less
; than 32 bits in significance, and so we don't worry about overflow.
; If this is used for clipped lines, these multiplies will have to
; be converted to give 64 bit results, because we can have 36 bits of
; significance!
lea edi,[eax + 8] ;edi = M0 + 8
mov esi,edx
imul esi,edi ;esi = dN * (M0 + 8)
mov edi,ecx
; We have to special case when N0 is 0 -- we know y0 will be zero.
; So we jump ahead a bit to a place where 'ebx' is assumed to contain
; y0 -- and it just so happens 'ebx' is zero in this case:
and ebx,F - 1
jz short @f
imul edi,ebx ;edi = dM * N0
sub esi,edi
; Calculate the x-coordinate of the first pixel:
if (flags AND ROUND_Y_DOWN)
cmp eax,1
sbb eax,8 ;M0 -= 8
else
sub eax,8 ;M0 -= 8
endif
sbb edi,edi
xor eax,edi
sub eax,edi ;M0 = ABS(M0)
cmp ebx,eax
sbb ebx,ebx
not ebx ;ebx = -y0
; Now adjust the error term accordingly:
@@:
if (flags AND ROUND_X_DOWN)
dec esi
endif
sar esi,FLOG2 ;esi = floor((M0 + 8) dN - N0 dM] / 16)
mov eax,[esp].sf_ptlOrg.ptl_x
mov edi,[esp].sf_ptlOrg.ptl_y
sub edi,ebx ;edi = ptlOrg.ptl_y + y0
and ebx,ecx
add ebx,esi
sub ebx,edx ;ebx = dM * x0 + initial error - dN
jl short @f ;if the error term >= 0, we have to
sub ebx,edx ; add 1 to the x position and subtract
inc eax ; dN off again
@@:
endm
;---------------------------Public-Routine------------------------------;
; vFastLine(ppdev, ppo, lNextScan, iColor)
;
; Draws fast lines. Or at least attempts to.
;
; Input:
;
; ppdev - PDEV pointer
; ppo - path
; lNextScan - delta to start of next scan (same as ppdev->lNextScan)
; iColor - color (least significant byte must be the same as the next
; least signficant byte, so that we can do words writes)
;
;-----------------------------------------------------------------------;
; NOTE: Don't go changing parameters without also changing STACK_FRAME!
cProc vFastLine,16,< \
uses esi edi ebx, \
ebp_ppdev: ptr, \
ebp_ppo: ptr, \
ebp_lNextScan: ptr, \
ebp_iColor: dword >
; Leave room for our stack frame.
;
; NOTE: Don't add local variables here -- you can't reference them with
; ebp anyway! Add them to the STACK_FRAME structure.
local aj[(size STACK_FRAME) - 4 * (STATE_MEM_SIZE + PROC_MEM_SIZE)]: byte
; We save 'ebp' on the stack (note that STACK_FRAME accounts for this push):
push ebp
; Now get some path stuff:
next_record:
mov esi,[esp].sf_ppo
lea eax,[esp].sf_pd
cCall PATHOBJ_bEnum,<esi,eax>
mov [esp].sf_bMore,eax ;save away return code for later
mov eax,[esp].sf_pd.pd_count;if 0 points in record, get outta here
or eax,eax
jz check_for_closefigure
lea edi,[8 * eax - 8]
add edi,[esp].sf_pd.pd_pptfx
mov [esp].sf_pptfxEnd,edi ;points to last point in record
mov ebx,[esp].sf_pd.pd_flags
test ebx,PD_BEGINSUBPATH
jz short continue_subpath
; Handle a new sub-path:
mov esi,[esp].sf_pd.pd_pptfx
add esi,8
mov [esp].sf_pptfx,esi
mov ecx,[edi].ptl_x ;remember last point in case we have
mov edx,[edi].ptl_y ; to continue to another record
mov [esp].sf_ptfxLast.ptl_x,ecx
mov [esp].sf_ptfxLast.ptl_y,edx
mov eax,[esi - 8].ptl_x ;load up current start and end point
mov ebx,[esi - 8].ptl_y
mov ecx,[esi].ptl_x
mov edx,[esi].ptl_y
mov [esp].sf_ptfxStartFigure.ptl_x,eax
mov [esp].sf_ptfxStartFigure.ptl_y,ebx
cmp esi,[esp].sf_pptfxEnd ;we have to be careful when the only
; point in the record is the start-
; figure point (pretty rare)
jbe new_line
jmp short next_record
continue_subpath:
; This record continues the path:
mov esi,[esp].sf_pd.pd_pptfx
mov eax,[esp].sf_ptfxLast.ptl_x ;load up current start point
mov ebx,[esp].sf_ptfxLast.ptl_y
mov ecx,[edi].ptl_x ;remember last point in case we have
mov edx,[edi].ptl_y ; to continue to another record
mov [esp].sf_ptfxLast.ptl_x,ecx
mov [esp].sf_ptfxLast.ptl_y,edx
mov ecx,[esi].ptl_x ;load up current end point
mov edx,[esi].ptl_y
mov [esp].sf_pptfx,esi
jmp short new_line
;/////////////////////////////////////////////////////////////////////
;// Next Line Stuff
;/////////////////////////////////////////////////////////////////////
handle_closefigure:
mov [esp].sf_pd.pd_flags,0
mov eax,[esp].sf_ptfxLast.ptl_x
mov ebx,[esp].sf_ptfxLast.ptl_y
mov ecx,[esp].sf_ptfxStartFigure.ptl_x
mov edx,[esp].sf_ptfxStartFigure.ptl_y
jmp new_line
; Before getting the next path record, see if we have to do a closefigure:
check_for_closefigure:
test [esp].sf_pd.pd_flags,PD_CLOSEFIGURE
jnz handle_closefigure
mov ecx,[esp].sf_bMore
or ecx,ecx
jnz next_record
all_done:
pop ebp
cRet vFastLine
public next_line
next_line::
mov esi,[esp].sf_pptfx
cmp esi,[esp].sf_pptfxEnd
jae short check_for_closefigure
mov eax,[esi].ptl_x
mov ebx,[esi].ptl_y
mov ecx,[esi+8].ptl_x
mov edx,[esi+8].ptl_y
add esi,8
mov [esp].sf_pptfx,esi
;/////////////////////////////////////////////////////////////////////
;// Main Loop
;/////////////////////////////////////////////////////////////////////
public new_line
new_line::
; Octants are numbered as follows:
;
; \ 5 | 6 /
; \ | /
; 4 \ | / 7
; \ /
; -----+-----
; /|\
; 3 / | \ 0
; / | \
; / 2 | 1 \
;
; eax = M0
; ebx = N0
; ecx = M1 (dM)
; edx = N1 (dN)
sub ecx,eax
jl octants_2_3_4_5
sub edx,ebx
jl octants_6_7
cmp ecx,edx
jl octant_1
;/////////////////////////////////////////////////////////////////////
;// Octant 0
;/////////////////////////////////////////////////////////////////////
public octant_0
octant_0::
mov esi,[esp].sf_lNextScan
mov [esp].sf_lDelta,esi ;we're going down
mov [esp].sf_pfnNextBank,offset bank_x_major_next_lower
mov esi,ecx
or esi,edx
jz next_line ;we do an early check here for
; lines that start and end on the
; same GIQ point, because those
; occur surprisingly often.
or esi,eax
or esi,ebx
and esi,F - 1
jnz oct_0_non_integer
or edx,edx
jz do_horizontal_line
mov esi,[esp].sf_ppdev
sar eax,FLOG2 ;x0
sar ebx,FLOG2 ;y0
cmp ebx,[esi].pdev_rcl1WindowClip.yTop
jl short oct_0_map_in_bank
cmp ebx,[esi].pdev_rcl1WindowClip.yBottom
jl short oct_0_done_bank_map
oct_0_map_in_bank:
push eax
push ecx
push edx
; ebx, esi, edi and ebp are preserved according to C calling conventions:
ptrCall <dword ptr [esi].pdev_pfnBankControl>, \
<esi, ebx, JustifyTop> ;###
pop edx
pop ecx
pop eax
public oct_0_done_bank_map
oct_0_done_bank_map::
mov edi,[esp].sf_lNextScan
imul edi,ebx
add edi,[esi].pdev_pvBitmapStart
add edi,eax ;edi now points to start byte
mov ebp,[esi].pdev_rcl1WindowClip.yBottom
sub ebp,ebx ;### ebp = # of scans before end of bank
mov esi,ecx
sar esi,FLOG2 ;esi = # of pixels to lay down
mov ebx,-1 ;### round y = 1/2 *DOWN* in value
sub ebx,ecx
sar ebx,1 ;now have error term
mov eax,[esp].sf_iColor
sub ecx,edx ;ecx = dM - dN
cmp edx,ecx
jg oct_07b
;-------------------------------------------------------------------------;
; Left-to-right Lines With ABS(Slope) <= 1/2
; ------------------------------------------
;
; Since the line's slope is less than 1/2, we have only 3 possibilities
; at each pair of pixels:
;
; Case 1: o Case 2: o o Case 3: o o o
; o o o
;
; Case: err + dN >= 0 err + 2dN >= 0 err + 2dN < 0
; New: err += 2dN - dM err += 2dN - dM err += 2dN
;
; eax = color
; ebx = error term
; ecx = dM - dN
; edx = dN
; esi = # of pixels to lay down
; edi = memory pointer
; ebp = # of scans before end of bank
;-------------------------------------------------------------------------;
public oct_07a
oct_07a::
test edi,1
jz short oct_07a_main ;start is word aligned
; Handle unaligned start:
dec esi
jl next_line
mov [edi],al
inc edi
add ebx,edx ;err += dN
jl short oct_07a_main
add edi,[esp].sf_lDelta
dec ebp ;hit a new bank?
jz short oct_07a_next_bank_3
oct_07a_done_bank_3:
sub ebx,ecx ;err += dN - dM
jl short oct_07a_continue
;;; Case 1:
public oct_07a_case_1
oct_07a_case_1::
sub esi,2
jl short oct_07a_done
mov [edi],al
add edi,[esp].sf_lDelta
add edi,2
dec ebp
jz short oct_07a_next_bank_1
oct_07a_done_bank_1:
mov [edi-1],al
sub ebx,ecx ;err += dN - dM
;;;case 1 is done
;;; Main loop:
oct_07a_main:
add ebx,edx ;err += dN
jge short oct_07a_case_1
oct_07a_continue:
sub esi,2
jl short oct_07a_done
mov [edi],ax
add edi,2
add ebx,edx ;err += dN
jl short oct_07a_main ;;;case 3 is done
;;; Handle end of case 2:
add edi,[esp].sf_lDelta
dec ebp
jz short oct_07a_next_bank_2
oct_07a_done_bank_2:
sub ebx,ecx ;err += dN - dM
jge short oct_07a_case_1
jmp short oct_07a_continue ;;;case 2 is done
oct_07a_done:
inc esi ;esi = -1 means do another pixel
jnz next_line
mov [edi],al
jmp next_line
oct_07a_next_bank_1:
mov [esp].sf_pfnReturn,offset oct_07a_done_bank_1
jmp [esp].sf_pfnNextBank
oct_07a_next_bank_2:
mov [esp].sf_pfnReturn,offset oct_07a_done_bank_2
jmp [esp].sf_pfnNextBank
oct_07a_next_bank_3:
mov [esp].sf_pfnReturn,offset oct_07a_done_bank_3
jmp [esp].sf_pfnNextBank
;-------------------------------------------------------------------------;
; Left-to-right Lines With 1/2 < ABS(Slope) <= 1
; ----------------------------------------------
;
; Since the line's slope is between 1/2 and 1, we have only 3 possibilities
; at each pair of pixels:
;
; Case 1: o o Case 2: o Case 3: o
; o o o o
; o
;
; Case: err + dN < 0 err + 2dN - dM < 0 err + 2dN - dM >= 0
; New: err += 2dN - dM err += 2dN - dM err += 2dN - 2dM
;
; eax = color
; ebx = error term
; ecx = dM - dN
; edx = dN
; esi = # of pixels to lay down
; edi = memory pointer
; ebp = # of scans before end of bank
;-------------------------------------------------------------------------;
public oct_07b
oct_07b::
test edi,1
jz short oct_07b_main
dec esi
jl next_line
mov [edi],al
inc edi
add ebx,edx ;err += dN
jl short oct_07b_main
add edi,[esp].sf_lDelta
dec ebp
jz short oct_07b_next_bank_4
oct_07b_done_bank_4:
sub ebx,ecx ;err += dN - dM
jge short oct_07b_continue
public oct_07b_case_1
oct_07b_case_1::
sub esi,2
jl short oct_07b_done
mov [edi],ax
add edi,[esp].sf_lDelta
add edi,2
dec ebp
jz short oct_07b_next_bank_1
oct_07b_done_bank_1:
sub ebx,ecx ;err += dN - dM
;;;case 1 is done
;;; Main loop:
oct_07b_main:
add ebx,edx ;err += dN
jl short oct_07b_case_1
oct_07b_continue:
sub esi,2
jl short oct_07b_done
mov [edi],al
add edi,[esp].sf_lDelta
add edi,2
dec ebp
jz short oct_07b_next_bank_2
oct_07b_done_bank_2:
mov [edi-1],al
sub ebx,ecx ;err += dN - dM
jl short oct_07b_main ;;;case 2 is done
add edi,[esp].sf_lDelta
dec ebp
jz oct_07b_next_bank_3
oct_07b_done_bank_3:
sub ebx,ecx ;err += dN - dM
jl short oct_07b_case_1 ;;;case 3 is done
jmp short oct_07b_continue
oct_07b_next_bank_4:
mov [esp].sf_pfnReturn,offset oct_07b_done_bank_4
jmp [esp].sf_pfnNextBank
oct_07b_next_bank_3:
mov [esp].sf_pfnReturn,offset oct_07b_done_bank_3
jmp [esp].sf_pfnNextBank
oct_07b_next_bank_2:
mov [esp].sf_pfnReturn,offset oct_07b_done_bank_2
jmp [esp].sf_pfnNextBank
oct_07b_next_bank_1:
mov [esp].sf_pfnReturn,offset oct_07b_done_bank_1
jmp [esp].sf_pfnNextBank
oct_07b_done:
inc esi
jnz next_line ;esi = -1 means do another pixel
mov [edi],al
jmp next_line
;-------------------------------------------------------------------------;
public oct_0_non_integer
oct_0_non_integer::
cmp ecx,edx
je oct_0_slope_one ;have a special case rounding rule for
; 45 degree lines (which only affects
; non-integer lines)
GIQ ROUND_X_AND_Y_DOWN ;### round x=1/2, y=1/2 down in value
or edx,edx
jz do_non_integer_horizontal_line
oct_0_common:
mov esi,[esp].sf_ppdev
cmp edi,[esi].pdev_rcl1WindowClip.yTop
jl short oct_0_nonint_map_in_bank
cmp edi,[esi].pdev_rcl1WindowClip.yBottom
jl short oct_0_nonint_done_bank_map
oct_0_nonint_map_in_bank:
push eax
push ecx
push edx
ptrCall <dword ptr [esi].pdev_pfnBankControl>, \
<esi, edi, JustifyTop> ;###
pop edx
pop ecx
pop eax
oct_0_nonint_done_bank_map:
mov ebp,[esi].pdev_rcl1WindowClip.yBottom
sub ebp,edi ;### ebp = # scans before end of bank
imul edi,[esp].sf_lNextScan ;
add edi,[esi].pdev_pvBitmapStart
add edi,eax ;edi now points to start byte
mov esi,[esp].sf_x1
sub esi,eax ;esi = # pixels to lay down
mov eax,[esp].sf_iColor
sub ecx,edx ;ecx = dM - dN
cmp edx,ecx
jg oct_07b
jmp oct_07a
;-------------------------------------------------------------------;
; 45 degree lines have a special rounding rule: when the line
; runs exactly half way between to pixels, the upper or right pel
; is illuminated. This translates into x=1/2 rounding up, and
; y=1/2 rounding down in value:
public oct_0_slope_one
oct_0_slope_one::
GIQ ROUND_Y_DOWN_SLOPE_ONE ;round y=1/2 down in value
jmp oct_0_common
;/////////////////////////////////////////////////////////////////////
;// Octant 1
;/////////////////////////////////////////////////////////////////////
public octant_1
octant_1::
mov [esp].sf_pfnNextBank,offset bank_y_major_next_lower
mov esi,eax
or esi,ebx
or esi,ecx
or esi,edx
and esi,F - 1
jnz oct_1_non_integer
mov esi,[esp].sf_ppdev
sar eax,FLOG2 ;x0
sar ebx,FLOG2 ;y0
cmp ebx,[esi].pdev_rcl1WindowClip.yTop
jl short oct_1_map_in_bank
cmp ebx,[esi].pdev_rcl1WindowClip.yBottom
jl short oct_1_done_bank_map
oct_1_map_in_bank:
push eax
push ecx
push edx
; ebx, esi, edi and ebp are preserved according to C calling conventions:
ptrCall <dword ptr [esi].pdev_pfnBankControl>, \
<esi, ebx, JustifyTop> ;###
pop edx
pop ecx
pop eax
public oct_1_done_bank_map
oct_1_done_bank_map::
mov edi,[esp].sf_lNextScan
imul edi,ebx
add edi,[esi].pdev_pvBitmapStart
add edi,eax ;edi now points to start byte
mov ebp,[esi].pdev_rcl1WindowClip.yBottom
sub ebp,ebx ;### ebp = # of scans before end of bank
mov esi,edx
sar esi,FLOG2 ;esi = # of pixels to lay down
sub esi,ebp
sbb ebx,ebx
and ebx,esi
add ebp,ebx ;ebp = # of pels in this bank
mov [esp].sf_cAfterThisBank,esi
mov esi,[esp].sf_lNextScan
mov ebx,-1 ;### round x = 1/2 *DOWN* in value
sub ebx,edx
sar ebx,1 ;now have error term
mov eax,[esp].sf_iColor
;-------------------------------------------------------------------------;
; Left-to-right Lines With Abs(Slope) > 1/2
; -----------------------------------------
;
; eax = color
; ebx = error term
; ecx = dM
; edx = dN
; esi = delta
; edi = memory pointer
; ebp = # of scans before end of bank
;-------------------------------------------------------------------------;
oct_1_main_loop:
dec ebp
jl short oct_1_see_if_more
mov [edi],al
add edi,esi
add ebx,ecx ;err += dM
jl short oct_1_main_loop
inc edi ;one to right
sub ebx,edx ;err -= dN
; Unroll a bit:
dec ebp
jl short oct_1_see_if_more
mov [edi],al
add edi,esi
add ebx,ecx ;err += dM
jl short oct_1_main_loop
inc edi ;one to right
sub ebx,edx ;err -= dN
jmp short oct_1_main_loop
public oct_1_see_if_more
oct_1_see_if_more::
mov eax,[esp].sf_cAfterThisBank
cmp eax,0
jle next_line
mov [esp].sf_pfnReturn,offset oct_1_main_loop
jmp [esp].sf_pfnNextBank
public oct_1_non_integer
oct_1_non_integer::
GIQR ROUND_X_AND_Y_DOWN ;### round x=1/2, y=1/2 down in value
mov esi,[esp].sf_ppdev
cmp edi,[esi].pdev_rcl1WindowClip.yTop
jl short oct_1_nonint_map_in_bank
cmp edi,[esi].pdev_rcl1WindowClip.yBottom
jl short oct_1_nonint_done_bank_map
oct_1_nonint_map_in_bank:
push eax
push ecx
push edx
ptrCall <dword ptr [esi].pdev_pfnBankControl>, \
<esi, edi, JustifyTop> ;###
pop edx
pop ecx
pop eax
oct_1_nonint_done_bank_map:
mov [esp].sf_y0,edi
imul edi,[esp].sf_lNextScan
add edi,[esi].pdev_pvBitmapStart
add edi,eax ;edi points to start byte
mov ebp,[esi].pdev_rcl1WindowClip.yBottom
mov esi,[esp].sf_y1
sub esi,ebp
sbb eax,eax
and eax,esi
add ebp,eax
sub ebp,[esp].sf_y0 ;ebp = min(y1,
; ppdev->rcl1WindowClip.yBottom) - y0
; (# of pixels to lay down)
mov [esp].sf_cAfterThisBank,esi
mov esi,[esp].sf_lNextScan
mov eax,[esp].sf_iColor
jmp oct_1_main_loop
;/////////////////////////////////////////////////////////////////////
;// Octant 3
;/////////////////////////////////////////////////////////////////////
octants_2_3_4_5:
neg ecx ;dM = -dM (now positive)
neg eax ;M0 = -M0
sub edx,ebx
jl octants_4_5
cmp ecx,edx
jl octant_2
public octant_3
octant_3::
mov esi,[esp].sf_lNextScan
mov [esp].sf_lDelta,esi ;we're going down
mov [esp].sf_pfnNextBank,offset bank_x_major_next_lower
mov esi,eax
or esi,ebx
or esi,ecx
or esi,edx
and esi,F - 1
jnz oct_3_non_integer
or edx,edx
jz flip_and_do_horizontal_line
mov esi,[esp].sf_ppdev
neg eax ;### untransform M0
sar eax,FLOG2 ;x0
sar ebx,FLOG2 ;y0
cmp ebx,[esi].pdev_rcl1WindowClip.yTop
jl short oct_3_map_in_bank
cmp ebx,[esi].pdev_rcl1WindowClip.yBottom
jl short oct_3_done_bank_map
oct_3_map_in_bank:
push eax
push ecx
push edx
; ebx, esi, edi and esi are preserved according to C calling conventions:
ptrCall <dword ptr [esi].pdev_pfnBankControl>, \
<esi, ebx, JustifyTop> ;###
pop edx
pop ecx
pop eax
public oct_3_done_bank_map
oct_3_done_bank_map::
mov edi,[esp].sf_lNextScan
imul edi,ebx
add edi,[esi].pdev_pvBitmapStart
add edi,eax ;edi now points to start byte
mov ebp,[esi].pdev_rcl1WindowClip.yBottom
sub ebp,ebx ;### ebp = # of scans before end of bank
mov esi,ecx
sar esi,FLOG2 ;esi = # of pixels to lay down
mov ebx,-1 ;### round y = 1/2 *DOWN* in value
sub ebx,ecx
sar ebx,1 ;now have error term
mov eax,[esp].sf_iColor
sub ecx,edx ;ecx = dM - dN
cmp edx,ecx
jg oct_34b
;-------------------------------------------------------------------------;
; Right-to-left Lines With ABS(Slope) <= 1/2
; ------------------------------------------
;
; Since the line's slope is less than 1/2, we have only 3 possibilities
; at each pair of pixels:
;
; Case 1: o Case 2: o o Case 3: o o o
; o o o
;
; Case: err + dN >= 0 err + 2dN >= 0 err + 2dN < 0
; New: err += 2dN - dM err += 2dN - dM err += 2dN
;
; eax = color
; ebx = error term
; ecx = dM - dN
; edx = dN
; esi = # of pixels to lay down
; edi = memory pointer
; ebp = # of scans before end of bank
;-------------------------------------------------------------------------;
oct_34a:
test edi,1
jnz short oct_34a_main ;### start is word aligned
; Handle unaligned start:
dec esi
jl next_line
mov [edi],al
dec edi ;###
add ebx,edx ;err += dN
jl short oct_34a_main
add edi,[esp].sf_lDelta
dec ebp ;hit a new bank?
jz short oct_34a_next_bank_3
oct_34a_done_bank_3:
sub ebx,ecx ;err += dN - dM
jl short oct_34a_continue
;;; Case 1:
public oct_34a_case_1
oct_34a_case_1::
sub esi,2
jl short oct_34a_done
mov [edi],al
add edi,[esp].sf_lDelta
sub edi,2 ;###
dec ebp
jz short oct_34a_next_bank_1
oct_34a_done_bank_1:
mov [edi+1],al
sub ebx,ecx ;err += dN - dM
;;;case 1 is done
;;; Main loop:
oct_34a_main:
add ebx,edx ;err += dN
jge short oct_34a_case_1
oct_34a_continue:
sub esi,2
jl short oct_34a_done
mov [edi-1],ax ;###
sub edi,2 ;###
add ebx,edx ;err += dN
jl short oct_34a_main ;;;case 3 is done
;;; Handle end of case 2:
add edi,[esp].sf_lDelta
dec ebp
jz short oct_34a_next_bank_2
oct_34a_done_bank_2:
sub ebx,ecx ;err += dN - dM
jge short oct_34a_case_1
jmp short oct_34a_continue ;;;case 2 is done
oct_34a_done:
inc esi ;esi = -1 means do another pixel
jnz next_line
mov [edi],al
jmp next_line
oct_34a_next_bank_1:
mov [esp].sf_pfnReturn,offset oct_34a_done_bank_1
jmp [esp].sf_pfnNextBank
oct_34a_next_bank_2:
mov [esp].sf_pfnReturn,offset oct_34a_done_bank_2
jmp [esp].sf_pfnNextBank
oct_34a_next_bank_3:
mov [esp].sf_pfnReturn,offset oct_34a_done_bank_3
jmp [esp].sf_pfnNextBank
;-------------------------------------------------------------------------;
; Right-to-left Lines With 1/2 < ABS(Slope) <= 1
; ----------------------------------------------
;
; Since the line's slope is between 1/2 and 1, we have only 3 possibilities
; at each pair of pixels:
;
; Case 1: o o Case 2: o Case 3: o
; o o o o
; o
;
; Case: err + dN < 0 err + 2dN - dM < 0 err + 2dN - dM >= 0
; New: err += 2dN - dM err += 2dN - dM err += 2dN - 2dM
;
; eax = color
; ebx = error term
; ecx = dM - dN
; edx = dN
; esi = # of pixels to lay down
; edi = memory pointer
; ebp = # of scans before end of bank
;-------------------------------------------------------------------------;
public oct_34b
oct_34b::
test edi,1
jnz short oct_34b_main ;###
dec esi
jl next_line
mov [edi],al
dec edi ;###
add ebx,edx ;err += dN
jl short oct_34b_main
add edi,[esp].sf_lDelta
dec ebp
jz short oct_34b_next_bank_4
oct_34b_done_bank_4:
sub ebx,ecx ;err += dN - dM
jge short oct_34b_continue
public oct_34b_case_1
oct_34b_case_1::
sub esi,2
jl short oct_34b_done
mov [edi-1],ax ;###
add edi,[esp].sf_lDelta
sub edi,2 ;###
dec ebp
jz short oct_34b_next_bank_1
oct_34b_done_bank_1:
sub ebx,ecx ;err += dN - dM
;;;case 1 is done
;;; Main loop:
oct_34b_main:
add ebx,edx ;err += dN
jl short oct_34b_case_1
oct_34b_continue:
sub esi,2
jl short oct_34b_done
mov [edi],al
add edi,[esp].sf_lDelta
sub edi,2 ;###
dec ebp
jz short oct_34b_next_bank_2
oct_34b_done_bank_2:
mov [edi+1],al
sub ebx,ecx ;err += dN - dM
jl short oct_34b_main ;;;case 2 is done
add edi,[esp].sf_lDelta
dec ebp
jz oct_34b_next_bank_3
oct_34b_done_bank_3:
sub ebx,ecx ;err += dN - dM
jl short oct_34b_case_1 ;;;case 3 is done
jmp short oct_34b_continue
oct_34b_next_bank_4:
mov [esp].sf_pfnReturn,offset oct_34b_done_bank_4
jmp [esp].sf_pfnNextBank
oct_34b_next_bank_3:
mov [esp].sf_pfnReturn,offset oct_34b_done_bank_3
jmp [esp].sf_pfnNextBank
oct_34b_next_bank_2:
mov [esp].sf_pfnReturn,offset oct_34b_done_bank_2
jmp [esp].sf_pfnNextBank
oct_34b_next_bank_1:
mov [esp].sf_pfnReturn,offset oct_34b_done_bank_1
jmp [esp].sf_pfnNextBank
oct_34b_done:
inc esi
jnz next_line ;esi = -1 means do another pixel
mov [edi],al
jmp next_line
;-------------------------------------------------------------------------;
public oct_3_non_integer
oct_3_non_integer::
GIQ ROUND_Y_DOWN ;### round y=1/2 down in value
;### (remember that we're flipped
;### in 'x')
or edx,edx
jz flip_and_do_non_integer_horizontal_line
mov esi,[esp].sf_ppdev
neg eax ;### Untransform x0
cmp edi,[esi].pdev_rcl1WindowClip.yTop
jl short oct_3_nonint_map_in_bank
cmp edi,[esi].pdev_rcl1WindowClip.yBottom
jl short oct_3_nonint_done_bank_map
oct_3_nonint_map_in_bank:
push eax
push ecx
push edx
ptrCall <dword ptr [esi].pdev_pfnBankControl>, \
<esi, edi, JustifyTop> ;###
pop edx
pop ecx
pop eax
oct_3_nonint_done_bank_map:
mov ebp,[esi].pdev_rcl1WindowClip.yBottom
sub ebp,edi ;### ebp = # scans before end of bank
imul edi,[esp].sf_lNextScan ;
add edi,[esi].pdev_pvBitmapStart
add edi,eax ;edi now points to start byte
mov esi,[esp].sf_x1
add esi,eax ;### esi = # pixels to lay down
mov eax,[esp].sf_iColor
sub ecx,edx ;ecx = dM - dN
cmp edx,ecx
jg oct_34b
jmp oct_34a
;/////////////////////////////////////////////////////////////////////
;// Octant 2
;/////////////////////////////////////////////////////////////////////
public octant_2
octant_2::
mov [esp].sf_pfnNextBank,offset bank_y_major_next_lower
mov esi,eax
or esi,ebx
or esi,ecx
or esi,edx
and esi,F - 1
jnz oct_2_non_integer
neg eax ;### untransform M0
mov esi,[esp].sf_ppdev
sar eax,FLOG2 ;x0
sar ebx,FLOG2 ;y0
cmp ebx,[esi].pdev_rcl1WindowClip.yTop
jl short oct_2_map_in_bank
cmp ebx,[esi].pdev_rcl1WindowClip.yBottom
jl short oct_2_done_bank_map
oct_2_map_in_bank:
push eax
push ecx
push edx
; ebx, esi, edi and ebp are preserved according to C calling conventions:
ptrCall <dword ptr [esi].pdev_pfnBankControl>, \
<esi, ebx, JustifyTop> ;###
pop edx
pop ecx
pop eax
public oct_2_done_bank_map
oct_2_done_bank_map::
mov edi,[esp].sf_lNextScan
imul edi,ebx
add edi,[esi].pdev_pvBitmapStart
add edi,eax ;edi now points to start byte
mov ebp,[esi].pdev_rcl1WindowClip.yBottom
sub ebp,ebx ;### ebp = # of scans before end of bank
mov esi,edx
sar esi,FLOG2 ;esi = # of pixels to lay down
sub esi,ebp
sbb ebx,ebx
and ebx,esi
add ebp,ebx ;ebp = # of pels in this bank
mov [esp].sf_cAfterThisBank,esi
mov esi,[esp].sf_lNextScan
xor ebx,ebx ;### round x = 1/2 *UP* in value
sub ebx,edx
sar ebx,1 ;now have error term
mov eax,[esp].sf_iColor
;-------------------------------------------------------------------------;
; Right-to-left Lines With Abs(Slope) > 1/2
; -----------------------------------------
;
; eax = color
; ebx = error term
; ecx = dM
; edx = dN
; esi = delta
; edi = memory pointer
; ebp = # of scans before end of bank
;-------------------------------------------------------------------------;
oct_2_main_loop:
dec ebp
jl short oct_2_see_if_more
mov [edi],al
add edi,esi
add ebx,ecx ;err += dM
jl short oct_2_main_loop
dec edi ;one to left
sub ebx,edx ;err -= dN
; Unroll a bit:
dec ebp
jl short oct_2_see_if_more
mov [edi],al
add edi,esi
add ebx,ecx ;err += dM
jl short oct_2_main_loop
dec edi ;one to left
sub ebx,edx ;err -= dN
jmp short oct_2_main_loop
public oct_2_see_if_more
oct_2_see_if_more::
mov eax,[esp].sf_cAfterThisBank
cmp eax,0
jle next_line
mov [esp].sf_pfnReturn,offset oct_2_main_loop
jmp [esp].sf_pfnNextBank
public oct_2_non_integer
oct_2_non_integer::
GIQR ROUND_Y_DOWN ;### round y=1/2 down in value
;### (remember that we're flipped
;### in 'x')
mov esi,[esp].sf_ppdev
neg eax ;### untransform x0
cmp edi,[esi].pdev_rcl1WindowClip.yTop
jl short oct_2_nonint_map_in_bank
cmp edi,[esi].pdev_rcl1WindowClip.yBottom
jl short oct_2_nonint_done_bank_map
oct_2_nonint_map_in_bank:
push eax
push ecx
push edx
ptrCall <dword ptr [esi].pdev_pfnBankControl>, \
<esi, edi, JustifyTop> ;###
pop edx
pop ecx
pop eax
oct_2_nonint_done_bank_map:
mov [esp].sf_y0,edi
imul edi,[esp].sf_lNextScan
add edi,[esi].pdev_pvBitmapStart
add edi,eax ;edi points to start byte
mov ebp,[esi].pdev_rcl1WindowClip.yBottom
mov esi,[esp].sf_y1
sub esi,ebp
sbb eax,eax
and eax,esi
add ebp,eax
sub ebp,[esp].sf_y0 ;ebp = min(y1,
; ppdev->rcl1WindowClip.yBottom) - y0
; (# of pixels to lay down)
mov [esp].sf_cAfterThisBank,esi
mov esi,[esp].sf_lNextScan
mov eax,[esp].sf_iColor
jmp oct_2_main_loop
;/////////////////////////////////////////////////////////////////////
;// Octant 4
;/////////////////////////////////////////////////////////////////////
octants_4_5:
neg edx
neg ebx
cmp ecx,edx
jl octant_5
public octant_4
octant_4::
mov esi,[esp].sf_lNextScan
neg esi
mov [esp].sf_lDelta,esi ;we're going up
mov [esp].sf_pfnNextBank,offset bank_x_major_next_upper
mov esi,eax
or esi,ebx
or esi,ecx
or esi,edx
and esi,F - 1
jnz oct_4_non_integer
neg eax ;### untransform x
neg ebx ;### untransform y
mov esi,[esp].sf_ppdev
sar eax,FLOG2 ;x0
sar ebx,FLOG2 ;y0
cmp ebx,[esi].pdev_rcl1WindowClip.yTop
jl short oct_4_map_in_bank
cmp ebx,[esi].pdev_rcl1WindowClip.yBottom
jl short oct_4_done_bank_map
oct_4_map_in_bank:
push eax
push ecx
push edx
; ebx, esi, edi and esi are preserved according to C calling conventions:
ptrCall <dword ptr [esi].pdev_pfnBankControl>, \
<esi, ebx, JustifyBottom> ;###
pop edx
pop ecx
pop eax
public oct_4_done_bank_map
oct_4_done_bank_map::
mov edi,[esp].sf_lNextScan
imul edi,ebx
add edi,[esi].pdev_pvBitmapStart
add edi,eax ;edi now points to start byte
mov ebp,ebx ;###
sub ebp,[esi].pdev_rcl1WindowClip.yTop
inc ebp ;### ebp = # scans before end of bank
mov esi,ecx
sar esi,FLOG2 ;esi = # of pixels to lay down
xor ebx,ebx ;### round y = 1/2 *UP* in value
sub ebx,ecx
sar ebx,1 ;now have error term
mov eax,[esp].sf_iColor
sub ecx,edx ;ecx = dM - dN
cmp edx,ecx
jg oct_34b
jmp oct_34a
public oct_4_non_integer
oct_4_non_integer::
cmp ecx,edx
je oct_4_slope_one
GIQ 0 ;###
;### (remember that we're flipped
;### in 'x' and 'y')
oct_4_common:
mov esi,[esp].sf_ppdev
neg edi ;### untransform y
neg eax ;### untransform x
cmp edi,[esi].pdev_rcl1WindowClip.yTop
jl short oct_4_nonint_map_in_bank
cmp edi,[esi].pdev_rcl1WindowClip.yBottom
jl short oct_4_nonint_done_bank_map
oct_4_nonint_map_in_bank:
push eax
push ecx
push edx
ptrCall <dword ptr [esi].pdev_pfnBankControl>, \
<esi, edi, JustifyBottom>;###
pop edx
pop ecx
pop eax
oct_4_nonint_done_bank_map:
mov ebp,edi ;###
sub ebp,[esi].pdev_rcl1WindowClip.yTop
inc ebp ;### esp = # scans before end of bank
imul edi,[esp].sf_lNextScan
add edi,[esi].pdev_pvBitmapStart
add edi,eax ;edi now points to start byte
mov esi,[esp].sf_x1
add esi,eax ;### esi = # pixels to lay down
mov eax,[esp].sf_iColor
sub ecx,edx ;ecx = dM - dN
cmp edx,ecx
jg oct_34b
jmp oct_34a
;-------------------------------------------------------------------;
; 45 degree lines have a special rounding rule: when the line
; runs exactly half way between to pixels, the upper or right pel
; is illuminated. This translates into x=1/2 rounding up, and
; y=1/2 rounding down in value:
public oct_4_slope_one
oct_4_slope_one::
GIQ ROUND_X_DOWN_SLOPE_ONE ;round x=1/2 down in value
jmp oct_4_common
;/////////////////////////////////////////////////////////////////////
;// Octant 5
;/////////////////////////////////////////////////////////////////////
public octant_5
octant_5::
mov [esp].sf_pfnNextBank,offset bank_y_major_next_upper
mov esi,eax
or esi,ebx
or esi,ecx
or esi,edx
and esi,F - 1
jnz oct_5_non_integer
mov esi,[esp].sf_ppdev
neg eax ;### untransform
neg ebx ;### untransform
sar eax,FLOG2 ;x0
sar ebx,FLOG2 ;y0
cmp ebx,[esi].pdev_rcl1WindowClip.yTop
jl short oct_5_map_in_bank
cmp ebx,[esi].pdev_rcl1WindowClip.yBottom
jl short oct_5_done_bank_map
oct_5_map_in_bank:
push eax
push ecx
push edx
; ebx, esi, edi and ebp are preserved according to C calling conventions:
ptrCall <dword ptr [esi].pdev_pfnBankControl>, \
<esi,ebx,JustifyBottom> ;###
pop edx
pop ecx
pop eax
public oct_5_done_bank_map
oct_5_done_bank_map::
mov edi,[esp].sf_lNextScan
imul edi,ebx
add edi,[esi].pdev_pvBitmapStart
add edi,eax ;edi now points to start byte
mov ebp,ebx ;###
sub ebp,[esi].pdev_rcl1WindowClip.yTop
inc ebp ;### ebp = # scans before end of bank
mov esi,edx
sar esi,FLOG2 ;esi = # of pixels to lay down
sub esi,ebp
sbb ebx,ebx
and ebx,esi
add ebp,ebx ;ebp = # of pels in this bank
mov [esp].sf_cAfterThisBank,esi
mov esi,[esp].sf_lNextScan
neg esi ;### going down!
xor ebx,ebx ;### round x = 1/2 *UP* in value
sub ebx,edx
sar ebx,1 ;now have error term
mov eax,[esp].sf_iColor
jmp oct_2_main_loop
public oct_5_non_integer
oct_5_non_integer::
GIQR 0 ;###
;### (remember that we're flipped
;### in 'x' and 'y')
mov esi,[esp].sf_ppdev
neg edi ;### untransform y0
neg eax ;### untransform x0
cmp edi,[esi].pdev_rcl1WindowClip.yTop
jl short oct_5_nonint_map_in_bank
cmp edi,[esi].pdev_rcl1WindowClip.yBottom
jl short oct_5_nonint_done_bank_map
oct_5_nonint_map_in_bank:
push eax
push ecx
push edx
ptrCall <dword ptr [esi].pdev_pfnBankControl>, \
<esi,edi,JustifyBottom> ;###
pop edx
pop ecx
pop eax
oct_5_nonint_done_bank_map:
mov [esp].sf_y0,edi
imul edi,[esp].sf_lNextScan
add edi,[esi].pdev_pvBitmapStart
add edi,eax ;edi points to start byte
mov ebp,[esp].sf_y0 ;###
mov esi,[esi].pdev_rcl1WindowClip.yTop
dec esi ;### make top exclusive
sub ebp,esi ;###
add esi,[esp].sf_y1 ;### don't forget that y1 wasn't un-
;### transformed (so this is an 'add')
jg short @F ;###
add ebp,esi ;###
@@:
mov [esp].sf_cAfterThisBank,esi
mov esi,[esp].sf_lNextScan
neg esi ;### going down!
mov eax,[esp].sf_iColor
jmp oct_2_main_loop
;/////////////////////////////////////////////////////////////////////
;// Octant 6
;/////////////////////////////////////////////////////////////////////
public octants_6_7
octants_6_7::
neg edx ;dN = -dN (now positive)
neg ebx ;M1 = -M1
cmp ecx,edx
jge octant_7
public octant_6
octant_6::
mov [esp].sf_pfnNextBank,offset bank_y_major_next_upper
mov esi,eax
or esi,ebx
or esi,ecx
or esi,edx
and esi,F - 1
jnz oct_6_non_integer
mov esi,[esp].sf_ppdev
neg ebx ;### untransform
sar eax,FLOG2 ;x0
sar ebx,FLOG2 ;y0
cmp ebx,[esi].pdev_rcl1WindowClip.yTop
jl short oct_6_map_in_bank
cmp ebx,[esi].pdev_rcl1WindowClip.yBottom
jl short oct_6_done_bank_map
oct_6_map_in_bank:
push eax
push ecx
push edx
; ebx, esi, edi and ebp are preserved according to C calling conventions:
ptrCall <dword ptr [esi].pdev_pfnBankControl>, \
<esi,ebx,JustifyBottom> ;###
pop edx
pop ecx
pop eax
public oct_6_done_bank_map
oct_6_done_bank_map::
mov edi,[esp].sf_lNextScan
imul edi,ebx
add edi,[esi].pdev_pvBitmapStart
add edi,eax ;edi now points to start byte
mov ebp,ebx ;###
sub ebp,[esi].pdev_rcl1WindowClip.yTop
inc ebp ;### ebp = # scans before end of bank
mov esi,edx
sar esi,FLOG2 ;esi = # of pixels to lay down
sub esi,ebp
sbb ebx,ebx
and ebx,esi
add ebp,ebx ;ebp = # of pels in this bank
mov [esp].sf_cAfterThisBank,esi
mov esi,[esp].sf_lNextScan
neg esi ;### going down!
mov ebx,-1 ;### round x = 1/2 *DOWN* in value
sub ebx,edx
sar ebx,1 ;now have error term
mov eax,[esp].sf_iColor
jmp oct_1_main_loop
public oct_6_non_integer
oct_6_non_integer::
GIQR ROUND_X_DOWN ;### round x=1/2 down in value
;### (remember that we're flipped
;### in 'y')
mov esi,[esp].sf_ppdev
neg edi ;### untransform y0
cmp edi,[esi].pdev_rcl1WindowClip.yTop
jl short oct_6_nonint_map_in_bank
cmp edi,[esi].pdev_rcl1WindowClip.yBottom
jl short oct_6_nonint_done_bank_map
oct_6_nonint_map_in_bank:
push eax
push ecx
push edx
ptrCall <dword ptr [esi].pdev_pfnBankControl>, \
<esi,edi,JustifyBottom> ;###
pop edx
pop ecx
pop eax
oct_6_nonint_done_bank_map:
mov [esp].sf_y0,edi
imul edi,[esp].sf_lNextScan
add edi,[esi].pdev_pvBitmapStart
add edi,eax ;edi points to start byte
mov ebp,[esp].sf_y0 ;###
mov esi,[esi].pdev_rcl1WindowClip.yTop
dec esi ;### make top exclusive
sub ebp,esi ;###
add esi,[esp].sf_y1 ;### don't forget that y1 wasn't un-
;### transformed (so this is an 'add')
jg short @F ;###
add ebp,esi ;###
@@:
mov [esp].sf_cAfterThisBank,esi
mov esi,[esp].sf_lNextScan
neg esi ;### going down!
mov eax,[esp].sf_iColor
jmp oct_1_main_loop
;/////////////////////////////////////////////////////////////////////
;// Octant 7
;/////////////////////////////////////////////////////////////////////
public octant_7
octant_7::
mov esi,[esp].sf_lNextScan
neg esi
mov [esp].sf_lDelta,esi ;we're going up
mov [esp].sf_pfnNextBank,offset bank_x_major_next_upper
mov esi,eax
or esi,ebx
or esi,ecx
or esi,edx
and esi,F - 1
jnz oct_7_non_integer
neg ebx ;### untransform y
mov esi,[esp].sf_ppdev
sar eax,FLOG2 ;x0
sar ebx,FLOG2 ;y0
cmp ebx,[esi].pdev_rcl1WindowClip.yTop
jl short oct_7_map_in_bank
cmp ebx,[esi].pdev_rcl1WindowClip.yBottom
jl short oct_7_done_bank_map
oct_7_map_in_bank:
push eax
push ecx
push edx
; ebx, esi, edi and esi are preserved according to C calling conventions:
ptrCall <dword ptr [esi].pdev_pfnBankControl>, \
<esi, ebx, JustifyBottom> ;###
pop edx
pop ecx
pop eax
public oct_7_done_bank_map
oct_7_done_bank_map::
mov edi,[esp].sf_lNextScan
imul edi,ebx
add edi,[esi].pdev_pvBitmapStart
add edi,eax ;edi now points to start byte
mov ebp,ebx ;###
sub ebp,[esi].pdev_rcl1WindowClip.yTop
inc ebp ;### ebp = # scans before end of bank
mov esi,ecx
sar esi,FLOG2 ;esi = # of pixels to lay down
xor ebx,ebx ;### round y = 1/2 *UP* in value
sub ebx,ecx
sar ebx,1 ;now have error term
mov eax,[esp].sf_iColor
sub ecx,edx ;ecx = dM - dN
cmp edx,ecx
jg oct_07b
jmp oct_07a
public oct_7_non_integer
oct_7_non_integer::
cmp ecx,edx
je oct_7_slope_one
GIQ ROUND_X_DOWN ;### round x=1/2 down in value
;### (remember that we're flipped
;### in 'y')
oct_7_common:
mov esi,[esp].sf_ppdev
neg edi ;### untransform y
cmp edi,[esi].pdev_rcl1WindowClip.yTop
jl short oct_7_nonint_map_in_bank
cmp edi,[esi].pdev_rcl1WindowClip.yBottom
jl short oct_7_nonint_done_bank_map
oct_7_nonint_map_in_bank:
push eax
push ecx
push edx
ptrCall <dword ptr [esi].pdev_pfnBankControl>, \
<esi, edi, JustifyBottom>;###
pop edx
pop ecx
pop eax
oct_7_nonint_done_bank_map:
mov ebp,edi ;###
sub ebp,[esi].pdev_rcl1WindowClip.yTop
inc ebp ;### esp = # scans before end of bank
imul edi,[esp].sf_lNextScan
add edi,[esi].pdev_pvBitmapStart
add edi,eax ;edi now points to start byte
mov esi,[esp].sf_x1
sub esi,eax ;esi = # pixels to lay down
mov eax,[esp].sf_iColor
sub ecx,edx ;ecx = dM - dN
cmp edx,ecx
jg oct_07b
jmp oct_07a
;-------------------------------------------------------------------;
; We have to special case those lines with a slope of exactly -1 when
; 'x' rounds down in value after normalizing:
public oct_7_slope_one
oct_7_slope_one::
GIQ ROUND_X_DOWN_SLOPE_ONE
jmp oct_7_common
;-------------------------------------------------------------------------;
; Function to get next lower bank for x-major lines.
;-------------------------------------------------------------------------;
public bank_x_major_next_lower
bank_x_major_next_lower::
push ebx
mov ebx,[esp+4].sf_ppdev ;NOTE: Add 4 because of above push!
push ecx
push edx
push esi
mov esi,[ebx].pdev_rcl1WindowClip.yBottom
sub edi,[ebx].pdev_pvBitmapStart
ptrCall <dword ptr [ebx].pdev_pfnBankControl>, \
<ebx,esi,JustifyTop>
add edi,[ebx].pdev_pvBitmapStart
mov ebp,[ebx].pdev_rcl1WindowClip.yBottom
sub ebp,esi
pop esi
pop edx
pop ecx
pop ebx
mov eax,[esp].sf_iColor
jmp [esp].sf_pfnReturn
;-------------------------------------------------------------------------;
; Function to get next upper bank for x-major lines.
;-------------------------------------------------------------------------;
public bank_x_major_next_upper
bank_x_major_next_upper::
push ebx
mov ebx,[esp+4].sf_ppdev ;NOTE: Add 4 because of above push!
push ecx
push edx
push esi
mov esi,[ebx].pdev_rcl1WindowClip.yTop
dec esi
sub edi,[ebx].pdev_pvBitmapStart
ptrCall <dword ptr [ebx].pdev_pfnBankControl>, \
<ebx,esi,JustifyBottom>
add edi,[ebx].pdev_pvBitmapStart
lea ebp,[esi+1]
sub ebp,[ebx].pdev_rcl1WindowClip.yTop
pop esi
pop edx
pop ecx
pop ebx
mov eax,[esp].sf_iColor
jmp [esp].sf_pfnReturn
;-------------------------------------------------------------------------;
; Function to get next lower bank for y-major lines.
;-------------------------------------------------------------------------;
public bank_y_major_next_lower
bank_y_major_next_lower::
; eax = # pels after this bank
push ebx
mov ebx,[esp+4].sf_ppdev ;NOTE: Plus 4 because of above push!
push ecx
push edx
push esi
mov esi,[ebx].pdev_rcl1WindowClip.yBottom
sub edi,[ebx].pdev_pvBitmapStart
push eax
ptrCall <dword ptr [ebx].pdev_pfnBankControl>, \
<ebx,esi,JustifyTop>
pop eax
add edi,[ebx].pdev_pvBitmapStart
mov ebp,[ebx].pdev_rcl1WindowClip.yBottom
sub ebp,esi ;ebp = # of pels can do in this bank
sub eax,ebp ;esi = # of pels after this bank
sbb ebx,ebx
and ebx,eax
add ebp,ebx ;ebp = # of pels in this bank
pop esi
pop edx
pop ecx
pop ebx
mov [esp].sf_cAfterThisBank,eax
;this has to be done after 'esp' is
; restored!
mov eax,[esp].sf_iColor
jmp [esp].sf_pfnReturn
;-------------------------------------------------------------------------;
; Function to get next upper bank for y-major lines.
;-------------------------------------------------------------------------;
public bank_y_major_next_upper
bank_y_major_next_upper::
; eax = # pels after this bank
push ebx
mov ebx,[esp+4].sf_ppdev ;NOTE: Plus 4 because of above push!
push ecx
push edx
push esi
mov ebp,[ebx].pdev_rcl1WindowClip.yTop
dec ebp
sub edi,[ebx].pdev_pvBitmapStart
push eax
ptrCall <dword ptr [ebx].pdev_pfnBankControl>, \
<ebx,ebp,JustifyBottom>
pop eax
add edi,[ebx].pdev_pvBitmapStart
inc ebp ;restore exclusiveness
sub ebp,[ebx].pdev_rcl1WindowClip.yTop
;ebp = # of pels can do in this bank
sub eax,ebp ;esi = # of pels after this bank
sbb ebx,ebx
and ebx,eax
add ebp,ebx ;ebp = # of pels in this bank
pop esi
pop edx
pop ecx
pop ebx
mov [esp].sf_cAfterThisBank,eax
;this has to be done after 'esp' is
; restored!
mov eax,[esp].sf_iColor
jmp [esp].sf_pfnReturn
;/////////////////////////////////////////////////////////////////////
;// Horizontal Line
;/////////////////////////////////////////////////////////////////////
public flip_and_do_non_integer_horizontal_line
flip_and_do_non_integer_horizontal_line::
mov ebx,edi
mov ecx,[esp].sf_x1
sub ecx,eax
jle next_line
add eax,ecx
neg eax
inc eax ;x0' = -(-original x0 - dx) + 1
jmp short horizontal_common
public do_non_integer_horizontal_line
do_non_integer_horizontal_line::
mov ebx,edi
mov ecx,[esp].sf_x1
sub ecx,eax
jg short horizontal_common
jmp next_line
public flip_and_do_horizontal_line
flip_and_do_horizontal_line::
; This 'flip' entry point is for lines that were originally right-to-left:
add eax,ecx
neg eax
add eax,F ;M0' = -(-original M0 - original dM) + 1
public do_horizontal_line
do_horizontal_line::
sar eax,FLOG2 ;x0 (we're now in pixel coordinates)
sar ebx,FLOG2 ;y0
sar ecx,FLOG2 ;dx
jz next_line
; NOTE: Have to have some pixels to light at this point
;
; eax = x0 (in pixel coordinates)
; ebx = y0
; ecx = dx (# pixels to light)
horizontal_common:
mov esi,[esp].sf_ppdev
cmp ecx,NUM_PELS_NEEDED_FOR_PLANAR_HORIZONTAL
jl do_short_horizontal_line
test [esi].pdev_fl,DRIVER_PLANAR_CAPABLE
jz do_short_horizontal_line
;---------------------------------------------------------------------;
; Draw horizontal lines using planar mode.
;
; NOTE: This code assumes that the length is at least 8 pels long!
public horizontal_planar
horizontal_planar::
mov edi,[esi].pdev_lPlanarNextScan
imul edi,ebx
cmp ebx,[esi].pdev_rcl1PlanarClip.yTop
jl short hor_planar_map_bank
cmp ebx,[esi].pdev_rcl1PlanarClip.yBottom
jl short hor_planar_done_bank
hor_planar_map_bank:
push eax
push ecx
; ebx, esi, edi and ebp are preserved according to C calling conventions:
ptrCall <dword ptr [esi].pdev_pfnPlanarControl>, \
<esi,ebx,JustifyTop>
pop ecx
pop eax
hor_planar_done_bank:
add edi,[esi].pdev_pvBitmapStart
mov ebp,eax ;save x0
sar eax,2
add edi,eax ;edi now points to start byte
and ebp,3
jz short hor_planar_start_middle
; When the left end doesn't start on a quadpixel boundary, we have to
; adjust the start address and do some other stuff:
mov [esp].sf_pjStart,edi
inc edi
sub ebp,4
add ecx,ebp ;adjust byte count to account for
; fractional start
hor_planar_start_middle:
mov eax,[esp].sf_iColor ;load the color
mov esi,ecx ;save length
test edi,1
jz short hor_planar_middle_aligned
mov [edi],al ;handle unaligned whole start byte
inc edi
sub ecx,4
hor_planar_middle_aligned:
shr ecx,3 ;NOTE: we look at the carry later!
rep stosw ;write middle as words
jnc short hor_planar_handle_ends
;NOTE: here we look at the carry!
mov [edi],al ;handle whole end byte
inc edi
hor_planar_handle_ends:
mov edx,VGA_BASE + SEQ_DATA
and esi,3
jz short hor_planar_left
hor_planar_right:
mov ecx,esi
mov eax,0f0h
rol al,cl ;we compute the mask instead of
; using a look-up table, because the
; table probably wouldn't be in the
; cache
; Set right mask by disabling some planes:
out dx,al
push eax ;we add a delay here because some
pop eax ; cards can't handle a write too soon
; after an out. Hopefully this will
; help.
mov eax,[esp].sf_iColor
mov [edi],al
hor_planar_left:
and ebp,3
jz short hor_planar_done
mov ecx,ebp
mov eax,0fh
shl eax,cl
; Set left mask by disabling some planes:
out dx,al
push eax ;we add a delay here because some
pop eax ; cards can't handle a write too soon
; after an out. Hopefully this will
; help.
mov edi,[esp].sf_pjStart
mov eax,[esp].sf_iColor
mov [edi],al
hor_planar_done:
mov al,MM_ALL
out dx,al
jmp next_line
;---------------------------------------------------------------------;
; Draw horizontal lines using linear mode.
public do_short_horizontal_line
do_short_horizontal_line::
mov edi,[esp].sf_lNextScan
imul edi,ebx
add edi,eax
cmp ebx,[esi].pdev_rcl1WindowClip.yTop
jl short hor_map_in_bank
cmp ebx,[esi].pdev_rcl1WindowClip.yBottom
jl short hor_done_bank_map
hor_map_in_bank:
push ecx
; ebx, esi, edi and ebp are preserved according to C calling conventions:
ptrCall <dword ptr [esi].pdev_pfnBankControl>, \
<esi,ebx,JustifyTop>
pop ecx
hor_done_bank_map:
add edi,[esi].pdev_pvBitmapStart
;edi now points to start byte
mov eax,[esp].sf_iColor
test edi,1
jz short hor_aligned
mov [edi],al ;write initial unaligned byte
inc edi
dec ecx
jz next_line
hor_aligned:
shr ecx,1 ;NOTE: we look at the carry later!
rep stosw ;write middle words
jnc next_line ;NOTE: here we look at the carry!
mov [edi],al ;write last byte
jmp next_line
endProc vFastLine
end