LETS OFFER THIS SACRIFICE TO LORD SMOLIO THE SMOLIARD

This commit is contained in:
CamilleLaVey
2026-08-13 00:36:33 -04:00
parent a18d2b5c05
commit 42c5a12577
7 changed files with 124 additions and 36 deletions
@@ -20,6 +20,7 @@ namespace {
constexpr f32 LSFG_FLOW_SCALE = 1.0f;
constexpr size_t COLOR_CHANNELS = 4;
constexpr u64 LSFG_REQUIRED_FRAMES = 2;
bool IsBlueFirst(VkFormat format) {
return format == VK_FORMAT_B8G8R8A8_UNORM || format == VK_FORMAT_B8G8R8A8_SRGB;
@@ -90,41 +91,31 @@ void WriteColorPpm(const std::filesystem::path& path, VkExtent2D extent,
WritePortablePixmap(path, "P6", extent, rgb);
}
void CopyPresentedFrame(vk::CommandBuffer cmdbuf, VkImage source, LsfgImage& destination,
VkExtent2D extent) {
const auto make_barrier = [](VkImage image, VkAccessFlags src_access, VkAccessFlags dst_access,
VkImageLayout old_layout, VkImageLayout new_layout) {
return VkImageMemoryBarrier{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = src_access,
.dstAccessMask = dst_access,
.oldLayout = old_layout,
.newLayout = new_layout,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = image,
.subresourceRange{
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
},
};
VkImageMemoryBarrier MakeTransitionBarrier(VkImage image, VkAccessFlags src_access,
VkAccessFlags dst_access, VkImageLayout old_layout,
VkImageLayout new_layout) {
return VkImageMemoryBarrier{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = src_access,
.dstAccessMask = dst_access,
.oldLayout = old_layout,
.newLayout = new_layout,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = image,
.subresourceRange{
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
},
};
}
const std::array before{
make_barrier(source, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL),
make_barrier(destination.Handle(), VK_ACCESS_SHADER_READ_BIT, VK_ACCESS_TRANSFER_WRITE_BIT,
destination.Layout(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL),
};
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, {}, {}, before);
const VkImageCopy region{
VkImageCopy MakeCopyRegion(VkExtent2D extent) {
return VkImageCopy{
.srcSubresource{
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.mipLevel = 0,
@@ -141,8 +132,24 @@ void CopyPresentedFrame(vk::CommandBuffer cmdbuf, VkImage source, LsfgImage& des
.dstOffset = {},
.extent = {.width = extent.width, .height = extent.height, .depth = 1},
};
}
void CopyPresentedFrame(vk::CommandBuffer cmdbuf, VkImage source, LsfgImage& destination,
VkExtent2D extent) {
const auto make_barrier = MakeTransitionBarrier;
const std::array before{
make_barrier(source, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL),
make_barrier(destination.Handle(), VK_ACCESS_SHADER_READ_BIT, VK_ACCESS_TRANSFER_WRITE_BIT,
destination.Layout(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL),
};
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, {}, {}, before);
cmdbuf.CopyImage(source, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, destination.Handle(),
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, region);
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, MakeCopyRegion(extent));
const std::array after{
make_barrier(source, VK_ACCESS_TRANSFER_READ_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
@@ -201,6 +208,50 @@ void FrameGen::Process(const Device& device, Frame* frame, VkFormat format) {
}
}
bool FrameGen::HasGeneratedFrame() const {
return chain.has_value() && frame_count >= LSFG_REQUIRED_FRAMES &&
Settings::values.frame_gen.GetValue();
}
void FrameGen::CopyToFrame(Frame* destination) {
scheduler.RequestOutsideRenderPassOperationContext();
scheduler.Record([this, target = *destination->image](vk::CommandBuffer cmdbuf) {
LsfgImage& source = chain->Output();
const VkExtent2D extent = source.Extent();
const std::array before{
MakeTransitionBarrier(source.Handle(), VK_ACCESS_SHADER_WRITE_BIT,
VK_ACCESS_TRANSFER_READ_BIT, source.Layout(),
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL),
MakeTransitionBarrier(target, 0, VK_ACCESS_TRANSFER_WRITE_BIT,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL),
};
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, {}, {}, before);
cmdbuf.CopyImage(source.Handle(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, target,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, MakeCopyRegion(extent));
const std::array after{
MakeTransitionBarrier(source.Handle(), VK_ACCESS_TRANSFER_READ_BIT,
VK_ACCESS_SHADER_WRITE_BIT,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_IMAGE_LAYOUT_GENERAL),
MakeTransitionBarrier(target, VK_ACCESS_TRANSFER_WRITE_BIT,
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_IMAGE_LAYOUT_GENERAL),
};
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
0, {}, {}, after);
source.SetLayout(VK_IMAGE_LAYOUT_GENERAL);
});
}
void FrameGen::Rebuild(const Device& device, VkExtent2D extent, VkFormat format) {
scheduler.Finish();
chain.reset();
@@ -23,6 +23,10 @@ public:
void Process(const Device& device, Frame* frame, VkFormat format);
[[nodiscard]] bool HasGeneratedFrame() const;
void CopyToFrame(Frame* destination);
private:
void Rebuild(const Device& device, VkExtent2D extent, VkFormat format);
void DumpDebugImages(u64 count);
@@ -195,6 +195,14 @@ void RendererVulkan::Composite(std::span<const Tegra::FramebufferConfig> framebu
frame_gen.Process(device, frame, swapchain.GetImageFormat());
if (frame_gen.HasGeneratedFrame() && present_manager.CanQueueExtraFrame()) {
Frame* generated = present_manager.GetRenderFrame();
blit_swapchain.PrepareFrame(device, generated, render_window.GetFramebufferLayout());
frame_gen.CopyToFrame(generated);
scheduler.Flush(*generated->render_ready);
present_manager.Present(generated);
}
scheduler.Flush(*frame->render_ready);
present_manager.Present(frame);
@@ -85,6 +85,17 @@ void BlitScreen::SetWindowAdaptPass(const Device& device) {
}
}
void BlitScreen::PrepareFrame(const Device& device, Frame* frame,
const Layout::FramebufferLayout& layout) {
if (!window_adapt || (frame->width == layout.width && frame->height == layout.height)) {
return;
}
WaitIdle(device);
present_manager.RecreateFrame(frame, layout.width, layout.height, swapchain_view_format,
window_adapt->GetRenderPass());
}
void BlitScreen::DrawToFrame(const Device& device, RasterizerVulkan& rasterizer, Frame* frame,
std::span<const Tegra::FramebufferConfig> framebuffers,
const Layout::FramebufferLayout& layout,
@@ -60,6 +60,8 @@ public:
const Layout::FramebufferLayout& layout, size_t current_swapchain_image_count,
VkFormat current_swapchain_view_format);
void PrepareFrame(const Device& device, Frame* frame, const Layout::FramebufferLayout& layout);
[[nodiscard]] vk::Framebuffer CreateFramebuffer(const Device& device, const Layout::FramebufferLayout& layout,
VkImageView image_view,
VkFormat current_view_format);
@@ -179,6 +179,15 @@ void PresentManager::Present(Frame* frame) {
}
}
bool PresentManager::CanQueueExtraFrame() {
if (!use_present_thread) {
return false;
}
std::scoped_lock lock{queue_mutex, free_mutex};
return present_queue.empty() && !free_queue.empty();
}
void PresentManager::RecreateFrame(Frame* frame, u32 width, u32 height, VkFormat image_view_format,
VkRenderPass rd) {
auto& dld = device.GetLogical();
@@ -202,8 +211,8 @@ void PresentManager::RecreateFrame(Frame* frame, u32 width, u32 height, VkFormat
.arrayLayers = 1,
.samples = VK_SAMPLE_COUNT_1_BIT,
.tiling = VK_IMAGE_TILING_OPTIMAL,
.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
VK_IMAGE_USAGE_SAMPLED_BIT,
.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr,
@@ -60,6 +60,9 @@ public:
/// Waits for the present thread to finish presenting all queued frames.
void WaitPresent();
/// Whether an additional frame can be queued without stalling the render thread
bool CanQueueExtraFrame();
private:
void PresentThread(std::stop_token token);