2

I'm having a really big problem with libgdx. I wrote a little CHIP8 emulator to learn how to use libgdx, but I'm still trying to figure out how to make it go faster. I use a Pixmap to update the screen and then render it to a Texture, but this seems not to be the best solution, because it runs very slowly. Here's the code:

package com.eud0x.chip8gdx;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.concurrent.TimeUnit;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Pixmap.Format;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.TextureData;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;

public class Chip8 extends ApplicationAdapter implements InputProcessor {
    SpriteBatch batch;
    Pixmap screen;
    Texture surface;
    C8Emulator chip8;

    @Override
    public void create () {
        batch = new SpriteBatch();
        chip8 = new C8Emulator();
        screen = new Pixmap(512, 256, Format.RGB888);
        chip8.initEmulator();
        try {
            chip8.loadGame("/home/antonio/PONG");
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        surface = new Texture(screen);
        Gdx.input.setInputProcessor(this);
    }

    @Override
    public void render () {
        chip8.emulateCycle();
        if ( chip8.drawflag != 0 ) {
            updateTexture();
            chip8.drawflag = 0;
        }
        batch.begin();
        batch.draw(surface, 0, 0);
        batch.end();
    }
    @Override
    public void dispose() {
        batch.dispose();
        screen.dispose();
        surface.dispose();
    }
    public void updateTexture() {
        screen.setColor(0,0,0,0);
        screen.fill();
        for ( int y = 0; y < 32; y++) {
            for ( int x = 0; x < 64; x++ ) {
                if (chip8.display[y][x] != 0) {
                    for (int cx = x*8; cx < x*8 + 8; cx++) {
                        for ( int cy = y*8; cy < y*8 + 8; cy++) {
                            screen.drawPixel(cx, cy, Color.WHITE.toIntBits());
                        }
                    }
                } 
            }
        }
        surface.draw(screen, 0, 0);
    }
@Override
    public boolean keyDown(int keycode) {
        switch (keycode) {
        case Keys.NUM_1:
            chip8.keyDown(0x1);
            break;
        case Keys.NUM_2:
            chip8.keyDown(0x2);
            break;
        case Keys.NUM_3:
            chip8.keyDown(0x3);
            break;
        case Keys.NUM_4:
            chip8.keyDown(0xC);
            break;
        case Keys.Q:
            chip8.keyDown(0x4);
            break;
        case Keys.W:
            chip8.keyDown(0x5);
            break;
        case Keys.E:
            chip8.keyDown(0x6);
            break;
        case Keys.R:
            chip8.keyDown(0xD);
            break;
        case Keys.A:
            chip8.keyDown(0x7);
            break;
        case Keys.S:
            chip8.keyDown(0x8);
            break;
        case Keys.D:
            chip8.keyDown(0x9);
            break;
        case Keys.F:
            chip8.keyDown(0xE);
            break;
        case Keys.Z:
            chip8.keyDown(0xA);
            break;
        case Keys.X:
            chip8.keyDown(0x0);
            break;
        case Keys.C:
            chip8.keyDown(0xB);
            break;
        case Keys.V:
            chip8.keyDown(0xF);
            break;
        default:
            break;  
        }
        return true;
    }

    @Override
    public boolean keyUp(int keycode) {
        switch (keycode) {
        case Keys.NUM_1:
            chip8.keyUp(0x1);
            break;
        case Keys.NUM_2:
            chip8.keyUp(0x2);
            break;
        case Keys.NUM_3:
            chip8.keyUp(0x3);
            break;
        case Keys.NUM_4:
            chip8.keyUp(0xC);
            break;
        case Keys.Q:
            chip8.keyUp(0x4);
            break;
        case Keys.W:
            chip8.keyUp(0x5);
            break;
        case Keys.E:
            chip8.keyUp(0x6);
            break;
        case Keys.R:
            chip8.keyUp(0xD);
            break;
        case Keys.A:
            chip8.keyUp(0x7);
            break;
        case Keys.S:
            chip8.keyUp(0x8);
            break;
        case Keys.D:
            chip8.keyUp(0x9);
            break;
        case Keys.F:
            chip8.keyUp(0xE);
            break;
        case Keys.Z:
            chip8.keyUp(0xA);
            break;
        case Keys.X:
            chip8.keyUp(0x0);
            break;
        case Keys.C:
            chip8.keyUp(0xB);
            break;
        case Keys.V:
            chip8.keyUp(0xF);
            break;
        default:
            break;  
        }
        return true;
    }

    @Override
    public boolean keyTyped(char character) {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean touchDown(int screenX, int screenY, int pointer, int button) {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean touchUp(int screenX, int screenY, int pointer, int button) {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean touchDragged(int screenX, int screenY, int pointer) {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean mouseMoved(int screenX, int screenY) {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean scrolled(int amount) {
        // TODO Auto-generated method stub
        return false;
    }
}

Does anyone know how to make it faster?

hayw1re
  • 36
  • 2

1 Answers1

0

It would be faster to draw individual pixels as sprites directly to the screen with SpriteBatch. You have at most 2048 pixels to draw at a time, and usually far less. 2048 sprites per frame is no problem for a desktop computer, but could potentially be an issue with older phones, but unless the loaded game draws a lot of white, I think it will be fine.

SpriteBatch batch;
Texture pixelSprite;
C8Emulator chip8;

@Override
public void create () {
    batch = new SpriteBatch();
    chip8 = new C8Emulator();

    Pixmap textureSource = new Pixmap(1, 1, Format.RGB8888);
    textureSource.setColor(1, 1, 1, 1);
    textureSource.fill();
    pixelSprite = new Texture(textureSource);
    textureSource.dispose();

    chip8.initEmulator();
    try {
        chip8.loadGame("/home/antonio/PONG");
    } catch (FileNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    Gdx.input.setInputProcessor(this);
}

@Override
public void render () {
    chip8.emulateCycle();

    //don't use draw flags. OpenGL redraws everything every frame
    Gdx.gl.glClearColor(0, 0, 0, 1);
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

    batch.begin();
    for ( int y = 0; y < 32; y++) {
        for ( int x = 0; x < 64; x++ ) {
            if (chip8.display[y][x] != 0) {
                spriteBatch.draw(pixelSprite, x*8, y*8, 8, 8);
            } 
        }
    }
    batch.end();
}

If you wanted to really optimize it, you could directly manipulate a Mesh object to draw points instead of sprites. This would cut the size of sprite vertex data by something like 80-90% such that drawing a pure white screen would be very fast even on old phones. But this is probably not necessary. You will probably instead need to throttle your simulation to slow it down.

Tenfour04
  • 83,111
  • 11
  • 94
  • 154