From ea6260a6380a5e53884dd4b89ae7dda84c6ad833 Mon Sep 17 00:00:00 2001 From: Kbz-8 Date: Sun, 23 Nov 2025 22:00:24 +0100 Subject: [PATCH] adding image to png export to C test --- .gitignore | 1 + build.zig | 2 ++ build.zig.zon | 4 +++ src/soft/Executor.zig | 26 ++++++++++++-- src/soft/SoftBuffer.zig | 2 +- src/soft/SoftCommandBuffer.zig | 19 ++++++++++ src/soft/SoftImage.zig | 2 +- src/soft/lib.zig | 4 ++- src/vulkan/CommandBuffer.zig | 50 ++++++++++++++++++++------- src/vulkan/Image.zig | 32 ++++++++++++----- src/vulkan/commands.zig | 59 +++++++++++++++++-------------- src/vulkan/lib.zig | 3 ++ src/vulkan/lib_vulkan.zig | 37 ++++++++++++++++++++ src/vulkan/logger.zig | 25 +++++++++++--- test/c/main.c | 63 +++++++++++++++++++--------------- 15 files changed, 247 insertions(+), 82 deletions(-) diff --git a/.gitignore b/.gitignore index 4b12691..3afd3a3 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ zig-out/ *.o .gdb_history *.json +*.png diff --git a/build.zig b/build.zig index e37a132..22920d4 100644 --- a/build.zig +++ b/build.zig @@ -92,6 +92,7 @@ pub fn build(b: *std.Build) !void { const volk = b.lazyDependency("volk", .{}) orelse continue; const kvf = b.lazyDependency("kvf", .{}) orelse continue; + const stb = b.lazyDependency("stb", .{}) orelse continue; const c_test_exe = b.addExecutable(.{ .name = b.fmt("c_test_vulkan_{s}", .{impl.name}), @@ -104,6 +105,7 @@ pub fn build(b: *std.Build) !void { c_test_exe.root_module.addSystemIncludePath(volk.path("")); c_test_exe.root_module.addSystemIncludePath(kvf.path("")); + c_test_exe.root_module.addSystemIncludePath(stb.path("")); c_test_exe.root_module.addSystemIncludePath(vulkan_headers.path("include")); c_test_exe.root_module.addCSourceFile(.{ diff --git a/build.zig.zon b/build.zig.zon index f9fc355..a527b3d 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -40,6 +40,10 @@ .hash = "N-V-__8AAEGKAgC2cGDnxmAIFKkaICxS_ogfVYWH83Re29zN", .lazy = true, }, + .stb = .{ + .url = "git+https://github.com/nothings/stb#f1c79c02822848a9bed4315b12c8c8f3761e1296", + .hash = "N-V-__8AABQ7TgCnPlp8MP4YA8znrjd6E-ZjpF1rvrS8J_2I", + }, }, .paths = .{ diff --git a/src/soft/Executor.zig b/src/soft/Executor.zig index 589753c..a1642b9 100644 --- a/src/soft/Executor.zig +++ b/src/soft/Executor.zig @@ -18,12 +18,31 @@ pub fn deinit(self: *Self) void { pub fn dispatch(self: *Self, command: *const cmd.Command) VkError!void { _ = self; switch (command.*) { + .ClearColorImage => |data| try clearColorImage(&data), .CopyBuffer => |data| try copyBuffer(&data), + .CopyImage => |data| try copyImage(&data), .FillBuffer => |data| try fillBuffer(&data), else => {}, } } +fn clearColorImage(data: *const cmd.CommandClearColorImage) VkError!void { + // TODO: use a blitter + + const image = data.image; + for (data.ranges) |range| { + const image_size = image.getTotalSize(); + + const memory = if (image.memory) |memory| memory else return VkError.ValidationFailed; + var memory_map: []u32 = @as([*]u32, @ptrCast(@alignCast(try memory.map(0, image_size))))[0..image_size]; + + _ = range; + _ = &memory_map; + + memory.unmap(); + } +} + fn copyBuffer(data: *const cmd.CommandCopyBuffer) VkError!void { for (data.regions) |region| { const src_memory = if (data.src.memory) |memory| memory else return VkError.ValidationFailed; @@ -39,10 +58,13 @@ fn copyBuffer(data: *const cmd.CommandCopyBuffer) VkError!void { } } +fn copyImage(data: *const cmd.CommandCopyImage) VkError!void { + _ = data; +} + fn fillBuffer(data: *const cmd.CommandFillBuffer) VkError!void { const memory = if (data.buffer.memory) |memory| memory else return VkError.ValidationFailed; - const raw_memory_map: [*]u32 = @ptrCast(@alignCast(try memory.map(data.offset, data.size))); - var memory_map: []u32 = raw_memory_map[0..data.size]; + var memory_map: []u32 = @as([*]u32, @ptrCast(@alignCast(try memory.map(data.offset, data.size))))[0..data.size]; for (0..@divExact(data.size, @sizeOf(u32))) |i| { memory_map[i] = data.data; diff --git a/src/soft/SoftBuffer.zig b/src/soft/SoftBuffer.zig index ecddef4..cc5202e 100644 --- a/src/soft/SoftBuffer.zig +++ b/src/soft/SoftBuffer.zig @@ -35,7 +35,7 @@ pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void { } pub fn getMemoryRequirements(interface: *Interface, requirements: *vk.MemoryRequirements) void { - requirements.alignment = lib.MEMORY_REQUIREMENTS_ALIGNMENT; + requirements.alignment = lib.MEMORY_REQUIREMENTS_BUFFER_ALIGNMENT; if (interface.usage.uniform_texel_buffer_bit or interface.usage.uniform_texel_buffer_bit) { requirements.alignment = @max(requirements.alignment, lib.MIN_TEXEL_BUFFER_ALIGNMENT); } diff --git a/src/soft/SoftCommandBuffer.zig b/src/soft/SoftCommandBuffer.zig index dd44a93..01dfff3 100644 --- a/src/soft/SoftCommandBuffer.zig +++ b/src/soft/SoftCommandBuffer.zig @@ -22,7 +22,9 @@ pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const v interface.dispatch_table = &.{ .begin = begin, + .clearColorImage = clearColorImage, .copyBuffer = copyBuffer, + .copyImage = copyImage, .end = end, .fillBuffer = fillBuffer, .reset = reset, @@ -58,6 +60,15 @@ pub fn reset(interface: *Interface, flags: vk.CommandBufferResetFlags) VkError!v // Commands ==================================================================================================== +pub fn clearColorImage(interface: *Interface, image: *base.Image, layout: vk.ImageLayout, color: *const vk.ClearColorValue, ranges: []const vk.ImageSubresourceRange) VkError!void { + // No-op + _ = interface; + _ = image; + _ = layout; + _ = color; + _ = ranges; +} + pub fn fillBuffer(interface: *Interface, buffer: *base.Buffer, offset: vk.DeviceSize, size: vk.DeviceSize, data: u32) VkError!void { // No-op _ = interface; @@ -74,3 +85,11 @@ pub fn copyBuffer(interface: *Interface, src: *base.Buffer, dst: *base.Buffer, r _ = dst; _ = regions; } + +pub fn copyImage(interface: *Interface, src: *base.Image, dst: *base.Image, regions: []const vk.ImageCopy) VkError!void { + // No-op + _ = interface; + _ = src; + _ = dst; + _ = regions; +} diff --git a/src/soft/SoftImage.zig b/src/soft/SoftImage.zig index 8ca46b7..c092999 100644 --- a/src/soft/SoftImage.zig +++ b/src/soft/SoftImage.zig @@ -36,5 +36,5 @@ pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void { pub fn getMemoryRequirements(interface: *Interface, requirements: *vk.MemoryRequirements) void { _ = interface; - requirements.alignment = lib.MEMORY_REQUIREMENTS_ALIGNMENT; + requirements.alignment = lib.MEMORY_REQUIREMENTS_IMAGE_ALIGNMENT; } diff --git a/src/soft/lib.zig b/src/soft/lib.zig index f8a844b..c26c624 100644 --- a/src/soft/lib.zig +++ b/src/soft/lib.zig @@ -29,7 +29,9 @@ pub const DEVICE_ID = 0x600DCAFE; pub const MEMORY_TYPE_GENERIC_BIT = 0; /// 16 bytes for 128-bit vector types. -pub const MEMORY_REQUIREMENTS_ALIGNMENT = 16; +pub const MEMORY_REQUIREMENTS_BUFFER_ALIGNMENT = 16; + +pub const MEMORY_REQUIREMENTS_IMAGE_ALIGNMENT = 256; /// Vulkan 1.2 requires buffer offset alignment to be at most 256. pub const MIN_TEXEL_BUFFER_ALIGNMENT = 256; diff --git a/src/vulkan/CommandBuffer.zig b/src/vulkan/CommandBuffer.zig index 9ca19ba..25c648e 100644 --- a/src/vulkan/CommandBuffer.zig +++ b/src/vulkan/CommandBuffer.zig @@ -11,6 +11,7 @@ const Device = @import("Device.zig"); const Buffer = @import("Buffer.zig"); const CommandPool = @import("CommandPool.zig"); +const Image = @import("Image.zig"); const COMMAND_BUFFER_BASE_CAPACITY = 256; @@ -38,7 +39,9 @@ dispatch_table: *const DispatchTable, pub const DispatchTable = struct { begin: *const fn (*Self, *const vk.CommandBufferBeginInfo) VkError!void, + clearColorImage: *const fn (*Self, *Image, vk.ImageLayout, *const vk.ClearColorValue, []const vk.ImageSubresourceRange) VkError!void, copyBuffer: *const fn (*Self, *Buffer, *Buffer, []const vk.BufferCopy) VkError!void, + copyImage: *const fn (*Self, *Image, *Image, []const vk.ImageCopy) VkError!void, end: *const fn (*Self) VkError!void, fillBuffer: *const fn (*Self, *Buffer, vk.DeviceSize, vk.DeviceSize, u32) VkError!void, reset: *const fn (*Self, vk.CommandBufferResetFlags) VkError!void, @@ -54,7 +57,7 @@ pub fn init(device: *Device, allocator: std.mem.Allocator, info: *const vk.Comma .pool = try NonDispatchable(CommandPool).fromHandleObject(info.command_pool), .state = .Initial, .begin_info = null, - .host_allocator = VulkanAllocator.from(allocator).clone(), + .host_allocator = VulkanAllocator.from(allocator).cloneWithScope(.object), .commands = std.ArrayList(cmd.Command).initCapacity(allocator, COMMAND_BUFFER_BASE_CAPACITY) catch return VkError.OutOfHostMemory, .state_mutex = .{}, .vtable = undefined, @@ -113,9 +116,11 @@ pub inline fn submit(self: *Self) VkError!void { fn cleanCommandList(self: *Self) void { const allocator = self.host_allocator.allocator(); - _ = allocator; for (self.commands.items) |command| { switch (command) { + .ClearColorImage => |data| allocator.free(data.ranges), + .CopyBuffer => |data| allocator.free(data.regions), + .CopyImage => |data| allocator.free(data.regions), else => {}, } } @@ -123,6 +128,37 @@ fn cleanCommandList(self: *Self) void { // Commands ==================================================================================================== +pub inline fn clearColorImage(self: *Self, image: *Image, layout: vk.ImageLayout, color: *const vk.ClearColorValue, ranges: []const vk.ImageSubresourceRange) VkError!void { + const allocator = self.host_allocator.allocator(); + self.commands.append(allocator, .{ .ClearColorImage = .{ + .image = image, + .layout = layout, + .clear_color = color.*, + .ranges = allocator.dupe(vk.ImageSubresourceRange, ranges) catch return VkError.OutOfHostMemory, + } }) catch return VkError.OutOfHostMemory; + try self.dispatch_table.clearColorImage(self, image, layout, color, ranges); +} + +pub inline fn copyBuffer(self: *Self, src: *Buffer, dst: *Buffer, regions: []const vk.BufferCopy) VkError!void { + const allocator = self.host_allocator.allocator(); + self.commands.append(allocator, .{ .CopyBuffer = .{ + .src = src, + .dst = dst, + .regions = allocator.dupe(vk.BufferCopy, regions) catch return VkError.OutOfHostMemory, + } }) catch return VkError.OutOfHostMemory; + try self.dispatch_table.copyBuffer(self, src, dst, regions); +} + +pub inline fn copyImage(self: *Self, src: *Image, dst: *Image, regions: []const vk.ImageCopy) VkError!void { + const allocator = self.host_allocator.allocator(); + self.commands.append(allocator, .{ .CopyImage = .{ + .src = src, + .dst = dst, + .regions = allocator.dupe(vk.ImageCopy, regions) catch return VkError.OutOfHostMemory, + } }) catch return VkError.OutOfHostMemory; + try self.dispatch_table.copyImage(self, src, dst, regions); +} + pub inline fn fillBuffer(self: *Self, buffer: *Buffer, offset: vk.DeviceSize, size: vk.DeviceSize, data: u32) VkError!void { const allocator = self.host_allocator.allocator(); self.commands.append(allocator, .{ .FillBuffer = .{ @@ -133,13 +169,3 @@ pub inline fn fillBuffer(self: *Self, buffer: *Buffer, offset: vk.DeviceSize, si } }) catch return VkError.OutOfHostMemory; try self.dispatch_table.fillBuffer(self, buffer, offset, size, data); } - -pub inline fn copyBuffer(self: *Self, src: *Buffer, dst: *Buffer, regions: []const vk.BufferCopy) VkError!void { - const allocator = self.host_allocator.allocator(); - self.commands.append(allocator, .{ .CopyBuffer = .{ - .src = src, - .dst = dst, - .regions = regions, - } }) catch return VkError.OutOfHostMemory; - try self.dispatch_table.copyBuffer(self, src, dst, regions); -} diff --git a/src/vulkan/Image.zig b/src/vulkan/Image.zig index fa1c690..44ada1d 100644 --- a/src/vulkan/Image.zig +++ b/src/vulkan/Image.zig @@ -1,8 +1,6 @@ const std = @import("std"); const vk = @import("vulkan"); -const vku = @cImport({ - @cInclude("vulkan/utility/vk_format_utils.h"); -}); +const lib = @import("lib.zig"); const VkError = @import("error_set.zig").VkError; const DeviceMemory = @import("DeviceMemory.zig"); @@ -55,17 +53,35 @@ pub inline fn destroy(self: *Self, allocator: std.mem.Allocator) void { } pub inline fn bindMemory(self: *Self, memory: *DeviceMemory, offset: vk.DeviceSize) VkError!void { - if (offset >= self.size or !self.allowed_memory_types.isSet(memory.memory_type_index)) { + const image_size = self.getTotalSize(); + if (offset >= image_size or !self.allowed_memory_types.isSet(memory.memory_type_index)) { return VkError.ValidationFailed; } self.memory = memory; - self.offset = offset; + self.memory_offset = offset; } pub inline fn getMemoryRequirements(self: *Self, requirements: *vk.MemoryRequirements) void { - const pixel_size = vku.vkuFormatTexelBlockSize(@intCast(@intFromEnum(self.format))); - - requirements.size = self.extent.width * self.extent.height * self.extent.depth * pixel_size; + const image_size = self.getTotalSize(); + requirements.size = image_size; requirements.memory_type_bits = self.allowed_memory_types.mask; self.vtable.getMemoryRequirements(self, requirements); } + +pub inline fn getClearFormat(self: *Self) vk.Format { + return if (lib.vku.vkuFormatIsSINT(@intCast(@intFromEnum(self.format)))) + .r32g32b32a32_sint + else if (lib.vku.vkuFormatIsUINT(@intCast(@intFromEnum(self.format)))) + .r32g32b32a32_uint + else + .r32g32b32a32_sfloat; +} + +pub inline fn getPixelSize(self: *Self) usize { + return lib.vku.vkuFormatTexelBlockSize(@intCast(@intFromEnum(self.format))); +} + +pub inline fn getTotalSize(self: *Self) usize { + const pixel_size = self.getPixelSize(); + return self.extent.width * self.extent.height * self.extent.depth * pixel_size; +} diff --git a/src/vulkan/commands.zig b/src/vulkan/commands.zig index f34e4ae..2366744 100644 --- a/src/vulkan/commands.zig +++ b/src/vulkan/commands.zig @@ -2,11 +2,14 @@ const std = @import("std"); const vk = @import("vulkan"); const Buffer = @import("Buffer.zig"); +const Image = @import("Image.zig"); pub const CommandType = enum { BindPipeline, BindVertexBuffer, + ClearColorImage, CopyBuffer, + CopyImage, Draw, DrawIndexed, DrawIndexedIndirect, @@ -14,32 +17,36 @@ pub const CommandType = enum { FillBuffer, }; -pub const CommandCopyBuffer = struct { - src: *Buffer, - dst: *Buffer, - regions: []const vk.BufferCopy, +pub const CommandBindPipeline = struct { + bind_point: vk.PipelineBindPoint, }; - -pub const CommandFillBuffer = struct { - buffer: *Buffer, - offset: vk.DeviceSize, - size: vk.DeviceSize, - data: u32, -}; - pub const CommandBindVertexBuffer = struct { buffers: []*const Buffer, offsets: []vk.DeviceSize, first_binding: u32, }; - +pub const CommandClearColorImage = struct { + image: *Image, + layout: vk.ImageLayout, + clear_color: vk.ClearColorValue, + ranges: []const vk.ImageSubresourceRange, +}; +pub const CommandCopyBuffer = struct { + src: *Buffer, + dst: *Buffer, + regions: []const vk.BufferCopy, +}; +pub const CommandCopyImage = struct { + src: *Image, + dst: *Image, + regions: []const vk.ImageCopy, +}; pub const CommandDraw = struct { vertex_count: u32, instance_count: u32, first_vertex: u32, first_instance: u32, }; - pub const CommandDrawIndexed = struct { index_count: u32, instance_count: u32, @@ -47,29 +54,31 @@ pub const CommandDrawIndexed = struct { vertex_offset: i32, first_instance: u32, }; - -pub const CommandDrawIndirect = struct { - buffer: *Buffer, - offset: vk.DeviceSize, - count: u32, - stride: u32, -}; - pub const CommandDrawIndexedIndirect = struct { buffer: *Buffer, offset: vk.DeviceSize, count: u32, stride: u32, }; - -pub const CommandBindPipeline = struct { - bind_point: vk.PipelineBindPoint, +pub const CommandDrawIndirect = struct { + buffer: *Buffer, + offset: vk.DeviceSize, + count: u32, + stride: u32, +}; +pub const CommandFillBuffer = struct { + buffer: *Buffer, + offset: vk.DeviceSize, + size: vk.DeviceSize, + data: u32, }; pub const Command = union(CommandType) { BindPipeline: CommandBindPipeline, BindVertexBuffer: CommandBindVertexBuffer, + ClearColorImage: CommandClearColorImage, CopyBuffer: CommandCopyBuffer, + CopyImage: CommandCopyImage, Draw: CommandDraw, DrawIndexed: CommandDrawIndexed, DrawIndexedIndirect: CommandDrawIndexedIndirect, diff --git a/src/vulkan/lib.zig b/src/vulkan/lib.zig index 7384593..862a7e2 100644 --- a/src/vulkan/lib.zig +++ b/src/vulkan/lib.zig @@ -2,6 +2,9 @@ const std = @import("std"); const vk = @import("vulkan"); +pub const vku = @cImport({ + @cInclude("vulkan/utility/vk_format_utils.h"); +}); pub const commands = @import("commands.zig"); pub const lib_vulkan = @import("lib_vulkan.zig"); diff --git a/src/vulkan/lib_vulkan.zig b/src/vulkan/lib_vulkan.zig index ece4944..6a9247d 100644 --- a/src/vulkan/lib_vulkan.zig +++ b/src/vulkan/lib_vulkan.zig @@ -91,7 +91,10 @@ const device_pfn_map = std.StaticStringMap(vk.PfnVoidFunction).initComptime(.{ functionMapEntryPoint("vkAllocateMemory"), functionMapEntryPoint("vkBeginCommandBuffer"), functionMapEntryPoint("vkBindBufferMemory"), + functionMapEntryPoint("vkBindImageMemory"), + functionMapEntryPoint("vkCmdClearColorImage"), functionMapEntryPoint("vkCmdCopyBuffer"), + functionMapEntryPoint("vkCmdCopyImage"), functionMapEntryPoint("vkCmdFillBuffer"), functionMapEntryPoint("vkCreateCommandPool"), functionMapEntryPoint("vkCreateBuffer"), @@ -458,6 +461,21 @@ pub export fn strollBindBufferMemory(p_device: vk.Device, p_buffer: vk.Buffer, p return .success; } +pub export fn strollBindImageMemory(p_device: vk.Device, p_image: vk.Image, p_memory: vk.DeviceMemory, offset: vk.DeviceSize) callconv(vk.vulkan_call_conv) vk.Result { + entryPointBeginLogTrace(.vkBindImageMemory); + defer entryPointEndLogTrace(); + + std.log.scoped(.vkBindImageMemory).debug("Binding device memory 0x{X} to image 0x{X}", .{ @intFromEnum(p_memory), @intFromEnum(p_image) }); + + Dispatchable(Device).checkHandleValidity(p_device) catch |err| return toVkResult(err); + + const image = NonDispatchable(Image).fromHandleObject(p_image) catch |err| return toVkResult(err); + const memory = NonDispatchable(DeviceMemory).fromHandleObject(p_memory) catch |err| return toVkResult(err); + + image.bindMemory(memory, offset) catch |err| return toVkResult(err); + return .success; +} + pub export fn strollCreateBuffer(p_device: vk.Device, p_info: ?*const vk.BufferCreateInfo, callbacks: ?*const vk.AllocationCallbacks, p_buffer: *vk.Buffer) callconv(vk.vulkan_call_conv) vk.Result { entryPointBeginLogTrace(.vkCreateBuffer); defer entryPointEndLogTrace(); @@ -728,6 +746,15 @@ pub export fn strollBeginCommandBuffer(p_cmd: vk.CommandBuffer, p_info: ?*const return .success; } +pub export fn strollCmdClearColorImage(p_cmd: vk.CommandBuffer, p_image: vk.Image, layout: vk.ImageLayout, color: *const vk.ClearColorValue, count: u32, ranges: [*]const vk.ImageSubresourceRange) callconv(vk.vulkan_call_conv) void { + entryPointBeginLogTrace(.vkCmdCopyImage); + defer entryPointEndLogTrace(); + + const cmd = Dispatchable(CommandBuffer).fromHandleObject(p_cmd) catch |err| return errorLogger(err); + const image = NonDispatchable(Image).fromHandleObject(p_image) catch |err| return errorLogger(err); + cmd.clearColorImage(image, layout, color, ranges[0..count]) catch |err| return errorLogger(err); +} + pub export fn strollCmdCopyBuffer(p_cmd: vk.CommandBuffer, p_src: vk.Buffer, p_dst: vk.Buffer, count: u32, regions: [*]const vk.BufferCopy) callconv(vk.vulkan_call_conv) void { entryPointBeginLogTrace(.vkCmdCopyBuffer); defer entryPointEndLogTrace(); @@ -738,6 +765,16 @@ pub export fn strollCmdCopyBuffer(p_cmd: vk.CommandBuffer, p_src: vk.Buffer, p_d cmd.copyBuffer(src, dst, regions[0..count]) catch |err| return errorLogger(err); } +pub export fn strollCmdCopyImage(p_cmd: vk.CommandBuffer, p_src: vk.Image, p_dst: vk.Image, count: u32, regions: [*]const vk.ImageCopy) callconv(vk.vulkan_call_conv) void { + entryPointBeginLogTrace(.vkCmdCopyImage); + defer entryPointEndLogTrace(); + + const cmd = Dispatchable(CommandBuffer).fromHandleObject(p_cmd) catch |err| return errorLogger(err); + const src = NonDispatchable(Image).fromHandleObject(p_src) catch |err| return errorLogger(err); + const dst = NonDispatchable(Image).fromHandleObject(p_dst) catch |err| return errorLogger(err); + cmd.copyImage(src, dst, regions[0..count]) catch |err| return errorLogger(err); +} + pub export fn strollCmdFillBuffer(p_cmd: vk.CommandBuffer, p_buffer: vk.Buffer, offset: vk.DeviceSize, size: vk.DeviceSize, data: u32) callconv(vk.vulkan_call_conv) void { entryPointBeginLogTrace(.vkCmdFillBuffer); defer entryPointEndLogTrace(); diff --git a/src/vulkan/logger.zig b/src/vulkan/logger.zig index b6be8c9..7f0c55e 100644 --- a/src/vulkan/logger.zig +++ b/src/vulkan/logger.zig @@ -18,6 +18,7 @@ comptime { const DebugStackElement = struct { log: [512]u8, indent_level: usize, + log_level: std.log.Level, }; var indent_level: usize = 0; @@ -73,9 +74,16 @@ pub fn log(comptime level: std.log.Level, comptime scope: @Type(.enum_literal), std.debug.lockStdErr(); defer std.debug.unlockStdErr(); - var buffer = std.mem.zeroes([512]u8); var stderr_file = std.fs.File.stderr(); - var out_config = std.Io.tty.Config.detect(stderr_file); + var stdout_file = std.fs.File.stdout(); + + const file = switch (level) { + .info, .debug => stdout_file, + .warn, .err => stderr_file, + }; + + var buffer = std.mem.zeroes([512]u8); + var out_config = std.Io.tty.Config.detect(file); var writer = std.Io.Writer.fixed(&buffer); var timezone = zdt.Timezone.tzLocal(std.heap.page_allocator) catch zdt.Timezone.UTC; @@ -111,12 +119,19 @@ pub fn log(comptime level: std.log.Level, comptime scope: @Type(.enum_literal), (debug_stack.addOne(std.heap.c_allocator) catch return).* = .{ .log = buffer, .indent_level = indent_level, + .log_level = level, }; } else { while (debug_stack.items.len != 0) { - const elem_buffer = debug_stack.orderedRemove(0).log; - _ = stderr_file.write(&elem_buffer) catch return; + const elem = debug_stack.orderedRemove(0); + switch (elem.log_level) { + .info, .debug => _ = stdout_file.write(&elem.log) catch {}, + .warn, .err => _ = stderr_file.write(&elem.log) catch {}, + } + } + switch (level) { + .info, .debug => _ = stdout_file.write(&buffer) catch {}, + .warn, .err => _ = stderr_file.write(&buffer) catch {}, } - _ = stderr_file.write(&buffer) catch return; } } diff --git a/test/c/main.c b/test/c/main.c index a5f48c9..fc17a8c 100644 --- a/test/c/main.c +++ b/test/c/main.c @@ -20,19 +20,35 @@ #define KVF_NO_KHR #include -void CreateAndBindMemoryToBuffer(VkPhysicalDevice physical_device, VkDevice device, VkBuffer buffer, VkDeviceMemory* memory , VkDeviceSize size, VkMemoryPropertyFlags props) +#define STB_IMAGE_WRITE_IMPLEMENTATION +#include + +void CreateAndBindMemoryToBuffer(VkPhysicalDevice physical_device, VkDevice device, VkBuffer buffer, VkDeviceMemory* memory, VkMemoryPropertyFlags props) { VkMemoryRequirements requirements; vkGetBufferMemoryRequirements(device, buffer, &requirements); VkMemoryAllocateInfo alloc_info = {0}; alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - alloc_info.allocationSize = size; + alloc_info.allocationSize = requirements.size; alloc_info.memoryTypeIndex = kvfFindMemoryType(physical_device, requirements.memoryTypeBits, props); kvfCheckVk(vkAllocateMemory(device, &alloc_info, NULL, memory)); kvfCheckVk(vkBindBufferMemory(device, buffer, *memory, 0)); } +void CreateAndBindMemoryToImage(VkPhysicalDevice physical_device, VkDevice device, VkImage image, VkDeviceMemory* memory, VkMemoryPropertyFlags props) +{ + VkMemoryRequirements requirements; + vkGetImageMemoryRequirements(device, image, &requirements); + + VkMemoryAllocateInfo alloc_info = {0}; + alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + alloc_info.allocationSize = requirements.size; + alloc_info.memoryTypeIndex = kvfFindMemoryType(physical_device, requirements.memoryTypeBits, props); + kvfCheckVk(vkAllocateMemory(device, &alloc_info, NULL, memory)); + kvfCheckVk(vkBindImageMemory(device, image, *memory, 0)); +} + int main(void) { volkInitialize(); @@ -65,15 +81,9 @@ int main(void) VkDevice device = kvfCreateDevice(physical_device, NULL, 0, NULL); volkLoadDevice(device); - VkBuffer buffer = kvfCreateBuffer(device, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, 256); + VkImage image = kvfCreateImage(device, 256, 256, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_TILING_LINEAR, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, KVF_IMAGE_COLOR); VkDeviceMemory memory; - CreateAndBindMemoryToBuffer(physical_device, device, buffer, &memory, 256, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - - VkBuffer buffer2 = kvfCreateBuffer(device, VK_BUFFER_USAGE_TRANSFER_DST_BIT, 256); - VkDeviceMemory memory2; - CreateAndBindMemoryToBuffer(physical_device, device, buffer2, &memory2, 256, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); - - VkImage image = kvfCreateImage(device, 256, 256, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_TILING_LINEAR, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, KVF_IMAGE_COLOR); + CreateAndBindMemoryToImage(physical_device, device, image, &memory, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); VkQueue queue = kvfGetDeviceQueue(device, KVF_GRAPHICS_QUEUE); VkFence fence = kvfCreateFence(device); @@ -83,33 +93,32 @@ int main(void) kvfBeginCommandBuffer(cmd, 0); { - vkCmdFillBuffer(cmd, buffer, 0, VK_WHOLE_SIZE, 0x600DCAFE); - - VkBufferCopy region = {0}; - region.srcOffset = 0; - region.dstOffset = 0; - region.size = 256; - vkCmdCopyBuffer(cmd, buffer, buffer2, 1, ®ion); + VkClearColorValue color = {0}; + color.uint32[0] = 0xFF; + color.uint32[1] = 0x00; + color.uint32[2] = 0x00; + color.uint32[3] = 0xFF; + VkImageSubresourceRange range = {0}; + range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + range.levelCount = 1; + range.layerCount = 1; + vkCmdClearColorImage(cmd, image, VK_IMAGE_LAYOUT_GENERAL, &color, 1, &range); } kvfEndCommandBuffer(cmd); kvfSubmitCommandBuffer(device, cmd, KVF_GRAPHICS_QUEUE, VK_NULL_HANDLE, VK_NULL_HANDLE, fence, NULL); kvfWaitForFence(device, fence); - uint32_t* map = NULL; - kvfCheckVk(vkMapMemory(device, memory2, 0, VK_WHOLE_SIZE, 0, (void**)&map)); - for(size_t i = 0; i < 64; i++) - printf("0x%X ", map[i]); - puts(""); - vkUnmapMemory(device, memory2); + void* map = NULL; + kvfCheckVk(vkMapMemory(device, memory, 0, VK_WHOLE_SIZE, 0, &map)); + if(!stbi_write_png("res.png", 256, 256, 4, map, 256 * 4)) + fprintf(stderr, "Failed to write result image to file\n"); + vkUnmapMemory(device, memory); kvfDestroyFence(device, fence); - kvfDestroyBuffer(device, buffer); - vkFreeMemory(device, memory, NULL); - kvfDestroyBuffer(device, buffer2); - vkFreeMemory(device, memory2, NULL); kvfDestroyImage(device, image); + vkFreeMemory(device, memory, NULL); kvfDestroyDevice(device); kvfDestroyInstance(instance);