mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-11-11 19:11:16 +01:00
Vulkan: parity with GL (P1–P7), shared GPU culling records (N6c), threaded command recording and render thread (M1, M4)
This commit is contained in:
156
rendering/vulkan14/vulkan14compute.h
Normal file
156
rendering/vulkan14/vulkan14compute.h
Normal file
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
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/.
|
||||
*/
|
||||
|
||||
// the compute passes of the vulkan renderer (the stages P of the plan): a kernel is a compute shader of shaders/vk14 with its
|
||||
// pipeline. its layout is the pass set of the scene (set 0, the persistent one, for the shaders which read the lights, the
|
||||
// clusters, the shadow maps or the weather of the pass) and a pushed set of its own (set 1), whose bindings are read from the
|
||||
// SPIR-V of the shader, with push constants for the parameters the opengl renderer gives its compute programs as loose
|
||||
// uniforms. the data of the gpu read back by the cpu goes through a readback ring, a buffer seen by the cpu for each frame in
|
||||
// flight, taken once the gpu is done with the frame
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "rendering/vulkan14/vulkan14common.h"
|
||||
#include "rendering/vulkan14/vulkan14descriptors.h"
|
||||
#include "rendering/vulkan14/vulkan14memory.h"
|
||||
#include "rendering/vulkan14/vulkan14shaders.h"
|
||||
|
||||
#include <optional>
|
||||
|
||||
namespace vk14
|
||||
{
|
||||
|
||||
// what a template of a pushed set reads for each of its bindings: an image or a buffer, laid out alike
|
||||
union descriptor
|
||||
{
|
||||
VkDescriptorImageInfo image;
|
||||
VkDescriptorBufferInfo buffer;
|
||||
};
|
||||
static_assert(sizeof(VkDescriptorImageInfo) == sizeof(VkDescriptorBufferInfo), "the images and the buffers of the templates are laid out by one stride");
|
||||
|
||||
inline descriptor image_descriptor(VkSampler Sampler, VkImageView View, VkImageLayout Layout)
|
||||
{
|
||||
descriptor result;
|
||||
result.image = VkDescriptorImageInfo{Sampler, View, Layout};
|
||||
return result;
|
||||
}
|
||||
inline descriptor storage_image(VkImageView View)
|
||||
{
|
||||
descriptor result;
|
||||
result.image = VkDescriptorImageInfo{VK_NULL_HANDLE, View, VK_IMAGE_LAYOUT_GENERAL};
|
||||
return result;
|
||||
}
|
||||
inline descriptor buffer_descriptor(VkBuffer Buffer, VkDeviceSize Offset, VkDeviceSize Range)
|
||||
{
|
||||
descriptor result;
|
||||
result.buffer = VkDescriptorBufferInfo{Buffer, Offset, Range};
|
||||
return result;
|
||||
}
|
||||
|
||||
// the bindings of the descriptor set Set the shader uses, from the decorations of its variables, in the order of the bindings
|
||||
std::vector<VkDescriptorSetLayoutBinding> reflect_bindings(std::vector<std::uint32_t> const &Spirv, std::uint32_t Set, VkShaderStageFlags Stages);
|
||||
|
||||
// the set of the compute kernels pushed with their dispatches
|
||||
constexpr std::uint32_t COMPUTE_PUSH_SET = 1;
|
||||
// the push constants of the kernels at most, vulkan 1.4 guarantees them
|
||||
constexpr std::uint32_t COMPUTE_PUSH_CONSTANTS = 256;
|
||||
|
||||
class compute_kernel
|
||||
{
|
||||
public:
|
||||
compute_kernel() = default;
|
||||
compute_kernel(compute_kernel const &) = delete;
|
||||
compute_kernel &operator=(compute_kernel const &) = delete;
|
||||
|
||||
// the kernel of the shader: Passlayout is the layout of the pass set of the scene, set 0 of every kernel; the bindings of
|
||||
// set 1 are those the shader declares. Specialization: the values of the constants 0, 1, 2 ...
|
||||
bool create(VkDevice Device, pipeline_library &Pipelines, std::shared_ptr<shader_code const> const &Shader, VkDescriptorSetLayout Passlayout, std::vector<std::uint32_t> const &Specialization, std::string const &Name);
|
||||
void destroy(VkDevice Device);
|
||||
explicit operator bool() const
|
||||
{
|
||||
return m_pipeline != VK_NULL_HANDLE;
|
||||
}
|
||||
VkPipelineLayout layout() const
|
||||
{
|
||||
return m_layout;
|
||||
}
|
||||
std::size_t bindings() const
|
||||
{
|
||||
return m_count;
|
||||
}
|
||||
// the pipeline bound, the set pushed (Descriptors in the order of the bindings of the shader), the constants pushed (Size
|
||||
// bytes) and the groups dispatched
|
||||
void dispatch(command_stream *Commands, descriptor const *Descriptors, void const *Constants, std::uint32_t Size, std::uint32_t X, std::uint32_t Y = 1, std::uint32_t Z = 1) const;
|
||||
template <typename Constants> void dispatch(command_stream *Commands, std::vector<descriptor> const &Descriptors, Constants const &Data, std::uint32_t X, std::uint32_t Y = 1, std::uint32_t Z = 1) const
|
||||
{
|
||||
static_assert(sizeof(Constants) <= COMPUTE_PUSH_CONSTANTS, "too many push constants");
|
||||
dispatch(Commands, Descriptors.data(), &Data, static_cast<std::uint32_t>(sizeof(Constants)), X, Y, Z);
|
||||
}
|
||||
// the same without push constants
|
||||
void run(command_stream *Commands, std::vector<descriptor> const &Descriptors, std::uint32_t X, std::uint32_t Y = 1, std::uint32_t Z = 1) const
|
||||
{
|
||||
dispatch(Commands, Descriptors.data(), nullptr, 0, X, Y, Z);
|
||||
}
|
||||
// the same with the groups taken from a buffer
|
||||
void dispatch_indirect(command_stream *Commands, descriptor const *Descriptors, void const *Constants, std::uint32_t Size, VkBuffer Buffer, VkDeviceSize Offset) const;
|
||||
|
||||
private:
|
||||
void bind(command_stream *Commands, descriptor const *Descriptors, void const *Constants, std::uint32_t Size) const;
|
||||
|
||||
push_set m_set;
|
||||
VkPipelineLayout m_layout{VK_NULL_HANDLE};
|
||||
VkPipeline m_pipeline{VK_NULL_HANDLE};
|
||||
std::size_t m_count{0};
|
||||
std::string m_name;
|
||||
};
|
||||
|
||||
// a global memory barrier, between the passes which write and read buffers (the images have their own, vk14::barriers())
|
||||
void memory_barrier(command_stream *Commands, VkPipelineStageFlags2 SrcStage, VkAccessFlags2 SrcAccess, VkPipelineStageFlags2 DstStage, VkAccessFlags2 DstAccess);
|
||||
// the writes of the compute passes made seen by what follows: the compute passes, the draws, the indirect commands, the copies
|
||||
void compute_barrier(command_stream *Commands);
|
||||
// Size bytes of Data (a multiple of 4, at most 64 KiB) written to the buffer from Offset with the commands of the frame, between
|
||||
// its reads by the shaders before and after. outside a rendering
|
||||
void update_buffer(command_stream *Commands, buffer const &Target, void const *Data, VkDeviceSize Size, VkDeviceSize Offset);
|
||||
|
||||
// data copied from the gpu for the cpu: a buffer per frame in flight, the copy of a frame read once the gpu is done with it
|
||||
class readback_ring
|
||||
{
|
||||
public:
|
||||
bool create(allocator const &Allocator, VkDeviceSize Size, std::uint32_t Frames, std::string const &Name);
|
||||
void destroy();
|
||||
// the copy of Size bytes (at most the size of the ring) of Source from Offset, in the frame of the slot, done by the gpu once
|
||||
// it reaches Value of the timeline
|
||||
void push(command_stream *Commands, std::uint32_t Slot, std::uint64_t Value, VkBuffer Source, VkDeviceSize Offset, VkDeviceSize Size);
|
||||
// the newest copy the gpu is done with (Completed: the value of the timeline it reached), copied to Data; false when there's
|
||||
// none newer than the one taken last
|
||||
bool pop(std::uint64_t Completed, void *Data, VkDeviceSize Size);
|
||||
// the frame of the copy taken last, for the data which tell what they were made for
|
||||
std::uint64_t popped_value() const
|
||||
{
|
||||
return m_popped;
|
||||
}
|
||||
std::uint32_t popped_slot() const
|
||||
{
|
||||
return m_poppedslot;
|
||||
}
|
||||
|
||||
private:
|
||||
struct slot
|
||||
{
|
||||
buffer data;
|
||||
std::uint64_t value{0};
|
||||
bool pending{false};
|
||||
};
|
||||
std::vector<slot> m_slots;
|
||||
VkDeviceSize m_size{0};
|
||||
std::uint64_t m_popped{0};
|
||||
std::uint32_t m_poppedslot{0};
|
||||
};
|
||||
|
||||
} // namespace vk14
|
||||
Reference in New Issue
Block a user