From 366404d274d80e3ba255772b731c16298cc46887 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Mon, 13 Feb 2023 09:36:43 +0100 Subject: [PATCH 01/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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 b723a4dec58c1eac8df770329e3ad0fb2a295c2b Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Tue, 28 Feb 2023 13:20:07 +0100 Subject: [PATCH 54/66] Added test cases for clearing storage buffers. --- .../gpu/tests/gpu_storage_buffer_test.cc | 93 ++++++++++++++++++- .../blender/gpu/vulkan/vk_command_buffer.cc | 5 + .../blender/gpu/vulkan/vk_command_buffer.hh | 1 + .../blender/gpu/vulkan/vk_storage_buffer.cc | 54 ++++++++++- 4 files changed, 147 insertions(+), 6 deletions(-) diff --git a/source/blender/gpu/tests/gpu_storage_buffer_test.cc b/source/blender/gpu/tests/gpu_storage_buffer_test.cc index 79b23e29407..e3d6e0660cd 100644 --- a/source/blender/gpu/tests/gpu_storage_buffer_test.cc +++ b/source/blender/gpu/tests/gpu_storage_buffer_test.cc @@ -4,6 +4,7 @@ #include "GPU_storage_buffer.h" +#include "BLI_math_vector_types.hh" #include "BLI_vector.hh" #include "gpu_testing.hh" @@ -22,7 +23,7 @@ static Vector test_data() return data; } -static void test_gpu_storage_buffer_create_update_read() +static void test_storage_buffer_create_update_read() { GPUStorageBuf *ssbo = GPU_storagebuf_create_ex( SIZE_IN_BYTES, nullptr, GPU_USAGE_STATIC, __func__); @@ -45,6 +46,94 @@ static void test_gpu_storage_buffer_create_update_read() GPU_storagebuf_free(ssbo); } -GPU_TEST(gpu_storage_buffer_create_update_read); +GPU_TEST(storage_buffer_create_update_read); + +static void test_storage_buffer_clear_zero() +{ + 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()); + GPU_storagebuf_clear_to_zero(ssbo); + + /* 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(0, read_data[i]); + } + + GPU_storagebuf_free(ssbo); +} + +GPU_TEST(storage_buffer_clear_zero); + +/* TODO: Make template.*/ +template static void storage_buffer_clear_uniform() +{ + GPUStorageBuf *ssbo = GPU_storagebuf_create_ex( + SIZE_IN_BYTES, nullptr, GPU_USAGE_STATIC, __func__); + EXPECT_NE(ssbo, nullptr); + + /* Read back data from SSBO. */ + int4 clear_data = {-1, -1, -1, -1}; + GPU_storagebuf_clear(ssbo, TextureFormat, GPU_DATA_INT, &clear_data); + + /* Check if data is the same. */ + Vector read_data; + read_data.resize(SIZE, 0); + GPU_storagebuf_read(ssbo, read_data.data()); + for (int i : IndexRange(SIZE)) { + EXPECT_EQ(clear_data[i % 4], read_data[i]); + } + + GPU_storagebuf_free(ssbo); +} + +static void test_storage_buffer_clear_RGBA32I_uniform() +{ + storage_buffer_clear_uniform(); +} +GPU_TEST(storage_buffer_clear_RGBA32I_uniform); + +static void test_storage_buffer_clear_RG32I_uniform() +{ + storage_buffer_clear_uniform(); +} +GPU_TEST(storage_buffer_clear_RG32I_uniform); + +static void test_storage_buffer_clear_RG32UI_uniform() +{ + storage_buffer_clear_uniform(); +} +GPU_TEST(storage_buffer_clear_RG32UI_uniform); + +static void test_storage_buffer_clear_RGBAI32() +{ + GPUStorageBuf *ssbo = GPU_storagebuf_create_ex( + SIZE_IN_BYTES, nullptr, GPU_USAGE_STATIC, __func__); + EXPECT_NE(ssbo, nullptr); + + /* Read back data from SSBO. */ + int4 clear_data = {-1, -2, -3, -4}; + GPU_storagebuf_clear(ssbo, GPU_RGBA32I, GPU_DATA_INT, &clear_data); + + /* Check if data is the same. */ + Vector read_data; + read_data.resize(SIZE, 0); + GPU_storagebuf_read(ssbo, read_data.data()); + for (int i : IndexRange(SIZE)) { + EXPECT_EQ(clear_data[i % 4], read_data[i]); + } + + GPU_storagebuf_free(ssbo); +} +GPU_TEST(storage_buffer_clear_RGBAI32); } // namespace blender::gpu::tests diff --git a/source/blender/gpu/vulkan/vk_command_buffer.cc b/source/blender/gpu/vulkan/vk_command_buffer.cc index b4526df6aba..af8d39bcf7b 100644 --- a/source/blender/gpu/vulkan/vk_command_buffer.cc +++ b/source/blender/gpu/vulkan/vk_command_buffer.cc @@ -86,6 +86,11 @@ void VKCommandBuffer::push_constants(const VKPushConstants &push_constants, push_constants.data()); } +void VKCommandBuffer::fill(VKBuffer &buffer, uint32_t clear_data) +{ + vkCmdFillBuffer(vk_command_buffer_, buffer.vk_handle(), 0, buffer.size_in_bytes(), clear_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 0f5f47a423a..103f4ac2300 100644 --- a/source/blender/gpu/vulkan/vk_command_buffer.hh +++ b/source/blender/gpu/vulkan/vk_command_buffer.hh @@ -51,6 +51,7 @@ class VKCommandBuffer : NonCopyable, NonMovable { void pipeline_barrier(VkPipelineStageFlags source_stages, VkPipelineStageFlags destination_stages); void pipeline_barrier(Span image_memory_barriers); + void fill(VKBuffer &buffer, uint32_t data); /** * Stop recording commands, encode + send the recordings to Vulkan, wait for the until the diff --git a/source/blender/gpu/vulkan/vk_storage_buffer.cc b/source/blender/gpu/vulkan/vk_storage_buffer.cc index 8b5545f223f..5f4e75ebce3 100644 --- a/source/blender/gpu/vulkan/vk_storage_buffer.cc +++ b/source/blender/gpu/vulkan/vk_storage_buffer.cc @@ -10,6 +10,8 @@ #include "vk_storage_buffer.hh" +#include "BLI_span.hh" + namespace blender::gpu { void VKStorageBuffer::update(const void *data) @@ -23,7 +25,11 @@ void VKStorageBuffer::update(const void *data) void VKStorageBuffer::allocate(VKContext &context) { - buffer_.create(context, size_in_bytes_, usage_, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); + buffer_.create(context, + size_in_bytes_, + usage_, + static_cast(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | + VK_BUFFER_USAGE_TRANSFER_DST_BIT)); } void VKStorageBuffer::bind(int slot) @@ -43,11 +49,51 @@ void VKStorageBuffer::unbind() { } -void VKStorageBuffer::clear(eGPUTextureFormat /*internal_format*/, - eGPUDataFormat /*data_format*/, - void * /*data*/) +static bool is_uniform(Span data) { + BLI_assert(!data.is_empty()); + uint32_t expected_value = data[0]; + for (uint32_t value : data) { + if (value != expected_value) { + return false; + } + } + return true; } + +static bool can_use_fill_command(eGPUTextureFormat internal_format, + eGPUDataFormat /*data_format*/, + void *data) +{ + int element_size = to_bytesize(internal_format); + int num_components = element_size / 8; + if (is_uniform(Span(static_cast(data), num_components))) { + return true; + } + return false; +} + +void VKStorageBuffer::clear(eGPUTextureFormat internal_format, + eGPUDataFormat data_format, + void *data) +{ + VKContext &context = *VKContext::get(); + if (!buffer_.is_allocated()) { + allocate(context); + } + + VKCommandBuffer &command_buffer = context.command_buffer_get(); + if (can_use_fill_command(internal_format, data_format, data)) { + /* When the data format is 4 bytes we can use vkCmdFillBuffer. + * Common case when using GPU_storagebuf_clear_to_zero. */ + command_buffer.fill(buffer_, *static_cast(data)); + return; + } + + /* TODO: Use a compute shader to clear the buffer. */ + BLI_assert_unreachable(); +} + void VKStorageBuffer::copy_sub(VertBuf * /*src*/, uint /*dst_offset*/, uint /*src_offset*/, -- 2.30.2 From 0632abc9f30ab9737cd5dcfabc587e266cc56a59 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Tue, 28 Feb 2023 15:22:34 +0100 Subject: [PATCH 55/66] Fix test case. when only a single command is used. --- source/blender/gpu/tests/gpu_storage_buffer_test.cc | 1 - source/blender/gpu/vulkan/vk_storage_buffer.cc | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/source/blender/gpu/tests/gpu_storage_buffer_test.cc b/source/blender/gpu/tests/gpu_storage_buffer_test.cc index e3d6e0660cd..07ccae97bc3 100644 --- a/source/blender/gpu/tests/gpu_storage_buffer_test.cc +++ b/source/blender/gpu/tests/gpu_storage_buffer_test.cc @@ -74,7 +74,6 @@ static void test_storage_buffer_clear_zero() GPU_TEST(storage_buffer_clear_zero); -/* TODO: Make template.*/ template static void storage_buffer_clear_uniform() { GPUStorageBuf *ssbo = GPU_storagebuf_create_ex( diff --git a/source/blender/gpu/vulkan/vk_storage_buffer.cc b/source/blender/gpu/vulkan/vk_storage_buffer.cc index 5f4e75ebce3..e1cb0887828 100644 --- a/source/blender/gpu/vulkan/vk_storage_buffer.cc +++ b/source/blender/gpu/vulkan/vk_storage_buffer.cc @@ -66,7 +66,7 @@ static bool can_use_fill_command(eGPUTextureFormat internal_format, void *data) { int element_size = to_bytesize(internal_format); - int num_components = element_size / 8; + int num_components = element_size / 4; if (is_uniform(Span(static_cast(data), num_components))) { return true; } -- 2.30.2 From 8957c56f62fdd5150ff5350f99f340f4a9ddf7e9 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Wed, 1 Mar 2023 10:21:28 +0100 Subject: [PATCH 56/66] Moved clearing to VKBuffer. --- source/blender/gpu/vulkan/vk_buffer.cc | 43 +++++++++++++++++++ source/blender/gpu/vulkan/vk_buffer.hh | 4 ++ .../blender/gpu/vulkan/vk_storage_buffer.cc | 38 +--------------- 3 files changed, 48 insertions(+), 37 deletions(-) diff --git a/source/blender/gpu/vulkan/vk_buffer.cc b/source/blender/gpu/vulkan/vk_buffer.cc index f882783041d..8a6b452eef2 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 "BLI_span.hh" namespace blender::gpu { @@ -75,6 +76,7 @@ bool VKBuffer::create(VKContext &context, bool VKBuffer::update(VKContext &context, const void *data) { + /* TODO: When size <64Kb we should use vkCmdUpdateBuffer. */ void *mapped_memory; bool result = map(context, &mapped_memory); if (result) { @@ -84,6 +86,47 @@ bool VKBuffer::update(VKContext &context, const void *data) return result; } +static bool is_uniform(Span data) +{ + BLI_assert(!data.is_empty()); + uint32_t expected_value = data[0]; + for (uint32_t value : data) { + if (value != expected_value) { + return false; + } + } + return true; +} + +static bool can_use_fill_command(eGPUTextureFormat internal_format, + eGPUDataFormat data_format, + void *data) +{ + /* TODO: See `validate_data_format` what we should support. */ + BLI_assert(ELEM(data_format, GPU_DATA_INT, GPU_DATA_UINT, GPU_DATA_FLOAT)); + UNUSED_VARS_NDEBUG(data_format); + const uint32_t element_size = to_bytesize(internal_format); + const uint32_t num_components = element_size / sizeof(uint32_t); + return is_uniform(Span(static_cast(data), num_components)); +} + +void VKBuffer::clear(VKContext &context, + eGPUTextureFormat internal_format, + eGPUDataFormat data_format, + void *data) +{ + VKCommandBuffer &command_buffer = context.command_buffer_get(); + if (can_use_fill_command(internal_format, data_format, data)) { + command_buffer.fill(*this, *static_cast(data)); + return; + } + + /* TODO: Use a compute shader to clear the buffer. This is performance wise not recommended, and + * should be avoided. There are some cases where we don't have a choice. Especially when using + * compute shaders.*/ + BLI_assert_unreachable(); +} + bool VKBuffer::map(VKContext &context, void **r_mapped_memory) const { VmaAllocator allocator = context.mem_allocator_get(); diff --git a/source/blender/gpu/vulkan/vk_buffer.hh b/source/blender/gpu/vulkan/vk_buffer.hh index 23a8c18aa39..0e4a4b2bca6 100644 --- a/source/blender/gpu/vulkan/vk_buffer.hh +++ b/source/blender/gpu/vulkan/vk_buffer.hh @@ -34,6 +34,10 @@ class VKBuffer { GPUUsageType usage, VkBufferUsageFlagBits buffer_usage); bool update(VKContext &context, const void *data); + void clear(VKContext &context, + eGPUTextureFormat internal_format, + eGPUDataFormat data_format, + void *data); 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_storage_buffer.cc b/source/blender/gpu/vulkan/vk_storage_buffer.cc index e1cb0887828..02627a9c002 100644 --- a/source/blender/gpu/vulkan/vk_storage_buffer.cc +++ b/source/blender/gpu/vulkan/vk_storage_buffer.cc @@ -10,8 +10,6 @@ #include "vk_storage_buffer.hh" -#include "BLI_span.hh" - namespace blender::gpu { void VKStorageBuffer::update(const void *data) @@ -49,30 +47,6 @@ void VKStorageBuffer::unbind() { } -static bool is_uniform(Span data) -{ - BLI_assert(!data.is_empty()); - uint32_t expected_value = data[0]; - for (uint32_t value : data) { - if (value != expected_value) { - return false; - } - } - return true; -} - -static bool can_use_fill_command(eGPUTextureFormat internal_format, - eGPUDataFormat /*data_format*/, - void *data) -{ - int element_size = to_bytesize(internal_format); - int num_components = element_size / 4; - if (is_uniform(Span(static_cast(data), num_components))) { - return true; - } - return false; -} - void VKStorageBuffer::clear(eGPUTextureFormat internal_format, eGPUDataFormat data_format, void *data) @@ -81,17 +55,7 @@ void VKStorageBuffer::clear(eGPUTextureFormat internal_format, if (!buffer_.is_allocated()) { allocate(context); } - - VKCommandBuffer &command_buffer = context.command_buffer_get(); - if (can_use_fill_command(internal_format, data_format, data)) { - /* When the data format is 4 bytes we can use vkCmdFillBuffer. - * Common case when using GPU_storagebuf_clear_to_zero. */ - command_buffer.fill(buffer_, *static_cast(data)); - return; - } - - /* TODO: Use a compute shader to clear the buffer. */ - BLI_assert_unreachable(); + buffer_.clear(context, internal_format, data_format, data); } void VKStorageBuffer::copy_sub(VertBuf * /*src*/, -- 2.30.2 From 96af333650c19248778e16087f92971e74c75ddd Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Tue, 7 Mar 2023 08:51:47 +0100 Subject: [PATCH 57/66] GPU: Refactor API for Clearing Storage Buffers. The previous API for clearing storage buffers was extracted from OpenGL. OpenGL has many options to support for data conversions, striding and sizzling. Metal and Vulkan don't have this inside the API and we have to deal it ourselves. Blender internally only uses a tiny subset for what is possible in OpenGL. making the current API to difficult to implement on our future platforms as we had to implement all cases, most even not used at all. By changing the API we make future development easier as we only need to implement what we are actually using. *New API* `GPU_storagebuf_clear_int(GPUStorageBuf* ssbo, int32_t* clear_data, uint8_t clear_data_len);` `GPU_storagebuf_clear_uint(GPUStorageBuf* ssbo, uint32_t* clear_data, uint8_t clear_data_len);` Related issue: #105492 --- .../engines/eevee_next/eevee_motion_blur.cc | 2 +- .../draw/engines/eevee_next/eevee_shadow.cc | 10 +++--- .../engines/workbench/workbench_shadow.cc | 6 ++-- source/blender/draw/intern/draw_view.cc | 2 +- source/blender/gpu/GPU_storage_buffer.h | 20 ++++++++--- .../blender/gpu/intern/gpu_storage_buffer.cc | 22 +++++++----- .../gpu/intern/gpu_storage_buffer_private.hh | 5 ++- .../blender/gpu/opengl/gl_storage_buffer.cc | 34 +++++++++++++------ .../blender/gpu/opengl/gl_storage_buffer.hh | 2 +- .../blender/gpu/vulkan/vk_storage_buffer.cc | 5 ++- .../blender/gpu/vulkan/vk_storage_buffer.hh | 2 +- 11 files changed, 68 insertions(+), 42 deletions(-) diff --git a/source/blender/draw/engines/eevee_next/eevee_motion_blur.cc b/source/blender/draw/engines/eevee_next/eevee_motion_blur.cc index d6fc74730b2..4316e78f77d 100644 --- a/source/blender/draw/engines/eevee_next/eevee_motion_blur.cc +++ b/source/blender/draw/engines/eevee_next/eevee_motion_blur.cc @@ -233,7 +233,7 @@ void MotionBlurModule::render(View &view, GPUTexture **input_tx, GPUTexture **ou tiles_tx_.acquire(tiles_extent, GPU_RGBA16F); - GPU_storagebuf_clear_to_zero(tile_indirection_buf_); + tile_indirection_buf_.clear_to_zero(); inst_.manager->submit(motion_blur_ps_, view); diff --git a/source/blender/draw/engines/eevee_next/eevee_shadow.cc b/source/blender/draw/engines/eevee_next/eevee_shadow.cc index 5b5eec04d9a..46043ad5564 100644 --- a/source/blender/draw/engines/eevee_next/eevee_shadow.cc +++ b/source/blender/draw/engines/eevee_next/eevee_shadow.cc @@ -834,17 +834,17 @@ void ShadowModule::end_sync() /* Clear tile-map clip buffer. */ union { ShadowTileMapClip clip; - int4 i; + uint4 i; } u; u.clip.clip_near_stored = 0.0f; u.clip.clip_far_stored = 0.0f; - u.clip.clip_near = int(0xFF7FFFFFu ^ 0x7FFFFFFFu); /* floatBitsToOrderedInt(-FLT_MAX) */ - u.clip.clip_far = 0x7F7FFFFF; /* floatBitsToOrderedInt(FLT_MAX) */ - GPU_storagebuf_clear(tilemap_pool.tilemaps_clip, GPU_RGBA32I, GPU_DATA_INT, &u.i); + u.clip.clip_near = 0xFF7FFFFFu ^ 0x7FFFFFFFu; /* floatBitsToOrderedInt(-FLT_MAX) */ + u.clip.clip_far = 0x7F7FFFFF; /* floatBitsToOrderedInt(FLT_MAX) */ + GPU_storagebuf_clear_uint(tilemap_pool.tilemaps_clip, u.i, 4); /* Clear cached page buffer. */ int2 data = {-1, -1}; - GPU_storagebuf_clear(pages_cached_data_, GPU_RG32I, GPU_DATA_INT, &data); + GPU_storagebuf_clear_int(pages_cached_data_, data, 2); /* Reset info to match new state. */ pages_infos_data_.page_free_count = shadow_page_len_; diff --git a/source/blender/draw/engines/workbench/workbench_shadow.cc b/source/blender/draw/engines/workbench/workbench_shadow.cc index ff50fd3732c..a2a2f4c6fd0 100644 --- a/source/blender/draw/engines/workbench/workbench_shadow.cc +++ b/source/blender/draw/engines/workbench/workbench_shadow.cc @@ -225,9 +225,9 @@ void ShadowPass::ShadowView::compute_visibility(ObjectBoundsBuf &bounds, if (current_pass_type_ == ShadowPass::PASS) { /* TODO(fclem): Resize to nearest pow2 to reduce fragmentation. */ pass_visibility_buf_.resize(words_len); - GPU_storagebuf_clear(pass_visibility_buf_, GPU_R32UI, GPU_DATA_UINT, &data); + GPU_storagebuf_clear_uint(pass_visibility_buf_, &data, 1); fail_visibility_buf_.resize(words_len); - GPU_storagebuf_clear(fail_visibility_buf_, GPU_R32UI, GPU_DATA_UINT, &data); + GPU_storagebuf_clear_uint(fail_visibility_buf_, &data, 1); } else if (current_pass_type_ == ShadowPass::FAIL) { /* Already computed in the ShadowPass::PASS */ @@ -236,7 +236,7 @@ void ShadowPass::ShadowView::compute_visibility(ObjectBoundsBuf &bounds, } else { visibility_buf_.resize(words_len); - GPU_storagebuf_clear(visibility_buf_, GPU_R32UI, GPU_DATA_UINT, &data); + GPU_storagebuf_clear_uint(visibility_buf_, &data, 1); } if (do_visibility_) { diff --git a/source/blender/draw/intern/draw_view.cc b/source/blender/draw/intern/draw_view.cc index 46fd82a239e..2fd2b0a07eb 100644 --- a/source/blender/draw/intern/draw_view.cc +++ b/source/blender/draw/intern/draw_view.cc @@ -281,7 +281,7 @@ void View::compute_visibility(ObjectBoundsBuf &bounds, uint resource_len, bool d visibility_buf_.resize(words_len); uint32_t data = 0xFFFFFFFFu; - GPU_storagebuf_clear(visibility_buf_, GPU_R32UI, GPU_DATA_UINT, &data); + GPU_storagebuf_clear_uint(visibility_buf_, &data, 1); if (do_visibility_) { GPUShader *shader = DRW_shader_draw_visibility_compute_get(); diff --git a/source/blender/gpu/GPU_storage_buffer.h b/source/blender/gpu/GPU_storage_buffer.h index 8ed60d9000a..4ca55ffda56 100644 --- a/source/blender/gpu/GPU_storage_buffer.h +++ b/source/blender/gpu/GPU_storage_buffer.h @@ -39,12 +39,24 @@ void GPU_storagebuf_bind(GPUStorageBuf *ssbo, int slot); void GPU_storagebuf_unbind(GPUStorageBuf *ssbo); void GPU_storagebuf_unbind_all(void); -void GPU_storagebuf_clear(GPUStorageBuf *ssbo, - eGPUTextureFormat internal_format, - eGPUDataFormat data_format, - void *data); void GPU_storagebuf_clear_to_zero(GPUStorageBuf *ssbo); +/** + * Clear the content of the buffer using the given #clear_data. #clear_data will be used as a + * repeatable pattern. + * + * NOTE: clear_data_len must be in range 1 to 4 (inclusive). + */ +void GPU_storagebuf_clear_uint(GPUStorageBuf *ssbo, uint32_t *clear_data, uint8_t clear_data_len); + +/** + * Clear the content of the buffer using the given #clear_data. #clear_data will be used as a + * repeatable pattern. + * + * NOTE: clear_data_len must be in range 1 to 4 (inclusive). + */ +void GPU_storagebuf_clear_int(GPUStorageBuf *ssbo, int32_t *clear_data, uint8_t clear_data_len); + /** * Read back content of the buffer to CPU for inspection. * Slow! Only use for inspection / debugging. diff --git a/source/blender/gpu/intern/gpu_storage_buffer.cc b/source/blender/gpu/intern/gpu_storage_buffer.cc index 460a643089c..3854f087e78 100644 --- a/source/blender/gpu/intern/gpu_storage_buffer.cc +++ b/source/blender/gpu/intern/gpu_storage_buffer.cc @@ -89,18 +89,22 @@ void GPU_storagebuf_unbind_all() /* FIXME */ } -void GPU_storagebuf_clear(GPUStorageBuf *ssbo, - eGPUTextureFormat internal_format, - eGPUDataFormat data_format, - void *data) -{ - unwrap(ssbo)->clear(internal_format, data_format, data); -} - void GPU_storagebuf_clear_to_zero(GPUStorageBuf *ssbo) { uint32_t data = 0u; - GPU_storagebuf_clear(ssbo, GPU_R32UI, GPU_DATA_UINT, &data); + GPU_storagebuf_clear_uint(ssbo, &data, 1); +} + +void GPU_storagebuf_clear_int(GPUStorageBuf *ssbo, int32_t *clear_data, uint8_t clear_data_len) +{ + uint32_t *clear_data_uint = static_cast(static_cast(clear_data)); + GPU_storagebuf_clear_uint(ssbo, clear_data_uint, clear_data_len); +} + +void GPU_storagebuf_clear_uint(GPUStorageBuf *ssbo, uint32_t *clear_data, uint8_t clear_data_len) +{ + BLI_assert(clear_data_len >= 1 && clear_data_len <= 4); + unwrap(ssbo)->clear(blender::Span(clear_data, clear_data_len)); } void GPU_storagebuf_copy_sub_from_vertbuf( diff --git a/source/blender/gpu/intern/gpu_storage_buffer_private.hh b/source/blender/gpu/intern/gpu_storage_buffer_private.hh index c05d8dc5b98..b1f1415f45d 100644 --- a/source/blender/gpu/intern/gpu_storage_buffer_private.hh +++ b/source/blender/gpu/intern/gpu_storage_buffer_private.hh @@ -7,6 +7,7 @@ #pragma once +#include "BLI_span.hh" #include "BLI_sys_types.h" struct GPUStorageBuf; @@ -42,9 +43,7 @@ class StorageBuf { virtual void update(const void *data) = 0; virtual void bind(int slot) = 0; virtual void unbind() = 0; - virtual void clear(eGPUTextureFormat internal_format, - eGPUDataFormat data_format, - void *data) = 0; + virtual void clear(Span data) = 0; virtual void copy_sub(VertBuf *src, uint dst_offset, uint src_offset, uint copy_size) = 0; virtual void read(void *data) = 0; }; diff --git a/source/blender/gpu/opengl/gl_storage_buffer.cc b/source/blender/gpu/opengl/gl_storage_buffer.cc index 5d876308b3c..4431b855971 100644 --- a/source/blender/gpu/opengl/gl_storage_buffer.cc +++ b/source/blender/gpu/opengl/gl_storage_buffer.cc @@ -117,27 +117,39 @@ void GLStorageBuf::unbind() slot_ = 0; } -void GLStorageBuf::clear(eGPUTextureFormat internal_format, eGPUDataFormat data_format, void *data) +void GLStorageBuf::clear(Span data) { if (ssbo_id_ == 0) { this->init(); } + GLenum internal_format = GL_R32UI; + GLenum format = GL_RED; + if (data.size() == 1) { + internal_format = GL_R32UI; + format = GL_RED; + } + else if (data.size() == 2) { + internal_format = GL_RG32UI; + format = GL_RG; + } + else if (data.size() == 3) { + internal_format = GL_RGB32UI; + format = GL_RGB; + } + else if (data.size() == 4) { + internal_format = GL_RGBA32UI; + format = GL_RGBA; + } + if (GLContext::direct_state_access_support) { - glClearNamedBufferData(ssbo_id_, - to_gl_internal_format(internal_format), - to_gl_data_format(internal_format), - to_gl(data_format), - data); + glClearNamedBufferData(ssbo_id_, internal_format, format, GL_UNSIGNED_INT, data.data()); } else { /* WATCH(@fclem): This should be ok since we only use clear outside of drawing functions. */ glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo_id_); - glClearBufferData(GL_SHADER_STORAGE_BUFFER, - to_gl_internal_format(internal_format), - to_gl_data_format(internal_format), - to_gl(data_format), - data); + glClearBufferData( + GL_SHADER_STORAGE_BUFFER, internal_format, format, GL_UNSIGNED_INT, data.data()); glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); } } diff --git a/source/blender/gpu/opengl/gl_storage_buffer.hh b/source/blender/gpu/opengl/gl_storage_buffer.hh index 680ce911bc7..08517997cfd 100644 --- a/source/blender/gpu/opengl/gl_storage_buffer.hh +++ b/source/blender/gpu/opengl/gl_storage_buffer.hh @@ -33,7 +33,7 @@ class GLStorageBuf : public StorageBuf { void update(const void *data) override; void bind(int slot) override; void unbind() override; - void clear(eGPUTextureFormat internal_format, eGPUDataFormat data_format, void *data) override; + void clear(Span data) override; void copy_sub(VertBuf *src, uint dst_offset, uint src_offset, uint copy_size) override; void read(void *data) override; diff --git a/source/blender/gpu/vulkan/vk_storage_buffer.cc b/source/blender/gpu/vulkan/vk_storage_buffer.cc index 8b5545f223f..27f35cc593c 100644 --- a/source/blender/gpu/vulkan/vk_storage_buffer.cc +++ b/source/blender/gpu/vulkan/vk_storage_buffer.cc @@ -43,11 +43,10 @@ void VKStorageBuffer::unbind() { } -void VKStorageBuffer::clear(eGPUTextureFormat /*internal_format*/, - eGPUDataFormat /*data_format*/, - void * /*data*/) +void VKStorageBuffer::clear(Span /*data*/) { } + void VKStorageBuffer::copy_sub(VertBuf * /*src*/, uint /*dst_offset*/, uint /*src_offset*/, diff --git a/source/blender/gpu/vulkan/vk_storage_buffer.hh b/source/blender/gpu/vulkan/vk_storage_buffer.hh index a9ee1a6256b..4e01d7b42e6 100644 --- a/source/blender/gpu/vulkan/vk_storage_buffer.hh +++ b/source/blender/gpu/vulkan/vk_storage_buffer.hh @@ -30,7 +30,7 @@ class VKStorageBuffer : public StorageBuf { void update(const void *data) override; void bind(int slot) override; void unbind() override; - void clear(eGPUTextureFormat internal_format, eGPUDataFormat data_format, void *data) override; + void clear(Span data) override; void copy_sub(VertBuf *src, uint dst_offset, uint src_offset, uint copy_size) override; void read(void *data) override; -- 2.30.2 From 57004af96eacb90b90dbc69fa3e853479c4b6c31 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Tue, 7 Mar 2023 14:38:58 +0100 Subject: [PATCH 58/66] Revert cleanup change. --- source/blender/draw/engines/eevee_next/eevee_motion_blur.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/draw/engines/eevee_next/eevee_motion_blur.cc b/source/blender/draw/engines/eevee_next/eevee_motion_blur.cc index 4316e78f77d..d6fc74730b2 100644 --- a/source/blender/draw/engines/eevee_next/eevee_motion_blur.cc +++ b/source/blender/draw/engines/eevee_next/eevee_motion_blur.cc @@ -233,7 +233,7 @@ void MotionBlurModule::render(View &view, GPUTexture **input_tx, GPUTexture **ou tiles_tx_.acquire(tiles_extent, GPU_RGBA16F); - tile_indirection_buf_.clear_to_zero(); + GPU_storagebuf_clear_to_zero(tile_indirection_buf_); inst_.manager->submit(motion_blur_ps_, view); -- 2.30.2 From 04aa6f381e43f6208428b5587dfa70f83c6cb0c9 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Tue, 7 Mar 2023 14:45:07 +0100 Subject: [PATCH 59/66] Revert partial change in eevee-next shadows. --- source/blender/draw/engines/eevee_next/eevee_shadow.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/blender/draw/engines/eevee_next/eevee_shadow.cc b/source/blender/draw/engines/eevee_next/eevee_shadow.cc index 46043ad5564..0608c32a29e 100644 --- a/source/blender/draw/engines/eevee_next/eevee_shadow.cc +++ b/source/blender/draw/engines/eevee_next/eevee_shadow.cc @@ -834,13 +834,13 @@ void ShadowModule::end_sync() /* Clear tile-map clip buffer. */ union { ShadowTileMapClip clip; - uint4 i; + int4 i; } u; u.clip.clip_near_stored = 0.0f; u.clip.clip_far_stored = 0.0f; - u.clip.clip_near = 0xFF7FFFFFu ^ 0x7FFFFFFFu; /* floatBitsToOrderedInt(-FLT_MAX) */ - u.clip.clip_far = 0x7F7FFFFF; /* floatBitsToOrderedInt(FLT_MAX) */ - GPU_storagebuf_clear_uint(tilemap_pool.tilemaps_clip, u.i, 4); + u.clip.clip_near = int(0xFF7FFFFFu ^ 0x7FFFFFFFu); /* floatBitsToOrderedInt(-FLT_MAX) */ + u.clip.clip_far = 0x7F7FFFFF; /* floatBitsToOrderedInt(FLT_MAX) */ + GPU_storagebuf_clear_int(tilemap_pool.tilemaps_clip, u.i, 4); /* Clear cached page buffer. */ int2 data = {-1, -1}; -- 2.30.2 From 1967026b22b704bca7084da6fde5b360c0dcb7a0 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Tue, 7 Mar 2023 15:01:10 +0100 Subject: [PATCH 60/66] Fix Shadow rendering in Eevee-next/Workbench-next. Used the integer gl formats and not the float ones. --- source/blender/gpu/opengl/gl_storage_buffer.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/blender/gpu/opengl/gl_storage_buffer.cc b/source/blender/gpu/opengl/gl_storage_buffer.cc index 4431b855971..041a41a17c1 100644 --- a/source/blender/gpu/opengl/gl_storage_buffer.cc +++ b/source/blender/gpu/opengl/gl_storage_buffer.cc @@ -127,19 +127,19 @@ void GLStorageBuf::clear(Span data) GLenum format = GL_RED; if (data.size() == 1) { internal_format = GL_R32UI; - format = GL_RED; + format = GL_RED_INTEGER; } else if (data.size() == 2) { internal_format = GL_RG32UI; - format = GL_RG; + format = GL_RG_INTEGER; } else if (data.size() == 3) { internal_format = GL_RGB32UI; - format = GL_RGB; + format = GL_RGB_INTEGER; } else if (data.size() == 4) { internal_format = GL_RGBA32UI; - format = GL_RGBA; + format = GL_RGBA_INTEGER; } if (GLContext::direct_state_access_support) { -- 2.30.2 From 83b62f256274c3c6dd3e049bf047fc3adb2c9038 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Tue, 7 Mar 2023 15:27:12 +0100 Subject: [PATCH 61/66] Resolve review comments. - Make clear_data_size an int. - Use GL_RED_INTEGER when initializing variable. --- source/blender/gpu/GPU_storage_buffer.h | 4 ++-- source/blender/gpu/intern/gpu_storage_buffer.cc | 4 ++-- source/blender/gpu/opengl/gl_storage_buffer.cc | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/source/blender/gpu/GPU_storage_buffer.h b/source/blender/gpu/GPU_storage_buffer.h index 4ca55ffda56..187c8e24f18 100644 --- a/source/blender/gpu/GPU_storage_buffer.h +++ b/source/blender/gpu/GPU_storage_buffer.h @@ -47,7 +47,7 @@ void GPU_storagebuf_clear_to_zero(GPUStorageBuf *ssbo); * * NOTE: clear_data_len must be in range 1 to 4 (inclusive). */ -void GPU_storagebuf_clear_uint(GPUStorageBuf *ssbo, uint32_t *clear_data, uint8_t clear_data_len); +void GPU_storagebuf_clear_uint(GPUStorageBuf *ssbo, uint32_t *clear_data, int clear_data_len); /** * Clear the content of the buffer using the given #clear_data. #clear_data will be used as a @@ -55,7 +55,7 @@ void GPU_storagebuf_clear_uint(GPUStorageBuf *ssbo, uint32_t *clear_data, uint8_ * * NOTE: clear_data_len must be in range 1 to 4 (inclusive). */ -void GPU_storagebuf_clear_int(GPUStorageBuf *ssbo, int32_t *clear_data, uint8_t clear_data_len); +void GPU_storagebuf_clear_int(GPUStorageBuf *ssbo, int32_t *clear_data, int clear_data_len); /** * Read back content of the buffer to CPU for inspection. diff --git a/source/blender/gpu/intern/gpu_storage_buffer.cc b/source/blender/gpu/intern/gpu_storage_buffer.cc index 3854f087e78..9a006aecea9 100644 --- a/source/blender/gpu/intern/gpu_storage_buffer.cc +++ b/source/blender/gpu/intern/gpu_storage_buffer.cc @@ -95,13 +95,13 @@ void GPU_storagebuf_clear_to_zero(GPUStorageBuf *ssbo) GPU_storagebuf_clear_uint(ssbo, &data, 1); } -void GPU_storagebuf_clear_int(GPUStorageBuf *ssbo, int32_t *clear_data, uint8_t clear_data_len) +void GPU_storagebuf_clear_int(GPUStorageBuf *ssbo, int32_t *clear_data, int clear_data_len) { uint32_t *clear_data_uint = static_cast(static_cast(clear_data)); GPU_storagebuf_clear_uint(ssbo, clear_data_uint, clear_data_len); } -void GPU_storagebuf_clear_uint(GPUStorageBuf *ssbo, uint32_t *clear_data, uint8_t clear_data_len) +void GPU_storagebuf_clear_uint(GPUStorageBuf *ssbo, uint32_t *clear_data, int clear_data_len) { BLI_assert(clear_data_len >= 1 && clear_data_len <= 4); unwrap(ssbo)->clear(blender::Span(clear_data, clear_data_len)); diff --git a/source/blender/gpu/opengl/gl_storage_buffer.cc b/source/blender/gpu/opengl/gl_storage_buffer.cc index 041a41a17c1..a1fa5713339 100644 --- a/source/blender/gpu/opengl/gl_storage_buffer.cc +++ b/source/blender/gpu/opengl/gl_storage_buffer.cc @@ -124,7 +124,7 @@ void GLStorageBuf::clear(Span data) } GLenum internal_format = GL_R32UI; - GLenum format = GL_RED; + GLenum format = GL_RED_INTEGER; if (data.size() == 1) { internal_format = GL_R32UI; format = GL_RED_INTEGER; -- 2.30.2 From 3739fc7aeade7fd2f2464a272411cd056c9e9a5c Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Wed, 8 Mar 2023 10:40:59 +0100 Subject: [PATCH 62/66] Eevee-next: Use Compute Shader to Clear Clipmaps. Clearing of clipmaps is the only place in Blender that uses non uniform data (not all components of the cleared data to be exact the same). Vulkan has only the possibility to clear buffers with using a single uint32_t. There were two solutions: - Add compute shader to Vulkan backend. - Make Eevee-next responsible to clear the clipmaps. When fixing this in the Vulkan backend it could lead to other issues as the backend isn't aware what is exactly required and might overwrite active bindings. We chose to make it a responsibility of Eevee-next as there it is clear what is needed. Related issue: #105492 --- source/blender/draw/CMakeLists.txt | 1 + .../draw/engines/eevee_next/eevee_defines.hh | 1 + .../draw/engines/eevee_next/eevee_shader.cc | 2 ++ .../draw/engines/eevee_next/eevee_shader.hh | 1 + .../draw/engines/eevee_next/eevee_shadow.cc | 21 +++++++++---------- .../eevee_shadow_clipmap_clear_comp.glsl | 11 ++++++++++ .../shaders/infos/eevee_shadow_info.hh | 7 +++++++ 7 files changed, 33 insertions(+), 11 deletions(-) create mode 100644 source/blender/draw/engines/eevee_next/shaders/eevee_shadow_clipmap_clear_comp.glsl diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 5c4a07a6cb8..be0d5a839ea 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -467,6 +467,7 @@ set(GLSL_SRC engines/eevee_next/shaders/eevee_sampling_lib.glsl engines/eevee_next/shaders/eevee_shadow_debug_frag.glsl engines/eevee_next/shaders/eevee_shadow_lib.glsl + engines/eevee_next/shaders/eevee_shadow_clipmap_clear_comp.glsl engines/eevee_next/shaders/eevee_shadow_page_allocate_comp.glsl engines/eevee_next/shaders/eevee_shadow_page_clear_comp.glsl engines/eevee_next/shaders/eevee_shadow_page_defrag_comp.glsl diff --git a/source/blender/draw/engines/eevee_next/eevee_defines.hh b/source/blender/draw/engines/eevee_next/eevee_defines.hh index 72470ab7060..bc778dc874d 100644 --- a/source/blender/draw/engines/eevee_next/eevee_defines.hh +++ b/source/blender/draw/engines/eevee_next/eevee_defines.hh @@ -54,6 +54,7 @@ #define SHADOW_PAGE_PER_ROW 64 #define SHADOW_ATLAS_SLOT 5 #define SHADOW_BOUNDS_GROUP_SIZE 64 +#define SHADOW_CLIPMAP_GROUP_SIZE 64 #define SHADOW_VIEW_MAX 64 /* Must match DRW_VIEW_MAX. */ /* Ray-tracing. */ diff --git a/source/blender/draw/engines/eevee_next/eevee_shader.cc b/source/blender/draw/engines/eevee_next/eevee_shader.cc index 0207a2574b2..cdf2115c743 100644 --- a/source/blender/draw/engines/eevee_next/eevee_shader.cc +++ b/source/blender/draw/engines/eevee_next/eevee_shader.cc @@ -142,6 +142,8 @@ const char *ShaderModule::static_shader_create_info_name_get(eShaderType shader_ return "eevee_light_culling_tile"; case LIGHT_CULLING_ZBIN: return "eevee_light_culling_zbin"; + case SHADOW_CLIPMAP_CLEAR: + return "eevee_shadow_clipmap_clear"; case SHADOW_DEBUG: return "eevee_shadow_debug"; case SHADOW_PAGE_ALLOCATE: diff --git a/source/blender/draw/engines/eevee_next/eevee_shader.hh b/source/blender/draw/engines/eevee_next/eevee_shader.hh index df689bb2717..d589c55cb50 100644 --- a/source/blender/draw/engines/eevee_next/eevee_shader.hh +++ b/source/blender/draw/engines/eevee_next/eevee_shader.hh @@ -62,6 +62,7 @@ enum eShaderType { MOTION_BLUR_TILE_FLATTEN_RENDER, MOTION_BLUR_TILE_FLATTEN_VIEWPORT, + SHADOW_CLIPMAP_CLEAR, SHADOW_DEBUG, SHADOW_PAGE_ALLOCATE, SHADOW_PAGE_CLEAR, diff --git a/source/blender/draw/engines/eevee_next/eevee_shadow.cc b/source/blender/draw/engines/eevee_next/eevee_shadow.cc index 5b5eec04d9a..6ab0b973965 100644 --- a/source/blender/draw/engines/eevee_next/eevee_shadow.cc +++ b/source/blender/draw/engines/eevee_next/eevee_shadow.cc @@ -831,17 +831,6 @@ void ShadowModule::end_sync() /* Clear tiles to not reference any page. */ tilemap_pool.tiles_data.clear_to_zero(); - /* Clear tile-map clip buffer. */ - union { - ShadowTileMapClip clip; - int4 i; - } u; - u.clip.clip_near_stored = 0.0f; - u.clip.clip_far_stored = 0.0f; - u.clip.clip_near = int(0xFF7FFFFFu ^ 0x7FFFFFFFu); /* floatBitsToOrderedInt(-FLT_MAX) */ - u.clip.clip_far = 0x7F7FFFFF; /* floatBitsToOrderedInt(FLT_MAX) */ - GPU_storagebuf_clear(tilemap_pool.tilemaps_clip, GPU_RGBA32I, GPU_DATA_INT, &u.i); - /* Clear cached page buffer. */ int2 data = {-1, -1}; GPU_storagebuf_clear(pages_cached_data_, GPU_RG32I, GPU_DATA_INT, &data); @@ -863,6 +852,16 @@ void ShadowModule::end_sync() PassSimple &pass = tilemap_setup_ps_; pass.init(); + { + /** Clear tile-map clip buffer. */ + PassSimple::Sub &sub = pass.sub("ClearClipmap"); + sub.shader_set(inst_.shaders.static_shader_get(SHADOW_CLIPMAP_CLEAR)); + sub.bind_ssbo("tilemaps_clip_buf", tilemap_pool.tilemaps_clip); + sub.dispatch(int3( + divide_ceil_u(tilemap_pool.tilemaps_clip.size(), SHADOW_CLIPMAP_GROUP_SIZE), 1, 1)); + sub.barrier(GPU_BARRIER_SHADER_STORAGE); + } + { /** Compute near/far clip distances for directional shadows based on casters bounds. */ PassSimple::Sub &sub = pass.sub("DirectionalBounds"); diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_clipmap_clear_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_clipmap_clear_comp.glsl new file mode 100644 index 00000000000..9fec03f0758 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_clipmap_clear_comp.glsl @@ -0,0 +1,11 @@ + +#pragma BLENDER_REQUIRE(gpu_shader_utildefines_lib.glsl) + +void main() +{ + int index = int(gl_GlobalInvocationID.x); + tilemaps_clip_buf[index].clip_near_stored = 0; + tilemaps_clip_buf[index].clip_far_stored = 0; + tilemaps_clip_buf[index].clip_near = floatBitsToOrderedInt(-FLT_MAX); + tilemaps_clip_buf[index].clip_far = floatBitsToOrderedInt(FLT_MAX); +} \ No newline at end of file diff --git a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_shadow_info.hh b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_shadow_info.hh index 378ec8d10a5..bfddeafdb41 100644 --- a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_shadow_info.hh +++ b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_shadow_info.hh @@ -8,6 +8,13 @@ /** \name Shadow pipeline * \{ */ +GPU_SHADER_CREATE_INFO(eevee_shadow_clipmap_clear) + .do_static_compilation(true) + .local_group_size(SHADOW_CLIPMAP_GROUP_SIZE) + .storage_buf(0, Qualifier::WRITE, "ShadowTileMapClip", "tilemaps_clip_buf[]") + .additional_info("eevee_shared") + .compute_source("eevee_shadow_clipmap_clear_comp.glsl"); + GPU_SHADER_CREATE_INFO(eevee_shadow_tilemap_bounds) .do_static_compilation(true) .local_group_size(SHADOW_BOUNDS_GROUP_SIZE) -- 2.30.2 From dc1392590199a6847edcfb62c8e0c74010b29fbc Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Wed, 8 Mar 2023 14:48:11 +0100 Subject: [PATCH 63/66] Updated API to only support a single 32bit value. --- .../draw/engines/eevee_next/eevee_shadow.cc | 3 +-- .../engines/workbench/workbench_shadow.cc | 8 +++--- source/blender/draw/intern/draw_view.cc | 4 +-- source/blender/gpu/GPU_storage_buffer.h | 16 +++--------- .../blender/gpu/intern/gpu_storage_buffer.cc | 14 +++-------- .../gpu/intern/gpu_storage_buffer_private.hh | 2 +- .../blender/gpu/opengl/gl_storage_buffer.cc | 25 +++---------------- .../blender/gpu/opengl/gl_storage_buffer.hh | 2 +- .../blender/gpu/vulkan/vk_storage_buffer.cc | 2 +- .../blender/gpu/vulkan/vk_storage_buffer.hh | 2 +- 10 files changed, 20 insertions(+), 58 deletions(-) diff --git a/source/blender/draw/engines/eevee_next/eevee_shadow.cc b/source/blender/draw/engines/eevee_next/eevee_shadow.cc index 397e3e3919d..28f0a3fc143 100644 --- a/source/blender/draw/engines/eevee_next/eevee_shadow.cc +++ b/source/blender/draw/engines/eevee_next/eevee_shadow.cc @@ -832,8 +832,7 @@ void ShadowModule::end_sync() tilemap_pool.tiles_data.clear_to_zero(); /* Clear cached page buffer. */ - int2 data = {-1, -1}; - GPU_storagebuf_clear_int(pages_cached_data_, data, 2); + GPU_storagebuf_clear(pages_cached_data_, -1); /* Reset info to match new state. */ pages_infos_data_.page_free_count = shadow_page_len_; diff --git a/source/blender/draw/engines/workbench/workbench_shadow.cc b/source/blender/draw/engines/workbench/workbench_shadow.cc index a2a2f4c6fd0..bf3abdd5b82 100644 --- a/source/blender/draw/engines/workbench/workbench_shadow.cc +++ b/source/blender/draw/engines/workbench/workbench_shadow.cc @@ -220,14 +220,14 @@ void ShadowPass::ShadowView::compute_visibility(ObjectBoundsBuf &bounds, uint words_len = (view_len_ == 1) ? divide_ceil_u(resource_len, 32) : resource_len * word_per_draw; words_len = ceil_to_multiple_u(max_ii(1, words_len), 4); - uint32_t data = 0xFFFFFFFFu; + const uint32_t data = 0xFFFFFFFFu; if (current_pass_type_ == ShadowPass::PASS) { /* TODO(fclem): Resize to nearest pow2 to reduce fragmentation. */ pass_visibility_buf_.resize(words_len); - GPU_storagebuf_clear_uint(pass_visibility_buf_, &data, 1); + GPU_storagebuf_clear(pass_visibility_buf_, data); fail_visibility_buf_.resize(words_len); - GPU_storagebuf_clear_uint(fail_visibility_buf_, &data, 1); + GPU_storagebuf_clear(fail_visibility_buf_, data); } else if (current_pass_type_ == ShadowPass::FAIL) { /* Already computed in the ShadowPass::PASS */ @@ -236,7 +236,7 @@ void ShadowPass::ShadowView::compute_visibility(ObjectBoundsBuf &bounds, } else { visibility_buf_.resize(words_len); - GPU_storagebuf_clear_uint(visibility_buf_, &data, 1); + GPU_storagebuf_clear(visibility_buf_, data); } if (do_visibility_) { diff --git a/source/blender/draw/intern/draw_view.cc b/source/blender/draw/intern/draw_view.cc index 2fd2b0a07eb..30417ff6420 100644 --- a/source/blender/draw/intern/draw_view.cc +++ b/source/blender/draw/intern/draw_view.cc @@ -280,8 +280,8 @@ void View::compute_visibility(ObjectBoundsBuf &bounds, uint resource_len, bool d /* TODO(fclem): Resize to nearest pow2 to reduce fragmentation. */ visibility_buf_.resize(words_len); - uint32_t data = 0xFFFFFFFFu; - GPU_storagebuf_clear_uint(visibility_buf_, &data, 1); + const uint32_t data = 0xFFFFFFFFu; + GPU_storagebuf_clear(visibility_buf_, data); if (do_visibility_) { GPUShader *shader = DRW_shader_draw_visibility_compute_get(); diff --git a/source/blender/gpu/GPU_storage_buffer.h b/source/blender/gpu/GPU_storage_buffer.h index 187c8e24f18..1399353b085 100644 --- a/source/blender/gpu/GPU_storage_buffer.h +++ b/source/blender/gpu/GPU_storage_buffer.h @@ -42,20 +42,10 @@ void GPU_storagebuf_unbind_all(void); void GPU_storagebuf_clear_to_zero(GPUStorageBuf *ssbo); /** - * Clear the content of the buffer using the given #clear_data. #clear_data will be used as a - * repeatable pattern. - * - * NOTE: clear_data_len must be in range 1 to 4 (inclusive). + * Clear the content of the buffer using the given #clear_value. #clear_value will be used as a + * repeatable pattern of 32bits. */ -void GPU_storagebuf_clear_uint(GPUStorageBuf *ssbo, uint32_t *clear_data, int clear_data_len); - -/** - * Clear the content of the buffer using the given #clear_data. #clear_data will be used as a - * repeatable pattern. - * - * NOTE: clear_data_len must be in range 1 to 4 (inclusive). - */ -void GPU_storagebuf_clear_int(GPUStorageBuf *ssbo, int32_t *clear_data, int clear_data_len); +void GPU_storagebuf_clear(GPUStorageBuf *ssbo, uint32_t clear_value); /** * Read back content of the buffer to CPU for inspection. diff --git a/source/blender/gpu/intern/gpu_storage_buffer.cc b/source/blender/gpu/intern/gpu_storage_buffer.cc index 9a006aecea9..d82f6fa6237 100644 --- a/source/blender/gpu/intern/gpu_storage_buffer.cc +++ b/source/blender/gpu/intern/gpu_storage_buffer.cc @@ -91,20 +91,12 @@ void GPU_storagebuf_unbind_all() void GPU_storagebuf_clear_to_zero(GPUStorageBuf *ssbo) { - uint32_t data = 0u; - GPU_storagebuf_clear_uint(ssbo, &data, 1); + GPU_storagebuf_clear(ssbo, 0); } -void GPU_storagebuf_clear_int(GPUStorageBuf *ssbo, int32_t *clear_data, int clear_data_len) +void GPU_storagebuf_clear(GPUStorageBuf *ssbo, uint32_t clear_value) { - uint32_t *clear_data_uint = static_cast(static_cast(clear_data)); - GPU_storagebuf_clear_uint(ssbo, clear_data_uint, clear_data_len); -} - -void GPU_storagebuf_clear_uint(GPUStorageBuf *ssbo, uint32_t *clear_data, int clear_data_len) -{ - BLI_assert(clear_data_len >= 1 && clear_data_len <= 4); - unwrap(ssbo)->clear(blender::Span(clear_data, clear_data_len)); + unwrap(ssbo)->clear(clear_value); } void GPU_storagebuf_copy_sub_from_vertbuf( diff --git a/source/blender/gpu/intern/gpu_storage_buffer_private.hh b/source/blender/gpu/intern/gpu_storage_buffer_private.hh index b1f1415f45d..6f0a97117ef 100644 --- a/source/blender/gpu/intern/gpu_storage_buffer_private.hh +++ b/source/blender/gpu/intern/gpu_storage_buffer_private.hh @@ -43,7 +43,7 @@ class StorageBuf { virtual void update(const void *data) = 0; virtual void bind(int slot) = 0; virtual void unbind() = 0; - virtual void clear(Span data) = 0; + virtual void clear(uint32_t clear_value) = 0; virtual void copy_sub(VertBuf *src, uint dst_offset, uint src_offset, uint copy_size) = 0; virtual void read(void *data) = 0; }; diff --git a/source/blender/gpu/opengl/gl_storage_buffer.cc b/source/blender/gpu/opengl/gl_storage_buffer.cc index a1fa5713339..3ecf115d491 100644 --- a/source/blender/gpu/opengl/gl_storage_buffer.cc +++ b/source/blender/gpu/opengl/gl_storage_buffer.cc @@ -117,39 +117,20 @@ void GLStorageBuf::unbind() slot_ = 0; } -void GLStorageBuf::clear(Span data) +void GLStorageBuf::clear(uint32_t clear_value) { if (ssbo_id_ == 0) { this->init(); } - GLenum internal_format = GL_R32UI; - GLenum format = GL_RED_INTEGER; - if (data.size() == 1) { - internal_format = GL_R32UI; - format = GL_RED_INTEGER; - } - else if (data.size() == 2) { - internal_format = GL_RG32UI; - format = GL_RG_INTEGER; - } - else if (data.size() == 3) { - internal_format = GL_RGB32UI; - format = GL_RGB_INTEGER; - } - else if (data.size() == 4) { - internal_format = GL_RGBA32UI; - format = GL_RGBA_INTEGER; - } - if (GLContext::direct_state_access_support) { - glClearNamedBufferData(ssbo_id_, internal_format, format, GL_UNSIGNED_INT, data.data()); + glClearNamedBufferData(ssbo_id_, GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT, &clear_value); } else { /* WATCH(@fclem): This should be ok since we only use clear outside of drawing functions. */ glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo_id_); glClearBufferData( - GL_SHADER_STORAGE_BUFFER, internal_format, format, GL_UNSIGNED_INT, data.data()); + GL_SHADER_STORAGE_BUFFER, GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT, &clear_value); glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); } } diff --git a/source/blender/gpu/opengl/gl_storage_buffer.hh b/source/blender/gpu/opengl/gl_storage_buffer.hh index 08517997cfd..3932698ea2d 100644 --- a/source/blender/gpu/opengl/gl_storage_buffer.hh +++ b/source/blender/gpu/opengl/gl_storage_buffer.hh @@ -33,7 +33,7 @@ class GLStorageBuf : public StorageBuf { void update(const void *data) override; void bind(int slot) override; void unbind() override; - void clear(Span data) override; + void clear(uint32_t clear_value) override; void copy_sub(VertBuf *src, uint dst_offset, uint src_offset, uint copy_size) override; void read(void *data) override; diff --git a/source/blender/gpu/vulkan/vk_storage_buffer.cc b/source/blender/gpu/vulkan/vk_storage_buffer.cc index 27f35cc593c..c2ef0c6508a 100644 --- a/source/blender/gpu/vulkan/vk_storage_buffer.cc +++ b/source/blender/gpu/vulkan/vk_storage_buffer.cc @@ -43,7 +43,7 @@ void VKStorageBuffer::unbind() { } -void VKStorageBuffer::clear(Span /*data*/) +void VKStorageBuffer::clear(uint32_t /*clear_value*/) { } diff --git a/source/blender/gpu/vulkan/vk_storage_buffer.hh b/source/blender/gpu/vulkan/vk_storage_buffer.hh index 4e01d7b42e6..b35e9d990c3 100644 --- a/source/blender/gpu/vulkan/vk_storage_buffer.hh +++ b/source/blender/gpu/vulkan/vk_storage_buffer.hh @@ -30,7 +30,7 @@ class VKStorageBuffer : public StorageBuf { void update(const void *data) override; void bind(int slot) override; void unbind() override; - void clear(Span data) override; + void clear(uint32_t clear_value) override; void copy_sub(VertBuf *src, uint dst_offset, uint src_offset, uint copy_size) override; void read(void *data) override; -- 2.30.2 From 0bc9e2e661145b7cc420078e54528bcf309e65c5 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Wed, 8 Mar 2023 14:49:32 +0100 Subject: [PATCH 64/66] Fix incorrect parameters in OpenGL storage buffer clear. --- source/blender/gpu/opengl/gl_storage_buffer.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/gpu/opengl/gl_storage_buffer.cc b/source/blender/gpu/opengl/gl_storage_buffer.cc index 3ecf115d491..5ad2ef00bd4 100644 --- a/source/blender/gpu/opengl/gl_storage_buffer.cc +++ b/source/blender/gpu/opengl/gl_storage_buffer.cc @@ -124,13 +124,13 @@ void GLStorageBuf::clear(uint32_t clear_value) } if (GLContext::direct_state_access_support) { - glClearNamedBufferData(ssbo_id_, GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT, &clear_value); + glClearNamedBufferData(ssbo_id_, GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT, &clear_value); } else { /* WATCH(@fclem): This should be ok since we only use clear outside of drawing functions. */ glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo_id_); glClearBufferData( - GL_SHADER_STORAGE_BUFFER, GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT, &clear_value); + GL_SHADER_STORAGE_BUFFER, GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT, &clear_value); glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); } } -- 2.30.2 From 27fab835cf49ce435a4355c032d7aa554510c4a3 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Thu, 9 Mar 2023 07:58:20 +0100 Subject: [PATCH 65/66] Limit to the number of items to clear. --- source/blender/draw/engines/eevee_next/eevee_shadow.cc | 1 + .../shaders/eevee_shadow_clipmap_clear_comp.glsl | 10 ++++++---- .../eevee_next/shaders/infos/eevee_shadow_info.hh | 1 + 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/source/blender/draw/engines/eevee_next/eevee_shadow.cc b/source/blender/draw/engines/eevee_next/eevee_shadow.cc index 6ab0b973965..985c0aef019 100644 --- a/source/blender/draw/engines/eevee_next/eevee_shadow.cc +++ b/source/blender/draw/engines/eevee_next/eevee_shadow.cc @@ -857,6 +857,7 @@ void ShadowModule::end_sync() PassSimple::Sub &sub = pass.sub("ClearClipmap"); sub.shader_set(inst_.shaders.static_shader_get(SHADOW_CLIPMAP_CLEAR)); sub.bind_ssbo("tilemaps_clip_buf", tilemap_pool.tilemaps_clip); + sub.push_constant("tilemaps_clip_buf_len", int(tilemap_pool.tilemaps_clip.size())); sub.dispatch(int3( divide_ceil_u(tilemap_pool.tilemaps_clip.size(), SHADOW_CLIPMAP_GROUP_SIZE), 1, 1)); sub.barrier(GPU_BARRIER_SHADER_STORAGE); diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_clipmap_clear_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_clipmap_clear_comp.glsl index 9fec03f0758..bb807a0a29f 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_clipmap_clear_comp.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_clipmap_clear_comp.glsl @@ -4,8 +4,10 @@ void main() { int index = int(gl_GlobalInvocationID.x); - tilemaps_clip_buf[index].clip_near_stored = 0; - tilemaps_clip_buf[index].clip_far_stored = 0; - tilemaps_clip_buf[index].clip_near = floatBitsToOrderedInt(-FLT_MAX); - tilemaps_clip_buf[index].clip_far = floatBitsToOrderedInt(FLT_MAX); + if (index < tilemaps_clip_buf_len) { + tilemaps_clip_buf[index].clip_near_stored = 0; + tilemaps_clip_buf[index].clip_far_stored = 0; + tilemaps_clip_buf[index].clip_near = floatBitsToOrderedInt(-FLT_MAX); + tilemaps_clip_buf[index].clip_far = floatBitsToOrderedInt(FLT_MAX); + } } \ No newline at end of file diff --git a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_shadow_info.hh b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_shadow_info.hh index bfddeafdb41..ebd76318f72 100644 --- a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_shadow_info.hh +++ b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_shadow_info.hh @@ -12,6 +12,7 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_clipmap_clear) .do_static_compilation(true) .local_group_size(SHADOW_CLIPMAP_GROUP_SIZE) .storage_buf(0, Qualifier::WRITE, "ShadowTileMapClip", "tilemaps_clip_buf[]") + .push_constant(Type::INT, "tilemaps_clip_buf_len") .additional_info("eevee_shared") .compute_source("eevee_shadow_clipmap_clear_comp.glsl"); -- 2.30.2 From e008eacfbecc632de7a324d939f391cf0d9ef0fa Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 17 Mar 2023 13:46:56 +0100 Subject: [PATCH 66/66] Remove unneeded includes. --- source/blender/gpu/tests/storage_buffer_test.cc | 1 - source/blender/gpu/vulkan/vk_buffer.cc | 1 - 2 files changed, 2 deletions(-) diff --git a/source/blender/gpu/tests/storage_buffer_test.cc b/source/blender/gpu/tests/storage_buffer_test.cc index bbf3c3f38d8..3903fade393 100644 --- a/source/blender/gpu/tests/storage_buffer_test.cc +++ b/source/blender/gpu/tests/storage_buffer_test.cc @@ -4,7 +4,6 @@ #include "GPU_storage_buffer.h" -#include "BLI_math_vector_types.hh" #include "BLI_vector.hh" #include "gpu_testing.hh" diff --git a/source/blender/gpu/vulkan/vk_buffer.cc b/source/blender/gpu/vulkan/vk_buffer.cc index b173ab64281..feb5ca9c9a0 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 "BLI_span.hh" namespace blender::gpu { -- 2.30.2