Speed boost DrawPixmap

BlitzMax Forums/BlitzMax Module Tweaks/Speed boost DrawPixmap

remz(Posted 2006) [#1]
Hey everyone,
I have created a way to get a good 200% speed increase in DrawPixmap under opengl. If you take a look at its current implementation:
	Method DrawPixmap( p:TPixmap,x,y )
		Local blend=state_blend
		DisableTex
		SetBlend SOLIDBLEND
		
		Local t:TPixmap=YFlipPixmap(p)
		If t.format<>PF_RGBA8888 t=ConvertPixmap( t,PF_RGBA8888 )
		glRasterPos2i 0,0
		glBitmap 0,0,0,0,x,-y-t.height,Null
		glDrawPixels t.width,t.height,GL_RGBA,GL_UNSIGNED_BYTE,t.pixels
		
		SetBlend blend
	End Method

You can see two important things going on:
- It will always YFLIP any pixmap you draw -> this will also create a duplicate pixmap in memory, copy your pixmap while yflipping it.
- It might also convert if your pixmap was not in PF_RGBA. This would mean another full size duplicate pixmap.

I have created a new method that I called: FastDrawPixmap that also supports scaling your pixmap in realtime (instead of having to use resizepixmap).
Here's the code:
	Method FastDrawPixmap( p:TPixmap,x,y,scalex#, scaley# )
		Local blend=state_blend
		DisableTex
		SetBlend SOLIDBLEND
		
		Local t:TPixmap=p
		If t.format<>PF_RGBA8888 t=ConvertPixmap(p, PF_RGBA8888 )
		glpixelzoom scalex#,-scaley#
		glRasterPos2i 0,0
		glBitmap 0,0,0,0,x,-y,Null
		glPixelStorei GL_UNPACK_ROW_LENGTH, p.pitch Shr 2
		glDrawPixels p.width, p.height, GL_RGBA, GL_UNSIGNED_BYTE, p.pixels
		
		SetBlend blend
	End Method

I removed the YFlip call by making glPixelStore supports pitch. Also with glPixelZoom with a negative y scale, the image will be drawn correctly. Scaling is supported and is super fast.
Note that I didn't remove the ConvertPixmap call, so whenever possible, keep your pixmaps in PF_RGBA format so they won't get converted every frame.

Here's some speed info from my iBook:
Time to draw 50 times a 512x384 pixmap using DrawPixmap: 505 msec
Same thing but if pixmap wasn't in PF_RGBA format: 778 msec

Now the same pixmap drawn with FastDrawPixmap: 269 msec

Another important speed tip:
If you draw a pixmap bigger than the screen, you should always use a PixmapWindow: you'll get a major speed boost without requiring additionnal memory.


Boiled Sweets(Posted 2006) [#2]
BRL?

Whould this be included in the official build?


degac(Posted 2006) [#3]
Many thanks for the tip! I implent this on the Mac version of my game!


ImaginaryHuman(Posted 2006) [#4]
You don't really have to do a ConvertPixmap at all, OpenGL is quite capable of reading different input formats.

Instead of GL_RGBA, just select the appropriate format to pass to it based on the current pixel format of the pixmap, eg...

Select t.Format
Case PF_RGBA8888 ReadFormat=GL_RBGA
Case PF_RGB888 ReadFormat=GL_RGB8
Case PF_A8 ReadFormat=GL_Alpha

etc... if you look at the code that converts a pixmap into an Image, you will find the conversion you need to transfer any format pixmap to the graphics card.

That should cut out the convert altogether.

What is that glBitmap() doing in there?


remz(Posted 2006) [#5]
It might be worth giving it a try! Saving this extra byte per pixel could be great. I'll try it later on. Thanks for the tip!

glBitmap, for some obscure reason I haven't deeply investigated, makes glDrawPixels clip correctly. If you remove it, the image will not get drawn at all if any part of it goes outside the viewport. Very strange.


xlsior(Posted 2006) [#6]
Very interesting.


remz(Posted 2006) [#7]
AngelDaniel, I tried with PF_RGB888 -> GL_RGB, and it gave an additionnal 17% speed increase! Along with saving the cost of the pixmap conversion.

Thanks for the tip!