diff --git a/lib/graphics_engine/src/ge_vulkan_draw_call.cpp b/lib/graphics_engine/src/ge_vulkan_draw_call.cpp index d789baaec..4f1685e07 100644 --- a/lib/graphics_engine/src/ge_vulkan_draw_call.cpp +++ b/lib/graphics_engine/src/ge_vulkan_draw_call.cpp @@ -549,25 +549,33 @@ start: void GEVulkanDrawCall::createVulkanData() { GEVulkanDriver* vk = getVKDriver(); + const bool use_base_vertex = GEVulkanFeatures::supportsBaseVertexRendering(); + // m_data_layout VkDescriptorSetLayoutBinding camera_layout_binding = {}; camera_layout_binding.binding = 0; camera_layout_binding.descriptorCount = 1; - camera_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + camera_layout_binding.descriptorType = use_base_vertex ? + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER : + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; camera_layout_binding.pImmutableSamplers = NULL; camera_layout_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; VkDescriptorSetLayoutBinding object_data_layout_binding = {}; object_data_layout_binding.binding = 1; object_data_layout_binding.descriptorCount = 1; - object_data_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + object_data_layout_binding.descriptorType = use_base_vertex ? + VK_DESCRIPTOR_TYPE_STORAGE_BUFFER : + VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC; object_data_layout_binding.pImmutableSamplers = NULL; object_data_layout_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; VkDescriptorSetLayoutBinding skinning_layout_binding = {}; skinning_layout_binding.binding = 2; skinning_layout_binding.descriptorCount = 1; - skinning_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + skinning_layout_binding.descriptorType = use_base_vertex ? + VK_DESCRIPTOR_TYPE_STORAGE_BUFFER : + VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC; skinning_layout_binding.pImmutableSamplers = NULL; skinning_layout_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; @@ -596,8 +604,18 @@ void GEVulkanDrawCall::createVulkanData() // m_descriptor_pool std::array sizes = {{ - { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, vk->getMaxFrameInFlight() }, - { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk->getMaxFrameInFlight() * 2 } + { + use_base_vertex ? + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER : + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, + vk->getMaxFrameInFlight() + }, + { + use_base_vertex ? + VK_DESCRIPTOR_TYPE_STORAGE_BUFFER : + VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, + vk->getMaxFrameInFlight() * 2 + } }}; VkDescriptorPoolCreateInfo pool_info = {}; @@ -697,21 +715,63 @@ void GEVulkanDrawCall::uploadDynamicData(GEVulkanDriver* vk, m_data_uploading.emplace_back((void*)m_data_padding, sbo_padding); } - const size_t object_data_size = - sizeof(ObjectData) * m_visible_objects.size(); - size_t ubo_alignment = limit.minUniformBufferOffsetAlignment; - size_t ubo_padding = getPadding( - m_skinning_data_padded_size + object_data_size, ubo_alignment); - m_object_data_padded_size = object_data_size + ubo_padding; - // https://github.com/google/filament/pull/3814 // Need both vertex and fragment bit VkPipelineStageFlags dst_stage = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - m_data_uploading.emplace_back((void*)m_visible_objects.data(), - object_data_size); - if (ubo_padding > 0) - m_data_uploading.emplace_back((void*)m_data_padding, ubo_padding); + + size_t ubo_alignment = limit.minUniformBufferOffsetAlignment; + size_t ubo_padding = 0; + const bool use_base_vertex = GEVulkanFeatures::supportsBaseVertexRendering(); + if (use_base_vertex) + { + const size_t object_data_size = + sizeof(ObjectData) * m_visible_objects.size(); + m_data_uploading.emplace_back((void*)m_visible_objects.data(), + object_data_size); + ubo_padding = getPadding( + m_skinning_data_padded_size + object_data_size, ubo_alignment); + if (ubo_padding > 0) + m_data_uploading.emplace_back((void*)m_data_padding, ubo_padding); + m_object_data_padded_size = object_data_size + ubo_padding; + } + else + { + m_object_data_padded_size = 0; + for (unsigned i = 0; i < m_cmds.size(); i++) + { + auto& cmd = m_cmds[i]; + size_t instance_size = + cmd.m_cmd.instanceCount * sizeof(ObjectData); + m_data_uploading.emplace_back( + &m_visible_objects[cmd.m_cmd.firstInstance], instance_size); + size_t cur_padding = getPadding( + m_skinning_data_padded_size + m_object_data_padded_size + + instance_size, sbo_alignment); + if (cur_padding > 0) + { + instance_size += cur_padding; + m_data_uploading.emplace_back((void*)m_data_padding, + cur_padding); + } + m_sbo_data_offset.push_back(m_object_data_padded_size); + m_object_data_padded_size += instance_size; + } + } + if (!use_base_vertex) + { + ubo_padding = getPadding(m_skinning_data_padded_size + + m_object_data_padded_size, ubo_alignment); + if (ubo_padding > 0) + { + m_data_uploading.emplace_back((void*)m_data_padding, + ubo_padding); + m_object_data_padded_size += ubo_padding; + } + // Make sure dynamic offset won't become invaild + m_dynamic_data->resizeIfNeeded(m_skinning_data_padded_size + + m_object_data_padded_size * 2 + sizeof(GEVulkanCameraUBO)); + } m_data_uploading.emplace_back(cam->getUBOData(), sizeof(GEVulkanCameraUBO)); const bool use_multidraw = GEVulkanFeatures::supportsMultiDrawIndirect() && @@ -753,6 +813,7 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, custom_cmd ? custom_cmd : vk->getCurrentCommandBuffer(); const unsigned cur_frame = vk->getCurrentFrame(); + const bool use_base_vertex = GEVulkanFeatures::supportsBaseVertexRendering(); VkDescriptorBufferInfo ubo_info; ubo_info.buffer = m_dynamic_data->getCurrentBuffer(); ubo_info.offset = m_skinning_data_padded_size + m_object_data_padded_size; @@ -763,7 +824,9 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, data_set[0].dstSet = m_data_descriptor_sets[cur_frame]; data_set[0].dstBinding = 0; data_set[0].dstArrayElement = 0; - data_set[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + data_set[0].descriptorType = use_base_vertex ? + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER : + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; data_set[0].descriptorCount = 1; data_set[0].pBufferInfo = &ubo_info; @@ -776,7 +839,9 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, data_set[1].dstSet = m_data_descriptor_sets[cur_frame]; data_set[1].dstBinding = 1; data_set[1].dstArrayElement = 0; - data_set[1].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + data_set[1].descriptorType = use_base_vertex ? + VK_DESCRIPTOR_TYPE_STORAGE_BUFFER : + VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC; data_set[1].descriptorCount = 1; data_set[1].pBufferInfo = &sbo_info_objects; @@ -789,7 +854,9 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, data_set[2].dstSet = m_data_descriptor_sets[cur_frame]; data_set[2].dstBinding = 2; data_set[2].dstArrayElement = 0; - data_set[2].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + data_set[2].descriptorType = use_base_vertex ? + VK_DESCRIPTOR_TYPE_STORAGE_BUFFER : + VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC; ; data_set[2].descriptorCount = 1; data_set[2].pBufferInfo = &sbo_info_skinning; @@ -805,8 +872,12 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, 0, NULL); } - vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, - m_pipeline_layout, 1, 1, &m_data_descriptor_sets[cur_frame], 0, NULL); + if (use_base_vertex) + { + vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + m_pipeline_layout, 1, 1, &m_data_descriptor_sets[cur_frame], 0, + NULL); + } GEVulkanMeshCache* mc = vk->getVulkanMeshCache(); std::array vertex_buffer = @@ -900,8 +971,21 @@ void GEVulkanDrawCall::render(GEVulkanDriver* vk, GEVulkanCameraSceneNode* cam, cur_pipeline = m_cmds[i].m_shader; bindPipeline(cmd, cur_pipeline); } + if (!use_base_vertex) + { + std::array dynamic_offsets = + {{ + 0u, + uint32_t(m_sbo_data_offset[i]), + 0u + }}; + vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, + m_pipeline_layout, 1, 1, &m_data_descriptor_sets[cur_frame], + dynamic_offsets.size(), dynamic_offsets.data()); + } vkCmdDrawIndexed(cmd, cur_cmd.indexCount, cur_cmd.instanceCount, - cur_cmd.firstIndex, cur_cmd.vertexOffset, cur_cmd.firstInstance); + cur_cmd.firstIndex, cur_cmd.vertexOffset, + use_base_vertex ? cur_cmd.firstInstance : 0); } } } // render diff --git a/lib/graphics_engine/src/ge_vulkan_draw_call.hpp b/lib/graphics_engine/src/ge_vulkan_draw_call.hpp index 9bcba069d..73c51dfe0 100644 --- a/lib/graphics_engine/src/ge_vulkan_draw_call.hpp +++ b/lib/graphics_engine/src/ge_vulkan_draw_call.hpp @@ -104,6 +104,8 @@ private: std::vector > m_data_uploading; + std::vector m_sbo_data_offset; + // ------------------------------------------------------------------------ void createAllPipelines(GEVulkanDriver* vk); // ------------------------------------------------------------------------ @@ -160,6 +162,7 @@ public: m_materials.clear(); m_skinning_nodes.clear(); m_data_uploading.clear(); + m_sbo_data_offset.clear(); } }; // GEVulkanDrawCall diff --git a/lib/graphics_engine/src/ge_vulkan_dynamic_buffer.cpp b/lib/graphics_engine/src/ge_vulkan_dynamic_buffer.cpp index 948313c9f..9b0fd75e9 100644 --- a/lib/graphics_engine/src/ge_vulkan_dynamic_buffer.cpp +++ b/lib/graphics_engine/src/ge_vulkan_dynamic_buffer.cpp @@ -164,13 +164,8 @@ void GEVulkanDynamicBuffer::setCurrentData(const std::vector< size_t size = 0; for (auto& p : data) size += p.second; - if (size > m_size) - { - destroy(); - m_size = size + 100; - for (unsigned i = 0; i < GEVulkanDriver::getMaxFrameInFlight(); i++) - initPerFrame(i); - } + resizeIfNeeded(size); + m_real_size = size; if (size == 0 || m_mapped_addr[cur_frame] == NULL) return; @@ -193,6 +188,18 @@ void GEVulkanDynamicBuffer::setCurrentData(const std::vector< } } // setCurrentData +// ---------------------------------------------------------------------------- +void GEVulkanDynamicBuffer::resizeIfNeeded(size_t new_size) +{ + if (new_size > m_size) + { + destroy(); + m_size = new_size + 100; + for (unsigned i = 0; i < GEVulkanDriver::getMaxFrameInFlight(); i++) + initPerFrame(i); + } +} // resizeIfNeeded + // ---------------------------------------------------------------------------- VkBuffer GEVulkanDynamicBuffer::getCurrentBuffer() const { diff --git a/lib/graphics_engine/src/ge_vulkan_dynamic_buffer.hpp b/lib/graphics_engine/src/ge_vulkan_dynamic_buffer.hpp index 79257b63e..9bcd40f77 100644 --- a/lib/graphics_engine/src/ge_vulkan_dynamic_buffer.hpp +++ b/lib/graphics_engine/src/ge_vulkan_dynamic_buffer.hpp @@ -58,6 +58,8 @@ public: // ------------------------------------------------------------------------ VkBuffer getCurrentBuffer() const; // ------------------------------------------------------------------------ + void resizeIfNeeded(size_t new_size); + // ------------------------------------------------------------------------ size_t getRealSize() const { return m_real_size; } }; // GEVulkanDynamicBuffer diff --git a/lib/graphics_engine/src/ge_vulkan_features.cpp b/lib/graphics_engine/src/ge_vulkan_features.cpp index b6a2378a0..5566dc4b7 100644 --- a/lib/graphics_engine/src/ge_vulkan_features.cpp +++ b/lib/graphics_engine/src/ge_vulkan_features.cpp @@ -24,6 +24,7 @@ bool g_supports_non_uniform_indexing = false; bool g_supports_partially_bound = false; uint32_t g_max_sampler_supported = 0; bool g_supports_multi_draw_indirect = false; +bool g_supports_base_vertex_rendering = true; } // GEVulkanFeatures // ============================================================================ @@ -124,6 +125,16 @@ void GEVulkanFeatures::init(GEVulkanDriver* vk) g_max_sampler_supported >= max_sampler_size; } } + +#if defined(__APPLE__) + MVKPhysicalDeviceMetalFeatures mvk_features = {}; + size_t mvk_features_size = sizeof(MVKPhysicalDeviceMetalFeatures); + vkGetPhysicalDeviceMetalFeaturesMVK(vk->getPhysicalDevice(), &mvk_features, + &mvk_features_size); + g_supports_base_vertex_rendering = mvk_features.baseVertexInstanceDrawing; + if (!g_supports_base_vertex_rendering) + g_supports_multi_draw_indirect = false; +#endif } // init // ---------------------------------------------------------------------------- @@ -147,6 +158,9 @@ void GEVulkanFeatures::printStats() os::Printer::log( "Vulkan supports multi-draw indirect", g_supports_multi_draw_indirect ? "true" : "false"); + os::Printer::log( + "Vulkan supports base vertex rendering", + g_supports_base_vertex_rendering ? "true" : "false"); os::Printer::log( "Vulkan descriptor indexes can be dynamically non-uniform", g_supports_non_uniform_indexing ? "true" : "false"); @@ -214,4 +228,10 @@ bool GEVulkanFeatures::supportsMultiDrawIndirect() return g_supports_multi_draw_indirect; } // supportsBindMeshTexturesAtOnce +// ---------------------------------------------------------------------------- +bool GEVulkanFeatures::supportsBaseVertexRendering() +{ + return g_supports_base_vertex_rendering; +} // supportsBindMeshTexturesAtOnce + } diff --git a/lib/graphics_engine/src/ge_vulkan_features.hpp b/lib/graphics_engine/src/ge_vulkan_features.hpp index 23f323061..1b3706452 100644 --- a/lib/graphics_engine/src/ge_vulkan_features.hpp +++ b/lib/graphics_engine/src/ge_vulkan_features.hpp @@ -30,6 +30,8 @@ bool supportsPartiallyBound(); bool supportsBindMeshTexturesAtOnce(); // ---------------------------------------------------------------------------- bool supportsMultiDrawIndirect(); +// ---------------------------------------------------------------------------- +bool supportsBaseVertexRendering(); }; // GEVulkanFeatures }