17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-11-11 11:19:48 +01:00

Add DLSS Frame Generation (gfx.framegeneration x2/x3/x4) and Reflex (gfx.reflex) to the Vulkan renderer

This commit is contained in:
2026-10-25 20:52:12 +01:00
parent 1841e6d7b0
commit a6bdeeaa2b
23 changed files with 1474 additions and 85 deletions

View File

@@ -40,6 +40,7 @@ http://mozilla.org/MPL/2.0/.
#include <array>
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <memory>
#include <mutex>
@@ -161,6 +162,27 @@ struct viewport_targets
bool srgb{true}; // the output encodes the colour (gfx.shadergamma no)
};
// the images of the frame generation of dlss (gfx.framegeneration) for the main window, made for its size and its format: the frame
// with the user interface (the backbuffer) and without it (the hudless), the frames generated, the size of the window; the depth
// and the velocities turned over (postfx_fg_flip.frag), the size of the scene. all of them storage images (ngx takes them so)
struct generation_targets
{
VkExtent2D extent{0, 0};
VkExtent2D render{0, 0};
VkFormat window_format{VK_FORMAT_UNDEFINED};
// unorm (a storage image can't be srgb), the bits of the format of the window where it can be, which go to it by copies; another
// one goes by blits
VkFormat format{VK_FORMAT_UNDEFINED};
bool blit{false};
std::shared_ptr<image> backbuffer;
std::shared_ptr<image> hudless;
std::shared_ptr<image> depth;
std::shared_ptr<image> motion;
std::array<std::shared_ptr<image>, 3> outputs;
// the format of the window can't take the frames (said in the log once)
VkFormat unusable{VK_FORMAT_UNDEFINED};
};
// the ring of a frame some data of the draws goes through, the descriptor of which reads a window of it: the window starts again
// further on when it's full, and the pass set is bound again with the new offset
struct window_ring
@@ -382,6 +404,8 @@ struct scene_state
bool cluster_heatmap_tried{false};
// the targets of the viewports, [0] the main window
std::vector<viewport_targets> targets;
// the frame generation of dlss for the main window
generation_targets generation;
// 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};
@@ -471,6 +495,14 @@ struct vulkan14_renderer::context
// dlss of the main viewport (gfx.antialiasing dlss), with the bias of the mipmaps of the textures of the scene it wants
vk14::dlss dlss;
float lod_bias{0.f};
// reflex (gfx.reflex, VK_NV_low_latency2): the timeline the sleep of the driver signals, its last value
VkSemaphore reflex{VK_NULL_HANDLE};
std::uint64_t reflexvalue{0};
// the presents of the main window with the frames generated by dlss (the render thread): when the last frame was handed over,
// the time between two (a moving average) which the frames of one are spread over, how long the last one took to be submitted
std::chrono::steady_clock::time_point present_last{};
double present_interval{0.0}; // seconds, 0: not known yet
double submit_time{0.0}; // seconds
// the textures of the files; made after the objects above and gone before them
std::unique_ptr<texture_bank> textures;
// [0]: the main window, then the windows of the extra viewports
@@ -503,6 +535,10 @@ struct vulkan14_renderer::context
std::vector<VkSemaphoreSubmitInfo> signals;
// the windows presented once the frame is submitted (the render thread)
std::vector<vk14::swapchain *> windows;
// the id of the frame for its present and for the markers of reflex
std::uint64_t present_id{0};
// when the main thread handed it over to the render thread
std::chrono::steady_clock::time_point handed{};
};
// the render thread and the job it's given
std::thread render_thread;
@@ -511,6 +547,7 @@ struct vulkan14_renderer::context
std::condition_variable render_idle;
render_job render_pending;
bool render_queued{false}; // render_pending holds a job not done yet
bool render_submitted{false}; // its frame is submitted, its windows may still be presented
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
@@ -527,8 +564,12 @@ struct vulkan14_renderer::context
// 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 part of it before the presents: its command buffers recorded and submitted
bool submit(render_job &Job, char const *&Failure);
// the windows of the frame submitted last presented, the frames generated for the main window before it (spread over the time
// of a frame when there's the render thread to wait); Id: the id of the present of the main window (0: none); false: the device or
// a surface is lost
bool present(std::vector<vk14::swapchain *> const &Windows, std::uint64_t Id);
// 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
@@ -542,6 +583,9 @@ struct vulkan14_renderer::context
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();
// waits until the render thread submitted the frame given to it (its presents may go on): the frames in flight and the streams
// are the main thread's again, the queue and the swapchains aren't until drain()
void wait_submitted();
// 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