Search code examples
androidimageemulation

Android - How can I draw frames pixel by pixel (for NES emulation) in android studio faster?


This is a NES emulator project I am working on. Every second I need to draw the screen around 60 times to get accurate emulation, which means, every second I have to draw at least 256 * 240 * 60 pixels. For drawing, I am using canvas. On which every frame, I am going through the data of 256 * 240 pixels and drawing them on screen. Unsurprisingly, it was terrible. My emulator draws less than a frame per second

public class GameCanvas extends View{
public void drawSprite(int x, int y, Olc2C02A.Sprite sprite, Canvas canvas){
        for (int ir = 0; ir < sprite.height; ir++){
            for (int ic = 0; ic < sprite.width; ic++){
                Olc2C02A.Pixel p = sprite.getPixel(ic, ir);
                if (p.a != 0){
                    int pr = p.r, pg = p.g, pb = p.b, pa = p.a;
                    painter.setColor(Color.argb(pa, pr, pg, pb));
                    canvas.drawPoint((x + ic), (y + ir), painter);
                }
            }
        }
    }

@Override
protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.parseColor("#000000"));
        drawSprite(0, 0, this.gameScreen, canvas);
    }

}

The above code is a slightly simplified version of my code. In this code I am only drawing pixel by pixel disregarding the actual size of each pixels that would be needed if I considered resizing the frame according to the size of the screen I am running this app on. The sprite is a 256x240 sized array of Pixel objects. Which are custom classes I made to store the color value of each pixel. Therefore, unfortunately, just slight performance boost isn't enough for the emulator. I need to draw at least 30 frames per second if I want my emulator to be functional. What other alternatives can I use for this task that can fit in my android studio project.


Solution

  • Nobody draws pixels. All the games use OpenGL.

    Even the GUI of an Android app (buttons/edits/pictures/...) is drawn using OpenGL.

    When you draw pixel by pixel you are using the CPU to render the graphics. You are not using the GPU (graphics card) at all. So this will never work.

    You have to use GLSurfaceView. You have to use OpenGL functions defined in GLES20, GLES30, ...

    See Android OpenGL guide.

    The NES graphics is based on quadratic stripes (textures). These stripes are loaded into the NES graphics card and can then be resized, rotated and transformed by the CPU inside the GPU. So the CPU can send a command to the GPU: "Please rotate stripe by 90 degrees" (for example). So the CPU never draws pixels but instead sends commands to the GPU.

    On Android you send such commands to the GPU using OpenGL. This makes it fast because the graphics calculation is out sourced to the GPU.

    Also note that DirectX is the Microsoft equivalent of OpenGL.

    I also want to add that when performing CPU intensive tasks it's better to use C/C++/Rust instead of Java/Kotlin. Because the first runs on the CPU directly while the latter doesn't. This saves battery and is faster. See JNI tips.