Help with my Render loop

Alright, so I wrote like three classes that I am uses to do my rendering in my game. For some reason, when I increase the tick rate of the thread ( increased tick = less sleep time ) the elapsed time of calling a single g.drawString() increases alot. I am thinking even if I have a thread that sleeps for 1ms vs a thread that sleeps for 1000ms, the rendering the thread does should take the same amount of time. I will paste my three classes so you can understand.

Any help at all would be much appreciated

package qo.engine.util;

public abstract class GameThread implements Runnable
{
    //boolean for the infinate loop in run method
    protected boolean running;
    //the sleep time in milliseconds
    protected long desiredTickTime;

    public GameThread(String threadName, int tick, int priority)
    {
        //makes this a thread
        Thread t = new Thread(this, threadName);
        t.setPriority(priority);

        //set the sleepTime with a given tick;
        desiredTickTime = (1000 / tick) * 1000000;

        //starts thread (run will be called first after thread starts)
        t.start();
    }

    //Called when this (a thread in general) is started
    //contains the code to make it continue to loop infinatly
    public void run()
    {
        running = true;
        long beforeTime, elapsedTime, tillTickMillis, tillTick;
        int tillTickNano;

        while (running)
        {

            //see how long it took to run the tick method
            beforeTime = System.nanoTime();
            tick();
            elapsedTime = System.nanoTime() - beforeTime;

            System.out.println(elapsedTime + " " + this.toString());
            
            //get the amount of time it should sleep for in nanos
            tillTick = desiredTickTime - elapsedTime;

            //checks if the clients computer is running too slow to afford
            //to sleep or not.  tillTick will be < 0 if their
            //computer took longer than desiredTickTime
            if (tillTick >= 0)
            {
                //convert to milliseconds
                tillTickMillis = (long)(tillTick / 1000000);

                //take out the millis, and return the left over nano
                tillTickNano = (int)(tillTick % 1000000);

                try
                {
                    Thread.sleep(tillTickMillis, (int)tillTickNano);
                }
                catch (InterruptedException ex)
                {
                }
            }
            else //computer took longer than desiredTickTime
            {
                System.out.println("Skipped a sleep in " + this.toString());
            }
        }
    }

    //stops the thread
    public void destroy()
    {
        running = false;
    }

    //Tick is called every time the thread awakes from the run function
    public abstract void tick();
}

package qo.engine.rendering;

import qo.engine.util.GameThread;
import java.awt.*;
import java.util.*;
import qo.engine.graphics.ScreenManager;

public abstract class RenderManager extends GameThread
{    
    protected static final int FONT_SIZE = 24;

    protected static final DisplayMode POSSIBLE_MODES[] = {
        new DisplayMode(800, 600, 32, 0),
        new DisplayMode(800, 600, 24, 0),
        new DisplayMode(800, 600, 16, 0),
        new DisplayMode(640, 480, 32, 0),
        new DisplayMode(640, 480, 24, 0),
        new DisplayMode(640, 480, 16, 0)
    };

    protected boolean initialized = false;
    protected ScreenManager screen;
    protected Window window;

    protected ArrayList<Object> entities;
    
    //screen.restoreScreen(); used for closing
    
    public RenderManager(String threadName, int TICK)
    {
        super(threadName, TICK, 8);

        screen = new ScreenManager();
        DisplayMode displayMode =
            screen.findFirstCompatibleMode(POSSIBLE_MODES);
        screen.setFullScreen(displayMode);

        window = screen.getFullScreenWindow();
        window.setFont(new Font("Dialog", Font.PLAIN, FONT_SIZE));
        window.setBackground(Color.blue);
        window.setForeground(Color.white);

        initialized = true;
    }

    public void tick()
    {
        if (!initialized)
            return;

        // draw the screen
        Graphics2D g = screen.getGraphics();
        //clears the screen
        g.fillRect(0,0, screen.getWidth(), screen.getHeight());//maybe use window.getHeight instead ?
        draw(g);        
        g.dispose();
        screen.update();
    }

    public void initEntities(ArrayList<Object> entities)
    {
        this.entities = entities;
    }

    public Window getWindow()
    {
        return window;
    }

    public ArrayList<Object> getEntities()
    {
        return entities;
    }
    
    //Draw everything in this function
    //Function passes the graphics, and every object in the game
    public abstract void draw(Graphics2D g);
}

package game;

import qo.engine.rendering.RenderManager;
import java.awt.*;
import java.util.*;

public class RenderProcessor extends RenderManager
{    
    public RenderProcessor(String threadName, int TICK)
    {
        super(threadName, TICK);
    }

    public void draw(Graphics2D g)
    {
        g.setColor(Color.BLACK);
        
        //g.draw((Rectangle)getEntities().get(0));
        g.drawString("hi", 10, 100);
    }
}

are you using active or passive rendering?

if passive, you may be staving the swing rendering thread when you increase your frame rate. I am not sure whether there are any blocking methods called internally when calling drawstring, but if there are then staving the swing thread could be causing these blocking calls to take longer…

but i could be talking a lot of crap :slight_smile:

Uhhh I forget the difference between active and passive =P. I found the problem seems to be in the BufferStrategy. Probably in the strategy.show(); when it is drawing. Is there a way to make my thread not call strategy.show(); if it has not already completed showing?

Also when i push the tick to 63,

GameMain:

RenderProcessor renderProcessor = new RenderProcessor(“Rendering”, 63); line 34

It causes the CPU usage to go straight up to like 50%, but on 62 it is fine.

I am going to continue posting stuff so anyone who tries to help me can know where to look.

it does look like you are using active rendering (i.e. using bufferstrategy )

normally one does not use threading for rendering and game loop but uses one single thread for both.

By being single threaded you can guarantee the .show() method is called in sequence not parallel.

I believe i have read somewhere that in fullscreen exclusive mode the update rate for page flipping is limited to the refresh rate of the screen… perhaps something similar is happening here?

For my own experience with framerate , it turned out that I was using too much the stdout printing.
so System.out.println(elapsedTime + " " + this.toString()); while in the render loop may hang up if another thread uses the stdout…

Also, you make conversion out of integers. Though int are smaller, nanotime will be more accurate if affected to a long variable…

What is more confusing, is that ms are 10^3 ns and not 10^6 as you wrote, didn’t you ? that would be the reason of wrong sleep time when you increase your ticktime : 63 ms are wrongly converted to 63 * 10^6 ns, that’s a 10^3 longer time (about 1 second, indeed).
::slight_smile: