Skip to content

Commit

Permalink
[EXPERIMENTAL] PlatformGraphics: Faster copyArea and flushGraphics
Browse files Browse the repository at this point in the history
Those are now using direct dataBuffer manipulation to write to
the screen, skipping overheads from temporary images and drawImage
calls where applicable. This also simplifies DirectGraphics'
getPixels(byte) operation by not needing to create an int array
with the canvas pixel data anymore.
  • Loading branch information
AShiningRay committed Dec 23, 2024
1 parent e2e44ef commit 5e51cfa
Showing 1 changed file with 35 additions and 23 deletions.
58 changes: 35 additions & 23 deletions src/org/recompile/mobile/PlatformGraphics.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public class PlatformGraphics extends javax.microedition.lcdui.Graphics implemen
{
protected BufferedImage canvas;
protected Graphics2D gc;
protected int[] canvasData;

protected Color awtColor;

Expand Down Expand Up @@ -72,6 +73,9 @@ public PlatformGraphics(PlatformImage image)
canvas = image.getCanvas();
gc = canvas.createGraphics();

canvasData = ((DataBufferInt) canvas.getRaster().getDataBuffer()).getData();


platformGraphics = this;

clipX = 0;
Expand Down Expand Up @@ -110,18 +114,31 @@ public void copyArea(int subx, int suby, int subw, int subh, int x, int y, int a
x = AnchorX(x, subw, anchor);
y = AnchorY(y, subh, anchor);

BufferedImage sub = new BufferedImage(subw, subh, BufferedImage.TYPE_INT_ARGB);

// Copy the pixels from the source area to the new image. getSubImage() makes both images contain the same data reference
for (int i = 0; i < subw; i++)
/*
* A neat trick here is that we don't need to check for types, as the copied
* subregion will always have the same data type as the original canvas it
* was copied from, be it INT_RGB, INT_ARGB, etc.
*/
// Create a data buffer to hold the copied pixel area
final int[] subPixels = new int[subw * subh];

// Copy pixels from the canvas subRegion to the subPixel array
for (int j = 0; j < subh; j++) {
for (int i = 0; i < subw; i++) {
subPixels[j * subw + i] = canvasData[(suby + j) * canvas.getWidth() + (subx + i)];
}
}

// Draw the copied pixels to the graphics context
int canvasWidth = canvas.getWidth();
for (int j = 0; j < subh; j++)
{
for (int j = 0; j < subh; j++)
for (int i = 0; i < subw; i++)
{
sub.setRGB(i, j, canvas.getRGB(subx + i, suby + j));
// Directly set pixels in the canvasData at the new position
canvasData[(y + j) * canvasWidth + (x + i)] = subPixels[j * subw + i];
}
}

gc.drawImage(sub, x, y, null);
}

public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle)
Expand Down Expand Up @@ -193,11 +210,11 @@ public void flushGraphics(Image image, int x, int y, int width, int height)
try
{
BufferedImage sub = image.platformImage.getCanvas().getSubimage(x, y, width, height);
final int[] pixels = ((DataBufferInt) sub.getRaster().getDataBuffer()).getData();

// Apply the backlight mask if Display, nokia's DeviceControl, or others request it for backlight effects.
if(Mobile.renderLCDMask)
{
final int[] pixels = ((DataBufferInt) sub.getRaster().getDataBuffer()).getData();
for(int i = 0; i < pixels.length; i++) { pixels[i] = pixels[i] & Mobile.lcdMaskColors[Mobile.maskIndex]; }
}

Expand All @@ -206,13 +223,13 @@ public void flushGraphics(Image image, int x, int y, int width, int height)
{
// Create an overlay image for the fun lights
BufferedImage overlayImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
int[] overlayData = ((DataBufferInt)overlayImage.getRaster().getDataBuffer()).getData();
drawFunLights(overlayData, width, height);

drawFunLights(overlayImage, width, height);

gc.drawImage(sub, x, y, null);
System.arraycopy(pixels, 0, canvasData, y * canvas.getWidth() + x, pixels.length);
gc.drawImage(overlayImage, x, y, null);
}
else { gc.drawImage(sub, x, y, null); }
}
else { System.arraycopy(pixels, 0, canvasData, y * canvas.getWidth() + x, pixels.length); }
}
catch (Exception e)
{
Expand Down Expand Up @@ -679,8 +696,6 @@ public void getPixels(byte[] pixels, byte[] transparencyMask, int offset, int sc
}
if (Math.abs(scanlength) < width) { throw new IllegalArgumentException("scanlength must be >= width");}

// Temporary canvas data array to read raw pixel data from.
int[] canvasData = ((DataBufferInt) canvas.getRaster().getDataBuffer()).getData();
// Just like DrawPixels(byte), we only handle BYTE_1_GRAY_VERTICAL and BYTE_1_GRAY yet
switch (format)
{
Expand Down Expand Up @@ -885,10 +900,8 @@ private static final BufferedImage manipulateImage(final BufferedImage image, fi
Motorola FunLights
****************************
*/
public void drawFunLights(BufferedImage overlayImage, int width, int height)
{
int[] pixelData = ((DataBufferInt)overlayImage.getRaster().getDataBuffer()).getData();

public void drawFunLights(int[] pixelData, int width, int height)
{
// Set pixels for the fun lights directly
for (int y = 0; y < height; y++)
{
Expand All @@ -914,12 +927,11 @@ else if (x >= width - Mobile.funLightRegionSize / 2) // Right Sideband Region
}

// Now apply a Gaussian blur using direct pixel manipulation
applyGaussianBlur(overlayImage, width, height);
applyGaussianBlur(pixelData, width, height);
}

private void applyGaussianBlur(BufferedImage image, int width, int height)
private void applyGaussianBlur(int[] pixels, int width, int height)
{
final int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
final int[] result = new int[pixels.length];

int kernelSize = 7;
Expand Down

0 comments on commit 5e51cfa

Please sign in to comment.