|
|
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.