Vulkan: Resource Submission Tracking #105183
|
@ -207,6 +207,7 @@ set(VULKAN_SRC
|
|||
vulkan/vk_pixel_buffer.cc
|
||||
vulkan/vk_push_constants.cc
|
||||
vulkan/vk_query.cc
|
||||
vulkan/vk_resource_tracker.cc
|
||||
vulkan/vk_shader.cc
|
||||
vulkan/vk_shader_interface.cc
|
||||
vulkan/vk_shader_log.cc
|
||||
|
@ -234,6 +235,7 @@ set(VULKAN_SRC
|
|||
vulkan/vk_pixel_buffer.hh
|
||||
vulkan/vk_push_constants.hh
|
||||
vulkan/vk_query.hh
|
||||
vulkan/vk_resource_tracker.hh
|
||||
vulkan/vk_shader.hh
|
||||
vulkan/vk_shader_interface.hh
|
||||
vulkan/vk_shader_log.hh
|
||||
|
|
|
@ -78,6 +78,11 @@ struct Shader {
|
|||
GPUShader *shader = nullptr;
|
||||
Vector<CallData> call_datas;
|
||||
|
||||
Shader()
|
||||
{
|
||||
call_datas.reserve(10);
|
||||
}
|
||||
|
||||
~Shader()
|
||||
{
|
||||
if (shader != nullptr) {
|
||||
|
@ -117,7 +122,9 @@ struct Shader {
|
|||
|
||||
void dispatch()
|
||||
{
|
||||
GPU_compute_dispatch(shader, 1, 1, 1);
|
||||
/* Dispatching 1000000 times to add some stress to the GPU. Without it tests may succeed when
|
||||
* using too simple shaders. */
|
||||
GPU_compute_dispatch(shader, 1000, 1000, 1);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -177,11 +184,7 @@ static void test_push_constants_512bytes()
|
|||
}
|
||||
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);
|
||||
|
@ -205,6 +208,5 @@ 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
|
||||
|
|
|
@ -66,13 +66,14 @@ void VKBackend::compute_dispatch(int groups_x_len, int groups_y_len, int groups_
|
|||
VKShader *shader = static_cast<VKShader *>(context.shader);
|
||||
VKCommandBuffer &command_buffer = context.command_buffer_get();
|
||||
VKPipeline &pipeline = shader->pipeline_get();
|
||||
VKDescriptorSet &descriptor_set = pipeline.descriptor_set_get();
|
||||
VKDescriptorSetTracker &descriptor_set = pipeline.descriptor_set_get();
|
||||
VKPushConstants &push_constants = pipeline.push_constants_get();
|
||||
|
||||
push_constants.update(context);
|
||||
descriptor_set.update(context.device_get());
|
||||
command_buffer.bind(
|
||||
descriptor_set, shader->vk_pipeline_layout_get(), VK_PIPELINE_BIND_POINT_COMPUTE);
|
||||
descriptor_set.update(context);
|
||||
command_buffer.bind(*descriptor_set.active_descriptor_set(),
|
||||
shader->vk_pipeline_layout_get(),
|
||||
VK_PIPELINE_BIND_POINT_COMPUTE);
|
||||
command_buffer.dispatch(groups_x_len, groups_y_len, groups_z_len);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
#include "vk_buffer.hh"
|
||||
#include "vk_context.hh"
|
||||
|
||||
namespace blender::gpu {
|
||||
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
#include "gpu_context_private.hh"
|
||||
|
||||
#include "vk_common.hh"
|
||||
#include "vk_context.hh"
|
||||
|
||||
namespace blender::gpu {
|
||||
class VKContext;
|
||||
|
||||
/**
|
||||
* Class for handing vulkan buffers (allocation/updating/binding).
|
||||
|
|
|
@ -32,6 +32,7 @@ void VKCommandBuffer::init(const VkDevice vk_device,
|
|||
vk_device_ = vk_device;
|
||||
vk_queue_ = vk_queue;
|
||||
vk_command_buffer_ = vk_command_buffer;
|
||||
submission_id_.reset();
|
||||
|
||||
if (vk_fence_ == VK_NULL_HANDLE) {
|
||||
VK_ALLOCATION_CALLBACKS;
|
||||
|
@ -160,6 +161,7 @@ void VKCommandBuffer::submit_encoded_commands()
|
|||
submit_info.pCommandBuffers = &vk_command_buffer_;
|
||||
|
||||
vkQueueSubmit(vk_queue_, 1, &submit_info, vk_fence_);
|
||||
submission_id_.next();
|
||||
}
|
||||
|
||||
} // namespace blender::gpu
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "vk_common.hh"
|
||||
#include "vk_resource_tracker.hh"
|
||||
|
||||
#include "BLI_utility_mixins.hh"
|
||||
|
||||
|
@ -27,6 +28,7 @@ class VKCommandBuffer : NonCopyable, NonMovable {
|
|||
|
||||
/** Owning handles */
|
||||
VkFence vk_fence_ = VK_NULL_HANDLE;
|
||||
VKSubmissionID submission_id_;
|
||||
|
||||
public:
|
||||
virtual ~VKCommandBuffer();
|
||||
|
@ -59,6 +61,11 @@ class VKCommandBuffer : NonCopyable, NonMovable {
|
|||
*/
|
||||
void submit();
|
||||
|
||||
const VKSubmissionID &submission_id_get() const
|
||||
{
|
||||
return submission_id_;
|
||||
}
|
||||
|
||||
private:
|
||||
void encode_recorded_commands();
|
||||
void submit_encoded_commands();
|
||||
|
|
|
@ -80,7 +80,8 @@ bool VKDescriptorPools::is_last_pool_active()
|
|||
return active_pool_index_ == pools_.size() - 1;
|
||||
}
|
||||
|
||||
VKDescriptorSet VKDescriptorPools::allocate(const VkDescriptorSetLayout &descriptor_set_layout)
|
||||
std::unique_ptr<VKDescriptorSet> VKDescriptorPools::allocate(
|
||||
const VkDescriptorSetLayout &descriptor_set_layout)
|
||||
{
|
||||
VkDescriptorSetAllocateInfo allocate_info = {};
|
||||
VkDescriptorPool pool = active_pool_get();
|
||||
|
@ -102,7 +103,7 @@ VKDescriptorSet VKDescriptorPools::allocate(const VkDescriptorSetLayout &descrip
|
|||
return allocate(descriptor_set_layout);
|
||||
}
|
||||
|
||||
return VKDescriptorSet(pool, vk_descriptor_set);
|
||||
return std::make_unique<VKDescriptorSet>(pool, vk_descriptor_set);
|
||||
}
|
||||
|
||||
void VKDescriptorPools::free(VKDescriptorSet &descriptor_set)
|
||||
|
|
|
@ -47,7 +47,7 @@ class VKDescriptorPools {
|
|||
|
||||
void init(const VkDevice vk_device);
|
||||
|
||||
VKDescriptorSet allocate(const VkDescriptorSetLayout &descriptor_set_layout);
|
||||
std::unique_ptr<VKDescriptorSet> allocate(const VkDescriptorSetLayout &descriptor_set_layout);
|
||||
void free(VKDescriptorSet &descriptor_set);
|
||||
|
||||
/**
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include "vk_descriptor_set.hh"
|
||||
#include "vk_index_buffer.hh"
|
||||
#include "vk_shader.hh"
|
||||
#include "vk_storage_buffer.hh"
|
||||
#include "vk_texture.hh"
|
||||
#include "vk_uniform_buffer.hh"
|
||||
|
@ -17,9 +18,7 @@
|
|||
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_))
|
||||
: vk_descriptor_pool_(other.vk_descriptor_pool_), vk_descriptor_set_(other.vk_descriptor_set_)
|
||||
{
|
||||
other.mark_freed();
|
||||
}
|
||||
|
@ -40,7 +39,8 @@ void VKDescriptorSet::mark_freed()
|
|||
vk_descriptor_pool_ = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
void VKDescriptorSet::bind(VKStorageBuffer &buffer, const Location location)
|
||||
void VKDescriptorSetTracker::bind(VKStorageBuffer &buffer,
|
||||
const VKDescriptorSet::Location location)
|
||||
{
|
||||
Binding &binding = ensure_location(location);
|
||||
binding.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
|
||||
|
@ -48,7 +48,8 @@ void VKDescriptorSet::bind(VKStorageBuffer &buffer, const Location location)
|
|||
binding.buffer_size = buffer.size_in_bytes();
|
||||
}
|
||||
|
||||
void VKDescriptorSet::bind_as_ssbo(VKVertexBuffer &buffer, const Location location)
|
||||
void VKDescriptorSetTracker::bind_as_ssbo(VKVertexBuffer &buffer,
|
||||
const VKDescriptorSet::Location location)
|
||||
{
|
||||
Binding &binding = ensure_location(location);
|
||||
binding.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
|
||||
|
@ -56,7 +57,8 @@ void VKDescriptorSet::bind_as_ssbo(VKVertexBuffer &buffer, const Location locati
|
|||
binding.buffer_size = buffer.size_used_get();
|
||||
}
|
||||
|
||||
void VKDescriptorSet::bind(VKUniformBuffer &buffer, const Location location)
|
||||
void VKDescriptorSetTracker::bind(VKUniformBuffer &buffer,
|
||||
const VKDescriptorSet::Location location)
|
||||
{
|
||||
Binding &binding = ensure_location(location);
|
||||
binding.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
|
@ -64,7 +66,8 @@ void VKDescriptorSet::bind(VKUniformBuffer &buffer, const Location location)
|
|||
binding.buffer_size = buffer.size_in_bytes();
|
||||
}
|
||||
|
||||
void VKDescriptorSet::bind_as_ssbo(VKIndexBuffer &buffer, const Location location)
|
||||
void VKDescriptorSetTracker::bind_as_ssbo(VKIndexBuffer &buffer,
|
||||
const VKDescriptorSet::Location location)
|
||||
{
|
||||
Binding &binding = ensure_location(location);
|
||||
binding.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
|
||||
|
@ -72,14 +75,16 @@ void VKDescriptorSet::bind_as_ssbo(VKIndexBuffer &buffer, const Location locatio
|
|||
binding.buffer_size = buffer.size_get();
|
||||
}
|
||||
|
||||
void VKDescriptorSet::image_bind(VKTexture &texture, const Location location)
|
||||
void VKDescriptorSetTracker::image_bind(VKTexture &texture,
|
||||
const VKDescriptorSet::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(const Location location)
|
||||
VKDescriptorSetTracker::Binding &VKDescriptorSetTracker::ensure_location(
|
||||
const VKDescriptorSet::Location location)
|
||||
{
|
||||
for (Binding &binding : bindings_) {
|
||||
if (binding.location == location) {
|
||||
|
@ -93,8 +98,12 @@ VKDescriptorSet::Binding &VKDescriptorSet::ensure_location(const Location locati
|
|||
return bindings_.last();
|
||||
}
|
||||
|
||||
void VKDescriptorSet::update(VkDevice vk_device)
|
||||
void VKDescriptorSetTracker::update(VKContext &context)
|
||||
{
|
||||
tracked_resource_for(context, !bindings_.is_empty());
|
||||
std::unique_ptr<VKDescriptorSet> &descriptor_set = active_descriptor_set();
|
||||
VkDescriptorSet vk_descriptor_set = descriptor_set->vk_handle();
|
||||
|
||||
Vector<VkDescriptorBufferInfo> buffer_infos;
|
||||
Vector<VkWriteDescriptorSet> descriptor_writes;
|
||||
|
||||
|
@ -109,7 +118,7 @@ void VKDescriptorSet::update(VkDevice vk_device)
|
|||
|
||||
VkWriteDescriptorSet write_descriptor = {};
|
||||
write_descriptor.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
write_descriptor.dstSet = vk_descriptor_set_;
|
||||
write_descriptor.dstSet = vk_descriptor_set;
|
||||
write_descriptor.dstBinding = binding.location;
|
||||
write_descriptor.descriptorCount = 1;
|
||||
write_descriptor.descriptorType = binding.type;
|
||||
|
@ -129,7 +138,7 @@ void VKDescriptorSet::update(VkDevice vk_device)
|
|||
|
||||
VkWriteDescriptorSet write_descriptor = {};
|
||||
write_descriptor.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
write_descriptor.dstSet = vk_descriptor_set_;
|
||||
write_descriptor.dstSet = vk_descriptor_set;
|
||||
write_descriptor.dstBinding = binding.location;
|
||||
write_descriptor.descriptorCount = 1;
|
||||
write_descriptor.descriptorType = binding.type;
|
||||
|
@ -141,10 +150,16 @@ void VKDescriptorSet::update(VkDevice vk_device)
|
|||
"Not all changes have been converted to a write descriptor. Check "
|
||||
"`Binding::is_buffer` and `Binding::is_image`.");
|
||||
|
||||
VkDevice vk_device = context.device_get();
|
||||
vkUpdateDescriptorSets(
|
||||
vk_device, descriptor_writes.size(), descriptor_writes.data(), 0, nullptr);
|
||||
|
||||
bindings_.clear();
|
||||
}
|
||||
|
||||
std::unique_ptr<VKDescriptorSet> VKDescriptorSetTracker::create_resource(VKContext &context)
|
||||
{
|
||||
return context.descriptor_pools_get().allocate(layout_);
|
||||
}
|
||||
|
||||
} // namespace blender::gpu
|
||||
|
|
|
@ -12,7 +12,10 @@
|
|||
|
||||
#include "gpu_shader_private.hh"
|
||||
|
||||
#include "vk_buffer.hh"
|
||||
#include "vk_common.hh"
|
||||
#include "vk_resource_tracker.hh"
|
||||
#include "vk_uniform_buffer.hh"
|
||||
|
||||
namespace blender::gpu {
|
||||
class VKIndexBuffer;
|
||||
|
@ -21,6 +24,7 @@ class VKStorageBuffer;
|
|||
class VKTexture;
|
||||
class VKUniformBuffer;
|
||||
class VKVertexBuffer;
|
||||
class VKDescriptorSetTracker;
|
||||
|
||||
/**
|
||||
* In vulkan shader resources (images and buffers) are grouped in descriptor sets.
|
||||
|
@ -31,7 +35,6 @@ class VKVertexBuffer;
|
|||
* to use 2 descriptor sets per shader. One for each #blender::gpu::shader::Frequency.
|
||||
*/
|
||||
class VKDescriptorSet : NonCopyable {
|
||||
struct Binding;
|
||||
|
||||
public:
|
||||
/**
|
||||
|
@ -69,42 +72,13 @@ class VKDescriptorSet : NonCopyable {
|
|||
return binding;
|
||||
}
|
||||
|
||||
friend struct Binding;
|
||||
friend struct VKDescriptorSetTracker;
|
||||
friend class VKShaderInterface;
|
||||
};
|
||||
|
||||
private:
|
||||
struct Binding {
|
||||
Location location;
|
||||
VkDescriptorType type;
|
||||
|
||||
VkBuffer vk_buffer = VK_NULL_HANDLE;
|
||||
VkDeviceSize buffer_size = 0;
|
||||
|
||||
VkImageView vk_image_view = VK_NULL_HANDLE;
|
||||
|
||||
Binding()
|
||||
{
|
||||
location.binding = 0;
|
||||
}
|
||||
|
||||
bool is_buffer() const
|
||||
{
|
||||
return ELEM(type, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
|
||||
}
|
||||
|
||||
bool is_image() const
|
||||
{
|
||||
return ELEM(type, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
|
||||
}
|
||||
};
|
||||
|
||||
VkDescriptorPool vk_descriptor_pool_ = VK_NULL_HANDLE;
|
||||
VkDescriptorSet vk_descriptor_set_ = VK_NULL_HANDLE;
|
||||
|
||||
/** A list of bindings that needs to be updated. */
|
||||
Vector<Binding> bindings_;
|
||||
|
||||
public:
|
||||
VKDescriptorSet() = default;
|
||||
VKDescriptorSet(VkDescriptorPool vk_descriptor_pool, VkDescriptorSet vk_descriptor_set)
|
||||
|
@ -131,22 +105,73 @@ class VKDescriptorSet : NonCopyable {
|
|||
{
|
||||
return vk_descriptor_pool_;
|
||||
}
|
||||
void mark_freed();
|
||||
};
|
||||
|
||||
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);
|
||||
class VKDescriptorSetTracker : protected VKResourceTracker<VKDescriptorSet> {
|
||||
friend class VKDescriptorSet;
|
||||
|
||||
public:
|
||||
struct Binding {
|
||||
VKDescriptorSet::Location location;
|
||||
VkDescriptorType type;
|
||||
|
||||
VkBuffer vk_buffer = VK_NULL_HANDLE;
|
||||
VkDeviceSize buffer_size = 0;
|
||||
|
||||
VkImageView vk_image_view = VK_NULL_HANDLE;
|
||||
|
||||
Binding()
|
||||
{
|
||||
location.binding = 0;
|
||||
}
|
||||
|
||||
bool is_buffer() const
|
||||
{
|
||||
return ELEM(type, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
|
||||
}
|
||||
|
||||
bool is_image() const
|
||||
{
|
||||
return ELEM(type, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
/** A list of bindings that needs to be updated.*/
|
||||
Vector<Binding> bindings_;
|
||||
VkDescriptorSetLayout layout_;
|
||||
|
||||
public:
|
||||
VKDescriptorSetTracker()
|
||||
{
|
||||
}
|
||||
|
||||
VKDescriptorSetTracker(VkDescriptorSetLayout layout) : layout_(layout)
|
||||
{
|
||||
}
|
||||
|
||||
void bind_as_ssbo(VKVertexBuffer &buffer, VKDescriptorSet::Location location);
|
||||
void bind_as_ssbo(VKIndexBuffer &buffer, VKDescriptorSet::Location location);
|
||||
void bind(VKStorageBuffer &buffer, VKDescriptorSet::Location location);
|
||||
void bind(VKUniformBuffer &buffer, VKDescriptorSet::Location location);
|
||||
void image_bind(VKTexture &texture, VKDescriptorSet::Location location);
|
||||
|
||||
/**
|
||||
* Update the descriptor set on the device.
|
||||
*/
|
||||
void update(VkDevice vk_device);
|
||||
void update(VKContext &context);
|
||||
|
||||
void mark_freed();
|
||||
std::unique_ptr<VKDescriptorSet> &active_descriptor_set()
|
||||
{
|
||||
return active_resource();
|
||||
}
|
||||
|
||||
protected:
|
||||
std::unique_ptr<VKDescriptorSet> create_resource(VKContext &context) override;
|
||||
|
||||
private:
|
||||
Binding &ensure_location(Location location);
|
||||
Binding &ensure_location(VKDescriptorSet::Location location);
|
||||
};
|
||||
|
||||
} // namespace blender::gpu
|
||||
|
|
|
@ -12,10 +12,10 @@
|
|||
namespace blender::gpu {
|
||||
|
||||
VKPipeline::VKPipeline(VkPipeline vk_pipeline,
|
||||
VKDescriptorSet &&descriptor_set,
|
||||
VkDescriptorSetLayout vk_descriptor_set_layout,
|
||||
VKPushConstants &&push_constants)
|
||||
: vk_pipeline_(vk_pipeline),
|
||||
descriptor_set_(std::move(descriptor_set)),
|
||||
descriptor_set_(vk_descriptor_set_layout),
|
||||
push_constants_(std::move(push_constants))
|
||||
{
|
||||
}
|
||||
|
@ -56,9 +56,8 @@ VKPipeline VKPipeline::create_compute_pipeline(
|
|||
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));
|
||||
return VKPipeline(vk_pipeline, descriptor_set_layout, std::move(push_constants));
|
||||
}
|
||||
|
||||
VkPipeline VKPipeline::vk_handle() const
|
||||
|
|
|
@ -21,7 +21,7 @@ class VKContext;
|
|||
|
||||
class VKPipeline : NonCopyable {
|
||||
VkPipeline vk_pipeline_ = VK_NULL_HANDLE;
|
||||
VKDescriptorSet descriptor_set_;
|
||||
VKDescriptorSetTracker descriptor_set_;
|
||||
VKPushConstants push_constants_;
|
||||
|
||||
public:
|
||||
|
@ -29,7 +29,7 @@ class VKPipeline : NonCopyable {
|
|||
|
||||
virtual ~VKPipeline();
|
||||
VKPipeline(VkPipeline vk_pipeline,
|
||||
VKDescriptorSet &&vk_descriptor_set,
|
||||
VkDescriptorSetLayout vk_descriptor_set_layout,
|
||||
VKPushConstants &&push_constants);
|
||||
VKPipeline &operator=(VKPipeline &&other)
|
||||
{
|
||||
|
@ -46,7 +46,7 @@ class VKPipeline : NonCopyable {
|
|||
VkPipelineLayout &pipeline_layouts,
|
||||
const VKPushConstants::Layout &push_constants_layout);
|
||||
|
||||
VKDescriptorSet &descriptor_set_get()
|
||||
VKDescriptorSetTracker &descriptor_set_get()
|
||||
{
|
||||
return descriptor_set_;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include "vk_pixel_buffer.hh"
|
||||
|
||||
#include "vk_context.hh"
|
||||
|
||||
namespace blender::gpu {
|
||||
|
||||
VKPixelBuffer::VKPixelBuffer(int64_t size) : PixelBuffer(size)
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include "vk_push_constants.hh"
|
||||
#include "vk_backend.hh"
|
||||
#include "vk_context.hh"
|
||||
#include "vk_memory_layout.hh"
|
||||
#include "vk_shader.hh"
|
||||
#include "vk_shader_interface.hh"
|
||||
|
@ -103,24 +104,12 @@ VKPushConstants::VKPushConstants() = default;
|
|||
VKPushConstants::VKPushConstants(const Layout *layout) : layout_(layout)
|
||||
{
|
||||
data_ = MEM_mallocN(layout->size_in_bytes(), __func__);
|
||||
switch (layout_->storage_type_get()) {
|
||||
case StorageType::UNIFORM_BUFFER:
|
||||
uniform_buffer_ = new VKUniformBuffer(layout_->size_in_bytes(), __func__);
|
||||
break;
|
||||
|
||||
case StorageType::PUSH_CONSTANTS:
|
||||
case StorageType::NONE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
VKPushConstants::VKPushConstants(VKPushConstants &&other) : layout_(other.layout_)
|
||||
{
|
||||
data_ = other.data_;
|
||||
other.data_ = nullptr;
|
||||
|
||||
uniform_buffer_ = other.uniform_buffer_;
|
||||
other.uniform_buffer_ = nullptr;
|
||||
}
|
||||
|
||||
VKPushConstants::~VKPushConstants()
|
||||
|
@ -129,9 +118,6 @@ VKPushConstants::~VKPushConstants()
|
|||
MEM_freeN(data_);
|
||||
data_ = nullptr;
|
||||
}
|
||||
|
||||
delete uniform_buffer_;
|
||||
uniform_buffer_ = nullptr;
|
||||
}
|
||||
|
||||
VKPushConstants &VKPushConstants::operator=(VKPushConstants &&other)
|
||||
|
@ -141,9 +127,6 @@ VKPushConstants &VKPushConstants::operator=(VKPushConstants &&other)
|
|||
data_ = other.data_;
|
||||
other.data_ = nullptr;
|
||||
|
||||
uniform_buffer_ = other.uniform_buffer_;
|
||||
other.uniform_buffer_ = nullptr;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -155,7 +138,7 @@ void VKPushConstants::update(VKContext &context)
|
|||
BLI_assert_msg(&pipeline.push_constants_get() == this,
|
||||
"Invalid state detected. Push constants doesn't belong to the active shader of "
|
||||
"the given context.");
|
||||
VKDescriptorSet &descriptor_set = pipeline.descriptor_set_get();
|
||||
VKDescriptorSetTracker &descriptor_set = pipeline.descriptor_set_get();
|
||||
|
||||
switch (layout_get().storage_type_get()) {
|
||||
case VKPushConstants::StorageType::NONE:
|
||||
|
@ -167,7 +150,7 @@ void VKPushConstants::update(VKContext &context)
|
|||
|
||||
case VKPushConstants::StorageType::UNIFORM_BUFFER:
|
||||
update_uniform_buffer();
|
||||
descriptor_set.bind(uniform_buffer_get(), layout_get().descriptor_set_location_get());
|
||||
descriptor_set.bind(*uniform_buffer_get(), layout_get().descriptor_set_location_get());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -175,16 +158,22 @@ void VKPushConstants::update(VKContext &context)
|
|||
void VKPushConstants::update_uniform_buffer()
|
||||
{
|
||||
BLI_assert(layout_->storage_type_get() == StorageType::UNIFORM_BUFFER);
|
||||
BLI_assert(uniform_buffer_ != nullptr);
|
||||
BLI_assert(data_ != nullptr);
|
||||
uniform_buffer_->update(data_);
|
||||
VKContext &context = *VKContext::get();
|
||||
std::unique_ptr<VKUniformBuffer> &uniform_buffer = tracked_resource_for(context, is_dirty_);
|
||||
uniform_buffer->update(data_);
|
||||
is_dirty_ = false;
|
||||
}
|
||||
|
||||
VKUniformBuffer &VKPushConstants::uniform_buffer_get()
|
||||
std::unique_ptr<VKUniformBuffer> &VKPushConstants::uniform_buffer_get()
|
||||
{
|
||||
BLI_assert(layout_->storage_type_get() == StorageType::UNIFORM_BUFFER);
|
||||
BLI_assert(uniform_buffer_ != nullptr);
|
||||
return *uniform_buffer_;
|
||||
return active_resource();
|
||||
}
|
||||
|
||||
std::unique_ptr<VKUniformBuffer> VKPushConstants::create_resource(VKContext & /*context*/)
|
||||
{
|
||||
return std::make_unique<VKUniformBuffer>(layout_->size_in_bytes(), __func__);
|
||||
}
|
||||
|
||||
} // namespace blender::gpu
|
||||
|
|
|
@ -43,7 +43,7 @@ class VKContext;
|
|||
* It should also keep track of the submissions in order to reuse the allocated
|
||||
* data.
|
||||
*/
|
||||
class VKPushConstants : NonCopyable {
|
||||
class VKPushConstants : VKResourceTracker<VKUniformBuffer> {
|
||||
public:
|
||||
/** Different methods to store push constants. */
|
||||
enum class StorageType {
|
||||
|
@ -151,7 +151,7 @@ class VKPushConstants : NonCopyable {
|
|||
private:
|
||||
const Layout *layout_ = nullptr;
|
||||
void *data_ = nullptr;
|
||||
VKUniformBuffer *uniform_buffer_ = nullptr;
|
||||
bool is_dirty_ = false;
|
||||
|
||||
public:
|
||||
VKPushConstants();
|
||||
|
@ -171,6 +171,11 @@ class VKPushConstants : NonCopyable {
|
|||
return *layout_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Part of Resource Tracking API is called when new resource is needed.
|
||||
*/
|
||||
std::unique_ptr<VKUniformBuffer> create_resource(VKContext &context) override;
|
||||
|
||||
/**
|
||||
* Get the reference to the active data.
|
||||
*
|
||||
|
@ -209,6 +214,7 @@ class VKPushConstants : NonCopyable {
|
|||
layout_->size_in_bytes(),
|
||||
"Tried to write outside the push constant allocated memory.");
|
||||
memcpy(dst, input_data, comp_len * array_size * sizeof(T));
|
||||
is_dirty_ = true;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -222,6 +228,7 @@ class VKPushConstants : NonCopyable {
|
|||
src += comp_len;
|
||||
dst += 4;
|
||||
}
|
||||
is_dirty_ = true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -243,7 +250,7 @@ class VKPushConstants : NonCopyable {
|
|||
*
|
||||
* Only valid when storage type = StorageType::UNIFORM_BUFFER.
|
||||
*/
|
||||
VKUniformBuffer &uniform_buffer_get();
|
||||
std::unique_ptr<VKUniformBuffer> &uniform_buffer_get();
|
||||
};
|
||||
|
||||
} // namespace blender::gpu
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2023 Blender Foundation. All rights reserved. */
|
||||
|
||||
/** \file
|
||||
* \ingroup gpu
|
||||
*/
|
||||
|
||||
#include "vk_resource_tracker.hh"
|
||||
#include "vk_context.hh"
|
||||
|
||||
namespace blender::gpu {
|
||||
bool VKSubmissionTracker::is_changed(VKContext &context)
|
||||
{
|
||||
VKCommandBuffer &command_buffer = context.command_buffer_get();
|
||||
const VKSubmissionID ¤t_id = command_buffer.submission_id_get();
|
||||
if (last_known_id_ != current_id) {
|
||||
last_known_id_ = current_id;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace blender::gpu
|
|
@ -0,0 +1,177 @@
|
|||
/* 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"
|
||||
|
||||
#include "vk_common.hh"
|
||||
|
||||
namespace blender::gpu {
|
||||
class VKContext;
|
||||
class VKCommandBuffer;
|
||||
|
||||
/**
|
||||
* In vulkan multiple commands can be in flight simultaneously.
|
||||
*
|
||||
* These commands can share the same resources like descriptor sets
|
||||
* or push constants. When between commands these resources are updated
|
||||
* a new version of these resources should be created.
|
||||
*
|
||||
* When a resource is updated it should check the submission id of the
|
||||
* command buffer. If it is different, then the resource can be reused.
|
||||
* If the submission id is the same a new version of the resource to now
|
||||
* intervene with other commands that uses the resource.
|
||||
*
|
||||
* VKSubmissionID is the identifier to keep track if a new submission is
|
||||
* being recorded.
|
||||
*/
|
||||
struct VKSubmissionID {
|
||||
private:
|
||||
Jeroen-Bakker marked this conversation as resolved
|
||||
int64_t id_ = -1;
|
||||
|
||||
public:
|
||||
VKSubmissionID() = default;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Reset the submission id.
|
||||
*
|
||||
* This should only be called during initialization of the command buffer.
|
||||
* As it leads to undesired behavior after resources are already tracking
|
||||
* the submission id.
|
||||
*/
|
||||
void reset()
|
||||
{
|
||||
id_ = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the submission id.
|
||||
*
|
||||
* Is called when submitting a command buffer to the queue. In this case resource
|
||||
* known that the next time it is used that it can free its sub resources used by
|
||||
* the previous submission.
|
||||
*/
|
||||
void next()
|
||||
{
|
||||
id_++;
|
||||
}
|
||||
|
||||
public:
|
||||
const VKSubmissionID &operator=(const VKSubmissionID &other)
|
||||
{
|
||||
id_ = other.id_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const VKSubmissionID &other)
|
||||
{
|
||||
return id_ == other.id_;
|
||||
}
|
||||
|
||||
bool operator!=(const VKSubmissionID &other)
|
||||
{
|
||||
return id_ != other.id_;
|
||||
}
|
||||
|
||||
friend class VKCommandBuffer;
|
||||
};
|
||||
|
||||
/**
|
||||
* Submission tracker keeps track of the last known submission id of the
|
||||
* command buffer.
|
||||
*/
|
||||
class VKSubmissionTracker {
|
||||
VKSubmissionID last_known_id_;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Check if the submission_id has changed since the last time it was called
|
||||
* on this VKSubmissionTracker.
|
||||
*/
|
||||
bool is_changed(VKContext &context);
|
||||
};
|
||||
|
||||
/**
|
||||
* VKResourceTracker will keep track of resources.
|
||||
*/
|
||||
template<typename Resource> class VKResourceTracker : NonCopyable {
|
||||
VKSubmissionTracker submission_tracker_;
|
||||
Vector<std::unique_ptr<Resource>> tracked_resources_;
|
||||
|
||||
protected:
|
||||
VKResourceTracker<Resource>() = default;
|
||||
VKResourceTracker<Resource>(VKResourceTracker<Resource> &&other)
|
||||
: submission_tracker_(other.submission_tracker_),
|
||||
tracked_resources_(std::move(other.tracked_resources_))
|
||||
{
|
||||
}
|
||||
|
||||
VKResourceTracker<Resource> &operator=(VKResourceTracker<Resource> &&other)
|
||||
{
|
||||
submission_tracker_ = other.submission_tracker_;
|
||||
tracked_resources_ = std::move(other.tracked_resources_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
virtual ~VKResourceTracker()
|
||||
{
|
||||
free_tracked_resources();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a resource what can be used by the resource tracker.
|
||||
*
|
||||
* When a different submission was detected all previous resources
|
||||
* will be freed and a new resource will be returned.
|
||||
*
|
||||
* When still in the same submission and we need to update the resource
|
||||
* (is_dirty=true) then a new resource will be returned. Otherwise
|
||||
* the previous used resource will be used.
|
||||
*
|
||||
* When no resources exists, a new resource will be created.
|
||||
*
|
||||
* The resource given back is owned by this resource tracker. And
|
||||
* the resource should not be stored outside this class as it might
|
||||
* be destroyed when the next submission is detected.
|
||||
*/
|
||||
std::unique_ptr<Resource> &tracked_resource_for(VKContext &context, const bool is_dirty)
|
||||
{
|
||||
if (submission_tracker_.is_changed(context)) {
|
||||
free_tracked_resources();
|
||||
tracked_resources_.append(create_resource(context));
|
||||
}
|
||||
else if (is_dirty || tracked_resources_.is_empty()) {
|
||||
tracked_resources_.append(create_resource(context));
|
||||
}
|
||||
return active_resource();
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to create a new resource. Can be called by the `tracked_resource_for` method.
|
||||
*/
|
||||
virtual std::unique_ptr<Resource> create_resource(VKContext &context) = 0;
|
||||
|
||||
/**
|
||||
* Return the active resource of the tracker.
|
||||
*/
|
||||
std::unique_ptr<Resource> &active_resource()
|
||||
{
|
||||
BLI_assert(!tracked_resources_.is_empty());
|
||||
return tracked_resources_.last();
|
||||
}
|
||||
|
||||
private:
|
||||
void free_tracked_resources()
|
||||
{
|
||||
tracked_resources_.clear();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace blender::gpu
|
|
@ -7,13 +7,15 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "BLI_utility_mixins.hh"
|
||||
|
||||
#include "gpu_uniform_buffer_private.hh"
|
||||
|
||||
#include "vk_buffer.hh"
|
||||
|
||||
namespace blender::gpu {
|
||||
|
||||
class VKUniformBuffer : public UniformBuf {
|
||||
class VKUniformBuffer : public UniformBuf, NonCopyable {
|
||||
VKBuffer buffer_;
|
||||
|
||||
public:
|
||||
|
|
Loading…
Reference in New Issue
So it is a vulkan specific struct but does not have a
VK
prefix? Either add the prefix or move togpu/intern
.Same thing for
ResourceTracker