Compare commits
2 Commits
743e3293bd
...
52cdbef876
Author | SHA1 | Date | |
---|---|---|---|
52cdbef876 | |||
d708144dca |
16
.vscode/launch.json
vendored
Normal file
16
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Debug",
|
||||||
|
"type": "gdb",
|
||||||
|
"request": "launch",
|
||||||
|
"target": "./zig-out/learnopengl",
|
||||||
|
"cwd": "${workspaceRoot}",
|
||||||
|
"valuesFormatting": "parseText"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -2,5 +2,6 @@
|
|||||||
{
|
{
|
||||||
"shader": "bloom_downsample.glsl",
|
"shader": "bloom_downsample.glsl",
|
||||||
"vertex": true,
|
"vertex": true,
|
||||||
"fragment": true
|
"fragment": true,
|
||||||
|
"compute": false
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
{
|
{
|
||||||
"shader": "bloom_upsample.glsl",
|
"shader": "bloom_upsample.glsl",
|
||||||
"vertex": true,
|
"vertex": true,
|
||||||
"fragment": true
|
"fragment": true,
|
||||||
|
"compute": false
|
||||||
}
|
}
|
||||||
|
@ -2,5 +2,6 @@
|
|||||||
{
|
{
|
||||||
"shader": "cube_shadow.glsl",
|
"shader": "cube_shadow.glsl",
|
||||||
"vertex": true,
|
"vertex": true,
|
||||||
"fragment": true
|
"fragment": true,
|
||||||
|
"compute": false
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"shader": "debug.glsl",
|
"shader": "debug.glsl",
|
||||||
"vertex": true,
|
"vertex": true,
|
||||||
"fragment": true
|
"fragment": true,
|
||||||
|
"compute": false
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"shader": "mesh.glsl",
|
"shader": "mesh.glsl",
|
||||||
"vertex": true,
|
"vertex": true,
|
||||||
"fragment": true
|
"fragment": true,
|
||||||
|
"compute": false
|
||||||
}
|
}
|
||||||
|
@ -2,5 +2,6 @@
|
|||||||
{
|
{
|
||||||
"shader": "post_process.glsl",
|
"shader": "post_process.glsl",
|
||||||
"vertex": true,
|
"vertex": true,
|
||||||
"fragment": true
|
"fragment": true,
|
||||||
|
"compute": false
|
||||||
}
|
}
|
||||||
|
@ -2,5 +2,6 @@
|
|||||||
{
|
{
|
||||||
"shader": "shadow.glsl",
|
"shader": "shadow.glsl",
|
||||||
"vertex": true,
|
"vertex": true,
|
||||||
"fragment": true
|
"fragment": true,
|
||||||
|
"compute": false
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"shader": "unlit.glsl",
|
"shader": "unlit.glsl",
|
||||||
"vertex": true,
|
"vertex": true,
|
||||||
"fragment": true
|
"fragment": true,
|
||||||
|
"compute": false
|
||||||
}
|
}
|
||||||
|
@ -2,5 +2,6 @@
|
|||||||
{
|
{
|
||||||
"shader": "z_prepass.glsl",
|
"shader": "z_prepass.glsl",
|
||||||
"vertex": true,
|
"vertex": true,
|
||||||
"fragment": true
|
"fragment": true,
|
||||||
|
"compute": false
|
||||||
}
|
}
|
||||||
|
29
build.zig
29
build.zig
@ -3,6 +3,20 @@ const Build = std.Build;
|
|||||||
const Step = Build.Step;
|
const Step = Build.Step;
|
||||||
const GenerateAssetManifest = @import("tools/GenerateAssetManifest.zig");
|
const GenerateAssetManifest = @import("tools/GenerateAssetManifest.zig");
|
||||||
|
|
||||||
|
fn buildVulkanWrapper(b: *Build, target: Build.ResolvedTarget, optimize: std.builtin.OptimizeMode) *Build.Module {
|
||||||
|
const registry = b.dependency("vulkan_headers", .{}).path("registry/vk.xml");
|
||||||
|
const vk_gen = b.dependency("vulkan_zig", .{}).artifact("vulkan-zig-generator");
|
||||||
|
const vk_generate_cmd = b.addRunArtifact(vk_gen);
|
||||||
|
vk_generate_cmd.addFileArg(registry);
|
||||||
|
const vk_zig_path = vk_generate_cmd.addOutputFileArg("vk.zig");
|
||||||
|
|
||||||
|
return b.addModule("vk", .{
|
||||||
|
.root_source_file = vk_zig_path,
|
||||||
|
.optimize = optimize,
|
||||||
|
.target = target,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Although this function looks imperative, note that its job is to
|
// Although this function looks imperative, note that its job is to
|
||||||
// declaratively construct a build graph that will be executed by an external
|
// declaratively construct a build graph that will be executed by an external
|
||||||
// runner.
|
// runner.
|
||||||
@ -23,6 +37,8 @@ pub fn build(b: *Build) void {
|
|||||||
"Prioritize performance, safety, or binary size for build time tools",
|
"Prioritize performance, safety, or binary size for build time tools",
|
||||||
) orelse .Debug;
|
) orelse .Debug;
|
||||||
|
|
||||||
|
const vk = buildVulkanWrapper(b, target, optimize);
|
||||||
|
|
||||||
const tracy = b.dependency("zig-tracy", .{
|
const tracy = b.dependency("zig-tracy", .{
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
@ -67,6 +83,7 @@ pub fn build(b: *Build) void {
|
|||||||
l.root_module.addImport("assets", assets_mod);
|
l.root_module.addImport("assets", assets_mod);
|
||||||
l.root_module.addImport("asset_manifest", asset_manifest_mod);
|
l.root_module.addImport("asset_manifest", asset_manifest_mod);
|
||||||
l.root_module.addImport("tracy", tracy.module("tracy"));
|
l.root_module.addImport("tracy", tracy.module("tracy"));
|
||||||
|
l.root_module.addImport("vk", vk);
|
||||||
l.linkLibrary(tracy.artifact("tracy"));
|
l.linkLibrary(tracy.artifact("tracy"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,7 +170,6 @@ pub fn build(b: *Build) void {
|
|||||||
|
|
||||||
const asset_extensions = [_][]const u8{
|
const asset_extensions = [_][]const u8{
|
||||||
"obj",
|
"obj",
|
||||||
"glsl",
|
|
||||||
"prog",
|
"prog",
|
||||||
"png",
|
"png",
|
||||||
"dds",
|
"dds",
|
||||||
@ -226,8 +242,14 @@ fn buildAssetCompiler(b: *Build, optimize: std.builtin.OptimizeMode, assets_mod:
|
|||||||
//.formats = @as([]const u8, "3DS,3MF,AC,AMF,ASE,Assbin,Assjson,Assxml,B3D,Blender,BVH,C4D,COB,Collada,CSM,DXF,FBX,glTF,glTF2,HMP,IFC,Irr,LWO,LWS,M3D,MD2,MD3,MD5,MDC,MDL,MMD,MS3D,NDO,NFF,Obj,OFF,Ogre,OpenGEX,Ply,Q3BSP,Q3D,Raw,SIB,SMD,Step,STEPParser,STL,Terragen,Unreal,X,X3D,XGL"),
|
//.formats = @as([]const u8, "3DS,3MF,AC,AMF,ASE,Assbin,Assjson,Assxml,B3D,Blender,BVH,C4D,COB,Collada,CSM,DXF,FBX,glTF,glTF2,HMP,IFC,Irr,LWO,LWS,M3D,MD2,MD3,MD5,MDC,MDL,MMD,MS3D,NDO,NFF,Obj,OFF,Ogre,OpenGEX,Ply,Q3BSP,Q3D,Raw,SIB,SMD,Step,STEPParser,STL,Terragen,Unreal,X,X3D,XGL"),
|
||||||
.formats = @as([]const u8, "Obj,FBX,glTF,glTF2,Blend"),
|
.formats = @as([]const u8, "Obj,FBX,glTF,glTF2,Blend"),
|
||||||
});
|
});
|
||||||
|
const mach_dxcompiler_dep = b.dependency("mach_dxcompiler", .{
|
||||||
|
.target = b.graph.host,
|
||||||
|
.optimize = optimize,
|
||||||
|
.from_source = true,
|
||||||
|
.spirv = true,
|
||||||
|
.skip_tests = true,
|
||||||
|
});
|
||||||
const zalgebra_dep = b.dependency("zalgebra", .{});
|
const zalgebra_dep = b.dependency("zalgebra", .{});
|
||||||
|
|
||||||
const assimp_lib = assimp_dep.artifact("assimp");
|
const assimp_lib = assimp_dep.artifact("assimp");
|
||||||
|
|
||||||
const assetc = b.addExecutable(.{
|
const assetc = b.addExecutable(.{
|
||||||
@ -247,8 +269,11 @@ fn buildAssetCompiler(b: *Build, optimize: std.builtin.OptimizeMode, assets_mod:
|
|||||||
assetc.linkSystemLibrary("ispc_texcomp");
|
assetc.linkSystemLibrary("ispc_texcomp");
|
||||||
|
|
||||||
const zalgebra_mod = zalgebra_dep.module("zalgebra");
|
const zalgebra_mod = zalgebra_dep.module("zalgebra");
|
||||||
|
const mach_dxcompiler_mod = mach_dxcompiler_dep.module("mach-dxcompiler");
|
||||||
const formats_mod = b.addModule("formats", .{ .root_source_file = b.path("src/formats.zig") });
|
const formats_mod = b.addModule("formats", .{ .root_source_file = b.path("src/formats.zig") });
|
||||||
|
|
||||||
formats_mod.addImport("zalgebra", zalgebra_mod);
|
formats_mod.addImport("zalgebra", zalgebra_mod);
|
||||||
|
formats_mod.addImport("mach-dxcompiler", mach_dxcompiler_mod);
|
||||||
formats_mod.addImport("assets", assets_mod);
|
formats_mod.addImport("assets", assets_mod);
|
||||||
assetc.root_module.addImport("formats", formats_mod);
|
assetc.root_module.addImport("formats", formats_mod);
|
||||||
assetc.root_module.addImport("zalgebra", zalgebra_mod);
|
assetc.root_module.addImport("zalgebra", zalgebra_mod);
|
||||||
|
@ -31,6 +31,18 @@
|
|||||||
.url = "https://github.com/sergeypdev/zig-tracy/tarball/2b818574810a66deacc424298c1a7679ca6e4375",
|
.url = "https://github.com/sergeypdev/zig-tracy/tarball/2b818574810a66deacc424298c1a7679ca6e4375",
|
||||||
.hash = "1220638bc94d67225a620e1abd71d85b299c8b764490fd51233ed73d76ee44cc5835",
|
.hash = "1220638bc94d67225a620e1abd71d85b299c8b764490fd51233ed73d76ee44cc5835",
|
||||||
},
|
},
|
||||||
|
.vulkan_headers = .{
|
||||||
|
.url = "https://github.com/KhronosGroup/Vulkan-Headers/archive/v1.3.283.tar.gz",
|
||||||
|
.hash = "1220a7e73d72a0d56bc2a65f9d8999a7c019e42260a0744c408d1cded111bc205e10",
|
||||||
|
},
|
||||||
|
.vulkan_zig = .{
|
||||||
|
.url = "https://github.com/Snektron/vulkan-zig/tarball/66b7b773bb61e2102025f2d5ff0ae8c5f53e19cc",
|
||||||
|
.hash = "12208958f173b8b81bfac797955f0416ab38b21d1f69d4ebf6c7ca460a828a41cd45",
|
||||||
|
},
|
||||||
|
.mach_dxcompiler = .{
|
||||||
|
.url = "https://github.com/sinnwrig/mach-dxcompiler/tarball/c3dfe92f3f04d4a3262dbc1a71f0016b9af92eb4",
|
||||||
|
.hash = "12202f48e7cf06b1f2ecfd84f16effbd5bb9d644ea17e8a6144b4301a4dea198cf9c",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
.paths = .{
|
.paths = .{
|
||||||
// This makes *all* files, recursively, included in this package. It is generally
|
// This makes *all* files, recursively, included in this package. It is generally
|
||||||
|
@ -304,6 +304,7 @@ fn didUpdate(self: *AssetManager, path: []const u8, last_modified: i128) bool {
|
|||||||
pub const ShaderProgramDefinition = struct {
|
pub const ShaderProgramDefinition = struct {
|
||||||
vertex: []const u8,
|
vertex: []const u8,
|
||||||
fragment: []const u8,
|
fragment: []const u8,
|
||||||
|
compute: []const u8,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn loadShaderProgram(self: *AssetManager, handle: Handle.ShaderProgram, permuted_id: AssetId, defines: []const DefinePair) LoadedShaderProgram {
|
pub fn loadShaderProgram(self: *AssetManager, handle: Handle.ShaderProgram, permuted_id: AssetId, defines: []const DefinePair) LoadedShaderProgram {
|
||||||
@ -318,8 +319,11 @@ fn loadShaderProgramErr(self: *AssetManager, id: AssetId, permuted_id: AssetId,
|
|||||||
const data = try self.loadFile(self.frame_arena, asset_manifest.getPath(id), SHADER_MAX_BYTES);
|
const data = try self.loadFile(self.frame_arena, asset_manifest.getPath(id), SHADER_MAX_BYTES);
|
||||||
const program = formats.ShaderProgram.fromBuffer(data.bytes);
|
const program = formats.ShaderProgram.fromBuffer(data.bytes);
|
||||||
|
|
||||||
if (!program.flags.vertex or !program.flags.fragment) {
|
const graphics_pipeline = program.flags.vertex and program.flags.fragment;
|
||||||
std.log.err("Can't compile shader program {s} without vertex AND fragment shaders\n", .{asset_manifest.getPath(id)});
|
const compute_pipeline = program.flags.compute;
|
||||||
|
|
||||||
|
if (!graphics_pipeline and !compute_pipeline) {
|
||||||
|
std.log.err("Can't compile shader program {s} without vertex AND fragment shaders or a compute shader\n", .{asset_manifest.getPath(id)});
|
||||||
return error.UnsupportedShader;
|
return error.UnsupportedShader;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -330,17 +334,27 @@ fn loadShaderProgramErr(self: *AssetManager, id: AssetId, permuted_id: AssetId,
|
|||||||
const prog = gl.createProgram();
|
const prog = gl.createProgram();
|
||||||
errdefer gl.deleteProgram(prog);
|
errdefer gl.deleteProgram(prog);
|
||||||
|
|
||||||
const vertex_shader = try self.compileShader(shader.source, .vertex);
|
if (program.flags.vertex and program.flags.fragment) {
|
||||||
defer gl.deleteShader(vertex_shader);
|
const vertex_shader = try self.compileShader(shader.source, .vertex);
|
||||||
const fragment_shader = try self.compileShader(shader.source, .fragment);
|
defer gl.deleteShader(vertex_shader);
|
||||||
defer gl.deleteShader(fragment_shader);
|
const fragment_shader = try self.compileShader(shader.source, .fragment);
|
||||||
|
defer gl.deleteShader(fragment_shader);
|
||||||
|
|
||||||
gl.attachShader(prog, vertex_shader);
|
gl.attachShader(prog, vertex_shader);
|
||||||
defer gl.detachShader(prog, vertex_shader);
|
defer gl.detachShader(prog, vertex_shader);
|
||||||
gl.attachShader(prog, fragment_shader);
|
gl.attachShader(prog, fragment_shader);
|
||||||
defer gl.detachShader(prog, fragment_shader);
|
defer gl.detachShader(prog, fragment_shader);
|
||||||
|
|
||||||
gl.linkProgram(prog);
|
gl.linkProgram(prog);
|
||||||
|
} else {
|
||||||
|
const compute_shader = try self.compileShader(shader.source, .compute);
|
||||||
|
defer gl.deleteShader(compute_shader);
|
||||||
|
|
||||||
|
gl.attachShader(prog, compute_shader);
|
||||||
|
defer gl.detachShader(prog, compute_shader);
|
||||||
|
|
||||||
|
gl.linkProgram(prog);
|
||||||
|
}
|
||||||
|
|
||||||
var success: c_int = 0;
|
var success: c_int = 0;
|
||||||
gl.getProgramiv(prog, gl.LINK_STATUS, &success);
|
gl.getProgramiv(prog, gl.LINK_STATUS, &success);
|
||||||
@ -774,20 +788,24 @@ pub const IndexSlice = struct {
|
|||||||
pub const ShaderType = enum {
|
pub const ShaderType = enum {
|
||||||
vertex,
|
vertex,
|
||||||
fragment,
|
fragment,
|
||||||
|
compute,
|
||||||
|
|
||||||
pub fn goGLType(self: ShaderType) gl.GLenum {
|
pub fn goGLType(self: ShaderType) gl.GLenum {
|
||||||
return switch (self) {
|
return switch (self) {
|
||||||
.vertex => gl.VERTEX_SHADER,
|
.vertex => gl.VERTEX_SHADER,
|
||||||
.fragment => gl.FRAGMENT_SHADER,
|
.fragment => gl.FRAGMENT_SHADER,
|
||||||
|
.compute => gl.COMPUTE_SHADER,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const VERTEX_DEFINES = "#version 460 core\n#define VERTEX_SHADER 1\n#define VERTEX_EXPORT out\n";
|
const VERTEX_DEFINES = "#version 460 core\n#define VERTEX_SHADER 1\n#define VERTEX_EXPORT out\n";
|
||||||
const FRAGMENT_DEFINES = "#version 460 core\n#define FRAGMENT_SHADER 1\n#define VERTEX_EXPORT in\n";
|
const FRAGMENT_DEFINES = "#version 460 core\n#define FRAGMENT_SHADER 1\n#define VERTEX_EXPORT in\n";
|
||||||
|
const COMPUTE_DEFINES = "#version 460 core\n#define COMPUTE_SHADER 1\n";
|
||||||
pub fn getDefines(self: ShaderType) []const u8 {
|
pub fn getDefines(self: ShaderType) []const u8 {
|
||||||
return switch (self) {
|
return switch (self) {
|
||||||
.vertex => VERTEX_DEFINES,
|
.vertex => VERTEX_DEFINES,
|
||||||
.fragment => FRAGMENT_DEFINES,
|
.fragment => FRAGMENT_DEFINES,
|
||||||
|
.compute => COMPUTE_DEFINES,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1578,18 +1596,18 @@ const VertexBufferHeap = struct {
|
|||||||
var index_buddy = try BuddyAllocator.init(allocator, 4096, 13);
|
var index_buddy = try BuddyAllocator.init(allocator, 4096, 13);
|
||||||
errdefer index_buddy.deinit();
|
errdefer index_buddy.deinit();
|
||||||
|
|
||||||
const vertex_buf_size = vertex_buddy.getSize();
|
// const vertex_buf_size = vertex_buddy.getSize();
|
||||||
const index_buf_size = index_buddy.getSize();
|
// const index_buf_size = index_buddy.getSize();
|
||||||
|
|
||||||
var bufs = [_]gl.GLuint{ 0, 0, 0, 0, 0 };
|
const bufs = [_]gl.GLuint{ 0, 0, 0, 0, 0 };
|
||||||
gl.createBuffers(bufs.len, &bufs);
|
// gl.createBuffers(bufs.len, &bufs);
|
||||||
errdefer gl.deleteBuffers(bufs.len, &bufs);
|
// errdefer gl.deleteBuffers(bufs.len, &bufs);
|
||||||
|
|
||||||
for (bufs) |buf| {
|
// for (bufs) |buf| {
|
||||||
if (buf == 0) {
|
// if (buf == 0) {
|
||||||
return error.BufferAllocationFailed;
|
// return error.BufferAllocationFailed;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
const vertices = Buffer.init(bufs[0], @sizeOf(formats.Vector3));
|
const vertices = Buffer.init(bufs[0], @sizeOf(formats.Vector3));
|
||||||
const normals = Buffer.init(bufs[1], @sizeOf(formats.Vector3));
|
const normals = Buffer.init(bufs[1], @sizeOf(formats.Vector3));
|
||||||
@ -1597,36 +1615,36 @@ const VertexBufferHeap = struct {
|
|||||||
const uvs = Buffer.init(bufs[3], @sizeOf(formats.Vector2));
|
const uvs = Buffer.init(bufs[3], @sizeOf(formats.Vector2));
|
||||||
const indices = Buffer.init(bufs[4], @sizeOf(formats.Index));
|
const indices = Buffer.init(bufs[4], @sizeOf(formats.Index));
|
||||||
|
|
||||||
gl.namedBufferStorage(
|
// gl.namedBufferStorage(
|
||||||
vertices.buffer,
|
// vertices.buffer,
|
||||||
@intCast(vertex_buf_size * @sizeOf(formats.Vector3)),
|
// @intCast(vertex_buf_size * @sizeOf(formats.Vector3)),
|
||||||
null,
|
// null,
|
||||||
gl.DYNAMIC_STORAGE_BIT,
|
// gl.DYNAMIC_STORAGE_BIT,
|
||||||
);
|
// );
|
||||||
gl.namedBufferStorage(
|
// gl.namedBufferStorage(
|
||||||
normals.buffer,
|
// normals.buffer,
|
||||||
@intCast(vertex_buf_size * @sizeOf(formats.Vector3)),
|
// @intCast(vertex_buf_size * @sizeOf(formats.Vector3)),
|
||||||
null,
|
// null,
|
||||||
gl.DYNAMIC_STORAGE_BIT,
|
// gl.DYNAMIC_STORAGE_BIT,
|
||||||
);
|
// );
|
||||||
gl.namedBufferStorage(
|
// gl.namedBufferStorage(
|
||||||
tangents.buffer,
|
// tangents.buffer,
|
||||||
@intCast(vertex_buf_size * @sizeOf(formats.Vector3)),
|
// @intCast(vertex_buf_size * @sizeOf(formats.Vector3)),
|
||||||
null,
|
// null,
|
||||||
gl.DYNAMIC_STORAGE_BIT,
|
// gl.DYNAMIC_STORAGE_BIT,
|
||||||
);
|
// );
|
||||||
gl.namedBufferStorage(
|
// gl.namedBufferStorage(
|
||||||
uvs.buffer,
|
// uvs.buffer,
|
||||||
@intCast(vertex_buf_size * @sizeOf(formats.Vector2)),
|
// @intCast(vertex_buf_size * @sizeOf(formats.Vector2)),
|
||||||
null,
|
// null,
|
||||||
gl.DYNAMIC_STORAGE_BIT,
|
// gl.DYNAMIC_STORAGE_BIT,
|
||||||
);
|
// );
|
||||||
gl.namedBufferStorage(
|
// gl.namedBufferStorage(
|
||||||
indices.buffer,
|
// indices.buffer,
|
||||||
@intCast(index_buf_size * @sizeOf(formats.Index)),
|
// @intCast(index_buf_size * @sizeOf(formats.Index)),
|
||||||
null,
|
// null,
|
||||||
gl.DYNAMIC_STORAGE_BIT,
|
// gl.DYNAMIC_STORAGE_BIT,
|
||||||
);
|
// );
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.vertex_buddy = vertex_buddy,
|
.vertex_buddy = vertex_buddy,
|
||||||
|
534
src/GraphicsContext.zig
Normal file
534
src/GraphicsContext.zig
Normal file
@ -0,0 +1,534 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const vk = @import("vk");
|
||||||
|
const c = @import("sdl.zig");
|
||||||
|
|
||||||
|
pub const GraphicsContext = @This();
|
||||||
|
|
||||||
|
const apis: []const vk.ApiInfo = &.{
|
||||||
|
vk.features.version_1_0,
|
||||||
|
vk.features.version_1_1,
|
||||||
|
vk.features.version_1_2,
|
||||||
|
vk.features.version_1_3,
|
||||||
|
vk.extensions.khr_surface,
|
||||||
|
vk.extensions.khr_swapchain,
|
||||||
|
};
|
||||||
|
|
||||||
|
const BaseDispatch = vk.BaseWrapper(apis);
|
||||||
|
const InstanceDispatch = vk.InstanceWrapper(apis);
|
||||||
|
const Instance = vk.InstanceProxy(apis);
|
||||||
|
const Device = vk.DeviceProxy(apis);
|
||||||
|
const DeviceDispatch = Device.Wrapper;
|
||||||
|
const CommandBuffer = vk.CommandBufferProxy(apis);
|
||||||
|
|
||||||
|
const device_extensions = [_][:0]const u8{
|
||||||
|
vk.extensions.khr_swapchain.name,
|
||||||
|
};
|
||||||
|
const vk_layers = [_][:0]const u8{"VK_LAYER_KHRONOS_validation"};
|
||||||
|
|
||||||
|
const MAX_FRAME_LAG = 3;
|
||||||
|
|
||||||
|
allocator: std.mem.Allocator = undefined,
|
||||||
|
window: *c.SDL_Window = undefined,
|
||||||
|
vkb: BaseDispatch = undefined,
|
||||||
|
vki: InstanceDispatch = undefined,
|
||||||
|
vkd: DeviceDispatch = undefined,
|
||||||
|
device_info: SelectedPhysicalDevice = undefined,
|
||||||
|
instance: Instance = undefined,
|
||||||
|
device: Device = undefined,
|
||||||
|
queues: DeviceQueues = undefined,
|
||||||
|
surface: vk.SurfaceKHR = .null_handle,
|
||||||
|
swapchain: vk.SwapchainKHR = .null_handle,
|
||||||
|
swapchain_extent: vk.Extent2D = .{ .width = 0, .height = 0 },
|
||||||
|
swapchain_images: []vk.Image = &.{},
|
||||||
|
|
||||||
|
// NOTE: TEST
|
||||||
|
frame: u32 = 0,
|
||||||
|
frame_syncs: [MAX_FRAME_LAG]Sync = [1]Sync{.{}} ** MAX_FRAME_LAG,
|
||||||
|
command_pool: vk.CommandPool = .null_handle,
|
||||||
|
|
||||||
|
const Sync = struct {
|
||||||
|
acquire_swapchain_image: vk.Semaphore = .null_handle,
|
||||||
|
draw_sema: vk.Semaphore = .null_handle,
|
||||||
|
draw_fence: vk.Fence = .null_handle,
|
||||||
|
|
||||||
|
pub fn waitForDrawAndReset(self: *Sync, gc: *GraphicsContext) !void {
|
||||||
|
_ = try gc.device.waitForFences(1, &.{self.draw_fence}, vk.TRUE, std.math.maxInt(u64));
|
||||||
|
try gc.device.resetFences(1, &.{self.draw_fence});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn init(self: *GraphicsContext, allocator: std.mem.Allocator, window: *c.SDL_Window) !void {
|
||||||
|
self.allocator = allocator;
|
||||||
|
self.window = window;
|
||||||
|
|
||||||
|
var scratch: [4096]u8 = undefined;
|
||||||
|
var fba = std.heap.FixedBufferAllocator.init(&scratch);
|
||||||
|
const vkGetInstanceProcAddr: vk.PfnGetInstanceProcAddr = @ptrCast(c.SDL_Vulkan_GetVkGetInstanceProcAddr());
|
||||||
|
|
||||||
|
var sdl_instance_ext_count: c_uint = 0;
|
||||||
|
if (c.SDL_Vulkan_GetInstanceExtensions(window, &sdl_instance_ext_count, null) == c.SDL_FALSE) {
|
||||||
|
std.debug.print("SDL_Vulkan_GetInstanceExtensions: get count {s}\n", .{c.SDL_GetError()});
|
||||||
|
return error.GetSDLExtensions;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sdl_instance_ext_names = try fba.allocator().alloc([*:0]const u8, sdl_instance_ext_count);
|
||||||
|
if (c.SDL_Vulkan_GetInstanceExtensions(window, &sdl_instance_ext_count, @ptrCast(sdl_instance_ext_names.ptr)) == c.SDL_FALSE) {
|
||||||
|
std.debug.print("SDL_Vulkan_GetInstanceExtensions: get names {s}\n", .{c.SDL_GetError()});
|
||||||
|
return error.GetSDLExtensions;
|
||||||
|
}
|
||||||
|
|
||||||
|
std.debug.print("SDL Extensions: {s}\n", .{sdl_instance_ext_names});
|
||||||
|
|
||||||
|
self.vkb = try BaseDispatch.load(vkGetInstanceProcAddr);
|
||||||
|
|
||||||
|
const instance_handle = try self.vkb.createInstance(&vk.InstanceCreateInfo{
|
||||||
|
.p_application_info = &vk.ApplicationInfo{
|
||||||
|
.api_version = vk.API_VERSION_1_3,
|
||||||
|
.application_version = 0,
|
||||||
|
.engine_version = 0,
|
||||||
|
},
|
||||||
|
.pp_enabled_layer_names = @ptrCast((&vk_layers).ptr),
|
||||||
|
.enabled_layer_count = @intCast(vk_layers.len),
|
||||||
|
.enabled_extension_count = @intCast(sdl_instance_ext_names.len),
|
||||||
|
.pp_enabled_extension_names = sdl_instance_ext_names.ptr,
|
||||||
|
}, null);
|
||||||
|
|
||||||
|
self.vki = try InstanceDispatch.load(instance_handle, vkGetInstanceProcAddr);
|
||||||
|
errdefer self.vki.destroyInstance(instance_handle, null);
|
||||||
|
self.instance = Instance.init(instance_handle, &self.vki);
|
||||||
|
|
||||||
|
var sdl_vksurface: c.VkSurfaceKHR = null;
|
||||||
|
if (c.SDL_Vulkan_CreateSurface(window, @as(*c.VkInstance, @ptrCast(&self.instance.handle)).*, &sdl_vksurface) == c.SDL_FALSE) {
|
||||||
|
std.debug.print("SDL_Vulkan_CreateSurface: {s}\n", .{c.SDL_GetError()});
|
||||||
|
return error.SDLVulkanCreateSurface;
|
||||||
|
}
|
||||||
|
std.debug.assert(sdl_vksurface != null);
|
||||||
|
self.surface = @as(*vk.SurfaceKHR, @ptrCast(&sdl_vksurface)).*;
|
||||||
|
|
||||||
|
const physical_devices = try self.instance.enumeratePhysicalDevicesAlloc(fba.allocator());
|
||||||
|
self.device_info = try selectPhysicalDevice(self.instance, self.surface, physical_devices);
|
||||||
|
const queue_config = try selectQueues(self.instance, self.device_info.physical_device);
|
||||||
|
|
||||||
|
const device_create_config = vk.DeviceCreateInfo{
|
||||||
|
.p_next = @ptrCast(&vk.PhysicalDeviceSynchronization2Features{ .synchronization_2 = vk.TRUE }),
|
||||||
|
.p_queue_create_infos = &queue_config.queue_create_info,
|
||||||
|
.queue_create_info_count = queue_config.queue_count,
|
||||||
|
.p_enabled_features = &self.device_info.features,
|
||||||
|
.pp_enabled_layer_names = @ptrCast((&vk_layers).ptr),
|
||||||
|
.enabled_layer_count = @intCast(vk_layers.len),
|
||||||
|
.pp_enabled_extension_names = @ptrCast((&device_extensions).ptr),
|
||||||
|
.enabled_extension_count = @intCast(device_extensions.len),
|
||||||
|
};
|
||||||
|
|
||||||
|
const device_handle = try self.instance.createDevice(self.device_info.physical_device, &device_create_config, null);
|
||||||
|
|
||||||
|
self.vkd = try DeviceDispatch.load(device_handle, self.instance.wrapper.dispatch.vkGetDeviceProcAddr);
|
||||||
|
errdefer self.vkd.destroyDevice(device_handle, null);
|
||||||
|
self.device = Device.init(device_handle, &self.vkd);
|
||||||
|
|
||||||
|
try self.maybeResizeSwapchain();
|
||||||
|
errdefer self.device.destroySwapchainKHR(self.swapchain, null);
|
||||||
|
|
||||||
|
// TODO: handle the case when different queue instance map to the same queue
|
||||||
|
const graphics_queue = QueueInstance{
|
||||||
|
.device = self.device,
|
||||||
|
.family = queue_config.graphics.family,
|
||||||
|
.handle = self.device.getDeviceQueue(queue_config.graphics.family, queue_config.graphics.index),
|
||||||
|
};
|
||||||
|
const compute_queue = QueueInstance{
|
||||||
|
.device = self.device,
|
||||||
|
.family = queue_config.compute.family,
|
||||||
|
.handle = self.device.getDeviceQueue(queue_config.graphics.family, queue_config.compute.index),
|
||||||
|
};
|
||||||
|
const host_to_device_queue = QueueInstance{
|
||||||
|
.device = self.device,
|
||||||
|
.family = queue_config.host_to_device.family,
|
||||||
|
.handle = self.device.getDeviceQueue(queue_config.graphics.family, queue_config.host_to_device.index),
|
||||||
|
};
|
||||||
|
const device_to_host_queue = QueueInstance{
|
||||||
|
.device = self.device,
|
||||||
|
.family = queue_config.device_to_host.family,
|
||||||
|
.handle = self.device.getDeviceQueue(queue_config.graphics.family, queue_config.device_to_host.index),
|
||||||
|
};
|
||||||
|
|
||||||
|
self.queues = DeviceQueues{
|
||||||
|
.graphics = graphics_queue,
|
||||||
|
.compute = compute_queue,
|
||||||
|
.host_to_device = host_to_device_queue,
|
||||||
|
.device_to_host = device_to_host_queue,
|
||||||
|
};
|
||||||
|
|
||||||
|
for (0..MAX_FRAME_LAG) |i| {
|
||||||
|
self.frame_syncs[i].acquire_swapchain_image = try self.device.createSemaphore(&.{}, null);
|
||||||
|
self.frame_syncs[i].draw_sema = try self.device.createSemaphore(&.{}, null);
|
||||||
|
self.frame_syncs[i].draw_fence = try self.device.createFence(&.{ .flags = .{ .signaled_bit = true } }, null);
|
||||||
|
}
|
||||||
|
self.command_pool = try self.queues.graphics.createCommandPool(.{});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw(self: *GraphicsContext) !void {
|
||||||
|
var cmd_bufs = [_]vk.CommandBuffer{.null_handle};
|
||||||
|
try self.device.allocateCommandBuffers(&.{
|
||||||
|
.command_pool = self.command_pool,
|
||||||
|
.level = .primary,
|
||||||
|
.command_buffer_count = cmd_bufs.len,
|
||||||
|
}, &cmd_bufs);
|
||||||
|
const test_cmd_buf = CommandBuffer.init(cmd_bufs[0], &self.vkd);
|
||||||
|
|
||||||
|
const sync = &self.frame_syncs[self.frame];
|
||||||
|
|
||||||
|
try sync.waitForDrawAndReset(self);
|
||||||
|
|
||||||
|
// Move this out into a separate func
|
||||||
|
const swapchain_image_index: u32 = blk: {
|
||||||
|
var found = false;
|
||||||
|
var swapchain_img: u32 = 0;
|
||||||
|
|
||||||
|
try self.maybeResizeSwapchain();
|
||||||
|
|
||||||
|
while (!found) {
|
||||||
|
const acquire_result = try self.device.acquireNextImageKHR(self.swapchain, std.math.maxInt(u64), sync.acquire_swapchain_image, .null_handle);
|
||||||
|
|
||||||
|
switch (acquire_result.result) {
|
||||||
|
.success, .suboptimal_khr => {
|
||||||
|
swapchain_img = acquire_result.image_index;
|
||||||
|
found = true;
|
||||||
|
},
|
||||||
|
.error_out_of_date_khr => {
|
||||||
|
// TODO: resize swapchain
|
||||||
|
std.debug.print("Out of date swapchain\n", .{});
|
||||||
|
try self.maybeResizeSwapchain();
|
||||||
|
},
|
||||||
|
.error_surface_lost_khr => {
|
||||||
|
// TODO: recreate surface
|
||||||
|
return error.SurfaceLost;
|
||||||
|
},
|
||||||
|
.not_ready => return error.SwapchainImageNotReady,
|
||||||
|
.timeout => return error.SwapchainImageTimeout,
|
||||||
|
else => {
|
||||||
|
std.debug.print("Unexpected value: {}\n", .{acquire_result.result});
|
||||||
|
@panic("Unexpected");
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break :blk swapchain_img;
|
||||||
|
};
|
||||||
|
|
||||||
|
const current_image = self.swapchain_images[swapchain_image_index];
|
||||||
|
|
||||||
|
try test_cmd_buf.beginCommandBuffer(&.{});
|
||||||
|
{
|
||||||
|
{
|
||||||
|
const img_barrier = vk.ImageMemoryBarrier2{
|
||||||
|
.image = current_image,
|
||||||
|
.old_layout = .undefined,
|
||||||
|
.new_layout = .transfer_dst_optimal,
|
||||||
|
.src_access_mask = .{},
|
||||||
|
.dst_access_mask = .{},
|
||||||
|
.src_queue_family_index = self.queues.graphics.family,
|
||||||
|
.dst_queue_family_index = self.queues.graphics.family,
|
||||||
|
.subresource_range = .{
|
||||||
|
.aspect_mask = .{ .color_bit = true },
|
||||||
|
.base_array_layer = 0,
|
||||||
|
.base_mip_level = 0,
|
||||||
|
.layer_count = 1,
|
||||||
|
.level_count = 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
test_cmd_buf.pipelineBarrier2(&.{
|
||||||
|
.p_image_memory_barriers = &.{img_barrier},
|
||||||
|
.image_memory_barrier_count = 1,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
test_cmd_buf.clearColorImage(current_image, .transfer_dst_optimal, &.{ .float_32 = .{ 0.8, 0.7, 0.6, 1.0 } }, 1, &.{.{
|
||||||
|
.aspect_mask = .{ .color_bit = true },
|
||||||
|
.base_array_layer = 0,
|
||||||
|
.base_mip_level = 0,
|
||||||
|
.layer_count = 1,
|
||||||
|
.level_count = 1,
|
||||||
|
}});
|
||||||
|
{
|
||||||
|
const img_barrier = vk.ImageMemoryBarrier2{
|
||||||
|
.image = current_image,
|
||||||
|
.old_layout = .transfer_dst_optimal,
|
||||||
|
.new_layout = .present_src_khr,
|
||||||
|
.src_access_mask = .{},
|
||||||
|
.dst_access_mask = .{},
|
||||||
|
.src_queue_family_index = self.queues.graphics.family,
|
||||||
|
.dst_queue_family_index = self.queues.graphics.family,
|
||||||
|
.subresource_range = .{
|
||||||
|
.aspect_mask = .{ .color_bit = true },
|
||||||
|
.base_array_layer = 0,
|
||||||
|
.base_mip_level = 0,
|
||||||
|
.layer_count = 1,
|
||||||
|
.level_count = 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
test_cmd_buf.pipelineBarrier2(&.{
|
||||||
|
.p_image_memory_barriers = &.{img_barrier},
|
||||||
|
.image_memory_barrier_count = 1,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try test_cmd_buf.endCommandBuffer();
|
||||||
|
|
||||||
|
try self.queues.graphics.submit(
|
||||||
|
&SubmitInfo{
|
||||||
|
.wait_semaphores = &.{sync.acquire_swapchain_image},
|
||||||
|
.wait_dst_stage_mask = &.{.{ .transfer_bit = true }},
|
||||||
|
.command_buffers = &.{test_cmd_buf.handle},
|
||||||
|
.signal_semaphores = &.{sync.draw_sema},
|
||||||
|
},
|
||||||
|
sync.draw_fence,
|
||||||
|
);
|
||||||
|
|
||||||
|
_ = try self.device.queuePresentKHR(self.queues.graphics.handle, &.{
|
||||||
|
.swapchain_count = 1,
|
||||||
|
.wait_semaphore_count = 1,
|
||||||
|
.p_wait_semaphores = &.{sync.draw_sema},
|
||||||
|
.p_swapchains = &.{self.swapchain},
|
||||||
|
.p_image_indices = &.{swapchain_image_index},
|
||||||
|
});
|
||||||
|
|
||||||
|
self.frame = (self.frame + 1) % MAX_FRAME_LAG;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn maybeResizeSwapchain(self: *GraphicsContext) !void {
|
||||||
|
var width: c_int = 0;
|
||||||
|
var height: c_int = 0;
|
||||||
|
c.SDL_Vulkan_GetDrawableSize(self.window, &width, &height);
|
||||||
|
const new_extent = vk.Extent2D{ .width = @intCast(width), .height = @intCast(height) };
|
||||||
|
|
||||||
|
if (self.swapchain_extent.width == new_extent.width and self.swapchain_extent.height == new_extent.height) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.swapchain_images.len > 0) {
|
||||||
|
self.allocator.free(self.swapchain_images);
|
||||||
|
self.swapchain_images = &.{};
|
||||||
|
}
|
||||||
|
self.swapchain_extent = new_extent;
|
||||||
|
const surface_caps = self.device_info.surface_capabilities;
|
||||||
|
self.swapchain = try self.device.createSwapchainKHR(&.{
|
||||||
|
.surface = self.surface,
|
||||||
|
.min_image_count = std.math.clamp(3, surface_caps.min_image_count, if (surface_caps.max_image_count == 0) std.math.maxInt(u32) else surface_caps.max_image_count),
|
||||||
|
.image_format = .r8g8b8a8_unorm, // tonemapping handles srgb
|
||||||
|
.image_color_space = .srgb_nonlinear_khr,
|
||||||
|
.image_extent = self.swapchain_extent,
|
||||||
|
.image_array_layers = 1,
|
||||||
|
.image_usage = .{
|
||||||
|
.color_attachment_bit = true,
|
||||||
|
.transfer_dst_bit = true,
|
||||||
|
},
|
||||||
|
.image_sharing_mode = .exclusive,
|
||||||
|
.present_mode = .fifo_khr, // required to be supported
|
||||||
|
.pre_transform = surface_caps.current_transform,
|
||||||
|
.composite_alpha = .{ .opaque_bit_khr = true },
|
||||||
|
.clipped = vk.TRUE,
|
||||||
|
.old_swapchain = self.swapchain,
|
||||||
|
}, null);
|
||||||
|
self.swapchain_images = try self.device.getSwapchainImagesAllocKHR(self.swapchain, self.allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const DeviceQueues = struct {
|
||||||
|
graphics: QueueInstance,
|
||||||
|
compute: QueueInstance,
|
||||||
|
host_to_device: QueueInstance,
|
||||||
|
device_to_host: QueueInstance,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const SubmitInfo = struct {
|
||||||
|
wait_semaphores: []const vk.Semaphore = &.{},
|
||||||
|
wait_dst_stage_mask: []const vk.PipelineStageFlags = &.{},
|
||||||
|
command_buffers: []const vk.CommandBuffer = &.{},
|
||||||
|
signal_semaphores: []const vk.Semaphore = &.{},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const QueueInstance = struct {
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
mu: std.Thread.Mutex = .{},
|
||||||
|
device: Device,
|
||||||
|
handle: vk.Queue,
|
||||||
|
family: u32,
|
||||||
|
|
||||||
|
pub fn createCommandPool(self: *Self, flags: vk.CommandPoolCreateFlags) !vk.CommandPool {
|
||||||
|
return self.device.createCommandPool(&.{
|
||||||
|
.flags = flags,
|
||||||
|
.queue_family_index = self.family,
|
||||||
|
}, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn submit(self: *Self, info: *const SubmitInfo, fence: vk.Fence) Device.QueueSubmitError!void {
|
||||||
|
std.debug.assert(info.wait_semaphores.len == info.wait_dst_stage_mask.len);
|
||||||
|
|
||||||
|
var vk_submit_info = vk.SubmitInfo{};
|
||||||
|
|
||||||
|
if (info.wait_semaphores.len > 0) {
|
||||||
|
vk_submit_info.p_wait_semaphores = info.wait_semaphores.ptr;
|
||||||
|
vk_submit_info.p_wait_dst_stage_mask = info.wait_dst_stage_mask.ptr;
|
||||||
|
vk_submit_info.wait_semaphore_count = @intCast(info.wait_semaphores.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.command_buffers.len > 0) {
|
||||||
|
vk_submit_info.p_command_buffers = info.command_buffers.ptr;
|
||||||
|
vk_submit_info.command_buffer_count = @intCast(info.command_buffers.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.signal_semaphores.len > 0) {
|
||||||
|
vk_submit_info.p_signal_semaphores = info.signal_semaphores.ptr;
|
||||||
|
vk_submit_info.signal_semaphore_count = @intCast(info.signal_semaphores.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
try self.submitVK(&.{vk_submit_info}, fence);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn submitVK(self: *Self, infos: []const vk.SubmitInfo, fence: vk.Fence) Device.QueueSubmitError!void {
|
||||||
|
self.mu.lock();
|
||||||
|
defer self.mu.unlock();
|
||||||
|
|
||||||
|
try self.device.queueSubmit(self.handle, @intCast(infos.len), infos.ptr, fence);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const SelectedPhysicalDevice = struct {
|
||||||
|
physical_device: vk.PhysicalDevice,
|
||||||
|
properties: vk.PhysicalDeviceProperties,
|
||||||
|
features: vk.PhysicalDeviceFeatures,
|
||||||
|
surface_capabilities: vk.SurfaceCapabilitiesKHR,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn selectPhysicalDevice(vki: Instance, surface: vk.SurfaceKHR, devices: []vk.PhysicalDevice) !SelectedPhysicalDevice {
|
||||||
|
// TODO: select suitable physical device, allow overriding using some user config
|
||||||
|
for (devices) |device| {
|
||||||
|
const props = vki.getPhysicalDeviceProperties(device);
|
||||||
|
const features = vki.getPhysicalDeviceFeatures(device);
|
||||||
|
const surface_caps = try vki.getPhysicalDeviceSurfaceCapabilitiesKHR(device, surface);
|
||||||
|
return SelectedPhysicalDevice{
|
||||||
|
.physical_device = device,
|
||||||
|
.properties = props,
|
||||||
|
.features = features,
|
||||||
|
.surface_capabilities = surface_caps,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return error.NoDeviceFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DeviceQueueConfig = struct {
|
||||||
|
const Config = struct {
|
||||||
|
family: u32,
|
||||||
|
index: u32,
|
||||||
|
};
|
||||||
|
queue_create_info: [4]vk.DeviceQueueCreateInfo = undefined,
|
||||||
|
queue_count: u32 = 0,
|
||||||
|
graphics: Config,
|
||||||
|
compute: Config,
|
||||||
|
host_to_device: Config,
|
||||||
|
device_to_host: Config,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Hardcode queue priorities, no idea why I would need to use them
|
||||||
|
const queue_priorities = [_]f32{ 1.0, 1.0, 1.0, 1.0, 1.0 };
|
||||||
|
|
||||||
|
fn selectQueues(instance: Instance, device: vk.PhysicalDevice) !DeviceQueueConfig {
|
||||||
|
var scratch: [1024]u8 = undefined;
|
||||||
|
var fba = std.heap.FixedBufferAllocator.init(&scratch);
|
||||||
|
const queue_family_props = try instance.getPhysicalDeviceQueueFamilyPropertiesAlloc(device, fba.allocator());
|
||||||
|
|
||||||
|
if (queue_family_props.len == 0) {
|
||||||
|
return error.NoQueues;
|
||||||
|
}
|
||||||
|
|
||||||
|
var queue_create_info: [4]vk.DeviceQueueCreateInfo = undefined;
|
||||||
|
var queue_count: u32 = 0;
|
||||||
|
var graphics: ?DeviceQueueConfig.Config = null;
|
||||||
|
var compute: ?DeviceQueueConfig.Config = null;
|
||||||
|
var host_to_device: ?DeviceQueueConfig.Config = null;
|
||||||
|
var device_to_host: ?DeviceQueueConfig.Config = null;
|
||||||
|
|
||||||
|
// We're on Intel most likely, just a single queue for everything :(
|
||||||
|
if (queue_family_props.len == 1) {
|
||||||
|
if (!queue_family_props[0].queue_flags.contains(.{ .graphics_bit = true, .compute_bit = true, .transfer_bit = true })) {
|
||||||
|
return error.InvalidQueue;
|
||||||
|
}
|
||||||
|
graphics = .{ .family = 0, .index = 0 };
|
||||||
|
compute = graphics;
|
||||||
|
device_to_host = graphics;
|
||||||
|
host_to_device = graphics;
|
||||||
|
queue_create_info[0] = .{
|
||||||
|
.queue_family_index = 0,
|
||||||
|
.queue_count = 1,
|
||||||
|
.p_queue_priorities = &queue_priorities,
|
||||||
|
};
|
||||||
|
queue_count = 1;
|
||||||
|
} else {
|
||||||
|
for (queue_family_props, 0..) |props, family_idx| {
|
||||||
|
// Jackpot, generous Jensen provided us with an all powerfull queue family, use it for everything
|
||||||
|
if (props.queue_flags.contains(.{ .graphics_bit = true, .compute_bit = true, .transfer_bit = true }) and props.queue_count >= 4) {
|
||||||
|
graphics = .{
|
||||||
|
.family = @intCast(family_idx),
|
||||||
|
.index = 0,
|
||||||
|
};
|
||||||
|
compute = .{
|
||||||
|
.family = @intCast(family_idx),
|
||||||
|
.index = 1,
|
||||||
|
};
|
||||||
|
host_to_device = .{
|
||||||
|
.family = @intCast(family_idx),
|
||||||
|
.index = 2,
|
||||||
|
};
|
||||||
|
device_to_host = .{
|
||||||
|
.family = @intCast(family_idx),
|
||||||
|
.index = 3,
|
||||||
|
};
|
||||||
|
queue_create_info[0] = .{
|
||||||
|
.queue_family_index = 0,
|
||||||
|
.queue_count = 4,
|
||||||
|
.p_queue_priorities = &queue_priorities,
|
||||||
|
};
|
||||||
|
queue_count = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: make queue create info for AMD
|
||||||
|
// Probably AMD, one graphics+compute queue, 2 separate compute queues, one pure transfer queue
|
||||||
|
if (props.queue_flags.graphics_bit) {
|
||||||
|
graphics = .{
|
||||||
|
.family = @intCast(family_idx),
|
||||||
|
.index = 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (props.queue_flags.compute_bit and (compute == null or !props.queue_flags.graphics_bit)) {
|
||||||
|
compute = .{
|
||||||
|
.family = @intCast(family_idx),
|
||||||
|
.index = 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (props.queue_flags.transfer_bit and (host_to_device == null or !props.queue_flags.graphics_bit or !props.queue_flags.compute_bit)) {
|
||||||
|
device_to_host = .{
|
||||||
|
.family = @intCast(family_idx),
|
||||||
|
.index = 0,
|
||||||
|
};
|
||||||
|
host_to_device = .{
|
||||||
|
.family = @intCast(family_idx),
|
||||||
|
.index = 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (graphics == null or compute == null or device_to_host == null or host_to_device == null) {
|
||||||
|
return error.MissingQueueFeatures;
|
||||||
|
}
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.queue_create_info = queue_create_info,
|
||||||
|
.queue_count = queue_count,
|
||||||
|
.graphics = graphics.?,
|
||||||
|
.compute = compute.?,
|
||||||
|
.host_to_device = host_to_device.?,
|
||||||
|
.device_to_host = device_to_host.?,
|
||||||
|
};
|
||||||
|
}
|
@ -9,6 +9,9 @@ const math = @import("math.zig");
|
|||||||
const formats = @import("formats.zig");
|
const formats = @import("formats.zig");
|
||||||
const AABB = AssetManager.AABB; // TODO: move AABB out of formats pls
|
const AABB = AssetManager.AABB; // TODO: move AABB out of formats pls
|
||||||
const tracy = @import("tracy");
|
const tracy = @import("tracy");
|
||||||
|
const GraphicsContext = @import("GraphicsContext.zig");
|
||||||
|
|
||||||
|
const gc = GraphicsContext.init();
|
||||||
|
|
||||||
const za = @import("zalgebra");
|
const za = @import("zalgebra");
|
||||||
const Vec2 = za.Vec2;
|
const Vec2 = za.Vec2;
|
||||||
@ -294,15 +297,16 @@ pub fn init(allocator: std.mem.Allocator, frame_arena: std.mem.Allocator, assetm
|
|||||||
gl.createFramebuffers(1, &render.shadow_framebuffer);
|
gl.createFramebuffers(1, &render.shadow_framebuffer);
|
||||||
checkGLError();
|
checkGLError();
|
||||||
std.debug.assert(render.shadow_framebuffer != 0);
|
std.debug.assert(render.shadow_framebuffer != 0);
|
||||||
gl.namedFramebufferDrawBuffer(render.shadow_framebuffer, gl.FRONT_LEFT);
|
|
||||||
gl.namedFramebufferReadBuffer(render.shadow_framebuffer, gl.NONE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify directional shadow framebuffer setup
|
// Verify directional shadow framebuffer setup
|
||||||
{
|
{
|
||||||
gl.namedFramebufferTextureLayer(render.shadow_framebuffer, gl.COLOR_ATTACHMENT0, render.shadow_texture_array, 0, 0);
|
gl.namedFramebufferTextureLayer(render.shadow_framebuffer, gl.COLOR_ATTACHMENT0, render.shadow_texture_array, 0, 0);
|
||||||
|
checkGLError();
|
||||||
gl.namedFramebufferTexture(render.shadow_framebuffer, gl.DEPTH_ATTACHMENT, render.direct_shadow_depth_buffer_texture, 0);
|
gl.namedFramebufferTexture(render.shadow_framebuffer, gl.DEPTH_ATTACHMENT, render.direct_shadow_depth_buffer_texture, 0);
|
||||||
|
checkGLError();
|
||||||
const check_fbo_status = gl.checkNamedFramebufferStatus(render.shadow_framebuffer, gl.DRAW_FRAMEBUFFER);
|
const check_fbo_status = gl.checkNamedFramebufferStatus(render.shadow_framebuffer, gl.DRAW_FRAMEBUFFER);
|
||||||
|
checkGLError();
|
||||||
if (check_fbo_status != gl.FRAMEBUFFER_COMPLETE) {
|
if (check_fbo_status != gl.FRAMEBUFFER_COMPLETE) {
|
||||||
std.log.debug("Shadow Framebuffer Incomplete: {}\n", .{check_fbo_status});
|
std.log.debug("Shadow Framebuffer Incomplete: {}\n", .{check_fbo_status});
|
||||||
}
|
}
|
||||||
@ -311,14 +315,18 @@ pub fn init(allocator: std.mem.Allocator, frame_arena: std.mem.Allocator, assetm
|
|||||||
// Verify cube shadow framebuffer setup
|
// Verify cube shadow framebuffer setup
|
||||||
{
|
{
|
||||||
gl.namedFramebufferTextureLayer(render.shadow_framebuffer, gl.COLOR_ATTACHMENT0, render.cube_shadow_texture_array, 0, 0);
|
gl.namedFramebufferTextureLayer(render.shadow_framebuffer, gl.COLOR_ATTACHMENT0, render.cube_shadow_texture_array, 0, 0);
|
||||||
|
checkGLError();
|
||||||
gl.namedFramebufferTexture(render.shadow_framebuffer, gl.DEPTH_ATTACHMENT, render.direct_shadow_depth_buffer_texture, 0);
|
gl.namedFramebufferTexture(render.shadow_framebuffer, gl.DEPTH_ATTACHMENT, render.direct_shadow_depth_buffer_texture, 0);
|
||||||
|
checkGLError();
|
||||||
const check_fbo_status = gl.checkNamedFramebufferStatus(render.shadow_framebuffer, gl.DRAW_FRAMEBUFFER);
|
const check_fbo_status = gl.checkNamedFramebufferStatus(render.shadow_framebuffer, gl.DRAW_FRAMEBUFFER);
|
||||||
|
checkGLError();
|
||||||
if (check_fbo_status != gl.FRAMEBUFFER_COMPLETE) {
|
if (check_fbo_status != gl.FRAMEBUFFER_COMPLETE) {
|
||||||
std.log.debug("Shadow Framebuffer Incomplete: {}\n", .{check_fbo_status});
|
std.log.debug("Shadow Framebuffer Incomplete: {}\n", .{check_fbo_status});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gl.createBuffers(1, &render.shadow_matrices_buffer);
|
gl.createBuffers(1, &render.shadow_matrices_buffer);
|
||||||
|
checkGLError();
|
||||||
|
|
||||||
gl.namedBufferStorage(
|
gl.namedBufferStorage(
|
||||||
render.shadow_matrices_buffer,
|
render.shadow_matrices_buffer,
|
||||||
@ -326,6 +334,7 @@ pub fn init(allocator: std.mem.Allocator, frame_arena: std.mem.Allocator, assetm
|
|||||||
null,
|
null,
|
||||||
gl.DYNAMIC_STORAGE_BIT,
|
gl.DYNAMIC_STORAGE_BIT,
|
||||||
);
|
);
|
||||||
|
checkGLError();
|
||||||
|
|
||||||
// SHADOW VAO
|
// SHADOW VAO
|
||||||
var vao: gl.GLuint = 0;
|
var vao: gl.GLuint = 0;
|
||||||
@ -338,35 +347,19 @@ pub fn init(allocator: std.mem.Allocator, frame_arena: std.mem.Allocator, assetm
|
|||||||
gl.enableVertexArrayAttrib(vao, Attrib.Position.value());
|
gl.enableVertexArrayAttrib(vao, Attrib.Position.value());
|
||||||
gl.vertexArrayAttribBinding(vao, Attrib.Position.value(), 0);
|
gl.vertexArrayAttribBinding(vao, Attrib.Position.value(), 0);
|
||||||
gl.vertexArrayAttribFormat(vao, Attrib.Position.value(), 3, gl.FLOAT, gl.FALSE, 0);
|
gl.vertexArrayAttribFormat(vao, Attrib.Position.value(), 3, gl.FLOAT, gl.FALSE, 0);
|
||||||
|
checkGLError();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Screen HDR FBO
|
// Screen HDR FBO
|
||||||
{
|
{
|
||||||
gl.createFramebuffers(1, &render.screen_fbo);
|
gl.createFramebuffers(1, &render.screen_fbo);
|
||||||
|
checkGLError();
|
||||||
std.debug.assert(render.screen_fbo != 0);
|
std.debug.assert(render.screen_fbo != 0);
|
||||||
|
|
||||||
var width: c_int = 0;
|
var width: c_int = 0;
|
||||||
var height: c_int = 0;
|
var height: c_int = 0;
|
||||||
c.SDL_GL_GetDrawableSize(globals.g_init.window, &width, &height);
|
c.SDL_GL_GetDrawableSize(globals.g_init.window, &width, &height);
|
||||||
|
|
||||||
var textures = [2]gl.GLuint{ 0, 0 };
|
|
||||||
gl.createTextures(gl.TEXTURE_2D, textures.len, &textures);
|
|
||||||
render.screen_color_texture = textures[0];
|
|
||||||
render.screen_depth_texture = textures[1];
|
|
||||||
|
|
||||||
std.debug.assert(render.screen_color_texture != 0);
|
|
||||||
std.debug.assert(render.screen_depth_texture != 0);
|
|
||||||
|
|
||||||
gl.textureParameteri(render.screen_color_texture, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
||||||
gl.textureParameteri(render.screen_color_texture, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
||||||
gl.textureParameteri(render.screen_color_texture, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
|
||||||
gl.textureParameteri(render.screen_color_texture, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
||||||
|
|
||||||
gl.textureParameteri(render.screen_depth_texture, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
||||||
gl.textureParameteri(render.screen_depth_texture, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
||||||
gl.textureParameteri(render.screen_depth_texture, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
|
||||||
gl.textureParameteri(render.screen_depth_texture, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
||||||
|
|
||||||
render.updateScreenBufferSize(width, height);
|
render.updateScreenBufferSize(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -425,21 +418,44 @@ fn calculateMipCount(width: c_int, height: c_int) usize {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn updateScreenBufferSize(self: *Render, width: c_int, height: c_int) void {
|
fn updateScreenBufferSize(self: *Render, width: c_int, height: c_int) void {
|
||||||
const mip_count = calculateMipCount(width, height);
|
if (self.screen_tex_size.eql(Vec2_i32.new(width, height)) and self.screen_color_texture != 0) {
|
||||||
|
return;
|
||||||
gl.bindTexture(gl.TEXTURE_2D, self.screen_color_texture);
|
|
||||||
for (0..mip_count) |mip_level| {
|
|
||||||
const size = getMipSize(width, height, mip_level);
|
|
||||||
std.log.debug("screen_color mip {} size {}x{}\n", .{ mip_level, size.x(), size.y() });
|
|
||||||
|
|
||||||
gl.texImage2D(gl.TEXTURE_2D, @intCast(mip_level), gl.RGB16F, size.x(), size.y(), 0, gl.RGB, gl.HALF_FLOAT, null);
|
|
||||||
checkGLError();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Depth doesn't need any mips cause it's not filterable anyway
|
if (self.screen_color_texture != 0) {
|
||||||
gl.bindTexture(gl.TEXTURE_2D, self.screen_depth_texture);
|
const old_textures = [_]gl.GLuint{ self.screen_color_texture, self.screen_depth_texture };
|
||||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT32F, width, height, 0, gl.DEPTH_COMPONENT, gl.FLOAT, null);
|
gl.deleteTextures(old_textures.len, &old_textures);
|
||||||
|
checkGLError();
|
||||||
|
self.screen_color_texture = 0;
|
||||||
|
self.screen_depth_texture = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
var textures = [2]gl.GLuint{ 0, 0 };
|
||||||
|
gl.createTextures(gl.TEXTURE_2D, textures.len, &textures);
|
||||||
checkGLError();
|
checkGLError();
|
||||||
|
self.screen_color_texture = textures[0];
|
||||||
|
self.screen_depth_texture = textures[1];
|
||||||
|
|
||||||
|
std.debug.assert(self.screen_color_texture != 0);
|
||||||
|
std.debug.assert(self.screen_depth_texture != 0);
|
||||||
|
|
||||||
|
const mip_count = calculateMipCount(width, height);
|
||||||
|
|
||||||
|
std.debug.print("screen_color_tex {}, depth {}, screen size {}x{}, mip count: {}\n", .{ self.screen_color_texture, self.screen_depth_texture, width, height, mip_count });
|
||||||
|
gl.textureStorage2D(self.screen_color_texture, @intCast(mip_count), gl.RGBA16F, width, height);
|
||||||
|
checkGLError();
|
||||||
|
gl.textureStorage2D(self.screen_depth_texture, 1, gl.DEPTH_COMPONENT24, width, height);
|
||||||
|
checkGLError();
|
||||||
|
|
||||||
|
gl.textureParameteri(self.screen_color_texture, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
||||||
|
gl.textureParameteri(self.screen_color_texture, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
||||||
|
gl.textureParameteri(self.screen_color_texture, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
||||||
|
gl.textureParameteri(self.screen_color_texture, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
||||||
|
|
||||||
|
gl.textureParameteri(self.screen_depth_texture, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
||||||
|
gl.textureParameteri(self.screen_depth_texture, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
||||||
|
gl.textureParameteri(self.screen_depth_texture, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
||||||
|
gl.textureParameteri(self.screen_depth_texture, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
||||||
|
|
||||||
self.screen_tex_size = Vec2_i32.new(width, height);
|
self.screen_tex_size = Vec2_i32.new(width, height);
|
||||||
self.screen_mip_count = mip_count;
|
self.screen_mip_count = mip_count;
|
||||||
@ -1489,6 +1505,7 @@ pub fn checkGLError() void {
|
|||||||
|
|
||||||
std.log.scoped(.OpenGL).err("OpenGL Failure: {s}\n", .{name});
|
std.log.scoped(.OpenGL).err("OpenGL Failure: {s}\n", .{name});
|
||||||
}
|
}
|
||||||
|
@panic("GL Error");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const DrawCommand = struct {
|
pub const DrawCommand = struct {
|
||||||
|
@ -124,7 +124,8 @@ pub const ShaderProgram = extern struct {
|
|||||||
pub const Flags = packed struct {
|
pub const Flags = packed struct {
|
||||||
vertex: bool,
|
vertex: bool,
|
||||||
fragment: bool,
|
fragment: bool,
|
||||||
_pad: u6 = 0,
|
compute: bool,
|
||||||
|
_pad: u5 = 0,
|
||||||
};
|
};
|
||||||
comptime {
|
comptime {
|
||||||
if (@bitSizeOf(Flags) != 8) {
|
if (@bitSizeOf(Flags) != 8) {
|
||||||
@ -142,24 +143,24 @@ pub const ShaderProgram = extern struct {
|
|||||||
|
|
||||||
test "ShaderProgram serialization" {
|
test "ShaderProgram serialization" {
|
||||||
const source = ShaderProgram{
|
const source = ShaderProgram{
|
||||||
.flags = .{ .vertex = true, .fragment = true },
|
.flags = .{ .vertex = true, .fragment = true, .compute = true },
|
||||||
.shader = .{ .id = 123 },
|
.shader = .{ .id = 123 },
|
||||||
};
|
};
|
||||||
|
|
||||||
var buf: [@sizeOf(ShaderProgram)]u8 = undefined;
|
var buf: [@sizeOf(ShaderProgram)]u8 = undefined;
|
||||||
var stream = std.io.fixedBufferStream(&buf);
|
var stream = std.io.fixedBufferStream(&buf);
|
||||||
try writeShaderProgram(stream.writer(), source.shader.id, source.flags.vertex, source.flags.fragment, native_endian);
|
try writeShaderProgram(stream.writer(), source.shader.id, source.flags.vertex, source.flags.fragment, source.flags.compute, native_endian);
|
||||||
|
|
||||||
const result: *align(1) ShaderProgram = @ptrCast(&buf);
|
const result: *align(1) ShaderProgram = @ptrCast(&buf);
|
||||||
|
|
||||||
try std.testing.expectEqual(source, result.*);
|
try std.testing.expectEqual(source, result.*);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn writeShaderProgram(writer: anytype, shader: u64, vertex: bool, fragment: bool, endian: std.builtin.Endian) !void {
|
pub fn writeShaderProgram(writer: anytype, shader: u64, vertex: bool, fragment: bool, compute: bool, endian: std.builtin.Endian) !void {
|
||||||
try writer.writeInt(u64, shader, endian);
|
try writer.writeInt(u64, shader, endian);
|
||||||
try writer.writeInt(
|
try writer.writeInt(
|
||||||
u8,
|
u8,
|
||||||
@bitCast(ShaderProgram.Flags{ .vertex = vertex, .fragment = fragment }),
|
@bitCast(ShaderProgram.Flags{ .vertex = vertex, .fragment = fragment, .compute = compute }),
|
||||||
endian,
|
endian,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
181
src/game.zig
181
src/game.zig
@ -3,7 +3,7 @@ const globals = @import("globals.zig");
|
|||||||
const InitMemory = globals.InitMemory;
|
const InitMemory = globals.InitMemory;
|
||||||
const GameMemory = globals.GameMemory;
|
const GameMemory = globals.GameMemory;
|
||||||
const c = @import("sdl.zig");
|
const c = @import("sdl.zig");
|
||||||
const gl = @import("gl.zig");
|
// const gl = @import("gl.zig");
|
||||||
const AssetManager = @import("AssetManager.zig");
|
const AssetManager = @import("AssetManager.zig");
|
||||||
const Render = @import("Render.zig");
|
const Render = @import("Render.zig");
|
||||||
const formats = @import("formats.zig");
|
const formats = @import("formats.zig");
|
||||||
@ -16,6 +16,7 @@ const Quat = za.Quat;
|
|||||||
const a = @import("asset_manifest");
|
const a = @import("asset_manifest");
|
||||||
const windows = std.os.windows;
|
const windows = std.os.windows;
|
||||||
const tracy = @import("tracy");
|
const tracy = @import("tracy");
|
||||||
|
const GraphicsContext = @import("GraphicsContext.zig");
|
||||||
|
|
||||||
pub extern "dwmapi" fn DwmEnableMMCSS(fEnableMMCSS: windows.BOOL) callconv(windows.WINAPI) windows.HRESULT;
|
pub extern "dwmapi" fn DwmEnableMMCSS(fEnableMMCSS: windows.BOOL) callconv(windows.WINAPI) windows.HRESULT;
|
||||||
pub extern "dwmapi" fn DwmFlush() callconv(windows.WINAPI) void;
|
pub extern "dwmapi" fn DwmFlush() callconv(windows.WINAPI) void;
|
||||||
@ -42,19 +43,19 @@ fn game_init_window_err(global_allocator: std.mem.Allocator) !void {
|
|||||||
// _ = DwmEnableMMCSS(1);
|
// _ = DwmEnableMMCSS(1);
|
||||||
try sdl_try(c.SDL_Init(c.SDL_INIT_EVERYTHING));
|
try sdl_try(c.SDL_Init(c.SDL_INIT_EVERYTHING));
|
||||||
|
|
||||||
try sdl_try(c.SDL_GL_SetAttribute(c.SDL_GL_DOUBLEBUFFER, 1));
|
// try sdl_try(c.SDL_GL_SetAttribute(c.SDL_GL_DOUBLEBUFFER, 1));
|
||||||
try sdl_try(c.SDL_GL_SetAttribute(c.SDL_GL_CONTEXT_MAJOR_VERSION, 4));
|
// try sdl_try(c.SDL_GL_SetAttribute(c.SDL_GL_CONTEXT_MAJOR_VERSION, 4));
|
||||||
try sdl_try(c.SDL_GL_SetAttribute(c.SDL_GL_CONTEXT_MINOR_VERSION, 5));
|
// try sdl_try(c.SDL_GL_SetAttribute(c.SDL_GL_CONTEXT_MINOR_VERSION, 5));
|
||||||
try sdl_try(c.SDL_GL_SetAttribute(c.SDL_GL_CONTEXT_PROFILE_MASK, c.SDL_GL_CONTEXT_PROFILE_CORE));
|
// try sdl_try(c.SDL_GL_SetAttribute(c.SDL_GL_CONTEXT_PROFILE_MASK, c.SDL_GL_CONTEXT_PROFILE_CORE));
|
||||||
try sdl_try(c.SDL_GL_SetAttribute(c.SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, 0));
|
// try sdl_try(c.SDL_GL_SetAttribute(c.SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, 0));
|
||||||
|
|
||||||
const maybe_window = c.SDL_CreateWindow(
|
const maybe_window = c.SDL_CreateWindow(
|
||||||
"Learn OpenGL with Zig!",
|
"Vulkan Engine",
|
||||||
c.SDL_WINDOWPOS_UNDEFINED,
|
c.SDL_WINDOWPOS_UNDEFINED,
|
||||||
c.SDL_WINDOWPOS_UNDEFINED,
|
c.SDL_WINDOWPOS_UNDEFINED,
|
||||||
globals.DEFAULT_WIDTH,
|
globals.DEFAULT_WIDTH,
|
||||||
globals.DEFAULT_HEIGHT,
|
globals.DEFAULT_HEIGHT,
|
||||||
c.SDL_WINDOW_SHOWN | c.SDL_WINDOW_OPENGL | c.SDL_WINDOW_ALLOW_HIGHDPI | c.SDL_WINDOW_RESIZABLE,
|
c.SDL_WINDOW_SHOWN | c.SDL_WINDOW_ALLOW_HIGHDPI | c.SDL_WINDOW_RESIZABLE | c.SDL_WINDOW_VULKAN,
|
||||||
);
|
);
|
||||||
if (maybe_window == null) {
|
if (maybe_window == null) {
|
||||||
std.log.err("SDL Error: {s}", .{c.SDL_GetError()});
|
std.log.err("SDL Error: {s}", .{c.SDL_GetError()});
|
||||||
@ -62,26 +63,28 @@ fn game_init_window_err(global_allocator: std.mem.Allocator) !void {
|
|||||||
}
|
}
|
||||||
const window = maybe_window.?;
|
const window = maybe_window.?;
|
||||||
|
|
||||||
const context = c.SDL_GL_CreateContext(window);
|
// const context = c.SDL_GL_CreateContext(window);
|
||||||
|
|
||||||
try sdl_try(c.SDL_GL_SetSwapInterval(0));
|
// try sdl_try(c.SDL_GL_SetSwapInterval(0));
|
||||||
|
|
||||||
globals.g_init = try global_allocator.create(InitMemory);
|
globals.g_init = try global_allocator.create(InitMemory);
|
||||||
globals.g_init_exists = true;
|
globals.g_init_exists = true;
|
||||||
globals.g_init.* = .{
|
globals.g_init.* = .{
|
||||||
.global_allocator = global_allocator,
|
.global_allocator = global_allocator,
|
||||||
.window = window,
|
.window = window,
|
||||||
.context = context,
|
.context = null,
|
||||||
.width = globals.DEFAULT_WIDTH,
|
.width = globals.DEFAULT_WIDTH,
|
||||||
.height = globals.DEFAULT_HEIGHT,
|
.height = globals.DEFAULT_HEIGHT,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
try globals.g_init.gc.init(global_allocator, window);
|
||||||
|
|
||||||
const version = &globals.g_init.syswm_info.version;
|
const version = &globals.g_init.syswm_info.version;
|
||||||
version.major = c.SDL_MAJOR_VERSION;
|
version.major = c.SDL_MAJOR_VERSION;
|
||||||
version.minor = c.SDL_MINOR_VERSION;
|
version.minor = c.SDL_MINOR_VERSION;
|
||||||
version.patch = c.SDL_PATCHLEVEL;
|
version.patch = c.SDL_PATCHLEVEL;
|
||||||
|
|
||||||
c.SDL_GL_GetDrawableSize(window, &globals.g_init.width, &globals.g_init.height);
|
// c.SDL_GL_GetDrawableSize(window, &globals.g_init.width, &globals.g_init.height);
|
||||||
|
|
||||||
if (c.SDL_GetWindowWMInfo(window, &globals.g_init.syswm_info) == 0) {
|
if (c.SDL_GetWindowWMInfo(window, &globals.g_init.syswm_info) == 0) {
|
||||||
const err = c.SDL_GetError();
|
const err = c.SDL_GetError();
|
||||||
@ -98,70 +101,70 @@ export fn game_init_window(global_allocator: *std.mem.Allocator) void {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn loadGL() void {
|
// fn loadGL() void {
|
||||||
const getProcAddress = struct {
|
// const getProcAddress = struct {
|
||||||
fn getProcAddress(ctx: @TypeOf(null), proc: [:0]const u8) ?gl.FunctionPointer {
|
// fn getProcAddress(ctx: @TypeOf(null), proc: [:0]const u8) ?gl.FunctionPointer {
|
||||||
_ = ctx;
|
// _ = ctx;
|
||||||
return @ptrCast(c.SDL_GL_GetProcAddress(proc));
|
// return @ptrCast(c.SDL_GL_GetProcAddress(proc));
|
||||||
}
|
// }
|
||||||
}.getProcAddress;
|
// }.getProcAddress;
|
||||||
gl.load(null, getProcAddress) catch |err| {
|
// gl.load(null, getProcAddress) catch |err| {
|
||||||
std.log.debug("Failed to load gl funcs {}\n", .{err});
|
// std.log.debug("Failed to load gl funcs {}\n", .{err});
|
||||||
@panic("gl.load");
|
// @panic("gl.load");
|
||||||
};
|
// };
|
||||||
gl.GL_ARB_bindless_texture.load(null, getProcAddress) catch |err| {
|
// gl.GL_ARB_bindless_texture.load(null, getProcAddress) catch |err| {
|
||||||
std.log.debug("Failed to load gl funcs GL_ARB_bindless_texture {}\n", .{err});
|
// std.log.debug("Failed to load gl funcs GL_ARB_bindless_texture {}\n", .{err});
|
||||||
@panic("gl.load");
|
// @panic("gl.load");
|
||||||
};
|
// };
|
||||||
gl.debugMessageCallback(glDebugCallback, null);
|
// gl.debugMessageCallback(glDebugCallback, null);
|
||||||
// gl.enable(gl.DEBUG_OUTPUT);
|
// // gl.enable(gl.DEBUG_OUTPUT);
|
||||||
// gl.enable(gl.DEBUG_OUTPUT_SYNCHRONOUS);
|
// // gl.enable(gl.DEBUG_OUTPUT_SYNCHRONOUS);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
fn glDebugCallback(source: gl.GLenum, _type: gl.GLenum, id: gl.GLuint, severity: gl.GLenum, length: gl.GLsizei, message: [*:0]const u8, userParam: ?*anyopaque) callconv(.C) void {
|
// fn glDebugCallback(source: gl.GLenum, _type: gl.GLenum, id: gl.GLuint, severity: gl.GLenum, length: gl.GLsizei, message: [*:0]const u8, userParam: ?*anyopaque) callconv(.C) void {
|
||||||
_ = userParam; // autofix
|
// _ = userParam; // autofix
|
||||||
const source_str = switch (source) {
|
// const source_str = switch (source) {
|
||||||
gl.DEBUG_SOURCE_API => "API",
|
// gl.DEBUG_SOURCE_API => "API",
|
||||||
gl.DEBUG_SOURCE_WINDOW_SYSTEM => "WindowSystem",
|
// gl.DEBUG_SOURCE_WINDOW_SYSTEM => "WindowSystem",
|
||||||
gl.DEBUG_SOURCE_APPLICATION => "App",
|
// gl.DEBUG_SOURCE_APPLICATION => "App",
|
||||||
gl.DEBUG_SOURCE_SHADER_COMPILER => "ShaderCompiler",
|
// gl.DEBUG_SOURCE_SHADER_COMPILER => "ShaderCompiler",
|
||||||
gl.DEBUG_SOURCE_THIRD_PARTY => "ThirdParty",
|
// gl.DEBUG_SOURCE_THIRD_PARTY => "ThirdParty",
|
||||||
gl.DEBUG_SOURCE_OTHER => "Other",
|
// gl.DEBUG_SOURCE_OTHER => "Other",
|
||||||
else => unreachable,
|
// else => unreachable,
|
||||||
};
|
// };
|
||||||
const type_str = switch (_type) {
|
// const type_str = switch (_type) {
|
||||||
gl.DEBUG_TYPE_ERROR => "Error",
|
// gl.DEBUG_TYPE_ERROR => "Error",
|
||||||
gl.DEBUG_TYPE_DEPRECATED_BEHAVIOR => "Deprecated Behaviour",
|
// gl.DEBUG_TYPE_DEPRECATED_BEHAVIOR => "Deprecated Behaviour",
|
||||||
gl.DEBUG_TYPE_UNDEFINED_BEHAVIOR => "Undefined Behaviour",
|
// gl.DEBUG_TYPE_UNDEFINED_BEHAVIOR => "Undefined Behaviour",
|
||||||
gl.DEBUG_TYPE_PORTABILITY => "Portability",
|
// gl.DEBUG_TYPE_PORTABILITY => "Portability",
|
||||||
gl.DEBUG_TYPE_PERFORMANCE => "Performance",
|
// gl.DEBUG_TYPE_PERFORMANCE => "Performance",
|
||||||
gl.DEBUG_TYPE_MARKER => "Marker",
|
// gl.DEBUG_TYPE_MARKER => "Marker",
|
||||||
gl.DEBUG_TYPE_PUSH_GROUP => "Push Group",
|
// gl.DEBUG_TYPE_PUSH_GROUP => "Push Group",
|
||||||
gl.DEBUG_TYPE_POP_GROUP => "Pop Group",
|
// gl.DEBUG_TYPE_POP_GROUP => "Pop Group",
|
||||||
gl.DEBUG_TYPE_OTHER => "Other",
|
// gl.DEBUG_TYPE_OTHER => "Other",
|
||||||
else => unreachable,
|
// else => unreachable,
|
||||||
};
|
// };
|
||||||
switch (severity) {
|
// switch (severity) {
|
||||||
gl.DEBUG_SEVERITY_HIGH => {
|
// gl.DEBUG_SEVERITY_HIGH => {
|
||||||
std.log.scoped(.OpenGL).err("{s}:{}:{s}: {s}", .{ source_str, id, type_str, message[0..@intCast(length)] });
|
// std.log.scoped(.OpenGL).err("{s}:{}:{s}: {s}", .{ source_str, id, type_str, message[0..@intCast(length)] });
|
||||||
},
|
// },
|
||||||
gl.DEBUG_SEVERITY_MEDIUM => {
|
// gl.DEBUG_SEVERITY_MEDIUM => {
|
||||||
std.log.scoped(.OpenGL).warn("{s}:{}:{s}: {s}", .{ source_str, id, type_str, message[0..@intCast(length)] });
|
// std.log.scoped(.OpenGL).warn("{s}:{}:{s}: {s}", .{ source_str, id, type_str, message[0..@intCast(length)] });
|
||||||
},
|
// },
|
||||||
gl.DEBUG_SEVERITY_LOW => {
|
// gl.DEBUG_SEVERITY_LOW => {
|
||||||
std.log.scoped(.OpenGL).debug("{s}:{}:{s}: {s}", .{ source_str, id, type_str, message[0..@intCast(length)] });
|
// std.log.scoped(.OpenGL).debug("{s}:{}:{s}: {s}", .{ source_str, id, type_str, message[0..@intCast(length)] });
|
||||||
},
|
// },
|
||||||
gl.DEBUG_SEVERITY_NOTIFICATION => {
|
// gl.DEBUG_SEVERITY_NOTIFICATION => {
|
||||||
std.log.scoped(.OpenGL).info("{s}:{}:{s}: {s}", .{ source_str, id, type_str, message[0..@intCast(length)] });
|
// std.log.scoped(.OpenGL).info("{s}:{}:{s}: {s}", .{ source_str, id, type_str, message[0..@intCast(length)] });
|
||||||
},
|
// },
|
||||||
else => unreachable,
|
// else => unreachable,
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
const mesh_program = a.ShaderPrograms.mesh;
|
const mesh_program = a.ShaderPrograms.mesh;
|
||||||
|
|
||||||
export fn game_init(global_allocator: *std.mem.Allocator) void {
|
export fn game_init(global_allocator: *std.mem.Allocator) void {
|
||||||
loadGL();
|
// loadGL();
|
||||||
tracy.startupProfiler();
|
tracy.startupProfiler();
|
||||||
|
|
||||||
std.log.debug("game_init\n", .{});
|
std.log.debug("game_init\n", .{});
|
||||||
@ -171,7 +174,7 @@ export fn game_init(global_allocator: *std.mem.Allocator) void {
|
|||||||
.global_allocator = global_allocator.*,
|
.global_allocator = global_allocator.*,
|
||||||
.frame_fba = std.heap.FixedBufferAllocator.init(frame_arena_buffer),
|
.frame_fba = std.heap.FixedBufferAllocator.init(frame_arena_buffer),
|
||||||
.assetman = AssetManager.init(global_allocator.*, globals.g_mem.frame_fba.allocator()),
|
.assetman = AssetManager.init(global_allocator.*, globals.g_mem.frame_fba.allocator()),
|
||||||
.render = Render.init(global_allocator.*, globals.g_mem.frame_fba.allocator(), &globals.g_mem.assetman),
|
// .render = Render.init(global_allocator.*, globals.g_mem.frame_fba.allocator(), &globals.g_mem.assetman),
|
||||||
.world = .{ .frame_arena = globals.g_mem.frame_fba.allocator() },
|
.world = .{ .frame_arena = globals.g_mem.frame_fba.allocator() },
|
||||||
};
|
};
|
||||||
globals.g_mem.render.camera = &globals.g_mem.free_cam.camera;
|
globals.g_mem.render.camera = &globals.g_mem.free_cam.camera;
|
||||||
@ -181,13 +184,13 @@ export fn game_init(global_allocator: *std.mem.Allocator) void {
|
|||||||
globals.g_mem.performance_frequency = c.SDL_GetPerformanceFrequency();
|
globals.g_mem.performance_frequency = c.SDL_GetPerformanceFrequency();
|
||||||
globals.g_mem.last_frame_time = c.SDL_GetPerformanceCounter();
|
globals.g_mem.last_frame_time = c.SDL_GetPerformanceCounter();
|
||||||
|
|
||||||
var majorVer: gl.GLint = 0;
|
// var majorVer: gl.GLint = 0;
|
||||||
var minorVer: gl.GLint = 0;
|
// var minorVer: gl.GLint = 0;
|
||||||
gl.getIntegerv(gl.MAJOR_VERSION, &majorVer);
|
// gl.getIntegerv(gl.MAJOR_VERSION, &majorVer);
|
||||||
gl.getIntegerv(gl.MINOR_VERSION, &minorVer);
|
// gl.getIntegerv(gl.MINOR_VERSION, &minorVer);
|
||||||
std.log.debug("OpenGL Version: {}.{}", .{ majorVer, minorVer });
|
// std.log.debug("OpenGL Version: {}.{}", .{ majorVer, minorVer });
|
||||||
|
|
||||||
gl.viewport(0, 0, globals.g_init.width, globals.g_init.height);
|
// gl.viewport(0, 0, globals.g_init.width, globals.g_init.height);
|
||||||
|
|
||||||
_ = globals.g_mem.world.addEntity(.{
|
_ = globals.g_mem.world.addEntity(.{
|
||||||
.flags = .{ .dir_light = true, .rotate = true },
|
.flags = .{ .dir_light = true, .rotate = true },
|
||||||
@ -402,7 +405,7 @@ export fn game_update() bool {
|
|||||||
c.SDL_GL_GetDrawableSize(ginit.window, &ginit.width, &ginit.height);
|
c.SDL_GL_GetDrawableSize(ginit.window, &ginit.width, &ginit.height);
|
||||||
std.log.debug("w: {}, h: {}\n", .{ ginit.width, ginit.height });
|
std.log.debug("w: {}, h: {}\n", .{ ginit.width, ginit.height });
|
||||||
|
|
||||||
gl.viewport(0, 0, ginit.width, ginit.height);
|
// gl.viewport(0, 0, ginit.width, ginit.height);
|
||||||
},
|
},
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
@ -458,8 +461,10 @@ export fn game_update() bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ginit.gc.draw() catch @panic("draw error");
|
||||||
|
|
||||||
// Render
|
// Render
|
||||||
{
|
if (false) {
|
||||||
const zone = tracy.initZone(@src(), .{ .name = "game.render()" });
|
const zone = tracy.initZone(@src(), .{ .name = "game.render()" });
|
||||||
defer zone.deinit();
|
defer zone.deinit();
|
||||||
gmem.render.begin();
|
gmem.render.begin();
|
||||||
@ -516,11 +521,11 @@ export fn game_update() bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
// {
|
||||||
const zone = tracy.initZone(@src(), .{ .name = "SDL_GL_SwapWindow" });
|
// const zone = tracy.initZone(@src(), .{ .name = "SDL_GL_SwapWindow" });
|
||||||
defer zone.deinit();
|
// defer zone.deinit();
|
||||||
c.SDL_GL_SwapWindow(ginit.window);
|
// c.SDL_GL_SwapWindow(ginit.window);
|
||||||
}
|
// }
|
||||||
tracy.frameMark();
|
tracy.frameMark();
|
||||||
//c.SDL_Delay(1);
|
//c.SDL_Delay(1);
|
||||||
|
|
||||||
@ -535,7 +540,7 @@ export fn game_shutdown() void {
|
|||||||
gmem.assetman.deinit();
|
gmem.assetman.deinit();
|
||||||
gmem.global_allocator.free(gmem.frame_fba.buffer);
|
gmem.global_allocator.free(gmem.frame_fba.buffer);
|
||||||
gmem.global_allocator.destroy(gmem);
|
gmem.global_allocator.destroy(gmem);
|
||||||
gl.disable(gl.DEBUG_OUTPUT);
|
// gl.disable(gl.DEBUG_OUTPUT);
|
||||||
tracy.shutdownProfiler();
|
tracy.shutdownProfiler();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -553,7 +558,7 @@ export fn game_hot_reload(init_memory: ?*anyopaque, gmemory: ?*anyopaque) void {
|
|||||||
if (init_memory) |init_mem| {
|
if (init_memory) |init_mem| {
|
||||||
globals.g_init = @alignCast(@ptrCast(init_mem));
|
globals.g_init = @alignCast(@ptrCast(init_mem));
|
||||||
globals.g_init_exists = true;
|
globals.g_init_exists = true;
|
||||||
loadGL();
|
// loadGL();
|
||||||
}
|
}
|
||||||
if (gmemory) |gmem| {
|
if (gmemory) |gmem| {
|
||||||
globals.g_mem = @alignCast(@ptrCast(gmem));
|
globals.g_mem = @alignCast(@ptrCast(gmem));
|
||||||
|
@ -3,6 +3,7 @@ const c = @import("sdl.zig");
|
|||||||
const Render = @import("Render.zig");
|
const Render = @import("Render.zig");
|
||||||
const AssetManager = @import("AssetManager.zig");
|
const AssetManager = @import("AssetManager.zig");
|
||||||
const World = @import("entity.zig").World;
|
const World = @import("entity.zig").World;
|
||||||
|
const GraphicsContext = @import("GraphicsContext.zig");
|
||||||
|
|
||||||
const za = @import("zalgebra");
|
const za = @import("zalgebra");
|
||||||
const Vec2 = za.Vec2;
|
const Vec2 = za.Vec2;
|
||||||
@ -28,12 +29,13 @@ pub const InitMemory = struct {
|
|||||||
fullscreen: bool = false,
|
fullscreen: bool = false,
|
||||||
vsync: bool = false,
|
vsync: bool = false,
|
||||||
syswm_info: c.SDL_SysWMinfo = .{},
|
syswm_info: c.SDL_SysWMinfo = .{},
|
||||||
|
gc: GraphicsContext = .{},
|
||||||
};
|
};
|
||||||
pub const GameMemory = struct {
|
pub const GameMemory = struct {
|
||||||
global_allocator: std.mem.Allocator,
|
global_allocator: std.mem.Allocator,
|
||||||
frame_fba: std.heap.FixedBufferAllocator,
|
frame_fba: std.heap.FixedBufferAllocator,
|
||||||
assetman: AssetManager,
|
assetman: AssetManager,
|
||||||
render: Render,
|
render: Render = undefined,
|
||||||
performance_frequency: u64 = 0,
|
performance_frequency: u64 = 0,
|
||||||
last_frame_time: u64 = 0,
|
last_frame_time: u64 = 0,
|
||||||
delta_time: f32 = 0.0000001,
|
delta_time: f32 = 0.0000001,
|
||||||
|
65
src/mem/Arena.zig
Normal file
65
src/mem/Arena.zig
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const Arena = @This();
|
||||||
|
|
||||||
|
memory: []align(std.mem.page_size) u8,
|
||||||
|
ptr: usize = 0,
|
||||||
|
commited_pages: usize = 0,
|
||||||
|
|
||||||
|
pub fn init(reserve_mem: usize) !Arena {
|
||||||
|
const slice = try std.posix.mmap(null, reserve_mem, std.posix.PROT.NONE, .{ .TYPE = .PRIVATE, .ANONYMOUS = true }, -1, 0);
|
||||||
|
|
||||||
|
return Arena{
|
||||||
|
.memory = slice,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn allocator(self: *Arena) std.mem.Allocator {
|
||||||
|
return std.mem.Allocator{
|
||||||
|
.ptr = @ptrCast(self),
|
||||||
|
.vtable = &vtable,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const vtable = std.mem.Allocator.VTable{
|
||||||
|
.alloc = rawAlloc,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// This function is not intended to be called except from within the
|
||||||
|
/// implementation of an Allocator
|
||||||
|
pub inline fn rawAlloc(self: *Arena, len: usize, ptr_align: u8, ret_addr: usize) ?[*]u8 {
|
||||||
|
_ = ret_addr; // autofix
|
||||||
|
const result = std.mem.alignForwardLog2(usize, self.ptr, ptr_align);
|
||||||
|
|
||||||
|
const new_ptr = result + len;
|
||||||
|
|
||||||
|
if (new_ptr >= self.memory.len) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_ptr >= self.getLastPageEnd()) {
|
||||||
|
self.reservePagesUpTo(new_ptr) catch {
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
self.ptr = new_ptr;
|
||||||
|
|
||||||
|
return &self.memory.ptr[result];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fn getLastPageEnd(self: *const Arena) usize {
|
||||||
|
return std.mem.page_size * (self.commited_pages + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reservePagesUpTo(self: *Arena, addr: usize) !void {
|
||||||
|
while (addr >= self.getLastPageEnd()) {
|
||||||
|
switch (std.os.errno(std.os.linux.mprotect(self.getLastPageEnd(), std.mem.page_size, std.os.linux.PROT.WRITE | std.os.linux.PROT.READ))) {
|
||||||
|
.SUCCESS => {},
|
||||||
|
.ENOMEM => return error.OutOfMemory,
|
||||||
|
.EINVAL => unreachable,
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
self.commited_pages += 1;
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
pub usingnamespace @cImport({
|
pub usingnamespace @cImport({
|
||||||
@cInclude("SDL2/SDL.h");
|
@cInclude("SDL2/SDL.h");
|
||||||
@cInclude("SDL2/SDL_syswm.h");
|
@cInclude("SDL2/SDL_syswm.h");
|
||||||
|
@cInclude("SDL2/SDL_vulkan.h");
|
||||||
});
|
});
|
||||||
|
|
||||||
// When using system sdl2 library this might not be defined
|
// When using system sdl2 library this might not be defined
|
||||||
|
@ -532,6 +532,7 @@ fn processShaderProgram(allocator: std.mem.Allocator, input: []const u8, output_
|
|||||||
shader: []const u8,
|
shader: []const u8,
|
||||||
vertex: bool,
|
vertex: bool,
|
||||||
fragment: bool,
|
fragment: bool,
|
||||||
|
compute: bool,
|
||||||
};
|
};
|
||||||
const program = try std.json.parseFromSlice(ShaderProgram, allocator, file_contents, .{});
|
const program = try std.json.parseFromSlice(ShaderProgram, allocator, file_contents, .{});
|
||||||
defer program.deinit();
|
defer program.deinit();
|
||||||
@ -549,7 +550,7 @@ fn processShaderProgram(allocator: std.mem.Allocator, input: []const u8, output_
|
|||||||
defer output.file.close();
|
defer output.file.close();
|
||||||
var buf_writer = std.io.bufferedWriter(output.file.writer());
|
var buf_writer = std.io.bufferedWriter(output.file.writer());
|
||||||
|
|
||||||
try formats.writeShaderProgram(buf_writer.writer(), shader_asset_id, program.value.vertex, program.value.fragment, formats.native_endian);
|
try formats.writeShaderProgram(buf_writer.writer(), shader_asset_id, program.value.vertex, program.value.fragment, program.value.compute, formats.native_endian);
|
||||||
try buf_writer.flush();
|
try buf_writer.flush();
|
||||||
}
|
}
|
||||||
const MipLevel = struct {
|
const MipLevel = struct {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user