diff --git a/JavaApp/libs/lwjgl-shaderc.jar b/JavaApp/libs/lwjgl-shaderc.jar new file mode 100644 index 00000000..773724de Binary files /dev/null and b/JavaApp/libs/lwjgl-shaderc.jar differ diff --git a/JavaApp/libs/lwjgl-vma.jar b/JavaApp/libs/lwjgl-vma.jar new file mode 100644 index 00000000..ac93a263 Binary files /dev/null and b/JavaApp/libs/lwjgl-vma.jar differ diff --git a/JavaApp/libs/lwjgl-vulkan.jar b/JavaApp/libs/lwjgl-vulkan.jar new file mode 100644 index 00000000..d5fea366 Binary files /dev/null and b/JavaApp/libs/lwjgl-vulkan.jar differ diff --git a/JavaApp/src/main/java/net/kdt/pojavlaunch/PojavLauncher.java b/JavaApp/src/main/java/net/kdt/pojavlaunch/PojavLauncher.java index 1fae9f31..00a7717d 100644 --- a/JavaApp/src/main/java/net/kdt/pojavlaunch/PojavLauncher.java +++ b/JavaApp/src/main/java/net/kdt/pojavlaunch/PojavLauncher.java @@ -53,6 +53,7 @@ public class PojavLauncher { MCOptionUtils.save(); System.setProperty("org.lwjgl.opengl.libname", System.getenv("POJAV_RENDERER")); + System.setProperty("org.lwjgl.vulkan.libname", "libMoltenVK.dylib"); Tools.mGLFWWindowWidth = Integer.parseInt(size[0]); Tools.mGLFWWindowHeight = Integer.parseInt(size[1]); diff --git a/JavaApp/src/main/java/org/lwjgl/glfw/GLFW.java b/JavaApp/src/main/java/org/lwjgl/glfw/GLFW.java index 16e26dbf..367e7056 100644 --- a/JavaApp/src/main/java/org/lwjgl/glfw/GLFW.java +++ b/JavaApp/src/main/java/org/lwjgl/glfw/GLFW.java @@ -586,6 +586,7 @@ public class GLFW //DetachOnCurrentThread = apiGetFunctionAddress(GLFW, "pojavDetachOnCurrentThread"), MakeContextCurrent = apiGetFunctionAddress(GLFW, "pojavMakeCurrent"), Terminate = apiGetFunctionAddress(GLFW, "pojavTerminate"), + SetWindowHint = apiGetFunctionAddress(GLFW, "pojavSetWindowHint"), SwapBuffers = apiGetFunctionAddress(GLFW, "pojavSwapBuffers"), SwapInterval = apiGetFunctionAddress(GLFW, "pojavSwapInterval"); } @@ -905,7 +906,8 @@ public class GLFW @Nullable @NativeType("GLFWvidmode const *") public static GLFWVidMode.Buffer glfwGetVideoModes(@NativeType("GLFWmonitor *") long monitor) { - MemoryStack stack = stackGet(); int stackPointer = stack.getPointer(); + MemoryStack stack = stackGet(); + int stackPointer = stack.getPointer(); IntBuffer count = stack.callocInt(1); try { // long __result = nglfwGetVideoModes(monitor, memAddress(count)); @@ -1017,12 +1019,16 @@ public class GLFW th.printStackTrace(); } } - + public static void glfwShowWindow(long window) { System.out.println("GLFW: Showing window " + window + ", " + internalGetWindow(window).toString()); nglfwSetShowingWindow(window); } - public static void glfwWindowHint(int hint, int value) {} + public static void glfwWindowHint(int hint, int value) { + long __functionAddress = Functions.SetWindowHint; + invokeV(hint, value, __functionAddress); + } + public static void glfwWindowHintString(int hint, @NativeType("const char *") ByteBuffer value) {} public static void glfwWindowHintString(int hint, @NativeType("const char *") CharSequence value) {} diff --git a/JavaApp/src/main/java/org/lwjgl/glfw/GLFWVulkan.java b/JavaApp/src/main/java/org/lwjgl/glfw/GLFWVulkan.java new file mode 100644 index 00000000..39335286 --- /dev/null +++ b/JavaApp/src/main/java/org/lwjgl/glfw/GLFWVulkan.java @@ -0,0 +1,274 @@ +/* + * Copyright LWJGL. All rights reserved. + * License terms: https://www.lwjgl.org/license + * MACHINE GENERATED FILE, DO NOT EDIT + */ +package org.lwjgl.glfw; + +import javax.annotation.*; + +import java.nio.*; + +import org.lwjgl.*; + +import org.lwjgl.system.*; + +import static org.lwjgl.system.APIUtil.*; +import static org.lwjgl.system.Checks.*; +import static org.lwjgl.system.JNI.*; +import static org.lwjgl.system.MemoryStack.*; +import static org.lwjgl.system.MemoryUtil.*; +import static org.lwjgl.vulkan.EXTMetalSurface.*; + +import org.lwjgl.vulkan.*; + +/** Native bindings to the GLFW library's Vulkan functions. */ +public class GLFWVulkan { + + protected GLFWVulkan() { + throw new UnsupportedOperationException(); + } + + static { + //invokeV(Functions.Init); + + +/* + if (Platform.get() == Platform.MACOSX) { + // Force GLFW to initialize Vulkan using the same library used by LWJGL. + FunctionProvider fp = VK.getFunctionProvider(); + if (fp instanceof SharedLibrary) { + String path = ((SharedLibrary)fp).getPath(); + if (path != null) { + try (MemoryStack stack = stackPush()) { + long _glfw_vulkan_library = apiGetFunctionAddress(GLFW.getLibrary(), "_glfw_vulkan_library"); + + memPutAddress(_glfw_vulkan_library, memAddress(stack.UTF8(path))); + glfwVulkanSupported(); + memPutAddress(_glfw_vulkan_library, NULL); + } + } + } + } +*/ + } + + // --- [ glfwVulkanSupported ] --- + + /** + * Returns whether the Vulkan loader has been found. This check is performed by {@link GLFW#glfwInit Init}. + * + *

The availability of a Vulkan loader does not by itself guarantee that window surface creation or even device creation is possible. Call + * {@link #glfwGetRequiredInstanceExtensions GetRequiredInstanceExtensions} to check whether the extensions necessary for Vulkan surface creation are available and + * {@link #glfwGetPhysicalDevicePresentationSupport GetPhysicalDevicePresentationSupport} to check whether a queue family of a physical device supports image presentation.

+ * + *

Possible errors include {@link GLFW#GLFW_NOT_INITIALIZED NOT_INITIALIZED}.

+ * + *

This function may be called from any thread.

+ * + * @return {@link GLFW#GLFW_TRUE TRUE} if Vulkan is available, or {@link GLFW#GLFW_FALSE FALSE} otherwise + * + * @since version 3.2 + */ + @NativeType("int") + public static boolean glfwVulkanSupported() { + return true; + } + + // --- [ glfwGetRequiredInstanceExtensions ] --- + + /** + * Returns an array of names of Vulkan instance extensions required by GLFW for creating Vulkan surfaces for GLFW windows. If successful, the list will + * always contain {@code VK_KHR_surface}, so if you don't require any additional extensions you can pass this list directly to the {@link VkInstanceCreateInfo} + * struct. + * + *

If Vulkan is not available on the machine, this function returns {@code NULL} and generates a {@link GLFW#GLFW_API_UNAVAILABLE API_UNAVAILABLE} error. Call {@link #glfwVulkanSupported VulkanSupported} to check whether + * Vulkan is available.

+ * + *

If Vulkan is available but no set of extensions allowing window surface creation was found, this function returns {@code NULL}. You may still use Vulkan for + * off-screen rendering and compute work.

+ * + *

Additional extensions may be required by future versions of GLFW. You should check if any extensions you wish to enable are already in the returned + * array, as it is an error to specify an extension more than once in the {@code VkInstanceCreateInfo} struct.

+ * + *

The returned array is allocated and freed by GLFW. You should not free it yourself. It is guaranteed to be valid only until the library is terminated.

+ * + *

This function may be called from any thread.

+ * + *

Possible errors include {@link GLFW#GLFW_NOT_INITIALIZED NOT_INITIALIZED} and {@link GLFW#GLFW_API_UNAVAILABLE API_UNAVAILABLE}.

+ * + * @return an array of ASCII encoded extension names, or {@code NULL} if an error occurred + * + * @since version 3.2 + */ + @Nullable + @NativeType("char const **") + public static PointerBuffer glfwGetRequiredInstanceExtensions() { + MemoryStack stack = MemoryStack.stackPush(); + String platformSurface; + if (Platform.get() == Platform.MACOSX) { + platformSurface = "VK_EXT_metal_surface"; + } else { + platformSurface = "VK_KHR_android_surface"; + } + return stack.pointers(stack.UTF8(KHRSurface.VK_KHR_SURFACE_EXTENSION_NAME), stack.UTF8(platformSurface)); + } + + // --- [ glfwGetInstanceProcAddress ] --- + + /** + * Returns the address of the specified Vulkan core or extension function for the specified instance. If instance is set to {@code NULL} it can return any + * function exported from the Vulkan loader, including at least the following functions: + * + * + * + *

If Vulkan is not available on the machine, this function returns {@code NULL} and generates a {@link GLFW#GLFW_API_UNAVAILABLE API_UNAVAILABLE} error. Call {@link #glfwVulkanSupported VulkanSupported} to check whether + * Vulkan is available.

+ * + *

This function is equivalent to calling {@link VK10#vkGetInstanceProcAddr} with a platform-specific query of the Vulkan loader as a fallback.

+ * + *

Possible errors include {@link GLFW#GLFW_NOT_INITIALIZED NOT_INITIALIZED} and {@link GLFW#GLFW_API_UNAVAILABLE API_UNAVAILABLE}.

+ * + *

The returned function pointer is valid until the library is terminated.

+ * + *

This function may be called from any thread.

+ * + * @param instance the Vulkan instance to query, or {@code NULL} to retrieve functions related to instance creation + * @param procname the ASCII encoded name of the function + * + * @return the address of the function, or {@code NULL} if an error occurred + * + * @since version 3.2 + */ + @NativeType("GLFWvkproc") + public static long glfwGetInstanceProcAddress(@Nullable VkInstance instance, @NativeType("char const *") ByteBuffer procname) { + return VK10.vkGetInstanceProcAddr(instance, procname); + } + + /** + * Returns the address of the specified Vulkan core or extension function for the specified instance. If instance is set to {@code NULL} it can return any + * function exported from the Vulkan loader, including at least the following functions: + * + * + * + *

If Vulkan is not available on the machine, this function returns {@code NULL} and generates a {@link GLFW#GLFW_API_UNAVAILABLE API_UNAVAILABLE} error. Call {@link #glfwVulkanSupported VulkanSupported} to check whether + * Vulkan is available.

+ * + *

This function is equivalent to calling {@link VK10#vkGetInstanceProcAddr} with a platform-specific query of the Vulkan loader as a fallback.

+ * + *

Possible errors include {@link GLFW#GLFW_NOT_INITIALIZED NOT_INITIALIZED} and {@link GLFW#GLFW_API_UNAVAILABLE API_UNAVAILABLE}.

+ * + *

The returned function pointer is valid until the library is terminated.

+ * + *

This function may be called from any thread.

+ * + * @param instance the Vulkan instance to query, or {@code NULL} to retrieve functions related to instance creation + * @param procname the ASCII encoded name of the function + * + * @return the address of the function, or {@code NULL} if an error occurred + * + * @since version 3.2 + */ + @NativeType("GLFWvkproc") + public static long glfwGetInstanceProcAddress(@Nullable VkInstance instance, @NativeType("char const *") CharSequence procname) { + return VK10.vkGetInstanceProcAddr(instance, procname); + } + + // --- [ glfwGetPhysicalDevicePresentationSupport ] --- + + /** + * Returns whether the specified queue family of the specified physical device supports presentation to the platform GLFW was built for. + * + *

If Vulkan or the required window surface creation instance extensions are not available on the machine, or if the specified instance was not created + * with the required extensions, this function returns {@link GLFW#GLFW_FALSE FALSE} and generates a {@link GLFW#GLFW_API_UNAVAILABLE API_UNAVAILABLE} error. Call {@link #glfwVulkanSupported VulkanSupported} to check whether Vulkan is + * available and {@link #glfwGetRequiredInstanceExtensions GetRequiredInstanceExtensions} to check what instance extensions are required.

+ * + *

Possible errors include {@link GLFW#GLFW_NOT_INITIALIZED NOT_INITIALIZED}, {@link GLFW#GLFW_API_UNAVAILABLE API_UNAVAILABLE} and {@link GLFW#GLFW_PLATFORM_ERROR PLATFORM_ERROR}.

+ * + *

This function may be called from any thread. For synchronization details of Vulkan objects, see the Vulkan specification.

+ * + * @param instance the instance that the physical device belongs to + * @param device the physical device that the queue family belongs to + * @param queuefamily the index of the queue family to query + * + * @return {@link GLFW#GLFW_TRUE TRUE} if the queue family supports presentation, or {@link GLFW#GLFW_FALSE FALSE} otherwise + * + * @since version 3.2 + */ + @NativeType("int") + public static boolean glfwGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, @NativeType("uint32_t") int queuefamily) { + return true; + } + + // --- [ glfwCreateWindowSurface ] --- + + /** + * Creates a Vulkan surface for the specified window. + * + *

If the Vulkan loader was not found at initialization, this function returns {@link VK10#VK_ERROR_INITIALIZATION_FAILED} and generates a {@link GLFW#GLFW_API_UNAVAILABLE API_UNAVAILABLE} error. + * Call {@link #glfwVulkanSupported VulkanSupported} to check whether the Vulkan loader was found.

+ * + *

If the required window surface creation instance extensions are not available or if the specified instance was not created with these extensions + * enabled, this function returns {@link VK10#VK_ERROR_EXTENSION_NOT_PRESENT} and generates a {@link GLFW#GLFW_API_UNAVAILABLE API_UNAVAILABLE} error. Call {@link #glfwGetRequiredInstanceExtensions GetRequiredInstanceExtensions} to + * check what instance extensions are required.

+ * + *

The window surface cannot be shared with another API so the window must have been created with the client api hint set to {@link GLFW#GLFW_NO_API NO_API} otherwise it + * generates a {@link GLFW#GLFW_INVALID_VALUE INVALID_VALUE} error and returns {@link KHRSurface#VK_ERROR_NATIVE_WINDOW_IN_USE_KHR}.

+ * + *

The window surface must be destroyed before the specified Vulkan instance. It is the responsibility of the caller to destroy the window surface. GLFW + * does not destroy it for you. Call {@link KHRSurface#vkDestroySurfaceKHR} to destroy the surface.

+ * + *

Possible errors include {@link GLFW#GLFW_NOT_INITIALIZED NOT_INITIALIZED}, {@link GLFW#GLFW_API_UNAVAILABLE API_UNAVAILABLE}, {@link GLFW#GLFW_PLATFORM_ERROR PLATFORM_ERROR} and {@link GLFW#GLFW_INVALID_VALUE INVALID_VALUE}.

+ * + *

If an error occurs before the creation call is made, GLFW returns the Vulkan error code most appropriate for the error. Appropriate use of + * {@link #glfwVulkanSupported VulkanSupported} and {@link #glfwGetRequiredInstanceExtensions GetRequiredInstanceExtensions} should eliminate almost all occurrences of these errors.

+ * + *

This function may be called from any thread. For synchronization details of Vulkan objects, see the Vulkan specification.

+ * + * @param instance the Vulkan instance to create the surface in + * @param window the window to create the surface for + * @param allocator the allocator to use, or {@code NULL} to use the default allocator. + * @param surface where to store the handle of the surface. This is set to {@link VK10#VK_NULL_HANDLE} if an error occurred. + * + * @return {@link VK10#VK_SUCCESS} if successful, or a Vulkan error code if an error occurred + * + * @since version 3.2 + */ + @NativeType("VkResult") + public static int glfwCreateWindowSurface(VkInstance instance, @NativeType("GLFWwindow *") long window, @Nullable @NativeType("VkAllocationCallbacks const *") VkAllocationCallbacks allocator, @NativeType("VkSurfaceKHR *") LongBuffer surface) { + if (CHECKS) { + check(surface, 1); + } + if (Platform.get() == Platform.MACOSX) { + VkMetalSurfaceCreateInfoEXT pCreateInfo = VkMetalSurfaceCreateInfoEXT + .calloc() + .sType(VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT) + .pLayer(PointerBuffer.create(window, 1)); + return vkCreateMetalSurfaceEXT(instance, pCreateInfo, null, surface); + } else { + // TODO: impl for Android + return 0; + } + } + + /** Array version of: {@link #glfwCreateWindowSurface CreateWindowSurface} */ + @NativeType("VkResult") + public static int glfwCreateWindowSurface(VkInstance instance, @NativeType("GLFWwindow *") long window, @Nullable @NativeType("VkAllocationCallbacks const *") VkAllocationCallbacks allocator, @NativeType("VkSurfaceKHR *") long[] surface) { + MemoryStack stack = stackGet(); + LongBuffer pSurface = stack.mallocLong(1); + int result = glfwCreateWindowSurface(instance, window, allocator, pSurface); + surface[0] = pSurface.get(0); + return result; + } + +} diff --git a/Natives/JavaLauncher.m b/Natives/JavaLauncher.m index a7099397..8f382ea1 100644 --- a/Natives/JavaLauncher.m +++ b/Natives/JavaLauncher.m @@ -289,7 +289,7 @@ int launchJVM(NSString *username, id launchTarget, int width, int height, int mi // Check if JVM restarts char *frameworkPath, *javaPath, *jnaLibPath, *userDir, *userHome, *memMin, *memMax, *arcDNS; - asprintf(&frameworkPath, "-Djava.library.path=%s/Frameworks:%s/Frameworks/libOSMesaOverride.dylib.framework", getenv("BUNDLE_PATH"), getenv("BUNDLE_PATH")); + asprintf(&frameworkPath, "-Djava.library.path=%1$s/Frameworks:%1$s/Frameworks/libOSMesaOverride.dylib.framework:%1$s/Frameworks/libMoltenVK.dylib.framework", getenv("BUNDLE_PATH")); asprintf(&javaPath, "%s/bin/java", javaHome); asprintf(&jnaLibPath, "-Djna.boot.library.path=%s/Frameworks/libjnidispatch.dylib.framework", getenv("BUNDLE_PATH")); asprintf(&userDir, "-Duser.dir=%s", getenv("POJAV_GAME_DIR")); diff --git a/Natives/LauncherPreferencesViewController.m b/Natives/LauncherPreferencesViewController.m index a0965976..648cb37d 100644 --- a/Natives/LauncherPreferencesViewController.m +++ b/Natives/LauncherPreferencesViewController.m @@ -217,6 +217,8 @@ int tempIndex; jargsTextField.delegate = self; jargsTextField.placeholder = @"Specify arguments..."; jargsTextField.text = (NSString *) getPreference(@"java_args"); + jargsTextField.autocorrectionType = UITextAutocorrectionTypeNo +; jargsTextField.contentVerticalAlignment = UIControlContentVerticalAlignmentTop; jargsTextField.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft; [tableView addSubview:jargsTextField]; diff --git a/Natives/SurfaceViewController.m b/Natives/SurfaceViewController.m index ad6d1331..ff0a9597 100644 --- a/Natives/SurfaceViewController.m +++ b/Natives/SurfaceViewController.m @@ -46,7 +46,7 @@ BOOL slideableHotbar; #pragma mark Class GameSurfaceView @implementation GameSurfaceView const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { - return gbuffer; + return gbuffer; } - (void)displayLayer { @@ -238,6 +238,7 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) { inputLengthView.backgroundColor = [UIColor colorWithWhite:1.0f alpha:0.6f]; [self.view addSubview:inputLengthView]; #endif + //self.inputView.autocorrectionType = UITextAutocorrectionTypeNo; self.inputView.delegate = self; self.inputView.lastPosition = 20; [self.inputView addTarget:self action:@selector(inputViewDidChange) forControlEvents:UIControlEventEditingChanged]; diff --git a/Natives/egl_bridge.m b/Natives/egl_bridge.m index e3dc1fec..32fefa9b 100644 --- a/Natives/egl_bridge.m +++ b/Natives/egl_bridge.m @@ -14,6 +14,7 @@ #include "GLES2/gl2.h" #include "egl_bridge.h" +#include "glfw_keycodes.h" #include "osmesa_internal.h" #include "log.h" @@ -71,6 +72,7 @@ int (*vtest_main_p) (int, const char*[]); void (*vtest_swap_buffers_p) (void); void* egl_make_current(void* window); +#define RENDERER_VULKAN 0 #define RENDERER_MTL_ANGLE 1 #define RENDERER_VK_ZINK 2 #define RENDERER_VIRGL 3 @@ -219,7 +221,10 @@ void loadSymbolsVirGL() { int pojavInit() { isInputReady = 1; mainThreadID = gettid(); + return JNI_TRUE; +} +jboolean pojavInit_OpenGL() { NSString *renderer = @(getenv("POJAV_RENDERER")); if ([renderer isEqualToString:@"libOSMesa.8.dylib"]) { config_renderer = RENDERER_VIRGL; @@ -346,6 +351,23 @@ int pojavInit() { return JNI_FALSE; } +void pojavSetWindowHint(int hint, int value) { + if (hint != GLFW_CLIENT_API) return; + switch (value) { + case GLFW_NO_API: + config_renderer = RENDERER_VULKAN; + /* Nothing to do: initialization is handled in Java-side */ + // pojavInit_Vulkan(); + break; + case GLFW_OPENGL_API: + pojavInit_OpenGL(); + break; + default: + NSLog(@"GLFW: Unimplemented API 0x%x", value); + abort(); + } +} + int32_t stride; bool stopSwapBuffers; void pojavSwapBuffers() { @@ -449,6 +471,10 @@ void pojavMakeCurrent(void* window) { } void* pojavCreateContext(void* contextSrc) { + if (config_renderer == RENDERER_VULKAN) { + return (__bridge void *)(((SurfaceViewController *)viewController).surfaceView.layer); + } + if (config_renderer == RENDERER_MTL_ANGLE) { const EGLint ctx_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 3, diff --git a/Natives/glfw_keycodes.h b/Natives/glfw_keycodes.h index a5d0dacc..ef1151fc 100644 --- a/Natives/glfw_keycodes.h +++ b/Natives/glfw_keycodes.h @@ -30,6 +30,11 @@ #pragma once +#define GLFW_CLIENT_API 0x22001 +/* Consider GLFW_NO_API as Vulkan API */ +#define GLFW_NO_API 0 +#define GLFW_OPENGL_API 0x30001 + /*! @defgroup hat_state Joystick hat states * @brief Joystick hat states. * diff --git a/Natives/resources/Frameworks/liblwjgl_vma.dylib b/Natives/resources/Frameworks/liblwjgl_vma.dylib new file mode 100644 index 00000000..43df6867 Binary files /dev/null and b/Natives/resources/Frameworks/liblwjgl_vma.dylib differ diff --git a/Natives/resources/Frameworks/libshaderc.dylib b/Natives/resources/Frameworks/libshaderc.dylib new file mode 100644 index 00000000..bbe8b8dd Binary files /dev/null and b/Natives/resources/Frameworks/libshaderc.dylib differ diff --git a/README.md b/README.md index 636b0313..a4e0e788 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,7 @@ PojavLauncher is amazing, and surprisingly stable, and it wouldn't be this way w - [DBNumberedSlider](https://github.com/immago/DBNumberedSlider): [Apache 2.0 License](https://github.com/immago/DBNumberedSlider/blob/master/LICENSE) - [fishhook](https://github.com/facebook/fishhook) (jailed environment usage only): [BSD-3 License](https://github.com/facebook/fishhook/blob/main/LICENSE). - [Java Native Access](https://github.com/java-native-access/jna): [Apache 2.0 License](https://github.com/java-native-access/jna/blob/master/LICENSE). +- [shaderc](https://github.com/google/shaderc) (used by mods that uses Vulkan for rendering): [Apache 2.0 License](https://github.com/google/shaderc/blob/main/LICENSE).