diff options
author | Juan Linietsky <reduzio@gmail.com> | 2019-06-24 16:13:06 -0300 |
---|---|---|
committer | Juan Linietsky <reduzio@gmail.com> | 2020-02-11 11:53:27 +0100 |
commit | 1b4281b895f3046ea972256182b18696a25f8316 (patch) | |
tree | 5f6b9c1600a4354f17b29e430a447d08f93ecf25 /drivers | |
parent | 42b44f43ee52eb664d3610d0fdae0eff14c00f0a (diff) |
basic 2D engine is more or less working with Vulkan, including editor.
Still a lot to do
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/dummy/rasterizer_dummy.h | 2 | ||||
-rw-r--r-- | drivers/gles2/rasterizer_storage_gles2.cpp | 2 | ||||
-rw-r--r-- | drivers/gles2/rasterizer_storage_gles2.h | 2 | ||||
-rw-r--r-- | drivers/gles3/rasterizer_storage_gles3.cpp | 2 | ||||
-rw-r--r-- | drivers/gles3/rasterizer_storage_gles3.h | 2 | ||||
-rw-r--r-- | drivers/vulkan/rendering_device_vulkan.cpp | 291 | ||||
-rw-r--r-- | drivers/vulkan/rendering_device_vulkan.h | 71 | ||||
-rw-r--r-- | drivers/vulkan/vk_mem_alloc.cpp | 3 | ||||
-rw-r--r-- | drivers/vulkan/vulkan_context.cpp | 504 | ||||
-rw-r--r-- | drivers/vulkan/vulkan_context.h | 93 |
10 files changed, 641 insertions, 331 deletions
diff --git a/drivers/dummy/rasterizer_dummy.h b/drivers/dummy/rasterizer_dummy.h index 648a8f8d44..796e276418 100644 --- a/drivers/dummy/rasterizer_dummy.h +++ b/drivers/dummy/rasterizer_dummy.h @@ -701,7 +701,7 @@ public: void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) {} void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) {} bool render_target_was_used(RID p_render_target) { return false; } - void render_target_clear_used_flag(RID p_render_target) {} + void render_target_set_as_unused(RID p_render_target) {} void render_target_set_msaa(RID p_render_target, VS::ViewportMSAA p_msaa) {} /* CANVAS SHADOW */ diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp index 0b44234173..2e06850413 100644 --- a/drivers/gles2/rasterizer_storage_gles2.cpp +++ b/drivers/gles2/rasterizer_storage_gles2.cpp @@ -5358,7 +5358,7 @@ bool RasterizerStorageGLES2::render_target_was_used(RID p_render_target) { return rt->used_in_frame; } -void RasterizerStorageGLES2::render_target_clear_used_flag(RID p_render_target) { +void RasterizerStorageGLES2::render_target_set_as_unused(RID p_render_target) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND(!rt); diff --git a/drivers/gles2/rasterizer_storage_gles2.h b/drivers/gles2/rasterizer_storage_gles2.h index de4dfe3f46..79e3f610ea 100644 --- a/drivers/gles2/rasterizer_storage_gles2.h +++ b/drivers/gles2/rasterizer_storage_gles2.h @@ -1247,7 +1247,7 @@ public: virtual void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value); virtual bool render_target_was_used(RID p_render_target); - virtual void render_target_clear_used_flag(RID p_render_target); + virtual void render_target_set_as_unused(RID p_render_target); virtual void render_target_set_msaa(RID p_render_target, VS::ViewportMSAA p_msaa); /* CANVAS SHADOW */ diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index 5542f06eb6..5b19dee7cb 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -7594,7 +7594,7 @@ bool RasterizerStorageGLES3::render_target_was_used(RID p_render_target) { return rt->used_in_frame; } -void RasterizerStorageGLES3::render_target_clear_used_flag(RID p_render_target) { +void RasterizerStorageGLES3::render_target_set_as_unused(RID p_render_target) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND(!rt); diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index 4137ab44fb..c4e4ac87e4 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -1404,7 +1404,7 @@ public: virtual void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value); virtual bool render_target_was_used(RID p_render_target); - virtual void render_target_clear_used_flag(RID p_render_target); + virtual void render_target_set_as_unused(RID p_render_target); virtual void render_target_set_msaa(RID p_render_target, VS::ViewportMSAA p_msaa); /* CANVAS SHADOW */ diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index ed044ceb05..516853a64e 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -24,20 +24,14 @@ void RenderingDeviceVulkan::_add_dependency(RID p_id, RID p_depends_on) { void RenderingDeviceVulkan::_free_dependencies(RID p_id) { //direct dependencies must be freed - List<RID> to_free; + Map<RID, Set<RID> >::Element *E = dependency_map.find(p_id); if (E) { - for (Set<RID>::Element *F = E->get().front(); F; F = F->next()) { - to_free.push_back(F->get()); + while (E->get().size()) { + free(E->get().front()->get()); } - dependency_map.erase(E); - - while (to_free.front()) { - free(to_free.front()->get()); - to_free.pop_front(); - } } //reverse depenencies must be unreferenced @@ -47,9 +41,9 @@ void RenderingDeviceVulkan::_free_dependencies(RID p_id) { for (Set<RID>::Element *F = E->get().front(); F; F = F->next()) { Map<RID, Set<RID> >::Element *G = dependency_map.find(F->get()); - if (G) { - G->get().erase(p_id); - } + ERR_CONTINUE(!G); + ERR_CONTINUE(!G->get().has(p_id)); + G->get().erase(p_id); } reverse_dependency_map.erase(E); @@ -1210,7 +1204,6 @@ Error RenderingDeviceVulkan::_buffer_free(Buffer *p_buffer) { ERR_FAIL_COND_V(p_buffer->size == 0, ERR_INVALID_PARAMETER); vmaDestroyBuffer(allocator, p_buffer->buffer, p_buffer->allocation); - vmaFreeMemory(allocator, p_buffer->allocation); p_buffer->buffer = NULL; p_buffer->allocation = NULL; p_buffer->size = 0; @@ -1455,6 +1448,16 @@ Error RenderingDeviceVulkan::_buffer_update(Buffer *p_buffer, size_t p_offset, c return OK; } +void RenderingDeviceVulkan::_memory_barrier(VkPipelineStageFlags p_src_stage_mask, VkPipelineStageFlags p_dst_stage_mask, VkAccessFlags p_src_access, VkAccessFlags p_dst_sccess, bool p_sync_with_draw) { + + VkMemoryBarrier mem_barrier; + mem_barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; + mem_barrier.pNext = NULL; + mem_barrier.srcAccessMask = p_src_access; + mem_barrier.dstAccessMask = p_dst_sccess; + + vkCmdPipelineBarrier(p_sync_with_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer, p_src_stage_mask, p_dst_stage_mask, 0, 1, &mem_barrier, 0, NULL, 0, NULL); +} /*****************/ /**** TEXTURE ****/ /*****************/ @@ -1753,7 +1756,6 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T if (err) { vmaDestroyImage(allocator, texture.image, texture.allocation); - vmaFreeMemory(allocator, texture.allocation); ERR_FAIL_V(RID()); } @@ -2082,6 +2084,16 @@ Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, con return OK; } +bool RenderingDeviceVulkan::texture_is_shared(RID p_texture) { + Texture *tex = texture_owner.getornull(p_texture); + ERR_FAIL_COND_V(!tex, false); + return tex->owner.is_valid(); +} + +bool RenderingDeviceVulkan::texture_is_valid(RID p_texture) { + return texture_owner.owns(p_texture); +} + bool RenderingDeviceVulkan::texture_is_format_supported_for_usage(DataFormat p_format, uint32_t p_usage) const { ERR_FAIL_INDEX_V(p_format, DATA_FORMAT_MAX, false); @@ -2487,7 +2499,9 @@ RID RenderingDeviceVulkan::vertex_buffer_create(uint32_t p_size_bytes, const Poo uint64_t data_size = p_data.size(); PoolVector<uint8_t>::Read r = p_data.read(); _buffer_update(&buffer, 0, r.ptr(), data_size); + _memory_barrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, false); } + return vertex_buffer_owner.make_rid(buffer); } @@ -2498,14 +2512,17 @@ RenderingDevice::VertexFormatID RenderingDeviceVulkan::vertex_format_create(cons VertexDescriptionKey key; key.vertex_formats = p_vertex_formats; - const Map<VertexDescriptionKey, VertexFormatID>::Element *E = vertex_format_cache.find(key); - if (E) { - return E->get(); + + VertexFormatID *idptr = vertex_format_cache.getptr(key); + if (idptr) { + return *idptr; } + //does not exist, create one and cache it VertexDescriptionCache vdcache; vdcache.bindings = memnew_arr(VkVertexInputBindingDescription, p_vertex_formats.size()); vdcache.attributes = memnew_arr(VkVertexInputAttributeDescription, p_vertex_formats.size()); + Set<int> used_locations; for (int i = 0; i < p_vertex_formats.size(); i++) { ERR_CONTINUE(p_vertex_formats[i].format >= DATA_FORMAT_MAX); @@ -2533,9 +2550,10 @@ RenderingDevice::VertexFormatID RenderingDeviceVulkan::vertex_format_create(cons vdcache.create_info.vertexBindingDescriptionCount = p_vertex_formats.size(); vdcache.create_info.pVertexBindingDescriptions = vdcache.bindings; + vdcache.vertex_formats = p_vertex_formats; VertexFormatID id = VertexFormatID(vertex_format_cache.size()) | (VertexFormatID(ID_TYPE_VERTEX_FORMAT) << ID_BASE_SHIFT); - vdcache.E = vertex_format_cache.insert(key, id); + vertex_format_cache[key] = id; vertex_formats[id] = vdcache; return id; } @@ -2547,7 +2565,7 @@ RID RenderingDeviceVulkan::vertex_array_create(uint32_t p_vertex_count, VertexFo ERR_FAIL_COND_V(!vertex_formats.has(p_vertex_format), RID()); const VertexDescriptionCache &vd = vertex_formats[p_vertex_format]; - ERR_FAIL_COND_V(vd.E->key().vertex_formats.size() != p_src_buffers.size(), RID()); + ERR_FAIL_COND_V(vd.vertex_formats.size() != p_src_buffers.size(), RID()); for (int i = 0; i < p_src_buffers.size(); i++) { ERR_FAIL_COND_V(!vertex_buffer_owner.owns(p_src_buffers[i]), RID()); @@ -2563,7 +2581,8 @@ RID RenderingDeviceVulkan::vertex_array_create(uint32_t p_vertex_count, VertexFo //validate with buffer { - const VertexDescription &atf = vd.E->key().vertex_formats[i]; + const VertexDescription &atf = vd.vertex_formats[i]; + uint32_t element_size = get_format_vertex_size(atf.format); ERR_FAIL_COND_V(element_size == 0, RID()); //should never happens since this was prevalidated @@ -2641,6 +2660,7 @@ RID RenderingDeviceVulkan::index_buffer_create(uint32_t p_index_count, IndexBuff uint64_t data_size = p_data.size(); PoolVector<uint8_t>::Read r = p_data.read(); _buffer_update(&index_buffer, 0, r.ptr(), data_size); + _memory_barrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_INDEX_READ_BIT, false); } return index_buffer_owner.make_rid(index_buffer); } @@ -3314,6 +3334,7 @@ RID RenderingDeviceVulkan::uniform_buffer_create(uint32_t p_size_bytes, const Po uint64_t data_size = p_data.size(); PoolVector<uint8_t>::Read r = p_data.read(); _buffer_update(&buffer, 0, r.ptr(), data_size); + _memory_barrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_UNIFORM_READ_BIT, false); } return uniform_buffer_owner.make_rid(buffer); } @@ -3332,6 +3353,7 @@ RID RenderingDeviceVulkan::storage_buffer_create(uint32_t p_size_bytes, const Po uint64_t data_size = p_data.size(); PoolVector<uint8_t>::Read r = p_data.read(); _buffer_update(&buffer, 0, r.ptr(), data_size); + _memory_barrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, false); } return storage_buffer_owner.make_rid(buffer); } @@ -3354,6 +3376,7 @@ RID RenderingDeviceVulkan::texture_buffer_create(uint32_t p_size_elements, DataF uint64_t data_size = p_data.size(); PoolVector<uint8_t>::Read r = p_data.read(); _buffer_update(&texture_buffer.buffer, 0, r.ptr(), data_size); + _memory_barrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, false); } VkBufferViewCreateInfo view_create_info; @@ -3483,6 +3506,9 @@ void RenderingDeviceVulkan::_descriptor_pool_free(const DescriptorPoolKey &p_key vkDestroyDescriptorPool(device, p_pool->pool, NULL); descriptor_pools[p_key].erase(p_pool); memdelete(p_pool); + if (descriptor_pools[p_key].empty()) { + descriptor_pools.erase(p_key); + } } } @@ -3857,16 +3883,29 @@ bool RenderingDeviceVulkan::uniform_set_is_valid(RID p_uniform_set) { Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, void *p_data, bool p_sync_with_draw) { _THREAD_SAFE_METHOD_ + VkPipelineStageFlags dst_stage_mask; + VkAccessFlags dst_access; + Buffer *buffer = NULL; if (vertex_buffer_owner.owns(p_buffer)) { + dst_stage_mask = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; + dst_access = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT; buffer = vertex_buffer_owner.getornull(p_buffer); } else if (index_buffer_owner.owns(p_buffer)) { + dst_stage_mask = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; + dst_access = VK_ACCESS_INDEX_READ_BIT; buffer = index_buffer_owner.getornull(p_buffer); } else if (uniform_buffer_owner.owns(p_buffer)) { + dst_stage_mask = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; + dst_access = VK_ACCESS_UNIFORM_READ_BIT; buffer = uniform_buffer_owner.getornull(p_buffer); } else if (texture_buffer_owner.owns(p_buffer)) { + dst_stage_mask = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; + dst_access = VK_ACCESS_SHADER_READ_BIT; buffer = &texture_buffer_owner.getornull(p_buffer)->buffer; } else if (storage_buffer_owner.owns(p_buffer)) { + dst_stage_mask = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; + dst_access = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; buffer = storage_buffer_owner.getornull(p_buffer); } else { ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Buffer argument is not a valid buffer of any type."); @@ -3875,7 +3914,14 @@ Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint ERR_FAIL_COND_V_MSG(p_offset + p_size > buffer->size, ERR_INVALID_PARAMETER, "Attempted to write buffer (" + itos((p_offset + p_size) - buffer->size) + " bytes) past the end."); - return _buffer_update(buffer, p_offset, (uint8_t *)p_data, p_size, p_sync_with_draw); + Error err = _buffer_update(buffer, p_offset, (uint8_t *)p_data, p_size, p_sync_with_draw); + if (err) { + return err; + } + + _memory_barrier(VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stage_mask, VK_ACCESS_TRANSFER_WRITE_BIT, dst_access, p_sync_with_draw); + + return err; } /*************************/ @@ -3908,17 +3954,16 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma if (p_vertex_format != INVALID_ID) { //uses vertices, else it does not ERR_FAIL_COND_V(!vertex_formats.has(p_vertex_format), RID()); - VertexDescriptionCache &vd = vertex_formats[p_vertex_format]; + const VertexDescriptionCache &vd = vertex_formats[p_vertex_format]; pipeline_vertex_input_state_create_info = vd.create_info; //validate with inputs for (int i = 0; i < shader->vertex_input_locations.size(); i++) { uint32_t location = shader->vertex_input_locations[i]; - const VertexDescriptionKey &k = vd.E->key(); bool found = false; - for (int j = 0; j < k.vertex_formats.size(); j++) { - if (k.vertex_formats[j].location == location) { + for (int j = 0; j < vd.vertex_formats.size(); j++) { + if (vd.vertex_formats[j].location == location) { found = true; } } @@ -4237,6 +4282,11 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma return id; } +bool RenderingDeviceVulkan::render_pipeline_is_valid(RID p_pipeline) { + _THREAD_SAFE_METHOD_ + return pipeline_owner.owns(p_pipeline); +} + /****************/ /**** SCREEN ****/ /****************/ @@ -4244,12 +4294,12 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma int RenderingDeviceVulkan::screen_get_width(int p_screen) const { _THREAD_SAFE_METHOD_ - return context->get_screen_width(p_screen); + return context->window_get_width(p_screen); } int RenderingDeviceVulkan::screen_get_height(int p_screen) const { _THREAD_SAFE_METHOD_ - return context->get_screen_height(p_screen); + return context->window_get_height(p_screen); } RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::screen_get_framebuffer_format() const { @@ -4295,11 +4345,11 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin_for_screen(in VkRenderPassBeginInfo render_pass_begin; render_pass_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; render_pass_begin.pNext = NULL; - render_pass_begin.renderPass = context->get_render_pass(); - render_pass_begin.framebuffer = context->get_frame_framebuffer(frame); + render_pass_begin.renderPass = context->window_get_render_pass(p_screen); + render_pass_begin.framebuffer = context->window_get_framebuffer(p_screen); - render_pass_begin.renderArea.extent.width = context->get_screen_width(p_screen); - render_pass_begin.renderArea.extent.height = context->get_screen_height(p_screen); + render_pass_begin.renderArea.extent.width = context->window_get_width(p_screen); + render_pass_begin.renderArea.extent.height = context->window_get_height(p_screen); render_pass_begin.renderArea.offset.x = 0; render_pass_begin.renderArea.offset.y = 0; @@ -4504,6 +4554,7 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebu vkCmdSetScissor(command_buffer, 0, 1, &scissor); + draw_list->viewport = Rect2i(viewport_offset, viewport_size); return ID_TYPE_DRAW_LIST; } @@ -4646,6 +4697,8 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p vkCmdSetScissor(command_buffer, 0, 1, &scissor); r_split_ids[i] = (DrawListID(1) << DrawListID(ID_TYPE_SPLIT_DRAW_LIST)) + i; + + draw_list[i].viewport = Rect2i(viewport_offset, viewport_size); } return OK; @@ -4776,6 +4829,15 @@ void RenderingDeviceVulkan::draw_list_bind_index_array(DrawListID p_list, RID p_ vkCmdBindIndexBuffer(dl->command_buffer, index_array->buffer, index_array->offset, index_array->index_type); } +void RenderingDeviceVulkan::draw_list_set_line_width(DrawListID p_list, float p_width) { + + DrawList *dl = _get_draw_list_ptr(p_list); + ERR_FAIL_COND(!dl); + ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); + + vkCmdSetLineWidth(dl->command_buffer, p_width); +} + void RenderingDeviceVulkan::draw_list_set_push_constant(DrawListID p_list, void *p_data, uint32_t p_data_size) { DrawList *dl = _get_draw_list_ptr(p_list); ERR_FAIL_COND(!dl); @@ -4873,8 +4935,37 @@ void RenderingDeviceVulkan::draw_list_draw(DrawListID p_list, bool p_use_indices } void RenderingDeviceVulkan::draw_list_enable_scissor(DrawListID p_list, const Rect2 &p_rect) { + DrawList *dl = _get_draw_list_ptr(p_list); + ERR_FAIL_COND(!dl); + ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); + + Rect2i rect = p_rect; + rect.position += dl->viewport.position; + + rect = dl->viewport.clip(rect); + + if (rect.get_area() == 0) { + return; + } + VkRect2D scissor; + scissor.offset.x = rect.position.x; + scissor.offset.y = rect.position.y; + scissor.extent.width = rect.size.width; + scissor.extent.height = rect.size.height; + + vkCmdSetScissor(dl->command_buffer, 0, 1, &scissor); } void RenderingDeviceVulkan::draw_list_disable_scissor(DrawListID p_list) { + DrawList *dl = _get_draw_list_ptr(p_list); + ERR_FAIL_COND(!dl); + ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified."); + + VkRect2D scissor; + scissor.offset.x = dl->viewport.position.x; + scissor.offset.y = dl->viewport.position.y; + scissor.extent.width = dl->viewport.size.width; + scissor.extent.height = dl->viewport.size.height; + vkCmdSetScissor(dl->command_buffer, 0, 1, &scissor); } void RenderingDeviceVulkan::draw_list_end() { @@ -4997,6 +5088,7 @@ void RenderingDeviceVulkan::_free_internal(RID p_id) { Buffer b; b.allocation = index_buffer->allocation; b.buffer = index_buffer->buffer; + b.size = index_buffer->size; frames[frame].buffers_to_dispose_of.push_back(b); index_buffer_owner.free(p_id); } else if (index_array_owner.owns(p_id)) { @@ -5050,42 +5142,42 @@ void RenderingDeviceVulkan::finalize_frame() { vkEndCommandBuffer(frames[frame].setup_command_buffer); vkEndCommandBuffer(frames[frame].draw_command_buffer); } + screen_prepared = false; } -void RenderingDeviceVulkan::_free_pending_resources() { +void RenderingDeviceVulkan::_free_pending_resources(int p_frame) { //free in dependency usage order, so nothing weird happens - //pipelines - while (frames[frame].pipelines_to_dispose_of.front()) { - RenderPipeline *pipeline = &frames[frame].pipelines_to_dispose_of.front()->get(); + while (frames[p_frame].pipelines_to_dispose_of.front()) { + RenderPipeline *pipeline = &frames[p_frame].pipelines_to_dispose_of.front()->get(); vkDestroyPipeline(device, pipeline->pipeline, NULL); - frames[frame].pipelines_to_dispose_of.pop_front(); + frames[p_frame].pipelines_to_dispose_of.pop_front(); } //uniform sets - while (frames[frame].uniform_sets_to_dispose_of.front()) { - UniformSet *uniform_set = &frames[frame].uniform_sets_to_dispose_of.front()->get(); + while (frames[p_frame].uniform_sets_to_dispose_of.front()) { + UniformSet *uniform_set = &frames[p_frame].uniform_sets_to_dispose_of.front()->get(); vkFreeDescriptorSets(device, uniform_set->pool->pool, 1, &uniform_set->descriptor_set); _descriptor_pool_free(uniform_set->pool_key, uniform_set->pool); - frames[frame].uniform_sets_to_dispose_of.pop_front(); + frames[p_frame].uniform_sets_to_dispose_of.pop_front(); } //buffer views - while (frames[frame].buffer_views_to_dispose_of.front()) { - VkBufferView buffer_view = frames[frame].buffer_views_to_dispose_of.front()->get(); + while (frames[p_frame].buffer_views_to_dispose_of.front()) { + VkBufferView buffer_view = frames[p_frame].buffer_views_to_dispose_of.front()->get(); vkDestroyBufferView(device, buffer_view, NULL); - frames[frame].buffer_views_to_dispose_of.pop_front(); + frames[p_frame].buffer_views_to_dispose_of.pop_front(); } //shaders - while (frames[frame].shaders_to_dispose_of.front()) { - Shader *shader = &frames[frame].shaders_to_dispose_of.front()->get(); + while (frames[p_frame].shaders_to_dispose_of.front()) { + Shader *shader = &frames[p_frame].shaders_to_dispose_of.front()->get(); //descriptor set layout for each set for (int i = 0; i < shader->sets.size(); i++) { @@ -5100,21 +5192,21 @@ void RenderingDeviceVulkan::_free_pending_resources() { vkDestroyShaderModule(device, shader->pipeline_stages[i].module, NULL); } - frames[frame].shaders_to_dispose_of.pop_front(); + frames[p_frame].shaders_to_dispose_of.pop_front(); } //samplers - while (frames[frame].samplers_to_dispose_of.front()) { - VkSampler sampler = frames[frame].samplers_to_dispose_of.front()->get(); + while (frames[p_frame].samplers_to_dispose_of.front()) { + VkSampler sampler = frames[p_frame].samplers_to_dispose_of.front()->get(); vkDestroySampler(device, sampler, NULL); - frames[frame].samplers_to_dispose_of.pop_front(); + frames[p_frame].samplers_to_dispose_of.pop_front(); } //framebuffers - while (frames[frame].framebuffers_to_dispose_of.front()) { - Framebuffer *framebuffer = &frames[frame].framebuffers_to_dispose_of.front()->get(); + while (frames[p_frame].framebuffers_to_dispose_of.front()) { + Framebuffer *framebuffer = &frames[p_frame].framebuffers_to_dispose_of.front()->get(); for (Map<Framebuffer::VersionKey, Framebuffer::Version>::Element *E = framebuffer->framebuffers.front(); E; E = E->next()) { //first framebuffer, then render pass because it depends on it @@ -5122,12 +5214,12 @@ void RenderingDeviceVulkan::_free_pending_resources() { vkDestroyRenderPass(device, E->get().render_pass, NULL); } - frames[frame].framebuffers_to_dispose_of.pop_front(); + frames[p_frame].framebuffers_to_dispose_of.pop_front(); } //textures - while (frames[frame].textures_to_dispose_of.front()) { - Texture *texture = &frames[frame].textures_to_dispose_of.front()->get(); + while (frames[p_frame].textures_to_dispose_of.front()) { + Texture *texture = &frames[p_frame].textures_to_dispose_of.front()->get(); if (texture->bound) { WARN_PRINT("Deleted a texture while it was bound.."); @@ -5136,19 +5228,25 @@ void RenderingDeviceVulkan::_free_pending_resources() { if (texture->owner.is_null()) { //actually owns the image and the allocation too vmaDestroyImage(allocator, texture->image, texture->allocation); - vmaFreeMemory(allocator, texture->allocation); } - frames[frame].textures_to_dispose_of.pop_front(); + frames[p_frame].textures_to_dispose_of.pop_front(); } //buffers - while (frames[frame].buffers_to_dispose_of.front()) { - _buffer_free(&frames[frame].buffers_to_dispose_of.front()->get()); + while (frames[p_frame].buffers_to_dispose_of.front()) { + + _buffer_free(&frames[p_frame].buffers_to_dispose_of.front()->get()); - frames[frame].buffers_to_dispose_of.pop_front(); + frames[p_frame].buffers_to_dispose_of.pop_front(); } } +void RenderingDeviceVulkan::prepare_screen_for_drawing() { + _THREAD_SAFE_METHOD_ + context->prepare_buffers(); + screen_prepared = true; +} + void RenderingDeviceVulkan::advance_frame() { _THREAD_SAFE_METHOD_ @@ -5157,7 +5255,7 @@ void RenderingDeviceVulkan::advance_frame() { frame = (frame + 1) % frame_count; //erase pending resources - _free_pending_resources(); + _free_pending_resources(frame); //create setup command buffer and set as the setup buffer @@ -5192,7 +5290,7 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context) { context = p_context; device = p_context->get_device(); - frame_count = p_context->get_frame_count(); + frame_count = p_context->get_swapchain_image_count() + 1; //always need one extra to ensure it's unused at any time, without having to use a fence for this. limits = p_context->get_device_limits(); { //initialize allocator @@ -5292,10 +5390,83 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context) { draw_list_count = 0; draw_list_split = false; } + +template <class T> +void RenderingDeviceVulkan::_free_rids(T &p_owner, const char *p_type) { + List<RID> owned; + p_owner.get_owned_list(&owned); + if (owned.size()) { + WARN_PRINT(itos(owned.size()) + " RIDs of type '" + p_type + "' were leaked."); + for (List<RID>::Element *E = owned.front(); E; E = E->next()) { + free(E->get()); + } + } +} + void RenderingDeviceVulkan::finalize() { + //free all resources + + context->flush(false, false); + + _free_rids(pipeline_owner, "Pipeline"); + _free_rids(uniform_set_owner, "UniformSet"); + _free_rids(texture_buffer_owner, "TextureBuffer"); + _free_rids(storage_buffer_owner, "StorageBuffer"); + _free_rids(uniform_buffer_owner, "UniformBuffer"); + _free_rids(shader_owner, "Shader"); + _free_rids(index_array_owner, "IndexArray"); + _free_rids(index_buffer_owner, "IndexBuffer"); + _free_rids(vertex_array_owner, "VertexArray"); + _free_rids(vertex_buffer_owner, "VertexBuffer"); + _free_rids(framebuffer_owner, "Framebuffer"); + _free_rids(sampler_owner, "Sampler"); + { + //for textures it's a bit more difficult because they may be shared + List<RID> owned; + texture_owner.get_owned_list(&owned); + if (owned.size()) { + WARN_PRINT(itos(owned.size()) + " RIDs of type 'Texture' were leaked."); + //free shared first + for (List<RID>::Element *E = owned.front(); E;) { + + List<RID>::Element *N = E->next(); + if (texture_is_shared(E->get())) { + free(E->get()); + owned.erase(E->get()); + } + E = N; + } + //free non shared second, this will avoid an error trying to free unexisting textures due to dependencies. + for (List<RID>::Element *E = owned.front(); E; E = E->next()) { + free(E->get()); + } + } + } + + //free everything pending + for (int i = 0; i < frame_count; i++) { + int f = (frame + i) % frame_count; + _free_pending_resources(f); + vkDestroyCommandPool(device, frames[i].command_pool, NULL); + } + + for (int i = 0; i < split_draw_list_allocators.size(); i++) { + vkDestroyCommandPool(device, split_draw_list_allocators[i].command_pool, NULL); + } + memdelete_arr(frames); + + for (int i = 0; i < staging_buffer_blocks.size(); i++) { + vmaDestroyBuffer(allocator, staging_buffer_blocks[i].buffer, staging_buffer_blocks[i].allocation); + } + + //all these should be clear at this point + ERR_FAIL_COND(descriptor_pools.size()); + ERR_FAIL_COND(dependency_map.size()); + ERR_FAIL_COND(reverse_dependency_map.size()); } RenderingDeviceVulkan::RenderingDeviceVulkan() { + screen_prepared = false; } diff --git a/drivers/vulkan/rendering_device_vulkan.h b/drivers/vulkan/rendering_device_vulkan.h index e1dfb1fc4b..5042078f84 100644 --- a/drivers/vulkan/rendering_device_vulkan.h +++ b/drivers/vulkan/rendering_device_vulkan.h @@ -6,6 +6,9 @@ #include "core/rid_owner.h" #include "servers/visual/rendering_device.h" #include "thirdparty/glslang/glslang/Public/ShaderLang.h" +#ifdef DEBUG_ENABLED +#define _DEBUG +#endif #include "vk_mem_alloc.h" #include <vulkan/vulkan.h> //todo: @@ -177,6 +180,8 @@ class RenderingDeviceVulkan : public RenderingDevice { Error _buffer_free(Buffer *p_buffer); Error _buffer_update(Buffer *p_buffer, size_t p_offset, const uint8_t *p_data, size_t p_data_size, bool p_use_draw_command_buffer = false, uint32_t p_required_align = 32); + void _memory_barrier(VkPipelineStageFlags p_src_stage_mask, VkPipelineStageFlags p_dst_stage_mask, VkAccessFlags p_src_access, VkAccessFlags p_dst_sccess, bool p_sync_with_draw); + /*********************/ /**** FRAMEBUFFER ****/ /*********************/ @@ -274,15 +279,13 @@ class RenderingDeviceVulkan : public RenderingDevice { struct VertexDescriptionKey { Vector<VertexDescription> vertex_formats; - int buffer_count; - bool operator<(const VertexDescriptionKey &p_key) const { - if (buffer_count != p_key.buffer_count) { - return buffer_count < p_key.buffer_count; - } - if (vertex_formats.size() != p_key.vertex_formats.size()) { - return vertex_formats.size() < p_key.vertex_formats.size(); + bool operator==(const VertexDescriptionKey &p_key) const { + int vdc = vertex_formats.size(); + int vdck = p_key.vertex_formats.size(); + + if (vdc != vdck) { + return false; } else { - int vdc = vertex_formats.size(); const VertexDescription *a_ptr = vertex_formats.ptr(); const VertexDescription *b_ptr = p_key.vertex_formats.ptr(); for (int i = 0; i < vdc; i++) { @@ -290,29 +293,51 @@ class RenderingDeviceVulkan : public RenderingDevice { const VertexDescription &b = b_ptr[i]; if (a.location != b.location) { - return a.location < b.location; + return false; } if (a.offset != b.offset) { - return a.offset < b.offset; + return false; } if (a.format != b.format) { - return a.format < b.format; + return false; } if (a.stride != b.stride) { - return a.stride < b.stride; + return false; } - return a.frequency < b.frequency; + return a.frequency != b.frequency; } - return false; //they are equal + return true; //they are equal } } + + uint32_t hash() const { + int vdc = vertex_formats.size(); + uint32_t h = hash_djb2_one_32(vdc); + const VertexDescription *ptr = vertex_formats.ptr(); + for (int i = 0; i < vdc; i++) { + const VertexDescription &vd = ptr[i]; + h = hash_djb2_one_32(vd.location, h); + h = hash_djb2_one_32(vd.offset, h); + h = hash_djb2_one_32(vd.format, h); + h = hash_djb2_one_32(vd.stride, h); + h = hash_djb2_one_32(vd.frequency, h); + } + return h; + } + }; + + struct VertexDescriptionHash { + static _FORCE_INLINE_ uint32_t hash(const VertexDescriptionKey &p_key) { + return p_key.hash(); + } }; // This is a cache and it's never freed, it ensures that // ID used for a specific format always remain the same. - Map<VertexDescriptionKey, VertexFormatID> vertex_format_cache; + HashMap<VertexDescriptionKey, VertexFormatID, VertexDescriptionHash> vertex_format_cache; + struct VertexDescriptionCache { - const Map<VertexDescriptionKey, VertexFormatID>::Element *E; + Vector<VertexDescription> vertex_formats; VkVertexInputBindingDescription *bindings; VkVertexInputAttributeDescription *attributes; VkPipelineVertexInputStateCreateInfo create_info; @@ -570,7 +595,7 @@ class RenderingDeviceVulkan : public RenderingDevice { struct DrawList { VkCommandBuffer command_buffer; //if persistent, this is owned, otherwise it's shared with the ringbuffer - + Rect2i viewport; struct Validation { bool active; //means command buffer was not closes, so you can keep adding things FramebufferFormatID framebuffer_format; @@ -669,7 +694,7 @@ class RenderingDeviceVulkan : public RenderingDevice { int frame_count; //total amount of frames uint64_t frames_drawn; - void _free_pending_resources(); + void _free_pending_resources(int p_frame); VmaAllocator allocator; @@ -677,12 +702,19 @@ class RenderingDeviceVulkan : public RenderingDevice { void _free_internal(RID p_id); + bool screen_prepared; + + template <class T> + void _free_rids(T &p_owner, const char *p_type); + public: virtual RID texture_create(const TextureFormat &p_format, const TextureView &p_view, const Vector<PoolVector<uint8_t> > &p_data = Vector<PoolVector<uint8_t> >()); virtual RID texture_create_shared(const TextureView &p_view, RID p_with_texture); virtual Error texture_update(RID p_texture, uint32_t p_layer, const PoolVector<uint8_t> &p_data, bool p_sync_with_draw = false); virtual bool texture_is_format_supported_for_usage(DataFormat p_format, uint32_t p_usage) const; + virtual bool texture_is_shared(RID p_texture); + virtual bool texture_is_valid(RID p_texture); /*********************/ /**** FRAMEBUFFER ****/ @@ -739,6 +771,7 @@ public: /*************************/ virtual RID render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const PipelineRasterizationState &p_rasterization_state, const PipelineMultisampleState &p_multisample_state, const PipelineDepthStencilState &p_depth_stencil_state, const PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags = 0); + virtual bool render_pipeline_is_valid(RID p_pipeline); /****************/ /**** SCREEN ****/ @@ -760,6 +793,7 @@ public: virtual void draw_list_bind_uniform_set(DrawListID p_list, RID p_uniform_set, uint32_t p_index); virtual void draw_list_bind_vertex_array(DrawListID p_list, RID p_vertex_array); virtual void draw_list_bind_index_array(DrawListID p_list, RID p_index_array); + virtual void draw_list_set_line_width(DrawListID p_list, float p_width); virtual void draw_list_set_push_constant(DrawListID p_list, void *p_data, uint32_t p_data_size); virtual void draw_list_draw(DrawListID p_list, bool p_use_indices, uint32_t p_instances = 1); @@ -775,6 +809,7 @@ public: virtual void free(RID p_id); + virtual void prepare_screen_for_drawing(); void initialize(VulkanContext *p_context); void finalize(); diff --git a/drivers/vulkan/vk_mem_alloc.cpp b/drivers/vulkan/vk_mem_alloc.cpp index a2023d33b2..8e91e8a08c 100644 --- a/drivers/vulkan/vk_mem_alloc.cpp +++ b/drivers/vulkan/vk_mem_alloc.cpp @@ -1,2 +1,5 @@ #define VMA_IMPLEMENTATION +#ifdef DEBUG_ENABLED +#define _DEBUG +#endif #include "vk_mem_alloc.h" diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp index 991429f963..37eb99db7a 100644 --- a/drivers/vulkan/vulkan_context.cpp +++ b/drivers/vulkan/vulkan_context.cpp @@ -471,10 +471,7 @@ Error VulkanContext::_create_device() { return OK; } -Error VulkanContext::_create_swap_chain() { - - VkResult err = _create_surface(&surface, inst); - ERR_FAIL_COND_V(err, ERR_CANT_CREATE); +Error VulkanContext::_initialize_queues(VkSurfaceKHR surface) { // Iterate over each queue to learn whether it supports presenting: VkBool32 *supportsPresent = (VkBool32 *)malloc(queue_family_count * sizeof(VkBool32)); @@ -551,7 +548,7 @@ Error VulkanContext::_create_swap_chain() { // Get the list of VkFormat's that are supported: uint32_t formatCount; - err = fpGetPhysicalDeviceSurfaceFormatsKHR(gpu, surface, &formatCount, NULL); + VkResult err = fpGetPhysicalDeviceSurfaceFormatsKHR(gpu, surface, &formatCount, NULL); ERR_FAIL_COND_V(err, ERR_CANT_CREATE); VkSurfaceFormatKHR *surfFormats = (VkSurfaceFormatKHR *)malloc(formatCount * sizeof(VkSurfaceFormatKHR)); err = fpGetPhysicalDeviceSurfaceFormatsKHR(gpu, surface, &formatCount, surfFormats); @@ -566,6 +563,13 @@ Error VulkanContext::_create_swap_chain() { format = surfFormats[0].format; } color_space = surfFormats[0].colorSpace; + + Error serr = _create_semaphores(); + if (serr) { + return serr; + } + + queues_initialized = true; return OK; } @@ -608,21 +612,111 @@ Error VulkanContext::_create_semaphores() { return OK; } -Error VulkanContext::_prepare_buffers() { +int VulkanContext::_window_create(VkSurfaceKHR p_surface, int p_width, int p_height) { + + if (!queues_initialized) { + // We use a single GPU, but we need a surface to initialize the + // queues, so this process must be deferred until a surface + // is created. + _initialize_queues(p_surface); + } + + Window window; + window.surface = p_surface; + window.width = p_width; + window.height = p_height; + Error err = _update_swap_chain(&window); + ERR_FAIL_COND_V(err != OK, -1); + + int id = last_window_id; + windows[id] = window; + last_window_id++; + return id; +} + +void VulkanContext::window_resize(int p_window, int p_width, int p_height) { + ERR_FAIL_COND(!windows.has(p_window)); + windows[p_window].width = p_width; + windows[p_window].height = p_height; + _update_swap_chain(&windows[p_window]); +} + +int VulkanContext::window_get_width(int p_window) { + ERR_FAIL_COND_V(!windows.has(p_window), -1); + return windows[p_window].width; +} + +int VulkanContext::window_get_height(int p_window) { + ERR_FAIL_COND_V(!windows.has(p_window), -1); + return windows[p_window].height; +} + +VkRenderPass VulkanContext::window_get_render_pass(int p_window) { + ERR_FAIL_COND_V(!windows.has(p_window), VK_NULL_HANDLE); + Window *w = &windows[p_window]; + //vulkan use of currentbuffer + return w->render_pass; +} + +VkFramebuffer VulkanContext::window_get_framebuffer(int p_window) { + ERR_FAIL_COND_V(!windows.has(p_window), VK_NULL_HANDLE); + ERR_FAIL_COND_V(!buffers_prepared, VK_NULL_HANDLE); + Window *w = &windows[p_window]; + //vulkan use of currentbuffer + return w->swapchain_image_resources[w->current_buffer].framebuffer; +} + +void VulkanContext::window_destroy(int p_window_id) { + ERR_FAIL_COND(!windows.has(p_window_id)); + _clean_up_swap_chain(&windows[p_window_id]); + vkDestroySurfaceKHR(inst, windows[p_window_id].surface, NULL); + windows.erase(p_window_id); +} + +Error VulkanContext::_clean_up_swap_chain(Window *window) { + + if (!window->swapchain) { + return OK; + } + vkDeviceWaitIdle(device); + + //this destroys images associated it seems + fpDestroySwapchainKHR(device, window->swapchain, NULL); + window->swapchain = VK_NULL_HANDLE; + vkDestroyRenderPass(device, window->render_pass, NULL); + if (window->swapchain_image_resources) { + for (uint32_t i = 0; i < swapchainImageCount; i++) { + vkDestroyImageView(device, window->swapchain_image_resources[i].view, NULL); + vkDestroyFramebuffer(device, window->swapchain_image_resources[i].framebuffer, NULL); + } + + free(window->swapchain_image_resources); + window->swapchain_image_resources = NULL; + } + if (separate_present_queue) { + vkDestroyCommandPool(device, window->present_cmd_pool, NULL); + } + return OK; +} + +Error VulkanContext::_update_swap_chain(Window *window) { VkResult err; - VkSwapchainKHR oldSwapchain = swapchain; + + if (window->swapchain) { + _clean_up_swap_chain(window); + } // Check the surface capabilities and formats VkSurfaceCapabilitiesKHR surfCapabilities; - err = fpGetPhysicalDeviceSurfaceCapabilitiesKHR(gpu, surface, &surfCapabilities); + err = fpGetPhysicalDeviceSurfaceCapabilitiesKHR(gpu, window->surface, &surfCapabilities); ERR_FAIL_COND_V(err, ERR_CANT_CREATE); uint32_t presentModeCount; - err = fpGetPhysicalDeviceSurfacePresentModesKHR(gpu, surface, &presentModeCount, NULL); + err = fpGetPhysicalDeviceSurfacePresentModesKHR(gpu, window->surface, &presentModeCount, NULL); ERR_FAIL_COND_V(err, ERR_CANT_CREATE); VkPresentModeKHR *presentModes = (VkPresentModeKHR *)malloc(presentModeCount * sizeof(VkPresentModeKHR)); ERR_FAIL_COND_V(!presentModes, ERR_CANT_CREATE); - err = fpGetPhysicalDeviceSurfacePresentModesKHR(gpu, surface, &presentModeCount, presentModes); + err = fpGetPhysicalDeviceSurfacePresentModesKHR(gpu, window->surface, &presentModeCount, presentModes); ERR_FAIL_COND_V(err, ERR_CANT_CREATE); VkExtent2D swapchainExtent; @@ -631,8 +725,8 @@ Error VulkanContext::_prepare_buffers() { // If the surface size is undefined, the size is set to the size // of the images requested, which must fit within the minimum and // maximum values. - swapchainExtent.width = width; - swapchainExtent.height = height; + swapchainExtent.width = window->width; + swapchainExtent.height = window->height; if (swapchainExtent.width < surfCapabilities.minImageExtent.width) { swapchainExtent.width = surfCapabilities.minImageExtent.width; @@ -648,17 +742,14 @@ Error VulkanContext::_prepare_buffers() { } else { // If the surface size is defined, the swap chain size must match swapchainExtent = surfCapabilities.currentExtent; - width = surfCapabilities.currentExtent.width; - height = surfCapabilities.currentExtent.height; + window->width = surfCapabilities.currentExtent.width; + window->height = surfCapabilities.currentExtent.height; } - if (width == 0 || height == 0) { - is_minimized = true; + if (window->width == 0 || window->height == 0) { + //likely window minimized, no swapchain created return OK; - } else { - is_minimized = false; } - // The FIFO present mode is guaranteed by the spec to be supported // and to have no tearing. It's a great default present mode to use. VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR; @@ -690,15 +781,15 @@ Error VulkanContext::_prepare_buffers() { // the application wants the late image to be immediately displayed, even // though that may mean some tearing. - if (presentMode != swapchainPresentMode) { + if (window->presentMode != swapchainPresentMode) { for (size_t i = 0; i < presentModeCount; ++i) { - if (presentModes[i] == presentMode) { - swapchainPresentMode = presentMode; + if (presentModes[i] == window->presentMode) { + swapchainPresentMode = window->presentMode; break; } } } - ERR_FAIL_COND_V_MSG(swapchainPresentMode != presentMode, ERR_CANT_CREATE, "Present mode specified is not supported\n"); + ERR_FAIL_COND_V_MSG(swapchainPresentMode != window->presentMode, ERR_CANT_CREATE, "Present mode specified is not supported\n"); // Determine the number of VkImages to use in the swap chain. // Application desires to acquire 3 images at a time for triple @@ -739,7 +830,7 @@ Error VulkanContext::_prepare_buffers() { VkSwapchainCreateInfoKHR swapchain_ci = { .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, .pNext = NULL, - .surface = surface, + .surface = window->surface, .minImageCount = desiredNumOfSwapchainImages, .imageFormat = format, .imageColorSpace = color_space, @@ -756,33 +847,33 @@ Error VulkanContext::_prepare_buffers() { .compositeAlpha = compositeAlpha, .presentMode = swapchainPresentMode, .clipped = true, - .oldSwapchain = oldSwapchain, + .oldSwapchain = NULL, }; - uint32_t i; - err = fpCreateSwapchainKHR(device, &swapchain_ci, NULL, &swapchain); - ERR_FAIL_COND_V(err, ERR_CANT_CREATE); - // If we just re-created an existing swapchain, we should destroy the old - // swapchain at this point. - // Note: destroying the swapchain also cleans up all its associated - // presentable images once the platform is done with them. - if (oldSwapchain != VK_NULL_HANDLE) { - fpDestroySwapchainKHR(device, oldSwapchain, NULL); - } + err = fpCreateSwapchainKHR(device, &swapchain_ci, NULL, &window->swapchain); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); - err = fpGetSwapchainImagesKHR(device, swapchain, &swapchainImageCount, NULL); + uint32_t sp_image_count; + err = fpGetSwapchainImagesKHR(device, window->swapchain, &sp_image_count, NULL); ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + if (swapchainImageCount == 0) { + //assign here for the first time. + swapchainImageCount = sp_image_count; + } else { + ERR_FAIL_COND_V(swapchainImageCount != sp_image_count, ERR_BUG); + } + VkImage *swapchainImages = (VkImage *)malloc(swapchainImageCount * sizeof(VkImage)); ERR_FAIL_COND_V(!swapchainImages, ERR_CANT_CREATE); - err = fpGetSwapchainImagesKHR(device, swapchain, &swapchainImageCount, swapchainImages); + err = fpGetSwapchainImagesKHR(device, window->swapchain, &swapchainImageCount, swapchainImages); ERR_FAIL_COND_V(err, ERR_CANT_CREATE); - swapchain_image_resources = + window->swapchain_image_resources = (SwapchainImageResources *)malloc(sizeof(SwapchainImageResources) * swapchainImageCount); - ERR_FAIL_COND_V(!swapchain_image_resources, ERR_CANT_CREATE); + ERR_FAIL_COND_V(!window->swapchain_image_resources, ERR_CANT_CREATE); - for (i = 0; i < swapchainImageCount; i++) { + for (uint32_t i = 0; i < swapchainImageCount; i++) { VkImageViewCreateInfo color_image_view = { .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, .pNext = NULL, @@ -798,118 +889,84 @@ Error VulkanContext::_prepare_buffers() { .subresourceRange = { .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .baseMipLevel = 0, .levelCount = 1, .baseArrayLayer = 0, .layerCount = 1 }, }; - swapchain_image_resources[i].image = swapchainImages[i]; + window->swapchain_image_resources[i].image = swapchainImages[i]; - color_image_view.image = swapchain_image_resources[i].image; + color_image_view.image = window->swapchain_image_resources[i].image; - err = vkCreateImageView(device, &color_image_view, NULL, &swapchain_image_resources[i].view); + err = vkCreateImageView(device, &color_image_view, NULL, &window->swapchain_image_resources[i].view); ERR_FAIL_COND_V(err, ERR_CANT_CREATE); } - if (VK_GOOGLE_display_timing_enabled) { - VkRefreshCycleDurationGOOGLE rc_dur; - err = fpGetRefreshCycleDurationGOOGLE(device, swapchain, &rc_dur); - ERR_FAIL_COND_V(err, ERR_CANT_CREATE); - refresh_duration = rc_dur.refreshDuration; - - syncd_with_actual_presents = false; - // Initially target 1X the refresh duration: - target_IPD = refresh_duration; - refresh_duration_multiplier = 1; - prev_desired_present_time = 0; - next_present_id = 1; - } - if (NULL != presentModes) { free(presentModes); } - return OK; -} - -Error VulkanContext::_prepare_framebuffers() { - - //for this, we only need color (no depth), since Godot does not render to the main - //render buffer - - const VkAttachmentDescription attachment = { - - .flags = 0, - .format = format, - .samples = VK_SAMPLE_COUNT_1_BIT, - .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, - .storeOp = VK_ATTACHMENT_STORE_OP_STORE, - .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, - .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, - .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, - .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, + /******** FRAMEBUFFER ************/ - }; - const VkAttachmentReference color_reference = { - .attachment = 0, - .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - }; + { + const VkAttachmentDescription attachment = { - const VkSubpassDescription subpass = { - .flags = 0, - .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, - .inputAttachmentCount = 0, - .pInputAttachments = NULL, - .colorAttachmentCount = 1, - .pColorAttachments = &color_reference, - .pResolveAttachments = NULL, - .pDepthStencilAttachment = NULL, - .preserveAttachmentCount = 0, - .pPreserveAttachments = NULL, - }; - const VkRenderPassCreateInfo rp_info = { - .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, - .pNext = NULL, - .flags = 0, - .attachmentCount = 1, - .pAttachments = &attachment, - .subpassCount = 1, - .pSubpasses = &subpass, - .dependencyCount = 0, - .pDependencies = NULL, - }; - VkResult err; + .flags = 0, + .format = format, + .samples = VK_SAMPLE_COUNT_1_BIT, + .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE, + .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, - err = vkCreateRenderPass(device, &rp_info, NULL, &render_pass); - ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + }; + const VkAttachmentReference color_reference = { + .attachment = 0, + .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + }; - for (uint32_t i = 0; i < swapchainImageCount; i++) { - const VkFramebufferCreateInfo fb_info = { - .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, + const VkSubpassDescription subpass = { + .flags = 0, + .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, + .inputAttachmentCount = 0, + .pInputAttachments = NULL, + .colorAttachmentCount = 1, + .pColorAttachments = &color_reference, + .pResolveAttachments = NULL, + .pDepthStencilAttachment = NULL, + .preserveAttachmentCount = 0, + .pPreserveAttachments = NULL, + }; + const VkRenderPassCreateInfo rp_info = { + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, .pNext = NULL, - .renderPass = render_pass, + .flags = 0, .attachmentCount = 1, - .pAttachments = &swapchain_image_resources[i].view, - .width = width, - .height = height, - .layers = 1, + .pAttachments = &attachment, + .subpassCount = 1, + .pSubpasses = &subpass, + .dependencyCount = 0, + .pDependencies = NULL, }; - err = vkCreateFramebuffer(device, &fb_info, NULL, &swapchain_image_resources[i].framebuffer); + err = vkCreateRenderPass(device, &rp_info, NULL, &window->render_pass); ERR_FAIL_COND_V(err, ERR_CANT_CREATE); - } - return OK; -} - -Error VulkanContext::_create_buffers() { - - Error error = _prepare_buffers(); - if (error != OK) { - return error; - } + for (uint32_t i = 0; i < swapchainImageCount; i++) { + const VkFramebufferCreateInfo fb_info = { + .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, + .pNext = NULL, + .renderPass = window->render_pass, + .attachmentCount = 1, + .pAttachments = &window->swapchain_image_resources[i].view, + .width = (uint32_t)window->width, + .height = (uint32_t)window->height, + .layers = 1, + }; - if (minimized) { - prepared = false; - return OK; + err = vkCreateFramebuffer(device, &fb_info, NULL, &window->swapchain_image_resources[i].framebuffer); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + } } - _prepare_framebuffers(); + /******** SEPARATE PRESENT QUEUE ************/ if (separate_present_queue) { const VkCommandPoolCreateInfo present_cmd_pool_info = { @@ -918,18 +975,18 @@ Error VulkanContext::_create_buffers() { .flags = 0, .queueFamilyIndex = present_queue_family_index, }; - VkResult err = vkCreateCommandPool(device, &present_cmd_pool_info, NULL, &present_cmd_pool); + err = vkCreateCommandPool(device, &present_cmd_pool_info, NULL, &window->present_cmd_pool); ERR_FAIL_COND_V(err, ERR_CANT_CREATE); const VkCommandBufferAllocateInfo present_cmd_info = { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, .pNext = NULL, - .commandPool = present_cmd_pool, + .commandPool = window->present_cmd_pool, .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, .commandBufferCount = 1, }; for (uint32_t i = 0; i < swapchainImageCount; i++) { err = vkAllocateCommandBuffers(device, &present_cmd_info, - &swapchain_image_resources[i].graphics_to_present_cmd); + &window->swapchain_image_resources[i].graphics_to_present_cmd); ERR_FAIL_COND_V(err, ERR_CANT_CREATE); const VkCommandBufferBeginInfo cmd_buf_info = { @@ -938,7 +995,7 @@ Error VulkanContext::_create_buffers() { .flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT, .pInheritanceInfo = NULL, }; - err = vkBeginCommandBuffer(swapchain_image_resources[i].graphics_to_present_cmd, &cmd_buf_info); + err = vkBeginCommandBuffer(window->swapchain_image_resources[i].graphics_to_present_cmd, &cmd_buf_info); ERR_FAIL_COND_V(err, ERR_CANT_CREATE); VkImageMemoryBarrier image_ownership_barrier = { .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, @@ -949,49 +1006,29 @@ Error VulkanContext::_create_buffers() { .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, .srcQueueFamilyIndex = graphics_queue_family_index, .dstQueueFamilyIndex = present_queue_family_index, - .image = swapchain_image_resources[i].image, + .image = window->swapchain_image_resources[i].image, .subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } }; - vkCmdPipelineBarrier(swapchain_image_resources[i].graphics_to_present_cmd, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + vkCmdPipelineBarrier(window->swapchain_image_resources[i].graphics_to_present_cmd, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, NULL, 0, NULL, 1, &image_ownership_barrier); - err = vkEndCommandBuffer(swapchain_image_resources[i].graphics_to_present_cmd); + err = vkEndCommandBuffer(window->swapchain_image_resources[i].graphics_to_present_cmd); ERR_FAIL_COND_V(err, ERR_CANT_CREATE); } } - current_buffer = 0; - prepared = true; + //reset current buffer + window->current_buffer = 0; return OK; } -Error VulkanContext::initialize(int p_width, int p_height, bool p_minimized) { - - screen_width = p_width; - screen_height = p_height; - minimized = p_minimized; +Error VulkanContext::initialize() { Error err = _create_physical_device(); if (err) { return err; } - - err = _create_swap_chain(); - if (err) { - return err; - } - - err = _create_semaphores(); - if (err) { - return err; - } - - err = _create_buffers(); - if (err) { - return err; - } - - print_line("Vulkan context creation success o_O"); + print_line("Vulkan physical device creation success o_O"); return OK; } @@ -1012,10 +1049,7 @@ void VulkanContext::append_command_buffer(const VkCommandBuffer &pCommandBuffer) void VulkanContext::flush(bool p_flush_setup, bool p_flush_pending) { // ensure everything else pending is executed - for (int i = 0; i < FRAME_LAG; i++) { - int to_fence = (frame_index + i) % FRAME_LAG; - vkWaitForFences(device, 1, &fences[to_fence], VK_TRUE, UINT64_MAX); - } + vkDeviceWaitIdle(device); //flush the pending setup buffer @@ -1038,7 +1072,7 @@ void VulkanContext::flush(bool p_flush_setup, bool p_flush_pending) { VkResult err = vkQueueSubmit(graphics_queue, 1, &submit_info, fences[frame_index]); command_buffer_queue.write[0] = NULL; ERR_FAIL_COND(err); - vkWaitForFences(device, 1, &fences[frame_index], VK_TRUE, UINT64_MAX); + vkDeviceWaitIdle(device); } if (p_flush_pending && command_buffer_count > 1) { @@ -1060,41 +1094,68 @@ void VulkanContext::flush(bool p_flush_setup, bool p_flush_pending) { VkResult err = vkQueueSubmit(graphics_queue, 1, &submit_info, fences[frame_index]); command_buffer_queue.write[0] = NULL; ERR_FAIL_COND(err); - vkWaitForFences(device, 1, &fences[frame_index], VK_TRUE, UINT64_MAX); + vkDeviceWaitIdle(device); command_buffer_count = 1; } } -Error VulkanContext::swap_buffers() { +Error VulkanContext::prepare_buffers() { + + if (!queues_initialized) { + return OK; + } - // print_line("swapbuffers?"); VkResult err; // Ensure no more than FRAME_LAG renderings are outstanding vkWaitForFences(device, 1, &fences[frame_index], VK_TRUE, UINT64_MAX); vkResetFences(device, 1, &fences[frame_index]); - do { - // Get the index of the next available swapchain image: - err = - fpAcquireNextImageKHR(device, swapchain, UINT64_MAX, - image_acquired_semaphores[frame_index], VK_NULL_HANDLE, ¤t_buffer); - - if (err == VK_ERROR_OUT_OF_DATE_KHR) { - // swapchain is out of date (e.g. the window was resized) and - // must be recreated: - print_line("early out of data"); - resize_notify(); - } else if (err == VK_SUBOPTIMAL_KHR) { - print_line("early suboptimal"); - // swapchain is not as optimal as it could be, but the platform's - // presentation engine will still present the image correctly. - break; - } else { - ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + for (Map<int, Window>::Element *E = windows.front(); E; E = E->next()) { + + Window *w = &E->get(); + + if (w->swapchain == VK_NULL_HANDLE) { + continue; } - } while (err != VK_SUCCESS); + + do { + // Get the index of the next available swapchain image: + err = + fpAcquireNextImageKHR(device, w->swapchain, UINT64_MAX, + image_acquired_semaphores[frame_index], VK_NULL_HANDLE, &w->current_buffer); + + if (err == VK_ERROR_OUT_OF_DATE_KHR) { + // swapchain is out of date (e.g. the window was resized) and + // must be recreated: + print_line("early out of data"); + //resize_notify(); + _update_swap_chain(w); + } else if (err == VK_SUBOPTIMAL_KHR) { + print_line("early suboptimal"); + // swapchain is not as optimal as it could be, but the platform's + // presentation engine will still present the image correctly. + break; + } else { + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + } + } while (err != VK_SUCCESS); + } + + buffers_prepared = true; + + return OK; +} + +Error VulkanContext::swap_buffers() { + + if (!queues_initialized) { + return OK; + } + + // print_line("swapbuffers?"); + VkResult err; #if 0 if (VK_GOOGLE_display_timing_enabled) { @@ -1154,8 +1215,21 @@ Error VulkanContext::swap_buffers() { pipe_stage_flags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; submit_info.waitSemaphoreCount = 1; submit_info.pWaitSemaphores = &draw_complete_semaphores[frame_index]; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &swapchain_image_resources[current_buffer].graphics_to_present_cmd; + submit_info.commandBufferCount = 0; + + VkCommandBuffer *cmdbufptr = (VkCommandBuffer *)alloca(sizeof(VkCommandBuffer *) * windows.size()); + submit_info.pCommandBuffers = cmdbufptr; + + for (Map<int, Window>::Element *E = windows.front(); E; E = E->next()) { + Window *w = &E->get(); + + if (w->swapchain == VK_NULL_HANDLE) { + continue; + } + cmdbufptr[submit_info.commandBufferCount] = w->swapchain_image_resources[w->current_buffer].graphics_to_present_cmd; + submit_info.commandBufferCount++; + } + submit_info.signalSemaphoreCount = 1; submit_info.pSignalSemaphores = &image_ownership_semaphores[frame_index]; err = vkQueueSubmit(present_queue, 1, &submit_info, nullFence); @@ -1169,10 +1243,28 @@ Error VulkanContext::swap_buffers() { .pNext = NULL, .waitSemaphoreCount = 1, .pWaitSemaphores = (separate_present_queue) ? &image_ownership_semaphores[frame_index] : &draw_complete_semaphores[frame_index], - .swapchainCount = 1, - .pSwapchains = &swapchain, - .pImageIndices = ¤t_buffer, + .swapchainCount = 0, + .pSwapchains = NULL, + .pImageIndices = NULL, }; + + VkSwapchainKHR *pSwapchains = (VkSwapchainKHR *)alloca(sizeof(VkSwapchainKHR *) * windows.size()); + uint32_t *pImageIndices = (uint32_t *)alloca(sizeof(uint32_t *) * windows.size()); + + present.pSwapchains = pSwapchains; + present.pImageIndices = pImageIndices; + + for (Map<int, Window>::Element *E = windows.front(); E; E = E->next()) { + Window *w = &E->get(); + + if (w->swapchain == VK_NULL_HANDLE) { + continue; + } + pSwapchains[present.swapchainCount] = w->swapchain; + pImageIndices[present.swapchainCount] = w->current_buffer; + present.swapchainCount++; + } + #if 0 if (VK_KHR_incremental_present_enabled) { // If using VK_KHR_incremental_present, we provide a hint of the region @@ -1261,6 +1353,7 @@ Error VulkanContext::swap_buffers() { ERR_FAIL_COND_V(err, ERR_CANT_CREATE); } + buffers_prepared = false; return OK; } @@ -1274,47 +1367,34 @@ VkDevice VulkanContext::get_device() { VkPhysicalDevice VulkanContext::get_physical_device() { return gpu; } -int VulkanContext::get_frame_count() const { +int VulkanContext::get_swapchain_image_count() const { return swapchainImageCount; } uint32_t VulkanContext::get_graphics_queue() const { return graphics_queue_family_index; } -int VulkanContext::get_screen_width(int p_screen) { - return width; -} - -int VulkanContext::get_screen_height(int p_screen) { - return height; -} - -VkFramebuffer VulkanContext::get_frame_framebuffer(int p_frame) { - return swapchain_image_resources[p_frame].framebuffer; -} VkFormat VulkanContext::get_screen_format() const { return format; } -VkRenderPass VulkanContext::get_render_pass() { - return render_pass; -} - VkPhysicalDeviceLimits VulkanContext::get_device_limits() const { return gpu_props.limits; } VulkanContext::VulkanContext() { - presentMode = VK_PRESENT_MODE_FIFO_KHR; command_buffer_count = 0; instance_validation_layers = NULL; use_validation_layers = true; VK_KHR_incremental_present_enabled = true; VK_GOOGLE_display_timing_enabled = true; - swapchain = NULL; - prepared = false; command_buffer_queue.resize(1); //first one is the setup command always command_buffer_queue.write[0] = NULL; command_buffer_count = 1; + queues_initialized = false; + + buffers_prepared = false; + swapchainImageCount = 0; + last_window_id = 0; } diff --git a/drivers/vulkan/vulkan_context.h b/drivers/vulkan/vulkan_context.h index 7a62ef51e2..4176f85c0f 100644 --- a/drivers/vulkan/vulkan_context.h +++ b/drivers/vulkan/vulkan_context.h @@ -2,6 +2,7 @@ #define VULKAN_CONTEXT_H #include "core/error_list.h" +#include "core/map.h" #include "core/ustring.h" #include <vulkan/vulkan.h> @@ -24,6 +25,7 @@ class VulkanContext { VkDevice device; //present + bool queues_initialized; uint32_t graphics_queue_family_index; uint32_t present_queue_family_index; bool separate_present_queue; @@ -40,36 +42,46 @@ class VulkanContext { typedef struct { VkImage image; - VkCommandBuffer cmd; VkCommandBuffer graphics_to_present_cmd; VkImageView view; - VkBuffer uniform_buffer; - VkDeviceMemory uniform_memory; VkFramebuffer framebuffer; - VkDescriptorSet descriptor_set; + } SwapchainImageResources; - VkSwapchainKHR swapchain; - SwapchainImageResources *swapchain_image_resources; - VkPresentModeKHR presentMode; + struct Window { + + bool is_minimzed; + VkSurfaceKHR surface; + VkSwapchainKHR swapchain; + SwapchainImageResources *swapchain_image_resources; + VkPresentModeKHR presentMode; + uint32_t current_buffer; + int width; + int height; + VkCommandPool present_cmd_pool; //for separate present queue + + VkRenderPass render_pass; + + Window() { + width = 0; + height = 0; + render_pass = VK_NULL_HANDLE; + current_buffer = 0; + surface = VK_NULL_HANDLE; + swapchain_image_resources = VK_NULL_HANDLE; + swapchain = VK_NULL_HANDLE; + is_minimzed = false; + presentMode = VK_PRESENT_MODE_FIFO_KHR; + } + }; + + Map<int, Window> windows; + int last_window_id; uint32_t swapchainImageCount; - uint64_t refresh_duration; - bool syncd_with_actual_presents; - uint64_t refresh_duration_multiplier; - uint64_t target_IPD; // image present duration (inverse of frame rate) - uint64_t prev_desired_present_time; - uint32_t next_present_id; - uint32_t last_early_id; // 0 if no early images - uint32_t last_late_id; // 0 if no late images - bool is_minimized; - uint32_t current_buffer; //commands - VkRenderPass render_pass; - VkCommandPool present_cmd_pool; //for separate present queue bool prepared; - int width, height; //extensions bool VK_KHR_incremental_present_enabled; @@ -111,38 +123,46 @@ class VulkanContext { void *pUserData); Error _create_physical_device(); + + Error _initialize_queues(VkSurfaceKHR surface); + Error _create_device(); - Error _create_swap_chain(); - Error _create_semaphores(); - Error _prepare_buffers(); - Error _prepare_framebuffers(); - Error _create_buffers(); + Error _clean_up_swap_chain(Window *window); + + Error _update_swap_chain(Window *window); - int screen_width; - int screen_height; - bool minimized; + Error _create_swap_chain(); + Error _create_semaphores(); Vector<VkCommandBuffer> command_buffer_queue; int command_buffer_count; protected: virtual const char *_get_platform_surface_extension() const = 0; - virtual VkResult _create_surface(VkSurfaceKHR *surface, VkInstance p_instance) = 0; + // virtual VkResult _create_surface(VkSurfaceKHR *surface, VkInstance p_instance) = 0; + + virtual int _window_create(VkSurfaceKHR p_surface, int p_width, int p_height); + + VkInstance _get_instance() { + return inst; + } - VkSurfaceKHR &get_surface() { return surface; } + bool buffers_prepared; public: VkDevice get_device(); VkPhysicalDevice get_physical_device(); - int get_frame_count() const; + int get_swapchain_image_count() const; uint32_t get_graphics_queue() const; - int get_screen_width(int p_screen = 0); - int get_screen_height(int p_screen = 0); + void window_resize(int p_window_id, int p_width, int p_height); + int window_get_width(int p_window = 0); + int window_get_height(int p_window = 0); + void window_destroy(int p_window_id); + VkFramebuffer window_get_framebuffer(int p_window = 0); + VkRenderPass window_get_render_pass(int p_window = 0); - VkFramebuffer get_frame_framebuffer(int p_frame); - VkRenderPass get_render_pass(); VkFormat get_screen_format() const; VkPhysicalDeviceLimits get_device_limits() const; @@ -150,8 +170,9 @@ public: void append_command_buffer(const VkCommandBuffer &pCommandBuffer); void resize_notify(); void flush(bool p_flush_setup = false, bool p_flush_pending = false); + Error prepare_buffers(); Error swap_buffers(); - Error initialize(int p_width, int p_height, bool p_minimized); + Error initialize(); VulkanContext(); }; |