mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-10-07 06:18:23 +00:00
Gamma pass on lsfg
This commit is contained in:
@@ -133,6 +133,8 @@ add_library(video_core STATIC
|
|||||||
renderer_vulkan/present/lsfg_beta.h
|
renderer_vulkan/present/lsfg_beta.h
|
||||||
renderer_vulkan/present/lsfg_common.cpp
|
renderer_vulkan/present/lsfg_common.cpp
|
||||||
renderer_vulkan/present/lsfg_common.h
|
renderer_vulkan/present/lsfg_common.h
|
||||||
|
renderer_vulkan/present/lsfg_gamma.cpp
|
||||||
|
renderer_vulkan/present/lsfg_gamma.h
|
||||||
renderer_vulkan/present/lsfg_mipmaps.cpp
|
renderer_vulkan/present/lsfg_mipmaps.cpp
|
||||||
renderer_vulkan/present/lsfg_mipmaps.h
|
renderer_vulkan/present/lsfg_mipmaps.h
|
||||||
renderer_vulkan/present/lsfg_shaders.cpp
|
renderer_vulkan/present/lsfg_shaders.cpp
|
||||||
|
|||||||
@@ -0,0 +1,172 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "video_core/frame_gen/lossless_dll.h"
|
||||||
|
#include "video_core/renderer_vulkan/present/lsfg_gamma.h"
|
||||||
|
#include "video_core/renderer_vulkan/present/lsfg_shaders.h"
|
||||||
|
#include "video_core/renderer_vulkan/present/util.h"
|
||||||
|
#include "video_core/vulkan_common/vulkan_device.h"
|
||||||
|
|
||||||
|
namespace Vulkan {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr u32 DISPATCH_TILE_SHIFT = 3;
|
||||||
|
|
||||||
|
[[nodiscard]] u32 GroupCount(u32 size) {
|
||||||
|
return (size + (1u << DISPATCH_TILE_SHIFT) - 1) >> DISPATCH_TILE_SHIFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // Anonymous namespace
|
||||||
|
|
||||||
|
LsfgGamma::LsfgGamma(const Device& device, MemoryAllocator& memory_allocator,
|
||||||
|
const LsfgShaders& shaders, LsfgResources& resources,
|
||||||
|
vk::DescriptorPool& descriptor_pool, LsfgImageHistory& inputs_,
|
||||||
|
LsfgImage& flow_input_, LsfgImage* previous_)
|
||||||
|
: inputs{&inputs_}, flow_input{&flow_input_}, previous{previous_} {
|
||||||
|
using namespace VideoCore::FrameGen::PerformanceShader;
|
||||||
|
|
||||||
|
passes[0] = LsfgPass(device, shaders, GAMMA[0],
|
||||||
|
{{1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER},
|
||||||
|
{2, VK_DESCRIPTOR_TYPE_SAMPLER},
|
||||||
|
{5, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE},
|
||||||
|
{3, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE}});
|
||||||
|
passes[1] = LsfgPass(device, shaders, GAMMA[1],
|
||||||
|
{{1, VK_DESCRIPTOR_TYPE_SAMPLER},
|
||||||
|
{3, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE},
|
||||||
|
{2, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE}});
|
||||||
|
passes[2] = LsfgPass(device, shaders, GAMMA[2],
|
||||||
|
{{1, VK_DESCRIPTOR_TYPE_SAMPLER},
|
||||||
|
{2, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE},
|
||||||
|
{2, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE}});
|
||||||
|
passes[3] = LsfgPass(device, shaders, GAMMA[3],
|
||||||
|
{{1, VK_DESCRIPTOR_TYPE_SAMPLER},
|
||||||
|
{2, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE},
|
||||||
|
{2, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE}});
|
||||||
|
passes[4] = LsfgPass(device, shaders, GAMMA[4],
|
||||||
|
{{1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER},
|
||||||
|
{2, VK_DESCRIPTOR_TYPE_SAMPLER},
|
||||||
|
{4, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE},
|
||||||
|
{1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE}});
|
||||||
|
|
||||||
|
const VkExtent2D extent = (*inputs)[0][0].Extent();
|
||||||
|
for (auto& image : temp1) {
|
||||||
|
image = LsfgImage(device, memory_allocator, extent);
|
||||||
|
}
|
||||||
|
for (auto& image : temp2) {
|
||||||
|
image = LsfgImage(device, memory_allocator, extent);
|
||||||
|
}
|
||||||
|
out_image = LsfgImage(device, memory_allocator, extent, LSFG_MOTION_FORMAT);
|
||||||
|
|
||||||
|
std::vector<VkDescriptorSetLayout> layouts;
|
||||||
|
for (size_t i = 0; i < LSFG_HISTORY_SLOTS; ++i) {
|
||||||
|
layouts.push_back(passes[0].SetLayout());
|
||||||
|
}
|
||||||
|
for (size_t i = 1; i < LSFG_GAMMA_STAGES; ++i) {
|
||||||
|
layouts.push_back(passes[i].SetLayout());
|
||||||
|
}
|
||||||
|
owned_sets = CreateWrappedDescriptorSets(descriptor_pool, layouts);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < LSFG_HISTORY_SLOTS; ++i) {
|
||||||
|
first_descriptor_sets[i] = owned_sets[i];
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < LSFG_GAMMA_STAGES - 1; ++i) {
|
||||||
|
descriptor_sets[i] = owned_sets[LSFG_HISTORY_SLOTS + i];
|
||||||
|
}
|
||||||
|
|
||||||
|
const VkSampler sampler = resources.GetSampler();
|
||||||
|
const VkSampler border_sampler = resources.GetSampler(
|
||||||
|
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, VK_COMPARE_OP_NEVER, true);
|
||||||
|
const VkSampler edge_sampler =
|
||||||
|
resources.GetSampler(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_COMPARE_OP_ALWAYS, false);
|
||||||
|
const VkBuffer buffer = resources.GetBuffer(LSFG_TIMESTAMP, previous == nullptr);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < LSFG_HISTORY_SLOTS; ++i) {
|
||||||
|
LsfgDescriptorWriter(first_descriptor_sets[i])
|
||||||
|
.AddUniformBuffer(buffer, LsfgResources::BufferSize())
|
||||||
|
.AddSampler(border_sampler)
|
||||||
|
.AddSampler(edge_sampler)
|
||||||
|
.AddSampledImages((*inputs)[(i + 2) % LSFG_HISTORY_SLOTS])
|
||||||
|
.AddSampledImages((*inputs)[i % LSFG_HISTORY_SLOTS])
|
||||||
|
.AddSampledImage(previous)
|
||||||
|
.AddStorageImages(temp1)
|
||||||
|
.Build(device);
|
||||||
|
}
|
||||||
|
LsfgDescriptorWriter(descriptor_sets[0])
|
||||||
|
.AddSampler(sampler)
|
||||||
|
.AddSampledImages(temp1)
|
||||||
|
.AddStorageImages(temp2)
|
||||||
|
.Build(device);
|
||||||
|
LsfgDescriptorWriter(descriptor_sets[1])
|
||||||
|
.AddSampler(sampler)
|
||||||
|
.AddSampledImages(temp2)
|
||||||
|
.AddStorageImage(temp1[0])
|
||||||
|
.AddStorageImage(temp1[1])
|
||||||
|
.Build(device);
|
||||||
|
LsfgDescriptorWriter(descriptor_sets[2])
|
||||||
|
.AddSampler(sampler)
|
||||||
|
.AddSampledImage(temp1[0])
|
||||||
|
.AddSampledImage(temp1[1])
|
||||||
|
.AddStorageImages(temp2)
|
||||||
|
.Build(device);
|
||||||
|
LsfgDescriptorWriter(descriptor_sets[3])
|
||||||
|
.AddUniformBuffer(buffer, LsfgResources::BufferSize())
|
||||||
|
.AddSampler(sampler)
|
||||||
|
.AddSampler(edge_sampler)
|
||||||
|
.AddSampledImages(temp2)
|
||||||
|
.AddSampledImage(previous)
|
||||||
|
.AddSampledImage(*flow_input)
|
||||||
|
.AddStorageImage(out_image)
|
||||||
|
.Build(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LsfgGamma::Dispatch(vk::CommandBuffer cmdbuf, u64 frame_count) {
|
||||||
|
const VkExtent2D extent = temp1[0].Extent();
|
||||||
|
const u32 groups_x = GroupCount(extent.width);
|
||||||
|
const u32 groups_y = GroupCount(extent.height);
|
||||||
|
|
||||||
|
const size_t slot = frame_count % LSFG_HISTORY_SLOTS;
|
||||||
|
const size_t previous_slot = (frame_count + 2) % LSFG_HISTORY_SLOTS;
|
||||||
|
|
||||||
|
LsfgBarriers(cmdbuf)
|
||||||
|
.WriteToReadAll((*inputs)[previous_slot])
|
||||||
|
.WriteToReadAll((*inputs)[slot])
|
||||||
|
.WriteToRead(previous)
|
||||||
|
.ReadToWriteAll(temp1)
|
||||||
|
.Build();
|
||||||
|
passes[0].Bind(cmdbuf, first_descriptor_sets[slot]);
|
||||||
|
cmdbuf.Dispatch(groups_x, groups_y, 1);
|
||||||
|
|
||||||
|
LsfgBarriers(cmdbuf).WriteToReadAll(temp1).ReadToWriteAll(temp2).Build();
|
||||||
|
passes[1].Bind(cmdbuf, descriptor_sets[0]);
|
||||||
|
cmdbuf.Dispatch(groups_x, groups_y, 1);
|
||||||
|
|
||||||
|
LsfgBarriers(cmdbuf)
|
||||||
|
.WriteToReadAll(temp2)
|
||||||
|
.ReadToWrite(temp1[0])
|
||||||
|
.ReadToWrite(temp1[1])
|
||||||
|
.Build();
|
||||||
|
passes[2].Bind(cmdbuf, descriptor_sets[1]);
|
||||||
|
cmdbuf.Dispatch(groups_x, groups_y, 1);
|
||||||
|
|
||||||
|
LsfgBarriers(cmdbuf)
|
||||||
|
.WriteToRead(temp1[0])
|
||||||
|
.WriteToRead(temp1[1])
|
||||||
|
.ReadToWriteAll(temp2)
|
||||||
|
.Build();
|
||||||
|
passes[3].Bind(cmdbuf, descriptor_sets[2]);
|
||||||
|
cmdbuf.Dispatch(groups_x, groups_y, 1);
|
||||||
|
|
||||||
|
LsfgBarriers(cmdbuf)
|
||||||
|
.WriteToReadAll(temp2)
|
||||||
|
.WriteToRead(previous)
|
||||||
|
.WriteToRead(*flow_input)
|
||||||
|
.ReadToWrite(out_image)
|
||||||
|
.Build();
|
||||||
|
passes[4].Bind(cmdbuf, descriptor_sets[3]);
|
||||||
|
cmdbuf.Dispatch(groups_x, groups_y, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Vulkan
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
#include "common/common_types.h"
|
||||||
|
#include "video_core/renderer_vulkan/present/lsfg_common.h"
|
||||||
|
|
||||||
|
namespace Vulkan {
|
||||||
|
|
||||||
|
class Device;
|
||||||
|
class LsfgShaders;
|
||||||
|
|
||||||
|
constexpr size_t LSFG_GAMMA_STAGES = 5;
|
||||||
|
constexpr size_t LSFG_GAMMA_TEMPS = 3;
|
||||||
|
|
||||||
|
class LsfgGamma {
|
||||||
|
public:
|
||||||
|
LsfgGamma() = default;
|
||||||
|
LsfgGamma(const Device& device, MemoryAllocator& memory_allocator, const LsfgShaders& shaders,
|
||||||
|
LsfgResources& resources, vk::DescriptorPool& descriptor_pool,
|
||||||
|
LsfgImageHistory& inputs, LsfgImage& flow_input, LsfgImage* previous);
|
||||||
|
|
||||||
|
void Dispatch(vk::CommandBuffer cmdbuf, u64 frame_count);
|
||||||
|
|
||||||
|
[[nodiscard]] LsfgImage& Output() {
|
||||||
|
return out_image;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
LsfgImageHistory* inputs{};
|
||||||
|
LsfgImage* flow_input{};
|
||||||
|
LsfgImage* previous{};
|
||||||
|
|
||||||
|
std::array<LsfgPass, LSFG_GAMMA_STAGES> passes;
|
||||||
|
std::array<VkDescriptorSet, LSFG_HISTORY_SLOTS> first_descriptor_sets{};
|
||||||
|
std::array<VkDescriptorSet, LSFG_GAMMA_STAGES - 1> descriptor_sets{};
|
||||||
|
vk::DescriptorSets owned_sets;
|
||||||
|
|
||||||
|
std::array<LsfgImage, LSFG_GAMMA_TEMPS> temp1;
|
||||||
|
LsfgImagePair temp2;
|
||||||
|
LsfgImage out_image;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Vulkan
|
||||||
Reference in New Issue
Block a user