Aaron Giles -- agiles@lucasarts.com
From: Aaron Giles, agiles@lucasarts.com To: Multiple recipients of list, mac-games-dev@solutions.apple.com >If anybody is still working on QuickDraw code, is there any way to impress >upon them the importance of adding fast pixel-doubling in CopyBits? I believe the DR3 release of DrawSprocket has a scaling mechanism you can use to specify pixel doubling. Cary can answer that one for sure; I'm just guessing from the API in DR3 (no docs yet). In the meantime, everyone should have the following PPCAsm code for a fast pixel double direct to the screen. This came out of one of the first Apple games kitchens (in Austin). I wrote the original version, and Eric Traut (author of the DR emulator) helped me with some pipelining issues. It was used in Dark Forces, and is pretty much public domain at this point. Globals: gDrawRowBytes is the rowbytes & 0x7fff of the destination GDevice gDrawStart is a pointer to the start of VRAM where you wish to draw to Parameters: draw_buffer is a pointer to the start of the source buffer dx,dy is the X,Y position to blit to, relative to gDrawStart w,h is the width and height of the source image (320x240, or whatever) modulus is the rowBytes of the source buffer # # # Import external global variables # # import gDrawRowBytes import gDrawStart # # # TOC space for external globals # # toc tc gDrawRowBytes[TC], gDrawRowBytes tc gDrawStart[TC], gDrawStart # # # Export function names we define here # # export BlitLargeAlign[DS] export .BlitLargeAlign[PR] # # # TOC space for our functions # # toc tc BlitLargeAlign[TC], BlitLargeAlign[DS] # # # Function descriptors for our functions # # csect BlitLargeAlign[DS] dc.l .BlitLargeAlign[PR] dc.l TOC[tc0] dc.l 0 # # # void BlitLargeAlign(uchar *draw_buffer, int dx, int dy, int w, int h, int modulus) # r3 r4 r5 r6 r7 r8 # csect .BlitLargeAlign[PR] fpTemp: EQU fp0 rSrcPtr: EQU r3 rdx: EQU r4 rDst2Ptr: EQU r4 rdy: EQU r5 rDst1Ptr: EQU r5 rWidth: EQU r6 rHeight: EQU r7 rModulus: EQU r8 rSStrd: EQU r8 rDStrd: EQU r9 # # note: we use the "red zone" to store a temporary double -- is this kosher? # # this location is at -8(SP); this saves us from needing to save any registers # sub rSStrd,rModulus,rWidth # subtract width from modulus for sstride neg rDStrd,rWidth # put -rWidth into rDblStrd lwz r11,gDrawRowBytes[TC](RTOC) # get ptr to rowBytes count in r11 srawi rWidth,rWidth,2 # divide width by 4 for counting lwz r11,0(r11) # get rowBytes into r11 subi rdx,rdx,4 # subtract 4 from dx -> don't have to sub from dst1/dst2 lwz r10,gDrawStart[TC](RTOC) # get ptr to drawStart in r10 add rDStrd,rDStrd,r11 # add rowBytes to -width lwz r10,0(r10) # get drawStart in r10 mullw rDst1Ptr,rdy,r11 # dst1 = dy * rowBytes add rDStrd,rDStrd,rDStrd # multiply dstride by 2 add rDst1Ptr,rDst1Ptr,rDst1Ptr # dst1 = dy * rowBytes * 2 add rdx,rdx,rdx # dx *= 2 add rDst1Ptr,rDst1Ptr,r10 # dst1 = dst1 + gDrawStart subi rWidth,rWidth,1 # subtract one from width add rDst1Ptr,rDst1Ptr,rdx # dst1 = dst1 + dx subi rSrcPtr,rSrcPtr,4 # subtract 4 from src add rDst2Ptr,rDst1Ptr,r11 # point dst2 to one row farther BlitLargeAlignY: # y count is in r7 lwzu r10,4(rSrcPtr) # load 4 pixels into r10 mr r0,r10 # put copy in r0 mr r11,r10 # and in r11 inslwi r0,r10,16,8 # copy upper 16 bits to middle of r0 insrwi r11,r10,16,8 # copy lower 16 bits to middle of r11 rlwimi r0,r10,16,24,31 # get remaining bits into r0 stw r0,-8(SP) # store upper 4 pixels into part of double rlwimi r11,r10,16,0,7 # get remaining bits into r11 stw r11,-4(SP) # store lower 4 pixels into part of double mtctr rWidth # copy width into counter lfd fpTemp,-8(SP) # load double into fpTemp BlitLargeAlignX: # x count is in ctr lwzu r10,4(rSrcPtr) # load 4 pixels into r10 stfdu fpTemp,8(rDst1Ptr) # store a double from before mr r0,r10 # put copy in r0 mr r11,r10 # and in r11 inslwi r0,r10,16,8 # copy upper 16 bits to middle of r0 insrwi r11,r10,16,8 # copy lower 16 bits to middle of r11 rlwimi r0,r10,16,24,31 # get remaining bits into r0 stw r0,-8(SP) # store upper 4 pixels into part of double rlwimi r11,r10,16,0,7 # get remaining bits into r11 stw r11,-4(SP) # store lower 4 pixels into part of double stfdu fpTemp,8(rDst2Ptr) # store a double from before lfd fpTemp,-8(SP) # load double into fpTemp bdnz+ BlitLargeAlignX # loop over all x stfdu fpTemp,8(rDst1Ptr) # store a double from before subic. rHeight,rHeight,1 # decrement height add rSrcPtr,rSrcPtr,rSStrd # point to start of next source row add rDst1Ptr,rDst1Ptr,rDStrd # point to start of first dest row stfdu fp0,8(r4) # store final double from before add rDst2Ptr,rDst2Ptr,rDStrd # point to start of second dest row bne+ BlitLargeAlignY # loop over all y blr # return --