From 1b4281b895f3046ea972256182b18696a25f8316 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Mon, 24 Jun 2019 16:13:06 -0300 Subject: [PATCH] basic 2D engine is more or less working with Vulkan, including editor. Still a lot to do --- core/rid_owner.h | 21 +- drivers/dummy/rasterizer_dummy.h | 2 +- drivers/gles2/rasterizer_storage_gles2.cpp | 2 +- drivers/gles2/rasterizer_storage_gles2.h | 2 +- drivers/gles3/rasterizer_storage_gles3.cpp | 2 +- drivers/gles3/rasterizer_storage_gles3.h | 2 +- drivers/vulkan/rendering_device_vulkan.cpp | 291 ++++-- drivers/vulkan/rendering_device_vulkan.h | 71 +- drivers/vulkan/vk_mem_alloc.cpp | 3 + drivers/vulkan/vulkan_context.cpp | 512 +++++----- drivers/vulkan/vulkan_context.h | 93 +- platform/x11/os_x11.cpp | 13 +- platform/x11/vulkan_context_x11.cpp | 15 +- platform/x11/vulkan_context_x11.h | 7 +- scene/gui/viewport_container.cpp | 4 +- scene/main/viewport.cpp | 17 +- scene/main/viewport.h | 3 +- scene/resources/texture.cpp | 32 +- scene/resources/texture.h | 4 +- servers/visual/rasterizer/rasterizer.h | 182 ++-- .../rasterizer/rasterizer_canvas_rd.cpp | 888 ++++++++++++------ .../visual/rasterizer/rasterizer_canvas_rd.h | 84 +- servers/visual/rasterizer/rasterizer_rd.cpp | 4 + servers/visual/rasterizer/rasterizer_rd.h | 1 + .../rasterizer/rasterizer_storage_rd.cpp | 229 +++-- .../visual/rasterizer/rasterizer_storage_rd.h | 23 +- ...render_pipeline_vertex_format_cache_rd.cpp | 5 +- servers/visual/rasterizer/shaders/canvas.glsl | 56 +- .../shaders/canvas_uniforms_inc.glsl | 34 +- servers/visual/rendering_device.h | 5 + servers/visual/visual_server_canvas.cpp | 182 ++-- servers/visual/visual_server_canvas.h | 4 +- servers/visual/visual_server_raster.h | 4 +- servers/visual/visual_server_viewport.cpp | 13 +- servers/visual/visual_server_wrap_mt.h | 4 +- servers/visual_server.h | 3 +- 36 files changed, 1840 insertions(+), 977 deletions(-) diff --git a/core/rid_owner.h b/core/rid_owner.h index 3e5635d385a..971218120f6 100644 --- a/core/rid_owner.h +++ b/core/rid_owner.h @@ -3,6 +3,7 @@ #include "core/print_string.h" #include "core/rid.h" +#include class RID_AllocBase { @@ -91,7 +92,7 @@ public: uint64_t id = p_rid.get_id(); uint32_t idx = uint32_t(id & 0xFFFFFFFF); - if (unlikely(idx >= alloc_count)) { + if (unlikely(idx >= max_alloc)) { return NULL; } @@ -110,7 +111,7 @@ public: uint64_t id = p_rid.get_id(); uint32_t idx = uint32_t(id & 0xFFFFFFFF); - if (unlikely(idx >= alloc_count)) { + if (unlikely(idx >= max_alloc)) { return false; } @@ -125,17 +126,13 @@ public: uint64_t id = p_rid.get_id(); uint32_t idx = uint32_t(id & 0xFFFFFFFF); - if (unlikely(idx >= alloc_count)) { - return; - } + ERR_FAIL_COND(idx >= max_alloc); uint32_t idx_chunk = idx / elements_in_chunk; uint32_t idx_element = idx % elements_in_chunk; uint32_t validator = uint32_t(id >> 32); - if (validator_chunks[idx_chunk][idx_element] != validator) { - return; - } + ERR_FAIL_COND(validator_chunks[idx_chunk][idx_element] != validator); chunks[idx_chunk][idx_element].~T(); validator_chunks[idx_chunk][idx_element] = 0xFFFFFFFF; // go invalid @@ -148,7 +145,7 @@ public: for (size_t i = 0; i < alloc_count; i++) { uint64_t idx = free_list_chunks[i / elements_in_chunk][i % elements_in_chunk]; uint64_t validator = validator_chunks[idx / elements_in_chunk][idx % elements_in_chunk]; - p_owned->push_back(_make_from_id((validator << 32) & idx)); + p_owned->push_back(_make_from_id((validator << 32) | idx)); } } @@ -170,9 +167,9 @@ public: ~RID_Alloc() { if (alloc_count) { if (description) { - print_error("ERROR: " + itos(alloc_count) + " RID allocations of type " + description + " were leaked at exit."); + print_error("ERROR: " + itos(alloc_count) + " RID allocations of type '" + description + "' were leaked at exit."); } else { - print_error("ERROR: " + itos(alloc_count) + " RID allocations of unspecified type were leaked at exit."); + print_error("ERROR: " + itos(alloc_count) + " RID allocations of type '" + typeid(T).name() + "' were leaked at exit."); } for (uint32_t i = 0; i < alloc_count; i++) { @@ -181,7 +178,7 @@ public: } } - uint32_t chunk_count = alloc_count == 0 ? 0 : (max_alloc / elements_in_chunk + 1); + uint32_t chunk_count = max_alloc / elements_in_chunk; for (uint32_t i = 0; i < chunk_count; i++) { memfree(chunks[i]); memfree(validator_chunks[i]); diff --git a/drivers/dummy/rasterizer_dummy.h b/drivers/dummy/rasterizer_dummy.h index 648a8f8d448..796e2764184 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 0b442341738..2e06850413e 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 de4dfe3f460..79e3f610ea6 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 5542f06eb6b..5b19dee7cb6 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 4137ab44fb6..c4e4ac87e4c 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 ed044ceb059..516853a64e4 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 to_free; + Map >::Element *E = dependency_map.find(p_id); if (E) { - for (Set::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::Element *F = E->get().front(); F; F = F->next()) { Map >::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::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::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 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::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::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::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::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::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()) { - frames[frame].buffers_to_dispose_of.pop_front(); + _buffer_free(&frames[p_frame].buffers_to_dispose_of.front()->get()); + + 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 +void RenderingDeviceVulkan::_free_rids(T &p_owner, const char *p_type) { + List owned; + p_owner.get_owned_list(&owned); + if (owned.size()) { + WARN_PRINT(itos(owned.size()) + " RIDs of type '" + p_type + "' were leaked."); + for (List::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 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::Element *E = owned.front(); E;) { + + List::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::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 e1dfb1fc4b3..5042078f849 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 //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 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 vertex_format_cache; + HashMap vertex_format_cache; + struct VertexDescriptionCache { - const Map::Element *E; + Vector 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 + 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 > &p_data = Vector >()); 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 &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 a2023d33b25..8e91e8a08c7 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 991429f963d..37eb99db7a1 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 = fpCreateSwapchainKHR(device, &swapchain_ci, NULL, &window->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); + 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); } - err = fpGetSwapchainImagesKHR(device, swapchain, &swapchainImageCount, NULL); - ERR_FAIL_COND_V(err, ERR_CANT_CREATE); - 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; -} + /******** FRAMEBUFFER ************/ -Error VulkanContext::_prepare_framebuffers() { + { + const VkAttachmentDescription attachment = { - //for this, we only need color (no depth), since Godot does not render to the main - //render buffer + .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, - 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, - - }; - const VkAttachmentReference color_reference = { - .attachment = 0, - .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - }; - - 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; - - err = vkCreateRenderPass(device, &rp_info, NULL, &render_pass); - ERR_FAIL_COND_V(err, ERR_CANT_CREATE); - - for (uint32_t i = 0; i < swapchainImageCount; i++) { - const VkFramebufferCreateInfo fb_info = { - .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, - .pNext = NULL, - .renderPass = render_pass, - .attachmentCount = 1, - .pAttachments = &swapchain_image_resources[i].view, - .width = width, - .height = height, - .layers = 1, + }; + const VkAttachmentReference color_reference = { + .attachment = 0, + .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, }; - err = vkCreateFramebuffer(device, &fb_info, NULL, &swapchain_image_resources[i].framebuffer); + 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, + }; + + err = vkCreateRenderPass(device, &rp_info, NULL, &window->render_pass); ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + + 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, + }; + + err = vkCreateFramebuffer(device, &fb_info, NULL, &window->swapchain_image_resources[i].framebuffer); + ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + } } - return OK; -} - -Error VulkanContext::_create_buffers() { - - Error error = _prepare_buffers(); - if (error != OK) { - return error; - } - - if (minimized) { - prepared = false; - return OK; - } - - _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); + for (Map::Element *E = windows.front(); E; E = E->next()) { - 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); + 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::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::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 7a62ef51e20..4176f85c0fe 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 @@ -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 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 _clean_up_swap_chain(Window *window); + + Error _update_swap_chain(Window *window); + Error _create_swap_chain(); Error _create_semaphores(); - Error _prepare_buffers(); - Error _prepare_framebuffers(); - Error _create_buffers(); - - int screen_width; - int screen_height; - bool minimized; - Vector 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; - VkSurfaceKHR &get_surface() { return surface; } + virtual int _window_create(VkSurfaceKHR p_surface, int p_width, int p_height); + + VkInstance _get_instance() { + return inst; + } + + 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(); }; diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index 14bb8dbcb8c..cfd3cea4eca 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -401,8 +401,10 @@ Error OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_a XFree(visualInfo); - context_vulkan = memnew(VulkanContextX11(x11_window, x11_display)); - context_vulkan->initialize(OS::get_singleton()->get_video_mode().width, OS::get_singleton()->get_video_mode().height, false); + context_vulkan = memnew(VulkanContextX11); + context_vulkan->initialize(); + context_vulkan->window_create(x11_window, x11_display, get_video_mode().width, get_video_mode().height); + //temporary rendering_device = memnew(RenderingDeviceVulkan); rendering_device->initialize(context_vulkan); @@ -1161,6 +1163,12 @@ void OS_X11::finalize() { cursors_cache.clear(); visual_server->finish(); memdelete(visual_server); + + rendering_device->finalize(); + memdelete(rendering_device); + + memdelete(context_vulkan); + //memdelete(rasterizer); memdelete(power_manager); @@ -2415,6 +2423,7 @@ void OS_X11::_window_changed(XEvent *event) { current_videomode.width = event->xconfigure.width; current_videomode.height = event->xconfigure.height; + context_vulkan->window_resize(0, current_videomode.width, current_videomode.height); } void OS_X11::process_xevents() { diff --git a/platform/x11/vulkan_context_x11.cpp b/platform/x11/vulkan_context_x11.cpp index eab7c3935b8..412cc2ddf83 100644 --- a/platform/x11/vulkan_context_x11.cpp +++ b/platform/x11/vulkan_context_x11.cpp @@ -4,19 +4,20 @@ const char *VulkanContextX11::_get_platform_surface_extension() const { return VK_KHR_XLIB_SURFACE_EXTENSION_NAME; } -VkResult VulkanContextX11::_create_surface(VkSurfaceKHR *surface, VkInstance p_instance) { +int VulkanContextX11::window_create(::Window p_window, Display *p_display, int p_width, int p_height) { VkXlibSurfaceCreateInfoKHR createInfo; createInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; createInfo.pNext = NULL; createInfo.flags = 0; - createInfo.dpy = display; - createInfo.window = window; + createInfo.dpy = p_display; + createInfo.window = p_window; - return vkCreateXlibSurfaceKHR(p_instance, &createInfo, NULL, surface); + VkSurfaceKHR surface; + VkResult err = vkCreateXlibSurfaceKHR(_get_instance(), &createInfo, NULL, &surface); + ERR_FAIL_COND_V(err, -1); + return _window_create(surface, p_width, p_height); } -VulkanContextX11::VulkanContextX11(Window p_window, Display *p_display) { - window = p_window; - display = p_display; +VulkanContextX11::VulkanContextX11() { } diff --git a/platform/x11/vulkan_context_x11.h b/platform/x11/vulkan_context_x11.h index b91f63bd27b..6631d39e988 100644 --- a/platform/x11/vulkan_context_x11.h +++ b/platform/x11/vulkan_context_x11.h @@ -5,14 +5,13 @@ #include class VulkanContextX11 : public VulkanContext { - Window window; - Display *display; virtual const char *_get_platform_surface_extension() const; - virtual VkResult _create_surface(VkSurfaceKHR *surface, VkInstance p_instance); public: - VulkanContextX11(Window p_window, Display *display); + int window_create(::Window p_window, Display *p_display, int p_width, int p_height); + + VulkanContextX11(); }; #endif // VULKAN_DEVICE_X11_H diff --git a/scene/gui/viewport_container.cpp b/scene/gui/viewport_container.cpp index 4565b4b5386..a76f2924d38 100644 --- a/scene/gui/viewport_container.cpp +++ b/scene/gui/viewport_container.cpp @@ -135,9 +135,9 @@ void ViewportContainer::_notification(int p_what) { continue; if (stretch) - draw_texture_rect(c->get_texture(), Rect2(Vector2(), get_size() * Size2(1, -1))); + draw_texture_rect(c->get_texture(), Rect2(Vector2(), get_size())); else - draw_texture_rect(c->get_texture(), Rect2(Vector2(), c->get_size() * Size2(1, -1))); + draw_texture_rect(c->get_texture(), Rect2(Vector2(), c->get_size())); } } } diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 412632acfce..0e658f7edd7 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -74,7 +74,13 @@ void ViewportTexture::setup_local_to_scene() { vp->viewport_textures.insert(this); - VS::get_singleton()->texture_set_proxy(proxy, vp->texture_rid); + if (proxy_ph.is_valid()) { + VS::get_singleton()->texture_proxy_update(proxy, vp->texture_rid); + VS::get_singleton()->free(proxy_ph); + } else { + ERR_FAIL_COND(proxy.is_valid()); //should be invalid + proxy = VS::get_singleton()->texture_proxy_create(vp->texture_rid); + } } void ViewportTexture::set_viewport_path_in_scene(const NodePath &p_path) { @@ -112,6 +118,10 @@ Size2 ViewportTexture::get_size() const { RID ViewportTexture::get_rid() const { //ERR_FAIL_COND_V_MSG(!vp, RID(), "Viewport Texture must be set to use it."); + if (proxy.is_null()) { + proxy_ph = VS::get_singleton()->texture_2d_placeholder_create(); + proxy = VS::get_singleton()->texture_proxy_create(proxy_ph); + } return proxy; } @@ -146,6 +156,9 @@ ViewportTexture::~ViewportTexture() { vp->viewport_textures.erase(this); } + if (proxy_ph.is_valid()) { + VS::get_singleton()->free(proxy_ph); + } VS::get_singleton()->free(proxy); } @@ -3309,7 +3322,7 @@ Viewport::Viewport() { default_texture.instance(); default_texture->vp = const_cast(this); viewport_textures.insert(default_texture.ptr()); - VS::get_singleton()->texture_set_proxy(default_texture->proxy, texture_rid); + default_texture->proxy = VS::get_singleton()->texture_proxy_create(texture_rid); //internal_listener = SpatialSoundServer::get_singleton()->listener_create(); audio_listener = false; diff --git a/scene/main/viewport.h b/scene/main/viewport.h index af7c8f1356b..38597e2e477 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -58,7 +58,8 @@ class ViewportTexture : public Texture2D { friend class Viewport; Viewport *vp; - RID proxy; + mutable RID proxy_ph; + mutable RID proxy; protected: static void _bind_methods(); diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index 4f41bce7233..c752ee08769 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -193,7 +193,7 @@ void ImageTexture::update(const Ref &p_image, bool p_immediate) { ERR_FAIL_COND(texture.is_null()); ERR_FAIL_COND(p_image->get_width() != w || p_image->get_height() != h); ERR_FAIL_COND(p_image->get_format() != format); - ERR_FAIL_COND(mipmaps != p_image->get_format()); + ERR_FAIL_COND(mipmaps != p_image->has_mipmaps()); if (p_immediate) { VisualServer::get_singleton()->texture_2d_update_immediate(texture, p_image); @@ -1584,11 +1584,18 @@ void ProxyTexture::_bind_methods() { void ProxyTexture::set_base(const Ref &p_texture) { ERR_FAIL_COND(p_texture == this); + base = p_texture; if (base.is_valid()) { - VS::get_singleton()->texture_set_proxy(proxy, base->get_rid()); - } else { - VS::get_singleton()->texture_set_proxy(proxy, RID()); + if (proxy_ph.is_valid()) { + VS::get_singleton()->texture_proxy_update(proxy, base->get_rid()); + VS::get_singleton()->free(proxy_ph); + proxy_ph = RID(); + } else if (proxy.is_valid()) { + VS::get_singleton()->texture_proxy_update(proxy, base->get_rid()); + } else { + proxy = VS::get_singleton()->texture_proxy_create(base->get_rid()); + } } } @@ -1611,6 +1618,10 @@ int ProxyTexture::get_height() const { } RID ProxyTexture::get_rid() const { + if (proxy.is_null()) { + proxy_ph = VS::get_singleton()->texture_2d_placeholder_create(); + proxy = VS::get_singleton()->texture_proxy_create(proxy_ph); + } return proxy; } @@ -1628,7 +1639,12 @@ ProxyTexture::ProxyTexture() { ProxyTexture::~ProxyTexture() { - //VS::get_singleton()->free(proxy); + if (proxy_ph.is_valid()) { + VS::get_singleton()->free(proxy_ph); + } + if (proxy.is_valid()) { + VS::get_singleton()->free(proxy); + } } ////////////////////////////////////////////// @@ -1673,7 +1689,7 @@ void AnimatedTexture::_update_proxy() { } if (frames[current_frame].texture.is_valid()) { - VisualServer::get_singleton()->texture_set_proxy(proxy, frames[current_frame].texture->get_rid()); + VisualServer::get_singleton()->texture_proxy_update(proxy, frames[current_frame].texture->get_rid()); } } @@ -1822,6 +1838,9 @@ void AnimatedTexture::_bind_methods() { AnimatedTexture::AnimatedTexture() { //proxy = VS::get_singleton()->texture_create(); + proxy_ph = VS::get_singleton()->texture_2d_placeholder_create(); + proxy = VS::get_singleton()->texture_proxy_create(proxy_ph); + VisualServer::get_singleton()->texture_set_force_redraw_if_visible(proxy, true); time = 0; frame_count = 1; @@ -1839,6 +1858,7 @@ AnimatedTexture::AnimatedTexture() { AnimatedTexture::~AnimatedTexture() { VS::get_singleton()->free(proxy); + VS::get_singleton()->free(proxy_ph); if (rw_lock) { memdelete(rw_lock); } diff --git a/scene/resources/texture.h b/scene/resources/texture.h index b255a3ebb22..d3650e83ce2 100644 --- a/scene/resources/texture.h +++ b/scene/resources/texture.h @@ -509,7 +509,8 @@ class ProxyTexture : public Texture2D { GDCLASS(ProxyTexture, Texture2D); private: - RID proxy; + mutable RID proxy_ph; + mutable RID proxy; Ref base; protected: @@ -540,6 +541,7 @@ private: MAX_FRAMES = 256 }; + RID proxy_ph; RID proxy; struct Frame { diff --git a/servers/visual/rasterizer/rasterizer.h b/servers/visual/rasterizer/rasterizer.h index c70056ea9a1..bb7c51f79be 100644 --- a/servers/visual/rasterizer/rasterizer.h +++ b/servers/visual/rasterizer/rasterizer.h @@ -182,10 +182,12 @@ public: virtual RID texture_2d_create(const Ref &p_image) = 0; virtual RID texture_2d_layered_create(const Vector > &p_layers, VS::TextureLayeredType p_layered_type) = 0; virtual RID texture_3d_create(const Vector > &p_slices) = 0; //all slices, then all the mipmaps, must be coherent + virtual RID texture_proxy_create(RID p_base) = 0; //all slices, then all the mipmaps, must be coherent virtual void texture_2d_update_immediate(RID p_texture, const Ref &p_image, int p_layer = 0) = 0; //mostly used for video and streaming virtual void texture_2d_update(RID p_texture, const Ref &p_image, int p_layer = 0) = 0; virtual void texture_3d_update(RID p_texture, const Ref &p_image, int p_depth, int p_mipmap) = 0; + virtual void texture_proxy_update(RID p_proxy, RID p_base) = 0; //these two APIs can be used together or in combination with the others. virtual RID texture_2d_placeholder_create() = 0; @@ -212,10 +214,9 @@ public: virtual void texture_debug_usage(List *r_info) = 0; - virtual void texture_set_proxy(RID p_proxy, RID p_base) = 0; virtual void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) = 0; - virtual Size2 texture_size_with_proxy(RID p_proxy) const = 0; + virtual Size2 texture_size_with_proxy(RID p_proxy) = 0; /* SKY API */ @@ -553,7 +554,12 @@ public: virtual void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) = 0; virtual void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) = 0; virtual bool render_target_was_used(RID p_render_target) = 0; - virtual void render_target_clear_used_flag(RID p_render_target) = 0; + virtual void render_target_set_as_unused(RID p_render_target) = 0; + + virtual void render_target_request_clear(RID p_render_target, const Color &p_clear_color) = 0; + virtual bool render_target_is_clear_requested(RID p_render_target) = 0; + virtual Color render_target_get_clear_request_color(RID p_render_target) = 0; + virtual void render_target_disable_clear_request(RID p_render_target) = 0; /* CANVAS SHADOW */ @@ -702,22 +708,50 @@ public: } }; + typedef uint64_t PolygonID; + virtual PolygonID request_polygon(const Vector &p_indices, const Vector &p_points, const Vector &p_colors, const Vector &p_uvs = Vector(), const Vector &p_bones = Vector(), const Vector &p_weights = Vector()) = 0; + virtual void free_polygon(PolygonID p_polygon) = 0; + + //also easier to wrap to avoid mistakes + struct Polygon { + + PolygonID polygon_id; + Rect2 rect_cache; + + _FORCE_INLINE_ void create(const Vector &p_indices, const Vector &p_points, const Vector &p_colors, const Vector &p_uvs = Vector(), const Vector &p_bones = Vector(), const Vector &p_weights = Vector()) { + ERR_FAIL_COND(polygon_id != 0); + { + uint32_t pc = p_points.size(); + const Vector2 *v2 = p_points.ptr(); + rect_cache.position = *v2; + for (uint32_t i = 1; i < pc; i++) { + rect_cache.expand_to(v2[i]); + } + } + polygon_id = singleton->request_polygon(p_indices, p_points, p_colors, p_uvs, p_bones, p_weights); + } + + _FORCE_INLINE_ Polygon() { polygon_id = 0; } + _FORCE_INLINE_ ~Polygon() { + if (polygon_id) singleton->free_polygon(polygon_id); + } + }; + + //item + struct Item { struct Command { enum Type { - TYPE_LINE, - TYPE_POLYLINE, TYPE_RECT, TYPE_NINEPATCH, - TYPE_PRIMITIVE, TYPE_POLYGON, + TYPE_PRIMITIVE, TYPE_MESH, TYPE_MULTIMESH, TYPE_PARTICLES, - TYPE_CIRCLE, TYPE_TRANSFORM, TYPE_CLIP_IGNORE, }; @@ -726,29 +760,6 @@ public: virtual ~Command() {} }; - struct CommandLine : public Command { - - Point2 from, to; - Color color; - float width; - bool antialiased; - CommandLine() { type = TYPE_LINE; } - }; - struct CommandPolyLine : public Command { - - bool antialiased; - bool multiline; - Vector triangles; - Vector triangle_colors; - Vector lines; - Vector line_colors; - CommandPolyLine() { - type = TYPE_POLYLINE; - antialiased = false; - multiline = false; - } - }; - struct CommandRect : public Command { Rect2 rect; @@ -782,37 +793,27 @@ public: } }; + struct CommandPolygon : public Command { + + VS::PrimitiveType primitive; + Polygon polygon; + Color specular_shininess; + TextureBinding texture_binding; + CommandPolygon() { + type = TYPE_POLYGON; + } + }; + struct CommandPrimitive : public Command { - Vector points; - Vector uvs; - Vector colors; - float width; + uint32_t point_count; + Vector2 points[4]; + Vector2 uvs[4]; + Color colors[4]; Color specular_shininess; TextureBinding texture_binding; CommandPrimitive() { type = TYPE_PRIMITIVE; - width = 1; - } - }; - - struct CommandPolygon : public Command { - - Vector indices; - Vector points; - Vector uvs; - Vector colors; - Vector bones; - Vector weights; - int count; - bool antialiased; - - Color specular_shininess; - TextureBinding texture_binding; - - CommandPolygon() { - type = TYPE_POLYGON; - count = 0; } }; @@ -842,14 +843,6 @@ public: CommandParticles() { type = TYPE_PARTICLES; } }; - struct CommandCircle : public Command { - - Point2 pos; - float radius; - Color color; - CommandCircle() { type = TYPE_CIRCLE; } - }; - struct CommandTransform : public Command { Transform2D xform; @@ -930,37 +923,6 @@ public: Rect2 r; switch (c->type) { - case Item::Command::TYPE_LINE: { - - const Item::CommandLine *line = static_cast(c); - r.position = line->from; - r.expand_to(line->to); - } break; - case Item::Command::TYPE_POLYLINE: { - - const Item::CommandPolyLine *pline = static_cast(c); - if (pline->triangles.size()) { - for (int j = 0; j < pline->triangles.size(); j++) { - - if (j == 0) { - r.position = pline->triangles[j]; - } else { - r.expand_to(pline->triangles[j]); - } - } - } else { - - for (int j = 0; j < pline->lines.size(); j++) { - - if (j == 0) { - r.position = pline->lines[j]; - } else { - r.expand_to(pline->lines[j]); - } - } - } - - } break; case Item::Command::TYPE_RECT: { const Item::CommandRect *crect = static_cast(c); @@ -972,22 +934,21 @@ public: const Item::CommandNinePatch *style = static_cast(c); r = style->rect; } break; - case Item::Command::TYPE_PRIMITIVE: { - const Item::CommandPrimitive *primitive = static_cast(c); - r.position = primitive->points[0]; - for (int j = 1; j < primitive->points.size(); j++) { - r.expand_to(primitive->points[j]); - } - } break; case Item::Command::TYPE_POLYGON: { const Item::CommandPolygon *polygon = static_cast(c); - int l = polygon->points.size(); - const Point2 *pp = &polygon->points[0]; - r.position = pp[0]; - for (int j = 1; j < l; j++) { - r.expand_to(pp[j]); + r = polygon->polygon.rect_cache; + } break; + case Item::Command::TYPE_PRIMITIVE: { + + const Item::CommandPrimitive *primitive = static_cast(c); + for (int j = 0; j < primitive->point_count; j++) { + if (j == 0) { + r.position = primitive->points[0]; + } else { + r.expand_to(primitive->points[j]); + } } } break; case Item::Command::TYPE_MESH: { @@ -1015,12 +976,6 @@ public: } } break; - case Item::Command::TYPE_CIRCLE: { - - const Item::CommandCircle *circle = static_cast(c); - r.position = Point2(-circle->radius, -circle->radius) + circle->pos; - r.size = Point2(circle->radius * 2.0, circle->radius * 2.0); - } break; case Item::Command::TYPE_TRANSFORM: { const Item::CommandTransform *transform = static_cast(c); @@ -1083,7 +1038,7 @@ public: } }; - virtual void canvas_render_items(RID p_to_render_target, bool p_clear, const Color &p_clear_color, Item *p_item_list, const Color &p_modulate, Light *p_light_list, const Transform2D &p_canvas_transform) = 0; + virtual void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, const Transform2D &p_canvas_transform) = 0; virtual void canvas_debug_viewport_shadows(Light *p_lights_with_shadow) = 0; struct LightOccluderInstance { @@ -1142,6 +1097,7 @@ public: //lens distorted parameters for VR should go here }; + virtual void prepare_for_blitting_render_targets() = 0; virtual void blit_render_targets_to_screen(int p_screen, const BlitToScreen *p_render_targets, int p_amount) = 0; virtual void end_frame(bool p_swap_buffers) = 0; diff --git a/servers/visual/rasterizer/rasterizer_canvas_rd.cpp b/servers/visual/rasterizer/rasterizer_canvas_rd.cpp index 61f3c1ffa1f..eef127eeeb5 100644 --- a/servers/visual/rasterizer/rasterizer_canvas_rd.cpp +++ b/servers/visual/rasterizer/rasterizer_canvas_rd.cpp @@ -1,5 +1,5 @@ #include "rasterizer_canvas_rd.h" - +#include "core/math/math_funcs.h" void RasterizerCanvasRD::_update_transform_2d_to_mat4(const Transform2D &p_transform, float *p_mat4) { p_mat4[0] = p_transform.elements[0][0]; @@ -33,6 +33,16 @@ void RasterizerCanvasRD::_update_transform_2d_to_mat2x4(const Transform2D &p_tra p_mat2x4[7] = p_transform.elements[2][1]; } +void RasterizerCanvasRD::_update_transform_2d_to_mat2x3(const Transform2D &p_transform, float *p_mat2x3) { + + p_mat2x3[0] = p_transform.elements[0][0]; + p_mat2x3[1] = p_transform.elements[0][1]; + p_mat2x3[2] = p_transform.elements[1][0]; + p_mat2x3[3] = p_transform.elements[1][1]; + p_mat2x3[4] = p_transform.elements[2][0]; + p_mat2x3[5] = p_transform.elements[2][1]; +} + void RasterizerCanvasRD::_update_transform_to_mat4(const Transform &p_transform, float *p_mat4) { p_mat4[0] = p_transform.basis.elements[0][0]; @@ -53,6 +63,70 @@ void RasterizerCanvasRD::_update_transform_to_mat4(const Transform &p_transform, p_mat4[15] = 1; } +RID RasterizerCanvasRD::_create_texture_binding(RID p_texture, RID p_normalmap, RID p_specular, VisualServer::CanvasItemTextureFilter p_filter, VisualServer::CanvasItemTextureRepeat p_repeat, RID p_multimesh) { + + Vector uniform_set; + + { // COLOR TEXTURE + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 1; + RID texture = storage->texture_get_rd_texture(p_texture); + if (!texture.is_valid()) { + //use default white texture + texture = default_textures.white_texture; + } + u.ids.push_back(texture); + uniform_set.push_back(u); + } + + { // NORMAL TEXTURE + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 2; + RID texture = storage->texture_get_rd_texture(p_normalmap); + if (!texture.is_valid()) { + //use default normal texture + texture = default_textures.normal_texture; + } + u.ids.push_back(texture); + uniform_set.push_back(u); + } + + { // SPECULAR TEXTURE + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 3; + RID texture = storage->texture_get_rd_texture(p_specular); + if (!texture.is_valid()) { + //use default white texture + texture = default_textures.white_texture; + } + u.ids.push_back(texture); + uniform_set.push_back(u); + } + + { // SAMPLER + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_SAMPLER; + u.binding = 4; + RID sampler = default_samplers.samplers[p_filter][p_repeat]; + ERR_FAIL_COND_V(sampler.is_null(), RID()); + u.ids.push_back(sampler); + uniform_set.push_back(u); + } + + { // MULTIMESH TEXTURE BUFFER + RD::Uniform u; + u.type = RD::UNIFORM_TYPE_TEXTURE_BUFFER; + u.binding = 5; + u.ids.push_back(default_textures.default_multimesh_tb); + uniform_set.push_back(u); + } + + return RD::get_singleton()->uniform_set_create(uniform_set, shader.default_version_rd_shader, 0); +} + RasterizerCanvas::TextureBindingID RasterizerCanvasRD::request_texture_binding(RID p_texture, RID p_normalmap, RID p_specular, VisualServer::CanvasItemTextureFilter p_filter, VisualServer::CanvasItemTextureRepeat p_repeat, RID p_multimesh) { if (p_filter == VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT) { @@ -99,77 +173,7 @@ RasterizerCanvas::TextureBindingID RasterizerCanvasRD::request_texture_binding(R } if (binding->uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(binding->uniform_set)) { - //needs to be re-created - - /* from GLSL: - layout(set = 0, binding = 1) uniform texture2D color_texture; - layout(set = 0, binding = 2) uniform texture2D normal_texture; - layout(set = 0, binding = 3) uniform texture2D specular_texture; - layout(set = 0, binding = 4) uniform sampler texture_sampler; - - layout(set = 0, binding = 5) uniform textureBuffer instancing_buffer; - */ - - Vector uniform_set; - - { // COLOR TEXTURE - RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; - u.binding = 1; - RID texture = storage->texture_get_rd_texture(p_texture); - if (!texture.is_valid()) { - //use default white texture - texture = default_textures.white_texture; - } - u.ids.push_back(texture); - uniform_set.push_back(u); - } - - { // NORMAL TEXTURE - RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; - u.binding = 2; - RID texture = storage->texture_get_rd_texture(p_normalmap); - if (!texture.is_valid()) { - //use default normal texture - texture = default_textures.normal_texture; - } - u.ids.push_back(texture); - uniform_set.push_back(u); - } - - { // SPECULAR TEXTURE - RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE; - u.binding = 3; - RID texture = storage->texture_get_rd_texture(p_specular); - if (!texture.is_valid()) { - //use default white texture - texture = default_textures.white_texture; - } - u.ids.push_back(texture); - uniform_set.push_back(u); - } - - { // SAMPLER - RD::Uniform u; - u.type = RD::UNIFORM_TYPE_SAMPLER; - u.binding = 4; - RID sampler = default_samplers.samplers[p_filter][p_repeat]; - ERR_FAIL_COND_V(sampler.is_null(), 0); - u.ids.push_back(sampler); - uniform_set.push_back(u); - } - - { // MULTIMESH TEXTURE BUFFER - RD::Uniform u; - u.type = RD::UNIFORM_TYPE_TEXTURE_BUFFER; - u.binding = 5; - u.ids.push_back(default_textures.default_multimesh_tb); - uniform_set.push_back(u); - } - - binding->uniform_set = RD::get_singleton()->uniform_set_create(uniform_set, shader.default_version_rd_shader, 0); + binding->uniform_set = _create_texture_binding(p_texture, p_normalmap, p_specular, p_filter, p_repeat, p_multimesh); } return id; @@ -191,7 +195,7 @@ void RasterizerCanvasRD::_dispose_bindings() { while (bindings.to_dispose_list.first()) { TextureBinding *binding = bindings.to_dispose_list.first()->self(); - if (binding->uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(binding->uniform_set)) { + if (binding->uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(binding->uniform_set)) { RD::get_singleton()->free(binding->uniform_set); } @@ -202,14 +206,302 @@ void RasterizerCanvasRD::_dispose_bindings() { } } -void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_item, RenderTargetFormat p_render_target_format, RD::TextureSamples p_samples, const Color &p_modulate, const Transform2D &p_canvas_transform_inverse) { +RasterizerCanvas::PolygonID RasterizerCanvasRD::request_polygon(const Vector &p_indices, const Vector &p_points, const Vector &p_colors, const Vector &p_uvs, const Vector &p_bones, const Vector &p_weights) { + + // Care must be taken to generate array formats + // in ways where they could be reused, so we will + // put single-occuring elements first, and repeated + // elements later. This way the generated formats are + // the same no matter the length of the arrays. + // This dramatically reduces the amount of pipeline objects + // that need to be created for these formats. + + uint32_t vertex_count = p_points.size(); + uint32_t base_offset = 0; + uint32_t stride = 2; //vertices always repeat + if ((uint32_t)p_colors.size() == vertex_count) { + stride += 4; + } else { + base_offset += 4; + } + if ((uint32_t)p_uvs.size() == vertex_count) { + stride += 2; + } else { + base_offset += 2; + } + if ((uint32_t)p_bones.size() == vertex_count * 4) { + stride += 4; + } else { + base_offset += 4; + } + if ((uint32_t)p_weights.size() == vertex_count * 4) { + stride += 4; + } else { + base_offset += 4; + } + + uint32_t buffer_size = base_offset + stride * p_points.size(); + + PoolVector polygon_buffer; + polygon_buffer.resize(buffer_size * sizeof(float)); + Vector descriptions; + descriptions.resize(5); + + { + PoolVector::Read r = polygon_buffer.read(); + float *fptr = (float *)r.ptr(); + uint32_t *uptr = (uint32_t *)r.ptr(); + uint32_t single_offset = 0; + + { //vertices + RD::VertexDescription vd; + vd.format = RD::DATA_FORMAT_R32G32_SFLOAT; + vd.offset = base_offset * sizeof(float); + vd.location = VS::ARRAY_VERTEX; + vd.stride = stride * sizeof(float); + + descriptions.write[0] = vd; + + const Vector2 *points_ptr = p_points.ptr(); + + for (uint32_t i = 0; i < vertex_count; i++) { + fptr[base_offset + i * stride + 0] = points_ptr[i].x; + fptr[base_offset + i * stride + 1] = points_ptr[i].y; + } + + base_offset += 2; + } + + //colors + if ((uint32_t)p_colors.size() == vertex_count) { + RD::VertexDescription vd; + vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT; + vd.offset = base_offset * sizeof(float); + vd.location = VS::ARRAY_COLOR; + vd.stride = stride * sizeof(float); + + descriptions.write[1] = vd; + + const Color *color_ptr = p_colors.ptr(); + + for (uint32_t i = 0; i < vertex_count; i++) { + fptr[base_offset + i * stride + 0] = color_ptr[i].r; + fptr[base_offset + i * stride + 1] = color_ptr[i].g; + fptr[base_offset + i * stride + 2] = color_ptr[i].b; + fptr[base_offset + i * stride + 3] = color_ptr[i].a; + } + base_offset += 4; + } else { + RD::VertexDescription vd; + vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT; + vd.offset = single_offset * sizeof(float); + vd.location = VS::ARRAY_COLOR; + vd.stride = 0; + + descriptions.write[1] = vd; + + Color color = p_colors.size() ? p_colors[0] : Color(1, 1, 1, 1); + fptr[single_offset + 0] = color.r; + fptr[single_offset + 1] = color.g; + fptr[single_offset + 2] = color.b; + fptr[single_offset + 3] = color.a; + + single_offset += 4; + } + + //uvs + if ((uint32_t)p_uvs.size() == vertex_count) { + RD::VertexDescription vd; + vd.format = RD::DATA_FORMAT_R32G32_SFLOAT; + vd.offset = base_offset * sizeof(float); + vd.location = VS::ARRAY_TEX_UV; + vd.stride = stride * sizeof(float); + + descriptions.write[2] = vd; + + const Vector2 *uv_ptr = p_uvs.ptr(); + + for (uint32_t i = 0; i < vertex_count; i++) { + fptr[base_offset + i * stride + 0] = uv_ptr[i].x; + fptr[base_offset + i * stride + 1] = uv_ptr[i].y; + } + base_offset += 2; + } else { + RD::VertexDescription vd; + vd.format = RD::DATA_FORMAT_R32G32_SFLOAT; + vd.offset = single_offset * sizeof(float); + vd.location = VS::ARRAY_TEX_UV; + vd.stride = 0; + + descriptions.write[2] = vd; + + Vector2 uv; + fptr[single_offset + 0] = uv.x; + fptr[single_offset + 1] = uv.y; + + single_offset += 2; + } + + //bones + if ((uint32_t)p_indices.size() == vertex_count * 4) { + RD::VertexDescription vd; + vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT; + vd.offset = base_offset * sizeof(float); + vd.location = VS::ARRAY_BONES; + vd.stride = stride * sizeof(float); + + descriptions.write[3] = vd; + + const int *bone_ptr = p_bones.ptr(); + + for (uint32_t i = 0; i < vertex_count; i++) { + uptr[base_offset + i * stride + 0] = bone_ptr[i * 4 + 0]; + uptr[base_offset + i * stride + 1] = bone_ptr[i * 4 + 1]; + uptr[base_offset + i * stride + 2] = bone_ptr[i * 4 + 2]; + uptr[base_offset + i * stride + 3] = bone_ptr[i * 4 + 3]; + } + + base_offset += 4; + } else { + RD::VertexDescription vd; + vd.format = RD::DATA_FORMAT_R32G32B32A32_UINT; + vd.offset = single_offset * sizeof(float); + vd.location = VS::ARRAY_BONES; + vd.stride = 0; + + descriptions.write[3] = vd; + + uptr[single_offset + 0] = 0; + uptr[single_offset + 1] = 0; + uptr[single_offset + 2] = 0; + uptr[single_offset + 3] = 0; + single_offset += 4; + } + + //bones + if ((uint32_t)p_weights.size() == vertex_count * 4) { + RD::VertexDescription vd; + vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT; + vd.offset = base_offset * sizeof(float); + vd.location = VS::ARRAY_WEIGHTS; + vd.stride = stride * sizeof(float); + + descriptions.write[4] = vd; + + const float *weight_ptr = p_weights.ptr(); + + for (uint32_t i = 0; i < vertex_count; i++) { + fptr[base_offset + i * stride + 0] = weight_ptr[i * 4 + 0]; + fptr[base_offset + i * stride + 1] = weight_ptr[i * 4 + 1]; + fptr[base_offset + i * stride + 2] = weight_ptr[i * 4 + 2]; + fptr[base_offset + i * stride + 3] = weight_ptr[i * 4 + 3]; + } + + base_offset += 4; + } else { + RD::VertexDescription vd; + vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT; + vd.offset = single_offset * sizeof(float); + vd.location = VS::ARRAY_WEIGHTS; + vd.stride = 0; + + descriptions.write[4] = vd; + + fptr[single_offset + 0] = 0.0; + fptr[single_offset + 1] = 0.0; + fptr[single_offset + 2] = 0.0; + fptr[single_offset + 3] = 0.0; + single_offset += 4; + } + + //check that everything is as it should be + ERR_FAIL_COND_V(single_offset != (base_offset - stride), 0); + ERR_FAIL_COND_V(((base_offset - stride) + stride * vertex_count) != buffer_size, 0); + } + + RD::VertexFormatID vertex_id = RD::get_singleton()->vertex_format_create(descriptions); + ERR_FAIL_COND_V(vertex_id == RD::INVALID_ID, 0); + + PolygonBuffers pb; + pb.vertex_buffer = RD::get_singleton()->vertex_buffer_create(polygon_buffer.size(), polygon_buffer); + Vector buffers; + buffers.resize(descriptions.size()); + for (int i = 0; i < descriptions.size(); i++) { + buffers.write[i] = pb.vertex_buffer; + } + pb.vertex_array = RD::get_singleton()->vertex_array_create(p_points.size(), vertex_id, buffers); + + if (p_indices.size()) { + //create indices, as indices were requested + PoolVector index_buffer; + index_buffer.resize(p_indices.size() * sizeof(int32_t)); + { + PoolVector::Write w = index_buffer.write(); + copymem(w.ptr(), p_indices.ptr(), sizeof(int32_t) * p_indices.size()); + } + pb.index_buffer = RD::get_singleton()->index_buffer_create(p_indices.size(), RD::INDEX_BUFFER_FORMAT_UINT32, index_buffer); + pb.indices = RD::get_singleton()->index_array_create(pb.index_buffer, 0, p_indices.size()); + } + + pb.vertex_format_id = vertex_id; + + PolygonID id = polygon_buffers.last_id++; + + polygon_buffers.polygons[id] = pb; + + return id; +} + +void RasterizerCanvasRD::free_polygon(PolygonID p_polygon) { + + PolygonBuffers *pb_ptr = polygon_buffers.polygons.getptr(p_polygon); + ERR_FAIL_COND(!pb_ptr); + + PolygonBuffers &pb = *pb_ptr; + + if (pb.indices.is_valid()) { + RD::get_singleton()->free(pb.indices); + } + if (pb.index_buffer.is_valid()) { + RD::get_singleton()->free(pb.index_buffer); + } + + RD::get_singleton()->free(pb.vertex_array); + RD::get_singleton()->free(pb.vertex_buffer); + + polygon_buffers.polygons.erase(p_polygon); +} + +Size2i RasterizerCanvasRD::_bind_texture_binding(TextureBindingID p_binding, RD::DrawListID p_draw_list) { + + TextureBinding **texture_binding_ptr = bindings.texture_bindings.getptr(p_binding); + ERR_FAIL_COND_V(!texture_binding_ptr, Size2i()); + TextureBinding *texture_binding = *texture_binding_ptr; + + if (!RD::get_singleton()->uniform_set_is_valid(texture_binding->uniform_set)) { + //texture may have changed (erased or replaced, see if we can fix) + texture_binding->uniform_set = _create_texture_binding(texture_binding->key.texture, texture_binding->key.normalmap, texture_binding->key.specular, texture_binding->key.texture_filter, texture_binding->key.texture_repeat, texture_binding->key.multimesh); + ERR_FAIL_COND_V(!texture_binding->uniform_set.is_valid(), Size2i(1, 1)); + } + + RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, texture_binding->uniform_set, 0); + if (texture_binding->key.texture.is_valid()) { + return storage->texture_2d_get_size(texture_binding->key.texture); + } else { + return Size2i(1, 1); + } +} + +//////////////////// +void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_item, RenderTargetFormat p_render_target_format, RD::TextureSamples p_samples, const Color &p_modulate, const Transform2D &p_canvas_transform_inverse, Item *¤t_clip) { int cc = p_item->commands.size(); const Item::Command *const *commands = p_item->commands.ptr(); //create an empty push constant PushConstant push_constant; - _update_transform_2d_to_mat2x4(p_canvas_transform_inverse * p_item->final_transform, push_constant.world); + Transform2D base_transform = p_canvas_transform_inverse * p_item->final_transform; + _update_transform_2d_to_mat2x3(base_transform, push_constant.world); for (int i = 0; i < 4; i++) { push_constant.modulation[i] = 0; push_constant.ninepatch_margins[i] = 0; @@ -226,120 +518,14 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ PipelineVariants *pipeline_variants = &shader.pipeline_variants; + bool reclip = false; + for (int i = 0; i < cc; i++) { const Item::Command *c = commands[i]; push_constant.flags = 0; //reset on each command for sanity switch (c->type) { -#if 0 - case Item::Command::TYPE_LINE: { - - Item::CommandLine *line = static_cast(c); - _set_texture_rect_mode(false); - - _bind_canvas_texture(RID(), RID()); - - glVertexAttrib4f(VS::ARRAY_COLOR, line->color.r, line->color.g, line->color.b, line->color.a); - - if (line->width <= 1) { - Vector2 verts[2] = { - Vector2(line->from.x, line->from.y), - Vector2(line->to.x, line->to.y) - }; - -#ifdef GLES_OVER_GL - if (line->antialiased) - glEnable(GL_LINE_SMOOTH); -#endif - //glLineWidth(line->width); - _draw_gui_primitive(2, verts, NULL, NULL); - -#ifdef GLES_OVER_GL - if (line->antialiased) - glDisable(GL_LINE_SMOOTH); -#endif - } else { - //thicker line - - Vector2 t = (line->from - line->to).normalized().tangent() * line->width * 0.5; - - Vector2 verts[4] = { - line->from - t, - line->from + t, - line->to + t, - line->to - t, - }; - - //glLineWidth(line->width); - _draw_gui_primitive(4, verts, NULL, NULL); -#ifdef GLES_OVER_GL - if (line->antialiased) { - glEnable(GL_LINE_SMOOTH); - for (int j = 0; j < 4; j++) { - Vector2 vertsl[2] = { - verts[j], - verts[(j + 1) % 4], - }; - _draw_gui_primitive(2, vertsl, NULL, NULL); - } - glDisable(GL_LINE_SMOOTH); - } -#endif - } - - } break; - case Item::Command::TYPE_POLYLINE: { - - Item::CommandPolyLine *pline = static_cast(c); - _set_texture_rect_mode(false); - - _bind_canvas_texture(RID(), RID()); - - if (pline->triangles.size()) { - - _draw_generic(GL_TRIANGLE_STRIP, pline->triangles.size(), pline->triangles.ptr(), NULL, pline->triangle_colors.ptr(), pline->triangle_colors.size() == 1); -#ifdef GLES_OVER_GL - glEnable(GL_LINE_SMOOTH); - if (pline->multiline) { - //needs to be different - } else { - _draw_generic(GL_LINE_LOOP, pline->lines.size(), pline->lines.ptr(), NULL, pline->line_colors.ptr(), pline->line_colors.size() == 1); - } - glDisable(GL_LINE_SMOOTH); -#endif - } else { - -#ifdef GLES_OVER_GL - if (pline->antialiased) - glEnable(GL_LINE_SMOOTH); -#endif - - if (pline->multiline) { - int todo = pline->lines.size() / 2; - int max_per_call = data.polygon_buffer_size / (sizeof(real_t) * 4); - int offset = 0; - - while (todo) { - int to_draw = MIN(max_per_call, todo); - _draw_generic(GL_LINES, to_draw * 2, &pline->lines.ptr()[offset], NULL, pline->line_colors.size() == 1 ? pline->line_colors.ptr() : &pline->line_colors.ptr()[offset], pline->line_colors.size() == 1); - todo -= to_draw; - offset += to_draw * 2; - } - - } else { - - _draw_generic(GL_LINE_STRIP, pline->lines.size(), pline->lines.ptr(), NULL, pline->line_colors.ptr(), pline->line_colors.size() == 1); - } - -#ifdef GLES_OVER_GL - if (pline->antialiased) - glDisable(GL_LINE_SMOOTH); -#endif - } - - } break; -#endif case Item::Command::TYPE_RECT: { const Item::CommandRect *rect = static_cast(c); @@ -354,18 +540,9 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ Size2 texpixel_size; { - TextureBinding **texture_binding_ptr = bindings.texture_bindings.getptr(rect->texture_binding.binding_id); - ERR_CONTINUE(!texture_binding_ptr); - TextureBinding *texture_binding = *texture_binding_ptr; - - RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, texture_binding->uniform_set, 0); - if (texture_binding->key.texture.is_valid()) { - Size2i tex_size = storage->texture_2d_get_size(texture_binding->key.texture); - if (tex_size.x != 0 && tex_size.y != 0) { - texpixel_size.x = 1.0 / tex_size.x; - texpixel_size.y = 1.0 / tex_size.y; - } - } + texpixel_size = _bind_texture_binding(rect->texture_binding.binding_id, p_draw_list); + texpixel_size.x = 1.0 / texpixel_size.x; + texpixel_size.y = 1.0 / texpixel_size.y; } Rect2 src_rect; @@ -457,17 +634,9 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ Size2 texpixel_size; { - TextureBinding **texture_binding_ptr = bindings.texture_bindings.getptr(np->texture_binding.binding_id); - ERR_CONTINUE(!texture_binding_ptr); - TextureBinding *texture_binding = *texture_binding_ptr; - RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, texture_binding->uniform_set, 0); - if (texture_binding->key.texture.is_valid()) { - Size2i tex_size = storage->texture_2d_get_size(texture_binding->key.texture); - if (tex_size.x != 0 && tex_size.y != 0) { - texpixel_size.x = 1.0 / tex_size.x; - texpixel_size.y = 1.0 / tex_size.y; - } - } + texpixel_size = _bind_texture_binding(np->texture_binding.binding_id, p_draw_list); + texpixel_size.x = 1.0 / texpixel_size.x; + texpixel_size.y = 1.0 / texpixel_size.y; } Rect2 src_rect; @@ -491,7 +660,7 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ push_constant.modulation[0] = np->color.r * p_modulate.r; push_constant.modulation[1] = np->color.g * p_modulate.g; push_constant.modulation[2] = np->color.b * p_modulate.b; - push_constant.modulation[3] = np->color.a; + push_constant.modulation[3] = np->color.a * p_modulate.a; push_constant.src_rect[0] = src_rect.position.x; push_constant.src_rect[1] = src_rect.position.y; @@ -523,54 +692,92 @@ void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_ RD::get_singleton()->draw_list_draw(p_draw_list, true); } break; -#if 0 -case Item::Command::TYPE_PRIMITIVE : { - - Item::CommandPrimitive *primitive = static_cast(c); - _set_texture_rect_mode(false); - - ERR_CONTINUE(primitive->points.size() < 1); - - RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(primitive->texture, primitive->normal_map); - - if (texture) { - Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); - state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size); - } - if (primitive->colors.size() == 1 && primitive->points.size() > 1) { - - Color col = primitive->colors[0]; - glVertexAttrib4f(VS::ARRAY_COLOR, col.r, col.g, col.b, col.a); - - } else if (primitive->colors.empty()) { - glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); - } - - _draw_gui_primitive(primitive->points.size(), primitive->points.ptr(), primitive->colors.ptr(), primitive->uvs.ptr()); - - } break; case Item::Command::TYPE_POLYGON: { - Item::CommandPolygon *polygon = static_cast(c); - _set_texture_rect_mode(false); + const Item::CommandPolygon *polygon = static_cast(c); - RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(polygon->texture, polygon->normal_map); - - if (texture) { - Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); - state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size); + PolygonBuffers *pb = polygon_buffers.polygons.getptr(polygon->polygon.polygon_id); + ERR_CONTINUE(!pb); + //bind pipeline + { + static const PipelineVariant variant[VS::PRIMITIVE_MAX] = { PIPELINE_VARIANT_ATTRIBUTE_POINTS, PIPELINE_VARIANT_ATTRIBUTE_LINES, PIPELINE_VARIANT_ATTRIBUTE_TRIANGLES }; + ERR_CONTINUE(polygon->primitive < 0 || polygon->primitive >= VS::PRIMITIVE_MAX); + RID pipeline = pipeline_variants->variants[p_render_target_format][variant[polygon->primitive]].get_render_pipeline(pb->vertex_format_id, p_samples); + RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline); } - _draw_polygon(polygon->indices.ptr(), polygon->count, polygon->points.size(), polygon->points.ptr(), polygon->uvs.ptr(), polygon->colors.ptr(), polygon->colors.size() == 1, polygon->bones.ptr(), polygon->weights.ptr()); -#ifdef GLES_OVER_GL - if (polygon->antialiased) { - glEnable(GL_LINE_SMOOTH); - _draw_generic(GL_LINE_LOOP, polygon->points.size(), polygon->points.ptr(), polygon->uvs.ptr(), polygon->colors.ptr(), polygon->colors.size() == 1); - glDisable(GL_LINE_SMOOTH); + if (polygon->primitive == VS::PRIMITIVE_LINES) { + //not supported in most hardware, so pointless + //RD::get_singleton()->draw_list_set_line_width(p_draw_list, polygon->line_width); } -#endif + + //bind textures + + Size2 texpixel_size; + { + texpixel_size = _bind_texture_binding(polygon->texture_binding.binding_id, p_draw_list); + texpixel_size.x = 1.0 / texpixel_size.x; + texpixel_size.y = 1.0 / texpixel_size.y; + } + + push_constant.modulation[0] = p_modulate.r; + push_constant.modulation[1] = p_modulate.g; + push_constant.modulation[2] = p_modulate.b; + push_constant.modulation[3] = p_modulate.a; + + for (int j = 0; j < 4; j++) { + push_constant.src_rect[j] = 0; + push_constant.dst_rect[j] = 0; + push_constant.ninepatch_margins[j] = 0; + } + + push_constant.color_texture_pixel_size[0] = texpixel_size.x; + push_constant.color_texture_pixel_size[1] = texpixel_size.y; + + RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant)); + RD::get_singleton()->draw_list_bind_vertex_array(p_draw_list, pb->vertex_array); + if (pb->indices.is_valid()) { + RD::get_singleton()->draw_list_bind_index_array(p_draw_list, pb->indices); + } + RD::get_singleton()->draw_list_draw(p_draw_list, pb->indices.is_valid()); } break; + case Item::Command::TYPE_PRIMITIVE: { + + const Item::CommandPrimitive *primitive = static_cast(c); + + //bind pipeline + { + static const PipelineVariant variant[4] = { PIPELINE_VARIANT_PRIMITIVE_POINTS, PIPELINE_VARIANT_PRIMITIVE_LINES, PIPELINE_VARIANT_PRIMITIVE_TRIANGLES, PIPELINE_VARIANT_PRIMITIVE_TRIANGLES }; + ERR_CONTINUE(primitive->point_count == 0 || primitive->point_count > 4); + RID pipeline = pipeline_variants->variants[p_render_target_format][variant[primitive->point_count - 1]].get_render_pipeline(RD::INVALID_ID, p_samples); + RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline); + } + + //bind textures + + { + _bind_texture_binding(primitive->texture_binding.binding_id, p_draw_list); + } + + for (uint32_t j = 0; j < primitive->point_count; j++) { + push_constant.points[j * 2 + 0] = primitive->points[j].x; + push_constant.points[j * 2 + 1] = primitive->points[j].y; + push_constant.uvs[j * 2 + 0] = primitive->uvs[j].x; + push_constant.uvs[j * 2 + 1] = primitive->uvs[j].y; + Color col = primitive->colors[j] * p_modulate; + push_constant.colors[j * 2 + 0] = (uint32_t(Math::make_half_float(col.g)) << 16) | Math::make_half_float(col.r); + push_constant.colors[j * 2 + 1] = (uint32_t(Math::make_half_float(col.a)) << 16) | Math::make_half_float(col.b); + } + RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant)); + + RD::get_singleton()->draw_list_bind_index_array(p_draw_list, primitive_arrays.index_array[primitive->point_count - 1]); + + RD::get_singleton()->draw_list_draw(p_draw_list, true); + + } break; + +#if 0 case Item::Command::TYPE_MESH: { Item::CommandMesh *mesh = static_cast(c); @@ -850,70 +1057,43 @@ case Item::Command::TYPE_PRIMITIVE : { _set_texture_rect_mode(false); } break; - case Item::Command::TYPE_CIRCLE: { - - _set_texture_rect_mode(false); - - Item::CommandCircle *circle = static_cast(c); - static const int numpoints = 32; - Vector2 points[numpoints + 1]; - points[numpoints] = circle->pos; - int indices[numpoints * 3]; - - for (int j = 0; j < numpoints; j++) { - - points[j] = circle->pos + Vector2(Math::sin(j * Math_PI * 2.0 / numpoints), Math::cos(j * Math_PI * 2.0 / numpoints)) * circle->radius; - indices[j * 3 + 0] = j; - indices[j * 3 + 1] = (j + 1) % numpoints; - indices[j * 3 + 2] = numpoints; - } - - _bind_canvas_texture(RID(), RID()); - _draw_polygon(indices, numpoints * 3, numpoints + 1, points, NULL, &circle->color, true, NULL, NULL); - - //_draw_polygon(numpoints*3,indices,points,NULL,&circle->color,RID(),true); - //canvas_draw_circle(circle->indices.size(),circle->indices.ptr(),circle->points.ptr(),circle->uvs.ptr(),circle->colors.ptr(),circle->texture,circle->colors.size()==1); - } break; +#endif case Item::Command::TYPE_TRANSFORM: { - Item::CommandTransform *transform = static_cast(c); - state.extra_matrix = transform->xform; - state.canvas_shader.set_uniform(CanvasShaderGLES3::EXTRA_MATRIX, state.extra_matrix); + const Item::CommandTransform *transform = static_cast(c); + base_transform = base_transform * transform->xform; + _update_transform_2d_to_mat2x3(base_transform, push_constant.world); } break; case Item::Command::TYPE_CLIP_IGNORE: { - Item::CommandClipIgnore *ci = static_cast(c); + const Item::CommandClipIgnore *ci = static_cast(c); if (current_clip) { if (ci->ignore != reclip) { - if (ci->ignore) { - glDisable(GL_SCISSOR_TEST); + if (ci->ignore) { + RD::get_singleton()->draw_list_disable_scissor(p_draw_list); reclip = true; } else { - glEnable(GL_SCISSOR_TEST); - //glScissor(viewport.x+current_clip->final_clip_rect.pos.x,viewport.y+ (viewport.height-(current_clip->final_clip_rect.pos.y+current_clip->final_clip_rect.size.height)), - //current_clip->final_clip_rect.size.width,current_clip->final_clip_rect.size.height); - int y = storage->frame.current_rt->height - (current_clip->final_clip_rect.position.y + current_clip->final_clip_rect.size.y); - if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP]) - y = current_clip->final_clip_rect.position.y; - - glScissor(current_clip->final_clip_rect.position.x, y, current_clip->final_clip_rect.size.x, current_clip->final_clip_rect.size.y); - + RD::get_singleton()->draw_list_enable_scissor(p_draw_list, current_clip->final_clip_rect); reclip = false; } } } } break; -#endif } } + + if (current_clip && reclip) { + //will make it re-enable clipping if needed afterwards + current_clip = NULL; + } } -void RasterizerCanvasRD::_render_items(RID p_to_render_target, bool p_clear, const Color &p_clear_color, int p_item_count, const Color &p_modulate, const Transform2D &p_transform) { +void RasterizerCanvasRD::_render_items(RID p_to_render_target, int p_item_count, const Color &p_modulate, const Transform2D &p_transform) { Item *current_clip = NULL; @@ -923,12 +1103,15 @@ void RasterizerCanvasRD::_render_items(RID p_to_render_target, bool p_clear, con RID framebuffer = storage->render_target_get_rd_framebuffer(p_to_render_target); Vector clear_colors; - if (p_clear) { - clear_colors.push_back(p_clear_color); + bool clear = false; + if (storage->render_target_is_clear_requested(p_to_render_target)) { + clear = true; + clear_colors.push_back(storage->render_target_get_clear_request_color(p_to_render_target)); + storage->render_target_disable_clear_request(p_to_render_target); } #warning TODO obtain from framebuffer format eventually when this is implemented RD::TextureSamples texture_samples = RD::TEXTURE_SAMPLES_1; - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, p_clear ? RD::INITIAL_ACTION_CLEAR : RD::INITIAL_ACTION_KEEP_COLOR, RD::FINAL_ACTION_READ_COLOR_DISCARD_DEPTH, clear_colors); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, clear ? RD::INITIAL_ACTION_CLEAR : RD::INITIAL_ACTION_KEEP_COLOR, RD::FINAL_ACTION_READ_COLOR_DISCARD_DEPTH, clear_colors); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, state.canvas_state_uniform_set, 3); @@ -953,10 +1136,10 @@ void RasterizerCanvasRD::_render_items(RID p_to_render_target, bool p_clear, con if (false) { //not skeleton - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, shader.default_material_uniform_set, 1); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, shader.default_skeleton_uniform_set, 1); } - _render_item(draw_list, ci, render_target_format, texture_samples, p_modulate, canvas_transform_inverse); + _render_item(draw_list, ci, render_target_format, texture_samples, p_modulate, canvas_transform_inverse, current_clip); } RD::get_singleton()->draw_list_end(); @@ -979,7 +1162,7 @@ void RasterizerCanvasRD::_update_canvas_state_uniform_set() { state.canvas_state_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shader.default_version_rd_shader, 3); // uses index 3 } -void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, bool p_clear, const Color &p_clear_color, Item *p_item_list, const Color &p_modulate, Light *p_light_list, const Transform2D &p_canvas_transform) { +void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, const Transform2D &p_canvas_transform) { int item_count = 0; @@ -1008,10 +1191,9 @@ void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, bool p_clea bool backbuffer_copy = ci->copy_back_buffer; // || shader uses SCREEN_TEXTURE if (!ci->next || backbuffer_copy || item_count == MAX_RENDER_ITEMS - 1) { - _render_items(p_to_render_target, p_clear, p_clear_color, item_count, p_modulate, p_canvas_transform); + _render_items(p_to_render_target, item_count, p_modulate, p_canvas_transform); //then reset item_count = 0; - p_clear = false; } if (ci->copy_back_buffer) { @@ -1170,8 +1352,10 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { Vector variants; variants.push_back(""); //none by default is first variant variants.push_back("#define USE_NINEPATCH\n"); //ninepatch is the second variant - variants.push_back("#define USE_VERTEX_ARRAYS\n"); //vertex arrays is the last variant - variants.push_back("#define USE_POINT_SIZE\n"); //for point drawing + variants.push_back("#define USE_PRIMITIVE\n"); //primitve is the third + variants.push_back("#define USE_PRIMITIVE\n#define USE_POINT_SIZE\n"); //points need point size + variants.push_back("#define USE_ATTRIBUTES\n"); // attributes for vertex arrays + variants.push_back("#define USE_ATTRIBUTES\n#define USE_POINT_SIZE\n"); //attributes with point size shader.canvas_shader.initialize(variants); shader.default_version = shader.canvas_shader.version_create(); @@ -1195,11 +1379,29 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { for (int i = 0; i < RENDER_TARGET_FORMAT_MAX; i++) { RD::FramebufferFormatID fb_format = shader.framebuffer_formats[i]; for (int j = 0; j < PIPELINE_VARIANT_MAX; j++) { - RD::RenderPrimitive primitive[PIPELINE_VARIANT_MAX] = { RD::RENDER_PRIMITIVE_TRIANGLES, RD::RENDER_PRIMITIVE_TRIANGLES, RD::RENDER_PRIMITIVE_TRIANGLES, RD::RENDER_PRIMITIVE_LINES, RD::RENDER_PRIMITIVE_POINTS }; - ShaderVariant shader_variants[PIPELINE_VARIANT_MAX] = { SHADER_VARIANT_QUAD, SHADER_VARIANT_NINEPATCH, SHADER_VARIANT_VERTICES, SHADER_VARIANT_VERTICES, SHADER_VARIANT_POINTS }; + RD::RenderPrimitive primitive[PIPELINE_VARIANT_MAX] = { + RD::RENDER_PRIMITIVE_TRIANGLES, + RD::RENDER_PRIMITIVE_TRIANGLES, + RD::RENDER_PRIMITIVE_TRIANGLES, + RD::RENDER_PRIMITIVE_LINES, + RD::RENDER_PRIMITIVE_POINTS, + RD::RENDER_PRIMITIVE_TRIANGLES, + RD::RENDER_PRIMITIVE_LINES, + RD::RENDER_PRIMITIVE_POINTS, + }; + ShaderVariant shader_variants[PIPELINE_VARIANT_MAX] = { + SHADER_VARIANT_QUAD, + SHADER_VARIANT_NINEPATCH, + SHADER_VARIANT_PRIMITIVE, + SHADER_VARIANT_PRIMITIVE, + SHADER_VARIANT_PRIMITIVE_POINTS, + SHADER_VARIANT_ATTRIBUTES, + SHADER_VARIANT_ATTRIBUTES, + SHADER_VARIANT_ATTRIBUTES_POINTS + }; RID shader_variant = shader.canvas_shader.version_get_shader(shader.default_version, shader_variants[j]); - shader.pipeline_variants.variants[i][j].setup(shader_variant, fb_format, primitive[j], RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_blend(), j == PIPELINE_VARIANT_LINES ? RD::DYNAMIC_STATE_LINE_WIDTH : 0); + shader.pipeline_variants.variants[i][j].setup(shader_variant, fb_format, primitive[j], RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_blend(), 0); } } @@ -1216,6 +1418,11 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { } } + { + //polygon buffers + polygon_buffers.last_id = 1; + } + { // default index buffer PoolVector pv; @@ -1230,17 +1437,24 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { p32[4] = 2; p32[5] = 3; } - RID index_buffer = RD::get_singleton()->index_buffer_create(6, RenderingDevice::INDEX_BUFFER_FORMAT_UINT32, pv); - shader.quad_index_array = RD::get_singleton()->index_array_create(index_buffer, 0, 6); + shader.quad_index_buffer = RD::get_singleton()->index_buffer_create(6, RenderingDevice::INDEX_BUFFER_FORMAT_UINT32, pv); + shader.quad_index_array = RD::get_singleton()->index_array_create(shader.quad_index_buffer, 0, 6); + } + + { //primitive + primitive_arrays.index_array[0] = shader.quad_index_array = RD::get_singleton()->index_array_create(shader.quad_index_buffer, 0, 1); + primitive_arrays.index_array[1] = shader.quad_index_array = RD::get_singleton()->index_array_create(shader.quad_index_buffer, 0, 2); + primitive_arrays.index_array[2] = shader.quad_index_array = RD::get_singleton()->index_array_create(shader.quad_index_buffer, 0, 3); + primitive_arrays.index_array[3] = shader.quad_index_array = RD::get_singleton()->index_array_create(shader.quad_index_buffer, 0, 6); } { //default skeleton buffer - shader.default_material_skeleton_uniform = RD::get_singleton()->uniform_buffer_create(sizeof(SkeletonUniform)); + shader.default_skeleton_uniform = RD::get_singleton()->uniform_buffer_create(sizeof(SkeletonUniform)); SkeletonUniform su; _update_transform_2d_to_mat4(Transform2D(), su.skeleton_inverse); _update_transform_2d_to_mat4(Transform2D(), su.skeleton_transform); - RD::get_singleton()->buffer_update(shader.default_material_skeleton_uniform, 0, sizeof(SkeletonUniform), &su); + RD::get_singleton()->buffer_update(shader.default_skeleton_uniform, 0, sizeof(SkeletonUniform), &su); } { //default material uniform set @@ -1248,7 +1462,7 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { RD::Uniform u; u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 2; - u.ids.push_back(shader.default_material_skeleton_uniform); + u.ids.push_back(shader.default_skeleton_uniform); default_material_uniforms.push_back(u); u.ids.clear(); @@ -1257,8 +1471,68 @@ RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) { u.ids.push_back(default_textures.default_multimesh_tb); default_material_uniforms.push_back(u); - shader.default_material_uniform_set = RD::get_singleton()->uniform_set_create(default_material_uniforms, shader.default_version_rd_shader, 1); + shader.default_skeleton_uniform_set = RD::get_singleton()->uniform_set_create(default_material_uniforms, shader.canvas_shader.version_get_shader(shader.default_version, SHADER_VARIANT_ATTRIBUTES), 2); } ERR_FAIL_COND(sizeof(PushConstant) != 128); } + +RasterizerCanvasRD::~RasterizerCanvasRD() { + + //canvas state + + if (state.canvas_state_buffer.is_valid()) { + RD::get_singleton()->free(state.canvas_state_buffer); + } + + if (state.canvas_state_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(state.canvas_state_uniform_set)) { + RD::get_singleton()->free(state.canvas_state_uniform_set); + } + + //bindings + { + + free_texture_binding(bindings.default_empty); + + //dispose pending + _dispose_bindings(); + //anything remains? + if (bindings.texture_bindings.size()) { + ERR_PRINT("Some texture bindings were not properly freed (leaked canvasitems?"); + const TextureBindingID *key = NULL; + while ((key = bindings.texture_bindings.next(key))) { + TextureBinding *tb = bindings.texture_bindings[*key]; + tb->reference_count = 1; + free_texture_binding(*key); + } + //dispose pending + _dispose_bindings(); + } + } + + //shaders + + RD::get_singleton()->free(shader.default_skeleton_uniform_set); + RD::get_singleton()->free(shader.default_skeleton_uniform); + shader.canvas_shader.version_free(shader.default_version); + + //buffers + RD::get_singleton()->free(shader.quad_index_array); + RD::get_singleton()->free(shader.quad_index_buffer); + + //pipelines don't need freeing, they are all gone after shaders are gone + + //samplers + for (int i = 1; i < VS::CANVAS_ITEM_TEXTURE_FILTER_MAX; i++) { + for (int j = 1; j < VS::CANVAS_ITEM_TEXTURE_REPEAT_MAX; j++) { + RD::get_singleton()->free(default_samplers.samplers[i][j]); + } + } + + //textures + RD::get_singleton()->free(default_textures.white_texture); + RD::get_singleton()->free(default_textures.black_texture); + RD::get_singleton()->free(default_textures.normal_texture); + RD::get_singleton()->free(default_textures.aniso_texture); + RD::get_singleton()->free(default_textures.default_multimesh_tb); +} diff --git a/servers/visual/rasterizer/rasterizer_canvas_rd.h b/servers/visual/rasterizer/rasterizer_canvas_rd.h index dbe6e7b394f..911a3b6225e 100644 --- a/servers/visual/rasterizer/rasterizer_canvas_rd.h +++ b/servers/visual/rasterizer/rasterizer_canvas_rd.h @@ -14,8 +14,10 @@ class RasterizerCanvasRD : public RasterizerCanvas { enum ShaderVariant { SHADER_VARIANT_QUAD, SHADER_VARIANT_NINEPATCH, - SHADER_VARIANT_VERTICES, - SHADER_VARIANT_POINTS, + SHADER_VARIANT_PRIMITIVE, + SHADER_VARIANT_PRIMITIVE_POINTS, + SHADER_VARIANT_ATTRIBUTES, + SHADER_VARIANT_ATTRIBUTES_POINTS, SHADER_VARIANT_MAX }; @@ -51,9 +53,12 @@ class RasterizerCanvasRD : public RasterizerCanvas { enum PipelineVariant { PIPELINE_VARIANT_QUAD, PIPELINE_VARIANT_NINEPATCH, - PIPELINE_VARIANT_TRIANGLES, - PIPELINE_VARIANT_LINES, - PIPELINE_VARIANT_POINTS, + PIPELINE_VARIANT_PRIMITIVE_TRIANGLES, + PIPELINE_VARIANT_PRIMITIVE_LINES, + PIPELINE_VARIANT_PRIMITIVE_POINTS, + PIPELINE_VARIANT_ATTRIBUTE_TRIANGLES, + PIPELINE_VARIANT_ATTRIBUTE_LINES, + PIPELINE_VARIANT_ATTRIBUTE_POINTS, PIPELINE_VARIANT_MAX }; struct PipelineVariants { @@ -65,12 +70,13 @@ class RasterizerCanvasRD : public RasterizerCanvas { RD::FramebufferFormatID framebuffer_formats[RENDER_TARGET_FORMAT_MAX]; RID default_version; RID default_version_rd_shader; + RID quad_index_buffer; RID quad_index_array; PipelineVariants pipeline_variants; // default_skeleton uniform set - RID default_material_skeleton_uniform; - RID default_material_uniform_set; + RID default_skeleton_uniform; + RID default_skeleton_uniform_set; } shader; @@ -126,6 +132,7 @@ class RasterizerCanvasRD : public RasterizerCanvas { TextureBindingID default_empty; } bindings; + RID _create_texture_binding(RID p_texture, RID p_normalmap, RID p_specular, VisualServer::CanvasItemTextureFilter p_filter, VisualServer::CanvasItemTextureRepeat p_repeat, RID p_multimesh); void _dispose_bindings(); struct { RID white_texture; @@ -143,6 +150,31 @@ class RasterizerCanvasRD : public RasterizerCanvas { VS::CanvasItemTextureRepeat default_repeat; } default_samplers; + /******************/ + /**** POLYGONS ****/ + /******************/ + + struct PolygonBuffers { + RD::VertexFormatID vertex_format_id; + RID vertex_buffer; + RID vertex_array; + RID index_buffer; + RID indices; + }; + + struct { + HashMap polygons; + PolygonID last_id; + } polygon_buffers; + + /********************/ + /**** PRIMITIVES ****/ + /********************/ + + struct { + RID index_array[4]; + } primitive_arrays; + /*******************/ /**** MATERIALS ****/ /*******************/ @@ -171,15 +203,26 @@ class RasterizerCanvasRD : public RasterizerCanvas { } state; struct PushConstant { - float world[8]; - float modulation[4]; - float ninepatch_margins[4]; - float dst_rect[4]; - float src_rect[4]; + float world[6]; uint32_t flags; uint32_t specular_shininess; - float color_texture_pixel_size[2]; - uint32_t pad[4]; + union { + //rect + struct { + float modulation[4]; + float ninepatch_margins[4]; + float dst_rect[4]; + float src_rect[4]; + float color_texture_pixel_size[2]; + uint32_t pad[6]; + }; + //primitive + struct { + float points[8]; // vec2 points[4] + uint32_t colors[8]; // colors encoded as half + float uvs[8]; // vec2 points[4] + }; + }; }; struct SkeletonUniform { @@ -193,10 +236,12 @@ class RasterizerCanvasRD : public RasterizerCanvas { Item *items[MAX_RENDER_ITEMS]; - void _render_item(RenderingDevice::DrawListID p_draw_list, const Item *p_item, RenderTargetFormat p_render_target_format, RenderingDevice::TextureSamples p_samples, const Color &p_modulate, const Transform2D &p_canvas_transform_inverse); - void _render_items(RID p_to_render_target, bool p_clear, const Color &p_clear_color, int p_item_count, const Color &p_modulate, const Transform2D &p_transform); + Size2i _bind_texture_binding(TextureBindingID p_binding, RenderingDevice::DrawListID p_draw_list); + void _render_item(RenderingDevice::DrawListID p_draw_list, const Item *p_item, RenderTargetFormat p_render_target_format, RenderingDevice::TextureSamples p_samples, const Color &p_modulate, const Transform2D &p_canvas_transform_inverse, Item *¤t_clip); + void _render_items(RID p_to_render_target, int p_item_count, const Color &p_modulate, const Transform2D &p_transform); void _update_transform_2d_to_mat2x4(const Transform2D &p_transform, float *p_mat2x4); + void _update_transform_2d_to_mat2x3(const Transform2D &p_transform, float *p_mat2x3); void _update_transform_2d_to_mat4(const Transform2D &p_transform, float *p_mat4); void _update_transform_to_mat4(const Transform &p_transform, float *p_mat4); @@ -207,11 +252,14 @@ public: TextureBindingID request_texture_binding(RID p_texture, RID p_normalmap, RID p_specular, VS::CanvasItemTextureFilter p_filter, VS::CanvasItemTextureRepeat p_repeat, RID p_multimesh); void free_texture_binding(TextureBindingID p_binding); + PolygonID request_polygon(const Vector &p_indices, const Vector &p_points, const Vector &p_colors, const Vector &p_uvs = Vector(), const Vector &p_bones = Vector(), const Vector &p_weights = Vector()); + void free_polygon(PolygonID p_polygon); + RID light_internal_create() { return RID(); } void light_internal_update(RID p_rid, Light *p_light) {} void light_internal_free(RID p_rid) {} - void canvas_render_items(RID p_to_render_target, bool p_clear, const Color &p_clear_color, Item *p_item_list, const Color &p_modulate, Light *p_light_list, const Transform2D &p_canvas_transform); + void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, const Transform2D &p_canvas_transform); void canvas_debug_viewport_shadows(Light *p_lights_with_shadow){}; @@ -223,7 +271,7 @@ public: void update(); RasterizerCanvasRD(RasterizerStorageRD *p_storage); - ~RasterizerCanvasRD() {} + ~RasterizerCanvasRD(); }; #endif // RASTERIZER_CANVAS_RD_H diff --git a/servers/visual/rasterizer/rasterizer_rd.cpp b/servers/visual/rasterizer/rasterizer_rd.cpp index 83c722b5d2e..62449fafb41 100644 --- a/servers/visual/rasterizer/rasterizer_rd.cpp +++ b/servers/visual/rasterizer/rasterizer_rd.cpp @@ -1,5 +1,9 @@ #include "rasterizer_rd.h" +void RasterizerRD::prepare_for_blitting_render_targets() { + RD::get_singleton()->prepare_screen_for_drawing(); +} + void RasterizerRD::blit_render_targets_to_screen(int p_screen, const BlitToScreen *p_render_targets, int p_amount) { RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin_for_screen(p_screen); diff --git a/servers/visual/rasterizer/rasterizer_rd.h b/servers/visual/rasterizer/rasterizer_rd.h index fb5945fa4d1..b895f480650 100644 --- a/servers/visual/rasterizer/rasterizer_rd.h +++ b/servers/visual/rasterizer/rasterizer_rd.h @@ -29,6 +29,7 @@ public: void initialize(); void begin_frame(double frame_step); + void prepare_for_blitting_render_targets(); void blit_render_targets_to_screen(int p_screen, const BlitToScreen *p_render_targets, int p_amount); void end_frame(bool p_swap_buffers); diff --git a/servers/visual/rasterizer/rasterizer_storage_rd.cpp b/servers/visual/rasterizer/rasterizer_storage_rd.cpp index e120b86ba3c..d38d0c62c87 100644 --- a/servers/visual/rasterizer/rasterizer_storage_rd.cpp +++ b/servers/visual/rasterizer/rasterizer_storage_rd.cpp @@ -486,6 +486,7 @@ RID RasterizerStorageRD::texture_2d_create(const Ref &p_image) { texture.layers = 1; texture.mipmaps = p_image->get_mipmap_count() + 1; texture.depth = 1; + texture.format = p_image->get_format(); texture.rd_type = RD::TEXTURE_TYPE_2D; texture.rd_format = ret_format.format; @@ -532,6 +533,8 @@ RID RasterizerStorageRD::texture_2d_create(const Ref &p_image) { texture.width_2d = texture.width; texture.height_2d = texture.height; texture.is_render_target = false; + texture.rd_view = rd_view; + texture.is_proxy = false; #warning TODO this is temporary to get things to work texture.image_cache_2d = p_image; @@ -549,6 +552,28 @@ RID RasterizerStorageRD::texture_3d_create(const Vector > &p_slices) return RID(); } +RID RasterizerStorageRD::texture_proxy_create(RID p_base) { + Texture *tex = texture_owner.getornull(p_base); + ERR_FAIL_COND_V(!tex, RID()); + Texture proxy_tex = *tex; + + proxy_tex.rd_view.format_override = tex->rd_format; + proxy_tex.rd_texture = RD::get_singleton()->texture_create_shared(proxy_tex.rd_view, tex->rd_texture); + if (proxy_tex.rd_texture_srgb.is_valid()) { + proxy_tex.rd_view.format_override = tex->rd_format_srgb; + proxy_tex.rd_texture_srgb = RD::get_singleton()->texture_create_shared(proxy_tex.rd_view, tex->rd_texture); + } + proxy_tex.proxy_to = p_base; + proxy_tex.is_render_target = false; + proxy_tex.is_proxy = true; + proxy_tex.proxies.clear(); + + RID rid = texture_owner.make_rid(proxy_tex); + + tex->proxies.push_back(rid); + return rid; +} + void RasterizerStorageRD::_texture_2d_update(RID p_texture, const Ref &p_image, int p_layer, bool p_immediate) { ERR_FAIL_COND(p_image.is_null() || p_image->empty()); @@ -581,6 +606,46 @@ void RasterizerStorageRD::texture_2d_update(RID p_texture, const Ref &p_i void RasterizerStorageRD::texture_3d_update(RID p_texture, const Ref &p_image, int p_depth, int p_mipmap) { } +void RasterizerStorageRD::texture_proxy_update(RID p_texture, RID p_proxy_to) { + + Texture *tex = texture_owner.getornull(p_texture); + ERR_FAIL_COND(!tex); + ERR_FAIL_COND(!tex->is_proxy); + Texture *proxy_to = texture_owner.getornull(p_proxy_to); + ERR_FAIL_COND(!proxy_to); + ERR_FAIL_COND(proxy_to->is_proxy); + + if (tex->proxy_to.is_valid()) { + //unlink proxy + if (RD::get_singleton()->texture_is_valid(tex->rd_texture)) { + RD::get_singleton()->free(tex->rd_texture); + tex->rd_texture = RID(); + } + if (RD::get_singleton()->texture_is_valid(tex->rd_texture_srgb)) { + RD::get_singleton()->free(tex->rd_texture_srgb); + tex->rd_texture_srgb = RID(); + } + Texture *prev_tex = texture_owner.getornull(tex->proxy_to); + ERR_FAIL_COND(!prev_tex); + prev_tex->proxies.erase(p_texture); + } + + *tex = *proxy_to; + + tex->proxy_to = p_proxy_to; + tex->is_render_target = false; + tex->is_proxy = true; + tex->proxies.clear(); + proxy_to->proxies.push_back(p_texture); + + tex->rd_view.format_override = tex->rd_format; + tex->rd_texture = RD::get_singleton()->texture_create_shared(tex->rd_view, proxy_to->rd_texture); + if (tex->rd_texture_srgb.is_valid()) { + tex->rd_view.format_override = tex->rd_format_srgb; + tex->rd_texture_srgb = RD::get_singleton()->texture_create_shared(tex->rd_view, proxy_to->rd_texture); + } +} + //these two APIs can be used together or in combination with the others. RID RasterizerStorageRD::texture_2d_placeholder_create() { @@ -629,20 +694,34 @@ void RasterizerStorageRD::texture_replace(RID p_texture, RID p_by_texture) { Texture *tex = texture_owner.getornull(p_texture); ERR_FAIL_COND(!tex); + ERR_FAIL_COND(tex->proxy_to.is_valid()); //cant replace proxy Texture *by_tex = texture_owner.getornull(p_by_texture); ERR_FAIL_COND(!by_tex); + ERR_FAIL_COND(by_tex->proxy_to.is_valid()); //cant replace proxy if (tex == by_tex) { return; } - RD::get_singleton()->free(tex->rd_texture); if (tex->rd_texture_srgb.is_valid()) { RD::get_singleton()->free(tex->rd_texture_srgb); } + RD::get_singleton()->free(tex->rd_texture); + + Vector proxies_to_update = tex->proxies; + Vector proxies_to_redirect = by_tex->proxies; *tex = *by_tex; + tex->proxies = proxies_to_update; //restore proxies, so they can be updated + + for (int i = 0; i < proxies_to_update.size(); i++) { + texture_proxy_update(proxies_to_update[i], p_texture); + } + for (int i = 0; i < proxies_to_redirect.size(); i++) { + texture_proxy_update(proxies_to_redirect[i], p_texture); + } + //delete last, so proxies can be updated texture_owner.free(p_by_texture); } void RasterizerStorageRD::texture_set_size_override(RID p_texture, int p_width, int p_height) { @@ -650,7 +729,7 @@ void RasterizerStorageRD::texture_set_size_override(RID p_texture, int p_width, ERR_FAIL_COND(!tex); ERR_FAIL_COND(tex->type != Texture::TYPE_2D); tex->width_2d = p_width; - tex->height_2d = p_width; + tex->height_2d = p_height; } void RasterizerStorageRD::texture_set_path(RID p_texture, const String &p_path) { @@ -673,8 +752,8 @@ void RasterizerStorageRD::texture_set_proxy(RID p_proxy, RID p_base) { void RasterizerStorageRD::texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) { } -Size2 RasterizerStorageRD::texture_size_with_proxy(RID p_proxy) const { - return Size2(); +Size2 RasterizerStorageRD::texture_size_with_proxy(RID p_proxy) { + return texture_2d_get_size(p_proxy); } /* RENDER TARGET API */ @@ -685,9 +764,6 @@ void RasterizerStorageRD::_clear_render_target(RenderTarget *rt) { if (rt->framebuffer.is_valid()) { RD::get_singleton()->free(rt->framebuffer); } - if (rt->color_srgb.is_valid()) { - RD::get_singleton()->free(rt->color_srgb); - } if (rt->color.is_valid()) { RD::get_singleton()->free(rt->color); @@ -695,14 +771,19 @@ void RasterizerStorageRD::_clear_render_target(RenderTarget *rt) { rt->framebuffer = RID(); rt->color = RID(); - rt->color_srgb = RID(); rt->dirty = true; - rt->texture_dirty = true; } void RasterizerStorageRD::_update_render_target(RenderTarget *rt) { + if (rt->texture.is_null()) { + //create a placeholder until updated + rt->texture = texture_2d_placeholder_create(); + Texture *tex = texture_owner.getornull(rt->texture); + tex->is_render_target = true; + } + _clear_render_target(rt); if (rt->size.width == 0 || rt->size.height == 0) { @@ -732,14 +813,6 @@ void RasterizerStorageRD::_update_render_target(RenderTarget *rt) { rt->color = RD::get_singleton()->texture_create(rd_format, rd_view); ERR_FAIL_COND(rt->color.is_null()); - if (rt->color_format_srgb != RD::DATA_FORMAT_MAX) { - rd_view.format_override = rt->color_format_srgb; - rt->color_srgb = RD::get_singleton()->texture_create_shared(rd_view, rt->color); - if (rt->color_srgb.is_null()) { - _clear_render_target(rt); - ERR_FAIL_COND(rt->color_srgb.is_null()); - } - } Vector fb_textures; fb_textures.push_back(rt->color); @@ -749,14 +822,55 @@ void RasterizerStorageRD::_update_render_target(RenderTarget *rt) { ERR_FAIL_COND(rt->framebuffer.is_null()); } + { //update texture + + Texture *tex = texture_owner.getornull(rt->texture); + + //free existing textures + if (RD::get_singleton()->texture_is_valid(tex->rd_texture)) { + RD::get_singleton()->free(tex->rd_texture); + } + if (RD::get_singleton()->texture_is_valid(tex->rd_texture_srgb)) { + RD::get_singleton()->free(tex->rd_texture_srgb); + } + + tex->rd_texture = RID(); + tex->rd_texture_srgb = RID(); + + //create shared textures to the color buffer, + //so transparent can be supported + RD::TextureView view; + view.format_override = rt->color_format; + if (!rt->flags[RENDER_TARGET_TRANSPARENT]) { + view.swizzle_a = RD::TEXTURE_SWIZZLE_ONE; + } + tex->rd_texture = RD::get_singleton()->texture_create_shared(view, rt->color); + if (rt->color_format_srgb != RD::DATA_FORMAT_MAX) { + view.format_override = rt->color_format_srgb; + tex->rd_texture_srgb = RD::get_singleton()->texture_create_shared(view, rt->color); + } + tex->rd_view = view; + tex->width = rt->size.width; + tex->height = rt->size.height; + tex->width_2d = rt->size.width; + tex->height_2d = rt->size.height; + tex->rd_format = rt->color_format; + tex->rd_format_srgb = rt->color_format_srgb; + tex->format = rt->image_format; + + Vector proxies = tex->proxies; //make a copy, since update may change it + for (int i = 0; i < proxies.size(); i++) { + texture_proxy_update(proxies[i], rt->texture); + } + } rt->dirty = false; } RID RasterizerStorageRD::render_target_create() { RenderTarget render_target; render_target.dirty = true; - render_target.texture_dirty = true; render_target.was_used = false; + render_target.clear_requested = false; for (int i = 0; i < RENDER_TARGET_FLAG_MAX; i++) { render_target.flags[i] = false; @@ -774,48 +888,14 @@ void RasterizerStorageRD::render_target_set_size(RID p_render_target, int p_widt rt->size.x = p_width; rt->size.y = p_height; rt->dirty = true; - rt->texture_dirty = true; } RID RasterizerStorageRD::render_target_get_texture(RID p_render_target) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND_V(!rt, RID()); - if (rt->texture_dirty) { - if (rt->dirty) { - _update_render_target(rt); - } - - if (rt->texture.is_null()) { - //kinda hacky, but not terrible - rt->texture = texture_2d_placeholder_create(); - } - - Texture *tex = texture_owner.getornull(rt->texture); - - if (!tex->is_render_target) { - //first allocation, fix it up - RD::get_singleton()->free(tex->rd_texture); - if (tex->rd_texture_srgb.is_null()) { - RD::get_singleton()->free(tex->rd_texture_srgb); - } - tex->is_render_target = true; - } - - if (!rt->color.is_null()) { - //there is a color buffer, update to it - tex->rd_texture = rt->color; - tex->rd_texture_srgb = rt->color_srgb; - tex->width = rt->size.width; - tex->height = rt->size.height; - tex->width_2d = rt->size.width; - tex->height_2d = rt->size.height; - tex->rd_format = rt->color_format; - tex->rd_format_srgb = rt->color_format_srgb; - tex->format = rt->image_format; - } - - rt->texture_dirty = false; + if (rt->dirty) { + _update_render_target(rt); } return rt->texture; @@ -829,7 +909,6 @@ void RasterizerStorageRD::render_target_set_flag(RID p_render_target, RenderTarg ERR_FAIL_COND(!rt); rt->flags[p_flag] = p_value; rt->dirty = true; - rt->texture_dirty = true; } bool RasterizerStorageRD::render_target_was_used(RID p_render_target) { @@ -839,7 +918,7 @@ bool RasterizerStorageRD::render_target_was_used(RID p_render_target) { return rt->was_used; } -void RasterizerStorageRD::render_target_clear_used_flag(RID p_render_target) { +void RasterizerStorageRD::render_target_set_as_unused(RID p_render_target) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND(!rt); @@ -864,6 +943,33 @@ RID RasterizerStorageRD::render_target_get_rd_framebuffer(RID p_render_target) { return rt->framebuffer; } +void RasterizerStorageRD::render_target_request_clear(RID p_render_target, const Color &p_clear_color) { + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND(!rt); + rt->clear_requested = true; + rt->clear_color = p_clear_color; +} + +bool RasterizerStorageRD::render_target_is_clear_requested(RID p_render_target) { + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND_V(!rt, false); + return rt->clear_requested; +} + +Color RasterizerStorageRD::render_target_get_clear_request_color(RID p_render_target) { + + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND_V(!rt, Color()); + return rt->clear_color; +} + +void RasterizerStorageRD::render_target_disable_clear_request(RID p_render_target) { + + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND(!rt); + rt->clear_requested = false; +} + bool RasterizerStorageRD::free(RID p_rid) { if (texture_owner.owns(p_rid)) { @@ -871,10 +977,19 @@ bool RasterizerStorageRD::free(RID p_rid) { ERR_FAIL_COND_V(t->is_render_target, false); - RD::get_singleton()->free(t->rd_texture); if (t->rd_texture_srgb.is_valid()) { + //erase this first, as it's a dependency of the one below RD::get_singleton()->free(t->rd_texture_srgb); } + RD::get_singleton()->free(t->rd_texture); + + for (int i = 0; i < t->proxies.size(); i++) { + Texture *p = texture_owner.getornull(t->proxies[i]); + ERR_CONTINUE(!p); + p->proxy_to = RID(); + p->rd_texture = RID(); + p->rd_texture_srgb = RID(); + } texture_owner.free(p_rid); } else if (render_target_owner.owns(p_rid)) { diff --git a/servers/visual/rasterizer/rasterizer_storage_rd.h b/servers/visual/rasterizer/rasterizer_storage_rd.h index caaaced75ff..39404347fb7 100644 --- a/servers/visual/rasterizer/rasterizer_storage_rd.h +++ b/servers/visual/rasterizer/rasterizer_storage_rd.h @@ -23,6 +23,8 @@ public: RenderingDevice::DataFormat rd_format; RenderingDevice::DataFormat rd_format_srgb; + RD::TextureView rd_view; + Image::Format format; int width; int height; @@ -34,9 +36,13 @@ public: int width_2d; bool is_render_target; + bool is_proxy; Ref image_cache_2d; String path; + + RID proxy_to; + Vector proxies; }; struct TextureToRDFormat { @@ -67,7 +73,6 @@ public: Size2i size; RID framebuffer; RID color; - RID color_srgb; //used for retrieving from CPU RD::DataFormat color_format; @@ -79,8 +84,11 @@ public: //texture generated for this owner (nor RD). RID texture; bool dirty; - bool texture_dirty; bool was_used; + + //clear request + bool clear_requested; + Color clear_color; }; RID_Owner render_target_owner; @@ -94,12 +102,14 @@ public: virtual RID texture_2d_create(const Ref &p_image); virtual RID texture_2d_layered_create(const Vector > &p_layers, VS::TextureLayeredType p_layered_type); virtual RID texture_3d_create(const Vector > &p_slices); //all slices, then all the mipmaps, must be coherent + virtual RID texture_proxy_create(RID p_base); virtual void _texture_2d_update(RID p_texture, const Ref &p_image, int p_layer, bool p_immediate); virtual void texture_2d_update_immediate(RID p_texture, const Ref &p_image, int p_layer = 0); //mostly used for video and streaming virtual void texture_2d_update(RID p_texture, const Ref &p_image, int p_layer = 0); virtual void texture_3d_update(RID p_texture, const Ref &p_image, int p_depth, int p_mipmap); + virtual void texture_proxy_update(RID p_texture, RID p_proxy_to); //these two APIs can be used together or in combination with the others. virtual RID texture_2d_placeholder_create(); @@ -125,7 +135,7 @@ public: virtual void texture_set_proxy(RID p_proxy, RID p_base); virtual void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable); - virtual Size2 texture_size_with_proxy(RID p_proxy) const; + virtual Size2 texture_size_with_proxy(RID p_proxy); //internal usage @@ -625,7 +635,12 @@ 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); - void render_target_clear_used_flag(RID p_render_target); + void render_target_set_as_unused(RID p_render_target); + + virtual void render_target_request_clear(RID p_render_target, const Color &p_clear_color); + virtual bool render_target_is_clear_requested(RID p_render_target); + virtual Color render_target_get_clear_request_color(RID p_render_target); + virtual void render_target_disable_clear_request(RID p_render_target); Size2 render_target_get_size(RID p_render_target); RID render_target_get_rd_framebuffer(RID p_render_target); diff --git a/servers/visual/rasterizer/render_pipeline_vertex_format_cache_rd.cpp b/servers/visual/rasterizer/render_pipeline_vertex_format_cache_rd.cpp index 441c70cdcff..be2aa95c34b 100644 --- a/servers/visual/rasterizer/render_pipeline_vertex_format_cache_rd.cpp +++ b/servers/visual/rasterizer/render_pipeline_vertex_format_cache_rd.cpp @@ -22,7 +22,10 @@ void RenderPipelineVertexFormatCacheRD::_clear() { for (int v = 0; v < RD::TEXTURE_SAMPLES_MAX; v++) { if (versions[v]) { for (uint32_t i = 0; i < version_count[v]; i++) { - RD::get_singleton()->free(versions[v][i].pipeline); + //shader may be gone, so this may not be valid + if (RD::get_singleton()->render_pipeline_is_valid(versions[v][i].pipeline)) { + RD::get_singleton()->free(versions[v][i].pipeline); + } } version_count[v] = 0; memfree(versions[v]); diff --git a/servers/visual/rasterizer/shaders/canvas.glsl b/servers/visual/rasterizer/shaders/canvas.glsl index f8900326c85..50782f99b0f 100644 --- a/servers/visual/rasterizer/shaders/canvas.glsl +++ b/servers/visual/rasterizer/shaders/canvas.glsl @@ -8,13 +8,14 @@ VERSION_DEFINES /* clang-format on */ -#ifdef USE_VERTEX_ARRAYS +#ifdef USE_ATTRIBUTES layout(location = 0) in vec2 vertex_attrib; layout(location = 3) in vec4 color_attrib; layout(location = 4) in vec2 uv_attrib; layout(location = 6) in uvec4 bone_indices_attrib; layout(location = 7) in vec4 bone_weights_attrib; + #endif #include "canvas_uniforms_inc.glsl" @@ -42,12 +43,45 @@ VERTEX_SHADER_GLOBALS void main() { vec4 instance_custom = vec4(0.0); +#ifdef USE_PRIMITIVE -#ifdef USE_VERTEX_ARRAYS +//weird bug, +//this works + vec2 vertex; + vec2 uv; + vec4 color; + + if (gl_VertexIndex==0) { + vertex = draw_data.points[0]; + uv = draw_data.uvs[0]; + color = vec4(unpackHalf2x16(draw_data.colors[0]),unpackHalf2x16(draw_data.colors[1])); + } else if (gl_VertexIndex==1) { + vertex = draw_data.points[1]; + uv = draw_data.uvs[1]; + color = vec4(unpackHalf2x16(draw_data.colors[2]),unpackHalf2x16(draw_data.colors[3])); + } else if (gl_VertexIndex==2) { + vertex = draw_data.points[2]; + uv = draw_data.uvs[2]; + color = vec4(unpackHalf2x16(draw_data.colors[4]),unpackHalf2x16(draw_data.colors[5])); + + } else { + vertex = draw_data.points[3]; + uv = draw_data.uvs[3]; + color = vec4(unpackHalf2x16(draw_data.colors[6]),unpackHalf2x16(draw_data.colors[7])); + } +// this does not +// vec2 vertex = draw_data.points[gl_VertexIndex]; +// vec2 uv = draw_data.uvs[gl_VertexIndex]; +// vec4 color = vec4(unpackHalf2x16(draw_data.colors[gl_VertexIndex*2+0]),unpackHalf2x16(draw_data.colors[gl_VertexIndex*2+1])); + uvec4 bone_indices = uvec4(0,0,0,0); + vec4 bone_weights = vec4(0,0,0,0); + +#elif defined(USE_ATTRIBUTES) vec2 vertex = vertex_attrib; vec4 color = color_attrib; vec2 uv = uv_attrib; + uvec4 bone_indices = bone_indices_attrib; vec4 bone_weights = bone_weights_attrib; #else @@ -55,16 +89,17 @@ void main() { vec2 vertex_base_arr[4] = vec2[](vec2(0.0,0.0),vec2(0.0,1.0),vec2(1.0,1.0),vec2(1.0,0.0)); vec2 vertex_base = vertex_base_arr[gl_VertexIndex]; - vec2 uv = draw_data.src_rect.xy + draw_data.src_rect.zw * ((draw_data.flags&FLAGS_TRANSPOSE_RECT)!=0 ? vertex_base.yx : vertex_base.xy); - vec4 color = vec4(1.0); + vec2 uv = draw_data.src_rect.xy + abs(draw_data.src_rect.zw) * ((draw_data.flags&FLAGS_TRANSPOSE_RECT)!=0 ? vertex_base.yx : vertex_base.xy); + vec4 color = draw_data.modulation; vec2 vertex = draw_data.dst_rect.xy + abs(draw_data.dst_rect.zw) * mix(vertex_base, vec2(1.0, 1.0) - vertex_base, lessThan(draw_data.src_rect.zw, vec2(0.0, 0.0))); uvec4 bone_indices = uvec4(0,0,0,0); vec4 bone_weights = vec4(0,0,0,0); #endif - mat4 world_matrix = transpose(mat4(draw_data.world[0],draw_data.world[1],vec4(0.0,0.0,1.0,0.0),vec4(0.0,0.0,0.0,1.0))); + mat4 world_matrix = mat4(vec4(draw_data.world_x,0.0,0.0),vec4(draw_data.world_y,0.0,0.0),vec4(0.0,0.0,1.0,0.0),vec4(draw_data.world_ofs,0.0,1.0)); #if 0 + if (draw_data.flags&FLAGS_INSTANCING_ENABLED) { uint offset = draw_data.flags&FLAGS_INSTANCING_STRIDE_MASK; @@ -101,10 +136,13 @@ void main() { #endif +#if !defined(USE_ATTRIBUTES) && !defined(USE_PRIMITIVE) if (bool(draw_data.flags&FLAGS_USING_PARTICLES)) { //scale by texture size vertex /= draw_data.color_texture_pixel_size; } +#endif + #ifdef USE_POINT_SIZE float point_size = 1.0; #endif @@ -134,6 +172,7 @@ VERTEX_SHADER_CODE uv += 1e-5; } +#ifdef USE_ATTRIBUTES #if 0 if (bool(draw_data.flags&FLAGS_USE_SKELETON) && bone_weights != vec4(0.0)) { //must be a valid bone //skeleton transform @@ -173,6 +212,7 @@ VERTEX_SHADER_CODE //outvec = bone_matrix * outvec; } +#endif #endif uv_interp = uv; @@ -285,7 +325,7 @@ void main() { vec4 color = color_interp; vec2 uv = uv_interp; -#ifndef USE_VERTEX_ARRAYS +#if !defined(USE_ATTRIBUTES) && !defined(USE_PRIMITIVE) #ifdef USE_NINEPATCH @@ -300,8 +340,7 @@ void main() { uv = uv * draw_data.src_rect.zw + draw_data.src_rect.xy; //apply region if needed -#endif - +#endif if (bool(draw_data.flags&FLAGS_CLIP_RECT_UV)) { uv = clamp(uv, draw_data.src_rect.xy, draw_data.src_rect.xy + abs(draw_data.src_rect.zw)); @@ -362,7 +401,6 @@ FRAGMENT_SHADER_CODE #endif } - color *= draw_data.modulation; #if 0 if (canvas_data.light_count > 0 ) { //do lighting diff --git a/servers/visual/rasterizer/shaders/canvas_uniforms_inc.glsl b/servers/visual/rasterizer/shaders/canvas_uniforms_inc.glsl index d49b628078f..e0f9e202ae0 100644 --- a/servers/visual/rasterizer/shaders/canvas_uniforms_inc.glsl +++ b/servers/visual/rasterizer/shaders/canvas_uniforms_inc.glsl @@ -17,24 +17,28 @@ #define FLAGS_USING_PARTICLES (1 << 13) #define FLAGS_USE_PIXEL_SNAP (1 << 14) -#define FLAGS_USE_SKELETON (1 << 15) #define FLAGS_NINEPATCH_H_MODE_SHIFT 16 #define FLAGS_NINEPATCH_V_MODE_SHIFT 18 -layout(push_constant, binding = 0, std140) uniform DrawData { - mat2x4 world; +layout(push_constant, binding = 0, std430) uniform DrawData { + vec2 world_x; + vec2 world_y; + vec2 world_ofs; + uint flags; + uint specular_shininess; +#ifdef USE_PRIMITIVE + vec2 points[4]; + uint colors[8]; + vec2 uvs[4]; +#else vec4 modulation; vec4 ninepatch_margins; vec4 dst_rect; //for built-in rect and UV vec4 src_rect; - uint flags; - uint specular_shininess; vec2 color_texture_pixel_size; - uint pad0; - uint pad1; - uint pad2; - uint pad3; + uint pad[6]; +#endif } draw_data; @@ -51,16 +55,18 @@ layout(set = 0, binding = 5) uniform textureBuffer instancing_buffer; // -/* SET2: Per Canvas Item Settings */ +/* SET2: Is the skeleton */ -layout(set = 1, binding = 1) uniform textureBuffer skeleton_buffer; +#ifdef USE_ATTRIBUTES -layout(set = 1, binding = 2, std140) uniform SkeletonData { - mat4 skeleton_transform; +layout(set = 2, binding = 0) uniform textureBuffer skeleton_buffer; + +layout(set = 2, binding = 1, std140) uniform SkeletonData { + mat4 skeleton_transform; //in world coordinates mat4 skeleton_transform_inverse; } skeleton_data; -// this set (set 2) is also used for instance specific uniforms +#endif /* SET3: Per Scene settings */ diff --git a/servers/visual/rendering_device.h b/servers/visual/rendering_device.h index d30af9a7cb5..493390ba07f 100644 --- a/servers/visual/rendering_device.h +++ b/servers/visual/rendering_device.h @@ -354,6 +354,8 @@ public: virtual Error texture_update(RID p_texture, uint32_t p_layer, const PoolVector &p_data, bool p_sync_with_draw = false) = 0; //this function can be used from any thread and it takes effect at the begining of the frame, unless sync with draw is used, which is used to mix updates with draw calls virtual bool texture_is_format_supported_for_usage(DataFormat p_format, uint32_t p_usage) const = 0; + virtual bool texture_is_shared(RID p_texture) =0; + virtual bool texture_is_valid(RID p_texture) = 0; /*********************/ /**** FRAMEBUFFER ****/ @@ -811,6 +813,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) = 0; + virtual bool render_pipeline_is_valid(RID p_pipeline) =0; /****************/ /**** SCREEN ****/ @@ -850,6 +853,7 @@ public: virtual void draw_list_bind_uniform_set(DrawListID p_list, RID p_uniform_set, uint32_t p_index) = 0; virtual void draw_list_bind_vertex_array(DrawListID p_list, RID p_vertex_array) = 0; virtual void draw_list_bind_index_array(DrawListID p_list, RID p_index_array) = 0; + virtual void draw_list_set_line_width(DrawListID p_list, float p_width) = 0; virtual void draw_list_set_push_constant(DrawListID p_list, void *p_data, uint32_t p_data_size) = 0; virtual void draw_list_draw(DrawListID p_list, bool p_use_indices, uint32_t p_instances = 1) = 0; @@ -866,6 +870,7 @@ public: virtual void free(RID p_id) = 0; //methods below not exposed, used by RenderingDeviceRD + virtual void prepare_screen_for_drawing() =0; virtual void finalize_frame() = 0; virtual void advance_frame() = 0; diff --git a/servers/visual/visual_server_canvas.cpp b/servers/visual/visual_server_canvas.cpp index 790dc594963..f44548adedf 100644 --- a/servers/visual/visual_server_canvas.cpp +++ b/servers/visual/visual_server_canvas.cpp @@ -35,7 +35,7 @@ static const int z_range = VS::CANVAS_ITEM_Z_MAX - VS::CANVAS_ITEM_Z_MIN + 1; -void VisualServerCanvas::_render_canvas_item_tree(RID p_to_render_target, bool p_clear, const Color &p_clear_color, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RasterizerCanvas::Light *p_lights) { +void VisualServerCanvas::_render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RasterizerCanvas::Light *p_lights) { memset(z_list, 0, z_range * sizeof(RasterizerCanvas::Item *)); memset(z_last_list, 0, z_range * sizeof(RasterizerCanvas::Item *)); @@ -62,7 +62,7 @@ void VisualServerCanvas::_render_canvas_item_tree(RID p_to_render_target, bool p } } - VSG::canvas_render->canvas_render_items(p_to_render_target, p_clear, p_clear_color, list, p_modulate, p_lights, p_transform); + VSG::canvas_render->canvas_render_items(p_to_render_target, list, p_modulate, p_lights, p_transform); } void _collect_ysort_children(VisualServerCanvas::Item *p_canvas_item, Transform2D p_transform, VisualServerCanvas::Item *p_material_owner, const Color p_modulate, VisualServerCanvas::Item **r_items, int &r_index) { @@ -243,7 +243,7 @@ void VisualServerCanvas::_light_mask_canvas_items(int p_z, RasterizerCanvas::Ite } } -void VisualServerCanvas::render_canvas(RID p_render_target, bool p_clear, const Color &p_clear_color, Canvas *p_canvas, const Transform2D &p_transform, RasterizerCanvas::Light *p_lights, RasterizerCanvas::Light *p_masked_lights, const Rect2 &p_clip_rect) { +void VisualServerCanvas::render_canvas(RID p_render_target, Canvas *p_canvas, const Transform2D &p_transform, RasterizerCanvas::Light *p_lights, RasterizerCanvas::Light *p_masked_lights, const Rect2 &p_clip_rect) { if (p_canvas->children_order_dirty) { @@ -264,30 +264,30 @@ void VisualServerCanvas::render_canvas(RID p_render_target, bool p_clear, const if (!has_mirror) { - _render_canvas_item_tree(p_render_target, p_clear, p_clear_color, ci, l, NULL, p_transform, p_clip_rect, p_canvas->modulate, p_lights); + _render_canvas_item_tree(p_render_target, ci, l, NULL, p_transform, p_clip_rect, p_canvas->modulate, p_lights); } else { //used for parallaxlayer mirroring for (int i = 0; i < l; i++) { const Canvas::ChildItem &ci2 = p_canvas->child_items[i]; - _render_canvas_item_tree(p_render_target, p_clear, p_clear_color, NULL, 0, ci2.item, p_transform, p_clip_rect, p_canvas->modulate, p_lights); + _render_canvas_item_tree(p_render_target, NULL, 0, ci2.item, p_transform, p_clip_rect, p_canvas->modulate, p_lights); //mirroring (useful for scrolling backgrounds) if (ci2.mirror.x != 0) { Transform2D xform2 = p_transform * Transform2D(0, Vector2(ci2.mirror.x, 0)); - _render_canvas_item_tree(p_render_target, false, Color(), NULL, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights); + _render_canvas_item_tree(p_render_target, NULL, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights); } if (ci2.mirror.y != 0) { Transform2D xform2 = p_transform * Transform2D(0, Vector2(0, ci2.mirror.y)); - _render_canvas_item_tree(p_render_target, false, Color(), NULL, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights); + _render_canvas_item_tree(p_render_target, NULL, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights); } if (ci2.mirror.y != 0 && ci2.mirror.x != 0) { Transform2D xform2 = p_transform * Transform2D(0, ci2.mirror); - _render_canvas_item_tree(p_render_target, false, Color(), NULL, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights); + _render_canvas_item_tree(p_render_target, NULL, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights); } } } @@ -487,15 +487,27 @@ void VisualServerCanvas::canvas_item_add_line(RID p_item, const Point2 &p_from, Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); - Item::CommandLine *line = memnew(Item::CommandLine); + Item::CommandPrimitive *line = memnew(Item::CommandPrimitive); ERR_FAIL_COND(!line); - line->color = p_color; - line->from = p_from; - line->to = p_to; - line->width = p_width; - line->antialiased = p_antialiased; - canvas_item->rect_dirty = true; + if (p_width > 1.001) { + Vector2 t = (p_from - p_to).tangent().normalized(); + line->points[0] = p_from + t * p_width; + line->points[1] = p_from - t * p_width; + line->points[2] = p_to - t * p_width; + line->points[3] = p_to + t * p_width; + line->point_count = 4; + } else { + line->point_count = 2; + line->points[0] = p_from; + line->points[1] = p_to; + } + for (int i = 0; i < line->point_count; i++) { + line->colors[i] = p_color; + } + line->specular_shininess = Color(1, 1, 1, 1); + + canvas_item->rect_dirty = true; canvas_item->commands.push_back(line); } @@ -505,21 +517,29 @@ void VisualServerCanvas::canvas_item_add_polyline(RID p_item, const Vectorantialiased = p_antialiased; - pline->multiline = false; + pline->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, RID(), RID(), RID(), VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED, RID()); - if (p_width <= 1) { - pline->lines = p_points; - pline->line_colors = p_colors; - if (pline->line_colors.size() == 0) { - pline->line_colors.push_back(Color(1, 1, 1, 1)); - } else if (pline->line_colors.size() > 1 && pline->line_colors.size() != pline->lines.size()) { - pline->line_colors.resize(1); + if (true || p_width <= 1) { +#define TODO make thick lines possible + Vector indices; + int pc = p_points.size(); + indices.resize((pc - 1) * 2); + { + int *iptr = indices.ptrw(); + for (int i = 0; i < (pc - 1); i++) { + iptr[i * 2 + 0] = i; + iptr[i * 2 + 1] = i + 1; + } } + + pline->primitive = VS::PRIMITIVE_LINES; + pline->specular_shininess = Color(1, 1, 1, 1); + pline->polygon.create(indices, p_points, p_colors); } else { +#if 0 //make a trianglestrip for drawing the line... Vector2 prev_t; pline->triangles.resize(p_points.size() * 2); @@ -579,6 +599,7 @@ void VisualServerCanvas::canvas_item_add_polyline(RID p_item, const Vectorrect_dirty = true; canvas_item->commands.push_back(pline); @@ -590,18 +611,18 @@ void VisualServerCanvas::canvas_item_add_multiline(RID p_item, const Vectorantialiased = false; //todo - pline->multiline = true; + pline->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, RID(), RID(), RID(), VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED, RID()); - pline->lines = p_points; - pline->line_colors = p_colors; - if (pline->line_colors.size() == 0) { - pline->line_colors.push_back(Color(1, 1, 1, 1)); - } else if (pline->line_colors.size() > 1 && pline->line_colors.size() != pline->lines.size()) { - pline->line_colors.resize(1); + if (true || p_width <= 1) { +#define TODO make thick lines possible + + pline->primitive = VS::PRIMITIVE_LINES; + pline->specular_shininess = Color(1, 1, 1, 1); + pline->polygon.create(Vector(), p_points, p_colors); + } else { } canvas_item->rect_dirty = true; @@ -627,12 +648,39 @@ void VisualServerCanvas::canvas_item_add_circle(RID p_item, const Point2 &p_pos, Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); - Item::CommandCircle *circle = memnew(Item::CommandCircle); + Item::CommandPolygon *circle = memnew(Item::CommandPolygon); ERR_FAIL_COND(!circle); - circle->color = p_color; - circle->pos = p_pos; - circle->radius = p_radius; + circle->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, RID(), RID(), RID(), VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED, RID()); + + circle->primitive = VS::PRIMITIVE_TRIANGLES; + circle->specular_shininess = Color(1, 1, 1, 1); + + Vector indices; + Vector points; + + static const int circle_points = 64; + + points.resize(circle_points); + for (int i = 0; i < circle_points; i++) { + float angle = (i / float(circle_points)) * 2 * Math_PI; + points.write[i].x = Math::cos(angle) * p_radius; + points.write[i].y = Math::sin(angle) * p_radius; + points.write[i] += p_pos; + } + indices.resize((circle_points - 2) * 3); + + for (int i = 0; i < circle_points - 2; i++) { + indices.write[i * 3 + 0] = 0; + indices.write[i * 3 + 1] = i + 1; + indices.write[i * 3 + 2] = i + 2; + } + + Vector color; + color.push_back(p_color); + circle->polygon.create(indices, points, color); + + canvas_item->rect_dirty = true; canvas_item->commands.push_back(circle); } @@ -746,17 +794,33 @@ void VisualServerCanvas::canvas_item_add_nine_patch(RID p_item, const Rect2 &p_r } void VisualServerCanvas::canvas_item_add_primitive(RID p_item, const Vector &p_points, const Vector &p_colors, const Vector &p_uvs, RID p_texture, float p_width, RID p_normal_map, RID p_specular_map, const Color &p_specular_color_shininess, VisualServer::CanvasItemTextureFilter p_filter, VisualServer::CanvasItemTextureRepeat p_repeat) { + uint32_t pc = p_points.size(); + ERR_FAIL_COND(pc == 0 || pc > 4); + Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); Item::CommandPrimitive *prim = memnew(Item::CommandPrimitive); ERR_FAIL_COND(!prim); + + for (int i = 0; i < p_points.size(); i++) { + prim->points[i] = p_points[i]; + if (i < p_uvs.size()) { + prim->uvs[i] = p_uvs[i]; + } + if (i < p_colors.size()) { + prim->colors[i] = p_colors[i]; + } else if (p_colors.size()) { + prim->colors[i] = p_colors[0]; + } else { + prim->colors[i] = Color(1, 1, 1, 1); + } + } + + prim->point_count = p_points.size(); + prim->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, p_texture, p_normal_map, p_specular_map, p_filter, p_repeat, RID()); prim->specular_shininess = p_specular_color_shininess; - prim->points = p_points; - prim->uvs = p_uvs; - prim->colors = p_colors; - prim->width = p_width; canvas_item->rect_dirty = true; canvas_item->commands.push_back(prim); @@ -779,14 +843,11 @@ void VisualServerCanvas::canvas_item_add_polygon(RID p_item, const Vectorprimitive = VS::PRIMITIVE_TRIANGLES; polygon->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, p_texture, p_normal_map, p_specular_map, p_filter, p_repeat, RID()); polygon->specular_shininess = p_specular_color_shininess; - polygon->points = p_points; - polygon->uvs = p_uvs; - polygon->colors = p_colors; - polygon->indices = indices; - polygon->count = indices.size(); - polygon->antialiased = p_antialiased; + polygon->polygon.create(indices, p_points, p_colors, p_uvs); + canvas_item->rect_dirty = true; canvas_item->commands.push_back(polygon); @@ -806,32 +867,13 @@ void VisualServerCanvas::canvas_item_add_triangle_array(RID p_item, const Vector const Vector &indices = p_indices; - int count = p_count * 3; - - if (indices.empty()) { - - ERR_FAIL_COND(vertex_count % 3 != 0); - if (p_count == -1) - count = vertex_count; - } else { - - ERR_FAIL_COND(indices.size() % 3 != 0); - if (p_count == -1) - count = indices.size(); - } - Item::CommandPolygon *polygon = memnew(Item::CommandPolygon); ERR_FAIL_COND(!polygon); polygon->texture_binding.create(canvas_item->texture_filter, canvas_item->texture_repeat, p_texture, p_normal_map, p_specular_map, p_filter, p_repeat, RID()); polygon->specular_shininess = p_specular_color_shininess; - polygon->points = p_points; - polygon->uvs = p_uvs; - polygon->colors = p_colors; - polygon->bones = p_bones; - polygon->weights = p_weights; - polygon->indices = indices; - polygon->count = count; - polygon->antialiased = p_antialiased; + polygon->polygon.create(indices, p_points, p_colors, p_uvs, p_bones, p_weights); + + polygon->primitive = VS::PRIMITIVE_TRIANGLES; canvas_item->rect_dirty = true; canvas_item->commands.push_back(polygon); diff --git a/servers/visual/visual_server_canvas.h b/servers/visual/visual_server_canvas.h index 4a1bce51f91..d979d202b4a 100644 --- a/servers/visual/visual_server_canvas.h +++ b/servers/visual/visual_server_canvas.h @@ -162,7 +162,7 @@ public: bool disable_scale; private: - void _render_canvas_item_tree(RID p_to_render_target, bool p_clear, const Color &p_clear_color, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RasterizerCanvas::Light *p_lights); + void _render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RasterizerCanvas::Light *p_lights); void _cull_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RasterizerCanvas::Item **z_list, RasterizerCanvas::Item **z_last_list, Item *p_canvas_clip, Item *p_material_owner); void _light_mask_canvas_items(int p_z, RasterizerCanvas::Item *p_canvas_item, RasterizerCanvas::Light *p_masked_lights); @@ -170,7 +170,7 @@ private: RasterizerCanvas::Item **z_last_list; public: - void render_canvas(RID p_render_target, bool p_clear, const Color &p_clear_color, Canvas *p_canvas, const Transform2D &p_transform, RasterizerCanvas::Light *p_lights, RasterizerCanvas::Light *p_masked_lights, const Rect2 &p_clip_rect); + void render_canvas(RID p_render_target, Canvas *p_canvas, const Transform2D &p_transform, RasterizerCanvas::Light *p_lights, RasterizerCanvas::Light *p_masked_lights, const Rect2 &p_clip_rect); RID canvas_create(); void canvas_set_item_mirroring(RID p_canvas, RID p_item, const Point2 &p_mirroring); diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index 32c14e6f219..ba4eccd0f08 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -150,12 +150,14 @@ public: BIND1R(RID, texture_2d_create, const Ref &) BIND2R(RID, texture_2d_layered_create, const Vector > &, TextureLayeredType) BIND1R(RID, texture_3d_create, const Vector > &) + BIND1R(RID, texture_proxy_create, RID) //goes pass-through BIND3(texture_2d_update_immediate, RID, const Ref &, int) //these go through command queue if they are in another thread BIND3(texture_2d_update, RID, const Ref &, int) BIND4(texture_3d_update, RID, const Ref &, int, int) + BIND2(texture_proxy_update, RID, RID) //these also go pass-through BIND0R(RID, texture_2d_placeholder_create) @@ -182,8 +184,6 @@ public: BIND1RC(String, texture_get_path, RID) BIND1(texture_debug_usage, List *) - BIND2(texture_set_proxy, RID, RID) - BIND2(texture_set_force_redraw_if_visible, RID, bool) /* SKY API */ diff --git a/servers/visual/visual_server_viewport.cpp b/servers/visual/visual_server_viewport.cpp index ca0caefc774..05db6454dc8 100644 --- a/servers/visual/visual_server_viewport.cpp +++ b/servers/visual/visual_server_viewport.cpp @@ -81,7 +81,7 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E bool scenario_draw_canvas_bg = false; //draw canvas, or some layer of it, as BG for 3D instead of in front int scenario_canvas_max_layer = 0; - bool cleared = false; + Color bgcolor = clear_color; if (!p_viewport->hide_canvas && !p_viewport->disable_environment && VSG::scene->scenario_owner.owns(p_viewport->scenario)) { @@ -106,9 +106,10 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E } } + VSG::storage->render_target_request_clear(p_viewport->render_target, bgcolor); + if (!scenario_draw_canvas_bg && can_draw_3d) { _draw_3d(p_viewport, p_eye); - cleared = true; //if 3D has drawn, 2D is cleared. } if (!p_viewport->hide_canvas) { @@ -240,8 +241,7 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E ptr = ptr->filter_next_ptr; } - VSG::canvas->render_canvas(p_viewport->render_target, !cleared, bgcolor, canvas, xform, canvas_lights, lights_with_mask, clip_rect); - cleared = true; + VSG::canvas->render_canvas(p_viewport->render_target, canvas, xform, canvas_lights, lights_with_mask, clip_rect); i++; if (scenario_draw_canvas_bg && E->key().get_layer() >= scenario_canvas_max_layer) { @@ -308,7 +308,7 @@ void VisualServerViewport::draw_viewports() { if (!visible) continue; - VSG::storage->render_target_clear_used_flag(vp->render_target); + VSG::storage->render_target_set_as_unused(vp->render_target); #if 0 if (vp->use_arvr && arvr_interface.is_valid()) { // override our size, make sure it matches our required size @@ -381,6 +381,9 @@ void VisualServerViewport::draw_viewports() { } VSG::scene_render->set_debug_draw_mode(VS::VIEWPORT_DEBUG_DRAW_DISABLED); + //this needs to be called to make screen swapping more efficient + VSG::rasterizer->prepare_for_blitting_render_targets(); + for (Map >::Element *E = blit_to_screen_list.front(); E; E = E->next()) { VSG::rasterizer->blit_render_targets_to_screen(E->key(), E->get().ptr(), E->get().size()); } diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index 6af6c3902e0..fb6f42d1a43 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -81,12 +81,14 @@ public: virtual RID texture_2d_create(const Ref &p_image) { return visual_server->texture_2d_create(p_image); } virtual RID texture_2d_layered_create(const Vector > &p_layers, TextureLayeredType p_layered_type) { return visual_server->texture_2d_layered_create(p_layers, p_layered_type); } virtual RID texture_3d_create(const Vector > &p_slices) { return visual_server->texture_3d_create(p_slices); } + virtual RID texture_proxy_create(RID p_base) { return visual_server->texture_proxy_create(p_base); } //goes pass-through virtual void texture_2d_update_immediate(RID p_texture, const Ref &p_image, int p_layer = 0) { visual_server->texture_2d_update_immediate(p_texture, p_image, p_layer); } //these go through command queue if they are in another thread FUNC3(texture_2d_update, RID, const Ref &, int) FUNC4(texture_3d_update, RID, const Ref &, int, int) + FUNC2(texture_proxy_update, RID, RID) //these also go pass-through virtual RID texture_2d_placeholder_create() { return visual_server->texture_2d_placeholder_create(); } @@ -113,8 +115,6 @@ public: FUNC1RC(String, texture_get_path, RID) FUNC1S(texture_debug_usage, List *) - FUNC2(texture_set_proxy, RID, RID) - FUNC2(texture_set_force_redraw_if_visible, RID, bool) /* SKY API */ diff --git a/servers/visual_server.h b/servers/visual_server.h index d96f7cbf10d..3b9f54f015b 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -99,10 +99,12 @@ public: virtual RID texture_2d_create(const Ref &p_image) = 0; virtual RID texture_2d_layered_create(const Vector > &p_layers, TextureLayeredType p_layered_type) = 0; virtual RID texture_3d_create(const Vector > &p_slices) = 0; //all slices, then all the mipmaps, must be coherent + virtual RID texture_proxy_create(RID p_base) = 0; virtual void texture_2d_update_immediate(RID p_texture, const Ref &p_image, int p_layer = 0) = 0; //mostly used for video and streaming virtual void texture_2d_update(RID p_texture, const Ref &p_image, int p_layer = 0) = 0; virtual void texture_3d_update(RID p_texture, const Ref &p_image, int p_depth, int p_mipmap) = 0; + virtual void texture_proxy_update(RID p_texture, RID p_proxy_to) = 0; //these two APIs can be used together or in combination with the others. virtual RID texture_2d_placeholder_create() = 0; @@ -152,7 +154,6 @@ public: virtual void texture_debug_usage(List *r_info) = 0; Array _texture_debug_usage_bind(); - virtual void texture_set_proxy(RID p_proxy, RID p_base) = 0; virtual void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) = 0; /* SKY API */