Skip to content

Commit

Permalink
Libretro: Use a byte image type for the canvas image
Browse files Browse the repository at this point in the history
This allows us to get the databuffer directly in byte[] form,
which means that manipulations can be done directly to it while
skipping costly calls to BufferedImage.getRGB().

In general, doesn't make much of a difference, although jBenchmark
reports 8% higher performance on average (9061 vs. 8376, i5-8250U)

At least it's closer to the standalone jar now, which scores an
average of about 9826 points in the same test platform. There's always
going to be an overhead due to how the libretro interface works though.
  • Loading branch information
AShiningRay committed Oct 6, 2024
1 parent 35bec88 commit 0bb967e
Showing 1 changed file with 24 additions and 15 deletions.
39 changes: 24 additions & 15 deletions src/org/recompile/freej2me/Libretro.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.awt.Canvas;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;

import java.util.Timer;
import java.util.TimerTask;
Expand Down Expand Up @@ -64,6 +65,7 @@ public class Libretro
private boolean[] pressedKeys = new boolean[128];

private byte[] frameBuffer = new byte[800*800*3];
private byte[] RGBframeBuffer = new byte[800*800*3];
private byte[] frameHeader = new byte[]{(byte)0xFE, 0, 0, 0, 0, 0};

private int mousex;
Expand Down Expand Up @@ -143,7 +145,7 @@ public Libretro(String args[])

/* Once it finishes parsing all arguments, it's time to set up freej2me-lr */

surface = new BufferedImage(lcdWidth, lcdHeight, BufferedImage.TYPE_INT_ARGB); // libretro display
surface = new BufferedImage(lcdWidth, lcdHeight, BufferedImage.TYPE_3BYTE_BGR); // libretro display
gc = (Graphics2D)surface.getGraphics();

Mobile.setPlatform(new MobilePlatform(lcdWidth, lcdHeight));
Expand Down Expand Up @@ -411,30 +413,37 @@ public void run()
break;

case 15:
// Send Frame Libretro //
/* Send Frame to Libretro */
try
{
final int[] data;

data = surface.getRGB(0, 0, lcdWidth, lcdHeight, null, 0, lcdWidth);

final int bufferLength = data.length*3;
int cb = 0;
for(int i=0; i<data.length; i++)
frameBuffer = ((DataBufferByte) surface.getRaster().getDataBuffer()).getData();

final int bufferLength = frameBuffer.length;

/*
* Convert BGR into RGB. Has a negligible performance impact compared to not doing this at all
* and sending the BGR array straight to libretro... and is faster than using getRGB().
*
* Copying from the original BGR array to a separate RGB array uses a bit more memory, but
* works correctly compared to just swapping the channels on the orignal array, where they
* still unknowingly end up incorrect from time to time. Runtime performance is pretty much
* the same for both methods.
*/
for(int i=0; i<bufferLength; i+=3)
{
frameBuffer[cb] = (byte)((data[i]>>16)&0xFF);
frameBuffer[cb+1] = (byte)((data[i]>>8)&0xFF);
frameBuffer[cb+2] = (byte)((data[i])&0xFF);
cb+=3;
RGBframeBuffer[i] = frameBuffer[i+2]; // [R]GB = BG[R]
RGBframeBuffer[i+1] = frameBuffer[i+1];
RGBframeBuffer[i+2] = frameBuffer[i]; // RG[B] = [B]GR
}

//frameHeader[0] = (byte)0xFE;
frameHeader[1] = (byte)((lcdWidth>>8)&0xFF);
frameHeader[2] = (byte)((lcdWidth)&0xFF);
frameHeader[3] = (byte)((lcdHeight>>8)&0xFF);
frameHeader[4] = (byte)((lcdHeight)&0xFF);

System.out.write(frameHeader, 0, 6);
System.out.write(frameBuffer, 0, bufferLength);
System.out.write(RGBframeBuffer, 0, bufferLength);
System.out.flush();
}
catch (Exception e)
Expand Down Expand Up @@ -499,7 +508,7 @@ private void settingsChanged()
lcdWidth = w;
lcdHeight = h;
Mobile.getPlatform().resizeLCD(w, h);
surface = new BufferedImage(lcdWidth, lcdHeight, BufferedImage.TYPE_INT_ARGB); // libretro display
surface = new BufferedImage(lcdWidth, lcdHeight, BufferedImage.TYPE_3BYTE_BGR); // libretro display
gc = (Graphics2D)surface.getGraphics();
}

Expand Down

0 comments on commit 0bb967e

Please sign in to comment.