Annotation of ntddk/src/video/displays/vga/i386/savescrn.asm, revision 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.