Slick Forums

Discuss the Slick 2D Library
It is currently Mon Nov 19, 2018 6:22 pm

All times are UTC




Post new topic Reply to topic  [ 1 post ] 
Author Message
PostPosted: Fri Dec 15, 2017 2:18 pm 
Offline

Joined: Fri Dec 15, 2017 1:06 pm
Posts: 1
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;
         }
      }
   }


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 1 post ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron
Powered by phpBB® Forum Software © phpBB Group