Annotation of ntddk/src/video/displays/vga/i386/patblt.asm, revision 1.1.1.1

1.1       root        1: ;-----------------------------------------------------------------------;
                      2: 
                      3: ; Set LOOP_UNROLL_SHIFT to the log2 of the number of times you want loops in
                      4: ; this module unrolled. For example, LOOP_UNROLL_SHIFT of 3 yields 2**3 = 8
                      5: ; times unrolling. This is the only thing you need to change to control
                      6: ; unrolling.
                      7: 
                      8: LOOP_UNROLL_SHIFT equ 2
                      9: 
                     10: ;-----------------------------------------------------------------------;
                     11: 
                     12: ; This delay is necessitated by a bug in the ATI Ultra when running in
                     13: ; VGA mode.
                     14: 
                     15: SLOW_OUT macro
                     16:         push    ecx
                     17:         pop     ecx
                     18:         out     dx,ax
                     19:         endm
                     20: 
                     21:                 .386
                     22: 
                     23: ifndef  DOS_PLATFORM
                     24:         .model  small,c
                     25: else
                     26: ifdef   STD_CALL
                     27:         .model  small,c
                     28: else
                     29:         .model  small,pascal
                     30: endif;  STD_CALL
                     31: endif;  DOS_PLATFORM
                     32: 
                     33:         assume cs:FLAT,ds:FLAT,es:FLAT,ss:FLAT
                     34:         assume fs:nothing,gs:nothing
                     35: 
                     36:         .xlist
                     37:         include stdcall.inc             ;calling convention cmacros
                     38:         include i386\egavga.inc
                     39:         include i386\strucs.inc
                     40:         include i386\unroll.inc
                     41:         include i386\ropdefs.inc
                     42:         include i386\display.inc         ; Display specific structures
                     43: 
                     44:         .list
                     45: 
                     46: ;-----------------------------------------------------------------------;
                     47: 
                     48:         .data
                     49: 
                     50: ;
                     51: ; We share some tables with vgablts.asm
                     52: ;
                     53: 
                     54: extrn   jALUFuncTable :byte
                     55: extrn   jLeftMask  :byte
                     56: extrn   jRightMask :byte
                     57: extrn   jForceOnTable :byte
                     58: extrn   jNotTable :byte
                     59: extrn   jInvertDest :byte
                     60: extrn   jForceOffTable :byte
                     61: extrn   vTrgBlt@20 :dword
                     62: 
                     63: ;-----------------------------------------------------------------------;
                     64: ; Table of routines to be called to draw edges, according to which edges are
                     65: ; partial and which edges are whole bytes.
                     66:         align   4
                     67:         public pfnEdgeDrawing
                     68: pfnEdgeDrawing  label   dword
                     69:         dd      edge_byte_setup
                     70:         dd      edge_byte_setup
                     71:         dd      check_next_bank
                     72:         dd      edge_byte_setup
                     73: 
                     74: ;-----------------------------------------------------------------------;
                     75: ; Table of pointers to tables used to find entries points in unrolled wide
                     76: ; whole byte code.
                     77: 
                     78:         align   4
                     79:         public pfnWideWholeRep
                     80: pfnWideWholeRep label   dword
                     81:         dd      pfnDrawWide00Entry
                     82:         dd      pfnDrawWide01Entry
                     83:         dd      pfnDrawWide10Entry
                     84:         dd      pfnDrawWide11Entry
                     85: 
                     86: ;-----------------------------------------------------------------------;
                     87: ; Table of pointers to tables used to find entry points in narrow, special-
                     88: ; cased unrolled replace whole byte code.
                     89: 
                     90: ; Note: The breakpoint where one should switch from special-casing to
                     91: ;  REP STOS is purely a guess on my part. 8 seemed reasonable.
                     92: 
                     93: ; Start address MOD 2 is 0.
                     94:         align   4
                     95:         public pfnWholeBytesMod0Entries
                     96: pfnWholeBytesMod0Entries  label   dword
                     97:         dd      0                       ;we never get a 0-wide case
                     98:         dd      pfnDraw1WideEvenEntry
                     99:         dd      pfnDraw2WideEvenEntry
                    100:         dd      pfnDraw3WideEvenEntry
                    101:         dd      pfnDraw4WideEvenEntry
                    102:         dd      pfnDraw5WideEvenEntry
                    103:         dd      pfnDraw6WideEvenEntry
                    104:         dd      pfnDraw7WideEvenEntry
                    105:         dd      pfnDraw8WideEvenEntry
                    106: MAX_REPLACE_SPECIAL equ     ($-pfnWholeBytesMod0Entries)/4
                    107: 
                    108: ; Start address MOD 2 is 1.
                    109:         align   4
                    110:         public pfnWholeBytesMod1Entries
                    111: pfnWholeBytesMod1Entries  label   dword
                    112:         dd      0                       ;we never get a 0-wide case
                    113:         dd      pfnDraw1WideOddEntry
                    114:         dd      pfnDraw2WideOddEntry
                    115:         dd      pfnDraw3WideOddEntry
                    116:         dd      pfnDraw4WideOddEntry
                    117:         dd      pfnDraw5WideOddEntry
                    118:         dd      pfnDraw6WideOddEntry
                    119:         dd      pfnDraw7WideOddEntry
                    120:         dd      pfnDraw8WideOddEntry
                    121: 
                    122: 
                    123: ;-----------------------------------------------------------------------;
                    124: ; Table of pointers to tables used to find entries points in narrow, special-
                    125: ; cased unrolled non-replace whole byte code.
                    126: 
                    127: ; Note: The breakpoint where one should switch from special-casing to
                    128: ;  REP MOVSB is purely a guess on my part. 5 seemed reasonable.
                    129: 
                    130:         align   4
                    131: pfnWholeBytesNonReplace  label   dword
                    132:         dd      0                       ;we never get a 0-wide case
                    133:         dd      pfnDraw1RWEntry
                    134:         dd      pfnDraw2RWEntry
                    135:         dd      pfnDraw3RWEntry
                    136:         dd      pfnDraw4RWEntry
                    137: MAX_NON_REPLACE_SPECIAL equ     ($-pfnWholeBytesNonReplace)/4
                    138: 
                    139: ; Master MOD 2 alignment look-up table for entry tables for two possible
                    140: ; alignments for narrow, special-cased unrolled replace whole byte code.
                    141:         align   4
                    142:         public pfnWholeBytesSpecial
                    143: pfnWholeBytesSpecial      label   dword
                    144:         dd      pfnWholeBytesMod0Entries
                    145:         dd      pfnWholeBytesMod1Entries
                    146: 
                    147:         .code
                    148: 
                    149: ;=============================================================================
                    150: 
                    151: _TEXT$01   SEGMENT DWORD USE32 PUBLIC 'CODE'
                    152:            ASSUME  CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
                    153: 
                    154: cProc   vMonoPatBlt,24,<    \
                    155:         uses esi edi ebx, \
                    156:         pdsurf: ptr DEVSURF, \
                    157:         culRcl: dword,       \
                    158:         prcl:   ptr RECTL,   \
                    159:         ulMix:  dword,       \
                    160:         pBrush: ptr oem_brush_def, \
                    161:         pBrushOrg: ptr POINTL >
                    162: 
                    163:         local   ulRowOffset :dword      ;Offset from start of scan line
                    164:                                         ; first byte to fill
                    165:         local   ulWholeBytes :dword     ;# of whole bytes to fill
                    166:         local   ulWholeWords :dword     ;# of whole words to fill excluding
                    167:                                         ;leading and/or trailing bytes
                    168:         local   pfnWholeFn  :dword      ;pointer to routine used to draw
                    169:                                         ; whole bytes
                    170:         local   ulScanWidth :dword      ;offset from start of one scan to start
                    171:                                         ; of next
                    172:         local   ulNextScan  :dword      ;offset from end of one scan line's
                    173:                                         ; fill to start of next
                    174:         local   ulCurrentTopScan :dword ;top scan line to fill in current bank
                    175:         local   ulMasks     :dword      ;low byte = right mask, high byte =
                    176:                                         ; left mask
                    177:         local   ulBottomScan :dword     ;bottom scan line of fill rectangle
                    178: 
                    179:         local   jALUFunc   :dword       ;VGA ALU logical operation (SET, AND,
                    180:                                         ; OR, or XOR)
                    181:         local   pfnStartDrawing :dword  ;pointer to function to call to start
                    182:                                         ; drawing
                    183:         local   pfnContinueDrawing :dword ;pointer to function to call to
                    184:                                         ; continue drawing after doing whole
                    185:                                         ; bytes
                    186:         local   ulLeftEdgeAdjust :dword ;used to bump the whole bytes start
                    187:                                         ; address past the left edge when the
                    188:                                         ; left edge is partial
                    189:         local   pfnWholeBytes :dword    ;pointer to table of entry points
                    190:                                         ; into unrolled loops for whole byte
                    191:                                         ; filling
                    192:         local   ulSpecialBytes          ;If we are doing a special case wide
                    193:                                         ; fill, this will be the width of the
                    194:                                         ; fill. We need this so we can properly
                    195:                                         ; increment to the next line.
                    196:         local   ulVbNextScan :dword     ;Offset from the end of the current
                    197:                                         ; wide fill drawing operation to the
                    198:                                         ; top of the next venetian blind line
                    199:         local   fdInvertDestFirst :dword;1 if the rop requires a pass to invert
                    200:                                         ; the destination before the normal
                    201:                                         ; pass
                    202: 
                    203:         local   ulPatternOrgY: dword    ;Local copy of the pattern offset Y
                    204: 
                    205:         local   ulVbBlindCount :dword   ;Temp Height of pattern.
                    206: 
                    207:         local   ulVbTopScan :dword      ;slats in our blinds
                    208: 
                    209:         local   ulVbStartScan :dword    ;Current to slat
                    210: 
                    211:         local   pUlVbPattern:dword      ;inner loop pattern pointer
                    212: 
                    213:         local   pUlPattern:dword        ;current pattern with proper Y offset
                    214: 
                    215:         local   ulVbMask                ;Inversion mask for partial edges
                    216: 
                    217:         local   ulVbYRound              ;
                    218: 
                    219:         local   ulVbYShift              ;
                    220: 
                    221:         local   RotatedPat[32]:byte     ;Aligned pattern buffer
                    222: 
                    223:         local   ulFgClr:dword           ;Local copy of the foreground color
                    224: 
                    225:         local   ulBkClr:dword           ;Local copy of the background color
                    226: 
                    227:         local   pfnWesTrick:dword       ;Pointer to the desired inner loop
                    228:                                         ; wes trick code. While we are doing
                    229:                                         ; a ROP to full bytes, this will point
                    230:                                         ; to do_wide_wes_trick otherwise it
                    231:                                         ; will point to do_edge_wes_trick for
                    232:                                         ; the edge cases
                    233:         cld
                    234: 
                    235: ;-----------------------------------------------------------------------;
                    236: ; Make sure there's something to draw; clip enumerations can be empty.
                    237: ;-----------------------------------------------------------------------;
                    238: 
                    239:         cmp     culRcl,0                ;any rects to fill?
                    240:         jz      vMonoPatBlts_done         ;no, we're done
                    241: 
                    242:         mov     esi,pBrush              ;point to the brush
                    243: 
                    244:         xor     eax,eax
                    245:         mov     al,[esi + oem_brush_fg]
                    246:         mov     ulFgClr,eax             ;Make local copy of the fg color
                    247: 
                    248:         mov     al,[esi + oem_brush_bg]
                    249:         mov     ulBkClr,eax             ;Make local copy of the bk color
                    250: 
                    251: ;-----------------------------------------------------------------------;
                    252: ; Set up for the desired raster op.
                    253: ;-----------------------------------------------------------------------;
                    254:         sub     ebx,ebx                 ;ignore any background mix; we're only
                    255:         mov     bl,byte ptr ulMix       ; concerned with the foreground in this
                    256:                                         ; module
                    257:         cmp     ebx,R2_NOP              ;is this NOP?
                    258:         jz      vMonoPatBlts_done       ;yes, we're done
                    259:         sub     eax,eax                 ;we want a dword
                    260:         mov     al,jInvertDest[ebx]     ;remember whether we need to invert the
                    261:         mov     fdInvertDestFirst,eax   ; destination before finishing the rop
                    262:         mov     eax,ulFgClr
                    263:         and     al,jForceOffTable[ebx]  ;force color to 0 if necessary
                    264:                                         ; (R2_BLACK)
                    265:         or      al,jForceOnTable[ebx]   ;force color to 0ffh if necessary
                    266:                                         ; (R2_WHITE, R2_NOT)
                    267:         xor     al,jNotTable[ebx]       ;invert color if necessary (any Pn mix)
                    268:                                         ;at this point, CH has the color we
                    269:                                         ; want to draw with; set up the VGA
                    270:                                         ; hardware to draw with that color
                    271:         mov     ulFgClr,eax
                    272: 
                    273:         mov     eax,ulBkClr
                    274:         and     al,jForceOffTable[ebx]  ;force color to 0 if necessary
                    275:                                         ; (R2_BLACK)
                    276:         or      al,jForceOnTable[ebx]   ;force color to 0ffh if necessary
                    277:                                         ; (R2_WHITE, R2_NOT)
                    278:         xor     al,jNotTable[ebx]       ;invert color if necessary (any Pn mix)
                    279:                                         ;at this point, CH has the color we
                    280:                                         ; want to draw with; set up the VGA
                    281:                                         ; hardware to draw with that color
                    282:         mov     ulBkClr,eax
                    283: 
                    284:         mov     ah,jALUFuncTable[ebx]   ;get the ALU logical function
                    285:         and     ah,ah                   ;is the logical function DR_SET?
                    286:         .errnz  DR_SET
                    287:         jz      short skip_ALU_set      ;yes, don't have to set because that's
                    288:                                         ; the VGA's default state
                    289:         mov     edx,VGA_BASE + GRAF_ADDR
                    290:         mov     al,GRAF_DATA_ROT
                    291:         SLOW_OUT                        ;set the ALU logical function
                    292: skip_ALU_set:
                    293:         mov     byte ptr jALUFunc,ah    ;remember the ALU logical function
                    294: 
                    295: ;-----------------------------------------------------------------------;
                    296: ; Set up variables that are constant for the entire time we're in this
                    297: ; module.
                    298: ;-----------------------------------------------------------------------;
                    299:         mov     edx,pBrushOrg           ;point to the brush origin
                    300: 
                    301:         mov     ecx,[edx].ptl_x
                    302:         and     ecx,15                  ;eax mod 16
                    303: 
                    304:         mov     eax,[edx].ptl_y
                    305:         mov     ulPatternOrgY,eax
                    306: 
                    307:         ;We are now going to make a copy of our rotated copy of our pattern.
                    308:         ;The reason that we do this is because we may be called with several
                    309:         ;rectangles and we don't really want to rotate the pattern data for
                    310:         ;each rectangle. We copy this rectangle to be double high so that
                    311:         ;we can incorperate our Y offest later without having to worry
                    312:         ;about running off the end of the pattern.
                    313: 
                    314:         lea     edi,RotatedPat          ;Pattern Dest
                    315:         mov     esi,[esi + oem_brush_pmono] ;Pattern Src
                    316:         or      cl,cl
                    317:         jnz     rotate_and_expand
                    318: 
                    319: INDEX=0
                    320:         rept    4                       ;patterns are 16x8
                    321:         mov     eax,[esi+INDEX]
                    322:         mov     [edi+INDEX],eax
                    323:         mov     [edi+16+INDEX],eax
                    324: INDEX=INDEX+4
                    325:         endm    ;-----------------
                    326:         jmp     fill_rect_loop
                    327: 
                    328: rotate_and_expand:
                    329: INDEX=0
                    330:         rept    8                       ;patterns are 16x8
                    331:         mov     ah,[esi+INDEX]          ;load bytes for shift
                    332:         mov     al,[esi+1+INDEX]        ;convert from little to big endian
                    333:         ror     ax,cl                   ;shift into position
                    334:         mov     [edi+INDEX],ah          ;save result
                    335:         mov     [edi+1+INDEX],al
                    336:         mov     [edi+16+INDEX],ah       ;save result to second copy
                    337:         mov     [edi+17+INDEX],al
                    338: INDEX=INDEX+2
                    339:         endm    ;-----------------
                    340: 
                    341: 
                    342: fill_rect_loop:
                    343: ;-----------------------------------------------------------------------;
                    344: ; Set up masks and widths.
                    345: ;-----------------------------------------------------------------------;
                    346:         mov     edi,prcl                ;point to rectangle to fill
                    347: 
                    348:         sub     eax,eax
                    349:         mov     ulLeftEdgeAdjust,eax    ;initalize variable
                    350:         mov     ulSpecialBytes,eax      ;initalize variable
                    351: 
                    352:         mov     eax,[edi].yBottom
                    353:         mov     ulBottomScan,eax        ;remember the bottom scan line of fill
                    354: 
                    355:         mov     ebx,[edi].xRight        ;right edge of fill (non-inclusive)
                    356:         mov     ecx,ebx
                    357:         and     ecx,0111b               ;intrabyte address of right edge
                    358:         mov     ah,jRightMask[ecx]      ;right edge mask
                    359: 
                    360:         mov     esi,[edi].xLeft         ;left edge of fill (inclusive)
                    361:         mov     ecx,esi
                    362:         shr     ecx,3                   ;/8 for start offset from left edge
                    363:                                         ; of scan line
                    364:         mov     ulRowOffset,ecx         ;remember offset from start of scan
                    365:                                         ; line
                    366:         sub     ebx,esi                 ;width in pixels of fill
                    367: 
                    368:         and     esi,0111b               ;intrabyte address of left edge
                    369:         mov     al,jLeftMask[esi]       ;left edge mask
                    370: 
                    371:         dec     ebx                     ;make inclusive on right
                    372:         add     ebx,esi                 ;inclusive width, starting counting at
                    373:                                         ; the beginning of the left edge byte
                    374:         shr     ebx,3                   ;width of fill in bytes touched - 1
                    375:         jnz     short more_than_1_byte  ;more than 1 byte is involved
                    376: 
                    377: ; Only one byte will be affected. Combine first/last masks.
                    378: 
                    379:         and     al,ah                   ;we'll use first byte mask only
                    380:         xor     ah,ah                   ;want last byte mask to be 0
                    381:         inc     ebx                     ;so there's one count to subtract below
                    382:                                         ; if this isn't a whole edge byte
                    383: more_than_1_byte:
                    384: 
                    385: ; If all pixels in the left edge are altered, combine the first byte into the
                    386: ; whole byte count and clear the first byte mask, because we can handle solid
                    387: ; edge bytes faster as part of the whole bytes. Ditto for the right edge.
                    388: 
                    389:         sub     ecx,ecx                 ;edge whole-status accumulator
                    390:         cmp     al,-1                   ;is left edge a whole byte or partial?
                    391:         adc     ecx,ecx                 ;ECX=1 if left edge partial, 0 if whole
                    392:         sub     ebx,ecx                 ;if left edge partial, deduct it from
                    393:                                         ; the whole bytes count
                    394:         mov     ulLeftEdgeAdjust,ecx    ;for skipping over the left edge if
                    395:                                         ; it's partial when pointing to the
                    396:                                         ; whole bytes
                    397:         and     ah,ah                   ;is right edge mask 0, meaning this
                    398:                                         ; fill is only 1 byte wide?
                    399:         jz      short save_masks        ;yes, no need to do anything
                    400:         cmp     ah,-1                   ;is right edge a whole byte or partial?
                    401:         jnz     short save_masks        ;partial
                    402:         mov     ah,0                    ;
                    403:         add     ecx,2                   ;bit 1 of ECX=0 if right edge partial,
                    404:                                         ; 1 if whole;
                    405:                                         ;bit 1=0 if left edge partial, 1 whole
                    406:         inc     ebx                     ;if right edge whole, include it in the
                    407:                                         ; whole bytes count
                    408: save_masks:
                    409:         mov     ulMasks,eax             ;save left and right clip masks
                    410:         mov     ulWholeBytes,ebx        ;save # of whole bytes
                    411: 
                    412:         mov     ecx,pfnEdgeDrawing[ecx*4] ;set address of routine to draw
                    413:         mov     pfnContinueDrawing,ecx    ; all partial (non-whole) edges
                    414: 
                    415:         and     ebx,ebx                 ;any whole bytes?
                    416:         jz      start_vec_set           ;no
                    417:                                         ;yes, so draw the whole bytes before
                    418:                                         ; the edge bytes
                    419: 
                    420: ; The whole bytes loop depends on the type of operation being done. If the
                    421: ; operation is one which uses DR_SET, then we can use a STOS-type operation,
                    422: ; else we have to use a MOVSB-type operation (to load the latches with the
                    423: ; existing contents of display memory to allow the ALUs to work).
                    424:         cmp     byte ptr jALUFunc,DR_SET ;is it a replace-type rop?
                    425:         jz      short is_replace_type   ;yes
                    426:                                         ;no, set up for non-replace whole bytes
                    427:         mov     ecx,offset non_replace_wide
                    428: 
                    429:         cmp     ebx,MAX_NON_REPLACE_SPECIAL ;too wide to special case?
                    430:         jb      short non_replace_spec     ;nope
                    431: 
                    432:         lea     eax,pfnDrawRWWideEntry  ;assume too wide to special-case
                    433:         mov     pfnWholeBytes,eax       ; table for width
                    434: 
                    435:         jmp     short start_vec_set
                    436: 
                    437:         align   4
                    438: non_replace_spec:
                    439: 
                    440:         mov     eax,pfnWholeBytesNonReplace[ebx*4] ;no, point to entry
                    441:         mov     pfnWholeBytes,eax       ; table for width
                    442:         mov     ulSpecialBytes,ebx
                    443:                                         ;narrow enough to special case. Look up
                    444:                                         ; the entry table for the special case
                    445:                                         ; base on the start alignment
                    446: 
                    447:         jmp     short start_vec_set
                    448: 
                    449:         align   4
                    450: is_replace_type:                        ;set up for replace-type rop
                    451:         cmp     ebx,MAX_REPLACE_SPECIAL ;too wide to special case?
                    452:         jnb     short is_wide_replace   ;yes
                    453: 
                    454:         mov     ulSpecialBytes,ebx
                    455:                                         ;narrow enough to special case. Look up
                    456:                                         ; the entry table for the special case
                    457:                                         ; base on the start alignment
                    458:         mov     ecx,ulRowOffset
                    459:         add     ecx,ulLeftEdgeAdjust    ;left edge whole bytes start offset
                    460:         and     ecx,01b                 ;left edge whole bytes start alignment
                    461:                                         ; MOD 2
                    462:         mov     ecx,pfnWholeBytesSpecial[ecx*4] ;look up table of entry
                    463:                                                       ; tables for alignment
                    464:         mov     ecx,[ecx+ebx*4]         ;look up entry table for width
                    465:         mov     pfnWholeBytes,ecx       ; table for width
                    466:         mov     ecx,offset whole_bytes_rep_wide
                    467: 
                    468:         jmp     short start_vec_set
                    469: 
                    470:         align   4
                    471: is_wide_replace:                        ;set up for wide replace-type op
                    472:                                         ;Note: assumes there is at least one
                    473:                                         ; full word involved!
                    474:         mov     ecx,ulRowOffset
                    475:         add     ecx,ulLeftEdgeAdjust    ;left edge whole bytes start offset
                    476:         neg     ecx
                    477:         and     ecx,01b
                    478:         mov     edx,ebx
                    479:         sub     edx,ecx                 ;ignore odd leading bytes
                    480:         mov     eax,edx
                    481:         shr     edx,1                   ;# of whole words across (not counting
                    482:                                         ; odd leading & trailing bytes)
                    483:         mov     ulWholeWords,edx
                    484:         and     eax,01b                 ;# of odd (fractional) trailing bytes
                    485:         add     ecx,ecx
                    486:         or      ecx,eax                 ;build a look-up index from the number
                    487:                                         ; of leading and trailing bytes
                    488:         mov     ecx,pfnWideWholeRep[ecx*4] ;proper drawing handler for front/
                    489:         mov     pfnWholeBytes,ecx          ; back alignment
                    490:         mov     ecx,offset whole_bytes_rep_wide
                    491:                                         ;set up to call routine to perform wide
                    492:                                         ; whole bytes fill
                    493: 
                    494: start_vec_set:
                    495:         mov     pfnStartDrawing,ecx     ; all partial (non-whole) edges
                    496: 
                    497:         mov     ecx,pdsurf
                    498:         mov     eax,[ecx].dsurf_lNextScan
                    499:         mov     ulScanWidth,eax         ;local copy of scan line width
                    500:         sub     eax,ebx                 ;EAX = delta to next scan
                    501:         mov     ulNextScan,eax
                    502: 
                    503:         mov     esi,pBrush
                    504:         mov     eax,[esi+oem_brush_height]
                    505:         dec     eax
                    506:         mov     ulVbYRound,eax
                    507:         mov     al,[esi + oem_brush_yshft] ; blind to the next.
                    508:         mov     ulVbYShift,eax
                    509: 
                    510:         mov     cl,al
                    511:         mov     eax,UlScanWidth
                    512:         shl     eax,cl                  ;ulNextScan * 8
                    513:         mov     ulVbNextScan,eax        ;
                    514: 
                    515:         cmp     fdInvertDestFirst,1     ;is this an invert-dest-plus-something-
                    516:                                         ; else rop that requires two passes?
                    517:         jnz     short do_single_pass
                    518: 
                    519:         lea     eax,vTrgBlt@20
                    520:         ptrCall <eax>,<pdsurf, culRcl, prcl, R2_NOT, -1>
                    521: 
                    522:         mov     ah,byte ptr jALUFunc    ;reset the ALU logical function
                    523:         mov     edx,VGA_BASE + GRAF_ADDR
                    524:         mov     al,GRAF_DATA_ROT
                    525:         SLOW_OUT                        ;set the ALU logical function
                    526: 
                    527: do_single_pass:
                    528:         call    draw_banks
                    529: 
                    530: ;-----------------------------------------------------------------------;
                    531: ; See if there are any more rectangles to fill.
                    532: ;-----------------------------------------------------------------------;
                    533: 
                    534:         add     prcl,(size RECTL) ;point to the next rectangle, if there is one
                    535:         dec     culRcl            ;count down the rectangles to fill
                    536:         jnz     fill_rect_loop
                    537: 
                    538: 
                    539: ;-----------------------------------------------------------------------;
                    540: ; We have filled all rectangles.  Restore the VGA to its default state.
                    541: ;-----------------------------------------------------------------------;
                    542: 
                    543:         mov     edx,VGA_BASE + GRAF_ADDR
                    544:         mov     eax,0000h + GRAF_ENAB_SR ;disable set/reset
                    545:         out     dx,ax
                    546:         mov     eax,GRAF_MODE + ((M_PROC_WRITE + M_DATA_READ) SHL 8)
                    547:         out     dx,ax                   ;restore read mode 0 and write mode 0
                    548:         mov     eax,(DR_SET shl 8) + GRAF_DATA_ROT ;set the logical function to
                    549:         out     dx,ax                             ; SET
                    550: vMonoPatBlts_done:
                    551:         cRet    vMonoPatBlt
                    552: 
                    553: ;-----------------------------------------------------------------------;
                    554: ; Fills all banks in the current fill rectangle. Called once per fill
                    555: ; rectangle, except for destination-inversion-plus-something-else rops.
                    556: ;-----------------------------------------------------------------------;
                    557: 
                    558:         align   4
                    559: draw_banks:
                    560: 
                    561: ;-----------------------------------------------------------------------;
                    562: ; Map in the bank containing the top scan to fill, if it's not mapped in
                    563: ; already.
                    564: ;-----------------------------------------------------------------------;
                    565: 
                    566:         mov     edi,prcl                ;point to rectangle to fill
                    567:         mov     ecx,pdsurf              ;point to surface
                    568:         mov     eax,[edi].yTop          ;top scan line of fill
                    569:         mov     ulCurrentTopScan,eax    ;this will be the fill top in 1st bank
                    570: 
                    571:         cmp     eax,[ecx].dsurf_rcl1WindowClip.yTop ;is fill top less than
                    572:                                                     ; current bank?
                    573:         jl      short map_init_bank             ;yes, map in proper bank
                    574:         cmp     eax,[ecx].dsurf_rcl1WindowClip.yBottom ;fill top greater than
                    575:                                                        ; current bank?
                    576:         jl      short init_bank_mapped          ;no, proper bank already mapped
                    577: map_init_bank:
                    578: 
                    579: ; Map in the bank containing the top scan line of the fill.
                    580: 
                    581:         ptrCall <dword ptr [ecx].dsurf_pfnBankControl>,<ecx,eax,JustifyTop>
                    582: 
                    583: init_bank_mapped:
                    584: 
                    585: ;-----------------------------------------------------------------------;
                    586: ; Main loop for processing fill in each bank.
                    587: ;-----------------------------------------------------------------------;
                    588: 
                    589: ; Compute the starting address and scan line count for the initial bank.
                    590: 
                    591:         mov     eax,pdsurf              ;EAX->target surface
                    592:         mov     ebx,ulBottomScan        ;bottom of destination rectangle
                    593:         cmp     ebx,[eax].dsurf_rcl1WindowClip.yBottom
                    594:                                         ;which comes first, the bottom of the
                    595:                                         ; dest rect or the bottom of the
                    596:                                         ; current bank?
                    597:         jl      short BottomScanSet     ;fill bottom comes first, so draw to
                    598:                                         ; that; this is the last bank in fill
                    599:         mov     ebx,[eax].dsurf_rcl1WindowClip.yBottom
                    600:                                         ;bank bottom comes first; draw to
                    601:                                         ; bottom of bank
                    602: BottomScanSet:
                    603:         mov     edi,ulCurrentTopScan    ;top scan line to fill in current bank
                    604:         sub     ebx,edi                 ;# of scans to fill in bank
                    605:         imul    edi,ulScanWidth         ;offset of starting scan line
                    606: 
                    607: ; Note that the start of the bitmap will change each time through the
                    608: ; bank loop, because the start of the bitmap is varied to map the
                    609: ; desired scan line to the banking window.
                    610: 
                    611:         add     edi,[eax].dsurf_pvBitmapStart ;start of scan in bitmap
                    612:         add     edi,ulRowOffset         ;EDI = start offset of fill in bitmap
                    613: 
                    614: ; We have computed the starting address and scan count. Time to start drawing
                    615: ; in the initial bank.
                    616: 
                    617:         mov     esi,pBrush              ;edx = min(PatternHeight,BltHeight)
                    618:         mov     ecx,[esi + oem_brush_height]
                    619:         sub     ecx,ebx
                    620:         sbb     edx,edx
                    621:         and     edx,ecx
                    622:         add     edx,ebx
                    623:         mov     ulVbBlindCount,edx
                    624: 
                    625: ; Brush alignment. We need to look at pptlBrush
                    626: 
                    627:         mov     eax,ulCurrentTopScan    ;top scan line to fill in current bank
                    628:         sub     eax,ulPatternOrgY       ;
                    629: 
                    630:         jns     short pos_y_offset      ;
                    631:         neg     eax                     ;
                    632:         and     eax,7                   ;-eax mod 8
                    633:         neg     eax                     ;
                    634:         add     eax,8                   ;
                    635:         jmp     short save_pat_pointer
                    636: pos_y_offset:
                    637:         and     eax,7                   ;eax mod 8
                    638: save_pat_pointer:
                    639:         add     eax,eax                 ;Y Offset * PatternWidth (2 bytes)
                    640: 
                    641:         lea     edx,RotatedPat          ;Pattern Dest
                    642:         add     eax,edx
                    643:         mov     pulPattern,eax          ;Drawing code uses this as the
                    644:                                         ;source for the pattern
                    645: 
                    646:         jmp     pfnStartDrawing
                    647: 
                    648: 
                    649: ;-----------------------------------------------------------------------;
                    650: ; Whole byte fills.
                    651: ;-----------------------------------------------------------------------;
                    652: 
                    653: ;-----------------------------------------------------------------------;
                    654: ; Handles non-replace whole byte fills wider than the maximum special
                    655: ; case width.
                    656: ;
                    657: ; The destination is not involved, so a STOS (or equivalent) can be used
                    658: ; (no read needed before write).
                    659: ;-----------------------------------------------------------------------;
                    660: 
                    661:         align   4
                    662:         public whole_bytes_rep_wide
                    663: whole_bytes_rep_wide:
                    664:         push    ebx                     ;save scan count
                    665:         push    edi                     ;save starting address
                    666: 
                    667:         add     edi,ulLeftEdgeAdjust    ;point to first whole byte to fill
                    668: 
                    669:         mov     edx,VGA_BASE + GRAF_ADDR
                    670:         mov     eax,GRAF_MODE + ((M_COLOR_WRITE + M_COLOR_READ) SHL 8)
                    671:         out     dx,ax                   ;write mode 2
                    672:         mov     eax,ulBkClr             ;Set the write mode to write mode
                    673:         mov     [edi],al                ; three after we load the latches
                    674:         mov     al,[edi]                ; with our background color
                    675: 
                    676:         mov     al,GRAF_SET_RESET       ;Set the foreground color
                    677:         out     dx,al                   ; into set/reset
                    678:         inc     edx
                    679:         in      al,dx
                    680:         and     eax,0f0h
                    681:         or      eax,ulFgClr
                    682:         out     dx,al
                    683:         dec     edx
                    684: 
                    685:         mov     eax,GRAF_MODE + ((M_AND_WRITE + M_COLOR_READ) SHL 8)
                    686:         out     dx,ax                   ;write mode 3 so we can do the masking
                    687:                                         ; without OUTs, read mode 1 so we can
                    688:                                         ; read 0xFF from memory always, for
                    689:                                         ; ANDing (because Color Don't Care is
                    690:                                         ; all zeros)
                    691: 
                    692:         mov     esi,pulPattern          ; pointer to pattern bits
                    693:         mov     ax,[esi]                ; into place
                    694:         add     esi,2
                    695:         mov     pulVbPattern,esi
                    696: 
                    697: 
                    698:         mov     ulVbTopScan,ebx         ;our pattern is 8 high so we don't
                    699:         add     ebx,ulVbYRound          ;Calc the number of lines to do
                    700:         mov     ecx,ulVbyShift
                    701:         shr     ebx,cl                  ;only need to go through the code
                    702:                                         ; count/8 times. We will handle any
                    703:                                         ; extra lines at the bottom
                    704:                                         ; (ulVbTopScan mod 8) in our loops.
                    705:         mov     edx,pfnWholeBytes
                    706:         push    ulVbBlindCount
                    707: 
                    708:         public wide_bytes_loop
                    709: wide_bytes_loop:
                    710:         SET_UP_UNROLL_VARS ebx, ecx, ebx, [edx], LOOP_UNROLL_SHIFT
                    711: 
                    712:         mov     esi,ulWholeWords        ;number of aligned word writes
                    713:         mov     edx,ulVbNextScan        ;offset from end of one scan line to
                    714:                                         ; start of next the same scan line
                    715:                                         ; in the next pattern.
                    716:         sub     edx,ulWholeBytes
                    717:         add     edx,ulSpecialBytes
                    718: 
                    719: 
                    720:         ; eax = rotated pattern
                    721:         ; ebx = unrolled count
                    722:         ; ecx = routine address
                    723:         ; edx = ulVbNextScan
                    724:         ; esi = ulFvWholeWords
                    725:         ; edi = pDest
                    726:         ;
                    727:         push    edi                     ;save out dest pointer
                    728:         call    ecx                     ;draw the wide whole bytes
                    729:         pop     edi                     ;restore out dest pointer
                    730: 
                    731:         add     edi,ulScanWidth         ;advance to next scan line
                    732: 
                    733:         dec     ulVbBlindCount
                    734:         jz      short wide_bytes_end
                    735: 
                    736:         mov     eax,ulVbTopScan           ;restore scan count
                    737:         dec     eax                     ;Subtract off completed top line
                    738:         mov     ulVbTopScan,eax
                    739:         add     eax,ulVbYRound          ;Calc the number of lines to do
                    740:         mov     ecx,ulVbyShift
                    741:         shr     eax,cl                  ;for this venetian blind pass
                    742:         mov     ebx,eax                 ;including any partial patterns
                    743:                                         ; at the bottom
                    744: 
                    745:         mov     esi,pulVbPattern        ;Pattern data
                    746:         mov     ax,[esi]                ;get pattern word
                    747:         add     esi,2
                    748:         mov     pulVbPattern,esi        ;save pattern pointer for later
                    749: 
                    750:         mov     edx,pfnWholeBytes
                    751: 
                    752:         jmp     short wide_bytes_loop
                    753: 
                    754: wide_bytes_end:
                    755:         pop     ulVbBlindCount
                    756:         pop     edi                     ;restore screen pointer
                    757:         pop     ebx                     ;restore fill scan count
                    758: 
                    759:         mov     edx,VGA_BASE + GRAF_ADDR ;restore proper read/write modes
                    760:         mov     eax,GRAF_MODE + ((M_PROC_WRITE + M_DATA_READ) SHL 8)
                    761:         out     dx,ax
                    762: 
                    763:         jmp     pfnContinueDrawing      ;either keep drawing or we're done
                    764: 
                    765: 
                    766: ;-----------------------------------------------------------------------;
                    767: ; Handle case where both edges are partial (non-whole) bytes.
                    768: ;-----------------------------------------------------------------------;
                    769: 
                    770:         align   4
                    771:         public  non_replace_wide
                    772: non_replace_wide:
                    773:         push    ebx                     ;Save line count
                    774:         push    edi                     ;Save Dest Addr
                    775: 
                    776:         add     edi,ulLeftEdgeAdjust    ;point to first whole byte to fill
                    777: 
                    778:         lea     eax,do_wide_wes_trick
                    779:         mov     pfnWesTrick,eax
                    780: 
                    781:         mov     ecx,ulFgClr
                    782:         xor     ecx,ulBkClr             ;mask = ulBkClr ^ ulFgClr
                    783: 
                    784:         mov     ah,cl                   ;sre = !mask
                    785:         not     ah                      ;Set/Reset Enable
                    786:         mov     edx,EGA_BASE+GRAF_ADDR
                    787:         mov     al,GRAF_ENAB_SR
                    788:         out     dx,ax                   ;Set Set/Reset Enable bits
                    789: 
                    790:         mov     ah,byte ptr ulBkClr     ;Set/Reset = background color
                    791:         mov     al,GRAF_SET_RESET
                    792:         out     dx,ax
                    793: 
                    794:         mov     eax,GRAF_MODE + ((M_PROC_WRITE + M_COLOR_READ) SHL 8)
                    795:         out     dx,ax                   ; Set Read Mode 0
                    796: 
                    797: ;save the width count and pfn here
                    798: 
                    799:         call    wes_trick
                    800: 
                    801:         mov     edx,EGA_BASE+SEQ_DATA
                    802:         mov     eax,0fh
                    803:         out     dx,al
                    804: 
                    805:         mov     edx,EGA_BASE+GRAF_ADDR
                    806:         mov     eax,GRAF_MODE + ((M_PROC_WRITE + M_DATA_READ) SHL 8)
                    807:         out     dx,ax
                    808: 
                    809:         mov     eax,GRAF_ENAB_SR
                    810:         out     dx,ax                   ;Reset Set/Reset Enable bits
                    811: 
                    812:         pop     edi
                    813:         pop     ebx
                    814: 
                    815:         jmp     pfnContinueDrawing      ;either keep drawing or we're done
                    816: 
                    817: ;-----------------------------------------------------------------------;
                    818: ; Process any left/right columns that that have to be done.
                    819: ;
                    820: ;   Currently:
                    821: ;       EBX =   height to fill, in scans
                    822: ;       EDI --> first byte of left edge
                    823: ;-----------------------------------------------------------------------;
                    824: 
                    825: 
                    826: ;-----------------------------------------------------------------------;
                    827: ; Handle case where both edges are partial (non-whole) bytes.
                    828: ;-----------------------------------------------------------------------;
                    829: 
                    830:         align   4
                    831:         public  edge_byte_setup
                    832: edge_byte_setup:
                    833:         lea     eax,do_edge_wes_trick
                    834:         mov     pfnWesTrick,eax
                    835: 
                    836:         mov     ecx,ulFgClr
                    837:         xor     ecx,ulBkClr             ;mask = ulBkClr ^ ulFgClr
                    838: 
                    839:         mov     ah,cl                   ;sre = !mask
                    840:         not     ah                      ;Set/Reset Enable
                    841:         mov     edx,EGA_BASE+GRAF_ADDR
                    842:         mov     al,GRAF_ENAB_SR
                    843:         out     dx,ax                   ;Set Set/Reset Enable bits
                    844: 
                    845:         mov     ah,byte ptr ulBkClr     ;Set/Reset = foreground color
                    846:         mov     al,GRAF_SET_RESET
                    847:         out     dx,ax
                    848: 
                    849:         mov     eax,ulLeftEdgeAdjust
                    850:         or      eax,eax
                    851:         jz      short do_right_edge
                    852: 
                    853:         mov     eax,ulMasks             ;Get Left/Right edge Masks
                    854:         mov     ah,al
                    855:         mov     al,GRAF_BIT_MASK
                    856:         mov     edx,EGA_BASE+GRAF_ADDR
                    857:         out     dx,ax
                    858: 
                    859:         inc     pulPattern              ;Adjust Pattern rotation
                    860: 
                    861:         push    ebx                     ;Save line count
                    862:         push    edi                     ;Save Dest Addr
                    863:         call    wes_trick
                    864:         pop     edi
                    865:         pop     ebx
                    866: 
                    867:         mov     eax,ulMasks             ;restore Left/Right edge Masks
                    868:         dec     pulPattern              ;Adjust Pattern rotation
                    869: 
                    870: do_right_edge:
                    871:         mov     eax,ulMasks             ;Get Left/Right edge Masks
                    872:         and     ah,0ffh
                    873:         jz      edge_done
                    874: 
                    875:         mov     al,GRAF_BIT_MASK
                    876:         mov     edx,EGA_BASE+GRAF_ADDR
                    877:         out     dx,ax
                    878: 
                    879:         add     edi,ulLeftEdgeAdjust    ;point to first whole byte to fill
                    880:         add     edi,ulWholeBytes        ;point to right edge byte to fill
                    881:         call    wes_trick
                    882: 
                    883: edge_done:
                    884:         mov     edx,EGA_BASE+SEQ_DATA
                    885:         mov     eax,0fh
                    886:         out     dx,al
                    887: 
                    888:         mov     edx,EGA_BASE+GRAF_ADDR
                    889:         mov     eax,GRAF_BIT_MASK+0ff00h
                    890:         out     dx,ax
                    891: 
                    892:         mov     eax,GRAF_ENAB_SR
                    893:         out     dx,ax                   ;Reset Set/Reset Enable bits
                    894: 
                    895: 
                    896: ;-----------------------------------------------------------------------;
                    897: ; See if there are any more banks to process.
                    898: ;-----------------------------------------------------------------------;
                    899: 
                    900:         public check_next_bank
                    901: check_next_bank:
                    902: 
                    903:         mov     edi,pdsurf
                    904:         mov     eax,[edi].dsurf_rcl1WindowClip.yBottom ;is the fill bottom in
                    905:         cmp     ulBottomScan,eax                       ; the current bank?
                    906:         jle     short banks_done        ;yes, so we're done
                    907:                                         ;no, map in the next bank and fill it
                    908:         mov     ulCurrentTopScan,eax    ;remember where the top of the bank
                    909:                                         ; we're about to map in is (same as
                    910:                                         ; bottom of bank we just did)
                    911: 
                    912:         ptrCall <dword ptr [edi].dsurf_pfnBankControl>,<edi,eax,JustifyTop>
                    913:                                         ;map in the bank
                    914: 
                    915: ; Compute the starting address and scan line count in this bank.
                    916: 
                    917:         mov     eax,pdsurf              ;EAX->target surface
                    918:         mov     ebx,ulBottomScan        ;bottom of destination rectangle
                    919:         cmp     ebx,[eax].dsurf_rcl1WindowClip.yBottom
                    920:                                         ;which comes first, the bottom of the
                    921:                                         ; dest rect or the bottom of the
                    922:                                         ; current bank?
                    923:         jl      short BottomScanSet2    ;fill bottom comes first, so draw to
                    924:                                         ; that; this is the last bank in fill
                    925:         mov     ebx,[eax].dsurf_rcl1WindowClip.yBottom
                    926:                                         ;bank bottom comes first; draw to
                    927:                                         ; bottom of bank
                    928: BottomScanSet2:
                    929:         mov     edi,ulCurrentTopScan    ;top scan line to fill in current bank
                    930:         sub     ebx,edi                 ;# of scans to fill in bank
                    931:         imul    edi,ulScanWidth         ;offset of starting scan line
                    932: 
                    933: ; Note that the start of the bitmap will change each time through the
                    934: ; bank loop, because the start of the bitmap is varied to map the
                    935: ; desired scan line to the banking window.
                    936: 
                    937:         add     edi,[eax].dsurf_pvBitmapStart ;start of scan in bitmap
                    938:         add     edi,ulRowOffset         ;EDI = start offset of fill in bitmap
                    939: 
                    940: ; We have computed the starting address and scan count. Time to start drawing
                    941: ; in the initial bank.
                    942: 
                    943:         mov     esi,pBrush              ;edx = min(PatternHeight,BltHeight)
                    944:         mov     ecx,[esi + oem_brush_height]
                    945:         sub     ecx,ebx
                    946:         sbb     edx,edx
                    947:         and     edx,ecx
                    948:         add     edx,ebx
                    949:         mov     ulVbBlindCount,edx
                    950: 
                    951: ; Brush alignment. We need to look at pptlBrush
                    952: 
                    953:         mov     eax,ulCurrentTopScan    ;top scan line to fill in current bank
                    954:         sub     eax,ulPatternOrgY       ;
                    955: 
                    956:         jns     short pos_y_offset1     ;
                    957:         neg     eax                     ;
                    958:         and     eax,7                   ;-eax mod 8
                    959:         neg     eax                     ;
                    960:         add     eax,8                   ;
                    961:         jmp     short save_pat_pointer1
                    962: pos_y_offset1:
                    963:         and     eax,7                   ;eax mod 8
                    964: save_pat_pointer1:
                    965:         add     eax,eax                 ;Y Offset * PatternWidth (2 bytes)
                    966: 
                    967:         lea     edx,RotatedPat          ;Pattern Dest
                    968:         add     eax,edx
                    969:         mov     pulPattern,eax          ;Drawing code uses this as the
                    970:                                         ;source for the pattern
                    971: 
                    972: ; Draw in the new bank.
                    973: 
                    974:         jmp     pfnStartDrawing
                    975: 
                    976: 
                    977: ;-----------------------------------------------------------------------;
                    978: ; Done with all banks in this fill.
                    979: 
                    980:         public banks_done
                    981: banks_done:
                    982:         PLAIN_RET
                    983: 
                    984: endProc vMonoPatBlt
                    985: 
                    986: ;----------------------------------------------------------------------------
                    987: ; Wes Trick Setup code. This code decides if this is a one or a two pass
                    988: ; operation.
                    989: ;----------------------------------------------------------------------------
                    990:         align   4
                    991:         public  wes_trick
                    992: wes_trick:
                    993:         mov     esi,pfnWesTrick
                    994: 
                    995:         mov     ecx,ulFgClr             ;
                    996:         mov     eax,ecx                 ;
                    997:         xor     ecx,ulBkClr             ;mask = ulBkClr ^ ulFgClr
                    998: 
                    999:         mov     edx,EGA_BASE+SEQ_DATA   ;Index should be pointing to the
                   1000:                                         ; plane mask (2)
                   1001:         mov     ch,cl
                   1002:         not     ch                      ;Set/Reset Enable bits
                   1003:         and     cl,al                   ;ulFgdColor & mask
                   1004:         or      cl,al
                   1005:         jz      short check_bk_bits     ;if zero - one background pass
                   1006: 
                   1007:         mov     ulVbMask,0              ;We do not want to invert the
                   1008:                                         ;foreground pass
                   1009:         or      ch,cl
                   1010:         mov     al,ch
                   1011:         out     dx,al                   ;Enable Planes for First Pass
                   1012: 
                   1013:         push    ecx
                   1014:         push    edi                     ;Save our Dest pointer
                   1015:         push    ebx                     ;Save our count
                   1016:         call    esi                     ;Draw the foreground pass
                   1017:         pop     ebx                     ;restore the line count
                   1018:         pop     edi                     ;restore the dest pointer
                   1019:         pop     eax                     ;Restore bk mask
                   1020:         mov     esi,pfnWesTrick
                   1021: 
                   1022: 
                   1023: check_bk_bits:
                   1024:         not     al
                   1025:         and     al,MM_ALL
                   1026:         jnz     short @f
                   1027:         ret
                   1028: @@:
                   1029:         mov     ulVbMask,-1             ;We do not want to invert the
                   1030:         mov     edx,EGA_BASE+SEQ_DATA   ;Index should be pointing to the
                   1031:                                         ; plane mask (2)
                   1032:         out     dx,al
                   1033:         jmp     esi
                   1034: 
                   1035: ;--------------------------------------------------------------------------
                   1036: ; Do the edges here.
                   1037: ;--------------------------------------------------------------------------
                   1038: 
                   1039:         align 4
                   1040:         public do_edge_wes_trick
                   1041: do_edge_wes_trick:
                   1042:         ;       ebx = line count
                   1043:         ;       edi = dest
                   1044: 
                   1045:         mov     ulVbTopScan,ebx         ;Mod 8 our count for the venetian blind
                   1046:         add     ebx,ulVbYRound          ;Calc the number of lines to do
                   1047:         mov     ecx,ulVbyShift
                   1048:         shr     ebx,cl
                   1049: 
                   1050:         mov     esi,pulPattern
                   1051:         mov     ax,[esi]                ;get pattern into place
                   1052:         add     esi,2                   ;patterns stored as words
                   1053:         xor     eax,ulVbMask            ;Invert the pattern if we are doing
                   1054:                                         ; a background pass
                   1055: 
                   1056:         push    ulVbBlindCount
                   1057:         ; Set up variables for entering unrolled loop.
                   1058: wes_trick_loop:
                   1059:         SET_UP_UNROLL_VARS ebx,edx, ebx,pfnDraw1WideEntry, LOOP_UNROLL_SHIFT
                   1060: 
                   1061:         mov     ecx,ulVbNextScan        ;offset from one scan to next
                   1062: 
                   1063:         push    edi                     ;save dest pointer
                   1064:         call    edx                     ;jump into the unrolled loop to draw
                   1065:         pop     edi                     ;restore dest pointer
                   1066: 
                   1067:         add     edi,ulScanWidth         ;move to next scan line
                   1068: 
                   1069:         dec     ulVbBlindCount
                   1070:         jz      short wes_trick_loop_done  ;jz if we are finished
                   1071: 
                   1072:         mov     eax,ulVbTopScan         ;restore scan count
                   1073:         dec     eax                     ;Subtract off completed top line
                   1074:         mov     ulVbTopScan,eax         ;save for next loop
                   1075:         add     eax,ulVbYRound          ;Calc the number of lines to do
                   1076:         mov     ecx,ulVbyShift          ;for this venetian blind pass
                   1077:         shr     eax,cl                  ;including any partial patterns
                   1078:         mov     ebx,eax                 ;at the bottom
                   1079: 
                   1080: 
                   1081:         mov     ax,[esi]
                   1082:         add     esi,2                   ;point to the next pattern line
                   1083:         xor     eax,ulVbMask            ;Invert the pattern if we are doing
                   1084:                                         ; a background pass
                   1085: 
                   1086:         jmp     short wes_trick_loop
                   1087: 
                   1088:         align   4
                   1089: wes_trick_loop_done:
                   1090:         pop     ulVbBlindCount
                   1091:         ret
                   1092: 
                   1093: ;--------------------------------------------------------------------------
                   1094: ; Do the middle bytes here for blts with rops.
                   1095: ;--------------------------------------------------------------------------
                   1096: 
                   1097:         align   4
                   1098:         public  do_wide_wes_trick
                   1099: do_wide_wes_trick:
                   1100:         ;       ebx = line count
                   1101:         ;       edi = dest
                   1102: 
                   1103:         mov     ulVbTopScan,ebx         ;Mod 8 our count for the venetian blind
                   1104:         add     ebx,ulVbYRound          ;Calc the number of lines to do
                   1105:         mov     ecx,ulVbyShift
                   1106:         shr     ebx,cl
                   1107: 
                   1108:         mov     esi,pulPattern
                   1109:         mov     al,[esi]                ;get pattern into place
                   1110:         add     esi,2                   ;patterns stored as words
                   1111:         mov     pulVbPattern,esi
                   1112:         xor     eax,ulVbMask            ;Invert the pattern if we are doing
                   1113:                                         ; a background pass
                   1114: 
                   1115:         push    ulVbBlindCount
                   1116: 
                   1117:         mov     edx,pfnWholeBytes
                   1118: 
                   1119:         ; Set up variables for entering unrolled loop.
                   1120: wide_wes_trick_loop:
                   1121: 
                   1122:         SET_UP_UNROLL_VARS ebx,ecx,ebx,[edx], LOOP_UNROLL_SHIFT
                   1123: 
                   1124:         mov     esi,ulWholeBytes
                   1125:         mov     edx,ulVbNextScan        ;offset from one scan to next
                   1126:         sub     edx,esi
                   1127:         add     edx,ulSpecialBytes
                   1128: 
                   1129:         push    edi                     ;save dest pointer
                   1130:         call    ecx                     ;jump into the unrolled loop to draw
                   1131:         pop     edi                     ;restore dest pointer
                   1132: 
                   1133:         add     edi,ulScanWidth         ;move to next scan line
                   1134: 
                   1135:         dec     ulVbBlindCount
                   1136:         jz      short wide_wes_trick_loop_done  ;jz if we are finished
                   1137: 
                   1138:         mov     eax,ulVbTopScan         ;restore scan count
                   1139:         dec     eax                     ;Subtract off completed top line
                   1140:         mov     ulVbTopScan,eax         ;save for next loop
                   1141:         add     eax,ulVbYRound          ;Calc the number of lines to do
                   1142:         mov     ecx,ulVbyShift          ;for this venetian blind pass
                   1143:         shr     eax,cl                  ;including any partial patterns
                   1144:         mov     ebx,eax                 ;at the bottom
                   1145: 
                   1146: 
                   1147:         mov     esi,pulVbPattern
                   1148:         mov     al,[esi]                ;get pattern word
                   1149:         add     esi,2                   ;point to the next pattern line
                   1150:         mov     pulVbPattern,esi
                   1151:         xor     eax,ulVbMask            ;Invert the pattern if we are doing
                   1152:                                         ; a background pass
                   1153: 
                   1154:         mov     edx,pfnWholeBytes
                   1155:         jmp     short wide_wes_trick_loop
                   1156: 
                   1157:         align   4
                   1158: wide_wes_trick_loop_done:
                   1159:         pop     ulVbBlindCount
                   1160:         ret
                   1161: 
                   1162: ;-----------------------------------------------------------------------;
                   1163: ; Unrolled loops.
                   1164: ;-----------------------------------------------------------------------;
                   1165: 
                   1166: ;-----------------------------------------------------------------------;
                   1167: ; Unrolled loop stuff for wide replace-type rops (arbitrary width).
                   1168: ;-----------------------------------------------------------------------;
                   1169: 
                   1170: ; Tables of entry points into unrolled wide write-only loops.
                   1171:         UNROLL_LOOP_ENTRY_TABLE pfnDrawWide00Entry,W00,LOOP_UNROLL_COUNT
                   1172:         UNROLL_LOOP_ENTRY_TABLE pfnDrawWide01Entry,W01,LOOP_UNROLL_COUNT
                   1173:         UNROLL_LOOP_ENTRY_TABLE pfnDrawWide10Entry,W10,LOOP_UNROLL_COUNT
                   1174:         UNROLL_LOOP_ENTRY_TABLE pfnDrawWide11Entry,W11,LOOP_UNROLL_COUNT
                   1175: 
                   1176: ;-----------------------------------------------------------------------;
                   1177: ; Macro to draw n bytes, 0 leading bytes, 0 trailing bytes, then advance
                   1178: ; to next scan line.
                   1179: 
                   1180: DRAW_WIDE_00 macro ENTRY_LABEL,ENTRY_INDEX
                   1181: &ENTRY_LABEL&ENTRY_INDEX&:
                   1182:         mov     ecx,esi         ;# of whole words
                   1183:         rep     stosw           ;fill all whole bytes as dwords
                   1184:         add     edi,edx         ;point to the next scan line
                   1185:         endm    ;-----------------------------------;
                   1186: 
                   1187: ; N-wide write-only, 0 leading bytes, 0 trailing bytes.
                   1188: ;  EAX = Pattern Byte
                   1189: ;  EBX = count of scans to fill ((total scans/ pattern height) + partial)
                   1190: ;  EDX = offset from end of one scan's fill to start of next similar line
                   1191: ;  ESI = pattern data
                   1192: ;  EDI = target address to fill
                   1193: 
                   1194:         align   4
                   1195: draw_wide_00_loop     proc    near
                   1196:         UNROLL_LOOP     DRAW_WIDE_00,W00,LOOP_UNROLL_COUNT
                   1197:         dec     ebx
                   1198:         jnz     draw_wide_00_loop
                   1199: 
                   1200:         ret
                   1201: 
                   1202: draw_wide_00_loop     endp
                   1203: 
                   1204: 
                   1205: ;-----------------------------------------------------------------------;
                   1206: ; Macro to draw n bytes, 0 leading bytes, 0 trailing bytes, then advance
                   1207: ; to next scan line.
                   1208: 
                   1209: DRAW_WIDE_01 macro ENTRY_LABEL,ENTRY_INDEX
                   1210: &ENTRY_LABEL&ENTRY_INDEX&:
                   1211:         mov     ecx,esi         ;# of whole words
                   1212:         rep     stosw           ;fill all whole bytes as dwords
                   1213:         mov     [edi],al        ;trailing byte
                   1214:         inc     edi
                   1215:         add     edi,edx         ;point to the next scan line
                   1216:         endm    ;-----------------------------------;
                   1217: 
                   1218: ; N-wide write-only, 0 leading bytes, 0 trailing bytes.
                   1219: ;  EAX = Pattern Byte
                   1220: ;  EBX = count of scans to fill ((total scans/ pattern height) + partial)
                   1221: ;  EDX = offset from end of one scan's fill to start of next similar line
                   1222: ;  ESI = pattern data
                   1223: ;  EDI = target address to fill
                   1224: 
                   1225:         align   4
                   1226: draw_wide_01_loop     proc    near
                   1227:         UNROLL_LOOP     DRAW_WIDE_01,W01,LOOP_UNROLL_COUNT
                   1228:         dec     ebx
                   1229:         jnz     draw_wide_01_loop
                   1230:         ret
                   1231: 
                   1232: draw_wide_01_loop     endp
                   1233: 
                   1234: 
                   1235: ;-----------------------------------------------------------------------;
                   1236: ; Macro to draw n bytes, 0 leading bytes, 0 trailing bytes, then advance
                   1237: ; to next scan line.
                   1238: 
                   1239: DRAW_WIDE_10 macro ENTRY_LABEL,ENTRY_INDEX
                   1240: &ENTRY_LABEL&ENTRY_INDEX&:
                   1241:         mov     [edi],ah        ;do leading byte
                   1242:         inc     edi             ;advance poitner
                   1243:         mov     ecx,esi         ;# of whole words
                   1244:         rep     stosw           ;fill all whole bytes as dwords
                   1245:         add     edi,edx         ;point to the next scan line
                   1246:         endm    ;-----------------------------------;
                   1247: 
                   1248: ; N-wide write-only, 0 leading bytes, 0 trailing bytes.
                   1249: ;  EAX = Pattern Byte
                   1250: ;  EBX = count of scans to fill ((total scans/ pattern height) + partial)
                   1251: ;  EDX = offset from end of one scan's fill to start of next similar line
                   1252: ;  ESI = pattern data
                   1253: ;  EDI = target address to fill
                   1254: 
                   1255:         align   4
                   1256: draw_wide_10_loop     proc    near
                   1257:         UNROLL_LOOP     DRAW_WIDE_10,W10,LOOP_UNROLL_COUNT
                   1258:         dec     ebx
                   1259:         jnz     draw_wide_10_loop
                   1260:         ret
                   1261: 
                   1262: draw_wide_10_loop     endp
                   1263: 
                   1264: ;-----------------------------------------------------------------------;
                   1265: ; Macro to draw n bytes, 0 leading bytes, 0 trailing bytes, then advance
                   1266: ; to next scan line.
                   1267: 
                   1268: DRAW_WIDE_11 macro ENTRY_LABEL,ENTRY_INDEX
                   1269: &ENTRY_LABEL&ENTRY_INDEX&:
                   1270:         mov     [edi],ah        ;do leading byte
                   1271:         inc     edi             ;advance poitner
                   1272:         mov     ecx,esi         ;# of whole words
                   1273:         rep     stosw           ;fill all whole bytes as dwords
                   1274:         mov     [edi],al        ;trailing byte
                   1275:         inc     edi
                   1276:         add     edi,edx         ;point to the next scan line
                   1277:         endm    ;-----------------------------------;
                   1278: 
                   1279: ; N-wide write-only, 0 leading bytes, 0 trailing bytes.
                   1280: ;  EAX = Pattern Byte
                   1281: ;  EBX = count of scans to fill ((total scans/ pattern height) + partial)
                   1282: ;  EDX = offset from end of one scan's fill to start of next similar line
                   1283: ;  ESI = pattern data
                   1284: ;  EDI = target address to fill
                   1285: 
                   1286:         align   4
                   1287: draw_wide_11_loop     proc    near
                   1288:         UNROLL_LOOP     DRAW_WIDE_11,W11,LOOP_UNROLL_COUNT
                   1289:         dec     ebx
                   1290:         jnz     draw_wide_11_loop
                   1291:         ret
                   1292: 
                   1293: draw_wide_11_loop     endp
                   1294: 
                   1295: ;-----------------------------------------------------------------------;
                   1296: ; Unrolled drawing stuff (unrolled to reduce jumps to speed things up),
                   1297: ; for cases where read before write is NOT required.
                   1298: ;-----------------------------------------------------------------------;
                   1299: 
                   1300: ; Tables of entry points into unrolled 1-, 2-, 3-, and 4-wide write-only loops.
                   1301: ; Note that there may be separate entry tables for various alignments of a
                   1302: ; specific width, in cases where performance can be improved by using different
                   1303: ; code for different alignments.
                   1304: 
                   1305:         UNROLL_LOOP_ENTRY_TABLE pfnDraw1WideEvenEntry,W1_EVEN,LOOP_UNROLL_COUNT
                   1306:         UNROLL_LOOP_ENTRY_TABLE pfnDraw1WideOddEntry,W1_ODD,LOOP_UNROLL_COUNT
                   1307:         UNROLL_LOOP_ENTRY_TABLE pfnDraw2WideEvenEntry,W2_EVEN,LOOP_UNROLL_COUNT
                   1308:         UNROLL_LOOP_ENTRY_TABLE pfnDraw2WideOddEntry,W2_ODD,LOOP_UNROLL_COUNT
                   1309:         UNROLL_LOOP_ENTRY_TABLE pfnDraw3WideEvenEntry,W3_EVEN,LOOP_UNROLL_COUNT
                   1310:         UNROLL_LOOP_ENTRY_TABLE pfnDraw3WideOddEntry,W3_ODD,LOOP_UNROLL_COUNT
                   1311:         UNROLL_LOOP_ENTRY_TABLE pfnDraw4WideEvenEntry,W4_EVEN,LOOP_UNROLL_COUNT
                   1312:         UNROLL_LOOP_ENTRY_TABLE pfnDraw4WideOddEntry,W4_ODD,LOOP_UNROLL_COUNT
                   1313:         UNROLL_LOOP_ENTRY_TABLE pfnDraw5WideEvenEntry,W5_EVEN,LOOP_UNROLL_COUNT
                   1314:         UNROLL_LOOP_ENTRY_TABLE pfnDraw5WideOddEntry,W5_ODD,LOOP_UNROLL_COUNT
                   1315:         UNROLL_LOOP_ENTRY_TABLE pfnDraw6WideEvenEntry,W6_EVEN,LOOP_UNROLL_COUNT
                   1316:         UNROLL_LOOP_ENTRY_TABLE pfnDraw6WideOddEntry,W6_ODD,LOOP_UNROLL_COUNT
                   1317:         UNROLL_LOOP_ENTRY_TABLE pfnDraw7WideEvenEntry,W7_EVEN,LOOP_UNROLL_COUNT
                   1318:         UNROLL_LOOP_ENTRY_TABLE pfnDraw7WideOddEntry,W7_ODD,LOOP_UNROLL_COUNT
                   1319:         UNROLL_LOOP_ENTRY_TABLE pfnDraw8WideEvenEntry,W8_EVEN,LOOP_UNROLL_COUNT
                   1320:         UNROLL_LOOP_ENTRY_TABLE pfnDraw8WideOddEntry,W8_ODD,LOOP_UNROLL_COUNT
                   1321: 
                   1322: ;-----------------------------------------------------------------------;
                   1323: ; Unrolled 1-, 2-, 3-, and 4-wide write-only edge-drawing loops.
                   1324: ;
                   1325: ; Entry:
                   1326: ;       AL/AX/EAX = pixel mask (if AX or EAX, then 0xFFFF or 0xFFFFFFFF)
                   1327: ;       EBX = unrolled loop count
                   1328: ;       ECX = scan line width in bytes
                   1329: ;       EDI = start offset
                   1330: ;
                   1331: ; EBX, EDI modified. All other registers preserved.
                   1332: 
                   1333: ;-----------------------------------------------------------------------;
                   1334: ; Macro to draw one write-only byte, then advance to next scan line.
                   1335: 
                   1336: DRAW_1_WIDE_EVEN macro ENTRY_LABEL,ENTRY_INDEX
                   1337: &ENTRY_LABEL&ENTRY_INDEX&:
                   1338:         mov     [edi],al                ;we always read 0xFF, so AL is written
                   1339:                                         ; as-is; because we're in write mode 3,
                   1340:                                         ; AL becomes the Bit Mask
                   1341:         add     edi,edx                 ;point to the next scan line
                   1342:         endm    ;-----------------------------------;
                   1343: 
                   1344: ; 1-wide write-only.
                   1345: 
                   1346:         align   4
                   1347: draw_1_wide_even_loop     proc    near
                   1348:         UNROLL_LOOP     DRAW_1_WIDE_EVEN,W1_EVEN,LOOP_UNROLL_COUNT
                   1349:         dec     ebx
                   1350:         jnz     draw_1_wide_even_loop
                   1351: 
                   1352:         ret
                   1353: 
                   1354: draw_1_wide_even_loop     endp
                   1355: 
                   1356: DRAW_1_WIDE_ODD macro ENTRY_LABEL,ENTRY_INDEX
                   1357: &ENTRY_LABEL&ENTRY_INDEX&:
                   1358:         mov     [edi],ah                ;we always read 0xFF, so AL is written
                   1359:                                         ; as-is; because we're in write mode 3,
                   1360:                                         ; AL becomes the Bit Mask
                   1361:         add     edi,edx                 ;point to the next scan line
                   1362:         endm    ;-----------------------------------;
                   1363: 
                   1364: ; 1-wide write-only.
                   1365: 
                   1366:         align   4
                   1367: draw_1_wide_odd_loop     proc    near
                   1368:         UNROLL_LOOP     DRAW_1_WIDE_ODD,W1_ODD,LOOP_UNROLL_COUNT
                   1369:         dec     ebx
                   1370:         jnz     draw_1_wide_odd_loop
                   1371: 
                   1372:         ret
                   1373: 
                   1374: draw_1_wide_odd_loop     endp
                   1375: 
                   1376: ;-----------------------------------------------------------------------;
                   1377: ; Macro to draw two write-only bytes, then advance to next scan line.
                   1378: 
                   1379: DRAW_2_WIDE_EVEN macro ENTRY_LABEL,ENTRY_INDEX
                   1380: &ENTRY_LABEL&ENTRY_INDEX&:
                   1381:         mov     [edi],ax
                   1382:         add     edi,edx                 ;point to the next scan line
                   1383:         endm    ;-----------------------------------;
                   1384: 
                   1385: ; 2-wide write-only.
                   1386: 
                   1387:         align   4
                   1388: draw_2_wide_even_loop     proc    near
                   1389:         UNROLL_LOOP     DRAW_2_WIDE_EVEN,W2_EVEN,LOOP_UNROLL_COUNT
                   1390:         dec     ebx
                   1391:         jnz     draw_2_wide_even_loop
                   1392: 
                   1393:         ret
                   1394: 
                   1395: draw_2_wide_even_loop     endp
                   1396: 
                   1397: DRAW_2_WIDE_ODD macro ENTRY_LABEL,ENTRY_INDEX
                   1398: &ENTRY_LABEL&ENTRY_INDEX&:
                   1399:         mov     [edi],ah
                   1400:         mov     [edi+1],al
                   1401:         add     edi,edx                 ;point to the next scan line
                   1402:         endm    ;-----------------------------------;
                   1403: 
                   1404: ; 2-wide write-only.
                   1405: 
                   1406:         align   4
                   1407: draw_2_wide_odd_loop     proc    near
                   1408:         UNROLL_LOOP     DRAW_2_WIDE_ODD,W2_ODD,LOOP_UNROLL_COUNT
                   1409:         dec     ebx
                   1410:         jnz     draw_2_wide_odd_loop
                   1411: 
                   1412:         ret
                   1413: 
                   1414: draw_2_wide_odd_loop     endp
                   1415: 
                   1416: ;-----------------------------------------------------------------------;
                   1417: ; Macro to draw three write-only bytes, then advance to next scan line.
                   1418: ; Optimized for even start address.
                   1419: 
                   1420: DRAW_3_WIDE_EVEN macro ENTRY_LABEL,ENTRY_INDEX
                   1421: &ENTRY_LABEL&ENTRY_INDEX&:
                   1422:         mov     [edi],ax
                   1423:         mov     [edi+2],al
                   1424:         add     edi,edx                 ;point to the next scan line
                   1425:         endm    ;-----------------------------------;
                   1426: 
                   1427: ; 3-wide write-only, starting at an even address.
                   1428: 
                   1429:         align   4
                   1430: draw_3_wide_even_loop     proc    near
                   1431:         UNROLL_LOOP     DRAW_3_WIDE_EVEN,W3_EVEN,LOOP_UNROLL_COUNT
                   1432:         dec     ebx
                   1433:         jnz     draw_3_wide_even_loop
                   1434: 
                   1435:         ret
                   1436: 
                   1437: draw_3_wide_even_loop     endp
                   1438: 
                   1439: ;-----------------------------------------------------------------------;
                   1440: ; Macro to draw three write-only bytes, then advance to next scan line.
                   1441: ; Optimized for odd start address.
                   1442: 
                   1443: DRAW_3_WIDE_ODD macro ENTRY_LABEL,ENTRY_INDEX
                   1444: &ENTRY_LABEL&ENTRY_INDEX&:
                   1445:         mov     [edi],ah
                   1446:         mov     [edi+1],ax
                   1447:         add     edi,edx                 ;point to the next scan line
                   1448:         endm    ;-----------------------------------;
                   1449: 
                   1450: ; 3-wide write-only, starting at an odd address.
                   1451: 
                   1452:         align   4
                   1453: draw_3_wide_odd_loop     proc    near
                   1454:         UNROLL_LOOP     DRAW_3_WIDE_ODD,W3_ODD,LOOP_UNROLL_COUNT
                   1455:         dec     ebx
                   1456:         jnz     draw_3_wide_odd_loop
                   1457: 
                   1458:         ret
                   1459: 
                   1460: draw_3_wide_odd_loop     endp
                   1461: 
                   1462: 
                   1463: ;-----------------------------------------------------------------------;
                   1464: ; Macro to draw three write-only bytes, then advance to next scan line.
                   1465: ; Optimized for even start address.
                   1466: 
                   1467: DRAW_4_WIDE_EVEN macro ENTRY_LABEL,ENTRY_INDEX
                   1468: &ENTRY_LABEL&ENTRY_INDEX&:
                   1469:         mov     [edi],ax
                   1470:         mov     [edi+2],ax
                   1471:         add     edi,edx                 ;point to the next scan line
                   1472:         endm    ;-----------------------------------;
                   1473: 
                   1474: ; 4-wide write-only, starting at an even address.
                   1475: 
                   1476:         align   4
                   1477: draw_4_wide_even_loop     proc    near
                   1478:         UNROLL_LOOP     DRAW_4_WIDE_EVEN,W4_EVEN,LOOP_UNROLL_COUNT
                   1479:         dec     ebx
                   1480:         jnz     draw_4_wide_even_loop
                   1481: 
                   1482:         ret
                   1483: 
                   1484: draw_4_wide_even_loop     endp
                   1485: 
                   1486: ;-----------------------------------------------------------------------;
                   1487: ; Macro to draw three write-only bytes, then advance to next scan line.
                   1488: ; Optimized for odd start address.
                   1489: 
                   1490: DRAW_4_WIDE_ODD macro ENTRY_LABEL,ENTRY_INDEX
                   1491: &ENTRY_LABEL&ENTRY_INDEX&:
                   1492:         mov     [edi],ah
                   1493:         mov     [edi+1],ax
                   1494:         mov     [edi+3],al
                   1495:         add     edi,edx                 ;point to the next scan line
                   1496:         endm    ;-----------------------------------;
                   1497: 
                   1498: ; 4-wide write-only, starting at an odd address.
                   1499: 
                   1500:         align   4
                   1501: draw_4_wide_odd_loop     proc    near
                   1502:         UNROLL_LOOP     DRAW_4_WIDE_ODD,W4_ODD,LOOP_UNROLL_COUNT
                   1503:         dec     ebx
                   1504:         jnz     draw_4_wide_odd_loop
                   1505: 
                   1506:         ret
                   1507: 
                   1508: draw_4_wide_odd_loop     endp
                   1509: 
                   1510: ;-----------------------------------------------------------------------;
                   1511: ; Macro to draw three write-only bytes, then advance to next scan line.
                   1512: ; Optimized for even start address.
                   1513: 
                   1514: DRAW_5_WIDE_EVEN macro ENTRY_LABEL,ENTRY_INDEX
                   1515: &ENTRY_LABEL&ENTRY_INDEX&:
                   1516:         mov     [edi],ax
                   1517:         mov     [edi+2],ax
                   1518:         mov     [edi+4],al
                   1519:         add     edi,edx                 ;point to the next scan line
                   1520:         endm    ;-----------------------------------;
                   1521: 
                   1522: ; 5-wide write-only, starting at an even address.
                   1523: 
                   1524:         align   4
                   1525: draw_5_wide_even_loop     proc    near
                   1526:         UNROLL_LOOP     DRAW_5_WIDE_EVEN,W5_EVEN,LOOP_UNROLL_COUNT
                   1527:         dec     ebx
                   1528:         jnz     draw_5_wide_even_loop
                   1529: 
                   1530:         ret
                   1531: 
                   1532: draw_5_wide_even_loop     endp
                   1533: 
                   1534: ;-----------------------------------------------------------------------;
                   1535: ; Macro to draw three write-only bytes, then advance to next scan line.
                   1536: ; Optimized for odd start address.
                   1537: 
                   1538: DRAW_5_WIDE_ODD macro ENTRY_LABEL,ENTRY_INDEX
                   1539: &ENTRY_LABEL&ENTRY_INDEX&:
                   1540:         mov     [edi],ah
                   1541:         mov     [edi+1],ax
                   1542:         mov     [edi+3],ax
                   1543:         add     edi,edx                 ;point to the next scan line
                   1544:         endm    ;-----------------------------------;
                   1545: 
                   1546: ; 5-wide write-only, starting at an odd address.
                   1547: 
                   1548:         align  4
                   1549: draw_5_wide_odd_loop     proc    near
                   1550:         UNROLL_LOOP     DRAW_5_WIDE_ODD,W5_ODD,LOOP_UNROLL_COUNT
                   1551:         dec     ebx
                   1552:         jnz     draw_5_wide_odd_loop
                   1553: 
                   1554:         ret
                   1555: 
                   1556: draw_5_wide_odd_loop     endp
                   1557: 
                   1558: ;-----------------------------------------------------------------------;
                   1559: ; Macro to draw three write-only bytes, then advance to next scan line.
                   1560: ; Optimized for even start address.
                   1561: 
                   1562: DRAW_6_WIDE_EVEN macro ENTRY_LABEL,ENTRY_INDEX
                   1563: &ENTRY_LABEL&ENTRY_INDEX&:
                   1564:         mov     [edi],ax
                   1565:         mov     [edi+2],ax
                   1566:         mov     [edi+4],ax
                   1567:         add     edi,edx                 ;point to the next scan line
                   1568:         endm    ;-----------------------------------;
                   1569: 
                   1570: ; 6-wide write-only, starting at an even address.
                   1571: 
                   1572:         align   4
                   1573: draw_6_wide_even_loop     proc    near
                   1574:         UNROLL_LOOP     DRAW_6_WIDE_EVEN,W6_EVEN,LOOP_UNROLL_COUNT
                   1575:         dec     ebx
                   1576:         jnz     draw_6_wide_even_loop
                   1577: 
                   1578:         ret
                   1579: 
                   1580: draw_6_wide_even_loop     endp
                   1581: 
                   1582: ;-----------------------------------------------------------------------;
                   1583: ; Macro to draw three write-only bytes, then advance to next scan line.
                   1584: ; Optimized for odd start address.
                   1585: 
                   1586: DRAW_6_WIDE_ODD macro ENTRY_LABEL,ENTRY_INDEX
                   1587: &ENTRY_LABEL&ENTRY_INDEX&:
                   1588:         mov     [edi],ah
                   1589:         mov     [edi+1],ax
                   1590:         mov     [edi+3],ax
                   1591:         mov     [edi+5],al
                   1592:         add     edi,edx                 ;point to the next scan line
                   1593:         endm    ;-----------------------------------;
                   1594: 
                   1595: ; 6-wide write-only, starting at an odd address.
                   1596: 
                   1597:         align   4
                   1598: draw_6_wide_odd_loop     proc    near
                   1599:         UNROLL_LOOP     DRAW_6_WIDE_ODD,W6_ODD,LOOP_UNROLL_COUNT
                   1600:         dec     ebx
                   1601:         jnz     draw_6_wide_odd_loop
                   1602: 
                   1603:         ret
                   1604: 
                   1605: draw_6_wide_odd_loop     endp
                   1606: 
                   1607: ;-----------------------------------------------------------------------;
                   1608: ; Macro to draw three write-only bytes, then advance to next scan line.
                   1609: ; Optimized for even start address.
                   1610: 
                   1611: DRAW_7_WIDE_EVEN macro ENTRY_LABEL,ENTRY_INDEX
                   1612: &ENTRY_LABEL&ENTRY_INDEX&:
                   1613:         mov     [edi],ax
                   1614:         mov     [edi+2],ax
                   1615:         mov     [edi+4],ax
                   1616:         mov     [edi+6],al
                   1617:         add     edi,edx                 ;point to the next scan line
                   1618:         endm    ;-----------------------------------;
                   1619: 
                   1620: ; 7-wide write-only, starting at an even address.
                   1621: 
                   1622:         align   4
                   1623: draw_7_wide_even_loop     proc    near
                   1624:         UNROLL_LOOP     DRAW_7_WIDE_EVEN,W7_EVEN,LOOP_UNROLL_COUNT
                   1625:         dec     ebx
                   1626:         jnz     draw_7_wide_even_loop
                   1627: 
                   1628:         ret
                   1629: 
                   1630: draw_7_wide_even_loop     endp
                   1631: 
                   1632: ;-----------------------------------------------------------------------;
                   1633: ; Macro to draw three write-only bytes, then advance to next scan line.
                   1634: ; Optimized for odd start address.
                   1635: 
                   1636: DRAW_7_WIDE_ODD macro ENTRY_LABEL,ENTRY_INDEX
                   1637: &ENTRY_LABEL&ENTRY_INDEX&:
                   1638:         mov     [edi],ah
                   1639:         mov     [edi+1],ax
                   1640:         mov     [edi+3],ax
                   1641:         mov     [edi+5],ax
                   1642:         add     edi,edx                 ;point to the next scan line
                   1643:         endm    ;-----------------------------------;
                   1644: 
                   1645: ; 7-wide write-only, starting at an odd address.
                   1646: 
                   1647:         align   4
                   1648: draw_7_wide_odd_loop     proc    near
                   1649:         UNROLL_LOOP     DRAW_7_WIDE_ODD,W7_ODD,LOOP_UNROLL_COUNT
                   1650:         dec     ebx
                   1651:         jnz     draw_7_wide_odd_loop
                   1652: 
                   1653:         ret
                   1654: 
                   1655: draw_7_wide_odd_loop     endp
                   1656: 
                   1657: ;-----------------------------------------------------------------------;
                   1658: ; Macro to draw three write-only bytes, then advance to next scan line.
                   1659: ; Optimized for even start address.
                   1660: 
                   1661: DRAW_8_WIDE_EVEN macro ENTRY_LABEL,ENTRY_INDEX
                   1662: &ENTRY_LABEL&ENTRY_INDEX&:
                   1663:         mov     [edi],ax
                   1664:         mov     [edi+2],ax
                   1665:         mov     [edi+4],ax
                   1666:         mov     [edi+6],ax
                   1667:         add     edi,edx                 ;point to the next scan line
                   1668:         endm    ;-----------------------------------;
                   1669: 
                   1670: ; 8-wide write-only, starting at an even address.
                   1671: 
                   1672:         align   4
                   1673: draw_8_wide_even_loop     proc    near
                   1674:         UNROLL_LOOP     DRAW_8_WIDE_EVEN,W8_EVEN,LOOP_UNROLL_COUNT
                   1675:         dec     ebx
                   1676:         jnz     draw_8_wide_even_loop
                   1677: 
                   1678:         ret
                   1679: 
                   1680: draw_8_wide_even_loop     endp
                   1681: 
                   1682: ;-----------------------------------------------------------------------;
                   1683: ; Macro to draw three write-only bytes, then advance to next scan line.
                   1684: ; Optimized for odd start address.
                   1685: 
                   1686: DRAW_8_WIDE_ODD macro ENTRY_LABEL,ENTRY_INDEX
                   1687: &ENTRY_LABEL&ENTRY_INDEX&:
                   1688:         mov     [edi],ah
                   1689:         mov     [edi+1],ax
                   1690:         mov     [edi+3],ax
                   1691:         mov     [edi+5],ax
                   1692:         mov     [edi+7],al
                   1693:         add     edi,edx                 ;point to the next scan line
                   1694:         endm    ;-----------------------------------;
                   1695: 
                   1696: ; 8-wide write-only, starting at an odd address.
                   1697: 
                   1698:         align   4
                   1699: draw_8_wide_odd_loop     proc    near
                   1700:         UNROLL_LOOP     DRAW_8_WIDE_ODD,W8_ODD,LOOP_UNROLL_COUNT
                   1701:         dec     ebx
                   1702:         jnz     draw_8_wide_odd_loop
                   1703: 
                   1704:         ret
                   1705: 
                   1706: draw_8_wide_odd_loop     endp
                   1707: 
                   1708: ;-----------------------------------------------------------------------;
                   1709: ; Unrolled 1-, 2-, 3-, and 4-wide read before write drawing loops.
                   1710: ;
                   1711: ; Entry:
                   1712: ;       AL = pixel mask
                   1713: ;       EBX = unrolled loop count
                   1714: ;       ECX = scan line width in bytes
                   1715: ;       EDI = start offset
                   1716: ;
                   1717: ; EBX, EDI modified. All other registers preserved.
                   1718: 
                   1719:         UNROLL_LOOP_ENTRY_TABLE pfnDraw1WideEntry,RW1,LOOP_UNROLL_COUNT
                   1720: 
                   1721: ;-----------------------------------------------------------------------;
                   1722: ; Macro to draw one read before write byte, then advance to next scan line.
                   1723: 
                   1724: DRAW_1_WIDE macro ENTRY_LABEL,ENTRY_INDEX
                   1725: &ENTRY_LABEL&ENTRY_INDEX&:
                   1726:         mov     dh,[edi]                ;load latches w/o destroying our data
                   1727:         mov     [edi],al                ;write out our byte
                   1728:         add     edi,ecx                 ;move to the next blind
                   1729:         endm    ;-----------------------------------;
                   1730: 
                   1731: ; 1-wide read/write.
                   1732: 
                   1733:         align   4
                   1734: draw_1_wide_loop     proc    near
                   1735:         UNROLL_LOOP     DRAW_1_WIDE,RW1,LOOP_UNROLL_COUNT
                   1736:         dec     ebx
                   1737:         jnz     draw_1_wide_loop
                   1738: 
                   1739:         ret
                   1740: 
                   1741: draw_1_wide_loop     endp
                   1742: 
                   1743: ; Tables of entry points into unrolled 1-, 2-, 3-, and 4-wide, and 5-or-wider
                   1744: ; read before write loops.
                   1745: 
                   1746:         UNROLL_LOOP_ENTRY_TABLE pfnDraw1RWEntry,RWW1,LOOP_UNROLL_COUNT
                   1747:         UNROLL_LOOP_ENTRY_TABLE pfnDraw2RWEntry,RWW2,LOOP_UNROLL_COUNT
                   1748:         UNROLL_LOOP_ENTRY_TABLE pfnDraw3RWEntry,RWW3,LOOP_UNROLL_COUNT
                   1749:         UNROLL_LOOP_ENTRY_TABLE pfnDraw4RWEntry,RWW4,LOOP_UNROLL_COUNT
                   1750:         UNROLL_LOOP_ENTRY_TABLE pfnDrawRWWideEntry,RWWIDE,LOOP_UNROLL_COUNT
                   1751: 
                   1752: 
                   1753: ;-----------------------------------------------------------------------;
                   1754: ; Unrolled 1-, 2-, 3-, and 4-wide read before write drawing loops.
                   1755: ;
                   1756: ; Entry:
                   1757: ;       AL = pixel mask
                   1758: ;       EBX = unrolled loop count
                   1759: ;       ECX = scan line width in bytes
                   1760: ;       EDI = start offset
                   1761: ;
                   1762: ; EBX, EDI modified. All other registers preserved.
                   1763: 
                   1764: ;-----------------------------------------------------------------------;
                   1765: ; Macro to draw one read before write byte, then advance to next scan line.
                   1766: 
                   1767: DRAW_1_WIDE_RW macro ENTRY_LABEL,ENTRY_INDEX
                   1768: &ENTRY_LABEL&ENTRY_INDEX&:
                   1769:         mov     ah,[edi]
                   1770:         mov     [edi],al
                   1771:         add     edi,edx                 ;point to the next scan line
                   1772:         endm    ;-----------------------------------;
                   1773: 
                   1774: ; 1-wide read/write.
                   1775: 
                   1776:         align   4
                   1777: draw_1_wide_rop_loop     proc    near
                   1778:         UNROLL_LOOP     DRAW_1_WIDE_RW,RWW1,LOOP_UNROLL_COUNT
                   1779:         dec     ebx
                   1780:         jnz     draw_1_wide_rop_loop
                   1781: 
                   1782:         ret
                   1783: 
                   1784: draw_1_wide_rop_loop     endp
                   1785: 
                   1786: ;-----------------------------------------------------------------------;
                   1787: ; Macro to draw two read before write bytes, then advance to next scan line.
                   1788: 
                   1789: DRAW_2_WIDE_RW macro ENTRY_LABEL,ENTRY_INDEX
                   1790: &ENTRY_LABEL&ENTRY_INDEX&:
                   1791:         mov     ah,[edi]
                   1792:         mov     [edi],al
                   1793:         mov     ah,[edi+1]
                   1794:         mov     [edi+1],al
                   1795:         add     edi,edx                 ;point to the next scan line
                   1796:         endm    ;-----------------------------------;
                   1797: 
                   1798: ; 2-wide read/write.
                   1799: 
                   1800:         align   4
                   1801: draw_2_wide_rop_loop     proc    near
                   1802:         UNROLL_LOOP     DRAW_2_WIDE_RW,RWW2,LOOP_UNROLL_COUNT
                   1803:         dec     ebx
                   1804:         jnz     draw_2_wide_rop_loop
                   1805: 
                   1806:         ret
                   1807: 
                   1808: draw_2_wide_rop_loop     endp
                   1809: 
                   1810: ;-----------------------------------------------------------------------;
                   1811: ; Macro to draw three read before write bytes, then advance to next scan line.
                   1812: 
                   1813: DRAW_3_WIDE_RW macro ENTRY_LABEL,ENTRY_INDEX
                   1814: &ENTRY_LABEL&ENTRY_INDEX&:
                   1815:         mov     ah,[edi]
                   1816:         mov     [edi],al
                   1817:         mov     ah,[edi+1]
                   1818:         mov     [edi+1],al
                   1819:         mov     ah,[edi+2]
                   1820:         mov     [edi+2],al
                   1821:         add     edi,edx                 ;point to the next scan line
                   1822:         endm    ;-----------------------------------;
                   1823: 
                   1824: ; 3-wide read/write.
                   1825: 
                   1826:         align   4
                   1827: draw_3_wide_rop_loop     proc    near
                   1828:         UNROLL_LOOP     DRAW_3_WIDE_RW,RWW3,LOOP_UNROLL_COUNT
                   1829:         dec     ebx
                   1830:         jnz     draw_3_wide_rop_loop
                   1831: 
                   1832:         ret
                   1833: 
                   1834: draw_3_wide_rop_loop     endp
                   1835: 
                   1836: ;-----------------------------------------------------------------------;
                   1837: ; Macro to draw four read before write bytes, then advance to next scan line.
                   1838: 
                   1839: DRAW_4_WIDE_RW macro ENTRY_LABEL,ENTRY_INDEX
                   1840: &ENTRY_LABEL&ENTRY_INDEX&:
                   1841:         mov     ah,[edi]
                   1842:         mov     [edi],al
                   1843:         mov     ah,[edi+1]
                   1844:         mov     [edi+1],al
                   1845:         mov     ah,[edi+2]
                   1846:         mov     [edi+2],al
                   1847:         mov     ah,[edi+3]
                   1848:         mov     [edi+3],al
                   1849:         add     edi,edx                 ;point to the next scan line
                   1850:         endm    ;-----------------------------------;
                   1851: 
                   1852: ; 4-wide read/write.
                   1853: 
                   1854:         align   4
                   1855: draw_4_wide_rop_loop     proc    near
                   1856:         UNROLL_LOOP     DRAW_4_WIDE_RW,RWW4,LOOP_UNROLL_COUNT
                   1857:         dec     ebx
                   1858:         jnz     draw_4_wide_rop_loop
                   1859: 
                   1860:         ret
                   1861: 
                   1862: draw_4_wide_rop_loop     endp
                   1863: 
                   1864: ;-----------------------------------------------------------------------;
                   1865: ; Unrolled 5-or-wider read before write loop.
                   1866: ;
                   1867: ; Entry:
                   1868: ;       EAX = # of bytes to fill across scan line (needed only by 5-or-wider
                   1869: ;               handler)
                   1870: ;       EBX = unrolled loop count
                   1871: ;       EDX = offset from end of one scan line to the start of the next next
                   1872: ;       EDI = start offset
                   1873: ;
                   1874: ; EBX, ECX, ESI, EDI modified. All other registers preserved.
                   1875: 
                   1876: ;-----------------------------------------------------------------------;
                   1877: ; Macro to draw five or more read before write bytes, then advance to
                   1878: ; next scan line. (Actually, will handle any number of bytes,
                   1879: ; including 0, but there are special-case handlers for narrow cases.)
                   1880: ; Works because reads of display memory return 0ffh, which then becomes the
                   1881: ; Bit Mask as it's written in write mode 3.
                   1882: 
                   1883: DRAW_WIDE_RW macro ENTRY_LABEL,ENTRY_INDEX
                   1884: &ENTRY_LABEL&ENTRY_INDEX&:
                   1885:         mov     ecx,esi
                   1886: @@:     mov     ah,[edi]
                   1887:         mov     [edi],al
                   1888:         inc     edi
                   1889:         dec     ecx
                   1890:         jnz     @b
                   1891:         add     edi,edx
                   1892:         endm    ;-----------------------------------;
                   1893: 
                   1894: ; 5-or-wider read/write.
                   1895: 
                   1896:         align   4
                   1897: draw_wide_rop_loop proc  near
                   1898:         UNROLL_LOOP     DRAW_WIDE_RW,RWWIDE,LOOP_UNROLL_COUNT
                   1899:         dec     ebx
                   1900:         jnz     draw_wide_rop_loop
                   1901: 
                   1902:         ret
                   1903: 
                   1904: draw_wide_rop_loop endp
                   1905: 
                   1906: _TEXT$01   ends
                   1907: 
                   1908:         end
                   1909: 
                   1910: ;masm386 -Mx -I..\..\inc -I..\..\..\inc -Id:\nt\public\sdk\inc -Di386=1 -DNT_INST=0 -DNT_UP=1 -DSTD_CALL -DDBG=1 -DDEVL=1 i386\patblt.asm,obj\i386\patblt.obj,x.lst;
                   1911: 
                   1912: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.