diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 8da94d392a9..5891fece198 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -269,6 +269,7 @@ set(VULKAN_SRC vulkan/vk_query.hh vulkan/render_graph/nodes/vk_blit_image_node.hh vulkan/render_graph/nodes/vk_clear_color_image_node.hh + vulkan/render_graph/nodes/vk_clear_depth_stencil_image_node.hh vulkan/render_graph/nodes/vk_copy_buffer_node.hh vulkan/render_graph/nodes/vk_copy_buffer_to_image_node.hh vulkan/render_graph/nodes/vk_copy_image_node.hh diff --git a/source/blender/gpu/vulkan/render_graph/nodes/vk_blit_image_node.hh b/source/blender/gpu/vulkan/render_graph/nodes/vk_blit_image_node.hh index 1c88c2c2c6a..f6a44fd59bb 100644 --- a/source/blender/gpu/vulkan/render_graph/nodes/vk_blit_image_node.hh +++ b/source/blender/gpu/vulkan/render_graph/nodes/vk_blit_image_node.hh @@ -56,10 +56,14 @@ class VKBlitImageNode : public VKNodeInfo { + public: + /** + * Update the node data with the data inside create_info. + * + * Has been implemented as a template to ensure all node specific data + * (`VK*Data`/`VK*CreateInfo`) types can be included in the same header file as the logic. The + * actual node data (`VKRenderGraphNode` includes all header files.) + */ + template static void set_node_data(Node &node, const CreateInfo &create_info) + { + node.clear_depth_stencil_image = create_info; + } + + /** + * Extract read/write resource dependencies from `create_info` and add them to `node_links`. + */ + void build_links(VKResourceStateTracker &resources, + VKRenderGraphNodeLinks &node_links, + const CreateInfo &create_info) override + { + ResourceWithStamp resource = resources.get_image_and_increase_stamp(create_info.vk_image); + node_links.outputs.append({resource, + VK_ACCESS_TRANSFER_WRITE_BIT, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + create_info.vk_image_subresource_range.aspectMask}); + } + + /** + * Build the commands and add them to the command_buffer. + */ + void build_commands(VKCommandBufferInterface &command_buffer, + const Data &data, + VKBoundPipelines & /*r_bound_pipelines*/) override + { + command_buffer.clear_depth_stencil_image(data.vk_image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + &data.vk_clear_depth_stencil_value, + 1, + &data.vk_image_subresource_range); + } +}; +} // namespace blender::gpu::render_graph diff --git a/source/blender/gpu/vulkan/render_graph/nodes/vk_copy_buffer_to_image_node.hh b/source/blender/gpu/vulkan/render_graph/nodes/vk_copy_buffer_to_image_node.hh index 49441a3b721..1b21a3d0c7f 100644 --- a/source/blender/gpu/vulkan/render_graph/nodes/vk_copy_buffer_to_image_node.hh +++ b/source/blender/gpu/vulkan/render_graph/nodes/vk_copy_buffer_to_image_node.hh @@ -49,8 +49,10 @@ class VKCopyBufferToImageNode : public VKNodeInfo(synchronization); std::scoped_lock lock(resources_.mutex); diff --git a/source/blender/gpu/vulkan/render_graph/vk_render_graph.hh b/source/blender/gpu/vulkan/render_graph/vk_render_graph.hh index 5955eaa4856..6c32b845638 100644 --- a/source/blender/gpu/vulkan/render_graph/vk_render_graph.hh +++ b/source/blender/gpu/vulkan/render_graph/vk_render_graph.hh @@ -132,6 +132,10 @@ class VKRenderGraph : public NonCopyable { { add_node(clear_color_image); } + void add_node(const VKClearDepthStencilImageNode::CreateInfo &clear_depth_stencil_image) + { + add_node(clear_depth_stencil_image); + } void add_node(const VKFillBufferNode::CreateInfo &fill_buffer) { add_node(fill_buffer); diff --git a/source/blender/gpu/vulkan/render_graph/vk_render_graph_links.hh b/source/blender/gpu/vulkan/render_graph/vk_render_graph_links.hh index 6e7b9ec5339..58155efede9 100644 --- a/source/blender/gpu/vulkan/render_graph/vk_render_graph_links.hh +++ b/source/blender/gpu/vulkan/render_graph/vk_render_graph_links.hh @@ -44,7 +44,12 @@ struct VKRenderGraphLink { * When generating the commands this attribute is compared with the actual image layout of the * the image. Additional pipeline barriers will be added to transit to the layout stored here. */ - VkImageLayout vk_image_layout; + VkImageLayout vk_image_layout = VK_IMAGE_LAYOUT_UNDEFINED; + + /** + * Which aspect of the image is being used. + */ + VkImageAspectFlags vk_image_aspect = VK_IMAGE_ASPECT_NONE; }; /** diff --git a/source/blender/gpu/vulkan/render_graph/vk_render_graph_node.hh b/source/blender/gpu/vulkan/render_graph/vk_render_graph_node.hh index dd76995a341..6841715be18 100644 --- a/source/blender/gpu/vulkan/render_graph/vk_render_graph_node.hh +++ b/source/blender/gpu/vulkan/render_graph/vk_render_graph_node.hh @@ -10,6 +10,7 @@ #include "nodes/vk_blit_image_node.hh" #include "nodes/vk_clear_color_image_node.hh" +#include "nodes/vk_clear_depth_stencil_image_node.hh" #include "nodes/vk_copy_buffer_node.hh" #include "nodes/vk_copy_buffer_to_image_node.hh" #include "nodes/vk_copy_image_node.hh" @@ -37,6 +38,7 @@ struct VKRenderGraphNode { union { VKBlitImageNode::Data blit_image; VKClearColorImageNode::Data clear_color_image; + VKClearDepthStencilImageNode::Data clear_depth_stencil_image; VKCopyBufferNode::Data copy_buffer; VKCopyBufferToImageNode::Data copy_buffer_to_image; VKCopyImageNode::Data copy_image; @@ -92,6 +94,8 @@ struct VKRenderGraphNode { return VK_PIPELINE_STAGE_NONE; case VKNodeType::CLEAR_COLOR_IMAGE: return VKClearColorImageNode::pipeline_stage; + case VKNodeType::CLEAR_DEPTH_STENCIL_IMAGE: + return VKClearDepthStencilImageNode::pipeline_stage; case VKNodeType::FILL_BUFFER: return VKFillBufferNode::pipeline_stage; case VKNodeType::COPY_BUFFER: @@ -133,6 +137,12 @@ struct VKRenderGraphNode { break; } + case VKNodeType::CLEAR_DEPTH_STENCIL_IMAGE: { + VKClearDepthStencilImageNode node_info; + node_info.build_commands(command_buffer, clear_depth_stencil_image, r_bound_pipelines); + break; + } + case VKNodeType::FILL_BUFFER: { VKFillBufferNode node_info; node_info.build_commands(command_buffer, fill_buffer, r_bound_pipelines); @@ -200,6 +210,7 @@ struct VKRenderGraphNode { case VKNodeType::UNUSED: case VKNodeType::CLEAR_COLOR_IMAGE: + case VKNodeType::CLEAR_DEPTH_STENCIL_IMAGE: case VKNodeType::FILL_BUFFER: case VKNodeType::COPY_BUFFER: case VKNodeType::COPY_IMAGE: diff --git a/source/blender/gpu/vulkan/render_graph/vk_resource_access_info.cc b/source/blender/gpu/vulkan/render_graph/vk_resource_access_info.cc index 2364fd06fd7..3e3a85424fd 100644 --- a/source/blender/gpu/vulkan/render_graph/vk_resource_access_info.cc +++ b/source/blender/gpu/vulkan/render_graph/vk_resource_access_info.cc @@ -58,16 +58,20 @@ void VKResourceAccessInfo::build_links(VKResourceStateTracker &resources, VkAccessFlags read_access = image_access.vk_access_flags & VK_ACCESS_READ_MASK; if (read_access != VK_ACCESS_NONE) { ResourceWithStamp versioned_resource = resources.get_image(image_access.vk_image); - node_links.inputs.append( - {versioned_resource, read_access, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL}); + node_links.inputs.append({versioned_resource, + read_access, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + image_access.vk_image_aspect}); } VkAccessFlags write_access = image_access.vk_access_flags & VK_ACCESS_WRITE_MASK; if (write_access != VK_ACCESS_NONE) { ResourceWithStamp versioned_resource = resources.get_image_and_increase_stamp( image_access.vk_image); - node_links.outputs.append( - {versioned_resource, write_access, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL}); + node_links.outputs.append({versioned_resource, + write_access, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + image_access.vk_image_aspect}); } } } diff --git a/source/blender/gpu/vulkan/render_graph/vk_resource_access_info.hh b/source/blender/gpu/vulkan/render_graph/vk_resource_access_info.hh index 44dea7f48a5..493e10785df 100644 --- a/source/blender/gpu/vulkan/render_graph/vk_resource_access_info.hh +++ b/source/blender/gpu/vulkan/render_graph/vk_resource_access_info.hh @@ -31,6 +31,7 @@ class VKRenderGraphLinks; struct VKImageAccess { VkImage vk_image; VkAccessFlags vk_access_flags; + VkImageAspectFlags vk_image_aspect; }; /** Struct describing the access to a buffer. */ diff --git a/source/blender/gpu/vulkan/vk_texture.cc b/source/blender/gpu/vulkan/vk_texture.cc index 755a257b600..d6cc8dc5550 100644 --- a/source/blender/gpu/vulkan/vk_texture.cc +++ b/source/blender/gpu/vulkan/vk_texture.cc @@ -142,22 +142,29 @@ void VKTexture::generate_mipmap() void VKTexture::copy_to(VKTexture &dst_texture, VkImageAspectFlags vk_image_aspect) { + render_graph::VKCopyImageNode::CreateInfo copy_image = {}; + copy_image.src_image = vk_image_handle(); + copy_image.dst_image = dst_texture.vk_image_handle(); + copy_image.region.srcSubresource.aspectMask = vk_image_aspect; + copy_image.region.srcSubresource.mipLevel = 0; + copy_image.region.srcSubresource.layerCount = vk_layer_count(1); + copy_image.region.dstSubresource.aspectMask = vk_image_aspect; + copy_image.region.dstSubresource.mipLevel = 0; + copy_image.region.dstSubresource.layerCount = vk_layer_count(1); + copy_image.region.extent = vk_extent_3d(0); + VKContext &context = *VKContext::get(); - layout_ensure(context, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); - dst_texture.layout_ensure(context, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + if (use_render_graph) { + context.render_graph.add_node(copy_image); + } + else { + layout_ensure(context, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + dst_texture.layout_ensure(context, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - VkImageCopy region = {}; - region.srcSubresource.aspectMask = vk_image_aspect; - region.srcSubresource.mipLevel = 0; - region.srcSubresource.layerCount = vk_layer_count(1); - region.dstSubresource.aspectMask = vk_image_aspect; - region.dstSubresource.mipLevel = 0; - region.dstSubresource.layerCount = vk_layer_count(1); - region.extent = vk_extent_3d(0); - - VKCommandBuffers &command_buffers = context.command_buffers_get(); - command_buffers.copy(dst_texture, *this, Span(®ion, 1)); - context.flush(); + VKCommandBuffers &command_buffers = context.command_buffers_get(); + command_buffers.copy(dst_texture, *this, Span(©_image.region, 1)); + context.flush(); + } } void VKTexture::copy_to(Texture *tex) @@ -177,17 +184,28 @@ void VKTexture::clear(eGPUDataFormat format, const void *data) { BLI_assert(!is_texture_view()); - VKContext &context = *VKContext::get(); - VKCommandBuffers &command_buffers = context.command_buffers_get(); - VkClearColorValue clear_color = to_vk_clear_color_value(format, data); - VkImageSubresourceRange range = {0}; - range.aspectMask = to_vk_image_aspect_flag_bits(device_format_); - range.levelCount = VK_REMAINING_MIP_LEVELS; - range.layerCount = VK_REMAINING_ARRAY_LAYERS; - layout_ensure(context, VK_IMAGE_LAYOUT_GENERAL); + render_graph::VKClearColorImageNode::CreateInfo clear_color_image = {}; + clear_color_image.vk_clear_color_value = to_vk_clear_color_value(format, data); + clear_color_image.vk_image = vk_image_handle(); + clear_color_image.vk_image_subresource_range.aspectMask = to_vk_image_aspect_flag_bits( + device_format_); + clear_color_image.vk_image_subresource_range.layerCount = VK_REMAINING_ARRAY_LAYERS; + clear_color_image.vk_image_subresource_range.levelCount = VK_REMAINING_MIP_LEVELS; - command_buffers.clear( - vk_image_, current_layout_get(), clear_color, Span(&range, 1)); + VKContext &context = *VKContext::get(); + + if (use_render_graph) { + context.render_graph.add_node(clear_color_image); + } + else { + layout_ensure(context, VK_IMAGE_LAYOUT_GENERAL); + VKCommandBuffers &command_buffers = context.command_buffers_get(); + command_buffers.clear( + clear_color_image.vk_image, + current_layout_get(), + clear_color_image.vk_clear_color_value, + Span(&clear_color_image.vk_image_subresource_range, 1)); + } } void VKTexture::clear_depth_stencil(const eGPUFrameBufferBits buffers, @@ -196,21 +214,28 @@ void VKTexture::clear_depth_stencil(const eGPUFrameBufferBits buffers, { BLI_assert(buffers & (GPU_DEPTH_BIT | GPU_STENCIL_BIT)); - VKContext &context = *VKContext::get(); - VKCommandBuffers &command_buffers = context.command_buffers_get(); - VkClearDepthStencilValue clear_depth_stencil; - clear_depth_stencil.depth = clear_depth; - clear_depth_stencil.stencil = clear_stencil; - VkImageSubresourceRange range = {0}; - range.aspectMask = to_vk_image_aspect_flag_bits(buffers & (GPU_DEPTH_BIT | GPU_STENCIL_BIT)); - range.levelCount = VK_REMAINING_MIP_LEVELS; - range.layerCount = VK_REMAINING_ARRAY_LAYERS; + render_graph::VKClearDepthStencilImageNode::CreateInfo clear_depth_stencil_image = {}; + clear_depth_stencil_image.vk_image = vk_image_handle(); + clear_depth_stencil_image.vk_clear_depth_stencil_value.depth = clear_depth; + clear_depth_stencil_image.vk_clear_depth_stencil_value.stencil = clear_stencil; + clear_depth_stencil_image.vk_image_subresource_range.aspectMask = to_vk_image_aspect_flag_bits( + buffers & (GPU_DEPTH_BIT | GPU_STENCIL_BIT)); + clear_depth_stencil_image.vk_image_subresource_range.layerCount = VK_REMAINING_ARRAY_LAYERS; + clear_depth_stencil_image.vk_image_subresource_range.levelCount = VK_REMAINING_MIP_LEVELS; - layout_ensure(context, VK_IMAGE_LAYOUT_GENERAL); - command_buffers.clear(vk_image_, - current_layout_get(), - clear_depth_stencil, - Span(&range, 1)); + VKContext &context = *VKContext::get(); + if (use_render_graph) { + context.render_graph.add_node(clear_depth_stencil_image); + } + else { + VKCommandBuffers &command_buffers = context.command_buffers_get(); + layout_ensure(context, VK_IMAGE_LAYOUT_GENERAL); + command_buffers.clear( + clear_depth_stencil_image.vk_image, + current_layout_get(), + clear_depth_stencil_image.vk_clear_depth_stencil_value, + Span(&clear_depth_stencil_image.vk_image_subresource_range, 1)); + } } void VKTexture::swizzle_set(const char swizzle_mask[4]) @@ -234,9 +259,6 @@ void VKTexture::mip_range_set(int min, int max) void VKTexture::read_sub( int mip, eGPUDataFormat format, const int region[6], const IndexRange layers, void *r_data) { - VKContext &context = *VKContext::get(); - layout_ensure(context, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); - /* Vulkan images cannot be directly mapped to host memory and requires a staging buffer. */ VKBuffer staging_buffer; @@ -246,22 +268,33 @@ void VKTexture::read_sub( staging_buffer.create(device_memory_size, GPU_USAGE_DYNAMIC, VK_BUFFER_USAGE_TRANSFER_DST_BIT); - VkBufferImageCopy buffer_image_copy = {}; - buffer_image_copy.imageOffset.x = region[0]; - buffer_image_copy.imageOffset.y = region[1]; - buffer_image_copy.imageOffset.z = region[2]; - buffer_image_copy.imageExtent.width = region[3]; - buffer_image_copy.imageExtent.height = region[4]; - buffer_image_copy.imageExtent.depth = region[5]; - buffer_image_copy.imageSubresource.aspectMask = to_vk_image_aspect_single_bit( + render_graph::VKCopyImageToBufferNode::CreateInfo copy_image_to_buffer = {}; + copy_image_to_buffer.src_image = vk_image_handle(); + copy_image_to_buffer.dst_buffer = staging_buffer.vk_handle(); + copy_image_to_buffer.region.imageOffset.x = region[0]; + copy_image_to_buffer.region.imageOffset.y = region[1]; + copy_image_to_buffer.region.imageOffset.z = region[2]; + copy_image_to_buffer.region.imageExtent.width = region[3]; + copy_image_to_buffer.region.imageExtent.height = region[4]; + copy_image_to_buffer.region.imageExtent.depth = region[5]; + copy_image_to_buffer.region.imageSubresource.aspectMask = to_vk_image_aspect_single_bit( to_vk_image_aspect_flag_bits(device_format_), false); - buffer_image_copy.imageSubresource.mipLevel = mip; - buffer_image_copy.imageSubresource.baseArrayLayer = layers.start(); - buffer_image_copy.imageSubresource.layerCount = layers.size(); + copy_image_to_buffer.region.imageSubresource.mipLevel = mip; + copy_image_to_buffer.region.imageSubresource.baseArrayLayer = layers.start(); + copy_image_to_buffer.region.imageSubresource.layerCount = layers.size(); - VKCommandBuffers &command_buffers = context.command_buffers_get(); - command_buffers.copy(staging_buffer, *this, Span(&buffer_image_copy, 1)); - context.flush(); + VKContext &context = *VKContext::get(); + if (use_render_graph) { + context.render_graph.add_node(copy_image_to_buffer); + context.render_graph.submit_buffer_for_read(staging_buffer.vk_handle()); + } + else { + layout_ensure(context, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + VKCommandBuffers &command_buffers = context.command_buffers_get(); + command_buffers.copy( + staging_buffer, *this, Span(©_image_to_buffer.region, 1)); + context.flush(); + } convert_device_to_host( r_data, staging_buffer.mapped_memory_get(), sample_len, format, format_, device_format_); @@ -319,7 +352,7 @@ void VKTexture::update_sub( /* Vulkan images cannot be directly mapped to host memory and requires a staging buffer. */ VKContext &context = *VKContext::get(); int layers = vk_layer_count(1); - size_t sample_len = size_t(extent.x) * extent.y * extent.z; + size_t sample_len = size_t(extent.x) * extent.y * extent.z * layers; size_t device_memory_size = sample_len * to_bytesize(device_format_); if (is_compressed) { @@ -338,23 +371,32 @@ void VKTexture::update_sub( convert_host_to_device( staging_buffer.mapped_memory_get(), data, sample_len, format, format_, device_format_); - VkBufferImageCopy region = {}; - region.imageExtent.width = extent.x; - region.imageExtent.height = extent.y; - region.imageExtent.depth = extent.z; - region.bufferRowLength = context.state_manager_get().texture_unpack_row_length_get(); - region.imageOffset.x = offset[0]; - region.imageOffset.y = offset[1]; - region.imageOffset.z = offset[2]; - region.imageSubresource.aspectMask = to_vk_image_aspect_single_bit( + render_graph::VKCopyBufferToImageNode::CreateInfo copy_buffer_to_image = {}; + copy_buffer_to_image.src_buffer = staging_buffer.vk_handle(); + copy_buffer_to_image.dst_image = vk_image_handle(); + copy_buffer_to_image.region.imageExtent.width = extent.x; + copy_buffer_to_image.region.imageExtent.height = extent.y; + copy_buffer_to_image.region.imageExtent.depth = extent.z; + copy_buffer_to_image.region.bufferRowLength = + context.state_manager_get().texture_unpack_row_length_get(); + copy_buffer_to_image.region.imageOffset.x = offset[0]; + copy_buffer_to_image.region.imageOffset.y = offset[1]; + copy_buffer_to_image.region.imageOffset.z = offset[2]; + copy_buffer_to_image.region.imageSubresource.aspectMask = to_vk_image_aspect_single_bit( to_vk_image_aspect_flag_bits(device_format_), false); - region.imageSubresource.mipLevel = mip; - region.imageSubresource.layerCount = layers; + copy_buffer_to_image.region.imageSubresource.mipLevel = mip; + copy_buffer_to_image.region.imageSubresource.layerCount = layers; - layout_ensure(context, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - VKCommandBuffers &command_buffers = context.command_buffers_get(); - command_buffers.copy(*this, staging_buffer, Span(®ion, 1)); - context.flush(); + if (use_render_graph) { + context.render_graph.add_node(copy_buffer_to_image); + } + else { + layout_ensure(context, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + VKCommandBuffers &command_buffers = context.command_buffers_get(); + command_buffers.copy( + *this, staging_buffer, Span(©_buffer_to_image.region, 1)); + context.flush(); + } } void VKTexture::update_sub(int /*offset*/[3], @@ -406,22 +448,30 @@ bool VKTexture::init_internal(VertBuf *vbo) if (!allocate()) { return false; } - VKVertexBuffer *vertex_buffer = unwrap(vbo); - VkBufferImageCopy region = {}; - region.imageExtent.width = w_; - region.imageExtent.height = 1; - region.imageExtent.depth = 1; - region.imageSubresource.aspectMask = to_vk_image_aspect_flag_bits(device_format_); - region.imageSubresource.mipLevel = 0; - region.imageSubresource.layerCount = 1; + render_graph::VKCopyBufferToImageNode::CreateInfo copy_buffer_to_image = {}; + copy_buffer_to_image.src_buffer = vertex_buffer->vk_handle(); + copy_buffer_to_image.dst_image = vk_image_handle(); + copy_buffer_to_image.region.imageExtent.width = w_; + copy_buffer_to_image.region.imageExtent.height = 1; + copy_buffer_to_image.region.imageExtent.depth = 1; + copy_buffer_to_image.region.imageSubresource.aspectMask = to_vk_image_aspect_flag_bits( + device_format_); + copy_buffer_to_image.region.imageSubresource.mipLevel = 0; + copy_buffer_to_image.region.imageSubresource.layerCount = 1; VKContext &context = *VKContext::get(); - layout_ensure(context, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - VKCommandBuffers &command_buffers = context.command_buffers_get(); - command_buffers.copy(*this, vertex_buffer->buffer_, Span(®ion, 1)); - context.flush(); + if (use_render_graph) { + context.render_graph.add_node(copy_buffer_to_image); + } + else { + layout_ensure(context, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + VKCommandBuffers &command_buffers = context.command_buffers_get(); + command_buffers.copy( + *this, vertex_buffer->buffer_, Span(©_buffer_to_image.region, 1)); + context.flush(); + } return true; }