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

1.1       root        1: ;---------------------------Module-Header------------------------------;
                      2: ; Module Name: savescrn.asm
                      3: ;
                      4: ; Copyright (c) 1992 Microsoft Corporation
                      5: ;-----------------------------------------------------------------------;
                      6: 
                      7: ;-----------------------------------------------------------------------;
                      8: ; VOID vSaveScreenBitsToMemory(PDEVSURF pdsurf, PRECTL prcl,
                      9: ;                              PVOID pjDestBuffer, ULONG ulSaveWidthInBytes,
                     10: ;                              ULONG ulSaveHeight, ULONG ulDestScanWidth);
                     11: ; Input:
                     12: ;  pdsurf - surface from which to copy
                     13: ;  prcl - pointer to rectangle to copy
                     14: ;  pjDestBuffer - pointer to destination memory buffer. Should have the same
                     15: ;                 dword alignment as the source rect left edge does in screen
                     16: ;                 memory
                     17: ;  ulSaveWidthInBytes - # of bytes to save per scan
                     18: ;  ulSaveHeight - # of scans to save
                     19: ;  ulDestScanWidth - distance from the start of one saved scan in the
                     20: ;                    destination buffer to the start of the next saved scan.
                     21: ;                    This should be a dword multiple, to maintain dword
                     22: ;                    alignment between the source and destination
                     23: ;
                     24: ; Copies a rectangle from VGA memory to a memory buffer.
                     25: ;
                     26: ;-----------------------------------------------------------------------;
                     27: ;
                     28: ; Note: Assumes all rectangles have positive heights and widths. Will not
                     29: ; work properly if this is not the case.
                     30: ;
                     31: ;-----------------------------------------------------------------------;
                     32: ;
                     33: ; Note: The rectangle is saved in interleaved-scan format; all four planes
                     34: ; of one scan are saved together, then all four plane of the next scan,
                     35: ; and so on. This is done for maximum restoration efficiency. Planes are
                     36: ; saved in order 3, 2, 1, 0:
                     37: ;
                     38: ;  Scan n, plane 3
                     39: ;  Scan n, plane 2
                     40: ;  Scan n, plane 1
                     41: ;  Scan n, plane 0
                     42: ;  Scan n+1, plane 3
                     43: ;  Scan n+1, plane 2
                     44: ;  Scan n+1, plane 1
                     45: ;  Scan n+1, plane 0
                     46: ;          :
                     47: ;
                     48: ; There may be padding on either edge of the saved bits in the destination
                     49: ; buffer, so that the destination can be dword aligned with the source.
                     50: ;
                     51: ;-----------------------------------------------------------------------;
                     52: ;Additional optimizations:
                     53: ;
                     54: ; Could handle odd bytes to dword align more efficiently, by having separate
                     55: ; optimizations for various alignment widths, thereby avoiding starting REP
                     56: ; and getting word accesses for 2 and 3 wide cases. Most VGAs are 8 or 16
                     57: ; bit devices, and for them, using MOVSB/REP MOVSW/MOVSB might actually be
                     58: ; faster, especially because it's easier to break out optimizations.
                     59: ;
                     60: ; Could end all scan handlers with loop bottom code.
                     61: ;
                     62: ;-----------------------------------------------------------------------;
                     63: 
                     64:                 .386
                     65: 
                     66: ifndef  DOS_PLATFORM
                     67:         .model  small,c
                     68: else
                     69: ifdef   STD_CALL
                     70:         .model  small,c
                     71: else
                     72:         .model  small,pascal
                     73: endif;  STD_CALL
                     74: endif;  DOS_PLATFORM
                     75: 
                     76:         assume cs:FLAT,ds:FLAT,es:FLAT,ss:FLAT
                     77:         assume fs:nothing,gs:nothing
                     78: 
                     79:         .xlist
                     80:         include stdcall.inc             ;calling convention cmacros
                     81:         include i386\egavga.inc
                     82:         include i386\strucs.inc
                     83: 
                     84:         .list
                     85: 
                     86:         .code
                     87: 
                     88: _TEXT$03   SEGMENT DWORD USE32 PUBLIC 'CODE'
                     89:            ASSUME  CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
                     90: 
                     91: ;-----------------------------------------------------------------------;
                     92: 
                     93: cProc   vSaveScreenBitsToMemory,24,< \
                     94:         uses    esi edi ebx,      \
                     95:         pdsurf:ptr,               \
                     96:         prcl:ptr,                 \
                     97:         pjDestBuffer:ptr,         \
                     98:         ulSaveWidthInBytes:dword, \
                     99:         ulSaveHeight:dword,       \
                    100:         ulDestScanWidth:dword     >
                    101: 
                    102:         local   ulCurrentTopScan :dword ;top scan line to copy from in current
                    103:                                         ; bank
                    104:         local   ulBottomScan :dword     ;bottom scan line of rectangle to copy
                    105:         local   pjSrcStart :dword       ;source address
                    106:         local   ulSrcDelta :dword       ;distance from end of source scan to
                    107:                                         ; start of next
                    108:         local   ulDestDelta :dword      ;distance from end of dest scan to
                    109:                                         ; start of next
                    110:         local   ulBlockHeight :dword    ;# of scans to copy in block
                    111:         local   ulLeadingBytes :dword   ;# of leading bytes to copy per scan
                    112:         local   ulMiddleDwords :dword   ;# of dwords to copy per scan
                    113:         local   ulTrailingBytes :dword  ;# of trailing bytes to copy per scan
                    114:         local   pfnCopyVector :dword    ;pointer to inner loop routine to copy
                    115:                                         ; from screen to buffer
                    116: 
                    117: ;-----------------------------------------------------------------------;
                    118: ; Leave the GC Index pointing to the Read Map for the rest of this routine.
                    119: ;-----------------------------------------------------------------------;
                    120: 
                    121:         mov     edx,VGA_BASE + GRAF_ADDR
                    122:         mov     al,GRAF_READ_MAP
                    123:         out     dx,al
                    124: 
                    125: ;-----------------------------------------------------------------------;
                    126: ; Set up local variables.
                    127: ;-----------------------------------------------------------------------;
                    128: 
                    129:         mov     edi,prcl                ;point to rectangle from which to copy
                    130:         mov     esi,pdsurf              ;point to surface from which to copy
                    131: 
                    132:         mov     eax,[edi].yBottom
                    133:         mov     ulBottomScan,eax        ;bottom scan line of source rect
                    134: 
                    135:         mov     eax,ulDestScanWidth
                    136:         shl     eax,2
                    137:         sub     eax,ulSaveWidthInBytes
                    138:         mov     ulDestDelta,eax ;distance from end of one scan's saved bits
                    139:                                 ; to start of next scan's (skips over the three
                    140:                                 ; other plane's save areas for each scan)
                    141:         mov     eax,[esi].dsurf_lNextScan
                    142:         sub     eax,ulSaveWidthInBytes
                    143:         mov     ulSrcDelta,eax  ;distance from end of one scan's bits to save
                    144:                                 ; to start of next scan's in display memory
                    145: 
                    146: ;-----------------------------------------------------------------------;
                    147: ; Set up for copying as much as possible via aligned dwords, and
                    148: ; select the most efficient loop for doing the copy, based on the copy
                    149: ; width, and on the necessity for leading and/or trailing bytes to
                    150: ; dword align.
                    151: ;-----------------------------------------------------------------------;
                    152: 
                    153:         mov     edx,ulSaveWidthInBytes  ;# of bytes to copy per scan
                    154:         cmp     edx,8                   ;if it's less than 8 bytes, just do a
                    155:                                         ; straight byte copy. This means we
                    156:                                         ; we only have to start 1 REP per line,
                    157:                                         ; and performing this check guarantees
                    158:                                         ; that we have at least 1 aligned dword
                    159:                                         ; to copy in the dword loops
                    160:         jb      short copy_all_as_bytes ;do straight byte copy
                    161:         mov     eax,pjDestBuffer
                    162:         neg     eax
                    163:         and     eax,3           ;# of bytes that have to be done as leading
                    164:                                 ; bytes to dword align with destination (note
                    165:                                 ; that for performance, the destination should
                    166:                                 ; be dword aligned with the source)
                    167:         jz      short copy_no_leading_bytes     ;no leading bytes
                    168:                                 ;leading bytes
                    169:         mov     ulLeadingBytes,eax
                    170:         mov     ebx,offset copy_to_buffer_l ;assume no trailing bytes
                    171:         sub     edx,eax         ;# of bytes after leading bytes
                    172:         mov     eax,edx
                    173:         shr     eax,2           ;# of dwords that can be handled as aligned
                    174:                                 ; dwords
                    175:         mov     ulMiddleDwords,eax
                    176:         and     edx,3           ;# of trailing bytes left after aligned dwords
                    177:                                 ; copied
                    178:         jz      short set_copy_vector ;no trailing bytes
                    179:         mov     ulTrailingBytes,edx
                    180:         mov     ebx,offset copy_to_buffer_lt    ;there are both leading and
                    181:                                                 ; trailing bytes
                    182:         jmp     short set_copy_vector
                    183: 
                    184:         align   4
                    185: copy_no_leading_bytes:
                    186:         mov     ebx,offset copy_to_buffer ;assume no trailing bytes
                    187:         mov     eax,edx
                    188:         shr     eax,2           ;# of dwords that can be handled as aligned
                    189:                                 ; dwords
                    190:         mov     ulMiddleDwords,eax
                    191:         and     edx,3           ;# of trailing bytes left after aligned dwords
                    192:                                 ; copied
                    193:         jz      short set_copy_vector ;no trailing bytes
                    194:         mov     ulTrailingBytes,edx
                    195:         mov     ebx,offset copy_to_buffer_t     ;there are trailing bytes
                    196:         jmp     short set_copy_vector
                    197: 
                    198: ; It's so narrow that we'll forget about aligned dwords, and just do a straight
                    199: ; byte copy, which we'll handle by treating the entire copy as leading bytes.
                    200:         align   4
                    201: copy_all_as_bytes:
                    202:         mov     ulLeadingBytes,edx
                    203:         mov     ebx,offset copy_to_buffer_lonly
                    204: 
                    205: set_copy_vector:
                    206:         mov     pfnCopyVector,ebx
                    207: 
                    208: ;-----------------------------------------------------------------------;
                    209: ; Map in the bank containing the top scan to copy, if it's not mapped in
                    210: ; already.
                    211: ;-----------------------------------------------------------------------;
                    212: 
                    213:         mov     eax,[edi].yTop          ;top scan line of copy
                    214:         mov     ulCurrentTopScan,eax    ;this will be the copy top in 1st bank
                    215: 
                    216:         cmp     eax,[esi].dsurf_rcl1WindowClip.yTop ;is copy top less than
                    217:                                                     ; current bank?
                    218:         jl      short map_init_bank             ;yes, map in proper bank
                    219:         cmp     eax,[esi].dsurf_rcl1WindowClip.yBottom ;copy top greater than
                    220:                                                        ; current bank?
                    221:         jl      short init_bank_mapped          ;no, proper bank already mapped
                    222: map_init_bank:
                    223: 
                    224: ; Map in the bank containing the top scan line of the copy.
                    225: 
                    226:         ptrCall   <dword ptr [esi].dsurf_pfnBankControl>,<esi,eax,JustifyTop>
                    227: 
                    228: init_bank_mapped:
                    229: 
                    230: ;-----------------------------------------------------------------------;
                    231: ; Calculate the initial start address from which to copy.
                    232: ;-----------------------------------------------------------------------;
                    233: 
                    234:         mov     eax,ulCurrentTopScan    ;top scan line to copy in current bank
                    235:         imul    [esi].dsurf_lNextScan   ;offset of starting scan line in bitmap
                    236:         add     eax,[esi].dsurf_pvBitmapStart ;start address of scan
                    237:         mov     ebx,[edi].xLeft
                    238:         shr     ebx,3                   ;convert from pixel to byte address
                    239:         add     eax,ebx                 ;start source address
                    240:         mov     pjSrcStart,eax
                    241: 
                    242: ;-----------------------------------------------------------------------;
                    243: ; Loop through and copy all bank blocks spanned by the source rectangle.
                    244: ;
                    245: ; Input:
                    246: ;  ESI = pdsurf
                    247: ;-----------------------------------------------------------------------;
                    248: 
                    249: copy_to_buffer_bank_loop:
                    250: 
                    251: ; Copy this bank block to the buffer.
                    252: 
                    253: ; Calculate # of scans in this bank.
                    254: 
                    255:         mov     ebx,ulBottomScan        ;bottom of source rectangle
                    256:         cmp     ebx,[esi].dsurf_rcl1WindowClip.yBottom
                    257:                                         ;which comes first, the bottom of the
                    258:                                         ; source rect or the bottom of the
                    259:                                         ; current bank?
                    260:         jl      short @F                ;source bottom comes first, so copy to
                    261:                                         ; that; this is the last bank in copy
                    262:         mov     ebx,[esi].dsurf_rcl1WindowClip.yBottom
                    263:                                         ;bank bottom comes first; copy to
                    264:                                         ; bottom of bank
                    265: @@:
                    266:         sub     ebx,ulCurrentTopScan    ;# of scans to copy in this bank
                    267:         mov     ulBlockHeight,ebx
                    268: 
                    269: ;-----------------------------------------------------------------------;
                    270: ; Loop through all four planes, copying all scans in this block for each
                    271: ; plane in turn.
                    272: ;-----------------------------------------------------------------------;
                    273: 
                    274:         mov     eax,3           ;start by copying plane 3
                    275: 
                    276: copy_whole_to_buffer_plane_loop:
                    277: 
                    278:         mov     edx,VGA_BASE + GRAF_DATA
                    279:         out     dx,al           ;set Read Map to plane from which we're copying
                    280: 
                    281:         push    eax             ;remember plane index
                    282: 
                    283:         mov     esi,pjSrcStart   ;point to start of source rect
                    284:         mov     edi,pjDestBuffer ;point to start of dest buffer
                    285:         mov     eax,ulDestScanWidth
                    286:         add     pjDestBuffer,eax ;point to start of next plane's scan in dest
                    287:                                  ; buffer
                    288:         mov     eax,ulSrcDelta   ;offset to next source scan
                    289:         mov     edx,ulDestDelta  ;offset to next dest scan
                    290:         mov     ebx,ulBlockHeight
                    291: 
                    292:         jmp     pfnCopyVector   ;jump to the appropriate loop to copy plane
                    293: 
                    294: ;-----------------------------------------------------------------------;
                    295: ; Copy loops, broken out by leading and trailing bytes needed for dword
                    296: ; alignment, plus one loop to perform a straight byte copy.
                    297: ;
                    298: ; Input:
                    299: ;  EAX = offset from end of one source scan to start of next
                    300: ;  EBX = block height in scans
                    301: ;  EDX = offset from end of one dest scan to start of next
                    302: ;  ESI = initial source copy address
                    303: ;  EDI = initial dest copy address
                    304: ;-----------------------------------------------------------------------;
                    305: 
                    306: ; All byte can be copied as aligned dwords (no leading or trailing bytes).
                    307:         align   4
                    308: copy_to_buffer:
                    309: copy_to_buffer_scan_loop:
                    310:         mov     ecx,ulMiddleDwords
                    311:         rep     movsd
                    312:         add     esi,eax         ;point to next source scan
                    313:         add     edi,edx         ;point to next dest scan
                    314:         dec     ebx             ;count down scan lines
                    315:         jnz     copy_to_buffer_scan_loop
                    316:         jmp     short copy_to_buffer_scans_done
                    317: 
                    318: ; Leading odd bytes, but no trailing bytes.
                    319:         align   4
                    320: copy_to_buffer_l:
                    321: copy_to_buffer_scan_loop_l:
                    322:         mov     ecx,ulLeadingBytes
                    323:         rep     movsb
                    324:         mov     ecx,ulMiddleDwords
                    325:         rep     movsd
                    326:         add     esi,eax         ;point to next source scan
                    327:         add     edi,edx         ;point to next dest scan
                    328:         dec     ebx             ;count down scan lines
                    329:         jnz     copy_to_buffer_scan_loop_l
                    330:         jmp     short copy_to_buffer_scans_done
                    331: 
                    332: ; Trailing odd bytes, but no leading bytes.
                    333:         align   4
                    334: copy_to_buffer_t:
                    335: copy_to_buffer_scan_loop_t:
                    336:         mov     ecx,ulMiddleDwords
                    337:         rep     movsd
                    338:         mov     ecx,ulTrailingBytes
                    339:         rep     movsb
                    340:         add     esi,eax         ;point to next source scan
                    341:         add     edi,edx         ;point to next dest scan
                    342:         dec     ebx             ;count down scan lines
                    343:         jnz     copy_to_buffer_scan_loop_t
                    344:         jmp     short copy_to_buffer_scans_done
                    345: 
                    346: ; Only leading bytes (straight byte copy; no aligned dwords).
                    347:         align   4
                    348: copy_to_buffer_lonly:
                    349: copy_to_buffer_scan_loop_lonly:
                    350:         mov     ecx,ulLeadingBytes
                    351:         rep     movsb
                    352:         add     esi,eax         ;point to next source scan
                    353:         add     edi,edx         ;point to next dest scan
                    354:         dec     ebx             ;count down scan lines
                    355:         jnz     copy_to_buffer_scan_loop_lonly
                    356:         jmp     short copy_to_buffer_scans_done
                    357: 
                    358: ; Leading and trailing odd bytes.
                    359:         align   4
                    360: copy_to_buffer_lt:
                    361: copy_to_buffer_scan_loop_lt:
                    362:         mov     ecx,ulLeadingBytes
                    363:         rep     movsb
                    364:         mov     ecx,ulMiddleDwords
                    365:         rep     movsd
                    366:         mov     ecx,ulTrailingBytes
                    367:         rep     movsb
                    368:         add     esi,eax         ;point to next source scan
                    369:         add     edi,edx         ;point to next dest scan
                    370:         dec     ebx             ;count down scan lines
                    371:         jnz     copy_to_buffer_scan_loop_lt
                    372: 
                    373: copy_to_buffer_scans_done:
                    374: 
                    375:         pop     eax             ;get back plane index
                    376:         dec     eax             ;count down planes
                    377:         jns     copy_whole_to_buffer_plane_loop
                    378: 
                    379: ; Remember where we left off, for the next block.
                    380: 
                    381:         mov     pjSrcStart,esi
                    382:         mov     eax,ulDestScanWidth
                    383:         lea     eax,[eax+eax*2] ;ulDestScanWidth*3
                    384:         sub     edi,eax         ;adjust back to first plane's save area
                    385:                                 ; (remember, scans are interleaved by plane, so
                    386:                                 ; there are four planes per scan; we're
                    387:                                 ; adjusting back from the fourth to the first)
                    388:         mov     pjDestBuffer,edi
                    389: 
                    390: ;-----------------------------------------------------------------------;
                    391: ; See if there are more banks to do
                    392: ;-----------------------------------------------------------------------;
                    393: 
                    394:         mov     esi,pdsurf
                    395:         mov     eax,[esi].dsurf_rcl1WindowClip.yBottom ;is the copy bottom in
                    396:         cmp     ulBottomScan,eax                       ; the current bank?
                    397:         jle     short copy_to_buffer_banks_done        ;yes, so we're done
                    398:                                         ;no, map in the next bank and copy it
                    399:         mov     ulCurrentTopScan,eax    ;remember where the top of the bank
                    400:                                         ; we're about to map in is (same as
                    401:                                         ; bottom of bank we just did)
                    402:         mov     edx,[esi].dsurf_pvBitmapStart
                    403:         sub     pjSrcStart,edx  ;convert from address to offset within bitmap
                    404: 
                    405:         ptrCall   <dword ptr [esi].dsurf_pfnBankControl>,<esi,eax,JustifyTop>
                    406:                                         ;map in the bank
                    407: 
                    408: ; Compute the starting address in this bank.
                    409: ; Note that the start of the bitmap will change each time through the
                    410: ; bank loop, because the start of the bitmap is varied to map the
                    411: ; desired scan line to the banking window.
                    412: 
                    413:         mov     eax,[esi].dsurf_pvBitmapStart
                    414:         add     pjSrcStart,eax  ;address of next scan to draw
                    415: 
                    416: ; Copy the new bank.
                    417: 
                    418:         jmp     copy_to_buffer_bank_loop
                    419: 
                    420: 
                    421: ;-----------------------------------------------------------------------;
                    422: ; Done with all banks.
                    423: ;-----------------------------------------------------------------------;
                    424:         align 4
                    425: copy_to_buffer_banks_done:
                    426: 
                    427:         cRet    vSaveScreenBitsToMemory ;done
                    428: 
                    429: ;-----------------------------------------------------------------------;
                    430: 
                    431: endProc vSaveScreenBitsToMemory
                    432: 
                    433: _TEXT$03   ends
                    434: 
                    435:         end
                    436: 
                    437: 

unix.superglobalmegacorp.com

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