Mail Archives: djgpp/1997/01/06/19:20:41
Eric J. Korpela wrote:
>
> In article <01b9b9ca$9cccd040$aaf15ecf AT platko DOT ix DOT netcom DOT com>,
> Chuck Jarenski <3455245 AT popnet DOT ca DOT out DOT net> wrote:
> >I'm trying to convert the following code from More Tricks of the
> >Game-Programming Gurus into DJGPP. I'm having a problem getting the code
> >in the book to work in the
> >AT&T syntax. (Remember ScreenWidth is a 32bit int with the value of 640
> >and I am using near pointers with mem protection off.)
> >
> > void vputpixel(int x, int y, char color, char far *vscreen)
> > {
> > asm {
> > push es
> > mov ax,[y]
> > mov bx,320
> > mul bx
> > add ax,[x]
> > les di,[vscreen]
> > mov di,ax
> > mov al,color
> > stosb
> > pop es
> > }
> > }
>
> Here I go into tirade mode. Not directed at you, but more toward
> programming book writers in general. The big problem is that they
> make novices think that a compiler is incapable of optimizing something
> as simple as a putpixel routine. There is no reason to resort
> to inline assembly. The above would translate as....
>
> void vputpixel(int x, int y, char color, char *vscreen)
> {
> vscreen[y*320+x]=color;
> }
>
> Run GCC on that and look at the output. Compare it to the above. GCC's
> output is better! (Using mul to multiply by a constant! Get real!)
> "Tricks of the Game Programming Gurus," heh. More like "Tricks of the
> Writers Who Don't Know Anything About Programming."
>
> Exit Tirade mode....
>
> >My AT&T code:
> >
> > void PutPixel(char *Buf, int X, int Y, char Color)
> > {
> > /* Places a pixel on the buffer at a X,Y location */
> >
> > __asm__ __volatile__("
> > pushl %%es
> > movl %0 , %%eax\n
> > movl $_ScreenWidth, %%ebx\n
> > mull %%ebx\n
> > addl %1, %%eax\n
> > lesl %2, %%edi\n
> > movl %%eax, %%edi\n
> > movb %%al, %3\n
> > stosb\n
> > popl %%ss"
> > :
> > : "g" (Y), "g" (X), "g" (Buf), "g" (Color)
> > : "memory"
> > );
> > }
> >
>
> First hint, (as above) don't use assembly unless you have to. And for
> putpixel, you don't have to. The above would work just fine as
>
> Buf[Y*ScreenWidth+X]=Color;
>
> Second, that multiply is expensive. If you can replace it by a constant,
> do so. If you can't, you may want to define your graphics buffer as follows...
>
> typedef unsigned char pixel;
>
> typedef struct {
> int width,height;
> pixel **lines;
> } GBuf;
>
> And create a buffer as follows....
>
> GBuf *Create_GBuf(int width, int height)
> {
> int i;
> GBuf *Buf=(GBuf *)calloc(1,sizeof(GBuf)+height*sizeof(pixel *)+
> width*height*sizeof(pixel));
> if (Buf) {
> Buf->width=width;
> Buf->height=height;
> /* Warning, confusing pointer arithmetic. Look carefully.... */
> Buf->lines=Buf+1;
> Buf->lines[0]=Buf->lines+height;
> for (i=1;i<height;i++) {
> Buf->lines[i]=Buf->lines[i-1]+width;
> }
> }
> return (Buf);
> }
>
> Then the putpixel function becomes....
>
> void vputpixel(int x, int y, pixel color, GBuf *Buf)
> /* This compiles to 5 instructions under SPARC */
> {
> Buf->lines[y][x]=color;
> }
>
> Voila, no more multiply! (Also, the routine easily changes to support
> 16 or 32 bit color. Just change the pixel typedef.) (And it's portable!)
>
> Third hint. You are playing around with segment registers. Don't, unless
> it's absolutely necessary. And if you do need to, load the register from
> a dpmi or go32 variable like _go32_dos_ds or my_ds.
>
> Hope this helps.
>
> Eric
> --
> Eric Korpela | An object at rest can never be
> korpela AT ssl DOT berkeley DOT edu | stopped.
> <a href="http://www.cs.indiana.edu/finger/mofo.ssl.berkeley.edu/korpela/w">
> Click here for more info.</a>
You're right! The writers did this to make money and didn't fully
optimize their code. Take, for example, the vputpixel() function. A much
faster way to do this would be through shifting with >> or <<. E-mail me
if anyone wants the code for a FAST one.
Dan
- Raw text -