|
|
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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.