Files
vulkan-zig/examples/main.zig
2020-07-04 04:19:32 +02:00

176 lines
5.3 KiB
Zig

const std = @import("std");
const vk = @import("vulkan");
const c = @import("c.zig");
const resources = @import("resources");
const GraphicsContext = @import("graphics_context.zig").GraphicsContext;
const Swapchain = @import("swapchain.zig").Swapchain;
const Allocator = std.mem.Allocator;
const app_name = "vulkan-zig example";
pub fn main() !void {
if (c.glfwInit() != c.GLFW_TRUE) return error.GlfwInitFailed;
defer c.glfwTerminate();
const extent = vk.Extent2D{.width = 800, .height = 600};
c.glfwWindowHint(c.GLFW_CLIENT_API, c.GLFW_NO_API);
const window = c.glfwCreateWindow(
extent.width,
extent.height,
app_name,
null,
null
) orelse return error.WindowInitFailed;
defer c.glfwDestroyWindow(window);
const allocator = std.heap.page_allocator;
const gc = try GraphicsContext.init(allocator, app_name, window);
defer gc.deinit();
std.debug.print("Using device: {}\n", .{gc.deviceName()});
var swapchain = try Swapchain.init(&gc, allocator, extent);
defer swapchain.deinit();
const pool = try gc.vkd.createCommandPool(gc.dev, .{
.flags = .{},
.queue_family_index = gc.graphics_queue.family,
}, null);
defer gc.vkd.destroyCommandPool(gc.dev, pool, null);
var cmdbufs = try createCommandBuffers(&gc, pool, allocator, swapchain);
defer destroyCommandBuffers(&gc, pool, allocator, cmdbufs);
while (c.glfwWindowShouldClose(window) == c.GLFW_FALSE) {
const cmdbuf = cmdbufs[swapchain.image_index];
const state = swapchain.present(cmdbuf) catch |err| switch (err) {
error.OutOfDateKHR => Swapchain.PresentState.suboptimal,
else => |narrow| return narrow,
};
if (state == .suboptimal) {
var w: c_int = undefined;
var h: c_int = undefined;
c.glfwGetWindowSize(window, &w, &h);
try swapchain.recreate(.{.width = @intCast(u32, w), .height = @intCast(u32, h)});
destroyCommandBuffers(&gc, pool, allocator, cmdbufs);
cmdbufs = try createCommandBuffers(&gc, pool, allocator, swapchain);
}
c.glfwSwapBuffers(window);
c.glfwPollEvents();
try gc.vkd.queueWaitIdle(gc.graphics_queue.handle);
}
}
fn createCommandBuffers(
gc: *const GraphicsContext,
pool: vk.CommandPool,
allocator: *Allocator,
swapchain: Swapchain,
) ![]vk.CommandBuffer {
const cmdbufs = try allocator.alloc(vk.CommandBuffer, swapchain.swap_images.len);
errdefer allocator.free(cmdbufs);
try gc.vkd.allocateCommandBuffers(gc.dev, .{
.command_pool = pool,
.level = .primary,
.command_buffer_count = @truncate(u32, cmdbufs.len),
}, cmdbufs.ptr);
errdefer gc.vkd.freeCommandBuffers(gc.dev, pool, @truncate(u32, cmdbufs.len), cmdbufs.ptr);
const subresource_range = vk.ImageSubresourceRange{
.aspect_mask = .{.color_bit = true},
.base_mip_level = 0,
.level_count = 1,
.base_array_layer = 0,
.layer_count = 1,
};
const color = vk.ClearColorValue{.float_32 = .{1, 0, 1, 1}};
for (cmdbufs) |cmdbuf, i| {
const image = swapchain.swap_images[i].image;
try gc.vkd.beginCommandBuffer(cmdbuf, .{
.flags = .{},
.p_inheritance_info = null,
});
imageTransition(
gc,
cmdbuf,
image,
subresource_range,
.{.layout = .@"undefined", .stage = .{.top_of_pipe_bit = true}},
.{.layout = .general, .stage = .{.top_of_pipe_bit = true}},
);
gc.vkd.cmdClearColorImage(
cmdbuf,
image,
.general,
color,
1,
@ptrCast([*]const vk.ImageSubresourceRange, &subresource_range),
);
imageTransition(
gc,
cmdbuf,
image,
subresource_range,
.{.layout = .general, .stage = .{.top_of_pipe_bit = true}},
.{.layout = .present_src_khr, .stage = .{.bottom_of_pipe_bit = true}},
);
try gc.vkd.endCommandBuffer(cmdbuf);
}
return cmdbufs;
}
fn destroyCommandBuffers(gc: *const GraphicsContext, pool: vk.CommandPool, allocator: *Allocator, cmdbufs: []vk.CommandBuffer) void {
gc.vkd.freeCommandBuffers(gc.dev, pool, @truncate(u32, cmdbufs.len), cmdbufs.ptr);
allocator.free(cmdbufs);
}
const ImageState = struct {
layout: vk.ImageLayout,
stage: vk.PipelineStageFlags,
access_mask: vk.AccessFlags = .{},
};
fn imageTransition(
gc: *const GraphicsContext,
cmdbuf: vk.CommandBuffer,
image: vk.Image,
subresource_range: vk.ImageSubresourceRange,
src: ImageState,
dst: ImageState
) void {
const barrier = vk.ImageMemoryBarrier{
.src_access_mask = src.access_mask,
.dst_access_mask = dst.access_mask,
.old_layout = src.layout,
.new_layout = dst.layout,
.src_queue_family_index = vk.QUEUE_FAMILY_IGNORED,
.dst_queue_family_index = vk.QUEUE_FAMILY_IGNORED,
.image = image,
.subresource_range = subresource_range,
};
gc.vkd.cmdPipelineBarrier(
cmdbuf, src.stage, dst.stage, .{},
0, undefined,
0, undefined,
1, @ptrCast([*]const vk.ImageMemoryBarrier, &barrier)
);
}