Compare commits

..

32 Commits

Author SHA1 Message Date
CamilleLaVey 5a72b9d622 More UI adjustments 2026-08-14 18:31:53 -04:00
CamilleLaVey 1112f12af7 Some changes to UI 2026-08-14 18:00:49 -04:00
CamilleLaVey ed7c256728 Another take 2026-08-14 03:53:59 -04:00
CamilleLaVey bc96de8eb6 Revert "A quick experiment on frame rate target" 2026-08-14 02:30:55 -04:00
CamilleLaVey 417d80fc42 A quick experiment on frame rate target 2026-08-14 02:09:45 -04:00
CamilleLaVey 0ea9b231da Increase and adjust descriptor slots 2026-08-14 00:58:52 -04:00
CamilleLaVey bdcdb14fce Quick fix 2026-08-14 00:38:17 -04:00
CamilleLaVey 9a8a30ba43 First intent on motion resolution flow auto 2026-08-13 21:17:09 -04:00
CamilleLaVey 59384de777 Revert the Auto policy 2026-08-13 20:42:49 -04:00
CamilleLaVey 9b20c6c609 Queues and refresh rate adjustments 2026-08-13 17:26:52 -04:00
CamilleLaVey 1428abe1d1 Ducky DUUUUUUUUUUUUUUCKS 2026-08-13 16:50:32 -04:00
CamilleLaVey f069ff50a6 Settings refinement 2026-08-13 15:52:37 -04:00
CamilleLaVey ae395352a7 Adjustments to the frames multiplier 2026-08-13 14:30:03 -04:00
CamilleLaVey 4ed084153f Licenses added 2026-08-13 12:47:05 -04:00
CamilleLaVey 81f396e70b Just an small experiment 2026-08-13 04:19:22 -04:00
CamilleLaVey 3725b4d46d Some sanitize changes on latency 2026-08-13 04:05:25 -04:00
CamilleLaVey 42b8ca5f9d Remove LSFG HDR + other optimizations on extra frame 2026-08-13 03:48:54 -04:00
CamilleLaVey 52ffc8a7ce Let's try FP16 2026-08-13 03:16:13 -04:00
CamilleLaVey e26bf22d36 Expose new settings 2026-08-13 01:41:35 -04:00
CamilleLaVey 42c5a12577 LETS OFFER THIS SACRIFICE TO LORD SMOLIO THE SMOLIARD 2026-08-13 00:36:33 -04:00
CamilleLaVey a18d2b5c05 Dump every lsfg stage and require null descriptors 2026-08-13 00:24:18 -04:00
CamilleLaVey 30be8a5e18 Correct the frame generation setting description 2026-08-12 23:57:36 -04:00
CamilleLaVey 44e3211d1c Wire the full lsfg chain into the present path 2026-08-12 23:56:52 -04:00
CamilleLaVey 52e0b2a005 Generate pass on lsfg 2026-08-12 23:43:34 -04:00
CamilleLaVey 9a1258c59d Delta pass on lsfg 2026-08-12 23:42:30 -04:00
CamilleLaVey 232656df4e Gamma pass on lsfg 2026-08-12 23:40:40 -04:00
CamilleLaVey 367e5084da Beta pass on lsfg 2026-08-12 23:38:38 -04:00
CamilleLaVey 7467506cfa Shared sampler and constant buffer pools on lsfg 2026-08-12 23:37:21 -04:00
CamilleLaVey 61f3a1d135 Alphas on lsfg 2026-08-12 23:24:57 -04:00
CamilleLaVey 4f4f4a3586 Add lsfg-vk to Initial setup 2026-08-12 22:50:21 -04:00
CamilleLaVey 8470ad4b2a Just a quick fix 2026-08-12 22:28:50 -04:00
CamilleLaVey 4b33a2746c First try lsfg-vk to Eden 2026-08-12 22:22:11 -04:00
18 changed files with 147 additions and 124 deletions
-3
View File
@@ -81,9 +81,6 @@ cmake_dependent_option(YUZU_USE_BUNDLED_QT "Download bundled Qt binaries" "${MSV
option(ENABLE_DEBUG_TOOLS "Enable debugging tools (maxwell disassembler, SPIRV translator, etc)" OFF)
option(ENABLE_WERROR "Enable -Werror diagnostics" ON)
# Lossless Scaling frame generation. Only Android.
cmake_dependent_option(ENABLE_LSFG "Enable Lossless Scaling frame generation" ON "ANDROID" OFF)
# non-linux bundled qt are static
if (YUZU_USE_BUNDLED_QT AND (APPLE OR NOT UNIX))
set(YUZU_STATIC_BUILD ON)
+6
View File
@@ -65,6 +65,12 @@
"repo": "eden-emulator/discord-rpc",
"version": "0d8b2d6a37"
},
"dxbc": {
"bundled": true,
"hash": "196d26c07747d7aa2ced6fb1a5ae6f665e9b917de223a540038690b037c70a1eeca51c21d42aa5bec9fff7df0a6656a75ee8b4e2cb4008469f18a6812280f831",
"repo": "PancakeTAS/dxbc",
"version": "78ab59a8aaeb43cd1b0a5e91ba86722433a10b78"
},
"enet": {
"find_args": "MODULE",
"hash": "a0d2fa8c957704dd49e00a726284ac5ca034b50b00d2b20a94fa1bbfbb80841467834bfdc84aa0ed0d6aab894608fd6c86c3b94eee46343f0e6d9c22e391dbf9",
+4
View File
@@ -92,6 +92,10 @@ AddDependentPackages(vulkan-headers vulkan-utility-libraries)
# frozen
AddJsonPackage(frozen)
# DXVK's DXBC compiler, used to translate the frame generation shaders
# out of a user-supplied Lossless.dll into SPIR-V
AddJsonPackage(dxbc)
# DiscordRPC
if (USE_DISCORD_PRESENCE)
if (ARCHITECTURE_arm64)
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.fragments
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.fragments
-16
View File
@@ -1429,36 +1429,20 @@ jint Java_org_yuzu_yuzu_1emu_NativeLibrary_installKeys(JNIEnv* env, jclass clazz
}
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getLosslessDllPath(JNIEnv* env, jclass clazz) {
#ifdef HAS_LSFG
const auto path = VideoCore::FrameGen::GetLosslessDllPath();
return Common::Android::ToJString(env, Common::FS::PathToUTF8String(path));
#else
return Common::Android::ToJString(env, "");
#endif
}
jint Java_org_yuzu_yuzu_1emu_NativeLibrary_validateLosslessDll(JNIEnv* env, jclass clazz) {
#ifdef HAS_LSFG
return static_cast<jint>(VideoCore::FrameGen::GetInstalledLosslessStatus());
#else
return static_cast<jint>(VideoCore::FrameGen::LosslessStatus::NotInstalled);
#endif
}
jint Java_org_yuzu_yuzu_1emu_NativeLibrary_prepareLosslessDll(JNIEnv* env, jclass clazz) {
#ifdef HAS_LSFG
return static_cast<jint>(VideoCore::FrameGen::BuildShaderCache());
#else
return static_cast<jint>(VideoCore::FrameGen::LosslessStatus::NotInstalled);
#endif
}
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_removeLosslessDll(JNIEnv* env, jclass clazz) {
#ifdef HAS_LSFG
return static_cast<jboolean>(VideoCore::FrameGen::RemoveInstalledLosslessDll());
#else
return static_cast<jboolean>(false);
#endif
}
jobjectArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPatchesForFile(JNIEnv* env, jobject jobj,
+1 -1
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
+1 -1
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
+27 -32
View File
@@ -59,6 +59,10 @@ add_library(video_core STATIC
engines/maxwell_dma.h
engines/puller.cpp
engines/puller.h
frame_gen/lossless_dll.cpp
frame_gen/lossless_dll.h
frame_gen/lsfg_translate.cpp
frame_gen/lsfg_translate.h
framebuffer_config.cpp
framebuffer_config.h
fsr.cpp
@@ -121,6 +125,28 @@ add_library(video_core STATIC
renderer_vulkan/present/anti_alias_pass.h
renderer_vulkan/present/filters.cpp
renderer_vulkan/present/filters.h
renderer_vulkan/present/frame_gen.cpp
renderer_vulkan/present/frame_gen.h
renderer_vulkan/present/frame_gen_pacer.cpp
renderer_vulkan/present/frame_gen_pacer.h
renderer_vulkan/present/lsfg_alpha.cpp
renderer_vulkan/present/lsfg_alpha.h
renderer_vulkan/present/lsfg_beta.cpp
renderer_vulkan/present/lsfg_beta.h
renderer_vulkan/present/lsfg_chain.cpp
renderer_vulkan/present/lsfg_chain.h
renderer_vulkan/present/lsfg_common.cpp
renderer_vulkan/present/lsfg_common.h
renderer_vulkan/present/lsfg_delta.cpp
renderer_vulkan/present/lsfg_delta.h
renderer_vulkan/present/lsfg_gamma.cpp
renderer_vulkan/present/lsfg_gamma.h
renderer_vulkan/present/lsfg_generate.cpp
renderer_vulkan/present/lsfg_generate.h
renderer_vulkan/present/lsfg_mipmaps.cpp
renderer_vulkan/present/lsfg_mipmaps.h
renderer_vulkan/present/lsfg_shaders.cpp
renderer_vulkan/present/lsfg_shaders.h
renderer_vulkan/present/fsr.cpp
renderer_vulkan/present/fsr.h
renderer_vulkan/present/fxaa.cpp
@@ -267,38 +293,6 @@ add_library(video_core STATIC
video_core.h
)
if (ENABLE_LSFG)
target_sources(video_core PRIVATE
frame_gen/lossless_dll.cpp
frame_gen/lossless_dll.h
frame_gen/lsfg_translate.cpp
frame_gen/lsfg_translate.h
renderer_vulkan/present/frame_gen.cpp
renderer_vulkan/present/frame_gen.h
renderer_vulkan/present/frame_gen_pacer.cpp
renderer_vulkan/present/frame_gen_pacer.h
renderer_vulkan/present/lsfg_alpha.cpp
renderer_vulkan/present/lsfg_alpha.h
renderer_vulkan/present/lsfg_beta.cpp
renderer_vulkan/present/lsfg_beta.h
renderer_vulkan/present/lsfg_chain.cpp
renderer_vulkan/present/lsfg_chain.h
renderer_vulkan/present/lsfg_common.cpp
renderer_vulkan/present/lsfg_common.h
renderer_vulkan/present/lsfg_delta.cpp
renderer_vulkan/present/lsfg_delta.h
renderer_vulkan/present/lsfg_gamma.cpp
renderer_vulkan/present/lsfg_gamma.h
renderer_vulkan/present/lsfg_generate.cpp
renderer_vulkan/present/lsfg_generate.h
renderer_vulkan/present/lsfg_mipmaps.cpp
renderer_vulkan/present/lsfg_mipmaps.h
renderer_vulkan/present/lsfg_shaders.cpp
renderer_vulkan/present/lsfg_shaders.h
)
target_compile_definitions(video_core PUBLIC HAS_LSFG)
endif()
if (ENABLE_OPENGL)
target_sources(video_core PRIVATE
renderer_opengl/present/filters.cpp
@@ -377,6 +371,7 @@ add_dependencies(video_core host_shaders)
target_include_directories(video_core PRIVATE ${HOST_SHADERS_INCLUDE})
target_link_libraries(video_core PRIVATE sirit::sirit)
target_link_libraries(video_core PRIVATE dxbc)
# Header-only stuff needed by all dependent targets
target_link_libraries(video_core PUBLIC Vulkan::Headers Vulkan::UtilityHeaders GPUOpen::VulkanMemoryAllocator)
+42 -20
View File
@@ -278,8 +278,14 @@ template <typename Map>
}
[[nodiscard]] u32 VariantOffset(ShaderVariant variant) {
return variant == ShaderVariant::NativeFp16 ? PerformanceShader::NATIVE_FP16_OFFSET
: PerformanceShader::NATIVE_FP32_OFFSET;
switch (variant) {
case ShaderVariant::NativeFp16:
return PerformanceShader::NATIVE_FP16_OFFSET;
case ShaderVariant::NativeFp32:
return PerformanceShader::NATIVE_FP32_OFFSET;
default:
return 0;
}
}
template <typename Map>
@@ -291,18 +297,14 @@ template <typename Map>
});
}
[[nodiscard]] std::optional<ShaderVariant> SelectVariant(const ResourceSpans& resources,
bool allow_fp16, bool prefer_fp16) {
[[nodiscard]] ShaderVariant SelectVariant(const ResourceSpans& resources, bool prefer_fp16) {
if (prefer_fp16 && HasNativeVariant(resources, ShaderVariant::NativeFp16)) {
return ShaderVariant::NativeFp16;
}
if (HasNativeVariant(resources, ShaderVariant::NativeFp32)) {
return ShaderVariant::NativeFp32;
}
if (allow_fp16 && HasNativeVariant(resources, ShaderVariant::NativeFp16)) {
return ShaderVariant::NativeFp16;
}
return std::nullopt;
return ShaderVariant::TranslatedDxbc;
}
[[nodiscard]] LosslessStatus TranslateAll(const ResourceSpans& resources,
@@ -315,11 +317,20 @@ template <typename Map>
if (hit == resources.end()) {
return LosslessStatus::MissingShaders;
}
std::vector<u32> adopted = AdoptSpirvModule(hit->second);
if (adopted.empty()) {
if (variant != ShaderVariant::TranslatedDxbc) {
std::vector<u32> adopted = AdoptSpirvModule(hit->second);
if (adopted.empty()) {
return LosslessStatus::TranslationFailed;
}
out_modules.emplace(id, std::move(adopted));
continue;
}
std::vector<u32> words = TranslateComputeShader(hit->second);
if (words.empty()) {
return LosslessStatus::TranslationFailed;
}
out_modules.emplace(id, std::move(adopted));
out_modules.emplace(id, std::move(words));
}
return LosslessStatus::Ok;
}
@@ -483,7 +494,21 @@ LosslessStatus GetInstalledLosslessStatus() {
return ValidateLosslessDll(GetLosslessDllPath());
}
LosslessStatus LoadShaderModules(ShaderModules& out_modules, bool allow_fp16, bool prefer_fp16) {
ShaderVariant GetAvailableVariant(bool prefer_fp16) {
std::vector<u8> image;
if (ReadImageFile(GetLosslessDllPath(), image) != LosslessStatus::Ok) {
return ShaderVariant::TranslatedDxbc;
}
ResourceSpans spans;
if (ParseShaderSpans(image, spans) != LosslessStatus::Ok) {
return ShaderVariant::TranslatedDxbc;
}
return SelectVariant(spans, prefer_fp16);
}
LosslessStatus LoadShaderModules(ShaderModules& out_modules, bool prefer_fp16) {
std::vector<u8> image;
const LosslessStatus read_status = ReadImageFile(GetLosslessDllPath(), image);
if (read_status != LosslessStatus::Ok) {
@@ -501,17 +526,14 @@ LosslessStatus LoadShaderModules(ShaderModules& out_modules, bool allow_fp16, bo
return parse_status;
}
const std::optional<ShaderVariant> variant = SelectVariant(spans, allow_fp16, prefer_fp16);
if (!variant) {
return LosslessStatus::MissingShaders;
}
const ShaderVariant variant = SelectVariant(spans, prefer_fp16);
if (ReadShaderCache(cache_path, source_size, source_hash, static_cast<u32>(*variant),
if (ReadShaderCache(cache_path, source_size, source_hash, static_cast<u32>(variant),
out_modules)) {
return LosslessStatus::Ok;
}
const LosslessStatus translate_status = TranslateAll(spans, out_modules, *variant);
const LosslessStatus translate_status = TranslateAll(spans, out_modules, variant);
if (translate_status != LosslessStatus::Ok) {
return translate_status;
}
@@ -522,7 +544,7 @@ LosslessStatus LoadShaderModules(ShaderModules& out_modules, bool allow_fp16, bo
.source_size = source_size,
.source_hash = source_hash,
.module_count = static_cast<u32>(out_modules.size()),
.variant = static_cast<u32>(*variant),
.variant = static_cast<u32>(variant),
};
if (!WriteShaderCache(cache_path, header, out_modules)) {
void(Common::FS::RemoveFile(cache_path));
@@ -534,7 +556,7 @@ LosslessStatus LoadShaderModules(ShaderModules& out_modules, bool allow_fp16, bo
LosslessStatus BuildShaderCache() {
ShaderModules modules;
return LoadShaderModules(modules, true);
return LoadShaderModules(modules);
}
bool RemoveInstalledLosslessDll() {
+5 -3
View File
@@ -29,8 +29,9 @@ using ShaderResources = std::map<u32, std::vector<u8>>;
using ShaderModules = std::map<u32, std::vector<u32>>;
enum class ShaderVariant : u32 {
NativeFp32 = 1,
NativeFp16 = 2,
TranslatedDxbc,
NativeFp32,
NativeFp16,
};
namespace PerformanceShader {
@@ -58,8 +59,9 @@ constexpr u32 NATIVE_FP32_OFFSET = 98;
[[nodiscard]] LosslessStatus BuildShaderCache();
[[nodiscard]] ShaderVariant GetAvailableVariant(bool prefer_fp16);
[[nodiscard]] LosslessStatus LoadShaderModules(ShaderModules& out_modules,
bool allow_fp16 = false,
bool prefer_fp16 = false);
bool RemoveInstalledLosslessDll();
+51 -15
View File
@@ -6,23 +6,37 @@
#include <map>
#include <tuple>
#include <dxbc_modinfo.h>
#include <dxbc_module.h>
#include <dxbc_reader.h>
#include <thirdparty/spirv.hpp>
#include "video_core/frame_gen/lsfg_translate.h"
namespace VideoCore::FrameGen {
namespace {
constexpr u32 SPIRV_MAGIC = 0x07230203;
constexpr u32 SPIRV_WORD_COUNT_SHIFT = 16;
constexpr u32 SPIRV_OPCODE_MASK = 0xffff;
constexpr u32 SPIRV_OP_FUNCTION = 54;
constexpr u32 SPIRV_OP_DECORATE = 71;
constexpr u32 SPIRV_DECORATION_BINDING = 33;
constexpr u32 SPIRV_DECORATION_DESCRIPTOR_SET = 34;
constexpr u32 DECORATION_LITERAL_WORD = 3;
constexpr size_t SPIRV_HEADER_WORDS = 5;
void RenumberBindings(dxvk::SpirvCodeBuffer& code) {
std::vector<u32> literal_offsets;
for (const auto instruction : code) {
if (instruction.opCode() == spv::OpFunction) {
break;
}
if (instruction.opCode() == spv::OpDecorate &&
instruction.arg(2) == spv::DecorationBinding) {
literal_offsets.push_back(instruction.offset() + DECORATION_LITERAL_WORD);
}
}
for (size_t i = 0; i < literal_offsets.size(); ++i) {
code.data()[literal_offsets[i]] = static_cast<u32>(i);
}
}
void RenumberBindingsInOrder(std::vector<u32>& words) {
struct Slot {
u32 set;
@@ -35,18 +49,18 @@ void RenumberBindingsInOrder(std::vector<u32>& words) {
size_t offset = SPIRV_HEADER_WORDS;
while (offset + 1 <= words.size()) {
const u32 length = words[offset] >> SPIRV_WORD_COUNT_SHIFT;
const u32 opcode = words[offset] & SPIRV_OPCODE_MASK;
const u32 length = words[offset] >> spv::WordCountShift;
const u32 opcode = words[offset] & spv::OpCodeMask;
if (length == 0 || offset + length > words.size()) {
return;
}
if (opcode == SPIRV_OP_FUNCTION) {
if (opcode == spv::OpFunction) {
break;
}
if (opcode == SPIRV_OP_DECORATE && length >= 4) {
if (words[offset + 2] == SPIRV_DECORATION_DESCRIPTOR_SET) {
if (opcode == spv::OpDecorate && length >= 4) {
if (words[offset + 2] == spv::DecorationDescriptorSet) {
sets[words[offset + 1]] = words[offset + 3];
} else if (words[offset + 2] == SPIRV_DECORATION_BINDING) {
} else if (words[offset + 2] == spv::DecorationBinding) {
slots.push_back(Slot{0, words[offset + 3], offset + DECORATION_LITERAL_WORD});
}
}
@@ -75,7 +89,7 @@ bool IsSpirvModule(std::span<const u8> blob) {
}
u32 magic{};
std::memcpy(&magic, blob.data(), sizeof(magic));
return magic == SPIRV_MAGIC;
return magic == spv::MagicNumber;
}
std::vector<u32> AdoptSpirvModule(std::span<const u8> blob) {
@@ -90,4 +104,26 @@ std::vector<u32> AdoptSpirvModule(std::span<const u8> blob) {
return words;
}
std::vector<u32> TranslateComputeShader(std::span<const u8> dxbc) {
if (dxbc.empty()) {
return {};
}
try {
dxvk::DxbcReader reader{reinterpret_cast<const char*>(dxbc.data()), dxbc.size()};
dxvk::DxbcModule module{reader};
const dxvk::DxbcModuleInfo module_info{};
dxvk::SpirvCodeBuffer code = module.compile(module_info, "CS");
if (code.dwords() == 0) {
return {};
}
RenumberBindings(code);
return std::vector<u32>{code.data(), code.data() + code.dwords()};
} catch (...) {
return {};
}
}
} // namespace VideoCore::FrameGen
@@ -14,4 +14,6 @@ namespace VideoCore::FrameGen {
[[nodiscard]] std::vector<u32> AdoptSpirvModule(std::span<const u8> blob);
[[nodiscard]] std::vector<u32> TranslateComputeShader(std::span<const u8> dxbc);
} // namespace VideoCore::FrameGen
@@ -14,11 +14,11 @@ LsfgShaders::LsfgShaders(const Device& device) {
return;
}
const bool allow_fp16 = device.IsFloat16Supported();
const bool prefer_fp16 = allow_fp16 && Settings::values.frame_gen_fp16.GetValue();
const bool prefer_fp16 =
Settings::values.frame_gen_fp16.GetValue() && device.IsFloat16Supported();
VideoCore::FrameGen::ShaderModules code;
if (VideoCore::FrameGen::LoadShaderModules(code, allow_fp16, prefer_fp16) !=
if (VideoCore::FrameGen::LoadShaderModules(code, prefer_fp16) !=
VideoCore::FrameGen::LosslessStatus::Ok) {
return;
}
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -49,7 +49,6 @@ constexpr VkExtent2D CaptureImageSize{
.height = VideoCore::Capture::LinearHeight,
};
#ifdef HAS_LSFG
[[nodiscard]] VkExtent2D GuestExtent(std::span<const Tegra::FramebufferConfig> framebuffers) {
if (framebuffers.empty()) {
return VkExtent2D{};
@@ -64,7 +63,6 @@ constexpr VkExtent2D CaptureImageSize{
.height = static_cast<u32>(framebuffer.crop_rect.GetHeight()),
};
}
#endif
constexpr VkExtent3D CaptureImageExtent{
.width = VideoCore::Capture::LinearWidth,
@@ -173,10 +171,7 @@ try
scheduler,
PresentFiltersForAppletCapture)
, rasterizer(render_window, gpu, device_memory, device, memory_allocator, state_tracker, scheduler)
#ifdef HAS_LSFG
, frame_gen(memory_allocator, scheduler)
#endif
{
, frame_gen(memory_allocator, scheduler) {
if (Settings::values.renderer_force_max_clock.GetValue() && device.ShouldBoostClocks()) {
turbo_mode.emplace(instance, dld);
@@ -213,7 +208,6 @@ void RendererVulkan::Composite(std::span<const Tegra::FramebufferConfig> framebu
render_window.GetFramebufferLayout(), swapchain.GetImageCount(),
swapchain.GetImageViewFormat());
#ifdef HAS_LSFG
void(frame_gen.WantedGenerations(present_manager.MaxExtraFrames()));
frame_gen.Process(device, frame, swapchain.GetImageFormat(), GuestExtent(framebuffers));
@@ -226,14 +220,11 @@ void RendererVulkan::Composite(std::span<const Tegra::FramebufferConfig> framebu
scheduler.Flush(*generated->render_ready);
present_manager.Present(generated);
}
#endif
scheduler.Flush(*frame->render_ready);
present_manager.Present(frame);
#ifdef HAS_LSFG
scheduler.DispatchWork();
#endif
gpu.RendererFrameEndNotify();
rasterizer.TickFrame();
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
@@ -13,9 +13,7 @@
#include "common/dynamic_library.h"
#include "video_core/host1x/gpu_device_memory_manager.h"
#include "video_core/renderer_base.h"
#ifdef HAS_LSFG
#include "video_core/renderer_vulkan/present/frame_gen.h"
#endif
#include "video_core/renderer_vulkan/vk_blit_screen.h"
#include "video_core/renderer_vulkan/vk_present_manager.h"
#include "video_core/renderer_vulkan/vk_rasterizer.h"
@@ -98,9 +96,7 @@ private:
BlitScreen blit_capture;
BlitScreen blit_applet;
RasterizerVulkan rasterizer;
#ifdef HAS_LSFG
FrameGen frame_gen;
#endif
std::optional<TurboMode> turbo_mode;
Frame applet_frame;
@@ -7,9 +7,7 @@
#include "common/settings.h"
#include "common/thread.h"
#include "core/frontend/emu_window.h"
#ifdef HAS_LSFG
#include "video_core/renderer_vulkan/present/lsfg_common.h"
#endif
#include "video_core/renderer_vulkan/vk_present_manager.h"
#include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_swapchain.h"
@@ -23,20 +21,14 @@ namespace Vulkan {
namespace {
constexpr size_t MAX_FRAMES_IN_FLIGHT = 7;
#ifdef HAS_LSFG
static_assert(MAX_FRAMES_IN_FLIGHT <= LSFG_MAX_TARGETS);
#endif
bool CanStoreToFrame(const vk::PhysicalDevice& physical_device, VkFormat format) {
#ifdef HAS_LSFG
if (!Settings::values.frame_gen.GetValue()) {
return false;
}
const VkFormatProperties props{physical_device.GetFormatProperties(format)};
return (props.optimalTilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) != 0;
#else
return false;
#endif
}
bool CanBlitToSwapchain(const vk::PhysicalDevice& physical_device, VkFormat format) {
@@ -358,15 +350,11 @@ void PresentManager::SetImageCount() {
// We cannot have more than 7 images in flight at any given time.
// FRAMES_IN_FLIGHT is 8, and the cache TICKS_TO_DESTROY is 8.
// Mali drivers will give us 6.
#ifdef HAS_LSFG
const size_t generations = Settings::FrameGenMaxGenerations();
const size_t queued_composites = Settings::values.frame_gen_queue_target.GetValue() + 1;
image_count =
std::clamp<size_t>((generations + 1) * queued_composites, swapchain.GetImageCount(),
MAX_FRAMES_IN_FLIGHT);
#else
image_count = std::min<size_t>(swapchain.GetImageCount(), MAX_FRAMES_IN_FLIGHT);
#endif
}
void PresentManager::CopyToSwapchain(Frame* frame) {