adding image to png export to C test

This commit is contained in:
2025-11-23 22:00:24 +01:00
parent 823f058612
commit ea6260a638
15 changed files with 247 additions and 82 deletions

1
.gitignore vendored
View File

@@ -4,3 +4,4 @@ zig-out/
*.o
.gdb_history
*.json
*.png

View File

@@ -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(.{

View File

@@ -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 = .{

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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,

View File

@@ -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");

View File

@@ -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();

View File

@@ -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;
}
}

View File

@@ -20,19 +20,35 @@
#define KVF_NO_KHR
#include <kvf.h>
void CreateAndBindMemoryToBuffer(VkPhysicalDevice physical_device, VkDevice device, VkBuffer buffer, VkDeviceMemory* memory , VkDeviceSize size, VkMemoryPropertyFlags props)
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include <stb_image_write.h>
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, &region);
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);