182 lines
6.6 KiB
Zig
182 lines
6.6 KiB
Zig
pub const MeshPool = struct {
|
|
allocator: std.mem.Allocator,
|
|
|
|
meshMap: std.AutoHashMapUnmanaged(u32, rend.IndexedMesh) = .{},
|
|
indexSpans: core.MergedSpans,
|
|
vertexSpans: core.MergedSpans,
|
|
|
|
indexBuffer: *gpu.GPUBuffer = undefined,
|
|
vertexBuffer: *gpu.GPUBuffer = undefined,
|
|
|
|
meshUpdates: core.RingQueue(rend.MeshUpdate),
|
|
|
|
device: *gpu.GPUDevice,
|
|
|
|
destroyList: std.ArrayList(*gpu.GPUTransferBuffer),
|
|
|
|
installedMeshes: std.AutoHashMapUnmanaged(u32, meshes.IndexedMesh) = .{},
|
|
|
|
pub fn create(device: *gpu.GPUDevice, allocator: std.mem.Allocator, settings: MeshPoolCreationSettings) !*@This() {
|
|
const self = try allocator.create(@This());
|
|
|
|
gMeshPool = self;
|
|
|
|
self.* = .{
|
|
.allocator = allocator,
|
|
.indexSpans = try core.MergedSpans.init(allocator, settings.indexCount),
|
|
.vertexSpans = try core.MergedSpans.init(allocator, settings.vertexCount),
|
|
.meshUpdates = try core.RingQueue(rend.MeshUpdate).init(allocator, 128),
|
|
.destroyList = std.ArrayList(*gpu.GPUTransferBuffer).init(allocator),
|
|
.device = device,
|
|
};
|
|
|
|
self.vertexBuffer = self.device.createGPUBuffer(&.{
|
|
.usage = .{ .bufferusageVertex = true },
|
|
.size = settings.vertexCount * @sizeOf(rend.MeshVertex),
|
|
.props = 0,
|
|
});
|
|
|
|
self.indexBuffer = self.device.createGPUBuffer(&.{
|
|
.usage = .{ .bufferusageIndex = true },
|
|
.size = settings.indexCount * @sizeOf(u32),
|
|
.props = 0,
|
|
});
|
|
|
|
core.graphics_log("mesh pool created {d}k vertices, {d}k indices", .{ settings.vertexCount / 1000, settings.indexCount / 1000 });
|
|
|
|
try assets.gAssetSys.registerLoader(try core.createObject(MeshAssetLoader, .{}));
|
|
|
|
return self;
|
|
}
|
|
|
|
pub fn onUploadCleanup(p: *anyopaque) void {
|
|
const self: *@This() = @ptrCast(@alignCast(p));
|
|
|
|
for (self.destroyList.items) |transferBuffer| {
|
|
self.device.releaseGPUTransferBuffer(transferBuffer);
|
|
}
|
|
|
|
self.destroyList.clearRetainingCapacity();
|
|
}
|
|
|
|
pub fn onUploadInner(self: *@This(), copyPass: *gpu.GPUCopyPass) !void {
|
|
self.meshUpdates.lock();
|
|
defer self.meshUpdates.unlock();
|
|
|
|
self.destroyList = std.ArrayList(*gpu.GPUTransferBuffer).init(self.allocator);
|
|
|
|
while (self.meshUpdates.popFromUnlocked()) |u| {
|
|
switch (u) {
|
|
.new => |new| {
|
|
const indexSpan = try self.addTransfer(copyPass, self.indexBuffer, u32, &self.indexSpans, new.indices);
|
|
const vertexSpan = try self.addTransfer(copyPass, self.vertexBuffer, meshes.MeshVertex, &self.vertexSpans, new.vertices);
|
|
|
|
var name = new.name;
|
|
core.graphics_log("uploading {d} vertices and {d} indices", .{ vertexSpan.size, indexSpan.size });
|
|
try self.installedMeshes.put(self.allocator, name.handle(), .{
|
|
.vertex = vertexSpan,
|
|
.index = indexSpan,
|
|
.name = new.name,
|
|
.jointRemap = null, // joint remaps... parse the installed skeletal meshes to generate this remap
|
|
});
|
|
},
|
|
.free => |free| {
|
|
var name = free.name;
|
|
if (!self.installedMeshes.remove(name.handle())) {
|
|
core.engine_log("unable to find handle from mesh pool.. {s}", .{name.utf8()});
|
|
}
|
|
self.vertexSpans.removeSpan(free.vertices);
|
|
self.indexSpans.removeSpan(free.indices);
|
|
},
|
|
}
|
|
|
|
u.deinit(self.allocator);
|
|
}
|
|
}
|
|
|
|
pub fn onUpload(p: *anyopaque, copyPass: *gpu.GPUCopyPass) void {
|
|
const self: *@This() = @ptrCast(@alignCast(p));
|
|
if (self.meshUpdates.count() <= 0)
|
|
return;
|
|
|
|
self.onUploadInner(copyPass) catch unreachable;
|
|
}
|
|
|
|
pub fn addTransfer(
|
|
self: *@This(),
|
|
copyPass: *gpu.GPUCopyPass,
|
|
destBuffer: *gpu.GPUBuffer,
|
|
comptime T: type,
|
|
mergedSpans: *core.MergedSpans,
|
|
uploadSlice: []const T,
|
|
) !core.Span {
|
|
const newSpan = try mergedSpans.allocate(@intCast(uploadSlice.len));
|
|
const upload = self.device.createGPUTransferBuffer(&.{ .usage = .transferbufferusageUpload, .size = @sizeOf(T) * newSpan.size, .props = 0 });
|
|
try self.destroyList.append(upload);
|
|
|
|
var mappedSlice: []T = undefined;
|
|
mappedSlice.ptr = @ptrCast(@alignCast(self.device.mapGPUTransferBuffer(upload, false)));
|
|
defer self.device.unmapGPUTransferBuffer(upload);
|
|
mappedSlice.len = uploadSlice.len;
|
|
std.mem.copyForwards(T, mappedSlice, uploadSlice);
|
|
|
|
//copyPass.uploadToGPUBuffer(source: [*c]const GPUTransferBufferLocation, destination: [*c]const GPUBufferRegion, cycle: bool)
|
|
copyPass.uploadToGPUBuffer(
|
|
&.{ .transfer_buffer = upload, .offset = 0 },
|
|
&.{ .buffer = destBuffer, .offset = newSpan.start, .size = newSpan.size },
|
|
false,
|
|
);
|
|
|
|
return newSpan;
|
|
}
|
|
|
|
// pushes the meshUpdate into the pool, either an insert or a free.
|
|
pub fn pushMeshUpdate(self: *@This(), meshUpdate: rend.MeshUpdate) !void {
|
|
try self.meshUpdates.pushLocked(meshUpdate);
|
|
}
|
|
|
|
pub fn destroy(p: *anyopaque) void {
|
|
const self: *@This() = @ptrCast(@alignCast(p));
|
|
|
|
self.device.releaseGPUBuffer(self.indexBuffer);
|
|
self.device.releaseGPUBuffer(self.vertexBuffer);
|
|
|
|
self.installedMeshes.deinit(self.allocator);
|
|
self.destroyList.deinit();
|
|
self.indexSpans.deinit();
|
|
self.meshUpdates.deinit();
|
|
self.vertexSpans.deinit();
|
|
self.allocator.destroy(self);
|
|
}
|
|
|
|
pub const MeshPoolCreationSettings = struct {
|
|
vertexCount: u32 = 4_000_000,
|
|
indexCount: u32 = 16_000_000,
|
|
};
|
|
};
|
|
|
|
/// === renderer interface implementation ===
|
|
var gMeshPool: *MeshPool = undefined;
|
|
|
|
pub fn getMesh(name: []const u8) ?rend.IndexedMesh {
|
|
var n = core.MakeName(name);
|
|
return getMeshByName(&n);
|
|
}
|
|
|
|
pub fn getMeshByName(name: *core.Name) ?rend.IndexedMesh {
|
|
return gMeshPool.installedMeshes.get(name.handle());
|
|
}
|
|
|
|
pub fn pushMeshUpdate(meshUpdate: rend.MeshUpdate) !void {
|
|
try gMeshPool.pushMeshUpdate(meshUpdate);
|
|
}
|
|
|
|
const MeshAssetLoader = @import("MeshAssetLoader.zig");
|
|
const sdl3 = @import("sdl3");
|
|
const gpu = sdl3.gpu;
|
|
const rend = @import("../rend.zig");
|
|
const std = @import("std");
|
|
const core = @import("core");
|
|
const assets = @import("assets");
|
|
const meshes = rend.meshes;
|