Ginger3D/src/main/java/com/github/hydos/ginger/engine/vulkan/utils/VKUtils.java

243 lines
9.8 KiB
Java

package com.github.hydos.ginger.engine.vulkan.utils;
import java.nio.IntBuffer;
import java.util.stream.IntStream;
import org.lwjgl.PointerBuffer;
import org.lwjgl.glfw.*;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.vulkan.*;
import com.github.hydos.ginger.engine.vulkan.VKConstants;
public class VKUtils
{
private static PointerBuffer getRequiredExtensions() {
PointerBuffer glfwExtensions = GLFWVulkan.glfwGetRequiredInstanceExtensions();
return glfwExtensions;
}
public static void createInstance() {
try(MemoryStack stack = MemoryStack.stackPush()) {
// Use calloc to initialize the structs with 0s. Otherwise, the program can crash due to random values
VkApplicationInfo appInfo = VkApplicationInfo.callocStack(stack);
appInfo.sType(VK12.VK_STRUCTURE_TYPE_APPLICATION_INFO);
appInfo.pApplicationName(stack.UTF8Safe("GingerGame"));
appInfo.applicationVersion(VK12.VK_MAKE_VERSION(1, 0, 0));
appInfo.pEngineName(stack.UTF8Safe("Ginger2"));
appInfo.engineVersion(VK12.VK_MAKE_VERSION(2, 0, 0));
appInfo.apiVersion(VK12.VK_API_VERSION_1_2);
VkInstanceCreateInfo createInfo = VkInstanceCreateInfo.callocStack(stack);
createInfo.sType(VK12.VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO);
createInfo.pApplicationInfo(appInfo);
// enabledExtensionCount is implicitly set when you call ppEnabledExtensionNames
createInfo.ppEnabledExtensionNames(getRequiredExtensions());
// We need to retrieve the pointer of the created instance
PointerBuffer instancePtr = stack.mallocPointer(1);
if(VK12.vkCreateInstance(createInfo, null, instancePtr) != VK12.VK_SUCCESS) {
throw new RuntimeException("Failed to create instance");
}
VKConstants.vulkanInstance = new VkInstance(instancePtr.get(0), createInfo);
}
}
public static void createPhysicalDevice() {
try(MemoryStack stack = MemoryStack.stackPush()) {
IntBuffer deviceCount = stack.ints(0);
VK12.vkEnumeratePhysicalDevices(VKConstants.vulkanInstance, deviceCount, null);
if(deviceCount.get(0) == 0) {
throw new RuntimeException("Failed to find GPUs with Vulkan support");
}
PointerBuffer ppPhysicalDevices = stack.mallocPointer(deviceCount.get(0));
VK12.vkEnumeratePhysicalDevices(VKConstants.vulkanInstance, deviceCount, ppPhysicalDevices);
VkPhysicalDevice device = null;
for(int i = 0;i < ppPhysicalDevices.capacity();i++) {
device = new VkPhysicalDevice(ppPhysicalDevices.get(i), VKConstants.vulkanInstance);
}
if(device == null) {
throw new RuntimeException("Failed to find a suitable GPU");
}
VKConstants.physicalDevice = device;
}
}
public static class QueueFamilyIndices {
// We use Integer to use null as the empty value
private Integer graphicsFamily;
private Integer presentFamily;
public boolean isComplete() {
return graphicsFamily != null && presentFamily != null;
}
public int[] unique() {
return IntStream.of(graphicsFamily, presentFamily).distinct().toArray();
}
}
public static void createLogicalDevice()
{
try(MemoryStack stack = MemoryStack.stackPush())
{
QueueFamilyIndices indices = findQueueFamilies();
int[] uniqueQueueFamilies = indices.unique();
VkDeviceQueueCreateInfo.Buffer queueCreateInfos = VkDeviceQueueCreateInfo.callocStack(uniqueQueueFamilies.length, stack);
for(int i = 0;i < uniqueQueueFamilies.length;i++) {
VkDeviceQueueCreateInfo queueCreateInfo = queueCreateInfos.get(i);
queueCreateInfo.sType(VK12.VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO);
queueCreateInfo.queueFamilyIndex(uniqueQueueFamilies[i]);
queueCreateInfo.pQueuePriorities(stack.floats(1.0f));
}
VkDeviceCreateInfo createInfo = VkDeviceCreateInfo.callocStack(stack);
createInfo.sType(VK12.VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO);
createInfo.pQueueCreateInfos(queueCreateInfos);
// queueCreateInfoCount is automatically set
PointerBuffer pDevice = stack.pointers(VK12.VK_NULL_HANDLE);
if(VK12.vkCreateDevice(VKConstants.physicalDevice, createInfo, null, pDevice) != VK12.VK_SUCCESS) {
throw new RuntimeException("Failed to create logical device");
}
VKConstants.device = new VkDevice(pDevice.get(0), VKConstants.physicalDevice, createInfo);
PointerBuffer pQueue = stack.pointers(VK12.VK_NULL_HANDLE);
VK12.vkGetDeviceQueue(VKConstants.device, indices.graphicsFamily, 0, pQueue);
VKConstants.graphicsQueue = new VkQueue(pQueue.get(0), VKConstants.device);
VK12.vkGetDeviceQueue(VKConstants.device, indices.presentFamily, 0, pQueue);
VKConstants.presentQueue = new VkQueue(pQueue.get(0), VKConstants.device);
}
}
private static QueueFamilyIndices findQueueFamilies() {
QueueFamilyIndices indices = new QueueFamilyIndices();
try(MemoryStack stack = MemoryStack.stackPush()) {
IntBuffer queueFamilyCount = stack.ints(0);
VK12.vkGetPhysicalDeviceQueueFamilyProperties(VKConstants.physicalDevice, queueFamilyCount, null);
VkQueueFamilyProperties.Buffer queueFamilies = VkQueueFamilyProperties.mallocStack(queueFamilyCount.get(0), stack);
VK12.vkGetPhysicalDeviceQueueFamilyProperties(VKConstants.physicalDevice, queueFamilyCount, queueFamilies);
IntBuffer presentSupport = stack.ints(VK12.VK_FALSE);
for(int i = 0;i < queueFamilies.capacity() || !indices.isComplete();i++) {
if((queueFamilies.get(i).queueFlags() & VK12.VK_QUEUE_GRAPHICS_BIT) != 0) {
indices.graphicsFamily = i;
}
KHRSurface.vkGetPhysicalDeviceSurfaceSupportKHR(
VKConstants.physicalDevice,
i, VKConstants.windowSurface,
presentSupport);
if(presentSupport.get(0) == VK12.VK_TRUE) {
indices.presentFamily = i;
}
}
return indices;
}
}
//some code from LWJGL examples for debugging (has changes)
public static String translateVulkanResult(int result) {
switch (result) {
// Success codes
case VK12.VK_SUCCESS:
return "Command successfully completed.";
case VK12.VK_NOT_READY:
return "A fence or query has not yet completed.";
case VK12.VK_TIMEOUT:
return "A wait operation has not completed in the specified time.";
case VK12.VK_EVENT_SET:
return "An event is signaled.";
case VK12.VK_EVENT_RESET:
return "An event is unsignaled.";
case VK12.VK_INCOMPLETE:
return "A return array was too small for the result.";
case KHRSwapchain.VK_SUBOPTIMAL_KHR:
return "A swapchain no longer matches the surface properties exactly, but can still be used to present to the surface successfully.";
// Error codes
case VK12.VK_ERROR_OUT_OF_HOST_MEMORY:
return "A host memory allocation has failed.";
case VK12.VK_ERROR_OUT_OF_DEVICE_MEMORY:
return "A device memory allocation has failed.";
case VK12.VK_ERROR_INITIALIZATION_FAILED:
return "Initialization of an object could not be completed for implementation-specific reasons.";
case VK12.VK_ERROR_DEVICE_LOST:
return "The logical or physical device has been lost.";
case VK12.VK_ERROR_MEMORY_MAP_FAILED:
return "Mapping of a memory object has failed.";
case VK12.VK_ERROR_LAYER_NOT_PRESENT:
return "A requested layer is not present or could not be loaded.";
case VK12.VK_ERROR_EXTENSION_NOT_PRESENT:
return "A requested extension is not supported.";
case VK12.VK_ERROR_FEATURE_NOT_PRESENT:
return "A requested feature is not supported.";
case VK12.VK_ERROR_INCOMPATIBLE_DRIVER:
return "The requested version of Vulkan is not supported by the driver or is otherwise incompatible for implementation-specific reasons.";
case VK12.VK_ERROR_TOO_MANY_OBJECTS:
return "Too many objects of the type have already been created.";
case VK12.VK_ERROR_FORMAT_NOT_SUPPORTED:
return "A requested format is not supported on this device.";
case KHRSurface.VK_ERROR_SURFACE_LOST_KHR:
return "A surface is no longer available.";
case KHRSurface.VK_ERROR_NATIVE_WINDOW_IN_USE_KHR:
return "The requested window is already connected to a VkSurfaceKHR, or to some other non-Vulkan API.";
case KHRSwapchain.VK_ERROR_OUT_OF_DATE_KHR:
return "A surface has changed in such a way that it is no longer compatible with the swapchain, and further presentation requests using the "
+ "swapchain will fail. Applications must query the new surface properties and recreate their swapchain if they wish to continue" + "presenting to the surface.";
case KHRDisplaySwapchain.VK_ERROR_INCOMPATIBLE_DISPLAY_KHR:
return "The display used by a swapchain does not use the same presentable image layout, or is incompatible in a way that prevents sharing an" + " image.";
case EXTDebugReport.VK_ERROR_VALIDATION_FAILED_EXT:
return "A validation layer found an error.";
default:
return String.format("%s [%d]", "Unknown", Integer.valueOf(result));
}
}
}