Skip to content

Commit

Permalink
* vk renderer2 - Support for doing scratch commands
Browse files Browse the repository at this point in the history
  • Loading branch information
harrand committed Mar 5, 2023
1 parent c06aca8 commit 5b48688
Show file tree
Hide file tree
Showing 4 changed files with 230 additions and 22 deletions.
10 changes: 10 additions & 0 deletions src/tz/gl/impl/vulkan/device2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,16 @@ namespace tz::gl
temp_fence.wait_until_signalled();
}

void device_command_pool::vk_submit_command(unsigned int fingerprint, std::size_t allocation_id, std::size_t buffer_id, vk2::hardware::Queue::SubmitInfo submit)
{
#if TZ_DEBUG
std::size_t debug_real_alloc_length = this->fingerprint_allocation_history[fingerprint].size();
tz::assert(debug_real_alloc_length > buffer_id, "attempted to submit & run scratch command buffer id %zu at (fingerprint:allocid) %u:%zu. there are only %zu buffers in this allocation. please submit a bug report.", buffer_id, fingerprint, allocation_id, debug_real_alloc_length);
#endif // TZ_DEBUG

this->get_original_queue(this->fingerprint_alloc_types[fingerprint])->submit(submit);
}

vk2::CommandPool::AllocationResult device_command_pool::impl_allocate_commands(const vk2::CommandPool::Allocation& alloc, unsigned int fingerprint, unsigned int attempt)
{
// allocate using the most recently created descriptor pool
Expand Down
1 change: 1 addition & 0 deletions src/tz/gl/impl/vulkan/device2.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ namespace tz::gl
void vk_free_commands(unsigned int fingerprint, std::size_t allocation_id, std::span<vk2::CommandBuffer> command_buffers);
void vk_command_pool_touch(unsigned int fingerprint, fingerprint_info_t finfo);
void vk_submit_and_run_commands_blocking(unsigned int fingerprint, std::size_t allocation_id, std::size_t buffer_id, const vk2::CommandBuffer& buffer);
void vk_submit_command(unsigned int fingerprint, std::size_t allocation_id, std::size_t buffer_id, vk2::hardware::Queue::SubmitInfo submit);
private:
struct allocation_history
{
Expand Down
206 changes: 198 additions & 8 deletions src/tz/gl/impl/vulkan/renderer2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -423,15 +423,23 @@ namespace tz::gl
// tell the device to do all the writes.
tz::gl::get_device2().vk_update_sets(update, renderer_vulkan_base::uid);
}
//--------------------------------------------------------------------------------------------------

renderer_output_manager::renderer_output_manager(const tz::gl::renderer_info& rinfo):
renderer_descriptor_manager(rinfo)
{

}

//--------------------------------------------------------------------------------------------------

renderer_command_processor::renderer_command_processor(const tz::gl::renderer_info& rinfo):
renderer_descriptor_manager(rinfo),
renderer_output_manager(rinfo),
render_wait_enabled(rinfo.get_options().contains(tz::gl::renderer_option::render_wait))
{
TZ_PROFZONE("renderer_command_processor - initialise", 0xFFAAAA00);
this->allocate_commands(command_type::both);
this->scratch_initialise_static_resources();
}

renderer_command_processor::~renderer_command_processor()
Expand All @@ -441,6 +449,12 @@ namespace tz::gl

void renderer_command_processor::do_scratch_work(std::function<void(vk2::CommandBufferRecording&)> record_commands)
{
TZ_PROFZONE("renderer_command_processor - scratch work...", 0xFFAAAA00);
if(this->scratch_command_buffer().command_count() > 0)
{
// this scratch command buffer is already populated with potentially different commands. purge and go again.
this->allocate_commands(command_type::scratch);
}
vk2::CommandBuffer& buf = this->scratch_command_buffer();
// firstly record the commands requested.
{
Expand All @@ -452,6 +466,26 @@ namespace tz::gl
tz::gl::get_device2().vk_submit_and_run_commands_blocking(renderer_vulkan_base::uid, scratch_id, 0, buf);
}

void renderer_command_processor::set_work_commands(std::function<void(vk2::CommandBufferRecording&, unsigned int)> work_record_commands)
{
TZ_PROFZONE("renderer_command_processor - set work commands", 0xFFAAAA00);
auto bufs = this->work_command_buffers();
if(std::any_of(bufs.begin(), bufs.end(), [](const auto& work_buf)
{
tz::assert(!work_buf.is_recording(), "attempt to set work commands while one or more of them is recording. sync error. please submit a bug report.");
return work_buf.command_count() > 0;
}))
{
// if any of the work command buffers have already been recorded, we need to purge.
this->allocate_commands(command_type::work);
}
for(unsigned int i = 0; i < bufs.size(); i++)
{
vk2::CommandBufferRecording record = bufs[i].record();
work_record_commands(record, i);
}
}

constexpr std::size_t cmdbuf_work_alloc_id = 0;
constexpr std::size_t cmdbuf_scratch_alloc_id = 1;

Expand Down Expand Up @@ -489,6 +523,7 @@ namespace tz::gl

void renderer_command_processor::free_commands(renderer_command_processor::command_type t)
{
TZ_PROFZONE("renderer_command_processor - free commands", 0xFFAAAA00);
if(this->command_allocations.empty())
{
return;
Expand All @@ -513,16 +548,133 @@ namespace tz::gl
void renderer_command_processor::scratch_initialise_static_resources()
{
TZ_PROFZONE("renderer_command_processor - scratch initialise static resources", 0xFFAAAA00);
// now the scratch buffer might've already been recorded earlier with commands. if so, we need to realloc it.
if(this->scratch_command_buffer().command_count() > 0)
// we need to create a staging buffer for each static_fixed buffer and image resource we have.
// these staging buffers should be cpu-writable (like a dynamic-fixed buffer resource), and we write in the data in the mapped ptr just like a dynamic resource.
// afterwards, we record a scratch buffer which does transfers between each staging buffer and its corresponding static resource.
// we then instantly wait on this work to be complete.
std::vector<vk2::Buffer> resource_staging_buffers;
resource_staging_buffers.reserve(renderer_resource_manager::resource_count());
for(std::size_t i = 0; i < renderer_resource_manager::resource_count(); i++)
{
// allocate already purges previous alloc, so just need to call free_commands aswell.
this->allocate_commands(command_type::scratch);
const icomponent* cmp = renderer_resource_manager::get_component(static_cast<tz::hanval>(i));
tz::assert(cmp != nullptr);
const iresource* res = cmp->get_resource();
tz::assert(res != nullptr);
if(res->get_access() != tz::gl::resource_access::static_fixed)
{
resource_staging_buffers.push_back(vk2::Buffer::null());
continue;
}
switch(res->get_type())
{
// create staging buffers and copy over spans.
case tz::gl::resource_type::buffer:
resource_staging_buffers.push_back
({{
.device = &tz::gl::get_device2().vk_get_logical_device(),
.size_bytes = res->data().size_bytes(),
.usage = {vk2::BufferUsage::TransferSource},
.residency = vk2::MemoryResidency::CPU
}});
break;
case tz::gl::resource_type::image:
{
auto* img = static_cast<const image_component_vulkan*>(cmp);
tz::assert(img != nullptr);
resource_staging_buffers.push_back
({{
.device = &tz::gl::get_device2().vk_get_logical_device(),
.size_bytes = tz::gl::pixel_size_bytes(img->get_format()) * img->get_dimensions()[0] * img->get_dimensions()[1],
.usage = {vk2::BufferUsage::TransferSource},
.residency = vk2::MemoryResidency::CPU
}});
}
break;
default:
tz::error("unrecognised resource_type. memory corruption?");
break;
}
// get the new staging buffer
vk2::Buffer& new_buf = resource_staging_buffers.back();
// write resource data
{
void* mapped_ptr = new_buf.map();
std::memcpy(mapped_ptr, res->data().data(), res->data().size_bytes());
new_buf.unmap();
}
}
this->do_scratch_work([](vk2::CommandBufferRecording& record)
this->do_static_resource_transfers(resource_staging_buffers);
}

void renderer_command_processor::do_static_resource_transfers(std::span<vk2::Buffer> resource_staging_buffers)
{
TZ_PROFZONE("renderer_command_processor - do static resource transfers", 0xFFAAAA00);
tz::assert(resource_staging_buffers.size() == renderer_resource_manager::resource_count(), "unexpected number of resource staging buffers. expected %u, got %zu", renderer_resource_manager::resource_count(), resource_staging_buffers.size());
this->do_scratch_work([this, &resource_staging_buffers](vk2::CommandBufferRecording& recording)
{
(void)record;
tz::error("NYI");
// we now have all the staging buffers we need. do all necessary transfers.
for(std::size_t i = 0; i < resource_staging_buffers.size(); i++)
{
vk2::Buffer& staging_buffer = resource_staging_buffers[i];
tz::gl::icomponent* cmp = renderer_resource_manager::get_component(static_cast<tz::hanval>(i));
const tz::gl::iresource* res = cmp->get_resource();
if(staging_buffer.is_null())
{
continue;
}
tz::assert(res->get_access() == tz::gl::resource_access::static_fixed, "while initialising static resources, detected non-static-fixed resource at handle %zu that somehow ended up with a non-null staging buffer. logic error. please submit a bug report.", i);
switch(res->get_type())
{
case tz::gl::resource_type::buffer:
// super easy, just copy the buffer.
recording.buffer_copy_buffer
({
.src = &staging_buffer,
.dst = &static_cast<buffer_component_vulkan*>(cmp)->vk_get_buffer()
});
break;
case tz::gl::resource_type::image:
{
// not so easy. copy the buffer, but do some layout transitions first.
vk2::Image& img = static_cast<image_component_vulkan*>(cmp)->vk_get_image();
vk2::ImageAspectFlags aspect = vk2::derive_aspect_from_format(img.get_format());
// Image will initially be in undefined layout. We need to:
// - Transition the texture component to TransferDestination
// - Transfer from the staging texture buffer
// - Transition the texture component to ShaderResource so it can be used in the shader.
recording.transition_image_layout
({
.image = &img,
.target_layout = vk2::ImageLayout::TransferDestination,
.source_access = {vk2::AccessFlag::NoneNeeded},
.destination_access = {vk2::AccessFlag::TransferOperationWrite},
.source_stage = vk2::PipelineStage::Top,
.destination_stage = vk2::PipelineStage::TransferCommands,
.image_aspects = aspect
});
recording.buffer_copy_image
({
.src = &staging_buffer,
.dst = &img,
.image_aspects = aspect
});
recording.transition_image_layout
({
.image = &img,
.target_layout = vk2::ImageLayout::ShaderResource,
.source_access = {vk2::AccessFlag::TransferOperationWrite},
.destination_access = {vk2::AccessFlag::ShaderResourceRead},
.source_stage = vk2::PipelineStage::TransferCommands,
.destination_stage = vk2::PipelineStage::FragmentShader,
.image_aspects = aspect
});
}
break;
default:
tz::error("invalid resource_type. memory corruption?");
break;
}
}
});
}

Expand All @@ -548,6 +700,12 @@ namespace tz::gl

}

const ioutput* renderer_vulkan2::get_output() const
{
tz::error("NYI");
return nullptr;
}

const tz::gl::renderer_options& renderer_vulkan2::get_options() const
{
return this->options;
Expand All @@ -557,4 +715,36 @@ namespace tz::gl
{
return this->state;
}

void renderer_vulkan2::render()
{
tz::error("NYI");
}

void renderer_vulkan2::edit(tz::gl::renderer_edit_request req)
{
(void)req;
tz::error("NYI");
}

void renderer_vulkan2::dbgui()
{
tz::error("NYI");
}

std::string_view renderer_vulkan2::debug_get_name() const
{
return "NYI";
}

renderer_vulkan2 renderer_vulkan2::null()
{
return {};
}

bool renderer_vulkan2::is_null() const
{
tz::error("NYI");
return true;
}
}
35 changes: 21 additions & 14 deletions src/tz/gl/impl/vulkan/renderer2.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,24 +72,35 @@ namespace tz::gl
vk2::DescriptorPool::AllocationResult descriptors = {};
};

class renderer_command_processor : public renderer_descriptor_manager
class renderer_output_manager : public renderer_descriptor_manager
{
public:
renderer_output_manager(const tz::gl::renderer_info& rinfo);
renderer_output_manager() = default;
private:
};

class renderer_command_processor : public renderer_output_manager
{
public:
renderer_command_processor(const tz::gl::renderer_info& info);
~renderer_command_processor();
renderer_command_processor() = default;
void do_scratch_work(std::function<void(vk2::CommandBufferRecording&)> record_commands);

enum class command_type
{
work,
scratch,
both
};
protected:
void do_scratch_work(std::function<void(vk2::CommandBufferRecording&)> record_commands);
void set_work_commands(std::function<void(vk2::CommandBufferRecording&, unsigned int)> work_record_commands);
private:
void allocate_commands(command_type t = command_type::both);
void free_commands(command_type t = command_type::both);
void scratch_initialise_static_resources();
void do_static_resource_transfers(std::span<vk2::Buffer> resource_staging_buffers);

std::span<vk2::CommandBuffer> work_command_buffers();
vk2::CommandBuffer& scratch_command_buffer();
Expand All @@ -101,23 +112,19 @@ namespace tz::gl
{
public:
renderer_vulkan2(const tz::gl::renderer_info& rinfo);
// Satisfies tz::nullable
static renderer_vulkan2 null();
bool is_null() const;

// NYI
const ioutput* get_output() const {return nullptr;}
const ioutput* get_output() const;
const tz::gl::renderer_options& get_options() const;
const tz::gl::render_state& get_state() const;
void render();
void edit(tz::gl::renderer_edit_request req);
void dbgui();
// NYI
void render() {}
// NYI
void edit(tz::gl::renderer_edit_request req){(void)req;}
// NYI
void dbgui(){}
// NYI
std::string_view debug_get_name(){return "NYI";}
std::string_view debug_get_name() const;

// Satisfies tz::nullable
static renderer_vulkan2 null();
bool is_null() const;
private:
renderer_vulkan2() = default;

Expand Down

0 comments on commit 5b48688

Please sign in to comment.