diff --git a/intern/ghost/intern/GHOST_ContextVK.cc b/intern/ghost/intern/GHOST_ContextVK.cc index 7854515af90..84db3abd055 100644 --- a/intern/ghost/intern/GHOST_ContextVK.cc +++ b/intern/ghost/intern/GHOST_ContextVK.cc @@ -710,7 +710,7 @@ static GHOST_TSuccess create_render_pass(VkDevice device, colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + colorAttachment.initialLayout = VK_IMAGE_LAYOUT_GENERAL; colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; VkAttachmentReference colorAttachmentRef = {}; diff --git a/scripts/startup/bl_ui/space_userpref.py b/scripts/startup/bl_ui/space_userpref.py index 00e82f83685..a45a23a566f 100644 --- a/scripts/startup/bl_ui/space_userpref.py +++ b/scripts/startup/bl_ui/space_userpref.py @@ -611,12 +611,6 @@ class USERPREF_PT_system_cycles_devices(SystemPanel, CenterAlignMixIn, Panel): class USERPREF_PT_system_gpu_backend(SystemPanel, CenterAlignMixIn, Panel): bl_label = "GPU Backend" - @classmethod - def poll(cls, _context): - # Only for Apple so far - import sys - return sys.platform == "darwin" - def draw_centered(self, context, layout): import gpu prefs = context.preferences diff --git a/source/blender/draw/engines/image/image_drawing_mode.hh b/source/blender/draw/engines/image/image_drawing_mode.hh index eacf854ac8b..cfb28d500d0 100644 --- a/source/blender/draw/engines/image/image_drawing_mode.hh +++ b/source/blender/draw/engines/image/image_drawing_mode.hh @@ -12,6 +12,8 @@ #include "IMB_imbuf_types.h" +#include "GPU_capabilities.h" + #include "BLI_math_matrix_types.hh" #include "BLI_math_vector_types.hh" @@ -510,7 +512,9 @@ template class ScreenSpaceDrawingMode : public AbstractD offset++; } } - IMB_gpu_clamp_half_float(&extracted_buffer); + if (!GPU_texture_clamp_to_half()) { + IMB_gpu_clamp_half_float(tile_buffer); + } GPU_texture_update_sub(texture, GPU_DATA_FLOAT, @@ -563,7 +567,9 @@ template class ScreenSpaceDrawingMode : public AbstractD } BKE_image_release_ibuf(image, tile_buffer, lock); } - IMB_gpu_clamp_half_float(&texture_buffer); + if (!GPU_texture_clamp_to_half()) { + IMB_gpu_clamp_half_float(&texture_buffer); + } GPU_texture_update(info.texture, GPU_DATA_FLOAT, texture_buffer.float_buffer.data); imb_freerectImbuf_all(&texture_buffer); } diff --git a/source/blender/gpu/GPU_capabilities.h b/source/blender/gpu/GPU_capabilities.h index 7ba6f6c0536..728853edd61 100644 --- a/source/blender/gpu/GPU_capabilities.h +++ b/source/blender/gpu/GPU_capabilities.h @@ -56,6 +56,9 @@ bool GPU_shader_draw_parameters_support(void); bool GPU_mem_stats_supported(void); void GPU_mem_stats_get(int *totalmem, int *freemem); +/* Check if the active GPU backend automatically clamp values to fit in 16F. */ +bool GPU_texture_clamp_to_half(void); + /** * Return support for the active context + window. */ diff --git a/source/blender/gpu/intern/gpu_capabilities.cc b/source/blender/gpu/intern/gpu_capabilities.cc index 6fe3ee21449..b97f7decd2d 100644 --- a/source/blender/gpu/intern/gpu_capabilities.cc +++ b/source/blender/gpu/intern/gpu_capabilities.cc @@ -202,6 +202,11 @@ bool GPU_transform_feedback_support(void) return GCaps.transform_feedback_support; } +bool GPU_texture_clamp_to_half(void) +{ + return GCaps.texture_clamp_to_half; +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/gpu/intern/gpu_capabilities_private.hh b/source/blender/gpu/intern/gpu_capabilities_private.hh index 8134c39871d..b6d5c39ef18 100644 --- a/source/blender/gpu/intern/gpu_capabilities_private.hh +++ b/source/blender/gpu/intern/gpu_capabilities_private.hh @@ -57,6 +57,7 @@ struct GPUCapabilities { bool use_hq_normals_workaround = false; bool clear_viewport_workaround = false; /* Vulkan related workarounds. */ + bool texture_clamp_to_half = false; /* Metal related workarounds. */ /* Minimum per-vertex stride in bytes (For a vertex buffer). */ diff --git a/source/blender/gpu/vulkan/vk_backend.cc b/source/blender/gpu/vulkan/vk_backend.cc index 1712532a1e4..8c0a0f3f4cb 100644 --- a/source/blender/gpu/vulkan/vk_backend.cc +++ b/source/blender/gpu/vulkan/vk_backend.cc @@ -199,6 +199,7 @@ void VKBackend::capabilities_init(VKDevice &device) GCaps.compute_shader_support = true; GCaps.shader_storage_buffer_objects_support = true; GCaps.shader_image_load_store_support = true; + GCaps.texture_clamp_to_half = true; GCaps.max_texture_size = max_ii(limits.maxImageDimension1D, limits.maxImageDimension2D); GCaps.max_texture_3d_size = limits.maxImageDimension3D; diff --git a/source/blender/gpu/vulkan/vk_batch.cc b/source/blender/gpu/vulkan/vk_batch.cc index 2d7e04db72a..d65dcf285f6 100644 --- a/source/blender/gpu/vulkan/vk_batch.cc +++ b/source/blender/gpu/vulkan/vk_batch.cc @@ -11,12 +11,12 @@ #include "vk_context.hh" #include "vk_index_buffer.hh" #include "vk_state_manager.hh" +#include "vk_storage_buffer.hh" #include "vk_vertex_attribute_object.hh" #include "vk_vertex_buffer.hh" namespace blender::gpu { - -void VKBatch::draw(int vertex_first, int vertex_count, int instance_first, int instance_count) +void VKBatch::draw_setup() { /* Currently the pipeline is rebuild on each draw command. Clearing the dirty flag for * consistency with the internals of GPU module. */ @@ -38,26 +38,53 @@ void VKBatch::draw(int vertex_first, int vertex_count, int instance_first, int i if (draw_indexed) { index_buffer->upload_data(); index_buffer->bind(context); - context.command_buffer_get().draw(index_buffer->index_len_get(), - instance_count, - index_buffer->index_start_get(), - vertex_first, - instance_first); } - else { - context.command_buffer_get().draw(vertex_first, vertex_count, instance_first, instance_count); - } - - context.command_buffer_get().submit(); } -void VKBatch::draw_indirect(GPUStorageBuf * /*indirect_buf*/, intptr_t /*offset*/) {} - -void VKBatch::multi_draw_indirect(GPUStorageBuf * /*indirect_buf*/, - int /*count*/, - intptr_t /*offset*/, - intptr_t /*stride*/) +void VKBatch::draw(int vertex_first, int vertex_count, int instance_first, int instance_count) { + draw_setup(); + + VKContext &context = *VKContext::get(); + VKCommandBuffer &command_buffer = context.command_buffer_get(); + VKIndexBuffer *index_buffer = index_buffer_get(); + const bool draw_indexed = index_buffer != nullptr; + if (draw_indexed) { + command_buffer.draw_indexed(index_buffer->index_len_get(), + instance_count, + index_buffer->index_start_get(), + vertex_first, + instance_first); + } + else { + command_buffer.draw(vertex_first, vertex_count, instance_first, instance_count); + } + command_buffer.submit(); +} + +void VKBatch::draw_indirect(GPUStorageBuf *indirect_buf, intptr_t offset) +{ + multi_draw_indirect(indirect_buf, 1, offset, 0); +} + +void VKBatch::multi_draw_indirect(GPUStorageBuf *indirect_buf, + int count, + intptr_t offset, + intptr_t stride) +{ + draw_setup(); + + VKStorageBuffer &indirect_buffer = *unwrap(unwrap(indirect_buf)); + VKContext &context = *VKContext::get(); + const bool draw_indexed = index_buffer_get() != nullptr; + VKCommandBuffer &command_buffer = context.command_buffer_get(); + if (draw_indexed) { + command_buffer.draw_indexed_indirect(indirect_buffer, offset, count, stride); + } + else { + command_buffer.draw_indirect(indirect_buffer, offset, count, stride); + } + command_buffer.submit(); } VKVertexBuffer *VKBatch::vertex_buffer_get(int index) diff --git a/source/blender/gpu/vulkan/vk_batch.hh b/source/blender/gpu/vulkan/vk_batch.hh index bdea6ab9bae..714c0fcf916 100644 --- a/source/blender/gpu/vulkan/vk_batch.hh +++ b/source/blender/gpu/vulkan/vk_batch.hh @@ -26,6 +26,9 @@ class VKBatch : public Batch { VKVertexBuffer *vertex_buffer_get(int index); VKVertexBuffer *instance_buffer_get(int index); VKIndexBuffer *index_buffer_get(); + + private: + void draw_setup(); }; } // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_buffer.cc b/source/blender/gpu/vulkan/vk_buffer.cc index dad8797b712..3f32c69e701 100644 --- a/source/blender/gpu/vulkan/vk_buffer.cc +++ b/source/blender/gpu/vulkan/vk_buffer.cc @@ -131,7 +131,9 @@ void VKBuffer::unmap() BLI_assert(is_mapped()); const VKDevice &device = VKBackend::get().device_get(); VmaAllocator allocator = device.mem_allocator_get(); - vmaUnmapMemory(allocator, allocation_); + if (allocator != VK_NULL_HANDLE) { + vmaUnmapMemory(allocator, allocation_); + } mapped_memory_ = nullptr; } @@ -143,7 +145,9 @@ bool VKBuffer::free() const VKDevice &device = VKBackend::get().device_get(); VmaAllocator allocator = device.mem_allocator_get(); - vmaDestroyBuffer(allocator, vk_buffer_, allocation_); + if (allocator != VK_NULL_HANDLE) { + vmaDestroyBuffer(allocator, vk_buffer_, allocation_); + } return true; } diff --git a/source/blender/gpu/vulkan/vk_command_buffer.cc b/source/blender/gpu/vulkan/vk_command_buffer.cc index 1e5b3898735..0ce6ea6974f 100644 --- a/source/blender/gpu/vulkan/vk_command_buffer.cc +++ b/source/blender/gpu/vulkan/vk_command_buffer.cc @@ -13,6 +13,7 @@ #include "vk_index_buffer.hh" #include "vk_memory.hh" #include "vk_pipeline.hh" +#include "vk_storage_buffer.hh" #include "vk_texture.hh" #include "vk_vertex_buffer.hh" @@ -258,7 +259,7 @@ void VKCommandBuffer::draw(int v_first, int v_count, int i_first, int i_count) state.draw_counts++; } -void VKCommandBuffer::draw( +void VKCommandBuffer::draw_indexed( int index_count, int instance_count, int first_index, int vertex_offset, int first_instance) { validate_framebuffer_exists(); @@ -268,6 +269,28 @@ void VKCommandBuffer::draw( state.draw_counts++; } +void VKCommandBuffer::draw_indirect(const VKStorageBuffer &buffer, + VkDeviceSize offset, + uint32_t draw_count, + uint32_t stride) +{ + validate_framebuffer_exists(); + ensure_active_framebuffer(); + vkCmdDrawIndirect(vk_command_buffer_, buffer.vk_handle(), offset, draw_count, stride); + state.draw_counts++; +} + +void VKCommandBuffer::draw_indexed_indirect(const VKStorageBuffer &buffer, + VkDeviceSize offset, + uint32_t draw_count, + uint32_t stride) +{ + validate_framebuffer_exists(); + ensure_active_framebuffer(); + vkCmdDrawIndexedIndirect(vk_command_buffer_, buffer.vk_handle(), offset, draw_count, stride); + state.draw_counts++; +} + void VKCommandBuffer::pipeline_barrier(VkPipelineStageFlags source_stages, VkPipelineStageFlags destination_stages) { diff --git a/source/blender/gpu/vulkan/vk_command_buffer.hh b/source/blender/gpu/vulkan/vk_command_buffer.hh index e84d6f94f9b..f63425a2ad2 100644 --- a/source/blender/gpu/vulkan/vk_command_buffer.hh +++ b/source/blender/gpu/vulkan/vk_command_buffer.hh @@ -23,6 +23,7 @@ class VKPipeline; class VKPushConstants; class VKTexture; class VKVertexBuffer; +class VKStorageBuffer; /** Command buffer to keep track of the life-time of a command buffer. */ class VKCommandBuffer : NonCopyable, NonMovable { @@ -188,8 +189,16 @@ class VKCommandBuffer : NonCopyable, NonMovable { void fill(VKBuffer &buffer, uint32_t data); void draw(int v_first, int v_count, int i_first, int i_count); - void draw( + void draw_indexed( int index_count, int instance_count, int first_index, int vertex_offset, int first_instance); + void draw_indirect(const VKStorageBuffer &buffer, + VkDeviceSize offset, + uint32_t draw_count, + uint32_t stride); + void draw_indexed_indirect(const VKStorageBuffer &buffer, + VkDeviceSize offset, + uint32_t draw_count, + uint32_t stride); /** * Stop recording commands, encode + send the recordings to Vulkan, wait for the until the diff --git a/source/blender/gpu/vulkan/vk_common.cc b/source/blender/gpu/vulkan/vk_common.cc index 4f85ad2e618..5c22184e862 100644 --- a/source/blender/gpu/vulkan/vk_common.cc +++ b/source/blender/gpu/vulkan/vk_common.cc @@ -58,9 +58,12 @@ VkImageAspectFlagBits to_vk_image_aspect_flag_bits(const eGPUTextureFormat forma case GPU_DEPTH_COMPONENT32F: case GPU_DEPTH_COMPONENT24: case GPU_DEPTH_COMPONENT16: + return VK_IMAGE_ASPECT_DEPTH_BIT; + case GPU_DEPTH32F_STENCIL8: case GPU_DEPTH24_STENCIL8: - return VK_IMAGE_ASPECT_DEPTH_BIT; + return static_cast(VK_IMAGE_ASPECT_DEPTH_BIT | + VK_IMAGE_ASPECT_STENCIL_BIT); /* Texture only formats. */ case GPU_RGB32UI: diff --git a/source/blender/gpu/vulkan/vk_data_conversion.cc b/source/blender/gpu/vulkan/vk_data_conversion.cc index 661b71420b3..3a78eeb955a 100644 --- a/source/blender/gpu/vulkan/vk_data_conversion.cc +++ b/source/blender/gpu/vulkan/vk_data_conversion.cc @@ -243,6 +243,7 @@ static ConversionType type_of_conversion_uint(eGPUTextureFormat device_format) case GPU_RG32UI: case GPU_R32UI: case GPU_DEPTH_COMPONENT24: + case GPU_DEPTH24_STENCIL8: return ConversionType::PASS_THROUGH; case GPU_RGBA16UI: @@ -284,7 +285,6 @@ static ConversionType type_of_conversion_uint(eGPUTextureFormat device_format) case GPU_RGB10_A2: case GPU_RGB10_A2UI: case GPU_R11F_G11F_B10F: - case GPU_DEPTH24_STENCIL8: case GPU_SRGB8_A8: case GPU_RGBA8_SNORM: case GPU_RGBA16_SNORM: diff --git a/source/blender/gpu/vulkan/vk_descriptor_set.hh b/source/blender/gpu/vulkan/vk_descriptor_set.hh index 454c03653ac..abf1404a592 100644 --- a/source/blender/gpu/vulkan/vk_descriptor_set.hh +++ b/source/blender/gpu/vulkan/vk_descriptor_set.hh @@ -169,6 +169,7 @@ class VKDescriptorSetTracker : protected VKResourceTracker { void bind(VKTexture &texture, VKDescriptorSet::Location location, VKSampler &sampler); /* Bind as uniform texel buffer. */ void bind(VKVertexBuffer &vertex_buffer, VKDescriptorSet::Location location); + /** * Some shaders don't need any descriptor sets so we don't need to bind them. * diff --git a/source/blender/gpu/vulkan/vk_framebuffer.cc b/source/blender/gpu/vulkan/vk_framebuffer.cc index 924fcf8875c..9dbbfe2c5b4 100644 --- a/source/blender/gpu/vulkan/vk_framebuffer.cc +++ b/source/blender/gpu/vulkan/vk_framebuffer.cc @@ -470,8 +470,11 @@ void VKFrameBuffer::render_pass_create() render_pass_info.pSubpasses = &subpass; const VKDevice &device = VKBackend::get().device_get(); - vkCreateRenderPass( + VkResult result = vkCreateRenderPass( device.device_get(), &render_pass_info, vk_allocation_callbacks, &vk_render_pass_); + if (result != VK_SUCCESS) { + BLI_assert_unreachable(); + } /* We might want to split frame-buffer and render pass. */ VkFramebufferCreateInfo framebuffer_create_info = {}; @@ -483,8 +486,11 @@ void VKFrameBuffer::render_pass_create() framebuffer_create_info.height = height_; framebuffer_create_info.layers = 1; - vkCreateFramebuffer( + result = vkCreateFramebuffer( device.device_get(), &framebuffer_create_info, vk_allocation_callbacks, &vk_framebuffer_); + if (result != VK_SUCCESS) { + BLI_assert_unreachable(); + } } void VKFrameBuffer::render_pass_free() diff --git a/source/blender/gpu/vulkan/vk_pipeline_state.hh b/source/blender/gpu/vulkan/vk_pipeline_state.hh index 7f891fc4e8a..55d0828a49d 100644 --- a/source/blender/gpu/vulkan/vk_pipeline_state.hh +++ b/source/blender/gpu/vulkan/vk_pipeline_state.hh @@ -16,6 +16,7 @@ namespace blender::gpu { class VKFrameBuffer; class VKPipelineStateManager { + private: GPUState current_; GPUStateMutable current_mutable_; diff --git a/source/blender/gpu/vulkan/vk_storage_buffer.cc b/source/blender/gpu/vulkan/vk_storage_buffer.cc index 0fc95f9b396..85024971d7c 100644 --- a/source/blender/gpu/vulkan/vk_storage_buffer.cc +++ b/source/blender/gpu/vulkan/vk_storage_buffer.cc @@ -32,6 +32,7 @@ void VKStorageBuffer::allocate() void VKStorageBuffer::bind(int slot) { + /* TODO: move Storage buffer bindings to state manager to reuse bindings.*/ VKContext &context = *VKContext::get(); if (!buffer_.is_allocated()) { allocate(); @@ -41,8 +42,9 @@ void VKStorageBuffer::bind(int slot) const std::optional location = shader_interface.descriptor_set_location( shader::ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER, slot); - BLI_assert_msg(location, "Locations to SSBOs should always exist."); - shader->pipeline_get().descriptor_set_get().bind(*this, *location); + if (location) { + shader->pipeline_get().descriptor_set_get().bind(*this, *location); + } } void VKStorageBuffer::unbind() {} diff --git a/source/blender/gpu/vulkan/vk_storage_buffer.hh b/source/blender/gpu/vulkan/vk_storage_buffer.hh index 4e798d00dca..4c92a5efb88 100644 --- a/source/blender/gpu/vulkan/vk_storage_buffer.hh +++ b/source/blender/gpu/vulkan/vk_storage_buffer.hh @@ -49,4 +49,9 @@ class VKStorageBuffer : public StorageBuf { void allocate(); }; +static inline VKStorageBuffer *unwrap(StorageBuf *storage_buffer) +{ + return static_cast(storage_buffer); +} + } // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_vertex_buffer.hh b/source/blender/gpu/vulkan/vk_vertex_buffer.hh index 6660cdedb84..796dd374347 100644 --- a/source/blender/gpu/vulkan/vk_vertex_buffer.hh +++ b/source/blender/gpu/vulkan/vk_vertex_buffer.hh @@ -13,6 +13,7 @@ #include "vk_buffer.hh" namespace blender::gpu { +class VKTexture; class VKVertexBuffer : public VertBuf { VKBuffer buffer_;