Compare commits

..

6 commits

Author SHA1 Message Date
8a017951aa
[qt_common] fix building with Qt 6.10 (#2713)
Qt old style include variables are deprecated in Qt, see <https://github.com/qt/qtbase/blob/v6.10.0/cmake/QtModuleConfig.cmake.in#L84>, and Qt 6.10 stopped exporting them after <ad7b94e163>.

Signed-off-by: Marcin Serwin <marcin@serwin.dev>

Co-authored-by: crueter <crueter@eden-emu.dev>
Reviewed-on: #2713
Co-authored-by: Marcin Serwin <marcin@serwin.dev>
Co-committed-by: Marcin Serwin <marcin@serwin.dev>
2025-10-10 22:33:15 +02:00
776958c79d
[vk] Introduce Ring Buffers for Uniform Buffer (#2698)
Create 3 ring buffers which rotates between buffers each frame to avoid GPU/CPU conflicts
BindMappedUniformBuffer first tries to allocate from the ring buffer and falls back to staging pool only if allocation is too large.
Note to testers:- please test the performance since it is primarily a performance optimization and also look for visual bugs.

Co-authored-by: wildcard <wildcard@eden-emu.dev>
Co-authored-by: MaranBr <maranbr@outlook.com>
Reviewed-on: #2698
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: Shinmegumi <shinmegumi@eden-emu.dev>
Co-committed-by: Shinmegumi <shinmegumi@eden-emu.dev>
2025-10-10 19:24:20 +02:00
3656253262
[acc] do not consider system profile as orphaned (#2708)
Profile 00000000000000000000000000000000 is apparently needed for acnh,
etc

Signed-off-by: crueter <crueter@eden-emu.dev>

Reviewed-on: #2708
2025-10-10 05:59:31 +02:00
b6241e4148
revert [vk] StreamBuffer Changes (#2684) (#2707)
revert [vk] StreamBuffer Changes (#2684)

Streambuffer changes did broke stuff in other games that got out of our scope of testing, we're going to study this changes in the future for better graphic stability.

Co-authored-by: Ribbit <ribbit@placeholder.com>
Reviewed-on: #2684
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Co-authored-by: Ribbit <ribbit@eden-emu.dev>
Co-committed-by: Ribbit <ribbit@eden-emu.dev>
Reviewed-on: #2707
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: CamilleLaVey <camillelavey99@gmail.com>
Co-committed-by: CamilleLaVey <camillelavey99@gmail.com>
2025-10-10 01:55:43 +02:00
bfffafe68b
[common] Change web offline applet default setting to HLE (#2705)
This prevents some games from ignoring the disable web applet setting.

Reviewed-on: #2705
Co-authored-by: MaranBr <maranbr@outlook.com>
Co-committed-by: MaranBr <maranbr@outlook.com>
2025-10-10 01:36:55 +02:00
3c6ef765af
revert [vk] Fast UBO: fix tracking, resize heuristics, add debug guard (#2695) (#2706)
revert [vk] Fast UBO: fix tracking, resize heuristics, add debug guard (#2695)

Well, stuff showed up after testing phase, that showed us this change break SMO and some mods after being merged directly into master, we will keep stuying why happens this and add a better handling later.

Co-authored-by: Ribbit <ribbit@placeholder.com>
Reviewed-on: #2695
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Co-authored-by: Ribbit <ribbit@eden-emu.dev>
Co-committed-by: Ribbit <ribbit@eden-emu.dev>

Reviewed-on: #2706
Co-authored-by: CamilleLaVey <camillelavey99@gmail.com>
Co-committed-by: CamilleLaVey <camillelavey99@gmail.com>
2025-10-09 21:37:27 +02:00
9 changed files with 97 additions and 64 deletions

View file

@ -161,7 +161,7 @@ struct Values {
Category::LibraryApplet};
Setting<AppletMode> photo_viewer_applet_mode{
linkage, AppletMode::LLE, "photo_viewer_applet_mode", Category::LibraryApplet};
Setting<AppletMode> offline_web_applet_mode{linkage, AppletMode::LLE, "offline_web_applet_mode",
Setting<AppletMode> offline_web_applet_mode{linkage, AppletMode::HLE, "offline_web_applet_mode",
Category::LibraryApplet};
Setting<AppletMode> login_share_applet_mode{linkage, AppletMode::HLE, "login_share_applet_mode",
Category::LibraryApplet};

View file

@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

View file

@ -509,6 +509,9 @@ std::vector<std::string> ProfileManager::FindOrphanedProfiles()
good_uuids.emplace_back(uuid_string);
}
// used for acnh, etc
good_uuids.emplace_back("00000000000000000000000000000000");
// TODO: fetch save_id programmatically
const auto path = Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir)
/ "user/save/0000000000000000";

View file

@ -45,6 +45,10 @@ if (NOT APPLE AND ENABLE_OPENGL)
target_compile_definitions(qt_common PUBLIC HAS_OPENGL)
endif()
if (NOT WIN32)
target_include_directories(qt_common PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS})
if (UNIX AND NOT APPLE)
if (TARGET Qt6::GuiPrivate)
target_link_libraries(qt_common PRIVATE Qt6::GuiPrivate)
else()
target_include_directories(yuzu PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS})
endif()
endif()

View file

@ -337,6 +337,11 @@ BufferCacheRuntime::BufferCacheRuntime(const Device& device_, MemoryAllocator& m
uint8_pass = std::make_unique<Uint8Pass>(device, scheduler, descriptor_pool, staging_pool,
compute_pass_descriptor_queue);
}
const u32 ubo_align = static_cast<u32>(
device.GetUniformBufferAlignment() //check if the device has it
);
// add the ability to change the size in settings in future
uniform_ring.Init(device, memory_allocator, 8 * 1024 * 1024 /* 8 MiB */, ubo_align ? ubo_align : 256);
quad_array_index_buffer = std::make_shared<QuadArrayIndexBuffer>(device_, memory_allocator_,
scheduler_, staging_pool_);
quad_strip_index_buffer = std::make_shared<QuadStripIndexBuffer>(device_, memory_allocator_,
@ -355,6 +360,42 @@ void BufferCacheRuntime::FreeDeferredStagingBuffer(StagingBufferRef& ref) {
staging_pool.FreeDeferred(ref);
}
void BufferCacheRuntime::UniformRing::Init(const Device& device,
MemoryAllocator& alloc,
u64 bytes, u32 alignment) {
for (size_t i = 0; i < NUM_FRAMES; ++i) {
VkBufferCreateInfo ci{
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.size = bytes,
.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr,
};
buffers[i] = alloc.CreateBuffer(ci, MemoryUsage::Upload);
mapped[i] = buffers[i].Mapped().data();
}
size = bytes;
align = alignment ? alignment : 256;
head = 0;
current_frame = 0;
}
std::span<u8> BufferCacheRuntime::UniformRing::Alloc(u32 bytes, u32& out_offset) {
const u64 aligned = Common::AlignUp(head, static_cast<u64>(align));
u64 end = aligned + bytes;
if (end > size) {
return {}; // Fallback to staging pool
}
out_offset = static_cast<u32>(aligned);
head = end;
return {mapped[current_frame] + out_offset, bytes};
}
u64 BufferCacheRuntime::GetDeviceLocalMemory() const {
return device.GetDeviceLocalMemory();
}
@ -375,6 +416,7 @@ void BufferCacheRuntime::TickFrame(Common::SlotVector<Buffer>& slot_buffers) noe
for (auto it = slot_buffers.begin(); it != slot_buffers.end(); it++) {
it->ResetUsageTracking();
}
uniform_ring.BeginFrame();
}
void BufferCacheRuntime::Finish() {

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -124,8 +127,15 @@ public:
void BindTransformFeedbackBuffers(VideoCommon::HostBindings<Buffer>& bindings);
std::span<u8> BindMappedUniformBuffer([[maybe_unused]] size_t stage,
[[maybe_unused]] u32 binding_index, u32 size) {
std::span<u8> BindMappedUniformBuffer([[maybe_unused]] size_t /*stage*/,
[[maybe_unused]] u32 /*binding_index*/,
u32 size) {
u32 offset = 0;
if (auto span = uniform_ring.Alloc(size, offset); !span.empty()) {
BindBuffer(*uniform_ring.buffers[uniform_ring.current_frame], offset, size);
return span;
}
// Fallback for giant requests
const StagingBufferRef ref = staging_pool.Request(size, MemoryUsage::Upload);
BindBuffer(ref.buffer, static_cast<u32>(ref.offset), size);
return ref.mapped_span;
@ -153,6 +163,24 @@ private:
void ReserveNullBuffer();
vk::Buffer CreateNullBuffer();
struct UniformRing {
static constexpr size_t NUM_FRAMES = 3;
std::array<vk::Buffer, NUM_FRAMES> buffers{};
std::array<u8*, NUM_FRAMES> mapped{};
u64 size = 0;
u64 head = 0;
u32 align = 256;
size_t current_frame = 0;
void Init(const Device& device, MemoryAllocator& alloc, u64 bytes, u32 alignment);
void BeginFrame() {
current_frame = (current_frame + 1) % NUM_FRAMES;
head = 0;
}
std::span<u8> Alloc(u32 bytes, u32& out_offset);
};
UniformRing uniform_ring;
const Device& device;
MemoryAllocator& memory_allocator;
Scheduler& scheduler;

View file

@ -33,29 +33,19 @@ constexpr VkDeviceSize MAX_STREAM_BUFFER_SIZE = 128_MiB;
size_t GetStreamBufferSize(const Device& device) {
VkDeviceSize size{0};
if (device.HasDebuggingToolAttached()) {
bool found_heap = false;
ForEachDeviceLocalHostVisibleHeap(device, [&size, &found_heap](size_t /*index*/, VkMemoryHeap& heap) {
ForEachDeviceLocalHostVisibleHeap(device, [&size](size_t index, VkMemoryHeap& heap) {
size = (std::max)(size, heap.size);
found_heap = true;
});
// If no suitable heap was found fall back to the default cap to avoid creating a zero-sized stream buffer.
if (!found_heap) {
size = MAX_STREAM_BUFFER_SIZE;
} else if (size <= 256_MiB) {
// If rebar is not supported, cut the max heap size to 40%. This will allow 2 captures to be
// loaded at the same time in RenderDoc. If rebar is supported, this shouldn't be an issue
// as the heap will be much larger.
// If rebar is not supported, cut the max heap size to 40%. This will allow 2 captures to be
// loaded at the same time in RenderDoc. If rebar is supported, this shouldn't be an issue
// as the heap will be much larger.
if (size <= 256_MiB) {
size = size * 40 / 100;
}
} else {
size = MAX_STREAM_BUFFER_SIZE;
}
// Clamp to the configured maximum, align up for safety, and ensure a sane minimum so
// region_size (stream_buffer_size / NUM_SYNCS) never becomes zero.
const VkDeviceSize aligned = (std::min)(Common::AlignUp(size, MAX_ALIGNMENT), MAX_STREAM_BUFFER_SIZE);
const VkDeviceSize min_size = MAX_ALIGNMENT * StagingBufferPool::NUM_SYNCS;
return static_cast<size_t>((std::max)(aligned, min_size));
return (std::min)(Common::AlignUp(size, MAX_ALIGNMENT), MAX_STREAM_BUFFER_SIZE);
}
} // Anonymous namespace
@ -116,53 +106,31 @@ void StagingBufferPool::TickFrame() {
}
StagingBufferRef StagingBufferPool::GetStreamBuffer(size_t size) {
const size_t aligned_size = Common::AlignUp(size, MAX_ALIGNMENT);
const bool wraps = iterator + size >= stream_buffer_size;
const size_t new_iterator =
wraps ? aligned_size : Common::AlignUp(iterator + size, MAX_ALIGNMENT);
const size_t begin_region = wraps ? 0 : Region(iterator);
const size_t last_byte = new_iterator == 0 ? 0 : new_iterator - 1;
const size_t end_region = (std::min)(Region(last_byte) + 1, NUM_SYNCS);
const size_t guard_begin = (std::min)(Region(free_iterator) + 1, NUM_SYNCS);
if (!wraps) {
if (guard_begin < end_region && AreRegionsActive(guard_begin, end_region)) {
// Avoid waiting for the previous usages to be free
return GetStagingBuffer(size, MemoryUsage::Upload);
}
} else if (guard_begin < NUM_SYNCS && AreRegionsActive(guard_begin, NUM_SYNCS)) {
if (AreRegionsActive(Region(free_iterator) + 1,
(std::min)(Region(iterator + size) + 1, NUM_SYNCS))) {
// Avoid waiting for the previous usages to be free
return GetStagingBuffer(size, MemoryUsage::Upload);
}
const u64 current_tick = scheduler.CurrentTick();
std::fill(sync_ticks.begin() + Region(used_iterator), sync_ticks.begin() + Region(iterator),
current_tick);
used_iterator = iterator;
free_iterator = (std::max)(free_iterator, iterator + size);
if (wraps) {
if (iterator + size >= stream_buffer_size) {
std::fill(sync_ticks.begin() + Region(used_iterator), sync_ticks.begin() + NUM_SYNCS,
current_tick);
used_iterator = 0;
iterator = 0;
free_iterator = size;
const size_t head_last_byte = aligned_size == 0 ? 0 : aligned_size - 1;
const size_t head_end_region = (std::min)(Region(head_last_byte) + 1, NUM_SYNCS);
if (AreRegionsActive(0, head_end_region)) {
if (AreRegionsActive(0, Region(size) + 1)) {
// Avoid waiting for the previous usages to be free
return GetStagingBuffer(size, MemoryUsage::Upload);
}
}
std::fill(sync_ticks.begin() + begin_region, sync_ticks.begin() + end_region, current_tick);
const size_t offset = wraps ? 0 : iterator;
iterator = new_iterator;
if (!wraps) {
free_iterator = (std::max)(free_iterator, offset + size);
}
const size_t offset = iterator;
iterator = Common::AlignUp(iterator + size, MAX_ALIGNMENT);
return StagingBufferRef{
.buffer = *stream_buffer,
.offset = static_cast<VkDeviceSize>(offset),

View file

@ -393,16 +393,8 @@ target_link_libraries(yuzu PRIVATE common core input_common frontend_common netw
target_link_libraries(yuzu PRIVATE Boost::headers glad Qt6::Widgets)
target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads)
if (NOT WIN32)
target_include_directories(yuzu PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS})
endif()
if (UNIX AND NOT APPLE)
target_link_libraries(yuzu PRIVATE Qt6::DBus)
if (TARGET Qt6::GuiPrivate)
target_link_libraries(yuzu PRIVATE Qt6::GuiPrivate)
endif()
endif()
target_compile_definitions(yuzu PRIVATE

View file

@ -83,8 +83,7 @@ void ConfigureDebug::SetConfiguration() {
#ifdef YUZU_USE_QT_WEB_ENGINE
ui->disable_web_applet->setChecked(UISettings::values.disable_web_applet.GetValue());
#else
ui->disable_web_applet->setEnabled(false);
ui->disable_web_applet->setText(tr("Web applet not compiled"));
ui->disable_web_applet->setVisible(false);
#endif
}