adding bounded arena allocator to renderer
This commit is contained in:
@@ -58,7 +58,7 @@ jobs:
|
|||||||
which deqp-runner && deqp-runner --version || echo "deqp-runner not found"
|
which deqp-runner && deqp-runner --version || echo "deqp-runner not found"
|
||||||
|
|
||||||
- name: Run Vulkan CTS
|
- name: Run Vulkan CTS
|
||||||
run: zig build cts-soft --release=fast -Dlogs="standard" -- -j4
|
run: zig build cts-soft --release=fast -- -j3
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
|
|
||||||
- name: Verify tests
|
- name: Verify tests
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const base = @import("base");
|
||||||
|
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
|
const Alignment = std.mem.Alignment;
|
||||||
|
|
||||||
|
mutex: base.SpinMutex,
|
||||||
|
arena: std.heap.ArenaAllocator,
|
||||||
|
bound: usize,
|
||||||
|
|
||||||
|
pub fn init(child_allocator: Allocator, bound: usize) Self {
|
||||||
|
return .{
|
||||||
|
.mutex = .{},
|
||||||
|
.arena = .init(child_allocator),
|
||||||
|
.bound = bound,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *Self) void {
|
||||||
|
self.arena.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn allocator(self: *const Self) Allocator {
|
||||||
|
return .{
|
||||||
|
.ptr = @ptrCast(@constCast(self)), // Ugly const cast for convenience
|
||||||
|
.vtable = &.{
|
||||||
|
.alloc = alloc,
|
||||||
|
.resize = resize,
|
||||||
|
.remap = remap,
|
||||||
|
.free = free,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn queryCapacity(self: *Self) usize {
|
||||||
|
return self.arena.queryCapacity();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn alloc(context: *anyopaque, len: usize, alignment: Alignment, ret_addr: usize) ?[*]u8 {
|
||||||
|
const self: *Self = @ptrCast(@alignCast(context));
|
||||||
|
self.mutex.lock();
|
||||||
|
defer self.mutex.unlock();
|
||||||
|
if (self.arena.queryCapacity() >= self.bound)
|
||||||
|
return null;
|
||||||
|
return self.arena.allocator().rawAlloc(len, alignment, ret_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resize(context: *anyopaque, ptr: []u8, alignment: Alignment, new_len: usize, ret_addr: usize) bool {
|
||||||
|
const self: *Self = @ptrCast(@alignCast(context));
|
||||||
|
self.mutex.lock();
|
||||||
|
defer self.mutex.unlock();
|
||||||
|
if (self.arena.queryCapacity() >= self.bound)
|
||||||
|
return false;
|
||||||
|
return self.arena.allocator().rawResize(ptr, alignment, new_len, ret_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remap(context: *anyopaque, ptr: []u8, alignment: Alignment, new_len: usize, ret_addr: usize) ?[*]u8 {
|
||||||
|
const self: *Self = @ptrCast(@alignCast(context));
|
||||||
|
self.mutex.lock();
|
||||||
|
defer self.mutex.unlock();
|
||||||
|
if (self.arena.queryCapacity() >= self.bound)
|
||||||
|
return null;
|
||||||
|
return self.arena.allocator().rawRemap(ptr, alignment, new_len, ret_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn free(context: *anyopaque, ptr: []u8, alignment: Alignment, ret_addr: usize) void {
|
||||||
|
const self: *Self = @ptrCast(@alignCast(context));
|
||||||
|
self.mutex.lock();
|
||||||
|
defer self.mutex.unlock();
|
||||||
|
return self.arena.allocator().rawFree(ptr, alignment, ret_addr);
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ const spv = @import("spv");
|
|||||||
pub const F32x4 = zm.F32x4;
|
pub const F32x4 = zm.F32x4;
|
||||||
|
|
||||||
const PipelineState = @import("Device.zig").PipelineState;
|
const PipelineState = @import("Device.zig").PipelineState;
|
||||||
|
const BoundedArenaAllocator = @import("BoundedArenaAllocator.zig");
|
||||||
|
|
||||||
const SoftBuffer = @import("../SoftBuffer.zig");
|
const SoftBuffer = @import("../SoftBuffer.zig");
|
||||||
const SoftDescriptorSet = @import("../SoftDescriptorSet.zig");
|
const SoftDescriptorSet = @import("../SoftDescriptorSet.zig");
|
||||||
@@ -26,6 +27,8 @@ const VkError = base.VkError;
|
|||||||
|
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
|
const @"1GiB" = 1_073_741_824;
|
||||||
|
|
||||||
pub const VertexBuffer = struct {
|
pub const VertexBuffer = struct {
|
||||||
buffer: *const SoftBuffer,
|
buffer: *const SoftBuffer,
|
||||||
offset: usize,
|
offset: usize,
|
||||||
@@ -100,7 +103,7 @@ pub fn init(device: *SoftDevice, state: *PipelineState) Self {
|
|||||||
pub fn draw(self: *Self, vertex_count: usize, instance_count: usize, first_vertex: usize, first_instance: usize) VkError!void {
|
pub fn draw(self: *Self, vertex_count: usize, instance_count: usize, first_vertex: usize, first_instance: usize) VkError!void {
|
||||||
const io = self.device.interface.io();
|
const io = self.device.interface.io();
|
||||||
|
|
||||||
var arena: std.heap.ArenaAllocator = .init(self.device.device_allocator.allocator());
|
var arena: BoundedArenaAllocator = .init(self.device.device_allocator.allocator(), @"1GiB");
|
||||||
defer arena.deinit();
|
defer arena.deinit();
|
||||||
const allocator = arena.allocator();
|
const allocator = arena.allocator();
|
||||||
|
|
||||||
@@ -131,7 +134,7 @@ pub fn draw(self: *Self, vertex_count: usize, instance_count: usize, first_verte
|
|||||||
pub fn drawIndexed(self: *Self, index_count: usize, instance_count: usize, first_index: usize, first_instance: usize, vertex_offset: i32) VkError!void {
|
pub fn drawIndexed(self: *Self, index_count: usize, instance_count: usize, first_index: usize, first_instance: usize, vertex_offset: i32) VkError!void {
|
||||||
const io = self.device.interface.io();
|
const io = self.device.interface.io();
|
||||||
|
|
||||||
var arena: std.heap.ArenaAllocator = .init(self.device.device_allocator.allocator());
|
var arena: BoundedArenaAllocator = .init(self.device.device_allocator.allocator(), @"1GiB");
|
||||||
defer arena.deinit();
|
defer arena.deinit();
|
||||||
const allocator = arena.allocator();
|
const allocator = arena.allocator();
|
||||||
|
|
||||||
|
|||||||
@@ -583,7 +583,7 @@ pub fn readFloat4(map: []const u8, src_format: vk.Format) F32x4 {
|
|||||||
|
|
||||||
.s8_uint => c[0] = @floatFromInt(map[0]),
|
.s8_uint => c[0] = @floatFromInt(map[0]),
|
||||||
|
|
||||||
else => {}, //base.unsupported("Blitter: read float from source format {any}", .{src_format}),
|
else => base.unsupported("Blitter: read float from source format {any}", .{src_format}),
|
||||||
}
|
}
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
@@ -637,7 +637,7 @@ pub fn writeFloat4(color: F32x4, map: []u8, dst_format: vk.Format) void {
|
|||||||
|
|
||||||
.r32g32b32a32_sfloat => std.mem.bytesAsValue(F32x4, map).* = color,
|
.r32g32b32a32_sfloat => std.mem.bytesAsValue(F32x4, map).* = color,
|
||||||
|
|
||||||
else => {}, //base.unsupported("Blitter: write float to destination format {any}", .{dst_format}),
|
else => base.unsupported("Blitter: write float to destination format {any}", .{dst_format}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -678,7 +678,7 @@ pub fn readInt4(map: []const u8, src_format: vk.Format) U32x4 {
|
|||||||
.r32g32b32a32_uint,
|
.r32g32b32a32_uint,
|
||||||
=> c = std.mem.bytesToValue(U32x4, map),
|
=> c = std.mem.bytesToValue(U32x4, map),
|
||||||
|
|
||||||
else => {}, //base.unsupported("Blitter: read int from source format {any}", .{src_format}),
|
else => base.unsupported("Blitter: read int from source format {any}", .{src_format}),
|
||||||
}
|
}
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
@@ -720,6 +720,6 @@ pub fn writeInt4(color: U32x4, map: []u8, dst_format: vk.Format) void {
|
|||||||
.r32g32b32a32_uint,
|
.r32g32b32a32_uint,
|
||||||
=> std.mem.bytesAsValue(U32x4, map).* = color,
|
=> std.mem.bytesAsValue(U32x4, map).* = color,
|
||||||
|
|
||||||
else => {}, //base.unsupported("Blitter: write int to destination format {any}", .{dst_format}),
|
else => base.unsupported("Blitter: write int to destination format {any}", .{dst_format}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -167,8 +167,6 @@ pub fn drawTriangleFilled(allocator: std.mem.Allocator, fragments: *std.ArrayLis
|
|||||||
.color = zm.f32x4(1.0, 1.0, 1.0, 1.0),
|
.color = zm.f32x4(1.0, 1.0, 1.0, 1.0),
|
||||||
.inputs = try interpolateVertexOutputs(allocator, v0, v1, v2, b0, b1, b2),
|
.inputs = try interpolateVertexOutputs(allocator, v0, v1, v2, b0, b1, b2),
|
||||||
}) catch return VkError.OutOfDeviceMemory;
|
}) catch return VkError.OutOfDeviceMemory;
|
||||||
if (fragments.items.len > 64_000)
|
|
||||||
return VkError.MemoryFootprintTooBigDrv;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
//! Atomic based spin mutex
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
mutex: std.atomic.Mutex = .unlocked,
|
||||||
|
|
||||||
|
pub fn lock(self: *@This()) void {
|
||||||
|
if (self.mutex.tryLock()) {
|
||||||
|
@branchHint(.likely);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (self.mutex.tryLock()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unlock(self: *@This()) void {
|
||||||
|
self.mutex.unlock();
|
||||||
|
}
|
||||||
@@ -55,7 +55,6 @@ pub const VkError = error{
|
|||||||
InvalidHandleDrv,
|
InvalidHandleDrv,
|
||||||
InvalidPipelineDrv,
|
InvalidPipelineDrv,
|
||||||
InvalidDeviceMemoryDrv,
|
InvalidDeviceMemoryDrv,
|
||||||
MemoryFootprintTooBigDrv,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub inline fn errorLogger(err: VkError) void {
|
pub inline fn errorLogger(err: VkError) void {
|
||||||
|
|||||||
@@ -4,29 +4,9 @@ const builtin = @import("builtin");
|
|||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const Alignment = std.mem.Alignment;
|
const Alignment = std.mem.Alignment;
|
||||||
|
|
||||||
/// Atomic based spin mutex
|
const SpinMutex = @import("SpinMutex.zig");
|
||||||
const AtomicMutex = struct {
|
|
||||||
mutex: std.atomic.Mutex = .unlocked,
|
|
||||||
|
|
||||||
fn lock(self: *@This()) void {
|
var mutex: SpinMutex = .{};
|
||||||
if (self.mutex.tryLock()) {
|
|
||||||
@branchHint(.likely);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
if (self.mutex.tryLock()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unlock(self: *@This()) void {
|
|
||||||
self.mutex.unlock();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var mutex: AtomicMutex = .{};
|
|
||||||
var child_allocator: std.mem.Allocator = if (builtin.link_libc) std.heap.c_allocator else std.heap.smp_allocator;
|
var child_allocator: std.mem.Allocator = if (builtin.link_libc) std.heap.c_allocator else std.heap.smp_allocator;
|
||||||
|
|
||||||
pub const fallback_host_allocator: Allocator = .{
|
pub const fallback_host_allocator: Allocator = .{
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ pub const NonDispatchable = @import("NonDispatchable.zig").NonDispatchable;
|
|||||||
pub const VkError = errors.VkError;
|
pub const VkError = errors.VkError;
|
||||||
pub const VulkanAllocator = @import("VulkanAllocator.zig");
|
pub const VulkanAllocator = @import("VulkanAllocator.zig");
|
||||||
pub const RefCounter = @import("RefCounter.zig");
|
pub const RefCounter = @import("RefCounter.zig");
|
||||||
|
pub const SpinMutex = @import("SpinMutex.zig");
|
||||||
|
|
||||||
pub const CommandBuffer = @import("CommandBuffer.zig");
|
pub const CommandBuffer = @import("CommandBuffer.zig");
|
||||||
pub const Device = @import("Device.zig");
|
pub const Device = @import("Device.zig");
|
||||||
|
|||||||
Reference in New Issue
Block a user