17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-26 15:54:53 +01:00
Files
maszyna/rendering/vulkan14/vulkan14commands.cpp

1005 lines
32 KiB
C++

/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#include "stdafx.h"
#include "rendering/vulkan14/vulkan14commands.h"
#include <algorithm>
#include <cassert>
#include <cstring>
namespace vk14
{
namespace
{
enum call_type : std::uint32_t
{
call_begin_rendering,
call_end_rendering,
call_pipeline_barrier,
call_bind_pipeline,
call_bind_descriptor_sets,
call_push_descriptors,
call_push_constants,
call_bind_vertex_buffers,
call_bind_index_buffer,
call_draw,
call_draw_indexed,
call_draw_indirect,
call_draw_indexed_indirect,
call_dispatch,
call_dispatch_indirect,
call_set_viewport,
call_set_scissor,
call_set_cull_mode,
call_set_front_face,
call_set_topology,
call_set_depth_test,
call_set_depth_write,
call_set_depth_compare,
call_set_depth_bias_enable,
call_set_depth_bias,
call_set_primitive_restart,
call_set_stencil_test,
call_fill_buffer,
call_update_buffer,
call_copy_buffer,
call_copy_image,
call_copy_buffer_to_image,
call_copy_image_to_buffer,
call_blit_image,
call_clear_color_image,
call_clear_depth_stencil_image,
call_write_timestamp,
call_reset_query_pool,
call_begin_query,
call_end_query,
call_begin_label,
call_end_label
};
struct call_header
{
std::uint32_t type;
std::uint32_t size; // bytes of the call with its header and its data, a multiple of 8
};
static_assert(sizeof(call_header) == 8, "the header of a call of a stream");
std::size_t constexpr no_data{~static_cast<std::size_t>(0)};
struct rendering_call
{
VkRenderingInfo info;
std::size_t colours;
std::size_t depth;
std::size_t stencil;
};
struct barrier_call
{
VkDependencyFlags flags;
std::uint32_t memory_count, buffer_count, image_count;
std::size_t memory, buffers, images;
};
struct pipeline_call
{
VkPipelineBindPoint bind_point;
VkPipeline pipeline;
};
struct sets_call
{
VkBindDescriptorSetsInfo info;
std::size_t sets;
std::size_t offsets;
};
struct pushed_call
{
VkPushDescriptorSetWithTemplateInfo info;
std::size_t data;
};
struct constants_call
{
VkPushConstantsInfo info;
std::size_t data;
};
struct vertex_buffers_call
{
std::uint32_t first, count;
std::size_t buffers, offsets;
};
struct index_buffer_call
{
VkBuffer buffer;
VkDeviceSize offset;
VkIndexType type;
};
struct draw_call
{
std::uint32_t vertices, instances, first_vertex, first_instance;
};
struct draw_indexed_call
{
std::uint32_t indices, instances, first_index;
std::int32_t vertex_offset;
std::uint32_t first_instance;
};
struct indirect_call
{
VkBuffer buffer;
VkDeviceSize offset;
std::uint32_t count, stride;
};
struct dispatch_call
{
std::uint32_t x, y, z;
};
struct viewports_call
{
std::uint32_t first, count;
std::size_t data;
};
struct value_call
{
std::uint32_t value;
};
struct bias_call
{
float constant, clamp, slope;
};
struct fill_call
{
VkBuffer buffer;
VkDeviceSize offset, size;
std::uint32_t data;
};
struct update_call
{
VkBuffer buffer;
VkDeviceSize offset, size;
std::size_t data;
};
// the copies and the blit: the info with its regions
template <typename Info_> struct copy_call
{
Info_ info;
std::size_t regions;
};
struct clear_call
{
VkImage image;
VkImageLayout layout;
VkClearColorValue colour;
VkClearDepthStencilValue depth;
std::uint32_t count;
std::size_t ranges;
};
struct query_call
{
VkPipelineStageFlags2 stage;
VkQueryPool pool;
std::uint32_t query, count;
VkQueryControlFlags flags;
};
struct label_call
{
float colour[4];
std::size_t name;
};
bool compute_stages(VkShaderStageFlags const Stages)
{
return (Stages & VK_SHADER_STAGE_COMPUTE_BIT) != 0;
}
bool graphics_stages(VkShaderStageFlags const Stages)
{
return (Stages & ~static_cast<VkShaderStageFlags>(VK_SHADER_STAGE_COMPUTE_BIT)) != 0;
}
} // namespace
void command_stream::clear()
{
m_data.clear();
m_chunks.clear();
m_chunks.emplace_back();
m_state.fill(no_call);
m_pushes.clear();
m_rendering = no_call;
m_queries = 0;
m_work = 0;
m_calls = 0;
m_finished = false;
}
std::size_t command_stream::add(std::uint32_t const Type, std::size_t const Size)
{
if (m_chunks.empty())
{
clear();
}
auto const call{m_data.size()};
auto const bytes{(header_size + Size + 7) & ~static_cast<std::size_t>(7)};
m_data.resize(call + bytes);
auto &header{*reinterpret_cast<call_header *>(m_data.data() + call)};
header.type = Type;
header.size = static_cast<std::uint32_t>(bytes);
++m_calls;
return call;
}
std::size_t command_stream::append(void const *Data, std::size_t const Bytes)
{
if ((Data == nullptr) || (Bytes == 0))
{
return no_data;
}
auto const offset{m_data.size()};
m_data.resize(offset + ((Bytes + 7) & ~static_cast<std::size_t>(7)));
std::memcpy(m_data.data() + offset, Data, Bytes);
return offset;
}
void command_stream::close(std::size_t const Call)
{
reinterpret_cast<call_header *>(m_data.data() + Call)->size = static_cast<std::uint32_t>(m_data.size() - Call);
}
void command_stream::work()
{
if ((++m_work >= chunk_work) && (m_queries == 0))
{
cut();
}
}
void command_stream::cut()
{
auto &current{m_chunks.back()};
current.end = m_data.size();
current.suspended = m_rendering;
chunk next;
next.first = m_data.size();
next.resumed = m_rendering;
// the state the next chunk starts with: the last call of each kind, in the order they were made
for (auto const call : m_state)
{
if (call != no_call)
{
next.state.push_back(call);
}
}
next.state.insert(next.state.end(), m_pushes.begin(), m_pushes.end());
std::sort(next.state.begin(), next.state.end());
next.state.erase(std::unique(next.state.begin(), next.state.end()), next.state.end());
m_chunks.push_back(std::move(next));
m_work = 0;
}
void command_stream::finish()
{
if (m_chunks.empty())
{
clear();
}
m_chunks.back().end = m_data.size();
m_chunks.back().suspended = no_call;
// a chunk left without calls
if ((m_chunks.size() > 1) && (m_chunks.back().first == m_chunks.back().end))
{
m_chunks.pop_back();
m_chunks.back().suspended = no_call;
}
m_finished = true;
}
// the calls
void command_stream::begin_rendering(VkRenderingInfo const *Info)
{
auto const call{add(call_begin_rendering, sizeof(rendering_call))};
auto const colours{append(Info->pColorAttachments, sizeof(VkRenderingAttachmentInfo) * Info->colorAttachmentCount)};
auto const depth{append(Info->pDepthAttachment, Info->pDepthAttachment != nullptr ? sizeof(VkRenderingAttachmentInfo) : 0)};
auto const stencil{append(Info->pStencilAttachment, Info->pStencilAttachment != nullptr ? sizeof(VkRenderingAttachmentInfo) : 0)};
auto &data{payload<rendering_call>(call)};
data.info = *Info;
assert(Info->pNext == nullptr);
data.info.pNext = nullptr;
data.info.pColorAttachments = nullptr;
data.info.pDepthAttachment = nullptr;
data.info.pStencilAttachment = nullptr;
data.colours = colours;
data.depth = depth;
data.stencil = stencil;
close(call);
m_rendering = call;
}
void command_stream::end_rendering()
{
add(call_end_rendering, 0);
m_rendering = no_call;
work();
}
void command_stream::pipeline_barrier2(VkDependencyInfo const *Dependency)
{
assert(Dependency->pNext == nullptr);
auto const call{add(call_pipeline_barrier, sizeof(barrier_call))};
auto const memory{append(Dependency->pMemoryBarriers, sizeof(VkMemoryBarrier2) * Dependency->memoryBarrierCount)};
auto const buffers{append(Dependency->pBufferMemoryBarriers, sizeof(VkBufferMemoryBarrier2) * Dependency->bufferMemoryBarrierCount)};
auto const images{append(Dependency->pImageMemoryBarriers, sizeof(VkImageMemoryBarrier2) * Dependency->imageMemoryBarrierCount)};
auto &data{payload<barrier_call>(call)};
data.flags = Dependency->dependencyFlags;
data.memory_count = Dependency->memoryBarrierCount;
data.buffer_count = Dependency->bufferMemoryBarrierCount;
data.image_count = Dependency->imageMemoryBarrierCount;
data.memory = memory;
data.buffers = buffers;
data.images = images;
close(call);
}
void command_stream::bind_pipeline(VkPipelineBindPoint const BindPoint, VkPipeline const Pipeline)
{
auto const call{add(call_bind_pipeline, sizeof(pipeline_call))};
payload<pipeline_call>(call) = pipeline_call{BindPoint, Pipeline};
remember(BindPoint == VK_PIPELINE_BIND_POINT_COMPUTE ? pipeline_compute : pipeline_graphics, call);
}
void command_stream::bind_descriptor_sets2(VkBindDescriptorSetsInfo const *Info)
{
auto const call{add(call_bind_descriptor_sets, sizeof(sets_call))};
auto const sets{append(Info->pDescriptorSets, sizeof(VkDescriptorSet) * Info->descriptorSetCount)};
auto const offsets{append(Info->pDynamicOffsets, sizeof(std::uint32_t) * Info->dynamicOffsetCount)};
auto &data{payload<sets_call>(call)};
data.info = *Info;
assert(Info->pNext == nullptr);
data.info.pNext = nullptr;
data.info.pDescriptorSets = nullptr;
data.info.pDynamicOffsets = nullptr;
data.sets = sets;
data.offsets = offsets;
close(call);
assert(Info->firstSet + Info->descriptorSetCount <= set_slots);
for (std::uint32_t set = Info->firstSet; (set < Info->firstSet + Info->descriptorSetCount) && (set < set_slots); ++set)
{
// a bind for the stages of both kinds stands for both
if (compute_stages(Info->stageFlags))
{
remember(sets_compute + set, call);
}
if (graphics_stages(Info->stageFlags))
{
remember(sets_graphics + set, call);
}
}
}
void command_stream::push_descriptor_set_with_template2(VkPushDescriptorSetWithTemplateInfo const *Info, std::size_t const Size, VkPipelineBindPoint const BindPoint)
{
auto const call{add(call_push_descriptors, sizeof(pushed_call))};
auto const data{append(Info->pData, Size)};
auto &call_data{payload<pushed_call>(call)};
call_data.info = *Info;
assert(Info->pNext == nullptr);
call_data.info.pNext = nullptr;
call_data.info.pData = nullptr;
call_data.data = data;
close(call);
assert(Info->set < set_slots);
if (Info->set < set_slots)
{
remember((BindPoint == VK_PIPELINE_BIND_POINT_COMPUTE ? pushed_compute : pushed_graphics) + Info->set, call);
}
}
void command_stream::push_constants2(VkPushConstantsInfo const *Info)
{
auto const call{add(call_push_constants, sizeof(constants_call))};
auto const data{append(Info->pValues, Info->size)};
auto &call_data{payload<constants_call>(call)};
call_data.info = *Info;
assert(Info->pNext == nullptr);
call_data.info.pNext = nullptr;
call_data.info.pValues = nullptr;
call_data.data = data;
close(call);
// a push of a part of the constants leaves the rest as the pushes before it made them: the last push of each range and stages
// is kept, the pushes are made again in their order
m_pushes.erase(std::remove_if(m_pushes.begin(), m_pushes.end(),
[&](std::size_t const Push) {
auto const &info{payload<constants_call>(Push).info};
return (info.offset == Info->offset) && (info.size == Info->size) && (info.stageFlags == Info->stageFlags);
}),
m_pushes.end());
m_pushes.push_back(call);
}
void command_stream::bind_vertex_buffers(std::uint32_t const First, std::uint32_t const Count, VkBuffer const *Buffers, VkDeviceSize const *Offsets)
{
auto const call{add(call_bind_vertex_buffers, sizeof(vertex_buffers_call))};
auto const buffers{append(Buffers, sizeof(VkBuffer) * Count)};
auto const offsets{append(Offsets, sizeof(VkDeviceSize) * Count)};
payload<vertex_buffers_call>(call) = vertex_buffers_call{First, Count, buffers, offsets};
close(call);
assert(First + Count <= vertex_slots);
for (std::uint32_t binding = First; (binding < First + Count) && (binding < vertex_slots); ++binding)
{
remember(vertex_buffers + binding, call);
}
}
void command_stream::bind_index_buffer(VkBuffer const Buffer, VkDeviceSize const Offset, VkIndexType const Type)
{
auto const call{add(call_bind_index_buffer, sizeof(index_buffer_call))};
payload<index_buffer_call>(call) = index_buffer_call{Buffer, Offset, Type};
remember(index_buffer, call);
}
void command_stream::draw(std::uint32_t const Vertices, std::uint32_t const Instances, std::uint32_t const FirstVertex, std::uint32_t const FirstInstance)
{
auto const call{add(call_draw, sizeof(draw_call))};
payload<draw_call>(call) = draw_call{Vertices, Instances, FirstVertex, FirstInstance};
work();
}
void command_stream::draw_indexed(std::uint32_t const Indices, std::uint32_t const Instances, std::uint32_t const FirstIndex, std::int32_t const VertexOffset, std::uint32_t const FirstInstance)
{
auto const call{add(call_draw_indexed, sizeof(draw_indexed_call))};
payload<draw_indexed_call>(call) = draw_indexed_call{Indices, Instances, FirstIndex, VertexOffset, FirstInstance};
work();
}
void command_stream::draw_indirect(VkBuffer const Buffer, VkDeviceSize const Offset, std::uint32_t const Count, std::uint32_t const Stride)
{
auto const call{add(call_draw_indirect, sizeof(indirect_call))};
payload<indirect_call>(call) = indirect_call{Buffer, Offset, Count, Stride};
work();
}
void command_stream::draw_indexed_indirect(VkBuffer const Buffer, VkDeviceSize const Offset, std::uint32_t const Count, std::uint32_t const Stride)
{
auto const call{add(call_draw_indexed_indirect, sizeof(indirect_call))};
payload<indirect_call>(call) = indirect_call{Buffer, Offset, Count, Stride};
work();
}
void command_stream::dispatch(std::uint32_t const X, std::uint32_t const Y, std::uint32_t const Z)
{
auto const call{add(call_dispatch, sizeof(dispatch_call))};
payload<dispatch_call>(call) = dispatch_call{X, Y, Z};
work();
}
void command_stream::dispatch_indirect(VkBuffer const Buffer, VkDeviceSize const Offset)
{
auto const call{add(call_dispatch_indirect, sizeof(indirect_call))};
payload<indirect_call>(call) = indirect_call{Buffer, Offset, 0, 0};
work();
}
void command_stream::set_viewport(std::uint32_t const First, std::uint32_t const Count, VkViewport const *Viewports)
{
auto const call{add(call_set_viewport, sizeof(viewports_call))};
auto const data{append(Viewports, sizeof(VkViewport) * Count)};
payload<viewports_call>(call) = viewports_call{First, Count, data};
close(call);
remember(viewport, call);
}
void command_stream::set_scissor(std::uint32_t const First, std::uint32_t const Count, VkRect2D const *Scissors)
{
auto const call{add(call_set_scissor, sizeof(viewports_call))};
auto const data{append(Scissors, sizeof(VkRect2D) * Count)};
payload<viewports_call>(call) = viewports_call{First, Count, data};
close(call);
remember(scissor, call);
}
#define VK14_VALUE_CALL(Name, Type, Call, Slot) \
void command_stream::Name(Type const Value) \
{ \
auto const call{add(Call, sizeof(value_call))}; \
payload<value_call>(call) = value_call{static_cast<std::uint32_t>(Value)}; \
remember(Slot, call); \
}
VK14_VALUE_CALL(set_cull_mode, VkCullModeFlags, call_set_cull_mode, cull_mode)
VK14_VALUE_CALL(set_front_face, VkFrontFace, call_set_front_face, front_face)
VK14_VALUE_CALL(set_primitive_topology, VkPrimitiveTopology, call_set_topology, topology)
VK14_VALUE_CALL(set_depth_test_enable, VkBool32, call_set_depth_test, depth_test)
VK14_VALUE_CALL(set_depth_write_enable, VkBool32, call_set_depth_write, depth_write)
VK14_VALUE_CALL(set_depth_compare_op, VkCompareOp, call_set_depth_compare, depth_compare)
VK14_VALUE_CALL(set_depth_bias_enable, VkBool32, call_set_depth_bias_enable, depth_bias_enable)
VK14_VALUE_CALL(set_primitive_restart_enable, VkBool32, call_set_primitive_restart, primitive_restart)
VK14_VALUE_CALL(set_stencil_test_enable, VkBool32, call_set_stencil_test, stencil_test)
#undef VK14_VALUE_CALL
void command_stream::set_depth_bias(float const Constant, float const Clamp, float const Slope)
{
auto const call{add(call_set_depth_bias, sizeof(bias_call))};
payload<bias_call>(call) = bias_call{Constant, Clamp, Slope};
remember(depth_bias, call);
}
void command_stream::fill_buffer(VkBuffer const Buffer, VkDeviceSize const Offset, VkDeviceSize const Size, std::uint32_t const Data)
{
auto const call{add(call_fill_buffer, sizeof(fill_call))};
payload<fill_call>(call) = fill_call{Buffer, Offset, Size, Data};
work();
}
void command_stream::update_buffer(VkBuffer const Buffer, VkDeviceSize const Offset, VkDeviceSize const Size, void const *Data)
{
auto const call{add(call_update_buffer, sizeof(update_call))};
auto const data{append(Data, static_cast<std::size_t>(Size))};
payload<update_call>(call) = update_call{Buffer, Offset, Size, data};
close(call);
work();
}
void command_stream::copy_buffer2(VkCopyBufferInfo2 const *Info)
{
auto const call{add(call_copy_buffer, sizeof(copy_call<VkCopyBufferInfo2>))};
auto const regions{append(Info->pRegions, sizeof(VkBufferCopy2) * Info->regionCount)};
auto &data{payload<copy_call<VkCopyBufferInfo2>>(call)};
data.info = *Info;
assert(Info->pNext == nullptr);
data.info.pNext = nullptr;
data.info.pRegions = nullptr;
data.regions = regions;
close(call);
work();
}
void command_stream::copy_image2(VkCopyImageInfo2 const *Info)
{
auto const call{add(call_copy_image, sizeof(copy_call<VkCopyImageInfo2>))};
auto const regions{append(Info->pRegions, sizeof(VkImageCopy2) * Info->regionCount)};
auto &data{payload<copy_call<VkCopyImageInfo2>>(call)};
data.info = *Info;
assert(Info->pNext == nullptr);
data.info.pNext = nullptr;
data.info.pRegions = nullptr;
data.regions = regions;
close(call);
work();
}
void command_stream::copy_buffer_to_image2(VkCopyBufferToImageInfo2 const *Info)
{
auto const call{add(call_copy_buffer_to_image, sizeof(copy_call<VkCopyBufferToImageInfo2>))};
auto const regions{append(Info->pRegions, sizeof(VkBufferImageCopy2) * Info->regionCount)};
auto &data{payload<copy_call<VkCopyBufferToImageInfo2>>(call)};
data.info = *Info;
assert(Info->pNext == nullptr);
data.info.pNext = nullptr;
data.info.pRegions = nullptr;
data.regions = regions;
close(call);
work();
}
void command_stream::copy_image_to_buffer2(VkCopyImageToBufferInfo2 const *Info)
{
auto const call{add(call_copy_image_to_buffer, sizeof(copy_call<VkCopyImageToBufferInfo2>))};
auto const regions{append(Info->pRegions, sizeof(VkBufferImageCopy2) * Info->regionCount)};
auto &data{payload<copy_call<VkCopyImageToBufferInfo2>>(call)};
data.info = *Info;
assert(Info->pNext == nullptr);
data.info.pNext = nullptr;
data.info.pRegions = nullptr;
data.regions = regions;
close(call);
work();
}
void command_stream::blit_image2(VkBlitImageInfo2 const *Info)
{
auto const call{add(call_blit_image, sizeof(copy_call<VkBlitImageInfo2>))};
auto const regions{append(Info->pRegions, sizeof(VkImageBlit2) * Info->regionCount)};
auto &data{payload<copy_call<VkBlitImageInfo2>>(call)};
data.info = *Info;
assert(Info->pNext == nullptr);
data.info.pNext = nullptr;
data.info.pRegions = nullptr;
data.regions = regions;
close(call);
work();
}
void command_stream::clear_color_image(VkImage const Image, VkImageLayout const Layout, VkClearColorValue const *Color, std::uint32_t const Count, VkImageSubresourceRange const *Ranges)
{
auto const call{add(call_clear_color_image, sizeof(clear_call))};
auto const ranges{append(Ranges, sizeof(VkImageSubresourceRange) * Count)};
auto &data{payload<clear_call>(call)};
data.image = Image;
data.layout = Layout;
data.colour = *Color;
data.depth = {};
data.count = Count;
data.ranges = ranges;
close(call);
work();
}
void command_stream::clear_depth_stencil_image(VkImage const Image, VkImageLayout const Layout, VkClearDepthStencilValue const *Value, std::uint32_t const Count, VkImageSubresourceRange const *Ranges)
{
auto const call{add(call_clear_depth_stencil_image, sizeof(clear_call))};
auto const ranges{append(Ranges, sizeof(VkImageSubresourceRange) * Count)};
auto &data{payload<clear_call>(call)};
data.image = Image;
data.layout = Layout;
data.colour = {};
data.depth = *Value;
data.count = Count;
data.ranges = ranges;
close(call);
work();
}
void command_stream::write_timestamp2(VkPipelineStageFlags2 const Stage, VkQueryPool const Pool, std::uint32_t const Query)
{
auto const call{add(call_write_timestamp, sizeof(query_call))};
payload<query_call>(call) = query_call{Stage, Pool, Query, 0, 0};
}
void command_stream::reset_query_pool(VkQueryPool const Pool, std::uint32_t const First, std::uint32_t const Count)
{
auto const call{add(call_reset_query_pool, sizeof(query_call))};
payload<query_call>(call) = query_call{VK_PIPELINE_STAGE_2_NONE, Pool, First, Count, 0};
}
void command_stream::begin_query(VkQueryPool const Pool, std::uint32_t const Query, VkQueryControlFlags const Flags)
{
auto const call{add(call_begin_query, sizeof(query_call))};
payload<query_call>(call) = query_call{VK_PIPELINE_STAGE_2_NONE, Pool, Query, 0, Flags};
// a query doesn't go on in another command buffer: no cut while it's active
++m_queries;
}
void command_stream::end_query(VkQueryPool const Pool, std::uint32_t const Query)
{
auto const call{add(call_end_query, sizeof(query_call))};
payload<query_call>(call) = query_call{VK_PIPELINE_STAGE_2_NONE, Pool, Query, 0, 0};
if (m_queries > 0)
{
--m_queries;
}
}
void command_stream::begin_debug_utils_label(VkDebugUtilsLabelEXT const *Label)
{
auto const call{add(call_begin_label, sizeof(label_call))};
auto const name{append(Label->pLabelName, (Label->pLabelName != nullptr) ? std::strlen(Label->pLabelName) + 1 : 0)};
auto &data{payload<label_call>(call)};
std::copy(std::begin(Label->color), std::end(Label->color), data.colour);
data.name = name;
close(call);
}
void command_stream::end_debug_utils_label()
{
add(call_end_label, 0);
}
// the replay
void command_stream::execute(std::size_t const Call, VkCommandBuffer const Buffer, VkRenderingFlags const Flags) const
{
auto const &header{*reinterpret_cast<call_header const *>(m_data.data() + Call)};
switch (header.type)
{
case call_begin_rendering:
{
auto const &data{payload<rendering_call>(Call)};
auto info{data.info};
info.flags |= Flags;
info.pColorAttachments = (data.colours != no_data ? at<VkRenderingAttachmentInfo>(data.colours) : nullptr);
info.pDepthAttachment = (data.depth != no_data ? at<VkRenderingAttachmentInfo>(data.depth) : nullptr);
info.pStencilAttachment = (data.stencil != no_data ? at<VkRenderingAttachmentInfo>(data.stencil) : nullptr);
vkCmdBeginRendering(Buffer, &info);
break;
}
case call_end_rendering:
vkCmdEndRendering(Buffer);
break;
case call_pipeline_barrier:
{
auto const &data{payload<barrier_call>(Call)};
VkDependencyInfo dependency{};
dependency.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO;
dependency.dependencyFlags = data.flags;
dependency.memoryBarrierCount = data.memory_count;
dependency.pMemoryBarriers = (data.memory != no_data ? at<VkMemoryBarrier2>(data.memory) : nullptr);
dependency.bufferMemoryBarrierCount = data.buffer_count;
dependency.pBufferMemoryBarriers = (data.buffers != no_data ? at<VkBufferMemoryBarrier2>(data.buffers) : nullptr);
dependency.imageMemoryBarrierCount = data.image_count;
dependency.pImageMemoryBarriers = (data.images != no_data ? at<VkImageMemoryBarrier2>(data.images) : nullptr);
vkCmdPipelineBarrier2(Buffer, &dependency);
break;
}
case call_bind_pipeline:
{
auto const &data{payload<pipeline_call>(Call)};
vkCmdBindPipeline(Buffer, data.bind_point, data.pipeline);
break;
}
case call_bind_descriptor_sets:
{
auto const &data{payload<sets_call>(Call)};
auto info{data.info};
info.pDescriptorSets = (data.sets != no_data ? at<VkDescriptorSet>(data.sets) : nullptr);
info.pDynamicOffsets = (data.offsets != no_data ? at<std::uint32_t>(data.offsets) : nullptr);
vkCmdBindDescriptorSets2(Buffer, &info);
break;
}
case call_push_descriptors:
{
auto const &data{payload<pushed_call>(Call)};
auto info{data.info};
info.pData = (data.data != no_data ? m_data.data() + data.data : nullptr);
vkCmdPushDescriptorSetWithTemplate2(Buffer, &info);
break;
}
case call_push_constants:
{
auto const &data{payload<constants_call>(Call)};
auto info{data.info};
info.pValues = (data.data != no_data ? m_data.data() + data.data : nullptr);
vkCmdPushConstants2(Buffer, &info);
break;
}
case call_bind_vertex_buffers:
{
auto const &data{payload<vertex_buffers_call>(Call)};
vkCmdBindVertexBuffers(Buffer, data.first, data.count, at<VkBuffer>(data.buffers), at<VkDeviceSize>(data.offsets));
break;
}
case call_bind_index_buffer:
{
auto const &data{payload<index_buffer_call>(Call)};
vkCmdBindIndexBuffer(Buffer, data.buffer, data.offset, data.type);
break;
}
case call_draw:
{
auto const &data{payload<draw_call>(Call)};
vkCmdDraw(Buffer, data.vertices, data.instances, data.first_vertex, data.first_instance);
break;
}
case call_draw_indexed:
{
auto const &data{payload<draw_indexed_call>(Call)};
vkCmdDrawIndexed(Buffer, data.indices, data.instances, data.first_index, data.vertex_offset, data.first_instance);
break;
}
case call_draw_indirect:
{
auto const &data{payload<indirect_call>(Call)};
vkCmdDrawIndirect(Buffer, data.buffer, data.offset, data.count, data.stride);
break;
}
case call_draw_indexed_indirect:
{
auto const &data{payload<indirect_call>(Call)};
vkCmdDrawIndexedIndirect(Buffer, data.buffer, data.offset, data.count, data.stride);
break;
}
case call_dispatch:
{
auto const &data{payload<dispatch_call>(Call)};
vkCmdDispatch(Buffer, data.x, data.y, data.z);
break;
}
case call_dispatch_indirect:
{
auto const &data{payload<indirect_call>(Call)};
vkCmdDispatchIndirect(Buffer, data.buffer, data.offset);
break;
}
case call_set_viewport:
{
auto const &data{payload<viewports_call>(Call)};
vkCmdSetViewport(Buffer, data.first, data.count, at<VkViewport>(data.data));
break;
}
case call_set_scissor:
{
auto const &data{payload<viewports_call>(Call)};
vkCmdSetScissor(Buffer, data.first, data.count, at<VkRect2D>(data.data));
break;
}
case call_set_cull_mode:
vkCmdSetCullMode(Buffer, static_cast<VkCullModeFlags>(payload<value_call>(Call).value));
break;
case call_set_front_face:
vkCmdSetFrontFace(Buffer, static_cast<VkFrontFace>(payload<value_call>(Call).value));
break;
case call_set_topology:
vkCmdSetPrimitiveTopology(Buffer, static_cast<VkPrimitiveTopology>(payload<value_call>(Call).value));
break;
case call_set_depth_test:
vkCmdSetDepthTestEnable(Buffer, static_cast<VkBool32>(payload<value_call>(Call).value));
break;
case call_set_depth_write:
vkCmdSetDepthWriteEnable(Buffer, static_cast<VkBool32>(payload<value_call>(Call).value));
break;
case call_set_depth_compare:
vkCmdSetDepthCompareOp(Buffer, static_cast<VkCompareOp>(payload<value_call>(Call).value));
break;
case call_set_depth_bias_enable:
vkCmdSetDepthBiasEnable(Buffer, static_cast<VkBool32>(payload<value_call>(Call).value));
break;
case call_set_depth_bias:
{
auto const &data{payload<bias_call>(Call)};
vkCmdSetDepthBias(Buffer, data.constant, data.clamp, data.slope);
break;
}
case call_set_primitive_restart:
vkCmdSetPrimitiveRestartEnable(Buffer, static_cast<VkBool32>(payload<value_call>(Call).value));
break;
case call_set_stencil_test:
vkCmdSetStencilTestEnable(Buffer, static_cast<VkBool32>(payload<value_call>(Call).value));
break;
case call_fill_buffer:
{
auto const &data{payload<fill_call>(Call)};
vkCmdFillBuffer(Buffer, data.buffer, data.offset, data.size, data.data);
break;
}
case call_update_buffer:
{
auto const &data{payload<update_call>(Call)};
vkCmdUpdateBuffer(Buffer, data.buffer, data.offset, data.size, m_data.data() + data.data);
break;
}
case call_copy_buffer:
{
auto const &data{payload<copy_call<VkCopyBufferInfo2>>(Call)};
auto info{data.info};
info.pRegions = at<VkBufferCopy2>(data.regions);
vkCmdCopyBuffer2(Buffer, &info);
break;
}
case call_copy_image:
{
auto const &data{payload<copy_call<VkCopyImageInfo2>>(Call)};
auto info{data.info};
info.pRegions = at<VkImageCopy2>(data.regions);
vkCmdCopyImage2(Buffer, &info);
break;
}
case call_copy_buffer_to_image:
{
auto const &data{payload<copy_call<VkCopyBufferToImageInfo2>>(Call)};
auto info{data.info};
info.pRegions = at<VkBufferImageCopy2>(data.regions);
vkCmdCopyBufferToImage2(Buffer, &info);
break;
}
case call_copy_image_to_buffer:
{
auto const &data{payload<copy_call<VkCopyImageToBufferInfo2>>(Call)};
auto info{data.info};
info.pRegions = at<VkBufferImageCopy2>(data.regions);
vkCmdCopyImageToBuffer2(Buffer, &info);
break;
}
case call_blit_image:
{
auto const &data{payload<copy_call<VkBlitImageInfo2>>(Call)};
auto info{data.info};
info.pRegions = at<VkImageBlit2>(data.regions);
vkCmdBlitImage2(Buffer, &info);
break;
}
case call_clear_color_image:
{
auto const &data{payload<clear_call>(Call)};
vkCmdClearColorImage(Buffer, data.image, data.layout, &data.colour, data.count, at<VkImageSubresourceRange>(data.ranges));
break;
}
case call_clear_depth_stencil_image:
{
auto const &data{payload<clear_call>(Call)};
vkCmdClearDepthStencilImage(Buffer, data.image, data.layout, &data.depth, data.count, at<VkImageSubresourceRange>(data.ranges));
break;
}
case call_write_timestamp:
{
auto const &data{payload<query_call>(Call)};
vkCmdWriteTimestamp2(Buffer, data.stage, data.pool, data.query);
break;
}
case call_reset_query_pool:
{
auto const &data{payload<query_call>(Call)};
vkCmdResetQueryPool(Buffer, data.pool, data.query, data.count);
break;
}
case call_begin_query:
{
auto const &data{payload<query_call>(Call)};
vkCmdBeginQuery(Buffer, data.pool, data.query, data.flags);
break;
}
case call_end_query:
{
auto const &data{payload<query_call>(Call)};
vkCmdEndQuery(Buffer, data.pool, data.query);
break;
}
case call_begin_label:
{
if (vkCmdBeginDebugUtilsLabelEXT != nullptr)
{
auto const &data{payload<label_call>(Call)};
VkDebugUtilsLabelEXT label{};
label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
label.pLabelName = (data.name != no_data ? at<char>(data.name) : "");
std::copy(std::begin(data.colour), std::end(data.colour), label.color);
vkCmdBeginDebugUtilsLabelEXT(Buffer, &label);
}
break;
}
case call_end_label:
if (vkCmdEndDebugUtilsLabelEXT != nullptr)
{
vkCmdEndDebugUtilsLabelEXT(Buffer);
}
break;
default:
break;
}
}
void command_stream::replay(std::size_t const Chunk, VkCommandBuffer const Buffer) const
{
if (Chunk >= m_chunks.size())
{
return;
}
auto const &chunk{m_chunks[Chunk]};
if (chunk.resumed != no_call)
{
// the rendering the chunk before suspended, and the state it left
execute(chunk.resumed, Buffer, VK_RENDERING_RESUMING_BIT | (chunk.suspended == chunk.resumed ? VK_RENDERING_SUSPENDING_BIT : 0));
}
for (auto const call : chunk.state)
{
execute(call, Buffer);
}
for (auto call = chunk.first; call < chunk.end;)
{
auto const &header{*reinterpret_cast<call_header const *>(m_data.data() + call)};
// the rendering going on in the next chunk is suspended
execute(call, Buffer, ((header.type == call_begin_rendering) && (call == chunk.suspended)) ? VK_RENDERING_SUSPENDING_BIT : 0);
call += header.size;
}
if (chunk.suspended != no_call)
{
vkCmdEndRendering(Buffer);
}
}
void command_stream::replay(VkCommandBuffer const Buffer) const
{
// the chunks one after another, the cuts made whole again: each call as it was made
for (auto call = std::size_t{0}; call < m_data.size();)
{
auto const &header{*reinterpret_cast<call_header const *>(m_data.data() + call)};
execute(call, Buffer);
call += header.size;
}
}
} // namespace vk14