|
|
1.1 root 1: ;---------------------------Module-Header------------------------------;
2: ; Module Name: restscrn.asm
3: ;
4: ; Copyright (c) 1992 Microsoft Corporation
5: ;-----------------------------------------------------------------------;
6: ;-----------------------------------------------------------------------;
7: ; VOID vRestoreScreenBitsFromMemory(PDEVSURF pdsurf, PRECTL prcl,
8: ; PVOID pjSrcBuffer, ULONG ulRestoreWidthInBytes,
9: ; ULONG ulSrcDelta);
10: ; Input:
11: ; pdsurf - surface to which to copy
12: ; prcl - pointer to rectangle to which to copy
13: ; pjSrcBuffer - pointer to source memory buffer. Should have the same
14: ; dword alignment as the dest rect left edge does in screen
15: ; memory
16: ; ulRestoreWidthInBytes - # of bytes to restore per scan (including any
17: ; partial edges)
18: ; ulSrcDelta - distance from end of one source scan to start of next.
19: ; together with ulRestoreWidthInBytes, should maintain
20: ; dword alignment between source and dest
21: ;
22: ; Copies a rectangle from a memory buffer to VGA memory.
23: ;
24: ;-----------------------------------------------------------------------;
25: ;
26: ; Note: Assumes all rectangles have positive heights and widths. Will not
27: ; work properly if this is not the case.
28: ;
29: ;-----------------------------------------------------------------------;
30: ;
31: ; Note: The rectangle is restored from interleaved-scan format; all four planes
32: ; of one scan are saved together, then all four planes of the next scan,
33: ; and so on. This is done for maximum restoration efficiency. Planes are
34: ; saved in order 3, 2, 1, 0:
35: ;
36: ; Scan n, plane 3
37: ; Scan n, plane 2
38: ; Scan n, plane 1
39: ; Scan n, plane 0
40: ; Scan n+1, plane 3
41: ; Scan n+1, plane 2
42: ; Scan n+1, plane 1
43: ; Scan n+1, plane 0
44: ; :
45: ;
46: ; There may be padding on either edge of the saved bits in the destination
47: ; buffer, so that the destination can be dword aligned with the source.
48: ;
49: ;-----------------------------------------------------------------------;
50: ;Additional optimizations:
51: ;
52: ; Could break out separate scan copy code with and without edge handling.
53: ; (Possibly by threading the desired operations, or by having many separate
54: ; optimizations.)
55: ;
56: ; Could handle odd bytes to dword align more efficiently, by having separate
57: ; optimizations for various alignment widths, thereby avoiding starting REP
58: ; and getting word accesses for 2 and 3 wide cases. Most VGAs are 8 or 16
59: ; bit devices, and for them, using MOVSB/REP MOVSW/MOVSB might actually be
60: ; faster, especially because it's easier to break out optimizations.
61: ;
62: ; Could end all scan handlers with loop bottom code.
63: ;
64: ; Could do more scans in one plane before doing next plane, to avoid
65: ; slow OUTs. This could cause color effects, but that might be avoidable
66: ; by scaling the # of scans done per plane to the width of the rectangle.
67: ;
68: ;-----------------------------------------------------------------------;
69:
70:
71: .386
72:
73: ifndef DOS_PLATFORM
74: .model small,c
75: else
76: ifdef STD_CALL
77: .model small,c
78: else
79: .model small,pascal
80: endif; STD_CALL
81: endif; DOS_PLATFORM
82:
83: assume cs:FLAT,ds:FLAT,es:FLAT,ss:FLAT
84: assume fs:nothing,gs:nothing
85:
86: .xlist
87: include stdcall.inc ;calling convention cmacros
88: include i386\egavga.inc
89: include i386\strucs.inc
90:
91: .list
92:
93: .data
94:
95: ;-----------------------------------------------------------------------;
96: ; Masks used to do left and right edge clipping for various alignments.
97: ; Low byte = destination mask, high byte = source mask.
98: ;-----------------------------------------------------------------------;
99: align 2
100: usLeftMasks label word
101: dw 0ff00h, 07f80h, 03fc0h, 01fe0h, 00ff0h, 007f8h, 003fch, 001feh
102:
103: usRightMasks label word
104: dw 0ff00h, 0807fh, 0c03fh, 0e01fh, 0f00fh, 0f807h, 0fc03h, 0fe01h
105:
106: ;-----------------------------------------------------------------------;
107: ; Same as above, but dest masks only, and whole byte case is represented
108: ; as 0ffh rather than 0. Used for 1-byte-wide cases.
109: ;-----------------------------------------------------------------------;
110: jLeftMasks label byte
111: db 0ffh, 080h, 0c0h, 0e0h, 0f0h, 0f8h, 0fch, 0feh
112:
113: jRightMasks label byte
114: db 0ffh, 07fh, 03fh, 01fh, 00fh, 007h, 003h, 001h
115:
116: .code
117:
118: _TEXT$03 SEGMENT DWORD USE32 PUBLIC 'CODE'
119: ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
120:
121: ;-----------------------------------------------------------------------;
122:
123: cProc vRestoreScreenBitsFromMemory,20,< \
124: uses esi edi ebx, \
125: pdsurf:ptr, \
126: prcl:ptr, \
127: pjSrcBuffer:ptr, \
128: ulRestoreWidthInBytes:dword, \
129: ulSrcDelta:dword >
130:
131: local ulCurrentTopScan :dword ;top scan line to copy to in current
132: ; bank
133: local ulBottomScan :dword ;bottom scan line of rectangle to which
134: ; to copy
135: local pjDstStart :dword ;destination address
136: local ulDstDelta :dword ;distance from end of dest scan to
137: ; start of next
138: local ulBlockHeight :dword ;# of scans to copy in block
139: local ulLeadingBytes :dword ;# of leading bytes to copy per scan
140: local ulMiddleDwords :dword ;# of dwords to copy per scan
141: local ulTrailingBytes :dword ;# of trailing bytes to copy per scan
142: local pfnCopyVector :dword ;pointer to inner loop routine to copy
143: ; from buffer to screen
144: local ulLeftMask :dword ;2 byte masks for left edge clipping
145: ; (low byte = dest mask,
146: ; high byte = src mask)
147: local ulRightMask :dword ;2 byte masks for right edge clipping
148:
149: ;-----------------------------------------------------------------------;
150: ; Leave the GC Index pointing to the Read Map for the rest of this routine.
151: ;-----------------------------------------------------------------------;
152:
153: mov edx,VGA_BASE + GRAF_ADDR
154: mov al,GRAF_READ_MAP
155: out dx,al
156:
157: ;-----------------------------------------------------------------------;
158: ; Set up local variables.
159: ;-----------------------------------------------------------------------;
160:
161: mov edi,prcl ;point to rectangle from which to copy
162: mov esi,pdsurf ;point to surface from which to copy
163:
164: mov eax,[edi].yBottom
165: mov ulBottomScan,eax ;bottom scan line of source rect
166:
167: mov eax,[esi].dsurf_lNextScan
168: sub eax,ulRestoreWidthInBytes
169: mov ulDstDelta,eax ;distance from end of one scan's bits to save
170: ; to start of next scan's in display memory
171:
172: ;-----------------------------------------------------------------------;
173: ; Figure out the left and right clip masks. If either or both edges are
174: ; solid, add them into the whole bytes.
175: ;-----------------------------------------------------------------------;
176:
177: mov ebx,[edi].xLeft
178: mov ecx,[edi].xRight
179: mov edx,ebx
180: lea eax,[ecx-1]
181: and ebx,0111b
182: and ecx,0111b
183:
184: and edx,not 0111b
185: sub eax,edx
186: shr eax,3 ;width in bytes - 1
187: ;only 1 byte wide?
188: jnz short @F ;no
189: ;1 byte wide; special case
190: mov al,jLeftMasks[ebx] ;look up left dest mask
191: and al,jRightMasks[ecx] ;factor in right dest mask
192: mov ah,0ffh
193: mov ebx,offset copy_from_buffer_l_whole_only ;assume whole byte
194: xor ah,al ;calculate matching dest mask
195: ;is this single byte a whole byte?
196: jz set_copy_vector ;yes, select whole byte optimization
197: ;no, select partial byte optimization
198: mov ebx,offset copy_from_buffer_l_partial_only
199: mov ulLeftMask,eax
200: jmp set_copy_vector
201:
202: align 4
203: @@: ;more than 1 byte wide
204:
205: mov edx,ulRestoreWidthInBytes
206:
207: mov ax,usLeftMasks[ebx*2] ;look up left masks
208: mov ulLeftMask,eax
209: and al,al ;any left clipping?
210: jz short @F ;no, do as part of whole bytes
211: dec edx ;yes, don't count as whole byte
212: @@:
213:
214:
215: mov ax,usRightMasks[ecx*2] ;look up right masks
216: mov ulRightMask,eax
217: and al,al ;any right clipping?
218: jz short @F ;no, do as part of whole bytes
219: dec edx ;yes, don't count as whole byte
220: @@:
221:
222: ;-----------------------------------------------------------------------;
223: ; Set up for copying as much as possible via aligned dwords, and
224: ; select the most efficient loop for doing the copy, based on the copy
225: ; width, and on the necessity for leading and/or trailing bytes to
226: ; dword align.
227: ;-----------------------------------------------------------------------;
228:
229: cmp edx,8 ;if it's less than 8 bytes, just do a
230: ; straight byte copy. This means we
231: ; we only have to start 1 REP per line,
232: ; and performing this check guarantees
233: ; that we have at least 1 aligned dword
234: ; to copy in the dword loops
235: jb short copy_all_as_bytes ;do straight byte copy
236: mov eax,pjSrcBuffer
237: neg eax
238: and eax,3 ;# of bytes that have to be done as leading
239: ; bytes to dword align with source (note that
240: ; for performance, the source should be dword
241: ; aligned with the destination)
242: jz short copy_no_leading_bytes ;no leading bytes
243: ;leading bytes
244: mov ulLeadingBytes,eax
245: mov ebx,offset copy_from_buffer_l ;assume no trailing bytes
246: sub edx,eax ;# of bytes after leading bytes
247: mov eax,edx
248: shr eax,2 ;# of dwords that can be handled as aligned
249: ; dwords
250: mov ulMiddleDwords,eax
251: and edx,3 ;# of trailing bytes left after aligned dwords
252: ; copied
253: jz short set_copy_vector ;no trailing bytes
254: mov ulTrailingBytes,edx
255: mov ebx,offset copy_from_buffer_lt ;there are both leading and
256: ; trailing bytes
257: jmp short set_copy_vector
258:
259: align 4
260: copy_no_leading_bytes:
261: mov ebx,offset copy_from_buffer ;assume no trailing bytes
262: mov eax,edx
263: shr eax,2 ;# of dwords that can be handled as aligned
264: ; dwords
265: mov ulMiddleDwords,eax
266: and edx,3 ;# of trailing bytes left after aligned dwords
267: ; copied
268: jz short set_copy_vector ;no trailing bytes
269: mov ulTrailingBytes,edx
270: mov ebx,offset copy_from_buffer_t ;there are trailing bytes
271: jmp short set_copy_vector
272:
273: ; It's so narrow that we'll forget about aligned dwords, and just do a straight
274: ; byte copy, which we'll handle by treating the entire copy as leading bytes.
275: align 4
276: copy_all_as_bytes:
277: mov ulLeadingBytes,edx
278: mov ebx,offset copy_from_buffer_lonly
279:
280: set_copy_vector:
281: mov pfnCopyVector,ebx
282:
283: ;-----------------------------------------------------------------------;
284: ; Map in the bank containing the top scan to copy, if it's not mapped in
285: ; already.
286: ;-----------------------------------------------------------------------;
287:
288: mov eax,[edi].yTop ;top scan line of copy
289: mov ulCurrentTopScan,eax ;this will be the copy top in 1st bank
290:
291: cmp eax,[esi].dsurf_rcl1WindowClip.yTop ;is copy top less than
292: ; current bank?
293: jl short map_init_bank ;yes, map in proper bank
294: cmp eax,[esi].dsurf_rcl1WindowClip.yBottom ;copy top greater than
295: ; current bank?
296: jl short init_bank_mapped ;no, proper bank already mapped
297: map_init_bank:
298:
299: ; Map in the bank containing the top scan line of the copy.
300:
301: ptrCall <dword ptr [esi].dsurf_pfnBankControl>,<esi,eax,JustifyTop>
302:
303: init_bank_mapped:
304:
305: ;-----------------------------------------------------------------------;
306: ; Calculate the initial start address to which to copy.
307: ;-----------------------------------------------------------------------;
308:
309: mov eax,ulCurrentTopScan ;top scan line to copy to in current
310: ; bank
311: imul [esi].dsurf_lNextScan ;offset of starting scan line in bitmap
312: add eax,[esi].dsurf_pvBitmapStart ;start address of scan
313: mov ebx,[edi].xLeft
314: shr ebx,3 ;convert from pixel to byte address
315: add eax,ebx ;start dest address
316: mov pjDstStart,eax
317:
318: ;-----------------------------------------------------------------------;
319: ; Loop through and copy all bank blocks spanned by the destination
320: ; rectangle.
321: ;
322: ; Input:
323: ; ESI = pdsurf
324: ;-----------------------------------------------------------------------;
325:
326: copy_from_buffer_bank_loop:
327:
328: ; Copy this bank block to the buffer.
329:
330: ; Calculate # of scans in this bank.
331:
332: mov ebx,ulBottomScan ;bottom of dest rectangle
333: cmp ebx,[esi].dsurf_rcl1WindowClip.yBottom
334: ;which comes first, the bottom of the
335: ; dest rect or the bottom of the
336: ; current bank?
337: jl short @F ;dest bottom comes first, so copy to
338: ; that; this is the last bank in copy
339: mov ebx,[esi].dsurf_rcl1WindowClip.yBottom
340: ;bank bottom comes first; copy to
341: ; bottom of bank
342: @@:
343: sub ebx,ulCurrentTopScan ;# of scans to copy in this bank
344: mov ulBlockHeight,ebx
345:
346: mov esi,pjSrcBuffer ;point to start of source rect
347:
348: mov dh,VGA_BASE SHR 8 ;leave DH pointing to VGA_BASE
349:
350: ;-----------------------------------------------------------------------;
351: ; Loop through all scans in this block, copying all four planes of each
352: ; scan in turn, then doing the next scan.
353: ;-----------------------------------------------------------------------;
354: copy_to_buffer_scan_loop:
355:
356: mov bl,MM_C3 ;start by copying to plane 3
357:
358: ;-----------------------------------------------------------------------;
359: ; Loop through all four planes, copying all scans in this block for each
360: ; plane in turn.
361: ;-----------------------------------------------------------------------;
362:
363: copy_to_buffer_plane_loop:
364:
365: mov dl,SEQ_DATA
366: mov al,bl
367: out dx,al ;set Map Mask to plane to which we're copying
368:
369: mov dl,GRAF_DATA
370: shr al,1
371: cmp al,3
372: adc al,-1
373: out dx,al
374:
375: mov edi,pjDstStart ;point to start of dest buffer (scan starts
376: ; at same address in all planes)
377: jmp pfnCopyVector ;jump to the appropriate loop to copy plane
378:
379: ;-----------------------------------------------------------------------;
380: ; Copy loops, broken out by leading and trailing bytes needed for dword
381: ; alignment, plus one loop to perform a straight byte copy.
382: ;
383: ; Input:
384: ; ESI = initial source copy address
385: ; EDI = initial dest copy address
386: ;-----------------------------------------------------------------------;
387:
388: ; All bytes can be copied as aligned dwords (no leading or trailing whole
389: ; bytes).
390: align 4
391: copy_from_buffer:
392:
393: ; Do the left edge byte, if there's a partial left edge byte.
394:
395: mov eax,ulLeftMask ;AL = dest mask, AH = source mask
396: and al,al ;any left mask?
397: jz short @F ;left edge is whole
398: and al,[edi] ;mask the dest
399: and ah,[esi] ;mask the source
400: inc esi ;point to next source byte
401: or al,ah ;combine the source and dest
402: stosb ;store the new byte
403: @@:
404:
405: ; Do the middle (whole) bytes.
406:
407: mov ecx,ulMiddleDwords
408: rep movsd
409:
410: ; Do the right edge byte, if there's a partial right edge byte.
411:
412: mov eax,ulRightMask ;AL = dest mask, AH = source mask
413: and al,al ;any left mask?
414: jz short @F ;right edge is whole
415: and al,[edi] ;mask the dest
416: and ah,[esi] ;mask the source
417: inc esi ;point to next source byte
418: or al,ah ;combine the source and dest
419: stosb ;store the new byte
420: @@:
421:
422: jmp copy_from_buffer_scan_done
423:
424: ; Leading odd whole bytes, but no trailing whole bytes.
425: align 4
426: copy_from_buffer_l:
427:
428: ; Do the left edge byte, if there's a partial left edge byte.
429:
430: mov eax,ulLeftMask ;AL = dest mask, AH = source mask
431: and al,al ;any left mask?
432: jz short @F ;left edge is whole
433: and al,[edi] ;mask the dest
434: and ah,[esi] ;mask the source
435: inc esi ;point to next source byte
436: or al,ah ;combine the source and dest
437: stosb ;store the new byte
438: @@:
439:
440: ; Do the middle (whole) bytes.
441:
442: mov ecx,ulLeadingBytes
443: rep movsb
444: mov ecx,ulMiddleDwords
445: rep movsd
446:
447: ; Do the right edge byte, if there's a partial right edge byte.
448:
449: mov eax,ulRightMask ;AL = dest mask, AH = source mask
450: and al,al ;any left mask?
451: jz short @F ;right edge is whole
452: and al,[edi] ;mask the dest
453: and ah,[esi] ;mask the source
454: inc esi ;point to next source byte
455: or al,ah ;combine the source and dest
456: stosb ;store the new byte
457: @@:
458:
459: jmp copy_from_buffer_scan_done
460:
461: ; Trailing odd whole bytes, but no leading whole bytes.
462: align 4
463: copy_from_buffer_t:
464:
465: ; Do the left edge byte, if there's a partial left edge byte.
466:
467: mov eax,ulLeftMask ;AL = dest mask, AH = source mask
468: and al,al ;any left mask?
469: jz short @F ;left edge is whole
470: and al,[edi] ;mask the dest
471: and ah,[esi] ;mask the source
472: inc esi ;point to next source byte
473: or al,ah ;combine the source and dest
474: stosb ;store the new byte
475: @@:
476:
477: ; Do the middle (whole) bytes.
478:
479: mov ecx,ulMiddleDwords
480: rep movsd
481: mov ecx,ulTrailingBytes
482: rep movsb
483:
484: ; Do the right edge byte, if there's a partial right edge byte.
485:
486: mov eax,ulRightMask ;AL = dest mask, AH = source mask
487: and al,al ;any left mask?
488: jz short @F ;right edge is whole
489: and al,[edi] ;mask the dest
490: and ah,[esi] ;mask the source
491: inc esi ;point to next source byte
492: or al,ah ;combine the source and dest
493: stosb ;store the new byte
494: @@:
495:
496: jmp copy_from_buffer_scan_done
497:
498: ; Only leading whole bytes (straight whole byte copy; no aligned dwords).
499: align 4
500: copy_from_buffer_lonly:
501:
502: ; Do the left edge byte, if there's a partial left edge byte.
503:
504: mov eax,ulLeftMask ;AL = dest mask, AH = source mask
505: and al,al ;any left mask?
506: jz short @F ;left edge is whole
507: and al,[edi] ;mask the dest
508: and ah,[esi] ;mask the source
509: inc esi ;point to next source byte
510: or al,ah ;combine the source and dest
511: stosb ;store the new byte
512: @@:
513:
514: ; Do the middle (whole) bytes.
515:
516: mov ecx,ulLeadingBytes
517: rep movsb
518:
519: ; Do the right edge byte, if there's a partial right edge byte.
520:
521: mov eax,ulRightMask ;AL = dest mask, AH = source mask
522: and al,al ;any left mask?
523: jz short @F ;right edge is whole
524: and al,[edi] ;mask the dest
525: and ah,[esi] ;mask the source
526: inc esi ;point to next source byte
527: or al,ah ;combine the source and dest
528: stosb ;store the new byte
529: @@:
530:
531: jmp short copy_from_buffer_scan_done
532:
533: ; Only one masked byte; no whole bytes and no right byte.
534: align 4
535: copy_from_buffer_l_partial_only:
536:
537: mov eax,ulLeftMask ;AL = dest mask, AH = source mask
538: and al,[edi] ;mask the dest
539: and ah,[esi] ;mask the source
540: inc esi ;point to next source byte
541: or al,ah ;combine the source and dest
542: stosb ;store the new byte
543: jmp short copy_from_buffer_scan_done
544:
545: ; Only one whole byte; no left byte and no right byte.
546: align 4
547: copy_from_buffer_l_whole_only:
548:
549: movsb ;copy the one byte
550: jmp short copy_from_buffer_scan_done
551:
552: ; Leading and trailing odd whole bytes.
553: align 4
554: copy_from_buffer_lt:
555:
556: ; Do the left edge byte, if there's a partial left edge byte.
557:
558: mov eax,ulLeftMask ;AL = dest mask, AH = source mask
559: and al,al ;any left mask?
560: jz short @F ;left edge is whole
561: and al,[edi] ;mask the dest
562: and ah,[esi] ;mask the source
563: inc esi ;point to next source byte
564: or al,ah ;combine the source and dest
565: stosb ;store the new byte
566: @@:
567:
568: ; Do the middle (whole) bytes.
569:
570: mov ecx,ulLeadingBytes
571: rep movsb
572: mov ecx,ulMiddleDwords
573: rep movsd
574: mov ecx,ulTrailingBytes
575: rep movsb
576:
577: ; Do the right edge byte, if there's a partial right edge byte.
578:
579: mov eax,ulRightMask ;AL = dest mask, AH = source mask
580: and al,al ;any left mask?
581: jz short @F ;right edge is whole
582: and al,[edi] ;mask the dest
583: and ah,[esi] ;mask the source
584: inc esi ;point to next source byte
585: or al,ah ;combine the source and dest
586: stosb ;store the new byte
587: @@:
588:
589: copy_from_buffer_scan_done:
590:
591: add esi,ulSrcDelta ;point to next source scan
592: shr bl,1 ;count down planes
593: jnz copy_to_buffer_plane_loop
594:
595: add edi,ulDstDelta ;point to next dest scan
596: mov pjDstStart,edi
597: dec ulBlockHeight ;count down scans
598: jnz copy_to_buffer_scan_loop
599:
600: ; Remember where we left off, for the next block.
601:
602: mov pjSrcBuffer,esi
603:
604: ;-----------------------------------------------------------------------;
605: ; See if there are more banks to do
606: ;-----------------------------------------------------------------------;
607:
608: mov esi,pdsurf
609: mov eax,[esi].dsurf_rcl1WindowClip.yBottom ;is the copy bottom in
610: cmp ulBottomScan,eax ; the current bank?
611: jle short copy_from_buffer_banks_done ;yes, so we're done
612: ;no, map in the next bank and copy it
613: mov ulCurrentTopScan,eax ;remember where the top of the bank
614: ; we're about to map in is (same as
615: ; bottom of bank we just did)
616: mov edx,[esi].dsurf_pvBitmapStart
617: sub pjDstStart,edx ;convert from address to offset within bitmap
618:
619: ptrCall <dword ptr [esi].dsurf_pfnBankControl>,<esi,eax,JustifyTop>
620: ;map in the bank
621:
622: ; Compute the starting address in this bank.
623: ; Note that the start of the bitmap will change each time through the
624: ; bank loop, because the start of the bitmap is varied to map the
625: ; desired scan line to the banking window.
626:
627: mov eax,[esi].dsurf_pvBitmapStart
628: add pjDstStart,eax ;address of next scan to draw
629:
630: ; Copy the new bank.
631:
632: jmp copy_from_buffer_bank_loop
633:
634:
635: ;-----------------------------------------------------------------------;
636: ; Done with all banks.
637: ;
638: ; At this point:
639: ; DX = VGA_BASE + GRAF_DATA
640: ;-----------------------------------------------------------------------;
641: align 4
642: copy_from_buffer_banks_done:
643:
644: mov ax,(MM_ALL shl 8)+SEQ_MAP_MASK ;restore writability for all planes
645: mov dx,VGA_BASE+SEQ_ADDR
646: out dx,ax
647:
648: cRet vRestoreScreenBitsFromMemory ;done
649:
650: ;-----------------------------------------------------------------------;
651:
652: endProc vRestoreScreenBitsFromMemory
653:
654: _TEXT$03 ends
655:
656: end
657:
658:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.