mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-29 15:07:29 +01:00
Add DLSS Frame Generation (gfx.framegeneration x2/x3/x4) and Reflex (gfx.reflex) to the Vulkan renderer
This commit is contained in:
@@ -529,16 +529,28 @@ bool vulkan14_renderer::Render()
|
||||
|
||||
Timer::subsystem.gfx_total.start();
|
||||
|
||||
// the render thread is done with the frame before: the queue, the swapchains and the frames are the main thread's again
|
||||
if (auto const *failure{ctx.drain()})
|
||||
// the render thread is done with the frame before: the queue, the swapchains and the frames are the main thread's again. with
|
||||
// the frame generation it may still be presenting it, the queue and the swapchains are waited for before the windows are acquired
|
||||
auto const latepresent{m_generated > 0};
|
||||
if (latepresent)
|
||||
{
|
||||
ctx.wait_submitted();
|
||||
}
|
||||
else if (auto const *failure{ctx.drain()})
|
||||
{
|
||||
report_device_lost(failure);
|
||||
return false;
|
||||
}
|
||||
// what the replay left to dlss; failed: off from now on, the scene of the main window stretched to it without anti-aliasing
|
||||
// reflex: the simulation of the frame is over, the frame is made
|
||||
if (false == ctx.windows.empty())
|
||||
{
|
||||
ctx.windows.front()->latency_marker(ctx.framecount + 1, VK_LATENCY_MARKER_SIMULATION_END_NV);
|
||||
}
|
||||
// what the replay left to dlss; failed: off from now on, the scene of the main window stretched to it without anti-aliasing (the
|
||||
// frame generation alone: the frames it was to make are the frame drawn, then it's off)
|
||||
if (auto const error{ctx.dlss.sync()}; false == error.empty())
|
||||
{
|
||||
vk14::log_error(error + "; dlss is off, the scene is stretched to the window without anti-aliasing");
|
||||
vk14::log_error(error + (ctx.dlss.failed() ? "; dlss is off, the scene is stretched to the window without anti-aliasing" : "; the frame generation is off"));
|
||||
}
|
||||
|
||||
// the gpu has to be done with the frame which used the slot before
|
||||
@@ -618,26 +630,46 @@ bool vulkan14_renderer::Render()
|
||||
}
|
||||
}
|
||||
|
||||
ctx.acquired.clear();
|
||||
for (auto &window : ctx.windows)
|
||||
{
|
||||
switch (window->acquire(slot))
|
||||
// the frame generation of dlss: the images of the main window for the frames it makes, where the scene is drawn with dlss. the
|
||||
// frames it can make are known once the windows are acquired; till then the frame is made for all of them
|
||||
auto const generating{(m_generated > 0) && simulation::is_ready && (false == Global.gfx_skiprendering) && dlss_active() && (false == ctx.dlss.generation_failed()) && (false == m_viewports.empty()) &&
|
||||
(m_viewports.front().window == 0) && (m_viewports.front().output_width > 0) && (ctx.scene.generation.unusable == VK_FORMAT_UNDEFINED)};
|
||||
m_generatedframe = (generating ? std::min(m_generated, ctx.windows.front()->generated_room()) : 0);
|
||||
m_generationinputs = false;
|
||||
auto const acquire_windows = [&]() {
|
||||
ctx.acquired.clear();
|
||||
for (auto &window : ctx.windows)
|
||||
{
|
||||
case vk14::swapchain::acquire_result::ready:
|
||||
ctx.acquired.push_back(window.get());
|
||||
break;
|
||||
case vk14::swapchain::acquire_result::skipped:
|
||||
break;
|
||||
default:
|
||||
if (window != ctx.windows.front())
|
||||
switch (window->acquire(slot, ((window == ctx.windows.front()) && generating) ? m_generated : 0))
|
||||
{
|
||||
// a window of an extra viewport which can't be shown doesn't stop the others
|
||||
case vk14::swapchain::acquire_result::ready:
|
||||
ctx.acquired.push_back(window.get());
|
||||
break;
|
||||
case vk14::swapchain::acquire_result::skipped:
|
||||
break;
|
||||
default:
|
||||
if (window != ctx.windows.front())
|
||||
{
|
||||
// a window of an extra viewport which can't be shown doesn't stop the others
|
||||
break;
|
||||
}
|
||||
ctx.acquired.clear();
|
||||
report_device_lost("acquiring an image");
|
||||
return false;
|
||||
}
|
||||
ctx.acquired.clear();
|
||||
report_device_lost("acquiring an image");
|
||||
return false;
|
||||
}
|
||||
m_generatedframe = 0;
|
||||
if (generating && (false == ctx.acquired.empty()) && (ctx.acquired.front() == ctx.windows.front().get()) && (ctx.windows.front()->generated_count() > 0) && prepare_generation(0))
|
||||
{
|
||||
m_generatedframe = ctx.windows.front()->generated_count();
|
||||
}
|
||||
return true;
|
||||
};
|
||||
// with the frame generation the render thread may still be presenting the frame before, spaced over the time of a frame: the
|
||||
// windows are acquired once the scene is recorded, after it's done
|
||||
if ((false == latepresent) && (false == acquire_windows()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
frame.number = ctx.framecount;
|
||||
@@ -792,6 +824,19 @@ bool vulkan14_renderer::Render()
|
||||
Application.render_ui();
|
||||
Timer::subsystem.gfx_gui.stop();
|
||||
|
||||
if (latepresent)
|
||||
{
|
||||
if (auto const *failure{ctx.drain()})
|
||||
{
|
||||
report_device_lost(failure);
|
||||
return false;
|
||||
}
|
||||
if (false == acquire_windows())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// the windows: the image of their viewport, the user interface over the main one
|
||||
bool uidrawn{false};
|
||||
for (auto *window : ctx.acquired)
|
||||
@@ -806,6 +851,13 @@ bool vulkan14_renderer::Render()
|
||||
}
|
||||
}
|
||||
auto const ismain{window == ctx.windows.front().get()};
|
||||
if (ismain && (window->generated_count() > 0) && (viewport < m_viewports.size()))
|
||||
{
|
||||
// with the frames generated by dlss (or the frame drawn again in their images, where they can't be made)
|
||||
render_generation(viewport);
|
||||
uidrawn = true;
|
||||
continue;
|
||||
}
|
||||
ctx.passes.begin_pass(ismain ? "ui" : "other viewports", {window->use(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, colour_stage, colour_access)});
|
||||
VkClearValue clear{};
|
||||
clear.color = {{0.f, 0.f, 0.f, 1.f}};
|
||||
@@ -892,7 +944,16 @@ bool vulkan14_renderer::Render()
|
||||
signal.semaphore = window->present_semaphore();
|
||||
signal.stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT;
|
||||
job.signals.push_back(signal);
|
||||
// the images of the frames generated, shown before it
|
||||
for (std::uint32_t i = 0; i < window->generated_count(); ++i)
|
||||
{
|
||||
wait.semaphore = window->generated_acquire_semaphore(slot, i);
|
||||
job.waits.push_back(wait);
|
||||
signal.semaphore = window->generated_present_semaphore(i);
|
||||
job.signals.push_back(signal);
|
||||
}
|
||||
}
|
||||
job.present_id = ctx.framecount + 1;
|
||||
VkSemaphoreSubmitInfo timelinesignal{};
|
||||
timelinesignal.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO;
|
||||
timelinesignal.semaphore = ctx.timeline;
|
||||
@@ -1319,6 +1380,10 @@ void vulkan14_renderer::render_viewport(std::size_t const Index)
|
||||
m_cabfuture = glm::mat4{1.f};
|
||||
if (taa)
|
||||
{
|
||||
// the frame generation takes the camera without the offset of the frame
|
||||
m_generationcamera.projection = m_renderpass.pass_camera.projection();
|
||||
m_generationcamera.view = glm::mat3{glm::dmat3{m_renderpass.pass_camera.modelview()}};
|
||||
m_generationcamera.position = glm::vec3{m_renderpass.pass_camera.position()};
|
||||
m_taa.set_phases(dlss ? m_context->dlss.jitter_phases() : 8);
|
||||
auto const *cab{((false == FreeFlyModeFlag) && Global.render_cab && (simulation::Train != nullptr)) ? simulation::Train->Dynamic() : nullptr};
|
||||
m_renderpass.pass_camera.projection() = m_taa.begin_frame(
|
||||
@@ -3086,6 +3151,311 @@ bool vulkan14_renderer::dlss_active() const
|
||||
return (m_dlssrender.x > 0) && Global.gfx_dlss() && m_context && m_context->dlss.available() && (false == m_context->dlss.failed());
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// the unorm format with the bits of a format of a window (a storage image can't be srgb)
|
||||
VkFormat unorm_format(VkFormat const Format)
|
||||
{
|
||||
switch (Format)
|
||||
{
|
||||
case VK_FORMAT_B8G8R8A8_SRGB:
|
||||
return VK_FORMAT_B8G8R8A8_UNORM;
|
||||
case VK_FORMAT_R8G8B8A8_SRGB:
|
||||
return VK_FORMAT_R8G8B8A8_UNORM;
|
||||
case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
|
||||
return VK_FORMAT_A8B8G8R8_UNORM_PACK32;
|
||||
default:
|
||||
return Format;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// the images of the frame generation for the size and the format of the main window; false: they can't be had
|
||||
bool vulkan14_renderer::prepare_generation(std::size_t const Index)
|
||||
{
|
||||
auto &ctx{*m_context};
|
||||
auto &generation{ctx.scene.generation};
|
||||
auto const &window{*ctx.windows[m_viewports[Index].window]};
|
||||
auto const extent{window.extent()};
|
||||
auto const windowformat{window.format()};
|
||||
if (generation.backbuffer && (generation.extent.width == extent.width) && (generation.extent.height == extent.height) && (generation.window_format == windowformat))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (generation.unusable == windowformat)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
auto const features = [&](VkFormat const Format) {
|
||||
VkFormatProperties properties{};
|
||||
vkGetPhysicalDeviceFormatProperties(ctx.device.physical(), Format, &properties);
|
||||
return properties.optimalTilingFeatures;
|
||||
};
|
||||
VkFormatFeatureFlags const needed{VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT | VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT};
|
||||
// the bits of the format of the window, copied to it; or else rgba, blitted to it
|
||||
auto format{unorm_format(windowformat)};
|
||||
auto blit{false};
|
||||
if ((features(format) & needed) != needed)
|
||||
{
|
||||
format = VK_FORMAT_R8G8B8A8_UNORM;
|
||||
blit = true;
|
||||
// a blit to an srgb window would encode the colour encoded already
|
||||
if (((features(format) & (needed | VK_FORMAT_FEATURE_BLIT_SRC_BIT)) != (needed | VK_FORMAT_FEATURE_BLIT_SRC_BIT)) || ((features(windowformat) & VK_FORMAT_FEATURE_BLIT_DST_BIT) == 0) || window.srgb())
|
||||
{
|
||||
generation.unusable = windowformat;
|
||||
vk14::log_info("gfx.framegeneration: the format " + std::to_string(windowformat) + " of the main window can't be given the frames, they aren't generated");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
vk14::generation_targets fresh;
|
||||
fresh.extent = extent;
|
||||
fresh.window_format = windowformat;
|
||||
fresh.format = format;
|
||||
fresh.blit = blit;
|
||||
auto make = [&](std::shared_ptr<vk14::image> &Image, VkImageUsageFlags const Usage, char const *Name) {
|
||||
vk14::image_desc desc;
|
||||
desc.format = format;
|
||||
desc.extent = {extent.width, extent.height, 1};
|
||||
desc.usage = Usage | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
||||
Image = std::make_shared<vk14::image>();
|
||||
if (false == Image->create(ctx.memory, desc, Name))
|
||||
{
|
||||
Image.reset();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
auto ok{make(fresh.backbuffer, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, "frame generation backbuffer") && make(fresh.hudless, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, "frame generation hudless")};
|
||||
for (std::uint32_t i = 0; ok && (i < m_generated); ++i)
|
||||
{
|
||||
ok = make(fresh.outputs[i], VK_IMAGE_USAGE_TRANSFER_DST_BIT, "frame generated");
|
||||
}
|
||||
// what was made for the window before goes once the frames which use it are done
|
||||
ctx.deletions.push(ctx.uploads.current_value(), [old = std::move(generation)]() {});
|
||||
if (false == ok)
|
||||
{
|
||||
generation = vk14::generation_targets{};
|
||||
generation.unusable = windowformat;
|
||||
vk14::log_error("gfx.framegeneration: the images for the window of " + std::to_string(extent.width) + "x" + std::to_string(extent.height) + " can't be made, the frames aren't generated");
|
||||
return false;
|
||||
}
|
||||
generation = std::move(fresh);
|
||||
return true;
|
||||
}
|
||||
|
||||
// the depth and the velocities of the main view turned the way up of the window, for the frame generation (after dlss, which made
|
||||
// the velocities of the sky)
|
||||
void vulkan14_renderer::flip_generation_inputs(std::size_t const Index)
|
||||
{
|
||||
auto &ctx{*m_context};
|
||||
auto &generation{ctx.scene.generation};
|
||||
auto &targets{ctx.scene.targets[Index]};
|
||||
if ((false == static_cast<bool>(targets.dlss_motion)) || (false == static_cast<bool>(targets.depth)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
auto const render{targets.extent};
|
||||
if ((false == static_cast<bool>(generation.depth)) || (generation.render.width != render.width) || (generation.render.height != render.height))
|
||||
{
|
||||
auto make = [&](std::shared_ptr<vk14::image> &Image, VkFormat const Format, char const *Name) {
|
||||
vk14::image_desc desc;
|
||||
desc.format = Format;
|
||||
desc.extent = {render.width, render.height, 1};
|
||||
desc.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT;
|
||||
Image = std::make_shared<vk14::image>();
|
||||
if (false == Image->create(ctx.memory, desc, Name))
|
||||
{
|
||||
Image.reset();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
ctx.deletions.push(ctx.uploads.current_value(), [depth = std::move(generation.depth), motion = std::move(generation.motion)]() {});
|
||||
generation.depth.reset();
|
||||
generation.motion.reset();
|
||||
generation.render = {0, 0};
|
||||
if ((false == make(generation.depth, VK_FORMAT_R32_SFLOAT, "frame generation depth")) || (false == make(generation.motion, VK_FORMAT_R16G16_SFLOAT, "frame generation velocity")))
|
||||
{
|
||||
generation.depth.reset();
|
||||
generation.motion.reset();
|
||||
return;
|
||||
}
|
||||
generation.render = render;
|
||||
}
|
||||
post_pass("postfx_fg_flip.frag", *generation.depth, {targets.depth.get()}, vk14::draw_constants{}, "frame generation inputs");
|
||||
post_pass("postfx_fg_flip.frag", *generation.motion, {targets.dlss_motion.get()}, vk14::draw_constants{});
|
||||
m_generationinputs = true;
|
||||
}
|
||||
|
||||
// the main window with the frames generated by dlss: the frame without the user interface and with it, the frames generated from it
|
||||
// and the last one, all of them copied to the images of the window acquired for them. without what the frame generation needs (its
|
||||
// images, the inputs of the frame) every image of the window gets the frame drawn
|
||||
void vulkan14_renderer::render_generation(std::size_t const Index)
|
||||
{
|
||||
auto &ctx{*m_context};
|
||||
auto &scene{ctx.scene};
|
||||
auto &generation{scene.generation};
|
||||
auto &window{*ctx.windows[m_viewports[Index].window]};
|
||||
auto const count{std::min<std::uint32_t>(window.generated_count(), m_generated)};
|
||||
auto const extent{window.extent()};
|
||||
auto const drawn{(Index < scene.targets.size()) && scene.targets[Index].output};
|
||||
VkClearValue clear{};
|
||||
clear.color = {{0.f, 0.f, 0.f, 1.f}};
|
||||
auto const ready{drawn && m_generationinputs && generation.backbuffer && generation.depth && (generation.extent.width == extent.width) && (generation.extent.height == extent.height)};
|
||||
if (false == ready)
|
||||
{
|
||||
for (std::uint32_t i = 0; i <= window.generated_count(); ++i)
|
||||
{
|
||||
auto const last{i == window.generated_count()};
|
||||
ctx.passes.begin_pass(last ? "ui" : "frame generation: the frame again",
|
||||
{last ? window.use(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, colour_stage, colour_access) : window.generated_use(i, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, colour_stage, colour_access)});
|
||||
auto attachment{attachment_info(last ? window.view() : window.generated_view(i), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true, clear)};
|
||||
VkRenderingInfo rendering{};
|
||||
rendering.sType = VK_STRUCTURE_TYPE_RENDERING_INFO;
|
||||
rendering.renderArea = {{0, 0}, extent};
|
||||
rendering.layerCount = 1;
|
||||
rendering.colorAttachmentCount = 1;
|
||||
rendering.pColorAttachments = &attachment;
|
||||
ctx.commands->begin_rendering(&rendering);
|
||||
if (drawn)
|
||||
{
|
||||
present_viewport(Index);
|
||||
}
|
||||
// the user interface in each of them (kept for the next one but the last)
|
||||
ctx.imgui.record(ctx.commands, extent, window.format(), window.srgb(), false == last);
|
||||
ctx.commands->end_rendering();
|
||||
ctx.passes.end_pass();
|
||||
}
|
||||
std::vector<vk14::image_use> presents{window.use(VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_PIPELINE_STAGE_2_NONE, VK_ACCESS_2_NONE)};
|
||||
for (std::uint32_t i = 0; i < window.generated_count(); ++i)
|
||||
{
|
||||
presents.push_back(window.generated_use(i, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_PIPELINE_STAGE_2_NONE, VK_ACCESS_2_NONE));
|
||||
}
|
||||
vk14::barriers(ctx.commands, presents);
|
||||
return;
|
||||
}
|
||||
|
||||
// the frame without the user interface, and with it
|
||||
auto drawto = [&](vk14::image &Target, bool const Ui, char const *Pass) {
|
||||
ctx.passes.begin_pass(Pass, {vk14::use_of(Target, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, colour_stage, colour_access)});
|
||||
auto attachment{attachment_info(Target.view(), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true, clear)};
|
||||
VkRenderingInfo rendering{};
|
||||
rendering.sType = VK_STRUCTURE_TYPE_RENDERING_INFO;
|
||||
rendering.renderArea = {{0, 0}, extent};
|
||||
rendering.layerCount = 1;
|
||||
rendering.colorAttachmentCount = 1;
|
||||
rendering.pColorAttachments = &attachment;
|
||||
ctx.commands->begin_rendering(&rendering);
|
||||
present_viewport(Index, &Target);
|
||||
if (Ui)
|
||||
{
|
||||
ctx.imgui.record(ctx.commands, extent, Target.desc().format, false);
|
||||
}
|
||||
ctx.commands->end_rendering();
|
||||
ctx.passes.end_pass();
|
||||
};
|
||||
drawto(*generation.hudless, false, "frame generation hudless");
|
||||
drawto(*generation.backbuffer, true, "ui");
|
||||
|
||||
// the frames between the last one and this one, by the passes of the library, whichever stages they are
|
||||
auto const stage{VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT};
|
||||
auto const read{VK_ACCESS_2_SHADER_READ_BIT | VK_ACCESS_2_TRANSFER_READ_BIT};
|
||||
std::vector<vk14::image_use> uses{vk14::use_of(*generation.backbuffer, VK_IMAGE_LAYOUT_GENERAL, stage, read), vk14::use_of(*generation.hudless, VK_IMAGE_LAYOUT_GENERAL, stage, read),
|
||||
vk14::use_of(*generation.depth, VK_IMAGE_LAYOUT_GENERAL, stage, read), vk14::use_of(*generation.motion, VK_IMAGE_LAYOUT_GENERAL, stage, read)};
|
||||
vk14::dlss::generation_inputs inputs;
|
||||
inputs.backbuffer = generation.backbuffer.get();
|
||||
inputs.hudless = generation.hudless.get();
|
||||
inputs.depth = generation.depth.get();
|
||||
inputs.motion = generation.motion.get();
|
||||
for (std::uint32_t i = 0; i < count; ++i)
|
||||
{
|
||||
uses.push_back(vk14::use_of(*generation.outputs[i], VK_IMAGE_LAYOUT_GENERAL, stage, read | VK_ACCESS_2_SHADER_WRITE_BIT | VK_ACCESS_2_TRANSFER_READ_BIT | VK_ACCESS_2_TRANSFER_WRITE_BIT));
|
||||
inputs.outputs.push_back(generation.outputs[i].get());
|
||||
}
|
||||
ctx.passes.begin_pass("frame generation", uses);
|
||||
auto const &camera{m_generationcamera};
|
||||
inputs.view_to_clip = camera.projection;
|
||||
inputs.clip_to_previous_clip = m_taa.reprojection_without_offset();
|
||||
inputs.position = camera.position;
|
||||
// the axes of the view in the world: the rows of the rotation of the world to the view (the view looks along its -z)
|
||||
inputs.right = glm::vec3{camera.view[0][0], camera.view[1][0], camera.view[2][0]};
|
||||
inputs.up = glm::vec3{camera.view[0][1], camera.view[1][1], camera.view[2][1]};
|
||||
inputs.forward = -glm::vec3{camera.view[0][2], camera.view[1][2], camera.view[2][2]};
|
||||
inputs.znear = m_colorpass.znear;
|
||||
inputs.zfar = m_colorpass.zfar;
|
||||
auto const yscale{camera.projection[1][1]};
|
||||
inputs.fov = (yscale > 0.f ? 2.f * std::atan(1.f / yscale) : glm::radians(45.f));
|
||||
inputs.aspect = ((camera.projection[0][0] > 0.f) ? yscale / camera.projection[0][0] : 1.f);
|
||||
inputs.jitter = m_taa.jitter();
|
||||
// its history is of no use after a frame without it (minimized, not drawn, without the images)
|
||||
inputs.reset = (false == m_taa.history_valid()) || (m_generationframe + 1 != ctx.framecount);
|
||||
m_generationframe = ctx.framecount;
|
||||
ctx.dlss.generate(*ctx.commands, inputs, ctx.deletions, ctx.uploads.current_value());
|
||||
ctx.passes.end_pass();
|
||||
|
||||
// the frames to the images of the window: the ones generated first, in the order they are shown, then the one drawn
|
||||
auto const transfer{VK_PIPELINE_STAGE_2_ALL_TRANSFER_BIT};
|
||||
std::vector<vk14::image_use> copies{vk14::use_of(*generation.backbuffer, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, transfer, VK_ACCESS_2_TRANSFER_READ_BIT),
|
||||
window.use(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, transfer, VK_ACCESS_2_TRANSFER_WRITE_BIT)};
|
||||
for (std::uint32_t i = 0; i < window.generated_count(); ++i)
|
||||
{
|
||||
auto &source{*generation.outputs[std::min(i, count - 1)]};
|
||||
copies.push_back(vk14::use_of(source, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, transfer, VK_ACCESS_2_TRANSFER_READ_BIT));
|
||||
copies.push_back(window.generated_use(i, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, transfer, VK_ACCESS_2_TRANSFER_WRITE_BIT));
|
||||
}
|
||||
ctx.passes.begin_pass("frame generation to the window", copies);
|
||||
auto const send = [&](vk14::image &Source, VkImage const Destination) {
|
||||
if (generation.blit)
|
||||
{
|
||||
VkImageBlit2 region{};
|
||||
region.sType = VK_STRUCTURE_TYPE_IMAGE_BLIT_2;
|
||||
region.srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
|
||||
region.dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
|
||||
region.srcOffsets[1] = {static_cast<std::int32_t>(extent.width), static_cast<std::int32_t>(extent.height), 1};
|
||||
region.dstOffsets[1] = region.srcOffsets[1];
|
||||
VkBlitImageInfo2 blit{};
|
||||
blit.sType = VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2;
|
||||
blit.srcImage = Source.handle();
|
||||
blit.srcImageLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||
blit.dstImage = Destination;
|
||||
blit.dstImageLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
blit.regionCount = 1;
|
||||
blit.pRegions = ®ion;
|
||||
blit.filter = VK_FILTER_NEAREST;
|
||||
ctx.commands->blit_image2(&blit);
|
||||
return;
|
||||
}
|
||||
VkImageCopy2 region{};
|
||||
region.sType = VK_STRUCTURE_TYPE_IMAGE_COPY_2;
|
||||
region.srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
|
||||
region.dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
|
||||
region.extent = {extent.width, extent.height, 1};
|
||||
VkCopyImageInfo2 copy{};
|
||||
copy.sType = VK_STRUCTURE_TYPE_COPY_IMAGE_INFO_2;
|
||||
copy.srcImage = Source.handle();
|
||||
copy.srcImageLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||
copy.dstImage = Destination;
|
||||
copy.dstImageLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
copy.regionCount = 1;
|
||||
copy.pRegions = ®ion;
|
||||
ctx.commands->copy_image2(©);
|
||||
};
|
||||
for (std::uint32_t i = 0; i < window.generated_count(); ++i)
|
||||
{
|
||||
send(*generation.outputs[std::min(i, count - 1)], window.generated_image(i));
|
||||
}
|
||||
send(*generation.backbuffer, window.image());
|
||||
ctx.passes.end_pass();
|
||||
std::vector<vk14::image_use> presents{window.use(VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_PIPELINE_STAGE_2_NONE, VK_ACCESS_2_NONE)};
|
||||
for (std::uint32_t i = 0; i < window.generated_count(); ++i)
|
||||
{
|
||||
presents.push_back(window.generated_use(i, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_PIPELINE_STAGE_2_NONE, VK_ACCESS_2_NONE));
|
||||
}
|
||||
vk14::barriers(ctx.commands, presents);
|
||||
}
|
||||
|
||||
// the post-processing of a viewport: from the colour of the scene to its output, which the window shows (the part of
|
||||
// opengl46_renderer::Render_pass() after the colour pass)
|
||||
void vulkan14_renderer::render_post(std::size_t const Index, bool const Motionblur)
|
||||
@@ -3109,6 +3479,10 @@ void vulkan14_renderer::render_post(std::size_t const Index, bool const Motionbl
|
||||
{
|
||||
render_dlss(Index);
|
||||
hdr = targets.dlss_output.get();
|
||||
if ((m_generatedframe > 0) && m_viewports[Index].main)
|
||||
{
|
||||
flip_generation_inputs(Index);
|
||||
}
|
||||
}
|
||||
// the temporal anti-aliasing: the scene blended into its history (the motion blur takes the result)
|
||||
if (m_motionhistory && targets.taa && targets.taa_history[0] && targets.taa_history[1] && targets.motion_image)
|
||||
@@ -3135,6 +3509,12 @@ void vulkan14_renderer::render_post(std::size_t const Index, bool const Motionbl
|
||||
{
|
||||
vk14::draw_constants constants;
|
||||
constants.data[0].x = m_framerate / (1.0 / Global.gfx_postfx_motionblur_shutter);
|
||||
// with the frames generated by dlss each frame drawn is shown for a part of its time: the blur as much shorter (the guide of
|
||||
// the frame generation)
|
||||
if (m_generationinputs && m_viewports[Index].main)
|
||||
{
|
||||
constants.data[0].x /= static_cast<float>(1 + m_generatedframe);
|
||||
}
|
||||
post_pass("postfx_motionblur.frag", *targets.blurred, {hdr, targets.motion_image.get(), targets.depth.get()}, constants, "resolve, ambient occlusion, motion blur");
|
||||
hdr = targets.blurred.get();
|
||||
}
|
||||
@@ -3172,21 +3552,25 @@ void vulkan14_renderer::render_post(std::size_t const Index, bool const Motionbl
|
||||
vk14::barriers(commands, {vk14::use_of(*targets.output, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT, sampled_access)});
|
||||
}
|
||||
|
||||
// the output of a viewport drawn to its window turned upside down (decision K8), inside the rendering of the window
|
||||
void vulkan14_renderer::present_viewport(std::size_t const Index)
|
||||
// the output of a viewport drawn to its window turned upside down (decision K8), inside the rendering of the window; or to Target,
|
||||
// an image of the size of the window in the place of it (the frame generation, unorm)
|
||||
void vulkan14_renderer::present_viewport(std::size_t const Index, vk14::image const *Target)
|
||||
{
|
||||
auto &ctx{*m_context};
|
||||
auto &scene{ctx.scene};
|
||||
auto &targets{scene.targets[Index]};
|
||||
auto const &window{*ctx.windows[m_viewports[Index].window]};
|
||||
auto const commands{ctx.commands};
|
||||
auto const format{Target != nullptr ? Target->desc().format : window.format()};
|
||||
auto const srgb{Target != nullptr ? false : window.srgb()};
|
||||
VkExtent2D const extent{Target != nullptr ? VkExtent2D{Target->desc().extent.width, Target->desc().extent.height} : window.extent()};
|
||||
// the output encoded already goes as it is; an srgb output to a window which isn't (no srgb format of the surface) is encoded
|
||||
auto const pipeline{post_pipeline("present.frag", static_cast<int>(window.format()), (targets.srgb && (false == window.srgb())) ? 1 : 0)};
|
||||
auto const pipeline{post_pipeline("present.frag", static_cast<int>(format), (targets.srgb && (false == srgb)) ? 1 : 0)};
|
||||
if (pipeline == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
vk14::set_draw_state(commands, window.extent());
|
||||
vk14::set_draw_state(commands, extent);
|
||||
commands->bind_pipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, reinterpret_cast<VkPipeline>(pipeline));
|
||||
commands->set_primitive_topology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP);
|
||||
std::array<vk14::descriptor, vk14::bindings::POST_TEXTURES + 1> descriptors;
|
||||
|
||||
Reference in New Issue
Block a user