diff options
author | quou <quou@disroot.org> | 2025-01-06 22:04:55 +1100 |
---|---|---|
committer | quou <quou@disroot.org> | 2025-01-06 22:05:26 +1100 |
commit | 1006ccf490c473447498a5c1a290e4dd9b55b7c2 (patch) | |
tree | 48f86d6a08307a0c09a351bde35bfa746bcc3c30 | |
parent | 0fc7b4180b21e965db94872c20ca57f1ec9cc40a (diff) |
cubemap support
-rw-r--r-- | c2.cpp | 3 | ||||
-rw-r--r-- | sc/sc.cpp | 12 | ||||
-rw-r--r-- | ui.cpp | 3 | ||||
-rw-r--r-- | video.cpp | 323 | ||||
-rw-r--r-- | video.hpp | 26 |
5 files changed, 314 insertions, 53 deletions
@@ -76,6 +76,9 @@ Texture_Id make_default_texture(Device* dev) { Texture_Flags::sampleable | Texture_Flags::copy_dst, 1, 1, + 1, + 1, + 1, buf ); dev->destroy_bufferi(buf); @@ -255,6 +255,7 @@ struct Desc { return &b; } void read_texture(cfg_Object* desc) { + const char* sdem; const char* sname = find_string_default(desc, "name", 0); if (!sname) { print_err("%s must have a name.\n", desc->name); @@ -276,9 +277,12 @@ struct Desc { t.stage = 0; t.dimension = 0; } + sdem = find_string_default(desc, "dimension", 0); Texture& t = textures[n]; t.stage |= 1 << stage_from_string(sstage); - t.dimension = find_int_default(desc, "dimension", 2); + t.dimension = + sdem && string_equal(sdem, "cube")? -6: + find_int_default(desc, "dimension", 2); } cfg_Object* read_struct(cfg_Object* desc) { const char* sname = find_string_default(desc, "name", 0); @@ -437,7 +441,11 @@ struct Desc { Descriptor* d = find_desc(it.first.c_str()); assert(d != 0); ss << "layout (binding = " << d->slot << ") "; - ss << "uniform sampler" << texture.dimension << "D "; + ss << "uniform sampler"; + if (texture.dimension == -6) + ss << "Cube "; + else + ss << texture.dimension << "D "; ss << it.first << ";\n"; } } @@ -109,6 +109,9 @@ static Texture_Id create_atlas(Device* d) { Texture_Flags::sampleable | Texture_Flags::copy_dst, w, 10, + 1, + 1, + 1, buf ); d->destroy_bufferi(buf); @@ -28,6 +28,7 @@ extern "C" { #include "glad_vk.h" +#include <math.h> #include <string.h> #ifdef min /* use std::min and max instead */ @@ -215,6 +216,10 @@ struct Vram_Allocator { assert(page->mapping != 0); return (char*)page->mapping + offset() + off; } + static Allocation null() { + Allocation r{}; + return r; + } }; struct Chunk { VkDeviceSize offset; @@ -341,15 +346,39 @@ static VkImageUsageFlags get_texture_usage(int flags) { return f; } -static VkImageAspectFlags get_image_aspect(int flags) { +static VkImageAspectFlags get_image_aspect( + Texture_Format fmt, + int flags +) { VkImageUsageFlags f = 0; - if (flags & Texture_Flags::depth_stencil_target) - f |= VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; - else + if (flags & Texture_Flags::depth_stencil_target) { + if (fmt == texture_format_d24s8) + f |= + VK_IMAGE_ASPECT_DEPTH_BIT | + VK_IMAGE_ASPECT_STENCIL_BIT; + else + f |= VK_IMAGE_ASPECT_DEPTH_BIT; + } else f |= VK_IMAGE_ASPECT_COLOR_BIT; return f; } +static VkImageViewType get_view_type(int a, int d, int flags) { + VkImageViewType t = VK_IMAGE_VIEW_TYPE_2D; + if (flags & Texture_Flags::cubemap) { + if (a > 1) + t = VK_IMAGE_VIEW_TYPE_CUBE; + else + t = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY; + } else if (d > 1) { + t = VK_IMAGE_VIEW_TYPE_3D; + assert(a == 1); + } else if (a > 1) { + t = VK_IMAGE_VIEW_TYPE_2D_ARRAY; + } + return t; +} + VkImageLayout state_to_image_layout(Resource_State s) { switch (s) { case undefined: return VK_IMAGE_LAYOUT_UNDEFINED; @@ -622,6 +651,24 @@ struct Texture_Vk : public Texture, public Late_Terminated { Vram_Allocator::Allocation memory; Resource_State state; + static void init( + Texture_Vk* t, + Texture_Id id, + VkImage img, + VkImageView v, + Vram_Allocator::Allocation mem, + Resource_State state, + Texture_Format fmt, + int flags, + int w, + int h, + int d, + int mip_count, + int array_size, + int start_mip, + int start_array, + bool alias + ); void destroy(Device_Vk*) override; void set_name(Device_Vk* dev, const char* name); }; @@ -718,6 +765,7 @@ struct Renderpass_Vk { struct Framebuffer_Vk { VkFramebuffer fbo; + int w, h; int age; void on_submit() { @@ -1432,6 +1480,9 @@ void Device_Vk::create_depth(int w, int h) { Texture_Flags::sampleable | Texture_Flags::depth_stencil_target, w, h, + 1, + 1, + 1, 0 ); } @@ -1720,7 +1771,7 @@ void Framebuffer_Vk::init( const Render_Pass& rp ) { bool has_depth = rp.depth.id; - int i, count = 0, w, h; + int i, count = 0; VkImageView atts[2]; VkResult r; VkFramebufferCreateInfo fbi{}; @@ -1794,14 +1845,15 @@ static VkImageView make_view( Device_Vk* dev, VkImage image, VkFormat fmt, - VkImageAspectFlags flags + VkImageAspectFlags flags, + VkImageViewType type ) { VkImageViewCreateInfo vi{}; VkResult r; VkImageView view; vi.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; vi.image = image; - vi.viewType = VK_IMAGE_VIEW_TYPE_2D; + vi.viewType = type; vi.format = fmt; vi.subresourceRange.aspectMask = flags; vi.subresourceRange.baseMipLevel = 0; @@ -1879,12 +1931,24 @@ Texture_Id Swapchain::create_image( ) { 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.fmt = texture_format_bgra8i_srgb; - tex.alias = true; + Texture_Vk::init( + &tex, + id, + image, + view, + Vram_Allocator::Allocation::null(), + Resource_State::undefined, + texture_format_bgra8i_srgb, + Texture_Flags::swapchain, + w, + h, + 1, + 1, + 1, + 0, + 0, + true + ); return id; } @@ -1908,7 +1972,8 @@ void Swapchain::get_images(Device_Vk* dev) { VkImageView view = make_view(dev, images[i], format.format, - VK_IMAGE_ASPECT_COLOR_BIT + VK_IMAGE_ASPECT_COLOR_BIT, + VK_IMAGE_VIEW_TYPE_2D ); textures[i] = create_image( dev, @@ -2276,6 +2341,7 @@ void Context::transition(Texture_Id id, Resource_State state) { VkImageLayout dst_layout = state_to_image_layout(state); VkPipelineStageFlags src_stage, dst_stage; if (tex.state == state) return; + ctx->check_end_rp(); tex.state = state; b.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; b.oldLayout = src_layout; @@ -2284,10 +2350,10 @@ void Context::transition(Texture_Id id, Resource_State state) { 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; + b.subresourceRange.baseMipLevel = tex.start_mip; + b.subresourceRange.levelCount = tex.mip_count; + b.subresourceRange.baseArrayLayer = tex.start_array; + b.subresourceRange.layerCount = tex.array_size; if ( tex.fmt == texture_format_d16 || tex.fmt == texture_format_d24s8 || @@ -2297,9 +2363,13 @@ void Context::transition(Texture_Id id, Resource_State state) { src_layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; if (dst_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) dst_layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - b.subresourceRange.aspectMask = - VK_IMAGE_ASPECT_DEPTH_BIT | - VK_IMAGE_ASPECT_STENCIL_BIT; + if (tex.fmt == texture_format_d24s8) { + b.subresourceRange.aspectMask = + VK_IMAGE_ASPECT_DEPTH_BIT | + VK_IMAGE_ASPECT_STENCIL_BIT; + } else + b.subresourceRange.aspectMask = + VK_IMAGE_ASPECT_DEPTH_BIT; b.oldLayout = src_layout; b.newLayout = dst_layout; } @@ -2365,6 +2435,22 @@ void Context::transition(Texture_Id id, Resource_State state) { dst_stage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + } else if ( + src_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL && + dst_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL + ) { + b.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + b.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + src_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dst_stage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + } else if ( + src_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL && + dst_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL + ) { + b.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + b.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + src_stage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + dst_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; } else { print_err("Bad resource transition.\n"); pbreak(389); @@ -2409,13 +2495,14 @@ std::pair<Renderpass_Vk&, Framebuffer_Vk&> Context_Vk::begin_rp( Framebuffer_Vk& fbo = dev->get_fbo(rpo, { rp }); VkRenderPassBeginInfo rpbi{}; VkClearValue clears[max_colour_attachments + 1]; + VkExtent2D extent{ (uint32_t)fbo.w, (uint32_t)fbo.h }; int i, c = rp.colour_count, clear_count = 0; bool has_depth = rp.depth.id; if (last_rpo == rpo.rpo && last_fbo == fbo.fbo) return { rpo, fbo }; check_end_rp(); - last_rpo = rpo.rpo; - last_fbo = fbo.fbo; + last_rpo = 0; + last_fbo = 0; for (i = 0; i < c; i++) { VkClearValue clear{}; const auto& tar = rp.colours[i]; @@ -2437,7 +2524,7 @@ std::pair<Renderpass_Vk&, Framebuffer_Vk&> Context_Vk::begin_rp( rpbi.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; rpbi.renderPass = rpo.rpo; rpbi.framebuffer = fbo.fbo; - rpbi.renderArea.extent = dev->swapchain.size; + rpbi.renderArea.extent = extent; rpbi.clearValueCount = clear_count; rpbi.pClearValues = clears; vkCmdBeginRenderPass( @@ -2446,6 +2533,8 @@ std::pair<Renderpass_Vk&, Framebuffer_Vk&> Context_Vk::begin_rp( VK_SUBPASS_CONTENTS_INLINE ); dev->first_rp = false; + last_rpo = rpo.rpo; + last_fbo = fbo.fbo; return { rpo, fbo }; } @@ -3432,6 +3521,9 @@ Texture_Id Device::create_texture( int flags, int w, int h, + int d, + int mip_count, + int array_size, Buffer_Id init ) { VkImageCreateInfo ii{}; @@ -3439,27 +3531,39 @@ Texture_Id Device::create_texture( Device_Vk* dev = (Device_Vk*)this; Texture_Id id = dev->alloc_texture(); Texture_Vk& tex = *(Texture_Vk*)&dev->get_texture(id); + VkImage image; + VkImageView view; + Vram_Allocator::Allocation mem; VkMemoryRequirements req; - VkImageAspectFlags aspect = get_image_aspect(flags); - tex.state = Resource_State::undefined; + VkImageAspectFlags aspect = get_image_aspect(fmt, flags); + VkImageViewCreateInfo vi{}; + VkImageCreateFlags image_flags = 0; + int array_count = array_size; + if (flags & Texture_Flags::cubemap) { + array_count *= 6; + image_flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; + } + if (mip_count == 0) + mip_count = (int)(std::floor(std::log2(std::max(w, h)))) + 1; ii.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - ii.imageType = VK_IMAGE_TYPE_2D; + ii.imageType = d == 1? VK_IMAGE_TYPE_2D: VK_IMAGE_TYPE_3D; ii.extent.width = w; ii.extent.height = h; - ii.extent.depth = 1; - ii.mipLevels = 1; - ii.arrayLayers = 1; + ii.extent.depth = d; + ii.mipLevels = mip_count; + ii.arrayLayers = array_count; ii.format = get_vk_format(fmt); ii.tiling = VK_IMAGE_TILING_OPTIMAL; ii.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; ii.usage = get_texture_usage(flags); ii.sharingMode = VK_SHARING_MODE_EXCLUSIVE; ii.samples = VK_SAMPLE_COUNT_1_BIT; - r = vkCreateImage(dev->dev, &ii, &dev->ac, &tex.image); + ii.flags = image_flags; + r = vkCreateImage(dev->dev, &ii, &dev->ac, &image); if (r != VK_SUCCESS) { print_err("Failed to create an image.\n"); } - vkGetImageMemoryRequirements(dev->dev, tex.image, &req); + vkGetImageMemoryRequirements(dev->dev, image, &req); { VkMemoryPropertyFlags props = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; @@ -3468,27 +3572,49 @@ Texture_Id Device::create_texture( print("Failed to find a satisfying memory type index.\n"); pbreak(mt); } - tex.memory = dev->vrama.alloc(mt, req.size, req.alignment); - if (!tex.memory.valid()) { + mem = dev->vrama.alloc(mt, req.size, req.alignment); + if (!mem.valid()) { print_err("Failed to allocate memory for texture.\n"); pbreak(900); } } vkBindImageMemory( dev->dev, - tex.image, - tex.memory.mem, - tex.memory.offset() + image, + mem.mem, + mem.offset() ); - tex.w = w; - tex.h = h; - tex.fmt = fmt; - tex.alias = false; - tex.view = make_view( - dev, - tex.image, - ii.format, - aspect + vi.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + vi.image = image; + vi.viewType = get_view_type(array_count, d, flags); + vi.format = ii.format; + vi.subresourceRange.aspectMask = aspect; + vi.subresourceRange.baseMipLevel = 0; + vi.subresourceRange.levelCount = mip_count; + vi.subresourceRange.baseArrayLayer = 0; + vi.subresourceRange.layerCount = array_count; + r = vkCreateImageView(dev->dev, &vi, &dev->ac, &view); + if (r != VK_SUCCESS) { + print_err("Failed to make image view.\n"); + pbreak((int)r); + } + Texture_Vk::init( + &tex, + id, + image, + view, + mem, + Resource_State::undefined, + fmt, + flags, + w, + h, + d, + mip_count, + array_size, + 0, + 0, + false ); if (init) { Context& ctx = dev->acquire(); @@ -3501,17 +3627,76 @@ Texture_Id Device::create_texture( return id; } +Texture_Id Device::alias_texture( + Texture_Id o, + const char* name, + Texture_Format fmt, + int flags, + int w, + int h, + int d, + int mip_count, + int array_size, + int start_mip, + int start_array +) { + Device_Vk* dev = (Device_Vk*)this; + Texture_Vk& texture = *(Texture_Vk*)&dev->get_texture(o); + Texture_Id ntid = dev->alloc_texture(); + Texture_Vk& nt = *(Texture_Vk*)&dev->get_texture(ntid); + VkImageViewCreateInfo vi{}; + VkImageView view; + VkResult r; + assert(!texture.alias); + vi.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + vi.image = texture.image; + vi.viewType = get_view_type(array_size, d, flags); + vi.format = get_vk_format(fmt); + vi.subresourceRange.aspectMask = get_image_aspect(fmt, flags); + vi.subresourceRange.baseMipLevel = start_mip; + vi.subresourceRange.levelCount = mip_count; + vi.subresourceRange.baseArrayLayer = start_array; + vi.subresourceRange.layerCount = array_size; + r = vkCreateImageView(dev->dev, &vi, &dev->ac, &view); + if (r != VK_SUCCESS) { + print_err("Failed to alias texture.\n"); + pbreak(r); + } + Texture_Vk::init( + &nt, + ntid, + texture.image, + view, + Vram_Allocator::Allocation::null(), + Resource_State::undefined, + fmt, + flags, + w, + h, + d, + mip_count, + array_size, + start_mip, + start_array, + true + ); + nt.set_name(dev, name); + return ntid; +} + void Texture_Vk::set_name(Device_Vk* dev, const char* name) { #ifdef DEBUG VkDebugUtilsObjectNameInfoEXT i{}; i.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; i.pObjectName = name; - i.objectType = VK_OBJECT_TYPE_IMAGE; - i.objectHandle = (uint64_t)image; - vkSetDebugUtilsObjectNameEXT(dev->dev, &i); i.objectType = VK_OBJECT_TYPE_IMAGE_VIEW; i.objectHandle = (uint64_t)view; vkSetDebugUtilsObjectNameEXT(dev->dev, &i); + if (!alias) { + i.objectType = VK_OBJECT_TYPE_IMAGE; + i.objectHandle = (uint64_t)image; + vkSetDebugUtilsObjectNameEXT(dev->dev, &i); + } #else (void)dev; (void)name; @@ -3740,6 +3925,9 @@ Asset* Texture_Loader::load( Texture_Flags::sampleable | Texture_Flags::copy_dst, w, h, + 1, + 1, + 1, buf ); dev->destroy_buffer(buf); @@ -3752,6 +3940,43 @@ void Texture_Loader::unload(Asset* a) { dev->destroy_texture(tex->id); } +void Texture_Vk::init( + Texture_Vk* t, + Texture_Id id, + VkImage img, + VkImageView v, + Vram_Allocator::Allocation mem, + Resource_State st, + Texture_Format fmt, + int flags, + int w, + int h, + int d, + int mip_count, + int array_size, + int start_mip, + int start_array, + bool alias +) { + t->id = id; + t->image = img; + t->view = v; + t->memory = mem; + t->state = st; + t->w = w; + t->h = h; + t->d = d; + t->mip_count = mip_count; + t->array_size = array_size; + t->fmt = fmt; + t->flags = flags; + t->mip_count = mip_count; + t->array_size = array_size; + t->start_mip = start_mip; + t->start_array = start_array; + t->alias = alias; +} + void Texture_Vk::destroy(Device_Vk* dev) { if (!alias) { vkDestroyImage(dev->dev, image, &dev->ac); @@ -335,7 +335,10 @@ enum Resource_State { struct Texture : public Asset { Texture_Id id; Texture_Format fmt; - int w, h; + int flags; + int w, h, d; + int mip_count, array_size; + int start_mip, start_array; bool alias; }; @@ -358,7 +361,9 @@ namespace Texture_Flags { colour_target = 1 << 1, depth_stencil_target = 1 << 2, copy_src = 1 << 3, - copy_dst = 1 << 4 + copy_dst = 1 << 4, + cubemap = 1 << 5, + swapchain = 1 << 6 }; }; @@ -456,8 +461,25 @@ struct Device { int flags, int w, int h, + int d, + int mip_count, + int array_size, Buffer_Id init ); + Texture_Id alias_texture( + Texture_Id o, + const char* name, + Texture_Format fmt, + int flags, + int w, + int h, + int d, + int mip_count, + int array_size, + int start_mip, + int start_array + ); + Texture_Id get_backbuffer(); Texture_Id get_depth_target(); Texture& get_texture(Texture_Id id); |