Refactored compilation and startup. Now everything is orchestrated through a simple API described in sideros_api.h. Also refactored some of the code to get rid of global C imports.
Signed-off-by: Lorenzo Torres <torres@sideros.org>
This commit is contained in:
parent
5b51a3d571
commit
b1bd949db5
12 changed files with 420 additions and 212 deletions
96
build.zig
96
build.zig
|
|
@ -6,8 +6,8 @@ pub fn build(b: *std.Build) void {
|
||||||
const target = b.standardTargetOptions(.{});
|
const target = b.standardTargetOptions(.{});
|
||||||
const optimize = b.standardOptimizeOption(.{});
|
const optimize = b.standardOptimizeOption(.{});
|
||||||
|
|
||||||
const sideros = b.createModule(.{
|
const math = b.createModule(.{
|
||||||
.root_source_file = b.path("src/sideros.zig"),
|
.root_source_file = b.path("src/math.zig"),
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
});
|
});
|
||||||
|
|
@ -17,14 +17,12 @@ pub fn build(b: *std.Build) void {
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
});
|
});
|
||||||
mods.addImport("sideros", sideros);
|
|
||||||
|
|
||||||
const ecs = b.createModule(.{
|
const ecs = b.createModule(.{
|
||||||
.root_source_file = b.path("src/ecs/ecs.zig"),
|
.root_source_file = b.path("src/ecs/ecs.zig"),
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
});
|
});
|
||||||
ecs.addImport("sideros", sideros);
|
|
||||||
|
|
||||||
const renderer = b.createModule(.{
|
const renderer = b.createModule(.{
|
||||||
.root_source_file = b.path("src/renderer/Renderer.zig"),
|
.root_source_file = b.path("src/renderer/Renderer.zig"),
|
||||||
|
|
@ -34,69 +32,79 @@ pub fn build(b: *std.Build) void {
|
||||||
});
|
});
|
||||||
renderer.addCSourceFile(.{ .file = b.path("ext/stb_image.c") });
|
renderer.addCSourceFile(.{ .file = b.path("ext/stb_image.c") });
|
||||||
renderer.addImport("sideros", sideros);
|
renderer.addImport("sideros", sideros);
|
||||||
|
renderer.addImport("math", math);
|
||||||
renderer.addImport("ecs", ecs);
|
renderer.addImport("ecs", ecs);
|
||||||
|
// TODO(ernesto): ecs and renderer should be decoupled
|
||||||
ecs.addImport("renderer", renderer);
|
ecs.addImport("renderer", renderer);
|
||||||
|
|
||||||
compileAllShaders(b, renderer);
|
compileAllShaders(b, renderer);
|
||||||
|
|
||||||
sideros.addImport("mods", mods);
|
const sideros = b.addStaticLibrary(.{
|
||||||
sideros.addImport("ecs", ecs);
|
|
||||||
sideros.addImport("renderer", renderer);
|
|
||||||
|
|
||||||
const exe = b.addExecutable(.{
|
|
||||||
.name = "sideros",
|
.name = "sideros",
|
||||||
.root_module = b.createModule(.{
|
.root_source_file = b.path("src/sideros.zig"),
|
||||||
.root_source_file = b.path("src/main.zig"),
|
.target = target,
|
||||||
.target = target,
|
.optimize = optimize,
|
||||||
.optimize = optimize,
|
|
||||||
}),
|
|
||||||
});
|
});
|
||||||
exe.root_module.addImport("sideros", sideros);
|
|
||||||
sideros.addIncludePath(b.path("ext"));
|
sideros.addIncludePath(b.path("ext"));
|
||||||
|
sideros.addIncludePath(b.path("src"));
|
||||||
|
|
||||||
exe.linkSystemLibrary("vulkan");
|
sideros.root_module.addImport("mods", mods);
|
||||||
exe.linkLibC();
|
sideros.root_module.addImport("ecs", ecs);
|
||||||
|
sideros.root_module.addImport("renderer", renderer);
|
||||||
|
|
||||||
|
b.installArtifact(sideros);
|
||||||
|
|
||||||
const options = b.addOptions();
|
const options = b.addOptions();
|
||||||
|
|
||||||
if (target.result.os.tag == .linux) {
|
switch (target.result.os.tag) {
|
||||||
const wayland = b.option(bool, "wayland", "Use Wayland to create the main window") orelse false;
|
.linux => {
|
||||||
if (wayland) {
|
const wayland = b.option(bool, "wayland", "Use Wayland to create the main window") orelse false;
|
||||||
exe.linkSystemLibrary("wayland-client");
|
options.addOption(bool, "wayland", wayland);
|
||||||
exe.root_module.addCSourceFile(.{ .file = b.path("ext/xdg-shell.c") });
|
|
||||||
} else {
|
const exe = b.addExecutable(.{
|
||||||
exe.linkSystemLibrary("xcb");
|
.name = if (wayland) "sideros-wayland" else "sideros-xorg",
|
||||||
exe.linkSystemLibrary("xcb-icccm");
|
.root_module = b.createModule(.{
|
||||||
}
|
.root_source_file = b.path(if (wayland) "src/wayland.zig" else "src/xorg.zig"),
|
||||||
options.addOption(bool, "wayland", wayland);
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
exe.root_module.addIncludePath(b.path("src"));
|
||||||
|
exe.linkLibrary(sideros);
|
||||||
|
exe.linkLibC();
|
||||||
|
exe.linkSystemLibrary("vulkan");
|
||||||
|
if (wayland) {
|
||||||
|
exe.root_module.addIncludePath(b.path("ext"));
|
||||||
|
exe.linkSystemLibrary("wayland-client");
|
||||||
|
exe.root_module.addCSourceFile(.{ .file = b.path("ext/xdg-shell.c") });
|
||||||
|
} else {
|
||||||
|
exe.linkSystemLibrary("xcb");
|
||||||
|
exe.linkSystemLibrary("xcb-icccm");
|
||||||
|
}
|
||||||
|
b.installArtifact(exe);
|
||||||
|
},
|
||||||
|
else => {
|
||||||
|
std.debug.panic("Compilation not implemented for OS: {any}\n", .{target.result.os.tag});
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
sideros.addOptions("config", options);
|
|
||||||
|
|
||||||
b.installArtifact(exe);
|
|
||||||
|
|
||||||
const root_lib = b.addLibrary(.{
|
|
||||||
.root_module = sideros,
|
|
||||||
.name = "sideros",
|
|
||||||
});
|
|
||||||
|
|
||||||
const install_docs = b.addInstallDirectory(.{
|
const install_docs = b.addInstallDirectory(.{
|
||||||
.source_dir = root_lib.getEmittedDocs(),
|
.source_dir = sideros.getEmittedDocs(),
|
||||||
.install_dir = .prefix,
|
.install_dir = .prefix,
|
||||||
.install_subdir = "docs/sideros",
|
.install_subdir = "docs/sideros",
|
||||||
});
|
});
|
||||||
const docs_step = b.step("docs", "Generate documentation");
|
const docs_step = b.step("docs", "Generate documentation");
|
||||||
docs_step.dependOn(&install_docs.step);
|
docs_step.dependOn(&install_docs.step);
|
||||||
|
|
||||||
const run_cmd = b.addRunArtifact(exe);
|
//const run_cmd = b.addRunArtifact(exe);
|
||||||
run_cmd.step.dependOn(b.getInstallStep());
|
//run_cmd.step.dependOn(b.getInstallStep());
|
||||||
|
|
||||||
if (b.args) |args| {
|
//if (b.args) |args| {
|
||||||
run_cmd.addArgs(args);
|
//run_cmd.addArgs(args);
|
||||||
}
|
//}
|
||||||
|
|
||||||
const run_step = b.step("run", "Run the app");
|
//const run_step = b.step("run", "Run the app");
|
||||||
run_step.dependOn(&run_cmd.step);
|
//run_step.dependOn(&run_cmd.step);
|
||||||
|
|
||||||
const exe_unit_tests = b.addTest(.{
|
const exe_unit_tests = b.addTest(.{
|
||||||
.root_module = b.createModule(.{
|
.root_module = b.createModule(.{
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
pub const components = @import("components.zig");
|
pub const components = @import("components.zig");
|
||||||
pub const entities = @import("entities.zig");
|
pub const entities = @import("entities.zig");
|
||||||
|
pub const Input = @import("Input.zig");
|
||||||
|
|
||||||
pub const SystemError = error{
|
pub const SystemError = error{
|
||||||
fail,
|
fail,
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ const components = @import("components.zig");
|
||||||
const sparse = @import("sparse.zig");
|
const sparse = @import("sparse.zig");
|
||||||
const Renderer = @import("renderer");
|
const Renderer = @import("renderer");
|
||||||
const Camera = @import("renderer").Camera;
|
const Camera = @import("renderer").Camera;
|
||||||
const Input = @import("sideros").Input;
|
|
||||||
const ecs = @import("ecs.zig");
|
const ecs = @import("ecs.zig");
|
||||||
|
const Input = ecs.Input;
|
||||||
|
|
||||||
pub const System = ecs.System;
|
pub const System = ecs.System;
|
||||||
pub const SystemGroup = []const System;
|
pub const SystemGroup = []const System;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const ecs = @import("ecs");
|
const ecs = @import("ecs");
|
||||||
const sideros = @import("sideros");
|
const math = @import("math");
|
||||||
const math = sideros.math;
|
|
||||||
|
|
||||||
const Camera = @This();
|
const Camera = @This();
|
||||||
const UP = @Vector(3, f32){ 0.0, 1.0, 0.0 };
|
const UP = @Vector(3, f32){ 0.0, 1.0, 0.0 };
|
||||||
|
|
@ -13,9 +12,9 @@ pub const Uniform = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
position: @Vector(3, f32),
|
position: @Vector(3, f32),
|
||||||
target: @Vector(3, f32) = .{0.0, 0.0, 0.0},
|
target: @Vector(3, f32) = .{ 0.0, 0.0, 0.0 },
|
||||||
front: @Vector(3, f32) = .{0.0, 0.0, 1.0 },
|
front: @Vector(3, f32) = .{ 0.0, 0.0, 1.0 },
|
||||||
up: @Vector(3, f32) = .{0.0, 1.0, 0.0 },
|
up: @Vector(3, f32) = .{ 0.0, 1.0, 0.0 },
|
||||||
speed: f32 = 2.5,
|
speed: f32 = 2.5,
|
||||||
|
|
||||||
pub fn getProjection(width: usize, height: usize) math.Matrix {
|
pub fn getProjection(width: usize, height: usize) math.Matrix {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
const c = @import("sideros").c;
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const vk = @import("vulkan.zig");
|
const vk = @import("vulkan.zig");
|
||||||
const gltf = @import("gltf.zig");
|
const gltf = @import("gltf.zig");
|
||||||
|
|
@ -19,11 +18,11 @@ pub const Vertex = struct {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bindingDescription() c.VkVertexInputBindingDescription {
|
pub fn bindingDescription() vk.c.VkVertexInputBindingDescription {
|
||||||
const binding_description: c.VkVertexInputBindingDescription = .{
|
const binding_description: vk.c.VkVertexInputBindingDescription = .{
|
||||||
.binding = 0,
|
.binding = 0,
|
||||||
.stride = @sizeOf(Vertex),
|
.stride = @sizeOf(Vertex),
|
||||||
.inputRate = c.VK_VERTEX_INPUT_RATE_VERTEX,
|
.inputRate = vk.c.VK_VERTEX_INPUT_RATE_VERTEX,
|
||||||
};
|
};
|
||||||
|
|
||||||
return binding_description;
|
return binding_description;
|
||||||
|
|
@ -89,7 +88,7 @@ pub fn createVertexBuffer(allocator: Allocator, device: anytype) !vk.Buffer {
|
||||||
|
|
||||||
const buffer = try device.createBuffer(vk.BufferUsage{ .transfer_src = true }, vk.BufferFlags{ .host_visible = true, .host_coherent = true }, @sizeOf([8]f32) * vertices.len);
|
const buffer = try device.createBuffer(vk.BufferUsage{ .transfer_src = true }, vk.BufferFlags{ .host_visible = true, .host_coherent = true }, @sizeOf([8]f32) * vertices.len);
|
||||||
|
|
||||||
try vk.mapError(c.vkMapMemory(
|
try vk.mapError(vk.c.vkMapMemory(
|
||||||
device.handle,
|
device.handle,
|
||||||
buffer.memory,
|
buffer.memory,
|
||||||
0,
|
0,
|
||||||
|
|
@ -104,7 +103,7 @@ pub fn createVertexBuffer(allocator: Allocator, device: anytype) !vk.Buffer {
|
||||||
@memcpy(gpu_vertices, @as([]Vertex, @ptrCast(final_array[0..])));
|
@memcpy(gpu_vertices, @as([]Vertex, @ptrCast(final_array[0..])));
|
||||||
}
|
}
|
||||||
|
|
||||||
c.vkUnmapMemory(device.handle, buffer.memory);
|
vk.c.vkUnmapMemory(device.handle, buffer.memory);
|
||||||
|
|
||||||
const vertex_buffer = try device.createBuffer(vk.BufferUsage{ .vertex_buffer = true, .transfer_dst = true }, vk.BufferFlags{ .device_local = true }, @sizeOf(Vertex) * vertices.len);
|
const vertex_buffer = try device.createBuffer(vk.BufferUsage{ .vertex_buffer = true, .transfer_dst = true }, vk.BufferFlags{ .device_local = true }, @sizeOf(Vertex) * vertices.len);
|
||||||
|
|
||||||
|
|
@ -126,7 +125,7 @@ pub fn createIndexBuffer(allocator: Allocator, device: anytype) !vk.Buffer {
|
||||||
|
|
||||||
const buffer = try device.createBuffer(vk.BufferUsage{ .transfer_src = true }, vk.BufferFlags{ .host_visible = true, .host_coherent = true }, @sizeOf(u16) * indices.len);
|
const buffer = try device.createBuffer(vk.BufferUsage{ .transfer_src = true }, vk.BufferFlags{ .host_visible = true, .host_coherent = true }, @sizeOf(u16) * indices.len);
|
||||||
|
|
||||||
try vk.mapError(c.vkMapMemory(
|
try vk.mapError(vk.c.vkMapMemory(
|
||||||
device.handle,
|
device.handle,
|
||||||
buffer.memory,
|
buffer.memory,
|
||||||
0,
|
0,
|
||||||
|
|
@ -141,7 +140,7 @@ pub fn createIndexBuffer(allocator: Allocator, device: anytype) !vk.Buffer {
|
||||||
@memcpy(gpu_indices, indices[0..]);
|
@memcpy(gpu_indices, indices[0..]);
|
||||||
}
|
}
|
||||||
|
|
||||||
c.vkUnmapMemory(device.handle, buffer.memory);
|
vk.c.vkUnmapMemory(device.handle, buffer.memory);
|
||||||
|
|
||||||
const index_buffer = try device.createBuffer(vk.BufferUsage{ .index_buffer = true, .transfer_dst = true }, vk.BufferFlags{ .device_local = true }, @sizeOf(u16) * indices.len);
|
const index_buffer = try device.createBuffer(vk.BufferUsage{ .index_buffer = true, .transfer_dst = true }, vk.BufferFlags{ .device_local = true }, @sizeOf(u16) * indices.len);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
const c = @import("sideros").c;
|
const math = @import("math");
|
||||||
const math = @import("sideros").math;
|
|
||||||
const ecs = @import("ecs");
|
const ecs = @import("ecs");
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const vk = @import("vulkan.zig");
|
const vk = @import("vulkan.zig");
|
||||||
|
|
@ -21,11 +20,9 @@ current_frame: u32,
|
||||||
vertex_buffer: vk.Buffer,
|
vertex_buffer: vk.Buffer,
|
||||||
index_buffer: vk.Buffer,
|
index_buffer: vk.Buffer,
|
||||||
|
|
||||||
pub fn init(comptime C: type, comptime S: type, allocator: Allocator, display: C, s: S) !Renderer {
|
pub fn init(allocator: Allocator, instance_handle: vk.c.VkInstance, surface_handle: vk.c.VkSurfaceKHR) !Renderer {
|
||||||
const instance = try vk.Instance.create(allocator);
|
const instance: vk.Instance = .{ .handle = instance_handle };
|
||||||
|
const surface: vk.Surface = .{ .handle = surface_handle };
|
||||||
const surface = try vk.Surface.create(C, S, instance, display, s);
|
|
||||||
|
|
||||||
var physical_device = try vk.PhysicalDevice.pick(allocator, instance);
|
var physical_device = try vk.PhysicalDevice.pick(allocator, instance);
|
||||||
const device = try physical_device.create_device(surface, allocator, 2);
|
const device = try physical_device.create_device(surface, allocator, 2);
|
||||||
|
|
||||||
|
|
@ -81,8 +78,6 @@ pub fn deinit(self: Renderer) void {
|
||||||
self.swapchain.destroy(self.device);
|
self.swapchain.destroy(self.device);
|
||||||
self.render_pass.destroy(self.device);
|
self.render_pass.destroy(self.device);
|
||||||
self.device.destroy();
|
self.device.destroy();
|
||||||
self.surface.destroy(self.instance);
|
|
||||||
self.instance.destroy();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: render is maybe a bad name? something like present() or submit() is better?
|
// TODO: render is maybe a bad name? something like present() or submit() is better?
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
pub const Texture = @import("Texture.zig");
|
pub const Texture = @import("Texture.zig");
|
||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const c = @import("sideros").c;
|
pub const c = @cImport({
|
||||||
|
@cInclude("vulkan/vulkan.h");
|
||||||
|
});
|
||||||
|
const math = @import("math");
|
||||||
const Mesh = @import("Mesh.zig");
|
const Mesh = @import("Mesh.zig");
|
||||||
const sideros = @import("sideros");
|
|
||||||
const Camera = @import("Camera.zig");
|
const Camera = @import("Camera.zig");
|
||||||
const math = sideros.math;
|
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
const config = sideros.config;
|
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const debug = (builtin.mode == .Debug);
|
const debug = (builtin.mode == .Debug);
|
||||||
|
|
||||||
|
|
@ -73,92 +73,6 @@ pub const BufferFlags = packed struct(u32) {
|
||||||
|
|
||||||
pub const Instance = struct {
|
pub const Instance = struct {
|
||||||
handle: c.VkInstance,
|
handle: c.VkInstance,
|
||||||
|
|
||||||
pub fn create(allocator: Allocator) !Instance {
|
|
||||||
const extensions = [_][*c]const u8 {if (config.wayland) c.VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME else c.VK_KHR_XCB_SURFACE_EXTENSION_NAME, c.VK_KHR_SURFACE_EXTENSION_NAME};
|
|
||||||
|
|
||||||
// Querry avaliable extensions size
|
|
||||||
var avaliableExtensionsCount: u32 = 0;
|
|
||||||
_ = c.vkEnumerateInstanceExtensionProperties(null, &avaliableExtensionsCount, null);
|
|
||||||
// Actually querry avaliable extensions
|
|
||||||
var avaliableExtensions = std.ArrayList(c.VkExtensionProperties).init(allocator);
|
|
||||||
try avaliableExtensions.resize(avaliableExtensionsCount);
|
|
||||||
defer avaliableExtensions.deinit();
|
|
||||||
_ = c.vkEnumerateInstanceExtensionProperties(null, &avaliableExtensionsCount, avaliableExtensions.items.ptr);
|
|
||||||
// Check the extensions we want against the extensions the user has
|
|
||||||
for (extensions) |need_ext| {
|
|
||||||
var found = false;
|
|
||||||
for (avaliableExtensions.items) |useable_ext| {
|
|
||||||
const extensionName: [*c]const u8 = &useable_ext.extensionName;
|
|
||||||
if (std.mem.eql(u8, std.mem.sliceTo(need_ext, 0), std.mem.sliceTo(extensionName, 0))) {
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found) {
|
|
||||||
std.debug.panic("ERROR: Needed vulkan extension {s} not found\n", .{need_ext});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Querry avaliable layers size
|
|
||||||
var avaliableLayersCount: u32 = 0;
|
|
||||||
_ = c.vkEnumerateInstanceLayerProperties(&avaliableLayersCount, null);
|
|
||||||
// Actually querry avaliable layers
|
|
||||||
var availableLayers = std.ArrayList(c.VkLayerProperties).init(allocator);
|
|
||||||
try availableLayers.resize(avaliableLayersCount);
|
|
||||||
defer availableLayers.deinit();
|
|
||||||
_ = c.vkEnumerateInstanceLayerProperties(&avaliableLayersCount, availableLayers.items.ptr);
|
|
||||||
// Every layer we do have we add to this list, if we don't have it no worries just print a message and continue
|
|
||||||
var newLayers = std.ArrayList([*c]const u8).init(allocator);
|
|
||||||
defer newLayers.deinit();
|
|
||||||
// Loop over layers we want
|
|
||||||
for (validation_layers) |want_layer| {
|
|
||||||
var found = false;
|
|
||||||
for (availableLayers.items) |useable_validation| {
|
|
||||||
const layer_name: [*c]const u8 = &useable_validation.layerName;
|
|
||||||
if (std.mem.eql(u8, std.mem.sliceTo(want_layer, 0), std.mem.sliceTo(layer_name, 0))) {
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found) {
|
|
||||||
std.debug.print("WARNING: Compiled in debug mode, but wanted validation layer {s} not found.\n", .{want_layer});
|
|
||||||
std.debug.print("NOTE: Validation layer will be removed from the wanted validation layers\n", .{});
|
|
||||||
} else {
|
|
||||||
try newLayers.append(want_layer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const app_info: c.VkApplicationInfo = .{
|
|
||||||
.sType = c.VK_STRUCTURE_TYPE_APPLICATION_INFO,
|
|
||||||
.pApplicationName = "sideros",
|
|
||||||
.applicationVersion = c.VK_MAKE_VERSION(1, 0, 0),
|
|
||||||
.engineVersion = c.VK_MAKE_VERSION(1, 0, 0),
|
|
||||||
.pEngineName = "sideros",
|
|
||||||
.apiVersion = c.VK_MAKE_VERSION(1, 3, 0),
|
|
||||||
};
|
|
||||||
|
|
||||||
const instance_info: c.VkInstanceCreateInfo = .{
|
|
||||||
.sType = c.VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
|
|
||||||
.pApplicationInfo = &app_info,
|
|
||||||
.enabledExtensionCount = @intCast(extensions.len),
|
|
||||||
.ppEnabledExtensionNames = @ptrCast(extensions[0..]),
|
|
||||||
.enabledLayerCount = @intCast(newLayers.items.len),
|
|
||||||
.ppEnabledLayerNames = newLayers.items.ptr,
|
|
||||||
};
|
|
||||||
|
|
||||||
var instance: c.VkInstance = undefined;
|
|
||||||
|
|
||||||
try mapError(c.vkCreateInstance(&instance_info, null, &instance));
|
|
||||||
|
|
||||||
return Instance{
|
|
||||||
.handle = instance,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn destroy(self: Instance) void {
|
|
||||||
c.vkDestroyInstance(self.handle, null);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Buffer = struct {
|
pub const Buffer = struct {
|
||||||
|
|
@ -608,7 +522,6 @@ pub fn GraphicsPipeline(comptime n: usize) type {
|
||||||
@ptrCast(&view_data),
|
@ptrCast(&view_data),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
|
||||||
const view_descriptor_buffer_info = c.VkDescriptorBufferInfo{
|
const view_descriptor_buffer_info = c.VkDescriptorBufferInfo{
|
||||||
.buffer = view_buffer.handle,
|
.buffer = view_buffer.handle,
|
||||||
.offset = 0,
|
.offset = 0,
|
||||||
|
|
@ -862,7 +775,7 @@ pub fn Swapchain(comptime n: usize) type {
|
||||||
if (capabilities.currentExtent.width != std.math.maxInt(u32)) {
|
if (capabilities.currentExtent.width != std.math.maxInt(u32)) {
|
||||||
extent = capabilities.currentExtent;
|
extent = capabilities.currentExtent;
|
||||||
} else {
|
} else {
|
||||||
const width: u32, const height: u32 = .{800, 600};
|
const width: u32, const height: u32 = .{ 800, 600 };
|
||||||
|
|
||||||
extent = .{
|
extent = .{
|
||||||
.width = @intCast(width),
|
.width = @intCast(width),
|
||||||
|
|
@ -993,30 +906,6 @@ pub fn Swapchain(comptime n: usize) type {
|
||||||
pub const Surface = struct {
|
pub const Surface = struct {
|
||||||
handle: c.VkSurfaceKHR,
|
handle: c.VkSurfaceKHR,
|
||||||
|
|
||||||
pub fn create(comptime C: type, comptime S: type, instance: Instance, display: C, surface: S) !Surface {
|
|
||||||
var handle: c.VkSurfaceKHR = undefined;
|
|
||||||
if (config.wayland) {
|
|
||||||
const create_info: c.VkWaylandSurfaceCreateInfoKHR = .{
|
|
||||||
.sType = c.VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR,
|
|
||||||
.display = display,
|
|
||||||
.surface = surface,
|
|
||||||
};
|
|
||||||
|
|
||||||
try mapError(c.vkCreateWaylandSurfaceKHR(instance.handle, &create_info, null, &handle));
|
|
||||||
} else {
|
|
||||||
const create_info: c.VkXcbSurfaceCreateInfoKHR = .{
|
|
||||||
.sType = c.VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR,
|
|
||||||
.connection = display,
|
|
||||||
.window = surface,
|
|
||||||
};
|
|
||||||
try mapError(c.vkCreateXcbSurfaceKHR(instance.handle, &create_info, null, &handle));
|
|
||||||
}
|
|
||||||
|
|
||||||
return .{
|
|
||||||
.handle = handle,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn presentModes(self: Surface, allocator: Allocator, device: PhysicalDevice) ![]c.VkPresentModeKHR {
|
pub fn presentModes(self: Surface, allocator: Allocator, device: PhysicalDevice) ![]c.VkPresentModeKHR {
|
||||||
var mode_count: u32 = 0;
|
var mode_count: u32 = 0;
|
||||||
try mapError(c.vkGetPhysicalDeviceSurfacePresentModesKHR(device.handle, self.handle, &mode_count, null));
|
try mapError(c.vkGetPhysicalDeviceSurfacePresentModesKHR(device.handle, self.handle, &mode_count, null));
|
||||||
|
|
@ -1040,10 +929,6 @@ pub const Surface = struct {
|
||||||
try mapError(c.vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device.handle, self.handle, &caps));
|
try mapError(c.vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device.handle, self.handle, &caps));
|
||||||
return caps;
|
return caps;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn destroy(self: Surface, instance: Instance) void {
|
|
||||||
c.vkDestroySurfaceKHR(instance.handle, self.handle, null);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn Device(comptime n: usize) type {
|
pub fn Device(comptime n: usize) type {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,40 @@
|
||||||
pub const math = @import("math.zig");
|
|
||||||
pub const Input = @import("Input.zig");
|
|
||||||
pub const mods = @import("mods");
|
|
||||||
pub const ecs = @import("ecs");
|
pub const ecs = @import("ecs");
|
||||||
pub const Renderer = @import("renderer");
|
pub const Renderer = @import("renderer");
|
||||||
pub const config = @import("config");
|
|
||||||
pub const c = @import("c.zig").c;
|
const api = @cImport({
|
||||||
|
@cInclude("sideros_api.h");
|
||||||
|
});
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
|
const allocator = gpa.allocator();
|
||||||
|
var pool: ecs.Pool = undefined;
|
||||||
|
var renderer: Renderer = undefined;
|
||||||
|
|
||||||
|
export fn sideros_init(init: api.GameInit) callconv(.C) void {
|
||||||
|
pool = ecs.Pool.init(allocator, .{
|
||||||
|
.camera = .{
|
||||||
|
.position = .{ 0.0, 0.0, 1.0 },
|
||||||
|
.target = .{ 0.0, 0.0, 0.0 },
|
||||||
|
},
|
||||||
|
.renderer = undefined,
|
||||||
|
.input = .{ .key_pressed = .{false} ** @intFromEnum(ecs.Input.KeyCode.menu) },
|
||||||
|
}) catch @panic("TODO: Gracefully handle error");
|
||||||
|
// TODO(ernesto): I think this @ptrCast are unavoidable but maybe not?
|
||||||
|
renderer = Renderer.init(allocator, @ptrCast(init.instance), @ptrCast(init.surface)) catch @panic("TODO: Gracefully handle error");
|
||||||
|
pool.addSystemGroup(&[_]ecs.System{Renderer.render}, true) catch @panic("TODO: Gracefuly handle error");
|
||||||
|
pool.resources.renderer = renderer;
|
||||||
|
pool.tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn sideros_update(gameUpdate: api.GameUpdate) callconv(.C) void {
|
||||||
|
_ = gameUpdate;
|
||||||
|
pool.tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn sideros_cleanup() callconv(.C) void {
|
||||||
|
renderer.deinit();
|
||||||
|
pool.deinit();
|
||||||
|
if (gpa.deinit() != .ok) @panic("Memory leaked");
|
||||||
|
}
|
||||||
|
|
|
||||||
13
src/sideros_api.h
Normal file
13
src/sideros_api.h
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
#include "vulkan/vulkan.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
VkInstance instance;
|
||||||
|
VkSurfaceKHR surface;
|
||||||
|
} GameInit;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
} GameUpdate;
|
||||||
|
|
||||||
|
void sideros_init(GameInit init);
|
||||||
|
void sideros_update(GameUpdate state);
|
||||||
|
void sideros_cleanup(void);
|
||||||
159
src/wayland.zig
159
src/wayland.zig
|
|
@ -1,7 +1,15 @@
|
||||||
const c = @import("sideros").c;
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const Renderer = @import("sideros").Renderer;
|
const c = @cImport({
|
||||||
const ecs = @import("sideros").ecs;
|
@cInclude("wayland-client.h");
|
||||||
|
@cInclude("xdg-shell.h");
|
||||||
|
@cInclude("vulkan/vulkan.h");
|
||||||
|
@cInclude("vulkan/vulkan_wayland.h");
|
||||||
|
});
|
||||||
|
const sideros = @cImport({
|
||||||
|
@cInclude("sideros_api.h");
|
||||||
|
});
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
const debug = builtin.mode == .Debug;
|
||||||
|
|
||||||
var resize = false;
|
var resize = false;
|
||||||
var quit = false;
|
var quit = false;
|
||||||
|
|
@ -12,10 +20,134 @@ const State = struct {
|
||||||
compositor: ?*c.wl_compositor = null,
|
compositor: ?*c.wl_compositor = null,
|
||||||
shell: ?*c.xdg_wm_base = null,
|
shell: ?*c.xdg_wm_base = null,
|
||||||
surface: ?*c.wl_surface = null,
|
surface: ?*c.wl_surface = null,
|
||||||
pool: *ecs.Pool = undefined,
|
|
||||||
configured: bool = false,
|
configured: bool = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const validation_layers: []const [*c]const u8 = if (!debug) &[0][*c]const u8{} else &[_][*c]const u8{
|
||||||
|
"VK_LAYER_KHRONOS_validation",
|
||||||
|
};
|
||||||
|
|
||||||
|
const device_extensions: []const [*c]const u8 = &[_][*c]const u8{
|
||||||
|
c.VK_KHR_SWAPCHAIN_EXTENSION_NAME,
|
||||||
|
};
|
||||||
|
|
||||||
|
const Error = error{
|
||||||
|
initialization_failed,
|
||||||
|
unknown_error,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn mapError(result: c_int) !void {
|
||||||
|
return switch (result) {
|
||||||
|
c.VK_SUCCESS => {},
|
||||||
|
c.VK_ERROR_INITIALIZATION_FAILED => Error.initialization_failed,
|
||||||
|
else => Error.unknown_error,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vulkan_init_instance(allocator: std.mem.Allocator, handle: *c.VkInstance) !void {
|
||||||
|
const extensions = [_][*c]const u8{ c.VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, c.VK_KHR_SURFACE_EXTENSION_NAME };
|
||||||
|
|
||||||
|
// Querry avaliable extensions size
|
||||||
|
var avaliableExtensionsCount: u32 = 0;
|
||||||
|
_ = c.vkEnumerateInstanceExtensionProperties(null, &avaliableExtensionsCount, null);
|
||||||
|
// Actually querry avaliable extensions
|
||||||
|
const avaliableExtensions = try allocator.alloc(c.VkExtensionProperties, avaliableExtensionsCount);
|
||||||
|
defer allocator.free(avaliableExtensions);
|
||||||
|
_ = c.vkEnumerateInstanceExtensionProperties(null, &avaliableExtensionsCount, avaliableExtensions.ptr);
|
||||||
|
|
||||||
|
// Check the extensions we want against the extensions the user has
|
||||||
|
for (extensions) |need_ext| {
|
||||||
|
var found = false;
|
||||||
|
const needName = std.mem.sliceTo(need_ext, 0);
|
||||||
|
for (avaliableExtensions) |useable_ext| {
|
||||||
|
const extensionName = useable_ext.extensionName[0..std.mem.indexOf(u8, &useable_ext.extensionName, &[_]u8{0}).?];
|
||||||
|
|
||||||
|
if (std.mem.eql(u8, needName, extensionName)) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
std.debug.panic("ERROR: Needed vulkan extension {s} not found\n", .{need_ext});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Querry avaliable layers size
|
||||||
|
var avaliableLayersCount: u32 = 0;
|
||||||
|
_ = c.vkEnumerateInstanceLayerProperties(&avaliableLayersCount, null);
|
||||||
|
// Actually querry avaliable layers
|
||||||
|
const availableLayers = try allocator.alloc(c.VkLayerProperties, avaliableLayersCount);
|
||||||
|
defer allocator.free(availableLayers);
|
||||||
|
_ = c.vkEnumerateInstanceLayerProperties(&avaliableLayersCount, availableLayers.ptr);
|
||||||
|
|
||||||
|
// Every layer we do have we add to this list, if we don't have it no worries just print a message and continue
|
||||||
|
var newLayers = std.ArrayList([*c]const u8).init(allocator);
|
||||||
|
defer newLayers.deinit();
|
||||||
|
// Loop over layers we want
|
||||||
|
for (validation_layers) |want_layer| {
|
||||||
|
var found = false;
|
||||||
|
for (availableLayers) |useable_validation| {
|
||||||
|
const layer_name: [*c]const u8 = &useable_validation.layerName;
|
||||||
|
if (std.mem.eql(u8, std.mem.sliceTo(want_layer, 0), std.mem.sliceTo(layer_name, 0))) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
std.debug.print("WARNING: Compiled in debug mode, but wanted validation layer {s} not found.\n", .{want_layer});
|
||||||
|
std.debug.print("NOTE: Validation layer will be removed from the wanted validation layers\n", .{});
|
||||||
|
} else {
|
||||||
|
try newLayers.append(want_layer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const app_info: c.VkApplicationInfo = .{
|
||||||
|
.sType = c.VK_STRUCTURE_TYPE_APPLICATION_INFO,
|
||||||
|
.pApplicationName = "sideros",
|
||||||
|
.applicationVersion = c.VK_MAKE_VERSION(1, 0, 0),
|
||||||
|
.engineVersion = c.VK_MAKE_VERSION(1, 0, 0),
|
||||||
|
.pEngineName = "sideros",
|
||||||
|
.apiVersion = c.VK_MAKE_VERSION(1, 3, 0),
|
||||||
|
};
|
||||||
|
|
||||||
|
const instance_info: c.VkInstanceCreateInfo = .{
|
||||||
|
.sType = c.VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
|
||||||
|
.pApplicationInfo = &app_info,
|
||||||
|
.enabledExtensionCount = @intCast(extensions.len),
|
||||||
|
.ppEnabledExtensionNames = @ptrCast(extensions[0..]),
|
||||||
|
.enabledLayerCount = @intCast(newLayers.items.len),
|
||||||
|
.ppEnabledLayerNames = newLayers.items.ptr,
|
||||||
|
};
|
||||||
|
|
||||||
|
try mapError(c.vkCreateInstance(&instance_info, null, handle));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vulkan_init_surface(instance: c.VkInstance, display: ?*c.wl_display, surface: ?*c.wl_surface, handle: *c.VkSurfaceKHR) !void {
|
||||||
|
const create_info: c.VkWaylandSurfaceCreateInfoKHR = .{
|
||||||
|
.sType = c.VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR,
|
||||||
|
.display = display,
|
||||||
|
.surface = surface,
|
||||||
|
};
|
||||||
|
try mapError(c.vkCreateWaylandSurfaceKHR(instance, &create_info, null, handle));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vulkan_init(allocator: std.mem.Allocator, display: ?*c.wl_display, surface: ?*c.wl_surface) !sideros.GameInit {
|
||||||
|
var gameInit: sideros.GameInit = undefined;
|
||||||
|
|
||||||
|
try vulkan_init_instance(allocator, &gameInit.instance);
|
||||||
|
// TODO(ernesto): This pointer cast is weird as fuck
|
||||||
|
try vulkan_init_surface(@ptrCast(gameInit.instance), display, surface, &gameInit.surface);
|
||||||
|
|
||||||
|
return gameInit;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vulkan_cleanup(gameInit: sideros.GameInit) void {
|
||||||
|
// TODO(ernesto): again this ptr
|
||||||
|
// this can be solved merging the cImports. But that seems uglier to me...
|
||||||
|
c.vkDestroySurfaceKHR(@ptrCast(gameInit.instance), @ptrCast(gameInit.surface), null);
|
||||||
|
c.vkDestroyInstance(@ptrCast(gameInit.instance), null);
|
||||||
|
}
|
||||||
|
|
||||||
fn registryHandleGlobal(data: ?*anyopaque, registry: ?*c.wl_registry, name: u32, interface: [*c]const u8, version: u32) callconv(.c) void {
|
fn registryHandleGlobal(data: ?*anyopaque, registry: ?*c.wl_registry, name: u32, interface: [*c]const u8, version: u32) callconv(.c) void {
|
||||||
_ = version;
|
_ = version;
|
||||||
const state: *State = @alignCast(@ptrCast(data));
|
const state: *State = @alignCast(@ptrCast(data));
|
||||||
|
|
@ -79,7 +211,9 @@ fn frameHandleDone(data: ?*anyopaque, callback: ?*c.wl_callback, time: u32) call
|
||||||
const cb = c.wl_surface_frame(state.surface);
|
const cb = c.wl_surface_frame(state.surface);
|
||||||
_ = c.wl_callback_add_listener(cb, &frame_listener, state);
|
_ = c.wl_callback_add_listener(cb, &frame_listener, state);
|
||||||
|
|
||||||
state.pool.tick();
|
const gameUpdate: sideros.GameUpdate = undefined;
|
||||||
|
sideros.sideros_update(gameUpdate);
|
||||||
|
|
||||||
_ = c.wl_surface_commit(state.surface);
|
_ = c.wl_surface_commit(state.surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -106,7 +240,7 @@ const registry_listener: c.wl_registry_listener = .{
|
||||||
.global_remove = registryHandleGlobalRemove,
|
.global_remove = registryHandleGlobalRemove,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn init(allocator: std.mem.Allocator, pool: *ecs.Pool) !void {
|
pub fn main() !void {
|
||||||
var state: State = .{};
|
var state: State = .{};
|
||||||
const display = c.wl_display_connect(null);
|
const display = c.wl_display_connect(null);
|
||||||
defer c.wl_display_disconnect(display);
|
defer c.wl_display_disconnect(display);
|
||||||
|
|
@ -131,18 +265,21 @@ pub fn init(allocator: std.mem.Allocator, pool: *ecs.Pool) !void {
|
||||||
c.xdg_toplevel_set_app_id(toplevel, @ptrCast(&title[0]));
|
c.xdg_toplevel_set_app_id(toplevel, @ptrCast(&title[0]));
|
||||||
c.xdg_toplevel_set_min_size(toplevel, 800, 600);
|
c.xdg_toplevel_set_min_size(toplevel, 800, 600);
|
||||||
c.xdg_toplevel_set_max_size(toplevel, 800, 600);
|
c.xdg_toplevel_set_max_size(toplevel, 800, 600);
|
||||||
|
|
||||||
_ = c.wl_surface_commit(surface);
|
_ = c.wl_surface_commit(surface);
|
||||||
|
|
||||||
while (!state.configured) {
|
while (!state.configured) {
|
||||||
_ = c.wl_display_dispatch(display);
|
_ = c.wl_display_dispatch(display);
|
||||||
}
|
}
|
||||||
|
|
||||||
var renderer = try Renderer.init(@TypeOf(display), @TypeOf(surface), allocator, display, surface);
|
|
||||||
|
|
||||||
pool.resources.renderer = &renderer;
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
state.pool = pool;
|
const allocator = gpa.allocator();
|
||||||
pool.tick();
|
defer if (gpa.deinit() != .ok) @panic("Platform memory leaked");
|
||||||
|
|
||||||
|
const gameInit = try vulkan_init(allocator, display, surface);
|
||||||
|
defer vulkan_cleanup(gameInit);
|
||||||
|
sideros.sideros_init(gameInit);
|
||||||
|
|
||||||
const cb = c.wl_surface_frame(surface);
|
const cb = c.wl_surface_frame(surface);
|
||||||
_ = c.wl_callback_add_listener(cb, &frame_listener, @ptrCast(&state));
|
_ = c.wl_callback_add_listener(cb, &frame_listener, @ptrCast(&state));
|
||||||
|
|
|
||||||
156
src/xorg.zig
156
src/xorg.zig
|
|
@ -1,9 +1,141 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const Renderer = @import("sideros").Renderer;
|
const sideros = @cImport({
|
||||||
const c = @import("sideros").c;
|
@cInclude("sideros_api.h");
|
||||||
const ecs = @import("sideros").ecs;
|
});
|
||||||
|
const c = @cImport({
|
||||||
|
@cInclude("xcb/xcb.h");
|
||||||
|
@cInclude("vulkan/vulkan.h");
|
||||||
|
@cInclude("vulkan/vulkan_xcb.h");
|
||||||
|
@cInclude("xcb/xcb_icccm.h");
|
||||||
|
});
|
||||||
|
|
||||||
pub fn init(allocator: std.mem.Allocator, pool: *ecs.Pool) !void {
|
const builtin = @import("builtin");
|
||||||
|
const debug = (builtin.mode == .Debug);
|
||||||
|
|
||||||
|
const validation_layers: []const [*c]const u8 = if (!debug) &[0][*c]const u8{} else &[_][*c]const u8{
|
||||||
|
"VK_LAYER_KHRONOS_validation",
|
||||||
|
};
|
||||||
|
|
||||||
|
const device_extensions: []const [*c]const u8 = &[_][*c]const u8{
|
||||||
|
c.VK_KHR_SWAPCHAIN_EXTENSION_NAME,
|
||||||
|
};
|
||||||
|
|
||||||
|
const Error = error{
|
||||||
|
initialization_failed,
|
||||||
|
unknown_error,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn mapError(result: c_int) !void {
|
||||||
|
return switch (result) {
|
||||||
|
c.VK_SUCCESS => {},
|
||||||
|
c.VK_ERROR_INITIALIZATION_FAILED => Error.initialization_failed,
|
||||||
|
else => Error.unknown_error,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vulkan_init_instance(allocator: std.mem.Allocator, handle: *c.VkInstance) !void {
|
||||||
|
const extensions = [_][*c]const u8{ c.VK_KHR_XCB_SURFACE_EXTENSION_NAME, c.VK_KHR_SURFACE_EXTENSION_NAME };
|
||||||
|
|
||||||
|
// Querry avaliable extensions size
|
||||||
|
var avaliableExtensionsCount: u32 = 0;
|
||||||
|
_ = c.vkEnumerateInstanceExtensionProperties(null, &avaliableExtensionsCount, null);
|
||||||
|
// Actually querry avaliable extensions
|
||||||
|
const avaliableExtensions = try allocator.alloc(c.VkExtensionProperties, avaliableExtensionsCount);
|
||||||
|
defer allocator.free(avaliableExtensions);
|
||||||
|
_ = c.vkEnumerateInstanceExtensionProperties(null, &avaliableExtensionsCount, avaliableExtensions.ptr);
|
||||||
|
|
||||||
|
// Check the extensions we want against the extensions the user has
|
||||||
|
for (extensions) |need_ext| {
|
||||||
|
var found = false;
|
||||||
|
const needName = std.mem.sliceTo(need_ext, 0);
|
||||||
|
for (avaliableExtensions) |useable_ext| {
|
||||||
|
const extensionName = useable_ext.extensionName[0..std.mem.indexOf(u8, &useable_ext.extensionName, &[_]u8{0}).?];
|
||||||
|
|
||||||
|
if (std.mem.eql(u8, needName, extensionName)) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
std.debug.panic("ERROR: Needed vulkan extension {s} not found\n", .{need_ext});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Querry avaliable layers size
|
||||||
|
var avaliableLayersCount: u32 = 0;
|
||||||
|
_ = c.vkEnumerateInstanceLayerProperties(&avaliableLayersCount, null);
|
||||||
|
// Actually querry avaliable layers
|
||||||
|
const availableLayers = try allocator.alloc(c.VkLayerProperties, avaliableLayersCount);
|
||||||
|
defer allocator.free(availableLayers);
|
||||||
|
_ = c.vkEnumerateInstanceLayerProperties(&avaliableLayersCount, availableLayers.ptr);
|
||||||
|
|
||||||
|
// Every layer we do have we add to this list, if we don't have it no worries just print a message and continue
|
||||||
|
var newLayers = std.ArrayList([*c]const u8).init(allocator);
|
||||||
|
defer newLayers.deinit();
|
||||||
|
// Loop over layers we want
|
||||||
|
for (validation_layers) |want_layer| {
|
||||||
|
var found = false;
|
||||||
|
for (availableLayers) |useable_validation| {
|
||||||
|
const layer_name: [*c]const u8 = &useable_validation.layerName;
|
||||||
|
if (std.mem.eql(u8, std.mem.sliceTo(want_layer, 0), std.mem.sliceTo(layer_name, 0))) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
std.debug.print("WARNING: Compiled in debug mode, but wanted validation layer {s} not found.\n", .{want_layer});
|
||||||
|
std.debug.print("NOTE: Validation layer will be removed from the wanted validation layers\n", .{});
|
||||||
|
} else {
|
||||||
|
try newLayers.append(want_layer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const app_info: c.VkApplicationInfo = .{
|
||||||
|
.sType = c.VK_STRUCTURE_TYPE_APPLICATION_INFO,
|
||||||
|
.pApplicationName = "sideros",
|
||||||
|
.applicationVersion = c.VK_MAKE_VERSION(1, 0, 0),
|
||||||
|
.engineVersion = c.VK_MAKE_VERSION(1, 0, 0),
|
||||||
|
.pEngineName = "sideros",
|
||||||
|
.apiVersion = c.VK_MAKE_VERSION(1, 3, 0),
|
||||||
|
};
|
||||||
|
|
||||||
|
const instance_info: c.VkInstanceCreateInfo = .{
|
||||||
|
.sType = c.VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
|
||||||
|
.pApplicationInfo = &app_info,
|
||||||
|
.enabledExtensionCount = @intCast(extensions.len),
|
||||||
|
.ppEnabledExtensionNames = @ptrCast(extensions[0..]),
|
||||||
|
.enabledLayerCount = @intCast(newLayers.items.len),
|
||||||
|
.ppEnabledLayerNames = newLayers.items.ptr,
|
||||||
|
};
|
||||||
|
|
||||||
|
try mapError(c.vkCreateInstance(&instance_info, null, handle));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vulkan_init_surface(instance: c.VkInstance, connection: ?*c.xcb_connection_t, window: u32, handle: *c.VkSurfaceKHR) !void {
|
||||||
|
const create_info: c.VkXcbSurfaceCreateInfoKHR = .{
|
||||||
|
.sType = c.VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR,
|
||||||
|
.connection = connection,
|
||||||
|
.window = window,
|
||||||
|
};
|
||||||
|
try mapError(c.vkCreateXcbSurfaceKHR(instance, &create_info, null, handle));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vulkan_init(allocator: std.mem.Allocator, connection: ?*c.xcb_connection_t, window: u32) !sideros.GameInit {
|
||||||
|
var gameInit: sideros.GameInit = undefined;
|
||||||
|
|
||||||
|
try vulkan_init_instance(allocator, &gameInit.instance);
|
||||||
|
// TODO(ernesto): This pointer cast is weird as fuck
|
||||||
|
try vulkan_init_surface(@ptrCast(gameInit.instance), connection, window, &gameInit.surface);
|
||||||
|
|
||||||
|
return gameInit;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vulkan_cleanup(gameInit: sideros.GameInit) void {
|
||||||
|
c.vkDestroySurfaceKHR(gameInit.instance, gameInit.surface, null);
|
||||||
|
c.vkDestroyInstance(gameInit.instance, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() !void {
|
||||||
const connection = c.xcb_connect(null, null);
|
const connection = c.xcb_connect(null, null);
|
||||||
defer c.xcb_disconnect(connection);
|
defer c.xcb_disconnect(connection);
|
||||||
|
|
||||||
|
|
@ -26,10 +158,14 @@ pub fn init(allocator: std.mem.Allocator, pool: *ecs.Pool) !void {
|
||||||
|
|
||||||
_ = c.xcb_flush(connection);
|
_ = c.xcb_flush(connection);
|
||||||
|
|
||||||
var renderer = try Renderer.init(@TypeOf(connection), @TypeOf(window), allocator, connection, window);
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
defer renderer.deinit();
|
const allocator = gpa.allocator();
|
||||||
|
defer if (gpa.deinit() != .ok) @panic("Memory leaked");
|
||||||
|
|
||||||
pool.resources.renderer = &renderer;
|
const gameInit = try vulkan_init(allocator, connection, window);
|
||||||
|
defer vulkan_cleanup(gameInit);
|
||||||
|
|
||||||
|
sideros.sideros_init(gameInit);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (c.xcb_poll_for_event(connection)) |e| {
|
if (c.xcb_poll_for_event(connection)) |e| {
|
||||||
|
|
@ -38,7 +174,9 @@ pub fn init(allocator: std.mem.Allocator, pool: *ecs.Pool) !void {
|
||||||
}
|
}
|
||||||
std.c.free(e);
|
std.c.free(e);
|
||||||
}
|
}
|
||||||
|
const gameUpdate: sideros.GameUpdate = undefined;
|
||||||
pool.tick();
|
sideros.sideros_update(gameUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sideros.sideros_cleanup();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue