Cached Rendering (Tiled Map / Static Scene)

Any community contributions to libgdx go here! Some may get included in the core API when permission is granted.

Cached Rendering (Tiled Map / Static Scene)

Postby methius » Tue Aug 23, 2011 9:41 pm

Keywords:
- Static scene compilation / caching
- Performance boost on modest scene: 60-80% (Nexus One: 35fps to 56; PC 700fps to 1600fps)

Hi all,

We're hard at work on an upcoming game (hopefully release next week; Prototype Defense), and our main render coder Enno Ruijters coded a caching routine for our map renderer.
Because our scene is made up for a large part of static images (background tiles / bases / etc), we thought it would be increase performance if we first drew the full static scene, retrieved the drawn image, and from then on rendered the cached image, instead of redrawing the entire scene.
If the projection matrix or the scene changes, we force a redraw.

We would love to hear feedback on the routine!

First the background data class:
Code: Select all
 private class BackgroundData implements TextureData
    {
      /* To anyone thinking it's easier to use ShortBuffers because
       * all pixels are stored in 16-bit format: It's no faster, and
       * the endianness conversion might even make it slower (and
       * I couldn't find out how to do them correctly).
       */
      private ByteBuffer image = null, tmp = null;
      private int log2width, log2height, tmpSize;

      public void read()
      {
         /* If the screen size has increased, the buffer needs
          * to be bigger.
          */
         if ( (1 << log2width) < _screenWidth)
            image = null;
         if ( (1 << log2height) < _screenHeight)
            image = null;
         if (image == null) {
            int width = _screenWidth-1, height = _screenHeight-1;
            for (log2width = 0; width > 0; log2width++)
               width >>= 1;
            for (log2height = 0; height > 0; log2height++)
               height >>= 1;
            image = ByteBuffer.allocateDirect(1 << (log2width + log2height + 1));
         }

         if (tmp == null || _screenHeight * _screenWidth != tmpSize)
         {
            tmpSize = _screenWidth * _screenHeight;
            tmp = ByteBuffer.allocate(tmpSize * 2);
         }

         Gdx.gl.glPixelStorei(GL10.GL_PACK_ALIGNMENT, 2);
         Gdx.gl.glReadPixels(0, 0, _screenWidth, _screenHeight,
                             GL10.GL_RGB,
                             GL10.GL_UNSIGNED_SHORT_5_6_5,
                             tmp);

         /* Because we can only load textures that have
          * power-of-two sizes, we now need to pad each line
          * of the texture to be a power of two.
          */
         int lineWidth = 1 << log2width;
         /* First line of actual data */
         int firstLine = (1 << log2height) - _screenHeight;
         byte buffer[] = tmp.array();
         for (int i = firstLine; i < (1 << log2height); i++) {
            image.position(i << (log2width + 1));
            image.put(buffer, (i-firstLine) * _screenWidth * 2, _screenWidth * 2);
         }
         image.rewind();
      }

      public void load()
      {
         Gdx.gl.glPixelStorei(GL10.GL_UNPACK_ALIGNMENT, 2);
         Gdx.gl.glTexImage2D(GL10.GL_TEXTURE_2D, 0,
               GL10.GL_RGB, 1 << log2width,
               1 << log2height, 0, GL10.GL_RGB,
                         GL10.GL_UNSIGNED_SHORT_5_6_5, image);
      }

      public int getWidth()
      {
         return 1 << log2width;
      }

      public int getHeight()
      {
         return 1 << log2height;
      }
   }


The drawing routine:

Code: Select all
// Repaint all for when the scene changed
// Null if we are initialising / lost context / disabled background Caching
// mode == mouse movement mode (DRAG/ZOOM/ETC)
if (repaintAll || background == null || mode != NONE) {
            _spriteBatch.setProjectionMatrix(_projection);
            _spriteBatch.begin();
            repaintAll = false;
            drawStaticScene();
            if ((mode == NONE && !bgCacheDisabled)) { // We are no longer moving the mouse && want a background cache
               _spriteBatch.end();
               bgData.read();
               if (background != null)
                  background.dispose();
               background = new Texture(bgData);
               _spriteBatch.begin();
            } else {
               background = null;
            }
         } else { // We should be drawing the cached texture
            _spriteBatch.setProjectionMatrix(_normalProjection);
            _spriteBatch.begin();
            _spriteBatch.draw(background, 0, 0);
            _spriteBatch.end();
            _spriteBatch.setProjectionMatrix(_projection);
            _spriteBatch.begin();
         }

                     // Continue render code
methius
 
Posts: 1
Joined: Tue Aug 23, 2011 9:30 pm

Re: Cached Rendering (Tiled Map / Static Scene)

Postby NateS » Wed Aug 24, 2011 7:50 am

You can use GL2 and FBOs. See FrameBufferTest.
NateS
 
Posts: 1980
Joined: Fri Nov 12, 2010 11:08 am

Re: Cached Rendering (Tiled Map / Static Scene)

Postby Hyper » Fri Aug 26, 2011 7:54 am

Have you tried to use SpriteCache class? Is your caching algorithm faster?
Hyper
 
Posts: 9
Joined: Tue Aug 23, 2011 6:38 pm


Return to Libgdx Contributions

Who is online

Users browsing this forum: No registered users and 1 guest