Files
goo-engine/source/blender/gpu/vulkan/vk_command_buffers.hh
T
Jeroen Bakker d09d93febf Vulkan: Store Vertex, Index and Storage Buffers on Device Memory
Currently all buffer types were stored in host memory, which is visible to the GPU as well.
This is typically slow as the data would be transferred over the PCI bus when used.

Most of the time Index and Vertex buffers are written once and read many times so it makes
more sense to locate them on the GPU. Storage buffers typically require quick access as they
are created for shading/compute purposes.

This PR will try to store vertex buffers, index buffers and storage buffers on device memory
to improve the performance.

Uniform buffers are still located on host memory as they can be uploaded during binding process.
This can (will) reset the graphics pipeline triggering draw calls using unattached resources.

In future this could be optimized further as in:
* using different pools for allocating specific buffers, with a fallback when buffers cannot be
  stored on the GPU anymore.
* store uniform buffers in device memory

Pull Request: https://projects.blender.org/blender/blender/pulls/115343
2023-11-24 13:52:48 +01:00

194 lines
6.1 KiB
C++

/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup gpu
*/
#pragma once
#include "vk_command_buffer.hh"
namespace blender::gpu {
class VKFrameBuffer;
class VKStorageBuffer;
class VKBuffer;
class VKVertexBuffer;
class VKIndexBuffer;
class VKTexture;
class VKPushConstants;
struct VKBufferWithOffset;
class VKPipeline;
class VKDescriptorSet;
class VKCommandBuffers : public NonCopyable, NonMovable {
VkCommandPool vk_command_pool_ = VK_NULL_HANDLE;
enum class Type {
DataTransferCompute = 0,
Graphics = 1,
Max = 2,
};
bool initialized_ = false;
/**
* Timeout to use when waiting for fences in nanoseconds.
*
* Currently added as the fence will halt when there are no commands in the command buffer for
* the second time. This should be solved and this timeout should be removed.
*/
static constexpr uint64_t FenceTimeout = UINT64_MAX;
/* Fence for CPU GPU synchronization when submitting the command buffers. */
VkFence vk_fence_ = VK_NULL_HANDLE;
/**
* Active framebuffer for graphics command buffer.
*/
VKFrameBuffer *framebuffer_ = nullptr;
bool framebuffer_bound_ = false;
/* TODO: General command buffer should not be used, but is added to help during the transition.*/
VKCommandBuffer buffers_[(int)Type::Max];
VKSubmissionID submission_id_;
public:
~VKCommandBuffers();
void init(const VKDevice &device);
/**
* Have these command buffers already been initialized?
*/
bool is_initialized() const
{
return initialized_;
}
void bind(const VKPipeline &vk_pipeline, VkPipelineBindPoint bind_point);
void bind(const VKDescriptorSet &descriptor_set,
const VkPipelineLayout vk_pipeline_layout,
VkPipelineBindPoint bind_point);
void bind(const uint32_t binding,
const VKVertexBuffer &vertex_buffer,
const VkDeviceSize offset);
/* Bind the given buffer as a vertex buffer. */
void bind(const uint32_t binding, const VKBufferWithOffset &vertex_buffer);
void bind(const uint32_t binding, const VkBuffer &vk_vertex_buffer, const VkDeviceSize offset);
/* Bind the given buffer as an index buffer. */
void bind(const VKBuffer &index_buffer, VkIndexType index_type);
void begin_render_pass(VKFrameBuffer &framebuffer);
void end_render_pass(const VKFrameBuffer &framebuffer);
/**
* 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);
void dispatch(int groups_x_len, int groups_y_len, int groups_z_len);
void dispatch(VKStorageBuffer &command_buffer);
/** Copy the contents of a texture MIP level to the dst buffer. */
void copy(VKBuffer &dst_buffer, VKTexture &src_texture, Span<VkBufferImageCopy> regions);
void copy(VKTexture &dst_texture, VKBuffer &src_buffer, Span<VkBufferImageCopy> regions);
void copy(VKTexture &dst_texture, VKTexture &src_texture, Span<VkImageCopy> regions);
void copy(const VKBuffer &dst_buffer, VkBuffer src_buffer, Span<VkBufferCopy> regions);
void blit(VKTexture &dst_texture, VKTexture &src_texture, Span<VkImageBlit> regions);
void blit(VKTexture &dst_texture,
VkImageLayout dst_layout,
VKTexture &src_texture,
VkImageLayout src_layout,
Span<VkImageBlit> regions);
void pipeline_barrier(VkPipelineStageFlags source_stages,
VkPipelineStageFlags destination_stages,
Span<VkImageMemoryBarrier> image_memory_barriers);
/**
* Clear color image resource.
*/
void clear(VkImage vk_image,
VkImageLayout vk_image_layout,
const VkClearColorValue &vk_clear_color,
Span<VkImageSubresourceRange> ranges);
/**
* Clear depth/stencil aspect of an image resource.
*/
void clear(VkImage vk_image,
VkImageLayout vk_image_layout,
const VkClearDepthStencilValue &vk_clear_color,
Span<VkImageSubresourceRange> ranges);
/**
* Clear attachments of the active framebuffer.
*/
void clear(Span<VkClearAttachment> attachments, Span<VkClearRect> areas);
void fill(VKBuffer &buffer, uint32_t data);
void draw(int v_first, int v_count, int i_first, int i_count);
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);
void submit();
const VKSubmissionID &submission_id_get() const
{
return submission_id_;
}
private:
void init_fence(const VKDevice &device);
void init_command_pool(const VKDevice &device);
void init_command_buffers(const VKDevice &device);
VKCommandBuffer &command_buffer_get(Type type)
{
return buffers_[(int)type];
}
/**
* Ensure that no draw_commands are scheduled.
*
* To ensure correct operation all draw commands should be flushed when adding a new compute
* command.
*/
void ensure_no_draw_commands();
/**
* Validate that there isn't a framebuffer being tracked (bound or not bound).
*
* Raises an assert in debug when a framebuffer is being tracked.
*/
void validate_framebuffer_not_exists();
/**
* Validate that there is a framebuffer being tracked (bound or not bound).
*
* Raises an assert in debug when no framebuffer is being tracked.
*/
void validate_framebuffer_exists();
/**
* Ensure that the tracked framebuffer is bound.
*/
void ensure_active_framebuffer();
/**
* Ensure that the tracked framebuffer is bound.
*/
void ensure_no_active_framebuffer();
};
} // namespace blender::gpu