From b293168cc158d65f1a5146f155921ff82119d1bc Mon Sep 17 00:00:00 2001 From: quou Date: Mon, 23 Dec 2024 14:41:01 +1100 Subject: Texture conversion and loading --- video.cpp | 584 ++++++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 476 insertions(+), 108 deletions(-) (limited to 'video.cpp') diff --git a/video.cpp b/video.cpp index 1670a61..8bc5080 100644 --- a/video.cpp +++ b/video.cpp @@ -176,6 +176,35 @@ struct Hash_Map { } }; +static VkFormat get_vk_format(Texture_Format fmt) { + switch (fmt) { + case texture_format_r8i: return VK_FORMAT_R8_UNORM; + case texture_format_r16f: return VK_FORMAT_R16_SFLOAT; + case texture_format_r32f: return VK_FORMAT_R32_SFLOAT; + case texture_format_rg8i: return VK_FORMAT_R8G8_UNORM; + case texture_format_rg16f: return VK_FORMAT_R16G16_SFLOAT; + case texture_format_rg32f: return VK_FORMAT_R32G32_SFLOAT; + case texture_format_rgb8i: return VK_FORMAT_R8G8B8_UNORM; + case texture_format_rgb16f: return VK_FORMAT_R16G16B16_SFLOAT; + case texture_format_rgb32f: return VK_FORMAT_R32G32B32_SFLOAT; + case texture_format_rgba8i: return VK_FORMAT_R8G8B8A8_UNORM; + case texture_format_rgba16f: return VK_FORMAT_R16G16B16A16_SFLOAT; + case texture_format_rgba32f: return VK_FORMAT_R32G32B32A32_SFLOAT; + case texture_format_bc1: return VK_FORMAT_BC1_RGB_UNORM_BLOCK; + default: assert(0); return VK_FORMAT_UNDEFINED; + } +} + +VkImageLayout state_to_image_layout(Resource_State s) { + switch (s) { + case undefined: return VK_IMAGE_LAYOUT_UNDEFINED; + case copy_dst: return VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + case copy_src: return VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + case shader_read: return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + default: assert(0); return VK_IMAGE_LAYOUT_UNDEFINED; + } +} + static void* vk_alloc( void* uptr, size_t size, @@ -295,6 +324,12 @@ static void deinit_swap_cap( if (cap->pms) heap_free(d->heap, cap->pms); } +struct Late_Terminated { + Late_Terminated* next; + + virtual void destroy(Device_Vk* dev) = 0; +}; + struct Swapchain { VkSwapchainKHR swapchain; Texture_Id* textures; @@ -308,6 +343,14 @@ struct Swapchain { void recreate(const App& app, Device_Vk* dev); void get_images(Device_Vk* dev); void destroy(Device_Vk* dev); + + Texture_Id create_image( + Device_Vk* dev, + VkImage image, + VkImageView view, + int w, + int h + ); }; #define max_contexts 16 @@ -317,7 +360,7 @@ enum { context_state_init = 1 << 1 }; -struct Shader_Vk : public Shader { +struct Shader_Vk : public Shader, public Late_Terminated { struct Attribute { char name[28]; SVariable_Type type; @@ -361,7 +404,7 @@ struct Shader_Vk : public Shader { Device_Vk* dev, FILE* f ); - void destroy_internal(Device_Vk* dev); + void destroy(Device_Vk* dev) override; static VkShaderStageFlagBits stage(Shader_Type type) { switch (type) { @@ -379,37 +422,42 @@ struct Shader_Vk : public Shader { struct Renderpass_Vk; struct Context_Vk : public Context { int state; + Device_Vk* dev; VkCommandBuffer cb; VkCommandPool pool; VkFence fence; VkSemaphore semaphore; - void init_pool(Device_Vk* dev); - void init_cb(Device_Vk* dev); - void init_sync(Device_Vk* dev); - void init(Device_Vk* dev); - void begin_record(Device_Vk* dev); - Context_Vk& acquire(Device_Vk* dev); + void init_pool(); + void init_cb(); + void init_sync(); + void init(Device_Vk* device); + void begin_record(); + Context_Vk& acquire(Device_Vk* device); void release(); - void destroy(Device_Vk* dev); + void destroy(); - Renderpass_Vk& begin_rp(Device& d, const Render_Pass& rp); + Renderpass_Vk& begin_rp(const Render_Pass& rp); void end_rp(Renderpass_Vk& rpo); }; -struct Texture_Vk : public Texture { +struct Texture_Vk : public Texture, public Late_Terminated { VkImage image; VkImageView view; + VkDeviceMemory memory; + Resource_State state; + + void destroy(Device_Vk*) override; }; -struct Buffer_Vk : public Buffer { +struct Buffer_Vk : public Buffer, public Late_Terminated { VkBuffer buf; VkDeviceMemory memory; VkDeviceSize size; int flags; void init(Device_Vk* dev, int flags, VkDeviceSize size); - void destroy(Device_Vk* dev); + void destroy(Device_Vk* dev) override; static VkBufferUsageFlags get_usage(int flags) { VkBufferUsageFlags r = 0; @@ -600,7 +648,44 @@ struct std::hash { struct Shader_Loader : public Asset_Loader { Device_Vk* dev; void init(Device_Vk* d); - Asset* load(Arena* a, Pack_File* f) override; + Asset* load(Arena* a, Arena* s, Pack_File* f) override; + void unload(Asset* a) override; +}; + +struct Texture_Loader : public Asset_Loader { + Device_Vk* dev; + static size_t calc_size(Texture_Format fmt, int w, int h); + void init(Device_Vk* d); + Asset* load(Arena* a, Arena* s, Pack_File* f) override; + void unload(Asset* a) override; + + Buffer_Id upload(void* buf, size_t size); + Texture_Id create_tex( + Texture_Format fmt, + int w, + int h + ); +}; + +struct Terminator { + Late_Terminated* queue; + + void execute(Device_Vk* dev) { + Late_Terminated* obj = queue; + for (; obj; obj = obj->next) + obj->destroy(dev); + queue = 0; + } + + void add(Late_Terminated* obj) { + if (queue) { + obj->next = queue; + queue = obj; + } else { + obj->next = 0; + queue = obj; + } + } }; struct Device_Vk : public Device { @@ -619,6 +704,7 @@ struct Device_Vk : public Device { Context_Vk contexts[max_contexts]; Context_Vk* current_ctx; Shader_Loader shader_loader; + Texture_Loader texture_loader; #ifdef DEBUG VkDebugUtilsMessengerEXT msg; #endif @@ -639,11 +725,10 @@ struct Device_Vk : public Device { Hash_Map rpo_cache; Hash_Map pso_cache; - Texture_Id alloc_texture( - VkImage img, - VkImageView view, - const Texture& copy - ); + Terminator* terminators; + uint32_t terminator_index; + + Texture_Id alloc_texture(); Buffer_Id alloc_buffer(); Vertex_Format_Id alloc_vf(); Vertex_Format_Id create_vf(Shader_Vk& shader); @@ -669,6 +754,8 @@ struct Device_Vk : public Device { Pipeline_Vk& get_pso(const Pso_Key& pop); void collect_garbage(); + void queue_destroy(Late_Terminated* obj); + void create_terminators(); int find_memory_type( uint32_t filter, @@ -980,7 +1067,9 @@ void Device_Vk::init_internal() { rpo_cache.init(); pso_cache.init(); shader_loader.init(this); + texture_loader.init(this); register_asset_loader("CSH2", &shader_loader); + register_asset_loader("TXTR", &texture_loader); find_exts(exts, ext_count); init_ac(); create_inst(exts, ext_count); @@ -993,12 +1082,31 @@ void Device_Vk::init_internal() { gladLoaderLoadVulkan(inst, phys_dev, dev); vkGetDeviceQueue(dev, (uint32_t)queue_index, 0, &queue); swapchain.init(*app, this); + terminators = 0; + terminator_index = 0; + create_terminators(); for (i = 0; i < max_contexts; i++) contexts[i].state = context_state_avail; } +void Device_Vk::create_terminators() { + int i, count = swapchain.image_count; + if (terminators) { + for (i = 0; i < count; i++) + terminators[i].execute(this); + heap_free(heap, terminators); + } + terminators = (Terminator*)heap_alloc( + heap, + count * sizeof *terminators + ); + for (i = 0; i < count; i++) { + terminators[i].queue = 0; + } +} + void Device_Vk::deinit_internal() { - int i; + int i, image_count = swapchain.image_count; vkDeviceWaitIdle(dev); swapchain.destroy(this); deinit_swap_cap(this, &swap_cap); @@ -1010,7 +1118,10 @@ void Device_Vk::deinit_internal() { for (i = 0; i < max_contexts; i++) { auto& context = contexts[i]; if (context.state & context_state_init) - context.destroy(this); + context.destroy(); + } + for (i = 0; i < image_count; i++) { + terminators[i].execute(this); } vkDestroyDevice(dev, &ac); #ifdef DEBUG @@ -1030,6 +1141,7 @@ void Device_Vk::on_resize_internal(int w, int h) { deinit_swap_cap(this, &swap_cap); get_swap_cap(this, phys_dev, surf, &swap_cap); swapchain.recreate(*app, this); + create_terminators(); } Renderpass_Vk& Device_Vk::create_rpo(const Render_Pass& rp) { @@ -1073,10 +1185,11 @@ void Renderpass_Vk::destroy(Device_Vk* dev) { } void Device_Vk::collect_garbage() { + int max_age = swapchain.image_count + 3; for (const auto& i: rpo_cache) { auto& rp = i.second; rp.age++; - if (rp.age > 3) { + if (rp.age > max_age) { rp.destroy(this); rpo_cache.remove(i.first); } @@ -1084,13 +1197,17 @@ void Device_Vk::collect_garbage() { for (const auto& i: pso_cache) { auto& pip = i.second; pip.age++; - if (pip.age > 3) { + if (pip.age > max_age) { pip.destroy(this); pso_cache.remove(i.first); } } } +void Device_Vk::queue_destroy(Late_Terminated* obj) { + terminators[terminator_index].add(obj); +} + int Device_Vk::find_memory_type( uint32_t filter, VkMemoryPropertyFlags flags @@ -1271,14 +1388,27 @@ void Swapchain::recreate(const App& app, Device_Vk* dev) { old.destroy(dev); } +Texture_Id Swapchain::create_image( + Device_Vk* dev, + VkImage image, + VkImageView view, + int w, + int h +) { + Texture_Id id = dev->alloc_texture(); + Texture_Vk& tex = *(Texture_Vk*)&dev->get_texture(id); + tex.image = image; + tex.view = view; + tex.w = w; + tex.h = h; + tex.alias = true; + return id; +} + void Swapchain::get_images(Device_Vk* dev) { unsigned count; int i; VkImage* images; - Texture info{}; - info.w = size.width; - info.h = size.height; - info.alias = true; vkGetSwapchainImagesKHR(dev->dev, swapchain, &count, 0); image_count = count; images = (VkImage*)heap_alloc( @@ -1296,7 +1426,13 @@ void Swapchain::get_images(Device_Vk* dev) { format.format, VK_IMAGE_ASPECT_COLOR_BIT ); - textures[i] = dev->alloc_texture(images[i], view, info); + textures[i] = create_image( + dev, + images[i], + view, + size.width, + size.height + ); } heap_free(dev->heap, images); } @@ -1339,6 +1475,9 @@ void Device::begin_frame() { Device_Vk* dev = (Device_Vk*)this; dev->collect_garbage(); dev->current_ctx = (Context_Vk*)&acquire(); + dev->terminator_index++; + dev->terminator_index %= dev->swapchain.image_count; + dev->terminators[dev->terminator_index].execute(dev); vkAcquireNextImageKHR( dev->dev, dev->swapchain.swapchain, @@ -1353,20 +1492,18 @@ void Device::begin_frame() { void Device::submit(Context& ctx_) { Context_Vk* ctx = (Context_Vk*)&ctx_; Device_Vk* dev = (Device_Vk*)this; - VkPipelineStageFlags stage = - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; VkSubmitInfo si{}; si.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - si.waitSemaphoreCount = 1; +/* si.waitSemaphoreCount = 1; si.pWaitSemaphores = &ctx->semaphore; si.pWaitDstStageMask = &stage; si.signalSemaphoreCount = 1; - si.pSignalSemaphores = &ctx->semaphore; + si.pSignalSemaphores = &ctx->semaphore;*/ si.commandBufferCount = 1; si.pCommandBuffers = &ctx->cb; vkEndCommandBuffer(ctx->cb); vkQueueSubmit(dev->queue, 1, &si, ctx->fence); - ctx->wait(*dev); + ctx->wait(); ctx->release(); } @@ -1374,18 +1511,27 @@ void Device::present() { Device_Vk* dev = (Device_Vk*)this; Context_Vk* ctx = dev->current_ctx; VkPresentInfoKHR pi{}; - VkSemaphore s[1]; - VkSwapchainKHR sw[1]; - submit(*ctx); - s[0] = ctx->semaphore; - sw[0] = dev->swapchain.swapchain; + VkSubmitInfo si{}; + VkPipelineStageFlags stage = + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + si.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + si.waitSemaphoreCount = 1; + si.pWaitSemaphores = &ctx->semaphore; + si.pWaitDstStageMask = &stage; + si.signalSemaphoreCount = 1; + si.pSignalSemaphores = &ctx->semaphore; + si.commandBufferCount = 1; + si.pCommandBuffers = &ctx->cb; + vkEndCommandBuffer(ctx->cb); + vkQueueSubmit(dev->queue, 1, &si, ctx->fence); pi.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; pi.waitSemaphoreCount = 1; - pi.pWaitSemaphores = s; + pi.pWaitSemaphores = &ctx->semaphore; pi.swapchainCount = 1; - pi.pSwapchains = sw; + pi.pSwapchains = &dev->swapchain.swapchain; pi.pImageIndices = &dev->backbuffer_index; vkQueuePresentKHR(dev->queue, &pi); + ctx->release(); } Texture_Id Device::get_backbuffer() { @@ -1396,16 +1542,9 @@ Texture& Device::get_texture(Texture_Id id) { return ((Device_Vk*)this)->textures[id]; } -Texture_Id Device_Vk::alloc_texture( - VkImage img, - VkImageView view, - const Texture& copy -) { +Texture_Id Device_Vk::alloc_texture() { Texture_Vk tex{}; Texture_Id id(texture_count++); - memcpy(&tex, ©, sizeof(Texture)); - tex.image = img; - tex.view = view; textures.set(id, tex); return id; } @@ -1445,16 +1584,12 @@ Shader_Id Device_Vk::alloc_shader() { void Device::destroy_texture(Texture_Id id) { Device_Vk* dev = (Device_Vk*)this; - Texture_Vk& tex = dev->textures[id]; - if (!tex.alias) - vkDestroyImage(dev->dev, tex.image, &dev->ac); - vkDestroyImageView(dev->dev, tex.view, &dev->ac); - dev->textures.remove(id); + dev->queue_destroy((Texture_Vk*)&dev->get_texture(id)); } -void Context::wait(Device& d) { +void Context::wait() { Context_Vk* ctx = (Context_Vk*)this; - Device_Vk* dev = (Device_Vk*)&d; + Device_Vk* dev = ctx->dev; vkWaitForFences( dev->dev, 1, @@ -1465,17 +1600,16 @@ void Context::wait(Device& d) { } void Context::submit( - Device& d, const Draw& draw, const Pipeline& p, const Render_Pass& rp ) { - Device_Vk* dev = (Device_Vk*)&d; Context_Vk* ctx = (Context_Vk*)this; + Device_Vk* dev = ctx->dev; Vertex_Buffer_Binding* binding; Pso_Key pso_key = { p, rp }; Pipeline_Vk& pso = dev->get_pso(pso_key); - auto& rpo = ctx->begin_rp(d, rp); + auto& rpo = ctx->begin_rp(rp); vkCmdBindPipeline( ctx->cb, VK_PIPELINE_BIND_POINT_GRAPHICS, @@ -1498,13 +1632,13 @@ void Context::submit( } void Context::submit( - Device& d, const Draw* draws, int count, const Pipeline& p, const Render_Pass& rp ) { - Device_Vk* dev = (Device_Vk*)&d; + Context_Vk* ctx = (Context_Vk*)this; + Device_Vk* dev = ctx->dev; (void)draws; (void)count; (void)p; @@ -1514,8 +1648,115 @@ void Context::submit( /* todo */ } -Renderpass_Vk& Context_Vk::begin_rp(Device& d, const Render_Pass& rp) { - Device_Vk* dev = (Device_Vk*)&d; +void Context::copy(Buffer_Id dst, Buffer_Id src) { + Context_Vk* ctx = (Context_Vk*)this; + Device_Vk* dev = ctx->dev; + Buffer_Vk& a = *(Buffer_Vk*)&dev->get_buffer(dst); + Buffer_Vk& b = *(Buffer_Vk*)&dev->get_buffer(src); + VkBufferCopy region{}; + region.srcOffset = 0; + region.dstOffset = 0; + region.size = b.size; + vkCmdCopyBuffer( + ctx->cb, + b.buf, + a.buf, + 1, + ®ion + ); +} + +void Context::copy(Texture_Id dst, Buffer_Id src) { + Context_Vk* ctx = (Context_Vk*)this; + Device_Vk* dev = ctx->dev; + Texture_Vk& a = *(Texture_Vk*)&dev->get_texture(dst); + Buffer_Vk& b = *(Buffer_Vk*)&dev->get_buffer(src); + VkBufferImageCopy c{}; + c.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + c.imageSubresource.layerCount = 1; + c.imageExtent.width = a.w; + c.imageExtent.height = a.h; + c.imageExtent.depth = 1; + vkCmdCopyBufferToImage( + ctx->cb, + b.buf, + a.image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, + &c + ); +} + +void Context::transition(Texture_Id id, Resource_State state) { + Context_Vk* ctx = (Context_Vk*)this; + Device_Vk* dev = ctx->dev; + Texture_Vk& tex = *(Texture_Vk*)&dev->get_texture(id); + VkImageMemoryBarrier b{}; + VkImageLayout src_layout = state_to_image_layout(tex.state); + VkImageLayout dst_layout = state_to_image_layout(state); + VkPipelineStageFlags src_stage, dst_stage; + b.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + b.oldLayout = src_layout; + b.newLayout = dst_layout; + b.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + b.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + b.image = tex.image; + b.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + b.subresourceRange.baseMipLevel = 0; + b.subresourceRange.levelCount = 1; + b.subresourceRange.baseArrayLayer = 0; + b.subresourceRange.layerCount = 1; + if ( + src_layout == VK_IMAGE_LAYOUT_UNDEFINED && + dst_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL + ) { + b.srcAccessMask = 0; + b.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + src_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + dst_stage = VK_PIPELINE_STAGE_TRANSFER_BIT; + } else if ( + src_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && + dst_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL + ) { + b.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + b.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + src_stage = VK_PIPELINE_STAGE_TRANSFER_BIT; + dst_stage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + } else if ( + src_layout == VK_IMAGE_LAYOUT_UNDEFINED && + dst_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL + ) { + b.srcAccessMask = 0; + b.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + src_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dst_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + } else if ( + src_layout == VK_IMAGE_LAYOUT_UNDEFINED && + dst_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL + ) { + b.srcAccessMask = 0; + b.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + src_stage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + dst_stage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + } else { + print_err("Bad resource transition.\n"); + pbreak(389); + } + vkCmdPipelineBarrier( + ctx->cb, + src_stage, + dst_stage, + 0, + 0, + 0, + 0, + 0, + 1, + &b + ); +} + +Renderpass_Vk& Context_Vk::begin_rp(const Render_Pass& rp) { Renderpass_Vk& rpo = dev->get_rpo(rp); VkRenderPassBeginInfo rpbi{}; rpbi.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; @@ -1537,13 +1778,13 @@ void Context_Vk::end_rp(Renderpass_Vk& rpo) { rpo.on_submit(); } -void Context::submit(Device& d, const Render_Pass& rp) { +void Context::submit(const Render_Pass& rp) { Context_Vk* ctx = (Context_Vk*)this; - auto& rpo = ctx->begin_rp(d, rp); + auto& rpo = ctx->begin_rp(rp); ctx->end_rp(rpo); } -void Context_Vk::init_pool(Device_Vk* dev) { +void Context_Vk::init_pool() { VkCommandPoolCreateInfo pi{}; VkResult r; pi.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; @@ -1556,7 +1797,7 @@ void Context_Vk::init_pool(Device_Vk* dev) { } } -void Context_Vk::init_cb(Device_Vk* dev) { +void Context_Vk::init_cb() { VkCommandBufferAllocateInfo ci{}; VkResult r; ci.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; @@ -1570,7 +1811,7 @@ void Context_Vk::init_cb(Device_Vk* dev) { } } -void Context_Vk::init_sync(Device_Vk* dev) { +void Context_Vk::init_sync() { VkFenceCreateInfo fi{}; VkSemaphoreCreateInfo si{}; VkResult r; @@ -1589,26 +1830,28 @@ void Context_Vk::init_sync(Device_Vk* dev) { } } -void Context_Vk::init(Device_Vk* dev) { - init_pool(dev); - init_cb(dev); - init_sync(dev); +void Context_Vk::init(Device_Vk* device) { + dev = device; + init_pool(); + init_cb(); + init_sync(); state |= context_state_init; } -void Context_Vk::begin_record(Device_Vk* dev) { +void Context_Vk::begin_record() { VkCommandBufferBeginInfo bi{}; bi.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + wait(); vkResetFences(dev->dev, 1, &fence); vkResetCommandBuffer(cb, 0); vkBeginCommandBuffer(cb, &bi); } -Context_Vk& Context_Vk::acquire(Device_Vk* dev) { +Context_Vk& Context_Vk::acquire(Device_Vk* device) { if (~state & context_state_init) - init(dev); + init(device); state &= ~context_state_avail; - begin_record(dev); + begin_record(); return *this; } @@ -1616,7 +1859,7 @@ void Context_Vk::release() { state |= context_state_avail; } -void Context_Vk::destroy(Device_Vk* dev) { +void Context_Vk::destroy() { state &= ~context_state_init; vkDestroyCommandPool(dev->dev, pool, &dev->ac); vkDestroySemaphore(dev->dev, semaphore, &dev->ac); @@ -2116,17 +2359,14 @@ void Shader_Vk::Vertex_Format::destroy(Device_Vk* dev) { heap_free(dev->heap, attributes); } -void Shader_Vk::destroy_internal(Device_Vk* dev) { +void Shader_Vk::destroy(Device_Vk* dev) { int i; for (i = 0; i < shader_type_count; i++) if (modules[i]) vkDestroyShaderModule(dev->dev, modules[i], &dev->ac); vfd.destroy(dev); dev->destroy_vf(vf); -} - -void Shader::destroy(Device* dev) { - ((Shader_Vk*)this)->destroy_internal((Device_Vk*)dev); + dev->shaders.remove(id); } int Shader::binding_index(const char* name) { @@ -2148,11 +2388,12 @@ int Shader::attribute_index(const char* name) { void Buffer_Vk::init( Device_Vk* dev, int flags, - VkDeviceSize size + VkDeviceSize s ) { VkBufferCreateInfo bi{}; VkMemoryRequirements req; VkResult r; + size = s; bi.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; bi.size = size; bi.usage = get_usage(flags); @@ -2190,6 +2431,7 @@ void Buffer_Vk::init( void Buffer_Vk::destroy(Device_Vk* dev) { vkDestroyBuffer(dev->dev, buf, &dev->ac); vkFreeMemory(dev->dev, memory, &dev->ac); + dev->buffers.remove(id); } Buffer_Id Device::create_buffer(size_t size, int flags) { @@ -2202,9 +2444,8 @@ Buffer_Id Device::create_buffer(size_t size, int flags) { void Device::destroy_buffer(Buffer_Id id) { Device_Vk* dev = (Device_Vk*)this; - Buffer_Vk& buf = *(Buffer_Vk*)&get_buffer(id); - buf.destroy(dev); - dev->buffers.remove(id); + Buffer_Vk* buf = (Buffer_Vk*)&get_buffer(id); + dev->queue_destroy(buf); } void* Device::map_buffer( @@ -2240,42 +2481,32 @@ Shader& Device::get_shader(Shader_Id id) { return ((Device_Vk*)this)->shaders[id]; } -bool Shader::load( - Asset_Loader* loader, - Arena* a, - Pack_File* f -) { - Device_Vk* dev = ((Shader_Loader*)loader)->dev; - Shader_Vk& sh = *(Shader_Vk*)this; - return sh.init(dev, f); -} - -void Shader::unload(Asset_Loader* loader_) { - Shader_Loader* loader = (Shader_Loader*)loader_; - Device_Vk* dev = loader->dev; - Shader_Vk& sh = *(Shader_Vk*)this; - sh.destroy(dev); - dev->shaders.remove(id); -} - void Shader_Loader::init(Device_Vk* d) { dev = d; } Asset* Shader_Loader::load( Arena* a, + Arena* s, Pack_File* f ) { - Shader_Vk* s; + Shader_Vk* shader; Shader_Id id; + (void)s; + (void)a; id = dev->alloc_shader(); - s = (Shader_Vk*)&dev->get_shader(id); - s->id = id; - if (!s->load(this, a, f)) { + shader = (Shader_Vk*)&dev->get_shader(id); + shader->id = id; + if (!shader->init(dev, f)) { dev->shaders.remove(id); return 0; } - return s; + return shader; +} + +void Shader_Loader::unload(Asset* a) { + Shader_Vk* sh = (Shader_Vk*)a; + dev->queue_destroy(sh); } bool Shader_Vk::init(Device_Vk* dev, Pack_File* f) { @@ -2323,3 +2554,140 @@ bool Shader_Vk::init(Device_Vk* dev, Pack_File* f) { return true; } +void Texture_Loader::init(Device_Vk* d) { + dev = d; +} + +size_t Texture_Loader::calc_size( + Texture_Format fmt, + int w, + int h +) { + switch (fmt) { + case texture_format_bc1: + return (w / 4) * (h / 4) * 8; + default: + print_err("Can't load this texture format.\n"); + pbreak(45498); + return 0; + } +} + +Buffer_Id Texture_Loader::upload(void* buf, size_t size) { + void* mem; + Buffer_Id id = dev->create_buffer( + size, + Buffer_Flags::copy_src | + Buffer_Flags::cpu_readwrite + ); + mem = dev->map_buffer(id, 0, size); + memcpy(mem, buf, size); + dev->unmap_buffer(id); + return id; +} + +Texture_Id Texture_Loader::create_tex( + Texture_Format fmt, + int w, + int h +) { + VkImageCreateInfo ii{}; + VkResult r; + Texture_Id id = dev->alloc_texture(); + Texture_Vk& tex = *(Texture_Vk*)&dev->get_texture(id); + VkMemoryRequirements req; + ii.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + ii.imageType = VK_IMAGE_TYPE_2D; + ii.extent.width = w; + ii.extent.height = h; + ii.extent.depth = 1; + ii.mipLevels = 1; + ii.arrayLayers = 1; + ii.format = get_vk_format(fmt); + ii.tiling = VK_IMAGE_TILING_OPTIMAL; + ii.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + ii.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; + ii.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + ii.samples = VK_SAMPLE_COUNT_1_BIT; + r = vkCreateImage(dev->dev, &ii, &dev->ac, &tex.image); + if (r != VK_SUCCESS) { + print_err("Failed to create an image.\n"); + } + vkGetImageMemoryRequirements(dev->dev, tex.image, &req); + { + VkMemoryPropertyFlags props = + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + int mt = dev->find_memory_type(req.memoryTypeBits, props); + VkMemoryAllocateInfo ai{}; + if (mt < 0) { + print("Failed to find a satisfying memory type index.\n"); + pbreak(mt); + } + ai.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + ai.allocationSize = req.size; + ai.memoryTypeIndex = mt; + r = vkAllocateMemory(dev->dev, &ai, &dev->ac, &tex.memory); + if (r == VK_ERROR_OUT_OF_DEVICE_MEMORY) { + print_err("Out of video memory.\n"); + pbreak(r); + } + if (r != VK_SUCCESS) { + print_err("VRAM allocation failed.\n"); + pbreak(r); + } + } + vkBindImageMemory(dev->dev, tex.image, tex.memory, 0); + tex.w = w; + tex.h = h; + tex.alias = false; + tex.view = make_view( + dev, + tex.image, + ii.format, + VK_IMAGE_ASPECT_COLOR_BIT + ); + return id; +} + +Asset* Texture_Loader::load(Arena* a, Arena* s, Pack_File* f) { + char magic[4]; + void* data; + int w, h; + size_t size; + Texture_Format fmt; + pack_read(f, magic, 4); + pack_read(f, &w, 4); + pack_read(f, &h, 4); + pack_read(f, &fmt, 4); + size = calc_size(fmt, w, h); + data = arena_alloc(s, size); + pack_read(f, data, size); + { + Buffer_Id buf = upload(data, size); + Texture_Id tex = create_tex(fmt, w, h); + { + Context& ctx = dev->acquire(); + ctx.transition(tex, Resource_State::copy_dst); + ctx.copy(tex, buf); + ctx.transition(tex, Resource_State::shader_read); + dev->submit(ctx); + dev->destroy_buffer(buf); + } + return &dev->get_texture(tex); + } +} + +void Texture_Loader::unload(Asset* a) { + Texture_Vk* tex = (Texture_Vk*)a; + tex->destroy(dev); +} + +void Texture_Vk::destroy(Device_Vk* dev) { + if (!alias) { + vkDestroyImage(dev->dev, image, &dev->ac); + vkFreeMemory(dev->dev, memory, &dev->ac); + } + vkDestroyImageView(dev->dev, view, &dev->ac); + dev->textures.remove(id); +} + -- cgit v1.2.3-54-g00ecf