1533 lines
70 KiB
C++
1533 lines
70 KiB
C++
/* Copyright (c) 2019-2025, Arm Limited and Contributors
|
|
* Copyright (c) 2024-2025, NVIDIA CORPORATION. All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 the "License";
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "common/hpp_vk_common.h"
|
|
#include "core/device.h"
|
|
#include "core/hpp_descriptor_set_layout.h"
|
|
#include "core/hpp_framebuffer.h"
|
|
#include "core/hpp_physical_device.h"
|
|
#include "core/hpp_render_pass.h"
|
|
#include "core/hpp_sampler.h"
|
|
#include "core/image.h"
|
|
#include "core/physical_device.h"
|
|
#include "hpp_resource_binding_state.h"
|
|
#include "rendering/hpp_pipeline_state.h"
|
|
#include "rendering/hpp_render_target.h"
|
|
#include "rendering/subpass.h"
|
|
|
|
namespace vkb
|
|
{
|
|
class QueryPool;
|
|
|
|
namespace core
|
|
{
|
|
class HPPQueryPool;
|
|
|
|
/**
|
|
* @brief Helper class to manage and record a command buffer, building and
|
|
* keeping track of pipeline state and resource bindings
|
|
*/
|
|
template <vkb::BindingType bindingType>
|
|
class CommandBuffer
|
|
: public vkb::core::VulkanResource<bindingType, typename std::conditional<bindingType == vkb::BindingType::Cpp, vk::CommandBuffer, VkCommandBuffer>::type>
|
|
{
|
|
using ParentType =
|
|
vkb::core::VulkanResource<bindingType, typename std::conditional<bindingType == vkb::BindingType::Cpp, vk::CommandBuffer, VkCommandBuffer>::type>;
|
|
|
|
public:
|
|
using BufferImageCopyType = typename std::conditional<bindingType == vkb::BindingType::Cpp, vk::BufferImageCopy, VkBufferImageCopy>::type;
|
|
using ClearAttachmentType = typename std::conditional<bindingType == vkb::BindingType::Cpp, vk::ClearAttachment, VkClearAttachment>::type;
|
|
using ClearRectType = typename std::conditional<bindingType == vkb::BindingType::Cpp, vk::ClearRect, VkClearRect>::type;
|
|
using ClearValueType = typename std::conditional<bindingType == vkb::BindingType::Cpp, vk::ClearValue, VkClearValue>::type;
|
|
using CommandBufferLevelType = typename std::conditional<bindingType == vkb::BindingType::Cpp, vk::CommandBufferLevel, VkCommandBufferLevel>::type;
|
|
using CommandBufferType = typename std::conditional<bindingType == vkb::BindingType::Cpp, vk::CommandBuffer, VkCommandBuffer>::type;
|
|
using CommandBufferUsageFlagsType =
|
|
typename std::conditional<bindingType == vkb::BindingType::Cpp, vk::CommandBufferUsageFlags, VkCommandBufferUsageFlags>::type;
|
|
using DeviceSizeType = typename std::conditional<bindingType == vkb::BindingType::Cpp, vk::DeviceSize, VkDeviceSize>::type;
|
|
using ImageBlitType = typename std::conditional<bindingType == vkb::BindingType::Cpp, vk::ImageBlit, VkImageBlit>::type;
|
|
using ImageCopyType = typename std::conditional<bindingType == vkb::BindingType::Cpp, vk::ImageCopy, VkImageCopy>::type;
|
|
using ImageLayoutType = typename std::conditional<bindingType == vkb::BindingType::Cpp, vk::ImageLayout, VkImageLayout>::type;
|
|
using ImageResolveType = typename std::conditional<bindingType == vkb::BindingType::Cpp, vk::ImageResolve, VkImageResolve>::type;
|
|
using IndexTypeType = typename std::conditional<bindingType == vkb::BindingType::Cpp, vk::IndexType, VkIndexType>::type;
|
|
using PipelineStagFlagBitsType =
|
|
typename std::conditional<bindingType == vkb::BindingType::Cpp, vk::PipelineStageFlagBits, VkPipelineStageFlagBits>::type;
|
|
using QueryControlFlagsType = typename std::conditional<bindingType == vkb::BindingType::Cpp, vk::QueryControlFlags, VkQueryControlFlags>::type;
|
|
using Rect2DType = typename std::conditional<bindingType == vkb::BindingType::Cpp, vk::Rect2D, VkRect2D>::type;
|
|
using ResultType = typename std::conditional<bindingType == vkb::BindingType::Cpp, vk::Result, VkResult>::type;
|
|
using SubpassContentsType = typename std::conditional<bindingType == vkb::BindingType::Cpp, vk::SubpassContents, VkSubpassContents>::type;
|
|
using ViewportType = typename std::conditional<bindingType == vkb::BindingType::Cpp, vk::Viewport, VkViewport>::type;
|
|
|
|
using BufferMemoryBarrierType =
|
|
typename std::conditional<bindingType == vkb::BindingType::Cpp, vkb::common::HPPBufferMemoryBarrier, vkb::BufferMemoryBarrier>::type;
|
|
using ColorBlendStateType =
|
|
typename std::conditional<bindingType == vkb::BindingType::Cpp, vkb::rendering::HPPColorBlendState, vkb::ColorBlendState>::type;
|
|
using DepthStencilStateType =
|
|
typename std::conditional<bindingType == vkb::BindingType::Cpp, vkb::rendering::HPPDepthStencilState, vkb::DepthStencilState>::type;
|
|
using FramebufferType = typename std::conditional<bindingType == vkb::BindingType::Cpp, vkb::core::HPPFramebuffer, vkb::Framebuffer>::type;
|
|
using ImageMemoryBarrierType =
|
|
typename std::conditional<bindingType == vkb::BindingType::Cpp, vkb::common::HPPImageMemoryBarrier, vkb::ImageMemoryBarrier>::type;
|
|
using ImageType = typename std::conditional<bindingType == vkb::BindingType::Cpp, vkb::core::HPPImage, vkb::core::Image>::type;
|
|
using ImageViewType = typename std::conditional<bindingType == vkb::BindingType::Cpp, vkb::core::HPPImageView, vkb::core::ImageView>::type;
|
|
using InputAssemblyStateType =
|
|
typename std::conditional<bindingType == vkb::BindingType::Cpp, vkb::rendering::HPPInputAssemblyState, vkb::InputAssemblyState>::type;
|
|
using LoadStoreInfoType = typename std::conditional<bindingType == vkb::BindingType::Cpp, vkb::common::HPPLoadStoreInfo, vkb::LoadStoreInfo>::type;
|
|
using MultisampleStateType =
|
|
typename std::conditional<bindingType == vkb::BindingType::Cpp, vkb::rendering::HPPMultisampleState, vkb::MultisampleState>::type;
|
|
using PipelineLayoutType = typename std::conditional<bindingType == vkb::BindingType::Cpp, vkb::core::HPPPipelineLayout, vkb::PipelineLayout>::type;
|
|
using QueryPoolType = typename std::conditional<bindingType == vkb::BindingType::Cpp, vkb::core::HPPQueryPool, vkb::QueryPool>::type;
|
|
using RasterizationStateType =
|
|
typename std::conditional<bindingType == vkb::BindingType::Cpp, vkb::rendering::HPPRasterizationState, vkb::RasterizationState>::type;
|
|
using RenderPassType = typename std::conditional<bindingType == vkb::BindingType::Cpp, vkb::core::HPPRenderPass, vkb::RenderPass>::type;
|
|
using RenderTargetType = typename std::conditional<bindingType == vkb::BindingType::Cpp, vkb::rendering::HPPRenderTarget, vkb::RenderTarget>::type;
|
|
using SamplerType = typename std::conditional<bindingType == vkb::BindingType::Cpp, vkb::core::HPPSampler, vkb::core::Sampler>::type;
|
|
using VertexInputStateType =
|
|
typename std::conditional<bindingType == vkb::BindingType::Cpp, vkb::rendering::HPPVertexInputState, vkb::VertexInputState>::type;
|
|
using ViewportStateType = typename std::conditional<bindingType == vkb::BindingType::Cpp, vkb::rendering::HPPViewportState, vkb::ViewportState>::type;
|
|
|
|
public:
|
|
CommandBuffer(vkb::core::CommandPool<bindingType> &command_pool, CommandBufferLevelType level);
|
|
~CommandBuffer();
|
|
CommandBuffer(CommandBuffer<bindingType> &&other) = default;
|
|
CommandBuffer &operator=(CommandBuffer<bindingType> &&) = default;
|
|
CommandBuffer(CommandBuffer<bindingType> const &) = delete;
|
|
CommandBuffer &operator=(CommandBuffer<bindingType> const &) = delete;
|
|
|
|
/**
|
|
* @brief Sets the command buffer so that it is ready for recording
|
|
* If it is a secondary command buffer, a pointer to the
|
|
* primary command buffer it inherits from must be provided
|
|
* @param flags Usage behavior for the command buffer
|
|
* @param primary_cmd_buf (optional)
|
|
*/
|
|
void begin(CommandBufferUsageFlagsType flags, CommandBuffer<bindingType> *primary_cmd_buf = nullptr);
|
|
|
|
/**
|
|
* @brief Sets the command buffer so that it is ready for recording
|
|
* If it is a secondary command buffer, pointers to the
|
|
* render pass and framebuffer as well as subpass index must be provided
|
|
* @param flags Usage behavior for the command buffer
|
|
* @param render_pass
|
|
* @param framebuffer
|
|
* @param subpass_index
|
|
*/
|
|
void begin(CommandBufferUsageFlagsType flags, const RenderPassType *render_pass, const FramebufferType *framebuffer, uint32_t subpass_index);
|
|
|
|
void begin_query(QueryPoolType const &query_pool, uint32_t query, QueryControlFlagsType flags);
|
|
void begin_render_pass(RenderTargetType const &render_target,
|
|
std::vector<LoadStoreInfoType> const &load_store_infos,
|
|
std::vector<ClearValueType> const &clear_values,
|
|
std::vector<std::unique_ptr<vkb::rendering::Subpass<bindingType>>> const &subpasses,
|
|
SubpassContentsType contents = VK_SUBPASS_CONTENTS_INLINE);
|
|
void begin_render_pass(RenderTargetType const &render_target,
|
|
RenderPassType const &render_pass,
|
|
FramebufferType const &framebuffer,
|
|
std::vector<ClearValueType> const &clear_values,
|
|
SubpassContentsType contents = vk::SubpassContents::eInline);
|
|
void bind_buffer(vkb::core::Buffer<bindingType> const &buffer, DeviceSizeType offset, DeviceSizeType range, uint32_t set, uint32_t binding, uint32_t array_element);
|
|
void bind_image(ImageViewType const &image_view, SamplerType const &sampler, uint32_t set, uint32_t binding, uint32_t array_element);
|
|
void bind_image(ImageViewType const &image_view, uint32_t set, uint32_t binding, uint32_t array_element);
|
|
void bind_index_buffer(vkb::core::Buffer<bindingType> const &buffer, DeviceSizeType offset, IndexTypeType index_type);
|
|
void bind_input(ImageViewType const &image_view, uint32_t set, uint32_t binding, uint32_t array_element);
|
|
void bind_lighting(vkb::rendering::LightingState<bindingType> &lighting_state, uint32_t set, uint32_t binding);
|
|
void bind_pipeline_layout(PipelineLayoutType &pipeline_layout);
|
|
void bind_vertex_buffers(uint32_t first_binding,
|
|
std::vector<std::reference_wrapper<const vkb::core::Buffer<bindingType>>> const &buffers,
|
|
std::vector<DeviceSizeType> const &offsets);
|
|
void blit_image(ImageType const &src_img, ImageType const &dst_img, std::vector<ImageBlitType> const ®ions);
|
|
void buffer_memory_barrier(vkb::core::Buffer<bindingType> const &buffer, DeviceSizeType offset, DeviceSizeType size, BufferMemoryBarrierType const &memory_barrier);
|
|
void clear(ClearAttachmentType const &info, ClearRectType const &rect);
|
|
void copy_buffer(vkb::core::Buffer<bindingType> const &src_buffer, vkb::core::Buffer<bindingType> const &dst_buffer, DeviceSizeType size);
|
|
void copy_buffer_to_image(vkb::core::Buffer<bindingType> const &buffer, ImageType const &image, std::vector<BufferImageCopyType> const ®ions);
|
|
void copy_image(ImageType const &src_img, ImageType const &dst_img, std::vector<ImageCopyType> const ®ions);
|
|
void copy_image_to_buffer(ImageType const &image,
|
|
ImageLayoutType image_layout,
|
|
vkb::core::Buffer<bindingType> const &buffer,
|
|
std::vector<BufferImageCopyType> const ®ions);
|
|
void dispatch(uint32_t group_count_x, uint32_t group_count_y, uint32_t group_count_z);
|
|
void dispatch_indirect(vkb::core::Buffer<bindingType> const &buffer, DeviceSizeType offset);
|
|
void draw(uint32_t vertex_count, uint32_t instance_count, uint32_t first_vertex, uint32_t first_instance);
|
|
void draw_indexed(uint32_t index_count, uint32_t instance_count, uint32_t first_index, int32_t vertex_offset, uint32_t first_instance);
|
|
void draw_indexed_indirect(vkb::core::Buffer<bindingType> const &buffer, DeviceSizeType offset, uint32_t draw_count, uint32_t stride);
|
|
void end();
|
|
void end_query(QueryPoolType const &query_pool, uint32_t query);
|
|
void end_render_pass();
|
|
void execute_commands(vkb::core::CommandBuffer<bindingType> &secondary_command_buffer);
|
|
void execute_commands(std::vector<std::shared_ptr<vkb::core::CommandBuffer<bindingType>>> &secondary_command_buffers);
|
|
CommandBufferLevelType get_level() const;
|
|
RenderPassType &get_render_pass(RenderTargetType const &render_target,
|
|
std::vector<LoadStoreInfoType> const &load_store_infos,
|
|
std::vector<std::unique_ptr<vkb::rendering::Subpass<bindingType>>> const &subpasses);
|
|
void image_memory_barrier(ImageViewType const &image_view, ImageMemoryBarrierType const &memory_barrier) const;
|
|
void image_memory_barrier(RenderTargetType &render_target, uint32_t view_index, ImageMemoryBarrierType const &memory_barrier) const;
|
|
void next_subpass();
|
|
|
|
/**
|
|
* @brief Records byte data into the command buffer to be pushed as push constants to each draw call
|
|
* @param values The byte data to store
|
|
*/
|
|
void push_constants(const std::vector<uint8_t> &values);
|
|
template <typename T>
|
|
void push_constants(const T &value);
|
|
|
|
/**
|
|
* @brief Reset the command buffer to a state where it can be recorded to
|
|
* @param reset_mode How to reset the buffer, should match the one used by the pool to allocate it
|
|
*/
|
|
ResultType reset(vkb::CommandBufferResetMode reset_mode);
|
|
|
|
void reset_query_pool(QueryPoolType const &query_pool, uint32_t first_query, uint32_t query_count);
|
|
void resolve_image(ImageType const &src_img, ImageType const &dst_img, std::vector<ImageResolveType> const ®ions);
|
|
void set_blend_constants(std::array<float, 4> const &blend_constants);
|
|
void set_color_blend_state(ColorBlendStateType const &state_info);
|
|
void set_depth_bias(float depth_bias_constant_factor, float depth_bias_clamp, float depth_bias_slope_factor);
|
|
void set_depth_bounds(float min_depth_bounds, float max_depth_bounds);
|
|
void set_depth_stencil_state(DepthStencilStateType const &state_info);
|
|
void set_input_assembly_state(InputAssemblyStateType const &state_info);
|
|
void set_line_width(float line_width);
|
|
void set_multisample_state(MultisampleStateType const &state_info);
|
|
void set_rasterization_state(RasterizationStateType const &state_info);
|
|
void set_scissor(uint32_t first_scissor, std::vector<Rect2DType> const &scissors);
|
|
|
|
template <class T>
|
|
void set_specialization_constant(uint32_t constant_id, T const &data);
|
|
void set_specialization_constant(uint32_t constant_id, std::vector<uint8_t> const &data);
|
|
|
|
void set_update_after_bind(bool update_after_bind_);
|
|
void set_vertex_input_state(VertexInputStateType const &state_info);
|
|
void set_viewport(uint32_t first_viewport, std::vector<ViewportType> const &viewports);
|
|
void set_viewport_state(ViewportStateType const &state_info);
|
|
void update_buffer(vkb::core::Buffer<bindingType> const &buffer, DeviceSizeType offset, std::vector<uint8_t> const &data);
|
|
void write_timestamp(PipelineStagFlagBitsType pipeline_stage, QueryPoolType const &query_pool, uint32_t query);
|
|
|
|
private:
|
|
/**
|
|
* @brief Flushes the command buffer, pushing the new changes
|
|
*/
|
|
void flush(vk::PipelineBindPoint pipeline_bind_point);
|
|
|
|
/**
|
|
* @brief Flush the push constant state
|
|
*/
|
|
void flush_push_constants();
|
|
|
|
/**
|
|
* @brief Check that the render area is an optimal size by comparing to the render area granularity
|
|
*/
|
|
bool is_render_size_optimal(const vk::Extent2D &extent, const vk::Rect2D &render_area);
|
|
|
|
private:
|
|
void begin_impl(vk::CommandBufferUsageFlags flags, vkb::core::CommandBuffer<bindingType> *primary_cmd_buf);
|
|
void begin_impl(vk::CommandBufferUsageFlags flags,
|
|
vkb::core::HPPRenderPass const *render_pass,
|
|
vkb::core::HPPFramebuffer const *framebuffer,
|
|
uint32_t subpass_index);
|
|
void begin_render_pass_impl(vkb::rendering::HPPRenderTarget const &render_target,
|
|
vkb::core::HPPRenderPass const &render_pass,
|
|
vkb::core::HPPFramebuffer const &framebuffer,
|
|
std::vector<vk::ClearValue> const &clear_values,
|
|
vk::SubpassContents contents);
|
|
void bind_vertex_buffers_impl(uint32_t first_binding,
|
|
std::vector<std::reference_wrapper<const vkb::core::BufferCpp>> const &buffers,
|
|
std::vector<vk::DeviceSize> const &offsets);
|
|
void buffer_memory_barrier_impl(vkb::core::BufferCpp const &buffer,
|
|
vk::DeviceSize offset,
|
|
vk::DeviceSize size,
|
|
vkb::common::HPPBufferMemoryBarrier const &memory_barrier);
|
|
void copy_buffer_impl(vkb::core::BufferCpp const &src_buffer, vkb::core::BufferCpp const &dst_buffer, vk::DeviceSize size);
|
|
void execute_commands_impl(std::vector<std::shared_ptr<vkb::core::CommandBuffer<vkb::BindingType::Cpp>>> &secondary_command_buffers);
|
|
void flush_impl(vkb::core::DeviceCpp &device, vk::PipelineBindPoint pipeline_bind_point);
|
|
void flush_descriptor_state_impl(vk::PipelineBindPoint pipeline_bind_point);
|
|
void flush_pipeline_state_impl(vkb::core::DeviceCpp &device, vk::PipelineBindPoint pipeline_bind_point);
|
|
vkb::core::HPPRenderPass &get_render_pass_impl(vkb::core::DeviceCpp &device,
|
|
vkb::rendering::HPPRenderTarget const &render_target,
|
|
std::vector<vkb::common::HPPLoadStoreInfo> const &load_store_infos,
|
|
std::vector<std::unique_ptr<vkb::rendering::SubpassCpp>> const &subpasses);
|
|
void image_memory_barrier_impl(vkb::core::HPPImageView const &image_view, vkb::common::HPPImageMemoryBarrier const &memory_barrier) const;
|
|
vk::Result reset_impl(vkb::CommandBufferResetMode reset_mode);
|
|
|
|
private:
|
|
vkb::core::CommandPoolCpp &command_pool;
|
|
vkb::core::HPPFramebuffer const *current_framebuffer = nullptr;
|
|
vkb::core::HPPRenderPass const *current_render_pass = nullptr;
|
|
std::unordered_map<uint32_t, vkb::core::HPPDescriptorSetLayout const *> descriptor_set_layout_binding_state;
|
|
vk::Extent2D last_framebuffer_extent = {};
|
|
vk::Extent2D last_render_area_extent = {};
|
|
const vk::CommandBufferLevel level = {};
|
|
const uint32_t max_push_constants_size = {};
|
|
vkb::rendering::HPPPipelineState pipeline_state = {};
|
|
vkb::HPPResourceBindingState resource_binding_state = {};
|
|
std::vector<uint8_t> stored_push_constants = {};
|
|
|
|
// If true, it becomes the responsibility of the caller to update ANY descriptor bindings
|
|
// that contain update after bind, as they wont be implicitly updated
|
|
bool update_after_bind = false;
|
|
};
|
|
|
|
using CommandBufferC = CommandBuffer<vkb::BindingType::C>;
|
|
using CommandBufferCpp = CommandBuffer<vkb::BindingType::Cpp>;
|
|
|
|
} // namespace core
|
|
} // namespace vkb
|
|
|
|
#include "core/command_pool.h"
|
|
#include "core/device.h"
|
|
#include "rendering/render_frame.h"
|
|
|
|
namespace vkb
|
|
{
|
|
namespace core
|
|
{
|
|
template <vkb::BindingType bindingType>
|
|
inline vkb::core::CommandBuffer<bindingType>::CommandBuffer(vkb::core::CommandPool<bindingType> &command_pool_, CommandBufferLevelType level_) :
|
|
vkb::core::VulkanResource<bindingType, CommandBufferType>(nullptr, &command_pool_.get_device()), level(static_cast<vk::CommandBufferLevel>(level_)), command_pool(reinterpret_cast<vkb::core::CommandPoolCpp &>(command_pool_)), max_push_constants_size(command_pool_.get_device().get_gpu().get_properties().limits.maxPushConstantsSize)
|
|
{
|
|
vk::CommandBufferAllocateInfo allocate_info{.commandPool = command_pool.get_handle(), .level = level, .commandBufferCount = 1};
|
|
|
|
this->set_handle(this->get_device().get_resource().allocateCommandBuffers(allocate_info).front());
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline CommandBuffer<bindingType>::~CommandBuffer()
|
|
{
|
|
// Destroy command buffer
|
|
if (this->has_handle())
|
|
{
|
|
this->get_device().get_resource().freeCommandBuffers(command_pool.get_handle(), this->get_resource());
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::begin(CommandBufferUsageFlagsType flags,
|
|
vkb::core::CommandBuffer<bindingType> *primary_cmd_buf)
|
|
{
|
|
if constexpr (bindingType == vkb::BindingType::Cpp)
|
|
{
|
|
begin_impl(flags, primary_cmd_buf);
|
|
}
|
|
else
|
|
{
|
|
begin_impl(static_cast<vk::CommandBufferUsageFlags>(flags), primary_cmd_buf);
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::begin_impl(vk::CommandBufferUsageFlags flags, vkb::core::CommandBuffer<bindingType> *primary_cmd_buf)
|
|
{
|
|
if (level == vk::CommandBufferLevel::eSecondary)
|
|
{
|
|
assert(primary_cmd_buf && "A primary command buffer pointer must be provided when calling begin from a secondary one");
|
|
|
|
return begin_impl(flags, primary_cmd_buf->current_render_pass, primary_cmd_buf->current_framebuffer, primary_cmd_buf->pipeline_state.get_subpass_index());
|
|
}
|
|
else
|
|
{
|
|
return begin_impl(flags, nullptr, nullptr, 0);
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::begin(CommandBufferUsageFlagsType flags,
|
|
const RenderPassType *render_pass,
|
|
const FramebufferType *framebuffer,
|
|
uint32_t subpass_index)
|
|
{
|
|
if constexpr (bindingType == vkb::BindingType::Cpp)
|
|
{
|
|
begin_impl(flags, render_pass, framebuffer, subpass_index);
|
|
}
|
|
else
|
|
{
|
|
begin_impl(static_cast<vk::CommandBufferUsageFlags>(flags),
|
|
reinterpret_cast<vkb::core::HPPRenderPass const *>(render_pass),
|
|
reinterpret_cast<vkb::core::HPPFramebuffer const *>(framebuffer),
|
|
subpass_index);
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::begin_impl(vk::CommandBufferUsageFlags flags,
|
|
vkb::core::HPPRenderPass const *render_pass,
|
|
vkb::core::HPPFramebuffer const *framebuffer,
|
|
uint32_t subpass_index)
|
|
{
|
|
// Reset state
|
|
pipeline_state.reset();
|
|
resource_binding_state.reset();
|
|
descriptor_set_layout_binding_state.clear();
|
|
stored_push_constants.clear();
|
|
|
|
vk::CommandBufferBeginInfo begin_info{.flags = flags};
|
|
vk::CommandBufferInheritanceInfo inheritance;
|
|
|
|
if (level == vk::CommandBufferLevel::eSecondary)
|
|
{
|
|
assert((render_pass && framebuffer) && "Render pass and framebuffer must be provided when calling begin from a secondary one");
|
|
|
|
current_render_pass = render_pass;
|
|
current_framebuffer = framebuffer;
|
|
|
|
inheritance.renderPass = current_render_pass->get_handle();
|
|
inheritance.framebuffer = current_framebuffer->get_handle();
|
|
inheritance.subpass = subpass_index;
|
|
|
|
begin_info.pInheritanceInfo = &inheritance;
|
|
}
|
|
|
|
this->get_resource().begin(begin_info);
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::begin_query(QueryPoolType const &query_pool, uint32_t query, QueryControlFlagsType flags)
|
|
{
|
|
if constexpr (bindingType == vkb::BindingType::Cpp)
|
|
{
|
|
this->get_resource().beginQuery(query_pool.get_resource(), query, flags);
|
|
}
|
|
else
|
|
{
|
|
this->get_resource().beginQuery(static_cast<vk::QueryPool const>(query_pool.get_handle()), query, static_cast<vk::QueryControlFlags>(flags));
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::begin_render_pass(RenderTargetType const &render_target,
|
|
std::vector<LoadStoreInfoType> const &load_store_infos,
|
|
std::vector<ClearValueType> const &clear_values,
|
|
std::vector<std::unique_ptr<vkb::rendering::Subpass<bindingType>>> const &subpasses,
|
|
SubpassContentsType contents)
|
|
{
|
|
// Reset state
|
|
pipeline_state.reset();
|
|
resource_binding_state.reset();
|
|
descriptor_set_layout_binding_state.clear();
|
|
|
|
auto &render_pass = get_render_pass(render_target, load_store_infos, subpasses);
|
|
auto &framebuffer = this->get_device().get_resource_cache().request_framebuffer(render_target, render_pass);
|
|
|
|
begin_render_pass(render_target, render_pass, framebuffer, clear_values, contents);
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::begin_render_pass(RenderTargetType const &render_target,
|
|
RenderPassType const &render_pass,
|
|
FramebufferType const &framebuffer,
|
|
std::vector<ClearValueType> const &clear_values,
|
|
SubpassContentsType contents)
|
|
{
|
|
if constexpr (bindingType == vkb::BindingType::Cpp)
|
|
{
|
|
begin_render_pass_impl(render_target, render_pass, framebuffer, clear_values, contents);
|
|
}
|
|
else
|
|
{
|
|
begin_render_pass_impl(reinterpret_cast<vkb::rendering::HPPRenderTarget const &>(render_target),
|
|
reinterpret_cast<vkb::core::HPPRenderPass const &>(render_pass),
|
|
reinterpret_cast<vkb::core::HPPFramebuffer const &>(framebuffer),
|
|
reinterpret_cast<std::vector<vk::ClearValue> const &>(clear_values),
|
|
static_cast<vk::SubpassContents>(contents));
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::begin_render_pass_impl(vkb::rendering::HPPRenderTarget const &render_target,
|
|
vkb::core::HPPRenderPass const &render_pass,
|
|
vkb::core::HPPFramebuffer const &framebuffer,
|
|
std::vector<vk::ClearValue> const &clear_values,
|
|
vk::SubpassContents contents)
|
|
{
|
|
current_render_pass = &render_pass;
|
|
current_framebuffer = &framebuffer;
|
|
|
|
// Begin render pass
|
|
vk::RenderPassBeginInfo begin_info{.renderPass = current_render_pass->get_handle(),
|
|
.framebuffer = current_framebuffer->get_handle(),
|
|
.renderArea = {.extent = render_target.get_extent()},
|
|
.clearValueCount = static_cast<uint32_t>(clear_values.size()),
|
|
.pClearValues = clear_values.data()};
|
|
|
|
const auto &framebuffer_extent = current_framebuffer->get_extent();
|
|
|
|
// Test the requested render area to confirm that it is optimal and could not cause a performance reduction
|
|
if (!is_render_size_optimal(framebuffer_extent, begin_info.renderArea))
|
|
{
|
|
// Only prints the warning if the framebuffer or render area are different since the last time the render size was not optimal
|
|
if ((framebuffer_extent != last_framebuffer_extent) || (begin_info.renderArea.extent != last_render_area_extent))
|
|
{
|
|
LOGW("Render target extent is not an optimal size, this may result in reduced performance.");
|
|
}
|
|
|
|
last_framebuffer_extent = framebuffer_extent;
|
|
last_render_area_extent = begin_info.renderArea.extent;
|
|
}
|
|
|
|
this->get_resource().beginRenderPass(begin_info, contents);
|
|
|
|
// Update blend state attachments for first subpass
|
|
auto blend_state = pipeline_state.get_color_blend_state();
|
|
blend_state.attachments.resize(current_render_pass->get_color_output_count(pipeline_state.get_subpass_index()));
|
|
pipeline_state.set_color_blend_state(blend_state);
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::bind_buffer(
|
|
vkb::core::Buffer<bindingType> const &buffer, DeviceSizeType offset, DeviceSizeType range, uint32_t set, uint32_t binding, uint32_t array_element)
|
|
{
|
|
if constexpr (bindingType == vkb::BindingType::Cpp)
|
|
{
|
|
resource_binding_state.bind_buffer(buffer, offset, range, set, binding, array_element);
|
|
}
|
|
else
|
|
{
|
|
resource_binding_state.bind_buffer(
|
|
reinterpret_cast<vkb::core::Buffer<vkb::BindingType::Cpp> const &>(buffer), offset, range, set, binding, array_element);
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::bind_image(
|
|
ImageViewType const &image_view, SamplerType const &sampler, uint32_t set, uint32_t binding, uint32_t array_element)
|
|
{
|
|
if constexpr (bindingType == vkb::BindingType::Cpp)
|
|
{
|
|
resource_binding_state.bind_image(image_view, sampler, set, binding, array_element);
|
|
}
|
|
else
|
|
{
|
|
resource_binding_state.bind_image(reinterpret_cast<vkb::core::HPPImageView const &>(image_view),
|
|
reinterpret_cast<vkb::core::HPPSampler const &>(sampler),
|
|
set,
|
|
binding,
|
|
array_element);
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::bind_image(ImageViewType const &image_view, uint32_t set, uint32_t binding, uint32_t array_element)
|
|
{
|
|
if constexpr (bindingType == vkb::BindingType::Cpp)
|
|
{
|
|
resource_binding_state.bind_image(image_view, set, binding, array_element);
|
|
}
|
|
else
|
|
{
|
|
resource_binding_state.bind_image(reinterpret_cast<vkb::core::HPPImageView const &>(image_view), set, binding, array_element);
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::bind_index_buffer(vkb::core::Buffer<bindingType> const &buffer, DeviceSizeType offset, IndexTypeType index_type)
|
|
{
|
|
if constexpr (bindingType == vkb::BindingType::Cpp)
|
|
{
|
|
this->get_resource().bindIndexBuffer(buffer.get_resource(), offset, index_type);
|
|
}
|
|
else
|
|
{
|
|
this->get_resource().bindIndexBuffer(buffer.get_resource(), static_cast<vk::DeviceSize>(offset), static_cast<vk::IndexType>(index_type));
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::bind_input(ImageViewType const &image_view, uint32_t set, uint32_t binding, uint32_t array_element)
|
|
{
|
|
if constexpr (bindingType == vkb::BindingType::Cpp)
|
|
{
|
|
resource_binding_state.bind_input(image_view, set, binding, array_element);
|
|
}
|
|
else
|
|
{
|
|
resource_binding_state.bind_input(reinterpret_cast<vkb::core::HPPImageView const &>(image_view), set, binding, array_element);
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::bind_lighting(vkb::rendering::LightingState<bindingType> &lighting_state, uint32_t set, uint32_t binding)
|
|
{
|
|
bind_buffer(lighting_state.light_buffer.get_buffer(), lighting_state.light_buffer.get_offset(), lighting_state.light_buffer.get_size(), set, binding, 0);
|
|
|
|
set_specialization_constant(0, to_u32(lighting_state.directional_lights.size()));
|
|
set_specialization_constant(1, to_u32(lighting_state.point_lights.size()));
|
|
set_specialization_constant(2, to_u32(lighting_state.spot_lights.size()));
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::bind_pipeline_layout(PipelineLayoutType &pipeline_layout)
|
|
{
|
|
if constexpr (bindingType == vkb::BindingType::Cpp)
|
|
{
|
|
pipeline_state.set_pipeline_layout(pipeline_layout);
|
|
}
|
|
else
|
|
{
|
|
pipeline_state.set_pipeline_layout(reinterpret_cast<vkb::core::HPPPipelineLayout &>(pipeline_layout));
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::bind_vertex_buffers(uint32_t first_binding,
|
|
std::vector<std::reference_wrapper<const vkb::core::Buffer<bindingType>>> const &buffers,
|
|
std::vector<DeviceSizeType> const &offsets)
|
|
{
|
|
if constexpr (bindingType == vkb::BindingType::Cpp)
|
|
{
|
|
bind_vertex_buffers_impl(first_binding, buffers, offsets);
|
|
}
|
|
else
|
|
{
|
|
bind_vertex_buffers_impl(first_binding,
|
|
reinterpret_cast<std::vector<std::reference_wrapper<vkb::core::BufferCpp const>> const &>(buffers),
|
|
reinterpret_cast<std::vector<vk::DeviceSize> const &>(offsets));
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::bind_vertex_buffers_impl(uint32_t first_binding,
|
|
std::vector<std::reference_wrapper<const vkb::core::BufferCpp>> const &buffers,
|
|
std::vector<vk::DeviceSize> const &offsets)
|
|
{
|
|
std::vector<vk::Buffer> buffer_handles(buffers.size(), nullptr);
|
|
std::transform(buffers.begin(), buffers.end(), buffer_handles.begin(), [](auto const &buffer) { return buffer.get().get_handle(); });
|
|
this->get_resource().bindVertexBuffers(first_binding, buffer_handles, offsets);
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::blit_image(ImageType const &src_img, ImageType const &dst_img, std::vector<ImageBlitType> const ®ions)
|
|
{
|
|
if constexpr (bindingType == vkb::BindingType::Cpp)
|
|
{
|
|
this->get_resource().blitImage(src_img.get_handle(),
|
|
vk::ImageLayout::eTransferSrcOptimal,
|
|
dst_img.get_handle(),
|
|
vk::ImageLayout::eTransferDstOptimal,
|
|
regions,
|
|
vk::Filter::eNearest);
|
|
}
|
|
else
|
|
{
|
|
this->get_resource().blitImage(src_img.get_resource(),
|
|
vk::ImageLayout::eTransferSrcOptimal,
|
|
dst_img.get_resource(),
|
|
vk::ImageLayout::eTransferDstOptimal,
|
|
reinterpret_cast<std::vector<vk::ImageBlit> const &>(regions),
|
|
vk::Filter::eNearest);
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::buffer_memory_barrier(vkb::core::Buffer<bindingType> const &buffer,
|
|
DeviceSizeType offset,
|
|
DeviceSizeType size,
|
|
BufferMemoryBarrierType const &memory_barrier)
|
|
{
|
|
if constexpr (bindingType == vkb::BindingType::Cpp)
|
|
{
|
|
buffer_memory_barrier_impl(buffer, offset, size, memory_barrier);
|
|
}
|
|
else
|
|
{
|
|
buffer_memory_barrier_impl(reinterpret_cast<vkb::core::BufferCpp const &>(buffer),
|
|
static_cast<vk::DeviceSize>(offset),
|
|
static_cast<vk::DeviceSize>(size),
|
|
reinterpret_cast<vkb::common::HPPBufferMemoryBarrier const &>(memory_barrier));
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::buffer_memory_barrier_impl(vkb::core::BufferCpp const &buffer,
|
|
vk::DeviceSize offset,
|
|
vk::DeviceSize size,
|
|
vkb::common::HPPBufferMemoryBarrier const &memory_barrier)
|
|
{
|
|
vk::BufferMemoryBarrier buffer_memory_barrier{.srcAccessMask = memory_barrier.src_access_mask,
|
|
.dstAccessMask = memory_barrier.dst_access_mask,
|
|
.buffer = buffer.get_handle(),
|
|
.offset = offset,
|
|
.size = size};
|
|
|
|
this->get_resource().pipelineBarrier(memory_barrier.src_stage_mask, memory_barrier.dst_stage_mask, {}, {}, buffer_memory_barrier, {});
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::clear(ClearAttachmentType const &attachment, ClearRectType const &rect)
|
|
{
|
|
if constexpr (bindingType == vkb::BindingType::Cpp)
|
|
{
|
|
this->get_resource().clearAttachments(attachment, rect);
|
|
}
|
|
else
|
|
{
|
|
this->get_resource().clearAttachments(reinterpret_cast<vk::ClearAttachment const &>(attachment), reinterpret_cast<vk::ClearRect const &>(rect));
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::copy_buffer(vkb::core::Buffer<bindingType> const &src_buffer,
|
|
vkb::core::Buffer<bindingType> const &dst_buffer,
|
|
DeviceSizeType size)
|
|
{
|
|
if constexpr (bindingType == vkb::BindingType::Cpp)
|
|
{
|
|
copy_buffer_impl(src_buffer, dst_buffer, size);
|
|
}
|
|
else
|
|
{
|
|
copy_buffer_impl(reinterpret_cast<vkb::core::BufferCpp const &>(src_buffer),
|
|
reinterpret_cast<vkb::core::BufferCpp const &>(dst_buffer),
|
|
static_cast<vk::DeviceSize>(size));
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void
|
|
CommandBuffer<bindingType>::copy_buffer_impl(vkb::core::BufferCpp const &src_buffer, vkb::core::BufferCpp const &dst_buffer, vk::DeviceSize size)
|
|
{
|
|
vk::BufferCopy copy_region{.size = size};
|
|
this->get_resource().copyBuffer(src_buffer.get_handle(), dst_buffer.get_handle(), copy_region);
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::copy_buffer_to_image(vkb::core::Buffer<bindingType> const &buffer,
|
|
ImageType const &image,
|
|
std::vector<BufferImageCopyType> const ®ions)
|
|
{
|
|
if constexpr (bindingType == vkb::BindingType::Cpp)
|
|
{
|
|
this->get_resource().copyBufferToImage(buffer.get_handle(), image.get_handle(), vk::ImageLayout::eTransferDstOptimal, regions);
|
|
}
|
|
else
|
|
{
|
|
this->get_resource().copyBufferToImage(buffer.get_resource(),
|
|
image.get_resource(),
|
|
vk::ImageLayout::eTransferDstOptimal,
|
|
reinterpret_cast<std::vector<vk::BufferImageCopy> const &>(regions));
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::copy_image(ImageType const &src_img, ImageType const &dst_img, std::vector<ImageCopyType> const ®ions)
|
|
{
|
|
if constexpr (bindingType == vkb::BindingType::Cpp)
|
|
{
|
|
this->get_resource().copyImage(src_img.get_handle(), vk::ImageLayout::eTransferSrcOptimal, dst_img.get_handle(), vk::ImageLayout::eTransferDstOptimal, regions);
|
|
}
|
|
else
|
|
{
|
|
this->get_resource().copyImage(src_img.get_resource(),
|
|
vk::ImageLayout::eTransferSrcOptimal,
|
|
dst_img.get_resource(),
|
|
vk::ImageLayout::eTransferDstOptimal,
|
|
reinterpret_cast<std::vector<vk::ImageCopy> const &>(regions));
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::copy_image_to_buffer(ImageType const &image,
|
|
ImageLayoutType image_layout,
|
|
vkb::core::Buffer<bindingType> const &buffer,
|
|
std::vector<BufferImageCopyType> const ®ions)
|
|
{
|
|
if constexpr (bindingType == vkb::BindingType::Cpp)
|
|
{
|
|
this->get_resource().copyImageToBuffer(image.get_handle(), image_layout, buffer.get_handle(), regions);
|
|
}
|
|
else
|
|
{
|
|
this->get_resource().copyImageToBuffer(image.get_resource(),
|
|
static_cast<vk::ImageLayout>(image_layout),
|
|
buffer.get_resource(),
|
|
reinterpret_cast<std::vector<vk::BufferImageCopy> const &>(regions));
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::dispatch(uint32_t group_count_x, uint32_t group_count_y, uint32_t group_count_z)
|
|
{
|
|
flush(vk::PipelineBindPoint::eCompute);
|
|
this->get_resource().dispatch(group_count_x, group_count_y, group_count_z);
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::dispatch_indirect(vkb::core::Buffer<bindingType> const &buffer, DeviceSizeType offset)
|
|
{
|
|
flush(vk::PipelineBindPoint::eCompute);
|
|
if constexpr (bindingType == vkb::BindingType::Cpp)
|
|
{
|
|
this->get_resource().dispatchIndirect(buffer.get_handle(), offset);
|
|
}
|
|
else
|
|
{
|
|
this->get_resource().dispatchIndirect(buffer.get_resource(), static_cast<vk::DeviceSize>(offset));
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::draw(uint32_t vertex_count, uint32_t instance_count, uint32_t first_vertex, uint32_t first_instance)
|
|
{
|
|
flush(vk::PipelineBindPoint::eGraphics);
|
|
this->get_resource().draw(vertex_count, instance_count, first_vertex, first_instance);
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::draw_indexed(
|
|
uint32_t index_count, uint32_t instance_count, uint32_t first_index, int32_t vertex_offset, uint32_t first_instance)
|
|
{
|
|
flush(vk::PipelineBindPoint::eGraphics);
|
|
this->get_resource().drawIndexed(index_count, instance_count, first_index, vertex_offset, first_instance);
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::draw_indexed_indirect(vkb::core::Buffer<bindingType> const &buffer, DeviceSizeType offset, uint32_t draw_count, uint32_t stride)
|
|
{
|
|
flush(vk::PipelineBindPoint::eGraphics);
|
|
if constexpr (bindingType == vkb::BindingType::Cpp)
|
|
{
|
|
this->get_resource().drawIndexedIndirect(buffer.get_handle(), offset, draw_count, stride);
|
|
}
|
|
else
|
|
{
|
|
this->get_resource().drawIndexedIndirect(buffer.get_resource(), static_cast<vk::DeviceSize>(offset), draw_count, stride);
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::end()
|
|
{
|
|
this->get_resource().end();
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::end_query(QueryPoolType const &query_pool, uint32_t query)
|
|
{
|
|
if constexpr (bindingType == vkb::BindingType::Cpp)
|
|
{
|
|
this->get_resource().endQuery(query_pool.get_handle(), query);
|
|
}
|
|
else
|
|
{
|
|
this->get_resource().endQuery(static_cast<vk::QueryPool>(query_pool.get_handle()), query);
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::end_render_pass()
|
|
{
|
|
this->get_resource().endRenderPass();
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline typename CommandBuffer<bindingType>::CommandBufferLevelType CommandBuffer<bindingType>::get_level() const
|
|
{
|
|
if constexpr (bindingType == vkb::BindingType::Cpp)
|
|
{
|
|
return level;
|
|
}
|
|
else
|
|
{
|
|
return static_cast<VkCommandBufferLevel>(level);
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::execute_commands(vkb::core::CommandBuffer<bindingType> &secondary_command_buffer)
|
|
{
|
|
this->get_resource().executeCommands(secondary_command_buffer.get_resource());
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::execute_commands(std::vector<std::shared_ptr<vkb::core::CommandBuffer<bindingType>>> &secondary_command_buffers)
|
|
{
|
|
if constexpr (bindingType == vkb::BindingType::Cpp)
|
|
{
|
|
execute_commands_impl(secondary_command_buffers);
|
|
}
|
|
else
|
|
{
|
|
execute_commands_impl(reinterpret_cast<std::vector<std::shared_ptr<vkb::core::CommandBufferCpp>> &>(secondary_command_buffers));
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::execute_commands_impl(std::vector<std::shared_ptr<vkb::core::CommandBuffer<vkb::BindingType::Cpp>>> &secondary_command_buffers)
|
|
{
|
|
std::vector<vk::CommandBuffer> sec_cmd_buf_handles(secondary_command_buffers.size(), nullptr);
|
|
std::transform(secondary_command_buffers.begin(),
|
|
secondary_command_buffers.end(),
|
|
sec_cmd_buf_handles.begin(),
|
|
[](auto const &sec_cmd_buf) { return sec_cmd_buf->get_handle(); });
|
|
this->get_resource().executeCommands(sec_cmd_buf_handles);
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline typename vkb::core::CommandBuffer<bindingType>::RenderPassType &
|
|
CommandBuffer<bindingType>::get_render_pass(RenderTargetType const &render_target,
|
|
std::vector<LoadStoreInfoType> const &load_store_infos,
|
|
std::vector<std::unique_ptr<vkb::rendering::Subpass<bindingType>>> const &subpasses)
|
|
{
|
|
if constexpr (bindingType == vkb::BindingType::Cpp)
|
|
{
|
|
return get_render_pass_impl(this->get_device(), render_target, load_store_infos, subpasses);
|
|
}
|
|
else
|
|
{
|
|
return reinterpret_cast<vkb::RenderPass &>(
|
|
get_render_pass_impl(reinterpret_cast<vkb::core::DeviceCpp &>(this->get_device()),
|
|
reinterpret_cast<vkb::rendering::HPPRenderTarget const &>(render_target),
|
|
reinterpret_cast<std::vector<vkb::common::HPPLoadStoreInfo> const &>(load_store_infos),
|
|
reinterpret_cast<std::vector<std::unique_ptr<vkb::rendering::SubpassCpp>> const &>(subpasses)));
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline vkb::core::HPPRenderPass &
|
|
CommandBuffer<bindingType>::get_render_pass_impl(vkb::core::DeviceCpp &device,
|
|
vkb::rendering::HPPRenderTarget const &render_target,
|
|
std::vector<vkb::common::HPPLoadStoreInfo> const &load_store_infos,
|
|
std::vector<std::unique_ptr<vkb::rendering::SubpassCpp>> const &subpasses)
|
|
{
|
|
// Create render pass
|
|
assert(subpasses.size() > 0 && "Cannot create a render pass without any subpass");
|
|
|
|
std::vector<vkb::core::HPPSubpassInfo> subpass_infos(subpasses.size());
|
|
auto subpass_info_it = subpass_infos.begin();
|
|
for (auto &subpass : subpasses)
|
|
{
|
|
subpass_info_it->input_attachments = subpass->get_input_attachments();
|
|
subpass_info_it->output_attachments = subpass->get_output_attachments();
|
|
subpass_info_it->color_resolve_attachments = subpass->get_color_resolve_attachments();
|
|
subpass_info_it->disable_depth_stencil_attachment = subpass->get_disable_depth_stencil_attachment();
|
|
subpass_info_it->depth_stencil_resolve_mode = subpass->get_depth_stencil_resolve_mode();
|
|
subpass_info_it->depth_stencil_resolve_attachment = subpass->get_depth_stencil_resolve_attachment();
|
|
subpass_info_it->debug_name = subpass->get_debug_name();
|
|
|
|
++subpass_info_it;
|
|
}
|
|
|
|
return device.get_resource_cache().request_render_pass(render_target.get_attachments(), load_store_infos, subpass_infos);
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::image_memory_barrier(RenderTargetType &render_target, uint32_t view_index, ImageMemoryBarrierType const &memory_barrier) const
|
|
{
|
|
auto const &image_view = render_target.get_views()[view_index];
|
|
|
|
if constexpr (bindingType == vkb::BindingType::Cpp)
|
|
{
|
|
image_memory_barrier_impl(image_view, memory_barrier);
|
|
}
|
|
else
|
|
{
|
|
image_memory_barrier_impl(reinterpret_cast<vkb::core::HPPImageView const &>(image_view),
|
|
reinterpret_cast<vkb::common::HPPImageMemoryBarrier const &>(memory_barrier));
|
|
}
|
|
|
|
render_target.set_layout(view_index, memory_barrier.new_layout);
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::image_memory_barrier(ImageViewType const &image_view, ImageMemoryBarrierType const &memory_barrier) const
|
|
{
|
|
if constexpr (bindingType == vkb::BindingType::Cpp)
|
|
{
|
|
image_memory_barrier_impl(image_view, memory_barrier);
|
|
}
|
|
else
|
|
{
|
|
image_memory_barrier_impl(reinterpret_cast<vkb::core::HPPImageView const &>(image_view),
|
|
reinterpret_cast<vkb::common::HPPImageMemoryBarrier const &>(memory_barrier));
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::image_memory_barrier_impl(vkb::core::HPPImageView const &image_view,
|
|
vkb::common::HPPImageMemoryBarrier const &memory_barrier) const
|
|
{
|
|
// Adjust barrier's subresource range for depth images
|
|
auto subresource_range = image_view.get_subresource_range();
|
|
auto format = image_view.get_format();
|
|
if (vkb::common::is_depth_only_format(format))
|
|
{
|
|
subresource_range.aspectMask = vk::ImageAspectFlagBits::eDepth;
|
|
}
|
|
else if (vkb::common::is_depth_stencil_format(format))
|
|
{
|
|
subresource_range.aspectMask = vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil;
|
|
}
|
|
|
|
// This can cause a queue family ownership transfer. Check the async_compute sample.
|
|
vk::ImageMemoryBarrier image_memory_barrier{.srcAccessMask = memory_barrier.src_access_mask,
|
|
.dstAccessMask = memory_barrier.dst_access_mask,
|
|
.oldLayout = memory_barrier.old_layout,
|
|
.newLayout = memory_barrier.new_layout,
|
|
.srcQueueFamilyIndex = memory_barrier.src_queue_family,
|
|
.dstQueueFamilyIndex = memory_barrier.dst_queue_family,
|
|
.image = image_view.get_image().get_handle(),
|
|
.subresourceRange = subresource_range};
|
|
|
|
vk::PipelineStageFlags src_stage_mask = memory_barrier.src_stage_mask;
|
|
vk::PipelineStageFlags dst_stage_mask = memory_barrier.dst_stage_mask;
|
|
|
|
this->get_resource().pipelineBarrier(src_stage_mask, dst_stage_mask, {}, {}, {}, image_memory_barrier);
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::next_subpass()
|
|
{
|
|
// Increment subpass index
|
|
pipeline_state.set_subpass_index(pipeline_state.get_subpass_index() + 1);
|
|
|
|
// Update blend state attachments
|
|
auto blend_state = pipeline_state.get_color_blend_state();
|
|
blend_state.attachments.resize(current_render_pass->get_color_output_count(pipeline_state.get_subpass_index()));
|
|
pipeline_state.set_color_blend_state(blend_state);
|
|
|
|
// Reset descriptor sets
|
|
resource_binding_state.reset();
|
|
descriptor_set_layout_binding_state.clear();
|
|
|
|
// Clear stored push constants
|
|
stored_push_constants.clear();
|
|
|
|
this->get_resource().nextSubpass(vk::SubpassContents::eInline);
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::push_constants(const std::vector<uint8_t> &values)
|
|
{
|
|
uint32_t push_constant_size = to_u32(stored_push_constants.size() + values.size());
|
|
|
|
if (push_constant_size > max_push_constants_size)
|
|
{
|
|
LOGE("Push constant limit of {} exceeded (pushing {} bytes for a total of {} bytes)", max_push_constants_size, values.size(), push_constant_size);
|
|
throw std::runtime_error("Push constant limit exceeded.");
|
|
}
|
|
else
|
|
{
|
|
stored_push_constants.insert(stored_push_constants.end(), values.begin(), values.end());
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
template <typename T>
|
|
inline void CommandBuffer<bindingType>::push_constants(const T &value)
|
|
{
|
|
auto data = to_bytes(value);
|
|
|
|
uint32_t size = to_u32(stored_push_constants.size() + data.size());
|
|
|
|
if (size > max_push_constants_size)
|
|
{
|
|
LOGE("Push constant limit exceeded ({} / {} bytes)", size, max_push_constants_size);
|
|
throw std::runtime_error("Cannot overflow push constant limit");
|
|
}
|
|
|
|
stored_push_constants.insert(stored_push_constants.end(), data.begin(), data.end());
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline typename CommandBuffer<bindingType>::ResultType CommandBuffer<bindingType>::reset(vkb::CommandBufferResetMode reset_mode)
|
|
{
|
|
if constexpr (bindingType == vkb::BindingType::Cpp)
|
|
{
|
|
return reset_impl(reset_mode);
|
|
}
|
|
else
|
|
{
|
|
return static_cast<VkResult>(reset_impl(reset_mode));
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline vk::Result CommandBuffer<bindingType>::reset_impl(vkb::CommandBufferResetMode reset_mode)
|
|
{
|
|
assert(reset_mode == command_pool.get_reset_mode() && "Command buffer reset mode must match the one used by the pool to allocate it");
|
|
if (reset_mode == vkb::CommandBufferResetMode::ResetIndividually)
|
|
{
|
|
this->get_resource().reset(vk::CommandBufferResetFlagBits::eReleaseResources);
|
|
}
|
|
|
|
return vk::Result::eSuccess;
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::reset_query_pool(QueryPoolType const &query_pool, uint32_t first_query, uint32_t query_count)
|
|
{
|
|
if constexpr (bindingType == vkb::BindingType::Cpp)
|
|
{
|
|
this->get_resource().resetQueryPool(query_pool.get_handle(), first_query, query_count);
|
|
}
|
|
else
|
|
{
|
|
this->get_resource().resetQueryPool(static_cast<vk::QueryPool>(query_pool.get_handle()), first_query, query_count);
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::resolve_image(ImageType const &src_img, ImageType const &dst_img, std::vector<ImageResolveType> const ®ions)
|
|
{
|
|
if constexpr (bindingType == vkb::BindingType::Cpp)
|
|
{
|
|
this->get_resource().resolveImage(
|
|
src_img.get_handle(), vk::ImageLayout::eTransferSrcOptimal, dst_img.get_handle(), vk::ImageLayout::eTransferDstOptimal, regions);
|
|
}
|
|
else
|
|
{
|
|
this->get_resource().resolveImage(src_img.get_resource(),
|
|
vk::ImageLayout::eTransferSrcOptimal,
|
|
dst_img.get_resource(),
|
|
vk::ImageLayout::eTransferDstOptimal,
|
|
reinterpret_cast<std::vector<vk::ImageResolve> const &>(regions));
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::set_blend_constants(std::array<float, 4> const &blend_constants)
|
|
{
|
|
this->get_resource().setBlendConstants(blend_constants.data());
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::set_color_blend_state(ColorBlendStateType const &state_info)
|
|
{
|
|
if constexpr (bindingType == vkb::BindingType::Cpp)
|
|
{
|
|
pipeline_state.set_color_blend_state(state_info);
|
|
}
|
|
else
|
|
{
|
|
pipeline_state.set_color_blend_state(reinterpret_cast<vkb::rendering::HPPColorBlendState const &>(state_info));
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::set_depth_bias(float depth_bias_constant_factor, float depth_bias_clamp, float depth_bias_slope_factor)
|
|
{
|
|
this->get_resource().setDepthBias(depth_bias_constant_factor, depth_bias_clamp, depth_bias_slope_factor);
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::set_depth_bounds(float min_depth_bounds, float max_depth_bounds)
|
|
{
|
|
this->get_handle().setDepthBounds(min_depth_bounds, max_depth_bounds);
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::set_depth_stencil_state(DepthStencilStateType const &state_info)
|
|
{
|
|
if constexpr (bindingType == vkb::BindingType::Cpp)
|
|
{
|
|
pipeline_state.set_depth_stencil_state(state_info);
|
|
}
|
|
else
|
|
{
|
|
pipeline_state.set_depth_stencil_state(reinterpret_cast<vkb::rendering::HPPDepthStencilState const &>(state_info));
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::set_input_assembly_state(InputAssemblyStateType const &state_info)
|
|
{
|
|
if constexpr (bindingType == vkb::BindingType::Cpp)
|
|
{
|
|
pipeline_state.set_input_assembly_state(state_info);
|
|
}
|
|
else
|
|
{
|
|
pipeline_state.set_input_assembly_state(reinterpret_cast<vkb::rendering::HPPInputAssemblyState const &>(state_info));
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::set_line_width(float line_width)
|
|
{
|
|
this->get_resource().setLineWidth(line_width);
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::set_multisample_state(MultisampleStateType const &state_info)
|
|
{
|
|
if constexpr (bindingType == vkb::BindingType::Cpp)
|
|
{
|
|
pipeline_state.set_multisample_state(state_info);
|
|
}
|
|
else
|
|
{
|
|
pipeline_state.set_multisample_state(reinterpret_cast<vkb::rendering::HPPMultisampleState const &>(state_info));
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::set_rasterization_state(RasterizationStateType const &state_info)
|
|
{
|
|
if constexpr (bindingType == vkb::BindingType::Cpp)
|
|
{
|
|
pipeline_state.set_rasterization_state(state_info);
|
|
}
|
|
else
|
|
{
|
|
pipeline_state.set_rasterization_state(reinterpret_cast<vkb::rendering::HPPRasterizationState const &>(state_info));
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::set_scissor(uint32_t first_scissor, std::vector<Rect2DType> const &scissors)
|
|
{
|
|
if constexpr (bindingType == vkb::BindingType::Cpp)
|
|
{
|
|
this->get_resource().setScissor(first_scissor, scissors);
|
|
}
|
|
else
|
|
{
|
|
this->get_resource().setScissor(first_scissor, reinterpret_cast<std::vector<vk::Rect2D> const &>(scissors));
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
template <class T>
|
|
inline void CommandBuffer<bindingType>::set_specialization_constant(uint32_t constant_id, T const &data)
|
|
{
|
|
if constexpr (std::is_same<T, bool>::value)
|
|
{
|
|
set_specialization_constant(constant_id, to_bytes(to_u32(data)));
|
|
}
|
|
else
|
|
{
|
|
set_specialization_constant(constant_id, to_bytes(data));
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::set_specialization_constant(uint32_t constant_id, std::vector<uint8_t> const &data)
|
|
{
|
|
pipeline_state.set_specialization_constant(constant_id, data);
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::set_update_after_bind(bool update_after_bind_)
|
|
{
|
|
update_after_bind = update_after_bind_;
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::set_vertex_input_state(VertexInputStateType const &state_info)
|
|
{
|
|
if constexpr (bindingType == vkb::BindingType::Cpp)
|
|
{
|
|
pipeline_state.set_vertex_input_state(state_info);
|
|
}
|
|
else
|
|
{
|
|
pipeline_state.set_vertex_input_state(reinterpret_cast<vkb::rendering::HPPVertexInputState const &>(state_info));
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::set_viewport(uint32_t first_viewport, std::vector<ViewportType> const &viewports)
|
|
{
|
|
if constexpr (bindingType == vkb::BindingType::Cpp)
|
|
{
|
|
this->get_resource().setViewport(first_viewport, viewports);
|
|
}
|
|
else
|
|
{
|
|
this->get_resource().setViewport(first_viewport, reinterpret_cast<std::vector<vk::Viewport> const &>(viewports));
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::set_viewport_state(ViewportStateType const &state_info)
|
|
{
|
|
if constexpr (bindingType == vkb::BindingType::Cpp)
|
|
{
|
|
pipeline_state.set_viewport_state(state_info);
|
|
}
|
|
else
|
|
{
|
|
pipeline_state.set_viewport_state(reinterpret_cast<vkb::rendering::HPPViewportState const &>(state_info));
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::update_buffer(vkb::core::Buffer<bindingType> const &buffer, DeviceSizeType offset, std::vector<uint8_t> const &data)
|
|
{
|
|
if constexpr (bindingType == vkb::BindingType::Cpp)
|
|
{
|
|
this->get_resource().template updateBuffer<uint8_t>(buffer.get_handle(), offset, data);
|
|
}
|
|
else
|
|
{
|
|
this->get_resource().template updateBuffer<uint8_t>(buffer.get_resource(), static_cast<vk::DeviceSize>(offset), data);
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::write_timestamp(PipelineStagFlagBitsType pipeline_stage, QueryPoolType const &query_pool, uint32_t query)
|
|
{
|
|
if constexpr (bindingType == vkb::BindingType::Cpp)
|
|
{
|
|
this->get_resource().writeTimestamp(pipeline_stage, query_pool.get_handle(), query);
|
|
}
|
|
else
|
|
{
|
|
this->get_resource().writeTimestamp(static_cast<vk::PipelineStageFlagBits>(pipeline_stage), query_pool.get_handle(), query);
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::flush(vk::PipelineBindPoint pipeline_bind_point)
|
|
{
|
|
if constexpr (bindingType == vkb::BindingType::Cpp)
|
|
{
|
|
flush_impl(this->get_device(), pipeline_bind_point);
|
|
}
|
|
else
|
|
{
|
|
flush_impl(reinterpret_cast<vkb::core::DeviceCpp &>(this->get_device()), pipeline_bind_point);
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::flush_impl(vkb::core::DeviceCpp &device, vk::PipelineBindPoint pipeline_bind_point)
|
|
{
|
|
flush_pipeline_state_impl(device, pipeline_bind_point);
|
|
flush_push_constants();
|
|
flush_descriptor_state_impl(pipeline_bind_point);
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::flush_descriptor_state_impl(vk::PipelineBindPoint pipeline_bind_point)
|
|
{
|
|
assert(command_pool.get_render_frame() && "The command pool must be associated to a render frame");
|
|
|
|
const auto &pipeline_layout = pipeline_state.get_pipeline_layout();
|
|
|
|
std::unordered_set<uint32_t> update_descriptor_sets;
|
|
|
|
// Iterate over the shader sets to check if they have already been bound
|
|
// If they have, add the set so that the command buffer later updates it
|
|
for (auto &set_it : pipeline_layout.get_shader_sets())
|
|
{
|
|
uint32_t descriptor_set_id = set_it.first;
|
|
|
|
auto descriptor_set_layout_it = descriptor_set_layout_binding_state.find(descriptor_set_id);
|
|
|
|
if (descriptor_set_layout_it != descriptor_set_layout_binding_state.end())
|
|
{
|
|
if (descriptor_set_layout_it->second->get_handle() != pipeline_layout.get_descriptor_set_layout(descriptor_set_id).get_handle())
|
|
{
|
|
update_descriptor_sets.emplace(descriptor_set_id);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Validate that the bound descriptor set layouts exist in the pipeline layout
|
|
for (auto set_it = descriptor_set_layout_binding_state.begin(); set_it != descriptor_set_layout_binding_state.end();)
|
|
{
|
|
if (!pipeline_layout.has_descriptor_set_layout(set_it->first))
|
|
{
|
|
set_it = descriptor_set_layout_binding_state.erase(set_it);
|
|
}
|
|
else
|
|
{
|
|
++set_it;
|
|
}
|
|
}
|
|
|
|
// Check if a descriptor set needs to be created
|
|
if (resource_binding_state.is_dirty() || !update_descriptor_sets.empty())
|
|
{
|
|
resource_binding_state.clear_dirty();
|
|
|
|
// Iterate over all of the resource sets bound by the command buffer
|
|
for (auto &resource_set_it : resource_binding_state.get_resource_sets())
|
|
{
|
|
uint32_t descriptor_set_id = resource_set_it.first;
|
|
auto &resource_set = resource_set_it.second;
|
|
|
|
// Don't update resource set if it's not in the update list OR its state hasn't changed
|
|
if (!resource_set.is_dirty() && (update_descriptor_sets.find(descriptor_set_id) == update_descriptor_sets.end()))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Clear dirty flag for resource set
|
|
resource_binding_state.clear_dirty(descriptor_set_id);
|
|
|
|
// Skip resource set if a descriptor set layout doesn't exist for it
|
|
if (!pipeline_layout.has_descriptor_set_layout(descriptor_set_id))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
auto &descriptor_set_layout = pipeline_layout.get_descriptor_set_layout(descriptor_set_id);
|
|
|
|
// Make descriptor set layout bound for current set
|
|
descriptor_set_layout_binding_state[descriptor_set_id] = &descriptor_set_layout;
|
|
|
|
BindingMap<vk::DescriptorBufferInfo> buffer_infos;
|
|
BindingMap<vk::DescriptorImageInfo> image_infos;
|
|
|
|
std::vector<uint32_t> dynamic_offsets;
|
|
|
|
// Iterate over all resource bindings
|
|
for (auto &binding_it : resource_set.get_resource_bindings())
|
|
{
|
|
auto binding_index = binding_it.first;
|
|
auto &binding_resources = binding_it.second;
|
|
|
|
// Check if binding exists in the pipeline layout
|
|
if (auto binding_info = descriptor_set_layout.get_layout_binding(binding_index))
|
|
{
|
|
// Iterate over all binding resources
|
|
for (auto &element_it : binding_resources)
|
|
{
|
|
auto array_element = element_it.first;
|
|
auto &resource_info = element_it.second;
|
|
|
|
// Pointer references
|
|
auto &buffer = resource_info.buffer;
|
|
auto &sampler = resource_info.sampler;
|
|
auto &image_view = resource_info.image_view;
|
|
|
|
// Get buffer info
|
|
if (buffer != nullptr && vkb::common::is_buffer_descriptor_type(binding_info->descriptorType))
|
|
{
|
|
vk::DescriptorBufferInfo buffer_info{resource_info.buffer->get_handle(), resource_info.offset, resource_info.range};
|
|
|
|
if (vkb::common::is_dynamic_buffer_descriptor_type(binding_info->descriptorType))
|
|
{
|
|
dynamic_offsets.push_back(to_u32(buffer_info.offset));
|
|
buffer_info.offset = 0;
|
|
}
|
|
|
|
buffer_infos[binding_index][array_element] = buffer_info;
|
|
}
|
|
|
|
// Get image info
|
|
else if (image_view != nullptr || sampler != nullptr)
|
|
{
|
|
// Can be null for input attachments
|
|
vk::DescriptorImageInfo image_info{sampler ? sampler->get_handle() : nullptr, image_view->get_handle()};
|
|
|
|
if (image_view != nullptr)
|
|
{
|
|
// Add image layout info based on descriptor type
|
|
switch (binding_info->descriptorType)
|
|
{
|
|
case vk::DescriptorType::eCombinedImageSampler:
|
|
image_info.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
|
|
break;
|
|
case vk::DescriptorType::eInputAttachment:
|
|
image_info.imageLayout = vkb::common::is_depth_format(image_view->get_format()) ? vk::ImageLayout::eDepthStencilReadOnlyOptimal : vk::ImageLayout::eShaderReadOnlyOptimal;
|
|
break;
|
|
case vk::DescriptorType::eStorageImage:
|
|
image_info.imageLayout = vk::ImageLayout::eGeneral;
|
|
break;
|
|
default:
|
|
continue;
|
|
}
|
|
}
|
|
|
|
image_infos[binding_index][array_element] = image_info;
|
|
}
|
|
}
|
|
|
|
assert((!update_after_bind || (buffer_infos.count(binding_index) > 0 || (image_infos.count(binding_index) > 0))) &&
|
|
"binding index with no buffer or image infos can't be checked for adding to bindings_to_update");
|
|
}
|
|
}
|
|
|
|
vk::DescriptorSet descriptor_set_handle = command_pool.get_render_frame()->request_descriptor_set(
|
|
descriptor_set_layout, buffer_infos, image_infos, update_after_bind, command_pool.get_thread_index());
|
|
|
|
// Bind descriptor set
|
|
this->get_resource().bindDescriptorSets(pipeline_bind_point, pipeline_layout.get_handle(), descriptor_set_id, descriptor_set_handle, dynamic_offsets);
|
|
}
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::flush_pipeline_state_impl(vkb::core::DeviceCpp &device, vk::PipelineBindPoint pipeline_bind_point)
|
|
{
|
|
// Create a new pipeline only if the graphics state changed
|
|
if (!pipeline_state.is_dirty())
|
|
{
|
|
return;
|
|
}
|
|
|
|
pipeline_state.clear_dirty();
|
|
|
|
// Create and bind pipeline
|
|
if (pipeline_bind_point == vk::PipelineBindPoint::eGraphics)
|
|
{
|
|
pipeline_state.set_render_pass(*current_render_pass);
|
|
auto &pipeline = device.get_resource_cache().request_graphics_pipeline(pipeline_state);
|
|
|
|
this->get_resource().bindPipeline(pipeline_bind_point, pipeline.get_handle());
|
|
}
|
|
else if (pipeline_bind_point == vk::PipelineBindPoint::eCompute)
|
|
{
|
|
auto &pipeline = device.get_resource_cache().request_compute_pipeline(pipeline_state);
|
|
|
|
this->get_resource().bindPipeline(pipeline_bind_point, pipeline.get_handle());
|
|
}
|
|
else
|
|
{
|
|
throw "Only graphics and compute pipeline bind points are supported now";
|
|
}
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline void CommandBuffer<bindingType>::flush_push_constants()
|
|
{
|
|
if (stored_push_constants.empty())
|
|
{
|
|
return;
|
|
}
|
|
|
|
auto const &pipeline_layout = pipeline_state.get_pipeline_layout();
|
|
|
|
vk::ShaderStageFlags shader_stage = pipeline_layout.get_push_constant_range_stage(to_u32(stored_push_constants.size()));
|
|
|
|
if (shader_stage)
|
|
{
|
|
this->get_resource().template pushConstants<uint8_t>(pipeline_layout.get_handle(), shader_stage, 0, stored_push_constants);
|
|
}
|
|
else
|
|
{
|
|
LOGW("Push constant range [{}, {}] not found", 0, stored_push_constants.size());
|
|
}
|
|
|
|
stored_push_constants.clear();
|
|
}
|
|
|
|
template <vkb::BindingType bindingType>
|
|
inline bool CommandBuffer<bindingType>::is_render_size_optimal(const vk::Extent2D &framebuffer_extent, const vk::Rect2D &render_area)
|
|
{
|
|
auto render_area_granularity = current_render_pass->get_render_area_granularity();
|
|
|
|
return ((render_area.offset.x % render_area_granularity.width == 0) && (render_area.offset.y % render_area_granularity.height == 0) &&
|
|
((render_area.extent.width % render_area_granularity.width == 0) ||
|
|
(render_area.offset.x + render_area.extent.width == framebuffer_extent.width)) &&
|
|
((render_area.extent.height % render_area_granularity.height == 0) ||
|
|
(render_area.offset.y + render_area.extent.height == framebuffer_extent.height)));
|
|
}
|
|
} // namespace core
|
|
} // namespace vkb
|