starting work on being able to load assets into vulkan

This commit is contained in:
matthew 2025-07-14 08:29:22 +10:00
parent 82df45e488
commit 0e03058714
4 changed files with 273 additions and 75 deletions

View File

@ -4,6 +4,13 @@ import aliases;
import core.memory;
import p = platform;
import r = renderer;
import util;
import core.simd;
struct Floats
{
f32 r = 0.0, g = 0.0, b = 0.0, a = 0.0;
}
void main()
{

View File

@ -2,13 +2,15 @@ import aliases;
import includes;
import assets;
import util;
import ap = assets;
import vk = vulkan;
import alloc;
import vulkan;
import vulkan : Destroy, Init, Draw, DrawIndexed, Bind, BindUIBuffers, BeginRender, SetUniform, PrepCompute, Dispatch, FinishFrame, BeginFrame;
import assets;
import u = util;
import p = platform;
alias Shader = VkShaderModule;
alias Pipeline = vk.PipelineHandle;
alias Pipeline = PipelineHandle;
alias Attribute = VkVertexInputAttributeDescription;
alias Buffer = VkBuffer;
@ -62,7 +64,10 @@ struct GfxPipelineInfo
struct Renderer
{
vk.Vulkan vulkan;
Arena arena;
Arena temp_arena;
Vulkan vk;
p.Window* window;
GlobalUniforms globals;
@ -113,19 +118,29 @@ struct Model
Buffer vertex_buffer;
Buffer index_buffer;
MeshPart[] parts;
string name;
Buffer[] materials;
u32[] m_indices;
ImageView[] textures;
u32[] t_indices;
}
Renderer
Init(p.Window* window)
{
u.Result!(vk.Vulkan) vk_result = vk.Init(window, u.MB(24), u.MB(32));
u.Result!(Vulkan) vk_result = Init(window, u.MB(24), u.MB(32));
assert(vk_result.ok, "Init failure: Unable to initialize Vulkan");
Renderer rd = {
vulkan: vk_result.value,
arena: CreateArena(u.MB(16)),
temp_arena: CreateArena(u.MB(16)),
vk: vk_result.value,
window: window,
ui_vertex_buf: vk.GetUIVertexBuffer(&vk_result.value),
ui_index_buf: vk.GetUIIndexBuffer(&vk_result.value),
ui_vertex_buf: GetUIVertexBuffer(&vk_result.value),
ui_index_buf: GetUIIndexBuffer(&vk_result.value),
};
GfxPipelineInfo triangle_info = {
@ -156,40 +171,112 @@ Init(p.Window* window)
bool
Cycle(Renderer* rd)
{
bool success = vk.BeginFrame(&rd.vulkan);
rd.ui_count = 0;
bool success = BeginFrame(rd);
if (success)
{
vk.Bind(&rd.vulkan, rd.compute_pipeline);
Bind(rd, &rd.compute_pipeline);
vk.SetUniform(&rd.vulkan, &rd.globals);
SetUniform(rd, &rd.globals);
DrawRect(rd, 150.0, 300.0, 200.0, 350.0, Vec4(r: 0.0, g: 0.0, b: 1.0, a: 1.0));
DrawRect(rd, 150.0, 300.0, 500.0, 700.0, Vec4(r: 0.0, g: 0.0, b: 1.0, a: 1.0));
vk.PrepCompute(&rd.vulkan);
PrepCompute(rd);
vk.Dispatch(&rd.vulkan);
Dispatch(rd);
vk.BeginRender(&rd.vulkan);
BeginRender(rd);
vk.Bind(&rd.vulkan, rd.ui_pipeline);
Bind(rd, &rd.ui_pipeline);
vk.BindUIBuffers(&rd.vulkan);
BindUIBuffers(rd);
vk.DrawIndexed(&rd.vulkan, 6, rd.ui_count);
DrawIndexed(rd, 6, rd.ui_count);
vk.Bind(&rd.vulkan, rd.triangle_pipeline);
Bind(rd, &rd.triangle_pipeline);
vk.Draw(&rd.vulkan, 3, 1);
Draw(rd, 3, 1);
success = vk.FinishFrame(&rd.vulkan);
success = FinishFrame(rd);
}
return success;
}
Model
LoadModel(Renderer* rd, string name)
{
Model model = {
name: name,
};
u8[] data = LoadAssetData(&rd.temp_arena, name);
m3d_t* m3d = m3d_load(data.ptr, null, null, null);
return model;
}
bool
BeginFrame(Renderer* rd)
{
return BeginFrame(&rd.vk);
}
bool
FinishFrame(Renderer* rd)
{
return FinishFrame(&rd.vk);
}
void
Dispatch(Renderer* rd)
{
Dispatch(&rd.vk);
}
void
PrepCompute(Renderer* rd)
{
PrepCompute(&rd.vk);
}
void
SetUniform(Renderer* rd, GlobalUniforms* uniforms)
{
SetUniform(&rd.vk, uniforms);
}
void
BeginRender(Renderer* rd)
{
BeginRender(&rd.vk);
}
void
BindUIBuffers(Renderer* rd)
{
BindUIBuffers(&rd.vk);
}
void
DrawIndexed(Renderer* rd, u32 index_count, u32 instance_count)
{
DrawIndexed(&rd.vk, index_count, instance_count);
}
void
Draw(Renderer* rd, u32 index_count, u32 instance_count)
{
Draw(&rd.vk, index_count, instance_count);
}
void Bind(Renderer* rd, Pipeline* pipeline)
{
Bind(&rd.vk, pipeline);
}
void
DrawRect(Renderer* rd, f32 p0_x, f32 p0_y, f32 p1_x, f32 p1_y, Vec4 col)
{
@ -214,21 +301,21 @@ DrawRect(Renderer* rd, f32 p0_x, f32 p0_y, f32 p1_x, f32 p1_y, Vec4 col)
Pipeline
BuildGfxPipeline(Renderer* rd, GfxPipelineInfo* info)
{
return vk.CreateGraphicsPipeline(&rd.vulkan, info);
return CreateGraphicsPipeline(&rd.vk, info);
}
Pipeline
BuildCompPipeline(Renderer* rd, string compute)
{
return vk.CreateComputePipeline(&rd.vulkan, compute);
return CreateComputePipeline(&rd.vk, compute);
}
void
Destroy(Renderer* rd)
{
vk.Destroy(&rd.vulkan, rd.triangle_pipeline);
vk.Destroy(&rd.vulkan, rd.compute_pipeline);
vk.Destroy(&rd.vulkan);
Destroy(&rd.vk, rd.triangle_pipeline);
Destroy(&rd.vk, rd.compute_pipeline);
Destroy(&rd.vk);
}

View File

@ -6,7 +6,7 @@ import std.algorithm.comparison;
import core.stdc.string : strcmp;
import std.format : sformat;
import u = util : HashTable, Result, Logf, Log, MB;
import a = alloc;
import alloc;
import p = platform;
import ap = assets;
import renderer;
@ -134,8 +134,8 @@ struct DescBindings
struct Vulkan
{
a.Arena arena;
a.Arena[FRAME_OVERLAP] frame_arenas;
Arena arena;
Arena[FRAME_OVERLAP] frame_arenas;
u32 frame_index;
u32 semaphore_index;
@ -212,10 +212,10 @@ Init(p.Window* window, u64 permanent_mem, u64 frame_mem)
bool success = true;
Vulkan vk = {
arena: a.CreateArena(permanent_mem),
arena: CreateArena(permanent_mem),
frame_arenas: [
a.CreateArena(frame_mem),
a.CreateArena(frame_mem),
CreateArena(frame_mem),
CreateArena(frame_mem),
],
window: window,
};
@ -604,9 +604,82 @@ ImmSubmit(Vulkan* vk, void delegate() fn)
return success;
}
void
bool
TransferAssets(Vulkan* vk)
{
return true;
}
ImageView
CreateImageView(Vulkan* vk, u32 w, u32 h, u32 ch)
{
VmaAllocationCreateInfo alloc_info = {
usage: VMA_MEMORY_USAGE_GPU_ONLY,
requiredFlags: VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
};
VkImageCreateInfo image_info = {
sType: VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
imageType: VK_IMAGE_TYPE_2D,
mipLevels: 1,
arrayLayers: 1,
format: VK_FORMAT_R8G8B8A8_SRGB,
tiling: VK_IMAGE_TILING_OPTIMAL,
initialLayout: VK_IMAGE_LAYOUT_UNDEFINED,
usage: VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
samples: VK_SAMPLE_COUNT_1_BIT,
extent: {
width: w,
height: h,
depth: 1,
},
};
if (vk.gfx_index != vk.tfer_index)
{
image_info.sharingMode = VK_SHARING_MODE_CONCURRENT;
image_info.queueFamilyIndexCount = 2;
image_info.pQueueFamilyIndices = cast(const u32*)[vk.gfx_index, vk.tfer_index];
}
ImageView view = {
format: VK_IMAGE_LAYOUT_UNDEFINED,
};
VkResult result = vmaCreateImage(vk.vma, &image_info, &alloc_info, &view.image, *view.alloc, null);
// TODO: handle errors and realloc
assert(VkCheck("CreateImageView failure: vmaCreateImage error", result), "CreateImageView failure");
VkImageViewCreateInfo view_info = {
sType: VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
image: view.image,
viewType: VK_IMAGE_VIEW_TYPE_2D,
format: VK_FORMAT_R8G8B8A8_SRGB,
subresourceRange: {
aspectMask: VK_IMAGE_ASPECT_COLOR_BIT,
levelCount: 1,
layerCount: 1,
},
};
result = vkCreateImageView(vk.device, &view_info, null, &view.view);
// TODO: also handle here
assert(VkCheck("CreateImageView failure: vkCreateImageView error", result), "CreateImageView failure");
return view;
}
u32
Push(Vulkan* vk, ImageView* view)
{
}
bool
Transfer(Vulkan* vk, Buffer* buf, u8[] data)
{
bool success = true;
u64 copied = 0;
while(copied != data.length)
{
@ -627,15 +700,19 @@ Transfer(Vulkan* vk, Buffer* buf, u8[] data)
vkCmdCopyBuffer(vk.imm_cmd, vk.transfer_buf.buffer, buf.buffer, 1, &copy);
};
ImmSubmit(vk, fn);
success = ImmSubmit(vk, fn);
copied += copy_length;
}
return success;
}
void
bool
Transfer(Vulkan* vk, Image* image, u8[] data, u32 w, u32 h)
{
bool success = true;
u64 copied = 0;
while(copied != data.length)
{
@ -669,10 +746,12 @@ Transfer(Vulkan* vk, Image* image, u8[] data, u32 w, u32 h)
Transition(vk.imm_cmd, image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
};
ImmSubmit(vk, fn);
success = ImmSubmit(vk, fn);
copied += copy_length;
}
return success;
}
pragma(inline): void
@ -717,7 +796,7 @@ Copy(VkCommandBuffer cmd, VkImage src, VkImage dst, VkExtent2D src_ext, VkExtent
}
void
Bind(Vulkan* vk, PipelineHandle pipeline)
Bind(Vulkan* vk, PipelineHandle* pipeline)
{
vkCmdBindPipeline(vk.cmds[vk.frame_index], pipeline.type, pipeline.handle);
@ -907,14 +986,10 @@ CreateGraphicsPipeline(Vulkan* vk, GfxPipelineInfo* build_info)
},
];
u8[] vert_bytes = ap.LoadAssetData(build_info.vertex_shader);
u8[] frag_bytes = ap.LoadAssetData(build_info.frag_shader);
Arena* arena = &vk.frame_arenas[0];
scope(exit)
{
ap.UnloadAssetData(build_info.vertex_shader);
ap.UnloadAssetData(build_info.frag_shader);
}
u8[] vert_bytes = ap.LoadAssetData(arena, build_info.vertex_shader);
u8[] frag_bytes = ap.LoadAssetData(arena, build_info.frag_shader);
assert(vert_bytes && frag_bytes, "Unable to load shaders");
@ -969,9 +1044,8 @@ CreateComputePipeline(Vulkan* vk, string shader)
},
};
u8[] comp_bytes = ap.LoadAssetData(shader);
u8[] comp_bytes = ap.LoadAssetData(&vk.frame_arenas[0], shader);
assert(comp_bytes != null, "Unable to load compute shader data");
scope(exit) ap.UnloadAssetData(shader);
Result!(Shader) comp_module = BuildShader(vk, comp_bytes);
assert(comp_module.ok, "Unable to build compute shader");
@ -1221,7 +1295,7 @@ InitDescriptors(Vulkan* vk)
vk.desc_bindings[i].lookup_table = u.CreateHashTable!(string, u32)(8);
u32 DESC_MAX_BINDINGS = 512;
vk.desc_bindings[i].free = a.AllocArray!(u32)(&vk.arena, DESC_MAX_BINDINGS);
vk.desc_bindings[i].free = AllocArray!(u32)(&vk.arena, DESC_MAX_BINDINGS);
u32 free_count = 0;
for(i32 j = DESC_MAX_BINDINGS-1; j >= 0; j -= 1)
@ -1323,7 +1397,7 @@ InitFrameStructures(Vulkan* vk)
Push(vk, SI.FrameStructures);
bool success = true;
a.Arena* arena = &vk.frame_arenas[0];
Arena* arena = &vk.frame_arenas[0];
VkSemaphoreCreateInfo sem_info = { sType: VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO };
@ -1344,7 +1418,7 @@ InitFrameStructures(Vulkan* vk)
};
u32 sem_count = cast(u32)vk.present_images.length;
vk.submit_sems = a.AllocArray!(VkSemaphore)(arena, sem_count);
vk.submit_sems = AllocArray!(VkSemaphore)(arena, sem_count);
foreach(i; 0 .. sem_count)
{
@ -1537,16 +1611,16 @@ CreateDrawImages(Vulkan* vk)
void
SelectSwapchainFormats(Vulkan* vk)
{
a.Arena* arena = &vk.frame_arenas[0];
Arena* arena = &vk.frame_arenas[0];
u32 format_count;
vkGetPhysicalDeviceSurfaceFormatsKHR(vk.physical_device, vk.surface, &format_count, null);
VkSurfaceFormatKHR[] formats = a.AllocArray!(VkSurfaceFormatKHR)(arena, format_count);
VkSurfaceFormatKHR[] formats = AllocArray!(VkSurfaceFormatKHR)(arena, format_count);
vkGetPhysicalDeviceSurfaceFormatsKHR(vk.physical_device, vk.surface, &format_count, formats.ptr);
u32 mode_count;
vkGetPhysicalDeviceSurfacePresentModesKHR(vk.physical_device, vk.surface, &mode_count, null);
VkPresentModeKHR[] modes = a.AllocArray!(VkPresentModeKHR)(arena, mode_count);
VkPresentModeKHR[] modes = AllocArray!(VkPresentModeKHR)(arena, mode_count);
vkGetPhysicalDeviceSurfacePresentModesKHR(vk.physical_device, vk.surface, &mode_count, modes.ptr);
VkPresentModeKHR present_mode = VK_PRESENT_MODE_FIFO_KHR;
@ -1569,7 +1643,7 @@ CreateSwapchain(Vulkan* vk)
Push(vk, SI.Swapchain);
bool success = true;
a.Arena* arena = &vk.frame_arenas[0];
Arena* arena = &vk.frame_arenas[0];
VkSurfaceCapabilitiesKHR cap;
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vk.physical_device, vk.surface, &cap);
@ -1604,11 +1678,11 @@ CreateSwapchain(Vulkan* vk)
u32 count;
vkGetSwapchainImagesKHR(vk.device, vk.swapchain, &count, null);
VkImage[] images = a.AllocArray!(VkImage)(arena, count);
VkImage[] images = AllocArray!(VkImage)(arena, count);
vkGetSwapchainImagesKHR(vk.device, vk.swapchain, &count, images.ptr);
VkImageView[] views = a.AllocArray!(VkImageView)(arena, count);
VkImageView[] views = AllocArray!(VkImageView)(arena, count);
vk.present_images = a.AllocArray!(ImageView)(&vk.arena, count);
vk.present_images = AllocArray!(ImageView)(&vk.arena, count);
VkImageViewCreateInfo view_info = {
sType: VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
@ -1693,11 +1767,11 @@ InitDevice(Vulkan* vk)
Push(vk, SI.Device);
bool success = false;
a.Arena* arena = &vk.frame_arenas[0];
Arena* arena = &vk.frame_arenas[0];
u32 count;
vkEnumeratePhysicalDevices(vk.instance, &count, null);
VkPhysicalDevice[] devices = a.AllocArray!(VkPhysicalDevice)(arena, count);
VkPhysicalDevice[] devices = AllocArray!(VkPhysicalDevice)(arena, count);
vkEnumeratePhysicalDevices(vk.instance, &count, devices.ptr);
VkPhysicalDevice physical_device = null;
@ -1882,7 +1956,7 @@ CheckDeviceFeatures(VkPhysicalDevice device)
}
bool
CheckDeviceProperties(a.Arena *arena, VkPhysicalDevice device, VkSurfaceKHR surface, b32* discrete)
CheckDeviceProperties(Arena *arena, VkPhysicalDevice device, VkSurfaceKHR surface, b32* discrete)
{
bool success = false;
@ -1893,7 +1967,7 @@ CheckDeviceProperties(a.Arena *arena, VkPhysicalDevice device, VkSurfaceKHR surf
{
u32 ext_count;
vkEnumerateDeviceExtensionProperties(device, null, &ext_count, null);
VkExtensionProperties[] ext_props = a.AllocArray!(VkExtensionProperties)(arena, ext_count);
VkExtensionProperties[] ext_props = AllocArray!(VkExtensionProperties)(arena, ext_count);
vkEnumerateDeviceExtensionProperties(device, null, &ext_count, ext_props.ptr);
i32 matched = 0;
@ -1924,7 +1998,7 @@ CheckDeviceProperties(a.Arena *arena, VkPhysicalDevice device, VkSurfaceKHR surf
}
QueueInfo
CheckQueueProperties(a.Arena *arena, VkPhysicalDevice device, VkSurfaceKHR surface)
CheckQueueProperties(Arena *arena, VkPhysicalDevice device, VkSurfaceKHR surface)
{
const u32 T_BIT = VK_QUEUE_TRANSFER_BIT;
const u32 C_BIT = VK_QUEUE_COMPUTE_BIT;
@ -1939,7 +2013,7 @@ CheckQueueProperties(a.Arena *arena, VkPhysicalDevice device, VkSurfaceKHR surfa
u32 count;
vkGetPhysicalDeviceQueueFamilyProperties(device, &count, null);
VkQueueFamilyProperties[] properties = a.AllocArray!(VkQueueFamilyProperties)(arena, count);
VkQueueFamilyProperties[] properties = AllocArray!(VkQueueFamilyProperties)(arena, count);
vkGetPhysicalDeviceQueueFamilyProperties(device, &count, properties.ptr);
if (count == 1 && properties[0].queueCount == 1 && u.BitEq(properties[0].queueFlags, T_BIT | C_BIT | G_BIT))
@ -2002,7 +2076,7 @@ CheckQueueProperties(a.Arena *arena, VkPhysicalDevice device, VkSurfaceKHR surfa
pragma(inline): void
Push(Vulkan* vk, StepInitialized step)
{
u.Node!(SI)* node = a.Alloc!(u.Node!(SI));
u.Node!(SI)* node = Alloc!(u.Node!(SI));
node.value = step;
u.PushFront(&vk.cleanup_list, node, null);
}
@ -2012,10 +2086,10 @@ DestroyRenderer(Vulkan* vk)
{
foreach(i, arena; vk.frame_arenas)
{
a.Free(vk.frame_arenas.ptr + i);
Free(vk.frame_arenas.ptr + i);
}
a.Free(&vk.arena);
Free(&vk.arena);
}
void
@ -2187,11 +2261,11 @@ InitInstance(Vulkan* vk)
Push(vk, SI.Instance);
bool success = true;
a.Arena* arena = &vk.frame_arenas[0];
Arena* arena = &vk.frame_arenas[0];
u32 count;
vkEnumerateInstanceLayerProperties(&count, null);
VkLayerProperties[] layers = a.AllocArray!(VkLayerProperties)(arena, count);
VkLayerProperties[] layers = AllocArray!(VkLayerProperties)(arena, count);
vkEnumerateInstanceLayerProperties(&count, layers.ptr);
foreach(i, layer; layers)

View File

@ -103,13 +103,43 @@ OpenAssetPack()
}
}
u8[]
LoadAssetData(string name)
pragma(inline): void
CheckAssetPack()
{
if (!Asset_Pack_Opened)
{
OpenAssetPack();
}
}
u8[]
LoadAssetData(Arena* arena, string name)
{
CheckAssetPack();
u64 hash = Hash(name);
u8[] data = null;
foreach(i, info; Asset_Info)
{
if (info.hash == hash)
{
data = AllocArray!(u8)(arena, info.length);
Asset_File.seek(info.offset);
Asset_File.rawRead(data);
assert(data != null && data.length == info.length, "LoadAssetData failure: Asset data loaded incorrectly");
break;
}
}
return data;
}
u8[]
LoadAssetData(string name)
{
CheckAssetPack();
u64 hash = Hash(name);
u8[] data = null;