diff --git a/src/android/app/src/main/res/values/arrays.xml b/src/android/app/src/main/res/values/arrays.xml
index 0fd6867632..cb108dc548 100644
--- a/src/android/app/src/main/res/values/arrays.xml
+++ b/src/android/app/src/main/res/values/arrays.xml
@@ -87,8 +87,8 @@
- @string/shader_backend_glsl
- - @string/shader_backend_spirv
- @string/shader_backend_glasm
+ - @string/shader_backend_spirv
diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml
index 043f89d3d2..910e9ec312 100644
--- a/src/android/app/src/main/res/values/strings.xml
+++ b/src/android/app/src/main/res/values/strings.xml
@@ -23,9 +23,9 @@
Show Speed
Display current emulation speed percentage
Show App Memory Usage
- Display the amount of RAM getting used by the emulator
+ Display the amount of RAM the emulator is using
Show System Memory Usage
- Display the amount of RAM getting used by the system
+ Display the amount of RAM used by the system
Show Battery Temperature
Display current Battery temperature in Celsius and Fahrenheit
Overlay Position
@@ -49,7 +49,7 @@
EDS3 + VertexInputDynamicState
Improves performance on newer devices. Only supported on Vulkan 1.3+ GPUs.
Synchronize Core Speed
- Synchronize the core tick speed to the maximum speed percentage to improve performance without altering the games actual speed.
+ Synchronize the core tick speed to the maximum speed percentage to improve performance without altering the game\'s actual speed.
Use Auto Stub
Automatically stub missing services and functions. This may improve compatibility but can cause crashes and stability issues.
Uninstall firmware
@@ -389,7 +389,7 @@
Optimize SPIRV output
Optimizes compiled shader to improve GPU efficiency.
Use asynchronous shaders
- Compiles shaders asynchronously, reducing stutter but may introduce glitches.
+ Compiles shaders asynchronously. This may reduce stutters but may also introduce glitches.
Use Fast GPU Time
Forces most games to run at their highest native resolution. This option is hacky and may cause issues.
Use reactive flushing
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index 3260ef8cc2..30f5ff7a75 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -1,6 +1,9 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: Copyright 2025 eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
#include
#include
#include
@@ -99,52 +102,91 @@ Device CreateDevice(const vk::Instance& instance, const vk::InstanceDispatch& dl
}
RendererVulkan::RendererVulkan(Core::Frontend::EmuWindow& emu_window,
- Tegra::MaxwellDeviceMemoryManager& device_memory_, Tegra::GPU& gpu_,
- std::unique_ptr context_) try
- : RendererBase(emu_window, std::move(context_)), device_memory(device_memory_), gpu(gpu_),
- library(OpenLibrary(context.get())),
- // Create raw Vulkan instance first
- instance(CreateInstance(*library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type,
- Settings::values.renderer_debug.GetValue())),
- // Now create RAII wrappers for the resources in the correct order
- managed_instance(MakeManagedInstance(instance, dld)),
- // Create debug messenger if debug is enabled
- debug_messenger(Settings::values.renderer_debug ? CreateDebugUtilsCallback(instance)
- : vk::DebugUtilsMessenger{}),
- managed_debug_messenger(Settings::values.renderer_debug
- ? MakeManagedDebugUtilsMessenger(debug_messenger, instance, dld)
- : ManagedDebugUtilsMessenger{}),
- // Create surface
- surface(CreateSurface(instance, render_window.GetWindowInfo())),
- managed_surface(MakeManagedSurface(surface, instance, dld)),
- device(CreateDevice(instance, dld, *surface)),
- memory_allocator(device), state_tracker(),
- scheduler(device, state_tracker),
- swapchain(*surface, device, scheduler, render_window.GetFramebufferLayout().width,
- render_window.GetFramebufferLayout().height),
- present_manager(instance, render_window, device, memory_allocator, scheduler, swapchain,
- *surface),
- blit_swapchain(device_memory, device, memory_allocator, present_manager, scheduler,
- PresentFiltersForDisplay),
- blit_capture(device_memory, device, memory_allocator, present_manager, scheduler,
- PresentFiltersForDisplay),
- blit_applet(device_memory, device, memory_allocator, present_manager, scheduler,
- PresentFiltersForAppletCapture),
- rasterizer(render_window, gpu, device_memory, device, memory_allocator, state_tracker,
- scheduler),
- applet_frame() {
+ Tegra::MaxwellDeviceMemoryManager& device_memory_,
+ Tegra::GPU& gpu_,
+ std::unique_ptr context_)
+try
+ : RendererBase(emu_window, std::move(context_))
+ , device_memory(device_memory_)
+ , gpu(gpu_)
+ , library(OpenLibrary(context.get()))
+ ,
+ // Create raw Vulkan instance first
+ instance(CreateInstance(*library,
+ dld,
+ VK_API_VERSION_1_1,
+ render_window.GetWindowInfo().type,
+ Settings::values.renderer_debug.GetValue()))
+ ,
+ // Now create RAII wrappers for the resources in the correct order
+ managed_instance(MakeManagedInstance(instance, dld))
+ ,
+ // Create debug messenger if debug is enabled
+ debug_messenger(Settings::values.renderer_debug ? CreateDebugUtilsCallback(instance)
+ : vk::DebugUtilsMessenger{})
+ , managed_debug_messenger(Settings::values.renderer_debug
+ ? MakeManagedDebugUtilsMessenger(debug_messenger, instance, dld)
+ : ManagedDebugUtilsMessenger{})
+ ,
+ // Create surface
+ surface(CreateSurface(instance, render_window.GetWindowInfo()))
+ , managed_surface(MakeManagedSurface(surface, instance, dld))
+ , device(CreateDevice(instance, dld, *surface))
+ , memory_allocator(device)
+ , state_tracker()
+ , scheduler(device, state_tracker)
+ , swapchain(*surface,
+ device,
+ scheduler,
+ render_window.GetFramebufferLayout().width,
+ render_window.GetFramebufferLayout().height)
+ , present_manager(instance,
+ render_window,
+ device,
+ memory_allocator,
+ scheduler,
+ swapchain,
+#ifdef ANDROID
+ surface)
+ ,
+#else
+ *surface)
+ ,
+#endif
+ blit_swapchain(device_memory,
+ device,
+ memory_allocator,
+ present_manager,
+ scheduler,
+ PresentFiltersForDisplay)
+ , blit_capture(device_memory,
+ device,
+ memory_allocator,
+ present_manager,
+ scheduler,
+ PresentFiltersForDisplay)
+ , blit_applet(device_memory,
+ device,
+ memory_allocator,
+ present_manager,
+ scheduler,
+ PresentFiltersForAppletCapture)
+ , rasterizer(render_window, gpu, device_memory, device, memory_allocator, state_tracker, scheduler)
+ , applet_frame() {
- if (Settings::values.renderer_force_max_clock.GetValue() && device.ShouldBoostClocks()) {
+ if (Settings::values.renderer_force_max_clock.GetValue() && device.ShouldBoostClocks()) {
turbo_mode.emplace(instance, dld);
scheduler.RegisterOnSubmit([this] { turbo_mode->QueueSubmitted(); });
}
+#ifndef ANDROID
// Release ownership from the old instance and surface
instance.release();
surface.release();
if (Settings::values.renderer_debug) {
debug_messenger.release();
}
+#endif
Report();
} catch (const vk::Exception& exception) {
diff --git a/src/video_core/renderer_vulkan/vk_present_manager.cpp b/src/video_core/renderer_vulkan/vk_present_manager.cpp
index 8f5edeae24..a448dc5288 100644
--- a/src/video_core/renderer_vulkan/vk_present_manager.cpp
+++ b/src/video_core/renderer_vulkan/vk_present_manager.cpp
@@ -95,15 +95,31 @@ bool CanBlitToSwapchain(const vk::PhysicalDevice& physical_device, VkFormat form
} // Anonymous namespace
-PresentManager::PresentManager(const vk::Instance& instance_, Core::Frontend::EmuWindow& render_window_,
- const Device& device_, MemoryAllocator& memory_allocator_, Scheduler& scheduler_,
- Swapchain& swapchain_, VkSurfaceKHR_T* surface_handle_)
- : instance{instance_}, render_window{render_window_}, device{device_},
- memory_allocator{memory_allocator_}, scheduler{scheduler_}, swapchain{swapchain_},
- surface_handle{surface_handle_},
- blit_supported{CanBlitToSwapchain(device.GetPhysical(),
- swapchain.GetImageViewFormat())},
- use_present_thread{Settings::values.async_presentation.GetValue()} {
+PresentManager::PresentManager(const vk::Instance& instance_,
+ Core::Frontend::EmuWindow& render_window_,
+ const Device& device_,
+ MemoryAllocator& memory_allocator_,
+ Scheduler& scheduler_,
+ Swapchain& swapchain_,
+#ifdef ANDROID
+ vk::SurfaceKHR& surface_)
+#else
+ VkSurfaceKHR_T* surface_handle_)
+#endif
+ : instance{instance_}
+ , render_window{render_window_}
+ , device{device_}
+ , memory_allocator{memory_allocator_}
+ , scheduler{scheduler_}
+ , swapchain{swapchain_}
+#ifdef ANDROID
+ , surface{surface_}
+#else
+ , surface_handle{surface_handle_}
+#endif
+ , blit_supported{CanBlitToSwapchain(device.GetPhysical(), swapchain.GetImageViewFormat())}
+ , use_present_thread{Settings::values.async_presentation.GetValue()}
+{
SetImageCount();
auto& dld = device.GetLogical();
@@ -289,7 +305,11 @@ void PresentManager::PresentThread(std::stop_token token) {
}
void PresentManager::RecreateSwapchain(Frame* frame) {
+#ifndef ANDROID
swapchain.Create(surface_handle, frame->width, frame->height); // Pass raw pointer
+#else
+ swapchain.Create(*surface, frame->width, frame->height); // Pass raw pointer
+#endif
SetImageCount();
}
@@ -307,6 +327,9 @@ void PresentManager::CopyToSwapchain(Frame* frame) {
try {
// Recreate surface and swapchain if needed.
if (requires_recreation) {
+#ifdef ANDROID
+ surface = CreateSurface(instance, render_window.GetWindowInfo());
+#endif
RecreateSwapchain(frame);
}
diff --git a/src/video_core/renderer_vulkan/vk_present_manager.h b/src/video_core/renderer_vulkan/vk_present_manager.h
index 96850ed56f..5820280602 100644
--- a/src/video_core/renderer_vulkan/vk_present_manager.h
+++ b/src/video_core/renderer_vulkan/vk_present_manager.h
@@ -37,9 +37,17 @@ struct Frame {
class PresentManager {
public:
- PresentManager(const vk::Instance& instance, Core::Frontend::EmuWindow& render_window,
- const Device& device, MemoryAllocator& memory_allocator, Scheduler& scheduler,
- Swapchain& swapchain, VkSurfaceKHR_T* surface_handle);
+ PresentManager(const vk::Instance& instance,
+ Core::Frontend::EmuWindow& render_window,
+ const Device& device,
+ MemoryAllocator& memory_allocator,
+ Scheduler& scheduler,
+ Swapchain& swapchain,
+#ifdef ANDROID
+ vk::SurfaceKHR& surface);
+#else
+ VkSurfaceKHR_T* surface_handle);
+#endif
~PresentManager();
/// Returns the last used presentation frame
@@ -73,7 +81,11 @@ private:
MemoryAllocator& memory_allocator;
Scheduler& scheduler;
Swapchain& swapchain;
+#ifdef ANDROID
+ vk::SurfaceKHR& surface;
+#else
VkSurfaceKHR_T* surface_handle;
+#endif
vk::CommandPool cmdpool;
std::vector frames;
std::queue present_queue;
diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp
index ec96b75036..a002ca83a0 100644
--- a/src/video_core/renderer_vulkan/vk_swapchain.cpp
+++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp
@@ -105,23 +105,58 @@ VkCompositeAlphaFlagBitsKHR ChooseAlphaFlags(const VkSurfaceCapabilitiesKHR& cap
} // Anonymous namespace
-Swapchain::Swapchain(VkSurfaceKHR_T* surface_handle_, const Device& device_, Scheduler& scheduler_,
- u32 width_, u32 height_)
- : surface_handle{surface_handle_}, device{device_}, scheduler{scheduler_} {
+Swapchain::Swapchain(
+#ifdef ANDROID
+ VkSurfaceKHR surface_,
+#else
+ VkSurfaceKHR_T* surface_handle_,
+#endif
+ const Device& device_,
+ Scheduler& scheduler_,
+ u32 width_,
+ u32 height_)
+#ifdef ANDROID
+ : surface(surface_)
+#else
+ : surface_handle{surface_handle_}
+#endif
+ , device{device_}
+ , scheduler{scheduler_}
+{
+#ifdef ANDROID
+ Create(surface, width_, height_);
+#else
Create(surface_handle, width_, height_);
+#endif
}
Swapchain::~Swapchain() = default;
-void Swapchain::Create(VkSurfaceKHR_T* surface_handle_, u32 width_, u32 height_) {
+void Swapchain::Create(
+#ifdef ANDROID
+ VkSurfaceKHR surface_,
+#else
+ VkSurfaceKHR_T* surface_handle_,
+#endif
+ u32 width_,
+ u32 height_)
+{
is_outdated = false;
is_suboptimal = false;
width = width_;
height = height_;
+#ifdef ANDROID
+ surface = surface_;
+#else
surface_handle = surface_handle_;
+#endif
const auto physical_device = device.GetPhysical();
+#ifdef ANDROID
+ const auto capabilities{physical_device.GetSurfaceCapabilitiesKHR(surface)};
+#else
const auto capabilities{physical_device.GetSurfaceCapabilitiesKHR(surface_handle)};
+#endif
if (capabilities.maxImageExtent.width == 0 || capabilities.maxImageExtent.height == 0) {
return;
}
@@ -199,10 +234,17 @@ void Swapchain::Present(VkSemaphore render_semaphore) {
void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities) {
const auto physical_device{device.GetPhysical()};
+
+#ifdef ANDROID
+ const auto formats{physical_device.GetSurfaceFormatsKHR(surface)};
+ const auto present_modes = physical_device.GetSurfacePresentModesKHR(surface);
+#else
const auto formats{physical_device.GetSurfaceFormatsKHR(surface_handle)};
const auto present_modes = physical_device.GetSurfacePresentModesKHR(surface_handle);
- has_mailbox = std::find(present_modes.begin(), present_modes.end(),
- VK_PRESENT_MODE_MAILBOX_KHR) != present_modes.end();
+#endif
+
+ has_mailbox = std::find(present_modes.begin(), present_modes.end(), VK_PRESENT_MODE_MAILBOX_KHR)
+ != present_modes.end();
has_imm = std::find(present_modes.begin(), present_modes.end(),
VK_PRESENT_MODE_IMMEDIATE_KHR) != present_modes.end();
has_fifo_relaxed = std::find(present_modes.begin(), present_modes.end(),
@@ -228,7 +270,11 @@ void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities) {
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
.pNext = nullptr,
.flags = 0,
+#ifdef ANDROID
+ .surface = surface,
+#else
.surface = surface_handle,
+#endif
.minImageCount = requested_image_count,
.imageFormat = surface_format.format,
.imageColorSpace = surface_format.colorSpace,
@@ -269,7 +315,11 @@ void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities) {
swapchain_ci.flags |= VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR;
}
// Request the size again to reduce the possibility of a TOCTOU race condition.
+#ifdef ANDROID
+ const auto updated_capabilities = physical_device.GetSurfaceCapabilitiesKHR(surface);
+#else
const auto updated_capabilities = physical_device.GetSurfaceCapabilitiesKHR(surface_handle);
+#endif
swapchain_ci.imageExtent = ChooseSwapExtent(updated_capabilities, width, height);
// Don't add code within this and the swapchain creation.
swapchain = device.GetLogical().CreateSwapchainKHR(swapchain_ci);
diff --git a/src/video_core/renderer_vulkan/vk_swapchain.h b/src/video_core/renderer_vulkan/vk_swapchain.h
index f5090c27f4..b3e1c4f025 100644
--- a/src/video_core/renderer_vulkan/vk_swapchain.h
+++ b/src/video_core/renderer_vulkan/vk_swapchain.h
@@ -21,12 +21,27 @@ class Scheduler;
class Swapchain {
public:
- explicit Swapchain(VkSurfaceKHR_T* surface_handle, const Device& device, Scheduler& scheduler, u32 width,
- u32 height);
+ explicit Swapchain(
+#ifdef ANDROID
+ VkSurfaceKHR surface,
+#else
+ VkSurfaceKHR_T* surface_handle,
+#endif
+ const Device& device,
+ Scheduler& scheduler,
+ u32 width,
+ u32 height);
~Swapchain();
/// Creates (or recreates) the swapchain with a given size.
- void Create(VkSurfaceKHR_T* surface_handle, u32 width, u32 height);
+ void Create(
+#ifdef ANDROID
+ VkSurfaceKHR surface,
+#else
+ VkSurfaceKHR_T* surface_handle,
+#endif
+ u32 width,
+ u32 height);
/// Acquires the next image in the swapchain, waits as needed.
bool AcquireNextImage();
@@ -110,7 +125,12 @@ private:
bool NeedsPresentModeUpdate() const;
+#ifdef ANDROID
+ VkSurfaceKHR surface;
+#else
VkSurfaceKHR_T* surface_handle;
+#endif
+
const Device& device;
Scheduler& scheduler;
diff --git a/src/video_core/vulkan_common/vulkan_wrapper.h b/src/video_core/vulkan_common/vulkan_wrapper.h
index aa9fb8e17b..4607bf516c 100644
--- a/src/video_core/vulkan_common/vulkan_wrapper.h
+++ b/src/video_core/vulkan_common/vulkan_wrapper.h
@@ -430,6 +430,7 @@ public:
return handle != nullptr;
}
+#ifndef ANDROID
/**
* Releases ownership of the managed handle.
* The caller is responsible for managing the lifetime of the returned handle.
@@ -438,6 +439,7 @@ public:
Type release() noexcept {
return std::exchange(handle, nullptr);
}
+#endif
protected:
Type handle = nullptr;
@@ -510,6 +512,7 @@ public:
return handle != nullptr;
}
+#ifndef ANDROID
/**
* Releases ownership of the managed handle.
* The caller is responsible for managing the lifetime of the returned handle.
@@ -518,6 +521,7 @@ public:
Type release() noexcept {
return std::exchange(handle, nullptr);
}
+#endif
protected:
Type handle = nullptr;
diff --git a/src/yuzu/configuration/shared_translation.cpp b/src/yuzu/configuration/shared_translation.cpp
index 38812a8033..02bb9a322f 100644
--- a/src/yuzu/configuration/shared_translation.cpp
+++ b/src/yuzu/configuration/shared_translation.cpp
@@ -544,7 +544,9 @@ std::unique_ptr ComboboxEnumeration(QWidget* parent) {
{
PAIR(MemoryLayout, Memory_4Gb, tr("4GB DRAM (Default)")),
PAIR(MemoryLayout, Memory_6Gb, tr("6GB DRAM (Unsafe)")),
- PAIR(MemoryLayout, Memory_8Gb, tr("8GB DRAM (Unsafe)")),
+ PAIR(MemoryLayout, Memory_8Gb, tr("8GB DRAM")),
+ PAIR(MemoryLayout, Memory_10Gb, tr("10GB DRAM (Unsafe)")),
+ PAIR(MemoryLayout, Memory_12Gb, tr("12GB DRAM (Unsafe)")),
}});
translations->insert({Settings::EnumMetadata::Index(),
{
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp
index 30a6886d73..21914e2d20 100644
--- a/src/yuzu/game_list.cpp
+++ b/src/yuzu/game_list.cpp
@@ -374,7 +374,7 @@ GameList::GameList(FileSys::VirtualFilesystem vfs_, FileSys::ManualContentProvid
warning_layout = new QHBoxLayout;
pre_alpha_warning = new QLabel;
pre_alpha_warning->setText(
- tr("IMPORTANT: Eden is PRE-ALPHA SOFTWARE."
+ tr("IMPORTANT: Eden is PRE-ALPHA SOFTWARE. "
"Bugs and unfinished features are expected to be present at this stage."));
pre_alpha_warning->setWordWrap(true);
pre_alpha_warning->setOpenExternalLinks(true);