File:  [WindowsNT SDKs] / ntddk / src / video / displays / vga / i386 / restscrn.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

;---------------------------Module-Header------------------------------;
; Module Name: restscrn.asm
;
; Copyright (c) 1992 Microsoft Corporation
;-----------------------------------------------------------------------;
;-----------------------------------------------------------------------;
; VOID vRestoreScreenBitsFromMemory(PDEVSURF pdsurf, PRECTL prcl,
;                              PVOID pjSrcBuffer, ULONG ulRestoreWidthInBytes,
;                              ULONG ulSrcDelta);
; Input:
;  pdsurf - surface to which to copy
;  prcl - pointer to rectangle to which to copy
;  pjSrcBuffer - pointer to source memory buffer. Should have the same
;                 dword alignment as the dest rect left edge does in screen
;                 memory
;  ulRestoreWidthInBytes - # of bytes to restore per scan (including any
;                 partial edges)
;  ulSrcDelta - distance from end of one source scan to start of next.
;                 together with ulRestoreWidthInBytes, should maintain
;                 dword alignment between source and dest
;
; Copies a rectangle from a memory buffer to VGA memory.
;
;-----------------------------------------------------------------------;
;
; Note: Assumes all rectangles have positive heights and widths. Will not
; work properly if this is not the case.
;
;-----------------------------------------------------------------------;
;
; Note: The rectangle is restored from interleaved-scan format; all four planes
; of one scan are saved together, then all four planes of the next scan,
; and so on. This is done for maximum restoration efficiency. Planes are
; saved in order 3, 2, 1, 0:
;
;  Scan n, plane 3
;  Scan n, plane 2
;  Scan n, plane 1
;  Scan n, plane 0
;  Scan n+1, plane 3
;  Scan n+1, plane 2
;  Scan n+1, plane 1
;  Scan n+1, plane 0
;          :
;
; There may be padding on either edge of the saved bits in the destination
; buffer, so that the destination can be dword aligned with the source.
;
;-----------------------------------------------------------------------;
;Additional optimizations:
;
; Could break out separate scan copy code with and without edge handling.
; (Possibly by threading the desired operations, or by having many separate
; optimizations.)
;
; Could handle odd bytes to dword align more efficiently, by having separate
; optimizations for various alignment widths, thereby avoiding starting REP
; and getting word accesses for 2 and 3 wide cases. Most VGAs are 8 or 16
; bit devices, and for them, using MOVSB/REP MOVSW/MOVSB might actually be
; faster, especially because it's easier to break out optimizations.
;
; Could end all scan handlers with loop bottom code.
;
; Could do more scans in one plane before doing next plane, to avoid
; slow OUTs. This could cause color effects, but that might be avoidable
; by scaling the # of scans done per plane to the width of the rectangle.
;
;-----------------------------------------------------------------------;


                .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

        .xlist
        include stdcall.inc             ;calling convention cmacros
        include i386\egavga.inc
        include i386\strucs.inc

        .list

        .data

;-----------------------------------------------------------------------;
; Masks used to do left and right edge clipping for various alignments.
; Low byte = destination mask, high byte = source mask.
;-----------------------------------------------------------------------;
        align   2
usLeftMasks     label   word
        dw      0ff00h, 07f80h, 03fc0h, 01fe0h, 00ff0h, 007f8h, 003fch, 001feh

usRightMasks    label   word
        dw      0ff00h, 0807fh, 0c03fh, 0e01fh, 0f00fh, 0f807h, 0fc03h, 0fe01h

;-----------------------------------------------------------------------;
; Same as above, but dest masks only, and whole byte case is represented
; as 0ffh rather than 0. Used for 1-byte-wide cases.
;-----------------------------------------------------------------------;
jLeftMasks      label   byte
        db      0ffh, 080h, 0c0h, 0e0h, 0f0h, 0f8h, 0fch, 0feh

jRightMasks     label   byte
        db      0ffh, 07fh, 03fh, 01fh, 00fh, 007h, 003h, 001h

        .code

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

;-----------------------------------------------------------------------;

cProc   vRestoreScreenBitsFromMemory,20,< \
        uses    esi edi ebx,         \
        pdsurf:ptr,                  \
        prcl:ptr,                    \
        pjSrcBuffer:ptr,             \
        ulRestoreWidthInBytes:dword, \
        ulSrcDelta:dword             >

        local   ulCurrentTopScan :dword ;top scan line to copy to in current
                                        ; bank
        local   ulBottomScan :dword     ;bottom scan line of rectangle to which
                                        ; to copy
        local   pjDstStart :dword       ;destination address
        local   ulDstDelta :dword       ;distance from end of dest scan to
                                        ; start of next
        local   ulBlockHeight :dword    ;# of scans to copy in block
        local   ulLeadingBytes :dword   ;# of leading bytes to copy per scan
        local   ulMiddleDwords :dword   ;# of dwords to copy per scan
        local   ulTrailingBytes :dword  ;# of trailing bytes to copy per scan
        local   pfnCopyVector :dword    ;pointer to inner loop routine to copy
                                        ; from buffer to screen
        local   ulLeftMask :dword       ;2 byte masks for left edge clipping
                                        ; (low byte = dest mask,
                                        ;  high byte = src mask)
        local   ulRightMask :dword      ;2 byte masks for right edge clipping

;-----------------------------------------------------------------------;
; Leave the GC Index pointing to the Read Map for the rest of this routine.
;-----------------------------------------------------------------------;

        mov     edx,VGA_BASE + GRAF_ADDR
        mov     al,GRAF_READ_MAP
        out     dx,al

;-----------------------------------------------------------------------;
; Set up local variables.
;-----------------------------------------------------------------------;

        mov     edi,prcl                ;point to rectangle from which to copy
        mov     esi,pdsurf              ;point to surface from which to copy

        mov     eax,[edi].yBottom
        mov     ulBottomScan,eax        ;bottom scan line of source rect

        mov     eax,[esi].dsurf_lNextScan
        sub     eax,ulRestoreWidthInBytes
        mov     ulDstDelta,eax  ;distance from end of one scan's bits to save
                                ; to start of next scan's in display memory

;-----------------------------------------------------------------------;
; Figure out the left and right clip masks. If either or both edges are
; solid, add them into the whole bytes.
;-----------------------------------------------------------------------;

        mov     ebx,[edi].xLeft
        mov     ecx,[edi].xRight
        mov     edx,ebx
        lea     eax,[ecx-1]
        and     ebx,0111b
        and     ecx,0111b

        and     edx,not 0111b
        sub     eax,edx
        shr     eax,3           ;width in bytes - 1
                                ;only 1 byte wide?
        jnz     short @F        ;no
                                ;1 byte wide; special case
        mov     al,jLeftMasks[ebx]      ;look up left dest mask
        and     al,jRightMasks[ecx]     ;factor in right dest mask
        mov     ah,0ffh
        mov     ebx,offset copy_from_buffer_l_whole_only ;assume whole byte
        xor     ah,al                   ;calculate matching dest mask
                                ;is this single byte a whole byte?
        jz      set_copy_vector ;yes, select whole byte optimization
                                ;no, select partial byte optimization
        mov     ebx,offset copy_from_buffer_l_partial_only
        mov     ulLeftMask,eax
        jmp     set_copy_vector

        align   4
@@:                                     ;more than 1 byte wide

        mov     edx,ulRestoreWidthInBytes

        mov     ax,usLeftMasks[ebx*2]   ;look up left masks
        mov     ulLeftMask,eax
        and     al,al                   ;any left clipping?
        jz      short @F                ;no, do as part of whole bytes
        dec     edx                     ;yes, don't count as whole byte
@@:


        mov     ax,usRightMasks[ecx*2]  ;look up right masks
        mov     ulRightMask,eax
        and     al,al                   ;any right clipping?
        jz      short @F                ;no, do as part of whole bytes
        dec     edx                     ;yes, don't count as whole byte
@@:

;-----------------------------------------------------------------------;
; Set up for copying as much as possible via aligned dwords, and
; select the most efficient loop for doing the copy, based on the copy
; width, and on the necessity for leading and/or trailing bytes to
; dword align.
;-----------------------------------------------------------------------;

        cmp     edx,8                   ;if it's less than 8 bytes, just do a
                                        ; straight byte copy. This means we
                                        ; we only have to start 1 REP per line,
                                        ; and performing this check guarantees
                                        ; that we have at least 1 aligned dword
                                        ; to copy in the dword loops
        jb      short copy_all_as_bytes ;do straight byte copy
        mov     eax,pjSrcBuffer
        neg     eax
        and     eax,3           ;# of bytes that have to be done as leading
                                ; bytes to dword align with source (note that
                                ; for performance, the source should be dword
                                ; aligned with the destination)
        jz      short copy_no_leading_bytes     ;no leading bytes
                                ;leading bytes
        mov     ulLeadingBytes,eax
        mov     ebx,offset copy_from_buffer_l ;assume no trailing bytes
        sub     edx,eax         ;# of bytes after leading bytes
        mov     eax,edx
        shr     eax,2           ;# of dwords that can be handled as aligned
                                ; dwords
        mov     ulMiddleDwords,eax
        and     edx,3           ;# of trailing bytes left after aligned dwords
                                ; copied
        jz      short set_copy_vector ;no trailing bytes
        mov     ulTrailingBytes,edx
        mov     ebx,offset copy_from_buffer_lt  ;there are both leading and
                                                ; trailing bytes
        jmp     short set_copy_vector

        align   4
copy_no_leading_bytes:
        mov     ebx,offset copy_from_buffer ;assume no trailing bytes
        mov     eax,edx
        shr     eax,2           ;# of dwords that can be handled as aligned
                                ; dwords
        mov     ulMiddleDwords,eax
        and     edx,3           ;# of trailing bytes left after aligned dwords
                                ; copied
        jz      short set_copy_vector ;no trailing bytes
        mov     ulTrailingBytes,edx
        mov     ebx,offset copy_from_buffer_t     ;there are trailing bytes
        jmp     short set_copy_vector

; It's so narrow that we'll forget about aligned dwords, and just do a straight
; byte copy, which we'll handle by treating the entire copy as leading bytes.
        align   4
copy_all_as_bytes:
        mov     ulLeadingBytes,edx
        mov     ebx,offset copy_from_buffer_lonly

set_copy_vector:
        mov     pfnCopyVector,ebx

;-----------------------------------------------------------------------;
; Map in the bank containing the top scan to copy, if it's not mapped in
; already.
;-----------------------------------------------------------------------;

        mov     eax,[edi].yTop          ;top scan line of copy
        mov     ulCurrentTopScan,eax    ;this will be the copy top in 1st bank

        cmp     eax,[esi].dsurf_rcl1WindowClip.yTop ;is copy top less than
                                                    ; current bank?
        jl      short map_init_bank             ;yes, map in proper bank
        cmp     eax,[esi].dsurf_rcl1WindowClip.yBottom ;copy top greater than
                                                       ; current bank?
        jl      short init_bank_mapped          ;no, proper bank already mapped
map_init_bank:

; Map in the bank containing the top scan line of the copy.

        ptrCall   <dword ptr [esi].dsurf_pfnBankControl>,<esi,eax,JustifyTop>

init_bank_mapped:

;-----------------------------------------------------------------------;
; Calculate the initial start address to which to copy.
;-----------------------------------------------------------------------;

        mov     eax,ulCurrentTopScan    ;top scan line to copy to in current
                                        ; bank
        imul    [esi].dsurf_lNextScan   ;offset of starting scan line in bitmap
        add     eax,[esi].dsurf_pvBitmapStart ;start address of scan
        mov     ebx,[edi].xLeft
        shr     ebx,3                   ;convert from pixel to byte address
        add     eax,ebx                 ;start dest address
        mov     pjDstStart,eax

;-----------------------------------------------------------------------;
; Loop through and copy all bank blocks spanned by the destination
; rectangle.
;
; Input:
;  ESI = pdsurf
;-----------------------------------------------------------------------;

copy_from_buffer_bank_loop:

; Copy this bank block to the buffer.

; Calculate # of scans in this bank.

        mov     ebx,ulBottomScan        ;bottom of dest rectangle
        cmp     ebx,[esi].dsurf_rcl1WindowClip.yBottom
                                        ;which comes first, the bottom of the
                                        ; dest rect or the bottom of the
                                        ; current bank?
        jl      short @F                ;dest bottom comes first, so copy to
                                        ; that; this is the last bank in copy
        mov     ebx,[esi].dsurf_rcl1WindowClip.yBottom
                                        ;bank bottom comes first; copy to
                                        ; bottom of bank
@@:
        sub     ebx,ulCurrentTopScan    ;# of scans to copy in this bank
        mov     ulBlockHeight,ebx

        mov     esi,pjSrcBuffer ;point to start of source rect

        mov     dh,VGA_BASE SHR 8       ;leave DH pointing to VGA_BASE

;-----------------------------------------------------------------------;
; Loop through all scans in this block, copying all four planes of each
; scan in turn, then doing the next scan.
;-----------------------------------------------------------------------;
copy_to_buffer_scan_loop:

        mov     bl,MM_C3        ;start by copying to plane 3

;-----------------------------------------------------------------------;
; Loop through all four planes, copying all scans in this block for each
; plane in turn.
;-----------------------------------------------------------------------;

copy_to_buffer_plane_loop:

        mov     dl,SEQ_DATA
        mov     al,bl
        out     dx,al           ;set Map Mask to plane to which we're copying

        mov     dl,GRAF_DATA
        shr     al,1
        cmp     al,3
        adc     al,-1
        out     dx,al

        mov     edi,pjDstStart  ;point to start of dest buffer (scan starts
                                ; at same address in all planes)
        jmp     pfnCopyVector   ;jump to the appropriate loop to copy plane

;-----------------------------------------------------------------------;
; Copy loops, broken out by leading and trailing bytes needed for dword
; alignment, plus one loop to perform a straight byte copy.
;
; Input:
;  ESI = initial source copy address
;  EDI = initial dest copy address
;-----------------------------------------------------------------------;

; All bytes can be copied as aligned dwords (no leading or trailing whole
; bytes).
        align   4
copy_from_buffer:

; Do the left edge byte, if there's a partial left edge byte.

        mov     eax,ulLeftMask  ;AL = dest mask, AH = source mask
        and     al,al           ;any left mask?
        jz      short @F        ;left edge is whole
        and     al,[edi]        ;mask the dest
        and     ah,[esi]        ;mask the source
        inc     esi             ;point to next source byte
        or      al,ah           ;combine the source and dest
        stosb                   ;store the new byte
@@:

; Do the middle (whole) bytes.

        mov     ecx,ulMiddleDwords
        rep     movsd

; Do the right edge byte, if there's a partial right edge byte.

        mov     eax,ulRightMask ;AL = dest mask, AH = source mask
        and     al,al           ;any left mask?
        jz      short @F        ;right edge is whole
        and     al,[edi]        ;mask the dest
        and     ah,[esi]        ;mask the source
        inc     esi             ;point to next source byte
        or      al,ah           ;combine the source and dest
        stosb                   ;store the new byte
@@:

        jmp     copy_from_buffer_scan_done

; Leading odd whole bytes, but no trailing whole bytes.
        align   4
copy_from_buffer_l:

; Do the left edge byte, if there's a partial left edge byte.

        mov     eax,ulLeftMask  ;AL = dest mask, AH = source mask
        and     al,al           ;any left mask?
        jz      short @F        ;left edge is whole
        and     al,[edi]        ;mask the dest
        and     ah,[esi]        ;mask the source
        inc     esi             ;point to next source byte
        or      al,ah           ;combine the source and dest
        stosb                   ;store the new byte
@@:

; Do the middle (whole) bytes.

        mov     ecx,ulLeadingBytes
        rep     movsb
        mov     ecx,ulMiddleDwords
        rep     movsd

; Do the right edge byte, if there's a partial right edge byte.

        mov     eax,ulRightMask ;AL = dest mask, AH = source mask
        and     al,al           ;any left mask?
        jz      short @F        ;right edge is whole
        and     al,[edi]        ;mask the dest
        and     ah,[esi]        ;mask the source
        inc     esi             ;point to next source byte
        or      al,ah           ;combine the source and dest
        stosb                   ;store the new byte
@@:

        jmp     copy_from_buffer_scan_done

; Trailing odd whole bytes, but no leading whole bytes.
        align   4
copy_from_buffer_t:

; Do the left edge byte, if there's a partial left edge byte.

        mov     eax,ulLeftMask  ;AL = dest mask, AH = source mask
        and     al,al           ;any left mask?
        jz      short @F        ;left edge is whole
        and     al,[edi]        ;mask the dest
        and     ah,[esi]        ;mask the source
        inc     esi             ;point to next source byte
        or      al,ah           ;combine the source and dest
        stosb                   ;store the new byte
@@:

; Do the middle (whole) bytes.

        mov     ecx,ulMiddleDwords
        rep     movsd
        mov     ecx,ulTrailingBytes
        rep     movsb

; Do the right edge byte, if there's a partial right edge byte.

        mov     eax,ulRightMask ;AL = dest mask, AH = source mask
        and     al,al           ;any left mask?
        jz      short @F        ;right edge is whole
        and     al,[edi]        ;mask the dest
        and     ah,[esi]        ;mask the source
        inc     esi             ;point to next source byte
        or      al,ah           ;combine the source and dest
        stosb                   ;store the new byte
@@:

        jmp     copy_from_buffer_scan_done

; Only leading whole bytes (straight whole byte copy; no aligned dwords).
        align   4
copy_from_buffer_lonly:

; Do the left edge byte, if there's a partial left edge byte.

        mov     eax,ulLeftMask  ;AL = dest mask, AH = source mask
        and     al,al           ;any left mask?
        jz      short @F        ;left edge is whole
        and     al,[edi]        ;mask the dest
        and     ah,[esi]        ;mask the source
        inc     esi             ;point to next source byte
        or      al,ah           ;combine the source and dest
        stosb                   ;store the new byte
@@:

; Do the middle (whole) bytes.

        mov     ecx,ulLeadingBytes
        rep     movsb

; Do the right edge byte, if there's a partial right edge byte.

        mov     eax,ulRightMask ;AL = dest mask, AH = source mask
        and     al,al           ;any left mask?
        jz      short @F        ;right edge is whole
        and     al,[edi]        ;mask the dest
        and     ah,[esi]        ;mask the source
        inc     esi             ;point to next source byte
        or      al,ah           ;combine the source and dest
        stosb                   ;store the new byte
@@:

        jmp     short copy_from_buffer_scan_done

; Only one masked byte; no whole bytes and no right byte.
        align   4
copy_from_buffer_l_partial_only:

        mov     eax,ulLeftMask  ;AL = dest mask, AH = source mask
        and     al,[edi]        ;mask the dest
        and     ah,[esi]        ;mask the source
        inc     esi             ;point to next source byte
        or      al,ah           ;combine the source and dest
        stosb                   ;store the new byte
        jmp     short copy_from_buffer_scan_done

; Only one whole byte; no left byte and no right byte.
        align   4
copy_from_buffer_l_whole_only:

        movsb                   ;copy the one byte
        jmp     short copy_from_buffer_scan_done

; Leading and trailing odd whole bytes.
        align   4
copy_from_buffer_lt:

; Do the left edge byte, if there's a partial left edge byte.

        mov     eax,ulLeftMask  ;AL = dest mask, AH = source mask
        and     al,al           ;any left mask?
        jz      short @F        ;left edge is whole
        and     al,[edi]        ;mask the dest
        and     ah,[esi]        ;mask the source
        inc     esi             ;point to next source byte
        or      al,ah           ;combine the source and dest
        stosb                   ;store the new byte
@@:

; Do the middle (whole) bytes.

        mov     ecx,ulLeadingBytes
        rep     movsb
        mov     ecx,ulMiddleDwords
        rep     movsd
        mov     ecx,ulTrailingBytes
        rep     movsb

; Do the right edge byte, if there's a partial right edge byte.

        mov     eax,ulRightMask ;AL = dest mask, AH = source mask
        and     al,al           ;any left mask?
        jz      short @F        ;right edge is whole
        and     al,[edi]        ;mask the dest
        and     ah,[esi]        ;mask the source
        inc     esi             ;point to next source byte
        or      al,ah           ;combine the source and dest
        stosb                   ;store the new byte
@@:

copy_from_buffer_scan_done:

        add     esi,ulSrcDelta  ;point to next source scan
        shr     bl,1            ;count down planes
        jnz     copy_to_buffer_plane_loop

        add     edi,ulDstDelta  ;point to next dest scan
        mov     pjDstStart,edi
        dec     ulBlockHeight   ;count down scans
        jnz     copy_to_buffer_scan_loop

; Remember where we left off, for the next block.

        mov     pjSrcBuffer,esi

;-----------------------------------------------------------------------;
; See if there are more banks to do
;-----------------------------------------------------------------------;

        mov     esi,pdsurf
        mov     eax,[esi].dsurf_rcl1WindowClip.yBottom ;is the copy bottom in
        cmp     ulBottomScan,eax                       ; the current bank?
        jle     short copy_from_buffer_banks_done        ;yes, so we're done
                                        ;no, map in the next bank and copy it
        mov     ulCurrentTopScan,eax    ;remember where the top of the bank
                                        ; we're about to map in is (same as
                                        ; bottom of bank we just did)
        mov     edx,[esi].dsurf_pvBitmapStart
        sub     pjDstStart,edx  ;convert from address to offset within bitmap

        ptrCall   <dword ptr [esi].dsurf_pfnBankControl>,<esi,eax,JustifyTop>
                                        ;map in the bank

; Compute the starting address in this bank.
; Note that the start of the bitmap will change each time through the
; bank loop, because the start of the bitmap is varied to map the
; desired scan line to the banking window.

        mov     eax,[esi].dsurf_pvBitmapStart
        add     pjDstStart,eax  ;address of next scan to draw

; Copy the new bank.

        jmp     copy_from_buffer_bank_loop


;-----------------------------------------------------------------------;
; Done with all banks.
;
; At this point:
;  DX = VGA_BASE + GRAF_DATA
;-----------------------------------------------------------------------;
        align 4
copy_from_buffer_banks_done:

        mov     ax,(MM_ALL shl 8)+SEQ_MAP_MASK  ;restore writability for all planes
        mov     dx,VGA_BASE+SEQ_ADDR
        out     dx,ax

        cRet    vRestoreScreenBitsFromMemory ;done

;-----------------------------------------------------------------------;

endProc vRestoreScreenBitsFromMemory

_TEXT$03   ends

        end



unix.superglobalmegacorp.com

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