File:  [WindowsNT SDKs] / ntddk / src / video / displays / vga / i386 / blt.asm
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Thu Aug 9 18:31:12 2018 UTC (7 years, 9 months ago) by root
Branches: msft, MAIN
CVS tags: ntddk-nov-1993, HEAD
Microsoft Windows NT Build 511 (DDK SDK) 11-01-1993

        page    ,132
        title   BitBLT
;---------------------------Module-Header------------------------------;
; Module Name: blt.asm
;
; Copyright (c) 1992 Microsoft Corporation
;-----------------------------------------------------------------------;
        .386

ifndef  DOS_PLATFORM
        .model  small,c
else
ifdef   STD_CALL
        .model  small,c
else
        .model  small,pascal
endif;  STD_CALL
endif;  DOS_PLATFORM

        assume cs:FLAT,ds:FLAT,es:FLAT,ss:FLAT
        assume fs:nothing,gs:nothing

        .code

_TEXT$02   SEGMENT DWORD USE32 PUBLIC 'CODE'
           ASSUME  CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING

        .xlist
        include stdcall.inc         ; calling convention cmacros

        include i386\cmacFLAT.inc   ; FLATland cmacros
        include i386\display.inc    ; Display specific structures
        include i386\ppc.inc        ; Pack pel conversion structure
        include i386\bitblt.inc     ; General definitions
        include i386\ropdefs.inc    ; Rop definitions
        include i386\roptable.inc   ; Raster op tables
        include i386\egavga.inc     ; EGA register definitions
        include i386\strucs.inc     ; Structure definitions
        .list


        EXTRNP  cblt
        EXTRNP  check_device_special_cases
        EXTRNP  packed_pel_comp_y
        EXTRNP  vDIB4Preprocess
        EXTRNP  vDIB8Preprocess

; The following two bitmask tables are used for fetching
; the first and last byte used-bits bitmask.

        public bitmask_tbl1
bitmask_tbl1    label   byte
        db      11111111b               ;Masks for leftmost byte
        db      01111111b
        db      00111111b
        db      00011111b
        db      00001111b
        db      00000111b
        db      00000011b
        db      00000001b

        public  bitmask_tbl2
bitmask_tbl2    label   byte
        db      10000000b               ;Masks for rightmost byte
        db      11000000b
        db      11100000b
        db      11110000b
        db      11111000b
        db      11111100b
        db      11111110b
        db      11111111b

; phase_tbl1 is used for loading the "used" bits and "saved" bits
; bitmasks for cases 1,2,3 where the step direction is left to
; right.  If it weren't for the case of zero, this could be done
; with a simple rotate of 00FF.   For cases 4,5,6, a simple rotate
; can create the mask needed.

        public  phase_tbl1
phase_tbl1      label   word
        db      11111111b,00000000b             ;Used bits, saved bits
        db      00000001b,11111110b
        db      00000011b,11111100b
        db      00000111b,11111000b
        db      00001111b,11110000b
        db      00011111b,11100000b
        db      00111111b,11000000b
        db      01111111b,10000000b

ProcName    xxxvCompiledBlt,vCompiledBlt,56

xxxvCompiledBlt proc uses esi edi ebx,\
        __pdsurfDst     :ptr,   \
        __DestxOrg      :dword, \
        __DestyOrg      :dword, \
        __pdsurfSrc     :ptr,   \
        __SrcxOrg       :dword, \
        __SrcyOrg       :dword, \
        __xExt          :dword, \
        __yExt          :dword, \
        __Rop           :dword, \
        __lpPBrush      :ptr,   \
        __bkColor       :dword, \
        __TextColor     :dword, \
        __pulXlateVec   :dword, \
        __pptlBrush     :ptr

        local       fr[SIZE FRAME]:byte

        cld                             ;Let's make no assumptions about this!

; We be hacking, so copy all the parameters into the local frame right now,
; so that the subroutines will have access to them.

        mov         eax,__pdsurfDst
        mov         fr.pdsurfDst,eax
        mov         eax,__DestxOrg
        mov         fr.DestxOrg,ax
        mov         eax,__DestyOrg
        mov         fr.DestyOrg,ax
        mov         eax,__pdsurfSrc
        mov         fr.pdsurfSrc,eax
        mov         eax,__SrcxOrg
        mov         fr.SrcxOrg,ax
        mov         eax,__SrcyOrg
        mov         fr.SrcyOrg,ax
        mov         eax,__xExt
        mov         fr.xExt,ax
        mov         eax,__yExt
        mov         fr.yExt,ax
        mov         eax,__Rop
        mov         fr.Rop,eax
        mov         eax,__lpPBrush
        mov         fr.lpPBrush,eax
        mov         eax,__bkColor
        mov         fr.bkColor,eax
        mov         eax,__TextColor
        mov         fr.TextColor,eax
        mov         eax,__pulXlateVec
        mov         fr.ppcBlt.pulXlate,eax
        mov         eax,__pptlBrush
        mov         fr.pptlBrush,eax

        subttl  ROP Preprocessing
        page

;-----------------------------------------------------------------------;
; Get the encoded raster operation, and map the raster op if needed.
;
; To map the ROPS 80h through FFh to 00h through 7Fh, take the
; 1's complement of the ROP, and invert the "negate needed" flag.
;-----------------------------------------------------------------------;

        xor     ax,ax                   ;Assume not 80h : FFh
        mov     bl,byte ptr fr.Rop
        or      bl,bl                   ;Is this in the second half (80-FF)?
        jns     parse_10                ;  No, rop index is correct
        not     bl                      ;  Yes, want the inverse
        mov     ah,HIGH NEGATE_NEEDED   ;Want to invert the not flag
        errnz   <LOW NEGATE_NEEDED>

parse_10:
        movzx   ebx,bl
        xor     ax,roptable[ebx*2]      ;Get ROP, maybe toggle negate flag
        mov     fr.operands,ax          ;Save the encoded raster operation

        mov     bl,ah                   ;Set fr.the_flags for source and pattern
        and     bl,HIGH (SOURCE_PRESENT+PATTERN_PRESENT)
        ror     bl,1

        errnz    <SOURCE_PRESENT - 0010000000000000b>
        errnz   <PATTERN_PRESENT - 0100000000000000b>
        errnz    <F0_SRC_PRESENT - 00010000b>
        errnz    <F0_PAT_PRESENT - 00100000b>

parse_end:


;-----------------------------------------------------------------------;
; pdevice_processing
;
; Check the required bitmaps for validity, get their parameters
; and store the information locally.
;
;       BL = Initial fr.the_flags
;            F0_SRC_PRESENT set if source needed
;            F0_PAT_PRESENT set if pattern needed
;-----------------------------------------------------------------------;

        xor     bh,bh                   ;BH = real fr.the_flags
        mov     fr.ppcBlt.fb,bh          ;No packed pel converison
        test    bl,F0_SRC_PRESENT       ;Is a source needed?
        jz      pdevice_decode_dest     ;  No, skip source validation
        mov     esi,fr.pdsurfSrc        ;Get pointer to source
        lea     edi,fr.src              ;--> where parameters will go
        push    ebp
        lea     ebp,fr.ppcBlt
        cCall   copy_dev                ;Get all the data
        pop     ebp
        test    fr.ppcBlt.fb,PPC_NEEDED ;Will we be converting from packed pel?
        jz      pdevice_decode_dest     ;  No
        MovAddr eax,vDIB8Preprocess,0
        cmp     fr.ppcBlt.iFormat,BMF_8BPP
        je      short @F
        MovAddr eax,vDIB4Preprocess,0
@@:
        push    ebp                     ;  Yes, do serious messing around
        lea     ebp,fr                  ;  Needs a frame pointer
        call    eax
        pop     ebp

pdevice_decode_dest:
        mov     esi,fr.pdsurfDst        ;Get pointer to destination
        lea     edi,fr.dest             ;--> where parameters will go
        cCall   copy_dev                ;Get all the data

; The pattern fetch code will be based on the color format of the
; destination.  If the destination is mono, then a mono fetch will be
; performed.  If the destination is color, then a color fetch will be
; performed.

        or      bh,bl                   ;Merge in F0_SRC_PRESENT, F0_PAT_PRESENT
        test    bh,F0_DEST_IS_COLOR     ;Show color pattern needed if
        jz      pdevice_chk_color_conv  ;  destination is color
        or      bh,F0_COLOR_PAT

;       Check for color conversion.  If so, then set F0_GAG_CHOKE.
;       Color conversion will exist if the source and destination are of
;       different color formats.

pdevice_chk_color_conv:
        test    bh,F0_SRC_PRESENT       ;Is there a source?
        jz      pdevice_set_dest_flag   ;  No, cannot be converting.
        mov     al,bh
        and     al,F0_SRC_IS_COLOR+F0_DEST_IS_COLOR
        jz      pdevice_set_src_flag    ;Both are monochrome
        xor     al,F0_SRC_IS_COLOR+F0_DEST_IS_COLOR
        jz      pdevice_set_src_flag    ;Both are color
        or      bh,F0_GAG_CHOKE         ;Mono ==> color or color ==> mono
        mov     al,fr.bkColor.SPECIAL
        mov     ah,fr.TextColor.SPECIAL
        errnz   C0_BIT+C1_BIT+C2_BIT+C3_BIT-0Fh
        and     ax,0F0Fh
        mov     fr.both_colors,ax

; Setup the scan line update flag in the source device structure.
; The source will use a monochrome style update if it is the display,
; it is monochrome, or it is color and the destination device is
; monochrome.

pdevice_set_src_flag:
        mov     al,bh                   ;Set 'Z' if to use color update
        and     al,F0_SRC_IS_DEV+F0_SRC_IS_COLOR+F0_DEST_IS_COLOR
        xor     al,F0_SRC_IS_COLOR+F0_DEST_IS_COLOR
        jnz     pdevice_set_dest_flag   ;Use the mono update
        or      fr.src.dev_flags,COLOR_UP;Show color scan update

; Setup the scan line update flag in the destination device
; structure.  The destination will use a monochrome update
; if it is monochrome or the display.  It will use a color
; update if it is a color bitmap.

pdevice_set_dest_flag:
        mov     al,bh                   ;Set 'Z' if to use color destination
        and     al,F0_DEST_IS_DEV+F0_DEST_IS_COLOR;  update code
        xor     al,F0_DEST_IS_COLOR
        jnz     pdevice_proc_end        ;Mono update
        or      fr.dest.dev_flags,COLOR_UP;Show color scan update
pdevice_proc_end:


        push    ebp                     ;Set up pointer to frame variables
        lea     ebp,fr
        cCall   pattern_preprocessing
        pop     ebp

        subttl  Phase Processing (X)
        page

; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
;       Now the real work comes along:  In which direction will the
;       copy be done?  Refer to the 10 possible types of overlap that
;       can occur (10 cases, 4 resulting types of action required).
;
;       If there is no source bitmap involved in this particular BLT,
;       then the path followed must allow for this.  This is done by
;       setting both the destination and source parameters equal.
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;

phase_processing:
phase_processing_x:
        mov     dx,fr.xExt              ;Get X extent
        dec     dx                      ;Make X extent inclusive
        mov     bx,fr.DestxOrg          ;Get destination X origin
        mov     di,bx
        and     bx,00000111b            ;Get offset of destination within byte

; If there is no source, then just use the pointer to the destination
; bitmap and load the same parameters, which will cause the "equality"
; path to be followed in the set-up code.  This path is the favored
; path for the case of no source bitmap.

        mov     ax,di                   ;Assume no source needed
        test    fr.the_flags,F0_SRC_PRESENT;Is a source needed?
        jz      phase_proc_10           ;  No, just use destination parameters
        mov     ax,fr.SrcxOrg           ;  Yes, get source origin X
        mov     fr.first_fetch,FF_TWO_INIT_FETCHES
                                        ;  Assume two initial fetches (if no
                                        ;    source, then it will be set = 1
                                        ;    later)
phase_proc_10:
        mov     si,ax
        and     ax,00000111b            ;Get offset of source within byte
        cmp     si,di                   ;Which direction will we be moving?
        jl      phase_proc_30           ;Move from right to left

; The starting X of the source rectangle is >= the starting X of
; the destination rectangle, therefore we will be moving bytes
; starting from the left and stepping right.
;
; Alternatively, this is the path taken if there is no source
; bitmap for the current BLT.
;
; Rectangle cases: 3,4,5,6,8

        sub     al,bl                   ;Compute horiz. phase  (source-dest)
        mov     fr.step_direction,STEPRIGHT ;Set direction of move
        movzx   ebx,bx
        mov     ah,[ebx].bitmask_tbl1   ;Get starting byte mask
        ja      phase_proc_two_fetches  ;Scan line case 2, everything is
                                        ;  already set for this case.

; Scan line cases 1 and 3:
;
; The correct first byte fetch needs to be set for the beginning
; of the outer loop, and the phase must be made into a positive
; number.
;
; This is the path that will be followed if there is no source bitmap
; for the current BLT.

        mov     fr.first_fetch,FF_ONE_INIT_FETCH;Set one initial fetch
        jmp     short pp_only_one_init_fetch

;-----------------------------------------------------------------------;
; If we get all the bits we need in the first fetch then a second
; (unnecessary) fetch could cause a GP Fault.  So let's examine this:
; The number of bits from (SI mod 8) to the end of the byte is the number
; of available bits we get on the first fetch.  This is (8 - (SI mod 8)).
; If this is greater than or equal to xExt then we have all the bits we
; need and we better not do the second fetch (even though the phase
; relationship may suggest we need it).
;
; Conclusion: If (8 - (SI mod 8)) >= xExt then DO NOT make second fetch.
;-----------------------------------------------------------------------;

phase_proc_two_fetches:
        mov     cx,8
        sub     cl,bl
        sub     cl,al

; We can save a couple cycles here since xExt - 1 is already in DX.
; The condition CX >= xExt is the same as CX > DX.

        cmp     cx,dx                   ;CX = (SI mod 8), DX = (xExt - 1)
        jle     pp_second_fetch_really_needed


;-----------------------------------------------------------------------;
; We are here BECAUSE the xExt is so small that we can get all the bits
; on the scanline with a single lodsb (no byte boundary is crossed) AND
; the phase relationship indicates that a second initial fetch is needed.
;
; We will override it and only do one fetch.  However, if we simply
; fail to do the second fetch then the phase code will screw us.
; It will be expecting the bits to get fetched in the first fetch, saved
; after the rotate, and mixed in in the second fetch's phase code.
; So after the first fetch the bits have been saved in BH, and ANDed out
; of the src data in AL.
;
; The solution is to set a flag here that tells the phase generation code
; not to generate the usual masking part of the phase code.
;
; Short Bitblt Cases:                   (8 bits or less)
;
;       1) neither crosses byte boundary.
;
;          a) phase requires second initial fetch
;
;             Kill the phase masking.  It will screw us.  There will
;             be just one lodsb and one stosb and the first byte mask
;             will protect the dest bits that should not get hit.
;
;          b) phase requires only one initial fetch
;
;             Phase masking is irrelevant.  Removing it would
;             be an optimiztation.
;
;       2) dest crosses byte boundary, but src does not
;
;          a) phase requires second initial fetch
;
;             impossible situation:  the way we determine that a 2nd fetch
;             is necessary is if the first fetch does not get enough needed
;             bits to satisfy the first dest byte.  Here the first fetch
;             gets ALL the bits and the first dest byte needs less than
;             ALL because it crosses a byte boundary.
;
;          b) phase requires only one initial fetch
;
;             Intervention would be bad.  None is necessary since the 2nd
;             initial fetch will not be done.  If we do intervene we will
;             cause trouble:  Killing the masking will prevent the
;             "saved bits" from being saved.  The first byte masking
;             can kill off these bits in AL and they will never
;             make it to the second stosb.
;
;       3) src crosses byte boundary  (dest may or may not)
;          (this is known to be untrue at this point)
;
;          There are bits we need in the second fetch, so a second
;          initial fetch can not cause a GP fault.  Therefore do
;          everything the same as we would have before.
;
;
; Conclusion:  Intervention to kill the phase masking is
;              necessary iff
;                 [src does not cross byte boundary] AND
;                 dest does not cross byte boundary  AND
;                 [phase requires second initial fetch].
;              and bad if
;                 dest crosses byte boundary, but [src does not]
;
; Statements in [] are known to be true at this point.
;
; Solution:
;
; If we always kill the phase-masking when neither crosses a byte
; boundary and never kill it otherwise then everyone will be happy
; (regardless of other conditions like whether phase requests a 2nd
; initial fetch).
;-----------------------------------------------------------------------;

        mov     fr.first_fetch,FF_ONLY_1_SRC_BYTE
        .errnz  FF_ONE_INIT_FETCH

pp_second_fetch_really_needed:
pp_only_one_init_fetch:
        mov     ch,ah

;-----------------------------------------------------------------------;
;       We now have the correct phase and the correct first character fetch
;       routine set.  Save the phase and ...
;
;       currently:   AL = phase
;                    BL = dest start mod 8
;                    CH = first byte mask
;                    DX = inclusive X bit count
;                    SI = source X start (if there is a source)
;                    DI = destination X start
;-----------------------------------------------------------------------;

phase_proc_20:
        add     al,8                    ;Phase must be positive
        and     al,00000111b

; To calculate the last byte mask, the inclusive count can be
; added to the start X MOD 8 value, and the result taken MOD 8.
; This is attractive since this is what is needed later for
; calculating the inclusive byte count, so save the result
; of the addition for later.

        add     bx,dx                   ;Add inclusive extent to dest MOD 8
        mov     dx,bx                   ;Save for innerloop count !!!
        and     ebx,00000111b           ;Set up bx for a base reg
        mov     cl,[ebx].bitmask_tbl2   ;Get last byte mask

;-----------------------------------------------------------------------;
; To avoid GP faults, we must never do an extra fetch we don't need.
; When we're ready for the last fetch there may already be enough bits
; saved from the previous fetch (which we plan to combine with the bits
; in the fetch we are about to do).  If so then we'd better not do this
; last fetch (it could cause a GP fault).
;
; The number of bits we have left from the previous byte is (8 - AL)
; AL is the phase.  (1 + BL) is the number of bits we actually need
; to write to the final destination byte.
;
; So if  (8 - AL) >= (1 + BL)  then DO NOT do the last fetch.  This
; simplifies:  if  (BL + AL) <= 7  then DO NOT do the last fetch.
;-----------------------------------------------------------------------;

        add     bl,al
        cmp     bl,7
        jg      phase_proc_last_fetch_needed
        or      fr.first_fetch,FF_NO_LAST_FETCH
phase_proc_last_fetch_needed:

        mov     bl,al                   ;Compute offset into phase mask table
        movzx   ebx,bx
        mov     bx,[ebx*2].phase_tbl1   ;Get the phase mask

;       Currently:
;               AL = phase
;               BX = phase mask
;               CL = last byte mask
;               CH = first byte mask
;               DX = inclusive bit count + dest start MOD 8
;               SI = source X start (if there is a source)
;               DI = destination starting X

        jmp     phase_proc_50           ;Finish here

; The starting X of the source rectangle is < the X of the destination
; rectangle, therefore we will be moving bytes starting from the right
; and stepping left.
;
; This code should never be reached if there is no source bitmap
; for the current BLT.
;
; Rectangle cases: 1,2,7

phase_proc_30:
        mov     fr.step_direction,ah    ;Set direction of move
        errnz   STEPLEFT
        movzx   ebx,bx
        mov     cl,[ebx].bitmask_tbl1   ;Get last byte mask
        push    bx
        add     ax,dx                   ;Find end of the source

; To calculate the first byte mask, the inclusive count is
; added to the start MOD 8 value, and the result taken MOD 8.
; This is attractive since this is what is needed later for
; calculating the inclusive byte count, so save the result
; of the addition for later.

        add     bx,dx                   ;Find end of the destination
        add     di,dx                   ;Will need to update dest start address
        add     si,dx                   ;  and source's too
        mov     dx,bx                   ;Save inclusive bit count + start MOD 8
        and     ax,00000111b            ;Get source offset within byte
        and     ebx,00000111b           ;Get dest   offset within byte
        mov     ch,[ebx].bitmask_tbl2   ;Get start byte mask
        cmp     al,bl                   ;Compute horiz. phase  (source-dest)
        jb      pp_double_fetch         ;Scan line case 5, everything is
                                        ;  already set for this case.

; Scan line cases 4 and 6:
;
; The correct first byte fetch needs to be set for the beginning
; of the outer loop

        mov     fr.first_fetch,FF_ONE_INIT_FETCH;Set initial fetch routine
        jmp     short pp_one_initial_fetch

;-----------------------------------------------------------------------;
; If only-one-fetch is already set, then the following is a NOP.
; It doesn't seem worth the effort to check and jmp around.
;
; If we get all the bits we need in the first fetch then a second
; (unnecessary) fetch could cause a GP Fault.  So let's examine this:
;
; (DX + SI) points to the first pel (remember we're stepping left).
; So the number of needed bits we get in the first fetch is
; ((DX + SI + 1) mod 8).  This is currently equal to AX.
; If AX >= xExt then we'd better not do two init fetches.
;-----------------------------------------------------------------------;

pp_double_fetch:
        dec     fr.xExt
        cmp     ax,fr.xExt
        jl      pp_double_fetch_really_needed
        mov     fr.first_fetch,FF_ONLY_1_SRC_BYTE
        .errnz  FF_ONE_INIT_FETCH
pp_double_fetch_really_needed:
        inc     fr.xExt

pp_one_initial_fetch:
        sub     al,bl                   ;Compute horiz. phase  (source-dest)
        add     al,8                    ;Ensure phase positive
        and     al,00000111b

;-----------------------------------------------------------------------;
; To avoid GP faults must never do an extra fetch we don't need.
; The last byte fetch is unnecessary if Phase is greater than or equal
; to 8 - BL.  Phase is the number of bits we still have from the previous
; fetch. 8 - BL is the number of bits we actually need to write to the
; final destination byte.  So if AL - (8 - BL) >= 0  skip the last fetch.
;-----------------------------------------------------------------------;

        pop     bx
        add     bl,al
        sub     bl,8
        jl      pp_need_last_fetch
        or      fr.first_fetch,FF_NO_LAST_FETCH
pp_need_last_fetch:
phase_proc_40:

;-----------------------------------------------------------------------;
;       We now have the correct phase and the correct first character fetch
;       routine set.  Generate the phase mask and save it.
;
;       currently:   AL = phase
;                    CH = first byte mask
;                    CL = last byte mask
;                    DX = inclusive bit count + start MOD 8

        mov     ah,cl                   ;Save last mask
        mov     cl,al                   ;Create the phase mask
        mov     bx,00FFh                ;  by shifting this
        shl     bx,cl                   ;  according to the phase
        mov     cl,ah                   ;Restore last mask
;       jmp     phase_proc_50           ;Go compute # of bytes to BLT
        errn$   phase_proc_50


; The different processing for the different X directions has been
; completed, and the processing which is the same regardless of
; the X direction is about to begin.
;
; The phase mask, the first/last byte masks, the X byte offsets,
; and the number of innerloop bytes must be calculated.
;
;
; Nasty stuff coming up here!  We now have to determine how
; many bits will be BLTed and how they are aligned within the bytes.
; This is how it's done (or how I'm going to do it):
;
; The number of bits (inclusive number that is) is added to the
; start MOD 8 value ( the left side of the rectangle, minimum X
; value), then the result is divided by 8. Then:
;
;
;    1) If the result is 0, then only one destination byte is being
;       BLTed.  In this case, the start & ending masks will be ANDed
;       together, the innerloop count (# of full bytes to BLT) will
;       be zeroed, and the fr.last_mask set to all 0's (don't alter any
;       bits in last byte which will be the byte following the first
;       (and only) byte).
;
;               |      x x x x x|               |
;               |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|
;                0 1 2 3 4 5 6 7
;
;               start MOD 8 = 3,  extent-1 = 4
;               3+7 DIV 8 = 0, only altering one byte
;
;
;
;    2) If the result is 1, then only two bytes will be BLTed.
;       In this case, the start and ending masks are valid, and
;       all that needs to be done is set the innerloop count to 0.
;       (it is true that the last byte could have all bits affected
;       the same as if the innerloop count was set to 1 and the
;       last byte mask was set to 0, but I don't think there would be
;       much time saved special casing this).
;
;               |  x x x x x x x|x x x x x x x|
;               |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|
;                0 1 2 3 4 5 6 7
;
;               start MOD 8 = 1,  extent-1 = 14
;               3+14 DIV 8 = 1.  There is a first and last
;               byte but no innerloop count
;
;
;
;    3) If the result is >1, then there is some number of entire
;       bytes to be BLted by the innerloop.  In this case the
;       number of innerloop bytes will be the result - 1.
;
;               |              x|x x x x x x x x|x
;               |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|
;                0 1 2 3 4 5 6 7
;
;               start MOD 8 = 7,  extent-1 = 9
;               7+9  DIV 8 = 2.  There is a first and last
;               byte and an innerloop count of 1 (result - 1)
;
;       Currently:      AL = horizontal phase
;                       BX = horizontal phase mask
;                       CH = first byte mask
;                       CL = last byte mask
;                       DX = left side X MOD 8 + inclusive X count
;                       SI = source start X
;                       DI = dest   start X

phase_proc_50:
        mov     fr.phase_h,al           ;Save horizontal phase
        mov     fr.mask_p,bx            ;Save phase mask
        shr     dx,3                    ;/8 to get full byte count
        jnz     phase_proc_60           ;Result is >0, check it out

; There will only be one byte affected.  Therefore the two byte masks
; must be combined, the last byte mask cleared, and the innerloop
; count set to zero.

        or      fr.first_fetch,FF_ONLY_1_DEST_BYTE
        and     ch,cl                   ;Combine the two masks
        xor     cl,cl                   ;Clear out the last byte mask
        inc     dx                      ;Now just fall through to set
        errn$   phase_proc_60           ;  the innerloop count to 0!

phase_proc_60:
        dec     dx                      ;Dec count (might become 0 just like
        movzx   edx,dx                  ;  we want), and save it
        mov     fr.inner_loop_count,edx
        mov     bl,ch
        mov     ch,cl                   ;Compute last byte mask
        not     cl                      ;  and save it
        mov     fr.last_mask,cx
        mov     bh,bl                   ;Compute start byte mask
        not     bl                      ;  and save it
        mov     fr.start_mask,bx

; There may or may not be a source bitmap for the following address
; computation.  If there is no source, then the vertical setup code
; will be entered with both the source and destination Y's set to the
; destination Y and the address calculation skipped.  If there is a
; source, then the address calculation will be performed and the
; vertical setup code entered with both the source and destination Y's.

phase_processing_y:
        shr     di,3                    ;Compute byte offset of destination
        movzx   edi,di                  ;  and add to current destination
        add     fr.dest.lp_bits,edi      ;  offset

        mov     dx,fr.DestyOrg          ;Get destination Y origin
        mov     ax,dx                   ;Assume no source
        mov     cl,fr.the_flags
        test    cl,F0_SRC_PRESENT       ;Is a source needed?
        jz      phase_proc_70           ;  No, skip source set-up
        shr     si,3                    ;Compute byte offset of source
        movzx   esi,si                  ;  and add to current source offset
        add     fr.src.lp_bits,esi
        mov     ax,fr.SrcyOrg           ;Get source Y origin


        subttl  Phase Processing (Y)
        page

; The horizontal parameters have been calculated.  Now the vertical
; parameters must be calculated.
;
; Currently:
;         DX = destination Y origin
;         AX = source Y origin (destination origin if no source)
;         CL = fr.the_flags

phase_proc_70:
        mov     bx,fr.yExt              ;Get the Y extent of the BLT
        dec     bx                      ;Make it inclusive


; The BLT will be Y+ if the top of the source is below or equal
; to the top of the destination (cases: 1,4,5,7,8).  The BLT
; will be Y- if the top of the source is above the top of the
; destination (cases: 2,3,6)
;
;
;                 !...................!
;                 !D                  !
;             ____!             ..x   !
;            |S   !               :   !     Start at top of S walking down
;            |    !                   !
;            |    !...................!
;            |                    :
;            |____________________:
;
;
;             __________________
;            |S                 |
;            |    .....................     Start at bottom of S walking up
;            |    !D                  !
;            |    !             :     !
;            |____!           ..x     !
;                 !                   !
;                 !....................


        mov     ch,INCREASE             ;Set Y direction for top to bottom
        cmp     ax,dx                   ;Which direction do we move?
        jge     phase_proc_80           ;Step down screen (cases: 1,4,5,7,8)


; Direction will be from bottom of the screen up (Y-)
;
; This code will not be executed if there is no source since
; both Y's were set to the destination Y.


        add     dx,bx                   ;Find bottom scan line index for
        add     ax,bx                   ;  destination and source
        mov     ch,DECREASE             ;Set pattern increment

phase_proc_80:
        mov     fr.pat_row,dl           ;Set pattern row and increment
        mov     fr.direction,ch
        sar     ch,1                    ;Map FF==>FF, 01==>00
        errnz   DECREASE-0FFFFFFFFh
        errnz   INCREASE-00001h


; The Y direction has been computed.  Compute the rest of the
; Y parameters.  These include the actual starting address,
; the scan line and plane increment values, and whether or not
; the extents will cross a 64K boundary.
;
; Currently:
;         DX = Y of starting destination scan
;         AX = Y of starting source scan
;         CH = BLT direction
;                00 = increasing BLT, Y+
;                FF = decreasing BLT, Y-
;         CL = fr.the_flags
;         BX = inclusive Y extent


phase_proc_90:
        test    cl,F0_SRC_PRESENT       ;Is a source needed?
        movsx   ecx,ch                  ;  (Want ECX = +/- 1)
        jz      phase_proc_100          ;  No, skip source set-up
        test    fr.ppcBlt.fb,PPC_NEEDED ;Packed pel conversion needed?
        jz      phase_proc_95           ;  No, use normal setup
        push    ebp                     ;  Yes, perform packed pel work
        lea     ebp,fr
        cCall   packed_pel_comp_y
        pop     ebp
        jmp     short phase_proc_100

phase_proc_95:
        push    dx                      ;Save destination Y
        push    ebp                     ;Mustn't trash frame pointer
        lea     ebp,fr.src              ;--> source data structure
        cCall   compute_y               ;Process as needed
        pop     ebp
        pop     dx                      ;Restore destination Y

phase_proc_100:
        push    ebp                     ;Mustn't trash frame pointer
        mov     ax,dx                   ;Put destination Y in ax
        lea     ebp,fr.dest             ;--> destination data structure
        cCall   compute_y
        pop     ebp                     ;Restore frame pointer

        push    ebp
        lea     ebp,fr
        cCall   check_device_special_cases
        pop     ebp
        jc      bitblt_exit             ;C ==> BLT done w/special case


        subttl  Memory allocation for BLT compilation
        page
cblt_allocate:
        sub     esp,MAX_BLT_SIZE
        mov     edi,esp
        mov     fr.blt_addr,edi         ;Save the address for later
        push    ebp
        lea     ebp,fr
        cCall   cblt                    ;compile the BLT onto the stack
        pop     ebp

; The BLT has been created on the stack.  Set up the initial registers,
; set the direction flag as needed, and execute the BLT.

        mov     esi,fr.src.lp_bits      ;--> source device's first byte
        mov     edi,fr.dest.lp_bits     ;--> destination device's first byte
        mov     cx,fr.yExt              ;Get count of lines to BLT
        cld                             ;Assume this is the direction
        cmp     fr.step_direction,STEPRIGHT ;Stepping to the right?
        jz      call_blt_do_it          ;  Yes
        std
call_blt_do_it:
        push    ebp                     ;MUST SAVE THIS
        call    fr.blt_addr             ;Call the FAR process
        pop     ebp
        add     esp,MAX_BLT_SIZE        ;Return BLT space
        errn$   bitblt_exit

bitblt_exit:

; Here we test if the VGA was involved and skip reseting the VGA state if
; it was not involved.

        test    fr.the_flags,F0_DEST_IS_DEV + F0_SRC_IS_DEV
        jz      ega_not_involved

; Restore EGA registers to the default state.

        mov     dx,EGA_BASE + SEQ_DATA
        mov     al,MM_ALL
        out     dx,al
        mov     dl,GRAF_ADDR
        mov     ax,0FF00h + GRAF_BIT_MASK
        out     dx,ax
        mov     ax,DR_SET shl 8 + GRAF_DATA_ROT
        out     dx,ax
        mov     ax,GRAF_ENAB_SR
        out     dx,ax
ega_not_involved:

        mov     eax,1                   ;Clear out error register (good exit)
        cld                             ;Leave direction cleared
        cRet    vCompiledBlt

xxxvCompiledBlt endp



;----------------------------Private-Routine----------------------------;
; copy_device
;
; Copy device information to frame.
;
; Entry:
;       ESI = pdsurf
;       EDI --> frame DEV structure
;       EBP --> PPC structure (for source only)
;       BH     =  fr.the_flags, accumulated so far
; Returns:
;       BH     =  fr.the_flags, accumulated so far
;       Carry clear if no error
;       EBP --> PPC structure
; Error Returns:
;       None
; Calls:
;       None
; History:
;  Sun 22-Feb-1987 16:29:09 -by-  Walt Moore [waltm]
; Created.
;-----------------------------------------------------------------------;

cProc   copy_dev

        mov     eax,[esi].dsurf_sizlSurf.sizl_cx
        mov     [edi].width_bits,ax
        mov     eax,[esi].dsurf_sizlSurf.sizl_cy
        mov     [edi].height,ax
        mov     eax,[esi].dsurf_lNextScan
        mov     [edi].width_b,ax
        mov     eax,[esi].dsurf_pvBitmapStart
        mov     [edi].lp_bits,eax
        mov     eax,[esi].dsurf_lNextPlane
        mov     [edi].next_plane,eax
        mov     al,[esi].dsurf_iFormat
        shl     bh,1
        cmp     al,BMF_PHYSDEVICE
        sete    ah
        or      bh,ah
        errnz   F0_SRC_IS_DEV-00001000b
        errnz   F0_DEST_IS_DEV-0000010b

        shl     bh,1
        cmp     al,BMF_1BPP
        je      copy_dev_20             ;Mono, color bit is clear
        or      bh,F0_DEST_IS_COLOR
        errnz   F0_SRC_IS_COLOR-00000100b
        errnz   F0_DEST_IS_COLOR-00000001b

; The source may be a packed pel source, which will have to be converted

        cmp     al,BMF_DEVICE           ;4 plane format
        je      copy_dev_20             ;  Yes, no packed pel conversion
        cmp     al,BMF_PHYSDEVICE
        je      copy_dev_20             ;  ditto

        mov     [ebp].iFormat,al        ;Save source format
        mov     [ebp].fb,PPC_NEEDED     ;Show conversion needed
copy_dev_20:

        mov     al,bh                   ;Set IS_COLOR and IS_DEVICE
        and     al,IS_COLOR+IS_DEVICE   ;  flags in the Device Flags
        errnz   IS_COLOR-F0_DEST_IS_COLOR ;Must be same bits
        mov     [edi].dev_flags,al
        cRet    copy_dev

endProc copy_dev


;----------------------------Private-Routine----------------------------;
; pattern_preprocessing
;
; If a pattern is needed, make sure that it isn't a hollow
; brush. If it is a hollow brush, then return an error.
;
; The type of brush to use will be set, and the brush pointer
; updated to point to the mono bits if the mono brush will be
; used.  The type of brush used will match the destination device.
;
; If the destination is mono and the source is color, then a mono
; brush fetch will be used, with the color brush munged in advance
; according to the background/foreground colors passed:
;
;     All brush pixels which match the background color should be set
;     to white (1).  All other brush pixels should be set to black (0).
;
;     If the physical color is stored as all 1's or 0's for each
;     plane, then by XORing the physical color for a plane with the
;     corresponding byte in the brush, and ORing the results, this
;     will give 0's where the color matched, and  1's where the colors
;     didn't match.  Inverting this result will then give 1's where
;     the brush matched the background color and 0's where it did not.
;
; If both the source and destination are color, or the source is mono
; and the destination color, then the color portion of the brush will
; be used.
;
; If both the source and destination are mono, then the monochrome
; portion of the brush will be used.
;
; Entry:
;       BH = fr.the_flags
;       EBP = fr
; Returns:
;       Carry flag clear if no error
; Error Returns:
;       Carry flag set if error (null lpPBrush, or hollow brush)
; Registers Preserved:
;       EBP
; Registers Destroyed:
;       AX,BX,CX,DX,SI,DI,DS,ES,flags
; Calls:
;       None
; History:
;  Sat 15-Aug-1987 18:20:34 -by-  Wesley O. Rupel [wesleyr]
; Added 4-plane support.
;  Sun 22-Feb-1987 16:29:09 -by-  Walt Moore [waltm]
; Created.
;-----------------------------------------------------------------------;

;------------------------------Pseudo-Code------------------------------;
; {
; }
;-----------------------------------------------------------------------;

cProc   pattern_preprocessing

        mov     [ebp].the_flags,bh      ;Save flag values
        test    bh,F0_PAT_PRESENT       ;Pattern required?
        jz      pattern_preproc_end     ;  No, skip pattern check
        mov     esi,[ebp].lpPBrush      ;--> physical brush
        mov     dl,[esi].oem_brush_accel;Save brush accelerator
        mov     [ebp].brush_accel,dl    ; in local variable frame
        test    dl,SOLID_BRUSH          ;Don't need to rotate a solid brush
        jnz     pattern_preproc_end

; !!! hack-o-ramma.  rotate the brush on the frame for now.

        push    ebx
        mov     edx,00000111b
        lea     edi,[ebp].a_brush.oem_brush_C0  ;EDI --> temp brush area
        mov     [ebp].lpPBrush,edi
        mov     ebx,[ebp].pptlBrush
        mov     ecx,dword ptr [ebx][0]
        and     ecx,edx
        mov     ebx,dword ptr [ebx][4]
        and     ebx,edx
        mov     ch,4

pattern_preproc_color:
        lodsb
        and     ebx,edx
        ror     al,cl
        mov     byte ptr [edi][ebx],al
        inc     ebx

        lodsb
        and     ebx,edx
        ror     al,cl
        mov     byte ptr [edi][ebx],al
        inc     ebx

        lodsb
        and     ebx,edx
        ror     al,cl
        mov     byte ptr [edi][ebx],al
        inc     ebx

        lodsb
        and     ebx,edx
        ror     al,cl
        mov     byte ptr [edi][ebx],al
        inc     ebx

        lodsb
        and     ebx,edx
        ror     al,cl
        mov     byte ptr [edi][ebx],al
        inc     ebx

        lodsb
        and     ebx,edx
        ror     al,cl
        mov     byte ptr [edi][ebx],al
        inc     ebx

        lodsb
        and     ebx,edx
        ror     al,cl
        mov     byte ptr [edi][ebx],al
        inc     ebx

        lodsb
        and     ebx,edx
        ror     al,cl
        mov     byte ptr [edi][ebx],al
        inc     ebx

        add     edi,8
        dec     ch
        jnz     pattern_preproc_color
        pop     ebx

pattern_preproc_end:
        clc
        cRet    pattern_preprocessing

endProc pattern_preprocessing


;----------------------------Private-Routine----------------------------;
; compute_y
;
; Compute y-related parameters.
;
; The parameters related to the Y coordinate and BLT direction
; are computed.  The parameters include:
;
;       a) Index to next scan line
;       b) Starting Y address calculation
;       d) Index to next plane
;
; Entry:
;       EBP --> DEV structure to use (src or dest)
;       AX  =  Y coordinate
;       ECX =  BLT direction
;              0000 = Y+
;              FFFF = Y-
;       BX  =  inclusive Y extent
; Returns:
;       ECX  =  BLT direction
;       EBX  =  inclusive count
; Registers Preserved:
;       EBP
; Registers Destroyed:
;       AX,DX,SI,DI,flags
; Calls:
;       None
; History:
;-----------------------------------------------------------------------;

cProc   compute_y

        movsx   esi,[ebp].width_b       ;Need bmWidthBytes a couple of times
        movzx   eax,ax
        mul     esi                     ;Compute Y address
        add     [ebp].lp_bits,eax
        xor     esi,ecx                 ;1's complement if Y-
        sub     esi,ecx                 ;2's complement if Y-

        test    [ebp].dev_flags,IS_DEVICE
        jnz     compute_y_done
        test    [ebp].dev_flags,IS_COLOR
        jz      compute_y_done


; !!! I need to rewrite how next scan is handled.  Currently, for +Y, next scan is 0,
; !!! and for -Y it is 2* -lNextScan

        add     esi,esi                 ;Assume -Y (comp 2 * -lNextScan)
        and     esi,ecx                 ;ESI = 0 if +Y, or 2 * -lNextScan

compute_y_done:
        mov     [ebp].next_scan,esi     ;Set index to next scan line
        cRet    compute_y               ;All done with device, small bitmaps

endProc compute_y

_TEXT$02   ends

        end


unix.superglobalmegacorp.com

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