mirror of
https://github.com/Nexoniarz/Finch.git
synced 2026-11-03 00:44:27 +00:00
- examples/opengl.fch: OpenGL 3.3 core, shaders, VAO/VBO, a spinning triangle (checked offscreen) - examples/vulkan.fch: instance, GPUs with properties/memory/queues, logical device and queue - ptr(n) and int(p) conversions for C APIs that pass offsets as pointers - .ptr works on string literals; a comma after the last call argument is allowed - a missing header included by an imported header is now named in the error - the old .fn extension hint is gone (Finch is new, there are no old files) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
137 lines
4.6 KiB
Text
137 lines
4.6 KiB
Text
// Vulkan from Finch: create an instance, list every GPU with its properties, memory and
|
|
// queues, then create a logical device and get a graphics queue. No window needed.
|
|
// Shows big C structs (with arrays of structs inside), out-parameters and Vulkan handles.
|
|
// Needs the Vulkan loader and headers (in shell.nix) and a Vulkan driver.
|
|
import "vulkan/vulkan.h"
|
|
link "vulkan"
|
|
|
|
fn check(i32 result, str what) {
|
|
if result != VK_SUCCESS {
|
|
print(what, "failed with VkResult", result)
|
|
exit(1)
|
|
}
|
|
}
|
|
|
|
fn version(u32 v) -> str {
|
|
return str(v >> 22) + "." + str((v >> 12) & 0x3FF) + "." + str(v & 0xFFF)
|
|
}
|
|
|
|
fn deviceType(i32 t) -> str {
|
|
if t == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU {
|
|
return "discrete GPU"
|
|
}
|
|
if t == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU {
|
|
return "integrated GPU"
|
|
}
|
|
if t == VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU {
|
|
return "virtual GPU"
|
|
}
|
|
if t == VK_PHYSICAL_DEVICE_TYPE_CPU {
|
|
return "CPU (software)"
|
|
}
|
|
return "other"
|
|
}
|
|
|
|
fn queueFlags(u32 f) -> str {
|
|
[]str parts
|
|
if f & VK_QUEUE_GRAPHICS_BIT != 0 {
|
|
parts.push("graphics")
|
|
}
|
|
if f & VK_QUEUE_COMPUTE_BIT != 0 {
|
|
parts.push("compute")
|
|
}
|
|
if f & VK_QUEUE_TRANSFER_BIT != 0 {
|
|
parts.push("transfer")
|
|
}
|
|
if f & VK_QUEUE_SPARSE_BINDING_BIT != 0 {
|
|
parts.push("sparse")
|
|
}
|
|
if f & VK_QUEUE_VIDEO_DECODE_BIT_KHR != 0 {
|
|
parts.push("video decode")
|
|
}
|
|
if f & VK_QUEUE_VIDEO_ENCODE_BIT_KHR != 0 {
|
|
parts.push("video encode")
|
|
}
|
|
if parts.len == 0 {
|
|
return "other"
|
|
}
|
|
return parts.join(", ")
|
|
}
|
|
|
|
fn main() {
|
|
app := VkApplicationInfo(
|
|
sType: VK_STRUCTURE_TYPE_APPLICATION_INFO,
|
|
pApplicationName: "Finch".ptr,
|
|
applicationVersion: 1,
|
|
pEngineName: "none".ptr,
|
|
apiVersion: 1 << 22, // Vulkan 1.0
|
|
)
|
|
info := VkInstanceCreateInfo(sType: VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, pApplicationInfo: addr(app))
|
|
ptr instance
|
|
check(vkCreateInstance(addr(info), null, addr(instance)), "vkCreateInstance")
|
|
defer vkDestroyInstance(instance, null)
|
|
|
|
u32 count
|
|
check(vkEnumeratePhysicalDevices(instance, addr(count), null), "counting GPUs")
|
|
[]ptr gpus
|
|
gpus.resize(count)
|
|
check(vkEnumeratePhysicalDevices(instance, addr(count), gpus.ptr), "listing GPUs")
|
|
print("Vulkan found", count, "device(s)")
|
|
|
|
for gpu in gpus {
|
|
VkPhysicalDeviceProperties props
|
|
vkGetPhysicalDeviceProperties(gpu, addr(props))
|
|
print()
|
|
print(str(props.deviceName.ptr))
|
|
print(" type:", deviceType(props.deviceType))
|
|
print(" Vulkan " + version(props.apiVersion) + ", driver " + str(props.driverVersion))
|
|
print(" biggest 2D image:", props.limits.maxImageDimension2D, "px")
|
|
|
|
VkPhysicalDeviceMemoryProperties mem
|
|
vkGetPhysicalDeviceMemoryProperties(gpu, addr(mem))
|
|
for h in 0..mem.memoryHeapCount {
|
|
heap := mem.memoryHeaps[h]
|
|
local := ""
|
|
if heap.flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT != 0 {
|
|
local = " (on the GPU)"
|
|
}
|
|
print(" memory heap " + str(h) + ": " + str(float(heap.size) / 1073741824.0) + " GiB" + local)
|
|
}
|
|
|
|
u32 families
|
|
vkGetPhysicalDeviceQueueFamilyProperties(gpu, addr(families), null)
|
|
[]VkQueueFamilyProperties queues
|
|
queues.resize(families)
|
|
vkGetPhysicalDeviceQueueFamilyProperties(gpu, addr(families), queues.ptr)
|
|
graphics := -1
|
|
for q in 0..queues.len {
|
|
print(" queue family " + str(q) + ": " + str(queues[q].queueCount) + " x " + queueFlags(queues[q].queueFlags))
|
|
if graphics < 0 && queues[q].queueFlags & VK_QUEUE_GRAPHICS_BIT != 0 {
|
|
graphics = q
|
|
}
|
|
}
|
|
if graphics < 0 {
|
|
continue
|
|
}
|
|
|
|
// a logical device with one graphics queue: what a renderer would start from
|
|
f32 priority = 1.0
|
|
queueInfo := VkDeviceQueueCreateInfo(
|
|
sType: VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
|
|
queueFamilyIndex: u32(graphics),
|
|
queueCount: 1,
|
|
pQueuePriorities: addr(priority),
|
|
)
|
|
deviceInfo := VkDeviceCreateInfo(
|
|
sType: VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
|
queueCreateInfoCount: 1,
|
|
pQueueCreateInfos: addr(queueInfo),
|
|
)
|
|
ptr device
|
|
check(vkCreateDevice(gpu, addr(deviceInfo), null, addr(device)), "vkCreateDevice")
|
|
ptr queue
|
|
vkGetDeviceQueue(device, u32(graphics), 0, addr(queue))
|
|
print(" created a device and got graphics queue", queue != null)
|
|
vkDestroyDevice(device, null)
|
|
}
|
|
}
|