Fixes + Refactor

This commit is contained in:
Florian RICHER 2025-05-20 13:23:05 +02:00
parent 2dee61f8e0
commit 9f713edf62
17 changed files with 206 additions and 93 deletions

3
.envrc
View file

@ -1,2 +1 @@
use flake use flake --impure

View file

@ -1,5 +1,10 @@
# Project # Project
## Info
Extensions used : `
vscjava.vscode-java-pack`
## Usefull command ## Usefull command
1. Compile 1. Compile

25
flake.lock generated
View file

@ -18,6 +18,30 @@
"type": "github" "type": "github"
} }
}, },
"nixgl": {
"inputs": {
"flake-utils": [
"flake-utils"
],
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1735283791,
"narHash": "sha256-JlT4VFs8aVlW+l151HZIZumfFsccZXcO/k5WpbYF09Y=",
"owner": "phirsch",
"repo": "nixGL",
"rev": "ea8baea3b9d854bf9cf5c834a805c50948dd2603",
"type": "github"
},
"original": {
"owner": "phirsch",
"ref": "fix-versionMatch",
"repo": "nixGL",
"type": "github"
}
},
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1728538411, "lastModified": 1728538411,
@ -37,6 +61,7 @@
"root": { "root": {
"inputs": { "inputs": {
"flake-utils": "flake-utils", "flake-utils": "flake-utils",
"nixgl": "nixgl",
"nixpkgs": "nixpkgs" "nixpkgs": "nixpkgs"
} }
}, },

View file

@ -4,26 +4,39 @@
inputs = { inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
flake-utils.url = "github:numtide/flake-utils"; flake-utils.url = "github:numtide/flake-utils";
nixgl = {
# Revert this to community version when https://github.com/nix-community/nixGL/pull/187 is merged
url = "github:phirsch/nixGL/fix-versionMatch";
inputs.nixpkgs.follows = "nixpkgs";
inputs.flake-utils.follows = "flake-utils";
};
}; };
outputs = { self, nixpkgs, flake-utils }: outputs = { nixpkgs, flake-utils, nixgl, ... }:
flake-utils.lib.eachSystem flake-utils.lib.allSystems (system: flake-utils.lib.eachSystem flake-utils.lib.allSystems (system:
let let
pkgs = import nixpkgs { inherit system; }; overlays = [ nixgl.overlay ];
pkgs = import nixpkgs {
inherit system overlays;
config.allowUnfree = true;
};
buildInputs = with pkgs; [ vulkan-headers vulkan-loader vulkan-validation-layers renderdoc ]; buildInputs = with pkgs; [ vulkan-headers vulkan-loader vulkan-validation-layers renderdoc ];
mkCustomShell = { extraPkgs ? [] }: pkgs.mkShell {
LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath buildInputs;
VK_LAYER_PATH = "${pkgs.vulkan-validation-layers}/share/vulkan/explicit_layer.d:${pkgs.renderdoc}/share/vulkan/implicit_layer.d";
packages = with pkgs; [
jdk22
maven
] ++ extraPkgs;
};
in in
{ {
devShells = { devShells = {
default = pkgs.mkShell { default = mkCustomShell { extraPkgs = [ pkgs.nixgl.auto.nixVulkanNvidia pkgs.nixgl.nixVulkanMesa ]; };
LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath buildInputs; nixos = mkCustomShell {};
VK_LAYER_PATH = "${pkgs.vulkan-validation-layers}/share/vulkan/explicit_layer.d:${pkgs.renderdoc}/share/vulkan/implicit_layer.d";
packages = with pkgs; [
jdk22
maven
];
};
}; };
}); });
} }

11
pom.xml
View file

@ -16,6 +16,7 @@
<maven.compiler.release>21</maven.compiler.release> <maven.compiler.release>21</maven.compiler.release>
<maven-compiler-plugin.version>3.13.0</maven-compiler-plugin.version> <maven-compiler-plugin.version>3.13.0</maven-compiler-plugin.version>
<maven-shade-plugin.version>3.6.0</maven-shade-plugin.version> <maven-shade-plugin.version>3.6.0</maven-shade-plugin.version>
<maven-mojo-exec-plugin.version>3.1.0</maven-mojo-exec-plugin.version>
<lwjgl.version>3.3.6</lwjgl.version> <lwjgl.version>3.3.6</lwjgl.version>
<joml.version>1.10.8</joml.version> <joml.version>1.10.8</joml.version>
<tinylog.version>2.7.0</tinylog.version> <tinylog.version>2.7.0</tinylog.version>
@ -204,11 +205,11 @@
</dependencies> </dependencies>
<build> <build>
<sourceDirectory>src</sourceDirectory> <sourceDirectory>src/main/java</sourceDirectory>
<resources> <resources>
<resource> <resource>
<directory>res</directory> <directory>src/main/resources</directory>
</resource> </resource>
</resources> </resources>
<plugins> <plugins>
<plugin> <plugin>
@ -218,7 +219,7 @@
<plugin> <plugin>
<groupId>org.codehaus.mojo</groupId> <groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId> <artifactId>exec-maven-plugin</artifactId>
<version>3.1.0</version> <version>${maven-mojo-exec-plugin.version}</version>
<configuration> <configuration>
<mainClass>${main.class}</mainClass> <mainClass>${main.class}</mainClass>
</configuration> </configuration>

View file

@ -1,6 +1,9 @@
package fr.mrdev023.vulkan_java; package fr.mrdev023.vulkan_java;
import fr.mrdev023.vulkan_java.renderer.Vulkan; import org.tinylog.Logger;
import fr.mrdev023.vulkan_java.vk.Vulkan;
import fr.mrdev023.vulkan_java.vk.VulkanError;
import fr.mrdev023.vulkan_java.window.Display; import fr.mrdev023.vulkan_java.window.Display;
import fr.mrdev023.vulkan_java.window.Input; import fr.mrdev023.vulkan_java.window.Input;
@ -9,7 +12,12 @@ public class App {
Display.create("My first application", 800, 600); Display.create("My first application", 800, 600);
Display.printMonitorsInfo(); Display.printMonitorsInfo();
Input.init(); Input.init();
Vulkan.init(); try {
Vulkan.init();
} catch (VulkanError e) {
Logger.error(e.getMessage());
System.exit(1);
}
while (!Display.isCloseRequested()) { while (!Display.isCloseRequested()) {
Display.updateEvent(); Display.updateEvent();

View file

@ -1,4 +1,4 @@
package fr.mrdev023.vulkan_java.renderer; package fr.mrdev023.vulkan_java.vk;
import org.lwjgl.PointerBuffer; import org.lwjgl.PointerBuffer;
import org.lwjgl.system.MemoryStack; import org.lwjgl.system.MemoryStack;
@ -8,8 +8,7 @@ import org.tinylog.Logger;
import java.nio.*; import java.nio.*;
import java.util.*; import java.util.*;
import static fr.mrdev023.vulkan_java.renderer.VulkanUtils.vkCheck; import static fr.mrdev023.vulkan_java.vk.VulkanError.vkCheck;
import static org.lwjgl.vulkan.KHRPortabilitySubset.VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME;
import static org.lwjgl.vulkan.VK11.*; import static org.lwjgl.vulkan.VK11.*;
public class Device { public class Device {
@ -17,20 +16,21 @@ public class Device {
private final PhysicalDevice physicalDevice; private final PhysicalDevice physicalDevice;
private final VkDevice vkDevice; private final VkDevice vkDevice;
public Device(PhysicalDevice physicalDevice) { public Device(PhysicalDevice physicalDevice) throws VulkanError {
Logger.debug("Creating device");
this.physicalDevice = physicalDevice; this.physicalDevice = physicalDevice;
try (MemoryStack stack = MemoryStack.stackPush()) {
try (MemoryStack stack = MemoryStack.stackPush()) {
// Define required extensions // Define required extensions
Set<String> deviceExtensions = getDeviceExtensions(); Set<String> deviceExtensions = getDeviceExtensions();
boolean usePortability = deviceExtensions.contains(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME) && VulkanUtils.getOS() == VulkanUtils.OSType.MACOS; boolean usePortability = deviceExtensions
.contains(KHRPortabilitySubset.VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME)
&& VulkanUtils.getOS() == VulkanUtils.OSType.MACOS;
int numExtensions = usePortability ? 2 : 1; int numExtensions = usePortability ? 2 : 1;
PointerBuffer requiredExtensions = stack.mallocPointer(numExtensions); PointerBuffer requiredExtensions = stack.mallocPointer(numExtensions);
requiredExtensions.put(stack.ASCII(KHRSwapchain.VK_KHR_SWAPCHAIN_EXTENSION_NAME)); requiredExtensions.put(stack.ASCII(KHRSwapchain.VK_KHR_SWAPCHAIN_EXTENSION_NAME));
if (usePortability) { if (usePortability) {
requiredExtensions.put(stack.ASCII(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME)); requiredExtensions.put(stack.ASCII(KHRPortabilitySubset.VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME));
} }
requiredExtensions.flip(); requiredExtensions.flip();
@ -40,7 +40,8 @@ public class Device {
// Enable all the queue families // Enable all the queue families
VkQueueFamilyProperties.Buffer queuePropsBuff = physicalDevice.getVkQueueFamilyProps(); VkQueueFamilyProperties.Buffer queuePropsBuff = physicalDevice.getVkQueueFamilyProps();
int numQueuesFamilies = queuePropsBuff.capacity(); int numQueuesFamilies = queuePropsBuff.capacity();
VkDeviceQueueCreateInfo.Buffer queueCreationInfoBuf = VkDeviceQueueCreateInfo.calloc(numQueuesFamilies, stack); VkDeviceQueueCreateInfo.Buffer queueCreationInfoBuf = VkDeviceQueueCreateInfo.calloc(numQueuesFamilies,
stack);
for (int i = 0; i < numQueuesFamilies; i++) { for (int i = 0; i < numQueuesFamilies; i++) {
FloatBuffer priorities = stack.callocFloat(queuePropsBuff.get(i).queueCount()); FloatBuffer priorities = stack.callocFloat(queuePropsBuff.get(i).queueCount());
queueCreationInfoBuf.get(i) queueCreationInfoBuf.get(i)
@ -60,6 +61,8 @@ public class Device {
"Failed to create device"); "Failed to create device");
vkDevice = new VkDevice(pp.get(0), physicalDevice.getVkPhysicalDevice(), deviceCreateInfo); vkDevice = new VkDevice(pp.get(0), physicalDevice.getVkPhysicalDevice(), deviceCreateInfo);
} }
Logger.debug("Vulkan device created");
} }
public void destroy() { public void destroy() {
@ -67,21 +70,31 @@ public class Device {
vkDestroyDevice(vkDevice, null); vkDestroyDevice(vkDevice, null);
} }
private Set<String> getDeviceExtensions() { private Set<String> getDeviceExtensions() throws VulkanError {
Set<String> deviceExtensions = new HashSet<>(); Set<String> deviceExtensions = new HashSet<>();
try (MemoryStack stack = MemoryStack.stackPush()) { try (MemoryStack stack = MemoryStack.stackPush()) {
// Get the number of device extensions
IntBuffer numExtensionsBuf = stack.callocInt(1); IntBuffer numExtensionsBuf = stack.callocInt(1);
vkEnumerateDeviceExtensionProperties(physicalDevice.getVkPhysicalDevice(), (String) null, numExtensionsBuf, null); int result = vkEnumerateDeviceExtensionProperties(physicalDevice.getVkPhysicalDevice(), (String) null,
int numExtensions = numExtensionsBuf.get(0); numExtensionsBuf,
Logger.debug("Device supports [{}] extensions", numExtensions); null);
vkCheck(result, "Failed to enumerate device extension properties");
int numExtensions = numExtensionsBuf.get(0);
Logger.debug("Vulkan device supported extensions ({}):", numExtensions);
// Get the device extensions
VkExtensionProperties.Buffer propsBuff = VkExtensionProperties.calloc(numExtensions, stack); VkExtensionProperties.Buffer propsBuff = VkExtensionProperties.calloc(numExtensions, stack);
vkEnumerateDeviceExtensionProperties(physicalDevice.getVkPhysicalDevice(), (String) null, numExtensionsBuf, propsBuff); result = vkEnumerateDeviceExtensionProperties(physicalDevice.getVkPhysicalDevice(), (String) null,
numExtensionsBuf,
propsBuff);
vkCheck(result, "Failed to enumerate device extension properties");
for (int i = 0; i < numExtensions; i++) { for (int i = 0; i < numExtensions; i++) {
VkExtensionProperties props = propsBuff.get(i); VkExtensionProperties props = propsBuff.get(i);
String extensionName = props.extensionNameString(); String extensionName = props.extensionNameString();
deviceExtensions.add(extensionName); deviceExtensions.add(extensionName);
Logger.debug("Supported device extension [{}]", extensionName); Logger.debug("\t - {}", extensionName);
} }
} }
return deviceExtensions; return deviceExtensions;

View file

@ -1,4 +1,4 @@
package fr.mrdev023.vulkan_java.renderer; package fr.mrdev023.vulkan_java.vk;
import org.lwjgl.PointerBuffer; import org.lwjgl.PointerBuffer;
import org.lwjgl.glfw.GLFWVulkan; import org.lwjgl.glfw.GLFWVulkan;
@ -9,7 +9,7 @@ import org.tinylog.Logger;
import java.nio.*; import java.nio.*;
import java.util.*; import java.util.*;
import static fr.mrdev023.vulkan_java.renderer.VulkanUtils.vkCheck; import static fr.mrdev023.vulkan_java.vk.VulkanError.vkCheck;
import static org.lwjgl.vulkan.EXTDebugUtils.*; import static org.lwjgl.vulkan.EXTDebugUtils.*;
import static org.lwjgl.vulkan.KHRPortabilityEnumeration.VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; import static org.lwjgl.vulkan.KHRPortabilityEnumeration.VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
import static org.lwjgl.vulkan.VK11.*; import static org.lwjgl.vulkan.VK11.*;
@ -28,7 +28,7 @@ public class Instance {
private VkDebugUtilsMessengerCreateInfoEXT debugUtils; private VkDebugUtilsMessengerCreateInfoEXT debugUtils;
private long vkDebugHandle; private long vkDebugHandle;
public Instance(boolean validate) { public Instance(boolean validate) throws VulkanError {
Logger.debug("Creating Vulkan instance"); Logger.debug("Creating Vulkan instance");
try (MemoryStack stack = MemoryStack.stackPush()) { try (MemoryStack stack = MemoryStack.stackPush()) {
// Create application information // Create application information
@ -47,11 +47,12 @@ public class Instance {
boolean supportsValidation = validate; boolean supportsValidation = validate;
if (validate && numValidationLayers == 0) { if (validate && numValidationLayers == 0) {
supportsValidation = false; supportsValidation = false;
Logger.warn("Request validation but no supported validation layers found. Falling back to no validation"); Logger.warn(
"Request validation but no supported validation layers found. Falling back to no validation");
} }
Logger.debug("Validation: {}", supportsValidation); Logger.debug("Validation: {}", supportsValidation);
// Set required layers // Set required layers
PointerBuffer requiredLayers = null; PointerBuffer requiredLayers = null;
if (supportsValidation) { if (supportsValidation) {
requiredLayers = stack.mallocPointer(numValidationLayers); requiredLayers = stack.mallocPointer(numValidationLayers);
@ -115,7 +116,8 @@ public class Instance {
vkDebugHandle = VK_NULL_HANDLE; vkDebugHandle = VK_NULL_HANDLE;
if (supportsValidation) { if (supportsValidation) {
LongBuffer longBuff = stack.mallocLong(1); LongBuffer longBuff = stack.mallocLong(1);
vkCheck(vkCreateDebugUtilsMessengerEXT(vkInstance, debugUtils, null, longBuff), "Error creating debug utils"); vkCheck(vkCreateDebugUtilsMessengerEXT(vkInstance, debugUtils, null, longBuff),
"Error creating debug utils");
vkDebugHandle = longBuff.get(0); vkDebugHandle = longBuff.get(0);
} }
} }
@ -128,7 +130,8 @@ public class Instance {
.messageSeverity(MESSAGE_SEVERITY_BITMASK) .messageSeverity(MESSAGE_SEVERITY_BITMASK)
.messageType(MESSAGE_TYPE_BITMASK) .messageType(MESSAGE_TYPE_BITMASK)
.pfnUserCallback((messageSeverity, messageTypes, pCallbackData, pUserData) -> { .pfnUserCallback((messageSeverity, messageTypes, pCallbackData, pUserData) -> {
VkDebugUtilsMessengerCallbackDataEXT callbackData = VkDebugUtilsMessengerCallbackDataEXT.create(pCallbackData); VkDebugUtilsMessengerCallbackDataEXT callbackData = VkDebugUtilsMessengerCallbackDataEXT
.create(pCallbackData);
if ((messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) != 0) { if ((messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) != 0) {
Logger.info("VkDebugUtilsCallback, {}", callbackData.pMessageString()); Logger.info("VkDebugUtilsCallback, {}", callbackData.pMessageString());
} else if ((messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) != 0) { } else if ((messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) != 0) {

View file

@ -1,4 +1,4 @@
package fr.mrdev023.vulkan_java.renderer; package fr.mrdev023.vulkan_java.vk;
import org.lwjgl.PointerBuffer; import org.lwjgl.PointerBuffer;
import org.lwjgl.system.MemoryStack; import org.lwjgl.system.MemoryStack;
@ -8,7 +8,7 @@ import org.tinylog.Logger;
import java.nio.IntBuffer; import java.nio.IntBuffer;
import java.util.*; import java.util.*;
import static fr.mrdev023.vulkan_java.renderer.VulkanUtils.vkCheck; import static fr.mrdev023.vulkan_java.vk.VulkanError.vkCheck;
import static org.lwjgl.vulkan.VK11.*; import static org.lwjgl.vulkan.VK11.*;
public class PhysicalDevice { public class PhysicalDevice {
@ -20,7 +20,7 @@ public class PhysicalDevice {
private final VkPhysicalDeviceProperties vkPhysicalDeviceProperties; private final VkPhysicalDeviceProperties vkPhysicalDeviceProperties;
private final VkQueueFamilyProperties.Buffer vkQueueFamilyProps; private final VkQueueFamilyProperties.Buffer vkQueueFamilyProps;
private PhysicalDevice(VkPhysicalDevice vkPhysicalDevice) { private PhysicalDevice(VkPhysicalDevice vkPhysicalDevice) throws VulkanError {
try (MemoryStack stack = MemoryStack.stackPush()) { try (MemoryStack stack = MemoryStack.stackPush()) {
this.vkPhysicalDevice = vkPhysicalDevice; this.vkPhysicalDevice = vkPhysicalDevice;
@ -34,7 +34,8 @@ public class PhysicalDevice {
vkCheck(vkEnumerateDeviceExtensionProperties(vkPhysicalDevice, (String) null, intBuffer, null), vkCheck(vkEnumerateDeviceExtensionProperties(vkPhysicalDevice, (String) null, intBuffer, null),
"Failed to get number of device extension properties"); "Failed to get number of device extension properties");
vkDeviceExtensions = VkExtensionProperties.calloc(intBuffer.get(0)); vkDeviceExtensions = VkExtensionProperties.calloc(intBuffer.get(0));
vkCheck(vkEnumerateDeviceExtensionProperties(vkPhysicalDevice, (String) null, intBuffer, vkDeviceExtensions), vkCheck(vkEnumerateDeviceExtensionProperties(vkPhysicalDevice, (String) null, intBuffer,
vkDeviceExtensions),
"Failed to get extension properties"); "Failed to get extension properties");
// Get Queue family properties // Get Queue family properties
@ -51,7 +52,8 @@ public class PhysicalDevice {
} }
} }
public static PhysicalDevice createPhysicalDevice(Instance instance, Optional<String> preferredDeviceName) { public static PhysicalDevice createPhysicalDevice(Instance instance, Optional<String> preferredDeviceName)
throws VulkanError {
Logger.debug("Selecting physical devices"); Logger.debug("Selecting physical devices");
PhysicalDevice selectedPhysicalDevice = null; PhysicalDevice selectedPhysicalDevice = null;
try (MemoryStack stack = MemoryStack.stackPush()) { try (MemoryStack stack = MemoryStack.stackPush()) {
@ -65,7 +67,8 @@ public class PhysicalDevice {
// Populate available devices // Populate available devices
List<PhysicalDevice> devices = new ArrayList<>(); List<PhysicalDevice> devices = new ArrayList<>();
for (int i = 0; i < numDevices; i++) { for (int i = 0; i < numDevices; i++) {
VkPhysicalDevice vkPhysicalDevice = new VkPhysicalDevice(pPhysicalDevices.get(i), instance.getVkInstance()); VkPhysicalDevice vkPhysicalDevice = new VkPhysicalDevice(pPhysicalDevices.get(i),
instance.getVkInstance());
PhysicalDevice physicalDevice = new PhysicalDevice(vkPhysicalDevice); PhysicalDevice physicalDevice = new PhysicalDevice(vkPhysicalDevice);
String deviceName = physicalDevice.getDeviceName(); String deviceName = physicalDevice.getDeviceName();
@ -83,7 +86,8 @@ public class PhysicalDevice {
} }
// No preferred device or it does not meet requirements, just pick the first one // No preferred device or it does not meet requirements, just pick the first one
selectedPhysicalDevice = selectedPhysicalDevice == null && !devices.isEmpty() ? devices.remove(0) : selectedPhysicalDevice; selectedPhysicalDevice = selectedPhysicalDevice == null && !devices.isEmpty() ? devices.remove(0)
: selectedPhysicalDevice;
// Clean up non-selected devices // Clean up non-selected devices
for (PhysicalDevice physicalDevice : devices) { for (PhysicalDevice physicalDevice : devices) {
@ -99,7 +103,7 @@ public class PhysicalDevice {
return selectedPhysicalDevice; return selectedPhysicalDevice;
} }
protected static PointerBuffer getPhysicalDevices(Instance instance, MemoryStack stack) { protected static PointerBuffer getPhysicalDevices(Instance instance, MemoryStack stack) throws VulkanError {
PointerBuffer pPhysicalDevices; PointerBuffer pPhysicalDevices;
// Get number of physical devices // Get number of physical devices
IntBuffer intBuffer = stack.mallocInt(1); IntBuffer intBuffer = stack.mallocInt(1);

View file

@ -1,4 +1,4 @@
package fr.mrdev023.vulkan_java.renderer; package fr.mrdev023.vulkan_java.vk;
import org.lwjgl.PointerBuffer; import org.lwjgl.PointerBuffer;
import org.lwjgl.system.MemoryStack; import org.lwjgl.system.MemoryStack;

View file

@ -1,11 +1,12 @@
package fr.mrdev023.vulkan_java.renderer; package fr.mrdev023.vulkan_java.vk;
import org.lwjgl.glfw.GLFWVulkan; import org.lwjgl.glfw.GLFWVulkan;
import org.lwjgl.system.MemoryStack; import org.lwjgl.system.MemoryStack;
import org.lwjgl.vulkan.KHRSurface; import org.lwjgl.vulkan.KHRSurface;
import org.lwjgl.vulkan.VK10;
import org.tinylog.Logger; import org.tinylog.Logger;
import static fr.mrdev023.vulkan_java.vk.VulkanError.vkCheck;
import java.nio.LongBuffer; import java.nio.LongBuffer;
public class Surface { public class Surface {
@ -13,25 +14,26 @@ public class Surface {
private final PhysicalDevice physicalDevice; private final PhysicalDevice physicalDevice;
private final long vkSurface; private final long vkSurface;
public Surface(PhysicalDevice physicalDevice, long windowHandle) { public Surface(PhysicalDevice physicalDevice, long windowHandle) throws VulkanError {
Logger.debug("Creating Vulkan surface");
this.physicalDevice = physicalDevice; this.physicalDevice = physicalDevice;
try (MemoryStack stack = MemoryStack.stackPush()) { try (MemoryStack stack = MemoryStack.stackPush()) {
LongBuffer pSurface = stack.mallocLong(1); LongBuffer pSurface = stack.mallocLong(1);
var result = GLFWVulkan.glfwCreateWindowSurface(this.physicalDevice.getVkPhysicalDevice().getInstance(), windowHandle,
null, pSurface);
if (result != VK10.VK_SUCCESS) { var result = GLFWVulkan.glfwCreateWindowSurface(this.physicalDevice.getVkPhysicalDevice().getInstance(),
throw new RuntimeException("Failed to create Vulkan surface"); windowHandle,
} null, pSurface);
vkCheck(result, "Failed to create Vulkan Surface");
vkSurface = pSurface.get(0); vkSurface = pSurface.get(0);
} }
Logger.debug("Vulkan surface created");
} }
public void destroy() { public void destroy() {
Logger.debug("Destroying Vulkan surface");
KHRSurface.vkDestroySurfaceKHR(physicalDevice.getVkPhysicalDevice().getInstance(), vkSurface, null); KHRSurface.vkDestroySurfaceKHR(physicalDevice.getVkPhysicalDevice().getInstance(), vkSurface, null);
Logger.debug("Vulkan surface destroyed");
} }
public long getVkSurface() { public long getVkSurface() {

View file

@ -1,4 +1,4 @@
package fr.mrdev023.vulkan_java.renderer; package fr.mrdev023.vulkan_java.vk;
import fr.mrdev023.vulkan_java.window.Display; import fr.mrdev023.vulkan_java.window.Display;
@ -14,7 +14,7 @@ public class Vulkan {
private static Surface surface; private static Surface surface;
private static Queue.GraphicsQueue graphicsQueue; private static Queue.GraphicsQueue graphicsQueue;
public static void init() { public static void init() throws VulkanError {
if (!glfwVulkanSupported()) { if (!glfwVulkanSupported()) {
throw new IllegalStateException("Cannot find a compatible Vulkan installable client driver (ICD)"); throw new IllegalStateException("Cannot find a compatible Vulkan installable client driver (ICD)");
} }

View file

@ -0,0 +1,39 @@
package fr.mrdev023.vulkan_java.vk;
import org.lwjgl.vulkan.VK10;
public class VulkanError extends Exception {
private VulkanError(int vulkanCode, String message) {
super(String.format("Vulkan error (Code: %s, Message: %s)", parseVulkanCode(vulkanCode), message));
}
public static void vkCheck(int result, String message) throws VulkanError {
if (result != VK10.VK_SUCCESS) {
throw new VulkanError(result, message);
}
}
private static String parseVulkanCode(int code) {
return switch (code) {
case VK10.VK_NOT_READY -> "VK_NOT_READY";
case VK10.VK_TIMEOUT -> "VK_TIMEOUT";
case VK10.VK_EVENT_SET -> "VK_EVENT_SET";
case VK10.VK_EVENT_RESET -> "VK_EVENT_RESET";
case VK10.VK_INCOMPLETE -> "VK_INCOMPLETE";
case VK10.VK_ERROR_OUT_OF_HOST_MEMORY -> "VK_ERROR_OUT_OF_HOST_MEMORY";
case VK10.VK_ERROR_OUT_OF_DEVICE_MEMORY -> "VK_ERROR_OUT_OF_DEVICE_MEMORY";
case VK10.VK_ERROR_INITIALIZATION_FAILED -> "VK_ERROR_INITIALIZATION_FAILED";
case VK10.VK_ERROR_DEVICE_LOST -> "VK_ERROR_DEVICE_LOST";
case VK10.VK_ERROR_MEMORY_MAP_FAILED -> "VK_ERROR_MEMORY_MAP_FAILED";
case VK10.VK_ERROR_LAYER_NOT_PRESENT -> "VK_ERROR_LAYER_NOT_PRESENT";
case VK10.VK_ERROR_EXTENSION_NOT_PRESENT -> "VK_ERROR_EXTENSION_NOT_PRESENT";
case VK10.VK_ERROR_FEATURE_NOT_PRESENT -> "VK_ERROR_FEATURE_NOT_PRESENT";
case VK10.VK_ERROR_INCOMPATIBLE_DRIVER -> "VK_ERROR_INCOMPATIBLE_DRIVER";
case VK10.VK_ERROR_TOO_MANY_OBJECTS -> "VK_ERROR_TOO_MANY_OBJECTS";
case VK10.VK_ERROR_FORMAT_NOT_SUPPORTED -> "VK_ERROR_FORMAT_NOT_SUPPORTED";
case VK10.VK_ERROR_FRAGMENTED_POOL -> "VK_ERROR_FRAGMENTED_POOL";
case VK10.VK_ERROR_UNKNOWN -> "VK_ERROR_UNKNOWN";
default -> String.format("UNKNOWN(%s)", code);
};
}
}

View file

@ -1,15 +1,9 @@
package fr.mrdev023.vulkan_java.renderer; package fr.mrdev023.vulkan_java.vk;
import java.util.Locale; import java.util.Locale;
import static org.lwjgl.vulkan.VK11.VK_SUCCESS;
public class VulkanUtils { public class VulkanUtils {
private VulkanUtils() {
// Utility class
}
public static OSType getOS() { public static OSType getOS() {
OSType result; OSType result;
String os = System.getProperty("os.name", "generic").toLowerCase(Locale.ENGLISH); String os = System.getProperty("os.name", "generic").toLowerCase(Locale.ENGLISH);
@ -26,11 +20,7 @@ public class VulkanUtils {
return result; return result;
} }
public static void vkCheck(int err, String errMsg) { public enum OSType {
if (err != VK_SUCCESS) { WINDOWS, MACOS, LINUX, OTHER
throw new RuntimeException(errMsg + ": " + err);
}
} }
public enum OSType {WINDOWS, MACOS, LINUX, OTHER}
} }

View file

@ -1,6 +1,5 @@
package fr.mrdev023.vulkan_java.window; package fr.mrdev023.vulkan_java.window;
import static org.lwjgl.glfw.Callbacks.glfwFreeCallbacks;
import static org.lwjgl.glfw.GLFW.*; import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.system.MemoryUtil.*; import static org.lwjgl.system.MemoryUtil.*;
@ -22,13 +21,13 @@ public class Display {
TITLE = title; TITLE = title;
displayMode = new DisplayMode(width, height); displayMode = new DisplayMode(width, height);
// Configure GLFW for Vulkan // Configure GLFW for Vulkan
glfwDefaultWindowHints(); glfwDefaultWindowHints();
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); // Tell GLFW not to create an OpenGL context glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); // Tell GLFW not to create an OpenGL context
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
// Create the window // Create the window
window = glfwCreateWindow(displayMode.getWidth(), displayMode.getHeight(), TITLE, NULL, NULL); window = glfwCreateWindow(displayMode.getWidth(), displayMode.getHeight(), TITLE, NULL, NULL);
if (window == NULL) if (window == NULL)
@ -47,8 +46,10 @@ public class Display {
} }
public static void setVSync(boolean a) { public static void setVSync(boolean a) {
if (a) glfwSwapInterval(1); if (a)
else glfwSwapInterval(0); glfwSwapInterval(1);
else
glfwSwapInterval(0);
} }
public static void setSample(int sample) { public static void setSample(int sample) {
@ -56,8 +57,10 @@ public class Display {
} }
public static void setResizable(boolean a) { public static void setResizable(boolean a) {
if (a) glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); if (a)
else glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
else
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
} }
public static void setTitle(String title) { public static void setTitle(String title) {
@ -76,7 +79,8 @@ public class Display {
int width = w.get(0); int width = w.get(0);
int height = h.get(0); int height = h.get(0);
if (Display.getDisplayMode().getWidth() != width || Display.getDisplayMode().getHeight() != height || hasResized) { if (Display.getDisplayMode().getWidth() != width || Display.getDisplayMode().getHeight() != height
|| hasResized) {
setDisplayMode(new DisplayMode(width, height)); setDisplayMode(new DisplayMode(width, height));
hasResized = false; hasResized = false;
return true; return true;
@ -94,9 +98,11 @@ public class Display {
} }
for (int i = 0; i < monitors.capacity(); i++) { for (int i = 0; i < monitors.capacity(); i++) {
m = glfwGetVideoMode(monitors.get(i)); m = glfwGetVideoMode(monitors.get(i));
if (m == null) continue; if (m == null)
continue;
System.out.println(glfwGetMonitorName(monitors.get(i)) + "(" + i + ") : " + m.width() + "x" + m.height() + ":" + m.refreshRate() + "Hz"); System.out.println(glfwGetMonitorName(monitors.get(i)) + "(" + i + ") : " + m.width() + "x" + m.height()
+ ":" + m.refreshRate() + "Hz");
} }
} }
@ -118,7 +124,8 @@ public class Display {
} }
public static void setDisplayMode(DisplayMode displayMode) { public static void setDisplayMode(DisplayMode displayMode) {
if (Display.displayMode == null || displayMode == null) return; if (Display.displayMode == null || displayMode == null)
return;
Display.displayMode.setDisplayMode(displayMode); Display.displayMode.setDisplayMode(displayMode);
hasResized = true; hasResized = true;
} }
@ -132,5 +139,4 @@ public class Display {
return window; return window;
} }
} }

View file

@ -65,7 +65,8 @@ public class Input {
int i = set.getKey(); int i = set.getKey();
int st = set.getValue(); int st = set.getValue();
if (i > -1 && i < NBRE_KEY) { if (i > -1 && i < NBRE_KEY) {
if (glfwGetKey(Display.getWindow(), i) == 0 && st == NONE) continue; if (glfwGetKey(Display.getWindow(), i) == 0 && st == NONE)
continue;
if (glfwGetKey(Display.getWindow(), i) == 1 && st == NONE) { if (glfwGetKey(Display.getWindow(), i) == 1 && st == NONE) {
state.replace(i, PRESSED); state.replace(i, PRESSED);
} else if (glfwGetKey(Display.getWindow(), i) == 1 && st == PRESSED) { } else if (glfwGetKey(Display.getWindow(), i) == 1 && st == PRESSED) {
@ -76,12 +77,14 @@ public class Input {
state.replace(i, NONE); state.replace(i, NONE);
} }
} else if (i >= MOUSE_OFFSET && i < MOUSE_OFFSET + NBRE_BUTTON) { } else if (i >= MOUSE_OFFSET && i < MOUSE_OFFSET + NBRE_BUTTON) {
if (glfwGetMouseButton(Display.getWindow(), i - MOUSE_OFFSET) == 0 && st == NONE) continue; if (glfwGetMouseButton(Display.getWindow(), i - MOUSE_OFFSET) == 0 && st == NONE)
continue;
if (glfwGetMouseButton(Display.getWindow(), i - MOUSE_OFFSET) == 1 && st == NONE) { if (glfwGetMouseButton(Display.getWindow(), i - MOUSE_OFFSET) == 1 && st == NONE) {
state.replace(i, PRESSED); state.replace(i, PRESSED);
} else if (glfwGetMouseButton(Display.getWindow(), i - MOUSE_OFFSET) == 1 && st == PRESSED) { } else if (glfwGetMouseButton(Display.getWindow(), i - MOUSE_OFFSET) == 1 && st == PRESSED) {
state.replace(i, REPEATED); state.replace(i, REPEATED);
} else if (glfwGetMouseButton(Display.getWindow(), i - MOUSE_OFFSET) == 0 && (st == PRESSED || st == REPEATED)) { } else if (glfwGetMouseButton(Display.getWindow(), i - MOUSE_OFFSET) == 0
&& (st == PRESSED || st == REPEATED)) {
state.replace(i, RELEASED); state.replace(i, RELEASED);
} else if (glfwGetMouseButton(Display.getWindow(), i - MOUSE_OFFSET) == 0 && st == RELEASED) { } else if (glfwGetMouseButton(Display.getWindow(), i - MOUSE_OFFSET) == 0 && st == RELEASED) {
state.replace(i, NONE); state.replace(i, NONE);

View file

@ -0,0 +1,2 @@
writer = console
writer.format = {level}: {class}: {message}