From d468c20fba75bc14a804dca5c7e7ba3d9d1b2598 Mon Sep 17 00:00:00 2001 From: javasabr Date: Fri, 30 Dec 2016 11:32:06 +0300 Subject: [PATCH] implemented LWJGL3 BufferAllocator --- .../com/jme3/util/BufferAllocatorFactory.java | 31 +++++++ .../main/java/com/jme3/util/BufferUtils.java | 50 ++++------- .../com/jme3/system/lwjgl/LwjglContext.java | 82 +++++++++++-------- .../com/jme3/util/LWJGLBufferAllocator.java | 24 ++++++ 4 files changed, 122 insertions(+), 65 deletions(-) create mode 100644 jme3-core/src/main/java/com/jme3/util/BufferAllocatorFactory.java create mode 100644 jme3-lwjgl3/src/main/java/com/jme3/util/LWJGLBufferAllocator.java diff --git a/jme3-core/src/main/java/com/jme3/util/BufferAllocatorFactory.java b/jme3-core/src/main/java/com/jme3/util/BufferAllocatorFactory.java new file mode 100644 index 000000000..dd77c4d1a --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/util/BufferAllocatorFactory.java @@ -0,0 +1,31 @@ +package com.jme3.util; + +import com.jme3.system.Annotations.Internal; + +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * The factory of buffer allocators. + * + * @author JavaSaBR + */ +@Internal +public class BufferAllocatorFactory { + + public static final String PROPERTY_BUFFER_ALLOCATOR_IMPLEMENTATION = "com.jme3.BufferAllocatorImplementation"; + + private static final Logger LOGGER = Logger.getLogger(BufferAllocatorFactory.class.getName()); + + @Internal + protected static BufferAllocator create() { + + final String className = System.getProperty(PROPERTY_BUFFER_ALLOCATOR_IMPLEMENTATION, ReflectionAllocator.class.getName()); + try { + return (BufferAllocator) Class.forName(className).newInstance(); + } catch (final Throwable e) { + LOGGER.log(Level.WARNING, "Unable to access {0}", className); + return new PrimitiveAllocator(); + } + } +} diff --git a/jme3-core/src/main/java/com/jme3/util/BufferUtils.java b/jme3-core/src/main/java/com/jme3/util/BufferUtils.java index 6ad4712b8..4fd5edb37 100644 --- a/jme3-core/src/main/java/com/jme3/util/BufferUtils.java +++ b/jme3-core/src/main/java/com/jme3/util/BufferUtils.java @@ -31,6 +31,12 @@ */ package com.jme3.util; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector2f; +import com.jme3.math.Vector3f; +import com.jme3.math.Vector4f; + import java.io.UnsupportedEncodingException; import java.lang.ref.PhantomReference; import java.lang.ref.Reference; @@ -45,12 +51,6 @@ import java.nio.LongBuffer; import java.nio.ShortBuffer; import java.util.concurrent.ConcurrentHashMap; -import com.jme3.math.ColorRGBA; -import com.jme3.math.Quaternion; -import com.jme3.math.Vector2f; -import com.jme3.math.Vector3f; -import com.jme3.math.Vector4f; - /** * BufferUtils is a helper class for generating nio buffers from * jME data classes such as Vectors and ColorRGBA. @@ -59,7 +59,11 @@ import com.jme3.math.Vector4f; * @version $Id: BufferUtils.java,v 1.16 2007/10/29 16:56:18 nca Exp $ */ public final class BufferUtils { - private static BufferAllocator allocator = new PrimitiveAllocator(); + + /** + * The field should be final to support thread-safe. + */ + private static final BufferAllocator ALLOCATOR = BufferAllocatorFactory.create(); private static boolean trackDirectMemory = false; private static ReferenceQueue removeCollected = new ReferenceQueue(); @@ -68,26 +72,6 @@ public final class BufferUtils { private static boolean used; - static { - try { - allocator = new ReflectionAllocator(); - } catch (Throwable t) { - t.printStackTrace(); - System.err.println("Error using ReflectionAllocator"); - } - } - - /** - * Warning! do only set this before JME is started! - */ - public static void setAllocator(BufferAllocator allocator) { - if (used) { - throw new IllegalStateException( - "An Buffer was already allocated, since it is quite likely that other dispose methods will create native dangling pointers or other fun things, this is forbidden to be changed at runtime"); - } - BufferUtils.allocator = allocator; - } - /** * Set it to true if you want to enable direct memory tracking for debugging * purpose. Default is false. To print direct memory usage use @@ -809,7 +793,7 @@ public final class BufferUtils { * @return the new DoubleBuffer */ public static DoubleBuffer createDoubleBuffer(int size) { - DoubleBuffer buf = allocator.allocate(8 * size).order(ByteOrder.nativeOrder()).asDoubleBuffer(); + DoubleBuffer buf = ALLOCATOR.allocate(8 * size).order(ByteOrder.nativeOrder()).asDoubleBuffer(); buf.clear(); onBufferAllocated(buf); return buf; @@ -872,7 +856,7 @@ public final class BufferUtils { * @return the new FloatBuffer */ public static FloatBuffer createFloatBuffer(int size) { - FloatBuffer buf = allocator.allocate(4 * size).order(ByteOrder.nativeOrder()).asFloatBuffer(); + FloatBuffer buf = ALLOCATOR.allocate(4 * size).order(ByteOrder.nativeOrder()).asFloatBuffer(); buf.clear(); onBufferAllocated(buf); return buf; @@ -934,7 +918,7 @@ public final class BufferUtils { * @return the new IntBuffer */ public static IntBuffer createIntBuffer(int size) { - IntBuffer buf = allocator.allocate(4 * size).order(ByteOrder.nativeOrder()).asIntBuffer(); + IntBuffer buf = ALLOCATOR.allocate(4 * size).order(ByteOrder.nativeOrder()).asIntBuffer(); buf.clear(); onBufferAllocated(buf); return buf; @@ -997,7 +981,7 @@ public final class BufferUtils { * @return the new IntBuffer */ public static ByteBuffer createByteBuffer(int size) { - ByteBuffer buf = allocator.allocate(size).order(ByteOrder.nativeOrder()); + ByteBuffer buf = ALLOCATOR.allocate(size).order(ByteOrder.nativeOrder()); buf.clear(); onBufferAllocated(buf); return buf; @@ -1079,7 +1063,7 @@ public final class BufferUtils { * @return the new ShortBuffer */ public static ShortBuffer createShortBuffer(int size) { - ShortBuffer buf = allocator.allocate(2 * size).order(ByteOrder.nativeOrder()).asShortBuffer(); + ShortBuffer buf = ALLOCATOR.allocate(2 * size).order(ByteOrder.nativeOrder()).asShortBuffer(); buf.clear(); onBufferAllocated(buf); return buf; @@ -1292,7 +1276,7 @@ public final class BufferUtils { if (!isDirect(toBeDestroyed)) { return; } - allocator.destroyDirectBuffer(toBeDestroyed); + ALLOCATOR.destroyDirectBuffer(toBeDestroyed); } /* diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java index 04265df97..b7222e388 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java @@ -32,6 +32,10 @@ package com.jme3.system.lwjgl; +import static org.lwjgl.opencl.CL10.CL_CONTEXT_PLATFORM; +import static org.lwjgl.opengl.GL.createCapabilities; +import static org.lwjgl.opengl.GL11.glGetInteger; + import com.jme3.input.lwjgl.GlfwJoystickInput; import com.jme3.input.lwjgl.GlfwKeyInput; import com.jme3.input.lwjgl.GlfwMouseInput; @@ -48,14 +52,24 @@ import com.jme3.renderer.lwjgl.LwjglGL; import com.jme3.renderer.lwjgl.LwjglGLExt; import com.jme3.renderer.lwjgl.LwjglGLFboEXT; import com.jme3.renderer.lwjgl.LwjglGLFboGL3; -import com.jme3.renderer.opengl.*; -import com.jme3.system.*; -import java.nio.IntBuffer; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.logging.Level; -import java.util.logging.Logger; +import com.jme3.renderer.opengl.GL; +import com.jme3.renderer.opengl.GL2; +import com.jme3.renderer.opengl.GL3; +import com.jme3.renderer.opengl.GL4; +import com.jme3.renderer.opengl.GLDebugDesktop; +import com.jme3.renderer.opengl.GLExt; +import com.jme3.renderer.opengl.GLFbo; +import com.jme3.renderer.opengl.GLRenderer; +import com.jme3.renderer.opengl.GLTiming; +import com.jme3.renderer.opengl.GLTimingState; +import com.jme3.renderer.opengl.GLTracer; +import com.jme3.system.AppSettings; +import com.jme3.system.JmeContext; +import com.jme3.system.SystemListener; +import com.jme3.system.Timer; +import com.jme3.util.BufferAllocatorFactory; +import com.jme3.util.LWJGLBufferAllocator; + import org.lwjgl.PointerBuffer; import org.lwjgl.glfw.GLFW; import org.lwjgl.opencl.*; @@ -63,18 +77,25 @@ import org.lwjgl.opengl.ARBDebugOutput; import org.lwjgl.opengl.ARBFramebufferObject; import org.lwjgl.opengl.EXTFramebufferMultisample; import org.lwjgl.opengl.GLCapabilities; +import org.lwjgl.system.Platform; -import static org.lwjgl.glfw.GLFW.GLFW_TRUE; -import static org.lwjgl.opencl.CL10.CL_CONTEXT_PLATFORM; -import static org.lwjgl.opengl.GL.createCapabilities; -import static org.lwjgl.opengl.GL11.glGetInteger; +import java.nio.IntBuffer; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.Level; +import java.util.logging.Logger; /** * A LWJGL implementation of a graphics context. */ public abstract class LwjglContext implements JmeContext { - private static final Logger logger = Logger.getLogger(LwjglContext.class.getName()); + private static final Logger LOGGER = Logger.getLogger(LwjglContext.class.getName()); + + static { + System.setProperty(BufferAllocatorFactory.PROPERTY_BUFFER_ALLOCATOR_IMPLEMENTATION, LWJGLBufferAllocator.class.getName()); + } public static final boolean CL_GL_SHARING_POSSIBLE = true; @@ -99,8 +120,8 @@ public abstract class LwjglContext implements JmeContext { } protected void printContextInitInfo() { - logger.log(Level.INFO, "LWJGL {0} context running on thread {1}\n" - + " * Graphics Adapter: GLFW {2}", + LOGGER.log(Level.INFO, "LWJGL {0} context running on thread {1}\n" + + " * Graphics Adapter: GLFW {2}", new Object[]{org.lwjgl.Version.getVersion(), Thread.currentThread().getName(), GLFW.glfwGetVersionString()}); } @@ -121,7 +142,7 @@ public abstract class LwjglContext implements JmeContext { samples = settings.getSamples(); final int supportedSamples = determineMaxSamples(); if (supportedSamples < samples) { - logger.log(Level.WARNING, + LOGGER.log(Level.WARNING, "Couldn't satisfy antialiasing samples requirement: x{0}. " + "Video hardware only supports: x{1}", new Object[]{samples, supportedSamples}); @@ -205,8 +226,6 @@ public abstract class LwjglContext implements JmeContext { * * Copied from the old release * - * @param filter the platform filter - * * @return the available platforms */ private static long[] getPlatforms() { @@ -233,12 +252,12 @@ public abstract class LwjglContext implements JmeContext { } protected void initOpenCL(long window) { - logger.info("Initialize OpenCL with LWJGL3"); + LOGGER.info("Initialize OpenCL with LWJGL3"); // try { // CL.create(); // } catch (Exception ex) { -// logger.log(Level.SEVERE, "Unable to initialize OpenCL", ex); +// LOGGER.log(Level.SEVERE, "Unable to initialize OpenCL", ex); // return; // } @@ -279,7 +298,7 @@ public abstract class LwjglContext implements JmeContext { platformInfos.append("\n * * Supports interop: ").append(device.hasOpenGLInterop()); } } - logger.info(platformInfos.toString()); + LOGGER.info(platformInfos.toString()); //choose devices PlatformChooser chooser = null; @@ -287,7 +306,7 @@ public abstract class LwjglContext implements JmeContext { try { chooser = (PlatformChooser) Class.forName(settings.getOpenCLPlatformChooser()).newInstance(); } catch (Exception ex) { - logger.log(Level.WARNING, "unable to instantiate custom PlatformChooser", ex); + LOGGER.log(Level.WARNING, "unable to instantiate custom PlatformChooser", ex); } } if (chooser == null) { @@ -298,35 +317,35 @@ public abstract class LwjglContext implements JmeContext { LwjglPlatform platform = null; for (Device d : choosenDevices) { if (!(d instanceof LwjglDevice)) { - logger.log(Level.SEVERE, "attempt to return a custom Device implementation from PlatformChooser: {0}", d); + LOGGER.log(Level.SEVERE, "attempt to return a custom Device implementation from PlatformChooser: {0}", d); return; } LwjglDevice ld = (LwjglDevice) d; if (platform == null) { platform = ld.getPlatform(); } else if (platform != ld.getPlatform()) { - logger.severe("attempt to use devices from different platforms"); + LOGGER.severe("attempt to use devices from different platforms"); return; } devices.add(ld.getDevice()); } if (devices.isEmpty()) { - logger.warning("no devices specified, no OpenCL context created"); + LOGGER.warning("no devices specified, no OpenCL context created"); return; } - logger.log(Level.INFO, "chosen platform: {0}", platform.getName()); - logger.log(Level.INFO, "chosen devices: {0}", choosenDevices); + LOGGER.log(Level.INFO, "chosen platform: {0}", platform.getName()); + LOGGER.log(Level.INFO, "chosen devices: {0}", choosenDevices); //create context try { long c = createContext(platform.getPlatform(), devices, window); clContext = new com.jme3.opencl.lwjgl.LwjglContext(c, (List) choosenDevices); - } catch (Exception ex) { - logger.log(Level.SEVERE, "Unable to create OpenCL context", ex); + } catch (final Exception ex) { + LOGGER.log(Level.SEVERE, "Unable to create OpenCL context", ex); return; } - logger.info("OpenCL context created"); + LOGGER.info("OpenCL context created"); } private long createContext(final long platform, final List devices, long window) throws Exception { @@ -338,7 +357,7 @@ public abstract class LwjglContext implements JmeContext { //https://github.com/glfw/glfw/issues/104 //https://github.com/LWJGL/lwjgl3/blob/master/modules/core/src/test/java/org/lwjgl/demo/opencl/Mandelbrot.java //TODO: test on Linus and MacOSX - switch (org.lwjgl.system.Platform.get()) { + switch (Platform.get()) { case WINDOWS: properties .put(KHRGLSharing.CL_GL_CONTEXT_KHR) @@ -446,5 +465,4 @@ public abstract class LwjglContext implements JmeContext { public Context getOpenCLContext() { return clContext; } - } diff --git a/jme3-lwjgl3/src/main/java/com/jme3/util/LWJGLBufferAllocator.java b/jme3-lwjgl3/src/main/java/com/jme3/util/LWJGLBufferAllocator.java new file mode 100644 index 000000000..5d65004cb --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/util/LWJGLBufferAllocator.java @@ -0,0 +1,24 @@ +package com.jme3.util; + +import org.lwjgl.system.MemoryUtil; + +import java.nio.Buffer; +import java.nio.ByteBuffer; + +/** + * The implementation of the {@link BufferAllocator} which use {@link MemoryUtil} to manage memory. + * + * @author JavaSaBr + */ +public class LWJGLBufferAllocator implements BufferAllocator { + + @Override + public void destroyDirectBuffer(final Buffer buffer) { + MemoryUtil.memFree(buffer); + } + + @Override + public ByteBuffer allocate(final int size) { + return MemoryUtil.memAlloc(size); + } +}