Pixmap to Image: resource usage

BlitzMax Forums/BlitzMax Programming/Pixmap to Image: resource usage

Rozek(Posted 2010) [#1]
Hello!

Whenever I convert a pixmap to an image or unlock a previously locked dynamic image, I face the problem that

- this operation is incredible slow and
- the process is leaking memory

Is there anything I can do in order to avoid the memory leak (and reduce the processor requirements)?

Thanks in advance for any hint!


ima747(Posted 2010) [#2]
What are you doing to convert pixmap to image exactly? Can you make an example?


Rozek(Posted 2010) [#3]
Examples
lockImage(anImage)
...(use Cairo to draw on the image)
unlockImage(anImage)

or
...(use Cairo to draw on a pixmap)
anImage = loadImage(aPixmap)

It's NOT Cairo, which causes the problems, but "unlockImage" or "loadImage"


ima747(Posted 2010) [#4]
Hmm I'm unfamiliar with Cairo so I'm afraid this is as far as I can help in that regard. What happens if you build your image off a copy of the pixmap instead of the actual pixmap from cairo?


Rozek(Posted 2010) [#5]
Well,

meanwhile, I got rid of the memory leak by more aggressive GLTexture deletion (see at the end of http://www.blitzmax.com/Community/posts.php?topic=89912). My Cairo drawing sequence works as follows

- Pixmap = createPixmap(320,480,PF_BGRA8888) <<< is done once, then cached
- Surface = TCairoImageSurface.CreateFromPixmap(Pixmap) <<< is done once, then cached
- Cairo = TCairo.create(Surface) <<< is done once, then cached

what's done repeatedly is

- Cairo.createContext()
- ... draw something
- Cairo.destroy()
- Image = loadImage(self.Pixmap)

The image is then actually drawn on screen.

This approach is performing awfully (it's great without "loadImage", but then nothing is shown on the screen) It's definitely the "image" step which costs a lot of performance...


ima747(Posted 2010) [#6]
just out of curiosity, what happens if you user DrawPixmap instead of DrawImage? still massively slow (would imply to me it's the access to the pixmap itself) or speedyish (I believe drawpixmap is much slower than drawimage, but haven't ever really bothered to test, so it shouldn't be as fast as a timage, but it shouldn't be MASSIVELY slow...).

what happens if you do something along these lines
...
Cairo.destroy()
local tempPixm:TPixmap = self.Pixmap.Copy() ' see if this line is crazy slow
Image = loadImage(tempPixm) ' or maybe it's slow here



Rozek(Posted 2010) [#7]
Logan,

using drawPixmap is as slow as using loadImage/drawImage.

Copying the Pixmap does not cost much, drawing an Image is quite cheap as well - thus, it's definitely the "loadImage" step (in my understanding, "drawPixmap" internally also generates an Image)


Brucey(Posted 2010) [#8]
Drawpixmap on GL is heavily driver dependent. There are much better ways to do the equivalent than those particular GL calls used.

Drawimage should be relatively quick. It depends how big your pixmap data is (if you are refreshing the texture every draw)


Rozek(Posted 2010) [#9]
Brucey,

in my case, the Image is 480x320x4 bytes = 614400kB or 153600 32bit words. And, yes, I might have to refresh the Image quite often (up to 30 times/sec) = 18.4 MB/sec

What about the performance of "loadImage"? Do you expect loadImage/drawImage to perform better than drawPixmap?


Rozek(Posted 2010) [#10]
Good morning!

I still suffer from the poor performance of my pixmap/image drawing...

Is there any recommendation for the Pixmap type on an Intel-based system? Currently, I am using
Pixmap = createPixmap(320,480,PF_BGRA8888)
which works, but slowly. If I try
Pixmap = createPixmap(320,480,PF_RGBA8888)
my application runs much(!) faster...but either the Cairo drawing sequence or the loadImage/drawImage sequence produces no output (have not yet checked where the problem is). The same applies to "PF_STDFORMAT".

Are there any recommendations?


Tommo(Posted 2010) [#11]
LoadImage will automatically convert input pixmap into PF_RGBA8888, and do some extra things over that pixmap(like make texture 2-power sized + smear its edges, build mipmaps if MIPMAPIMAGE flag is set), then upload it to GL Texture. It will cost quite a while if it has to do all those process jobs.


Rozek(Posted 2010) [#12]
Tommo,

thanks for the explanation of "loadImage" - it gives me some more ideas to experiment with!

Are you certain about the format (PF_RGBA8888)? Because, if I prepare the Pixmap (and use the same format) everything runs much faster - but produces no output! But, well, perhaps I have to check if the "no output" phenomena stems from Cairo...

EDIT: yes, you can be certain - disabling the Cairo drawing stuff, changing from PF_BGRA8888 to PF_RGBA8888 makes my program 3(three!) times faster!!!! Unfortunately, however, Cairo then produces no output any longer...will have to ask Brucey what I can do next

EDIT: meanwhile I experimented with two pixmaps: PF_BGRA8888 for Cairo and PF_RGBA8888 for displaying (with "convertPixmap" in between) - but ended up with the same poor performance than before :-(

EDIT: I even wrote my own conversion routine but could speed it up only slightly - thus, it's definitely the format conversion which performs so poorly!

For those interested in my pixmap format conversion (from PF_BGRA8888 to PF_RGBA8888 or vice-versa), here is my code:
local i:int
local Src:int ptr = int ptr(PixmapPixelPtr(SrcMap))
local Dst:int ptr = int ptr(PixmapPixelPtr(DstMap))
local Pixel:int
for i = 0 to 320*480-1
  Pixel = Src[i]
  Dst[i] = (Pixel & $FF00FF00) | ((Pixel & $00FF0000) shr 16) | ((Pixel & $000000FF) shl 16)
next
Both bitmaps have the size 320x480 pixels in this case. The "trick" is using "int ptr"s and doing some bit masking and shifting. If you access byte by byte you end up with the same performance as the built-in conversion routine (because the internal conversion routine uses byte-wise access)

EDIT: another note: of course, you could even do the format conversion "in-situ" (i.e. using the same pixmap as Src and Dst, but "loadImage" would still assume the old (and slow) pixmap format and convert the pixmap again - unless you find a way to change the Pixmap format setting "on-the-fly" to the one needed for Cairo or loadImage, resp.

EDIT: strange...changing an pixmap#s format is actually quite simple: just access the "format" field of the pixmap. Trying so (and converting the pixmap "in-situ"), however, ended up with even (significantly!) worse performance than before (i.e. when I used two pixmaps). I would have assumed a slightly better performance, though

Nevertheless: thanks a lot for your hint!


Rozek(Posted 2010) [#13]
Hmmm,

it seems as if I would have to live with the necessary conversion from BGRA to RGBA (damn...I hate wasting processor cycles!)

Does anybody assume that or has an idea one could speed up the conversion somehow? Could C be somewhat faster? Or the use of assembler with special Intel CPU commands? Or even with the benefit of OpenGL?

Without that horrible conversion my program runs three times faster!!!!!


Rozek(Posted 2010) [#14]
Ok, forget everything!

Just for curiosity, I recompiled my application without debugging support...and it became so incredibly must faster (factor 6) that it's no longer necessary to worry about performance enhancements of the conversion step!

I may probably check if any of the optimizations I made before might be dropped, but now my program is running as fast as I would like it to run!

EDIT: my conversion routine still gives a slight performance gain (18% CPU usage with "convertPixmap" vs. 15% CPU usage with my versoin) but this might not be worth using it