Slick Forums
http://slick.ninjacave.com/forum/

Rendering is extremely slow
http://slick.ninjacave.com/forum/viewtopic.php?f=3&t=8449
Page 1 of 1

Author:  JayanWarden [ Fri Dec 15, 2017 2:18 pm ]
Post subject:  Rendering is extremely slow

Hello everyone,

I am trying out GPU accelerated rendering and Slick for the first time and I am doing some experiments right now.

I am currently trying to render a grid of 512x512 tiles, each with 32x32 pixels on a screen with 1280x720 resolution.
I am not doing any visibility checks, so every tile gets drawn.

The empty screen gives me about 2k FPS.
When I add the 512x512 tiles, the FPS drop to just 5...
At 32 x 32 tiles, the FPS hovers at around 45-50.
I have seen people in the forum who say that they get solid framerates with hundreds of thousands of sprites...

What I was thinking of was a bottleneck in the crossthread communication.
I have a bit of experience with threading in java, so I have the logic updates happening in a separate thread. For now this thread is simply adding grass tiles in a grid to the scene.

At first I thought that my locking of the required lists is slowing down the rendering, but I ruled that out when I applied "batch fetching" of all drawable entities.
Attached you will find my code for rendering and the loops... Excuse any mistakes I am doing, I have literally never done any graphical stuff before, horrible coding scemes aside.

The Window class (aka. the OGL Thread):
Code:
public class Window extends BasicGame {

   private Core core;
   
   private Queue<ImageRequest> imageRequestQueue = new LinkedBlockingQueue<ImageRequest>();
   private List<Entity> pendingQueue = new ArrayList<Entity>();

   public Window(String title, Core core) {
      super(title);
      this.core = core;
   }

   @Override
   public void render(GameContainer arg0, Graphics arg1) throws SlickException {
     core.textureLoader.start();
    while (true)
    {
      pendingQueue.clear();
      boolean success = core.getNextEntity(pendingQueue, 4086);
      if ( !success )
      {
        break;
      }
      else
      {
        for(Entity e : pendingQueue) {
          e.draw(arg0, arg1);
        }
      }
    }
    core.textureLoader.stop();
   }

   @Override
   public void init(GameContainer arg0) throws SlickException {
      Thread oThread = new Thread(core);
      oThread.start();
   }

   @Override
   public void update(GameContainer arg0, int arg1) throws SlickException {
     checkForImageRequest();
   }
   
   private void checkForImageRequest() {
     if(imageRequestQueue.size() >= 1) {
       ImageRequest r = imageRequestQueue.poll();
       try
      {
        Image o = new Image(r.getStrPath());
        r.setoImage(o);
        r.setFinished(true);
      }
      catch (SlickException e)
      {
        e.printStackTrace();
      }
     }
   }
   
   public void putImageRequest(ImageRequest r) {
     imageRequestQueue.offer(r);
   }

}


The main draing code is called from every Entity e that implements Entity:
Code:
public class Grass implements Entity {

   private Image texture;
   private int x, y, width, height;

   public Grass(int x, int y, int width, int height, Core core) {
      this.x = x;
      this.y = y;
      this.width = width;
      this.height = height;
      init(core);
   }

   private void init(Core core) {
      texture = core.textureLoader.getTexture("textures/test/simplegrass.png");
   }

   @Override
   public void update() {
      // TODO Auto-generated method stub

   }

   @Override
   public void draw(GameContainer gameContainer, Graphics g) {
      texture.draw(x, y);
   }

}


Above you have seen the line
Code:
core.textureLoader.start()
.
That refers to the following class:
Code:
public class TextureLoader
{

  private Window context;

  private List<Image> aTextures = new ArrayList<Image>();
  private Map<String, Integer> mPathToIndex = new HashMap<String, Integer>();

  public TextureLoader(Window window)
  {
    context = window;
  }

  // TODO: Move image loading to init() of the Window Thread!
  // alle Bilder müssen im Window-Thread geladen werden!!!
  public Image getTexture(String strPath)
  {
    Integer lookup = mPathToIndex.get(strPath);
    if ( lookup == null )
    {
      ImageRequest r = new ImageRequest();
      r.setStrPath(strPath);
      context.putImageRequest(r);
      int counter = 0;
      while (!r.finished && counter <= 2000)
      {
        try
        {
          Thread.sleep(1);
        }
        catch (InterruptedException e)
        {
          e.printStackTrace();
        }
        counter++;
      }
      Image o = r.getoImage();
      if ( o != null )
      {
        aTextures.add(o);
        mPathToIndex.put(strPath, aTextures.size() - 1);
      }
      return o;
    }
    else
    {
      return aTextures.get(lookup);
    }
  }

  public void start() {
    for(Image o : aTextures) {
      o.startUse();
    }
  }
 
  public void stop() {
    for(Image o : aTextures) {
      o.endUse();
    }
  }
 
}


And finally here is the code in the Core class that handles the fetch for every drawable entity:
Code:
public boolean getNextEntity(List<Entity> cache, int toCache) {
      synchronized (aEntities) {
        int iCounter = 0;
         while(entityListCounter < aEntities.size() && iCounter < toCache) {
           cache.add(aEntities.get(entityListCounter));
            entityListCounter++;
            iCounter++;
         }
         if(iCounter >= 1) {
           return true;
         }
         else {
           entityListCounter = 0;
           return false;
         }
      }
   }

Page 1 of 1 All times are UTC
Powered by phpBB® Forum Software © phpBB Group
http://www.phpbb.com/