diff options
-rw-r--r-- | c2.cpp | 4 | ||||
-rw-r--r-- | video.cpp | 273 |
2 files changed, 217 insertions, 60 deletions
@@ -236,6 +236,7 @@ struct Sky { cb->iview = cam.get_view().inverse(); cb->iprojection = cam.get_proj().inverse(); config.unmap(d); + config.update(d->get_ctx()); render_imp( d, a, @@ -284,7 +285,6 @@ struct Sky { draw.verts = vbb; draw.vertex_count = 3; draw.instance_count = 1; - config.update(ctx); ctx.submit(draw, pip, pass); } }; @@ -407,7 +407,6 @@ struct Env_Probe { Context& ctx = dev->get_ctx(); update_cbuffer(dev); for (i = 0; i < 6; i++) { - ctx.transition(faces[i], Resource_State::render_target); pb.begin_rp(); pb.rp_target(faces[i], Clear_Mode::discard); pb.rp_depth_target(cubemap_depth, 1.0f); @@ -421,7 +420,6 @@ struct Env_Probe { cubemap_res, cubemap_res ); - ctx.transition(faces[i], Resource_State::shader_read); } } }; @@ -3,6 +3,7 @@ #define device_heap_size (1024 * 1024 * 8) #define max_textures 1024 +#define max_texture_alias 32 #define max_buffers 1024 #define max_vertex_formats 64 #define max_rpos 64 @@ -379,19 +380,27 @@ static VkImageViewType get_view_type(int a, int d, int flags) { return t; } +template <bool Depth> 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; - case render_target: return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + case render_target: + return Depth? + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; case presentable: return VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; } assert(0); return VK_IMAGE_LAYOUT_UNDEFINED; } +VkImageLayout state_to_image_layout(Resource_State s) { + return state_to_image_layout<false>(s); +} + static void* __stdcall vk_alloc( void* uptr, size_t size, @@ -616,6 +625,8 @@ struct Shader_Vk : public Shader, public Late_Terminated { struct Renderpass_Vk; struct Framebuffer_Vk; +struct Pipeline_Vk; +struct Rpo_Key; struct Context_Vk : public Context { int state; Device_Vk* dev; @@ -639,10 +650,19 @@ struct Context_Vk : public Context { void destroy(); std::pair<Renderpass_Vk&, Framebuffer_Vk&> begin_rp( - const Render_Pass& rp + const Rpo_Key& rp + ); + void end_rp( + const Render_Pass& rp, + Renderpass_Vk& rpo, + Framebuffer_Vk& fbo ); - void end_rp(Renderpass_Vk& rpo, Framebuffer_Vk& fbo); void check_end_rp(); + + void submit_descriptors( + const Pipeline_Vk& pso, + const Pipeline& p + ); }; struct Texture_Vk : public Texture, public Late_Terminated { @@ -650,10 +670,14 @@ struct Texture_Vk : public Texture, public Late_Terminated { VkImageView view; Vram_Allocator::Allocation memory; Resource_State state; + Texture_Id parent; + Texture_Id children[max_texture_alias]; + int child_count; static void init( Texture_Vk* t, Texture_Id id, + Texture_Id parent, VkImage img, VkImageView v, Vram_Allocator::Allocation mem, @@ -671,6 +695,9 @@ struct Texture_Vk : public Texture, public Late_Terminated { ); void destroy(Device_Vk*) override; void set_name(Device_Vk* dev, const char* name); + void add_child(Texture_Id id); + void rem_child(Texture_Id id); + bool child_states_same(Device_Vk* dev); }; struct Buffer_Vk : public Buffer, public Late_Terminated { @@ -711,14 +738,30 @@ struct Buffer_Vk : public Buffer, public Late_Terminated { } }; +struct Render_Pass_States { + Resource_State colours[max_colour_attachments]; + Resource_State depth; + int colour_count; + + bool operator==(const Render_Pass_States& other) const { + int i; + if (colour_count != other.colour_count) return false; + if (depth != other.depth) return false; + for (i = 0; i < colour_count; i++) + if (colours[i] != other.colours[i]) + return false; + return true; + } +}; + struct Rpo_Key { - bool is_first; Render_Pass rpo; + Render_Pass_States states; bool operator==(const Rpo_Key& other) const { return - is_first == other.is_first && - rpo.layout_eq(other.rpo); + rpo.layout_eq(other.rpo) && + states == other.states; } }; @@ -902,8 +945,8 @@ struct Hash_Function<Rpo_Key> { size_t operator()(const Rpo_Key& k) const { return (size_t)fnv1a64_2( k.rpo.layout_hash, - (uint8_t*)&k.is_first, - 1 + (uint8_t*)&k.states, + sizeof k.states ); } }; @@ -1061,7 +1104,6 @@ struct Device_Vk : public Device { Terminator* terminators; uint32_t terminator_index; - bool first_rp; Texture_Id depth; @@ -1116,6 +1158,7 @@ struct Device_Vk : public Device { uint32_t filter, VkMemoryPropertyFlags flags ); + Render_Pass_States get_rp_states(const Render_Pass& p); }; #ifdef DEBUG @@ -1682,6 +1725,25 @@ int Device_Vk::find_memory_type( return -1; } +Render_Pass_States Device_Vk::get_rp_states( + const Render_Pass& p +) { + int i; + Render_Pass_States s{}; + s.colour_count = p.colour_count; + for (i = 0; i < p.colour_count; i++) { + Texture_Vk& t = + *(Texture_Vk*)&get_texture(p.colours[i].id); + s.colours[i] = t.state; + } + if (p.depth.id) { + Texture_Vk& t = + *(Texture_Vk*)&get_texture(p.depth.id); + s.depth = t.state; + } + return s; +} + VkAttachmentLoadOp Renderpass_Vk::load_op_from_mode( Clear_Mode m ) { @@ -1704,6 +1766,7 @@ void Renderpass_Vk::init( VkSubpassDescription sd{}; VkResult r; auto& rp = rpk.rpo; + auto& states = rpk.states; bool has_depth = rp.depth.id; int count = 0, i, c = rp.colour_count; zero(ads, sizeof ads); @@ -1717,10 +1780,11 @@ void Renderpass_Vk::init( ad.storeOp = VK_ATTACHMENT_STORE_OP_STORE; ad.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; ad.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - if (rpk.is_first) - ad.initialLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - else - ad.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + if (colour.mode == Clear_Mode::restore) { + Resource_State state = states.colours[i]; + ad.initialLayout = state_to_image_layout(state); + } else + ad.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; ad.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; car.attachment = index; car.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; @@ -1734,10 +1798,11 @@ void Renderpass_Vk::init( ad.storeOp = VK_ATTACHMENT_STORE_OP_STORE; ad.stencilLoadOp = ad.loadOp; ad.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; - if (rp.depth.mode != Clear_Mode::restore) + if (rp.depth.mode == Clear_Mode::restore) { + Resource_State state = states.depth; + ad.initialLayout = state_to_image_layout<true>(state); + } else ad.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - else - ad.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; ad.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; dar.attachment = i; dar.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; @@ -1934,6 +1999,7 @@ Texture_Id Swapchain::create_image( Texture_Vk::init( &tex, id, + 0, image, view, Vram_Allocator::Allocation::null(), @@ -1982,9 +2048,6 @@ void Swapchain::get_images(Device_Vk* dev) { size.width, size.height ); - /* needs to be presentable since the first renderpass - * will expect it to be presentable from "last" frame */ - ctx.transition(textures[i], Resource_State::presentable); } dev->submit(ctx); heap_free(dev->heap, images); @@ -2047,7 +2110,6 @@ void Device::begin_frame() { &dev->backbuffer_index ); dev->backbuffer_id = dev->swapchain.textures[dev->backbuffer_index]; - dev->first_rp = true; } void Device::submit(Context& ctx_) { @@ -2205,13 +2267,9 @@ void Context::submit( Context_Vk* ctx = (Context_Vk*)this; Device_Vk* dev = ctx->dev; Vertex_Buffer_Binding* binding; - Rpo_Key rpo_key = { dev->first_rp, rp }; + Rpo_Key rpo_key = { rp, dev->get_rp_states(rp) }; Pso_Key pso_key = { p, rpo_key }; Pipeline_Vk& pso = dev->get_pso(pso_key); - Descriptor_Set_Vk* dso = 0; - if (p.descriptor_count) - dso = &dev->get_dso(pso, *(Dso_Key*)&p); - auto [rpo, fbo] = ctx->begin_rp(rp); Texture_Vk& target = *(Texture_Vk*)&dev->get_texture( dev->get_backbuffer() ); @@ -2223,19 +2281,8 @@ void Context::submit( pso.pip ); ctx->last_pso = pso.pip; - if (dso && dso->dset != ctx->last_dso) { - vkCmdBindDescriptorSets( - ctx->cb, - VK_PIPELINE_BIND_POINT_GRAPHICS, - pso.lay, - 0, - 1, - &dso->dset, - 0, - 0 - ); - ctx->last_dso = dso->dset; - } + ctx->submit_descriptors(pso, p); + auto [rpo, fbo] = ctx->begin_rp(rpo_key); for (binding = draw.verts; binding->id; binding++) { VkBuffer buf = ((Buffer_Vk*)&dev->get_buffer(binding->id))->buf; VkDeviceSize offset = (VkDeviceSize)binding->offset; @@ -2268,10 +2315,8 @@ void Context::submit( draw.first_instance ); } - ctx->end_rp(rpo, fbo); + ctx->end_rp(rp, rpo, fbo); pso.on_submit(); - if (dso) - dso->on_submit(); } void Context::submit( @@ -2316,6 +2361,7 @@ void Context::copy(Texture_Id dst, Buffer_Id src) { Texture_Vk& a = *(Texture_Vk*)&dev->get_texture(dst); Buffer_Vk& b = *(Buffer_Vk*)&dev->get_buffer(src); VkBufferImageCopy c{}; + transition(dst, Resource_State::copy_dst); c.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; c.imageSubresource.layerCount = 1; c.imageExtent.width = a.w; @@ -2337,12 +2383,35 @@ void Context::transition(Texture_Id id, Resource_State state) { Device_Vk* dev = ctx->dev; Texture_Vk& tex = *(Texture_Vk*)&dev->get_texture(id); VkImageMemoryBarrier b{}; + int c = tex.child_count; VkImageLayout src_layout = state_to_image_layout(tex.state); VkImageLayout dst_layout = state_to_image_layout(state); VkPipelineStageFlags src_stage, dst_stage; + if (c) { + if (tex.child_states_same(dev)) { + tex.state = + ((Texture_Vk*)&dev->get_texture(tex.children[0]))->state; + src_layout = state_to_image_layout(tex.state); + } else { + ctx->check_end_rp(); + int i; + for (i = 0; i < c; i++) { + transition(tex.children[i], state); + } + tex.state = state; + return; + } + } if (tex.state == state) return; ctx->check_end_rp(); - tex.state = state; + tex.state = state; { + int i; + for (i = 0; i < c; i++) { + Texture_Vk& child = + *(Texture_Vk*)&dev->get_texture(tex.children[i]); + child.state = state; + } + } b.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; b.oldLayout = src_layout; b.newLayout = dst_layout; @@ -2489,9 +2558,10 @@ void Context::debug_pop() { } std::pair<Renderpass_Vk&, Framebuffer_Vk&> Context_Vk::begin_rp( - const Render_Pass& rp + const Rpo_Key& rpk ) { - Renderpass_Vk& rpo = dev->get_rpo({ dev->first_rp, rp}); + const Render_Pass& rp = rpk.rpo; + Renderpass_Vk& rpo = dev->get_rpo(rpk); Framebuffer_Vk& fbo = dev->get_fbo(rpo, { rp }); VkRenderPassBeginInfo rpbi{}; VkClearValue clears[max_colour_attachments + 1]; @@ -2518,8 +2588,6 @@ std::pair<Renderpass_Vk&, Framebuffer_Vk&> Context_Vk::begin_rp( dc.depthStencil.depth = rp.depth.clear.depth; dc.depthStencil.stencil = 0; /* todo */ clears[clear_count++] = dc; - if (rp.depth.mode == Clear_Mode::restore) - transition(rp.depth.id, Resource_State::render_target); } rpbi.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; rpbi.renderPass = rpo.rpo; @@ -2532,13 +2600,28 @@ std::pair<Renderpass_Vk&, Framebuffer_Vk&> Context_Vk::begin_rp( &rpbi, VK_SUBPASS_CONTENTS_INLINE ); - dev->first_rp = false; last_rpo = rpo.rpo; last_fbo = fbo.fbo; return { rpo, fbo }; } -void Context_Vk::end_rp(Renderpass_Vk& rpo, Framebuffer_Vk& fbo) { +void Context_Vk::end_rp( + const Render_Pass& rp, + Renderpass_Vk& rpo, + Framebuffer_Vk& fbo +) { + bool has_depth = rp.depth.id; + int i, c = rp.colour_count; + for (i = 0; i < c; i++){ + Texture_Vk& tex = + *(Texture_Vk*)&dev->get_texture(rp.colours[i].id); + tex.state = Resource_State::render_target; + } + if (has_depth) { + Texture_Vk& tex = + *(Texture_Vk*)&dev->get_texture(rp.depth.id); + tex.state = Resource_State::render_target; + } rpo.on_submit(); fbo.on_submit(); } @@ -2550,10 +2633,49 @@ void Context_Vk::check_end_rp() { } } +void Context_Vk::submit_descriptors( + const Pipeline_Vk& pso, + const Pipeline& p +) { + Descriptor_Set_Vk* dso = 0; + if (p.descriptor_count) { + dso = &dev->get_dso(pso, *(Dso_Key*)&p); + if (dso->dset == last_dso) return; + + int i, c = p.descriptor_count; + for (i = 0; i < c; i++) { + const auto& desc = p.descriptors[i]; + switch (desc.type) { + case Descriptor::Type::texture: { + const auto& td = *(const Texture_Descriptor*)desc.payload; + transition(td.texture, Resource_State::shader_read); + } break; + case Descriptor::Type::constant_buffer: + break; /* todo */ + } + } + vkCmdBindDescriptorSets( + cb, + VK_PIPELINE_BIND_POINT_GRAPHICS, + pso.lay, + 0, + 1, + &dso->dset, + 0, + 0 + ); + last_dso = dso->dset; + dso->on_submit(); + } +} + void Context::submit(const Render_Pass& rp) { Context_Vk* ctx = (Context_Vk*)this; - auto [rpo, fbo] = ctx->begin_rp(rp); - ctx->end_rp(rpo, fbo); + auto [rpo, fbo] = ctx->begin_rp({ + rp, + ctx->dev->get_rp_states(rp) + }); + ctx->end_rp(rp, rpo, fbo); } void Context_Vk::init_pool() { @@ -3538,9 +3660,8 @@ Texture_Id Device::create_texture( 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; + array_size *= 6; image_flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; } if (mip_count == 0) @@ -3551,7 +3672,7 @@ Texture_Id Device::create_texture( ii.extent.height = h; ii.extent.depth = d; ii.mipLevels = mip_count; - ii.arrayLayers = array_count; + ii.arrayLayers = array_size; ii.format = get_vk_format(fmt); ii.tiling = VK_IMAGE_TILING_OPTIMAL; ii.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; @@ -3586,13 +3707,13 @@ Texture_Id Device::create_texture( ); vi.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; vi.image = image; - vi.viewType = get_view_type(array_count, d, flags); + vi.viewType = get_view_type(array_size, 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; + vi.subresourceRange.layerCount = array_size; r = vkCreateImageView(dev->dev, &vi, &dev->ac, &view); if (r != VK_SUCCESS) { print_err("Failed to make image view.\n"); @@ -3601,6 +3722,7 @@ Texture_Id Device::create_texture( Texture_Vk::init( &tex, id, + 0, image, view, mem, @@ -3618,9 +3740,7 @@ Texture_Id Device::create_texture( ); if (init) { Context& ctx = dev->acquire(); - ctx.transition(id, Resource_State::copy_dst); ctx.copy(id, init); - ctx.transition(id, Resource_State::shader_read); dev->submit(ctx); } tex.set_name(dev, name); @@ -3665,6 +3785,7 @@ Texture_Id Device::alias_texture( Texture_Vk::init( &nt, ntid, + o, texture.image, view, Vram_Allocator::Allocation::null(), @@ -3680,6 +3801,7 @@ Texture_Id Device::alias_texture( start_array, true ); + texture.add_child(ntid); nt.set_name(dev, name); return ntid; } @@ -3703,6 +3825,37 @@ void Texture_Vk::set_name(Device_Vk* dev, const char* name) { #endif } +void Texture_Vk::add_child(Texture_Id id) { + assert(child_count < max_texture_alias); + children[child_count++] = id; +} + +void Texture_Vk::rem_child(Texture_Id id) { + int i; + for (i = 0; i < child_count; i++) { + if (children[i] == id) { + children[i] = children[child_count - 1]; + return; + } + } +} + +bool Texture_Vk::child_states_same(Device_Vk* dev) { + int i, c = child_count; + bool r = true; + for (i = 0; i < c; i++) { + Texture_Vk& a = + *(Texture_Vk*)&dev->get_texture(children[i]); + int j; + for (j = i + 1; j < c; j++) { + Texture_Vk& b = + *(Texture_Vk*)&dev->get_texture(children[j]); + if (a.state != b.state) r = false; + } + } + return r; +} + Shader& Device::get_shader(Shader_Id id) { Device_Vk* dev = (Device_Vk*)this; assert(id.index); @@ -3943,6 +4096,7 @@ void Texture_Loader::unload(Asset* a) { void Texture_Vk::init( Texture_Vk* t, Texture_Id id, + Texture_Id parent, VkImage img, VkImageView v, Vram_Allocator::Allocation mem, @@ -3959,6 +4113,7 @@ void Texture_Vk::init( bool alias ) { t->id = id; + t->parent = parent; t->image = img; t->view = v; t->memory = mem; @@ -3982,6 +4137,10 @@ void Texture_Vk::destroy(Device_Vk* dev) { vkDestroyImage(dev->dev, image, &dev->ac); dev->vrama.free(memory); } + if (parent) { + Texture_Vk& t = *(Texture_Vk*)&dev->get_texture(parent); + t.rem_child(id); + } vkDestroyImageView(dev->dev, view, &dev->ac); dev->textures.remove(id); } |