#1793 gfx::Image - A trap for young players

SlimerDude Mon 27 Feb 2012

It'd be beneficial if the Image Docs were updated with the addendum:

Ensure you call fwt::Desktop#disposeImage() to dispose of allocated System resources. 
Simply leaving Images to go out of scope will result in memory leaks.

I guess the same should be written about Font and Color also.

Double buffering in my app was eating up about 1 Gb per minute! Eeek!

This also leads me to ask about the tight coupling between gfx::Image and fwt::Desktop... is not possible to have Image and Desktop in the same pod? Or maybe a means to dispose of the Image in the gfx pod?

Akcelisto Mon 27 Feb 2012

?!?! Yes, it's trap. I think that gfx::Image is like BufferedImage and stores in heap. And disposes by gc.

But now I confused. Why fwt::Desktop#disposeImage? When it need called? Give me example, plz.

SlimerDude Mon 27 Feb 2012

Sure, my one and only use case looks like this:

class PitCanvas : Canvas {

  override Void onPaint(Graphics g) {
    Image? buffer
    try {
      buffer = Image.makePainted(Size(500, 500)) |gfx| {
        ... draw stuff ...
      }

      x := (bounds.w - size) / 2
      y := (bounds.h - size) / 2

      clearScreen(g, x, y)    
      g.drawImage(buffer, x, y)

    } finally {
      if (buffer != null)
        Desktop.disposeImage(buffer)
    }
  }
}

as I say, I use it for double buffering so the screen updates don't flicker.

Steve.

brian Mon 27 Feb 2012

The way this stuff is designed is that gfx is designed to be independently used from fwt. Which makes sense if you consider we often wish to model concepts such as color, fonts, and images independent from a specific toolkit (for example if we wanted to create a css API).

Then the FWT maps those instances like Color, Font, and Image into SWT/OS resources as needed when you use them in a context such as FWT rendering. Only after they get used like this do they require disposing. And in general when you create colors, font, images you tend to reuse them over and over so dispose isn't needed. But if creating lots of any of these things, then you definitely want to explicitly dispose them to free up memory. Images especially since they can take up lots of memory.

This is sort of how dispose end up in Desktop. But I agree its not a very discoverable design. So I moved the dispose method directly into Image, Font, and Color and deprecated the Desktop versions. I have a bit of plumbing already to make that work, so seems like a much cleaner design.

as I say, I use it for double buffering so the screen updates don't flicker.

One trick which can really increase performance is to allocate your double buffer once and then reuse across all paints until you need a resize it. That avoids repetitive really big memory allocations.

Akcelisto Mon 27 Feb 2012

SWT have own double buffering. FWT no have it?

SlimerDude Mon 27 Feb 2012

Cheers Brain, I'll try the single allocation. (But for what it does, it's not so bad right now.)

SlimerDude Mon 27 Feb 2012

Ah yes, I remember now...

Other than Image#makePainted I couldn't find any other way to (re)draw an Image from a Graphics context. For unlike a Canvas, the Image doesn't seem to allow you to redraw its contents.

Have I missed any part of the gfx / fwt API or is constructing a new Image currently the only way to draw offscreen?

SlimerDude Mon 27 Feb 2012

Then again, the flicker (if I draw straight to the Canvas) does give it a bit a cool retro CRT feel!

go4 Tue 28 Feb 2012

Another design is to keep Image as mixin. so the implemention can hold a handle of native image. Avoid the images cache, and could dispose image by java garbage collector.

@SlimerDude: If you want more powerful graphics API. see: https://bitbucket.org/chunquedong/fan3d It support mutable image, affine transform, draw path...

Login or Signup to reply.