mirror of
https://git.citron-emu.org/citron/emulator
synced 2025-12-22 20:03:42 +00:00
Merge branch 'remove-frame-generation-wip' into 'master'
feat: remove frame generation options from all platforms See merge request citron/rewrite!49
This commit is contained in:
@@ -29,8 +29,6 @@ enum class IntSetting(override val key: String) : AbstractIntSetting {
|
|||||||
VERTICAL_ALIGNMENT("vertical_alignment"),
|
VERTICAL_ALIGNMENT("vertical_alignment"),
|
||||||
FSR_SHARPENING_SLIDER("fsr_sharpening_slider"),
|
FSR_SHARPENING_SLIDER("fsr_sharpening_slider"),
|
||||||
FSR2_QUALITY_MODE("fsr2_quality_mode"),
|
FSR2_QUALITY_MODE("fsr2_quality_mode"),
|
||||||
FRAME_GENERATION("frame_generation"),
|
|
||||||
FRAME_GENERATION_MODE("frame_generation_mode"),
|
|
||||||
FRAME_SKIPPING("frame_skipping"),
|
FRAME_SKIPPING("frame_skipping"),
|
||||||
FRAME_SKIPPING_MODE("frame_skipping_mode"),
|
FRAME_SKIPPING_MODE("frame_skipping_mode"),
|
||||||
|
|
||||||
|
|||||||
@@ -443,24 +443,7 @@ abstract class SettingsItem(
|
|||||||
valuesId = R.array.vramUsageModeValues
|
valuesId = R.array.vramUsageModeValues
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
put(
|
|
||||||
SingleChoiceSetting(
|
|
||||||
IntSetting.FRAME_GENERATION,
|
|
||||||
titleId = R.string.frame_generation,
|
|
||||||
descriptionId = R.string.frame_generation_description,
|
|
||||||
choicesId = R.array.frameGenerationNames,
|
|
||||||
valuesId = R.array.frameGenerationValues
|
|
||||||
)
|
|
||||||
)
|
|
||||||
put(
|
|
||||||
SingleChoiceSetting(
|
|
||||||
IntSetting.FRAME_GENERATION_MODE,
|
|
||||||
titleId = R.string.frame_generation_mode,
|
|
||||||
descriptionId = R.string.frame_generation_mode_description,
|
|
||||||
choicesId = R.array.frameGenerationModeNames,
|
|
||||||
valuesId = R.array.frameGenerationModeValues
|
|
||||||
)
|
|
||||||
)
|
|
||||||
put(
|
put(
|
||||||
SingleChoiceSetting(
|
SingleChoiceSetting(
|
||||||
IntSetting.FRAME_SKIPPING,
|
IntSetting.FRAME_SKIPPING,
|
||||||
|
|||||||
@@ -997,10 +997,6 @@ class SettingsFragmentPresenter(
|
|||||||
add(IntSetting.SHADER_BACKEND.key)
|
add(IntSetting.SHADER_BACKEND.key)
|
||||||
add(IntSetting.VRAM_USAGE_MODE.key)
|
add(IntSetting.VRAM_USAGE_MODE.key)
|
||||||
|
|
||||||
add(HeaderSetting(R.string.frame_generation_header))
|
|
||||||
add(IntSetting.FRAME_GENERATION.key)
|
|
||||||
add(IntSetting.FRAME_GENERATION_MODE.key)
|
|
||||||
|
|
||||||
add(HeaderSetting(R.string.frame_skipping_header))
|
add(HeaderSetting(R.string.frame_skipping_header))
|
||||||
add(IntSetting.FRAME_SKIPPING.key)
|
add(IntSetting.FRAME_SKIPPING.key)
|
||||||
add(IntSetting.FRAME_SKIPPING_MODE.key)
|
add(IntSetting.FRAME_SKIPPING_MODE.key)
|
||||||
|
|||||||
@@ -187,25 +187,7 @@
|
|||||||
<item>3</item>
|
<item>3</item>
|
||||||
</integer-array>
|
</integer-array>
|
||||||
|
|
||||||
<string-array name="frameGenerationNames">
|
|
||||||
<item>@string/frame_generation_disabled</item>
|
|
||||||
<item>@string/frame_generation_enabled</item>
|
|
||||||
</string-array>
|
|
||||||
|
|
||||||
<integer-array name="frameGenerationValues">
|
|
||||||
<item>0</item>
|
|
||||||
<item>1</item>
|
|
||||||
</integer-array>
|
|
||||||
|
|
||||||
<string-array name="frameGenerationModeNames">
|
|
||||||
<item>@string/frame_generation_mode_interpolation</item>
|
|
||||||
<item>@string/frame_generation_mode_extrapolation</item>
|
|
||||||
</string-array>
|
|
||||||
|
|
||||||
<integer-array name="frameGenerationModeValues">
|
|
||||||
<item>0</item>
|
|
||||||
<item>1</item>
|
|
||||||
</integer-array>
|
|
||||||
|
|
||||||
<string-array name="frameSkippingNames">
|
<string-array name="frameSkippingNames">
|
||||||
<item>@string/frame_skipping_disabled</item>
|
<item>@string/frame_skipping_disabled</item>
|
||||||
|
|||||||
@@ -424,7 +424,6 @@
|
|||||||
<string name="astc_settings_header">ASTC Settings</string>
|
<string name="astc_settings_header">ASTC Settings</string>
|
||||||
<string name="advanced_graphics_header">Advanced Graphics</string>
|
<string name="advanced_graphics_header">Advanced Graphics</string>
|
||||||
<string name="applet_settings_header">Applet Settings</string>
|
<string name="applet_settings_header">Applet Settings</string>
|
||||||
<string name="frame_generation_header">Frame Generation</string>
|
|
||||||
|
|
||||||
<!-- Applet Mode Settings -->
|
<!-- Applet Mode Settings -->
|
||||||
<string name="cabinet_applet_mode">Cabinet Applet Mode</string>
|
<string name="cabinet_applet_mode">Cabinet Applet Mode</string>
|
||||||
@@ -1229,14 +1228,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
<string name="shader_backend_description">Controls which shader backend to use for rendering.</string>
|
<string name="shader_backend_description">Controls which shader backend to use for rendering.</string>
|
||||||
<string name="vram_usage_mode">VRAM Usage Mode</string>
|
<string name="vram_usage_mode">VRAM Usage Mode</string>
|
||||||
<string name="vram_usage_mode_description">Controls how aggressively VRAM is used. Conservative mode limits VRAM usage for better stability.</string>
|
<string name="vram_usage_mode_description">Controls how aggressively VRAM is used. Conservative mode limits VRAM usage for better stability.</string>
|
||||||
<string name="frame_generation">Frame Generation</string>
|
|
||||||
<string name="frame_generation_description">Enables frame generation to create intermediate frames, potentially doubling the perceived frame rate.</string>
|
|
||||||
<string name="frame_generation_mode">Frame Generation Mode</string>
|
|
||||||
<string name="frame_generation_mode_description">Interpolation creates frames between existing ones, while Extrapolation predicts future frames.</string>
|
|
||||||
<string name="frame_generation_disabled">Disabled</string>
|
|
||||||
<string name="frame_generation_enabled">Enabled</string>
|
|
||||||
<string name="frame_generation_mode_interpolation">Interpolation</string>
|
|
||||||
<string name="frame_generation_mode_extrapolation">Extrapolation</string>
|
|
||||||
<string name="frame_skipping">Frame Skipping</string>
|
<string name="frame_skipping">Frame Skipping</string>
|
||||||
<string name="frame_skipping_description">Skips frames to maintain performance when the system cannot keep up with the target frame rate.</string>
|
<string name="frame_skipping_description">Skips frames to maintain performance when the system cannot keep up with the target frame rate.</string>
|
||||||
<string name="frame_skipping_mode">Frame Skipping Mode</string>
|
<string name="frame_skipping_mode">Frame Skipping Mode</string>
|
||||||
|
|||||||
@@ -129,10 +129,7 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent) {
|
|||||||
tr("Determines how sharpened the image will look while using FSR's dynamic contrast."));
|
tr("Determines how sharpened the image will look while using FSR's dynamic contrast."));
|
||||||
INSERT(Settings, fsr2_quality_mode, tr("FSR 2.0 Quality Mode:"),
|
INSERT(Settings, fsr2_quality_mode, tr("FSR 2.0 Quality Mode:"),
|
||||||
tr("Selects the quality mode for FSR 2.0 upscaling. Quality provides better image quality, Performance provides better performance."));
|
tr("Selects the quality mode for FSR 2.0 upscaling. Quality provides better image quality, Performance provides better performance."));
|
||||||
INSERT(Settings, frame_generation, tr("Frame Generation:"),
|
|
||||||
tr("Enables frame generation to create intermediate frames, potentially doubling the perceived frame rate."));
|
|
||||||
INSERT(Settings, frame_generation_mode, tr("Frame Generation Mode:"),
|
|
||||||
tr("Interpolation creates frames between existing ones, while Extrapolation predicts future frames."));
|
|
||||||
INSERT(Settings, frame_skipping, tr("Frame Skipping:"),
|
INSERT(Settings, frame_skipping, tr("Frame Skipping:"),
|
||||||
tr("Skips frames to maintain performance when the system cannot keep up with the target frame rate."));
|
tr("Skips frames to maintain performance when the system cannot keep up with the target frame rate."));
|
||||||
INSERT(Settings, frame_skipping_mode, tr("Frame Skipping Mode:"),
|
INSERT(Settings, frame_skipping_mode, tr("Frame Skipping Mode:"),
|
||||||
@@ -419,16 +416,7 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent) {
|
|||||||
PAIR(FSR2QualityMode, Performance, tr("Performance")),
|
PAIR(FSR2QualityMode, Performance, tr("Performance")),
|
||||||
PAIR(FSR2QualityMode, UltraPerformance, tr("Ultra Performance")),
|
PAIR(FSR2QualityMode, UltraPerformance, tr("Ultra Performance")),
|
||||||
}});
|
}});
|
||||||
translations->insert({Settings::EnumMetadata<Settings::FrameGeneration>::Index(),
|
|
||||||
{
|
|
||||||
PAIR(FrameGeneration, Disabled, tr("Disabled")),
|
|
||||||
PAIR(FrameGeneration, Enabled, tr("Enabled")),
|
|
||||||
}});
|
|
||||||
translations->insert({Settings::EnumMetadata<Settings::FrameGenerationMode>::Index(),
|
|
||||||
{
|
|
||||||
PAIR(FrameGenerationMode, Interpolation, tr("Interpolation")),
|
|
||||||
PAIR(FrameGenerationMode, Extrapolation, tr("Extrapolation")),
|
|
||||||
}});
|
|
||||||
translations->insert({Settings::EnumMetadata<Settings::FrameSkipping>::Index(),
|
translations->insert({Settings::EnumMetadata<Settings::FrameSkipping>::Index(),
|
||||||
{
|
{
|
||||||
PAIR(FrameSkipping, Disabled, tr("Disabled")),
|
PAIR(FrameSkipping, Disabled, tr("Disabled")),
|
||||||
|
|||||||
@@ -358,25 +358,7 @@ struct Values {
|
|||||||
true,
|
true,
|
||||||
true};
|
true};
|
||||||
|
|
||||||
SwitchableSetting<FrameGeneration, true> frame_generation{linkage,
|
|
||||||
FrameGeneration::Disabled, // Disabled by default
|
|
||||||
FrameGeneration::Disabled,
|
|
||||||
FrameGeneration::Enabled,
|
|
||||||
"frame_generation",
|
|
||||||
Category::Renderer,
|
|
||||||
Specialization::Default,
|
|
||||||
true,
|
|
||||||
true};
|
|
||||||
|
|
||||||
SwitchableSetting<FrameGenerationMode, true> frame_generation_mode{linkage,
|
|
||||||
FrameGenerationMode::Interpolation, // Interpolation by default
|
|
||||||
FrameGenerationMode::Interpolation,
|
|
||||||
FrameGenerationMode::Extrapolation,
|
|
||||||
"frame_generation_mode",
|
|
||||||
Category::Renderer,
|
|
||||||
Specialization::Default,
|
|
||||||
true,
|
|
||||||
true};
|
|
||||||
|
|
||||||
SwitchableSetting<FrameSkipping, true> frame_skipping{linkage,
|
SwitchableSetting<FrameSkipping, true> frame_skipping{linkage,
|
||||||
FrameSkipping::Disabled, // Disabled by default
|
FrameSkipping::Disabled, // Disabled by default
|
||||||
|
|||||||
@@ -153,10 +153,6 @@ ENUM(AntiAliasing, None, Fxaa, Smaa, MaxEnum);
|
|||||||
|
|
||||||
ENUM(FSR2QualityMode, Quality, Balanced, Performance, UltraPerformance);
|
ENUM(FSR2QualityMode, Quality, Balanced, Performance, UltraPerformance);
|
||||||
|
|
||||||
ENUM(FrameGeneration, Disabled, Enabled, MaxEnum);
|
|
||||||
|
|
||||||
ENUM(FrameGenerationMode, Interpolation, Extrapolation, MaxEnum);
|
|
||||||
|
|
||||||
ENUM(FrameSkipping, Disabled, Enabled, MaxEnum);
|
ENUM(FrameSkipping, Disabled, Enabled, MaxEnum);
|
||||||
|
|
||||||
ENUM(FrameSkippingMode, Adaptive, Fixed, MaxEnum);
|
ENUM(FrameSkippingMode, Adaptive, Fixed, MaxEnum);
|
||||||
|
|||||||
@@ -182,8 +182,6 @@ add_library(video_core STATIC
|
|||||||
renderer_vulkan/present/fsr.h
|
renderer_vulkan/present/fsr.h
|
||||||
renderer_vulkan/present/fsr2.cpp
|
renderer_vulkan/present/fsr2.cpp
|
||||||
renderer_vulkan/present/fsr2.h
|
renderer_vulkan/present/fsr2.h
|
||||||
renderer_vulkan/present/frame_generation.cpp
|
|
||||||
renderer_vulkan/present/frame_generation.h
|
|
||||||
frame_skipping.cpp
|
frame_skipping.cpp
|
||||||
frame_skipping.h
|
frame_skipping.h
|
||||||
renderer_vulkan/present/fxaa.cpp
|
renderer_vulkan/present/fxaa.cpp
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
namespace Vulkan {
|
|
||||||
namespace FrameGenShaders {
|
|
||||||
|
|
||||||
// Minimal fragment shader for frame generation
|
|
||||||
constexpr std::array<std::uint32_t, 4> FRAG_SPV = {{
|
|
||||||
0x07230203, 0x00010000, 0x0008000A, 0x00000004
|
|
||||||
}};
|
|
||||||
|
|
||||||
} // namespace FrameGenShaders
|
|
||||||
} // namespace Vulkan
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
namespace Vulkan {
|
|
||||||
namespace FrameGenShaders {
|
|
||||||
|
|
||||||
// Minimal vertex shader for frame generation
|
|
||||||
constexpr std::array<std::uint32_t, 4> VERT_SPV = {{
|
|
||||||
0x07230203, 0x00010000, 0x0008000A, 0x00000004
|
|
||||||
}};
|
|
||||||
|
|
||||||
} // namespace FrameGenShaders
|
|
||||||
} // namespace Vulkan
|
|
||||||
@@ -1,163 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#include <bit>
|
|
||||||
#include "common/common_types.h"
|
|
||||||
#include "common/div_ceil.h"
|
|
||||||
#include "common/settings.h"
|
|
||||||
|
|
||||||
#include "video_core/host_shaders/vulkan_frame_generation_vert_spv.h"
|
|
||||||
#include "video_core/host_shaders/vulkan_frame_generation_frag_spv.h"
|
|
||||||
#include "video_core/host_shaders/vulkan_motion_estimation_frag_spv.h"
|
|
||||||
#include "video_core/host_shaders/vulkan_frame_interpolation_frag_spv.h"
|
|
||||||
#include "video_core/renderer_vulkan/present/frame_generation.h"
|
|
||||||
#include "video_core/renderer_vulkan/present/util.h"
|
|
||||||
#include "video_core/renderer_vulkan/vk_scheduler.h"
|
|
||||||
#include "video_core/renderer_vulkan/vk_shader_util.h"
|
|
||||||
#include "video_core/vulkan_common/vulkan_device.h"
|
|
||||||
|
|
||||||
namespace Vulkan {
|
|
||||||
|
|
||||||
using PushConstants = std::array<u32, 4 * 4>;
|
|
||||||
|
|
||||||
FrameGeneration::FrameGeneration(const Device& device, MemoryAllocator& memory_allocator, size_t image_count,
|
|
||||||
VkExtent2D extent)
|
|
||||||
: m_device{device}, m_memory_allocator{memory_allocator}, m_image_count{image_count}, m_extent{extent} {
|
|
||||||
// Simplified constructor - no complex initialization needed for safe pass-through implementation
|
|
||||||
}
|
|
||||||
|
|
||||||
void FrameGeneration::CreateImages() {
|
|
||||||
m_dynamic_images.resize(m_image_count);
|
|
||||||
for (auto& images : m_dynamic_images) {
|
|
||||||
for (size_t i = 0; i < MaxFrameGenStage; i++) {
|
|
||||||
images.images[i] = CreateWrappedImage(m_memory_allocator, m_extent, VK_FORMAT_R16G16B16A16_SFLOAT);
|
|
||||||
images.image_views[i] = CreateWrappedImageView(m_device, images.images[i], VK_FORMAT_R16G16B16A16_SFLOAT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create frame buffer for motion estimation
|
|
||||||
m_previous_frames.resize(m_image_count);
|
|
||||||
m_previous_frame_views.resize(m_image_count);
|
|
||||||
for (size_t i = 0; i < m_image_count; i++) {
|
|
||||||
m_previous_frames[i] = CreateWrappedImage(m_memory_allocator, m_extent, VK_FORMAT_R8G8B8A8_UNORM);
|
|
||||||
m_previous_frame_views[i] = CreateWrappedImageView(m_device, m_previous_frames[i], VK_FORMAT_R8G8B8A8_UNORM);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FrameGeneration::CreateRenderPasses() {
|
|
||||||
m_renderpass = CreateWrappedRenderPass(m_device, VK_FORMAT_R16G16B16A16_SFLOAT);
|
|
||||||
|
|
||||||
for (auto& images : m_dynamic_images) {
|
|
||||||
images.framebuffers[MotionEstimation] =
|
|
||||||
CreateWrappedFramebuffer(m_device, m_renderpass, images.image_views[MotionEstimation], m_extent);
|
|
||||||
images.framebuffers[FrameInterpolation] =
|
|
||||||
CreateWrappedFramebuffer(m_device, m_renderpass, images.image_views[FrameInterpolation], m_extent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FrameGeneration::CreateSampler() {
|
|
||||||
m_sampler = CreateBilinearSampler(m_device);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FrameGeneration::CreateShaders() {
|
|
||||||
m_vert_shader = BuildShader(m_device, Vulkan::FrameGenShaders::VERT_SPV);
|
|
||||||
m_motion_estimation_shader = BuildShader(m_device, Vulkan::FrameGenShaders::MOTION_ESTIMATION_FRAG_SPV);
|
|
||||||
m_frame_interpolation_shader = BuildShader(m_device, Vulkan::FrameGenShaders::FRAME_INTERPOLATION_FRAG_SPV);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FrameGeneration::CreateDescriptorPool() {
|
|
||||||
// MotionEstimation: 2 descriptors (current + previous frame)
|
|
||||||
// FrameInterpolation: 3 descriptors (current + previous + motion vectors)
|
|
||||||
// 5 descriptors, 2 descriptor sets per invocation
|
|
||||||
m_descriptor_pool = CreateWrappedDescriptorPool(m_device, 5 * m_image_count, 2 * m_image_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FrameGeneration::CreateDescriptorSetLayout() {
|
|
||||||
m_descriptor_set_layout =
|
|
||||||
CreateWrappedDescriptorSetLayout(m_device, {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER});
|
|
||||||
}
|
|
||||||
|
|
||||||
void FrameGeneration::CreateDescriptorSets() {
|
|
||||||
std::vector<VkDescriptorSetLayout> layouts(MaxFrameGenStage, *m_descriptor_set_layout);
|
|
||||||
|
|
||||||
for (auto& images : m_dynamic_images) {
|
|
||||||
images.descriptor_sets = CreateWrappedDescriptorSets(m_descriptor_pool, layouts);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FrameGeneration::CreatePipelineLayouts() {
|
|
||||||
const VkPushConstantRange range{
|
|
||||||
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
|
|
||||||
.offset = 0,
|
|
||||||
.size = sizeof(PushConstants),
|
|
||||||
};
|
|
||||||
VkPipelineLayoutCreateInfo ci{
|
|
||||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
|
||||||
.pNext = nullptr,
|
|
||||||
.flags = 0,
|
|
||||||
.setLayoutCount = 1,
|
|
||||||
.pSetLayouts = m_descriptor_set_layout.address(),
|
|
||||||
.pushConstantRangeCount = 1,
|
|
||||||
.pPushConstantRanges = &range,
|
|
||||||
};
|
|
||||||
|
|
||||||
m_pipeline_layout = m_device.GetLogical().CreatePipelineLayout(ci);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FrameGeneration::CreatePipelines() {
|
|
||||||
m_motion_estimation_pipeline = CreateWrappedPipeline(m_device, m_renderpass, m_pipeline_layout,
|
|
||||||
std::tie(m_vert_shader, m_motion_estimation_shader));
|
|
||||||
m_frame_interpolation_pipeline = CreateWrappedPipeline(m_device, m_renderpass, m_pipeline_layout,
|
|
||||||
std::tie(m_vert_shader, m_frame_interpolation_shader));
|
|
||||||
}
|
|
||||||
|
|
||||||
void FrameGeneration::UpdateDescriptorSets(VkImageView image_view, size_t image_index) {
|
|
||||||
Images& images = m_dynamic_images[image_index];
|
|
||||||
std::vector<VkDescriptorImageInfo> image_infos;
|
|
||||||
std::vector<VkWriteDescriptorSet> updates;
|
|
||||||
image_infos.reserve(5);
|
|
||||||
|
|
||||||
// Motion estimation: current frame + previous frame
|
|
||||||
updates.push_back(CreateWriteDescriptorSet(image_infos, *m_sampler, image_view,
|
|
||||||
images.descriptor_sets[MotionEstimation], 0));
|
|
||||||
updates.push_back(CreateWriteDescriptorSet(image_infos, *m_sampler, *m_previous_frame_views[image_index],
|
|
||||||
images.descriptor_sets[MotionEstimation], 1));
|
|
||||||
|
|
||||||
// Frame interpolation: current frame + previous frame + motion vectors
|
|
||||||
updates.push_back(CreateWriteDescriptorSet(image_infos, *m_sampler, image_view,
|
|
||||||
images.descriptor_sets[FrameInterpolation], 0));
|
|
||||||
updates.push_back(CreateWriteDescriptorSet(image_infos, *m_sampler, *m_previous_frame_views[image_index],
|
|
||||||
images.descriptor_sets[FrameInterpolation], 1));
|
|
||||||
updates.push_back(CreateWriteDescriptorSet(image_infos, *m_sampler, *images.image_views[MotionEstimation],
|
|
||||||
images.descriptor_sets[FrameInterpolation], 2));
|
|
||||||
|
|
||||||
m_device.GetLogical().UpdateDescriptorSets(updates, {});
|
|
||||||
}
|
|
||||||
|
|
||||||
void FrameGeneration::UploadImages(Scheduler& scheduler) {
|
|
||||||
if (m_images_ready) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
scheduler.Record([&](vk::CommandBuffer cmdbuf) {
|
|
||||||
for (auto& image : m_dynamic_images) {
|
|
||||||
ClearColorImage(cmdbuf, *image.images[MotionEstimation]);
|
|
||||||
ClearColorImage(cmdbuf, *image.images[FrameInterpolation]);
|
|
||||||
}
|
|
||||||
for (auto& frame : m_previous_frames) {
|
|
||||||
ClearColorImage(cmdbuf, *frame);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
scheduler.Finish();
|
|
||||||
|
|
||||||
m_images_ready = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkImageView FrameGeneration::Draw(Scheduler& scheduler, size_t image_index, VkImage source_image,
|
|
||||||
VkImageView source_image_view, VkExtent2D input_image_extent,
|
|
||||||
const Common::Rectangle<f32>& crop_rect) {
|
|
||||||
// TODO(zephyron): Implement a better frame generation method
|
|
||||||
return source_image_view;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Vulkan
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "common/math_util.h"
|
|
||||||
#include "video_core/vulkan_common/vulkan_memory_allocator.h"
|
|
||||||
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
|
||||||
|
|
||||||
namespace Vulkan {
|
|
||||||
|
|
||||||
class Device;
|
|
||||||
class Scheduler;
|
|
||||||
|
|
||||||
class FrameGeneration {
|
|
||||||
public:
|
|
||||||
explicit FrameGeneration(const Device& device, MemoryAllocator& memory_allocator, size_t image_count,
|
|
||||||
VkExtent2D extent);
|
|
||||||
VkImageView Draw(Scheduler& scheduler, size_t image_index, VkImage source_image,
|
|
||||||
VkImageView source_image_view, VkExtent2D input_image_extent,
|
|
||||||
const Common::Rectangle<f32>& crop_rect);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void CreateImages();
|
|
||||||
void CreateRenderPasses();
|
|
||||||
void CreateSampler();
|
|
||||||
void CreateShaders();
|
|
||||||
void CreateDescriptorPool();
|
|
||||||
void CreateDescriptorSetLayout();
|
|
||||||
void CreateDescriptorSets();
|
|
||||||
void CreatePipelineLayouts();
|
|
||||||
void CreatePipelines();
|
|
||||||
|
|
||||||
void UploadImages(Scheduler& scheduler);
|
|
||||||
void UpdateDescriptorSets(VkImageView image_view, size_t image_index);
|
|
||||||
|
|
||||||
const Device& m_device;
|
|
||||||
MemoryAllocator& m_memory_allocator;
|
|
||||||
const size_t m_image_count;
|
|
||||||
const VkExtent2D m_extent;
|
|
||||||
|
|
||||||
enum FrameGenStage {
|
|
||||||
MotionEstimation,
|
|
||||||
FrameInterpolation,
|
|
||||||
MaxFrameGenStage,
|
|
||||||
};
|
|
||||||
|
|
||||||
vk::DescriptorPool m_descriptor_pool;
|
|
||||||
vk::DescriptorSetLayout m_descriptor_set_layout;
|
|
||||||
vk::PipelineLayout m_pipeline_layout;
|
|
||||||
vk::ShaderModule m_vert_shader;
|
|
||||||
vk::ShaderModule m_motion_estimation_shader;
|
|
||||||
vk::ShaderModule m_frame_interpolation_shader;
|
|
||||||
vk::Pipeline m_motion_estimation_pipeline;
|
|
||||||
vk::Pipeline m_frame_interpolation_pipeline;
|
|
||||||
vk::RenderPass m_renderpass;
|
|
||||||
vk::Sampler m_sampler;
|
|
||||||
|
|
||||||
struct Images {
|
|
||||||
vk::DescriptorSets descriptor_sets;
|
|
||||||
std::array<vk::Image, MaxFrameGenStage> images;
|
|
||||||
std::array<vk::ImageView, MaxFrameGenStage> image_views;
|
|
||||||
std::array<vk::Framebuffer, MaxFrameGenStage> framebuffers;
|
|
||||||
};
|
|
||||||
std::vector<Images> m_dynamic_images;
|
|
||||||
bool m_images_ready{};
|
|
||||||
|
|
||||||
// Frame buffering for motion estimation
|
|
||||||
std::vector<vk::Image> m_previous_frames;
|
|
||||||
std::vector<vk::ImageView> m_previous_frame_views;
|
|
||||||
size_t m_current_frame_index{};
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Vulkan
|
|
||||||
@@ -9,7 +9,6 @@
|
|||||||
#include "video_core/framebuffer_config.h"
|
#include "video_core/framebuffer_config.h"
|
||||||
#include "video_core/renderer_vulkan/present/fsr.h"
|
#include "video_core/renderer_vulkan/present/fsr.h"
|
||||||
#include "video_core/renderer_vulkan/present/fsr2.h"
|
#include "video_core/renderer_vulkan/present/fsr2.h"
|
||||||
#include "video_core/renderer_vulkan/present/frame_generation.h"
|
|
||||||
#include "video_core/renderer_vulkan/present/fxaa.h"
|
#include "video_core/renderer_vulkan/present/fxaa.h"
|
||||||
#include "video_core/renderer_vulkan/present/layer.h"
|
#include "video_core/renderer_vulkan/present/layer.h"
|
||||||
#include "video_core/renderer_vulkan/present/present_push_constants.h"
|
#include "video_core/renderer_vulkan/present/present_push_constants.h"
|
||||||
@@ -63,10 +62,6 @@ Layer::Layer(const Device& device_, MemoryAllocator& memory_allocator_, Schedule
|
|||||||
if (filters.get_scaling_filter() == Settings::ScalingFilter::Fsr2) {
|
if (filters.get_scaling_filter() == Settings::ScalingFilter::Fsr2) {
|
||||||
CreateFSR2(output_size);
|
CreateFSR2(output_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Settings::values.frame_generation.GetValue() == Settings::FrameGeneration::Enabled) {
|
|
||||||
CreateFrameGeneration(output_size);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Layer::~Layer() {
|
Layer::~Layer() {
|
||||||
@@ -122,13 +117,6 @@ void Layer::ConfigureDraw(PresentPushConstants* out_push_constants,
|
|||||||
render_extent, crop_rect);
|
render_extent, crop_rect);
|
||||||
crop_rect = {0, 0, 1, 1};
|
crop_rect = {0, 0, 1, 1};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (frame_generation) {
|
|
||||||
source_image_view = frame_generation->Draw(scheduler, image_index, source_image, source_image_view,
|
|
||||||
render_extent, crop_rect);
|
|
||||||
crop_rect = {0, 0, 1, 1};
|
|
||||||
}
|
|
||||||
|
|
||||||
SetMatrixData(*out_push_constants, layout);
|
SetMatrixData(*out_push_constants, layout);
|
||||||
SetVertexData(*out_push_constants, layout, crop_rect);
|
SetVertexData(*out_push_constants, layout, crop_rect);
|
||||||
|
|
||||||
@@ -182,10 +170,6 @@ void Layer::CreateFSR2(VkExtent2D output_size) {
|
|||||||
fsr2 = std::make_unique<FSR2>(device, memory_allocator, image_count, output_size);
|
fsr2 = std::make_unique<FSR2>(device, memory_allocator, image_count, output_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Layer::CreateFrameGeneration(VkExtent2D output_size) {
|
|
||||||
frame_generation = std::make_unique<FrameGeneration>(device, memory_allocator, image_count, output_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Layer::RefreshResources(const Tegra::FramebufferConfig& framebuffer) {
|
void Layer::RefreshResources(const Tegra::FramebufferConfig& framebuffer) {
|
||||||
if (framebuffer.width == raw_width && framebuffer.height == raw_height &&
|
if (framebuffer.width == raw_width && framebuffer.height == raw_height &&
|
||||||
framebuffer.pixel_format == pixel_format && !raw_images.empty()) {
|
framebuffer.pixel_format == pixel_format && !raw_images.empty()) {
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ class AntiAliasPass;
|
|||||||
class Device;
|
class Device;
|
||||||
class FSR;
|
class FSR;
|
||||||
class FSR2;
|
class FSR2;
|
||||||
class FrameGeneration;
|
|
||||||
class MemoryAllocator;
|
class MemoryAllocator;
|
||||||
struct PresentPushConstants;
|
struct PresentPushConstants;
|
||||||
class RasterizerVulkan;
|
class RasterizerVulkan;
|
||||||
@@ -59,7 +58,6 @@ private:
|
|||||||
void CreateRawImages(const Tegra::FramebufferConfig& framebuffer);
|
void CreateRawImages(const Tegra::FramebufferConfig& framebuffer);
|
||||||
void CreateFSR(VkExtent2D output_size);
|
void CreateFSR(VkExtent2D output_size);
|
||||||
void CreateFSR2(VkExtent2D output_size);
|
void CreateFSR2(VkExtent2D output_size);
|
||||||
void CreateFrameGeneration(VkExtent2D output_size);
|
|
||||||
|
|
||||||
void RefreshResources(const Tegra::FramebufferConfig& framebuffer);
|
void RefreshResources(const Tegra::FramebufferConfig& framebuffer);
|
||||||
void SetAntiAliasPass();
|
void SetAntiAliasPass();
|
||||||
@@ -96,7 +94,6 @@ private:
|
|||||||
|
|
||||||
std::unique_ptr<FSR> fsr{};
|
std::unique_ptr<FSR> fsr{};
|
||||||
std::unique_ptr<FSR2> fsr2{};
|
std::unique_ptr<FSR2> fsr2{};
|
||||||
std::unique_ptr<FrameGeneration> frame_generation{};
|
|
||||||
std::vector<u64> resource_ticks{};
|
std::vector<u64> resource_ticks{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user