trying out the depot project

This commit is contained in:
peterino2 2025-10-26 15:50:42 -07:00
parent 338954aa8a
commit cf0f27cc92
10 changed files with 284 additions and 57 deletions

View File

@ -114,7 +114,9 @@ This project uses git-bug for distributed bug tracking. Bug data is stored direc
- `git bug bug show <id>` - Display bug details - `git bug bug show <id>` - Display bug details
- `git bug bug comment <id>` - Add a comment to a bug - `git bug bug comment <id>` - Add a comment to a bug
- `git bug bug status <id>` - Display bug status - `git bug bug status <id>` - Display bug status
- `git bug bug label <id> <label>` - Add a label to a bug - `git bug bug label new <id> <label>` - Add a label to a bug
- `git bug bug label rm <id> <label>` - Remove a label from a bug
- `git bug bug label <id>` - Display labels for a bug
- `git bug bug status:open` - List only open bugs - `git bug bug status:open` - List only open bugs
- `git bug pull` - Pull bug updates from remote - `git bug pull` - Pull bug updates from remote
- `git bug push` - Push bug updates to remote - `git bug push` - Push bug updates to remote
@ -126,3 +128,14 @@ This project uses git-bug for distributed bug tracking. Bug data is stored direc
- Use labels to categorize bugs by component (e.g., `core`, `rendering`, `physics`, `build-system`) - Use labels to categorize bugs by component (e.g., `core`, `rendering`, `physics`, `build-system`)
- Use `--non-interactive` flag for scripting - Use `--non-interactive` flag for scripting
- Keep bug descriptions factual - describe what happens, not speculation about why - Keep bug descriptions factual - describe what happens, not speculation about why
### Standard Labels
Use these standard labels to categorize bugs:
- **Component labels**: `core`, `rendering`, `physics`, `build-system`, `platform`, `assets`, `audio`, `ui`
- **Type labels**:
- `memory` - Memory allocation, leaks, or performance issues
- `threading` - Job system, parallelization, race conditions, or deadlocks
- `crash` - Application crashes or critical failures
- `build` - Build system or compilation issues

35
depot/build.zig Normal file
View File

@ -0,0 +1,35 @@
const std = @import("std");
const Backlog = @import("Backlog");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
var blbuild = Backlog.init(b, .{
.target = target,
.optimize = optimize,
.backlogRoot = "../",
});
// blbuild.addDependencyInstalls(b, .ReleaseFast); //.ReleaseFast);
const exileMain = blbuild.program(.{
.name = "exileMain",
.desc = "A tiny shooter made with this engine.",
.root_source_file = b.path("src/main.zig"),
});
exileMain.setModuleEnabled("imgui", true);
exileMain.setModuleEnabled("audio", true);
exileMain.setModuleEnabled("physics", true);
exileMain.setModuleEnabled("ui", true);
exileMain.setModuleEnabled("sys", true);
exileMain.setModuleEnabled("net", true);
{
const exileGame = exileMain.addDynamicModule("exileGame", b.path("src/exileGame.zig"));
_ = exileGame.compileInstall();
}
_ = exileMain.compileInstall();
}

37
depot/build.zig.zon Normal file
View File

@ -0,0 +1,37 @@
.{
.name = .MyProjects,
.version = "0.0.0",
.dependencies = .{
// Neonwood's /lib folder contains
// third party libraries.
//
// They can be directly accessed
//
// as well as any of the engine/ libraries
//
// in the general case though,
// engine libraries
.Backlog = .{ .path = "../" },
.SpirvReflect = .{ .path = "../lib/spirv-reflect-zig" },
.gameExtras = .{.path = "../extras/gameExtras"},
.videoplayer = .{.path = "../extras/videoplayer"},
.doomplayer = .{.path = "../extras/doomplayer"},
.bsp = .{.path = "../extras/bsp"},
.zphysics = .{.path = "../lib/zphysics"},
.spng = .{ .path = "../lib/spng" },
.ozz = .{ .path = "../lib/ozz" },
.sdl3 = .{ .path = "../lib/sdl3" },
.miniaudio = .{ .path = "../lib/miniaudio" },
.lua = .{ .path = "../lib/lua" },
.enet = .{ .path = "../lib/enet" },
},
.paths = .{
"",
},
}

3
depot/readme.md Normal file
View File

@ -0,0 +1,3 @@
# studio games depot
!! not for open source.

View File

@ -0,0 +1,34 @@
pub var NeonObjectTable = core.EngineObjectVTable.from(@This(), "main");
allocator: std.mem.Allocator,
pub fn init(allocator: std.mem.Allocator) !*@This() {
const self = try allocator.create(@This());
self.* = .{
.allocator = allocator,
};
return self;
}
pub fn prepare(self: *@This()) !void {
_ = self;
try api.loadDynamicModules();
}
pub fn tick(self: *@This(), dt: f64) void {
_ = self;
_ = dt;
}
pub fn deinit(self: *@This()) void {
self.allocator.destroy(self);
}
pub fn main() anyerror!void {
var spec = try api.getSpec("minimal");
_ = api.startEngine(&NeonObjectTable, &spec);
}
const std = @import("std");
const api = @import("backlog");
const core = api.core;

View File

@ -367,13 +367,14 @@ pub fn shutdown_module(_: std.mem.Allocator) void {
ecs.shutdown(); ecs.shutdown();
algorithm.destroyNameRegistry(); algorithm.destroyNameRegistry();
gEngine.deinit();
gPackerFS.destroy(); gPackerFS.destroy();
// LUA BEGIN // LUA BEGIN
// script.shutdown_lua(); // script.shutdown_lua();
// LUA END // LUA END
console.shutdown(); console.shutdown();
algorithm.string_pool.shutdown(); algorithm.string_pool.shutdown();
gEngine.deinit();
return; return;
} }

View File

@ -239,7 +239,7 @@ pub const JobWorker = struct {
}; };
const Src = std.builtin.SourceLocation; const Src = std.builtin.SourceLocation;
pub fn Barrier(src: Src) type { pub fn BarrierCV(src: Src) type {
return struct { return struct {
pub const Src = src; pub const Src = src;
@ -248,7 +248,7 @@ pub fn Barrier(src: Src) type {
pub var mutex: std.Thread.Mutex = .{}; pub var mutex: std.Thread.Mutex = .{};
pub var cv: std.Thread.Condition = .{}; pub var cv: std.Thread.Condition = .{};
pub fn sync(threadId: u32, threadCount: u32) !void { pub fn sync(threadId: u32, barrierCount: u32) !void {
_ = threadId; _ = threadId;
mutex.lock(); mutex.lock();
@ -256,18 +256,47 @@ pub fn Barrier(src: Src) type {
count += 1; count += 1;
if (count == threadCount) { if (count == barrierCount) {
// 2 second timeout
count = 0; count = 0;
generation += 1; generation += 1;
cv.broadcast(); cv.broadcast();
} else { } else {
// 2 second timeout
try cv.timedWait(&mutex, 1000 * 1000 * 1000 * 2); try cv.timedWait(&mutex, 1000 * 1000 * 1000 * 2);
} }
} }
}; };
} }
pub fn BarrierSpin(src: Src) type {
return struct {
pub const Src = src;
pub var count: std.atomic.Value(u32) = std.atomic.Value(u32).init(0);
pub var park: std.atomic.Value(bool) = std.atomic.Value(bool).init(false);
pub fn sync(threadId: u32, barrierCount: u32) !void {
_ = threadId;
const c = count.fetchAdd(1, .release);
if(c + 1 == barrierCount)
{
park.store(true, .release);
while(count.load(.acquire) > 1) {}
_ = count.fetchSub(1, .release);
park.store(false, .release);
}
else
{
while(park.load(.acquire) == false) {}
_ = count.fetchSub(1, .seq_cst);
}
}
};
}
pub const Barrier = BarrierSpin;
pub const ThreadContext = struct { pub const ThreadContext = struct {
const Self = @This(); const Self = @This();

View File

@ -56,6 +56,8 @@ pub const SceneObjectRepr = struct {
attachmentMode: SceneAttachMode = .relative, // doesn't do anything yet, only support relative right now attachmentMode: SceneAttachMode = .relative, // doesn't do anything yet, only support relative right now
transformOverride: ?*core.Transform = null, transformOverride: ?*core.Transform = null,
lastUpdate: u32 = 0, lastUpdate: u32 = 0,
merge: std.atomic.Value(bool) = std.atomic.Value(bool).init(false), // set to true if we've merged already, false if we havent
}; };
pub const SceneObject = struct { pub const SceneObject = struct {
@ -300,6 +302,9 @@ pub const SceneSystem = struct {
tickCount: u32 = 0, tickCount: u32 = 0,
sceneObjectContainer: *SceneObjectSet = undefined, sceneObjectContainer: *SceneObjectSet = undefined,
cachedOutputs: std.ArrayList(std.ArrayList(core.Transform)) = .{},
writeOutList: std.ArrayList(std.ArrayList(usize)) = .{},
pub const Field = SceneObjectSet.Field; pub const Field = SceneObjectSet.Field;
pub const FieldType = SceneObjectSet.FieldType; pub const FieldType = SceneObjectSet.FieldType;
@ -326,16 +331,6 @@ pub const SceneSystem = struct {
} else {} } else {}
} }
// core.engine_log("final\n{d} {d} {d} {d}\n{d} {d} {d} {d}", .{
// final[0][0],
// final[0][1],
// final[0][2],
// final[0][3],
// final[1][0],
// final[1][1],
// final[1][2],
// final[1][3],
// });
repr.transform = core.zm.mul( repr.transform = core.zm.mul(
core.zm.mul( core.zm.mul(
core.zm.mul( core.zm.mul(
@ -347,17 +342,6 @@ pub const SceneSystem = struct {
final, final,
); );
// core.engine_log("final\n{d} {d} {d} {d}\n{d} {d} {d} {d}", .{
// repr.transform[0][0],
// repr.transform[0][1],
// repr.transform[0][2],
// repr.transform[0][3],
// repr.transform[1][0],
// repr.transform[1][1],
// repr.transform[1][2],
// repr.transform[1][3],
// });
repr.lastUpdate = self.tickCount; repr.lastUpdate = self.tickCount;
} }
@ -375,6 +359,8 @@ pub const SceneSystem = struct {
} }
} }
pub const MaxWorkerCount = 24;
// ----- NeonObject interace ---- // ----- NeonObject interace ----
pub fn init(allocator: std.mem.Allocator) !*@This() { pub fn init(allocator: std.mem.Allocator) !*@This() {
const self = try allocator.create(@This()); const self = try allocator.create(@This());
@ -387,9 +373,28 @@ pub const SceneSystem = struct {
Scene.SceneObjectContainer = try SceneObjectSet.create(allocator); Scene.SceneObjectContainer = try SceneObjectSet.create(allocator);
self.sceneObjectContainer = Scene.SceneObjectContainer; self.sceneObjectContainer = Scene.SceneObjectContainer;
for (0..MaxWorkerCount) |i| {
_ = i;
try self.cachedOutputs.append(self.allocator, .{});
try self.writeOutList.append(self.allocator, .{});
}
return self; return self;
} }
pub fn getOutputList(self: *@This(), threadId: u32) !*std.ArrayList(usize) {
const outputLen = self.sceneObjectContainer.denseItems(._repr).len;
try self.writeOutList.items[threadId].ensureTotalCapacity(self.allocator, outputLen);
self.writeOutList.items[threadId].shrinkRetainingCapacity(0);
return &self.writeOutList.items[threadId];
}
pub fn getOutputForWorker(self: *@This(), threadId: u32) ![]core.Transform {
const outputLen = self.sceneObjectContainer.denseItems(._repr).len;
try self.cachedOutputs.items[threadId].resize(self.allocator, outputLen);
return self.cachedOutputs.items[threadId].items;
}
pub fn preTick(self: *@This(), dt: f64) !void { pub fn preTick(self: *@This(), dt: f64) !void {
_ = dt; _ = dt;
self.tickCount +%= 1; self.tickCount +%= 1;
@ -407,9 +412,17 @@ pub const SceneSystem = struct {
} }
pub fn deinit(self: *@This()) void { pub fn deinit(self: *@This()) void {
for (self.cachedOutputs.items) |*i| {
i.deinit(self.allocator);
}
for (self.writeOutList.items) |*i| {
i.deinit(self.allocator);
}
self.dynamicObjects.deinit(self.allocator); self.dynamicObjects.deinit(self.allocator);
self.childrenArena.deinit(); self.childrenArena.deinit();
Scene.SceneObjectContainer.destroy(); Scene.SceneObjectContainer.destroy();
self.cachedOutputs.deinit(self.allocator);
self.writeOutList.deinit(self.allocator);
self.allocator.destroy(self); self.allocator.destroy(self);
} }
}; };

2
lib/tracy/build.zig vendored
View File

@ -11,7 +11,7 @@ pub fn build(b: *std.Build) void {
//const tracy_enabled = b.option(bool, "tracy", "Enables tracy integration") orelse false; //const tracy_enabled = b.option(bool, "tracy", "Enables tracy integration") orelse false;
const tracy_enabled: bool = true; //if (b.graph.env_map.hash_map.get("WITH_TRACY") != null) true else false; const tracy_enabled: bool = false; //if (b.graph.env_map.hash_map.get("WITH_TRACY") != null) true else false;
// if (b.graph.env_map.hash_map.get("WITH_TRACY")) |with_tracy| { // if (b.graph.env_map.hash_map.get("WITH_TRACY")) |with_tracy| {
// tracy_enabled = with_tracy; // tracy_enabled = with_tracy;
// } // }

View File

@ -14,8 +14,7 @@ pub fn create(allocator: std.mem.Allocator) !*@This() {
pub fn prepare(self: *@This()) !void { pub fn prepare(self: *@This()) !void {
_ = self; _ = self;
for(0..120_000) |i| for (0..120_000) |i| {
{
_ = i; _ = i;
const e = try core.createEntity(); const e = try core.createEntity();
const x = e.addComponent(core.Scene).?; const x = e.addComponent(core.Scene).?;
@ -31,7 +30,7 @@ pub fn tick(self: *@This(), dt: f64) void {
const start = core.getEngineTime(); const start = core.getEngineTime();
core.parallelJob(UpdateWorldTransformsJob{}, false, 10) catch unreachable; core.parallelJob(UpdateWorldTransformsJob{}, false, 1) catch unreachable;
// wait 10 ms // wait 10 ms
while (core.getEngineTime() - start < 0.010) { while (core.getEngineTime() - start < 0.010) {
@ -47,7 +46,7 @@ pub fn deinit(self: *@This()) void {
} }
const Src = std.builtin.SourceLocation; const Src = std.builtin.SourceLocation;
pub fn Barrier(src: Src) type { pub fn BarrierCV(src: Src) type {
return struct { return struct {
pub const Src = src; pub const Src = src;
@ -76,6 +75,32 @@ pub fn Barrier(src: Src) type {
}; };
} }
pub fn BarrierSpin(src: Src) type {
return struct {
pub const Src = src;
pub var count: std.atomic.Value(u32) = std.atomic.Value(u32).init(0);
pub var park: std.atomic.Value(bool) = std.atomic.Value(bool).init(false);
pub fn sync(threadId: u32, barrierCount: u32) !void {
_ = threadId;
const c = count.fetchAdd(1, .release);
if (c + 1 == barrierCount) {
park.store(true, .release);
while (count.load(.acquire) > 1) {}
_ = count.fetchSub(1, .release);
park.store(false, .release);
} else {
while (park.load(.acquire) == false) {}
_ = count.fetchSub(1, .seq_cst);
}
}
};
}
pub const Barrier = BarrierSpin;
const MultiJob = struct { const MultiJob = struct {
threadId: u32 = 0, threadId: u32 = 0,
threadCount: u32 = 1, threadCount: u32 = 1,
@ -120,10 +145,10 @@ const UpdateWorldTransformsJob = struct {
defer z.End(); defer z.End();
thread.barrier(@src()) catch unreachable; thread.barrier(@src()) catch unreachable;
var outputs: std.ArrayList(core.math.Transform) = .{}; const outputs = core.get(core.SceneSystem).getOutputForWorker(thread.threadId) catch return;
var outputList: std.ArrayList(usize) = .{}; const outputList = core.get(core.SceneSystem).getOutputList(thread.threadId) catch return;
self.updateTransformsHierarchy(thread, &outputs, &outputList) catch |err| switch (err) { self.updateTransformsHierarchy(thread, outputs, outputList) catch |err| switch (err) {
error.OutOfMemory => { error.OutOfMemory => {
unreachable; unreachable;
}, },
@ -133,43 +158,80 @@ const UpdateWorldTransformsJob = struct {
// }, // },
}; };
// sync results of output List const denseRepr = core.Scene.SceneObjectContainer.denseItems(._repr);
thread.barrier(@src()) catch unreachable;
// write out all results, there likely is no issue with false sharing as transforms are exactly 64 bytes const z3 = core.tracy.ZoneN(@src(), "Merge Outputs");
// const dense = self.world.denseScenes(); // merge outputs
// for (outputList.items) |i| { // current a noop just iterate over the outputlist
// // dense[i].transform = outputs.items[i]; for (outputList.items) |outIndex| {
// } if (denseRepr[outIndex].merge.cmpxchgStrong(false, true, .seq_cst, .acquire) != null) {
denseRepr[outIndex].transform = outputs[outIndex];
}
}
z3.End();
thread.barrier(@src()) catch unreachable;
} }
pub fn updateTransformsHierarchy(self: @This(), thread: *core.ThreadContext, outputs: *std.ArrayList(core.math.Transform), outputList: *std.ArrayList(usize)) !void { fn updateTransform(
_ = outputList; self: @This(),
_ = self; thread: *core.ThreadContext,
index: usize,
densePosRot: []core.scene.ScenePosRot,
denseRepr: []core.scene.SceneObjectRepr,
outputs: []core.math.Transform,
outputList: *std.ArrayList(usize),
) void {
var final: core.Transform = core.zm.identity();
const repr = denseRepr[index];
if (repr.parent) |parent| {
if (core.Scene.SceneObjectContainer.sparseToDense(parent)) |parentIndex| {
self.updateTransform(thread, parentIndex, densePosRot, denseRepr, outputs, outputList);
const parentTransform = outputs[parentIndex];
final = core.zm.mul(parentTransform, final);
} else {}
}
const posRot = densePosRot[index];
outputs[index] = core.zm.mul(
core.zm.mul(
core.zm.mul(
core.zm.scalingV(posRot.scale.toZm()),
core.zm.matFromQuat(posRot.rotation.quat),
),
core.zm.translationV(posRot.position.toZm()),
),
final,
);
outputList.appendAssumeCapacity(index);
}
pub fn updateTransformsHierarchy(self: @This(), thread: *core.ThreadContext, outputs: []core.math.Transform, outputList: *std.ArrayList(usize)) !void {
const z = core.tracy.ZoneN(@src(), "updateTransformsHierarchy"); const z = core.tracy.ZoneN(@src(), "updateTransformsHierarchy");
defer z.End(); defer z.End();
//const dense = self.world.denseScenes(); //const dense = self.world.denseScenes();
const densePosRot = core.Scene.SceneObjectContainer.denseItems(.posRot); const densePosRot = core.Scene.SceneObjectContainer.denseItems(.posRot);
const denseRepr = core.Scene.SceneObjectContainer.denseItems(._repr);
// everything allocated with thread.scratch is blown away when the thread is complete // everything allocated with thread.scratch is blown away when the thread is complete
try outputs.resize(thread.scratch(), densePosRot.len); // try outputs.resize(thread.scratch(), densePosRot.len);
// scan and mark all root nodes for update // scan and mark all root nodes for update
const split = thread.splitSlice(core.scene.ScenePosRot, densePosRot); const split = thread.splitSlice(core.scene.SceneObjectRepr, denseRepr);
const locals:[]core.math.Transform = try thread.scratch().alloc(core.math.Transform, split.slice.len); // const locals:[]core.math.Transform = try thread.scratch().alloc(core.math.Transform, split.slice.len);
const z2 = core.tracy.ZoneN(@src(), "WalkAndResolve"); const z2 = core.tracy.ZoneN(@src(), "WalkAndResolve");
defer z2.End(); for (split.slice, 0..) |*repr, i| {
for (split.slice, 0..) |posRot, i| {
const index = split.startIndex + i; const index = split.startIndex + i;
_ = index; self.updateTransform(thread, index, densePosRot, denseRepr, outputs, outputList);
//repr.cmpxchgStrong(false, true, .seq_cst, .acquire)
locals[i] = posRot.toTransform(); repr.merge.store(false, .seq_cst); // reset the merge big
} }
z2.End();
//for (split.slice, 0..) |repr, i| {
//}
} }
}; };