From 19b9f1fad671da1e5ad8610b1531de2528a38f8e Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Mon, 11 Mar 2019 00:21:31 +0100 Subject: [PATCH] Initial tests of GPU rendering Successfully rendered to the map via the GPU (well not really, it falls back to an alternative algorithm) Dropping the PXCLib - finally realized that the GPU speed massively increases after the first pass --- VirtualComputer/dependency-reduced-pom.xml | 3 + VirtualComputer/pom.xml | 8 ++ .../sznp/virtualcomputer/DirectRenderer.java | 3 +- .../src/sznp/virtualcomputer/GPURenderer.java | 76 +++++++++++++++++++ .../sznp/virtualcomputer/MCFrameBuffer.java | 8 +- .../src/sznp/virtualcomputer/PluginMain.java | 13 +++- .../src/sznp/virtualcomputer/Test.java | 34 ++++++--- 7 files changed, 128 insertions(+), 17 deletions(-) create mode 100644 VirtualComputer/src/sznp/virtualcomputer/GPURenderer.java diff --git a/VirtualComputer/dependency-reduced-pom.xml b/VirtualComputer/dependency-reduced-pom.xml index 9fbc306..6fe3136 100644 --- a/VirtualComputer/dependency-reduced-pom.xml +++ b/VirtualComputer/dependency-reduced-pom.xml @@ -28,6 +28,9 @@ 1.8 1.8 + + -g + diff --git a/VirtualComputer/pom.xml b/VirtualComputer/pom.xml index cb1f018..08dd9fa 100644 --- a/VirtualComputer/pom.xml +++ b/VirtualComputer/pom.xml @@ -28,6 +28,9 @@ 1.8 1.8 + + -g + @@ -92,5 +95,10 @@ aparapi 1.10.0 + + org.projectlombok + lombok + 1.16.16 + \ No newline at end of file diff --git a/VirtualComputer/src/sznp/virtualcomputer/DirectRenderer.java b/VirtualComputer/src/sznp/virtualcomputer/DirectRenderer.java index 1e88ecf..bb6d76a 100644 --- a/VirtualComputer/src/sznp/virtualcomputer/DirectRenderer.java +++ b/VirtualComputer/src/sznp/virtualcomputer/DirectRenderer.java @@ -68,7 +68,8 @@ public class DirectRenderer implements IRenderer { if(System.nanoTime()-lastrender<100*1000*1000) return; try { - long p = PluginMain.pxc.updateAndGetMap((int) x, (int) y, (int) width, (int) height, null); + //long p = PluginMain.pxc.updateAndGetMap((int) x, (int) y, (int) width, (int) height, null); + long p = 0; //TODO: Not used (class) if (p == 0) return; byte[] img = new Pointer(p).getByteArray(0, 128 * 128); boolean hascolor=false; diff --git a/VirtualComputer/src/sznp/virtualcomputer/GPURenderer.java b/VirtualComputer/src/sznp/virtualcomputer/GPURenderer.java new file mode 100644 index 0000000..fafe0c9 --- /dev/null +++ b/VirtualComputer/src/sznp/virtualcomputer/GPURenderer.java @@ -0,0 +1,76 @@ +package sznp.virtualcomputer; + +import com.aparapi.Kernel; +import com.aparapi.Range; +import lombok.Setter; +import net.minecraft.server.v1_12_R1.WorldMap; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_12_R1.map.RenderData; +import org.bukkit.entity.Player; +import org.bukkit.map.MapCanvas; +import org.bukkit.map.MapRenderer; +import org.bukkit.map.MapView; + +import java.lang.reflect.Field; +import java.util.Map; + +public class GPURenderer extends MapRenderer implements IRenderer { + private byte[] buffer; + private MapView map; + private Kernel kernel; + @Setter + private static int width; + private Range range; + + public GPURenderer(short id, World world, int mapx, int mapy) throws Exception { + map = IRenderer.prepare(id, world); + final Field field = map.getClass().getDeclaredField("renderCache"); + field.setAccessible(true); + @SuppressWarnings("unchecked") final Map renderCache = (Map) field.get(map); + + RenderData render = renderCache.get(null); + + if (render == null) + renderCache.put(null, render = new RenderData()); + + this.buffer = render.buffer; + + kernel = new Kernel() { + @Override + public void run() { + int mx = getGlobalId(0); + int my = getGlobalId(1); + int imgx = mx + mapx * 128; + int imgy = my + mapy * 128; + int imgi = imgy * width + imgx; + buffer[my * 128 + mx] = matchColor(PluginMain.pixels[imgi]); + } + }; + range = Range.create2D(128, 128); + + map.addRenderer(this); + } + + @Override + public void render(MapView map, MapCanvas canvas, Player player) { + try { + if (width == 0) return; //TODO: Stop rendering after computer is stopped + Field field = canvas.getClass().getDeclaredField("buffer"); + field.setAccessible(true); + buffer = (byte[]) field.get(canvas); + kernel.put(buffer).put(PluginMain.pixels).execute(range).get(buffer); + field = map.getClass().getDeclaredField("worldMap"); + field.setAccessible(true); + WorldMap wmap = (WorldMap) field.get(map); + wmap.flagDirty(0, 0); + wmap.flagDirty(127, 127); // Send the whole image - TODO: Only send changes + } catch (Exception e) { + e.printStackTrace(); + } + } + + private byte matchColor(int bgra) { //TODO + return 48; + } +} diff --git a/VirtualComputer/src/sznp/virtualcomputer/MCFrameBuffer.java b/VirtualComputer/src/sznp/virtualcomputer/MCFrameBuffer.java index 679ea15..5396676 100644 --- a/VirtualComputer/src/sznp/virtualcomputer/MCFrameBuffer.java +++ b/VirtualComputer/src/sznp/virtualcomputer/MCFrameBuffer.java @@ -105,9 +105,11 @@ public class MCFrameBuffer implements IFramebuffer { holder.value.getTypedWrapped().queryBitmapInfo(ptr, w, h, bpp, bpl, pf); System.out.println("Arr0:" + ptr[0]); System.out.println("whbppbplpf: " + w[0] + " " + h[0] + " " + bpp[0] + " " + bpl[0] + " " + pf[0]); - if(PluginMain.direct) - PluginMain.pxc.setSource(ptr[0], (int)w[0], (int)h[0], PluginMain.MCX, PluginMain.MCY); - else { + if (PluginMain.direct) { + //PluginMain.pxc.setSource(ptr[0], (int)w[0], (int)h[0], PluginMain.MCX, PluginMain.MCY); + PluginMain.pixels = new Pointer(ptr[0]).getByteArray(0L, (int) (w[0] * h[0] * 4)); + GPURenderer.setWidth((int) w[0]); + } else { PluginMain.allpixels = new Pointer(ptr[0]).getByteBuffer(0L, width * height * 4); if (width * height > 640 * 480) PluginMain.allpixels.limit(640 * 480 * 4); diff --git a/VirtualComputer/src/sznp/virtualcomputer/PluginMain.java b/VirtualComputer/src/sznp/virtualcomputer/PluginMain.java index c0ddbf4..c525b1a 100644 --- a/VirtualComputer/src/sznp/virtualcomputer/PluginMain.java +++ b/VirtualComputer/src/sznp/virtualcomputer/PluginMain.java @@ -37,8 +37,12 @@ public class PluginMain extends JavaPlugin { /** * Only used if {@link #direct} is true. */ - public static PXCLib pxc; + //public static PXCLib pxc; public static boolean direct; + /** + * Only used if {@link #direct} is true. + */ + public static byte[] pixels; // Fired when plugin is first enabled @Override @@ -73,9 +77,10 @@ public class PluginMain extends JavaPlugin { ccs.sendMessage("§bLoading Screen..."); try { //throw new NoClassDefFoundError("Test error pls ignore"); - for (short i = 0; i < 20; i++) - renderers.add(new DirectRenderer(i, Bukkit.getWorlds().get(0), i * 128 * 128 * 4)); // TODO: The pixels are selected in a horribly wrong way probably - pxc = LibraryLoader.create(PXCLib.class).search(getDataFolder().getAbsolutePath()).load("pxc"); + for (short i = 0; i < 5; i++) + for (short j = 0; j < 4; j++) + renderers.add(new GPURenderer(i, Bukkit.getWorlds().get(0), i, j)); + //pxc = LibraryLoader.create(PXCLib.class).search(getDataFolder().getAbsolutePath()).load("pxc"); direct=true; ccs.sendMessage("§bUsing Direct Renderer, all good"); } catch (NoClassDefFoundError | Exception e) { diff --git a/VirtualComputer/src/sznp/virtualcomputer/Test.java b/VirtualComputer/src/sznp/virtualcomputer/Test.java index 427fcb6..c9dcec2 100644 --- a/VirtualComputer/src/sznp/virtualcomputer/Test.java +++ b/VirtualComputer/src/sznp/virtualcomputer/Test.java @@ -2,7 +2,6 @@ package sznp.virtualcomputer; import com.aparapi.Kernel; import com.aparapi.Range; -import com.sun.jna.Native; import com.sun.jna.Pointer; import jnr.ffi.LibraryLoader; import org.bukkit.Color; @@ -12,9 +11,7 @@ import java.io.File; import java.lang.reflect.Field; import java.nio.Buffer; import java.nio.ByteBuffer; -import java.util.Arrays; import java.util.stream.IntStream; -import java.util.stream.LongStream; public class Test { public static void main(String[] args) { @@ -28,7 +25,6 @@ public class Test { //final int[] b={10,80,10,3,32,20,56,85,51,968,156,5894,10,60,52}; //final int[] a={5,6}; //final int[] b={10,80}; - long t=System.nanoTime(); int[] a= IntStream.range(0, 640*480).toArray(); final int[] res=new int[a.length]; Kernel kernel=new Kernel() { @@ -37,14 +33,20 @@ public class Test { int i=getGlobalId(); //System.out.println(i); //res[i]=a[i]+b[i]; - Color c=Color.fromBGR((int)a[i]); - res[i]= MapPalette.matchColor(c.getRed(), c.getGreen(), c.getBlue()); + //res[i]= MapPalette.matchColor(a[i] & 0x0000FF, a[i] & 0x00FF00 >> 8, a[i] & 0xFF0000 >> 16); + res[i] = a[i]; } }; - kernel.execute(Range.create(res.length)); + long t = System.nanoTime(); + kernel.put(a).execute(Range.create(res.length)).get(res); //System.out.println(Arrays.toString(res)); System.out.println(a[10]); System.out.println("OpenCL time: "+(System.nanoTime()-t)/1000000f+"ms"); + a[50] = 652; //Massive speedups after the fist pass + t = System.nanoTime(); + kernel.put(a).execute(Range.create(res.length)).get(res); + System.out.println(a[10]); + System.out.println("Second OpenCL time: " + (System.nanoTime() - t) / 1000000f + "ms"); t=System.nanoTime(); for (int i = 0; i < res.length; i++) { @@ -58,15 +60,29 @@ public class Test { System.out.println("Sys time: "+(System.nanoTime()-t)/1000000f+"ms"); PXCLib pxc = LibraryLoader.create(PXCLib.class).search(new File("").getAbsolutePath()).load("pxc"); - ByteBuffer bb=ByteBuffer.allocateDirect(640*480); + ByteBuffer bb = ByteBuffer.allocateDirect(640 * 480 * 4); try { Field f=Buffer.class.getDeclaredField("address"); f.setAccessible(true); long addr= (long) f.get(bb); pxc.setSource(addr, 640, 480, 5, 4); - pxc.updateAndGetMap(0, 0, 640, 480, null); + t = System.nanoTime(); + long p = pxc.updateAndGetMap(0, 0, 640, 480, null); + if (p == 0) return; + byte[] img = new Pointer(p).getByteArray(0, 128 * 128); + System.out.println("img[50]: " + img[50]); + System.out.println("Native time: " + (System.nanoTime() - t) / 1000000f + "ms"); } catch (NoSuchFieldException | IllegalAccessException e) { e.printStackTrace(); } + + kernel = new Kernel() { + @Override + public void run() { + PXCLib pxc = LibraryLoader.create(PXCLib.class).search(new File("").getAbsolutePath()).load("pxc"); + pxc.updateAndGetMap(0, 0, 0, 0, null); + } + }; + kernel.execute(Range.create(1)); } }