mirror of
https://github.com/PixelGuys/Cubyz.git
synced 2025-09-22 10:53:55 -04:00
Vulkan: Select the physical device (#1749)
progress towards #102 I also made a new Window, which is hidden by default, but we can use it to start drawing things in Vulkan parallel to the rest of the game in the future, to ease the transition process.
This commit is contained in:
parent
2ef1e1860f
commit
a4a79603ba
@ -9,37 +9,37 @@
|
||||
.lazy = true,
|
||||
},
|
||||
.cubyz_deps_headers = .{
|
||||
.url = "https://github.com/PixelGuys/Cubyz-Libs/releases/download/7/cubyz_deps_headers.tar.gz",
|
||||
.hash = "N-V-__8AAKJ9OwA8jY0yp1Lokn0e8tdmOaz1MLUCFh-azTZq",
|
||||
.url = "https://github.com/PixelGuys/Cubyz-Libs/releases/download/8/cubyz_deps_headers.tar.gz",
|
||||
.hash = "N-V-__8AAI-aOwAGCfJiF1xWZSQ0yxGSyyuj-VO5P_UqqyJ0",
|
||||
},
|
||||
.cubyz_deps_aarch64_macos = .{
|
||||
.url = "https://github.com/PixelGuys/Cubyz-Libs/releases/download/7/cubyz_deps_aarch64-macos-none.tar.gz",
|
||||
.hash = "N-V-__8AACiCRALoq18Einwt-YUa-hM441UctNoLBgclCjS8",
|
||||
.url = "https://github.com/PixelGuys/Cubyz-Libs/releases/download/8/cubyz_deps_aarch64-macos-none.tar.gz",
|
||||
.hash = "N-V-__8AAI-aOwAGCfJiF1xWZSQ0yxGSyyuj-VO5P_UqqyJ0",
|
||||
.lazy = true,
|
||||
},
|
||||
.cubyz_deps_aarch64_linux = .{
|
||||
.url = "https://github.com/PixelGuys/Cubyz-Libs/releases/download/7/cubyz_deps_aarch64-linux-musl.tar.gz",
|
||||
.hash = "N-V-__8AAHg2lgJB3mcjhodFwzlJJ8_Nm1SmGackQ5268vg-",
|
||||
.url = "https://github.com/PixelGuys/Cubyz-Libs/releases/download/8/cubyz_deps_aarch64-linux-musl.tar.gz",
|
||||
.hash = "N-V-__8AAI-aOwAGCfJiF1xWZSQ0yxGSyyuj-VO5P_UqqyJ0",
|
||||
.lazy = true,
|
||||
},
|
||||
.cubyz_deps_aarch64_windows = .{
|
||||
.url = "https://github.com/PixelGuys/Cubyz-Libs/releases/download/7/cubyz_deps_aarch64-windows-gnu.tar.gz",
|
||||
.hash = "N-V-__8AAPYXtQJNrOeyHuVk3vNvOh8XMQ3p23ZXhlzf-yRK",
|
||||
.url = "https://github.com/PixelGuys/Cubyz-Libs/releases/download/8/cubyz_deps_aarch64-windows-gnu.tar.gz",
|
||||
.hash = "N-V-__8AAAI8tQKULcx4VW98BqluDNYJhHtN2OBlFw2Cm19f",
|
||||
.lazy = true,
|
||||
},
|
||||
.cubyz_deps_x86_64_macos = .{
|
||||
.url = "https://github.com/PixelGuys/Cubyz-Libs/releases/download/7/cubyz_deps_x86_64-macos-none.tar.gz",
|
||||
.hash = "N-V-__8AAIydPQJgYAFNXcw3ytC6-hFSUf-cJPUmcD26cPWd",
|
||||
.url = "https://github.com/PixelGuys/Cubyz-Libs/releases/download/8/cubyz_deps_x86_64-macos-none.tar.gz",
|
||||
.hash = "N-V-__8AANi9PQLVH2WpYTmNnlcdBHDkNZI9yJz6fAznklHu",
|
||||
.lazy = true,
|
||||
},
|
||||
.cubyz_deps_x86_64_linux = .{
|
||||
.url = "https://github.com/PixelGuys/Cubyz-Libs/releases/download/7/cubyz_deps_x86_64-linux-musl.tar.gz",
|
||||
.hash = "N-V-__8AANZnlAJC50QAqnYfjyySyZkE0iiuvozhG4-ZSIiY",
|
||||
.url = "https://github.com/PixelGuys/Cubyz-Libs/releases/download/8/cubyz_deps_x86_64-linux-musl.tar.gz",
|
||||
.hash = "N-V-__8AAIKQlALN_67_ilCxZcxIGddSBBi7A4lVVa0jFeW9",
|
||||
.lazy = true,
|
||||
},
|
||||
.cubyz_deps_x86_64_windows = .{
|
||||
.url = "https://github.com/PixelGuys/Cubyz-Libs/releases/download/7/cubyz_deps_x86_64-windows-gnu.tar.gz",
|
||||
.hash = "N-V-__8AAKwH1wLR7xuDyeH7WPnmJKSQWpj4LAcg_EV-wAX7",
|
||||
.url = "https://github.com/PixelGuys/Cubyz-Libs/releases/download/8/cubyz_deps_x86_64-windows-gnu.tar.gz",
|
||||
.hash = "N-V-__8AAM4p1wKrLLOhfB8egk7fpA7WnEGIU46h_pKk8Xou",
|
||||
.lazy = true,
|
||||
},
|
||||
.cubyz_large_assets = .{
|
||||
|
@ -20,6 +20,7 @@ pub var lastUsedMouse: bool = true;
|
||||
pub var width: u31 = 1280;
|
||||
pub var height: u31 = 720;
|
||||
pub var window: *c.GLFWwindow = undefined;
|
||||
pub var vulkanWindow: *c.GLFWwindow = undefined;
|
||||
pub var grabbed: bool = false;
|
||||
pub var scrollOffset: f32 = 0;
|
||||
|
||||
@ -646,9 +647,16 @@ pub fn init() void { // MARK: init()
|
||||
if(c.glfwVulkanSupported() == c.GLFW_FALSE) {
|
||||
std.log.err("Vulkan is not supported. Please update your drivers if you want to keep playing Cubyz in the future.", .{});
|
||||
} else {
|
||||
vulkan.init();
|
||||
c.glfwWindowHint(c.GLFW_CLIENT_API, c.GLFW_NO_API);
|
||||
c.glfwWindowHint(c.GLFW_VISIBLE, c.GLFW_FALSE);
|
||||
vulkanWindow = c.glfwCreateWindow(width, height, "Cubyz", null, null) orelse @panic("Failed to create GLFW window");
|
||||
vulkan.init(vulkanWindow) catch |err| {
|
||||
std.log.err("Error while initializing Vulkan: {s}", .{@errorName(err)});
|
||||
};
|
||||
}
|
||||
|
||||
c.glfwWindowHint(c.GLFW_CLIENT_API, c.GLFW_OPENGL_API);
|
||||
c.glfwWindowHint(c.GLFW_VISIBLE, c.GLFW_TRUE);
|
||||
c.glfwWindowHint(c.GLFW_OPENGL_DEBUG_CONTEXT, 1);
|
||||
c.glfwWindowHint(c.GLFW_CONTEXT_VERSION_MAJOR, 4);
|
||||
c.glfwWindowHint(c.GLFW_CONTEXT_VERSION_MINOR, 6);
|
||||
@ -692,6 +700,7 @@ pub fn init() void { // MARK: init()
|
||||
pub fn deinit() void {
|
||||
Gamepad.deinit();
|
||||
c.glfwDestroyWindow(window);
|
||||
c.glfwDestroyWindow(vulkanWindow);
|
||||
vulkan.deinit();
|
||||
c.glfwTerminate();
|
||||
}
|
||||
|
@ -75,31 +75,63 @@ fn checkResultIfAvailable(result: anytype) void {
|
||||
fn allocEnumerationGeneric(function: anytype, allocator: NeverFailingAllocator, args: anytype) []@typeInfo(@typeInfo(@TypeOf(function)).@"fn".params[@typeInfo(@TypeOf(function)).@"fn".params.len - 1].type.?).pointer.child {
|
||||
const T = @typeInfo(@typeInfo(@TypeOf(function)).@"fn".params[@typeInfo(@TypeOf(function)).@"fn".params.len - 1].type.?).pointer.child;
|
||||
var count: u32 = 0;
|
||||
checkResultIfAvailable(@call(.auto, function, args ++ .{&count, null}));
|
||||
const list = allocator.alloc(T, count);
|
||||
checkResultIfAvailable(@call(.auto, function, args ++ .{&count, list.ptr}));
|
||||
return list;
|
||||
while(true) {
|
||||
checkResultIfAvailable(@call(.auto, function, args ++ .{&count, null}));
|
||||
const list = allocator.alloc(T, count);
|
||||
const result = @call(.auto, function, args ++ .{&count, list.ptr});
|
||||
if(@TypeOf(result) != void and result == c.VK_INCOMPLETE) {
|
||||
allocator.free(list);
|
||||
continue;
|
||||
}
|
||||
checkResultIfAvailable(result);
|
||||
|
||||
if(count < list.len) return allocator.realloc(list, count);
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Enumerators
|
||||
|
||||
pub fn enumerateInstanceLayerProperties(allocator: NeverFailingAllocator) []c.VkLayerProperties {
|
||||
return allocEnumerationGeneric(c.vkEnumerateInstanceLayerProperties, allocator, .{});
|
||||
}
|
||||
|
||||
pub fn enumerateInstanceExtensionProperties(allocator: NeverFailingAllocator, layerName: ?[*:0]u8) []c.VkExtensionProperties {
|
||||
pub fn enumerateInstanceExtensionProperties(allocator: NeverFailingAllocator, layerName: ?[*:0]const u8) []c.VkExtensionProperties {
|
||||
return allocEnumerationGeneric(c.vkEnumerateInstanceExtensionProperties, allocator, .{layerName});
|
||||
}
|
||||
|
||||
pub fn enumeratePhysicalDevices(allocator: NeverFailingAllocator) []c.VkPhysicalDevice {
|
||||
return allocEnumerationGeneric(c.vkEnumeratePhysicalDevices, allocator, .{instance});
|
||||
}
|
||||
|
||||
pub fn enumerateDeviceExtensionProperties(allocator: NeverFailingAllocator, dev: c.VkPhysicalDevice, layerName: ?[*:0]const u8) []c.VkExtensionProperties {
|
||||
return allocEnumerationGeneric(c.vkEnumerateDeviceExtensionProperties, allocator, .{dev, layerName});
|
||||
}
|
||||
|
||||
pub fn getPhysicalDeviceQueueFamilyProperties(allocator: NeverFailingAllocator, dev: c.VkPhysicalDevice) []c.VkQueueFamilyProperties {
|
||||
return allocEnumerationGeneric(c.vkGetPhysicalDeviceQueueFamilyProperties, allocator, .{dev});
|
||||
}
|
||||
|
||||
pub fn getPhysicalDeviceSurfaceFormatsKHR(allocator: NeverFailingAllocator, dev: c.VkPhysicalDevice) []c.VkSurfaceFormatKHR {
|
||||
return allocEnumerationGeneric(c.vkGetPhysicalDeviceSurfaceFormatsKHR, allocator, .{dev, surface});
|
||||
}
|
||||
|
||||
// MARK: globals
|
||||
|
||||
var instance: c.VkInstance = undefined;
|
||||
var surface: c.VkSurfaceKHR = undefined;
|
||||
var physicalDevice: c.VkPhysicalDevice = undefined;
|
||||
|
||||
// MARK: init
|
||||
|
||||
pub fn init() void {
|
||||
pub fn init(window: ?*c.GLFWwindow) !void {
|
||||
createInstance();
|
||||
checkResult(c.glfwCreateWindowSurface(instance, window, null, &surface));
|
||||
try pickPhysicalDevice();
|
||||
}
|
||||
|
||||
pub fn deinit() void {
|
||||
c.vkDestroySurfaceKHR(instance, surface, null);
|
||||
c.vkDestroyInstance(instance, null);
|
||||
}
|
||||
|
||||
@ -156,3 +188,111 @@ pub fn createInstance() void {
|
||||
};
|
||||
checkResult(c.vkCreateInstance(&createInfo, null, &instance));
|
||||
}
|
||||
|
||||
// MARK: Physical Device
|
||||
|
||||
const deviceExtensions = [_][*:0]const u8{
|
||||
c.VK_KHR_SWAPCHAIN_EXTENSION_NAME,
|
||||
};
|
||||
|
||||
const QueueFamilyIndidices = struct {
|
||||
graphicsFamily: ?u32 = null,
|
||||
presentFamily: ?u32 = null,
|
||||
|
||||
fn isComplete(self: QueueFamilyIndidices) bool {
|
||||
return self.graphicsFamily != null and self.presentFamily != null;
|
||||
}
|
||||
};
|
||||
|
||||
fn findQueueFamilies(dev: c.VkPhysicalDevice) QueueFamilyIndidices {
|
||||
var result: QueueFamilyIndidices = .{};
|
||||
const queueFamilies = getPhysicalDeviceQueueFamilyProperties(main.stackAllocator, dev);
|
||||
defer main.stackAllocator.free(queueFamilies);
|
||||
for(queueFamilies, 0..) |family, i| {
|
||||
if(family.queueFlags & c.VK_QUEUE_GRAPHICS_BIT != 0) {
|
||||
result.graphicsFamily = @intCast(i);
|
||||
}
|
||||
var presentSupport: u32 = 0;
|
||||
checkResult(c.vkGetPhysicalDeviceSurfaceSupportKHR(dev, @intCast(i), surface, &presentSupport));
|
||||
if(presentSupport != 0) {
|
||||
result.presentFamily = @intCast(i);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
fn checkDeviceExtensionSupport(dev: c.VkPhysicalDevice) bool {
|
||||
const availableExtension = enumerateDeviceExtensionProperties(main.stackAllocator, dev, null);
|
||||
defer main.stackAllocator.free(availableExtension);
|
||||
for(deviceExtensions) |requiredName| continueOuter: {
|
||||
for(availableExtension) |available| {
|
||||
if(std.mem.eql(u8, std.mem.span(requiredName), std.mem.span(@as([*:0]const u8, @ptrCast(&available.extensionName))))) {
|
||||
break :continueOuter;
|
||||
}
|
||||
}
|
||||
std.log.warn("Rejecting device because extension {s} was not found", .{requiredName});
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
fn getDeviceScore(dev: c.VkPhysicalDevice) f32 {
|
||||
var properties: c.VkPhysicalDeviceProperties = undefined;
|
||||
c.vkGetPhysicalDeviceProperties(dev, &properties);
|
||||
var features: c.VkPhysicalDeviceFeatures = undefined;
|
||||
c.vkGetPhysicalDeviceFeatures(dev, &features);
|
||||
std.log.debug("Device: {s}", .{@as([*:0]const u8, @ptrCast(&properties.deviceName))});
|
||||
std.log.debug("Properties: {}", .{properties});
|
||||
std.log.debug("Features: {}", .{features});
|
||||
|
||||
const baseScore: f32 = switch(properties.deviceType) {
|
||||
c.VK_PHYSICAL_DEVICE_TYPE_CPU => 1e-9,
|
||||
c.VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU => 1e9,
|
||||
c.VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU => 1,
|
||||
else => 0.1,
|
||||
};
|
||||
|
||||
const availableExtension = enumerateDeviceExtensionProperties(main.stackAllocator, dev, null);
|
||||
defer main.stackAllocator.free(availableExtension);
|
||||
std.log.debug("Device extensions:", .{});
|
||||
for(availableExtension) |ext| {
|
||||
std.log.debug("\t{s}", .{ext.extensionName});
|
||||
}
|
||||
if(!findQueueFamilies(dev).isComplete() or !checkDeviceExtensionSupport(dev)) return 0;
|
||||
|
||||
if(features.multiDrawIndirect != c.VK_TRUE) {
|
||||
std.log.warn("Rejecting device: multDrawIndirect is not supported", .{});
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(features.dualSrcBlend != c.VK_TRUE) {
|
||||
std.log.warn("Rejecting device: dual source blending is not supported", .{});
|
||||
return 0;
|
||||
}
|
||||
|
||||
return baseScore;
|
||||
}
|
||||
|
||||
fn pickPhysicalDevice() !void {
|
||||
const devices = enumeratePhysicalDevices(main.stackAllocator);
|
||||
defer main.stackAllocator.free(devices);
|
||||
if(devices.len == 0) {
|
||||
return error.NoDevicesFound;
|
||||
}
|
||||
var bestScore: f32 = 0;
|
||||
for(devices) |dev| {
|
||||
const score = getDeviceScore(dev);
|
||||
if(score > bestScore) {
|
||||
bestScore = score;
|
||||
physicalDevice = dev;
|
||||
}
|
||||
}
|
||||
|
||||
if(bestScore == 0) {
|
||||
return error.NoCapableDeviceFound;
|
||||
}
|
||||
|
||||
var properties: c.VkPhysicalDeviceProperties = undefined;
|
||||
c.vkGetPhysicalDeviceProperties(physicalDevice, &properties);
|
||||
std.log.info("Selected device {s}", .{@as([*:0]const u8, @ptrCast(&properties.deviceName))});
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user