mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-11-11 12:24:25 +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:
@@ -25,11 +25,23 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "rendering/vulkan14/vulkan14imgui.h"
|
||||
#include "rendering/vulkan14/vulkan14bindings.h"
|
||||
#include "rendering/vulkan14/vulkan14geometry.h"
|
||||
#include "rendering/vulkan14/vulkan14compute.h"
|
||||
#include "rendering/vulkan14/vulkan14cull.h"
|
||||
#include "rendering/vulkan14/vulkan14shadows.h"
|
||||
#include "rendering/vulkan14/vulkan14terrain.h"
|
||||
#include "rendering/vulkan14/vulkan14grass.h"
|
||||
#include "rendering/vulkan14/vulkan14particles.h"
|
||||
#include "rendering/vulkan14/vulkan14commands.h"
|
||||
#include "utilities/workerpool.h"
|
||||
#include "model/material.h"
|
||||
#include "gl/ubo.h"
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
@@ -42,8 +54,10 @@ enum class vertex_kind : std::uint8_t
|
||||
none, // made by the vertex shader (the celestial bodies, the full screen quads)
|
||||
scene, // gfx::basic_vertex and the user data, the geometry banks
|
||||
colour, // position and colour, the sky dome
|
||||
star, // direction with the magnitude and colour with the phase of the twinkling in one stream, the stars
|
||||
particle, // position, colour and texture coordinates in one stream, the smoke
|
||||
position_uv // position and texture coordinates in two streams, the precipitation
|
||||
position_uv, // position and texture coordinates in two streams, the precipitation
|
||||
particle_instance // three vec4 of gl::particle_draw for each instance, the particles of the gpu
|
||||
};
|
||||
|
||||
// the push constants of the pipelines of the scene and of the post-processing (shaders/vk14/common.glsl, draw_constants_block)
|
||||
@@ -65,6 +79,12 @@ struct scene_program : public gfx::shader_program
|
||||
// the fragment shader of the passes without the velocity target (NO_MOTION_OUTPUT), made when it's first needed
|
||||
std::string fragment_name;
|
||||
std::shared_ptr<shader_code const> fragment_single;
|
||||
// the vertex shader, and the definitions both stages were made with
|
||||
std::string vertex_name;
|
||||
std::string defines;
|
||||
// the variant of the multi draws of the instances drawn from the gpu culling (MODEL_DRAWS), made when it's first needed
|
||||
std::shared_ptr<scene_program> multidraw;
|
||||
bool multidraw_tried{false};
|
||||
vertex_kind vertices{vertex_kind::scene};
|
||||
std::unordered_map<std::uint64_t, VkPipeline> pipelines;
|
||||
};
|
||||
@@ -76,6 +96,8 @@ struct target_formats
|
||||
std::uint32_t colours{0};
|
||||
VkFormat depth{VK_FORMAT_UNDEFINED};
|
||||
VkSampleCountFlagBits samples{VK_SAMPLE_COUNT_1_BIT};
|
||||
// the views drawn at once (multiview), 0: none
|
||||
std::uint32_t view_mask{0};
|
||||
// the number the pipelines of the targets are known by
|
||||
std::uint32_t id{0};
|
||||
};
|
||||
@@ -102,6 +124,19 @@ struct viewport_targets
|
||||
std::shared_ptr<image> output;
|
||||
// the depth under the cursor of the editor: one sample of the depth of the ground resolved to it, and the buffer it's read back with
|
||||
std::shared_ptr<image> cursor_depth;
|
||||
// the depth of the opaque scene drawn before its colour, which the contact shadows read (the stage P3), and the formats of the
|
||||
// pass drawing it (the depth alone)
|
||||
std::shared_ptr<image> scene_depth;
|
||||
target_formats depth_formats;
|
||||
// the ambient occlusion (gfx.postfx.ao, the stage P3), half the size: the raw one and the smoothed one; made when it's on
|
||||
std::shared_ptr<image> ssao;
|
||||
std::shared_ptr<image> ssao_blur;
|
||||
// the formats of the passes drawn over the colour of the scene after it (the ambient occlusion): the colour alone
|
||||
target_formats post_formats;
|
||||
// the bloom chain (gfx.postfx.bloom, the stage P1): the levels down, half the size each, and up, one fewer
|
||||
std::vector<std::shared_ptr<image>> bloom_down;
|
||||
std::vector<std::shared_ptr<image>> bloom_up;
|
||||
std::vector<glm::ivec2> bloom_sizes;
|
||||
target_formats formats;
|
||||
target_formats output_formats;
|
||||
bool srgb{true}; // the output encodes the colour (gfx.shadergamma no)
|
||||
@@ -129,6 +164,16 @@ struct cluster_state
|
||||
bool stale{true}; // the boxes have to be made anew
|
||||
VkDeviceSize params_offset{0}; // in the ring of the frame, for the pass under way
|
||||
std::uint32_t lights_total{0};
|
||||
// the counters of the cullings read back, for the debug panel (gl::cluster_grid::cull_stats): entries of the index list in
|
||||
// use, lights dropped from full clusters, the most of them seen
|
||||
readback_ring counters_readback;
|
||||
struct
|
||||
{
|
||||
std::uint32_t index_count{0};
|
||||
std::uint32_t overflow_count{0};
|
||||
std::uint32_t overflow_peak{0};
|
||||
bool valid{false};
|
||||
} stats;
|
||||
};
|
||||
|
||||
// a picking or a reading of a value of the depth, waiting for the gpu to be done with the frame it was made in
|
||||
@@ -140,6 +185,104 @@ struct readback
|
||||
glm::ivec2 position{0};
|
||||
};
|
||||
|
||||
// the light of the sky on the gpu (the stage P1, opengl46_sky): the buffers the shading reads (the directional ambient light,
|
||||
// the parameters of the atmosphere), the look-up tables of the atmosphere with the kernels making them and the result read
|
||||
// back, the environment map prefiltered with the GGX lobe, the stars
|
||||
struct sky_state
|
||||
{
|
||||
buffer sky; // gl::sky_data
|
||||
buffer atmosphere; // gl::atmosphere_ubs
|
||||
buffer result; // gl::atmosphere_result, written by atmosphere_ambient.comp
|
||||
readback_ring result_readback;
|
||||
std::shared_ptr<image> transmittance;
|
||||
std::shared_ptr<image> multiscattering;
|
||||
std::shared_ptr<image> skyview;
|
||||
bool tables_ready{false}; // the tables were made once (they are black before)
|
||||
compute_kernel transmittance_kernel;
|
||||
compute_kernel multiscattering_kernel;
|
||||
compute_kernel skyview_kernel;
|
||||
compute_kernel ambient_kernel;
|
||||
// the prefiltered environment map, a cube view of each of its levels for the prefilter to write
|
||||
std::shared_ptr<image> ggx;
|
||||
std::vector<VkImageView> ggx_levels;
|
||||
bool ggx_ready{false};
|
||||
compute_kernel prefilter_kernel;
|
||||
// what the buffers were last given
|
||||
gl::sky_data uploaded{};
|
||||
bool sky_uploaded{false};
|
||||
// the dome drawn with the atmosphere, the stars of the catalogue
|
||||
std::shared_ptr<scene_program> atmosphere_dome;
|
||||
std::shared_ptr<scene_program> stars;
|
||||
std::shared_ptr<buffer> star_vertices;
|
||||
std::uint32_t star_count{0};
|
||||
};
|
||||
|
||||
// the automatic exposure (the stage P1, opengl46_exposure): the histogram and the exposure on the gpu (gl::exposure_data), the
|
||||
// kernels, the values read back for the debug window
|
||||
struct exposure_state
|
||||
{
|
||||
buffer data;
|
||||
compute_kernel histogram;
|
||||
compute_kernel average;
|
||||
readback_ring readback;
|
||||
float values[4]{1.f, 1.f, 1.f, 0.f};
|
||||
bool cleared{false};
|
||||
};
|
||||
|
||||
// the weather on the gpu (the stage P2, opengl46_weather): the noises of the clouds, the map of their shadows, the clouds of the
|
||||
// main view and their history, the panorama of the clouds for the other views, the fog volume of the main view and its
|
||||
// history, with the kernels making them, and the program laying the clouds and the fog over the sky
|
||||
struct weather_resources
|
||||
{
|
||||
std::shared_ptr<image> shape_noise;
|
||||
std::shared_ptr<image> detail_noise;
|
||||
std::shared_ptr<image> coverage_noise;
|
||||
bool noise_made{false};
|
||||
std::shared_ptr<image> shadow_map;
|
||||
int shadow_size{0};
|
||||
// the clouds of the main view, at a part of its resolution
|
||||
glm::ivec2 view_size{0};
|
||||
std::shared_ptr<image> clouds_color;
|
||||
std::shared_ptr<image> clouds_depth;
|
||||
std::array<std::shared_ptr<image>, 2> clouds_history;
|
||||
int clouds_current{0}; // the history holding the latest result
|
||||
std::shared_ptr<image> panorama;
|
||||
glm::ivec2 panorama_size{0};
|
||||
// what the panorama is marched with as its depth, which it doesn't write
|
||||
std::shared_ptr<image> depth_dummy;
|
||||
// the fog volume: the scattering of the cells and its history, the fog integrated along the view
|
||||
glm::ivec3 fog_grid{0};
|
||||
std::array<std::shared_ptr<image>, 2> fog_scattering;
|
||||
int fog_current{0};
|
||||
std::shared_ptr<image> fog_integrated;
|
||||
compute_kernel noise;
|
||||
compute_kernel march;
|
||||
compute_kernel temporal;
|
||||
compute_kernel shadow;
|
||||
compute_kernel horizon;
|
||||
compute_kernel inject;
|
||||
compute_kernel integrate;
|
||||
std::shared_ptr<scene_program> sky;
|
||||
};
|
||||
|
||||
// the gpu culling of the instances (the stage P5, Global.gfx_gpucull): the cullings of the passes, which share the records and
|
||||
// the kernels with the one of the main view, and the depth pyramid of its occlusion test
|
||||
struct cull_resources
|
||||
{
|
||||
instance_cull main;
|
||||
std::array<instance_cull, 3> cascades;
|
||||
instance_cull reflections;
|
||||
// the maps of headlights, by the slot of the map, and the scenery parts of the maps of lamps, by their order among those drawn
|
||||
// in a frame: the passes of a frame don't share the buffers of a culling. made when first needed
|
||||
std::vector<std::unique_ptr<instance_cull>> headlights;
|
||||
std::vector<std::unique_ptr<instance_cull>> lamps;
|
||||
hiz_pyramid hiz;
|
||||
bool ready{false};
|
||||
// the cascades of the sun shadows fitted to the depth of the main view (gfx.shadow.sdsm), made when they're first needed
|
||||
shadow_fitter shadowfit;
|
||||
bool shadowfit_tried{false};
|
||||
};
|
||||
|
||||
// what the scene is drawn with
|
||||
struct scene_state
|
||||
{
|
||||
@@ -163,6 +306,8 @@ struct scene_state
|
||||
};
|
||||
std::array<VkDescriptorSet, set_count> pass_sets{};
|
||||
bool pass_sets_stale{true};
|
||||
// the pass sets were made anew this many times (the ones of the cullings follow them)
|
||||
std::uint64_t pass_generation{0};
|
||||
// the rings of the draws: the blocks of the models (gl::model_ubs) and the modelview matrices of the instances
|
||||
window_ring draws;
|
||||
window_ring instances;
|
||||
@@ -178,10 +323,48 @@ struct scene_state
|
||||
std::array<VkImageView, 6> env_faces{};
|
||||
std::shared_ptr<image> pick_colour;
|
||||
std::shared_ptr<image> pick_depth;
|
||||
// the stand-ins of the images of the stages P the pass sets hold until there are real ones: a volume (the fog volume, the noises
|
||||
// of the clouds), the cube shadow maps of the lamps, the shadow maps of the headlights, the depth of the scene
|
||||
std::shared_ptr<image> volume_empty;
|
||||
std::shared_ptr<image> cube_shadow_empty;
|
||||
std::shared_ptr<image> headlight_shadow_empty;
|
||||
std::shared_ptr<image> depth_empty;
|
||||
// the colours of the fog towards the horizon (the stage P2), a block of the pass sets
|
||||
buffer weather_horizon;
|
||||
VkImageView headlights_view{VK_NULL_HANDLE}; // the one the pass sets were made with
|
||||
VkSampler headlights_sampler{VK_NULL_HANDLE};
|
||||
// the views of the images of the bindings of each pass set it was made with (vulkan14scene.cpp, pass_set_images())
|
||||
std::array<std::array<VkImageView, bindings::PASS_BINDING_COUNT>, 3> pass_images{};
|
||||
cluster_state clusters;
|
||||
// the ambient occlusion: the noise of the older ssao, the kernels of the ground truth one, the program applying it
|
||||
std::shared_ptr<image> ssao_noise;
|
||||
compute_kernel gtao_main;
|
||||
compute_kernel gtao_denoise;
|
||||
std::shared_ptr<scene_program> ao_apply;
|
||||
sky_state sky;
|
||||
exposure_state exposure;
|
||||
weather_resources weather;
|
||||
cull_resources cull;
|
||||
// the shadow maps of the lamps and the headlights (the stage P4), and the programs drawing the cube maps
|
||||
local_shadow_maps lamps;
|
||||
std::shared_ptr<scene_program> cube_shadow, cube_alpha_shadow;
|
||||
target_formats cube_formats;
|
||||
// the materials of the heightmap terrain (the stage P6), made with the bank of the textures
|
||||
std::unique_ptr<terrain_materials> terrain;
|
||||
// the grass of the heightmap terrain, and its program, made when it's first drawn
|
||||
grass_field grass;
|
||||
std::shared_ptr<scene_program> grass_program;
|
||||
bool grass_tried{false};
|
||||
// the smoke and the rain or snow of the gpu
|
||||
gpu_particles particles;
|
||||
// the heatmap of the light clusters (gfx.lights.clusterheatmap), made when it's first drawn
|
||||
std::shared_ptr<scene_program> cluster_heatmap;
|
||||
bool cluster_heatmap_tried{false};
|
||||
// the targets of the viewports, [0] the main window
|
||||
std::vector<viewport_targets> targets;
|
||||
// the format of the levels of the bloom chains: no alpha, no negative values, half the memory of rgba16f, where the device
|
||||
// draws to it
|
||||
VkFormat bloom_format{VK_FORMAT_B10G11R11_UFLOAT_PACK32};
|
||||
// the formats of the passes which don't depend on the viewport
|
||||
target_formats shadow_formats;
|
||||
target_formats reflection_formats;
|
||||
@@ -190,6 +373,9 @@ struct scene_state
|
||||
// the programs: of the materials (by the name Fetch_Shader() is given), and the ones of the renderer
|
||||
std::unordered_map<std::string, std::shared_ptr<scene_program>> materials;
|
||||
std::shared_ptr<scene_program> shadow, alpha_shadow, pick, pick_surface, line, billboard, freespot, celestial, skydome, smoke, precipitation;
|
||||
// the depth prepass of the scene (the stage P3): without and with the alpha test, and which of them a program of a material takes
|
||||
std::shared_ptr<scene_program> prepass, prepass_alpha;
|
||||
std::unordered_map<gfx::shader_program const *, int> prepass_classes;
|
||||
// the post-processing, by the fragment shader
|
||||
std::unordered_map<std::string, std::shared_ptr<shader_code const>> post_fragments;
|
||||
std::shared_ptr<shader_code const> quad;
|
||||
@@ -225,7 +411,20 @@ struct vulkan14_renderer::context
|
||||
VkCommandPool pool{VK_NULL_HANDLE};
|
||||
// the uploads of the frame go to the queue first, then the commands of the frame
|
||||
VkCommandBuffer uploads{VK_NULL_HANDLE};
|
||||
VkCommandBuffer commands{VK_NULL_HANDLE};
|
||||
// the calls made while the frame is made, recorded into the command buffers once it's done (M1): the uploads into theirs,
|
||||
// the commands chunk by chunk by the workers
|
||||
vk14::command_stream upload_stream;
|
||||
vk14::command_stream commands;
|
||||
// a command pool for each worker, with the command buffers it made
|
||||
struct worker_commands
|
||||
{
|
||||
VkCommandPool pool{VK_NULL_HANDLE};
|
||||
std::vector<VkCommandBuffer> buffers;
|
||||
std::size_t used{0};
|
||||
};
|
||||
std::vector<worker_commands> workers;
|
||||
// the command buffers of the chunks of the frame, in their order
|
||||
std::vector<VkCommandBuffer> chunks;
|
||||
// the value of the timeline semaphore the gpu reaches when it's done with the frame; 0: never submitted
|
||||
std::uint64_t done{0};
|
||||
// the number of the frame, for the report of a lost device
|
||||
@@ -262,7 +461,35 @@ struct vulkan14_renderer::context
|
||||
bool devicelost{false};
|
||||
// the frame being recorded: its index among the frames in flight, its commands
|
||||
std::uint32_t slot{0};
|
||||
VkCommandBuffer commands{VK_NULL_HANDLE};
|
||||
vk14::command_stream *commands{nullptr};
|
||||
// the threads recording the command buffers of the frames: a pool of its own, the one of the application is for the simulation
|
||||
worker_pool workers;
|
||||
// the cpu time the command buffers of the last frame took to record, in milliseconds; its calls and chunks
|
||||
std::atomic<double> record_time{0.0};
|
||||
std::atomic<std::size_t> record_calls{0};
|
||||
std::atomic<std::size_t> record_chunks{0};
|
||||
std::atomic<std::size_t> record_threads{0};
|
||||
// what's left of a frame made by the main thread: recording its command buffers, submitting them, presenting its windows
|
||||
struct render_job
|
||||
{
|
||||
frame *target{nullptr};
|
||||
bool uploaded{false};
|
||||
std::vector<VkSemaphoreSubmitInfo> waits;
|
||||
std::vector<VkSemaphoreSubmitInfo> signals;
|
||||
// the windows presented once the frame is submitted (the render thread)
|
||||
std::vector<vk14::swapchain *> windows;
|
||||
};
|
||||
// the render thread and the job it's given
|
||||
std::thread render_thread;
|
||||
std::mutex render_mutex;
|
||||
std::condition_variable render_wake;
|
||||
std::condition_variable render_idle;
|
||||
render_job render_pending;
|
||||
bool render_queued{false}; // render_pending holds a job not done yet
|
||||
bool render_stop{false};
|
||||
char const *render_failure{nullptr};
|
||||
// how long the main thread waited for the render thread at the start of the last frame, in milliseconds
|
||||
double render_wait{0.0};
|
||||
|
||||
~context()
|
||||
{
|
||||
@@ -270,6 +497,26 @@ struct vulkan14_renderer::context
|
||||
}
|
||||
|
||||
bool create_frames(std::uint32_t const Count, std::string &Reason);
|
||||
// the streams of Frame recorded into its command buffers; false: no command buffer for them
|
||||
bool record(frame &Frame, bool Uploads);
|
||||
|
||||
// the job done; false: Failure says where it failed
|
||||
bool execute(render_job &Job, char const *&Failure);
|
||||
// the windows of the frame submitted last presented; false: the device or a surface is lost
|
||||
bool present(std::vector<vk14::swapchain *> const &Windows);
|
||||
// the render thread (gfx.vulkan.renderthread, M4): the frames are recorded, submitted and presented by it while the main
|
||||
// thread goes on with the simulation of the next one. the main thread waits for it to be done before it begins a frame and
|
||||
// before anything else touches the queue, the swapchains or the device as a whole
|
||||
void start_render_thread();
|
||||
void stop_render_thread();
|
||||
bool render_threaded() const
|
||||
{
|
||||
return render_thread.joinable();
|
||||
}
|
||||
// the job given to the render thread
|
||||
void hand_over(render_job &&Job);
|
||||
// waits until the render thread is done with the jobs given to it; where it failed, if it did
|
||||
char const *drain();
|
||||
// the parts of the renderer made once the device is there
|
||||
bool create_core(std::uint32_t const Frames, std::string &Reason);
|
||||
// the value of the timeline the gpu reached, 0 when it can't be read
|
||||
@@ -282,7 +529,7 @@ struct vulkan14_renderer::context
|
||||
// the state of the draws of the walk being recorded into a pass of the scene
|
||||
struct vulkan14_renderer::draw_state
|
||||
{
|
||||
VkCommandBuffer commands{VK_NULL_HANDLE};
|
||||
vk14::command_stream *commands{nullptr};
|
||||
vk14::target_formats const *targets{nullptr};
|
||||
VkExtent2D extent{0, 0};
|
||||
vk14::scene_state::pass_set_kind set{vk14::scene_state::set_plain};
|
||||
@@ -292,6 +539,7 @@ struct vulkan14_renderer::draw_state
|
||||
std::uint32_t scene_offset{0};
|
||||
std::uint32_t light_offset{0};
|
||||
std::uint32_t cluster_offset{0};
|
||||
std::uint32_t weather_offset{0};
|
||||
bool set_dirty{true};
|
||||
// the program and the textures for the next draw (walk_material(), walk_program(), walk_texture())
|
||||
vk14::scene_program *program{nullptr};
|
||||
@@ -319,4 +567,20 @@ struct vulkan14_renderer::draw_state
|
||||
std::uint32_t query{~0u}; // the query under way
|
||||
// the draws made in the pass, for the debug panel
|
||||
std::uint32_t draws{0};
|
||||
// the depth of the scene before its colour (the stage P3): the walk draws with the programs of the depth prepass, and what they
|
||||
// don't draw is left out (depthskip, set by walk_material())
|
||||
bool depthpass{false};
|
||||
bool depthskip{true};
|
||||
// the pass sets of a culling, the instance buffer its output, for the indirect draws of its instances; null: the pass sets
|
||||
VkDescriptorSet const *cull_sets{nullptr};
|
||||
// the rendering under way, begun again where it was after it was ended for the compute passes of the culling
|
||||
struct rendering_resume
|
||||
{
|
||||
std::array<VkRenderingAttachmentInfo, 2> colours{};
|
||||
VkRenderingAttachmentInfo depth{};
|
||||
bool has_depth{false};
|
||||
VkRenderingInfo info{};
|
||||
std::vector<vk14::image_use> uses;
|
||||
bool valid{false};
|
||||
} resume;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user