From 366404d274d80e3ba255772b731c16298cc46887 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Mon, 13 Feb 2023 09:36:43 +0100 Subject: [PATCH 01/55] Vulkan: Initial Compute Shaders and SSBO+VBO support. This patch adds initial support for compute shaders and SSBOs to the vulkan backend. As the development is oriented to the test- cases we have the implementation is limited to what is used there. It has been validated that with this patch 2 test cases are running as expected - `GPUVulkanTest.gpu_shader_compute_ssbo` - `GPUVulkanTest.gpu_storage_buffer_create_update_read` This patch includes: - Allocating VkBuffer on device. - Uploading data from CPU to VkBuffer. - Binding VkBuffer as SSBO to a compute shader. - Execute compute shader and altering VkBuffer. - Download the VkBuffer to CPU ram. - Validate that it worked. GHOST API has been changed as the original design was created before we even had support for compute shaders in blender. The function `GHOST_getVulkanBackbuffer` has been separated to retrieve the command buffer without a backbuffer (`GHOST_getVulkanCommandBuffer`). In order to do correct command buffer processing we needed access to the queue owned by GHOST. This is returned as part of the `GHOST_getVulkanHandles` function. --- intern/ghost/GHOST_C-api.h | 5 +- intern/ghost/GHOST_IContext.h | 11 +- intern/ghost/GHOST_IWindow.h | 1 - intern/ghost/intern/GHOST_C-api.cpp | 15 +- intern/ghost/intern/GHOST_Context.h | 9 +- intern/ghost/intern/GHOST_ContextVK.cpp | 82 +++++-- intern/ghost/intern/GHOST_ContextVK.h | 17 +- intern/ghost/intern/GHOST_Window.cpp | 3 +- intern/ghost/intern/GHOST_Window.h | 8 +- source/blender/gpu/CMakeLists.txt | 16 ++ .../gpu/intern/gpu_storage_buffer_private.hh | 2 + source/blender/gpu/tests/gpu_shader_test.cc | 8 +- .../gpu/tests/gpu_storage_buffer_test.cc | 50 +++++ source/blender/gpu/tests/gpu_testing.cc | 5 +- .../tests/shaders/gpu_compute_ssbo_test.glsl | 5 + source/blender/gpu/vulkan/vk_backend.cc | 15 +- source/blender/gpu/vulkan/vk_buffer.cc | 107 +++++++++ source/blender/gpu/vulkan/vk_buffer.hh | 56 +++++ .../blender/gpu/vulkan/vk_command_buffer.cc | 98 +++++++++ .../blender/gpu/vulkan/vk_command_buffer.hh | 52 +++++ source/blender/gpu/vulkan/vk_context.cc | 33 ++- source/blender/gpu/vulkan/vk_context.hh | 38 +++- .../blender/gpu/vulkan/vk_descriptor_pools.cc | 110 ++++++++++ .../blender/gpu/vulkan/vk_descriptor_pools.hh | 68 ++++++ .../blender/gpu/vulkan/vk_descriptor_set.cc | 88 ++++++++ .../blender/gpu/vulkan/vk_descriptor_set.hh | 76 +++++++ source/blender/gpu/vulkan/vk_pipeline.cc | 64 ++++++ source/blender/gpu/vulkan/vk_pipeline.hh | 55 +++++ source/blender/gpu/vulkan/vk_shader.cc | 207 +++++++++++++++--- source/blender/gpu/vulkan/vk_shader.hh | 24 +- .../blender/gpu/vulkan/vk_shader_interface.cc | 55 +++++ .../blender/gpu/vulkan/vk_shader_interface.hh | 20 ++ source/blender/gpu/vulkan/vk_state_manager.cc | 51 +++++ source/blender/gpu/vulkan/vk_state_manager.hh | 30 +++ .../blender/gpu/vulkan/vk_storage_buffer.cc | 37 +++- .../blender/gpu/vulkan/vk_storage_buffer.hh | 23 +- source/blender/gpu/vulkan/vk_vertex_buffer.cc | 30 ++- source/blender/gpu/vulkan/vk_vertex_buffer.hh | 12 + 38 files changed, 1475 insertions(+), 111 deletions(-) create mode 100644 source/blender/gpu/tests/gpu_storage_buffer_test.cc create mode 100644 source/blender/gpu/tests/shaders/gpu_compute_ssbo_test.glsl create mode 100644 source/blender/gpu/vulkan/vk_buffer.cc create mode 100644 source/blender/gpu/vulkan/vk_buffer.hh create mode 100644 source/blender/gpu/vulkan/vk_command_buffer.cc create mode 100644 source/blender/gpu/vulkan/vk_command_buffer.hh create mode 100644 source/blender/gpu/vulkan/vk_descriptor_pools.cc create mode 100644 source/blender/gpu/vulkan/vk_descriptor_pools.hh create mode 100644 source/blender/gpu/vulkan/vk_descriptor_set.cc create mode 100644 source/blender/gpu/vulkan/vk_descriptor_set.hh create mode 100644 source/blender/gpu/vulkan/vk_pipeline.cc create mode 100644 source/blender/gpu/vulkan/vk_pipeline.hh create mode 100644 source/blender/gpu/vulkan/vk_shader_interface.cc create mode 100644 source/blender/gpu/vulkan/vk_shader_interface.hh create mode 100644 source/blender/gpu/vulkan/vk_state_manager.cc create mode 100644 source/blender/gpu/vulkan/vk_state_manager.hh diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h index cf810caf778..92219bdbd64 100644 --- a/intern/ghost/GHOST_C-api.h +++ b/intern/ghost/GHOST_C-api.h @@ -1201,7 +1201,9 @@ void GHOST_GetVulkanHandles(GHOST_ContextHandle context, void *r_instance, void *r_physical_device, void *r_device, - uint32_t *r_graphic_queue_family); + uint32_t *r_graphic_queue_family, + void *r_queue); +void GHOST_GetVulkanCommandBuffer(GHOST_ContextHandle context, void *r_command_buffer); /** * Return VULKAN back-buffer resources handles for the given window. @@ -1209,7 +1211,6 @@ void GHOST_GetVulkanHandles(GHOST_ContextHandle context, void GHOST_GetVulkanBackbuffer(GHOST_WindowHandle windowhandle, void *image, void *framebuffer, - void *command_buffer, void *render_pass, void *extent, uint32_t *fb_id); diff --git a/intern/ghost/GHOST_IContext.h b/intern/ghost/GHOST_IContext.h index 52863e8c061..b7c681c9843 100644 --- a/intern/ghost/GHOST_IContext.h +++ b/intern/ghost/GHOST_IContext.h @@ -40,19 +40,16 @@ class GHOST_IContext { virtual unsigned int getDefaultFramebuffer() = 0; - virtual GHOST_TSuccess getVulkanHandles(void *, void *, void *, uint32_t *) = 0; + virtual GHOST_TSuccess getVulkanHandles(void *, void *, void *, uint32_t *, void *) = 0; + virtual GHOST_TSuccess getVulkanCommandBuffer(void * /*r_command_buffer*/) = 0; /** * Gets the Vulkan framebuffer related resource handles associated with the Vulkan context. * Needs to be called after each swap events as the framebuffer will change. * \return A boolean success indicator. */ - virtual GHOST_TSuccess getVulkanBackbuffer(void *image, - void *framebuffer, - void *command_buffer, - void *render_pass, - void *extent, - uint32_t *fb_id) = 0; + virtual GHOST_TSuccess getVulkanBackbuffer( + void *image, void *framebuffer, void *render_pass, void *extent, uint32_t *fb_id) = 0; virtual GHOST_TSuccess swapBuffers() = 0; diff --git a/intern/ghost/GHOST_IWindow.h b/intern/ghost/GHOST_IWindow.h index 403f9e388cc..4fc24b6ca86 100644 --- a/intern/ghost/GHOST_IWindow.h +++ b/intern/ghost/GHOST_IWindow.h @@ -217,7 +217,6 @@ class GHOST_IWindow { */ virtual GHOST_TSuccess getVulkanBackbuffer(void *image, void *framebuffer, - void *command_buffer, void *render_pass, void *extent, uint32_t *fb_id) = 0; diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp index a3c1eedc9c0..986f88205c7 100644 --- a/intern/ghost/intern/GHOST_C-api.cpp +++ b/intern/ghost/intern/GHOST_C-api.cpp @@ -1203,22 +1203,29 @@ void GHOST_GetVulkanHandles(GHOST_ContextHandle contexthandle, void *r_instance, void *r_physical_device, void *r_device, - uint32_t *r_graphic_queue_family) + uint32_t *r_graphic_queue_family, + void *r_queue) { GHOST_IContext *context = (GHOST_IContext *)contexthandle; - context->getVulkanHandles(r_instance, r_physical_device, r_device, r_graphic_queue_family); + context->getVulkanHandles( + r_instance, r_physical_device, r_device, r_graphic_queue_family, r_queue); +} + +void GHOST_GetVulkanCommandBuffer(GHOST_ContextHandle contexthandle, void *r_command_buffer) +{ + GHOST_IContext *context = (GHOST_IContext *)contexthandle; + context->getVulkanCommandBuffer(r_command_buffer); } void GHOST_GetVulkanBackbuffer(GHOST_WindowHandle windowhandle, void *image, void *framebuffer, - void *command_buffer, void *render_pass, void *extent, uint32_t *fb_id) { GHOST_IWindow *window = (GHOST_IWindow *)windowhandle; - window->getVulkanBackbuffer(image, framebuffer, command_buffer, render_pass, extent, fb_id); + window->getVulkanBackbuffer(image, framebuffer, render_pass, extent, fb_id); } #endif /* WITH_VULKAN */ diff --git a/intern/ghost/intern/GHOST_Context.h b/intern/ghost/intern/GHOST_Context.h index d4cc0d18e55..577b04bdce9 100644 --- a/intern/ghost/intern/GHOST_Context.h +++ b/intern/ghost/intern/GHOST_Context.h @@ -142,7 +142,13 @@ class GHOST_Context : public GHOST_IContext { virtual GHOST_TSuccess getVulkanHandles(void * /*r_instance*/, void * /*r_physical_device*/, void * /*r_device*/, - uint32_t * /*r_graphic_queue_family*/) override + uint32_t * /*r_graphic_queue_family*/, + void * /*r_queue*/) override + { + return GHOST_kFailure; + }; + + virtual GHOST_TSuccess getVulkanCommandBuffer(void * /*r_command_buffer*/) override { return GHOST_kFailure; }; @@ -154,7 +160,6 @@ class GHOST_Context : public GHOST_IContext { */ virtual GHOST_TSuccess getVulkanBackbuffer(void * /*image*/, void * /*framebuffer*/, - void * /*command_buffer*/, void * /*render_pass*/, void * /*extent*/, uint32_t * /*fb_id*/) override diff --git a/intern/ghost/intern/GHOST_ContextVK.cpp b/intern/ghost/intern/GHOST_ContextVK.cpp index 4ee48243234..3f9b197939a 100644 --- a/intern/ghost/intern/GHOST_ContextVK.cpp +++ b/intern/ghost/intern/GHOST_ContextVK.cpp @@ -288,19 +288,14 @@ GHOST_TSuccess GHOST_ContextVK::swapBuffers() return GHOST_kSuccess; } -GHOST_TSuccess GHOST_ContextVK::getVulkanBackbuffer(void *image, - void *framebuffer, - void *command_buffer, - void *render_pass, - void *extent, - uint32_t *fb_id) +GHOST_TSuccess GHOST_ContextVK::getVulkanBackbuffer( + void *image, void *framebuffer, void *render_pass, void *extent, uint32_t *fb_id) { if (m_swapchain == VK_NULL_HANDLE) { return GHOST_kFailure; } *((VkImage *)image) = m_swapchain_images[m_currentImage]; *((VkFramebuffer *)framebuffer) = m_swapchain_framebuffers[m_currentImage]; - *((VkCommandBuffer *)command_buffer) = m_command_buffers[m_currentImage]; *((VkRenderPass *)render_pass) = m_render_pass; *((VkExtent2D *)extent) = m_render_extent; *fb_id = m_swapchain_id * 10 + m_currentFrame; @@ -311,12 +306,30 @@ GHOST_TSuccess GHOST_ContextVK::getVulkanBackbuffer(void *image, GHOST_TSuccess GHOST_ContextVK::getVulkanHandles(void *r_instance, void *r_physical_device, void *r_device, - uint32_t *r_graphic_queue_family) + uint32_t *r_graphic_queue_family, + void *r_queue) { *((VkInstance *)r_instance) = m_instance; *((VkPhysicalDevice *)r_physical_device) = m_physical_device; *((VkDevice *)r_device) = m_device; *r_graphic_queue_family = m_queue_family_graphic; + *((VkQueue *)r_queue) = m_graphic_queue; + + return GHOST_kSuccess; +} + +GHOST_TSuccess GHOST_ContextVK::getVulkanCommandBuffer(void *r_command_buffer) +{ + if (m_command_buffers.empty()) { + return GHOST_kFailure; + } + + if (m_swapchain == VK_NULL_HANDLE) { + *((VkCommandBuffer *)r_command_buffer) = m_command_buffers[0]; + } + else { + *((VkCommandBuffer *)r_command_buffer) = m_command_buffers[m_currentImage]; + } return GHOST_kSuccess; } @@ -520,6 +533,9 @@ static GHOST_TSuccess getGraphicQueueFamily(VkPhysicalDevice device, uint32_t *r *r_queue_index = 0; for (const auto &queue_family : queue_families) { + /* Every vulkan implementation by spec must have one queue family that support both graphics + * and compute pipelines. We select this one; compute only queue family hints at async compute + * implementations.*/ if ((queue_family.queueFlags & VK_QUEUE_GRAPHICS_BIT) && (queue_family.queueFlags & VK_QUEUE_COMPUTE_BIT)) { return GHOST_kSuccess; @@ -619,16 +635,36 @@ static GHOST_TSuccess selectPresentMode(VkPhysicalDevice device, return GHOST_kFailure; } -GHOST_TSuccess GHOST_ContextVK::createCommandBuffers() +GHOST_TSuccess GHOST_ContextVK::createCommandPools() { - m_command_buffers.resize(m_swapchain_image_views.size()); - VkCommandPoolCreateInfo poolInfo = {}; poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; poolInfo.queueFamilyIndex = m_queue_family_graphic; VK_CHECK(vkCreateCommandPool(m_device, &poolInfo, NULL, &m_command_pool)); + return GHOST_kSuccess; +} + +GHOST_TSuccess GHOST_ContextVK::createGraphicsCommandBuffer() +{ + assert(m_command_pool != VK_NULL_HANDLE); + assert(m_command_buffers.size() == 0); + m_command_buffers.resize(1); + VkCommandBufferAllocateInfo alloc_info = {}; + alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + alloc_info.commandPool = m_command_pool; + alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + alloc_info.commandBufferCount = static_cast(m_command_buffers.size()); + + VK_CHECK(vkAllocateCommandBuffers(m_device, &alloc_info, m_command_buffers.data())); + return GHOST_kSuccess; +} + +GHOST_TSuccess GHOST_ContextVK::createGraphicsCommandBuffers() +{ + assert(m_command_pool != VK_NULL_HANDLE); + m_command_buffers.resize(m_swapchain_image_views.size()); VkCommandBufferAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; @@ -637,7 +673,6 @@ GHOST_TSuccess GHOST_ContextVK::createCommandBuffers() alloc_info.commandBufferCount = static_cast(m_command_buffers.size()); VK_CHECK(vkAllocateCommandBuffers(m_device, &alloc_info, m_command_buffers.data())); - return GHOST_kSuccess; } @@ -776,7 +811,7 @@ GHOST_TSuccess GHOST_ContextVK::createSwapchain() VK_CHECK(vkCreateFence(m_device, &fence_info, NULL, &m_in_flight_fences[i])); } - createCommandBuffers(); + createGraphicsCommandBuffers(); return GHOST_kSuccess; } @@ -841,6 +876,13 @@ GHOST_TSuccess GHOST_ContextVK::initializeDrawingContext() extensions_device.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); } + extensions_device.push_back("VK_KHR_dedicated_allocation"); + extensions_device.push_back("VK_KHR_get_memory_requirements2"); + /* Enable MoltenVK required instance extensions.*/ +#ifdef VK_MVK_MOLTENVK_EXTENSION_NAME + requireExtension( + extensions_available, extensions_enabled, "VK_KHR_get_physical_device_properties2"); +#endif VkApplicationInfo app_info = {}; app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; @@ -903,6 +945,15 @@ GHOST_TSuccess GHOST_ContextVK::initializeDrawingContext() return GHOST_kFailure; } +#ifdef VK_MVK_MOLTENVK_EXTENSION_NAME + /* According to the Vulkan specs, when `VK_KHR_portability_subset` is available it should be + * enabled. See + * https://vulkan.lunarg.com/doc/view/1.2.198.1/mac/1.2-extensions/vkspec.html#VUID-VkDeviceCreateInfo-pProperties-04451*/ + if (device_extensions_support(m_physical_device, {VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME})) { + extensions_device.push_back(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME); + } +#endif + vector queue_create_infos; { @@ -962,11 +1013,14 @@ GHOST_TSuccess GHOST_ContextVK::initializeDrawingContext() vkGetDeviceQueue(m_device, m_queue_family_graphic, 0, &m_graphic_queue); + createCommandPools(); if (use_window_surface) { vkGetDeviceQueue(m_device, m_queue_family_present, 0, &m_present_queue); - createSwapchain(); } + else { + createGraphicsCommandBuffer(); + } return GHOST_kSuccess; } diff --git a/intern/ghost/intern/GHOST_ContextVK.h b/intern/ghost/intern/GHOST_ContextVK.h index 1a2d38bc701..0daa9e40027 100644 --- a/intern/ghost/intern/GHOST_ContextVK.h +++ b/intern/ghost/intern/GHOST_ContextVK.h @@ -113,18 +113,17 @@ class GHOST_ContextVK : public GHOST_Context { GHOST_TSuccess getVulkanHandles(void *r_instance, void *r_physical_device, void *r_device, - uint32_t *r_graphic_queue_family); + uint32_t *r_graphic_queue_family, + void *r_queue); + GHOST_TSuccess getVulkanCommandBuffer(void *r_command_buffer); + /** * Gets the Vulkan framebuffer related resource handles associated with the Vulkan context. * Needs to be called after each swap events as the framebuffer will change. * \return A boolean success indicator. */ - GHOST_TSuccess getVulkanBackbuffer(void *image, - void *framebuffer, - void *command_buffer, - void *render_pass, - void *extent, - uint32_t *fb_id); + GHOST_TSuccess getVulkanBackbuffer( + void *image, void *framebuffer, void *render_pass, void *extent, uint32_t *fb_id); /** * Sets the swap interval for swapBuffers. @@ -200,6 +199,8 @@ class GHOST_ContextVK : public GHOST_Context { GHOST_TSuccess pickPhysicalDevice(std::vector required_exts); GHOST_TSuccess createSwapchain(); GHOST_TSuccess destroySwapchain(); - GHOST_TSuccess createCommandBuffers(); + GHOST_TSuccess createCommandPools(); + GHOST_TSuccess createGraphicsCommandBuffers(); + GHOST_TSuccess createGraphicsCommandBuffer(); GHOST_TSuccess recordCommandBuffers(); }; diff --git a/intern/ghost/intern/GHOST_Window.cpp b/intern/ghost/intern/GHOST_Window.cpp index 202f803f710..a1444bd5c8a 100644 --- a/intern/ghost/intern/GHOST_Window.cpp +++ b/intern/ghost/intern/GHOST_Window.cpp @@ -109,13 +109,12 @@ uint GHOST_Window::getDefaultFramebuffer() GHOST_TSuccess GHOST_Window::getVulkanBackbuffer(void *image, void *framebuffer, - void *command_buffer, void *render_pass, void *extent, uint32_t *fb_id) { return m_context->getVulkanBackbuffer( - image, framebuffer, command_buffer, render_pass, extent, fb_id); + image, framebuffer, render_pass, extent, fb_id); } GHOST_TSuccess GHOST_Window::activateDrawingContext() diff --git a/intern/ghost/intern/GHOST_Window.h b/intern/ghost/intern/GHOST_Window.h index 04ce9fed950..e008fcc72c1 100644 --- a/intern/ghost/intern/GHOST_Window.h +++ b/intern/ghost/intern/GHOST_Window.h @@ -274,12 +274,8 @@ class GHOST_Window : public GHOST_IWindow { * Needs to be called after each swap events as the framebuffer will change. * \return A boolean success indicator. */ - virtual GHOST_TSuccess getVulkanBackbuffer(void *image, - void *framebuffer, - void *command_buffer, - void *render_pass, - void *extent, - uint32_t *fb_id) override; + virtual GHOST_TSuccess getVulkanBackbuffer( + void *image, void *framebuffer, void *render_pass, void *extent, uint32_t *fb_id) override; /** * Returns the window user data. diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 623dd899717..f2dc0f273fd 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -190,16 +190,23 @@ set(OPENGL_SRC set(VULKAN_SRC vulkan/vk_backend.cc vulkan/vk_batch.cc + vulkan/vk_buffer.cc vulkan/vk_context.cc + vulkan/vk_command_buffer.cc + vulkan/vk_descriptor_pools.cc + vulkan/vk_descriptor_set.cc vulkan/vk_drawlist.cc vulkan/vk_fence.cc vulkan/vk_framebuffer.cc vulkan/vk_index_buffer.cc + vulkan/vk_pipeline.cc vulkan/vk_memory.cc vulkan/vk_pixel_buffer.cc vulkan/vk_query.cc vulkan/vk_shader.cc + vulkan/vk_shader_interface.cc vulkan/vk_shader_log.cc + vulkan/vk_state_manager.cc vulkan/vk_storage_buffer.cc vulkan/vk_texture.cc vulkan/vk_uniform_buffer.cc @@ -207,16 +214,23 @@ set(VULKAN_SRC vulkan/vk_backend.hh vulkan/vk_batch.hh + vulkan/vk_buffer.hh vulkan/vk_context.hh + vulkan/vk_command_buffer.hh + vulkan/vk_descriptor_pools.hh + vulkan/vk_descriptor_set.hh vulkan/vk_drawlist.hh vulkan/vk_fence.hh vulkan/vk_framebuffer.hh vulkan/vk_index_buffer.hh + vulkan/vk_pipeline.hh vulkan/vk_memory.hh vulkan/vk_pixel_buffer.hh vulkan/vk_query.hh vulkan/vk_shader.hh + vulkan/vk_shader_interface.hh vulkan/vk_shader_log.hh + vulkan/vk_state_manager.hh vulkan/vk_storage_buffer.hh vulkan/vk_texture.hh vulkan/vk_uniform_buffer.hh @@ -510,6 +524,7 @@ set(GLSL_SRC_TEST tests/shaders/gpu_compute_1d_test.glsl tests/shaders/gpu_compute_2d_test.glsl tests/shaders/gpu_compute_ibo_test.glsl + tests/shaders/gpu_compute_ssbo_test.glsl tests/shaders/gpu_compute_vbo_test.glsl tests/shaders/gpu_compute_dummy_test.glsl ) @@ -787,6 +802,7 @@ if(WITH_GTESTS) tests/gpu_index_buffer_test.cc tests/gpu_shader_builtin_test.cc tests/gpu_shader_test.cc + tests/gpu_storage_buffer_test.cc tests/gpu_testing.hh ) diff --git a/source/blender/gpu/intern/gpu_storage_buffer_private.hh b/source/blender/gpu/intern/gpu_storage_buffer_private.hh index cdc53dc0a26..c05d8dc5b98 100644 --- a/source/blender/gpu/intern/gpu_storage_buffer_private.hh +++ b/source/blender/gpu/intern/gpu_storage_buffer_private.hh @@ -14,6 +14,8 @@ struct GPUStorageBuf; namespace blender { namespace gpu { +class VertBuf; + #ifdef DEBUG # define DEBUG_NAME_LEN 64 #else diff --git a/source/blender/gpu/tests/gpu_shader_test.cc b/source/blender/gpu/tests/gpu_shader_test.cc index c07fda843c7..615f10b82b6 100644 --- a/source/blender/gpu/tests/gpu_shader_test.cc +++ b/source/blender/gpu/tests/gpu_shader_test.cc @@ -212,7 +212,7 @@ GPU_TEST(gpu_shader_compute_ibo) static void test_gpu_shader_compute_ssbo() { - if (!GPU_compute_shader_support()) { + if (!GPU_compute_shader_support() && !GPU_shader_storage_buffer_objects_support()) { /* We can't test as a the platform does not support compute shaders. */ std::cout << "Skipping compute shader test: platform not supported"; return; @@ -221,14 +221,14 @@ static void test_gpu_shader_compute_ssbo() static constexpr uint SIZE = 128; /* Build compute shader. */ - GPUShader *shader = GPU_shader_create_from_info_name("gpu_compute_ibo_test"); + GPUShader *shader = GPU_shader_create_from_info_name("gpu_compute_ssbo_test"); EXPECT_NE(shader, nullptr); GPU_shader_bind(shader); /* Construct IBO. */ GPUStorageBuf *ssbo = GPU_storagebuf_create_ex( SIZE * sizeof(uint32_t), nullptr, GPU_USAGE_DEVICE_ONLY, __func__); - GPU_storagebuf_bind(ssbo, GPU_shader_get_ssbo(shader, "out_indices")); + GPU_storagebuf_bind(ssbo, GPU_shader_get_ssbo(shader, "data_out")); /* Dispatch compute task. */ GPU_compute_dispatch(shader, SIZE, 1, 1); @@ -240,7 +240,7 @@ static void test_gpu_shader_compute_ssbo() uint32_t data[SIZE]; GPU_storagebuf_read(ssbo, data); for (int index = 0; index < SIZE; index++) { - uint32_t expected = index; + uint32_t expected = index * 4; EXPECT_EQ(data[index], expected); } diff --git a/source/blender/gpu/tests/gpu_storage_buffer_test.cc b/source/blender/gpu/tests/gpu_storage_buffer_test.cc new file mode 100644 index 00000000000..38004391dd8 --- /dev/null +++ b/source/blender/gpu/tests/gpu_storage_buffer_test.cc @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include "testing/testing.h" + +#include "GPU_storage_buffer.h" + +#include "BLI_vector.hh" + +#include "gpu_testing.hh" + +namespace blender::gpu::tests { + +constexpr size_t SIZE = 128; +constexpr size_t SIZE_IN_BYTES = SIZE * sizeof(int); + +static Vector test_data() +{ + Vector data; + for (int i : IndexRange(SIZE)) { + data.append(i); + } + return data; +} + +static void test_gpu_storage_buffer_create_update_read() +{ + GPUStorageBuf *ssbo = GPU_storagebuf_create_ex( + SIZE_IN_BYTES, nullptr, GPU_USAGE_STATIC, __func__); + EXPECT_NE(ssbo, nullptr); + + /* Upload some dummy data. */ + const Vector data = test_data(); + GPU_storagebuf_update(ssbo, data.data()); + + /* Read back data from SSBO. */ + Vector read_data; + read_data.resize(SIZE, 0); + GPU_storagebuf_read(ssbo, read_data.data()); + + /* Check if data is the same.*/ + for (int i : IndexRange(SIZE)) { + EXPECT_EQ(data[i], read_data[i]); + } + + GPU_storagebuf_free(ssbo); +} + +GPU_TEST(gpu_storage_buffer_create_update_read); + +} // namespace blender::gpu::tests \ No newline at end of file diff --git a/source/blender/gpu/tests/gpu_testing.cc b/source/blender/gpu/tests/gpu_testing.cc index 1f54837cca3..fd28a18a24b 100644 --- a/source/blender/gpu/tests/gpu_testing.cc +++ b/source/blender/gpu/tests/gpu_testing.cc @@ -15,18 +15,21 @@ namespace blender::gpu { void GPUTest::SetUp() { GPU_backend_type_selection_set(gpu_backend_type); - GHOST_GLSettings glSettings = {0}; + GHOST_GLSettings glSettings = {}; glSettings.context_type = draw_context_type; + glSettings.flags = GHOST_glDebugContext; CLG_init(); ghost_system = GHOST_CreateSystem(); ghost_context = GHOST_CreateOpenGLContext(ghost_system, glSettings); GHOST_ActivateOpenGLContext(ghost_context); context = GPU_context_create(nullptr, ghost_context); GPU_init(); + GPU_context_begin_frame(context); } void GPUTest::TearDown() { + GPU_context_end_frame(context); GPU_exit(); GPU_context_discard(context); GHOST_DisposeOpenGLContext(ghost_system, ghost_context); diff --git a/source/blender/gpu/tests/shaders/gpu_compute_ssbo_test.glsl b/source/blender/gpu/tests/shaders/gpu_compute_ssbo_test.glsl new file mode 100644 index 00000000000..b7a7390f309 --- /dev/null +++ b/source/blender/gpu/tests/shaders/gpu_compute_ssbo_test.glsl @@ -0,0 +1,5 @@ +void main() +{ + int store_index = int(gl_GlobalInvocationID.x); + data_out[store_index] = store_index * 4; +} diff --git a/source/blender/gpu/vulkan/vk_backend.cc b/source/blender/gpu/vulkan/vk_backend.cc index 74d9d8bed8e..5989a899f6a 100644 --- a/source/blender/gpu/vulkan/vk_backend.cc +++ b/source/blender/gpu/vulkan/vk_backend.cc @@ -60,8 +60,17 @@ void VKBackend::samplers_update() { } -void VKBackend::compute_dispatch(int /*groups_x_len*/, int /*groups_y_len*/, int /*groups_z_len*/) +void VKBackend::compute_dispatch(int groups_x_len, int groups_y_len, int groups_z_len) { + VKContext &context = *VKContext::get(); + VKShader *shader = static_cast(context.shader); + VKCommandBuffer &command_buffer = context.command_buffer_get(); + VKPipeline &pipeline = shader->pipeline_get(); + VKDescriptorSet &descriptor_set = pipeline.descriptor_set_get(); + descriptor_set.update(context.device_get()); + command_buffer.bind( + descriptor_set, shader->vk_pipeline_layout_get(), VK_PIPELINE_BIND_POINT_COMPUTE); + command_buffer.dispatch(groups_x_len, groups_y_len, groups_z_len); } void VKBackend::compute_dispatch_indirect(StorageBuf * /*indirect_buf*/) @@ -123,9 +132,9 @@ UniformBuf *VKBackend::uniformbuf_alloc(int size, const char *name) return new VKUniformBuffer(size, name); } -StorageBuf *VKBackend::storagebuf_alloc(int size, GPUUsageType /*usage*/, const char *name) +StorageBuf *VKBackend::storagebuf_alloc(int size, GPUUsageType usage, const char *name) { - return new VKStorageBuffer(size, name); + return new VKStorageBuffer(size, usage, name); } VertBuf *VKBackend::vertbuf_alloc() diff --git a/source/blender/gpu/vulkan/vk_buffer.cc b/source/blender/gpu/vulkan/vk_buffer.cc new file mode 100644 index 00000000000..f02c2ef9b5f --- /dev/null +++ b/source/blender/gpu/vulkan/vk_buffer.cc @@ -0,0 +1,107 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2023 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#include "vk_buffer.hh" + +namespace blender::gpu { + +VKBuffer::~VKBuffer() +{ + VKContext &context = *VKContext::get(); + free(context); +} + +bool VKBuffer::is_allocated() const +{ + return allocation_ != VK_NULL_HANDLE; +} + +static VmaAllocationCreateFlagBits vma_allocation_flags(GPUUsageType usage) +{ + switch (usage) { + case GPU_USAGE_STATIC: + return static_cast( + VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT); + case GPU_USAGE_DYNAMIC: + return static_cast( + VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT); + case GPU_USAGE_DEVICE_ONLY: + return static_cast( + VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT | + VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT); + case GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY: + case GPU_USAGE_STREAM: + break; + } + BLI_assert_msg(false, "Unimplemented GPUUsageType"); + return static_cast(VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT | + VMA_ALLOCATION_CREATE_MAPPED_BIT); +} + +bool VKBuffer::create(VKContext &context, + int64_t size_in_bytes, + GPUUsageType usage, + VkBufferUsageFlagBits buffer_usage) +{ + BLI_assert(!is_allocated()); + + size_in_bytes_ = size_in_bytes; + + VmaAllocator allocator = context.mem_allocator_get(); + VkBufferCreateInfo create_info = {}; + create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + create_info.flags = 0; + create_info.size = size_in_bytes; + create_info.usage = buffer_usage; + /* For now the compute and graphics command queues are the same, so we can safely assume + * exclusive mode.*/ + create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + create_info.queueFamilyIndexCount = 1; + create_info.pQueueFamilyIndices = context.queue_family_ptr_get(); + + VmaAllocationCreateInfo vma_create_info = {}; + vma_create_info.flags = vma_allocation_flags(usage); + vma_create_info.priority = 1.0f; + vma_create_info.usage = VMA_MEMORY_USAGE_AUTO; + + VkResult result = vmaCreateBuffer( + allocator, &create_info, &vma_create_info, &vk_buffer_, &allocation_, nullptr); + return result == VK_SUCCESS; +} + +bool VKBuffer::update(VKContext &context, const void *data) +{ + void *mapped_memory; + bool result = map(context, &mapped_memory); + if (result) { + memcpy(mapped_memory, data, size_in_bytes_); + unmap(context); + } + return result; +} + +bool VKBuffer::map(VKContext &context, void **r_mapped_memory) const +{ + VmaAllocator allocator = context.mem_allocator_get(); + VkResult result = vmaMapMemory(allocator, allocation_, r_mapped_memory); + return result == VK_SUCCESS; +} + +void VKBuffer::unmap(VKContext &context) const +{ + VmaAllocator allocator = context.mem_allocator_get(); + vmaUnmapMemory(allocator, allocation_); +} + +bool VKBuffer::free(VKContext &context) +{ + VmaAllocator allocator = context.mem_allocator_get(); + vmaDestroyBuffer(allocator, vk_buffer_, allocation_); + return true; +} + +} // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_buffer.hh b/source/blender/gpu/vulkan/vk_buffer.hh new file mode 100644 index 00000000000..ecfe176f9b8 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_buffer.hh @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2023 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "gpu_context_private.hh" +#include "vk_context.hh" + +#ifdef __APPLE__ +# include +#else +# include +#endif + +namespace blender::gpu { + +/** + * Class for handing vulkan buffers (allocation/updating/binding). + */ +class VKBuffer { + int64_t size_in_bytes_; + VkBuffer vk_buffer_ = VK_NULL_HANDLE; + VmaAllocation allocation_ = VK_NULL_HANDLE; + + public: + VKBuffer() = default; + virtual ~VKBuffer(); + + /** Has this buffer been allocated? */ + bool is_allocated() const; + + bool create(VKContext &context, + int64_t size, + GPUUsageType usage, + VkBufferUsageFlagBits buffer_usage); + bool update(VKContext &context, const void *data); + // TODO: add partial_update (update_sub) + bool free(VKContext &context); + bool map(VKContext &context, void **r_mapped_memory)const; + void unmap(VKContext &context)const ; + + int64_t size_in_bytes() const + { + return size_in_bytes_; + } + + VkBuffer vk_handle() const + { + return vk_buffer_; + } +}; +} // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_command_buffer.cc b/source/blender/gpu/vulkan/vk_command_buffer.cc new file mode 100644 index 00000000000..5f80facfe01 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_command_buffer.cc @@ -0,0 +1,98 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2023 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#include "vk_command_buffer.hh" +#include "vk_context.hh" + +#include "BLI_assert.h" + +namespace blender::gpu { + +VKCommandBuffer::~VKCommandBuffer() +{ + if (vk_device_ != VK_NULL_HANDLE) { + vkDestroyFence(vk_device_, vk_fence_, nullptr); + vk_fence_ = VK_NULL_HANDLE; + } +} + +void VKCommandBuffer::init(const VkDevice vk_device, + const VkQueue vk_queue, + VkCommandBuffer vk_command_buffer) +{ + vk_device_ = vk_device; + vk_queue_ = vk_queue; + vk_command_buffer_ = vk_command_buffer; + + if (vk_fence_ == VK_NULL_HANDLE) { + VkFenceCreateInfo fenceInfo{}; + fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; + vkCreateFence(vk_device_, &fenceInfo, nullptr, &vk_fence_); + } +} + +void VKCommandBuffer::begin_recording() +{ + vkWaitForFences(vk_device_, 1, &vk_fence_, VK_TRUE, UINT64_MAX); + vkResetFences(vk_device_, 1, &vk_fence_); + vkResetCommandBuffer(vk_command_buffer_, 0); + + VkCommandBufferBeginInfo begin_info = {}; + begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + vkBeginCommandBuffer(vk_command_buffer_, &begin_info); +} + +void VKCommandBuffer::end_recording() +{ + vkEndCommandBuffer(vk_command_buffer_); +} + +void VKCommandBuffer::bind(const VKPipeline &pipeline, VkPipelineBindPoint bind_point) +{ + vkCmdBindPipeline(vk_command_buffer_, bind_point, pipeline.vk_handle()); +} +void VKCommandBuffer::bind(const VKDescriptorSet &descriptor_set, + const VkPipelineLayout vk_pipeline_layout, + VkPipelineBindPoint bind_point) +{ + VkDescriptorSet vk_descriptor_set = descriptor_set.vk_handle(); + vkCmdBindDescriptorSets( + vk_command_buffer_, bind_point, vk_pipeline_layout, 0, 1, &vk_descriptor_set, 0, 0); +} + +void VKCommandBuffer::dispatch(int groups_x_len, int groups_y_len, int groups_z_len) +{ + vkCmdDispatch(vk_command_buffer_, groups_x_len, groups_y_len, groups_z_len); +} + +void VKCommandBuffer::submit() +{ + end_recording(); + encode_recorded_commands(); + submit_encoded_commands(); + begin_recording(); +} + +void VKCommandBuffer::encode_recorded_commands() +{ + /* TODO: Intentionally not implemented. For the graphics pipeline we want to extract the + * resources and its usages so we can encode multiple commands in the same command buffer. This + * will also require to change the begin/end recording to be only inside this function. */ +} + +void VKCommandBuffer::submit_encoded_commands() +{ + VkSubmitInfo submit_info = {}; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &vk_command_buffer_; + + vkQueueSubmit(vk_queue_, 1, &submit_info, vk_fence_); +} + +} // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_command_buffer.hh b/source/blender/gpu/vulkan/vk_command_buffer.hh new file mode 100644 index 00000000000..97bf644b8f3 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_command_buffer.hh @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2023 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#ifdef __APPLE__ +# include +#else +# include +#endif + +#include "vk_pipeline.hh" + +namespace blender::gpu { + +/** Command buffer to keep track of the life-time of a command buffer.*/ +class VKCommandBuffer : NonCopyable, NonMovable { + /** None owning handle to the command buffer and device. Handle is owned by `GHOST_ContextVK`.*/ + VkDevice vk_device_ = VK_NULL_HANDLE; + VkCommandBuffer vk_command_buffer_ = VK_NULL_HANDLE; + VkQueue vk_queue_ = VK_NULL_HANDLE; + + /** Owning handles */ + VkFence vk_fence_ = VK_NULL_HANDLE; + + public: + virtual ~VKCommandBuffer(); + void init(const VkDevice vk_device, const VkQueue vk_queue, VkCommandBuffer vk_command_buffer); + void begin_recording(); + void end_recording(); + void bind(const VKPipeline &vk_pipeline, VkPipelineBindPoint bind_point); + void bind(const VKDescriptorSet &descriptor_set, + const VkPipelineLayout vk_pipeline_layout, + VkPipelineBindPoint bind_point); + void dispatch(int groups_x_len, int groups_y_len, int groups_z_len); + + /** + * Stop recording commands, encode + send the recordings to Vulkan, wait for the until the + * commands have been executed and start the command buffer to accept recordings again. + */ + void submit(); + + private: + void encode_recorded_commands(); + void submit_encoded_commands(); +}; + +} // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_context.cc b/source/blender/gpu/vulkan/vk_context.cc index 853968daa22..4fdf19415bf 100644 --- a/source/blender/gpu/vulkan/vk_context.cc +++ b/source/blender/gpu/vulkan/vk_context.cc @@ -8,6 +8,7 @@ #include "vk_context.hh" #include "vk_backend.hh" +#include "vk_state_manager.hh" #include "GHOST_C-api.h" @@ -19,21 +20,28 @@ VKContext::VKContext(void *ghost_window, void *ghost_context) if (ghost_window) { ghost_context = GHOST_GetDrawingContext((GHOST_WindowHandle)ghost_window); } + ghost_context_ = ghost_context; GHOST_GetVulkanHandles((GHOST_ContextHandle)ghost_context, - &instance_, - &physical_device_, - &device_, - &graphic_queue_family_); + &vk_instance_, + &vk_physical_device_, + &vk_device_, + &vk_queue_family_, + &vk_queue_); /* Initialize the memory allocator. */ VmaAllocatorCreateInfo info = {}; - /* Should use same vulkan version as GHOST. */ - info.vulkanApiVersion = VK_API_VERSION_1_2; - info.physicalDevice = physical_device_; - info.device = device_; - info.instance = instance_; + /* Should use same vulkan version as GHOST, but set to 1.0 for now. Raising it to 1.2 requires + * correct extensions and functions to be found, which doesn't out-of-the-box. We should fix + * this, but to continue the development at hand we lower the API to 1.0.*/ + info.vulkanApiVersion = VK_API_VERSION_1_0; + info.physicalDevice = vk_physical_device_; + info.device = vk_device_; + info.instance = vk_instance_; vmaCreateAllocator(&info, &mem_allocator_); + descriptor_pools_.init(vk_device_); + + state_manager = new VKStateManager(); VKBackend::capabilities_init(*this); } @@ -53,10 +61,17 @@ void VKContext::deactivate() void VKContext::begin_frame() { + VkCommandBuffer command_buffer = VK_NULL_HANDLE; + GHOST_GetVulkanCommandBuffer(static_cast(ghost_context_), &command_buffer); + command_buffer_.init(vk_device_, vk_queue_, command_buffer); + command_buffer_.begin_recording(); + + descriptor_pools_.reset(); } void VKContext::end_frame() { + command_buffer_.end_recording(); } void VKContext::flush() diff --git a/source/blender/gpu/vulkan/vk_context.hh b/source/blender/gpu/vulkan/vk_context.hh index 5ad1a5029ba..1c0b71cb67a 100644 --- a/source/blender/gpu/vulkan/vk_context.hh +++ b/source/blender/gpu/vulkan/vk_context.hh @@ -9,6 +9,9 @@ #include "gpu_context_private.hh" +#include "vk_command_buffer.hh" +#include "vk_descriptor_pools.hh" + #include "vk_mem_alloc.h" #ifdef __APPLE__ @@ -22,13 +25,18 @@ namespace blender::gpu { class VKContext : public Context { private: /** Copies of the handles owned by the GHOST context. */ - VkInstance instance_ = VK_NULL_HANDLE; - VkPhysicalDevice physical_device_ = VK_NULL_HANDLE; - VkDevice device_ = VK_NULL_HANDLE; - uint32_t graphic_queue_family_ = 0; + VkInstance vk_instance_ = VK_NULL_HANDLE; + VkPhysicalDevice vk_physical_device_ = VK_NULL_HANDLE; + VkDevice vk_device_ = VK_NULL_HANDLE; + VKCommandBuffer command_buffer_; + uint32_t vk_queue_family_ = 0; + VkQueue vk_queue_ = VK_NULL_HANDLE; /** Allocator used for texture and buffers and other resources. */ VmaAllocator mem_allocator_ = VK_NULL_HANDLE; + VKDescriptorPools descriptor_pools_; + + void *ghost_context_; public: VKContext(void *ghost_window, void *ghost_context); @@ -54,7 +62,27 @@ class VKContext : public Context { VkDevice device_get() const { - return device_; + return vk_device_; + } + + VKCommandBuffer &command_buffer_get() + { + return command_buffer_; + } + + VkQueue queue_get() const + { + return vk_queue_; + } + + const uint32_t *queue_family_ptr_get() const + { + return &vk_queue_family_; + } + + VKDescriptorPools &descriptor_pools_get() + { + return descriptor_pools_; } VmaAllocator mem_allocator_get() const diff --git a/source/blender/gpu/vulkan/vk_descriptor_pools.cc b/source/blender/gpu/vulkan/vk_descriptor_pools.cc new file mode 100644 index 00000000000..48d1e7d16e6 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_descriptor_pools.cc @@ -0,0 +1,110 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2023 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#include "vk_descriptor_pools.hh" + +namespace blender::gpu { +VKDescriptorPools::VKDescriptorPools() +{ +} + +VKDescriptorPools::~VKDescriptorPools() +{ + for (const VkDescriptorPool vk_descriptor_pool : pools_) { + BLI_assert(vk_device_ != VK_NULL_HANDLE); + vkDestroyDescriptorPool(vk_device_, vk_descriptor_pool, nullptr); + } + vk_device_ = VK_NULL_HANDLE; +} + +void VKDescriptorPools::init(const VkDevice vk_device) +{ + BLI_assert(vk_device_ == VK_NULL_HANDLE); + vk_device_ = vk_device; + add_new_pool(); +} + +void VKDescriptorPools::reset() +{ + active_pool_index_ = 0; +} + +void VKDescriptorPools::add_new_pool() +{ + Vector pool_sizes = { + {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, POOL_SIZE_UNIFORM_BUFFER}, + {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, POOL_SIZE_STORAGE_BUFFER}, + }; + VkDescriptorPoolCreateInfo pool_info = {}; + pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; + pool_info.maxSets = POOL_SIZE_DESCRIPTOR_SETS; + pool_info.poolSizeCount = pool_sizes.size(); + pool_info.pPoolSizes = pool_sizes.data(); + VkDescriptorPool descriptor_pool = VK_NULL_HANDLE; + VkResult result = vkCreateDescriptorPool(vk_device_, &pool_info, nullptr, &descriptor_pool); + UNUSED_VARS(result); + pools_.append(descriptor_pool); +} + +VkDescriptorPool VKDescriptorPools::active_pool_get() +{ + BLI_assert(!pools_.is_empty()); + return pools_[active_pool_index_]; +} + +void VKDescriptorPools::activate_next_pool() +{ + BLI_assert(!is_last_pool_active()); + active_pool_index_ += 1; +} + +void VKDescriptorPools::activate_last_pool() +{ + active_pool_index_ = pools_.size() - 1; +} + +bool VKDescriptorPools::is_last_pool_active() +{ + return active_pool_index_ == pools_.size() - 1; +} + +VKDescriptorSet VKDescriptorPools::allocate(const VkDescriptorSetLayout &descriptor_set_layout) +{ + VkDescriptorSetAllocateInfo allocate_info = {}; + VkDescriptorPool pool = active_pool_get(); + allocate_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + allocate_info.descriptorPool = pool; + allocate_info.descriptorSetCount = 1; + allocate_info.pSetLayouts = &descriptor_set_layout; + VkDescriptorSet vk_descriptor_set = VK_NULL_HANDLE; + VkResult result = vkAllocateDescriptorSets(vk_device_, &allocate_info, &vk_descriptor_set); + + if (result == VK_ERROR_OUT_OF_POOL_MEMORY) { + if (is_last_pool_active()) { + add_new_pool(); + activate_last_pool(); + } + else { + activate_next_pool(); + } + return allocate(descriptor_set_layout); + } + + return VKDescriptorSet(pool, vk_descriptor_set); +} + +void VKDescriptorPools::free(VKDescriptorSet &descriptor_set) +{ + VkDescriptorSet vk_descriptor_set = descriptor_set.vk_handle(); + VkDescriptorPool vk_descriptor_pool = descriptor_set.vk_pool_handle(); + BLI_assert(pools_.contains(vk_descriptor_pool)); + vkFreeDescriptorSets(vk_device_, vk_descriptor_pool, 1, &vk_descriptor_set); + descriptor_set.mark_freed(); +} + +} // namespace blender::gpu \ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_descriptor_pools.hh b/source/blender/gpu/vulkan/vk_descriptor_pools.hh new file mode 100644 index 00000000000..3b071c140f7 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_descriptor_pools.hh @@ -0,0 +1,68 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2023 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "BLI_vector.hh" + +#ifdef __APPLE__ +# include +#else +# include +#endif + +#include "vk_descriptor_set.hh" + +namespace blender::gpu { + +/** + * List of VkDescriptorPools. + * + * In Vulkan a pool is constructed with a fixed size per resource type. When more resources are + * needed it a next pool should be created. VKDescriptorPools will keep track of those pools and + * construct new pools when the previous one is exhausted. + * + * At the beginning of a new frame the descriptor pools are reset. This will start allocating + * again from the first descriptor pool in order to use freed space from previous pools. + */ +class VKDescriptorPools { + /** + * Pool sizes to use. When one descriptor pool is requested to allocate a descriptor but isn't + * able to do so, it will fail. + * + * Better defaults should be set later on, when we know more about our resource usage. + */ + static constexpr uint32_t POOL_SIZE_UNIFORM_BUFFER = 1000; + static constexpr uint32_t POOL_SIZE_STORAGE_BUFFER = 1000; + static constexpr uint32_t POOL_SIZE_DESCRIPTOR_SETS = 1000; + + VkDevice vk_device_ = VK_NULL_HANDLE; + Vector pools_; + int64_t active_pool_index_ = 0; + + public: + VKDescriptorPools(); + ~VKDescriptorPools(); + + void init(const VkDevice vk_device); + + VKDescriptorSet allocate(const VkDescriptorSetLayout &descriptor_set_layout); + void free(VKDescriptorSet &descriptor_set); + + /** + * Reset the pools to start looking for free space from the first descriptor pool. + */ + void reset(); + + private: + VkDescriptorPool active_pool_get(); + void activate_next_pool(); + void activate_last_pool(); + bool is_last_pool_active(); + void add_new_pool(); +}; +} // namespace blender::gpu \ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_descriptor_set.cc b/source/blender/gpu/vulkan/vk_descriptor_set.cc new file mode 100644 index 00000000000..9b28e3f16c2 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_descriptor_set.cc @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2023 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#include "vk_descriptor_set.hh" +#include "vk_storage_buffer.hh" +#include "vk_vertex_buffer.hh" + +#include "BLI_assert.h" + +namespace blender::gpu { +VKDescriptorSet::~VKDescriptorSet() +{ + if (vk_descriptor_set_ != VK_NULL_HANDLE) { + /* Handle should be given back to the pool.*/ + VKContext &context = *VKContext::get(); + context.descriptor_pools_get().free(*this); + BLI_assert(vk_descriptor_set_ == VK_NULL_HANDLE); + } +} + +void VKDescriptorSet::mark_freed() +{ + vk_descriptor_set_ = VK_NULL_HANDLE; + vk_descriptor_pool_ = VK_NULL_HANDLE; +} + +void VKDescriptorSet::bind(VKStorageBuffer &buffer, int location) +{ + Binding &binding = ensure_location(location); + binding.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + binding.vk_buffer = buffer.vk_handle(); + binding.buffer_size = buffer.size_in_bytes(); +} + +void VKDescriptorSet::bind_as_ssbo(VKVertexBuffer &buffer, int location) +{ + Binding &binding = ensure_location(location); + binding.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + binding.vk_buffer = buffer.vk_handle(); + binding.buffer_size = buffer.size_used_get(); +} + +VKDescriptorSet::Binding &VKDescriptorSet::ensure_location(int location) +{ + for (Binding &binding : bindings_) { + if (binding.location == location) { + return binding; + } + } + + Binding binding; + binding.vk_buffer = VK_NULL_HANDLE; + binding.buffer_size = 0; + binding.location = location; + bindings_.append(binding); + return bindings_.last(); +} + +void VKDescriptorSet::update(VkDevice vk_device) +{ + Vector buffer_infos; + Vector descriptor_writes; + for (const Binding &binding : bindings_) { + VkDescriptorBufferInfo buffer_info = {}; + buffer_info.buffer = binding.vk_buffer; + buffer_info.range = binding.buffer_size; + buffer_infos.append(buffer_info); + + VkWriteDescriptorSet write_descriptor = {}; + write_descriptor.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write_descriptor.dstSet = vk_descriptor_set_; + write_descriptor.dstBinding = binding.location; + write_descriptor.descriptorCount = 1; + write_descriptor.descriptorType = binding.type; + write_descriptor.pBufferInfo = &buffer_infos.last(); + + descriptor_writes.append(write_descriptor); + } + + vkUpdateDescriptorSets( + vk_device, descriptor_writes.size(), descriptor_writes.data(), 0, nullptr); +} + +} // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_descriptor_set.hh b/source/blender/gpu/vulkan/vk_descriptor_set.hh new file mode 100644 index 00000000000..ebfa2386095 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_descriptor_set.hh @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2023 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "BLI_utility_mixins.hh" +#include "BLI_vector.hh" + +#ifdef __APPLE__ +# include +#else +# include +#endif + +namespace blender::gpu { +class VKStorageBuffer; +class VKVertexBuffer; + +class VKDescriptorSet : NonCopyable { + struct Binding { + int location; + VkDescriptorType type; + VkBuffer vk_buffer = VK_NULL_HANDLE; + VkDeviceSize buffer_size; + }; + + VkDescriptorPool vk_descriptor_pool_ = VK_NULL_HANDLE; + VkDescriptorSet vk_descriptor_set_ = VK_NULL_HANDLE; + + Vector bindings_; + + public: + VKDescriptorSet() = default; + VKDescriptorSet(VkDescriptorPool vk_descriptor_pool, VkDescriptorSet vk_descriptor_set) + : vk_descriptor_pool_(vk_descriptor_pool), vk_descriptor_set_(vk_descriptor_set) + { + } + virtual ~VKDescriptorSet(); + + VKDescriptorSet &operator=(VKDescriptorSet &&other) + { + vk_descriptor_set_ = other.vk_descriptor_set_; + vk_descriptor_pool_ = other.vk_descriptor_pool_; + other.mark_freed(); + return *this; + } + + VkDescriptorSet vk_handle() const + { + return vk_descriptor_set_; + } + + VkDescriptorPool vk_pool_handle() const + { + return vk_descriptor_pool_; + } + + void bind_as_ssbo(VKVertexBuffer &buffer, int location); + void bind(VKStorageBuffer &buffer, int location); + + /** + * Update the descriptor set on the device. + */ + void update(VkDevice vk_device); + + void mark_freed(); + + private: + Binding &ensure_location(int location); +}; + +} // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_pipeline.cc b/source/blender/gpu/vulkan/vk_pipeline.cc new file mode 100644 index 00000000000..c6174536366 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_pipeline.cc @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2023 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#include "vk_pipeline.hh" +#include "vk_context.hh" + +namespace blender::gpu { + +VKPipeline::VKPipeline(VkPipeline vk_pipeline, VKDescriptorSet &&vk_descriptor_set) + : vk_pipeline_(vk_pipeline) +{ + descriptor_set_ = std::move(vk_descriptor_set); +} + +VKPipeline::~VKPipeline() +{ + VkDevice vk_device = VKContext::get()->device_get(); + if (vk_pipeline_ != VK_NULL_HANDLE) { + vkDestroyPipeline(vk_device, vk_pipeline_, nullptr); + } +} + +VKPipeline VKPipeline::create_compute_pipeline(VKContext &context, + VkShaderModule compute_module, + VkDescriptorSetLayout &descriptor_set_layout, + VkPipelineLayout &pipeline_layout) +{ + VkDevice vk_device = context.device_get(); + VkComputePipelineCreateInfo pipeline_info = {}; + pipeline_info.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; + pipeline_info.flags = 0; + pipeline_info.stage = {}; + pipeline_info.stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + pipeline_info.stage.flags = 0; + pipeline_info.stage.stage = VK_SHADER_STAGE_COMPUTE_BIT; + pipeline_info.stage.module = compute_module; + pipeline_info.layout = pipeline_layout; + pipeline_info.stage.pName = "main"; + + VkPipeline pipeline; + if (vkCreateComputePipelines(vk_device, nullptr, 1, &pipeline_info, nullptr, &pipeline) != + VK_SUCCESS) { + return VKPipeline(); + } + + VKDescriptorSet descriptor_set = context.descriptor_pools_get().allocate(descriptor_set_layout); + return VKPipeline(pipeline, std::move(descriptor_set)); +} + +VkPipeline VKPipeline::vk_handle() const +{ + return vk_pipeline_; +} + +bool VKPipeline::is_valid() const +{ + return vk_pipeline_ != VK_NULL_HANDLE; +} + +} // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_pipeline.hh b/source/blender/gpu/vulkan/vk_pipeline.hh new file mode 100644 index 00000000000..6111a888d82 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_pipeline.hh @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2023 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#ifdef __APPLE__ +# include +#else +# include +#endif + +#include "BLI_utility_mixins.hh" +#include "BLI_vector.hh" + +#include "vk_descriptor_set.hh" + +namespace blender::gpu { +class VKContext; + +class VKPipeline : NonCopyable { + VKDescriptorSet descriptor_set_; + VkPipeline vk_pipeline_ = VK_NULL_HANDLE; + + public: + VKPipeline() = default; + + virtual ~VKPipeline(); + VKPipeline(VkPipeline vk_pipeline, VKDescriptorSet &&vk_descriptor_set); + VKPipeline &operator=(VKPipeline &&other) + { + vk_pipeline_ = other.vk_pipeline_; + other.vk_pipeline_ = VK_NULL_HANDLE; + descriptor_set_ = std::move(other.descriptor_set_); + return *this; + } + + static VKPipeline create_compute_pipeline(VKContext &context, + VkShaderModule compute_module, + VkDescriptorSetLayout &descriptor_set_layout, + VkPipelineLayout &pipeline_layouts); + + VKDescriptorSet &descriptor_set_get() + { + return descriptor_set_; + } + + VkPipeline vk_handle() const; + bool is_valid() const; +}; + +} // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_shader.cc b/source/blender/gpu/vulkan/vk_shader.cc index 3f145bd4763..6ea97124cab 100644 --- a/source/blender/gpu/vulkan/vk_shader.cc +++ b/source/blender/gpu/vulkan/vk_shader.cc @@ -9,6 +9,7 @@ #include "vk_backend.hh" #include "vk_memory.hh" +#include "vk_shader_interface.hh" #include "vk_shader_log.hh" #include "BLI_string_utils.h" @@ -603,6 +604,14 @@ VKShader::~VKShader() vkDestroyShaderModule(device, compute_module_, vk_allocation_callbacks); compute_module_ = VK_NULL_HANDLE; } + if (pipeline_layout_ != VK_NULL_HANDLE) { + vkDestroyPipelineLayout(device, pipeline_layout_, nullptr); + pipeline_layout_ = VK_NULL_HANDLE; + } + if (layout_ != VK_NULL_HANDLE) { + vkDestroyDescriptorSetLayout(device, layout_, nullptr); + layout_ = VK_NULL_HANDLE; + } } void VKShader::build_shader_module(MutableSpan sources, @@ -646,52 +655,162 @@ bool VKShader::finalize(const shader::ShaderCreateInfo *info) return false; } - if (vertex_module_ != VK_NULL_HANDLE) { + VkDevice vk_device = context_->device_get(); + if (!finalize_descriptor_set_layouts(vk_device, *info)) { + return false; + } + if (!finalize_pipeline_layout(vk_device, *info)) { + return false; + } + + /* TODO we might need to move the actual pipeline construction to a later stage as the graphics + * pipeline requires more data before it can be constructed.*/ + bool result; + if (is_graphics_shader()) { BLI_assert((fragment_module_ != VK_NULL_HANDLE && info->tf_type_ == GPU_SHADER_TFB_NONE) || (fragment_module_ == VK_NULL_HANDLE && info->tf_type_ != GPU_SHADER_TFB_NONE)); BLI_assert(compute_module_ == VK_NULL_HANDLE); - - VkPipelineShaderStageCreateInfo vertex_stage_info = {}; - vertex_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - vertex_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT; - vertex_stage_info.module = vertex_module_; - vertex_stage_info.pName = "main"; - pipeline_infos_.append(vertex_stage_info); - - if (geometry_module_ != VK_NULL_HANDLE) { - VkPipelineShaderStageCreateInfo geo_stage_info = {}; - geo_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - geo_stage_info.stage = VK_SHADER_STAGE_GEOMETRY_BIT; - geo_stage_info.module = geometry_module_; - geo_stage_info.pName = "main"; - pipeline_infos_.append(geo_stage_info); - } - if (fragment_module_ != VK_NULL_HANDLE) { - VkPipelineShaderStageCreateInfo fragment_stage_info = {}; - fragment_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - fragment_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT; - fragment_stage_info.module = fragment_module_; - fragment_stage_info.pName = "main"; - pipeline_infos_.append(fragment_stage_info); - } + result = finalize_graphics_pipeline(vk_device); } else { BLI_assert(vertex_module_ == VK_NULL_HANDLE); BLI_assert(geometry_module_ == VK_NULL_HANDLE); BLI_assert(fragment_module_ == VK_NULL_HANDLE); BLI_assert(compute_module_ != VK_NULL_HANDLE); - - VkPipelineShaderStageCreateInfo compute_stage_info = {}; - compute_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - compute_stage_info.stage = VK_SHADER_STAGE_GEOMETRY_BIT; - compute_stage_info.module = compute_module_; - compute_stage_info.pName = "main"; - pipeline_infos_.append(compute_stage_info); + compute_pipeline_ = std::move(VKPipeline::create_compute_pipeline( + *context_, compute_module_, layout_, pipeline_layout_)); + result = compute_pipeline_.is_valid(); } -#ifdef NDEBUG - UNUSED_VARS(info); -#endif + if (result) { + VKShaderInterface *vk_interface = new VKShaderInterface(); + vk_interface->init(*info); + interface = vk_interface; + } + return result; +} + +bool VKShader::finalize_graphics_pipeline(VkDevice /*vk_device */) +{ + Vector pipeline_stages; + VkPipelineShaderStageCreateInfo vertex_stage_info = {}; + vertex_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + vertex_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT; + vertex_stage_info.module = vertex_module_; + vertex_stage_info.pName = "main"; + pipeline_stages.append(vertex_stage_info); + + if (geometry_module_ != VK_NULL_HANDLE) { + VkPipelineShaderStageCreateInfo geo_stage_info = {}; + geo_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + geo_stage_info.stage = VK_SHADER_STAGE_GEOMETRY_BIT; + geo_stage_info.module = geometry_module_; + geo_stage_info.pName = "main"; + pipeline_stages.append(geo_stage_info); + } + if (fragment_module_ != VK_NULL_HANDLE) { + VkPipelineShaderStageCreateInfo fragment_stage_info = {}; + fragment_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + fragment_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT; + fragment_stage_info.module = fragment_module_; + fragment_stage_info.pName = "main"; + pipeline_stages.append(fragment_stage_info); + } + + return true; +} + +bool VKShader::finalize_pipeline_layout(VkDevice vk_device, + const shader::ShaderCreateInfo & /*info*/) +{ + VkPipelineLayoutCreateInfo pipeline_info = {}; + pipeline_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipeline_info.flags = 0; + pipeline_info.setLayoutCount = 1; + pipeline_info.pSetLayouts = &layout_; + + if (vkCreatePipelineLayout(vk_device, &pipeline_info, nullptr, &pipeline_layout_) != + VK_SUCCESS) { + return false; + }; + + return true; +} + +static VkDescriptorType descriptor_type( + const shader::ShaderCreateInfo::Resource::BindType bind_type) +{ + switch (bind_type) { + case shader::ShaderCreateInfo::Resource::BindType::IMAGE: + return VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + case shader::ShaderCreateInfo::Resource::BindType::SAMPLER: + return VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + case shader::ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER: + return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + case shader::ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER: + return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + } + BLI_assert_unreachable(); + return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; +} + +static VkDescriptorSetLayoutBinding create_descriptor_set_layout_binding( + const shader::ShaderCreateInfo::Resource &resource) +{ + VkDescriptorSetLayoutBinding binding = {}; + binding.binding = resource.slot; + binding.descriptorType = descriptor_type(resource.bind_type); + binding.descriptorCount = 1; + binding.stageFlags = VK_SHADER_STAGE_ALL; + binding.pImmutableSamplers = nullptr; + + return binding; +} + +static void add_descriptor_set_layout_bindings( + const Vector &resources, + Vector &r_bindings) +{ + for (const shader::ShaderCreateInfo::Resource &resource : resources) { + r_bindings.append(create_descriptor_set_layout_binding(resource)); + } +} + +static VkDescriptorSetLayoutCreateInfo create_descriptor_set_layout( + const Vector &resources, + Vector &r_bindings) +{ + add_descriptor_set_layout_bindings(resources, r_bindings); + VkDescriptorSetLayoutCreateInfo set_info = {}; + set_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + set_info.flags = 0; + set_info.pNext = nullptr; + set_info.bindingCount = r_bindings.size(); + set_info.pBindings = r_bindings.data(); + return set_info; +} + +bool VKShader::finalize_descriptor_set_layouts(VkDevice vk_device, + const shader::ShaderCreateInfo &info) +{ + if (info.pass_resources_.is_empty() && info.batch_resources_.is_empty()) { + return true; + } + + /* Currently we create a single descriptor set. The goal would be to create one descriptor set + * for Frequency::PASS/BATCH. This isn't possible as areas expect that the binding location is + * static and predictable (eevee-next) or the binding location can be mapped to a single number + * (python). */ + Vector all_resources; + all_resources.extend(info.pass_resources_); + all_resources.extend(info.batch_resources_); + + Vector bindings; + VkDescriptorSetLayoutCreateInfo layout_info = create_descriptor_set_layout(all_resources, + bindings); + if (vkCreateDescriptorSetLayout(vk_device, &layout_info, nullptr, &layout_) != VK_SUCCESS) { + return false; + }; return true; } @@ -712,10 +831,23 @@ void VKShader::transform_feedback_disable() void VKShader::bind() { + VKContext *context = VKContext::get(); + + if (is_compute_shader()) { + context->command_buffer_get().bind(compute_pipeline_, VK_PIPELINE_BIND_POINT_COMPUTE); + } + else { + BLI_assert_unreachable(); + } } void VKShader::unbind() { + if (is_compute_shader()) { + } + else { + BLI_assert_unreachable(); + } } void VKShader::uniform_float(int /*location*/, @@ -954,4 +1086,9 @@ int VKShader::program_handle_get() const return -1; } +VKPipeline &VKShader::pipeline_get() +{ + return compute_pipeline_; +} + } // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_shader.hh b/source/blender/gpu/vulkan/vk_shader.hh index 2fca185ea93..ad44491b07e 100644 --- a/source/blender/gpu/vulkan/vk_shader.hh +++ b/source/blender/gpu/vulkan/vk_shader.hh @@ -24,7 +24,9 @@ class VKShader : public Shader { VkShaderModule fragment_module_ = VK_NULL_HANDLE; VkShaderModule compute_module_ = VK_NULL_HANDLE; bool compilation_failed_ = false; - Vector pipeline_infos_; + VkDescriptorSetLayout layout_; + VkPipelineLayout pipeline_layout_ = VK_NULL_HANDLE; + VKPipeline compute_pipeline_; public: VKShader(const char *name); @@ -57,12 +59,32 @@ class VKShader : public Shader { /* DEPRECATED: Kept only because of BGL API. */ int program_handle_get() const override; + VKPipeline &pipeline_get(); + /* TODO: should be part of VKPipeline.*/ + VkPipelineLayout vk_pipeline_layout_get() const + { + return pipeline_layout_; + } + private: Vector compile_glsl_to_spirv(Span sources, shaderc_shader_kind kind); void build_shader_module(Span spirv_module, VkShaderModule *r_shader_module); void build_shader_module(MutableSpan sources, shaderc_shader_kind stage, VkShaderModule *r_shader_module); + bool finalize_descriptor_set_layouts(VkDevice vk_device, const shader::ShaderCreateInfo &info); + bool finalize_pipeline_layout(VkDevice vk_device, const shader::ShaderCreateInfo &info); + bool finalize_graphics_pipeline(VkDevice vk_device); + + bool is_graphics_shader() const + { + return !is_compute_shader(); + } + + bool is_compute_shader() const + { + return compute_module_ != VK_NULL_HANDLE; + } }; } // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_shader_interface.cc b/source/blender/gpu/vulkan/vk_shader_interface.cc new file mode 100644 index 00000000000..00dbbf7820d --- /dev/null +++ b/source/blender/gpu/vulkan/vk_shader_interface.cc @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2023 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#include "vk_shader_interface.hh" + +namespace blender::gpu { + +void VKShaderInterface::init(const shader::ShaderCreateInfo &info) +{ + using namespace blender::gpu::shader; + + ssbo_len_ = 0; + + Vector all_resources; + all_resources.extend(info.pass_resources_); + all_resources.extend(info.batch_resources_); + + for (ShaderCreateInfo::Resource &res : all_resources) { + switch (res.bind_type) { + case ShaderCreateInfo::Resource::BindType::IMAGE: + case ShaderCreateInfo::Resource::BindType::SAMPLER: + case ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER: + // BLI_assert_msg(false, "not implemented yet"); + break; + case ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER: + ssbo_len_++; + break; + } + } + + int32_t input_tot_len = ssbo_len_; + inputs_ = static_cast( + MEM_calloc_arrayN(input_tot_len, sizeof(ShaderInput), __func__)); + ShaderInput *input = inputs_; + + name_buffer_ = (char *)MEM_mallocN(info.interface_names_size_, "name_buffer"); + uint32_t name_buffer_offset = 0; + + for (const ShaderCreateInfo::Resource &res : all_resources) { + if (res.bind_type == ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER) { + copy_input_name(input, res.storagebuf.name, name_buffer_, name_buffer_offset); + input->location = input->binding = res.slot; + enabled_ssbo_mask_ |= (1 << input->binding); + input++; + } + } + + sort_inputs(); +} + +} // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_shader_interface.hh b/source/blender/gpu/vulkan/vk_shader_interface.hh new file mode 100644 index 00000000000..f741a0b133e --- /dev/null +++ b/source/blender/gpu/vulkan/vk_shader_interface.hh @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2023 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "gpu_shader_create_info.hh" +#include "gpu_shader_interface.hh" + +namespace blender::gpu { +class VKShaderInterface : public ShaderInterface { + public: + VKShaderInterface() = default; + + void init(const shader::ShaderCreateInfo &info); +}; +} // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_state_manager.cc b/source/blender/gpu/vulkan/vk_state_manager.cc new file mode 100644 index 00000000000..3bde798e5e9 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_state_manager.cc @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2023 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#include "vk_state_manager.hh" + +namespace blender::gpu { +void VKStateManager::apply_state() +{ +} + +void VKStateManager::force_state() +{ +} + +void VKStateManager::issue_barrier(eGPUBarrier /*barrier_bits*/) +{ +} + +void VKStateManager::texture_bind(Texture * /*tex*/, eGPUSamplerState /*sampler*/, int /*unit*/) +{ +} + +void VKStateManager::texture_unbind(Texture * /*tex*/) +{ +} + +void VKStateManager::texture_unbind_all() +{ +} + +void VKStateManager::image_bind(Texture * /*tex*/, int /*unit*/) +{ +} + +void VKStateManager::image_unbind(Texture * /*tex*/) +{ +} + +void VKStateManager::image_unbind_all() +{ +} + +void VKStateManager::texture_unpack_row_length_set(uint /*len*/) +{ +} + +} // namespace blender::gpu \ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_state_manager.hh b/source/blender/gpu/vulkan/vk_state_manager.hh new file mode 100644 index 00000000000..4d2643485c1 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_state_manager.hh @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2023 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "gpu_state_private.hh" + +namespace blender::gpu { +class VKStateManager : public StateManager { + public: + void apply_state() override; + void force_state() override; + + void issue_barrier(eGPUBarrier barrier_bits) override; + + void texture_bind(Texture *tex, eGPUSamplerState sampler, int unit) override; + void texture_unbind(Texture *tex) override; + void texture_unbind_all() override; + + void image_bind(Texture *tex, int unit) override; + void image_unbind(Texture *tex) override; + void image_unbind_all() override; + + void texture_unpack_row_length_set(uint len) override; +}; +} // namespace blender::gpu \ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_storage_buffer.cc b/source/blender/gpu/vulkan/vk_storage_buffer.cc index 40c770fa1d2..d11bc46e88d 100644 --- a/source/blender/gpu/vulkan/vk_storage_buffer.cc +++ b/source/blender/gpu/vulkan/vk_storage_buffer.cc @@ -4,19 +4,35 @@ /** \file * \ingroup gpu */ - +#include "vk_shader.hh" #include "vk_vertex_buffer.hh" #include "vk_storage_buffer.hh" namespace blender::gpu { -void VKStorageBuffer::update(const void * /*data*/) +void VKStorageBuffer::update(const void *data) { + VKContext &context = *VKContext::get(); + if (!buffer_.is_allocated()) { + allocate(context); + } + buffer_.update(context, data); } -void VKStorageBuffer::bind(int /*slot*/) +void VKStorageBuffer::allocate(VKContext &context) { + buffer_.create(context, size_in_bytes_, usage_, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); +} + +void VKStorageBuffer::bind(int slot) +{ + VKContext &context = *VKContext::get(); + if (!buffer_.is_allocated()) { + allocate(context); + } + VKShader *shader = static_cast(context.shader); + shader->pipeline_get().descriptor_set_get().bind(*this, slot); } void VKStorageBuffer::unbind() @@ -35,8 +51,21 @@ void VKStorageBuffer::copy_sub(VertBuf * /*src*/, { } -void VKStorageBuffer::read(void * /*data*/) +void VKStorageBuffer::read(void *data) { + VKContext &context = *VKContext::get(); + if (!buffer_.is_allocated()) { + allocate(context); + } + + VKCommandBuffer &command_buffer = context.command_buffer_get(); + command_buffer.submit(); + + void *mapped_memory; + if (buffer_.map(context, &mapped_memory)) { + memcpy(data, mapped_memory, size_in_bytes_); + buffer_.unmap(context); + } } } // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_storage_buffer.hh b/source/blender/gpu/vulkan/vk_storage_buffer.hh index ab3cb584ea0..a9ee1a6256b 100644 --- a/source/blender/gpu/vulkan/vk_storage_buffer.hh +++ b/source/blender/gpu/vulkan/vk_storage_buffer.hh @@ -10,12 +10,20 @@ #include "GPU_texture.h" #include "gpu_storage_buffer_private.hh" +#include "gpu_vertex_buffer_private.hh" + +#include "vk_buffer.hh" namespace blender::gpu { +class VertBuf; class VKStorageBuffer : public StorageBuf { + GPUUsageType usage_; + VKBuffer buffer_; + public: - VKStorageBuffer(int size, const char *name) : StorageBuf(size, name) + VKStorageBuffer(int size, GPUUsageType usage, const char *name) + : StorageBuf(size, name), usage_(usage) { } @@ -25,6 +33,19 @@ class VKStorageBuffer : public StorageBuf { void clear(eGPUTextureFormat internal_format, eGPUDataFormat data_format, void *data) override; void copy_sub(VertBuf *src, uint dst_offset, uint src_offset, uint copy_size) override; void read(void *data) override; + + VkBuffer vk_handle() const + { + return buffer_.vk_handle(); + } + + int64_t size_in_bytes() const + { + return buffer_.size_in_bytes(); + } + + private: + void allocate(VKContext &context); }; } // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_vertex_buffer.cc b/source/blender/gpu/vulkan/vk_vertex_buffer.cc index f2326ddb134..00bb97a6fcc 100644 --- a/source/blender/gpu/vulkan/vk_vertex_buffer.cc +++ b/source/blender/gpu/vulkan/vk_vertex_buffer.cc @@ -7,6 +7,7 @@ #include "MEM_guardedalloc.h" +#include "vk_shader.hh" #include "vk_vertex_buffer.hh" namespace blender::gpu { @@ -16,8 +17,15 @@ VKVertexBuffer::~VKVertexBuffer() release_data(); } -void VKVertexBuffer::bind_as_ssbo(uint /*binding*/) +void VKVertexBuffer::bind_as_ssbo(uint binding) { + VKContext &context = *VKContext::get(); + if (!buffer_.is_allocated()) { + allocate(context); + } + + VKShader *shader = static_cast(context.shader); + shader->pipeline_get().descriptor_set_get().bind_as_ssbo(*this, binding); } void VKVertexBuffer::bind_as_texture(uint /*binding*/) @@ -32,8 +40,17 @@ void VKVertexBuffer::update_sub(uint /*start*/, uint /*len*/, const void * /*dat { } -void VKVertexBuffer::read(void * /*data*/) const +void VKVertexBuffer::read(void *data) const { + VKContext &context = *VKContext::get(); + VKCommandBuffer &command_buffer = context.command_buffer_get(); + command_buffer.submit(); + + void *mapped_memory; + if (buffer_.map(context, &mapped_memory)) { + memcpy(data, mapped_memory, size_used_get()); + buffer_.unmap(context); + } } void VKVertexBuffer::acquire_data() @@ -64,4 +81,13 @@ void VKVertexBuffer::duplicate_data(VertBuf * /*dst*/) { } +void VKVertexBuffer::allocate(VKContext &context) +{ + buffer_.create(context, + size_used_get(), + usage_, + static_cast(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | + VK_BUFFER_USAGE_VERTEX_BUFFER_BIT)); +} + } // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_vertex_buffer.hh b/source/blender/gpu/vulkan/vk_vertex_buffer.hh index ebc3e105553..1bf8e782a1e 100644 --- a/source/blender/gpu/vulkan/vk_vertex_buffer.hh +++ b/source/blender/gpu/vulkan/vk_vertex_buffer.hh @@ -9,9 +9,13 @@ #include "gpu_vertex_buffer_private.hh" +#include "vk_buffer.hh" + namespace blender::gpu { class VKVertexBuffer : public VertBuf { + VKBuffer buffer_; + public: ~VKVertexBuffer(); @@ -22,12 +26,20 @@ class VKVertexBuffer : public VertBuf { void update_sub(uint start, uint len, const void *data) override; void read(void *data) const override; + VkBuffer vk_handle() const + { + return buffer_.vk_handle(); + } + protected: void acquire_data() override; void resize_data() override; void release_data() override; void upload_data() override; void duplicate_data(VertBuf *dst) override; + + private: + void allocate(VKContext &context); }; } // namespace blender::gpu -- 2.30.2 From 95609c174ed31cc78b331b212db7cf8901229438 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Mon, 13 Feb 2023 09:45:52 +0100 Subject: [PATCH 02/55] Fix missing create info for ssbo test. --- source/blender/gpu/shaders/infos/gpu_shader_test_info.hh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source/blender/gpu/shaders/infos/gpu_shader_test_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_test_info.hh index 1141e915c87..e612c7ebbb1 100644 --- a/source/blender/gpu/shaders/infos/gpu_shader_test_info.hh +++ b/source/blender/gpu/shaders/infos/gpu_shader_test_info.hh @@ -42,6 +42,12 @@ GPU_SHADER_CREATE_INFO(gpu_compute_vbo_test) .compute_source("gpu_compute_vbo_test.glsl") .do_static_compilation(true); +GPU_SHADER_CREATE_INFO(gpu_compute_ssbo_test) + .local_group_size(1) + .storage_buf(0, Qualifier::WRITE, "int", "data_out[]") + .compute_source("gpu_compute_ssbo_test.glsl") + .do_static_compilation(true); + GPU_SHADER_CREATE_INFO(gpu_compute_ssbo_binding_test) .local_group_size(1) .storage_buf(0, Qualifier::WRITE, "int", "data0[]") -- 2.30.2 From 033165476091531a3622caa8e05120a6b7e9416c Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Mon, 13 Feb 2023 13:29:56 +0100 Subject: [PATCH 03/55] Added initial support for index buffers. --- .../blender/gpu/vulkan/vk_descriptor_set.cc | 9 ++++++ .../blender/gpu/vulkan/vk_descriptor_set.hh | 2 ++ source/blender/gpu/vulkan/vk_index_buffer.cc | 31 +++++++++++++++++-- source/blender/gpu/vulkan/vk_index_buffer.hh | 10 ++++++ 4 files changed, 50 insertions(+), 2 deletions(-) diff --git a/source/blender/gpu/vulkan/vk_descriptor_set.cc b/source/blender/gpu/vulkan/vk_descriptor_set.cc index 9b28e3f16c2..5d4c058029f 100644 --- a/source/blender/gpu/vulkan/vk_descriptor_set.cc +++ b/source/blender/gpu/vulkan/vk_descriptor_set.cc @@ -6,6 +6,7 @@ */ #include "vk_descriptor_set.hh" +#include "vk_index_buffer.hh" #include "vk_storage_buffer.hh" #include "vk_vertex_buffer.hh" @@ -44,6 +45,14 @@ void VKDescriptorSet::bind_as_ssbo(VKVertexBuffer &buffer, int location) binding.buffer_size = buffer.size_used_get(); } +void VKDescriptorSet::bind_as_ssbo(VKIndexBuffer &buffer, int location) +{ + Binding &binding = ensure_location(location); + binding.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + binding.vk_buffer = buffer.vk_handle(); + binding.buffer_size = buffer.size_get(); +} + VKDescriptorSet::Binding &VKDescriptorSet::ensure_location(int location) { for (Binding &binding : bindings_) { diff --git a/source/blender/gpu/vulkan/vk_descriptor_set.hh b/source/blender/gpu/vulkan/vk_descriptor_set.hh index ebfa2386095..1e1f6ad3772 100644 --- a/source/blender/gpu/vulkan/vk_descriptor_set.hh +++ b/source/blender/gpu/vulkan/vk_descriptor_set.hh @@ -19,6 +19,7 @@ namespace blender::gpu { class VKStorageBuffer; class VKVertexBuffer; +class VKIndexBuffer; class VKDescriptorSet : NonCopyable { struct Binding { @@ -60,6 +61,7 @@ class VKDescriptorSet : NonCopyable { } void bind_as_ssbo(VKVertexBuffer &buffer, int location); + void bind_as_ssbo(VKIndexBuffer &buffer, int location); void bind(VKStorageBuffer &buffer, int location); /** diff --git a/source/blender/gpu/vulkan/vk_index_buffer.cc b/source/blender/gpu/vulkan/vk_index_buffer.cc index 70387bd0fce..67a50b134d0 100644 --- a/source/blender/gpu/vulkan/vk_index_buffer.cc +++ b/source/blender/gpu/vulkan/vk_index_buffer.cc @@ -6,6 +6,7 @@ */ #include "vk_index_buffer.hh" +#include "vk_shader.hh" namespace blender::gpu { @@ -13,12 +14,28 @@ void VKIndexBuffer::upload_data() { } -void VKIndexBuffer::bind_as_ssbo(uint /*binding*/) +void VKIndexBuffer::bind_as_ssbo(uint binding) { + VKContext &context = *VKContext::get(); + if (!buffer_.is_allocated()) { + allocate(context); + } + + VKShader *shader = static_cast(context.shader); + shader->pipeline_get().descriptor_set_get().bind_as_ssbo(*this, binding); } -void VKIndexBuffer::read(uint32_t * /*data*/) const +void VKIndexBuffer::read(uint32_t *data) const { + VKContext &context = *VKContext::get(); + VKCommandBuffer &command_buffer = context.command_buffer_get(); + command_buffer.submit(); + + void *mapped_memory; + if (buffer_.map(context, &mapped_memory)) { + memcpy(data, mapped_memory, size_get()); + buffer_.unmap(context); + } } void VKIndexBuffer::update_sub(uint /*start*/, uint /*len*/, const void * /*data*/) @@ -29,4 +46,14 @@ void VKIndexBuffer::strip_restart_indices() { } +void VKIndexBuffer::allocate(VKContext &context) +{ + GPUUsageType usage = data_ == nullptr ? GPU_USAGE_DEVICE_ONLY : GPU_USAGE_STATIC; + buffer_.create(context, + size_get(), + usage, + static_cast(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | + VK_BUFFER_USAGE_INDEX_BUFFER_BIT)); +} + } // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_index_buffer.hh b/source/blender/gpu/vulkan/vk_index_buffer.hh index 7586b49ff21..26134f8d390 100644 --- a/source/blender/gpu/vulkan/vk_index_buffer.hh +++ b/source/blender/gpu/vulkan/vk_index_buffer.hh @@ -9,9 +9,13 @@ #include "gpu_index_buffer_private.hh" +#include "vk_buffer.hh" + namespace blender::gpu { class VKIndexBuffer : public IndexBuf { + VKBuffer buffer_; + public: void upload_data() override; @@ -21,8 +25,14 @@ class VKIndexBuffer : public IndexBuf { void update_sub(uint start, uint len, const void *data) override; + VkBuffer vk_handle() + { + return buffer_.vk_handle(); + } + private: void strip_restart_indices() override; + void allocate(VKContext &context); }; } // namespace blender::gpu -- 2.30.2 From 8b6db40cccc5af328201b7f67fbc35accb4ddd75 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Mon, 13 Feb 2023 13:56:26 +0100 Subject: [PATCH 04/55] Use guardedalloc for vulkan allocations. --- source/blender/gpu/vulkan/vk_command_buffer.cc | 7 +++++-- source/blender/gpu/vulkan/vk_context.cc | 3 +++ source/blender/gpu/vulkan/vk_descriptor_pools.cc | 8 ++++++-- source/blender/gpu/vulkan/vk_memory.cc | 4 +++- source/blender/gpu/vulkan/vk_pipeline.cc | 8 ++++++-- source/blender/gpu/vulkan/vk_shader.cc | 14 +++++++++----- 6 files changed, 32 insertions(+), 12 deletions(-) diff --git a/source/blender/gpu/vulkan/vk_command_buffer.cc b/source/blender/gpu/vulkan/vk_command_buffer.cc index 5f80facfe01..1f4cc806ba9 100644 --- a/source/blender/gpu/vulkan/vk_command_buffer.cc +++ b/source/blender/gpu/vulkan/vk_command_buffer.cc @@ -7,6 +7,7 @@ #include "vk_command_buffer.hh" #include "vk_context.hh" +#include "vk_memory.hh" #include "BLI_assert.h" @@ -15,7 +16,8 @@ namespace blender::gpu { VKCommandBuffer::~VKCommandBuffer() { if (vk_device_ != VK_NULL_HANDLE) { - vkDestroyFence(vk_device_, vk_fence_, nullptr); + VK_ALLOCATION_CALLBACKS; + vkDestroyFence(vk_device_, vk_fence_, vk_allocation_callbacks); vk_fence_ = VK_NULL_HANDLE; } } @@ -29,10 +31,11 @@ void VKCommandBuffer::init(const VkDevice vk_device, vk_command_buffer_ = vk_command_buffer; if (vk_fence_ == VK_NULL_HANDLE) { + VK_ALLOCATION_CALLBACKS; VkFenceCreateInfo fenceInfo{}; fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; - vkCreateFence(vk_device_, &fenceInfo, nullptr, &vk_fence_); + vkCreateFence(vk_device_, &fenceInfo, vk_allocation_callbacks, &vk_fence_); } } diff --git a/source/blender/gpu/vulkan/vk_context.cc b/source/blender/gpu/vulkan/vk_context.cc index 4fdf19415bf..3452b52b86e 100644 --- a/source/blender/gpu/vulkan/vk_context.cc +++ b/source/blender/gpu/vulkan/vk_context.cc @@ -8,6 +8,7 @@ #include "vk_context.hh" #include "vk_backend.hh" +#include "vk_memory.hh" #include "vk_state_manager.hh" #include "GHOST_C-api.h" @@ -16,6 +17,7 @@ namespace blender::gpu { VKContext::VKContext(void *ghost_window, void *ghost_context) { + VK_ALLOCATION_CALLBACKS; ghost_window_ = ghost_window; if (ghost_window) { ghost_context = GHOST_GetDrawingContext((GHOST_WindowHandle)ghost_window); @@ -38,6 +40,7 @@ VKContext::VKContext(void *ghost_window, void *ghost_context) info.physicalDevice = vk_physical_device_; info.device = vk_device_; info.instance = vk_instance_; + info.pAllocationCallbacks = vk_allocation_callbacks; vmaCreateAllocator(&info, &mem_allocator_); descriptor_pools_.init(vk_device_); diff --git a/source/blender/gpu/vulkan/vk_descriptor_pools.cc b/source/blender/gpu/vulkan/vk_descriptor_pools.cc index 48d1e7d16e6..e75acd53e4b 100644 --- a/source/blender/gpu/vulkan/vk_descriptor_pools.cc +++ b/source/blender/gpu/vulkan/vk_descriptor_pools.cc @@ -6,6 +6,7 @@ */ #include "vk_descriptor_pools.hh" +#include "vk_memory.hh" namespace blender::gpu { VKDescriptorPools::VKDescriptorPools() @@ -14,9 +15,10 @@ VKDescriptorPools::VKDescriptorPools() VKDescriptorPools::~VKDescriptorPools() { + VK_ALLOCATION_CALLBACKS for (const VkDescriptorPool vk_descriptor_pool : pools_) { BLI_assert(vk_device_ != VK_NULL_HANDLE); - vkDestroyDescriptorPool(vk_device_, vk_descriptor_pool, nullptr); + vkDestroyDescriptorPool(vk_device_, vk_descriptor_pool, vk_allocation_callbacks); } vk_device_ = VK_NULL_HANDLE; } @@ -35,6 +37,7 @@ void VKDescriptorPools::reset() void VKDescriptorPools::add_new_pool() { + VK_ALLOCATION_CALLBACKS Vector pool_sizes = { {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, POOL_SIZE_UNIFORM_BUFFER}, {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, POOL_SIZE_STORAGE_BUFFER}, @@ -46,7 +49,8 @@ void VKDescriptorPools::add_new_pool() pool_info.poolSizeCount = pool_sizes.size(); pool_info.pPoolSizes = pool_sizes.data(); VkDescriptorPool descriptor_pool = VK_NULL_HANDLE; - VkResult result = vkCreateDescriptorPool(vk_device_, &pool_info, nullptr, &descriptor_pool); + VkResult result = vkCreateDescriptorPool( + vk_device_, &pool_info, vk_allocation_callbacks, &descriptor_pool); UNUSED_VARS(result); pools_.append(descriptor_pool); } diff --git a/source/blender/gpu/vulkan/vk_memory.cc b/source/blender/gpu/vulkan/vk_memory.cc index e02ca0b014f..87a4d78d66b 100644 --- a/source/blender/gpu/vulkan/vk_memory.cc +++ b/source/blender/gpu/vulkan/vk_memory.cc @@ -37,7 +37,9 @@ void *vk_memory_reallocation(void *user_data, void vk_memory_free(void * /*user_data*/, void *memory) { - MEM_freeN(memory); + if (memory != nullptr) { + MEM_freeN(memory); + } } #endif diff --git a/source/blender/gpu/vulkan/vk_pipeline.cc b/source/blender/gpu/vulkan/vk_pipeline.cc index c6174536366..7df78597e50 100644 --- a/source/blender/gpu/vulkan/vk_pipeline.cc +++ b/source/blender/gpu/vulkan/vk_pipeline.cc @@ -7,6 +7,7 @@ #include "vk_pipeline.hh" #include "vk_context.hh" +#include "vk_memory.hh" namespace blender::gpu { @@ -18,9 +19,10 @@ VKPipeline::VKPipeline(VkPipeline vk_pipeline, VKDescriptorSet &&vk_descriptor_s VKPipeline::~VKPipeline() { + VK_ALLOCATION_CALLBACKS VkDevice vk_device = VKContext::get()->device_get(); if (vk_pipeline_ != VK_NULL_HANDLE) { - vkDestroyPipeline(vk_device, vk_pipeline_, nullptr); + vkDestroyPipeline(vk_device, vk_pipeline_, vk_allocation_callbacks); } } @@ -29,6 +31,7 @@ VKPipeline VKPipeline::create_compute_pipeline(VKContext &context, VkDescriptorSetLayout &descriptor_set_layout, VkPipelineLayout &pipeline_layout) { + VK_ALLOCATION_CALLBACKS VkDevice vk_device = context.device_get(); VkComputePipelineCreateInfo pipeline_info = {}; pipeline_info.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; @@ -42,7 +45,8 @@ VKPipeline VKPipeline::create_compute_pipeline(VKContext &context, pipeline_info.stage.pName = "main"; VkPipeline pipeline; - if (vkCreateComputePipelines(vk_device, nullptr, 1, &pipeline_info, nullptr, &pipeline) != + if (vkCreateComputePipelines( + vk_device, nullptr, 1, &pipeline_info, vk_allocation_callbacks, &pipeline) != VK_SUCCESS) { return VKPipeline(); } diff --git a/source/blender/gpu/vulkan/vk_shader.cc b/source/blender/gpu/vulkan/vk_shader.cc index 6ea97124cab..7572f15f265 100644 --- a/source/blender/gpu/vulkan/vk_shader.cc +++ b/source/blender/gpu/vulkan/vk_shader.cc @@ -605,11 +605,11 @@ VKShader::~VKShader() compute_module_ = VK_NULL_HANDLE; } if (pipeline_layout_ != VK_NULL_HANDLE) { - vkDestroyPipelineLayout(device, pipeline_layout_, nullptr); + vkDestroyPipelineLayout(device, pipeline_layout_, vk_allocation_callbacks); pipeline_layout_ = VK_NULL_HANDLE; } if (layout_ != VK_NULL_HANDLE) { - vkDestroyDescriptorSetLayout(device, layout_, nullptr); + vkDestroyDescriptorSetLayout(device, layout_, vk_allocation_callbacks); layout_ = VK_NULL_HANDLE; } } @@ -723,14 +723,15 @@ bool VKShader::finalize_graphics_pipeline(VkDevice /*vk_device */) bool VKShader::finalize_pipeline_layout(VkDevice vk_device, const shader::ShaderCreateInfo & /*info*/) { + VK_ALLOCATION_CALLBACKS VkPipelineLayoutCreateInfo pipeline_info = {}; pipeline_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipeline_info.flags = 0; pipeline_info.setLayoutCount = 1; pipeline_info.pSetLayouts = &layout_; - if (vkCreatePipelineLayout(vk_device, &pipeline_info, nullptr, &pipeline_layout_) != - VK_SUCCESS) { + if (vkCreatePipelineLayout( + vk_device, &pipeline_info, vk_allocation_callbacks, &pipeline_layout_) != VK_SUCCESS) { return false; }; @@ -797,6 +798,8 @@ bool VKShader::finalize_descriptor_set_layouts(VkDevice vk_device, return true; } + VK_ALLOCATION_CALLBACKS + /* Currently we create a single descriptor set. The goal would be to create one descriptor set * for Frequency::PASS/BATCH. This isn't possible as areas expect that the binding location is * static and predictable (eevee-next) or the binding location can be mapped to a single number @@ -808,7 +811,8 @@ bool VKShader::finalize_descriptor_set_layouts(VkDevice vk_device, Vector bindings; VkDescriptorSetLayoutCreateInfo layout_info = create_descriptor_set_layout(all_resources, bindings); - if (vkCreateDescriptorSetLayout(vk_device, &layout_info, nullptr, &layout_) != VK_SUCCESS) { + if (vkCreateDescriptorSetLayout(vk_device, &layout_info, vk_allocation_callbacks, &layout_) != + VK_SUCCESS) { return false; }; -- 2.30.2 From 319c79128dc18e5c08f0ce4d5fda77b9982960dd Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Mon, 13 Feb 2023 14:24:55 +0100 Subject: [PATCH 05/55] Fix ssbo name change during merge. --- source/blender/gpu/tests/gpu_shader_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/gpu/tests/gpu_shader_test.cc b/source/blender/gpu/tests/gpu_shader_test.cc index 250e1c343cb..cbbee0192a1 100644 --- a/source/blender/gpu/tests/gpu_shader_test.cc +++ b/source/blender/gpu/tests/gpu_shader_test.cc @@ -228,7 +228,7 @@ static void test_gpu_shader_compute_ssbo() /* Construct IBO. */ GPUStorageBuf *ssbo = GPU_storagebuf_create_ex( SIZE * sizeof(uint32_t), nullptr, GPU_USAGE_DEVICE_ONLY, __func__); - GPU_storagebuf_bind(ssbo, GPU_shader_get_ssbo_binding(shader, "out_indices")); + GPU_storagebuf_bind(ssbo, GPU_shader_get_ssbo_binding(shader, "data_out")); /* Dispatch compute task. */ GPU_compute_dispatch(shader, SIZE, 1, 1); -- 2.30.2 From afa2d25db0b44ccacd7fa13e1b4b932fd05c8ab9 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Mon, 13 Feb 2023 16:08:55 +0100 Subject: [PATCH 06/55] Added 1d texture, bind as image. Descriptor sets still needs to be updated. --- .../blender/gpu/vulkan/vk_descriptor_pools.cc | 2 +- .../blender/gpu/vulkan/vk_descriptor_pools.hh | 2 +- .../blender/gpu/vulkan/vk_descriptor_set.cc | 5 + .../blender/gpu/vulkan/vk_descriptor_set.hh | 2 + source/blender/gpu/vulkan/vk_shader.cc | 2 +- .../blender/gpu/vulkan/vk_shader_interface.cc | 16 ++- source/blender/gpu/vulkan/vk_state_manager.cc | 5 +- source/blender/gpu/vulkan/vk_texture.cc | 126 +++++++++++++++++- source/blender/gpu/vulkan/vk_texture.hh | 21 +++ 9 files changed, 175 insertions(+), 6 deletions(-) diff --git a/source/blender/gpu/vulkan/vk_descriptor_pools.cc b/source/blender/gpu/vulkan/vk_descriptor_pools.cc index e75acd53e4b..0caadf61567 100644 --- a/source/blender/gpu/vulkan/vk_descriptor_pools.cc +++ b/source/blender/gpu/vulkan/vk_descriptor_pools.cc @@ -39,8 +39,8 @@ void VKDescriptorPools::add_new_pool() { VK_ALLOCATION_CALLBACKS Vector pool_sizes = { - {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, POOL_SIZE_UNIFORM_BUFFER}, {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, POOL_SIZE_STORAGE_BUFFER}, + {VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, POOL_SIZE_STORAGE_IMAGE}, }; VkDescriptorPoolCreateInfo pool_info = {}; pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; diff --git a/source/blender/gpu/vulkan/vk_descriptor_pools.hh b/source/blender/gpu/vulkan/vk_descriptor_pools.hh index 3b071c140f7..2d37cb237f2 100644 --- a/source/blender/gpu/vulkan/vk_descriptor_pools.hh +++ b/source/blender/gpu/vulkan/vk_descriptor_pools.hh @@ -36,9 +36,9 @@ class VKDescriptorPools { * * Better defaults should be set later on, when we know more about our resource usage. */ - static constexpr uint32_t POOL_SIZE_UNIFORM_BUFFER = 1000; static constexpr uint32_t POOL_SIZE_STORAGE_BUFFER = 1000; static constexpr uint32_t POOL_SIZE_DESCRIPTOR_SETS = 1000; + static constexpr uint32_t POOL_SIZE_STORAGE_IMAGE = 1000; VkDevice vk_device_ = VK_NULL_HANDLE; Vector pools_; diff --git a/source/blender/gpu/vulkan/vk_descriptor_set.cc b/source/blender/gpu/vulkan/vk_descriptor_set.cc index 5d4c058029f..5d719c16007 100644 --- a/source/blender/gpu/vulkan/vk_descriptor_set.cc +++ b/source/blender/gpu/vulkan/vk_descriptor_set.cc @@ -8,6 +8,7 @@ #include "vk_descriptor_set.hh" #include "vk_index_buffer.hh" #include "vk_storage_buffer.hh" +#include "vk_texture.hh" #include "vk_vertex_buffer.hh" #include "BLI_assert.h" @@ -53,6 +54,10 @@ void VKDescriptorSet::bind_as_ssbo(VKIndexBuffer &buffer, int location) binding.buffer_size = buffer.size_get(); } +void VKDescriptorSet::image_bind(VKTexture &texture, int location) +{ +} + VKDescriptorSet::Binding &VKDescriptorSet::ensure_location(int location) { for (Binding &binding : bindings_) { diff --git a/source/blender/gpu/vulkan/vk_descriptor_set.hh b/source/blender/gpu/vulkan/vk_descriptor_set.hh index 1e1f6ad3772..1dd20b4924d 100644 --- a/source/blender/gpu/vulkan/vk_descriptor_set.hh +++ b/source/blender/gpu/vulkan/vk_descriptor_set.hh @@ -20,6 +20,7 @@ namespace blender::gpu { class VKStorageBuffer; class VKVertexBuffer; class VKIndexBuffer; +class VKTexture; class VKDescriptorSet : NonCopyable { struct Binding { @@ -63,6 +64,7 @@ class VKDescriptorSet : NonCopyable { void bind_as_ssbo(VKVertexBuffer &buffer, int location); void bind_as_ssbo(VKIndexBuffer &buffer, int location); void bind(VKStorageBuffer &buffer, int location); + void image_bind(VKTexture &texture, int location); /** * Update the descriptor set on the device. diff --git a/source/blender/gpu/vulkan/vk_shader.cc b/source/blender/gpu/vulkan/vk_shader.cc index 7572f15f265..11a37b3ceea 100644 --- a/source/blender/gpu/vulkan/vk_shader.cc +++ b/source/blender/gpu/vulkan/vk_shader.cc @@ -743,7 +743,7 @@ static VkDescriptorType descriptor_type( { switch (bind_type) { case shader::ShaderCreateInfo::Resource::BindType::IMAGE: - return VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; case shader::ShaderCreateInfo::Resource::BindType::SAMPLER: return VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; case shader::ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER: diff --git a/source/blender/gpu/vulkan/vk_shader_interface.cc b/source/blender/gpu/vulkan/vk_shader_interface.cc index 00dbbf7820d..b0b47e3a4c3 100644 --- a/source/blender/gpu/vulkan/vk_shader_interface.cc +++ b/source/blender/gpu/vulkan/vk_shader_interface.cc @@ -13,6 +13,7 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) { using namespace blender::gpu::shader; + uniform_len_ = 0; ssbo_len_ = 0; Vector all_resources; @@ -22,6 +23,8 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) for (ShaderCreateInfo::Resource &res : all_resources) { switch (res.bind_type) { case ShaderCreateInfo::Resource::BindType::IMAGE: + uniform_len_++; + break; case ShaderCreateInfo::Resource::BindType::SAMPLER: case ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER: // BLI_assert_msg(false, "not implemented yet"); @@ -32,14 +35,25 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) } } - int32_t input_tot_len = ssbo_len_; + int32_t input_tot_len = ssbo_len_ + uniform_len_; inputs_ = static_cast( MEM_calloc_arrayN(input_tot_len, sizeof(ShaderInput), __func__)); ShaderInput *input = inputs_; name_buffer_ = (char *)MEM_mallocN(info.interface_names_size_, "name_buffer"); uint32_t name_buffer_offset = 0; + /* Images */ + /* NOTE: should be extended with uniforms and samplers.*/ + for (const ShaderCreateInfo::Resource &res : all_resources) { + if (res.bind_type == ShaderCreateInfo::Resource::BindType::IMAGE) { + copy_input_name(input, res.image.name, name_buffer_, name_buffer_offset); + input->location = input->binding = res.slot; + enabled_ima_mask_ |= (1 << input->binding); + input++; + } + } + /* Storage buffers */ for (const ShaderCreateInfo::Resource &res : all_resources) { if (res.bind_type == ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER) { copy_input_name(input, res.storagebuf.name, name_buffer_, name_buffer_offset); diff --git a/source/blender/gpu/vulkan/vk_state_manager.cc b/source/blender/gpu/vulkan/vk_state_manager.cc index 3bde798e5e9..7eb80ef27e3 100644 --- a/source/blender/gpu/vulkan/vk_state_manager.cc +++ b/source/blender/gpu/vulkan/vk_state_manager.cc @@ -6,6 +6,7 @@ */ #include "vk_state_manager.hh" +#include "vk_texture.hh" namespace blender::gpu { void VKStateManager::apply_state() @@ -32,8 +33,10 @@ void VKStateManager::texture_unbind_all() { } -void VKStateManager::image_bind(Texture * /*tex*/, int /*unit*/) +void VKStateManager::image_bind(Texture *tex, int binding) { + VKTexture *texture = unwrap(tex); + texture->image_bind(binding); } void VKStateManager::image_unbind(Texture * /*tex*/) diff --git a/source/blender/gpu/vulkan/vk_texture.cc b/source/blender/gpu/vulkan/vk_texture.cc index 3215268b7bc..4cbd0c8d57b 100644 --- a/source/blender/gpu/vulkan/vk_texture.cc +++ b/source/blender/gpu/vulkan/vk_texture.cc @@ -7,8 +7,17 @@ #include "vk_texture.hh" +#include "vk_context.hh" +#include "vk_shader.hh" + namespace blender::gpu { +VKTexture::~VKTexture() +{ + VKContext &context = *VKContext::get(); + vmaDestroyImage(context.mem_allocator_get(), vk_image_, allocation_); +} + void VKTexture::generate_mipmap() { } @@ -59,9 +68,73 @@ uint VKTexture::gl_bindcode_get() const return 0; } +static VkFormat to_vk_format(const eGPUTextureFormat format) +{ + switch (format) { + case GPU_RGBA32F: + return VK_FORMAT_R32G32B32A32_SFLOAT; + case GPU_RGBA8UI: + case GPU_RGBA8I: + case GPU_RGBA8: + case GPU_RGBA32UI: + case GPU_RGBA32I: + case GPU_RGBA16UI: + case GPU_RGBA16I: + case GPU_RGBA16F: + case GPU_RGBA16: + case GPU_RG8UI: + case GPU_RG8I: + case GPU_RG8: + case GPU_RG32UI: + case GPU_RG32I: + case GPU_RG32F: + case GPU_RG16UI: + case GPU_RG16I: + case GPU_RG16F: + case GPU_RG16: + case GPU_R8UI: + case GPU_R8I: + case GPU_R8: + case GPU_R32UI: + case GPU_R32I: + case GPU_R32F: + case GPU_R16UI: + case GPU_R16I: + case GPU_R16F: + case GPU_R16: + + /* + case GPU_RGB10_A2: + case GPU_R11F_G11F_B10F: + case GPU_DEPTH32F_STENCIL8: + case GPU_DEPTH24_STENCIL8: + case GPU_SRGB8_A8:*/ + + /* Texture only format */ + case GPU_RGB16F: + + /* Special formats texture only */ + case GPU_SRGB8_A8_DXT1: + case GPU_SRGB8_A8_DXT3: + case GPU_SRGB8_A8_DXT5: + case GPU_RGBA8_DXT1: + case GPU_RGBA8_DXT3: + case GPU_RGBA8_DXT5: + + /* Depth Formats */ + case GPU_DEPTH_COMPONENT32F: + case GPU_DEPTH_COMPONENT24: + case GPU_DEPTH_COMPONENT16: + default: + BLI_assert_unreachable(); + } + return VK_FORMAT_UNDEFINED; +} + bool VKTexture::init_internal() { - return false; + /* TODO: add some pre-initialization to reduce some work later on.*/ + return true; } bool VKTexture::init_internal(GPUVertBuf * /*vbo*/) @@ -74,4 +147,55 @@ bool VKTexture::init_internal(const GPUTexture * /*src*/, int /*mip_offset*/, in return false; } +bool VKTexture::is_allocated() +{ + return vk_image_ != VK_NULL_HANDLE && allocation_ != VK_NULL_HANDLE; +} + +bool VKTexture::allocate() +{ + BLI_assert(!is_allocated()); + + VKContext &context = *VKContext::get(); + VkImageCreateInfo imgCreateInfo = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO}; + imgCreateInfo.imageType = VK_IMAGE_TYPE_1D; + imgCreateInfo.extent.width = width_get(); + imgCreateInfo.extent.height = 1; + imgCreateInfo.extent.depth = 1; + imgCreateInfo.mipLevels = 1; + imgCreateInfo.arrayLayers = 1; + imgCreateInfo.format = to_vk_format(format_); + imgCreateInfo.tiling = VK_IMAGE_TILING_LINEAR; + imgCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imgCreateInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT; + imgCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; + + VmaAllocationCreateInfo allocCreateInfo = {}; + allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO; + allocCreateInfo.flags = static_cast( + VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT); + allocCreateInfo.priority = 1.0f; + + VkResult result = vmaCreateImage(context.mem_allocator_get(), + &imgCreateInfo, + &allocCreateInfo, + &vk_image_, + &allocation_, + nullptr); + if (result != VK_SUCCESS) { + return false; + } + return true; +} + +void VKTexture::image_bind(int location) +{ + if (!is_allocated()) { + allocate(); + } + VKContext &context = *VKContext::get(); + VKShader *shader = static_cast(context.shader); + shader->pipeline_get().descriptor_set_get().image_bind(*this, location); +} + } // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_texture.hh b/source/blender/gpu/vulkan/vk_texture.hh index 087c4ca8a9a..4f628961f4c 100644 --- a/source/blender/gpu/vulkan/vk_texture.hh +++ b/source/blender/gpu/vulkan/vk_texture.hh @@ -8,14 +8,19 @@ #pragma once #include "gpu_texture_private.hh" +#include "vk_context.hh" namespace blender::gpu { class VKTexture : public Texture { + VkImage vk_image_ = VK_NULL_HANDLE; + VmaAllocation allocation_ = VK_NULL_HANDLE; + public: VKTexture(const char *name) : Texture(name) { } + virtual ~VKTexture() override; void generate_mipmap() override; void copy_to(Texture *tex) override; @@ -34,10 +39,26 @@ class VKTexture : public Texture { /* TODO(fclem): Legacy. Should be removed at some point. */ uint gl_bindcode_get() const override; + void image_bind(int location); + protected: bool init_internal() override; bool init_internal(GPUVertBuf *vbo) override; bool init_internal(const GPUTexture *src, int mip_offset, int layer_offset) override; + + private: + /** Is this texture already allocated on device.*/ + bool is_allocated(); + /** + * Allocate the texture of the device. Result is `true` when texture is successfully allocated + * on the device. + */ + bool allocate(); }; +static inline VKTexture *unwrap(Texture *tex) +{ + return static_cast(tex); +} + } // namespace blender::gpu -- 2.30.2 From fda61f18d12cc8e3678dc6752acb4b73375c574b Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Tue, 14 Feb 2023 12:38:20 +0100 Subject: [PATCH 07/55] Add support for 1d textures. --- source/blender/gpu/vulkan/vk_buffer.hh | 6 +- .../blender/gpu/vulkan/vk_command_buffer.cc | 43 ++++ .../blender/gpu/vulkan/vk_command_buffer.hh | 7 + source/blender/gpu/vulkan/vk_context.cc | 2 + .../blender/gpu/vulkan/vk_descriptor_set.cc | 30 ++- .../blender/gpu/vulkan/vk_descriptor_set.hh | 17 +- source/blender/gpu/vulkan/vk_state_manager.cc | 5 + source/blender/gpu/vulkan/vk_texture.cc | 210 ++++++++++++++++-- source/blender/gpu/vulkan/vk_texture.hh | 13 ++ 9 files changed, 307 insertions(+), 26 deletions(-) diff --git a/source/blender/gpu/vulkan/vk_buffer.hh b/source/blender/gpu/vulkan/vk_buffer.hh index ecfe176f9b8..174bebade3e 100644 --- a/source/blender/gpu/vulkan/vk_buffer.hh +++ b/source/blender/gpu/vulkan/vk_buffer.hh @@ -16,6 +16,8 @@ # include #endif +#include "vk_mem_alloc.h" + namespace blender::gpu { /** @@ -40,8 +42,8 @@ class VKBuffer { bool update(VKContext &context, const void *data); // TODO: add partial_update (update_sub) bool free(VKContext &context); - bool map(VKContext &context, void **r_mapped_memory)const; - void unmap(VKContext &context)const ; + bool map(VKContext &context, void **r_mapped_memory) const; + void unmap(VKContext &context) const; int64_t size_in_bytes() const { diff --git a/source/blender/gpu/vulkan/vk_command_buffer.cc b/source/blender/gpu/vulkan/vk_command_buffer.cc index 1f4cc806ba9..70386e8c5ed 100644 --- a/source/blender/gpu/vulkan/vk_command_buffer.cc +++ b/source/blender/gpu/vulkan/vk_command_buffer.cc @@ -6,8 +6,10 @@ */ #include "vk_command_buffer.hh" +#include "vk_buffer.hh" #include "vk_context.hh" #include "vk_memory.hh" +#include "vk_texture.hh" #include "BLI_assert.h" @@ -68,6 +70,47 @@ void VKCommandBuffer::bind(const VKDescriptorSet &descriptor_set, vk_command_buffer_, bind_point, vk_pipeline_layout, 0, 1, &vk_descriptor_set, 0, 0); } +void VKCommandBuffer::copy(VKBuffer &dst_buffer, + VKTexture &src_texture, + Span regions) +{ + vkCmdCopyImageToBuffer(vk_command_buffer_, + src_texture.vk_image_handle(), + VK_IMAGE_LAYOUT_GENERAL, + dst_buffer.vk_handle(), + regions.size(), + regions.data()); +} + +void VKCommandBuffer::pipeline_barrier(VkPipelineStageFlags source_stages, + VkPipelineStageFlags destination_stages) +{ + vkCmdPipelineBarrier(vk_command_buffer_, + source_stages, + destination_stages, + 0, + 0, + nullptr, + 0, + nullptr, + 0, + nullptr); +} + +void VKCommandBuffer::pipeline_barrier(Span image_memory_barriers) +{ + vkCmdPipelineBarrier(vk_command_buffer_, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_DEPENDENCY_BY_REGION_BIT, + 0, + nullptr, + 0, + nullptr, + image_memory_barriers.size(), + image_memory_barriers.data()); +} + void VKCommandBuffer::dispatch(int groups_x_len, int groups_y_len, int groups_z_len) { vkCmdDispatch(vk_command_buffer_, groups_x_len, groups_y_len, groups_z_len); diff --git a/source/blender/gpu/vulkan/vk_command_buffer.hh b/source/blender/gpu/vulkan/vk_command_buffer.hh index 97bf644b8f3..325f030ba77 100644 --- a/source/blender/gpu/vulkan/vk_command_buffer.hh +++ b/source/blender/gpu/vulkan/vk_command_buffer.hh @@ -16,6 +16,8 @@ #include "vk_pipeline.hh" namespace blender::gpu { +class VKBuffer; +class VKTexture; /** Command buffer to keep track of the life-time of a command buffer.*/ class VKCommandBuffer : NonCopyable, NonMovable { @@ -37,6 +39,11 @@ class VKCommandBuffer : NonCopyable, NonMovable { const VkPipelineLayout vk_pipeline_layout, VkPipelineBindPoint bind_point); void dispatch(int groups_x_len, int groups_y_len, int groups_z_len); + /* Copy the contents of a texture mip level to the dst buffer.*/ + void copy(VKBuffer &dst_buffer, VKTexture &src_texture, Span regions); + void pipeline_barrier(VkPipelineStageFlags source_stages, + VkPipelineStageFlags destination_stages); + void pipeline_barrier(Span image_memory_barriers); /** * Stop recording commands, encode + send the recordings to Vulkan, wait for the until the diff --git a/source/blender/gpu/vulkan/vk_context.cc b/source/blender/gpu/vulkan/vk_context.cc index 3452b52b86e..4a5e67259d3 100644 --- a/source/blender/gpu/vulkan/vk_context.cc +++ b/source/blender/gpu/vulkan/vk_context.cc @@ -79,10 +79,12 @@ void VKContext::end_frame() void VKContext::flush() { + command_buffer_.submit(); } void VKContext::finish() { + command_buffer_.submit(); } void VKContext::memory_statistics_get(int * /*total_mem*/, int * /*free_mem*/) diff --git a/source/blender/gpu/vulkan/vk_descriptor_set.cc b/source/blender/gpu/vulkan/vk_descriptor_set.cc index 5d719c16007..e82d5a897f2 100644 --- a/source/blender/gpu/vulkan/vk_descriptor_set.cc +++ b/source/blender/gpu/vulkan/vk_descriptor_set.cc @@ -56,6 +56,9 @@ void VKDescriptorSet::bind_as_ssbo(VKIndexBuffer &buffer, int location) void VKDescriptorSet::image_bind(VKTexture &texture, int location) { + Binding &binding = ensure_location(location); + binding.type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + binding.vk_image_view = texture.vk_image_view_handle(); } VKDescriptorSet::Binding &VKDescriptorSet::ensure_location(int location) @@ -66,9 +69,7 @@ VKDescriptorSet::Binding &VKDescriptorSet::ensure_location(int location) } } - Binding binding; - binding.vk_buffer = VK_NULL_HANDLE; - binding.buffer_size = 0; + Binding binding = {}; binding.location = location; bindings_.append(binding); return bindings_.last(); @@ -78,7 +79,11 @@ void VKDescriptorSet::update(VkDevice vk_device) { Vector buffer_infos; Vector descriptor_writes; + for (const Binding &binding : bindings_) { + if (!binding.is_buffer()) { + continue; + } VkDescriptorBufferInfo buffer_info = {}; buffer_info.buffer = binding.vk_buffer; buffer_info.range = binding.buffer_size; @@ -91,7 +96,26 @@ void VKDescriptorSet::update(VkDevice vk_device) write_descriptor.descriptorCount = 1; write_descriptor.descriptorType = binding.type; write_descriptor.pBufferInfo = &buffer_infos.last(); + descriptor_writes.append(write_descriptor); + } + Vector image_infos; + for (const Binding &binding : bindings_) { + if (!binding.is_image()) { + continue; + } + VkDescriptorImageInfo image_info = {}; + image_info.imageView = binding.vk_image_view; + image_info.imageLayout = VK_IMAGE_LAYOUT_GENERAL; + image_infos.append(image_info); + + VkWriteDescriptorSet write_descriptor = {}; + write_descriptor.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write_descriptor.dstSet = vk_descriptor_set_; + write_descriptor.dstBinding = binding.location; + write_descriptor.descriptorCount = 1; + write_descriptor.descriptorType = binding.type; + write_descriptor.pImageInfo = &image_infos.last(); descriptor_writes.append(write_descriptor); } diff --git a/source/blender/gpu/vulkan/vk_descriptor_set.hh b/source/blender/gpu/vulkan/vk_descriptor_set.hh index 1dd20b4924d..e9c2bcd446c 100644 --- a/source/blender/gpu/vulkan/vk_descriptor_set.hh +++ b/source/blender/gpu/vulkan/vk_descriptor_set.hh @@ -24,10 +24,23 @@ class VKTexture; class VKDescriptorSet : NonCopyable { struct Binding { - int location; + int location = -1; VkDescriptorType type; + VkBuffer vk_buffer = VK_NULL_HANDLE; - VkDeviceSize buffer_size; + VkDeviceSize buffer_size = 0; + + VkImageView vk_image_view = VK_NULL_HANDLE; + + bool is_buffer() const + { + return ELEM(type, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + } + + bool is_image() const + { + return ELEM(type, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE); + } }; VkDescriptorPool vk_descriptor_pool_ = VK_NULL_HANDLE; diff --git a/source/blender/gpu/vulkan/vk_state_manager.cc b/source/blender/gpu/vulkan/vk_state_manager.cc index 7eb80ef27e3..4e6eb3298bd 100644 --- a/source/blender/gpu/vulkan/vk_state_manager.cc +++ b/source/blender/gpu/vulkan/vk_state_manager.cc @@ -19,6 +19,11 @@ void VKStateManager::force_state() void VKStateManager::issue_barrier(eGPUBarrier /*barrier_bits*/) { + VKContext &context = *VKContext::get(); + VKCommandBuffer &command_buffer = context.command_buffer_get(); + /* TODO: Pipeline barriers should be added. We might be able to extract it from + * the actual pipeline, later on, but for now we submit the work as barrier. */ + command_buffer.submit(); } void VKStateManager::texture_bind(Texture * /*tex*/, eGPUSamplerState /*sampler*/, int /*unit*/) diff --git a/source/blender/gpu/vulkan/vk_texture.cc b/source/blender/gpu/vulkan/vk_texture.cc index 4cbd0c8d57b..ed13ba758bb 100644 --- a/source/blender/gpu/vulkan/vk_texture.cc +++ b/source/blender/gpu/vulkan/vk_texture.cc @@ -7,15 +7,81 @@ #include "vk_texture.hh" +#include "vk_buffer.hh" #include "vk_context.hh" +#include "vk_memory.hh" #include "vk_shader.hh" namespace blender::gpu { +static VkImageAspectFlagBits to_vk_image_aspect_flag_bits(const eGPUTextureFormat format) +{ + switch (format) { + case GPU_RGBA32F: + case GPU_RGBA8UI: + case GPU_RGBA8I: + case GPU_RGBA8: + case GPU_RGBA32UI: + case GPU_RGBA32I: + case GPU_RGBA16UI: + case GPU_RGBA16I: + case GPU_RGBA16F: + case GPU_RGBA16: + case GPU_RG8UI: + case GPU_RG8I: + case GPU_RG8: + case GPU_RG32UI: + case GPU_RG32I: + case GPU_RG32F: + case GPU_RG16UI: + case GPU_RG16I: + case GPU_RG16F: + case GPU_RG16: + case GPU_R8UI: + case GPU_R8I: + case GPU_R8: + case GPU_R32UI: + case GPU_R32I: + case GPU_R32F: + case GPU_R16UI: + case GPU_R16I: + case GPU_R16F: + case GPU_R16: + case GPU_RGB10_A2: + case GPU_R11F_G11F_B10F: + case GPU_SRGB8_A8: + case GPU_RGB16F: + case GPU_SRGB8_A8_DXT1: + case GPU_SRGB8_A8_DXT3: + case GPU_SRGB8_A8_DXT5: + case GPU_RGBA8_DXT1: + case GPU_RGBA8_DXT3: + case GPU_RGBA8_DXT5: + return VK_IMAGE_ASPECT_COLOR_BIT; + + case GPU_DEPTH32F_STENCIL8: + case GPU_DEPTH24_STENCIL8: + return static_cast(VK_IMAGE_ASPECT_DEPTH_BIT | + VK_IMAGE_ASPECT_STENCIL_BIT); + + case GPU_DEPTH_COMPONENT24: + case GPU_DEPTH_COMPONENT16: + return VK_IMAGE_ASPECT_DEPTH_BIT; + + case GPU_DEPTH_COMPONENT32F: + /* Not supported by Vulkan*/ + BLI_assert_unreachable(); + } + return static_cast(0); +} + VKTexture::~VKTexture() { + VK_ALLOCATION_CALLBACKS + VKContext &context = *VKContext::get(); vmaDestroyImage(context.mem_allocator_get(), vk_image_, allocation_); + vkDestroyImageView(context.device_get(), vk_image_view_, vk_allocation_callbacks); } void VKTexture::generate_mipmap() @@ -42,9 +108,49 @@ void VKTexture::mip_range_set(int /*min*/, int /*max*/) { } -void *VKTexture::read(int /*mip*/, eGPUDataFormat /*format*/) +void *VKTexture::read(int mip, eGPUDataFormat format) { - return nullptr; + /* Vulkan images cannot be directly mapped to host memory and requires a staging buffer.*/ + VKContext &context = *VKContext::get(); + VKBuffer staging_buffer; + + /* NOTE: mip_size_get() won't override any dimension that is equal to 0. */ + int extent[3] = {1, 1, 1}; + mip_size_get(mip, extent); + size_t sample_len = extent[0] * extent[1] * extent[2]; + /* NOTE: to_bytesize returns number of bits. */ + size_t device_memory_size = sample_len * to_component_len(format_) * to_bytesize(format_) / 8; + /* NOTE: to_bytesize returns number of bytes here. */ + size_t host_memory_size = sample_len * to_bytesize(format_, format); + + staging_buffer.create( + context, device_memory_size, GPU_USAGE_DEVICE_ONLY, VK_BUFFER_USAGE_TRANSFER_DST_BIT); + + VkBufferImageCopy region = {}; + region.imageExtent.width = extent[0]; + region.imageExtent.height = extent[1]; + region.imageExtent.depth = extent[2]; + region.imageSubresource.aspectMask = to_vk_image_aspect_flag_bits(format_); + region.imageSubresource.mipLevel = mip; + region.imageSubresource.layerCount = 1; + + VKCommandBuffer &command_buffer = context.command_buffer_get(); + command_buffer.copy(staging_buffer, *this, Span(®ion, 1)); + command_buffer.submit(); + + void *mapped_data; + staging_buffer.map(context, &mapped_data); + + void *data = MEM_mallocN(host_memory_size, __func__); + + /* TODO: add conversion when data format is different.*/ + BLI_assert_msg(device_memory_size == host_memory_size, + "Memory data conversions not implemented yet"); + + memcpy(data, mapped_data, host_memory_size); + staging_buffer.unmap(context); + + return data; } void VKTexture::update_sub(int /*mip*/, @@ -103,12 +209,11 @@ static VkFormat to_vk_format(const eGPUTextureFormat format) case GPU_R16F: case GPU_R16: - /* case GPU_RGB10_A2: case GPU_R11F_G11F_B10F: case GPU_DEPTH32F_STENCIL8: case GPU_DEPTH24_STENCIL8: - case GPU_SRGB8_A8:*/ + case GPU_SRGB8_A8: /* Texture only format */ case GPU_RGB16F: @@ -125,7 +230,6 @@ static VkFormat to_vk_format(const eGPUTextureFormat format) case GPU_DEPTH_COMPONENT32F: case GPU_DEPTH_COMPONENT24: case GPU_DEPTH_COMPONENT16: - default: BLI_assert_unreachable(); } return VK_FORMAT_UNDEFINED; @@ -152,23 +256,66 @@ bool VKTexture::is_allocated() return vk_image_ != VK_NULL_HANDLE && allocation_ != VK_NULL_HANDLE; } +static VkImageViewType to_vk_image_view_type(const eGPUTextureType type) +{ + switch (type) { + case GPU_TEXTURE_1D: + case GPU_TEXTURE_BUFFER: + return VK_IMAGE_VIEW_TYPE_1D; + case GPU_TEXTURE_2D: + return VK_IMAGE_VIEW_TYPE_2D; + case GPU_TEXTURE_3D: + return VK_IMAGE_VIEW_TYPE_3D; + case GPU_TEXTURE_CUBE: + return VK_IMAGE_VIEW_TYPE_CUBE; + case GPU_TEXTURE_1D_ARRAY: + return VK_IMAGE_VIEW_TYPE_1D_ARRAY; + case GPU_TEXTURE_2D_ARRAY: + return VK_IMAGE_VIEW_TYPE_2D_ARRAY; + case GPU_TEXTURE_CUBE_ARRAY: + return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY; + + case GPU_TEXTURE_ARRAY: + /* GPU_TEXTURE_ARRAY should always be used together with 1D, 2D, or CUBE*/ + BLI_assert_unreachable(); + break; + } + + return VK_IMAGE_VIEW_TYPE_1D; +} + +static VkComponentMapping to_vk_component_mapping(const eGPUTextureFormat /*format*/) +{ + /* TODO: this should map to OpenGL defaults based on the eGPUTextureFormat*/ + VkComponentMapping component_mapping; + component_mapping.r = VK_COMPONENT_SWIZZLE_R; + component_mapping.g = VK_COMPONENT_SWIZZLE_G; + component_mapping.b = VK_COMPONENT_SWIZZLE_B; + component_mapping.a = VK_COMPONENT_SWIZZLE_A; + return component_mapping; +} + bool VKTexture::allocate() { BLI_assert(!is_allocated()); VKContext &context = *VKContext::get(); - VkImageCreateInfo imgCreateInfo = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO}; - imgCreateInfo.imageType = VK_IMAGE_TYPE_1D; - imgCreateInfo.extent.width = width_get(); - imgCreateInfo.extent.height = 1; - imgCreateInfo.extent.depth = 1; - imgCreateInfo.mipLevels = 1; - imgCreateInfo.arrayLayers = 1; - imgCreateInfo.format = to_vk_format(format_); - imgCreateInfo.tiling = VK_IMAGE_TILING_LINEAR; - imgCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - imgCreateInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT; - imgCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; + VkImageCreateInfo image_info = {}; + image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + image_info.imageType = VK_IMAGE_TYPE_1D; + image_info.extent.width = width_get(); + image_info.extent.height = 1; + image_info.extent.depth = 1; + image_info.mipLevels = 1; + image_info.arrayLayers = 1; + image_info.format = to_vk_format(format_); + image_info.tiling = VK_IMAGE_TILING_LINEAR; + /* TODO: PREINITIALIZED should be for device only textures. Others should use + * VK_IMAGE_LAYOUT_UNDEFINED and upload its content.*/ + image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + image_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | + VK_IMAGE_USAGE_STORAGE_BIT; + image_info.samples = VK_SAMPLE_COUNT_1_BIT; VmaAllocationCreateInfo allocCreateInfo = {}; allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO; @@ -177,7 +324,7 @@ bool VKTexture::allocate() allocCreateInfo.priority = 1.0f; VkResult result = vmaCreateImage(context.mem_allocator_get(), - &imgCreateInfo, + &image_info, &allocCreateInfo, &vk_image_, &allocation_, @@ -185,7 +332,32 @@ bool VKTexture::allocate() if (result != VK_SUCCESS) { return false; } - return true; + + /* Promote image to the correct layout.*/ + VkImageMemoryBarrier barrier{}; + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; + barrier.image = vk_image_; + barrier.subresourceRange.aspectMask = to_vk_image_aspect_flag_bits(format_); + barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; + barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS; + context.command_buffer_get().pipeline_barrier(Span(&barrier, 1)); + + VK_ALLOCATION_CALLBACKS + VkImageViewCreateInfo image_view_info = {}; + image_view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + image_view_info.image = vk_image_; + image_view_info.viewType = to_vk_image_view_type(type_); + image_view_info.format = to_vk_format(format_); + image_view_info.components = to_vk_component_mapping(format_); + image_view_info.subresourceRange.aspectMask = to_vk_image_aspect_flag_bits(format_); + image_view_info.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; + image_view_info.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS; + + result = vkCreateImageView( + context.device_get(), &image_view_info, vk_allocation_callbacks, &vk_image_view_); + return result == VK_SUCCESS; } void VKTexture::image_bind(int location) diff --git a/source/blender/gpu/vulkan/vk_texture.hh b/source/blender/gpu/vulkan/vk_texture.hh index 4f628961f4c..e0b1fe84ec9 100644 --- a/source/blender/gpu/vulkan/vk_texture.hh +++ b/source/blender/gpu/vulkan/vk_texture.hh @@ -10,10 +10,13 @@ #include "gpu_texture_private.hh" #include "vk_context.hh" +#include "vk_mem_alloc.h" + namespace blender::gpu { class VKTexture : public Texture { VkImage vk_image_ = VK_NULL_HANDLE; + VkImageView vk_image_view_ = VK_NULL_HANDLE; VmaAllocation allocation_ = VK_NULL_HANDLE; public: @@ -40,6 +43,14 @@ class VKTexture : public Texture { uint gl_bindcode_get() const override; void image_bind(int location); + VkImage vk_image_handle() const + { + return vk_image_; + } + VkImageView vk_image_view_handle() const + { + return vk_image_view_; + } protected: bool init_internal() override; @@ -54,6 +65,8 @@ class VKTexture : public Texture { * on the device. */ bool allocate(); + + VkImageViewType vk_image_view_type() const; }; static inline VKTexture *unwrap(Texture *tex) -- 2.30.2 From 64c20b4d6ed17a786ba81a3722e32aa6df750612 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Tue, 14 Feb 2023 12:58:11 +0100 Subject: [PATCH 08/55] Add support for 2d and 3d textures. --- source/blender/gpu/vulkan/vk_texture.cc | 35 ++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/source/blender/gpu/vulkan/vk_texture.cc b/source/blender/gpu/vulkan/vk_texture.cc index ed13ba758bb..38d9d3fe16b 100644 --- a/source/blender/gpu/vulkan/vk_texture.cc +++ b/source/blender/gpu/vulkan/vk_texture.cc @@ -256,6 +256,30 @@ bool VKTexture::is_allocated() return vk_image_ != VK_NULL_HANDLE && allocation_ != VK_NULL_HANDLE; } +static VkImageType to_vk_image_type(const eGPUTextureType type) +{ + switch (type) { + case GPU_TEXTURE_1D: + case GPU_TEXTURE_BUFFER: + case GPU_TEXTURE_1D_ARRAY: + return VK_IMAGE_TYPE_1D; + case GPU_TEXTURE_2D: + case GPU_TEXTURE_2D_ARRAY: + return VK_IMAGE_TYPE_2D; + case GPU_TEXTURE_3D: + case GPU_TEXTURE_CUBE: + case GPU_TEXTURE_CUBE_ARRAY: + return VK_IMAGE_TYPE_3D; + + case GPU_TEXTURE_ARRAY: + /* GPU_TEXTURE_ARRAY should always be used together with 1D, 2D, or CUBE*/ + BLI_assert_unreachable(); + break; + } + + return VK_IMAGE_TYPE_1D; +} + static VkImageViewType to_vk_image_view_type(const eGPUTextureType type) { switch (type) { @@ -299,13 +323,16 @@ bool VKTexture::allocate() { BLI_assert(!is_allocated()); + int extent[3] = {1, 1, 1}; + mip_size_get(0, extent); + VKContext &context = *VKContext::get(); VkImageCreateInfo image_info = {}; image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - image_info.imageType = VK_IMAGE_TYPE_1D; - image_info.extent.width = width_get(); - image_info.extent.height = 1; - image_info.extent.depth = 1; + image_info.imageType = to_vk_image_type(type_); + image_info.extent.width = extent[0]; + image_info.extent.height = extent[1]; + image_info.extent.depth = extent[2]; image_info.mipLevels = 1; image_info.arrayLayers = 1; image_info.format = to_vk_format(format_); -- 2.30.2 From 6225cb7c94c1301660a2229342a091083969f290 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Tue, 14 Feb 2023 13:46:31 +0100 Subject: [PATCH 09/55] Introduce vk_common. --- source/blender/gpu/CMakeLists.txt | 1 + source/blender/gpu/vulkan/vk_backend.hh | 7 ++----- source/blender/gpu/vulkan/vk_buffer.hh | 8 ++------ source/blender/gpu/vulkan/vk_command_buffer.hh | 7 +------ source/blender/gpu/vulkan/vk_common.hh | 14 ++++++++++++++ source/blender/gpu/vulkan/vk_context.hh | 6 ------ source/blender/gpu/vulkan/vk_descriptor_pools.hh | 6 ------ source/blender/gpu/vulkan/vk_descriptor_set.hh | 6 +----- source/blender/gpu/vulkan/vk_memory.hh | 9 +++------ source/blender/gpu/vulkan/vk_pipeline.hh | 7 +------ 10 files changed, 25 insertions(+), 46 deletions(-) create mode 100644 source/blender/gpu/vulkan/vk_common.hh diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index c4da6452f46..c7fe1defe6e 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -217,6 +217,7 @@ set(VULKAN_SRC vulkan/vk_buffer.hh vulkan/vk_context.hh vulkan/vk_command_buffer.hh + vulkan/vk_common.hh vulkan/vk_descriptor_pools.hh vulkan/vk_descriptor_set.hh vulkan/vk_drawlist.hh diff --git a/source/blender/gpu/vulkan/vk_backend.hh b/source/blender/gpu/vulkan/vk_backend.hh index f51798eb9c0..01c85792018 100644 --- a/source/blender/gpu/vulkan/vk_backend.hh +++ b/source/blender/gpu/vulkan/vk_backend.hh @@ -9,11 +9,8 @@ #include "gpu_backend.hh" -#ifdef __APPLE__ -# include -#else -# include -#endif +#include "vk_common.hh" + #include "shaderc/shaderc.hpp" namespace blender::gpu { diff --git a/source/blender/gpu/vulkan/vk_buffer.hh b/source/blender/gpu/vulkan/vk_buffer.hh index 174bebade3e..e93fd37a623 100644 --- a/source/blender/gpu/vulkan/vk_buffer.hh +++ b/source/blender/gpu/vulkan/vk_buffer.hh @@ -8,13 +8,9 @@ #pragma once #include "gpu_context_private.hh" -#include "vk_context.hh" -#ifdef __APPLE__ -# include -#else -# include -#endif +#include "vk_common.hh" +#include "vk_context.hh" #include "vk_mem_alloc.h" diff --git a/source/blender/gpu/vulkan/vk_command_buffer.hh b/source/blender/gpu/vulkan/vk_command_buffer.hh index 325f030ba77..61bb12497e5 100644 --- a/source/blender/gpu/vulkan/vk_command_buffer.hh +++ b/source/blender/gpu/vulkan/vk_command_buffer.hh @@ -7,12 +7,7 @@ #pragma once -#ifdef __APPLE__ -# include -#else -# include -#endif - +#include "vk_common.hh" #include "vk_pipeline.hh" namespace blender::gpu { diff --git a/source/blender/gpu/vulkan/vk_common.hh b/source/blender/gpu/vulkan/vk_common.hh new file mode 100644 index 00000000000..55967e70b7c --- /dev/null +++ b/source/blender/gpu/vulkan/vk_common.hh @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2023 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#ifdef __APPLE__ +# include +#else +# include +#endif diff --git a/source/blender/gpu/vulkan/vk_context.hh b/source/blender/gpu/vulkan/vk_context.hh index 1c0b71cb67a..a2c4ba210ee 100644 --- a/source/blender/gpu/vulkan/vk_context.hh +++ b/source/blender/gpu/vulkan/vk_context.hh @@ -14,12 +14,6 @@ #include "vk_mem_alloc.h" -#ifdef __APPLE__ -# include -#else -# include -#endif - namespace blender::gpu { class VKContext : public Context { diff --git a/source/blender/gpu/vulkan/vk_descriptor_pools.hh b/source/blender/gpu/vulkan/vk_descriptor_pools.hh index 2d37cb237f2..a7d10fd373e 100644 --- a/source/blender/gpu/vulkan/vk_descriptor_pools.hh +++ b/source/blender/gpu/vulkan/vk_descriptor_pools.hh @@ -9,12 +9,6 @@ #include "BLI_vector.hh" -#ifdef __APPLE__ -# include -#else -# include -#endif - #include "vk_descriptor_set.hh" namespace blender::gpu { diff --git a/source/blender/gpu/vulkan/vk_descriptor_set.hh b/source/blender/gpu/vulkan/vk_descriptor_set.hh index e9c2bcd446c..c93cdabff11 100644 --- a/source/blender/gpu/vulkan/vk_descriptor_set.hh +++ b/source/blender/gpu/vulkan/vk_descriptor_set.hh @@ -10,11 +10,7 @@ #include "BLI_utility_mixins.hh" #include "BLI_vector.hh" -#ifdef __APPLE__ -# include -#else -# include -#endif +#include "vk_common.hh" namespace blender::gpu { class VKStorageBuffer; diff --git a/source/blender/gpu/vulkan/vk_memory.hh b/source/blender/gpu/vulkan/vk_memory.hh index 91802cb8193..2188ab063d7 100644 --- a/source/blender/gpu/vulkan/vk_memory.hh +++ b/source/blender/gpu/vulkan/vk_memory.hh @@ -7,11 +7,7 @@ #pragma once -#ifdef __APPLE__ -# include -#else -# include -#endif +#include "vk_common.hh" namespace blender::gpu { @@ -55,7 +51,8 @@ constexpr VkAllocationCallbacks vk_allocation_callbacks_init(const char *name) # define VK_ALLOCATION_CALLBACKS \ static constexpr const VkAllocationCallbacks vk_allocation_callbacks_ = \ vk_allocation_callbacks_init(__func__); \ - static constexpr const VkAllocationCallbacks *vk_allocation_callbacks = &vk_allocation_callbacks_; + static constexpr const VkAllocationCallbacks *vk_allocation_callbacks = \ + &vk_allocation_callbacks_; #else # define VK_ALLOCATION_CALLBACKS \ static constexpr const VkAllocationCallbacks *vk_allocation_callbacks = nullptr; diff --git a/source/blender/gpu/vulkan/vk_pipeline.hh b/source/blender/gpu/vulkan/vk_pipeline.hh index 6111a888d82..b718924be7b 100644 --- a/source/blender/gpu/vulkan/vk_pipeline.hh +++ b/source/blender/gpu/vulkan/vk_pipeline.hh @@ -7,15 +7,10 @@ #pragma once -#ifdef __APPLE__ -# include -#else -# include -#endif - #include "BLI_utility_mixins.hh" #include "BLI_vector.hh" +#include "vk_common.hh" #include "vk_descriptor_set.hh" namespace blender::gpu { -- 2.30.2 From 22cc7f7749afb16e821fab7a0d7802095dce174e Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Tue, 14 Feb 2023 14:07:30 +0100 Subject: [PATCH 10/55] Fixed unneeded std::move. --- source/blender/gpu/vulkan/vk_shader.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/gpu/vulkan/vk_shader.cc b/source/blender/gpu/vulkan/vk_shader.cc index 11a37b3ceea..af1212dc2f1 100644 --- a/source/blender/gpu/vulkan/vk_shader.cc +++ b/source/blender/gpu/vulkan/vk_shader.cc @@ -677,8 +677,8 @@ bool VKShader::finalize(const shader::ShaderCreateInfo *info) BLI_assert(geometry_module_ == VK_NULL_HANDLE); BLI_assert(fragment_module_ == VK_NULL_HANDLE); BLI_assert(compute_module_ != VK_NULL_HANDLE); - compute_pipeline_ = std::move(VKPipeline::create_compute_pipeline( - *context_, compute_module_, layout_, pipeline_layout_)); + compute_pipeline_ = VKPipeline::create_compute_pipeline( + *context_, compute_module_, layout_, pipeline_layout_); result = compute_pipeline_.is_valid(); } -- 2.30.2 From a2ba452c31a146b99f5ad0056fbaf23175f4fe48 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Tue, 14 Feb 2023 14:23:41 +0100 Subject: [PATCH 11/55] Move common data conversions to vk_common. --- source/blender/gpu/CMakeLists.txt | 1 + source/blender/gpu/vulkan/vk_common.cc | 196 ++++++++++++++++++++++++ source/blender/gpu/vulkan/vk_common.hh | 12 ++ source/blender/gpu/vulkan/vk_texture.cc | 191 +---------------------- 4 files changed, 212 insertions(+), 188 deletions(-) create mode 100644 source/blender/gpu/vulkan/vk_common.cc diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index c7fe1defe6e..6bb92aa212b 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -193,6 +193,7 @@ set(VULKAN_SRC vulkan/vk_buffer.cc vulkan/vk_context.cc vulkan/vk_command_buffer.cc + vulkan/vk_common.cc vulkan/vk_descriptor_pools.cc vulkan/vk_descriptor_set.cc vulkan/vk_drawlist.cc diff --git a/source/blender/gpu/vulkan/vk_common.cc b/source/blender/gpu/vulkan/vk_common.cc new file mode 100644 index 00000000000..e3df0475776 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_common.cc @@ -0,0 +1,196 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2023 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#include "vk_common.hh" + +namespace blender::gpu { +VkImageAspectFlagBits to_vk_image_aspect_flag_bits(const eGPUTextureFormat format) +{ + switch (format) { + case GPU_RGBA32F: + case GPU_RGBA8UI: + case GPU_RGBA8I: + case GPU_RGBA8: + case GPU_RGBA32UI: + case GPU_RGBA32I: + case GPU_RGBA16UI: + case GPU_RGBA16I: + case GPU_RGBA16F: + case GPU_RGBA16: + case GPU_RG8UI: + case GPU_RG8I: + case GPU_RG8: + case GPU_RG32UI: + case GPU_RG32I: + case GPU_RG32F: + case GPU_RG16UI: + case GPU_RG16I: + case GPU_RG16F: + case GPU_RG16: + case GPU_R8UI: + case GPU_R8I: + case GPU_R8: + case GPU_R32UI: + case GPU_R32I: + case GPU_R32F: + case GPU_R16UI: + case GPU_R16I: + case GPU_R16F: + case GPU_R16: + case GPU_RGB10_A2: + case GPU_R11F_G11F_B10F: + case GPU_SRGB8_A8: + case GPU_RGB16F: + case GPU_SRGB8_A8_DXT1: + case GPU_SRGB8_A8_DXT3: + case GPU_SRGB8_A8_DXT5: + case GPU_RGBA8_DXT1: + case GPU_RGBA8_DXT3: + case GPU_RGBA8_DXT5: + return VK_IMAGE_ASPECT_COLOR_BIT; + + case GPU_DEPTH32F_STENCIL8: + case GPU_DEPTH24_STENCIL8: + return static_cast(VK_IMAGE_ASPECT_DEPTH_BIT | + VK_IMAGE_ASPECT_STENCIL_BIT); + + case GPU_DEPTH_COMPONENT24: + case GPU_DEPTH_COMPONENT16: + return VK_IMAGE_ASPECT_DEPTH_BIT; + + case GPU_DEPTH_COMPONENT32F: + /* Not supported by Vulkan*/ + BLI_assert_unreachable(); + } + return static_cast(0); +} + +VkFormat to_vk_format(const eGPUTextureFormat format) +{ + switch (format) { + case GPU_RGBA32F: + return VK_FORMAT_R32G32B32A32_SFLOAT; + case GPU_RGBA8UI: + case GPU_RGBA8I: + case GPU_RGBA8: + case GPU_RGBA32UI: + case GPU_RGBA32I: + case GPU_RGBA16UI: + case GPU_RGBA16I: + case GPU_RGBA16F: + case GPU_RGBA16: + case GPU_RG8UI: + case GPU_RG8I: + case GPU_RG8: + case GPU_RG32UI: + case GPU_RG32I: + case GPU_RG32F: + case GPU_RG16UI: + case GPU_RG16I: + case GPU_RG16F: + case GPU_RG16: + case GPU_R8UI: + case GPU_R8I: + case GPU_R8: + case GPU_R32UI: + case GPU_R32I: + case GPU_R32F: + case GPU_R16UI: + case GPU_R16I: + case GPU_R16F: + case GPU_R16: + + case GPU_RGB10_A2: + case GPU_R11F_G11F_B10F: + case GPU_DEPTH32F_STENCIL8: + case GPU_DEPTH24_STENCIL8: + case GPU_SRGB8_A8: + + /* Texture only format */ + case GPU_RGB16F: + + /* Special formats texture only */ + case GPU_SRGB8_A8_DXT1: + case GPU_SRGB8_A8_DXT3: + case GPU_SRGB8_A8_DXT5: + case GPU_RGBA8_DXT1: + case GPU_RGBA8_DXT3: + case GPU_RGBA8_DXT5: + + /* Depth Formats */ + case GPU_DEPTH_COMPONENT32F: + case GPU_DEPTH_COMPONENT24: + case GPU_DEPTH_COMPONENT16: + BLI_assert_unreachable(); + } + return VK_FORMAT_UNDEFINED; +} + +VkImageType to_vk_image_type(const eGPUTextureType type) +{ + switch (type) { + case GPU_TEXTURE_1D: + case GPU_TEXTURE_BUFFER: + case GPU_TEXTURE_1D_ARRAY: + return VK_IMAGE_TYPE_1D; + case GPU_TEXTURE_2D: + case GPU_TEXTURE_2D_ARRAY: + return VK_IMAGE_TYPE_2D; + case GPU_TEXTURE_3D: + case GPU_TEXTURE_CUBE: + case GPU_TEXTURE_CUBE_ARRAY: + return VK_IMAGE_TYPE_3D; + + case GPU_TEXTURE_ARRAY: + /* GPU_TEXTURE_ARRAY should always be used together with 1D, 2D, or CUBE*/ + BLI_assert_unreachable(); + break; + } + + return VK_IMAGE_TYPE_1D; +} + +VkImageViewType to_vk_image_view_type(const eGPUTextureType type) +{ + switch (type) { + case GPU_TEXTURE_1D: + case GPU_TEXTURE_BUFFER: + return VK_IMAGE_VIEW_TYPE_1D; + case GPU_TEXTURE_2D: + return VK_IMAGE_VIEW_TYPE_2D; + case GPU_TEXTURE_3D: + return VK_IMAGE_VIEW_TYPE_3D; + case GPU_TEXTURE_CUBE: + return VK_IMAGE_VIEW_TYPE_CUBE; + case GPU_TEXTURE_1D_ARRAY: + return VK_IMAGE_VIEW_TYPE_1D_ARRAY; + case GPU_TEXTURE_2D_ARRAY: + return VK_IMAGE_VIEW_TYPE_2D_ARRAY; + case GPU_TEXTURE_CUBE_ARRAY: + return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY; + + case GPU_TEXTURE_ARRAY: + /* GPU_TEXTURE_ARRAY should always be used together with 1D, 2D, or CUBE*/ + BLI_assert_unreachable(); + break; + } + + return VK_IMAGE_VIEW_TYPE_1D; +} + +VkComponentMapping to_vk_component_mapping(const eGPUTextureFormat /*format*/) +{ + /* TODO: this should map to OpenGL defaults based on the eGPUTextureFormat*/ + VkComponentMapping component_mapping; + component_mapping.r = VK_COMPONENT_SWIZZLE_R; + component_mapping.g = VK_COMPONENT_SWIZZLE_G; + component_mapping.b = VK_COMPONENT_SWIZZLE_B; + component_mapping.a = VK_COMPONENT_SWIZZLE_A; + return component_mapping; +} + +} // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_common.hh b/source/blender/gpu/vulkan/vk_common.hh index 55967e70b7c..b2645cd2e8c 100644 --- a/source/blender/gpu/vulkan/vk_common.hh +++ b/source/blender/gpu/vulkan/vk_common.hh @@ -12,3 +12,15 @@ #else # include #endif + +#include "gpu_texture_private.hh" + +namespace blender::gpu { + +VkImageAspectFlagBits to_vk_image_aspect_flag_bits(const eGPUTextureFormat format); +VkFormat to_vk_format(const eGPUTextureFormat format); +VkComponentMapping to_vk_component_mapping(const eGPUTextureFormat format); +VkImageViewType to_vk_image_view_type(const eGPUTextureType type); +VkImageType to_vk_image_type(const eGPUTextureType type); + +} // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_texture.cc b/source/blender/gpu/vulkan/vk_texture.cc index 38d9d3fe16b..20577f2c494 100644 --- a/source/blender/gpu/vulkan/vk_texture.cc +++ b/source/blender/gpu/vulkan/vk_texture.cc @@ -14,67 +14,6 @@ namespace blender::gpu { -static VkImageAspectFlagBits to_vk_image_aspect_flag_bits(const eGPUTextureFormat format) -{ - switch (format) { - case GPU_RGBA32F: - case GPU_RGBA8UI: - case GPU_RGBA8I: - case GPU_RGBA8: - case GPU_RGBA32UI: - case GPU_RGBA32I: - case GPU_RGBA16UI: - case GPU_RGBA16I: - case GPU_RGBA16F: - case GPU_RGBA16: - case GPU_RG8UI: - case GPU_RG8I: - case GPU_RG8: - case GPU_RG32UI: - case GPU_RG32I: - case GPU_RG32F: - case GPU_RG16UI: - case GPU_RG16I: - case GPU_RG16F: - case GPU_RG16: - case GPU_R8UI: - case GPU_R8I: - case GPU_R8: - case GPU_R32UI: - case GPU_R32I: - case GPU_R32F: - case GPU_R16UI: - case GPU_R16I: - case GPU_R16F: - case GPU_R16: - case GPU_RGB10_A2: - case GPU_R11F_G11F_B10F: - case GPU_SRGB8_A8: - case GPU_RGB16F: - case GPU_SRGB8_A8_DXT1: - case GPU_SRGB8_A8_DXT3: - case GPU_SRGB8_A8_DXT5: - case GPU_RGBA8_DXT1: - case GPU_RGBA8_DXT3: - case GPU_RGBA8_DXT5: - return VK_IMAGE_ASPECT_COLOR_BIT; - - case GPU_DEPTH32F_STENCIL8: - case GPU_DEPTH24_STENCIL8: - return static_cast(VK_IMAGE_ASPECT_DEPTH_BIT | - VK_IMAGE_ASPECT_STENCIL_BIT); - - case GPU_DEPTH_COMPONENT24: - case GPU_DEPTH_COMPONENT16: - return VK_IMAGE_ASPECT_DEPTH_BIT; - - case GPU_DEPTH_COMPONENT32F: - /* Not supported by Vulkan*/ - BLI_assert_unreachable(); - } - return static_cast(0); -} - VKTexture::~VKTexture() { VK_ALLOCATION_CALLBACKS @@ -174,70 +113,11 @@ uint VKTexture::gl_bindcode_get() const return 0; } -static VkFormat to_vk_format(const eGPUTextureFormat format) -{ - switch (format) { - case GPU_RGBA32F: - return VK_FORMAT_R32G32B32A32_SFLOAT; - case GPU_RGBA8UI: - case GPU_RGBA8I: - case GPU_RGBA8: - case GPU_RGBA32UI: - case GPU_RGBA32I: - case GPU_RGBA16UI: - case GPU_RGBA16I: - case GPU_RGBA16F: - case GPU_RGBA16: - case GPU_RG8UI: - case GPU_RG8I: - case GPU_RG8: - case GPU_RG32UI: - case GPU_RG32I: - case GPU_RG32F: - case GPU_RG16UI: - case GPU_RG16I: - case GPU_RG16F: - case GPU_RG16: - case GPU_R8UI: - case GPU_R8I: - case GPU_R8: - case GPU_R32UI: - case GPU_R32I: - case GPU_R32F: - case GPU_R16UI: - case GPU_R16I: - case GPU_R16F: - case GPU_R16: - - case GPU_RGB10_A2: - case GPU_R11F_G11F_B10F: - case GPU_DEPTH32F_STENCIL8: - case GPU_DEPTH24_STENCIL8: - case GPU_SRGB8_A8: - - /* Texture only format */ - case GPU_RGB16F: - - /* Special formats texture only */ - case GPU_SRGB8_A8_DXT1: - case GPU_SRGB8_A8_DXT3: - case GPU_SRGB8_A8_DXT5: - case GPU_RGBA8_DXT1: - case GPU_RGBA8_DXT3: - case GPU_RGBA8_DXT5: - - /* Depth Formats */ - case GPU_DEPTH_COMPONENT32F: - case GPU_DEPTH_COMPONENT24: - case GPU_DEPTH_COMPONENT16: - BLI_assert_unreachable(); - } - return VK_FORMAT_UNDEFINED; -} - bool VKTexture::init_internal() { - /* TODO: add some pre-initialization to reduce some work later on.*/ + /* Initialization can only happen after the usage is known. By the current API this isn't set + * at this moment, so we cannot initialize here. The initialization is postponed until the + * allocation of the texture on the device.*/ return true; } @@ -256,69 +136,6 @@ bool VKTexture::is_allocated() return vk_image_ != VK_NULL_HANDLE && allocation_ != VK_NULL_HANDLE; } -static VkImageType to_vk_image_type(const eGPUTextureType type) -{ - switch (type) { - case GPU_TEXTURE_1D: - case GPU_TEXTURE_BUFFER: - case GPU_TEXTURE_1D_ARRAY: - return VK_IMAGE_TYPE_1D; - case GPU_TEXTURE_2D: - case GPU_TEXTURE_2D_ARRAY: - return VK_IMAGE_TYPE_2D; - case GPU_TEXTURE_3D: - case GPU_TEXTURE_CUBE: - case GPU_TEXTURE_CUBE_ARRAY: - return VK_IMAGE_TYPE_3D; - - case GPU_TEXTURE_ARRAY: - /* GPU_TEXTURE_ARRAY should always be used together with 1D, 2D, or CUBE*/ - BLI_assert_unreachable(); - break; - } - - return VK_IMAGE_TYPE_1D; -} - -static VkImageViewType to_vk_image_view_type(const eGPUTextureType type) -{ - switch (type) { - case GPU_TEXTURE_1D: - case GPU_TEXTURE_BUFFER: - return VK_IMAGE_VIEW_TYPE_1D; - case GPU_TEXTURE_2D: - return VK_IMAGE_VIEW_TYPE_2D; - case GPU_TEXTURE_3D: - return VK_IMAGE_VIEW_TYPE_3D; - case GPU_TEXTURE_CUBE: - return VK_IMAGE_VIEW_TYPE_CUBE; - case GPU_TEXTURE_1D_ARRAY: - return VK_IMAGE_VIEW_TYPE_1D_ARRAY; - case GPU_TEXTURE_2D_ARRAY: - return VK_IMAGE_VIEW_TYPE_2D_ARRAY; - case GPU_TEXTURE_CUBE_ARRAY: - return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY; - - case GPU_TEXTURE_ARRAY: - /* GPU_TEXTURE_ARRAY should always be used together with 1D, 2D, or CUBE*/ - BLI_assert_unreachable(); - break; - } - - return VK_IMAGE_VIEW_TYPE_1D; -} - -static VkComponentMapping to_vk_component_mapping(const eGPUTextureFormat /*format*/) -{ - /* TODO: this should map to OpenGL defaults based on the eGPUTextureFormat*/ - VkComponentMapping component_mapping; - component_mapping.r = VK_COMPONENT_SWIZZLE_R; - component_mapping.g = VK_COMPONENT_SWIZZLE_G; - component_mapping.b = VK_COMPONENT_SWIZZLE_B; - component_mapping.a = VK_COMPONENT_SWIZZLE_A; - return component_mapping; -} - bool VKTexture::allocate() { BLI_assert(!is_allocated()); @@ -337,8 +154,6 @@ bool VKTexture::allocate() image_info.arrayLayers = 1; image_info.format = to_vk_format(format_); image_info.tiling = VK_IMAGE_TILING_LINEAR; - /* TODO: PREINITIALIZED should be for device only textures. Others should use - * VK_IMAGE_LAYOUT_UNDEFINED and upload its content.*/ image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; image_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT; -- 2.30.2 From d75180cfba1fe12591614bb62a0394203206fe93 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Tue, 14 Feb 2023 14:43:15 +0100 Subject: [PATCH 12/55] Improve comments of known limitations of the implementation. --- source/blender/gpu/vulkan/vk_buffer.cc | 4 ++-- source/blender/gpu/vulkan/vk_buffer.hh | 1 - source/blender/gpu/vulkan/vk_command_buffer.cc | 6 +++--- source/blender/gpu/vulkan/vk_common.cc | 3 ++- source/blender/gpu/vulkan/vk_context.cc | 6 +++--- source/blender/gpu/vulkan/vk_shader.hh | 1 - 6 files changed, 10 insertions(+), 11 deletions(-) diff --git a/source/blender/gpu/vulkan/vk_buffer.cc b/source/blender/gpu/vulkan/vk_buffer.cc index f02c2ef9b5f..f882783041d 100644 --- a/source/blender/gpu/vulkan/vk_buffer.cc +++ b/source/blender/gpu/vulkan/vk_buffer.cc @@ -57,8 +57,8 @@ bool VKBuffer::create(VKContext &context, create_info.flags = 0; create_info.size = size_in_bytes; create_info.usage = buffer_usage; - /* For now the compute and graphics command queues are the same, so we can safely assume - * exclusive mode.*/ + /* We use the same command queue for the compute and graphics pipeline, so it is safe to use + * exclusive resource handling. */ create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; create_info.queueFamilyIndexCount = 1; create_info.pQueueFamilyIndices = context.queue_family_ptr_get(); diff --git a/source/blender/gpu/vulkan/vk_buffer.hh b/source/blender/gpu/vulkan/vk_buffer.hh index e93fd37a623..875876ccab1 100644 --- a/source/blender/gpu/vulkan/vk_buffer.hh +++ b/source/blender/gpu/vulkan/vk_buffer.hh @@ -36,7 +36,6 @@ class VKBuffer { GPUUsageType usage, VkBufferUsageFlagBits buffer_usage); bool update(VKContext &context, const void *data); - // TODO: add partial_update (update_sub) bool free(VKContext &context); bool map(VKContext &context, void **r_mapped_memory) const; void unmap(VKContext &context) const; diff --git a/source/blender/gpu/vulkan/vk_command_buffer.cc b/source/blender/gpu/vulkan/vk_command_buffer.cc index 70386e8c5ed..12821142b32 100644 --- a/source/blender/gpu/vulkan/vk_command_buffer.cc +++ b/source/blender/gpu/vulkan/vk_command_buffer.cc @@ -126,9 +126,9 @@ void VKCommandBuffer::submit() void VKCommandBuffer::encode_recorded_commands() { - /* TODO: Intentionally not implemented. For the graphics pipeline we want to extract the - * resources and its usages so we can encode multiple commands in the same command buffer. This - * will also require to change the begin/end recording to be only inside this function. */ + /* Intentionally not implemented. For the graphics pipeline we want to extract the + * resources and its usages so we can encode multiple commands in the same command buffer with + * the correct synchorinzations. */ } void VKCommandBuffer::submit_encoded_commands() diff --git a/source/blender/gpu/vulkan/vk_common.cc b/source/blender/gpu/vulkan/vk_common.cc index e3df0475776..ecfccad8294 100644 --- a/source/blender/gpu/vulkan/vk_common.cc +++ b/source/blender/gpu/vulkan/vk_common.cc @@ -184,7 +184,8 @@ VkImageViewType to_vk_image_view_type(const eGPUTextureType type) VkComponentMapping to_vk_component_mapping(const eGPUTextureFormat /*format*/) { - /* TODO: this should map to OpenGL defaults based on the eGPUTextureFormat*/ + /* TODO: this should map to OpenGL defaults based on the eGPUTextureFormat. The implementation of + * this function will be implemented when implementing other parts of VKTexture.*/ VkComponentMapping component_mapping; component_mapping.r = VK_COMPONENT_SWIZZLE_R; component_mapping.g = VK_COMPONENT_SWIZZLE_G; diff --git a/source/blender/gpu/vulkan/vk_context.cc b/source/blender/gpu/vulkan/vk_context.cc index 4a5e67259d3..f28d570fd0f 100644 --- a/source/blender/gpu/vulkan/vk_context.cc +++ b/source/blender/gpu/vulkan/vk_context.cc @@ -33,9 +33,9 @@ VKContext::VKContext(void *ghost_window, void *ghost_context) /* Initialize the memory allocator. */ VmaAllocatorCreateInfo info = {}; - /* Should use same vulkan version as GHOST, but set to 1.0 for now. Raising it to 1.2 requires - * correct extensions and functions to be found, which doesn't out-of-the-box. We should fix - * this, but to continue the development at hand we lower the API to 1.0.*/ + /* Should use same vulkan version as GHOST (1.2), but set to 1.0 as 1.2 requires + * correct extensions and functions to be found by VMA, which isn't working as expected and + * requires more research. To continue development we lower the API to version 1.0.*/ info.vulkanApiVersion = VK_API_VERSION_1_0; info.physicalDevice = vk_physical_device_; info.device = vk_device_; diff --git a/source/blender/gpu/vulkan/vk_shader.hh b/source/blender/gpu/vulkan/vk_shader.hh index ad44491b07e..b334ae39648 100644 --- a/source/blender/gpu/vulkan/vk_shader.hh +++ b/source/blender/gpu/vulkan/vk_shader.hh @@ -60,7 +60,6 @@ class VKShader : public Shader { int program_handle_get() const override; VKPipeline &pipeline_get(); - /* TODO: should be part of VKPipeline.*/ VkPipelineLayout vk_pipeline_layout_get() const { return pipeline_layout_; -- 2.30.2 From 26b0c7c3fb5d83a1a223be037402835243eed138 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Thu, 16 Feb 2023 07:50:25 +0100 Subject: [PATCH 13/55] Increase descriptor pool resources. Added image samplers and uniform buffers. Required for shader builder. --- source/blender/gpu/vulkan/vk_descriptor_pools.cc | 2 ++ source/blender/gpu/vulkan/vk_descriptor_pools.hh | 2 ++ 2 files changed, 4 insertions(+) diff --git a/source/blender/gpu/vulkan/vk_descriptor_pools.cc b/source/blender/gpu/vulkan/vk_descriptor_pools.cc index 0caadf61567..a83e83f7aa3 100644 --- a/source/blender/gpu/vulkan/vk_descriptor_pools.cc +++ b/source/blender/gpu/vulkan/vk_descriptor_pools.cc @@ -41,6 +41,8 @@ void VKDescriptorPools::add_new_pool() Vector pool_sizes = { {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, POOL_SIZE_STORAGE_BUFFER}, {VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, POOL_SIZE_STORAGE_IMAGE}, + {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, POOL_SIZE_COMBINED_IMAGE_SAMPLER}, + {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, POOL_SIZE_UNIFORM_BUFFER}, }; VkDescriptorPoolCreateInfo pool_info = {}; pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; diff --git a/source/blender/gpu/vulkan/vk_descriptor_pools.hh b/source/blender/gpu/vulkan/vk_descriptor_pools.hh index a7d10fd373e..71292e019a3 100644 --- a/source/blender/gpu/vulkan/vk_descriptor_pools.hh +++ b/source/blender/gpu/vulkan/vk_descriptor_pools.hh @@ -33,6 +33,8 @@ class VKDescriptorPools { static constexpr uint32_t POOL_SIZE_STORAGE_BUFFER = 1000; static constexpr uint32_t POOL_SIZE_DESCRIPTOR_SETS = 1000; static constexpr uint32_t POOL_SIZE_STORAGE_IMAGE = 1000; + static constexpr uint32_t POOL_SIZE_COMBINED_IMAGE_SAMPLER = 1000; + static constexpr uint32_t POOL_SIZE_UNIFORM_BUFFER = 1000; VkDevice vk_device_ = VK_NULL_HANDLE; Vector pools_; -- 2.30.2 From 68bbed1e4b596eafa2925a996e9c648ced24e836 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Thu, 16 Feb 2023 09:27:29 +0100 Subject: [PATCH 14/55] Added initial support for sampling. --- .../blender/gpu/vulkan/vk_shader_interface.cc | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/source/blender/gpu/vulkan/vk_shader_interface.cc b/source/blender/gpu/vulkan/vk_shader_interface.cc index b0b47e3a4c3..688287953c0 100644 --- a/source/blender/gpu/vulkan/vk_shader_interface.cc +++ b/source/blender/gpu/vulkan/vk_shader_interface.cc @@ -15,6 +15,7 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) uniform_len_ = 0; ssbo_len_ = 0; + ubo_len_ = 0; Vector all_resources; all_resources.extend(info.pass_resources_); @@ -26,8 +27,10 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) uniform_len_++; break; case ShaderCreateInfo::Resource::BindType::SAMPLER: + uniform_len_++; + break; case ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER: - // BLI_assert_msg(false, "not implemented yet"); + ubo_len_++; break; case ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER: ssbo_len_++; @@ -35,16 +38,32 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) } } - int32_t input_tot_len = ssbo_len_ + uniform_len_; + int32_t input_tot_len = ubo_len_ + uniform_len_ + ssbo_len_; inputs_ = static_cast( MEM_calloc_arrayN(input_tot_len, sizeof(ShaderInput), __func__)); ShaderInput *input = inputs_; name_buffer_ = (char *)MEM_mallocN(info.interface_names_size_, "name_buffer"); uint32_t name_buffer_offset = 0; - /* Images */ - /* NOTE: should be extended with uniforms and samplers.*/ + + /* Uniform blocks */ for (const ShaderCreateInfo::Resource &res : all_resources) { + if (res.bind_type == ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER) { + copy_input_name(input, res.image.name, name_buffer_, name_buffer_offset); + input->location = input->binding = res.slot; + enabled_ubo_mask_ |= (1 << input->binding); + input++; + } + } + + /* Images, Samplers and buffers. */ + for (const ShaderCreateInfo::Resource &res : all_resources) { + if (res.bind_type == ShaderCreateInfo::Resource::BindType::SAMPLER) { + copy_input_name(input, res.sampler.name, name_buffer_, name_buffer_offset); + input->location = input->binding = res.slot; + enabled_tex_mask_ |= (1 << input->binding); + input++; + } if (res.bind_type == ShaderCreateInfo::Resource::BindType::IMAGE) { copy_input_name(input, res.image.name, name_buffer_, name_buffer_offset); input->location = input->binding = res.slot; -- 2.30.2 From 4fcaf128b0320cea5f6297c2622662451d051fbb Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Thu, 16 Feb 2023 10:25:44 +0100 Subject: [PATCH 15/55] Added documentation to the GHOST C-api and Context. --- intern/ghost/GHOST_C-api.h | 78 ++++++++++++++++++++++++--- intern/ghost/GHOST_IContext.h | 82 ++++++++++++++++++++++++++--- intern/ghost/intern/GHOST_Context.h | 74 ++++++++++++++++++++++---- 3 files changed, 211 insertions(+), 23 deletions(-) diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h index 92219bdbd64..899aaa7de22 100644 --- a/intern/ghost/GHOST_C-api.h +++ b/intern/ghost/GHOST_C-api.h @@ -1195,7 +1195,30 @@ int GHOST_XrGetControllerModelData(GHOST_XrContextHandle xr_context, #ifdef WITH_VULKAN_BACKEND /** - * Return VULKAN handles for the given context. + * Get Vulkan handles for the given context. + * + * These handles are the same for a given context. + * Should should only be called when using a Vulkan context. + * Other contexts will not return any handles and leave the + * handles where the parameters are referring to unmodified. + * + * \param context: GHOST context handle of a vulkan context to + * get the Vulkan handles from. + * \param r_instance: After calling this function the VkInstance + * referenced by this parameter will contain the VKInstance handle + * of the context associated with the `context` parameter. + * \param r_physical_device: After calling this function the VkPhysicalDevice + * referenced by this parameter will contain the VKPhysicalDevice handle + * of the context associated with the `context` parameter. + * \param r_device: After calling this function the VkDevice + * referenced by this parameter will contain the VKDevice handle + * of the context associated with the `context` parameter. + * \param r_graphic_queue_family: After calling this function the uint32_t + * referenced by this parameter will contain the graphic queue family id + * of the context associated with the `context` parameter. + * \param r_queue: After calling this function the VkQueue + * referenced by this parameter will contain the VKQueue handle + * of the context associated with the `context` parameter. */ void GHOST_GetVulkanHandles(GHOST_ContextHandle context, void *r_instance, @@ -1203,17 +1226,58 @@ void GHOST_GetVulkanHandles(GHOST_ContextHandle context, void *r_device, uint32_t *r_graphic_queue_family, void *r_queue); + +/** + * Return Vulkan command buffer. + * + * Command buffers are different for each image in the swap chain. + * At the start of each frame the correct command buffer should be + * retrieved with this function. + * + * Should should only be called when using a Vulkan context. + * Other contexts will not return any handles and leave the + * handles where the parameters are referring to unmodified. + * + * \param context: GHOST context handle to a vulkan context to get the + * command queue from. + * \param r_command_buffer: After calling this function the VkCommandBuffer + * referenced by this parameter will contain the VKCommandBuffer handle + * of the current back buffer (when swap chains are enabled) or + * it will contain a general VkCommandQueue. + */ void GHOST_GetVulkanCommandBuffer(GHOST_ContextHandle context, void *r_command_buffer); /** - * Return VULKAN back-buffer resources handles for the given window. + * Gets the Vulkan backbuffer related resource handles associated with the Vulkan context. + * Needs to be called after each swap event as the backbuffer will change. + * + * Should should only be called when using a Vulkan context with an active swap chain. + * Other contexts will not return any handles and leave the + * handles where the parameters are referring to unmodified. + * + * \param windowhandle: GHOST window handle to a window to get the resource from. + * \param r_image: After calling this function the VkImage + * referenced by this parameter will contain the VKImage handle + * of the current back buffer. + * \param r_framebuffer: After calling this function the VkFramebuffer + * referenced by this parameter will contain the VKFramebuffer handle + * of the current back buffer. + * \param r_render_pass: After calling this function the VkRenderPass + * referenced by this parameter will contain the VKRenderPass handle + * of the current back buffer. + * \param r_extent: After calling this function the VkExtent2D + * referenced by this parameter will contain the size of the + * frame buffer and image in pixels. + * \param r_fb_id: After calling this function the uint32_t + * referenced by this parameter will contain the id of the + * framebuffer of the current back buffer. */ void GHOST_GetVulkanBackbuffer(GHOST_WindowHandle windowhandle, - void *image, - void *framebuffer, - void *render_pass, - void *extent, - uint32_t *fb_id); + void *r_image, + void *r_framebuffer, + void *r_render_pass, + void *r_extent, + uint32_t *r_fb_id); #endif diff --git a/intern/ghost/GHOST_IContext.h b/intern/ghost/GHOST_IContext.h index b7c681c9843..8499e6b2905 100644 --- a/intern/ghost/GHOST_IContext.h +++ b/intern/ghost/GHOST_IContext.h @@ -40,16 +40,84 @@ class GHOST_IContext { virtual unsigned int getDefaultFramebuffer() = 0; - virtual GHOST_TSuccess getVulkanHandles(void *, void *, void *, uint32_t *, void *) = 0; - virtual GHOST_TSuccess getVulkanCommandBuffer(void * /*r_command_buffer*/) = 0; + /** + * Get Vulkan handles for the given context. + * + * These handles are the same for a given context. + * Should should only be called when using a Vulkan context. + * Other contexts will not return any handles and leave the + * handles where the parameters are referring to unmodified. + * + * \param r_instance: After calling this function the VkInstance + * referenced by this parameter will contain the VKInstance handle + * of the context associated with the `context` parameter. + * \param r_physical_device: After calling this function the VkPhysicalDevice + * referenced by this parameter will contain the VKPhysicalDevice handle + * of the context associated with the `context` parameter. + * \param r_device: After calling this function the VkDevice + * referenced by this parameter will contain the VKDevice handle + * of the context associated with the `context` parameter. + * \param r_graphic_queue_family: After calling this function the uint32_t + * referenced by this parameter will contain the graphic queue family id + * of the context associated with the `context` parameter. + * \param r_queue: After calling this function the VkQueue + * referenced by this parameter will contain the VKQueue handle + * of the context associated with the `context` parameter. + * \returns GHOST_kFailure when context isn't a Vulkan context. + * GHOST_kSuccess when the context is a Vulkan context and the + * handles have been set. + */ + virtual GHOST_TSuccess getVulkanHandles(void *r_instance, + void *r_physical_device, + void *r_device, + uint32_t *r_graphic_queue_family, + void *r_queue) = 0; /** - * Gets the Vulkan framebuffer related resource handles associated with the Vulkan context. - * Needs to be called after each swap events as the framebuffer will change. - * \return A boolean success indicator. + * Return Vulkan command buffer. + * + * Command buffers are different for each image in the swap chain. + * At the start of each frame the correct command buffer should be + * retrieved with this function. + * + * \param r_command_buffer: After calling this function the VkCommandBuffer + * referenced by this parameter will contain the VKCommandBuffer handle + * of the current back buffer (when swap chains are enabled) or + * it will contain a general VkCommandQueue. + * \returns GHOST_kFailure when context isn't a Vulkan context. + * GHOST_kSuccess when the context is a Vulkan context and the + * handles have been set. */ - virtual GHOST_TSuccess getVulkanBackbuffer( - void *image, void *framebuffer, void *render_pass, void *extent, uint32_t *fb_id) = 0; + virtual GHOST_TSuccess getVulkanCommandBuffer(void *r_command_buffer) = 0; + + /** + * Gets the Vulkan backbuffer related resource handles associated with the Vulkan context. + * Needs to be called after each swap event as the backbuffer will change. + * + * \param r_image: After calling this function the VkImage + * referenced by this parameter will contain the VKImage handle + * of the current back buffer. + * \param r_framebuffer: After calling this function the VkFramebuffer + * referenced by this parameter will contain the VKFramebuffer handle + * of the current back buffer. + * \param r_render_pass: After calling this function the VkRenderPass + * referenced by this parameter will contain the VKRenderPass handle + * of the current back buffer. + * \param r_extent: After calling this function the VkExtent2D + * referenced by this parameter will contain the size of the + * frame buffer and image in pixels. + * \param r_fb_id: After calling this function the uint32_t + * referenced by this parameter will contain the id of the + * framebuffer of the current back buffer. + * \returns GHOST_kFailure when context isn't a Vulkan context. + * GHOST_kSuccess when the context is a Vulkan context and the + * handles have been set. + */ + virtual GHOST_TSuccess getVulkanBackbuffer(void *r_image, + void *r_framebuffer, + void *r_render_pass, + void *r_extent, + uint32_t *r_fb_id) = 0; virtual GHOST_TSuccess swapBuffers() = 0; diff --git a/intern/ghost/intern/GHOST_Context.h b/intern/ghost/intern/GHOST_Context.h index 577b04bdce9..6fd212f7eb3 100644 --- a/intern/ghost/intern/GHOST_Context.h +++ b/intern/ghost/intern/GHOST_Context.h @@ -136,8 +136,31 @@ class GHOST_Context : public GHOST_IContext { } /** - * Gets the Vulkan context related resource handles. - * \return A boolean success indicator. + * Get Vulkan handles for the given context. + * + * These handles are the same for a given context. + * Should should only be called when using a Vulkan context. + * Other contexts will not return any handles and leave the + * handles where the parameters are referring to unmodified. + * + * \param r_instance: After calling this function the VkInstance + * referenced by this parameter will contain the VKInstance handle + * of the context associated with the `context` parameter. + * \param r_physical_device: After calling this function the VkPhysicalDevice + * referenced by this parameter will contain the VKPhysicalDevice handle + * of the context associated with the `context` parameter. + * \param r_device: After calling this function the VkDevice + * referenced by this parameter will contain the VKDevice handle + * of the context associated with the `context` parameter. + * \param r_graphic_queue_family: After calling this function the uint32_t + * referenced by this parameter will contain the graphic queue family id + * of the context associated with the `context` parameter. + * \param r_queue: After calling this function the VkQueue + * referenced by this parameter will contain the VKQueue handle + * of the context associated with the `context` parameter. + * \returns GHOST_kFailure when context isn't a Vulkan context. + * GHOST_kSuccess when the context is a Vulkan context and the + * handles have been set. */ virtual GHOST_TSuccess getVulkanHandles(void * /*r_instance*/, void * /*r_physical_device*/, @@ -148,20 +171,53 @@ class GHOST_Context : public GHOST_IContext { return GHOST_kFailure; }; + /** + * Return Vulkan command buffer. + * + * Command buffers are different for each image in the swap chain. + * At the start of each frame the correct command buffer should be + * retrieved with this function. + * + * \param r_command_buffer: After calling this function the VkCommandBuffer + * referenced by this parameter will contain the VKCommandBuffer handle + * of the current back buffer (when swap chains are enabled) or + * it will contain a general VkCommandQueue. + * \returns GHOST_kFailure when context isn't a Vulkan context. + * GHOST_kSuccess when the context is a Vulkan context and the + * handles have been set. + */ virtual GHOST_TSuccess getVulkanCommandBuffer(void * /*r_command_buffer*/) override { return GHOST_kFailure; }; /** - * Gets the Vulkan framebuffer related resource handles associated with the Vulkan context. - * Needs to be called after each swap events as the framebuffer will change. - * \return A boolean success indicator. + * Gets the Vulkan backbuffer related resource handles associated with the Vulkan context. + * Needs to be called after each swap event as the backbuffer will change. + * + * \param r_image: After calling this function the VkImage + * referenced by this parameter will contain the VKImage handle + * of the current back buffer. + * \param r_framebuffer: After calling this function the VkFramebuffer + * referenced by this parameter will contain the VKFramebuffer handle + * of the current back buffer. + * \param r_render_pass: After calling this function the VkRenderPass + * referenced by this parameter will contain the VKRenderPass handle + * of the current back buffer. + * \param r_extent: After calling this function the VkExtent2D + * referenced by this parameter will contain the size of the + * frame buffer and image in pixels. + * \param r_fb_id: After calling this function the uint32_t + * referenced by this parameter will contain the id of the + * framebuffer of the current back buffer. + * \returns GHOST_kFailure when context isn't a Vulkan context. + * GHOST_kSuccess when the context is a Vulkan context and the + * handles have been set. */ - virtual GHOST_TSuccess getVulkanBackbuffer(void * /*image*/, - void * /*framebuffer*/, - void * /*render_pass*/, - void * /*extent*/, + virtual GHOST_TSuccess getVulkanBackbuffer(void * /*r_image*/, + void * /*r_framebuffer*/, + void * /*r_render_pass*/, + void * /*r_extent*/, uint32_t * /*fb_id*/) override { return GHOST_kFailure; -- 2.30.2 From 380e69148e44381b4af9d30764f5dbf76efb9e9e Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Thu, 16 Feb 2023 12:13:14 +0100 Subject: [PATCH 16/55] Check if image format is supported. --- source/blender/gpu/vulkan/vk_context.hh | 5 +++++ source/blender/gpu/vulkan/vk_texture.cc | 24 ++++++++++++++++++------ 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/source/blender/gpu/vulkan/vk_context.hh b/source/blender/gpu/vulkan/vk_context.hh index a2c4ba210ee..a2521ade77c 100644 --- a/source/blender/gpu/vulkan/vk_context.hh +++ b/source/blender/gpu/vulkan/vk_context.hh @@ -54,6 +54,11 @@ class VKContext : public Context { return static_cast(Context::get()); } + VkPhysicalDevice physical_device_get() const + { + return vk_physical_device_; + } + VkDevice device_get() const { return vk_device_; diff --git a/source/blender/gpu/vulkan/vk_texture.cc b/source/blender/gpu/vulkan/vk_texture.cc index 20577f2c494..be7a247fa11 100644 --- a/source/blender/gpu/vulkan/vk_texture.cc +++ b/source/blender/gpu/vulkan/vk_texture.cc @@ -165,12 +165,24 @@ bool VKTexture::allocate() VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT); allocCreateInfo.priority = 1.0f; - VkResult result = vmaCreateImage(context.mem_allocator_get(), - &image_info, - &allocCreateInfo, - &vk_image_, - &allocation_, - nullptr); + VkImageFormatProperties image_format = {}; + VkResult result = vkGetPhysicalDeviceImageFormatProperties(context.physical_device_get(), + image_info.format, + image_info.imageType, + image_info.tiling, + image_info.usage, + image_info.flags, + &image_format); + if (result != VK_SUCCESS) { + return false; + } + + result = vmaCreateImage(context.mem_allocator_get(), + &image_info, + &allocCreateInfo, + &vk_image_, + &allocation_, + nullptr); if (result != VK_SUCCESS) { return false; } -- 2.30.2 From 74c505c25de437e802ff0939f21a83a98bfb543c Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 17 Feb 2023 09:00:44 +0100 Subject: [PATCH 17/55] Separate descriptor set bindings and gpu module bindings. --- .../gpu/intern/gpu_shader_interface.hh | 8 +++ .../blender/gpu/vulkan/vk_descriptor_set.cc | 12 ++-- .../blender/gpu/vulkan/vk_descriptor_set.hh | 70 +++++++++++++++++-- source/blender/gpu/vulkan/vk_index_buffer.cc | 6 +- source/blender/gpu/vulkan/vk_shader.cc | 60 ++++++++++++---- source/blender/gpu/vulkan/vk_shader.hh | 7 +- .../blender/gpu/vulkan/vk_shader_interface.cc | 37 ++++++++-- .../blender/gpu/vulkan/vk_shader_interface.hh | 9 +++ .../blender/gpu/vulkan/vk_storage_buffer.cc | 6 +- source/blender/gpu/vulkan/vk_texture.cc | 36 ++++++---- source/blender/gpu/vulkan/vk_vertex_buffer.cc | 6 +- 11 files changed, 211 insertions(+), 46 deletions(-) diff --git a/source/blender/gpu/intern/gpu_shader_interface.hh b/source/blender/gpu/intern/gpu_shader_interface.hh index fc9eafca3a5..24c4bde0971 100644 --- a/source/blender/gpu/intern/gpu_shader_interface.hh +++ b/source/blender/gpu/intern/gpu_shader_interface.hh @@ -26,6 +26,14 @@ namespace blender::gpu { typedef struct ShaderInput { uint32_t name_offset; uint32_t name_hash; + /** + * Location is openGl legacy and its legacy usages should be phased out in Blender 3.7. + * + * Vulkan backend use location to encode the descriptor set binding. This binding is different + * than the binding stored in the binding attribute. In Vulkan the binding inside a descriptor + * set must be unique. In future the location will also be used to select the right descriptor + * set. + */ int32_t location; /** Defined at interface creation or in shader. Only for Samplers, UBOs and Vertex Attributes. */ int32_t binding; diff --git a/source/blender/gpu/vulkan/vk_descriptor_set.cc b/source/blender/gpu/vulkan/vk_descriptor_set.cc index e82d5a897f2..e41c21dda54 100644 --- a/source/blender/gpu/vulkan/vk_descriptor_set.cc +++ b/source/blender/gpu/vulkan/vk_descriptor_set.cc @@ -30,7 +30,7 @@ void VKDescriptorSet::mark_freed() vk_descriptor_pool_ = VK_NULL_HANDLE; } -void VKDescriptorSet::bind(VKStorageBuffer &buffer, int location) +void VKDescriptorSet::bind(VKStorageBuffer &buffer, const Location location) { Binding &binding = ensure_location(location); binding.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; @@ -38,7 +38,7 @@ void VKDescriptorSet::bind(VKStorageBuffer &buffer, int location) binding.buffer_size = buffer.size_in_bytes(); } -void VKDescriptorSet::bind_as_ssbo(VKVertexBuffer &buffer, int location) +void VKDescriptorSet::bind_as_ssbo(VKVertexBuffer &buffer, const Location location) { Binding &binding = ensure_location(location); binding.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; @@ -46,7 +46,7 @@ void VKDescriptorSet::bind_as_ssbo(VKVertexBuffer &buffer, int location) binding.buffer_size = buffer.size_used_get(); } -void VKDescriptorSet::bind_as_ssbo(VKIndexBuffer &buffer, int location) +void VKDescriptorSet::bind_as_ssbo(VKIndexBuffer &buffer, const Location location) { Binding &binding = ensure_location(location); binding.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; @@ -54,14 +54,14 @@ void VKDescriptorSet::bind_as_ssbo(VKIndexBuffer &buffer, int location) binding.buffer_size = buffer.size_get(); } -void VKDescriptorSet::image_bind(VKTexture &texture, int location) +void VKDescriptorSet::image_bind(VKTexture &texture, const Location location) { Binding &binding = ensure_location(location); binding.type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; binding.vk_image_view = texture.vk_image_view_handle(); } -VKDescriptorSet::Binding &VKDescriptorSet::ensure_location(int location) +VKDescriptorSet::Binding &VKDescriptorSet::ensure_location(const Location location) { for (Binding &binding : bindings_) { if (binding.location == location) { @@ -121,6 +121,8 @@ void VKDescriptorSet::update(VkDevice vk_device) vkUpdateDescriptorSets( vk_device, descriptor_writes.size(), descriptor_writes.data(), 0, nullptr); + + bindings_.clear(); } } // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_descriptor_set.hh b/source/blender/gpu/vulkan/vk_descriptor_set.hh index c93cdabff11..f16f939c98c 100644 --- a/source/blender/gpu/vulkan/vk_descriptor_set.hh +++ b/source/blender/gpu/vulkan/vk_descriptor_set.hh @@ -10,6 +10,8 @@ #include "BLI_utility_mixins.hh" #include "BLI_vector.hh" +#include "gpu_shader_private.hh" + #include "vk_common.hh" namespace blender::gpu { @@ -18,9 +20,59 @@ class VKVertexBuffer; class VKIndexBuffer; class VKTexture; +/** + * In vulkan shader resources (images and buffers) are grouped in descriptor sets. + * + * The resources inside a descriptor set can be updated and bound per set. + * + * Currently Blender only supports a single descriptor set per shader, but it is planned to be able + * to use 2 descriptor sets per shader. Only for each #blender::gpu::shader::Frequency. + */ class VKDescriptorSet : NonCopyable { + struct Binding; + + public: + /** + * Binding location of a resource in a descriptor set. + * + * Locations and bindings are used for different reasons. In the Vulkan backend we use + * ShaderInput.location to store the descriptor set + the resource binding inside the descriptor + * set. To ease the development the VKDescriptorSet::Location will be used to hide this + * confusion. + * + * NOTE: [future development] When supporting multiple descriptor sets the encoding/decoding can + * be centralized here. Location will then also contain the descriptor set index. + */ + struct Location { + private: + /** + * References to a binding in the descriptor set. + */ + uint32_t binding; + + Location() = default; + + public: + Location(const ShaderInput *shader_input) : binding(shader_input->location) + { + } + + bool operator==(const Location &other) const + { + return binding == other.binding; + } + + operator uint32_t() const + { + return binding; + } + + friend struct Binding; + }; + + private: struct Binding { - int location = -1; + Location location; VkDescriptorType type; VkBuffer vk_buffer = VK_NULL_HANDLE; @@ -28,6 +80,11 @@ class VKDescriptorSet : NonCopyable { VkImageView vk_image_view = VK_NULL_HANDLE; + Binding() + { + location.binding = 0; + } + bool is_buffer() const { return ELEM(type, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); @@ -42,6 +99,7 @@ class VKDescriptorSet : NonCopyable { VkDescriptorPool vk_descriptor_pool_ = VK_NULL_HANDLE; VkDescriptorSet vk_descriptor_set_ = VK_NULL_HANDLE; + /** A list of bindings that needs to be updated.*/ Vector bindings_; public: @@ -70,10 +128,10 @@ class VKDescriptorSet : NonCopyable { return vk_descriptor_pool_; } - void bind_as_ssbo(VKVertexBuffer &buffer, int location); - void bind_as_ssbo(VKIndexBuffer &buffer, int location); - void bind(VKStorageBuffer &buffer, int location); - void image_bind(VKTexture &texture, int location); + void bind_as_ssbo(VKVertexBuffer &buffer, Location location); + void bind_as_ssbo(VKIndexBuffer &buffer, Location location); + void bind(VKStorageBuffer &buffer, Location location); + void image_bind(VKTexture &texture, Location location); /** * Update the descriptor set on the device. @@ -83,7 +141,7 @@ class VKDescriptorSet : NonCopyable { void mark_freed(); private: - Binding &ensure_location(int location); + Binding &ensure_location(Location location); }; } // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_index_buffer.cc b/source/blender/gpu/vulkan/vk_index_buffer.cc index 67a50b134d0..1d6e620a395 100644 --- a/source/blender/gpu/vulkan/vk_index_buffer.cc +++ b/source/blender/gpu/vulkan/vk_index_buffer.cc @@ -7,6 +7,7 @@ #include "vk_index_buffer.hh" #include "vk_shader.hh" +#include "vk_shader_interface.hh" namespace blender::gpu { @@ -22,7 +23,10 @@ void VKIndexBuffer::bind_as_ssbo(uint binding) } VKShader *shader = static_cast(context.shader); - shader->pipeline_get().descriptor_set_get().bind_as_ssbo(*this, binding); + const VKShaderInterface &shader_interface = shader->interface_get(); + const ShaderInput *shader_input = shader_interface.shader_input_get( + shader::ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER, binding); + shader->pipeline_get().descriptor_set_get().bind_as_ssbo(*this, shader_input); } void VKIndexBuffer::read(uint32_t *data) const diff --git a/source/blender/gpu/vulkan/vk_shader.cc b/source/blender/gpu/vulkan/vk_shader.cc index af1212dc2f1..cb069e45819 100644 --- a/source/blender/gpu/vulkan/vk_shader.cc +++ b/source/blender/gpu/vulkan/vk_shader.cc @@ -325,9 +325,11 @@ static std::ostream &print_qualifier(std::ostream &os, const Qualifier &qualifie return os; } -static void print_resource(std::ostream &os, const ShaderCreateInfo::Resource &res) +static void print_resource(std::ostream &os, + const ShaderInput &shader_input, + const ShaderCreateInfo::Resource &res) { - os << "layout(binding = " << res.slot; + os << "layout(binding = " << shader_input.location; if (res.bind_type == ShaderCreateInfo::Resource::BindType::IMAGE) { os << ", " << to_string(res.image.format); } @@ -373,6 +375,18 @@ static void print_resource(std::ostream &os, const ShaderCreateInfo::Resource &r } } +static void print_resource(std::ostream &os, + const VKShaderInterface &shader_interface, + const ShaderCreateInfo::Resource &res) +{ + const ShaderInput *shader_input = shader_interface.shader_input_get(res); + if (shader_input == nullptr) { + BLI_assert_msg(shader_input, "Cannot find shader input for resource"); + return; + } + print_resource(os, *shader_input, res); +} + static void print_resource_alias(std::ostream &os, const ShaderCreateInfo::Resource &res) { int64_t array_offset; @@ -655,8 +669,11 @@ bool VKShader::finalize(const shader::ShaderCreateInfo *info) return false; } + VKShaderInterface *vk_interface = new VKShaderInterface(); + vk_interface->init(*info); + VkDevice vk_device = context_->device_get(); - if (!finalize_descriptor_set_layouts(vk_device, *info)) { + if (!finalize_descriptor_set_layouts(vk_device, *vk_interface, *info)) { return false; } if (!finalize_pipeline_layout(vk_device, *info)) { @@ -683,10 +700,11 @@ bool VKShader::finalize(const shader::ShaderCreateInfo *info) } if (result) { - VKShaderInterface *vk_interface = new VKShaderInterface(); - vk_interface->init(*info); interface = vk_interface; } + else { + delete vk_interface; + } return result; } @@ -756,10 +774,10 @@ static VkDescriptorType descriptor_type( } static VkDescriptorSetLayoutBinding create_descriptor_set_layout_binding( - const shader::ShaderCreateInfo::Resource &resource) + const ShaderInput &shader_input, const shader::ShaderCreateInfo::Resource &resource) { VkDescriptorSetLayoutBinding binding = {}; - binding.binding = resource.slot; + binding.binding = shader_input.location; binding.descriptorType = descriptor_type(resource.bind_type); binding.descriptorCount = 1; binding.stageFlags = VK_SHADER_STAGE_ALL; @@ -769,19 +787,27 @@ static VkDescriptorSetLayoutBinding create_descriptor_set_layout_binding( } static void add_descriptor_set_layout_bindings( + const VKShaderInterface &interface, const Vector &resources, Vector &r_bindings) { for (const shader::ShaderCreateInfo::Resource &resource : resources) { - r_bindings.append(create_descriptor_set_layout_binding(resource)); + const ShaderInput *shader_input = interface.shader_input_get(resource); + if (shader_input == nullptr) { + BLI_assert_msg(shader_input, "Cannot find shader input for resource."); + continue; + } + + r_bindings.append(create_descriptor_set_layout_binding(*shader_input, resource)); } } static VkDescriptorSetLayoutCreateInfo create_descriptor_set_layout( + const VKShaderInterface &interface, const Vector &resources, Vector &r_bindings) { - add_descriptor_set_layout_bindings(resources, r_bindings); + add_descriptor_set_layout_bindings(interface, resources, r_bindings); VkDescriptorSetLayoutCreateInfo set_info = {}; set_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; set_info.flags = 0; @@ -792,6 +818,7 @@ static VkDescriptorSetLayoutCreateInfo create_descriptor_set_layout( } bool VKShader::finalize_descriptor_set_layouts(VkDevice vk_device, + const VKShaderInterface &shader_interface, const shader::ShaderCreateInfo &info) { if (info.pass_resources_.is_empty() && info.batch_resources_.is_empty()) { @@ -809,8 +836,8 @@ bool VKShader::finalize_descriptor_set_layouts(VkDevice vk_device, all_resources.extend(info.batch_resources_); Vector bindings; - VkDescriptorSetLayoutCreateInfo layout_info = create_descriptor_set_layout(all_resources, - bindings); + VkDescriptorSetLayoutCreateInfo layout_info = create_descriptor_set_layout( + shader_interface, all_resources, bindings); if (vkCreateDescriptorSetLayout(vk_device, &layout_info, vk_allocation_callbacks, &layout_) != VK_SUCCESS) { return false; @@ -869,11 +896,13 @@ void VKShader::uniform_int(int /*location*/, std::string VKShader::resources_declare(const shader::ShaderCreateInfo &info) const { + VKShaderInterface interface; + interface.init(info); std::stringstream ss; ss << "\n/* Pass Resources. */\n"; for (const ShaderCreateInfo::Resource &res : info.pass_resources_) { - print_resource(ss, res); + print_resource(ss, interface, res); } for (const ShaderCreateInfo::Resource &res : info.pass_resources_) { print_resource_alias(ss, res); @@ -881,7 +910,7 @@ std::string VKShader::resources_declare(const shader::ShaderCreateInfo &info) co ss << "\n/* Batch Resources. */\n"; for (const ShaderCreateInfo::Resource &res : info.batch_resources_) { - print_resource(ss, res); + print_resource(ss, interface, res); } for (const ShaderCreateInfo::Resource &res : info.batch_resources_) { print_resource_alias(ss, res); @@ -1095,4 +1124,9 @@ VKPipeline &VKShader::pipeline_get() return compute_pipeline_; } +const VKShaderInterface &VKShader::interface_get() const +{ + return *static_cast(interface); +} + } // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_shader.hh b/source/blender/gpu/vulkan/vk_shader.hh index b334ae39648..9c091a16598 100644 --- a/source/blender/gpu/vulkan/vk_shader.hh +++ b/source/blender/gpu/vulkan/vk_shader.hh @@ -15,6 +15,7 @@ #include "BLI_string_ref.hh" namespace blender::gpu { +class VKShaderInterface; class VKShader : public Shader { private: @@ -65,13 +66,17 @@ class VKShader : public Shader { return pipeline_layout_; } + const VKShaderInterface &interface_get() const; + private: Vector compile_glsl_to_spirv(Span sources, shaderc_shader_kind kind); void build_shader_module(Span spirv_module, VkShaderModule *r_shader_module); void build_shader_module(MutableSpan sources, shaderc_shader_kind stage, VkShaderModule *r_shader_module); - bool finalize_descriptor_set_layouts(VkDevice vk_device, const shader::ShaderCreateInfo &info); + bool finalize_descriptor_set_layouts(VkDevice vk_device, + const VKShaderInterface &shader_interface, + const shader::ShaderCreateInfo &info); bool finalize_pipeline_layout(VkDevice vk_device, const shader::ShaderCreateInfo &info); bool finalize_graphics_pipeline(VkDevice vk_device); diff --git a/source/blender/gpu/vulkan/vk_shader_interface.cc b/source/blender/gpu/vulkan/vk_shader_interface.cc index 688287953c0..6b5624182d5 100644 --- a/source/blender/gpu/vulkan/vk_shader_interface.cc +++ b/source/blender/gpu/vulkan/vk_shader_interface.cc @@ -13,6 +13,7 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) { using namespace blender::gpu::shader; + attr_len_ = 0; uniform_len_ = 0; ssbo_len_ = 0; ubo_len_ = 0; @@ -46,11 +47,14 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) name_buffer_ = (char *)MEM_mallocN(info.interface_names_size_, "name_buffer"); uint32_t name_buffer_offset = 0; + int location = 0; + /* Uniform blocks */ for (const ShaderCreateInfo::Resource &res : all_resources) { if (res.bind_type == ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER) { copy_input_name(input, res.image.name, name_buffer_, name_buffer_offset); - input->location = input->binding = res.slot; + input->location = location++; + input->binding = res.slot; enabled_ubo_mask_ |= (1 << input->binding); input++; } @@ -60,13 +64,15 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) for (const ShaderCreateInfo::Resource &res : all_resources) { if (res.bind_type == ShaderCreateInfo::Resource::BindType::SAMPLER) { copy_input_name(input, res.sampler.name, name_buffer_, name_buffer_offset); - input->location = input->binding = res.slot; + input->location = location++; + input->binding = res.slot; enabled_tex_mask_ |= (1 << input->binding); input++; } if (res.bind_type == ShaderCreateInfo::Resource::BindType::IMAGE) { copy_input_name(input, res.image.name, name_buffer_, name_buffer_offset); - input->location = input->binding = res.slot; + input->location = location++; + input->binding = res.slot; enabled_ima_mask_ |= (1 << input->binding); input++; } @@ -76,7 +82,8 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) for (const ShaderCreateInfo::Resource &res : all_resources) { if (res.bind_type == ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER) { copy_input_name(input, res.storagebuf.name, name_buffer_, name_buffer_offset); - input->location = input->binding = res.slot; + input->location = location++; + input->binding = res.slot; enabled_ssbo_mask_ |= (1 << input->binding); input++; } @@ -85,4 +92,26 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) sort_inputs(); } +const ShaderInput *VKShaderInterface::shader_input_get( + const shader::ShaderCreateInfo::Resource &resource) const +{ + return shader_input_get(resource.bind_type, resource.slot); +} + +const ShaderInput *VKShaderInterface::shader_input_get( + const shader::ShaderCreateInfo::Resource::BindType &bind_type, int binding) const +{ + switch (bind_type) { + case shader::ShaderCreateInfo::Resource::BindType::IMAGE: + return texture_get(binding); + case shader::ShaderCreateInfo::Resource::BindType::SAMPLER: + return texture_get(binding); + case shader::ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER: + return ssbo_get(binding); + case shader::ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER: + return ubo_get(binding); + } + return nullptr; +} + } // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_shader_interface.hh b/source/blender/gpu/vulkan/vk_shader_interface.hh index f741a0b133e..437dbde703c 100644 --- a/source/blender/gpu/vulkan/vk_shader_interface.hh +++ b/source/blender/gpu/vulkan/vk_shader_interface.hh @@ -16,5 +16,14 @@ class VKShaderInterface : public ShaderInterface { VKShaderInterface() = default; void init(const shader::ShaderCreateInfo &info); + /** + * Retrieve the shader input for the given resource. + * + * nullptr is returned when resource could not be found. + * Should only happen when still developing the Vulkan shader. + */ + const ShaderInput *shader_input_get(const shader::ShaderCreateInfo::Resource &resource) const; + const ShaderInput *shader_input_get( + const shader::ShaderCreateInfo::Resource::BindType &bind_type, int binding) const; }; } // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_storage_buffer.cc b/source/blender/gpu/vulkan/vk_storage_buffer.cc index d11bc46e88d..5c6d8a10244 100644 --- a/source/blender/gpu/vulkan/vk_storage_buffer.cc +++ b/source/blender/gpu/vulkan/vk_storage_buffer.cc @@ -5,6 +5,7 @@ * \ingroup gpu */ #include "vk_shader.hh" +#include "vk_shader_interface.hh" #include "vk_vertex_buffer.hh" #include "vk_storage_buffer.hh" @@ -32,7 +33,10 @@ void VKStorageBuffer::bind(int slot) allocate(context); } VKShader *shader = static_cast(context.shader); - shader->pipeline_get().descriptor_set_get().bind(*this, slot); + const VKShaderInterface &shader_interface = shader->interface_get(); + const ShaderInput *shader_input = shader_interface.shader_input_get( + shader::ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER, slot); + shader->pipeline_get().descriptor_set_get().bind(*this, shader_input); } void VKStorageBuffer::unbind() diff --git a/source/blender/gpu/vulkan/vk_texture.cc b/source/blender/gpu/vulkan/vk_texture.cc index be7a247fa11..bb587d477aa 100644 --- a/source/blender/gpu/vulkan/vk_texture.cc +++ b/source/blender/gpu/vulkan/vk_texture.cc @@ -11,6 +11,9 @@ #include "vk_context.hh" #include "vk_memory.hh" #include "vk_shader.hh" +#include "vk_shader_interface.hh" + +#include "BKE_global.h" namespace blender::gpu { @@ -159,24 +162,27 @@ bool VKTexture::allocate() VK_IMAGE_USAGE_STORAGE_BIT; image_info.samples = VK_SAMPLE_COUNT_1_BIT; + VkResult result; + if (G.debug &= G_DEBUG_GPU) { + VkImageFormatProperties image_format = {}; + result = vkGetPhysicalDeviceImageFormatProperties(context.physical_device_get(), + image_info.format, + image_info.imageType, + image_info.tiling, + image_info.usage, + image_info.flags, + &image_format); + if (result != VK_SUCCESS) { + printf("Image type not supported on device.\n"); + return false; + } + } + VmaAllocationCreateInfo allocCreateInfo = {}; allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO; allocCreateInfo.flags = static_cast( VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT); allocCreateInfo.priority = 1.0f; - - VkImageFormatProperties image_format = {}; - VkResult result = vkGetPhysicalDeviceImageFormatProperties(context.physical_device_get(), - image_info.format, - image_info.imageType, - image_info.tiling, - image_info.usage, - image_info.flags, - &image_format); - if (result != VK_SUCCESS) { - return false; - } - result = vmaCreateImage(context.mem_allocator_get(), &image_info, &allocCreateInfo, @@ -214,13 +220,15 @@ bool VKTexture::allocate() return result == VK_SUCCESS; } -void VKTexture::image_bind(int location) +void VKTexture::image_bind(int binding) { if (!is_allocated()) { allocate(); } VKContext &context = *VKContext::get(); VKShader *shader = static_cast(context.shader); + VKDescriptorSet::Location location(shader->interface_get().shader_input_get( + shader::ShaderCreateInfo::Resource::BindType::IMAGE, binding)); shader->pipeline_get().descriptor_set_get().image_bind(*this, location); } diff --git a/source/blender/gpu/vulkan/vk_vertex_buffer.cc b/source/blender/gpu/vulkan/vk_vertex_buffer.cc index 00bb97a6fcc..5d44b2e2c4f 100644 --- a/source/blender/gpu/vulkan/vk_vertex_buffer.cc +++ b/source/blender/gpu/vulkan/vk_vertex_buffer.cc @@ -8,6 +8,7 @@ #include "MEM_guardedalloc.h" #include "vk_shader.hh" +#include "vk_shader_interface.hh" #include "vk_vertex_buffer.hh" namespace blender::gpu { @@ -25,7 +26,10 @@ void VKVertexBuffer::bind_as_ssbo(uint binding) } VKShader *shader = static_cast(context.shader); - shader->pipeline_get().descriptor_set_get().bind_as_ssbo(*this, binding); + const VKShaderInterface &shader_interface = shader->interface_get(); + const ShaderInput *shader_input = shader_interface.shader_input_get( + shader::ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER, binding); + shader->pipeline_get().descriptor_set_get().bind_as_ssbo(*this, shader_input); } void VKVertexBuffer::bind_as_texture(uint /*binding*/) -- 2.30.2 From 1a6a97d8dfa0d84c1cfebf47a665afc4bf4872f4 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 17 Feb 2023 09:40:17 +0100 Subject: [PATCH 18/55] Add support for shader input lookup in shaders using samplers + images. --- source/blender/gpu/vulkan/vk_shader_interface.cc | 8 +++++--- source/blender/gpu/vulkan/vk_shader_interface.hh | 10 ++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/source/blender/gpu/vulkan/vk_shader_interface.cc b/source/blender/gpu/vulkan/vk_shader_interface.cc index 6b5624182d5..4db76a03735 100644 --- a/source/blender/gpu/vulkan/vk_shader_interface.cc +++ b/source/blender/gpu/vulkan/vk_shader_interface.cc @@ -17,6 +17,7 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) uniform_len_ = 0; ssbo_len_ = 0; ubo_len_ = 0; + image_offset_ = 0; Vector all_resources; all_resources.extend(info.pass_resources_); @@ -28,6 +29,7 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) uniform_len_++; break; case ShaderCreateInfo::Resource::BindType::SAMPLER: + image_offset_++; uniform_len_++; break; case ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER: @@ -69,10 +71,10 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) enabled_tex_mask_ |= (1 << input->binding); input++; } - if (res.bind_type == ShaderCreateInfo::Resource::BindType::IMAGE) { + else if (res.bind_type == ShaderCreateInfo::Resource::BindType::IMAGE) { copy_input_name(input, res.image.name, name_buffer_, name_buffer_offset); input->location = location++; - input->binding = res.slot; + input->binding = res.slot + image_offset_; enabled_ima_mask_ |= (1 << input->binding); input++; } @@ -103,7 +105,7 @@ const ShaderInput *VKShaderInterface::shader_input_get( { switch (bind_type) { case shader::ShaderCreateInfo::Resource::BindType::IMAGE: - return texture_get(binding); + return texture_get(binding + image_offset_); case shader::ShaderCreateInfo::Resource::BindType::SAMPLER: return texture_get(binding); case shader::ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER: diff --git a/source/blender/gpu/vulkan/vk_shader_interface.hh b/source/blender/gpu/vulkan/vk_shader_interface.hh index 437dbde703c..4e099feb680 100644 --- a/source/blender/gpu/vulkan/vk_shader_interface.hh +++ b/source/blender/gpu/vulkan/vk_shader_interface.hh @@ -12,6 +12,16 @@ namespace blender::gpu { class VKShaderInterface : public ShaderInterface { + private: + /** + * Offset when searching for a shader input based on a binding number. + * + * When shaders combine images and samplers, the images have to be offset to find the correct + * shader input. Both textures and images are stored in the uniform list and their ID can be + * overlapping. + */ + uint32_t image_offset_ = 0; + public: VKShaderInterface() = default; -- 2.30.2 From aca7d7ed352331c379367870b8bbc9654822c74c Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 17 Feb 2023 10:05:29 +0100 Subject: [PATCH 19/55] Add support for shaders without any resources. --- source/blender/gpu/vulkan/vk_shader.cc | 9 ++++++++- source/blender/gpu/vulkan/vk_shader.hh | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/source/blender/gpu/vulkan/vk_shader.cc b/source/blender/gpu/vulkan/vk_shader.cc index 3f65219b6e8..0921cef9a47 100644 --- a/source/blender/gpu/vulkan/vk_shader.cc +++ b/source/blender/gpu/vulkan/vk_shader.cc @@ -746,10 +746,12 @@ bool VKShader::finalize_pipeline_layout(VkDevice vk_device, const shader::ShaderCreateInfo & /*info*/) { VK_ALLOCATION_CALLBACKS + + const uint32_t layout_count = layout_ == VK_NULL_HANDLE ? 0 : 1; VkPipelineLayoutCreateInfo pipeline_info = {}; pipeline_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipeline_info.flags = 0; - pipeline_info.setLayoutCount = 1; + pipeline_info.setLayoutCount = layout_count; pipeline_info.pSetLayouts = &layout_; if (vkCreatePipelineLayout( @@ -904,6 +906,11 @@ std::string VKShader::resources_declare(const shader::ShaderCreateInfo &info) co interface.init(info); std::stringstream ss; + if (info.name_ == "gpu_shader_keyframe_shape") { + printf("%s\n", __func__); + interface.debug_print(); + } + ss << "\n/* Pass Resources. */\n"; for (const ShaderCreateInfo::Resource &res : info.pass_resources_) { print_resource(ss, interface, res); diff --git a/source/blender/gpu/vulkan/vk_shader.hh b/source/blender/gpu/vulkan/vk_shader.hh index b0a41ffd74c..b4c138f00b4 100644 --- a/source/blender/gpu/vulkan/vk_shader.hh +++ b/source/blender/gpu/vulkan/vk_shader.hh @@ -25,7 +25,7 @@ class VKShader : public Shader { VkShaderModule fragment_module_ = VK_NULL_HANDLE; VkShaderModule compute_module_ = VK_NULL_HANDLE; bool compilation_failed_ = false; - VkDescriptorSetLayout layout_; + VkDescriptorSetLayout layout_ = VK_NULL_HANDLE; VkPipelineLayout pipeline_layout_ = VK_NULL_HANDLE; VKPipeline compute_pipeline_; -- 2.30.2 From 902250a704318cd343af86dca87e9fc4547d0f94 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 17 Feb 2023 10:15:14 +0100 Subject: [PATCH 20/55] Remove debug statement. --- source/blender/gpu/vulkan/vk_shader.cc | 5 ----- 1 file changed, 5 deletions(-) diff --git a/source/blender/gpu/vulkan/vk_shader.cc b/source/blender/gpu/vulkan/vk_shader.cc index 0921cef9a47..7d5f2409bc6 100644 --- a/source/blender/gpu/vulkan/vk_shader.cc +++ b/source/blender/gpu/vulkan/vk_shader.cc @@ -906,11 +906,6 @@ std::string VKShader::resources_declare(const shader::ShaderCreateInfo &info) co interface.init(info); std::stringstream ss; - if (info.name_ == "gpu_shader_keyframe_shape") { - printf("%s\n", __func__); - interface.debug_print(); - } - ss << "\n/* Pass Resources. */\n"; for (const ShaderCreateInfo::Resource &res : info.pass_resources_) { print_resource(ss, interface, res); -- 2.30.2 From c7b9a5a75979da751a7c23300b5b9f8a4810b6af Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 17 Feb 2023 11:29:20 +0100 Subject: [PATCH 21/55] Remove binding clashing between textures and images. --- source/blender/gpu/vulkan/vk_shader_interface.cc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/source/blender/gpu/vulkan/vk_shader_interface.cc b/source/blender/gpu/vulkan/vk_shader_interface.cc index 4db76a03735..cec6213bc5b 100644 --- a/source/blender/gpu/vulkan/vk_shader_interface.cc +++ b/source/blender/gpu/vulkan/vk_shader_interface.cc @@ -17,7 +17,7 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) uniform_len_ = 0; ssbo_len_ = 0; ubo_len_ = 0; - image_offset_ = 0; + image_offset_ = -1; Vector all_resources; all_resources.extend(info.pass_resources_); @@ -29,7 +29,7 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) uniform_len_++; break; case ShaderCreateInfo::Resource::BindType::SAMPLER: - image_offset_++; + image_offset_ = max_ii(image_offset_, res.slot); uniform_len_++; break; case ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER: @@ -40,6 +40,8 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) break; } } + /* Make sure that the image slots don't overlap with the sampler slots.*/ + image_offset_ += 1; int32_t input_tot_len = ubo_len_ + uniform_len_ + ssbo_len_; inputs_ = static_cast( @@ -57,7 +59,6 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) copy_input_name(input, res.image.name, name_buffer_, name_buffer_offset); input->location = location++; input->binding = res.slot; - enabled_ubo_mask_ |= (1 << input->binding); input++; } } @@ -68,14 +69,12 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) copy_input_name(input, res.sampler.name, name_buffer_, name_buffer_offset); input->location = location++; input->binding = res.slot; - enabled_tex_mask_ |= (1 << input->binding); input++; } else if (res.bind_type == ShaderCreateInfo::Resource::BindType::IMAGE) { copy_input_name(input, res.image.name, name_buffer_, name_buffer_offset); input->location = location++; input->binding = res.slot + image_offset_; - enabled_ima_mask_ |= (1 << input->binding); input++; } } @@ -86,7 +85,6 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) copy_input_name(input, res.storagebuf.name, name_buffer_, name_buffer_offset); input->location = location++; input->binding = res.slot; - enabled_ssbo_mask_ |= (1 << input->binding); input++; } } -- 2.30.2 From e7d683106e0940f254044b0a4b87cdd8bfc3faa2 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 17 Feb 2023 15:20:12 +0100 Subject: [PATCH 22/55] Initial commit for push constants. --- source/blender/gpu/CMakeLists.txt | 3 + .../gpu/tests/gpu_push_constants_test.cc | 19 +++ .../blender/gpu/vulkan/vk_descriptor_pools.cc | 1 + .../blender/gpu/vulkan/vk_descriptor_pools.hh | 1 + .../blender/gpu/vulkan/vk_push_constants.cc | 109 ++++++++++++++++++ .../blender/gpu/vulkan/vk_push_constants.hh | 44 +++++++ source/blender/gpu/vulkan/vk_shader.cc | 101 +++++++++++++++- source/blender/gpu/vulkan/vk_shader.hh | 2 + 8 files changed, 274 insertions(+), 6 deletions(-) create mode 100644 source/blender/gpu/tests/gpu_push_constants_test.cc create mode 100644 source/blender/gpu/vulkan/vk_push_constants.cc create mode 100644 source/blender/gpu/vulkan/vk_push_constants.hh diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index e4b57804929..d3d7c738d39 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -204,6 +204,7 @@ set(VULKAN_SRC vulkan/vk_pipeline.cc vulkan/vk_memory.cc vulkan/vk_pixel_buffer.cc + vulkan/vk_push_constants.cc vulkan/vk_query.cc vulkan/vk_shader.cc vulkan/vk_shader_interface.cc @@ -229,6 +230,7 @@ set(VULKAN_SRC vulkan/vk_pipeline.hh vulkan/vk_memory.hh vulkan/vk_pixel_buffer.hh + vulkan/vk_push_constants.hh vulkan/vk_query.hh vulkan/vk_shader.hh vulkan/vk_shader_interface.hh @@ -802,6 +804,7 @@ if(WITH_GTESTS) tests/gpu_testing.cc tests/gpu_index_buffer_test.cc + tests/gpu_push_constants_test.cc tests/gpu_shader_builtin_test.cc tests/gpu_shader_test.cc tests/gpu_storage_buffer_test.cc diff --git a/source/blender/gpu/tests/gpu_push_constants_test.cc b/source/blender/gpu/tests/gpu_push_constants_test.cc new file mode 100644 index 00000000000..0c08b971f02 --- /dev/null +++ b/source/blender/gpu/tests/gpu_push_constants_test.cc @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include "testing/testing.h" + +#include "GPU_storage_buffer.h" + +#include "BLI_vector.hh" + +#include "gpu_testing.hh" + +namespace blender::gpu::tests { + +static void test_push_constants() +{ +} + +GPU_TEST(push_constants); + +} // namespace blender::gpu::tests \ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_descriptor_pools.cc b/source/blender/gpu/vulkan/vk_descriptor_pools.cc index a83e83f7aa3..d525cd918e7 100644 --- a/source/blender/gpu/vulkan/vk_descriptor_pools.cc +++ b/source/blender/gpu/vulkan/vk_descriptor_pools.cc @@ -43,6 +43,7 @@ void VKDescriptorPools::add_new_pool() {VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, POOL_SIZE_STORAGE_IMAGE}, {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, POOL_SIZE_COMBINED_IMAGE_SAMPLER}, {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, POOL_SIZE_UNIFORM_BUFFER}, + {VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, POOL_SIZE_UNIFORM_TEXEL_BUFFER}, }; VkDescriptorPoolCreateInfo pool_info = {}; pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; diff --git a/source/blender/gpu/vulkan/vk_descriptor_pools.hh b/source/blender/gpu/vulkan/vk_descriptor_pools.hh index 71292e019a3..8e90fafa87b 100644 --- a/source/blender/gpu/vulkan/vk_descriptor_pools.hh +++ b/source/blender/gpu/vulkan/vk_descriptor_pools.hh @@ -35,6 +35,7 @@ class VKDescriptorPools { static constexpr uint32_t POOL_SIZE_STORAGE_IMAGE = 1000; static constexpr uint32_t POOL_SIZE_COMBINED_IMAGE_SAMPLER = 1000; static constexpr uint32_t POOL_SIZE_UNIFORM_BUFFER = 1000; + static constexpr uint32_t POOL_SIZE_UNIFORM_TEXEL_BUFFER = 1000; VkDevice vk_device_ = VK_NULL_HANDLE; Vector pools_; diff --git a/source/blender/gpu/vulkan/vk_push_constants.cc b/source/blender/gpu/vulkan/vk_push_constants.cc new file mode 100644 index 00000000000..095168f5c6a --- /dev/null +++ b/source/blender/gpu/vulkan/vk_push_constants.cc @@ -0,0 +1,109 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2023 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#include "vk_push_constants.hh" + +namespace blender::gpu { + +static uint32_t to_component_size(const shader::Type /*type*/) +{ + return 4; +} + +static uint32_t to_num_components(const shader::Type type) +{ + switch (type) { + case shader::Type::FLOAT: + case shader::Type::UINT: + case shader::Type::INT: + case shader::Type::BOOL: + return 1; + case shader::Type::VEC2: + case shader::Type::UVEC2: + case shader::Type::IVEC2: + return 2; + case shader::Type::VEC3: + case shader::Type::UVEC3: + case shader::Type::IVEC3: + case shader::Type::VEC4: + case shader::Type::UVEC4: + case shader::Type::IVEC4: + return 4; + case shader::Type::MAT3: + return 12; + case shader::Type::MAT4: + return 16; + default: + BLI_assert_msg(false, "Type not supported as push constant"); + } + return 0; +} + +static uint32_t to_alignment(const shader::Type type) +{ + switch (type) { + case shader::Type::FLOAT: + case shader::Type::UINT: + case shader::Type::INT: + case shader::Type::BOOL: + return 4; + case shader::Type::VEC2: + case shader::Type::UVEC2: + case shader::Type::IVEC2: + return 8; + case shader::Type::VEC3: + case shader::Type::UVEC3: + case shader::Type::IVEC3: + case shader::Type::VEC4: + case shader::Type::UVEC4: + case shader::Type::IVEC4: + case shader::Type::MAT3: + case shader::Type::MAT4: + return 16; + default: + BLI_assert_msg(false, "Type not supported as push constant"); + } + return 0; +} + +static VKPushConstantsLayout::PushConstantLayout init_constant( + const shader::ShaderCreateInfo::PushConst &push_constant, uint32_t *r_offset) +{ + VKPushConstantsLayout::PushConstantLayout layout; + layout.type = push_constant.type; + layout.array_size = push_constant.array_size; + layout.offset = *r_offset; + + /* Perform alignment. */ + uint32_t alignment = to_alignment(push_constant.type); + uint32_t alignment_mask = alignment - 1; + if ((layout.offset & alignment_mask) != 0) { + layout.offset &= ~alignment_mask; + layout.offset += alignment; + } + + uint32_t size = to_num_components(push_constant.type) * to_component_size(push_constant.type); + if (push_constant.array_size != 0) { + size *= push_constant.array_size; + } + + *r_offset = layout.offset + size; + return layout; +} + +void VKPushConstantsLayout::init(const shader::ShaderCreateInfo &info, + const VKShaderInterface &interface) +{ + BLI_assert(push_constants.is_empty()); + uint32_t offset = 0; + for (const shader::ShaderCreateInfo::PushConst &push_constant : info.push_constants_) { + push_constants.append(init_constant(push_constant, &offset)); + } + size_in_bytes_ = offset; +} + +} // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_push_constants.hh b/source/blender/gpu/vulkan/vk_push_constants.hh new file mode 100644 index 00000000000..47cdd1659b0 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_push_constants.hh @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2023 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "BLI_vector.hh" + +#include "vk_common.hh" +#include "vk_shader_interface.hh" + +namespace blender::gpu { + +struct VKPushConstantsLayout { + struct PushConstantLayout { + uint32_t offset; + shader::Type type; + int array_size; + }; + + private: + Vector push_constants; + uint32_t size_in_bytes_; + + public: + void init(const shader::ShaderCreateInfo &info, const VKShaderInterface &interface); + + uint32_t size_in_bytes() const + { + return size_in_bytes_; + } +}; + +struct VKPushConstants { + const VKPushConstantsLayout &layout_; + uint32_t *data = nullptr; + + VKPushConstants(const VKPushConstantsLayout &layout); +}; + +} // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_shader.cc b/source/blender/gpu/vulkan/vk_shader.cc index 7d5f2409bc6..017a6e3533f 100644 --- a/source/blender/gpu/vulkan/vk_shader.cc +++ b/source/blender/gpu/vulkan/vk_shader.cc @@ -680,6 +680,7 @@ bool VKShader::finalize(const shader::ShaderCreateInfo *info) if (!finalize_descriptor_set_layouts(vk_device, *vk_interface, *info)) { return false; } + push_constants_layout_.init(*info, *vk_interface); if (!finalize_pipeline_layout(vk_device, *info)) { return false; } @@ -749,10 +750,18 @@ bool VKShader::finalize_pipeline_layout(VkDevice vk_device, const uint32_t layout_count = layout_ == VK_NULL_HANDLE ? 0 : 1; VkPipelineLayoutCreateInfo pipeline_info = {}; + VkPushConstantRange push_constant_range = {}; pipeline_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipeline_info.flags = 0; pipeline_info.setLayoutCount = layout_count; pipeline_info.pSetLayouts = &layout_; + if (push_constants_layout_.size_in_bytes() != 0) { + push_constant_range.offset = 0; + push_constant_range.size = push_constants_layout_.size_in_bytes(); + push_constant_range.stageFlags = VK_SHADER_STAGE_ALL; + pipeline_info.pushConstantRangeCount = 1; + pipeline_info.pPushConstantRanges = &push_constant_range; + } if (vkCreatePipelineLayout( vk_device, &pipeline_info, vk_allocation_callbacks, &pipeline_layout_) != VK_SUCCESS) { @@ -762,14 +771,94 @@ bool VKShader::finalize_pipeline_layout(VkDevice vk_device, return true; } -static VkDescriptorType descriptor_type( - const shader::ShaderCreateInfo::Resource::BindType bind_type) +static VkDescriptorType storage_descriptor_type(const shader::ImageType &image_type) { - switch (bind_type) { - case shader::ShaderCreateInfo::Resource::BindType::IMAGE: + switch (image_type) { + case shader::ImageType::FLOAT_1D: + case shader::ImageType::FLOAT_1D_ARRAY: + case shader::ImageType::FLOAT_2D: + case shader::ImageType::FLOAT_2D_ARRAY: + case shader::ImageType::FLOAT_3D: + case shader::ImageType::FLOAT_CUBE: + case shader::ImageType::FLOAT_CUBE_ARRAY: + case shader::ImageType::INT_1D: + case shader::ImageType::INT_1D_ARRAY: + case shader::ImageType::INT_2D: + case shader::ImageType::INT_2D_ARRAY: + case shader::ImageType::INT_3D: + case shader::ImageType::INT_CUBE: + case shader::ImageType::INT_CUBE_ARRAY: + case shader::ImageType::UINT_1D: + case shader::ImageType::UINT_1D_ARRAY: + case shader::ImageType::UINT_2D: + case shader::ImageType::UINT_2D_ARRAY: + case shader::ImageType::UINT_3D: + case shader::ImageType::UINT_CUBE: + case shader::ImageType::UINT_CUBE_ARRAY: return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - case shader::ShaderCreateInfo::Resource::BindType::SAMPLER: + + case shader::ImageType::FLOAT_BUFFER: + case shader::ImageType::INT_BUFFER: + case shader::ImageType::UINT_BUFFER: + return VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; + + default: + BLI_assert_msg(false, "ImageType not supported."); + } + + return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; +} + +static VkDescriptorType sampler_descriptor_type(const shader::ImageType &image_type) +{ + switch (image_type) { + case shader::ImageType::FLOAT_1D: + case shader::ImageType::FLOAT_1D_ARRAY: + case shader::ImageType::FLOAT_2D: + case shader::ImageType::FLOAT_2D_ARRAY: + case shader::ImageType::FLOAT_3D: + case shader::ImageType::FLOAT_CUBE: + case shader::ImageType::FLOAT_CUBE_ARRAY: + case shader::ImageType::INT_1D: + case shader::ImageType::INT_1D_ARRAY: + case shader::ImageType::INT_2D: + case shader::ImageType::INT_2D_ARRAY: + case shader::ImageType::INT_3D: + case shader::ImageType::INT_CUBE: + case shader::ImageType::INT_CUBE_ARRAY: + case shader::ImageType::UINT_1D: + case shader::ImageType::UINT_1D_ARRAY: + case shader::ImageType::UINT_2D: + case shader::ImageType::UINT_2D_ARRAY: + case shader::ImageType::UINT_3D: + case shader::ImageType::UINT_CUBE: + case shader::ImageType::UINT_CUBE_ARRAY: + case shader::ImageType::SHADOW_2D: + case shader::ImageType::SHADOW_2D_ARRAY: + case shader::ImageType::SHADOW_CUBE: + case shader::ImageType::SHADOW_CUBE_ARRAY: + case shader::ImageType::DEPTH_2D: + case shader::ImageType::DEPTH_2D_ARRAY: + case shader::ImageType::DEPTH_CUBE: + case shader::ImageType::DEPTH_CUBE_ARRAY: return VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + + case shader::ImageType::FLOAT_BUFFER: + case shader::ImageType::INT_BUFFER: + case shader::ImageType::UINT_BUFFER: + return VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; + } + + return VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; +} + +static VkDescriptorType descriptor_type(const shader::ShaderCreateInfo::Resource &resource) +{ + switch (resource.bind_type) { + case shader::ShaderCreateInfo::Resource::BindType::IMAGE: + return storage_descriptor_type(resource.image.type); + case shader::ShaderCreateInfo::Resource::BindType::SAMPLER: + return sampler_descriptor_type(resource.sampler.type); case shader::ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER: return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; case shader::ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER: @@ -784,7 +873,7 @@ static VkDescriptorSetLayoutBinding create_descriptor_set_layout_binding( { VkDescriptorSetLayoutBinding binding = {}; binding.binding = shader_input.location; - binding.descriptorType = descriptor_type(resource.bind_type); + binding.descriptorType = descriptor_type(resource); binding.descriptorCount = 1; binding.stageFlags = VK_SHADER_STAGE_ALL; binding.pImmutableSamplers = nullptr; diff --git a/source/blender/gpu/vulkan/vk_shader.hh b/source/blender/gpu/vulkan/vk_shader.hh index b4c138f00b4..d88489a2c5e 100644 --- a/source/blender/gpu/vulkan/vk_shader.hh +++ b/source/blender/gpu/vulkan/vk_shader.hh @@ -11,6 +11,7 @@ #include "vk_backend.hh" #include "vk_context.hh" +#include "vk_push_constants.hh" #include "BLI_string_ref.hh" @@ -27,6 +28,7 @@ class VKShader : public Shader { bool compilation_failed_ = false; VkDescriptorSetLayout layout_ = VK_NULL_HANDLE; VkPipelineLayout pipeline_layout_ = VK_NULL_HANDLE; + VKPushConstantsLayout push_constants_layout_; VKPipeline compute_pipeline_; public: -- 2.30.2 From a8dc114efc1196a448cb3ed28a954585a85851d2 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Mon, 20 Feb 2023 15:43:31 +0100 Subject: [PATCH 23/55] First round trip of using push constants. --- source/blender/gpu/CMakeLists.txt | 1 + .../gpu/shaders/infos/gpu_shader_test_info.hh | 13 ++++ .../gpu/tests/gpu_push_constants_test.cc | 65 ++++++++++++++++++- .../shaders/gpu_push_constants_test.glsl | 16 +++++ source/blender/gpu/vulkan/vk_backend.cc | 2 + .../blender/gpu/vulkan/vk_command_buffer.cc | 16 +++++ .../blender/gpu/vulkan/vk_command_buffer.hh | 4 ++ source/blender/gpu/vulkan/vk_context.cc | 8 +++ source/blender/gpu/vulkan/vk_context.hh | 11 ++++ .../blender/gpu/vulkan/vk_descriptor_set.cc | 9 +++ .../blender/gpu/vulkan/vk_descriptor_set.hh | 1 + source/blender/gpu/vulkan/vk_pipeline.cc | 20 ++++-- source/blender/gpu/vulkan/vk_pipeline.hh | 19 +++++- .../blender/gpu/vulkan/vk_push_constants.cc | 48 +++++++++++++- .../blender/gpu/vulkan/vk_push_constants.hh | 60 +++++++++++++++-- source/blender/gpu/vulkan/vk_shader.cc | 12 ++-- .../blender/gpu/vulkan/vk_shader_interface.cc | 16 ++++- 17 files changed, 296 insertions(+), 25 deletions(-) create mode 100644 source/blender/gpu/tests/shaders/gpu_push_constants_test.glsl diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index d3d7c738d39..d08b41e52fc 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -531,6 +531,7 @@ set(GLSL_SRC_TEST tests/shaders/gpu_compute_ssbo_test.glsl tests/shaders/gpu_compute_vbo_test.glsl tests/shaders/gpu_compute_dummy_test.glsl + tests/shaders/gpu_push_constants_test.glsl ) set(MTL_BACKEND_GLSL_SRC diff --git a/source/blender/gpu/shaders/infos/gpu_shader_test_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_test_info.hh index e612c7ebbb1..5343b64a2e2 100644 --- a/source/blender/gpu/shaders/infos/gpu_shader_test_info.hh +++ b/source/blender/gpu/shaders/infos/gpu_shader_test_info.hh @@ -55,6 +55,19 @@ GPU_SHADER_CREATE_INFO(gpu_compute_ssbo_binding_test) .compute_source("gpu_compute_dummy_test.glsl") .do_static_compilation(true); +GPU_SHADER_CREATE_INFO(gpu_push_constants_base_test) + .local_group_size(1) + .storage_buf(0, Qualifier::WRITE, "float", "data_out[]") + .compute_source("gpu_push_constants_test.glsl"); + +GPU_SHADER_CREATE_INFO(gpu_push_constants_packed_test) + .additional_info("gpu_push_constants_base_test") + .push_constant(Type::FLOAT, "float_in") + .push_constant(Type::VEC2, "vec2_in") + .push_constant(Type::VEC3, "vec3_in") + .push_constant(Type::VEC4, "vec4_in") + .do_static_compilation(true); + GPU_SHADER_CREATE_INFO(eevee_shadow_test) .fragment_source("eevee_shadow_test.glsl") .additional_info("gpu_shader_test") diff --git a/source/blender/gpu/tests/gpu_push_constants_test.cc b/source/blender/gpu/tests/gpu_push_constants_test.cc index 0c08b971f02..b0a80e5669c 100644 --- a/source/blender/gpu/tests/gpu_push_constants_test.cc +++ b/source/blender/gpu/tests/gpu_push_constants_test.cc @@ -2,18 +2,79 @@ #include "testing/testing.h" +#include "GPU_capabilities.h" +#include "GPU_compute.h" +#include "GPU_shader.h" #include "GPU_storage_buffer.h" +#include "BLI_math_vector.hh" #include "BLI_vector.hh" #include "gpu_testing.hh" namespace blender::gpu::tests { -static void test_push_constants() +static void push_constants(const char *info_name) { + if (!GPU_compute_shader_support() && !GPU_shader_storage_buffer_objects_support()) { + /* We can't test as a the platform does not support compute shaders. */ + std::cout << "Skipping test: platform not supported"; + return; + } + + static constexpr uint SIZE = 16; + + /* Build compute shader. */ + GPUShader *shader = GPU_shader_create_from_info_name(info_name); + EXPECT_NE(shader, nullptr); + GPU_shader_bind(shader); + + /* Construct IBO. */ + GPUStorageBuf *ssbo = GPU_storagebuf_create_ex( + SIZE * sizeof(float), nullptr, GPU_USAGE_DEVICE_ONLY, __func__); + GPU_storagebuf_bind(ssbo, GPU_shader_get_ssbo_binding(shader, "data_out")); + + const float float_in = 10.0f; + const float2 vec2_in(20.0f, 21.0f); + const float3 vec3_in(30.0f, 31.0f, 32.0f); + const float4 vec4_in(40.0f, 41.0f, 42.0f, 43.0f); + GPU_shader_uniform_1f(shader, "float_in", float_in); + GPU_shader_uniform_2fv(shader, "vec2_in", vec2_in); + GPU_shader_uniform_3fv(shader, "vec3_in", vec3_in); + GPU_shader_uniform_4fv(shader, "vec4_in", vec4_in); + + /* Dispatch compute task. */ + GPU_compute_dispatch(shader, 1, 1, 1); + + /* Check if compute has been done. */ + GPU_memory_barrier(GPU_BARRIER_SHADER_STORAGE); + + /* Download the index buffer. */ + float data[SIZE]; + GPU_storagebuf_read(ssbo, data); + + /* Check the results. */ + EXPECT_EQ(data[0], float_in); + EXPECT_EQ(data[1], vec2_in.x); + EXPECT_EQ(data[2], vec2_in.y); + EXPECT_EQ(data[3], vec3_in.x); + EXPECT_EQ(data[4], vec3_in.y); + EXPECT_EQ(data[5], vec3_in.z); + EXPECT_EQ(data[6], vec4_in.x); + EXPECT_EQ(data[7], vec4_in.y); + EXPECT_EQ(data[8], vec4_in.z); + EXPECT_EQ(data[9], vec4_in.w); + + /* Cleanup. */ + GPU_shader_unbind(); + GPU_storagebuf_free(ssbo); + GPU_shader_free(shader); } -GPU_TEST(push_constants); +static void test_push_constants_packed() +{ + push_constants("gpu_push_constants_packed_test"); +} +GPU_TEST(push_constants_packed) } // namespace blender::gpu::tests \ No newline at end of file diff --git a/source/blender/gpu/tests/shaders/gpu_push_constants_test.glsl b/source/blender/gpu/tests/shaders/gpu_push_constants_test.glsl new file mode 100644 index 00000000000..1e99d74d3c3 --- /dev/null +++ b/source/blender/gpu/tests/shaders/gpu_push_constants_test.glsl @@ -0,0 +1,16 @@ +void main() +{ + data_out[0] = float_in; + + data_out[1] = vec2_in.x; + data_out[2] = vec2_in.y; + + data_out[3] = vec3_in.x; + data_out[4] = vec3_in.y; + data_out[5] = vec3_in.z; + + data_out[6] = vec4_in.x; + data_out[7] = vec4_in.y; + data_out[8] = vec4_in.z; + data_out[9] = vec4_in.w; +} diff --git a/source/blender/gpu/vulkan/vk_backend.cc b/source/blender/gpu/vulkan/vk_backend.cc index 5989a899f6a..475b1870cd2 100644 --- a/source/blender/gpu/vulkan/vk_backend.cc +++ b/source/blender/gpu/vulkan/vk_backend.cc @@ -70,6 +70,8 @@ void VKBackend::compute_dispatch(int groups_x_len, int groups_y_len, int groups_ descriptor_set.update(context.device_get()); command_buffer.bind( descriptor_set, shader->vk_pipeline_layout_get(), VK_PIPELINE_BIND_POINT_COMPUTE); + command_buffer.push_constants( + pipeline.push_constants_get(), shader->vk_pipeline_layout_get(), VK_SHADER_STAGE_ALL); command_buffer.dispatch(groups_x_len, groups_y_len, groups_z_len); } diff --git a/source/blender/gpu/vulkan/vk_command_buffer.cc b/source/blender/gpu/vulkan/vk_command_buffer.cc index 12821142b32..c9eb1e9857b 100644 --- a/source/blender/gpu/vulkan/vk_command_buffer.cc +++ b/source/blender/gpu/vulkan/vk_command_buffer.cc @@ -61,6 +61,7 @@ void VKCommandBuffer::bind(const VKPipeline &pipeline, VkPipelineBindPoint bind_ { vkCmdBindPipeline(vk_command_buffer_, bind_point, pipeline.vk_handle()); } + void VKCommandBuffer::bind(const VKDescriptorSet &descriptor_set, const VkPipelineLayout vk_pipeline_layout, VkPipelineBindPoint bind_point) @@ -70,6 +71,21 @@ void VKCommandBuffer::bind(const VKDescriptorSet &descriptor_set, vk_command_buffer_, bind_point, vk_pipeline_layout, 0, 1, &vk_descriptor_set, 0, 0); } +void VKCommandBuffer::push_constants(const VKPushConstants &push_constants, + const VkPipelineLayout vk_pipeline_layout, + const VkShaderStageFlags vk_shader_stages) +{ + if (push_constants.size_in_bytes() == 0) { + return; + } + vkCmdPushConstants(vk_command_buffer_, + vk_pipeline_layout, + vk_shader_stages, + push_constants.offset(), + push_constants.size_in_bytes(), + push_constants.data()); +} + void VKCommandBuffer::copy(VKBuffer &dst_buffer, VKTexture &src_texture, Span regions) diff --git a/source/blender/gpu/vulkan/vk_command_buffer.hh b/source/blender/gpu/vulkan/vk_command_buffer.hh index 61bb12497e5..f8393d3ccf8 100644 --- a/source/blender/gpu/vulkan/vk_command_buffer.hh +++ b/source/blender/gpu/vulkan/vk_command_buffer.hh @@ -13,6 +13,7 @@ namespace blender::gpu { class VKBuffer; class VKTexture; +class VKPushConstants; /** Command buffer to keep track of the life-time of a command buffer.*/ class VKCommandBuffer : NonCopyable, NonMovable { @@ -33,6 +34,9 @@ class VKCommandBuffer : NonCopyable, NonMovable { void bind(const VKDescriptorSet &descriptor_set, const VkPipelineLayout vk_pipeline_layout, VkPipelineBindPoint bind_point); + void push_constants(const VKPushConstants &push_constants, + const VkPipelineLayout vk_pipeline_layout, + const VkShaderStageFlags vk_shader_stages); void dispatch(int groups_x_len, int groups_y_len, int groups_z_len); /* Copy the contents of a texture mip level to the dst buffer.*/ void copy(VKBuffer &dst_buffer, VKTexture &src_texture, Span regions); diff --git a/source/blender/gpu/vulkan/vk_context.cc b/source/blender/gpu/vulkan/vk_context.cc index f28d570fd0f..ab5f3bbc790 100644 --- a/source/blender/gpu/vulkan/vk_context.cc +++ b/source/blender/gpu/vulkan/vk_context.cc @@ -30,6 +30,7 @@ VKContext::VKContext(void *ghost_window, void *ghost_context) &vk_device_, &vk_queue_family_, &vk_queue_); + init_physical_device_limits(); /* Initialize the memory allocator. */ VmaAllocatorCreateInfo info = {}; @@ -54,6 +55,13 @@ VKContext::~VKContext() vmaDestroyAllocator(mem_allocator_); } +void VKContext::init_physical_device_limits() +{ + VkPhysicalDeviceProperties properties = {}; + vkGetPhysicalDeviceProperties(vk_physical_device_, &properties); + vk_physical_device_limits_ = properties.limits; +} + void VKContext::activate() { } diff --git a/source/blender/gpu/vulkan/vk_context.hh b/source/blender/gpu/vulkan/vk_context.hh index a2521ade77c..954ead30ad1 100644 --- a/source/blender/gpu/vulkan/vk_context.hh +++ b/source/blender/gpu/vulkan/vk_context.hh @@ -30,6 +30,9 @@ class VKContext : public Context { VmaAllocator mem_allocator_ = VK_NULL_HANDLE; VKDescriptorPools descriptor_pools_; + /** Limits of the device linked to this context. */ + VkPhysicalDeviceLimits vk_physical_device_limits_; + void *ghost_context_; public: @@ -59,6 +62,11 @@ class VKContext : public Context { return vk_physical_device_; } + const VkPhysicalDeviceLimits &physical_device_limits_get() const + { + return vk_physical_device_limits_; + } + VkDevice device_get() const { return vk_device_; @@ -88,6 +96,9 @@ class VKContext : public Context { { return mem_allocator_; } + + private: + void init_physical_device_limits(); }; } // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_descriptor_set.cc b/source/blender/gpu/vulkan/vk_descriptor_set.cc index e41c21dda54..44f9d95ad36 100644 --- a/source/blender/gpu/vulkan/vk_descriptor_set.cc +++ b/source/blender/gpu/vulkan/vk_descriptor_set.cc @@ -14,6 +14,15 @@ #include "BLI_assert.h" namespace blender::gpu { + +VKDescriptorSet::VKDescriptorSet(VKDescriptorSet &&other) + : vk_descriptor_pool_(other.vk_descriptor_pool_), + vk_descriptor_set_(other.vk_descriptor_set_), + bindings_(std::move(other.bindings_)) +{ + other.mark_freed(); +} + VKDescriptorSet::~VKDescriptorSet() { if (vk_descriptor_set_ != VK_NULL_HANDLE) { diff --git a/source/blender/gpu/vulkan/vk_descriptor_set.hh b/source/blender/gpu/vulkan/vk_descriptor_set.hh index f16f939c98c..ea4fc288fc2 100644 --- a/source/blender/gpu/vulkan/vk_descriptor_set.hh +++ b/source/blender/gpu/vulkan/vk_descriptor_set.hh @@ -108,6 +108,7 @@ class VKDescriptorSet : NonCopyable { : vk_descriptor_pool_(vk_descriptor_pool), vk_descriptor_set_(vk_descriptor_set) { } + VKDescriptorSet(VKDescriptorSet &&other); virtual ~VKDescriptorSet(); VKDescriptorSet &operator=(VKDescriptorSet &&other) diff --git a/source/blender/gpu/vulkan/vk_pipeline.cc b/source/blender/gpu/vulkan/vk_pipeline.cc index 7df78597e50..73d552c9797 100644 --- a/source/blender/gpu/vulkan/vk_pipeline.cc +++ b/source/blender/gpu/vulkan/vk_pipeline.cc @@ -11,10 +11,13 @@ namespace blender::gpu { -VKPipeline::VKPipeline(VkPipeline vk_pipeline, VKDescriptorSet &&vk_descriptor_set) - : vk_pipeline_(vk_pipeline) +VKPipeline::VKPipeline(VkPipeline vk_pipeline, + VKDescriptorSet &&descriptor_set, + VKPushConstants &&push_constants) + : vk_pipeline_(vk_pipeline), + descriptor_set_(std::move(descriptor_set)), + push_constants_(std::move(push_constants)) { - descriptor_set_ = std::move(vk_descriptor_set); } VKPipeline::~VKPipeline() @@ -29,7 +32,8 @@ VKPipeline::~VKPipeline() VKPipeline VKPipeline::create_compute_pipeline(VKContext &context, VkShaderModule compute_module, VkDescriptorSetLayout &descriptor_set_layout, - VkPipelineLayout &pipeline_layout) + VkPipelineLayout &pipeline_layout, + VKPushConstantsLayout &push_constants_layout) { VK_ALLOCATION_CALLBACKS VkDevice vk_device = context.device_get(); @@ -44,15 +48,17 @@ VKPipeline VKPipeline::create_compute_pipeline(VKContext &context, pipeline_info.layout = pipeline_layout; pipeline_info.stage.pName = "main"; - VkPipeline pipeline; + VkPipeline vk_pipeline; if (vkCreateComputePipelines( - vk_device, nullptr, 1, &pipeline_info, vk_allocation_callbacks, &pipeline) != + vk_device, nullptr, 1, &pipeline_info, vk_allocation_callbacks, &vk_pipeline) != VK_SUCCESS) { return VKPipeline(); } VKDescriptorSet descriptor_set = context.descriptor_pools_get().allocate(descriptor_set_layout); - return VKPipeline(pipeline, std::move(descriptor_set)); + VKPushConstants push_constants(push_constants_layout); + return VKPipeline( + vk_pipeline, std::move(descriptor_set), std::move(push_constants)); } VkPipeline VKPipeline::vk_handle() const diff --git a/source/blender/gpu/vulkan/vk_pipeline.hh b/source/blender/gpu/vulkan/vk_pipeline.hh index b718924be7b..2f004af4ac7 100644 --- a/source/blender/gpu/vulkan/vk_pipeline.hh +++ b/source/blender/gpu/vulkan/vk_pipeline.hh @@ -7,42 +7,55 @@ #pragma once +#include + #include "BLI_utility_mixins.hh" #include "BLI_vector.hh" #include "vk_common.hh" #include "vk_descriptor_set.hh" +#include "vk_push_constants.hh" namespace blender::gpu { class VKContext; class VKPipeline : NonCopyable { - VKDescriptorSet descriptor_set_; VkPipeline vk_pipeline_ = VK_NULL_HANDLE; + VKDescriptorSet descriptor_set_; + VKPushConstants push_constants_; public: VKPipeline() = default; virtual ~VKPipeline(); - VKPipeline(VkPipeline vk_pipeline, VKDescriptorSet &&vk_descriptor_set); + VKPipeline(VkPipeline vk_pipeline, + VKDescriptorSet &&vk_descriptor_set, + VKPushConstants &&push_constants); VKPipeline &operator=(VKPipeline &&other) { vk_pipeline_ = other.vk_pipeline_; other.vk_pipeline_ = VK_NULL_HANDLE; descriptor_set_ = std::move(other.descriptor_set_); + push_constants_ = std::move(other.push_constants_); return *this; } static VKPipeline create_compute_pipeline(VKContext &context, VkShaderModule compute_module, VkDescriptorSetLayout &descriptor_set_layout, - VkPipelineLayout &pipeline_layouts); + VkPipelineLayout &pipeline_layouts, + VKPushConstantsLayout &push_constants_layout); VKDescriptorSet &descriptor_set_get() { return descriptor_set_; } + VKPushConstants &push_constants_get() + { + return push_constants_; + } + VkPipeline vk_handle() const; bool is_valid() const; }; diff --git a/source/blender/gpu/vulkan/vk_push_constants.cc b/source/blender/gpu/vulkan/vk_push_constants.cc index 095168f5c6a..e17617d7b38 100644 --- a/source/blender/gpu/vulkan/vk_push_constants.cc +++ b/source/blender/gpu/vulkan/vk_push_constants.cc @@ -71,9 +71,12 @@ static uint32_t to_alignment(const shader::Type type) } static VKPushConstantsLayout::PushConstantLayout init_constant( - const shader::ShaderCreateInfo::PushConst &push_constant, uint32_t *r_offset) + const shader::ShaderCreateInfo::PushConst &push_constant, + const ShaderInput &shader_input, + uint32_t *r_offset) { VKPushConstantsLayout::PushConstantLayout layout; + layout.location = shader_input.location; layout.type = push_constant.type; layout.array_size = push_constant.array_size; layout.offset = *r_offset; @@ -101,9 +104,50 @@ void VKPushConstantsLayout::init(const shader::ShaderCreateInfo &info, BLI_assert(push_constants.is_empty()); uint32_t offset = 0; for (const shader::ShaderCreateInfo::PushConst &push_constant : info.push_constants_) { - push_constants.append(init_constant(push_constant, &offset)); + const ShaderInput *shader_input = interface.uniform_get(push_constant.name.c_str()); + BLI_assert(shader_input); + push_constants.append(init_constant(push_constant, *shader_input, &offset)); } size_in_bytes_ = offset; } +const VKPushConstantsLayout::PushConstantLayout *VKPushConstantsLayout::find( + int32_t location) const +{ + for (const PushConstantLayout &push_constant : push_constants) { + if (push_constant.location == location) { + return &push_constant; + } + } + return nullptr; +} + +VKPushConstants::VKPushConstants(VKPushConstantsLayout &layout) : layout_(layout) +{ + data_ = MEM_mallocN(layout.size_in_bytes(), __func__); +} + +VKPushConstants::VKPushConstants(VKPushConstants &&other) : layout_(other.layout_) +{ + data_ = other.data_; + other.data_ = nullptr; +} + +VKPushConstants::~VKPushConstants() +{ + if (data_ != nullptr) { + MEM_freeN(data_); + data_ = nullptr; + } +} + +VKPushConstants &VKPushConstants::operator=(VKPushConstants &&other) +{ + layout_ = other.layout_; + data_ = other.data_; + other.data_ = nullptr; + + return *this; +} + } // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_push_constants.hh b/source/blender/gpu/vulkan/vk_push_constants.hh index 47cdd1659b0..f8c06c5e57b 100644 --- a/source/blender/gpu/vulkan/vk_push_constants.hh +++ b/source/blender/gpu/vulkan/vk_push_constants.hh @@ -7,6 +7,7 @@ #pragma once +#include "BLI_utility_mixins.hh" #include "BLI_vector.hh" #include "vk_common.hh" @@ -16,6 +17,11 @@ namespace blender::gpu { struct VKPushConstantsLayout { struct PushConstantLayout { + /* TODO: location requires sequential lookups, we should make the location index based for + * quicker access. */ + int32_t location; + + /** Offset in the push constant data (in bytes). */ uint32_t offset; shader::Type type; int array_size; @@ -32,13 +38,59 @@ struct VKPushConstantsLayout { { return size_in_bytes_; } + + const PushConstantLayout *find(int32_t location) const; }; -struct VKPushConstants { - const VKPushConstantsLayout &layout_; - uint32_t *data = nullptr; +static VKPushConstantsLayout dummy_layout; +class VKPushConstants : NonCopyable { - VKPushConstants(const VKPushConstantsLayout &layout); + private: + VKPushConstantsLayout &layout_ = dummy_layout; + void *data_ = nullptr; + + public: + VKPushConstants() = default; + VKPushConstants(VKPushConstantsLayout &layout); + VKPushConstants(VKPushConstants &&other); + virtual ~VKPushConstants(); + + VKPushConstants &operator=(VKPushConstants &&other); + + size_t offset() const + { + return 0; + } + + size_t size_in_bytes() const + { + return layout_.size_in_bytes(); + } + + const void *data() const + { + return data_; + } + + template + void push_constant_set(int32_t location, + int32_t comp_len, + int32_t array_size, + const T *input_data) + { + const VKPushConstantsLayout::PushConstantLayout *push_constant_layout = layout_.find(location); + if (push_constant_layout == nullptr) { + /* Currently the builtin uniforms are set using a predefined location each time a shader is + * bound.*/ + return; + } + BLI_assert_msg(push_constant_layout->offset + comp_len * array_size * sizeof(T) <= + layout_.size_in_bytes(), + "Tried to write outside the push constant allocated memory."); + uint8_t *bytes = static_cast(data_); + T *dst = static_cast(static_cast(&bytes[push_constant_layout->offset])); + memcpy(dst, input_data, comp_len * array_size * sizeof(T)); + } }; } // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_shader.cc b/source/blender/gpu/vulkan/vk_shader.cc index 017a6e3533f..4853d63146e 100644 --- a/source/blender/gpu/vulkan/vk_shader.cc +++ b/source/blender/gpu/vulkan/vk_shader.cc @@ -700,7 +700,7 @@ bool VKShader::finalize(const shader::ShaderCreateInfo *info) BLI_assert(fragment_module_ == VK_NULL_HANDLE); BLI_assert(compute_module_ != VK_NULL_HANDLE); compute_pipeline_ = VKPipeline::create_compute_pipeline( - *context_, compute_module_, layout_, pipeline_layout_); + *context_, compute_module_, layout_, pipeline_layout_, push_constants_layout_); result = compute_pipeline_.is_valid(); } @@ -976,12 +976,11 @@ void VKShader::unbind() } } -void VKShader::uniform_float(int /*location*/, - int /*comp_len*/, - int /*array_size*/, - const float * /*data*/) +void VKShader::uniform_float(int location, int comp_len, int array_size, const float *data) { + pipeline_get().push_constants_get().push_constant_set(location, comp_len, array_size, data); } + void VKShader::uniform_int(int /*location*/, int /*comp_len*/, int /*array_size*/, @@ -991,6 +990,9 @@ void VKShader::uniform_int(int /*location*/, std::string VKShader::resources_declare(const shader::ShaderCreateInfo &info) const { + if (info.name_ == "workbench_next_prepass_ptcloud_opaque_flat_texture_clip") { + printf("%s\n", info.name_.c_str()); + } VKShaderInterface interface; interface.init(info); std::stringstream ss; diff --git a/source/blender/gpu/vulkan/vk_shader_interface.cc b/source/blender/gpu/vulkan/vk_shader_interface.cc index cec6213bc5b..d172c978097 100644 --- a/source/blender/gpu/vulkan/vk_shader_interface.cc +++ b/source/blender/gpu/vulkan/vk_shader_interface.cc @@ -14,7 +14,7 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) using namespace blender::gpu::shader; attr_len_ = 0; - uniform_len_ = 0; + uniform_len_ = info.push_constants_.size(); ssbo_len_ = 0; ubo_len_ = 0; image_offset_ = -1; @@ -51,7 +51,7 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) name_buffer_ = (char *)MEM_mallocN(info.interface_names_size_, "name_buffer"); uint32_t name_buffer_offset = 0; - int location = 0; + int32_t location = 0; /* Uniform blocks */ for (const ShaderCreateInfo::Resource &res : all_resources) { @@ -79,6 +79,18 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) } } + /* Push constants. */ + /* NOTE: Push constants must be added after other uniform resources as resources have strict + * rules for their 'location' due to descriptor sets. Push constants only need an unique location + * as it is only used by the GPU module internally.*/ + int32_t push_constant_location = location + 1024; + for (const ShaderCreateInfo::PushConst &push_constant : info.push_constants_) { + copy_input_name(input, push_constant.name, name_buffer_, name_buffer_offset); + input->location = push_constant_location++; + input->binding = -1; + input++; + } + /* Storage buffers */ for (const ShaderCreateInfo::Resource &res : all_resources) { if (res.bind_type == ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER) { -- 2.30.2 From 797320c96be0987058d173c10087f18658e8d906 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Tue, 21 Feb 2023 14:27:11 +0100 Subject: [PATCH 24/55] Use storage buffers as fallback. Eventually we want to use uniform buffers as they are a bit faster. But they require std140. --- .../gpu/shaders/infos/gpu_shader_test_info.hh | 18 +++ .../gpu/tests/gpu_push_constants_test.cc | 18 +++ source/blender/gpu/vulkan/vk_backend.cc | 20 +++- source/blender/gpu/vulkan/vk_buffer.cc | 1 + source/blender/gpu/vulkan/vk_buffer.hh | 2 +- .../blender/gpu/vulkan/vk_command_buffer.cc | 3 +- .../blender/gpu/vulkan/vk_command_buffer.hh | 5 +- .../blender/gpu/vulkan/vk_descriptor_set.hh | 3 +- source/blender/gpu/vulkan/vk_pipeline.cc | 9 +- source/blender/gpu/vulkan/vk_pipeline.hh | 2 +- .../blender/gpu/vulkan/vk_push_constants.cc | 105 ++++++++++++++---- .../blender/gpu/vulkan/vk_push_constants.hh | 88 +++++++++++++-- source/blender/gpu/vulkan/vk_shader.cc | 84 ++++++++++---- source/blender/gpu/vulkan/vk_shader.hh | 5 +- .../blender/gpu/vulkan/vk_shader_interface.cc | 33 +++++- .../blender/gpu/vulkan/vk_shader_interface.hh | 14 +++ 16 files changed, 337 insertions(+), 73 deletions(-) diff --git a/source/blender/gpu/shaders/infos/gpu_shader_test_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_test_info.hh index 5343b64a2e2..e252414c939 100644 --- a/source/blender/gpu/shaders/infos/gpu_shader_test_info.hh +++ b/source/blender/gpu/shaders/infos/gpu_shader_test_info.hh @@ -55,6 +55,7 @@ GPU_SHADER_CREATE_INFO(gpu_compute_ssbo_binding_test) .compute_source("gpu_compute_dummy_test.glsl") .do_static_compilation(true); +/* Push constants*/ GPU_SHADER_CREATE_INFO(gpu_push_constants_base_test) .local_group_size(1) .storage_buf(0, Qualifier::WRITE, "float", "data_out[]") @@ -68,6 +69,23 @@ GPU_SHADER_CREATE_INFO(gpu_push_constants_packed_test) .push_constant(Type::VEC4, "vec4_in") .do_static_compilation(true); +/* Push constants size test. */ +GPU_SHADER_CREATE_INFO(gpu_push_constants_128bytes_test) + .additional_info("gpu_push_constants_packed_test") + .push_constant(Type::FLOAT, "filler", 20) + .do_static_compilation(true); + +GPU_SHADER_CREATE_INFO(gpu_push_constants_256bytes_test) + .additional_info("gpu_push_constants_128bytes_test") + .push_constant(Type::FLOAT, "filler2", 32) + .do_static_compilation(true); + +/* It is expected that this shader will use uniform buffers and not push constants.*/ +GPU_SHADER_CREATE_INFO(gpu_push_constants_512bytes_test) + .additional_info("gpu_push_constants_256bytes_test") + .push_constant(Type::FLOAT, "filler3", 64) + .do_static_compilation(true); + GPU_SHADER_CREATE_INFO(eevee_shadow_test) .fragment_source("eevee_shadow_test.glsl") .additional_info("gpu_shader_test") diff --git a/source/blender/gpu/tests/gpu_push_constants_test.cc b/source/blender/gpu/tests/gpu_push_constants_test.cc index b0a80e5669c..7d362592f07 100644 --- a/source/blender/gpu/tests/gpu_push_constants_test.cc +++ b/source/blender/gpu/tests/gpu_push_constants_test.cc @@ -77,4 +77,22 @@ static void test_push_constants_packed() } GPU_TEST(push_constants_packed) +static void test_push_constants_128bytes() +{ + push_constants("gpu_push_constants_128bytes_test"); +} +GPU_TEST(push_constants_128bytes) + +static void test_push_constants_256bytes() +{ + push_constants("gpu_push_constants_256bytes_test"); +} +GPU_TEST(push_constants_256bytes) + +static void test_push_constants_512bytes() +{ + push_constants("gpu_push_constants_512bytes_test"); +} +GPU_TEST(push_constants_512bytes) + } // namespace blender::gpu::tests \ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_backend.cc b/source/blender/gpu/vulkan/vk_backend.cc index 475b1870cd2..3809a0ddd90 100644 --- a/source/blender/gpu/vulkan/vk_backend.cc +++ b/source/blender/gpu/vulkan/vk_backend.cc @@ -67,11 +67,27 @@ void VKBackend::compute_dispatch(int groups_x_len, int groups_y_len, int groups_ VKCommandBuffer &command_buffer = context.command_buffer_get(); VKPipeline &pipeline = shader->pipeline_get(); VKDescriptorSet &descriptor_set = pipeline.descriptor_set_get(); + VKPushConstants &push_constants = pipeline.push_constants_get(); + + /* Update push constants based on their storage type.*/ + switch (push_constants.storage_type_get()) { + case VKPushConstantsLayout::StorageType::NONE: + break; + + case VKPushConstantsLayout::StorageType::PUSH_CONSTANTS: + command_buffer.push_constants( + push_constants, shader->vk_pipeline_layout_get(), VK_SHADER_STAGE_ALL); + break; + + case VKPushConstantsLayout::StorageType::STORAGE_BUFFER: + push_constants.update_storage_buffer(context.device_get()); + descriptor_set.bind(push_constants.storage_buffer_get(), + push_constants.storage_buffer_binding_get()); + break; + } descriptor_set.update(context.device_get()); command_buffer.bind( descriptor_set, shader->vk_pipeline_layout_get(), VK_PIPELINE_BIND_POINT_COMPUTE); - command_buffer.push_constants( - pipeline.push_constants_get(), shader->vk_pipeline_layout_get(), VK_SHADER_STAGE_ALL); command_buffer.dispatch(groups_x_len, groups_y_len, groups_z_len); } diff --git a/source/blender/gpu/vulkan/vk_buffer.cc b/source/blender/gpu/vulkan/vk_buffer.cc index f882783041d..7b4a994edd5 100644 --- a/source/blender/gpu/vulkan/vk_buffer.cc +++ b/source/blender/gpu/vulkan/vk_buffer.cc @@ -6,6 +6,7 @@ */ #include "vk_buffer.hh" +#include "vk_context.hh" namespace blender::gpu { diff --git a/source/blender/gpu/vulkan/vk_buffer.hh b/source/blender/gpu/vulkan/vk_buffer.hh index 875876ccab1..3dcd4054b43 100644 --- a/source/blender/gpu/vulkan/vk_buffer.hh +++ b/source/blender/gpu/vulkan/vk_buffer.hh @@ -10,11 +10,11 @@ #include "gpu_context_private.hh" #include "vk_common.hh" -#include "vk_context.hh" #include "vk_mem_alloc.h" namespace blender::gpu { +class VKContext; /** * Class for handing vulkan buffers (allocation/updating/binding). diff --git a/source/blender/gpu/vulkan/vk_command_buffer.cc b/source/blender/gpu/vulkan/vk_command_buffer.cc index c9eb1e9857b..c53d9e6fc61 100644 --- a/source/blender/gpu/vulkan/vk_command_buffer.cc +++ b/source/blender/gpu/vulkan/vk_command_buffer.cc @@ -10,6 +10,7 @@ #include "vk_context.hh" #include "vk_memory.hh" #include "vk_texture.hh" +#include "vk_pipeline.hh" #include "BLI_assert.h" @@ -75,7 +76,7 @@ void VKCommandBuffer::push_constants(const VKPushConstants &push_constants, const VkPipelineLayout vk_pipeline_layout, const VkShaderStageFlags vk_shader_stages) { - if (push_constants.size_in_bytes() == 0) { + if (push_constants.storage_type_get() != VKPushConstantsLayout::StorageType::PUSH_CONSTANTS) { return; } vkCmdPushConstants(vk_command_buffer_, diff --git a/source/blender/gpu/vulkan/vk_command_buffer.hh b/source/blender/gpu/vulkan/vk_command_buffer.hh index f8393d3ccf8..175c8ed502b 100644 --- a/source/blender/gpu/vulkan/vk_command_buffer.hh +++ b/source/blender/gpu/vulkan/vk_command_buffer.hh @@ -8,12 +8,15 @@ #pragma once #include "vk_common.hh" -#include "vk_pipeline.hh" + +#include "BLI_utility_mixins.hh" namespace blender::gpu { class VKBuffer; class VKTexture; class VKPushConstants; +class VKPipeline; +class VKDescriptorSet; /** Command buffer to keep track of the life-time of a command buffer.*/ class VKCommandBuffer : NonCopyable, NonMovable { diff --git a/source/blender/gpu/vulkan/vk_descriptor_set.hh b/source/blender/gpu/vulkan/vk_descriptor_set.hh index ea4fc288fc2..2f3c3f42e28 100644 --- a/source/blender/gpu/vulkan/vk_descriptor_set.hh +++ b/source/blender/gpu/vulkan/vk_descriptor_set.hh @@ -50,9 +50,8 @@ class VKDescriptorSet : NonCopyable { */ uint32_t binding; - Location() = default; - public: + Location() = default; Location(const ShaderInput *shader_input) : binding(shader_input->location) { } diff --git a/source/blender/gpu/vulkan/vk_pipeline.cc b/source/blender/gpu/vulkan/vk_pipeline.cc index 73d552c9797..890808645f5 100644 --- a/source/blender/gpu/vulkan/vk_pipeline.cc +++ b/source/blender/gpu/vulkan/vk_pipeline.cc @@ -33,7 +33,7 @@ VKPipeline VKPipeline::create_compute_pipeline(VKContext &context, VkShaderModule compute_module, VkDescriptorSetLayout &descriptor_set_layout, VkPipelineLayout &pipeline_layout, - VKPushConstantsLayout &push_constants_layout) + const VKPushConstantsLayout &push_constants_layout) { VK_ALLOCATION_CALLBACKS VkDevice vk_device = context.device_get(); @@ -52,13 +52,12 @@ VKPipeline VKPipeline::create_compute_pipeline(VKContext &context, if (vkCreateComputePipelines( vk_device, nullptr, 1, &pipeline_info, vk_allocation_callbacks, &vk_pipeline) != VK_SUCCESS) { - return VKPipeline(); + //return VKPipeline(); } VKDescriptorSet descriptor_set = context.descriptor_pools_get().allocate(descriptor_set_layout); - VKPushConstants push_constants(push_constants_layout); - return VKPipeline( - vk_pipeline, std::move(descriptor_set), std::move(push_constants)); + VKPushConstants push_constants(&push_constants_layout); + return VKPipeline(vk_pipeline, std::move(descriptor_set), std::move(push_constants)); } VkPipeline VKPipeline::vk_handle() const diff --git a/source/blender/gpu/vulkan/vk_pipeline.hh b/source/blender/gpu/vulkan/vk_pipeline.hh index 2f004af4ac7..3509bb63b15 100644 --- a/source/blender/gpu/vulkan/vk_pipeline.hh +++ b/source/blender/gpu/vulkan/vk_pipeline.hh @@ -44,7 +44,7 @@ class VKPipeline : NonCopyable { VkShaderModule compute_module, VkDescriptorSetLayout &descriptor_set_layout, VkPipelineLayout &pipeline_layouts, - VKPushConstantsLayout &push_constants_layout); + const VKPushConstantsLayout &push_constants_layout); VKDescriptorSet &descriptor_set_get() { diff --git a/source/blender/gpu/vulkan/vk_push_constants.cc b/source/blender/gpu/vulkan/vk_push_constants.cc index e17617d7b38..3aa81ad5bad 100644 --- a/source/blender/gpu/vulkan/vk_push_constants.cc +++ b/source/blender/gpu/vulkan/vk_push_constants.cc @@ -6,15 +6,17 @@ */ #include "vk_push_constants.hh" +#include "vk_backend.hh" +#include "vk_shader_interface.hh" namespace blender::gpu { -static uint32_t to_component_size(const shader::Type /*type*/) +constexpr uint32_t to_component_size(const shader::Type /*type*/) { return 4; } -static uint32_t to_num_components(const shader::Type type) +constexpr uint32_t to_num_components(const shader::Type type) { switch (type) { case shader::Type::FLOAT: @@ -43,7 +45,7 @@ static uint32_t to_num_components(const shader::Type type) return 0; } -static uint32_t to_alignment(const shader::Type type) +constexpr uint32_t to_alignment(const shader::Type type) { switch (type) { case shader::Type::FLOAT: @@ -70,38 +72,71 @@ static uint32_t to_alignment(const shader::Type type) return 0; } +static void align(const shader::ShaderCreateInfo::PushConst &push_constant, uint32_t *r_offset) +{ + uint32_t alignment = to_alignment(push_constant.type); + uint32_t alignment_mask = alignment - 1; + uint32_t offset = *r_offset; + if ((offset & alignment_mask) != 0) { + offset &= ~alignment_mask; + offset += alignment; + *r_offset = offset; + } +} + +static void reserve(const shader::ShaderCreateInfo::PushConst &push_constant, uint32_t *r_offset) +{ + uint32_t size = to_num_components(push_constant.type) * to_component_size(push_constant.type); + if (push_constant.array_size != 0) { + size *= push_constant.array_size; + } + *r_offset += size; +} + static VKPushConstantsLayout::PushConstantLayout init_constant( const shader::ShaderCreateInfo::PushConst &push_constant, const ShaderInput &shader_input, uint32_t *r_offset) { + align(push_constant, r_offset); + VKPushConstantsLayout::PushConstantLayout layout; layout.location = shader_input.location; layout.type = push_constant.type; layout.array_size = push_constant.array_size; layout.offset = *r_offset; - /* Perform alignment. */ - uint32_t alignment = to_alignment(push_constant.type); - uint32_t alignment_mask = alignment - 1; - if ((layout.offset & alignment_mask) != 0) { - layout.offset &= ~alignment_mask; - layout.offset += alignment; - } - - uint32_t size = to_num_components(push_constant.type) * to_component_size(push_constant.type); - if (push_constant.array_size != 0) { - size *= push_constant.array_size; - } - - *r_offset = layout.offset + size; + reserve(push_constant, r_offset); return layout; } +VKPushConstantsLayout::StorageType VKPushConstantsLayout::determine_storage_type( + const shader::ShaderCreateInfo &info, const VkPhysicalDeviceLimits &vk_physical_device_limits) +{ + if (info.push_constants_.is_empty()) { + return StorageType::NONE; + } + + uint32_t offset = 0; + for (const shader::ShaderCreateInfo::PushConst &push_constant : info.push_constants_) { + align(push_constant, &offset); + reserve(push_constant, &offset); + } + return offset <= vk_physical_device_limits.maxPushConstantsSize ? StorageType::PUSH_CONSTANTS : + StorageType::STORAGE_BUFFER; +} + void VKPushConstantsLayout::init(const shader::ShaderCreateInfo &info, - const VKShaderInterface &interface) + const VKShaderInterface &interface, + const StorageType storage_type, + const ShaderInput *shader_input) { BLI_assert(push_constants.is_empty()); + storage_type_ = storage_type; + if (storage_type == StorageType::STORAGE_BUFFER) { + BLI_assert(shader_input); + storage_buffer_binding_ = VKDescriptorSet::Location(shader_input); + } uint32_t offset = 0; for (const shader::ShaderCreateInfo::PushConst &push_constant : info.push_constants_) { const ShaderInput *shader_input = interface.uniform_get(push_constant.name.c_str()); @@ -121,16 +156,22 @@ const VKPushConstantsLayout::PushConstantLayout *VKPushConstantsLayout::find( } return nullptr; } - -VKPushConstants::VKPushConstants(VKPushConstantsLayout &layout) : layout_(layout) +VKPushConstants::VKPushConstants() = default; +VKPushConstants::VKPushConstants(const VKPushConstantsLayout *layout) : layout_(layout) { - data_ = MEM_mallocN(layout.size_in_bytes(), __func__); + data_ = MEM_mallocN(layout->size_in_bytes(), __func__); + if (storage_type_get() == VKPushConstantsLayout::StorageType::STORAGE_BUFFER) { + storage_buffer_ = new VKStorageBuffer(size_in_bytes(), GPU_USAGE_DYNAMIC, __func__); + } } VKPushConstants::VKPushConstants(VKPushConstants &&other) : layout_(other.layout_) { data_ = other.data_; other.data_ = nullptr; + + storage_buffer_ = other.storage_buffer_; + other.storage_buffer_ = nullptr; } VKPushConstants::~VKPushConstants() @@ -139,15 +180,37 @@ VKPushConstants::~VKPushConstants() MEM_freeN(data_); data_ = nullptr; } + + delete storage_buffer_; + storage_buffer_ = nullptr; } VKPushConstants &VKPushConstants::operator=(VKPushConstants &&other) { layout_ = other.layout_; + data_ = other.data_; other.data_ = nullptr; + storage_buffer_ = other.storage_buffer_; + other.storage_buffer_ = nullptr; + return *this; } +void VKPushConstants::update_storage_buffer(VkDevice /*vk_device*/) +{ + BLI_assert(storage_type_get() == VKPushConstantsLayout::StorageType::STORAGE_BUFFER); + BLI_assert(storage_buffer_ != nullptr); + BLI_assert(data_ != nullptr); + storage_buffer_->update(data_); +} + +VKStorageBuffer &VKPushConstants::storage_buffer_get() +{ + BLI_assert(storage_type_get() == VKPushConstantsLayout::StorageType::STORAGE_BUFFER); + BLI_assert(storage_buffer_ != nullptr); + return *storage_buffer_; +} + } // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_push_constants.hh b/source/blender/gpu/vulkan/vk_push_constants.hh index f8c06c5e57b..9579738412e 100644 --- a/source/blender/gpu/vulkan/vk_push_constants.hh +++ b/source/blender/gpu/vulkan/vk_push_constants.hh @@ -3,6 +3,17 @@ /** \file * \ingroup gpu + * + * Push constants is a way to quickly provide a small amount of uniform data to shaders. It should + * be much quicker than UBOs but a huge limitation is the size of data - spec requires 128 bytes to + * be available for a push constant range. Hardware vendors may support more, but compared to other + * means it is still very little (for example 256 bytes). + * + * Due to this size requirements we try to use push constants when it fits on the device. If it + * doesn't fit we fallback to use an uniform buffer. + * + * Shader developers are responsible to fine-tune the performance of the shader. One way to do this + * is to tailor what will be sent as a push constant to keep the push constants within the limits. */ #pragma once @@ -10,12 +21,27 @@ #include "BLI_utility_mixins.hh" #include "BLI_vector.hh" +#include "gpu_shader_create_info.hh" + #include "vk_common.hh" -#include "vk_shader_interface.hh" +//#include "vk_context.hh" +#include "vk_descriptor_set.hh" +#include "vk_storage_buffer.hh" namespace blender::gpu { +class VKShaderInterface; +/** + * Describe the layout of the push constants and the storage type that should be used. + */ struct VKPushConstantsLayout { + /* Should the push constant use regular push constants or a buffer.*/ + enum class StorageType { + NONE, + PUSH_CONSTANTS, + STORAGE_BUFFER, + }; + struct PushConstantLayout { /* TODO: location requires sequential lookups, we should make the location index based for * quicker access. */ @@ -29,10 +55,34 @@ struct VKPushConstantsLayout { private: Vector push_constants; - uint32_t size_in_bytes_; + uint32_t size_in_bytes_ = 0; + StorageType storage_type_ = StorageType::NONE; + /** + * Binding index in the descriptor set when the push constants use an uniform buffer. + */ + VKDescriptorSet::Location storage_buffer_binding_; public: - void init(const shader::ShaderCreateInfo &info, const VKShaderInterface &interface); + static StorageType determine_storage_type( + const shader::ShaderCreateInfo &info, + const VkPhysicalDeviceLimits &vk_physical_device_limits); + void init(const shader::ShaderCreateInfo &info, + const VKShaderInterface &interface, + StorageType storage_type, + const ShaderInput *shader_input); + + /** + * Return the storage type that is used. + */ + StorageType storage_type_get() const + { + return storage_type_; + } + + VKDescriptorSet::Location storage_buffer_binding_get() const + { + return storage_buffer_binding_; + } uint32_t size_in_bytes() const { @@ -42,16 +92,16 @@ struct VKPushConstantsLayout { const PushConstantLayout *find(int32_t location) const; }; -static VKPushConstantsLayout dummy_layout; class VKPushConstants : NonCopyable { private: - VKPushConstantsLayout &layout_ = dummy_layout; + const VKPushConstantsLayout *layout_ = nullptr; void *data_ = nullptr; + VKStorageBuffer *storage_buffer_ = nullptr; public: - VKPushConstants() = default; - VKPushConstants(VKPushConstantsLayout &layout); + VKPushConstants(); + VKPushConstants(const VKPushConstantsLayout *layout); VKPushConstants(VKPushConstants &&other); virtual ~VKPushConstants(); @@ -64,9 +114,22 @@ class VKPushConstants : NonCopyable { size_t size_in_bytes() const { - return layout_.size_in_bytes(); + return layout_->size_in_bytes(); } + VKPushConstantsLayout::StorageType storage_type_get() const + { + return layout_->storage_type_get(); + } + + VKDescriptorSet::Location storage_buffer_binding_get() const + { + return layout_->storage_buffer_binding_get(); + } + + void update_storage_buffer(VkDevice vk_device); + VKStorageBuffer &storage_buffer_get(); + const void *data() const { return data_; @@ -78,14 +141,15 @@ class VKPushConstants : NonCopyable { int32_t array_size, const T *input_data) { - const VKPushConstantsLayout::PushConstantLayout *push_constant_layout = layout_.find(location); + const VKPushConstantsLayout::PushConstantLayout *push_constant_layout = layout_->find( + location); if (push_constant_layout == nullptr) { - /* Currently the builtin uniforms are set using a predefined location each time a shader is - * bound.*/ + /* TODO: Currently the builtin uniforms are set using a predefined location each time a + * shader is bound. This needs to be fixed in the VKShaderInterface.*/ return; } BLI_assert_msg(push_constant_layout->offset + comp_len * array_size * sizeof(T) <= - layout_.size_in_bytes(), + layout_->size_in_bytes(), "Tried to write outside the push constant allocated memory."); uint8_t *bytes = static_cast(data_); T *dst = static_cast(static_cast(&bytes[push_constant_layout->offset])); diff --git a/source/blender/gpu/vulkan/vk_shader.cc b/source/blender/gpu/vulkan/vk_shader.cc index 4853d63146e..4e70a1acb00 100644 --- a/source/blender/gpu/vulkan/vk_shader.cc +++ b/source/blender/gpu/vulkan/vk_shader.cc @@ -680,8 +680,7 @@ bool VKShader::finalize(const shader::ShaderCreateInfo *info) if (!finalize_descriptor_set_layouts(vk_device, *vk_interface, *info)) { return false; } - push_constants_layout_.init(*info, *vk_interface); - if (!finalize_pipeline_layout(vk_device, *info)) { + if (!finalize_pipeline_layout(vk_device, *vk_interface)) { return false; } @@ -700,7 +699,11 @@ bool VKShader::finalize(const shader::ShaderCreateInfo *info) BLI_assert(fragment_module_ == VK_NULL_HANDLE); BLI_assert(compute_module_ != VK_NULL_HANDLE); compute_pipeline_ = VKPipeline::create_compute_pipeline( - *context_, compute_module_, layout_, pipeline_layout_, push_constants_layout_); + *context_, + compute_module_, + layout_, + pipeline_layout_, + vk_interface->push_constants_layout_get()); result = compute_pipeline_.is_valid(); } @@ -744,7 +747,7 @@ bool VKShader::finalize_graphics_pipeline(VkDevice /*vk_device */) } bool VKShader::finalize_pipeline_layout(VkDevice vk_device, - const shader::ShaderCreateInfo & /*info*/) + const VKShaderInterface &shader_interface) { VK_ALLOCATION_CALLBACKS @@ -755,9 +758,14 @@ bool VKShader::finalize_pipeline_layout(VkDevice vk_device, pipeline_info.flags = 0; pipeline_info.setLayoutCount = layout_count; pipeline_info.pSetLayouts = &layout_; - if (push_constants_layout_.size_in_bytes() != 0) { + + /* Setup push constants. */ + const VKPushConstantsLayout &push_constants_layout = + shader_interface.push_constants_layout_get(); + if (push_constants_layout.storage_type_get() == + VKPushConstantsLayout::StorageType::PUSH_CONSTANTS) { push_constant_range.offset = 0; - push_constant_range.size = push_constants_layout_.size_in_bytes(); + push_constant_range.size = push_constants_layout.size_in_bytes(); push_constant_range.stageFlags = VK_SHADER_STAGE_ALL; pipeline_info.pushConstantRangeCount = 1; pipeline_info.pPushConstantRanges = &push_constant_range; @@ -881,6 +889,21 @@ static VkDescriptorSetLayoutBinding create_descriptor_set_layout_binding( return binding; } +static VkDescriptorSetLayoutBinding create_descriptor_set_layout_binding( + const VKPushConstantsLayout &push_constants_layout) +{ + BLI_assert(push_constants_layout.storage_type_get() == + VKPushConstantsLayout::StorageType::STORAGE_BUFFER); + VkDescriptorSetLayoutBinding binding = {}; + binding.binding = push_constants_layout.storage_buffer_binding_get(); + binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + binding.descriptorCount = 1; + binding.stageFlags = VK_SHADER_STAGE_ALL; + binding.pImmutableSamplers = nullptr; + + return binding; +} + static void add_descriptor_set_layout_bindings( const VKShaderInterface &interface, const Vector &resources, @@ -895,6 +918,13 @@ static void add_descriptor_set_layout_bindings( r_bindings.append(create_descriptor_set_layout_binding(*shader_input, resource)); } + + /* Add push constants to the descriptor when push constants are stored in a storage buffer.*/ + const VKPushConstantsLayout &push_constants_layout = interface.push_constants_layout_get(); + if (push_constants_layout.storage_type_get() == + VKPushConstantsLayout::StorageType::STORAGE_BUFFER) { + r_bindings.append(create_descriptor_set_layout_binding(push_constants_layout)); + } } static VkDescriptorSetLayoutCreateInfo create_descriptor_set_layout( @@ -912,11 +942,19 @@ static VkDescriptorSetLayoutCreateInfo create_descriptor_set_layout( return set_info; } +static bool descriptor_sets_needed(const VKShaderInterface &shader_interface, + const shader::ShaderCreateInfo &info) +{ + return !info.pass_resources_.is_empty() || !info.batch_resources_.is_empty() || + shader_interface.push_constants_layout_get().storage_type_get() == + VKPushConstantsLayout::StorageType::STORAGE_BUFFER; +} + bool VKShader::finalize_descriptor_set_layouts(VkDevice vk_device, const VKShaderInterface &shader_interface, const shader::ShaderCreateInfo &info) { - if (info.pass_resources_.is_empty() && info.batch_resources_.is_empty()) { + if (!descriptor_sets_needed(shader_interface, info)) { return true; } @@ -981,18 +1019,13 @@ void VKShader::uniform_float(int location, int comp_len, int array_size, const f pipeline_get().push_constants_get().push_constant_set(location, comp_len, array_size, data); } -void VKShader::uniform_int(int /*location*/, - int /*comp_len*/, - int /*array_size*/, - const int * /*data*/) +void VKShader::uniform_int(int location, int comp_len, int array_size, const int *data) { + pipeline_get().push_constants_get().push_constant_set(location, comp_len, array_size, data); } std::string VKShader::resources_declare(const shader::ShaderCreateInfo &info) const { - if (info.name_ == "workbench_next_prepass_ptcloud_opaque_flat_texture_clip") { - printf("%s\n", info.name_.c_str()); - } VKShaderInterface interface; interface.init(info); std::stringstream ss; @@ -1013,9 +1046,19 @@ std::string VKShader::resources_declare(const shader::ShaderCreateInfo &info) co print_resource_alias(ss, res); } - if (!info.push_constants_.is_empty()) { + /* Push constants. */ + const VKPushConstantsLayout &push_constants_layout = interface.push_constants_layout_get(); + const VKPushConstantsLayout::StorageType push_constants_storage = + push_constants_layout.storage_type_get(); + if (push_constants_storage != VKPushConstantsLayout::StorageType::NONE) { ss << "\n/* Push Constants. */\n"; - ss << "layout(push_constant) uniform constants\n"; + if (push_constants_storage == VKPushConstantsLayout::StorageType::PUSH_CONSTANTS) { + ss << "layout(push_constant) uniform constants\n"; + } + else /* VKPushConstantsLayout::StorageType::STORAGE_BUFFER*/ { + ss << "layout(binding = " << push_constants_layout.storage_buffer_binding_get() + << ", std430) buffer constants\n"; + } ss << "{\n"; for (const ShaderCreateInfo::PushConst &uniform : info.push_constants_) { ss << " " << to_string(uniform.type) << " pc_" << uniform.name; @@ -1044,12 +1087,6 @@ std::string VKShader::vertex_interface_declare(const shader::ShaderCreateInfo &i ss << "layout(location = " << attr.index << ") "; ss << "in " << to_string(attr.type) << " " << attr.name << ";\n"; } - /* NOTE(D4490): Fix a bug where shader without any vertex attributes do not behave correctly. - */ - if (GPU_type_matches_ex(GPU_DEVICE_APPLE, GPU_OS_MAC, GPU_DRIVER_ANY, GPU_BACKEND_OPENGL) && - info.vertex_inputs_.is_empty()) { - ss << "in float gpu_dummy_workaround;\n"; - } ss << "\n/* Interfaces. */\n"; int location = 0; for (const StageInterfaceInfo *iface : info.vertex_out_interfaces_) { @@ -1223,6 +1260,9 @@ VKPipeline &VKShader::pipeline_get() const VKShaderInterface &VKShader::interface_get() const { + BLI_assert_msg(interface != nullptr, + "Unable to access the shader interface when finalizing the shader, use the " + "instance created in the finalize method."); return *static_cast(interface); } diff --git a/source/blender/gpu/vulkan/vk_shader.hh b/source/blender/gpu/vulkan/vk_shader.hh index d88489a2c5e..21a99269f5c 100644 --- a/source/blender/gpu/vulkan/vk_shader.hh +++ b/source/blender/gpu/vulkan/vk_shader.hh @@ -11,7 +11,7 @@ #include "vk_backend.hh" #include "vk_context.hh" -#include "vk_push_constants.hh" +#include "vk_pipeline.hh" #include "BLI_string_ref.hh" @@ -28,7 +28,6 @@ class VKShader : public Shader { bool compilation_failed_ = false; VkDescriptorSetLayout layout_ = VK_NULL_HANDLE; VkPipelineLayout pipeline_layout_ = VK_NULL_HANDLE; - VKPushConstantsLayout push_constants_layout_; VKPipeline compute_pipeline_; public: @@ -80,7 +79,7 @@ class VKShader : public Shader { bool finalize_descriptor_set_layouts(VkDevice vk_device, const VKShaderInterface &shader_interface, const shader::ShaderCreateInfo &info); - bool finalize_pipeline_layout(VkDevice vk_device, const shader::ShaderCreateInfo &info); + bool finalize_pipeline_layout(VkDevice vk_device, const VKShaderInterface &shader_interface); bool finalize_graphics_pipeline(VkDevice vk_device); bool is_graphics_shader() const diff --git a/source/blender/gpu/vulkan/vk_shader_interface.cc b/source/blender/gpu/vulkan/vk_shader_interface.cc index d172c978097..48246300ae9 100644 --- a/source/blender/gpu/vulkan/vk_shader_interface.cc +++ b/source/blender/gpu/vulkan/vk_shader_interface.cc @@ -6,6 +6,7 @@ */ #include "vk_shader_interface.hh" +#include "vk_context.hh" namespace blender::gpu { @@ -40,15 +41,26 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) break; } } + + /* Reserve 1 storage buffer for push constants fallback. */ + size_t names_size = info.interface_names_size_; + VKContext &context = *VKContext::get(); + const VKPushConstantsLayout::StorageType push_constants_storage_type = + VKPushConstantsLayout::determine_storage_type(info, context.physical_device_limits_get()); + if (push_constants_storage_type == VKPushConstantsLayout::StorageType::STORAGE_BUFFER) { + ssbo_len_++; + names_size += PUSH_CONSTANTS_FALLBACK_NAME_LEN + 1; + } + /* Make sure that the image slots don't overlap with the sampler slots.*/ - image_offset_ += 1; + image_offset_++; int32_t input_tot_len = ubo_len_ + uniform_len_ + ssbo_len_; inputs_ = static_cast( MEM_calloc_arrayN(input_tot_len, sizeof(ShaderInput), __func__)); ShaderInput *input = inputs_; - name_buffer_ = (char *)MEM_mallocN(info.interface_names_size_, "name_buffer"); + name_buffer_ = (char *)MEM_mallocN(names_size, "name_buffer"); uint32_t name_buffer_offset = 0; int32_t location = 0; @@ -101,6 +113,23 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) } } + /* Push constant post initialization.*/ + /* + * When using storage buffer storage type we need to add it to the the name list here. + * Also determine the location as this is used inside the descriptor set as its binding number. + */ + int32_t push_constants_fallback_location = -1; + ShaderInput *push_constants_fallback_input = nullptr; + if (push_constants_storage_type == VKPushConstantsLayout::StorageType::STORAGE_BUFFER) { + copy_input_name(input, PUSH_CONSTANTS_FALLBACK_NAME, name_buffer_, name_buffer_offset); + input->location = push_constants_fallback_location = location++; + input->binding = -1; + push_constants_fallback_input = input; + input++; + } + push_constants_layout_.init( + info, *this, push_constants_storage_type, push_constants_fallback_input); + sort_inputs(); } diff --git a/source/blender/gpu/vulkan/vk_shader_interface.hh b/source/blender/gpu/vulkan/vk_shader_interface.hh index 4e099feb680..a217351ad0e 100644 --- a/source/blender/gpu/vulkan/vk_shader_interface.hh +++ b/source/blender/gpu/vulkan/vk_shader_interface.hh @@ -10,6 +10,8 @@ #include "gpu_shader_create_info.hh" #include "gpu_shader_interface.hh" +#include "vk_push_constants.hh" + namespace blender::gpu { class VKShaderInterface : public ShaderInterface { private: @@ -22,6 +24,13 @@ class VKShaderInterface : public ShaderInterface { */ uint32_t image_offset_ = 0; + VKPushConstantsLayout push_constants_layout_; + + public: + static constexpr StringRefNull PUSH_CONSTANTS_FALLBACK_NAME = StringRefNull( + "push_constants_fallback", 23); + static constexpr size_t PUSH_CONSTANTS_FALLBACK_NAME_LEN = PUSH_CONSTANTS_FALLBACK_NAME.size(); + public: VKShaderInterface() = default; @@ -35,5 +44,10 @@ class VKShaderInterface : public ShaderInterface { const ShaderInput *shader_input_get(const shader::ShaderCreateInfo::Resource &resource) const; const ShaderInput *shader_input_get( const shader::ShaderCreateInfo::Resource::BindType &bind_type, int binding) const; + + const VKPushConstantsLayout &push_constants_layout_get() const + { + return push_constants_layout_; + } }; } // namespace blender::gpu -- 2.30.2 From 76dcdf78e9fb58858f319c3ab601369812057476 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Tue, 21 Feb 2023 16:17:00 +0100 Subject: [PATCH 25/55] Move std430 layout utility to vk_memory. --- source/blender/gpu/vulkan/vk_memory.cc | 61 ++++++++++++++ source/blender/gpu/vulkan/vk_memory.hh | 14 ++++ .../blender/gpu/vulkan/vk_push_constants.cc | 80 +++---------------- 3 files changed, 87 insertions(+), 68 deletions(-) diff --git a/source/blender/gpu/vulkan/vk_memory.cc b/source/blender/gpu/vulkan/vk_memory.cc index 87a4d78d66b..8f7ba9965bb 100644 --- a/source/blender/gpu/vulkan/vk_memory.cc +++ b/source/blender/gpu/vulkan/vk_memory.cc @@ -44,4 +44,65 @@ void vk_memory_free(void * /*user_data*/, void *memory) #endif +uint32_t Std430::component_mem_size(const shader::Type /*type*/) +{ + return 4; +} + +uint32_t Std430::element_alignment(const shader::Type type) +{ + switch (type) { + case shader::Type::FLOAT: + case shader::Type::UINT: + case shader::Type::INT: + case shader::Type::BOOL: + return 4; + case shader::Type::VEC2: + case shader::Type::UVEC2: + case shader::Type::IVEC2: + return 8; + case shader::Type::VEC3: + case shader::Type::UVEC3: + case shader::Type::IVEC3: + case shader::Type::VEC4: + case shader::Type::UVEC4: + case shader::Type::IVEC4: + case shader::Type::MAT3: + case shader::Type::MAT4: + return 16; + default: + BLI_assert_msg(false, "Type not supported as push constant"); + } + return 0; +} + +uint32_t Std430::element_components_len(const shader::Type type) +{ + switch (type) { + case shader::Type::FLOAT: + case shader::Type::UINT: + case shader::Type::INT: + case shader::Type::BOOL: + return 1; + case shader::Type::VEC2: + case shader::Type::UVEC2: + case shader::Type::IVEC2: + return 2; + case shader::Type::VEC3: + case shader::Type::UVEC3: + case shader::Type::IVEC3: + case shader::Type::VEC4: + case shader::Type::UVEC4: + case shader::Type::IVEC4: + return 4; + case shader::Type::MAT3: + return 12; + case shader::Type::MAT4: + return 16; + default: + BLI_assert_msg(false, "Type not supported as push constant"); + } + return 0; +} + } // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_memory.hh b/source/blender/gpu/vulkan/vk_memory.hh index 2f42eaa90c0..fdff3099886 100644 --- a/source/blender/gpu/vulkan/vk_memory.hh +++ b/source/blender/gpu/vulkan/vk_memory.hh @@ -9,6 +9,8 @@ #include "vk_common.hh" +#include "gpu_shader_create_info.hh" + namespace blender::gpu { /** @@ -58,4 +60,16 @@ constexpr VkAllocationCallbacks vk_allocation_callbacks_init(const char *name) static constexpr const VkAllocationCallbacks *vk_allocation_callbacks = nullptr; #endif +/** + * Information about alignment/components and memory size for types when using std430 layout. + */ +struct Std430 { + /** Get the memory size in bytes of a single component using by the given type.*/ + static uint32_t component_mem_size(const shader::Type type); + /** Get to alignment of the given type in bytes.*/ + static uint32_t element_alignment(const shader::Type type); + /** Get the number of components that should be allocated for the given type.*/ + static uint32_t element_components_len(const shader::Type type); +}; + } // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_push_constants.cc b/source/blender/gpu/vulkan/vk_push_constants.cc index 3aa81ad5bad..5ef62fc80c8 100644 --- a/source/blender/gpu/vulkan/vk_push_constants.cc +++ b/source/blender/gpu/vulkan/vk_push_constants.cc @@ -7,74 +7,15 @@ #include "vk_push_constants.hh" #include "vk_backend.hh" +#include "vk_memory.hh" #include "vk_shader_interface.hh" namespace blender::gpu { -constexpr uint32_t to_component_size(const shader::Type /*type*/) -{ - return 4; -} - -constexpr uint32_t to_num_components(const shader::Type type) -{ - switch (type) { - case shader::Type::FLOAT: - case shader::Type::UINT: - case shader::Type::INT: - case shader::Type::BOOL: - return 1; - case shader::Type::VEC2: - case shader::Type::UVEC2: - case shader::Type::IVEC2: - return 2; - case shader::Type::VEC3: - case shader::Type::UVEC3: - case shader::Type::IVEC3: - case shader::Type::VEC4: - case shader::Type::UVEC4: - case shader::Type::IVEC4: - return 4; - case shader::Type::MAT3: - return 12; - case shader::Type::MAT4: - return 16; - default: - BLI_assert_msg(false, "Type not supported as push constant"); - } - return 0; -} - -constexpr uint32_t to_alignment(const shader::Type type) -{ - switch (type) { - case shader::Type::FLOAT: - case shader::Type::UINT: - case shader::Type::INT: - case shader::Type::BOOL: - return 4; - case shader::Type::VEC2: - case shader::Type::UVEC2: - case shader::Type::IVEC2: - return 8; - case shader::Type::VEC3: - case shader::Type::UVEC3: - case shader::Type::IVEC3: - case shader::Type::VEC4: - case shader::Type::UVEC4: - case shader::Type::IVEC4: - case shader::Type::MAT3: - case shader::Type::MAT4: - return 16; - default: - BLI_assert_msg(false, "Type not supported as push constant"); - } - return 0; -} - +template static void align(const shader::ShaderCreateInfo::PushConst &push_constant, uint32_t *r_offset) { - uint32_t alignment = to_alignment(push_constant.type); + uint32_t alignment = Layout::element_alignment(push_constant.type); uint32_t alignment_mask = alignment - 1; uint32_t offset = *r_offset; if ((offset & alignment_mask) != 0) { @@ -84,21 +25,24 @@ static void align(const shader::ShaderCreateInfo::PushConst &push_constant, uint } } +template static void reserve(const shader::ShaderCreateInfo::PushConst &push_constant, uint32_t *r_offset) { - uint32_t size = to_num_components(push_constant.type) * to_component_size(push_constant.type); + uint32_t size = Layout::element_components_len(push_constant.type) * + Layout::component_mem_size(push_constant.type); if (push_constant.array_size != 0) { size *= push_constant.array_size; } *r_offset += size; } +template static VKPushConstantsLayout::PushConstantLayout init_constant( const shader::ShaderCreateInfo::PushConst &push_constant, const ShaderInput &shader_input, uint32_t *r_offset) { - align(push_constant, r_offset); + align(push_constant, r_offset); VKPushConstantsLayout::PushConstantLayout layout; layout.location = shader_input.location; @@ -106,7 +50,7 @@ static VKPushConstantsLayout::PushConstantLayout init_constant( layout.array_size = push_constant.array_size; layout.offset = *r_offset; - reserve(push_constant, r_offset); + reserve(push_constant, r_offset); return layout; } @@ -119,8 +63,8 @@ VKPushConstantsLayout::StorageType VKPushConstantsLayout::determine_storage_type uint32_t offset = 0; for (const shader::ShaderCreateInfo::PushConst &push_constant : info.push_constants_) { - align(push_constant, &offset); - reserve(push_constant, &offset); + align(push_constant, &offset); + reserve(push_constant, &offset); } return offset <= vk_physical_device_limits.maxPushConstantsSize ? StorageType::PUSH_CONSTANTS : StorageType::STORAGE_BUFFER; @@ -141,7 +85,7 @@ void VKPushConstantsLayout::init(const shader::ShaderCreateInfo &info, for (const shader::ShaderCreateInfo::PushConst &push_constant : info.push_constants_) { const ShaderInput *shader_input = interface.uniform_get(push_constant.name.c_str()); BLI_assert(shader_input); - push_constants.append(init_constant(push_constant, *shader_input, &offset)); + push_constants.append(init_constant(push_constant, *shader_input, &offset)); } size_in_bytes_ = offset; } -- 2.30.2 From 0ae03c78f4dbaa063903376f3b4d3573d4262f7f Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Tue, 21 Feb 2023 20:21:14 +0100 Subject: [PATCH 26/55] Use uniform buffers for fallback. (still in progress) --- source/blender/gpu/vulkan/vk_backend.cc | 6 ++ .../blender/gpu/vulkan/vk_descriptor_set.cc | 9 +++ .../blender/gpu/vulkan/vk_descriptor_set.hh | 2 + source/blender/gpu/vulkan/vk_memory.cc | 61 ++++++++++++++ source/blender/gpu/vulkan/vk_memory.hh | 12 +++ .../blender/gpu/vulkan/vk_push_constants.cc | 79 +++++++++++++++---- .../blender/gpu/vulkan/vk_push_constants.hh | 9 ++- source/blender/gpu/vulkan/vk_shader.cc | 19 +++-- .../blender/gpu/vulkan/vk_shader_interface.cc | 16 +++- .../blender/gpu/vulkan/vk_uniform_buffer.cc | 13 ++- .../blender/gpu/vulkan/vk_uniform_buffer.hh | 17 ++++ 11 files changed, 218 insertions(+), 25 deletions(-) diff --git a/source/blender/gpu/vulkan/vk_backend.cc b/source/blender/gpu/vulkan/vk_backend.cc index 3809a0ddd90..bc3647551b2 100644 --- a/source/blender/gpu/vulkan/vk_backend.cc +++ b/source/blender/gpu/vulkan/vk_backend.cc @@ -84,6 +84,12 @@ void VKBackend::compute_dispatch(int groups_x_len, int groups_y_len, int groups_ descriptor_set.bind(push_constants.storage_buffer_get(), push_constants.storage_buffer_binding_get()); break; + + case VKPushConstantsLayout::StorageType::UNIFORM_BUFFER: + push_constants.update_uniform_buffer(context.device_get()); + descriptor_set.bind(push_constants.uniform_buffer_get(), + push_constants.storage_buffer_binding_get()); + break; } descriptor_set.update(context.device_get()); command_buffer.bind( diff --git a/source/blender/gpu/vulkan/vk_descriptor_set.cc b/source/blender/gpu/vulkan/vk_descriptor_set.cc index 44f9d95ad36..756d6e438b8 100644 --- a/source/blender/gpu/vulkan/vk_descriptor_set.cc +++ b/source/blender/gpu/vulkan/vk_descriptor_set.cc @@ -9,6 +9,7 @@ #include "vk_index_buffer.hh" #include "vk_storage_buffer.hh" #include "vk_texture.hh" +#include "vk_uniform_buffer.hh" #include "vk_vertex_buffer.hh" #include "BLI_assert.h" @@ -47,6 +48,14 @@ void VKDescriptorSet::bind(VKStorageBuffer &buffer, const Location location) binding.buffer_size = buffer.size_in_bytes(); } +void VKDescriptorSet::bind(VKUniformBuffer &buffer, const Location location) +{ + Binding &binding = ensure_location(location); + binding.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + binding.vk_buffer = buffer.vk_handle(); + binding.buffer_size = buffer.size_in_bytes(); +} + void VKDescriptorSet::bind_as_ssbo(VKVertexBuffer &buffer, const Location location) { Binding &binding = ensure_location(location); diff --git a/source/blender/gpu/vulkan/vk_descriptor_set.hh b/source/blender/gpu/vulkan/vk_descriptor_set.hh index 2f3c3f42e28..e32af7bf478 100644 --- a/source/blender/gpu/vulkan/vk_descriptor_set.hh +++ b/source/blender/gpu/vulkan/vk_descriptor_set.hh @@ -16,6 +16,7 @@ namespace blender::gpu { class VKStorageBuffer; +class VKUniformBuffer; class VKVertexBuffer; class VKIndexBuffer; class VKTexture; @@ -131,6 +132,7 @@ class VKDescriptorSet : NonCopyable { void bind_as_ssbo(VKVertexBuffer &buffer, Location location); void bind_as_ssbo(VKIndexBuffer &buffer, Location location); void bind(VKStorageBuffer &buffer, Location location); + void bind(VKUniformBuffer &buffer, Location location); void image_bind(VKTexture &texture, Location location); /** diff --git a/source/blender/gpu/vulkan/vk_memory.cc b/source/blender/gpu/vulkan/vk_memory.cc index 8f7ba9965bb..b2eebaa16c9 100644 --- a/source/blender/gpu/vulkan/vk_memory.cc +++ b/source/blender/gpu/vulkan/vk_memory.cc @@ -105,4 +105,65 @@ uint32_t Std430::element_components_len(const shader::Type type) return 0; } +uint32_t Std140::component_mem_size(const shader::Type /*type*/) +{ + return 4; +} + +uint32_t Std140::element_alignment(const shader::Type type) +{ + switch (type) { + case shader::Type::FLOAT: + case shader::Type::UINT: + case shader::Type::INT: + case shader::Type::BOOL: + return 4; + case shader::Type::VEC2: + case shader::Type::UVEC2: + case shader::Type::IVEC2: + return 8; + case shader::Type::VEC3: + case shader::Type::UVEC3: + case shader::Type::IVEC3: + case shader::Type::VEC4: + case shader::Type::UVEC4: + case shader::Type::IVEC4: + case shader::Type::MAT3: + case shader::Type::MAT4: + return 16; + default: + BLI_assert_msg(false, "Type not supported as push constant"); + } + return 0; +} + +uint32_t Std140::element_components_len(const shader::Type type) +{ + switch (type) { + case shader::Type::FLOAT: + case shader::Type::UINT: + case shader::Type::INT: + case shader::Type::BOOL: + return 1; + case shader::Type::VEC2: + case shader::Type::UVEC2: + case shader::Type::IVEC2: + return 2; + case shader::Type::VEC3: + case shader::Type::UVEC3: + case shader::Type::IVEC3: + case shader::Type::VEC4: + case shader::Type::UVEC4: + case shader::Type::IVEC4: + return 4; + case shader::Type::MAT3: + return 12; + case shader::Type::MAT4: + return 16; + default: + BLI_assert_msg(false, "Type not supported as push constant"); + } + return 0; +} + } // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_memory.hh b/source/blender/gpu/vulkan/vk_memory.hh index fdff3099886..7b5b25a5614 100644 --- a/source/blender/gpu/vulkan/vk_memory.hh +++ b/source/blender/gpu/vulkan/vk_memory.hh @@ -72,4 +72,16 @@ struct Std430 { static uint32_t element_components_len(const shader::Type type); }; +/** + * Information about alignment/components and memory size for types when using std140 layout. + */ +struct Std140 { + /** Get the memory size in bytes of a single component using by the given type.*/ + static uint32_t component_mem_size(const shader::Type type); + /** Get to alignment of the given type in bytes.*/ + static uint32_t element_alignment(const shader::Type type); + /** Get the number of components that should be allocated for the given type.*/ + static uint32_t element_components_len(const shader::Type type); +}; + } // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_push_constants.cc b/source/blender/gpu/vulkan/vk_push_constants.cc index 5ef62fc80c8..f8fd628d7d6 100644 --- a/source/blender/gpu/vulkan/vk_push_constants.cc +++ b/source/blender/gpu/vulkan/vk_push_constants.cc @@ -9,13 +9,14 @@ #include "vk_backend.hh" #include "vk_memory.hh" #include "vk_shader_interface.hh" +#include "vk_storage_buffer.hh" +#include "vk_uniform_buffer.hh" namespace blender::gpu { -template -static void align(const shader::ShaderCreateInfo::PushConst &push_constant, uint32_t *r_offset) +template static void align(const shader::Type &type, uint32_t *r_offset) { - uint32_t alignment = Layout::element_alignment(push_constant.type); + uint32_t alignment = Layout::element_alignment(type); uint32_t alignment_mask = alignment - 1; uint32_t offset = *r_offset; if ((offset & alignment_mask) != 0) { @@ -42,7 +43,7 @@ static VKPushConstantsLayout::PushConstantLayout init_constant( const ShaderInput &shader_input, uint32_t *r_offset) { - align(push_constant, r_offset); + align(push_constant.type, r_offset); VKPushConstantsLayout::PushConstantLayout layout; layout.location = shader_input.location; @@ -54,6 +55,21 @@ static VKPushConstantsLayout::PushConstantLayout init_constant( return layout; } +template +uint32_t struct_size(Span push_constants) +{ + uint32_t offset = 0; + for (const shader::ShaderCreateInfo::PushConst &push_constant : push_constants) { + align(push_constant.type, &offset); + reserve(push_constant, &offset); + } + + /* Make sure result is aligned to 64 bytes.*/ + align(shader::Type::VEC4, &offset); + + return offset; +} + VKPushConstantsLayout::StorageType VKPushConstantsLayout::determine_storage_type( const shader::ShaderCreateInfo &info, const VkPhysicalDeviceLimits &vk_physical_device_limits) { @@ -61,13 +77,9 @@ VKPushConstantsLayout::StorageType VKPushConstantsLayout::determine_storage_type return StorageType::NONE; } - uint32_t offset = 0; - for (const shader::ShaderCreateInfo::PushConst &push_constant : info.push_constants_) { - align(push_constant, &offset); - reserve(push_constant, &offset); - } - return offset <= vk_physical_device_limits.maxPushConstantsSize ? StorageType::PUSH_CONSTANTS : - StorageType::STORAGE_BUFFER; + uint32_t size = struct_size(info.push_constants_); + return size <= vk_physical_device_limits.maxPushConstantsSize ? StorageType::PUSH_CONSTANTS : + StorageType::STORAGE_BUFFER; } void VKPushConstantsLayout::init(const shader::ShaderCreateInfo &info, @@ -77,7 +89,7 @@ void VKPushConstantsLayout::init(const shader::ShaderCreateInfo &info, { BLI_assert(push_constants.is_empty()); storage_type_ = storage_type; - if (storage_type == StorageType::STORAGE_BUFFER) { + if (ELEM(storage_type, StorageType::STORAGE_BUFFER, StorageType::UNIFORM_BUFFER)) { BLI_assert(shader_input); storage_buffer_binding_ = VKDescriptorSet::Location(shader_input); } @@ -85,7 +97,12 @@ void VKPushConstantsLayout::init(const shader::ShaderCreateInfo &info, for (const shader::ShaderCreateInfo::PushConst &push_constant : info.push_constants_) { const ShaderInput *shader_input = interface.uniform_get(push_constant.name.c_str()); BLI_assert(shader_input); - push_constants.append(init_constant(push_constant, *shader_input, &offset)); + if (storage_type == StorageType::UNIFORM_BUFFER) { + push_constants.append(init_constant(push_constant, *shader_input, &offset)); + } + else { + push_constants.append(init_constant(push_constant, *shader_input, &offset)); + } } size_in_bytes_ = offset; } @@ -100,12 +117,23 @@ const VKPushConstantsLayout::PushConstantLayout *VKPushConstantsLayout::find( } return nullptr; } + VKPushConstants::VKPushConstants() = default; VKPushConstants::VKPushConstants(const VKPushConstantsLayout *layout) : layout_(layout) { data_ = MEM_mallocN(layout->size_in_bytes(), __func__); - if (storage_type_get() == VKPushConstantsLayout::StorageType::STORAGE_BUFFER) { - storage_buffer_ = new VKStorageBuffer(size_in_bytes(), GPU_USAGE_DYNAMIC, __func__); + switch (storage_type_get()) { + case VKPushConstantsLayout::StorageType::STORAGE_BUFFER: + storage_buffer_ = new VKStorageBuffer(size_in_bytes(), GPU_USAGE_DYNAMIC, __func__); + break; + + case VKPushConstantsLayout::StorageType::UNIFORM_BUFFER: + uniform_buffer_ = new VKUniformBuffer(size_in_bytes(), __func__); + break; + + case VKPushConstantsLayout::StorageType::PUSH_CONSTANTS: + case VKPushConstantsLayout::StorageType::NONE: + break; } } @@ -116,6 +144,9 @@ VKPushConstants::VKPushConstants(VKPushConstants &&other) : layout_(other.layout storage_buffer_ = other.storage_buffer_; other.storage_buffer_ = nullptr; + + uniform_buffer_ = other.uniform_buffer_; + other.uniform_buffer_ = nullptr; } VKPushConstants::~VKPushConstants() @@ -127,6 +158,9 @@ VKPushConstants::~VKPushConstants() delete storage_buffer_; storage_buffer_ = nullptr; + + delete uniform_buffer_; + uniform_buffer_ = nullptr; } VKPushConstants &VKPushConstants::operator=(VKPushConstants &&other) @@ -157,4 +191,19 @@ VKStorageBuffer &VKPushConstants::storage_buffer_get() return *storage_buffer_; } +void VKPushConstants::update_uniform_buffer(VkDevice /*vk_device*/) +{ + BLI_assert(storage_type_get() == VKPushConstantsLayout::StorageType::UNIFORM_BUFFER); + BLI_assert(uniform_buffer_ != nullptr); + BLI_assert(data_ != nullptr); + uniform_buffer_->update(data_); +} + +VKUniformBuffer &VKPushConstants::uniform_buffer_get() +{ + BLI_assert(storage_type_get() == VKPushConstantsLayout::StorageType::UNIFORM_BUFFER); + BLI_assert(uniform_buffer_ != nullptr); + return *uniform_buffer_; +} + } // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_push_constants.hh b/source/blender/gpu/vulkan/vk_push_constants.hh index 9579738412e..5177824107c 100644 --- a/source/blender/gpu/vulkan/vk_push_constants.hh +++ b/source/blender/gpu/vulkan/vk_push_constants.hh @@ -24,12 +24,12 @@ #include "gpu_shader_create_info.hh" #include "vk_common.hh" -//#include "vk_context.hh" #include "vk_descriptor_set.hh" -#include "vk_storage_buffer.hh" namespace blender::gpu { class VKShaderInterface; +class VKUniformBuffer; +class VKStorageBuffer; /** * Describe the layout of the push constants and the storage type that should be used. @@ -40,6 +40,7 @@ struct VKPushConstantsLayout { NONE, PUSH_CONSTANTS, STORAGE_BUFFER, + UNIFORM_BUFFER, }; struct PushConstantLayout { @@ -98,6 +99,7 @@ class VKPushConstants : NonCopyable { const VKPushConstantsLayout *layout_ = nullptr; void *data_ = nullptr; VKStorageBuffer *storage_buffer_ = nullptr; + VKUniformBuffer *uniform_buffer_ = nullptr; public: VKPushConstants(); @@ -130,6 +132,9 @@ class VKPushConstants : NonCopyable { void update_storage_buffer(VkDevice vk_device); VKStorageBuffer &storage_buffer_get(); + void update_uniform_buffer(VkDevice vk_device); + VKUniformBuffer &uniform_buffer_get(); + const void *data() const { return data_; diff --git a/source/blender/gpu/vulkan/vk_shader.cc b/source/blender/gpu/vulkan/vk_shader.cc index 4e70a1acb00..86de1da510e 100644 --- a/source/blender/gpu/vulkan/vk_shader.cc +++ b/source/blender/gpu/vulkan/vk_shader.cc @@ -892,11 +892,15 @@ static VkDescriptorSetLayoutBinding create_descriptor_set_layout_binding( static VkDescriptorSetLayoutBinding create_descriptor_set_layout_binding( const VKPushConstantsLayout &push_constants_layout) { - BLI_assert(push_constants_layout.storage_type_get() == - VKPushConstantsLayout::StorageType::STORAGE_BUFFER); + BLI_assert(ELEM(push_constants_layout.storage_type_get(), + VKPushConstantsLayout::StorageType::STORAGE_BUFFER, + VKPushConstantsLayout::StorageType::UNIFORM_BUFFER)); VkDescriptorSetLayoutBinding binding = {}; binding.binding = push_constants_layout.storage_buffer_binding_get(); - binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + binding.descriptorType = push_constants_layout.storage_type_get() == + VKPushConstantsLayout::StorageType::STORAGE_BUFFER ? + VK_DESCRIPTOR_TYPE_STORAGE_BUFFER : + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; binding.descriptorCount = 1; binding.stageFlags = VK_SHADER_STAGE_ALL; binding.pImmutableSamplers = nullptr; @@ -946,8 +950,9 @@ static bool descriptor_sets_needed(const VKShaderInterface &shader_interface, const shader::ShaderCreateInfo &info) { return !info.pass_resources_.is_empty() || !info.batch_resources_.is_empty() || - shader_interface.push_constants_layout_get().storage_type_get() == - VKPushConstantsLayout::StorageType::STORAGE_BUFFER; + ELEM(shader_interface.push_constants_layout_get().storage_type_get(), + VKPushConstantsLayout::StorageType::STORAGE_BUFFER, + VKPushConstantsLayout::StorageType::UNIFORM_BUFFER); } bool VKShader::finalize_descriptor_set_layouts(VkDevice vk_device, @@ -1055,6 +1060,10 @@ std::string VKShader::resources_declare(const shader::ShaderCreateInfo &info) co if (push_constants_storage == VKPushConstantsLayout::StorageType::PUSH_CONSTANTS) { ss << "layout(push_constant) uniform constants\n"; } + else if (push_constants_storage == VKPushConstantsLayout::StorageType::UNIFORM_BUFFER) { + ss << "layout(binding = " << push_constants_layout.storage_buffer_binding_get() + << ", std140) uniform constants\n"; + } else /* VKPushConstantsLayout::StorageType::STORAGE_BUFFER*/ { ss << "layout(binding = " << push_constants_layout.storage_buffer_binding_get() << ", std430) buffer constants\n"; diff --git a/source/blender/gpu/vulkan/vk_shader_interface.cc b/source/blender/gpu/vulkan/vk_shader_interface.cc index 48246300ae9..536ac488d1d 100644 --- a/source/blender/gpu/vulkan/vk_shader_interface.cc +++ b/source/blender/gpu/vulkan/vk_shader_interface.cc @@ -51,6 +51,10 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) ssbo_len_++; names_size += PUSH_CONSTANTS_FALLBACK_NAME_LEN + 1; } + else if (push_constants_storage_type == VKPushConstantsLayout::StorageType::UNIFORM_BUFFER) { + ubo_len_++; + names_size += PUSH_CONSTANTS_FALLBACK_NAME_LEN + 1; + } /* Make sure that the image slots don't overlap with the sampler slots.*/ image_offset_++; @@ -74,6 +78,16 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) input++; } } + /* Add push constant when using uniform buffer as fallback. */ + int32_t push_constants_fallback_location = -1; + ShaderInput *push_constants_fallback_input = nullptr; + if (push_constants_storage_type == VKPushConstantsLayout::StorageType::UNIFORM_BUFFER) { + copy_input_name(input, PUSH_CONSTANTS_FALLBACK_NAME, name_buffer_, name_buffer_offset); + input->location = push_constants_fallback_location = location++; + input->binding = -1; + push_constants_fallback_input = input; + input++; + } /* Images, Samplers and buffers. */ for (const ShaderCreateInfo::Resource &res : all_resources) { @@ -118,8 +132,6 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) * When using storage buffer storage type we need to add it to the the name list here. * Also determine the location as this is used inside the descriptor set as its binding number. */ - int32_t push_constants_fallback_location = -1; - ShaderInput *push_constants_fallback_input = nullptr; if (push_constants_storage_type == VKPushConstantsLayout::StorageType::STORAGE_BUFFER) { copy_input_name(input, PUSH_CONSTANTS_FALLBACK_NAME, name_buffer_, name_buffer_offset); input->location = push_constants_fallback_location = location++; diff --git a/source/blender/gpu/vulkan/vk_uniform_buffer.cc b/source/blender/gpu/vulkan/vk_uniform_buffer.cc index a5024517ce5..1aee3c3eee4 100644 --- a/source/blender/gpu/vulkan/vk_uniform_buffer.cc +++ b/source/blender/gpu/vulkan/vk_uniform_buffer.cc @@ -6,11 +6,22 @@ */ #include "vk_uniform_buffer.hh" +#include "vk_context.hh" namespace blender::gpu { -void VKUniformBuffer::update(const void * /*data*/) +void VKUniformBuffer::update(const void *data) { + VKContext &context = *VKContext::get(); + if (!buffer_.is_allocated()) { + allocate(context); + } + buffer_.update(context, data); +} + +void VKUniformBuffer::allocate(VKContext &context) +{ + buffer_.create(context, size_in_bytes_, GPU_USAGE_STATIC, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); } void VKUniformBuffer::clear_to_zero() diff --git a/source/blender/gpu/vulkan/vk_uniform_buffer.hh b/source/blender/gpu/vulkan/vk_uniform_buffer.hh index bd5b136f249..ebacb23fed2 100644 --- a/source/blender/gpu/vulkan/vk_uniform_buffer.hh +++ b/source/blender/gpu/vulkan/vk_uniform_buffer.hh @@ -9,9 +9,13 @@ #include "gpu_uniform_buffer_private.hh" +#include "vk_buffer.hh" + namespace blender::gpu { class VKUniformBuffer : public UniformBuf { + VKBuffer buffer_; + public: VKUniformBuffer(int size, const char *name) : UniformBuf(size, name) { @@ -22,6 +26,19 @@ class VKUniformBuffer : public UniformBuf { void bind(int slot) override; void bind_as_ssbo(int slot) override; void unbind() override; + + VkBuffer vk_handle() const + { + return buffer_.vk_handle(); + } + + size_t size_in_bytes() const + { + return size_in_bytes_; + } + + private: + void allocate(VKContext &context); }; } // namespace blender::gpu -- 2.30.2 From dee686bd9d359d00d8a69c5a7ab4bf1ae6ce4283 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Tue, 21 Feb 2023 21:39:17 +0100 Subject: [PATCH 27/55] Some small tweaks --- source/blender/gpu/vulkan/vk_backend.cc | 6 ++-- .../blender/gpu/vulkan/vk_command_buffer.cc | 7 +++-- source/blender/gpu/vulkan/vk_pipeline.cc | 2 +- .../blender/gpu/vulkan/vk_push_constants.cc | 18 +++++------ .../blender/gpu/vulkan/vk_push_constants.hh | 31 +++++++++++-------- source/blender/gpu/vulkan/vk_shader.cc | 5 +-- .../blender/gpu/vulkan/vk_shader_interface.cc | 1 + 7 files changed, 39 insertions(+), 31 deletions(-) diff --git a/source/blender/gpu/vulkan/vk_backend.cc b/source/blender/gpu/vulkan/vk_backend.cc index bc3647551b2..688e8fd5691 100644 --- a/source/blender/gpu/vulkan/vk_backend.cc +++ b/source/blender/gpu/vulkan/vk_backend.cc @@ -70,7 +70,7 @@ void VKBackend::compute_dispatch(int groups_x_len, int groups_y_len, int groups_ VKPushConstants &push_constants = pipeline.push_constants_get(); /* Update push constants based on their storage type.*/ - switch (push_constants.storage_type_get()) { + switch (push_constants.layout_get().storage_type_get()) { case VKPushConstantsLayout::StorageType::NONE: break; @@ -82,13 +82,13 @@ void VKBackend::compute_dispatch(int groups_x_len, int groups_y_len, int groups_ case VKPushConstantsLayout::StorageType::STORAGE_BUFFER: push_constants.update_storage_buffer(context.device_get()); descriptor_set.bind(push_constants.storage_buffer_get(), - push_constants.storage_buffer_binding_get()); + push_constants.layout_get().storage_buffer_binding_get()); break; case VKPushConstantsLayout::StorageType::UNIFORM_BUFFER: push_constants.update_uniform_buffer(context.device_get()); descriptor_set.bind(push_constants.uniform_buffer_get(), - push_constants.storage_buffer_binding_get()); + push_constants.layout_get().storage_buffer_binding_get()); break; } descriptor_set.update(context.device_get()); diff --git a/source/blender/gpu/vulkan/vk_command_buffer.cc b/source/blender/gpu/vulkan/vk_command_buffer.cc index c53d9e6fc61..c3b36b9d903 100644 --- a/source/blender/gpu/vulkan/vk_command_buffer.cc +++ b/source/blender/gpu/vulkan/vk_command_buffer.cc @@ -9,8 +9,8 @@ #include "vk_buffer.hh" #include "vk_context.hh" #include "vk_memory.hh" -#include "vk_texture.hh" #include "vk_pipeline.hh" +#include "vk_texture.hh" #include "BLI_assert.h" @@ -76,14 +76,15 @@ void VKCommandBuffer::push_constants(const VKPushConstants &push_constants, const VkPipelineLayout vk_pipeline_layout, const VkShaderStageFlags vk_shader_stages) { - if (push_constants.storage_type_get() != VKPushConstantsLayout::StorageType::PUSH_CONSTANTS) { + if (push_constants.layout_get().storage_type_get() != + VKPushConstantsLayout::StorageType::PUSH_CONSTANTS) { return; } vkCmdPushConstants(vk_command_buffer_, vk_pipeline_layout, vk_shader_stages, push_constants.offset(), - push_constants.size_in_bytes(), + push_constants.layout_get().size_in_bytes(), push_constants.data()); } diff --git a/source/blender/gpu/vulkan/vk_pipeline.cc b/source/blender/gpu/vulkan/vk_pipeline.cc index 890808645f5..c66c46c76d9 100644 --- a/source/blender/gpu/vulkan/vk_pipeline.cc +++ b/source/blender/gpu/vulkan/vk_pipeline.cc @@ -52,7 +52,7 @@ VKPipeline VKPipeline::create_compute_pipeline(VKContext &context, if (vkCreateComputePipelines( vk_device, nullptr, 1, &pipeline_info, vk_allocation_callbacks, &vk_pipeline) != VK_SUCCESS) { - //return VKPipeline(); + return VKPipeline(); } VKDescriptorSet descriptor_set = context.descriptor_pools_get().allocate(descriptor_set_layout); diff --git a/source/blender/gpu/vulkan/vk_push_constants.cc b/source/blender/gpu/vulkan/vk_push_constants.cc index f8fd628d7d6..3bed7e6d75f 100644 --- a/source/blender/gpu/vulkan/vk_push_constants.cc +++ b/source/blender/gpu/vulkan/vk_push_constants.cc @@ -78,8 +78,8 @@ VKPushConstantsLayout::StorageType VKPushConstantsLayout::determine_storage_type } uint32_t size = struct_size(info.push_constants_); - return size <= vk_physical_device_limits.maxPushConstantsSize ? StorageType::PUSH_CONSTANTS : - StorageType::STORAGE_BUFFER; + return size <= vk_physical_device_limits.maxPushConstantsSize ? STORAGE_TYPE_DEFAULT : + STORAGE_TYPE_FALLBACK; } void VKPushConstantsLayout::init(const shader::ShaderCreateInfo &info, @@ -122,13 +122,13 @@ VKPushConstants::VKPushConstants() = default; VKPushConstants::VKPushConstants(const VKPushConstantsLayout *layout) : layout_(layout) { data_ = MEM_mallocN(layout->size_in_bytes(), __func__); - switch (storage_type_get()) { + switch (layout_->storage_type_get()) { case VKPushConstantsLayout::StorageType::STORAGE_BUFFER: - storage_buffer_ = new VKStorageBuffer(size_in_bytes(), GPU_USAGE_DYNAMIC, __func__); + storage_buffer_ = new VKStorageBuffer(layout_->size_in_bytes(), GPU_USAGE_DYNAMIC, __func__); break; case VKPushConstantsLayout::StorageType::UNIFORM_BUFFER: - uniform_buffer_ = new VKUniformBuffer(size_in_bytes(), __func__); + uniform_buffer_ = new VKUniformBuffer(layout_->size_in_bytes(), __func__); break; case VKPushConstantsLayout::StorageType::PUSH_CONSTANTS: @@ -178,7 +178,7 @@ VKPushConstants &VKPushConstants::operator=(VKPushConstants &&other) void VKPushConstants::update_storage_buffer(VkDevice /*vk_device*/) { - BLI_assert(storage_type_get() == VKPushConstantsLayout::StorageType::STORAGE_BUFFER); + BLI_assert(layout_->storage_type_get() == VKPushConstantsLayout::StorageType::STORAGE_BUFFER); BLI_assert(storage_buffer_ != nullptr); BLI_assert(data_ != nullptr); storage_buffer_->update(data_); @@ -186,14 +186,14 @@ void VKPushConstants::update_storage_buffer(VkDevice /*vk_device*/) VKStorageBuffer &VKPushConstants::storage_buffer_get() { - BLI_assert(storage_type_get() == VKPushConstantsLayout::StorageType::STORAGE_BUFFER); + BLI_assert(layout_->storage_type_get() == VKPushConstantsLayout::StorageType::STORAGE_BUFFER); BLI_assert(storage_buffer_ != nullptr); return *storage_buffer_; } void VKPushConstants::update_uniform_buffer(VkDevice /*vk_device*/) { - BLI_assert(storage_type_get() == VKPushConstantsLayout::StorageType::UNIFORM_BUFFER); + BLI_assert(layout_->storage_type_get() == VKPushConstantsLayout::StorageType::UNIFORM_BUFFER); BLI_assert(uniform_buffer_ != nullptr); BLI_assert(data_ != nullptr); uniform_buffer_->update(data_); @@ -201,7 +201,7 @@ void VKPushConstants::update_uniform_buffer(VkDevice /*vk_device*/) VKUniformBuffer &VKPushConstants::uniform_buffer_get() { - BLI_assert(storage_type_get() == VKPushConstantsLayout::StorageType::UNIFORM_BUFFER); + BLI_assert(layout_->storage_type_get() == VKPushConstantsLayout::StorageType::UNIFORM_BUFFER); BLI_assert(uniform_buffer_ != nullptr); return *uniform_buffer_; } diff --git a/source/blender/gpu/vulkan/vk_push_constants.hh b/source/blender/gpu/vulkan/vk_push_constants.hh index 5177824107c..be3bbfe64f7 100644 --- a/source/blender/gpu/vulkan/vk_push_constants.hh +++ b/source/blender/gpu/vulkan/vk_push_constants.hh @@ -35,13 +35,28 @@ class VKStorageBuffer; * Describe the layout of the push constants and the storage type that should be used. */ struct VKPushConstantsLayout { - /* Should the push constant use regular push constants or a buffer.*/ + /* Different methods to store push constants.*/ enum class StorageType { + /** Push constants aren't in use.*/ NONE, + + /** Store push constants as regular vulkan push constants.*/ PUSH_CONSTANTS, + + /** + * Fallback when push constants doesn't meet the device requirements. This fallback uses a + * storage buffer. + */ STORAGE_BUFFER, + + /** + * Fallback when push constants doesn't meet the device requirements. This fallback uses an + * uniform buffer. + */ UNIFORM_BUFFER, }; + static constexpr StorageType STORAGE_TYPE_DEFAULT = StorageType::PUSH_CONSTANTS; + static constexpr StorageType STORAGE_TYPE_FALLBACK = StorageType::UNIFORM_BUFFER; struct PushConstantLayout { /* TODO: location requires sequential lookups, we should make the location index based for @@ -114,19 +129,9 @@ class VKPushConstants : NonCopyable { return 0; } - size_t size_in_bytes() const + const VKPushConstantsLayout &layout_get() const { - return layout_->size_in_bytes(); - } - - VKPushConstantsLayout::StorageType storage_type_get() const - { - return layout_->storage_type_get(); - } - - VKDescriptorSet::Location storage_buffer_binding_get() const - { - return layout_->storage_buffer_binding_get(); + return *layout_; } void update_storage_buffer(VkDevice vk_device); diff --git a/source/blender/gpu/vulkan/vk_shader.cc b/source/blender/gpu/vulkan/vk_shader.cc index 86de1da510e..cd5bb74181b 100644 --- a/source/blender/gpu/vulkan/vk_shader.cc +++ b/source/blender/gpu/vulkan/vk_shader.cc @@ -925,8 +925,9 @@ static void add_descriptor_set_layout_bindings( /* Add push constants to the descriptor when push constants are stored in a storage buffer.*/ const VKPushConstantsLayout &push_constants_layout = interface.push_constants_layout_get(); - if (push_constants_layout.storage_type_get() == - VKPushConstantsLayout::StorageType::STORAGE_BUFFER) { + if (ELEM(push_constants_layout.storage_type_get(), + VKPushConstantsLayout::StorageType::UNIFORM_BUFFER, + VKPushConstantsLayout::StorageType::STORAGE_BUFFER)) { r_bindings.append(create_descriptor_set_layout_binding(push_constants_layout)); } } diff --git a/source/blender/gpu/vulkan/vk_shader_interface.cc b/source/blender/gpu/vulkan/vk_shader_interface.cc index 536ac488d1d..29b95ba1d61 100644 --- a/source/blender/gpu/vulkan/vk_shader_interface.cc +++ b/source/blender/gpu/vulkan/vk_shader_interface.cc @@ -143,6 +143,7 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) info, *this, push_constants_storage_type, push_constants_fallback_input); sort_inputs(); + debug_print(); } const ShaderInput *VKShaderInterface::shader_input_get( -- 2.30.2 From 56cbef9e02bba39dfc100b28e9ce7b1daa586561 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Wed, 22 Feb 2023 07:01:07 +0100 Subject: [PATCH 28/55] Refactored shader interface to keep track of descriptor sets. --- .../blender/gpu/vulkan/vk_descriptor_set.hh | 9 ++- source/blender/gpu/vulkan/vk_index_buffer.cc | 4 +- .../blender/gpu/vulkan/vk_push_constants.cc | 8 ++- .../blender/gpu/vulkan/vk_push_constants.hh | 2 +- source/blender/gpu/vulkan/vk_shader.cc | 25 +++---- .../blender/gpu/vulkan/vk_shader_interface.cc | 69 +++++++++++++------ .../blender/gpu/vulkan/vk_shader_interface.hh | 23 +++++-- .../blender/gpu/vulkan/vk_storage_buffer.cc | 4 +- source/blender/gpu/vulkan/vk_texture.cc | 4 +- source/blender/gpu/vulkan/vk_vertex_buffer.cc | 4 +- 10 files changed, 95 insertions(+), 57 deletions(-) diff --git a/source/blender/gpu/vulkan/vk_descriptor_set.hh b/source/blender/gpu/vulkan/vk_descriptor_set.hh index e32af7bf478..bd78d0c84f1 100644 --- a/source/blender/gpu/vulkan/vk_descriptor_set.hh +++ b/source/blender/gpu/vulkan/vk_descriptor_set.hh @@ -20,6 +20,7 @@ class VKUniformBuffer; class VKVertexBuffer; class VKIndexBuffer; class VKTexture; +class VKShaderInterface; /** * In vulkan shader resources (images and buffers) are grouped in descriptor sets. @@ -51,12 +52,13 @@ class VKDescriptorSet : NonCopyable { */ uint32_t binding; - public: - Location() = default; - Location(const ShaderInput *shader_input) : binding(shader_input->location) + Location(uint32_t binding) : binding(binding) { } + public: + Location() = default; + bool operator==(const Location &other) const { return binding == other.binding; @@ -68,6 +70,7 @@ class VKDescriptorSet : NonCopyable { } friend struct Binding; + friend class VKShaderInterface; }; private: diff --git a/source/blender/gpu/vulkan/vk_index_buffer.cc b/source/blender/gpu/vulkan/vk_index_buffer.cc index 1d6e620a395..32b5659b8db 100644 --- a/source/blender/gpu/vulkan/vk_index_buffer.cc +++ b/source/blender/gpu/vulkan/vk_index_buffer.cc @@ -24,9 +24,9 @@ void VKIndexBuffer::bind_as_ssbo(uint binding) VKShader *shader = static_cast(context.shader); const VKShaderInterface &shader_interface = shader->interface_get(); - const ShaderInput *shader_input = shader_interface.shader_input_get( + const VKDescriptorSet::Location location = shader_interface.descriptor_set_location( shader::ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER, binding); - shader->pipeline_get().descriptor_set_get().bind_as_ssbo(*this, shader_input); + shader->pipeline_get().descriptor_set_get().bind_as_ssbo(*this, location); } void VKIndexBuffer::read(uint32_t *data) const diff --git a/source/blender/gpu/vulkan/vk_push_constants.cc b/source/blender/gpu/vulkan/vk_push_constants.cc index 3bed7e6d75f..41b8f26e157 100644 --- a/source/blender/gpu/vulkan/vk_push_constants.cc +++ b/source/blender/gpu/vulkan/vk_push_constants.cc @@ -85,13 +85,12 @@ VKPushConstantsLayout::StorageType VKPushConstantsLayout::determine_storage_type void VKPushConstantsLayout::init(const shader::ShaderCreateInfo &info, const VKShaderInterface &interface, const StorageType storage_type, - const ShaderInput *shader_input) + const VKDescriptorSet::Location location) { BLI_assert(push_constants.is_empty()); storage_type_ = storage_type; if (ELEM(storage_type, StorageType::STORAGE_BUFFER, StorageType::UNIFORM_BUFFER)) { - BLI_assert(shader_input); - storage_buffer_binding_ = VKDescriptorSet::Location(shader_input); + storage_buffer_binding_ = location; } uint32_t offset = 0; for (const shader::ShaderCreateInfo::PushConst &push_constant : info.push_constants_) { @@ -173,6 +172,9 @@ VKPushConstants &VKPushConstants::operator=(VKPushConstants &&other) storage_buffer_ = other.storage_buffer_; other.storage_buffer_ = nullptr; + uniform_buffer_ = other.uniform_buffer_; + other.uniform_buffer_ = nullptr; + return *this; } diff --git a/source/blender/gpu/vulkan/vk_push_constants.hh b/source/blender/gpu/vulkan/vk_push_constants.hh index be3bbfe64f7..4a9e0509e92 100644 --- a/source/blender/gpu/vulkan/vk_push_constants.hh +++ b/source/blender/gpu/vulkan/vk_push_constants.hh @@ -85,7 +85,7 @@ struct VKPushConstantsLayout { void init(const shader::ShaderCreateInfo &info, const VKShaderInterface &interface, StorageType storage_type, - const ShaderInput *shader_input); + VKDescriptorSet::Location location); /** * Return the storage type that is used. diff --git a/source/blender/gpu/vulkan/vk_shader.cc b/source/blender/gpu/vulkan/vk_shader.cc index cd5bb74181b..f14904ef0b7 100644 --- a/source/blender/gpu/vulkan/vk_shader.cc +++ b/source/blender/gpu/vulkan/vk_shader.cc @@ -326,10 +326,10 @@ static std::ostream &print_qualifier(std::ostream &os, const Qualifier &qualifie } static void print_resource(std::ostream &os, - const ShaderInput &shader_input, + const VKDescriptorSet::Location location, const ShaderCreateInfo::Resource &res) { - os << "layout(binding = " << shader_input.location; + os << "layout(binding = " << (uint32_t)location; if (res.bind_type == ShaderCreateInfo::Resource::BindType::IMAGE) { os << ", " << to_string(res.image.format); } @@ -379,12 +379,8 @@ static void print_resource(std::ostream &os, const VKShaderInterface &shader_interface, const ShaderCreateInfo::Resource &res) { - const ShaderInput *shader_input = shader_interface.shader_input_get(res); - if (shader_input == nullptr) { - BLI_assert_msg(shader_input, "Cannot find shader input for resource"); - return; - } - print_resource(os, *shader_input, res); + const VKDescriptorSet::Location location = shader_interface.descriptor_set_location(res); + print_resource(os, location, res); } static void print_resource_alias(std::ostream &os, const ShaderCreateInfo::Resource &res) @@ -877,10 +873,10 @@ static VkDescriptorType descriptor_type(const shader::ShaderCreateInfo::Resource } static VkDescriptorSetLayoutBinding create_descriptor_set_layout_binding( - const ShaderInput &shader_input, const shader::ShaderCreateInfo::Resource &resource) + const VKDescriptorSet::Location location, const shader::ShaderCreateInfo::Resource &resource) { VkDescriptorSetLayoutBinding binding = {}; - binding.binding = shader_input.location; + binding.binding = location; binding.descriptorType = descriptor_type(resource); binding.descriptorCount = 1; binding.stageFlags = VK_SHADER_STAGE_ALL; @@ -914,13 +910,8 @@ static void add_descriptor_set_layout_bindings( Vector &r_bindings) { for (const shader::ShaderCreateInfo::Resource &resource : resources) { - const ShaderInput *shader_input = interface.shader_input_get(resource); - if (shader_input == nullptr) { - BLI_assert_msg(shader_input, "Cannot find shader input for resource."); - continue; - } - - r_bindings.append(create_descriptor_set_layout_binding(*shader_input, resource)); + const VKDescriptorSet::Location location = interface.descriptor_set_location(resource); + r_bindings.append(create_descriptor_set_layout_binding(location, resource)); } /* Add push constants to the descriptor when push constants are stored in a storage buffer.*/ diff --git a/source/blender/gpu/vulkan/vk_shader_interface.cc b/source/blender/gpu/vulkan/vk_shader_interface.cc index 29b95ba1d61..8f9f44264b2 100644 --- a/source/blender/gpu/vulkan/vk_shader_interface.cc +++ b/source/blender/gpu/vulkan/vk_shader_interface.cc @@ -62,30 +62,29 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) int32_t input_tot_len = ubo_len_ + uniform_len_ + ssbo_len_; inputs_ = static_cast( MEM_calloc_arrayN(input_tot_len, sizeof(ShaderInput), __func__)); + descriptor_set_locations_ = Array(input_tot_len); ShaderInput *input = inputs_; name_buffer_ = (char *)MEM_mallocN(names_size, "name_buffer"); uint32_t name_buffer_offset = 0; - - int32_t location = 0; + uint32_t descriptor_set_location = 0; /* Uniform blocks */ for (const ShaderCreateInfo::Resource &res : all_resources) { if (res.bind_type == ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER) { copy_input_name(input, res.image.name, name_buffer_, name_buffer_offset); - input->location = location++; - input->binding = res.slot; + input->location = input->binding = res.slot; + descriptor_set_location_update(input, descriptor_set_location++); input++; } } /* Add push constant when using uniform buffer as fallback. */ int32_t push_constants_fallback_location = -1; - ShaderInput *push_constants_fallback_input = nullptr; if (push_constants_storage_type == VKPushConstantsLayout::StorageType::UNIFORM_BUFFER) { copy_input_name(input, PUSH_CONSTANTS_FALLBACK_NAME, name_buffer_, name_buffer_offset); - input->location = push_constants_fallback_location = location++; - input->binding = -1; - push_constants_fallback_input = input; + input->location = input->binding = -1; + push_constants_fallback_location = descriptor_set_location++; + descriptor_set_location_update(input, push_constants_fallback_location); input++; } @@ -93,14 +92,14 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) for (const ShaderCreateInfo::Resource &res : all_resources) { if (res.bind_type == ShaderCreateInfo::Resource::BindType::SAMPLER) { copy_input_name(input, res.sampler.name, name_buffer_, name_buffer_offset); - input->location = location++; - input->binding = res.slot; + input->location = input->binding = res.slot; + descriptor_set_location_update(input, descriptor_set_location++); input++; } else if (res.bind_type == ShaderCreateInfo::Resource::BindType::IMAGE) { copy_input_name(input, res.image.name, name_buffer_, name_buffer_offset); - input->location = location++; - input->binding = res.slot + image_offset_; + input->location = input->binding = res.slot + image_offset_; + descriptor_set_location_update(input, descriptor_set_location++); input++; } } @@ -109,7 +108,7 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) /* NOTE: Push constants must be added after other uniform resources as resources have strict * rules for their 'location' due to descriptor sets. Push constants only need an unique location * as it is only used by the GPU module internally.*/ - int32_t push_constant_location = location + 1024; + int32_t push_constant_location = 1024; for (const ShaderCreateInfo::PushConst &push_constant : info.push_constants_) { copy_input_name(input, push_constant.name, name_buffer_, name_buffer_offset); input->location = push_constant_location++; @@ -121,8 +120,8 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) for (const ShaderCreateInfo::Resource &res : all_resources) { if (res.bind_type == ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER) { copy_input_name(input, res.storagebuf.name, name_buffer_, name_buffer_offset); - input->location = location++; - input->binding = res.slot; + input->location = input->binding = res.slot; + descriptor_set_location_update(input, descriptor_set_location++); input++; } } @@ -134,16 +133,46 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) */ if (push_constants_storage_type == VKPushConstantsLayout::StorageType::STORAGE_BUFFER) { copy_input_name(input, PUSH_CONSTANTS_FALLBACK_NAME, name_buffer_, name_buffer_offset); - input->location = push_constants_fallback_location = location++; - input->binding = -1; - push_constants_fallback_input = input; + input->location = input->binding = -1; + push_constants_fallback_location = descriptor_set_location++; + descriptor_set_location_update(input, push_constants_fallback_location); input++; } push_constants_layout_.init( - info, *this, push_constants_storage_type, push_constants_fallback_input); + info, *this, push_constants_storage_type, push_constants_fallback_location); sort_inputs(); - debug_print(); + // debug_print(); +} + +void VKShaderInterface::descriptor_set_location_update(const ShaderInput *shader_input, + const VKDescriptorSet::Location location) +{ + int32_t index = (shader_input - inputs_) / sizeof(ShaderInput); + descriptor_set_locations_[index] = location; +} + +const VKDescriptorSet::Location VKShaderInterface::descriptor_set_location( + const ShaderInput *shader_input) const +{ + int32_t index = (shader_input - inputs_) / sizeof(ShaderInput); + return descriptor_set_locations_[index]; +} + +const VKDescriptorSet::Location VKShaderInterface::descriptor_set_location( + const shader::ShaderCreateInfo::Resource &resource) const +{ + const ShaderInput *shader_input = shader_input_get(resource); + BLI_assert(shader_input); + return descriptor_set_location(shader_input); +} + +const VKDescriptorSet::Location VKShaderInterface::descriptor_set_location( + const shader::ShaderCreateInfo::Resource::BindType &bind_type, int binding) const +{ + const ShaderInput *shader_input = shader_input_get(bind_type, binding); + BLI_assert(shader_input); + return descriptor_set_location(shader_input); } const ShaderInput *VKShaderInterface::shader_input_get( diff --git a/source/blender/gpu/vulkan/vk_shader_interface.hh b/source/blender/gpu/vulkan/vk_shader_interface.hh index a217351ad0e..ef96ea3aafd 100644 --- a/source/blender/gpu/vulkan/vk_shader_interface.hh +++ b/source/blender/gpu/vulkan/vk_shader_interface.hh @@ -10,6 +10,8 @@ #include "gpu_shader_create_info.hh" #include "gpu_shader_interface.hh" +#include "BLI_array.hh" + #include "vk_push_constants.hh" namespace blender::gpu { @@ -25,6 +27,7 @@ class VKShaderInterface : public ShaderInterface { uint32_t image_offset_ = 0; VKPushConstantsLayout push_constants_layout_; + Array descriptor_set_locations_; public: static constexpr StringRefNull PUSH_CONSTANTS_FALLBACK_NAME = StringRefNull( @@ -35,6 +38,18 @@ class VKShaderInterface : public ShaderInterface { VKShaderInterface() = default; void init(const shader::ShaderCreateInfo &info); + + const VKDescriptorSet::Location descriptor_set_location( + const shader::ShaderCreateInfo::Resource &resource) const; + const VKDescriptorSet::Location descriptor_set_location( + const shader::ShaderCreateInfo::Resource::BindType &bind_type, int binding) const; + + const VKPushConstantsLayout &push_constants_layout_get() const + { + return push_constants_layout_; + } + + private: /** * Retrieve the shader input for the given resource. * @@ -44,10 +59,8 @@ class VKShaderInterface : public ShaderInterface { const ShaderInput *shader_input_get(const shader::ShaderCreateInfo::Resource &resource) const; const ShaderInput *shader_input_get( const shader::ShaderCreateInfo::Resource::BindType &bind_type, int binding) const; - - const VKPushConstantsLayout &push_constants_layout_get() const - { - return push_constants_layout_; - } + const VKDescriptorSet::Location descriptor_set_location(const ShaderInput *shader_input) const; + void descriptor_set_location_update(const ShaderInput *shader_input, + const VKDescriptorSet::Location location); }; } // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_storage_buffer.cc b/source/blender/gpu/vulkan/vk_storage_buffer.cc index 5c6d8a10244..8b5545f223f 100644 --- a/source/blender/gpu/vulkan/vk_storage_buffer.cc +++ b/source/blender/gpu/vulkan/vk_storage_buffer.cc @@ -34,9 +34,9 @@ void VKStorageBuffer::bind(int slot) } VKShader *shader = static_cast(context.shader); const VKShaderInterface &shader_interface = shader->interface_get(); - const ShaderInput *shader_input = shader_interface.shader_input_get( + const VKDescriptorSet::Location location = shader_interface.descriptor_set_location( shader::ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER, slot); - shader->pipeline_get().descriptor_set_get().bind(*this, shader_input); + shader->pipeline_get().descriptor_set_get().bind(*this, location); } void VKStorageBuffer::unbind() diff --git a/source/blender/gpu/vulkan/vk_texture.cc b/source/blender/gpu/vulkan/vk_texture.cc index bb587d477aa..1a691fb6b8c 100644 --- a/source/blender/gpu/vulkan/vk_texture.cc +++ b/source/blender/gpu/vulkan/vk_texture.cc @@ -227,8 +227,8 @@ void VKTexture::image_bind(int binding) } VKContext &context = *VKContext::get(); VKShader *shader = static_cast(context.shader); - VKDescriptorSet::Location location(shader->interface_get().shader_input_get( - shader::ShaderCreateInfo::Resource::BindType::IMAGE, binding)); + const VKDescriptorSet::Location location = shader->interface_get().descriptor_set_location( + shader::ShaderCreateInfo::Resource::BindType::IMAGE, binding); shader->pipeline_get().descriptor_set_get().image_bind(*this, location); } diff --git a/source/blender/gpu/vulkan/vk_vertex_buffer.cc b/source/blender/gpu/vulkan/vk_vertex_buffer.cc index 5d44b2e2c4f..b28822ab705 100644 --- a/source/blender/gpu/vulkan/vk_vertex_buffer.cc +++ b/source/blender/gpu/vulkan/vk_vertex_buffer.cc @@ -27,9 +27,9 @@ void VKVertexBuffer::bind_as_ssbo(uint binding) VKShader *shader = static_cast(context.shader); const VKShaderInterface &shader_interface = shader->interface_get(); - const ShaderInput *shader_input = shader_interface.shader_input_get( + const VKDescriptorSet::Location location = shader_interface.descriptor_set_location( shader::ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER, binding); - shader->pipeline_get().descriptor_set_get().bind_as_ssbo(*this, shader_input); + shader->pipeline_get().descriptor_set_get().bind_as_ssbo(*this, location); } void VKVertexBuffer::bind_as_texture(uint /*binding*/) -- 2.30.2 From 9e6947d7445a8f29c09a9091fe964cde8b6569ee Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Wed, 22 Feb 2023 09:56:10 +0100 Subject: [PATCH 29/55] Determine descriptor set location after input sorting. --- .../blender/gpu/vulkan/vk_shader_interface.cc | 57 ++++++++++++++----- 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/source/blender/gpu/vulkan/vk_shader_interface.cc b/source/blender/gpu/vulkan/vk_shader_interface.cc index 8f9f44264b2..cf6f72596f0 100644 --- a/source/blender/gpu/vulkan/vk_shader_interface.cc +++ b/source/blender/gpu/vulkan/vk_shader_interface.cc @@ -62,19 +62,16 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) int32_t input_tot_len = ubo_len_ + uniform_len_ + ssbo_len_; inputs_ = static_cast( MEM_calloc_arrayN(input_tot_len, sizeof(ShaderInput), __func__)); - descriptor_set_locations_ = Array(input_tot_len); ShaderInput *input = inputs_; name_buffer_ = (char *)MEM_mallocN(names_size, "name_buffer"); uint32_t name_buffer_offset = 0; - uint32_t descriptor_set_location = 0; /* Uniform blocks */ for (const ShaderCreateInfo::Resource &res : all_resources) { if (res.bind_type == ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER) { copy_input_name(input, res.image.name, name_buffer_, name_buffer_offset); input->location = input->binding = res.slot; - descriptor_set_location_update(input, descriptor_set_location++); input++; } } @@ -83,8 +80,6 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) if (push_constants_storage_type == VKPushConstantsLayout::StorageType::UNIFORM_BUFFER) { copy_input_name(input, PUSH_CONSTANTS_FALLBACK_NAME, name_buffer_, name_buffer_offset); input->location = input->binding = -1; - push_constants_fallback_location = descriptor_set_location++; - descriptor_set_location_update(input, push_constants_fallback_location); input++; } @@ -93,13 +88,11 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) if (res.bind_type == ShaderCreateInfo::Resource::BindType::SAMPLER) { copy_input_name(input, res.sampler.name, name_buffer_, name_buffer_offset); input->location = input->binding = res.slot; - descriptor_set_location_update(input, descriptor_set_location++); input++; } else if (res.bind_type == ShaderCreateInfo::Resource::BindType::IMAGE) { copy_input_name(input, res.image.name, name_buffer_, name_buffer_offset); input->location = input->binding = res.slot + image_offset_; - descriptor_set_location_update(input, descriptor_set_location++); input++; } } @@ -121,7 +114,6 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) if (res.bind_type == ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER) { copy_input_name(input, res.storagebuf.name, name_buffer_, name_buffer_offset); input->location = input->binding = res.slot; - descriptor_set_location_update(input, descriptor_set_location++); input++; } } @@ -134,28 +126,63 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) if (push_constants_storage_type == VKPushConstantsLayout::StorageType::STORAGE_BUFFER) { copy_input_name(input, PUSH_CONSTANTS_FALLBACK_NAME, name_buffer_, name_buffer_offset); input->location = input->binding = -1; - push_constants_fallback_location = descriptor_set_location++; - descriptor_set_location_update(input, push_constants_fallback_location); input++; } - push_constants_layout_.init( - info, *this, push_constants_storage_type, push_constants_fallback_location); sort_inputs(); - // debug_print(); + + /* Determine the descriptor set locations after the inputs have been sorted.*/ + descriptor_set_locations_ = Array(input_tot_len); + uint32_t descriptor_set_location = 0; + for (ShaderCreateInfo::Resource &res : all_resources) { + const ShaderInput *input = shader_input_get(res); + descriptor_set_location_update(input, descriptor_set_location++); + } + + /* Post initializing push constants.*/ + /* Determine the binding location of push constants fallback buffer.*/ + int32_t push_constant_descriptor_set_location = -1; + switch (push_constants_storage_type) { + case VKPushConstantsLayout::StorageType::NONE: + case VKPushConstantsLayout::StorageType::PUSH_CONSTANTS: + break; + + case VKPushConstantsLayout::StorageType::STORAGE_BUFFER: { + push_constant_descriptor_set_location = descriptor_set_location++; + const ShaderInput *push_constant_input = ssbo_get(PUSH_CONSTANTS_FALLBACK_NAME.c_str()); + descriptor_set_location_update(push_constant_input, push_constants_fallback_location); + break; + } + + case VKPushConstantsLayout::StorageType::UNIFORM_BUFFER: { + push_constant_descriptor_set_location = descriptor_set_location++; + const ShaderInput *push_constant_input = ubo_get(PUSH_CONSTANTS_FALLBACK_NAME.c_str()); + descriptor_set_location_update(push_constant_input, push_constants_fallback_location); + break; + } + } + push_constants_layout_.init( + info, *this, push_constants_storage_type, push_constant_descriptor_set_location); +} + +static int32_t shader_input_index(const ShaderInput *shader_inputs, + const ShaderInput *shader_input) +{ + int32_t index = (shader_input - shader_inputs); + return index; } void VKShaderInterface::descriptor_set_location_update(const ShaderInput *shader_input, const VKDescriptorSet::Location location) { - int32_t index = (shader_input - inputs_) / sizeof(ShaderInput); + int32_t index = shader_input_index(inputs_, shader_input); descriptor_set_locations_[index] = location; } const VKDescriptorSet::Location VKShaderInterface::descriptor_set_location( const ShaderInput *shader_input) const { - int32_t index = (shader_input - inputs_) / sizeof(ShaderInput); + int32_t index = shader_input_index(inputs_, shader_input); return descriptor_set_locations_[index]; } -- 2.30.2 From 05d533e0576e63e808a7ad133c2e65c5a3b0dc5a Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Wed, 22 Feb 2023 10:19:44 +0100 Subject: [PATCH 30/55] Fix issue where uniform buffers where not updated in the descriptor set. --- source/blender/gpu/vulkan/vk_descriptor_set.cc | 4 ++++ source/blender/gpu/vulkan/vk_descriptor_set.hh | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/source/blender/gpu/vulkan/vk_descriptor_set.cc b/source/blender/gpu/vulkan/vk_descriptor_set.cc index 756d6e438b8..b2c32a302a2 100644 --- a/source/blender/gpu/vulkan/vk_descriptor_set.cc +++ b/source/blender/gpu/vulkan/vk_descriptor_set.cc @@ -137,6 +137,10 @@ void VKDescriptorSet::update(VkDevice vk_device) descriptor_writes.append(write_descriptor); } + BLI_assert_msg(image_infos.size() + buffer_infos.size() == descriptor_writes.size(), + "Not all changes have been converted to a write descriptor. Check " + "`Binding::is_buffer` and `Binding::is_image`."); + vkUpdateDescriptorSets( vk_device, descriptor_writes.size(), descriptor_writes.data(), 0, nullptr); diff --git a/source/blender/gpu/vulkan/vk_descriptor_set.hh b/source/blender/gpu/vulkan/vk_descriptor_set.hh index bd78d0c84f1..8c8233f0b87 100644 --- a/source/blender/gpu/vulkan/vk_descriptor_set.hh +++ b/source/blender/gpu/vulkan/vk_descriptor_set.hh @@ -90,7 +90,7 @@ class VKDescriptorSet : NonCopyable { bool is_buffer() const { - return ELEM(type, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + return ELEM(type, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); } bool is_image() const -- 2.30.2 From 739d088c55dbf14bab4054c37c0e63572d78ff24 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Wed, 22 Feb 2023 12:06:09 +0100 Subject: [PATCH 31/55] Initial (incomplete) Std140 implementation. --- source/blender/gpu/CMakeLists.txt | 2 + source/blender/gpu/vulkan/vk_memory.cc | 122 ------------- source/blender/gpu/vulkan/vk_memory.hh | 26 --- source/blender/gpu/vulkan/vk_memory_layout.cc | 166 ++++++++++++++++++ source/blender/gpu/vulkan/vk_memory_layout.hh | 83 +++++++++ .../blender/gpu/vulkan/vk_push_constants.cc | 37 ++-- .../blender/gpu/vulkan/vk_push_constants.hh | 2 +- 7 files changed, 262 insertions(+), 176 deletions(-) create mode 100644 source/blender/gpu/vulkan/vk_memory_layout.cc create mode 100644 source/blender/gpu/vulkan/vk_memory_layout.hh diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index d08b41e52fc..cc9a7b5014c 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -202,6 +202,7 @@ set(VULKAN_SRC vulkan/vk_framebuffer.cc vulkan/vk_index_buffer.cc vulkan/vk_pipeline.cc + vulkan/vk_memory_layout.cc vulkan/vk_memory.cc vulkan/vk_pixel_buffer.cc vulkan/vk_push_constants.cc @@ -228,6 +229,7 @@ set(VULKAN_SRC vulkan/vk_framebuffer.hh vulkan/vk_index_buffer.hh vulkan/vk_pipeline.hh + vulkan/vk_memory_layout.hh vulkan/vk_memory.hh vulkan/vk_pixel_buffer.hh vulkan/vk_push_constants.hh diff --git a/source/blender/gpu/vulkan/vk_memory.cc b/source/blender/gpu/vulkan/vk_memory.cc index b2eebaa16c9..87a4d78d66b 100644 --- a/source/blender/gpu/vulkan/vk_memory.cc +++ b/source/blender/gpu/vulkan/vk_memory.cc @@ -44,126 +44,4 @@ void vk_memory_free(void * /*user_data*/, void *memory) #endif -uint32_t Std430::component_mem_size(const shader::Type /*type*/) -{ - return 4; -} - -uint32_t Std430::element_alignment(const shader::Type type) -{ - switch (type) { - case shader::Type::FLOAT: - case shader::Type::UINT: - case shader::Type::INT: - case shader::Type::BOOL: - return 4; - case shader::Type::VEC2: - case shader::Type::UVEC2: - case shader::Type::IVEC2: - return 8; - case shader::Type::VEC3: - case shader::Type::UVEC3: - case shader::Type::IVEC3: - case shader::Type::VEC4: - case shader::Type::UVEC4: - case shader::Type::IVEC4: - case shader::Type::MAT3: - case shader::Type::MAT4: - return 16; - default: - BLI_assert_msg(false, "Type not supported as push constant"); - } - return 0; -} - -uint32_t Std430::element_components_len(const shader::Type type) -{ - switch (type) { - case shader::Type::FLOAT: - case shader::Type::UINT: - case shader::Type::INT: - case shader::Type::BOOL: - return 1; - case shader::Type::VEC2: - case shader::Type::UVEC2: - case shader::Type::IVEC2: - return 2; - case shader::Type::VEC3: - case shader::Type::UVEC3: - case shader::Type::IVEC3: - case shader::Type::VEC4: - case shader::Type::UVEC4: - case shader::Type::IVEC4: - return 4; - case shader::Type::MAT3: - return 12; - case shader::Type::MAT4: - return 16; - default: - BLI_assert_msg(false, "Type not supported as push constant"); - } - return 0; -} - -uint32_t Std140::component_mem_size(const shader::Type /*type*/) -{ - return 4; -} - -uint32_t Std140::element_alignment(const shader::Type type) -{ - switch (type) { - case shader::Type::FLOAT: - case shader::Type::UINT: - case shader::Type::INT: - case shader::Type::BOOL: - return 4; - case shader::Type::VEC2: - case shader::Type::UVEC2: - case shader::Type::IVEC2: - return 8; - case shader::Type::VEC3: - case shader::Type::UVEC3: - case shader::Type::IVEC3: - case shader::Type::VEC4: - case shader::Type::UVEC4: - case shader::Type::IVEC4: - case shader::Type::MAT3: - case shader::Type::MAT4: - return 16; - default: - BLI_assert_msg(false, "Type not supported as push constant"); - } - return 0; -} - -uint32_t Std140::element_components_len(const shader::Type type) -{ - switch (type) { - case shader::Type::FLOAT: - case shader::Type::UINT: - case shader::Type::INT: - case shader::Type::BOOL: - return 1; - case shader::Type::VEC2: - case shader::Type::UVEC2: - case shader::Type::IVEC2: - return 2; - case shader::Type::VEC3: - case shader::Type::UVEC3: - case shader::Type::IVEC3: - case shader::Type::VEC4: - case shader::Type::UVEC4: - case shader::Type::IVEC4: - return 4; - case shader::Type::MAT3: - return 12; - case shader::Type::MAT4: - return 16; - default: - BLI_assert_msg(false, "Type not supported as push constant"); - } - return 0; -} - } // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_memory.hh b/source/blender/gpu/vulkan/vk_memory.hh index 7b5b25a5614..2f42eaa90c0 100644 --- a/source/blender/gpu/vulkan/vk_memory.hh +++ b/source/blender/gpu/vulkan/vk_memory.hh @@ -9,8 +9,6 @@ #include "vk_common.hh" -#include "gpu_shader_create_info.hh" - namespace blender::gpu { /** @@ -60,28 +58,4 @@ constexpr VkAllocationCallbacks vk_allocation_callbacks_init(const char *name) static constexpr const VkAllocationCallbacks *vk_allocation_callbacks = nullptr; #endif -/** - * Information about alignment/components and memory size for types when using std430 layout. - */ -struct Std430 { - /** Get the memory size in bytes of a single component using by the given type.*/ - static uint32_t component_mem_size(const shader::Type type); - /** Get to alignment of the given type in bytes.*/ - static uint32_t element_alignment(const shader::Type type); - /** Get the number of components that should be allocated for the given type.*/ - static uint32_t element_components_len(const shader::Type type); -}; - -/** - * Information about alignment/components and memory size for types when using std140 layout. - */ -struct Std140 { - /** Get the memory size in bytes of a single component using by the given type.*/ - static uint32_t component_mem_size(const shader::Type type); - /** Get to alignment of the given type in bytes.*/ - static uint32_t element_alignment(const shader::Type type); - /** Get the number of components that should be allocated for the given type.*/ - static uint32_t element_components_len(const shader::Type type); -}; - } // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_memory_layout.cc b/source/blender/gpu/vulkan/vk_memory_layout.cc new file mode 100644 index 00000000000..20dae69c20e --- /dev/null +++ b/source/blender/gpu/vulkan/vk_memory_layout.cc @@ -0,0 +1,166 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2023 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#include "vk_memory_layout.hh" + +namespace blender::gpu { + +uint32_t Std430::component_mem_size(const shader::Type /*type*/) +{ + return 4; +} + +uint32_t Std430::element_alignment(const shader::Type type) +{ + switch (type) { + case shader::Type::FLOAT: + case shader::Type::UINT: + case shader::Type::INT: + case shader::Type::BOOL: + return 4; + case shader::Type::VEC2: + case shader::Type::UVEC2: + case shader::Type::IVEC2: + return 8; + case shader::Type::VEC3: + case shader::Type::UVEC3: + case shader::Type::IVEC3: + case shader::Type::VEC4: + case shader::Type::UVEC4: + case shader::Type::IVEC4: + case shader::Type::MAT3: + case shader::Type::MAT4: + return 16; + default: + BLI_assert_msg(false, "Type not supported as push constant"); + } + return 0; +} + +uint32_t Std430::element_components_len(const shader::Type type) +{ + switch (type) { + case shader::Type::FLOAT: + case shader::Type::UINT: + case shader::Type::INT: + case shader::Type::BOOL: + return 1; + case shader::Type::VEC2: + case shader::Type::UVEC2: + case shader::Type::IVEC2: + return 2; + case shader::Type::VEC3: + case shader::Type::UVEC3: + case shader::Type::IVEC3: + case shader::Type::VEC4: + case shader::Type::UVEC4: + case shader::Type::IVEC4: + return 4; + case shader::Type::MAT3: + return 12; + case shader::Type::MAT4: + return 16; + default: + BLI_assert_msg(false, "Type not supported as push constant"); + } + return 0; +} + +uint32_t Std430::array_components_len(const shader::Type type) +{ + return Std430::element_components_len(type); +} + +uint32_t Std140::component_mem_size(const shader::Type /*type*/) +{ + return 4; +} + +uint32_t Std140::element_alignment(const shader::Type type) +{ + switch (type) { + case shader::Type::FLOAT: + case shader::Type::UINT: + case shader::Type::INT: + case shader::Type::BOOL: + return 4; + case shader::Type::VEC2: + case shader::Type::UVEC2: + case shader::Type::IVEC2: + return 8; + case shader::Type::VEC3: + case shader::Type::UVEC3: + case shader::Type::IVEC3: + case shader::Type::VEC4: + case shader::Type::UVEC4: + case shader::Type::IVEC4: + case shader::Type::MAT3: + case shader::Type::MAT4: + return 16; + default: + BLI_assert_msg(false, "Type not supported as push constant"); + } + return 0; +} + +uint32_t Std140::element_components_len(const shader::Type type) +{ + switch (type) { + case shader::Type::FLOAT: + case shader::Type::UINT: + case shader::Type::INT: + case shader::Type::BOOL: + return 1; + case shader::Type::VEC2: + case shader::Type::UVEC2: + case shader::Type::IVEC2: + return 2; + case shader::Type::VEC3: + case shader::Type::UVEC3: + case shader::Type::IVEC3: + case shader::Type::VEC4: + case shader::Type::UVEC4: + case shader::Type::IVEC4: + return 4; + case shader::Type::MAT3: + return 12; + case shader::Type::MAT4: + return 16; + default: + BLI_assert_msg(false, "Type not supported as push constant"); + } + return 0; +} + +uint32_t Std140::array_components_len(const shader::Type type) +{ + switch (type) { + case shader::Type::FLOAT: + case shader::Type::UINT: + case shader::Type::INT: + case shader::Type::BOOL: + case shader::Type::VEC2: + case shader::Type::UVEC2: + case shader::Type::IVEC2: + case shader::Type::VEC3: + case shader::Type::UVEC3: + case shader::Type::IVEC3: + case shader::Type::VEC4: + case shader::Type::UVEC4: + case shader::Type::IVEC4: + return 4; + case shader::Type::MAT3: + return 12; + case shader::Type::MAT4: + return 16; + default: + BLI_assert_msg(false, "Type not supported as push constant"); + } + return 0; +} + +} // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_memory_layout.hh b/source/blender/gpu/vulkan/vk_memory_layout.hh new file mode 100644 index 00000000000..fde918f05a5 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_memory_layout.hh @@ -0,0 +1,83 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2023 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "gpu_shader_create_info.hh" + +namespace blender::gpu { + +/** + * Information about alignment/components and memory size for types when using std430 layout. + */ +struct Std430 { + /** Get the memory size in bytes of a single component using by the given type.*/ + static uint32_t component_mem_size(const shader::Type type); + /** Get to alignment of the given type in bytes.*/ + static uint32_t element_alignment(const shader::Type type); + /** Get the number of components that should be allocated for the given type.*/ + static uint32_t element_components_len(const shader::Type type); + /** Get the number of components of the given type when used in an array.*/ + static uint32_t array_components_len(const shader::Type type); +}; + +/** + * Information about alignment/components and memory size for types when using std140 layout. + */ +struct Std140 { + /** Get the memory size in bytes of a single component using by the given type.*/ + static uint32_t component_mem_size(const shader::Type type); + /** Get to alignment of the given type in bytes.*/ + static uint32_t element_alignment(const shader::Type type); + /** Get the number of components that should be allocated for the given type.*/ + static uint32_t element_components_len(const shader::Type type); + /** Get the number of components of the given type when used in an array.*/ + static uint32_t array_components_len(const shader::Type type); +}; + +template static void align(const shader::Type &type, uint32_t *r_offset) +{ + uint32_t alignment = Layout::element_alignment(type); + uint32_t alignment_mask = alignment - 1; + uint32_t offset = *r_offset; + if ((offset & alignment_mask) != 0) { + offset &= ~alignment_mask; + offset += alignment; + *r_offset = offset; + } +} + +template static uint32_t element_stride(const shader::Type type) +{ + return Layout::element_components_len(type) * Layout::component_mem_size(type); +} + +template static uint32_t array_stride(const shader::Type type) +{ + return Layout::array_components_len(type) * Layout::component_mem_size(type); +} + +template +static void reserve(const shader::Type type, int32_t array_size, uint32_t *r_offset) +{ + uint32_t size = array_size == 0 ? element_stride(type) : + array_stride(type) * array_size; + *r_offset += size; +} + +template +static void reserve(const shader::ShaderCreateInfo::PushConst &push_constant, uint32_t *r_offset) +{ + reserve(push_constant.type, push_constant.array_size, r_offset); +} + +template static void align_end_of_struct(uint32_t *r_offset) +{ + align(shader::Type::VEC4, r_offset); +} + +} // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_push_constants.cc b/source/blender/gpu/vulkan/vk_push_constants.cc index 41b8f26e157..bc196673318 100644 --- a/source/blender/gpu/vulkan/vk_push_constants.cc +++ b/source/blender/gpu/vulkan/vk_push_constants.cc @@ -7,36 +7,13 @@ #include "vk_push_constants.hh" #include "vk_backend.hh" -#include "vk_memory.hh" +#include "vk_memory_layout.hh" #include "vk_shader_interface.hh" #include "vk_storage_buffer.hh" #include "vk_uniform_buffer.hh" namespace blender::gpu { -template static void align(const shader::Type &type, uint32_t *r_offset) -{ - uint32_t alignment = Layout::element_alignment(type); - uint32_t alignment_mask = alignment - 1; - uint32_t offset = *r_offset; - if ((offset & alignment_mask) != 0) { - offset &= ~alignment_mask; - offset += alignment; - *r_offset = offset; - } -} - -template -static void reserve(const shader::ShaderCreateInfo::PushConst &push_constant, uint32_t *r_offset) -{ - uint32_t size = Layout::element_components_len(push_constant.type) * - Layout::component_mem_size(push_constant.type); - if (push_constant.array_size != 0) { - size *= push_constant.array_size; - } - *r_offset += size; -} - template static VKPushConstantsLayout::PushConstantLayout init_constant( const shader::ShaderCreateInfo::PushConst &push_constant, @@ -64,9 +41,7 @@ uint32_t struct_size(Span push_constants) reserve(push_constant, &offset); } - /* Make sure result is aligned to 64 bytes.*/ - align(shader::Type::VEC4, &offset); - + align_end_of_struct(&offset); return offset; } @@ -103,6 +78,14 @@ void VKPushConstantsLayout::init(const shader::ShaderCreateInfo &info, push_constants.append(init_constant(push_constant, *shader_input, &offset)); } } + + /* Align end of struct. */ + if (storage_type == StorageType::UNIFORM_BUFFER) { + align(shader::Type::VEC4, &offset); + } + else { + align_end_of_struct(&offset); + } size_in_bytes_ = offset; } diff --git a/source/blender/gpu/vulkan/vk_push_constants.hh b/source/blender/gpu/vulkan/vk_push_constants.hh index 4a9e0509e92..cc2fde87057 100644 --- a/source/blender/gpu/vulkan/vk_push_constants.hh +++ b/source/blender/gpu/vulkan/vk_push_constants.hh @@ -55,7 +55,7 @@ struct VKPushConstantsLayout { */ UNIFORM_BUFFER, }; - static constexpr StorageType STORAGE_TYPE_DEFAULT = StorageType::PUSH_CONSTANTS; + static constexpr StorageType STORAGE_TYPE_DEFAULT = StorageType::UNIFORM_BUFFER; static constexpr StorageType STORAGE_TYPE_FALLBACK = StorageType::UNIFORM_BUFFER; struct PushConstantLayout { -- 2.30.2 From c9bd43b0a1e3b768593a4c74c9fd56cb157a992e Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Wed, 22 Feb 2023 12:42:05 +0100 Subject: [PATCH 32/55] Remove Storage buffers for push constants. --- source/blender/gpu/vulkan/vk_backend.cc | 8 +---- .../blender/gpu/vulkan/vk_push_constants.cc | 35 +++---------------- .../blender/gpu/vulkan/vk_push_constants.hh | 18 ++-------- source/blender/gpu/vulkan/vk_shader.cc | 20 ++++------- .../blender/gpu/vulkan/vk_shader_interface.cc | 24 +------------ 5 files changed, 16 insertions(+), 89 deletions(-) diff --git a/source/blender/gpu/vulkan/vk_backend.cc b/source/blender/gpu/vulkan/vk_backend.cc index 688e8fd5691..1fc5f0bdb76 100644 --- a/source/blender/gpu/vulkan/vk_backend.cc +++ b/source/blender/gpu/vulkan/vk_backend.cc @@ -79,14 +79,8 @@ void VKBackend::compute_dispatch(int groups_x_len, int groups_y_len, int groups_ push_constants, shader->vk_pipeline_layout_get(), VK_SHADER_STAGE_ALL); break; - case VKPushConstantsLayout::StorageType::STORAGE_BUFFER: - push_constants.update_storage_buffer(context.device_get()); - descriptor_set.bind(push_constants.storage_buffer_get(), - push_constants.layout_get().storage_buffer_binding_get()); - break; - case VKPushConstantsLayout::StorageType::UNIFORM_BUFFER: - push_constants.update_uniform_buffer(context.device_get()); + push_constants.update_uniform_buffer(); descriptor_set.bind(push_constants.uniform_buffer_get(), push_constants.layout_get().storage_buffer_binding_get()); break; diff --git a/source/blender/gpu/vulkan/vk_push_constants.cc b/source/blender/gpu/vulkan/vk_push_constants.cc index bc196673318..f5dd57a7904 100644 --- a/source/blender/gpu/vulkan/vk_push_constants.cc +++ b/source/blender/gpu/vulkan/vk_push_constants.cc @@ -64,10 +64,11 @@ void VKPushConstantsLayout::init(const shader::ShaderCreateInfo &info, { BLI_assert(push_constants.is_empty()); storage_type_ = storage_type; - if (ELEM(storage_type, StorageType::STORAGE_BUFFER, StorageType::UNIFORM_BUFFER)) { + if (storage_type == StorageType::UNIFORM_BUFFER) { storage_buffer_binding_ = location; } uint32_t offset = 0; + /* TODO: add template for readability.*/ for (const shader::ShaderCreateInfo::PushConst &push_constant : info.push_constants_) { const ShaderInput *shader_input = interface.uniform_get(push_constant.name.c_str()); BLI_assert(shader_input); @@ -81,7 +82,7 @@ void VKPushConstantsLayout::init(const shader::ShaderCreateInfo &info, /* Align end of struct. */ if (storage_type == StorageType::UNIFORM_BUFFER) { - align(shader::Type::VEC4, &offset); + align_end_of_struct(&offset); } else { align_end_of_struct(&offset); @@ -105,10 +106,6 @@ VKPushConstants::VKPushConstants(const VKPushConstantsLayout *layout) : layout_( { data_ = MEM_mallocN(layout->size_in_bytes(), __func__); switch (layout_->storage_type_get()) { - case VKPushConstantsLayout::StorageType::STORAGE_BUFFER: - storage_buffer_ = new VKStorageBuffer(layout_->size_in_bytes(), GPU_USAGE_DYNAMIC, __func__); - break; - case VKPushConstantsLayout::StorageType::UNIFORM_BUFFER: uniform_buffer_ = new VKUniformBuffer(layout_->size_in_bytes(), __func__); break; @@ -124,9 +121,6 @@ VKPushConstants::VKPushConstants(VKPushConstants &&other) : layout_(other.layout data_ = other.data_; other.data_ = nullptr; - storage_buffer_ = other.storage_buffer_; - other.storage_buffer_ = nullptr; - uniform_buffer_ = other.uniform_buffer_; other.uniform_buffer_ = nullptr; } @@ -138,9 +132,6 @@ VKPushConstants::~VKPushConstants() data_ = nullptr; } - delete storage_buffer_; - storage_buffer_ = nullptr; - delete uniform_buffer_; uniform_buffer_ = nullptr; } @@ -152,31 +143,13 @@ VKPushConstants &VKPushConstants::operator=(VKPushConstants &&other) data_ = other.data_; other.data_ = nullptr; - storage_buffer_ = other.storage_buffer_; - other.storage_buffer_ = nullptr; - uniform_buffer_ = other.uniform_buffer_; other.uniform_buffer_ = nullptr; return *this; } -void VKPushConstants::update_storage_buffer(VkDevice /*vk_device*/) -{ - BLI_assert(layout_->storage_type_get() == VKPushConstantsLayout::StorageType::STORAGE_BUFFER); - BLI_assert(storage_buffer_ != nullptr); - BLI_assert(data_ != nullptr); - storage_buffer_->update(data_); -} - -VKStorageBuffer &VKPushConstants::storage_buffer_get() -{ - BLI_assert(layout_->storage_type_get() == VKPushConstantsLayout::StorageType::STORAGE_BUFFER); - BLI_assert(storage_buffer_ != nullptr); - return *storage_buffer_; -} - -void VKPushConstants::update_uniform_buffer(VkDevice /*vk_device*/) +void VKPushConstants::update_uniform_buffer() { BLI_assert(layout_->storage_type_get() == VKPushConstantsLayout::StorageType::UNIFORM_BUFFER); BLI_assert(uniform_buffer_ != nullptr); diff --git a/source/blender/gpu/vulkan/vk_push_constants.hh b/source/blender/gpu/vulkan/vk_push_constants.hh index cc2fde87057..4bcf812ae2d 100644 --- a/source/blender/gpu/vulkan/vk_push_constants.hh +++ b/source/blender/gpu/vulkan/vk_push_constants.hh @@ -29,7 +29,6 @@ namespace blender::gpu { class VKShaderInterface; class VKUniformBuffer; -class VKStorageBuffer; /** * Describe the layout of the push constants and the storage type that should be used. @@ -44,18 +43,11 @@ struct VKPushConstantsLayout { PUSH_CONSTANTS, /** - * Fallback when push constants doesn't meet the device requirements. This fallback uses a - * storage buffer. - */ - STORAGE_BUFFER, - - /** - * Fallback when push constants doesn't meet the device requirements. This fallback uses an - * uniform buffer. + * Fallback when push constants doesn't meet the device requirements. */ UNIFORM_BUFFER, }; - static constexpr StorageType STORAGE_TYPE_DEFAULT = StorageType::UNIFORM_BUFFER; + static constexpr StorageType STORAGE_TYPE_DEFAULT = StorageType::PUSH_CONSTANTS; static constexpr StorageType STORAGE_TYPE_FALLBACK = StorageType::UNIFORM_BUFFER; struct PushConstantLayout { @@ -113,7 +105,6 @@ class VKPushConstants : NonCopyable { private: const VKPushConstantsLayout *layout_ = nullptr; void *data_ = nullptr; - VKStorageBuffer *storage_buffer_ = nullptr; VKUniformBuffer *uniform_buffer_ = nullptr; public: @@ -134,10 +125,7 @@ class VKPushConstants : NonCopyable { return *layout_; } - void update_storage_buffer(VkDevice vk_device); - VKStorageBuffer &storage_buffer_get(); - - void update_uniform_buffer(VkDevice vk_device); + void update_uniform_buffer(); VKUniformBuffer &uniform_buffer_get(); const void *data() const diff --git a/source/blender/gpu/vulkan/vk_shader.cc b/source/blender/gpu/vulkan/vk_shader.cc index f14904ef0b7..69cf9304663 100644 --- a/source/blender/gpu/vulkan/vk_shader.cc +++ b/source/blender/gpu/vulkan/vk_shader.cc @@ -888,15 +888,11 @@ static VkDescriptorSetLayoutBinding create_descriptor_set_layout_binding( static VkDescriptorSetLayoutBinding create_descriptor_set_layout_binding( const VKPushConstantsLayout &push_constants_layout) { - BLI_assert(ELEM(push_constants_layout.storage_type_get(), - VKPushConstantsLayout::StorageType::STORAGE_BUFFER, - VKPushConstantsLayout::StorageType::UNIFORM_BUFFER)); + BLI_assert(push_constants_layout.storage_type_get() == + VKPushConstantsLayout::StorageType::UNIFORM_BUFFER); VkDescriptorSetLayoutBinding binding = {}; binding.binding = push_constants_layout.storage_buffer_binding_get(); - binding.descriptorType = push_constants_layout.storage_type_get() == - VKPushConstantsLayout::StorageType::STORAGE_BUFFER ? - VK_DESCRIPTOR_TYPE_STORAGE_BUFFER : - VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; binding.descriptorCount = 1; binding.stageFlags = VK_SHADER_STAGE_ALL; binding.pImmutableSamplers = nullptr; @@ -916,9 +912,8 @@ static void add_descriptor_set_layout_bindings( /* Add push constants to the descriptor when push constants are stored in a storage buffer.*/ const VKPushConstantsLayout &push_constants_layout = interface.push_constants_layout_get(); - if (ELEM(push_constants_layout.storage_type_get(), - VKPushConstantsLayout::StorageType::UNIFORM_BUFFER, - VKPushConstantsLayout::StorageType::STORAGE_BUFFER)) { + if (push_constants_layout.storage_type_get() == + VKPushConstantsLayout::StorageType::UNIFORM_BUFFER) { r_bindings.append(create_descriptor_set_layout_binding(push_constants_layout)); } } @@ -942,9 +937,8 @@ static bool descriptor_sets_needed(const VKShaderInterface &shader_interface, const shader::ShaderCreateInfo &info) { return !info.pass_resources_.is_empty() || !info.batch_resources_.is_empty() || - ELEM(shader_interface.push_constants_layout_get().storage_type_get(), - VKPushConstantsLayout::StorageType::STORAGE_BUFFER, - VKPushConstantsLayout::StorageType::UNIFORM_BUFFER); + shader_interface.push_constants_layout_get().storage_type_get() == + VKPushConstantsLayout::StorageType::UNIFORM_BUFFER; } bool VKShader::finalize_descriptor_set_layouts(VkDevice vk_device, diff --git a/source/blender/gpu/vulkan/vk_shader_interface.cc b/source/blender/gpu/vulkan/vk_shader_interface.cc index cf6f72596f0..aa715296745 100644 --- a/source/blender/gpu/vulkan/vk_shader_interface.cc +++ b/source/blender/gpu/vulkan/vk_shader_interface.cc @@ -47,11 +47,7 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) VKContext &context = *VKContext::get(); const VKPushConstantsLayout::StorageType push_constants_storage_type = VKPushConstantsLayout::determine_storage_type(info, context.physical_device_limits_get()); - if (push_constants_storage_type == VKPushConstantsLayout::StorageType::STORAGE_BUFFER) { - ssbo_len_++; - names_size += PUSH_CONSTANTS_FALLBACK_NAME_LEN + 1; - } - else if (push_constants_storage_type == VKPushConstantsLayout::StorageType::UNIFORM_BUFFER) { + if (push_constants_storage_type == VKPushConstantsLayout::StorageType::UNIFORM_BUFFER) { ubo_len_++; names_size += PUSH_CONSTANTS_FALLBACK_NAME_LEN + 1; } @@ -118,17 +114,6 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) } } - /* Push constant post initialization.*/ - /* - * When using storage buffer storage type we need to add it to the the name list here. - * Also determine the location as this is used inside the descriptor set as its binding number. - */ - if (push_constants_storage_type == VKPushConstantsLayout::StorageType::STORAGE_BUFFER) { - copy_input_name(input, PUSH_CONSTANTS_FALLBACK_NAME, name_buffer_, name_buffer_offset); - input->location = input->binding = -1; - input++; - } - sort_inputs(); /* Determine the descriptor set locations after the inputs have been sorted.*/ @@ -147,13 +132,6 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) case VKPushConstantsLayout::StorageType::PUSH_CONSTANTS: break; - case VKPushConstantsLayout::StorageType::STORAGE_BUFFER: { - push_constant_descriptor_set_location = descriptor_set_location++; - const ShaderInput *push_constant_input = ssbo_get(PUSH_CONSTANTS_FALLBACK_NAME.c_str()); - descriptor_set_location_update(push_constant_input, push_constants_fallback_location); - break; - } - case VKPushConstantsLayout::StorageType::UNIFORM_BUFFER: { push_constant_descriptor_set_location = descriptor_set_location++; const ShaderInput *push_constant_input = ubo_get(PUSH_CONSTANTS_FALLBACK_NAME.c_str()); -- 2.30.2 From edc641947f08071fa0534f382e292302ed9f218a Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Wed, 22 Feb 2023 13:04:59 +0100 Subject: [PATCH 33/55] Small clean ups. --- .../gpu/shaders/infos/gpu_shader_test_info.hh | 1 - .../blender/gpu/vulkan/vk_push_constants.cc | 36 +++++++++---------- .../blender/gpu/vulkan/vk_push_constants.hh | 3 +- .../blender/gpu/vulkan/vk_shader_interface.cc | 15 +++----- 4 files changed, 22 insertions(+), 33 deletions(-) diff --git a/source/blender/gpu/shaders/infos/gpu_shader_test_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_test_info.hh index e252414c939..7b1d4ac08a7 100644 --- a/source/blender/gpu/shaders/infos/gpu_shader_test_info.hh +++ b/source/blender/gpu/shaders/infos/gpu_shader_test_info.hh @@ -80,7 +80,6 @@ GPU_SHADER_CREATE_INFO(gpu_push_constants_256bytes_test) .push_constant(Type::FLOAT, "filler2", 32) .do_static_compilation(true); -/* It is expected that this shader will use uniform buffers and not push constants.*/ GPU_SHADER_CREATE_INFO(gpu_push_constants_512bytes_test) .additional_info("gpu_push_constants_256bytes_test") .push_constant(Type::FLOAT, "filler3", 64) diff --git a/source/blender/gpu/vulkan/vk_push_constants.cc b/source/blender/gpu/vulkan/vk_push_constants.cc index f5dd57a7904..a66ff11cccd 100644 --- a/source/blender/gpu/vulkan/vk_push_constants.cc +++ b/source/blender/gpu/vulkan/vk_push_constants.cc @@ -57,6 +57,19 @@ VKPushConstantsLayout::StorageType VKPushConstantsLayout::determine_storage_type STORAGE_TYPE_FALLBACK; } +template +void init_struct(const shader::ShaderCreateInfo &info, + const VKShaderInterface &interface, + Vector &r_struct, + uint32_t *r_offset) +{ + for (const shader::ShaderCreateInfo::PushConst &push_constant : info.push_constants_) { + const ShaderInput *shader_input = interface.uniform_get(push_constant.name.c_str()); + r_struct.append(init_constant(push_constant, *shader_input, r_offset)); + } + align_end_of_struct(r_offset); +} + void VKPushConstantsLayout::init(const shader::ShaderCreateInfo &info, const VKShaderInterface &interface, const StorageType storage_type, @@ -64,30 +77,15 @@ void VKPushConstantsLayout::init(const shader::ShaderCreateInfo &info, { BLI_assert(push_constants.is_empty()); storage_type_ = storage_type; + + size_in_bytes_ = 0; if (storage_type == StorageType::UNIFORM_BUFFER) { storage_buffer_binding_ = location; - } - uint32_t offset = 0; - /* TODO: add template for readability.*/ - for (const shader::ShaderCreateInfo::PushConst &push_constant : info.push_constants_) { - const ShaderInput *shader_input = interface.uniform_get(push_constant.name.c_str()); - BLI_assert(shader_input); - if (storage_type == StorageType::UNIFORM_BUFFER) { - push_constants.append(init_constant(push_constant, *shader_input, &offset)); - } - else { - push_constants.append(init_constant(push_constant, *shader_input, &offset)); - } - } - - /* Align end of struct. */ - if (storage_type == StorageType::UNIFORM_BUFFER) { - align_end_of_struct(&offset); + init_struct(info, interface, push_constants, &size_in_bytes_); } else { - align_end_of_struct(&offset); + init_struct(info, interface, push_constants, &size_in_bytes_); } - size_in_bytes_ = offset; } const VKPushConstantsLayout::PushConstantLayout *VKPushConstantsLayout::find( diff --git a/source/blender/gpu/vulkan/vk_push_constants.hh b/source/blender/gpu/vulkan/vk_push_constants.hh index 4bcf812ae2d..2dbdd0924bb 100644 --- a/source/blender/gpu/vulkan/vk_push_constants.hh +++ b/source/blender/gpu/vulkan/vk_push_constants.hh @@ -51,8 +51,7 @@ struct VKPushConstantsLayout { static constexpr StorageType STORAGE_TYPE_FALLBACK = StorageType::UNIFORM_BUFFER; struct PushConstantLayout { - /* TODO: location requires sequential lookups, we should make the location index based for - * quicker access. */ + /* Used as lookup based on ShaderInput.*/ int32_t location; /** Offset in the push constant data (in bytes). */ diff --git a/source/blender/gpu/vulkan/vk_shader_interface.cc b/source/blender/gpu/vulkan/vk_shader_interface.cc index aa715296745..b0232523cd5 100644 --- a/source/blender/gpu/vulkan/vk_shader_interface.cc +++ b/source/blender/gpu/vulkan/vk_shader_interface.cc @@ -127,17 +127,10 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) /* Post initializing push constants.*/ /* Determine the binding location of push constants fallback buffer.*/ int32_t push_constant_descriptor_set_location = -1; - switch (push_constants_storage_type) { - case VKPushConstantsLayout::StorageType::NONE: - case VKPushConstantsLayout::StorageType::PUSH_CONSTANTS: - break; - - case VKPushConstantsLayout::StorageType::UNIFORM_BUFFER: { - push_constant_descriptor_set_location = descriptor_set_location++; - const ShaderInput *push_constant_input = ubo_get(PUSH_CONSTANTS_FALLBACK_NAME.c_str()); - descriptor_set_location_update(push_constant_input, push_constants_fallback_location); - break; - } + if (push_constants_storage_type == VKPushConstantsLayout::StorageType::UNIFORM_BUFFER) { + push_constant_descriptor_set_location = descriptor_set_location++; + const ShaderInput *push_constant_input = ubo_get(PUSH_CONSTANTS_FALLBACK_NAME.c_str()); + descriptor_set_location_update(push_constant_input, push_constants_fallback_location); } push_constants_layout_.init( info, *this, push_constants_storage_type, push_constant_descriptor_set_location); -- 2.30.2 From 27590e3a11e7edaaba119f2a25f4177caec98960 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Wed, 22 Feb 2023 14:51:45 +0100 Subject: [PATCH 34/55] Fix incorrect comment. --- source/blender/gpu/tests/gpu_push_constants_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/gpu/tests/gpu_push_constants_test.cc b/source/blender/gpu/tests/gpu_push_constants_test.cc index 7d362592f07..1fdf3b002e4 100644 --- a/source/blender/gpu/tests/gpu_push_constants_test.cc +++ b/source/blender/gpu/tests/gpu_push_constants_test.cc @@ -29,7 +29,7 @@ static void push_constants(const char *info_name) EXPECT_NE(shader, nullptr); GPU_shader_bind(shader); - /* Construct IBO. */ + /* Construct SSBO. */ GPUStorageBuf *ssbo = GPU_storagebuf_create_ex( SIZE * sizeof(float), nullptr, GPU_USAGE_DEVICE_ONLY, __func__); GPU_storagebuf_bind(ssbo, GPU_shader_get_ssbo_binding(shader, "data_out")); -- 2.30.2 From 7b9edb674f389b6b0d9f9e3d71b6634e6a586921 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Wed, 22 Feb 2023 16:58:48 +0100 Subject: [PATCH 35/55] Missing removal of storage buffer. --- source/blender/gpu/vulkan/vk_shader.cc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/source/blender/gpu/vulkan/vk_shader.cc b/source/blender/gpu/vulkan/vk_shader.cc index a2bd4575c7b..89d39704860 100644 --- a/source/blender/gpu/vulkan/vk_shader.cc +++ b/source/blender/gpu/vulkan/vk_shader.cc @@ -1050,10 +1050,6 @@ std::string VKShader::resources_declare(const shader::ShaderCreateInfo &info) co ss << "layout(binding = " << push_constants_layout.storage_buffer_binding_get() << ", std140) uniform constants\n"; } - else /* VKPushConstantsLayout::StorageType::STORAGE_BUFFER*/ { - ss << "layout(binding = " << push_constants_layout.storage_buffer_binding_get() - << ", std430) buffer constants\n"; - } ss << "{\n"; for (const ShaderCreateInfo::PushConst &uniform : info.push_constants_) { ss << " " << to_string(uniform.type) << " pc_" << uniform.name; -- 2.30.2 From a26eca251b3ad605a653e226c08e84da7dc189ce Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Wed, 22 Feb 2023 17:45:13 +0100 Subject: [PATCH 36/55] Added test cases for std140. --- source/blender/gpu/CMakeLists.txt | 6 ++ .../blender/gpu/tests/memory_layout_test.cc | 100 ++++++++++++++++++ source/blender/gpu/vulkan/vk_memory_layout.cc | 10 +- source/blender/gpu/vulkan/vk_memory_layout.hh | 17 ++- .../blender/gpu/vulkan/vk_push_constants.cc | 8 +- 5 files changed, 124 insertions(+), 17 deletions(-) create mode 100644 source/blender/gpu/tests/memory_layout_test.cc diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index cc9a7b5014c..6159d04a5c5 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -814,6 +814,12 @@ if(WITH_GTESTS) tests/gpu_testing.hh ) + if(WITH_VULKAN_BACKEND) + list(APPEND TEST_SRC + tests/memory_layout_test.cc + ) + endif() + set(TEST_INC ) set(TEST_LIB diff --git a/source/blender/gpu/tests/memory_layout_test.cc b/source/blender/gpu/tests/memory_layout_test.cc new file mode 100644 index 00000000000..9e21a2d3064 --- /dev/null +++ b/source/blender/gpu/tests/memory_layout_test.cc @@ -0,0 +1,100 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include "testing/testing.h" + +#include "../vulkan/vk_memory_layout.hh" + +namespace blender::gpu { + +template +static void def_attr(const shader::Type type, + const int array_size, + const uint32_t expected_alignment, + const uint32_t expected_reserve, + uint32_t *r_offset) +{ + align(type, array_size, r_offset); + EXPECT_EQ(*r_offset, expected_alignment); + reserve(type, array_size, r_offset); + EXPECT_EQ(*r_offset, expected_reserve); +} + +TEST(std140, fl) +{ + uint32_t offset = 0; + + def_attr(shader::Type::FLOAT, 0, 0, 4, &offset); + + align_end_of_struct(&offset); + EXPECT_EQ(offset, 16); +} + +TEST(std140, _2fl) +{ + uint32_t offset = 0; + + def_attr(shader::Type::FLOAT, 0, 0, 4, &offset); + def_attr(shader::Type::FLOAT, 0, 4, 8, &offset); + + align_end_of_struct(&offset); + EXPECT_EQ(offset, 16); +} + +TEST(std140, _3fl) +{ + uint32_t offset = 0; + + def_attr(shader::Type::FLOAT, 0, 0, 4, &offset); + def_attr(shader::Type::FLOAT, 0, 4, 8, &offset); + def_attr(shader::Type::FLOAT, 0, 8, 12, &offset); + + align_end_of_struct(&offset); + EXPECT_EQ(offset, 16); +} + +TEST(std140, _4fl) +{ + uint32_t offset = 0; + + def_attr(shader::Type::FLOAT, 0, 0, 4, &offset); + def_attr(shader::Type::FLOAT, 0, 4, 8, &offset); + def_attr(shader::Type::FLOAT, 0, 8, 12, &offset); + def_attr(shader::Type::FLOAT, 0, 12, 16, &offset); + + align_end_of_struct(&offset); + EXPECT_EQ(offset, 16); +} + +TEST(std140, fl2) +{ + uint32_t offset = 0; + + def_attr(shader::Type::FLOAT, 2, 0, 16, &offset); + + align_end_of_struct(&offset); + EXPECT_EQ(offset, 16); +} + +TEST(std140, fl_fl2) +{ + uint32_t offset = 0; + + def_attr(shader::Type::FLOAT, 0, 0, 4, &offset); + def_attr(shader::Type::FLOAT, 2, 16, 48, &offset); + + align_end_of_struct(&offset); + EXPECT_EQ(offset, 48); +} + +TEST(std140, fl_vec2) +{ + uint32_t offset = 0; + + def_attr(shader::Type::FLOAT, 0, 0, 4, &offset); + def_attr(shader::Type::VEC2, 0, 8, 16, &offset); + + align_end_of_struct(&offset); + EXPECT_EQ(offset, 16); +} + +} // namespace blender::gpu \ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_memory_layout.cc b/source/blender/gpu/vulkan/vk_memory_layout.cc index 20dae69c20e..52f2f07a1d7 100644 --- a/source/blender/gpu/vulkan/vk_memory_layout.cc +++ b/source/blender/gpu/vulkan/vk_memory_layout.cc @@ -14,8 +14,11 @@ uint32_t Std430::component_mem_size(const shader::Type /*type*/) return 4; } -uint32_t Std430::element_alignment(const shader::Type type) +uint32_t Std430::element_alignment(const shader::Type type, const bool is_array) { + if (is_array) { + return 16; + } switch (type) { case shader::Type::FLOAT: case shader::Type::UINT: @@ -80,8 +83,11 @@ uint32_t Std140::component_mem_size(const shader::Type /*type*/) return 4; } -uint32_t Std140::element_alignment(const shader::Type type) +uint32_t Std140::element_alignment(const shader::Type type, const bool is_array) { + if (is_array) { + return 16; + } switch (type) { case shader::Type::FLOAT: case shader::Type::UINT: diff --git a/source/blender/gpu/vulkan/vk_memory_layout.hh b/source/blender/gpu/vulkan/vk_memory_layout.hh index fde918f05a5..fad5405a956 100644 --- a/source/blender/gpu/vulkan/vk_memory_layout.hh +++ b/source/blender/gpu/vulkan/vk_memory_layout.hh @@ -18,7 +18,7 @@ struct Std430 { /** Get the memory size in bytes of a single component using by the given type.*/ static uint32_t component_mem_size(const shader::Type type); /** Get to alignment of the given type in bytes.*/ - static uint32_t element_alignment(const shader::Type type); + static uint32_t element_alignment(const shader::Type type, bool is_array); /** Get the number of components that should be allocated for the given type.*/ static uint32_t element_components_len(const shader::Type type); /** Get the number of components of the given type when used in an array.*/ @@ -32,16 +32,17 @@ struct Std140 { /** Get the memory size in bytes of a single component using by the given type.*/ static uint32_t component_mem_size(const shader::Type type); /** Get to alignment of the given type in bytes.*/ - static uint32_t element_alignment(const shader::Type type); + static uint32_t element_alignment(const shader::Type type, bool is_array); /** Get the number of components that should be allocated for the given type.*/ static uint32_t element_components_len(const shader::Type type); /** Get the number of components of the given type when used in an array.*/ static uint32_t array_components_len(const shader::Type type); }; -template static void align(const shader::Type &type, uint32_t *r_offset) +template +static void align(const shader::Type &type, const int32_t array_size, uint32_t *r_offset) { - uint32_t alignment = Layout::element_alignment(type); + uint32_t alignment = Layout::element_alignment(type, array_size != 0); uint32_t alignment_mask = alignment - 1; uint32_t offset = *r_offset; if ((offset & alignment_mask) != 0) { @@ -69,15 +70,9 @@ static void reserve(const shader::Type type, int32_t array_size, uint32_t *r_off *r_offset += size; } -template -static void reserve(const shader::ShaderCreateInfo::PushConst &push_constant, uint32_t *r_offset) -{ - reserve(push_constant.type, push_constant.array_size, r_offset); -} - template static void align_end_of_struct(uint32_t *r_offset) { - align(shader::Type::VEC4, r_offset); + align(shader::Type::VEC4, 0, r_offset); } } // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_push_constants.cc b/source/blender/gpu/vulkan/vk_push_constants.cc index a66ff11cccd..4277be9ba75 100644 --- a/source/blender/gpu/vulkan/vk_push_constants.cc +++ b/source/blender/gpu/vulkan/vk_push_constants.cc @@ -20,7 +20,7 @@ static VKPushConstantsLayout::PushConstantLayout init_constant( const ShaderInput &shader_input, uint32_t *r_offset) { - align(push_constant.type, r_offset); + align(push_constant.type, push_constant.array_size, r_offset); VKPushConstantsLayout::PushConstantLayout layout; layout.location = shader_input.location; @@ -28,7 +28,7 @@ static VKPushConstantsLayout::PushConstantLayout init_constant( layout.array_size = push_constant.array_size; layout.offset = *r_offset; - reserve(push_constant, r_offset); + reserve(push_constant.type, push_constant.array_size, r_offset); return layout; } @@ -37,8 +37,8 @@ uint32_t struct_size(Span push_constants) { uint32_t offset = 0; for (const shader::ShaderCreateInfo::PushConst &push_constant : push_constants) { - align(push_constant.type, &offset); - reserve(push_constant, &offset); + align(push_constant.type, push_constant.array_size, &offset); + reserve(push_constant.type, push_constant.array_size, &offset); } align_end_of_struct(&offset); -- 2.30.2 From df5985548afff1ac9455d9a5afcbcb2f0a7824d8 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Wed, 22 Feb 2023 17:53:39 +0100 Subject: [PATCH 37/55] Fixed test case. --- source/blender/gpu/tests/memory_layout_test.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/gpu/tests/memory_layout_test.cc b/source/blender/gpu/tests/memory_layout_test.cc index 9e21a2d3064..55d7f336701 100644 --- a/source/blender/gpu/tests/memory_layout_test.cc +++ b/source/blender/gpu/tests/memory_layout_test.cc @@ -69,10 +69,10 @@ TEST(std140, fl2) { uint32_t offset = 0; - def_attr(shader::Type::FLOAT, 2, 0, 16, &offset); + def_attr(shader::Type::FLOAT, 2, 0, 32, &offset); align_end_of_struct(&offset); - EXPECT_EQ(offset, 16); + EXPECT_EQ(offset, 32); } TEST(std140, fl_fl2) -- 2.30.2 From e8ad8d934e5c521b23242bb704a801052937ea32 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Wed, 22 Feb 2023 19:22:51 +0100 Subject: [PATCH 38/55] Documentation. --- source/blender/gpu/vulkan/vk_memory_layout.hh | 75 ++++++++++++------ .../blender/gpu/vulkan/vk_push_constants.hh | 78 ++++++++++++++++++- .../blender/gpu/vulkan/vk_shader_interface.hh | 4 + 3 files changed, 132 insertions(+), 25 deletions(-) diff --git a/source/blender/gpu/vulkan/vk_memory_layout.hh b/source/blender/gpu/vulkan/vk_memory_layout.hh index fad5405a956..16c5811a752 100644 --- a/source/blender/gpu/vulkan/vk_memory_layout.hh +++ b/source/blender/gpu/vulkan/vk_memory_layout.hh @@ -11,20 +11,6 @@ namespace blender::gpu { -/** - * Information about alignment/components and memory size for types when using std430 layout. - */ -struct Std430 { - /** Get the memory size in bytes of a single component using by the given type.*/ - static uint32_t component_mem_size(const shader::Type type); - /** Get to alignment of the given type in bytes.*/ - static uint32_t element_alignment(const shader::Type type, bool is_array); - /** Get the number of components that should be allocated for the given type.*/ - static uint32_t element_components_len(const shader::Type type); - /** Get the number of components of the given type when used in an array.*/ - static uint32_t array_components_len(const shader::Type type); -}; - /** * Information about alignment/components and memory size for types when using std140 layout. */ @@ -39,6 +25,39 @@ struct Std140 { static uint32_t array_components_len(const shader::Type type); }; +/** + * Information about alignment/components and memory size for types when using std430 layout. + */ +struct Std430 { + /** Get the memory size in bytes of a single component using by the given type.*/ + static uint32_t component_mem_size(const shader::Type type); + /** Get to alignment of the given type in bytes.*/ + static uint32_t element_alignment(const shader::Type type, bool is_array); + /** Get the number of components that should be allocated for the given type.*/ + static uint32_t element_components_len(const shader::Type type); + /** Get the number of components of the given type when used in an array.*/ + static uint32_t array_components_len(const shader::Type type); +}; + +template static uint32_t element_stride(const shader::Type type) +{ + return Layout::element_components_len(type) * Layout::component_mem_size(type); +} + +template static uint32_t array_stride(const shader::Type type) +{ + return Layout::array_components_len(type) * Layout::component_mem_size(type); +} + +/** + * Move the r_offset to the next alignment where the given type+array_size can be + * reserved. + * + * 'type': The type that needs to be aligned. + * 'array_size': The array_size that needs to be aligned. (0=no array). + * 'r_offset': After the call it will point to the byte where the reservation + * can happen. + */ template static void align(const shader::Type &type, const int32_t array_size, uint32_t *r_offset) { @@ -52,16 +71,18 @@ static void align(const shader::Type &type, const int32_t array_size, uint32_t * } } -template static uint32_t element_stride(const shader::Type type) -{ - return Layout::element_components_len(type) * Layout::component_mem_size(type); -} - -template static uint32_t array_stride(const shader::Type type) -{ - return Layout::array_components_len(type) * Layout::component_mem_size(type); -} - +/** + * Reserve space for the given type and array size. + * + * This function doesn't handle alignment this needs to be done up front by calling + * 'align' function. Caller is responsible for this. + * + * 'type': The type that needs to be reserved. + * 'array_size': The array_size that needs to be reserved. (0=no array). + * 'r_offset': When calling needs to be pointing to the aligned location where to + * reserve space. After the call it will point to the byte just after reserved + * space. + */ template static void reserve(const shader::Type type, int32_t array_size, uint32_t *r_offset) { @@ -70,6 +91,12 @@ static void reserve(const shader::Type type, int32_t array_size, uint32_t *r_off *r_offset += size; } +/** + * Update 'r_offset' to be aligned to the end of the struct. + * + * Call this function when all attributes have been added to make sure that the struct size is + * correct. + */ template static void align_end_of_struct(uint32_t *r_offset) { align(shader::Type::VEC4, 0, r_offset); diff --git a/source/blender/gpu/vulkan/vk_push_constants.hh b/source/blender/gpu/vulkan/vk_push_constants.hh index 2dbdd0924bb..2ff1c5fa2df 100644 --- a/source/blender/gpu/vulkan/vk_push_constants.hh +++ b/source/blender/gpu/vulkan/vk_push_constants.hh @@ -70,9 +70,30 @@ struct VKPushConstantsLayout { VKDescriptorSet::Location storage_buffer_binding_; public: + /** + * Return the desired storage type that can fit the push constants of the given shader create + * info, matching the device limits. + * + * Returns: + * - StorageType::NONE: No push constants are needed. + * - StorageType::PUSH_CONSTANTS: Regular vulkan push constants can be used. + * - StorageType::UNIFORM_BUFFER: The push constants don't fit in the limits of the given device. + * A uniform buffer should be used as a fallback method. + */ static StorageType determine_storage_type( const shader::ShaderCreateInfo &info, const VkPhysicalDeviceLimits &vk_physical_device_limits); + + /** + * Initialize the push constants of the given shader create info with the + * binding location. + * + * interface: Uniform locations of the interface are used as lookup key. + * storage_type: The type of storage for push constants to use. + * location: When storage_type=StorageType::UNIFORM_BUFFER this contains + * the location in the descriptor set where the uniform buffer can be + * bound. + */ void init(const shader::ShaderCreateInfo &info, const VKShaderInterface &interface, StorageType storage_type, @@ -86,21 +107,44 @@ struct VKPushConstantsLayout { return storage_type_; } + /** + * Get the binding location for the uniform buffer. + * + * Only valid when storage_type=StorageType::UNIFORM_BUFFER. + */ VKDescriptorSet::Location storage_buffer_binding_get() const { return storage_buffer_binding_; } + /** + * Get the size needed to store the push constants. + */ uint32_t size_in_bytes() const { return size_in_bytes_; } + /** + * Find the push constant layout for the given location. + * Location = ShaderInput.location. + */ const PushConstantLayout *find(int32_t location) const; }; +/** + * Container to store push constants in a buffer. + * + * Can handle buffers with different memory layouts (std140/std430) + * Which memory layout is used is based on the storage type. + * + * VKPushConstantsLayout only describes the buffer, an instance of this + * class can handle setting/modifying/duplicating push constants. + * + * It should also keep track of the submissions in order to reuse the allocated + * data. + */ class VKPushConstants : NonCopyable { - private: const VKPushConstantsLayout *layout_ = nullptr; void *data_ = nullptr; @@ -124,14 +168,46 @@ class VKPushConstants : NonCopyable { return *layout_; } + /** + * When storage type = StorageType::UNIFORM_BUFFER use this method to update the uniform + * buffer. + * + * It must be called just before adding a draw/compute command to the command queue. + */ void update_uniform_buffer(); + + /** + * Get a reference to the uniform buffer. + * + * Only valid when storage type = StorageType::UNIFORM_BUFFER. + */ VKUniformBuffer &uniform_buffer_get(); + /** + * Get the reference to the active data. + * + * Data can get inactive when push constants are modified, after being added to the command + * queue. We still keep track of the old data for reuse and make sure we don't overwrite data + * that is still not on the GPU. + */ const void *data() const { return data_; } + /** + * Modify a push constant. + * + * location: ShaderInput.location of the push constant to update. + * comp_len: number of components has the data type that is being updated. + * array_size: number of elements when an array to update. (0=no array) + * input_data: packed source data to use. + * + * TODO: this function still needs to convert the input_data layout to that + * what the storage type is expected. + * TODO: Current implementation has a work around for missing implementation + * of builtin uniforms. Builtin uniforms should eventually also be supported. + */ template void push_constant_set(int32_t location, int32_t comp_len, diff --git a/source/blender/gpu/vulkan/vk_shader_interface.hh b/source/blender/gpu/vulkan/vk_shader_interface.hh index d12ab3bd02f..82bcca9f680 100644 --- a/source/blender/gpu/vulkan/vk_shader_interface.hh +++ b/source/blender/gpu/vulkan/vk_shader_interface.hh @@ -32,6 +32,9 @@ class VKShaderInterface : public ShaderInterface { VKPushConstantsLayout push_constants_layout_; public: + /** + * When the push constants fallback is used, this name will be used in the GLSL source. + */ static constexpr StringRefNull PUSH_CONSTANTS_FALLBACK_NAME = StringRefNull( "push_constants_fallback", 23); static constexpr size_t PUSH_CONSTANTS_FALLBACK_NAME_LEN = PUSH_CONSTANTS_FALLBACK_NAME.size(); @@ -46,6 +49,7 @@ class VKShaderInterface : public ShaderInterface { const VKDescriptorSet::Location descriptor_set_location( const shader::ShaderCreateInfo::Resource::BindType &bind_type, int binding) const; + /** Get the VKPushConstantsLayout of the shader.*/ const VKPushConstantsLayout &push_constants_layout_get() const { return push_constants_layout_; -- 2.30.2 From 87feaaf40f89a4f227e8f53f20e9044404b14119 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Wed, 22 Feb 2023 20:32:20 +0100 Subject: [PATCH 39/55] Updated assert message to be more generic. --- source/blender/gpu/vulkan/vk_memory_layout.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/source/blender/gpu/vulkan/vk_memory_layout.cc b/source/blender/gpu/vulkan/vk_memory_layout.cc index 52f2f07a1d7..4d4e784d99f 100644 --- a/source/blender/gpu/vulkan/vk_memory_layout.cc +++ b/source/blender/gpu/vulkan/vk_memory_layout.cc @@ -39,7 +39,7 @@ uint32_t Std430::element_alignment(const shader::Type type, const bool is_array) case shader::Type::MAT4: return 16; default: - BLI_assert_msg(false, "Type not supported as push constant"); + BLI_assert_msg(false, "Type not supported in dynamic structs."); } return 0; } @@ -68,7 +68,7 @@ uint32_t Std430::element_components_len(const shader::Type type) case shader::Type::MAT4: return 16; default: - BLI_assert_msg(false, "Type not supported as push constant"); + BLI_assert_msg(false, "Type not supported in dynamic structs."); } return 0; } @@ -108,7 +108,7 @@ uint32_t Std140::element_alignment(const shader::Type type, const bool is_array) case shader::Type::MAT4: return 16; default: - BLI_assert_msg(false, "Type not supported as push constant"); + BLI_assert_msg(false, "Type not supported in dynamic structs."); } return 0; } @@ -137,7 +137,7 @@ uint32_t Std140::element_components_len(const shader::Type type) case shader::Type::MAT4: return 16; default: - BLI_assert_msg(false, "Type not supported as push constant"); + BLI_assert_msg(false, "Type not supported in dynamic structs."); } return 0; } @@ -164,7 +164,7 @@ uint32_t Std140::array_components_len(const shader::Type type) case shader::Type::MAT4: return 16; default: - BLI_assert_msg(false, "Type not supported as push constant"); + BLI_assert_msg(false, "Type not supported in dynamic structs."); } return 0; } -- 2.30.2 From 2765552504c19375ab7f87011e519c9563a4f121 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Wed, 22 Feb 2023 20:42:44 +0100 Subject: [PATCH 40/55] Add builtin uniforms. --- source/blender/gpu/vulkan/vk_push_constants.hh | 8 +------- source/blender/gpu/vulkan/vk_shader_interface.cc | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/source/blender/gpu/vulkan/vk_push_constants.hh b/source/blender/gpu/vulkan/vk_push_constants.hh index 2ff1c5fa2df..c236455ad30 100644 --- a/source/blender/gpu/vulkan/vk_push_constants.hh +++ b/source/blender/gpu/vulkan/vk_push_constants.hh @@ -205,8 +205,6 @@ class VKPushConstants : NonCopyable { * * TODO: this function still needs to convert the input_data layout to that * what the storage type is expected. - * TODO: Current implementation has a work around for missing implementation - * of builtin uniforms. Builtin uniforms should eventually also be supported. */ template void push_constant_set(int32_t location, @@ -216,11 +214,7 @@ class VKPushConstants : NonCopyable { { const VKPushConstantsLayout::PushConstantLayout *push_constant_layout = layout_->find( location); - if (push_constant_layout == nullptr) { - /* TODO: Currently the builtin uniforms are set using a predefined location each time a - * shader is bound. This needs to be fixed in the VKShaderInterface.*/ - return; - } + BLI_assert(push_constant_layout); BLI_assert_msg(push_constant_layout->offset + comp_len * array_size * sizeof(T) <= layout_->size_in_bytes(), "Tried to write outside the push constant allocated memory."); diff --git a/source/blender/gpu/vulkan/vk_shader_interface.cc b/source/blender/gpu/vulkan/vk_shader_interface.cc index b0232523cd5..694101c8040 100644 --- a/source/blender/gpu/vulkan/vk_shader_interface.cc +++ b/source/blender/gpu/vulkan/vk_shader_interface.cc @@ -116,6 +116,20 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) sort_inputs(); + /* Builtin Uniforms */ + for (int32_t u_int = 0; u_int < GPU_NUM_UNIFORMS; u_int++) { + GPUUniformBuiltin u = static_cast(u_int); + const ShaderInput *uni = this->uniform_get(builtin_uniform_name(u)); + builtins_[u] = (uni != nullptr) ? uni->location : -1; + } + + /* Builtin Uniforms Blocks */ + for (int32_t u_int = 0; u_int < GPU_NUM_UNIFORM_BLOCKS; u_int++) { + GPUUniformBlockBuiltin u = static_cast(u_int); + const ShaderInput *block = this->ubo_get(builtin_uniform_block_name(u)); + builtin_blocks_[u] = (block != nullptr) ? block->binding : -1; + } + /* Determine the descriptor set locations after the inputs have been sorted.*/ descriptor_set_locations_ = Array(input_tot_len); uint32_t descriptor_set_location = 0; -- 2.30.2 From 9698a12bc3256013e001bb35e0e7fe2aac5e9889 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Wed, 22 Feb 2023 21:00:52 +0100 Subject: [PATCH 41/55] Element striding of std140 arrays. --- .../blender/gpu/vulkan/vk_push_constants.hh | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/source/blender/gpu/vulkan/vk_push_constants.hh b/source/blender/gpu/vulkan/vk_push_constants.hh index c236455ad30..4c62a47238c 100644 --- a/source/blender/gpu/vulkan/vk_push_constants.hh +++ b/source/blender/gpu/vulkan/vk_push_constants.hh @@ -215,12 +215,28 @@ class VKPushConstants : NonCopyable { const VKPushConstantsLayout::PushConstantLayout *push_constant_layout = layout_->find( location); BLI_assert(push_constant_layout); - BLI_assert_msg(push_constant_layout->offset + comp_len * array_size * sizeof(T) <= - layout_->size_in_bytes(), - "Tried to write outside the push constant allocated memory."); + uint8_t *bytes = static_cast(data_); T *dst = static_cast(static_cast(&bytes[push_constant_layout->offset])); - memcpy(dst, input_data, comp_len * array_size * sizeof(T)); + if (layout_->storage_type_get() == VKPushConstantsLayout::StorageType::PUSH_CONSTANTS || + array_size == 0) { + BLI_assert_msg(push_constant_layout->offset + comp_len * array_size * sizeof(T) <= + layout_->size_in_bytes(), + "Tried to write outside the push constant allocated memory."); + memcpy(dst, input_data, comp_len * array_size * sizeof(T)); + return; + } + + /* Store elements in uniform buffer as array. In Std140 arrays have an element stride of 16 + * bytes.*/ + BLI_assert(sizeof(T) == 4); + const T *src = input_data; + for (const int i : IndexRange(array_size)) { + UNUSED_VARS(i); + memcpy(dst, src, comp_len * sizeof(T)); + src += comp_len; + dst += 4; + } } }; -- 2.30.2 From 64e4d5e7d581c74236c11884ec06a2eaeb924e7d Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Thu, 23 Feb 2023 12:55:41 +0100 Subject: [PATCH 42/55] Identified resource change issue. --- .../gpu/shaders/infos/gpu_shader_test_info.hh | 4 +- .../gpu/tests/gpu_push_constants_test.cc | 215 +++++++++++++----- 2 files changed, 166 insertions(+), 53 deletions(-) diff --git a/source/blender/gpu/shaders/infos/gpu_shader_test_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_test_info.hh index 7b1d4ac08a7..d6b74def77e 100644 --- a/source/blender/gpu/shaders/infos/gpu_shader_test_info.hh +++ b/source/blender/gpu/shaders/infos/gpu_shader_test_info.hh @@ -61,7 +61,7 @@ GPU_SHADER_CREATE_INFO(gpu_push_constants_base_test) .storage_buf(0, Qualifier::WRITE, "float", "data_out[]") .compute_source("gpu_push_constants_test.glsl"); -GPU_SHADER_CREATE_INFO(gpu_push_constants_packed_test) +GPU_SHADER_CREATE_INFO(gpu_push_constants_test) .additional_info("gpu_push_constants_base_test") .push_constant(Type::FLOAT, "float_in") .push_constant(Type::VEC2, "vec2_in") @@ -71,7 +71,7 @@ GPU_SHADER_CREATE_INFO(gpu_push_constants_packed_test) /* Push constants size test. */ GPU_SHADER_CREATE_INFO(gpu_push_constants_128bytes_test) - .additional_info("gpu_push_constants_packed_test") + .additional_info("gpu_push_constants_test") .push_constant(Type::FLOAT, "filler", 20) .do_static_compilation(true); diff --git a/source/blender/gpu/tests/gpu_push_constants_test.cc b/source/blender/gpu/tests/gpu_push_constants_test.cc index 1fdf3b002e4..c944ece3d91 100644 --- a/source/blender/gpu/tests/gpu_push_constants_test.cc +++ b/source/blender/gpu/tests/gpu_push_constants_test.cc @@ -8,13 +8,122 @@ #include "GPU_storage_buffer.h" #include "BLI_math_vector.hh" +#include "BLI_utility_mixins.hh" #include "BLI_vector.hh" #include "gpu_testing.hh" namespace blender::gpu::tests { +struct CallData { + GPUStorageBuf *ssbo = nullptr; + Vector data; -static void push_constants(const char *info_name) + float float_in; + float2 vec2_in; + float3 vec3_in; + float4 vec4_in; + + void init_ssbo(size_t num_floats) + { + if (ssbo == nullptr) { + ssbo = GPU_storagebuf_create_ex( + num_floats * sizeof(float), nullptr, GPU_USAGE_DEVICE_ONLY, __func__); + data.resize(num_floats); + } + } + + ~CallData() + { + if (ssbo != nullptr) { + GPU_storagebuf_free(ssbo); + ssbo = nullptr; + } + } + + void generate_test_data(const float components_mul, const float component_mul) + { + float_in = components_mul; + vec2_in = float2(components_mul * 2.0, components_mul * 2.0 + component_mul); + vec3_in = float3(components_mul * 3.0, + components_mul * 3.0 + component_mul, + components_mul * 3.0 + component_mul * 2.0); + vec4_in = float4(components_mul * 4.0, + components_mul * 4.0 + component_mul, + components_mul * 4.0 + component_mul * 2.0, + components_mul * 4.0 + component_mul * 3.0); + } + + void read_back() + { + GPU_memory_barrier(GPU_BARRIER_SHADER_STORAGE); + GPU_storagebuf_read(ssbo, data.data()); + } + + void validate() + { + /* Check the results. */ + EXPECT_EQ(data[0], float_in); + EXPECT_EQ(data[1], vec2_in.x); + EXPECT_EQ(data[2], vec2_in.y); + EXPECT_EQ(data[3], vec3_in.x); + EXPECT_EQ(data[4], vec3_in.y); + EXPECT_EQ(data[5], vec3_in.z); + EXPECT_EQ(data[6], vec4_in.x); + EXPECT_EQ(data[7], vec4_in.y); + EXPECT_EQ(data[8], vec4_in.z); + EXPECT_EQ(data[9], vec4_in.w); + } +}; + +struct Shader { + GPUShader *shader = nullptr; + Vector call_datas; + + ~Shader() + { + if (shader != nullptr) { + GPU_shader_unbind(); + GPU_shader_free(shader); + } + } + + void init_shader(const char *info_name) + { + if (shader == nullptr) { + shader = GPU_shader_create_from_info_name(info_name); + EXPECT_NE(shader, nullptr); + GPU_shader_bind(shader); + } + } + + CallData &new_call() + { + CallData call_data; + call_datas.append(call_data); + return call_datas.last(); + } + + void bind(CallData &call_data) + { + GPU_storagebuf_bind(call_data.ssbo, GPU_shader_get_ssbo_binding(shader, "data_out")); + } + + void update_push_constants(const CallData &call_data) + { + GPU_shader_uniform_1f(shader, "float_in", call_data.float_in); + GPU_shader_uniform_2fv(shader, "vec2_in", call_data.vec2_in); + GPU_shader_uniform_3fv(shader, "vec3_in", call_data.vec3_in); + GPU_shader_uniform_4fv(shader, "vec4_in", call_data.vec4_in); + } + + void dispatch() + { + GPU_compute_dispatch(shader, 1, 1, 1); + } +}; + +/** Test the given info when doing a single call. */ +static void do_push_constants_test(const char *info_name, const int num_calls_simultaneously = 1) { if (!GPU_compute_shader_support() && !GPU_shader_storage_buffer_objects_support()) { /* We can't test as a the platform does not support compute shaders. */ @@ -24,75 +133,79 @@ static void push_constants(const char *info_name) static constexpr uint SIZE = 16; - /* Build compute shader. */ - GPUShader *shader = GPU_shader_create_from_info_name(info_name); - EXPECT_NE(shader, nullptr); - GPU_shader_bind(shader); + Shader shader; + shader.init_shader(info_name); - /* Construct SSBO. */ - GPUStorageBuf *ssbo = GPU_storagebuf_create_ex( - SIZE * sizeof(float), nullptr, GPU_USAGE_DEVICE_ONLY, __func__); - GPU_storagebuf_bind(ssbo, GPU_shader_get_ssbo_binding(shader, "data_out")); - - const float float_in = 10.0f; - const float2 vec2_in(20.0f, 21.0f); - const float3 vec3_in(30.0f, 31.0f, 32.0f); - const float4 vec4_in(40.0f, 41.0f, 42.0f, 43.0f); - GPU_shader_uniform_1f(shader, "float_in", float_in); - GPU_shader_uniform_2fv(shader, "vec2_in", vec2_in); - GPU_shader_uniform_3fv(shader, "vec3_in", vec3_in); - GPU_shader_uniform_4fv(shader, "vec4_in", vec4_in); - - /* Dispatch compute task. */ - GPU_compute_dispatch(shader, 1, 1, 1); - - /* Check if compute has been done. */ - GPU_memory_barrier(GPU_BARRIER_SHADER_STORAGE); - - /* Download the index buffer. */ - float data[SIZE]; - GPU_storagebuf_read(ssbo, data); - - /* Check the results. */ - EXPECT_EQ(data[0], float_in); - EXPECT_EQ(data[1], vec2_in.x); - EXPECT_EQ(data[2], vec2_in.y); - EXPECT_EQ(data[3], vec3_in.x); - EXPECT_EQ(data[4], vec3_in.y); - EXPECT_EQ(data[5], vec3_in.z); - EXPECT_EQ(data[6], vec4_in.x); - EXPECT_EQ(data[7], vec4_in.y); - EXPECT_EQ(data[8], vec4_in.z); - EXPECT_EQ(data[9], vec4_in.w); - - /* Cleanup. */ - GPU_shader_unbind(); - GPU_storagebuf_free(ssbo); - GPU_shader_free(shader); + for (const int call_index : IndexRange(num_calls_simultaneously)) { + CallData &call_data = shader.new_call(); + call_data.generate_test_data(call_index * 10.0, call_index * 1.0); + call_data.init_ssbo(SIZE); + shader.bind(call_data); + shader.update_push_constants(call_data); + shader.dispatch(); + } + /* All calls will be "simultaneously" in flight. First readback will wait until the dispatches + * have finished execution.*/ + for (const int call_index : IndexRange(num_calls_simultaneously)) { + CallData &call_data = shader.call_datas[call_index]; + call_data.read_back(); + call_data.validate(); + } } -static void test_push_constants_packed() +/* Test case with single call as sanity check, before we make it more interesting.*/ +static void test_push_constants() { - push_constants("gpu_push_constants_packed_test"); + do_push_constants_test("gpu_push_constants_test"); } -GPU_TEST(push_constants_packed) +GPU_TEST(push_constants) static void test_push_constants_128bytes() { - push_constants("gpu_push_constants_128bytes_test"); + do_push_constants_test("gpu_push_constants_128bytes_test"); } GPU_TEST(push_constants_128bytes) static void test_push_constants_256bytes() { - push_constants("gpu_push_constants_256bytes_test"); + do_push_constants_test("gpu_push_constants_256bytes_test"); } GPU_TEST(push_constants_256bytes) static void test_push_constants_512bytes() { - push_constants("gpu_push_constants_512bytes_test"); + do_push_constants_test("gpu_push_constants_512bytes_test"); } GPU_TEST(push_constants_512bytes) +#if 0 +/* Schedule multiple simultaneously. */ +/* These test have been disabled for now as this will to be solved in a separate PR. + * - DescriptorSets may not be altered, when they are in the command queue or being executed. + */ +static void test_push_constants_multiple() +{ + do_push_constants_test("gpu_push_constants_test", 10); +} +GPU_TEST(push_constants_multiple) + +static void test_push_constants_multiple_128bytes() +{ + do_push_constants_test("gpu_push_constants_128bytes_test", 10); +} +GPU_TEST(push_constants_multiple_128bytes) + +static void test_push_constants_multiple_256bytes() +{ + do_push_constants_test("gpu_push_constants_256bytes_test", 10); +} +GPU_TEST(push_constants_multiple_256bytes) + +static void test_push_constants_multiple_512bytes() +{ + do_push_constants_test("gpu_push_constants_512bytes_test", 10); +} +GPU_TEST(push_constants_multiple_512bytes) +#endif + } // namespace blender::gpu::tests \ No newline at end of file -- 2.30.2 From c088dcbaaba6f02ca9e7c9852f61358ebfb0de20 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Thu, 23 Feb 2023 13:31:03 +0100 Subject: [PATCH 43/55] Reverted unneeded change in includes. --- source/blender/gpu/vulkan/vk_buffer.cc | 1 - source/blender/gpu/vulkan/vk_buffer.hh | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/source/blender/gpu/vulkan/vk_buffer.cc b/source/blender/gpu/vulkan/vk_buffer.cc index 7b4a994edd5..f882783041d 100644 --- a/source/blender/gpu/vulkan/vk_buffer.cc +++ b/source/blender/gpu/vulkan/vk_buffer.cc @@ -6,7 +6,6 @@ */ #include "vk_buffer.hh" -#include "vk_context.hh" namespace blender::gpu { diff --git a/source/blender/gpu/vulkan/vk_buffer.hh b/source/blender/gpu/vulkan/vk_buffer.hh index 3dcd4054b43..875876ccab1 100644 --- a/source/blender/gpu/vulkan/vk_buffer.hh +++ b/source/blender/gpu/vulkan/vk_buffer.hh @@ -10,11 +10,11 @@ #include "gpu_context_private.hh" #include "vk_common.hh" +#include "vk_context.hh" #include "vk_mem_alloc.h" namespace blender::gpu { -class VKContext; /** * Class for handing vulkan buffers (allocation/updating/binding). -- 2.30.2 From 868b2e377f5d3283286b598e4704cecf8564dbb1 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Thu, 23 Feb 2023 13:35:33 +0100 Subject: [PATCH 44/55] Added documentation. --- source/blender/gpu/vulkan/vk_command_buffer.cc | 6 ++---- source/blender/gpu/vulkan/vk_command_buffer.hh | 5 +++++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/source/blender/gpu/vulkan/vk_command_buffer.cc b/source/blender/gpu/vulkan/vk_command_buffer.cc index c3b36b9d903..b5211c5d9fb 100644 --- a/source/blender/gpu/vulkan/vk_command_buffer.cc +++ b/source/blender/gpu/vulkan/vk_command_buffer.cc @@ -76,10 +76,8 @@ void VKCommandBuffer::push_constants(const VKPushConstants &push_constants, const VkPipelineLayout vk_pipeline_layout, const VkShaderStageFlags vk_shader_stages) { - if (push_constants.layout_get().storage_type_get() != - VKPushConstantsLayout::StorageType::PUSH_CONSTANTS) { - return; - } + BLI_assert(push_constants.layout_get().storage_type_get() == + VKPushConstantsLayout::StorageType::PUSH_CONSTANTS); vkCmdPushConstants(vk_command_buffer_, vk_pipeline_layout, vk_shader_stages, diff --git a/source/blender/gpu/vulkan/vk_command_buffer.hh b/source/blender/gpu/vulkan/vk_command_buffer.hh index 175c8ed502b..6eecbe5ad48 100644 --- a/source/blender/gpu/vulkan/vk_command_buffer.hh +++ b/source/blender/gpu/vulkan/vk_command_buffer.hh @@ -37,6 +37,11 @@ class VKCommandBuffer : NonCopyable, NonMovable { void bind(const VKDescriptorSet &descriptor_set, const VkPipelineLayout vk_pipeline_layout, VkPipelineBindPoint bind_point); + /** + * Add a push constant command to the command buffer. + * + * Only valid when the storage type of push_constants is StorageType::PUSH_CONSTANTS. + */ void push_constants(const VKPushConstants &push_constants, const VkPipelineLayout vk_pipeline_layout, const VkShaderStageFlags vk_shader_stages); -- 2.30.2 From b4cad5c613c17894ad517e031f8f461eca7bac52 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Thu, 23 Feb 2023 15:01:21 +0100 Subject: [PATCH 45/55] Remove unneeded comment. --- source/blender/gpu/vulkan/vk_shader_interface.cc | 3 --- 1 file changed, 3 deletions(-) diff --git a/source/blender/gpu/vulkan/vk_shader_interface.cc b/source/blender/gpu/vulkan/vk_shader_interface.cc index 694101c8040..1b0ca863129 100644 --- a/source/blender/gpu/vulkan/vk_shader_interface.cc +++ b/source/blender/gpu/vulkan/vk_shader_interface.cc @@ -94,9 +94,6 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) } /* Push constants. */ - /* NOTE: Push constants must be added after other uniform resources as resources have strict - * rules for their 'location' due to descriptor sets. Push constants only need an unique location - * as it is only used by the GPU module internally.*/ int32_t push_constant_location = 1024; for (const ShaderCreateInfo::PushConst &push_constant : info.push_constants_) { copy_input_name(input, push_constant.name, name_buffer_, name_buffer_offset); -- 2.30.2 From d20bf06825ebad16df864e735bf531ccd4cdaede Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Thu, 23 Feb 2023 17:55:55 +0100 Subject: [PATCH 46/55] Cleanup: Moved Layout inside VKPushConstants. --- source/blender/gpu/vulkan/vk_backend.cc | 6 +- .../blender/gpu/vulkan/vk_command_buffer.cc | 2 +- source/blender/gpu/vulkan/vk_pipeline.cc | 11 +- source/blender/gpu/vulkan/vk_pipeline.hh | 2 +- .../blender/gpu/vulkan/vk_push_constants.cc | 33 ++- .../blender/gpu/vulkan/vk_push_constants.hh | 218 +++++++++--------- source/blender/gpu/vulkan/vk_shader.cc | 26 +-- .../blender/gpu/vulkan/vk_shader_interface.cc | 10 +- .../blender/gpu/vulkan/vk_shader_interface.hh | 6 +- 9 files changed, 156 insertions(+), 158 deletions(-) diff --git a/source/blender/gpu/vulkan/vk_backend.cc b/source/blender/gpu/vulkan/vk_backend.cc index 1fc5f0bdb76..fd13c238854 100644 --- a/source/blender/gpu/vulkan/vk_backend.cc +++ b/source/blender/gpu/vulkan/vk_backend.cc @@ -71,15 +71,15 @@ void VKBackend::compute_dispatch(int groups_x_len, int groups_y_len, int groups_ /* Update push constants based on their storage type.*/ switch (push_constants.layout_get().storage_type_get()) { - case VKPushConstantsLayout::StorageType::NONE: + case VKPushConstants::StorageType::NONE: break; - case VKPushConstantsLayout::StorageType::PUSH_CONSTANTS: + case VKPushConstants::StorageType::PUSH_CONSTANTS: command_buffer.push_constants( push_constants, shader->vk_pipeline_layout_get(), VK_SHADER_STAGE_ALL); break; - case VKPushConstantsLayout::StorageType::UNIFORM_BUFFER: + case VKPushConstants::StorageType::UNIFORM_BUFFER: push_constants.update_uniform_buffer(); descriptor_set.bind(push_constants.uniform_buffer_get(), push_constants.layout_get().storage_buffer_binding_get()); diff --git a/source/blender/gpu/vulkan/vk_command_buffer.cc b/source/blender/gpu/vulkan/vk_command_buffer.cc index b5211c5d9fb..fa8d2971b72 100644 --- a/source/blender/gpu/vulkan/vk_command_buffer.cc +++ b/source/blender/gpu/vulkan/vk_command_buffer.cc @@ -77,7 +77,7 @@ void VKCommandBuffer::push_constants(const VKPushConstants &push_constants, const VkShaderStageFlags vk_shader_stages) { BLI_assert(push_constants.layout_get().storage_type_get() == - VKPushConstantsLayout::StorageType::PUSH_CONSTANTS); + VKPushConstants::StorageType::PUSH_CONSTANTS); vkCmdPushConstants(vk_command_buffer_, vk_pipeline_layout, vk_shader_stages, diff --git a/source/blender/gpu/vulkan/vk_pipeline.cc b/source/blender/gpu/vulkan/vk_pipeline.cc index c66c46c76d9..d8f75c55f87 100644 --- a/source/blender/gpu/vulkan/vk_pipeline.cc +++ b/source/blender/gpu/vulkan/vk_pipeline.cc @@ -29,11 +29,12 @@ VKPipeline::~VKPipeline() } } -VKPipeline VKPipeline::create_compute_pipeline(VKContext &context, - VkShaderModule compute_module, - VkDescriptorSetLayout &descriptor_set_layout, - VkPipelineLayout &pipeline_layout, - const VKPushConstantsLayout &push_constants_layout) +VKPipeline VKPipeline::create_compute_pipeline( + VKContext &context, + VkShaderModule compute_module, + VkDescriptorSetLayout &descriptor_set_layout, + VkPipelineLayout &pipeline_layout, + const VKPushConstants::Layout &push_constants_layout) { VK_ALLOCATION_CALLBACKS VkDevice vk_device = context.device_get(); diff --git a/source/blender/gpu/vulkan/vk_pipeline.hh b/source/blender/gpu/vulkan/vk_pipeline.hh index 3509bb63b15..5723d8d0ea6 100644 --- a/source/blender/gpu/vulkan/vk_pipeline.hh +++ b/source/blender/gpu/vulkan/vk_pipeline.hh @@ -44,7 +44,7 @@ class VKPipeline : NonCopyable { VkShaderModule compute_module, VkDescriptorSetLayout &descriptor_set_layout, VkPipelineLayout &pipeline_layouts, - const VKPushConstantsLayout &push_constants_layout); + const VKPushConstants::Layout &push_constants_layout); VKDescriptorSet &descriptor_set_get() { diff --git a/source/blender/gpu/vulkan/vk_push_constants.cc b/source/blender/gpu/vulkan/vk_push_constants.cc index 4277be9ba75..450fee45bb5 100644 --- a/source/blender/gpu/vulkan/vk_push_constants.cc +++ b/source/blender/gpu/vulkan/vk_push_constants.cc @@ -15,14 +15,14 @@ namespace blender::gpu { template -static VKPushConstantsLayout::PushConstantLayout init_constant( +static VKPushConstants::Layout::PushConstant init_constant( const shader::ShaderCreateInfo::PushConst &push_constant, const ShaderInput &shader_input, uint32_t *r_offset) { align(push_constant.type, push_constant.array_size, r_offset); - VKPushConstantsLayout::PushConstantLayout layout; + VKPushConstants::Layout::PushConstant layout; layout.location = shader_input.location; layout.type = push_constant.type; layout.array_size = push_constant.array_size; @@ -45,7 +45,7 @@ uint32_t struct_size(Span push_constants) return offset; } -VKPushConstantsLayout::StorageType VKPushConstantsLayout::determine_storage_type( +VKPushConstants::StorageType VKPushConstants::Layout::determine_storage_type( const shader::ShaderCreateInfo &info, const VkPhysicalDeviceLimits &vk_physical_device_limits) { if (info.push_constants_.is_empty()) { @@ -60,7 +60,7 @@ VKPushConstantsLayout::StorageType VKPushConstantsLayout::determine_storage_type template void init_struct(const shader::ShaderCreateInfo &info, const VKShaderInterface &interface, - Vector &r_struct, + Vector &r_struct, uint32_t *r_offset) { for (const shader::ShaderCreateInfo::PushConst &push_constant : info.push_constants_) { @@ -70,10 +70,10 @@ void init_struct(const shader::ShaderCreateInfo &info, align_end_of_struct(r_offset); } -void VKPushConstantsLayout::init(const shader::ShaderCreateInfo &info, - const VKShaderInterface &interface, - const StorageType storage_type, - const VKDescriptorSet::Location location) +void VKPushConstants::Layout::init(const shader::ShaderCreateInfo &info, + const VKShaderInterface &interface, + const StorageType storage_type, + const VKDescriptorSet::Location location) { BLI_assert(push_constants.is_empty()); storage_type_ = storage_type; @@ -88,10 +88,9 @@ void VKPushConstantsLayout::init(const shader::ShaderCreateInfo &info, } } -const VKPushConstantsLayout::PushConstantLayout *VKPushConstantsLayout::find( - int32_t location) const +const VKPushConstants::Layout::PushConstant *VKPushConstants::Layout::find(int32_t location) const { - for (const PushConstantLayout &push_constant : push_constants) { + for (const PushConstant &push_constant : push_constants) { if (push_constant.location == location) { return &push_constant; } @@ -100,16 +99,16 @@ const VKPushConstantsLayout::PushConstantLayout *VKPushConstantsLayout::find( } VKPushConstants::VKPushConstants() = default; -VKPushConstants::VKPushConstants(const VKPushConstantsLayout *layout) : layout_(layout) +VKPushConstants::VKPushConstants(const Layout *layout) : layout_(layout) { data_ = MEM_mallocN(layout->size_in_bytes(), __func__); switch (layout_->storage_type_get()) { - case VKPushConstantsLayout::StorageType::UNIFORM_BUFFER: + case StorageType::UNIFORM_BUFFER: uniform_buffer_ = new VKUniformBuffer(layout_->size_in_bytes(), __func__); break; - case VKPushConstantsLayout::StorageType::PUSH_CONSTANTS: - case VKPushConstantsLayout::StorageType::NONE: + case StorageType::PUSH_CONSTANTS: + case StorageType::NONE: break; } } @@ -149,7 +148,7 @@ VKPushConstants &VKPushConstants::operator=(VKPushConstants &&other) void VKPushConstants::update_uniform_buffer() { - BLI_assert(layout_->storage_type_get() == VKPushConstantsLayout::StorageType::UNIFORM_BUFFER); + BLI_assert(layout_->storage_type_get() == StorageType::UNIFORM_BUFFER); BLI_assert(uniform_buffer_ != nullptr); BLI_assert(data_ != nullptr); uniform_buffer_->update(data_); @@ -157,7 +156,7 @@ void VKPushConstants::update_uniform_buffer() VKUniformBuffer &VKPushConstants::uniform_buffer_get() { - BLI_assert(layout_->storage_type_get() == VKPushConstantsLayout::StorageType::UNIFORM_BUFFER); + BLI_assert(layout_->storage_type_get() == StorageType::UNIFORM_BUFFER); BLI_assert(uniform_buffer_ != nullptr); return *uniform_buffer_; } diff --git a/source/blender/gpu/vulkan/vk_push_constants.hh b/source/blender/gpu/vulkan/vk_push_constants.hh index 4c62a47238c..887338d237e 100644 --- a/source/blender/gpu/vulkan/vk_push_constants.hh +++ b/source/blender/gpu/vulkan/vk_push_constants.hh @@ -30,108 +30,6 @@ namespace blender::gpu { class VKShaderInterface; class VKUniformBuffer; -/** - * Describe the layout of the push constants and the storage type that should be used. - */ -struct VKPushConstantsLayout { - /* Different methods to store push constants.*/ - enum class StorageType { - /** Push constants aren't in use.*/ - NONE, - - /** Store push constants as regular vulkan push constants.*/ - PUSH_CONSTANTS, - - /** - * Fallback when push constants doesn't meet the device requirements. - */ - UNIFORM_BUFFER, - }; - static constexpr StorageType STORAGE_TYPE_DEFAULT = StorageType::PUSH_CONSTANTS; - static constexpr StorageType STORAGE_TYPE_FALLBACK = StorageType::UNIFORM_BUFFER; - - struct PushConstantLayout { - /* Used as lookup based on ShaderInput.*/ - int32_t location; - - /** Offset in the push constant data (in bytes). */ - uint32_t offset; - shader::Type type; - int array_size; - }; - - private: - Vector push_constants; - uint32_t size_in_bytes_ = 0; - StorageType storage_type_ = StorageType::NONE; - /** - * Binding index in the descriptor set when the push constants use an uniform buffer. - */ - VKDescriptorSet::Location storage_buffer_binding_; - - public: - /** - * Return the desired storage type that can fit the push constants of the given shader create - * info, matching the device limits. - * - * Returns: - * - StorageType::NONE: No push constants are needed. - * - StorageType::PUSH_CONSTANTS: Regular vulkan push constants can be used. - * - StorageType::UNIFORM_BUFFER: The push constants don't fit in the limits of the given device. - * A uniform buffer should be used as a fallback method. - */ - static StorageType determine_storage_type( - const shader::ShaderCreateInfo &info, - const VkPhysicalDeviceLimits &vk_physical_device_limits); - - /** - * Initialize the push constants of the given shader create info with the - * binding location. - * - * interface: Uniform locations of the interface are used as lookup key. - * storage_type: The type of storage for push constants to use. - * location: When storage_type=StorageType::UNIFORM_BUFFER this contains - * the location in the descriptor set where the uniform buffer can be - * bound. - */ - void init(const shader::ShaderCreateInfo &info, - const VKShaderInterface &interface, - StorageType storage_type, - VKDescriptorSet::Location location); - - /** - * Return the storage type that is used. - */ - StorageType storage_type_get() const - { - return storage_type_; - } - - /** - * Get the binding location for the uniform buffer. - * - * Only valid when storage_type=StorageType::UNIFORM_BUFFER. - */ - VKDescriptorSet::Location storage_buffer_binding_get() const - { - return storage_buffer_binding_; - } - - /** - * Get the size needed to store the push constants. - */ - uint32_t size_in_bytes() const - { - return size_in_bytes_; - } - - /** - * Find the push constant layout for the given location. - * Location = ShaderInput.location. - */ - const PushConstantLayout *find(int32_t location) const; -}; - /** * Container to store push constants in a buffer. * @@ -145,14 +43,118 @@ struct VKPushConstantsLayout { * data. */ class VKPushConstants : NonCopyable { + public: + /** Different methods to store push constants.*/ + enum class StorageType { + /** Push constants aren't in use.*/ + NONE, + + /** Store push constants as regular vulkan push constants.*/ + PUSH_CONSTANTS, + + /** + * Fallback when push constants doesn't meet the device requirements. + */ + UNIFORM_BUFFER, + }; + + /** + * Describe the layout of the push constants and the storage type that should be used. + */ + struct Layout { + static constexpr StorageType STORAGE_TYPE_DEFAULT = StorageType::PUSH_CONSTANTS; + static constexpr StorageType STORAGE_TYPE_FALLBACK = StorageType::UNIFORM_BUFFER; + + struct PushConstant { + /* Used as lookup based on ShaderInput.*/ + int32_t location; + + /** Offset in the push constant data (in bytes). */ + uint32_t offset; + shader::Type type; + int array_size; + }; + + private: + Vector push_constants; + uint32_t size_in_bytes_ = 0; + StorageType storage_type_ = StorageType::NONE; + /** + * Binding index in the descriptor set when the push constants use an uniform buffer. + */ + VKDescriptorSet::Location storage_buffer_binding_; + + public: + /** + * Return the desired storage type that can fit the push constants of the given shader create + * info, matching the device limits. + * + * Returns: + * - StorageType::NONE: No push constants are needed. + * - StorageType::PUSH_CONSTANTS: Regular vulkan push constants can be used. + * - StorageType::UNIFORM_BUFFER: The push constants don't fit in the limits of the given + * device. A uniform buffer should be used as a fallback method. + */ + static StorageType determine_storage_type( + const shader::ShaderCreateInfo &info, + const VkPhysicalDeviceLimits &vk_physical_device_limits); + + /** + * Initialize the push constants of the given shader create info with the + * binding location. + * + * interface: Uniform locations of the interface are used as lookup key. + * storage_type: The type of storage for push constants to use. + * location: When storage_type=StorageType::UNIFORM_BUFFER this contains + * the location in the descriptor set where the uniform buffer can be + * bound. + */ + void init(const shader::ShaderCreateInfo &info, + const VKShaderInterface &interface, + StorageType storage_type, + VKDescriptorSet::Location location); + + /** + * Return the storage type that is used. + */ + StorageType storage_type_get() const + { + return storage_type_; + } + + /** + * Get the binding location for the uniform buffer. + * + * Only valid when storage_type=StorageType::UNIFORM_BUFFER. + */ + VKDescriptorSet::Location storage_buffer_binding_get() const + { + return storage_buffer_binding_; + } + + /** + * Get the size needed to store the push constants. + */ + uint32_t size_in_bytes() const + { + return size_in_bytes_; + } + + /** + * Find the push constant layout for the given location. + * Location = ShaderInput.location. + */ + const PushConstant *find(int32_t location) const; + }; + private: - const VKPushConstantsLayout *layout_ = nullptr; + const Layout *layout_ = nullptr; void *data_ = nullptr; VKUniformBuffer *uniform_buffer_ = nullptr; public: VKPushConstants(); - VKPushConstants(const VKPushConstantsLayout *layout); + VKPushConstants(const Layout *layout); VKPushConstants(VKPushConstants &&other); virtual ~VKPushConstants(); @@ -163,7 +165,7 @@ class VKPushConstants : NonCopyable { return 0; } - const VKPushConstantsLayout &layout_get() const + const Layout &layout_get() const { return *layout_; } @@ -212,14 +214,12 @@ class VKPushConstants : NonCopyable { int32_t array_size, const T *input_data) { - const VKPushConstantsLayout::PushConstantLayout *push_constant_layout = layout_->find( - location); + const Layout::PushConstant *push_constant_layout = layout_->find(location); BLI_assert(push_constant_layout); uint8_t *bytes = static_cast(data_); T *dst = static_cast(static_cast(&bytes[push_constant_layout->offset])); - if (layout_->storage_type_get() == VKPushConstantsLayout::StorageType::PUSH_CONSTANTS || - array_size == 0) { + if (layout_->storage_type_get() == StorageType::PUSH_CONSTANTS || array_size == 0) { BLI_assert_msg(push_constant_layout->offset + comp_len * array_size * sizeof(T) <= layout_->size_in_bytes(), "Tried to write outside the push constant allocated memory."); diff --git a/source/blender/gpu/vulkan/vk_shader.cc b/source/blender/gpu/vulkan/vk_shader.cc index 89d39704860..cda88aeceaa 100644 --- a/source/blender/gpu/vulkan/vk_shader.cc +++ b/source/blender/gpu/vulkan/vk_shader.cc @@ -756,10 +756,9 @@ bool VKShader::finalize_pipeline_layout(VkDevice vk_device, pipeline_info.pSetLayouts = &layout_; /* Setup push constants. */ - const VKPushConstantsLayout &push_constants_layout = + const VKPushConstants::Layout &push_constants_layout = shader_interface.push_constants_layout_get(); - if (push_constants_layout.storage_type_get() == - VKPushConstantsLayout::StorageType::PUSH_CONSTANTS) { + if (push_constants_layout.storage_type_get() == VKPushConstants::StorageType::PUSH_CONSTANTS) { push_constant_range.offset = 0; push_constant_range.size = push_constants_layout.size_in_bytes(); push_constant_range.stageFlags = VK_SHADER_STAGE_ALL; @@ -886,10 +885,10 @@ static VkDescriptorSetLayoutBinding create_descriptor_set_layout_binding( } static VkDescriptorSetLayoutBinding create_descriptor_set_layout_binding( - const VKPushConstantsLayout &push_constants_layout) + const VKPushConstants::Layout &push_constants_layout) { BLI_assert(push_constants_layout.storage_type_get() == - VKPushConstantsLayout::StorageType::UNIFORM_BUFFER); + VKPushConstants::StorageType::UNIFORM_BUFFER); VkDescriptorSetLayoutBinding binding = {}; binding.binding = push_constants_layout.storage_buffer_binding_get(); binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; @@ -911,9 +910,8 @@ static void add_descriptor_set_layout_bindings( } /* Add push constants to the descriptor when push constants are stored in an uniform buffer.*/ - const VKPushConstantsLayout &push_constants_layout = interface.push_constants_layout_get(); - if (push_constants_layout.storage_type_get() == - VKPushConstantsLayout::StorageType::UNIFORM_BUFFER) { + const VKPushConstants::Layout &push_constants_layout = interface.push_constants_layout_get(); + if (push_constants_layout.storage_type_get() == VKPushConstants::StorageType::UNIFORM_BUFFER) { r_bindings.append(create_descriptor_set_layout_binding(push_constants_layout)); } } @@ -938,7 +936,7 @@ static bool descriptor_sets_needed(const VKShaderInterface &shader_interface, { return !info.pass_resources_.is_empty() || !info.batch_resources_.is_empty() || shader_interface.push_constants_layout_get().storage_type_get() == - VKPushConstantsLayout::StorageType::UNIFORM_BUFFER; + VKPushConstants::StorageType::UNIFORM_BUFFER; } bool VKShader::finalize_descriptor_set_layouts(VkDevice vk_device, @@ -1038,15 +1036,15 @@ std::string VKShader::resources_declare(const shader::ShaderCreateInfo &info) co } /* Push constants. */ - const VKPushConstantsLayout &push_constants_layout = interface.push_constants_layout_get(); - const VKPushConstantsLayout::StorageType push_constants_storage = + const VKPushConstants::Layout &push_constants_layout = interface.push_constants_layout_get(); + const VKPushConstants::StorageType push_constants_storage = push_constants_layout.storage_type_get(); - if (push_constants_storage != VKPushConstantsLayout::StorageType::NONE) { + if (push_constants_storage != VKPushConstants::StorageType::NONE) { ss << "\n/* Push Constants. */\n"; - if (push_constants_storage == VKPushConstantsLayout::StorageType::PUSH_CONSTANTS) { + if (push_constants_storage == VKPushConstants::StorageType::PUSH_CONSTANTS) { ss << "layout(push_constant) uniform constants\n"; } - else if (push_constants_storage == VKPushConstantsLayout::StorageType::UNIFORM_BUFFER) { + else if (push_constants_storage == VKPushConstants::StorageType::UNIFORM_BUFFER) { ss << "layout(binding = " << push_constants_layout.storage_buffer_binding_get() << ", std140) uniform constants\n"; } diff --git a/source/blender/gpu/vulkan/vk_shader_interface.cc b/source/blender/gpu/vulkan/vk_shader_interface.cc index 1b0ca863129..325d04c0bf4 100644 --- a/source/blender/gpu/vulkan/vk_shader_interface.cc +++ b/source/blender/gpu/vulkan/vk_shader_interface.cc @@ -45,9 +45,9 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) /* Reserve 1 storage buffer for push constants fallback. */ size_t names_size = info.interface_names_size_; VKContext &context = *VKContext::get(); - const VKPushConstantsLayout::StorageType push_constants_storage_type = - VKPushConstantsLayout::determine_storage_type(info, context.physical_device_limits_get()); - if (push_constants_storage_type == VKPushConstantsLayout::StorageType::UNIFORM_BUFFER) { + const VKPushConstants::StorageType push_constants_storage_type = + VKPushConstants::Layout::determine_storage_type(info, context.physical_device_limits_get()); + if (push_constants_storage_type == VKPushConstants::StorageType::UNIFORM_BUFFER) { ubo_len_++; names_size += PUSH_CONSTANTS_FALLBACK_NAME_LEN + 1; } @@ -73,7 +73,7 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) } /* Add push constant when using uniform buffer as fallback. */ int32_t push_constants_fallback_location = -1; - if (push_constants_storage_type == VKPushConstantsLayout::StorageType::UNIFORM_BUFFER) { + if (push_constants_storage_type == VKPushConstants::StorageType::UNIFORM_BUFFER) { copy_input_name(input, PUSH_CONSTANTS_FALLBACK_NAME, name_buffer_, name_buffer_offset); input->location = input->binding = -1; input++; @@ -138,7 +138,7 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) /* Post initializing push constants.*/ /* Determine the binding location of push constants fallback buffer.*/ int32_t push_constant_descriptor_set_location = -1; - if (push_constants_storage_type == VKPushConstantsLayout::StorageType::UNIFORM_BUFFER) { + if (push_constants_storage_type == VKPushConstants::StorageType::UNIFORM_BUFFER) { push_constant_descriptor_set_location = descriptor_set_location++; const ShaderInput *push_constant_input = ubo_get(PUSH_CONSTANTS_FALLBACK_NAME.c_str()); descriptor_set_location_update(push_constant_input, push_constants_fallback_location); diff --git a/source/blender/gpu/vulkan/vk_shader_interface.hh b/source/blender/gpu/vulkan/vk_shader_interface.hh index 82bcca9f680..f0ada3fb28e 100644 --- a/source/blender/gpu/vulkan/vk_shader_interface.hh +++ b/source/blender/gpu/vulkan/vk_shader_interface.hh @@ -29,7 +29,7 @@ class VKShaderInterface : public ShaderInterface { uint32_t image_offset_ = 0; Array descriptor_set_locations_; - VKPushConstantsLayout push_constants_layout_; + VKPushConstants::Layout push_constants_layout_; public: /** @@ -49,8 +49,8 @@ class VKShaderInterface : public ShaderInterface { const VKDescriptorSet::Location descriptor_set_location( const shader::ShaderCreateInfo::Resource::BindType &bind_type, int binding) const; - /** Get the VKPushConstantsLayout of the shader.*/ - const VKPushConstantsLayout &push_constants_layout_get() const + /** Get the Layout of the shader.*/ + const VKPushConstants::Layout &push_constants_layout_get() const { return push_constants_layout_; } -- 2.30.2 From 8a591a78456c5141a9448b226d9b5e33831247d3 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Thu, 23 Feb 2023 18:20:02 +0100 Subject: [PATCH 47/55] Cleanup: function naming. --- source/blender/gpu/vulkan/vk_backend.cc | 2 +- source/blender/gpu/vulkan/vk_push_constants.cc | 2 +- source/blender/gpu/vulkan/vk_push_constants.hh | 9 +++------ source/blender/gpu/vulkan/vk_shader.cc | 4 ++-- 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/source/blender/gpu/vulkan/vk_backend.cc b/source/blender/gpu/vulkan/vk_backend.cc index fd13c238854..f2076270696 100644 --- a/source/blender/gpu/vulkan/vk_backend.cc +++ b/source/blender/gpu/vulkan/vk_backend.cc @@ -82,7 +82,7 @@ void VKBackend::compute_dispatch(int groups_x_len, int groups_y_len, int groups_ case VKPushConstants::StorageType::UNIFORM_BUFFER: push_constants.update_uniform_buffer(); descriptor_set.bind(push_constants.uniform_buffer_get(), - push_constants.layout_get().storage_buffer_binding_get()); + push_constants.layout_get().descriptor_set_location_get()); break; } descriptor_set.update(context.device_get()); diff --git a/source/blender/gpu/vulkan/vk_push_constants.cc b/source/blender/gpu/vulkan/vk_push_constants.cc index 450fee45bb5..1d68b9ba448 100644 --- a/source/blender/gpu/vulkan/vk_push_constants.cc +++ b/source/blender/gpu/vulkan/vk_push_constants.cc @@ -80,7 +80,7 @@ void VKPushConstants::Layout::init(const shader::ShaderCreateInfo &info, size_in_bytes_ = 0; if (storage_type == StorageType::UNIFORM_BUFFER) { - storage_buffer_binding_ = location; + descriptor_set_location_ = location; init_struct(info, interface, push_constants, &size_in_bytes_); } else { diff --git a/source/blender/gpu/vulkan/vk_push_constants.hh b/source/blender/gpu/vulkan/vk_push_constants.hh index 887338d237e..a35844aab91 100644 --- a/source/blender/gpu/vulkan/vk_push_constants.hh +++ b/source/blender/gpu/vulkan/vk_push_constants.hh @@ -82,7 +82,7 @@ class VKPushConstants : NonCopyable { /** * Binding index in the descriptor set when the push constants use an uniform buffer. */ - VKDescriptorSet::Location storage_buffer_binding_; + VKDescriptorSet::Location descriptor_set_location_; public: /** @@ -127,9 +127,9 @@ class VKPushConstants : NonCopyable { * * Only valid when storage_type=StorageType::UNIFORM_BUFFER. */ - VKDescriptorSet::Location storage_buffer_binding_get() const + VKDescriptorSet::Location descriptor_set_location_get() const { - return storage_buffer_binding_; + return descriptor_set_location_; } /** @@ -204,9 +204,6 @@ class VKPushConstants : NonCopyable { * comp_len: number of components has the data type that is being updated. * array_size: number of elements when an array to update. (0=no array) * input_data: packed source data to use. - * - * TODO: this function still needs to convert the input_data layout to that - * what the storage type is expected. */ template void push_constant_set(int32_t location, diff --git a/source/blender/gpu/vulkan/vk_shader.cc b/source/blender/gpu/vulkan/vk_shader.cc index cda88aeceaa..9b42370db49 100644 --- a/source/blender/gpu/vulkan/vk_shader.cc +++ b/source/blender/gpu/vulkan/vk_shader.cc @@ -890,7 +890,7 @@ static VkDescriptorSetLayoutBinding create_descriptor_set_layout_binding( BLI_assert(push_constants_layout.storage_type_get() == VKPushConstants::StorageType::UNIFORM_BUFFER); VkDescriptorSetLayoutBinding binding = {}; - binding.binding = push_constants_layout.storage_buffer_binding_get(); + binding.binding = push_constants_layout.descriptor_set_location_get(); binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; binding.descriptorCount = 1; binding.stageFlags = VK_SHADER_STAGE_ALL; @@ -1045,7 +1045,7 @@ std::string VKShader::resources_declare(const shader::ShaderCreateInfo &info) co ss << "layout(push_constant) uniform constants\n"; } else if (push_constants_storage == VKPushConstants::StorageType::UNIFORM_BUFFER) { - ss << "layout(binding = " << push_constants_layout.storage_buffer_binding_get() + ss << "layout(binding = " << push_constants_layout.descriptor_set_location_get() << ", std140) uniform constants\n"; } ss << "{\n"; -- 2.30.2 From 7876291d087c42a85925c332e6ba36c7890cb650 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Thu, 23 Feb 2023 18:22:12 +0100 Subject: [PATCH 48/55] Cleanup: Incorrect reference to storage buffer in comment. --- source/blender/gpu/vulkan/vk_shader_interface.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/gpu/vulkan/vk_shader_interface.cc b/source/blender/gpu/vulkan/vk_shader_interface.cc index 325d04c0bf4..e46bb0372b5 100644 --- a/source/blender/gpu/vulkan/vk_shader_interface.cc +++ b/source/blender/gpu/vulkan/vk_shader_interface.cc @@ -42,7 +42,7 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) } } - /* Reserve 1 storage buffer for push constants fallback. */ + /* Reserve 1 uniform buffer for push constants fallback. */ size_t names_size = info.interface_names_size_; VKContext &context = *VKContext::get(); const VKPushConstants::StorageType push_constants_storage_type = -- 2.30.2 From ad5ac6bdf7fae5cd0379d2db44d81c9a1662bb1b Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Thu, 23 Feb 2023 18:24:14 +0100 Subject: [PATCH 49/55] Cleanup: Spelling in comment. --- source/blender/gpu/vulkan/vk_shader_interface.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/gpu/vulkan/vk_shader_interface.hh b/source/blender/gpu/vulkan/vk_shader_interface.hh index f0ada3fb28e..6edba398ed0 100644 --- a/source/blender/gpu/vulkan/vk_shader_interface.hh +++ b/source/blender/gpu/vulkan/vk_shader_interface.hh @@ -33,7 +33,7 @@ class VKShaderInterface : public ShaderInterface { public: /** - * When the push constants fallback is used, this name will be used in the GLSL source. + * GLSL resource name for the push constants fallback. */ static constexpr StringRefNull PUSH_CONSTANTS_FALLBACK_NAME = StringRefNull( "push_constants_fallback", 23); -- 2.30.2 From 390cee5f88b3054b95b456d94e5720ae7d2fc6e0 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Mon, 27 Feb 2023 13:04:12 +0100 Subject: [PATCH 50/55] Naming parameters generate_test_data function. --- .../gpu/tests/gpu_push_constants_test.cc | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/source/blender/gpu/tests/gpu_push_constants_test.cc b/source/blender/gpu/tests/gpu_push_constants_test.cc index c944ece3d91..31321401bb9 100644 --- a/source/blender/gpu/tests/gpu_push_constants_test.cc +++ b/source/blender/gpu/tests/gpu_push_constants_test.cc @@ -40,17 +40,16 @@ struct CallData { } } - void generate_test_data(const float components_mul, const float component_mul) + void generate_test_data(const float vector_mul, const float scalar_mul) { - float_in = components_mul; - vec2_in = float2(components_mul * 2.0, components_mul * 2.0 + component_mul); - vec3_in = float3(components_mul * 3.0, - components_mul * 3.0 + component_mul, - components_mul * 3.0 + component_mul * 2.0); - vec4_in = float4(components_mul * 4.0, - components_mul * 4.0 + component_mul, - components_mul * 4.0 + component_mul * 2.0, - components_mul * 4.0 + component_mul * 3.0); + float_in = vector_mul; + vec2_in = float2(vector_mul * 2.0, vector_mul * 2.0 + scalar_mul); + vec3_in = float3( + vector_mul * 3.0, vector_mul * 3.0 + scalar_mul, vector_mul * 3.0 + scalar_mul * 2.0); + vec4_in = float4(vector_mul * 4.0, + vector_mul * 4.0 + scalar_mul, + vector_mul * 4.0 + scalar_mul * 2.0, + vector_mul * 4.0 + scalar_mul * 3.0); } void read_back() -- 2.30.2 From f9e23882c73d2ba250b1d22aa59f60eb03c7355e Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Mon, 27 Feb 2023 13:05:55 +0100 Subject: [PATCH 51/55] Rename template argument Layout->LayoutT --- source/blender/gpu/vulkan/vk_memory_layout.hh | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/source/blender/gpu/vulkan/vk_memory_layout.hh b/source/blender/gpu/vulkan/vk_memory_layout.hh index 16c5811a752..1641c49e20d 100644 --- a/source/blender/gpu/vulkan/vk_memory_layout.hh +++ b/source/blender/gpu/vulkan/vk_memory_layout.hh @@ -39,14 +39,14 @@ struct Std430 { static uint32_t array_components_len(const shader::Type type); }; -template static uint32_t element_stride(const shader::Type type) +template static uint32_t element_stride(const shader::Type type) { - return Layout::element_components_len(type) * Layout::component_mem_size(type); + return LayoutT::element_components_len(type) * LayoutT::component_mem_size(type); } -template static uint32_t array_stride(const shader::Type type) +template static uint32_t array_stride(const shader::Type type) { - return Layout::array_components_len(type) * Layout::component_mem_size(type); + return LayoutT::array_components_len(type) * LayoutT::component_mem_size(type); } /** @@ -58,10 +58,10 @@ template static uint32_t array_stride(const shader::Type type) * 'r_offset': After the call it will point to the byte where the reservation * can happen. */ -template +template static void align(const shader::Type &type, const int32_t array_size, uint32_t *r_offset) { - uint32_t alignment = Layout::element_alignment(type, array_size != 0); + uint32_t alignment = LayoutT::element_alignment(type, array_size != 0); uint32_t alignment_mask = alignment - 1; uint32_t offset = *r_offset; if ((offset & alignment_mask) != 0) { @@ -83,11 +83,11 @@ static void align(const shader::Type &type, const int32_t array_size, uint32_t * * reserve space. After the call it will point to the byte just after reserved * space. */ -template +template static void reserve(const shader::Type type, int32_t array_size, uint32_t *r_offset) { - uint32_t size = array_size == 0 ? element_stride(type) : - array_stride(type) * array_size; + uint32_t size = array_size == 0 ? element_stride(type) : + array_stride(type) * array_size; *r_offset += size; } @@ -97,9 +97,9 @@ static void reserve(const shader::Type type, int32_t array_size, uint32_t *r_off * Call this function when all attributes have been added to make sure that the struct size is * correct. */ -template static void align_end_of_struct(uint32_t *r_offset) +template static void align_end_of_struct(uint32_t *r_offset) { - align(shader::Type::VEC4, 0, r_offset); + align(shader::Type::VEC4, 0, r_offset); } } // namespace blender::gpu -- 2.30.2 From 919e0ece3b6134eba303a1aa6428638e16392083 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Mon, 27 Feb 2023 13:11:34 +0100 Subject: [PATCH 52/55] Use single memcpy when copying an array that is tightly packed in std140. --- source/blender/gpu/vulkan/vk_push_constants.hh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/blender/gpu/vulkan/vk_push_constants.hh b/source/blender/gpu/vulkan/vk_push_constants.hh index a35844aab91..4cc0624e506 100644 --- a/source/blender/gpu/vulkan/vk_push_constants.hh +++ b/source/blender/gpu/vulkan/vk_push_constants.hh @@ -216,7 +216,9 @@ class VKPushConstants : NonCopyable { uint8_t *bytes = static_cast(data_); T *dst = static_cast(static_cast(&bytes[push_constant_layout->offset])); - if (layout_->storage_type_get() == StorageType::PUSH_CONSTANTS || array_size == 0) { + const bool is_tightly_std140_packed = (comp_len % 4) == 0; + if (layout_->storage_type_get() == StorageType::PUSH_CONSTANTS || array_size == 0 || + is_tightly_std140_packed) { BLI_assert_msg(push_constant_layout->offset + comp_len * array_size * sizeof(T) <= layout_->size_in_bytes(), "Tried to write outside the push constant allocated memory."); -- 2.30.2 From 0c5745f060ed0e4fabe1bda3840bdf3a8d95c6ea Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Mon, 27 Feb 2023 14:03:32 +0100 Subject: [PATCH 53/55] Missing renames Layout->LayoutT --- source/blender/gpu/vulkan/vk_push_constants.cc | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/source/blender/gpu/vulkan/vk_push_constants.cc b/source/blender/gpu/vulkan/vk_push_constants.cc index 1d68b9ba448..fe8b707e719 100644 --- a/source/blender/gpu/vulkan/vk_push_constants.cc +++ b/source/blender/gpu/vulkan/vk_push_constants.cc @@ -14,13 +14,13 @@ namespace blender::gpu { -template +template static VKPushConstants::Layout::PushConstant init_constant( const shader::ShaderCreateInfo::PushConst &push_constant, const ShaderInput &shader_input, uint32_t *r_offset) { - align(push_constant.type, push_constant.array_size, r_offset); + align(push_constant.type, push_constant.array_size, r_offset); VKPushConstants::Layout::PushConstant layout; layout.location = shader_input.location; @@ -28,20 +28,20 @@ static VKPushConstants::Layout::PushConstant init_constant( layout.array_size = push_constant.array_size; layout.offset = *r_offset; - reserve(push_constant.type, push_constant.array_size, r_offset); + reserve(push_constant.type, push_constant.array_size, r_offset); return layout; } -template +template uint32_t struct_size(Span push_constants) { uint32_t offset = 0; for (const shader::ShaderCreateInfo::PushConst &push_constant : push_constants) { - align(push_constant.type, push_constant.array_size, &offset); - reserve(push_constant.type, push_constant.array_size, &offset); + align(push_constant.type, push_constant.array_size, &offset); + reserve(push_constant.type, push_constant.array_size, &offset); } - align_end_of_struct(&offset); + align_end_of_struct(&offset); return offset; } @@ -57,7 +57,7 @@ VKPushConstants::StorageType VKPushConstants::Layout::determine_storage_type( STORAGE_TYPE_FALLBACK; } -template +template void init_struct(const shader::ShaderCreateInfo &info, const VKShaderInterface &interface, Vector &r_struct, @@ -65,7 +65,7 @@ void init_struct(const shader::ShaderCreateInfo &info, { for (const shader::ShaderCreateInfo::PushConst &push_constant : info.push_constants_) { const ShaderInput *shader_input = interface.uniform_get(push_constant.name.c_str()); - r_struct.append(init_constant(push_constant, *shader_input, r_offset)); + r_struct.append(init_constant(push_constant, *shader_input, r_offset)); } align_end_of_struct(r_offset); } -- 2.30.2 From 70b1f871a707d2b57ec5c50676a91e0704e7fc36 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Mon, 6 Mar 2023 10:46:16 +0100 Subject: [PATCH 54/55] Moved fallback name to local static const of init. * constexpr isn't compiling on all platforms (CLang/Apple) * Visibility is only in a single function. --- source/blender/gpu/vulkan/vk_shader_interface.cc | 5 ++++- source/blender/gpu/vulkan/vk_shader_interface.hh | 7 ------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/source/blender/gpu/vulkan/vk_shader_interface.cc b/source/blender/gpu/vulkan/vk_shader_interface.cc index 96ee4b8c9c0..64d55065c80 100644 --- a/source/blender/gpu/vulkan/vk_shader_interface.cc +++ b/source/blender/gpu/vulkan/vk_shader_interface.cc @@ -12,6 +12,9 @@ namespace blender::gpu { void VKShaderInterface::init(const shader::ShaderCreateInfo &info) { + static char PUSH_CONSTANTS_FALLBACK_NAME[] = "push_constants_fallback"; + static size_t PUSH_CONSTANTS_FALLBACK_NAME_LEN = strlen(PUSH_CONSTANTS_FALLBACK_NAME); + using namespace blender::gpu::shader; attr_len_ = 0; @@ -140,7 +143,7 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) int32_t push_constant_descriptor_set_location = -1; if (push_constants_storage_type == VKPushConstants::StorageType::UNIFORM_BUFFER) { push_constant_descriptor_set_location = descriptor_set_location++; - const ShaderInput *push_constant_input = ubo_get(PUSH_CONSTANTS_FALLBACK_NAME.c_str()); + const ShaderInput *push_constant_input = ubo_get(PUSH_CONSTANTS_FALLBACK_NAME); descriptor_set_location_update(push_constant_input, push_constants_fallback_location); } push_constants_layout_.init( diff --git a/source/blender/gpu/vulkan/vk_shader_interface.hh b/source/blender/gpu/vulkan/vk_shader_interface.hh index 6edba398ed0..f0b9606bc19 100644 --- a/source/blender/gpu/vulkan/vk_shader_interface.hh +++ b/source/blender/gpu/vulkan/vk_shader_interface.hh @@ -31,13 +31,6 @@ class VKShaderInterface : public ShaderInterface { VKPushConstants::Layout push_constants_layout_; - public: - /** - * GLSL resource name for the push constants fallback. - */ - static constexpr StringRefNull PUSH_CONSTANTS_FALLBACK_NAME = StringRefNull( - "push_constants_fallback", 23); - static constexpr size_t PUSH_CONSTANTS_FALLBACK_NAME_LEN = PUSH_CONSTANTS_FALLBACK_NAME.size(); public: VKShaderInterface() = default; -- 2.30.2 From a265b199851aee6876f79cfbb8d8eaf5cfb262ca Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Mon, 6 Mar 2023 11:07:50 +0100 Subject: [PATCH 55/55] Hide updating of push constants inside VKPushConstants.update. --- source/blender/gpu/vulkan/vk_backend.cc | 17 +-------- .../blender/gpu/vulkan/vk_push_constants.cc | 26 +++++++++++++ .../blender/gpu/vulkan/vk_push_constants.hh | 37 +++++++++++-------- 3 files changed, 49 insertions(+), 31 deletions(-) diff --git a/source/blender/gpu/vulkan/vk_backend.cc b/source/blender/gpu/vulkan/vk_backend.cc index f2076270696..c97ef26b3f6 100644 --- a/source/blender/gpu/vulkan/vk_backend.cc +++ b/source/blender/gpu/vulkan/vk_backend.cc @@ -69,22 +69,7 @@ void VKBackend::compute_dispatch(int groups_x_len, int groups_y_len, int groups_ VKDescriptorSet &descriptor_set = pipeline.descriptor_set_get(); VKPushConstants &push_constants = pipeline.push_constants_get(); - /* Update push constants based on their storage type.*/ - switch (push_constants.layout_get().storage_type_get()) { - case VKPushConstants::StorageType::NONE: - break; - - case VKPushConstants::StorageType::PUSH_CONSTANTS: - command_buffer.push_constants( - push_constants, shader->vk_pipeline_layout_get(), VK_SHADER_STAGE_ALL); - break; - - case VKPushConstants::StorageType::UNIFORM_BUFFER: - push_constants.update_uniform_buffer(); - descriptor_set.bind(push_constants.uniform_buffer_get(), - push_constants.layout_get().descriptor_set_location_get()); - break; - } + push_constants.update(context); descriptor_set.update(context.device_get()); command_buffer.bind( descriptor_set, shader->vk_pipeline_layout_get(), VK_PIPELINE_BIND_POINT_COMPUTE); diff --git a/source/blender/gpu/vulkan/vk_push_constants.cc b/source/blender/gpu/vulkan/vk_push_constants.cc index fe8b707e719..d7b423cbd1c 100644 --- a/source/blender/gpu/vulkan/vk_push_constants.cc +++ b/source/blender/gpu/vulkan/vk_push_constants.cc @@ -8,6 +8,7 @@ #include "vk_push_constants.hh" #include "vk_backend.hh" #include "vk_memory_layout.hh" +#include "vk_shader.hh" #include "vk_shader_interface.hh" #include "vk_storage_buffer.hh" #include "vk_uniform_buffer.hh" @@ -146,6 +147,31 @@ VKPushConstants &VKPushConstants::operator=(VKPushConstants &&other) return *this; } +void VKPushConstants::update(VKContext &context) +{ + VKShader *shader = static_cast(context.shader); + VKCommandBuffer &command_buffer = context.command_buffer_get(); + VKPipeline &pipeline = shader->pipeline_get(); + BLI_assert_msg(&pipeline.push_constants_get() == this, + "Invalid state detected. Push constants doesn't belong to the active shader of " + "the given context."); + VKDescriptorSet &descriptor_set = pipeline.descriptor_set_get(); + + switch (layout_get().storage_type_get()) { + case VKPushConstants::StorageType::NONE: + break; + + case VKPushConstants::StorageType::PUSH_CONSTANTS: + command_buffer.push_constants(*this, shader->vk_pipeline_layout_get(), VK_SHADER_STAGE_ALL); + break; + + case VKPushConstants::StorageType::UNIFORM_BUFFER: + update_uniform_buffer(); + descriptor_set.bind(uniform_buffer_get(), layout_get().descriptor_set_location_get()); + break; + } +} + void VKPushConstants::update_uniform_buffer() { BLI_assert(layout_->storage_type_get() == StorageType::UNIFORM_BUFFER); diff --git a/source/blender/gpu/vulkan/vk_push_constants.hh b/source/blender/gpu/vulkan/vk_push_constants.hh index 4cc0624e506..9625320b239 100644 --- a/source/blender/gpu/vulkan/vk_push_constants.hh +++ b/source/blender/gpu/vulkan/vk_push_constants.hh @@ -29,6 +29,7 @@ namespace blender::gpu { class VKShaderInterface; class VKUniformBuffer; +class VKContext; /** * Container to store push constants in a buffer. @@ -170,21 +171,6 @@ class VKPushConstants : NonCopyable { return *layout_; } - /** - * When storage type = StorageType::UNIFORM_BUFFER use this method to update the uniform - * buffer. - * - * It must be called just before adding a draw/compute command to the command queue. - */ - void update_uniform_buffer(); - - /** - * Get a reference to the uniform buffer. - * - * Only valid when storage type = StorageType::UNIFORM_BUFFER. - */ - VKUniformBuffer &uniform_buffer_get(); - /** * Get the reference to the active data. * @@ -237,6 +223,27 @@ class VKPushConstants : NonCopyable { dst += 4; } } + + /** + * Update the GPU resources with the latest push constants. + */ + void update(VKContext &context); + + private: + /** + * When storage type = StorageType::UNIFORM_BUFFER use this method to update the uniform + * buffer. + * + * It must be called just before adding a draw/compute command to the command queue. + */ + void update_uniform_buffer(); + + /** + * Get a reference to the uniform buffer. + * + * Only valid when storage type = StorageType::UNIFORM_BUFFER. + */ + VKUniformBuffer &uniform_buffer_get(); }; } // namespace blender::gpu -- 2.30.2