With Java2D it's common to "pre-render" things to improve performance. In OpenGL, it's often more efficient to render the elements directly to the screen. Here are some considerations:
1.
To create an off screen image, we tell OpenGL to allocate a new texture. Since Slick ensures all textures are power-of-two-size (since older drivers may not support NPOT), this means that an offscreen image the size of the window (e.g. 1920x1080) will be padded to 2048x2048. Likewise, a 300x65 image will be padded to 512x128. This could potentially be a lot of wasted space.
2.
One of the major causes of poor performance in 2D games is "texture thrashing." Let's say we load two PNG images with Slick -- both will be allocated to separate textures. Because of the way Slick uses OpenGL (i.e. "old school immediate mode"), we can only bind a single texture at a time. So, in order to render the two sprites one after another, OpenGL first needs to bind texture A, then draw it, then bind texture B, then draw it. The more textures we need to bind per frame, the more our game will slow down. This is why we tend to use sprite sheets and startUse/drawEmbedded/endUse -- it allows us to bind a
single texture per frame and re-use it for many images.
Minimizing texture thrashing is a very common way to optimize games/graphics. There are now extensions that allow for multi-texturing, but they may not be reliable for older platforms and Slick's codebase isn't really suitable for that kind of OpenGL usage.
So, if you were to create all of your "pre-rendered" images in the same texture, you would not lose much performance. But this brings me to my next point...
3.
You may run into a bottleneck eventually rendering many sprites, but chances are this bottleneck will lie with the GPU's "fill rate" limitations. This is simply the number of pixels you can render every frame. If you are using full-screen resolution and drawing each tile many times (e.g. for lighting effects), you may very quickly run into fill rate limitations. Offscreen rendering will not improve your performance since you will still be drawing the same number of pixels (or more).
4.
OpenGL is fast. Very fast. If you're using drawEmbedded, you can push tens of thousands of small sprites per frame. Most games will never have that much going on at once; and often you will be using simple culling (i.e. "not in view") to further improve your performance. So, really, you shouldn't be using offscreen images unless absolutely necessary -- this all falls under "premature optimization."
Quote:
So if I understand the first post correctly, I shouldn't do this using Image.createOffScreenImage() and a subsequent getGraphics() because this triggers the memory leak, right?
The memory leak is not a huge deal; it only creates a single extra texture at instantiation (since you should never be creating a new image every frame). The problem arises when you use "new Image(int, int)" (which creates an OpenGL texture) and then "getGraphics" (which creates another OpenGL texture). The
solution is to use the utility method, like so, which will only create a total of one texture:
Code:
//instead of "new Image(512, 512)"
Image image = Image.createOffscreenGraphics(512, 512);
imageGraphics = image.getGraphics();
Ideally Slick will be patched up so that "new Image(512, 512)" works without any issue; at which point the above utility method will be deprecated (but provide the exact same functionality). But this patch may not come for a while since it requires a pretty substantial change to Slick's codebase.
Regarding copyArea; that method never invokes getGraphics and so no extra textures are created. You don't need to use createOffscreenGraphics if you plan to use copyArea.
TL;DR - Don't bother with offscreen graphics unless you absolutely need to, since rendering to the screen is almost always a better option. If you really need to use offscreen images, then don't worry too much about the memory leak, it will hopefully be fixed at some point. If you want the best practice, for now you can use createOffscreenGraphics(..) instead of "new Image(w, h)".
EDIT:
Also regarding copyArea, it's there if you need it, but generally it's better to use offscreen graphics and render directly to them. Compare the following: (a) drawing to the screen, and then copying all of those pixels to an image, or (b) simply drawing to an image. (b) is faster since it skips the copying.