& mask,
const UniformBufferSizes* sizes) {
- if constexpr (HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS) {
- if (channel_state->enabled_uniform_buffer_masks != mask) {
- if constexpr (IS_OPENGL) {
- channel_state->fast_bound_uniform_buffers.fill(0);
- }
+ const bool mask_changed = channel_state->enabled_uniform_buffer_masks != mask;
+ if (mask_changed) {
+ channel_state->fast_bound_uniform_buffers.fill(0);
+ if constexpr (HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS) {
channel_state->dirty_uniform_buffers.fill(~u32{0});
channel_state->uniform_buffer_binding_sizes.fill({});
}
@@ -806,7 +805,7 @@ void BufferCache::BindHostGraphicsUniformBuffer(size_t stage, u32 index, u32
channel_state->uniform_buffer_binding_sizes[stage][binding_index] != size;
if (should_fast_bind) {
// We only have to bind when the currently bound buffer is not the fast version
- channel_state->fast_bound_uniform_buffers[stage] |= 1U << binding_index;
+ channel_state->fast_bound_uniform_buffers[stage] |= 1u << binding_index;
channel_state->uniform_buffer_binding_sizes[stage][binding_index] = size;
runtime.BindFastUniformBuffer(stage, binding_index, size);
}
@@ -815,13 +814,22 @@ void BufferCache
::BindHostGraphicsUniformBuffer(size_t stage, u32 index, u32
return;
}
}
- if constexpr (IS_OPENGL) {
- channel_state->fast_bound_uniform_buffers[stage] |= 1U << binding_index;
- channel_state->uniform_buffer_binding_sizes[stage][binding_index] = size;
- }
+ channel_state->fast_bound_uniform_buffers[stage] |= 1u << binding_index;
+ channel_state->uniform_buffer_binding_sizes[stage][binding_index] = size;
// Stream buffer path to avoid stalling on non-Nvidia drivers or Vulkan
const std::span span = runtime.BindMappedUniformBuffer(stage, binding_index, size);
+#ifdef YUZU_DEBUG
+ ASSERT(binding_index < NUM_GRAPHICS_UNIFORM_BUFFERS);
+ ASSERT(span.size() >= size && "UBO stream span too small");
+ if (!device_memory.ReadBlockFastChecked(device_addr, span.data(), size)) {
+ LOG_CRITICAL(Render, "DeviceMemory OOB/unmapped: addr=0x{:x} size={}", device_addr, size);
+ channel_state->fast_bound_uniform_buffers[stage] &= ~(1u << binding_index);
+ ASSERT(false);
+ return;
+ }
+#else
device_memory.ReadBlockUnsafe(device_addr, span.data(), size);
+#endif
return;
}
// Classic cached path
@@ -830,7 +838,8 @@ void BufferCache::BindHostGraphicsUniformBuffer(size_t stage, u32 index, u32
}
// Skip binding if it's not needed and if the bound buffer is not the fast version
// This exists to avoid instances where the fast buffer is bound and a GPU write happens
- needs_bind |= HasFastUniformBufferBound(stage, binding_index);
+ const bool was_fast_bound = HasFastUniformBufferBound(stage, binding_index);
+ needs_bind |= was_fast_bound;
if constexpr (HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS) {
needs_bind |= channel_state->uniform_buffer_binding_sizes[stage][binding_index] != size;
}
@@ -839,9 +848,6 @@ void BufferCache
::BindHostGraphicsUniformBuffer(size_t stage, u32 index, u32
}
const u32 offset = buffer.Offset(device_addr);
if constexpr (IS_OPENGL) {
- // Fast buffer will be unbound
- channel_state->fast_bound_uniform_buffers[stage] &= ~(1U << binding_index);
-
// Mark the index as dirty if offset doesn't match
const bool is_copy_bind = offset != 0 && !runtime.SupportsNonZeroUniformOffset();
channel_state->dirty_uniform_buffers[stage] |= (is_copy_bind ? 1U : 0U) << index;
@@ -855,6 +861,7 @@ void BufferCache
::BindHostGraphicsUniformBuffer(size_t stage, u32 index, u32
} else {
runtime.BindUniformBuffer(buffer, offset, size);
}
+ channel_state->fast_bound_uniform_buffers[stage] &= ~(1u << binding_index);
}
template
@@ -1789,12 +1796,7 @@ std::span BufferCache::ImmediateBuffer(size_t wanted_capacity) {
template
bool BufferCache::HasFastUniformBufferBound(size_t stage, u32 binding_index) const noexcept {
- if constexpr (IS_OPENGL) {
- return ((channel_state->fast_bound_uniform_buffers[stage] >> binding_index) & 1) != 0;
- } else {
- // Only OpenGL has fast uniform buffers
- return false;
- }
+ return ((channel_state->fast_bound_uniform_buffers[stage] >> binding_index) & 1u) != 0;
}
template
diff --git a/src/video_core/buffer_cache/buffer_cache_base.h b/src/video_core/buffer_cache/buffer_cache_base.h
index 486d19fb79..09631ffd83 100644
--- a/src/video_core/buffer_cache/buffer_cache_base.h
+++ b/src/video_core/buffer_cache/buffer_cache_base.h
@@ -53,6 +53,7 @@ constexpr u32 NUM_COMPUTE_UNIFORM_BUFFERS = 8;
constexpr u32 NUM_STORAGE_BUFFERS = 16;
constexpr u32 NUM_TEXTURE_BUFFERS = 32;
constexpr u32 NUM_STAGES = 5;
+static_assert(NUM_GRAPHICS_UNIFORM_BUFFERS <= 32, "fast bitmask must fit u32");
using UniformBufferSizes = std::array, NUM_STAGES>;
using ComputeUniformBufferSizes = std::array;
@@ -137,8 +138,8 @@ public:
u32 written_compute_texture_buffers = 0;
u32 image_compute_texture_buffers = 0;
- std::array uniform_cache_hits{};
- std::array uniform_cache_shots{};
+ std::array uniform_cache_hits{};
+ std::array uniform_cache_shots{};
u32 uniform_buffer_skip_cache_size = DEFAULT_SKIP_CACHE_SIZE;
diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp
index ecc4f77dc7..0fbe707b04 100644
--- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp
+++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp
@@ -25,12 +25,12 @@ namespace {
using namespace Common::Literals;
-// Maximum potential alignment of a Vulkan buffer
-constexpr VkDeviceSize MAX_ALIGNMENT = 256;
+// Minimum alignment we want to enforce for the streaming ring
+constexpr VkDeviceSize MIN_STREAM_ALIGNMENT = 256;
// Stream buffer size in bytes
constexpr VkDeviceSize MAX_STREAM_BUFFER_SIZE = 128_MiB;
-size_t GetStreamBufferSize(const Device& device) {
+size_t GetStreamBufferSize(const Device& device, VkDeviceSize alignment) {
VkDeviceSize size{0};
if (device.HasDebuggingToolAttached()) {
bool found_heap = false;
@@ -53,8 +53,9 @@ size_t GetStreamBufferSize(const Device& device) {
// 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;
+ const VkDeviceSize aligned =
+ (std::min)(Common::AlignUp(size, alignment), MAX_STREAM_BUFFER_SIZE);
+ const VkDeviceSize min_size = alignment * StagingBufferPool::NUM_SYNCS;
return static_cast((std::max)(aligned, min_size));
}
} // Anonymous namespace
@@ -62,8 +63,10 @@ size_t GetStreamBufferSize(const Device& device) {
StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& memory_allocator_,
Scheduler& scheduler_)
: device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_},
- stream_buffer_size{GetStreamBufferSize(device)}, region_size{stream_buffer_size /
- StagingBufferPool::NUM_SYNCS} {
+ stream_alignment{std::max(device_.GetUniformBufferAlignment(),
+ MIN_STREAM_ALIGNMENT)},
+ stream_buffer_size{GetStreamBufferSize(device_, stream_alignment)},
+ region_size{stream_buffer_size / StagingBufferPool::NUM_SYNCS} {
VkBufferCreateInfo stream_ci = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr,
@@ -116,10 +119,11 @@ void StagingBufferPool::TickFrame() {
}
StagingBufferRef StagingBufferPool::GetStreamBuffer(size_t size) {
- const size_t aligned_size = Common::AlignUp(size, MAX_ALIGNMENT);
+ const size_t alignment = static_cast(stream_alignment);
+ const size_t aligned_size = Common::AlignUp(size, alignment);
const bool wraps = iterator + size >= stream_buffer_size;
const size_t new_iterator =
- wraps ? aligned_size : Common::AlignUp(iterator + size, MAX_ALIGNMENT);
+ wraps ? aligned_size : Common::AlignUp(iterator + size, 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);
@@ -145,7 +149,7 @@ StagingBufferRef StagingBufferPool::GetStreamBuffer(size_t size) {
current_tick);
used_iterator = 0;
iterator = 0;
- free_iterator = size;
+ free_iterator = aligned_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)) {
@@ -160,7 +164,7 @@ StagingBufferRef StagingBufferPool::GetStreamBuffer(size_t size) {
iterator = new_iterator;
if (!wraps) {
- free_iterator = (std::max)(free_iterator, offset + size);
+ free_iterator = (std::max)(free_iterator, offset + aligned_size);
}
return StagingBufferRef{
diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h
index f63a203272..5c40ca069f 100644
--- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h
+++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
@@ -102,6 +105,7 @@ private:
MemoryAllocator& memory_allocator;
Scheduler& scheduler;
+ VkDeviceSize stream_alignment;
vk::Buffer stream_buffer;
std::span stream_pointer;
VkDeviceSize stream_buffer_size;
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index 010a3db174..f4669d0914 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -393,7 +393,7 @@ endif()
target_link_libraries(yuzu PRIVATE nlohmann_json::nlohmann_json)
target_link_libraries(yuzu PRIVATE common core input_common frontend_common network video_core qt_common)
-target_link_libraries(yuzu PRIVATE Boost::headers glad Qt6::Widgets Qt6::Concurrent)
+target_link_libraries(yuzu PRIVATE Boost::headers glad Qt6::Widgets)
target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads)
if (NOT WIN32)
@@ -408,6 +408,25 @@ if (UNIX AND NOT APPLE)
endif()
endif()
+target_compile_definitions(yuzu PRIVATE
+ # Use QStringBuilder for string concatenation to reduce
+ # the overall number of temporary strings created.
+ QT_USE_QSTRINGBUILDER
+
+ # Disable implicit conversions from/to C strings
+ QT_NO_CAST_FROM_ASCII
+ QT_NO_CAST_TO_ASCII
+
+ # Disable implicit type narrowing in signal/slot connect() calls.
+ QT_NO_NARROWING_CONVERSIONS_IN_CONNECT
+
+ # Disable unsafe overloads of QProcess' start() function.
+ QT_NO_PROCESS_COMBINED_ARGUMENT_START
+
+ # Disable implicit QString->QUrl conversions to enforce use of proper resolving functions.
+ QT_NO_URL_CAST_FROM_STRING
+)
+
if (YUZU_ENABLE_COMPATIBILITY_REPORTING)
target_compile_definitions(yuzu PRIVATE YUZU_ENABLE_COMPATIBILITY_REPORTING)
endif()
diff --git a/src/yuzu/compatdb.cpp b/src/yuzu/compatdb.cpp
index 6d5d263e16..0e58f17405 100644
--- a/src/yuzu/compatdb.cpp
+++ b/src/yuzu/compatdb.cpp
@@ -1,13 +1,10 @@
-// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
-// SPDX-License-Identifier: GPL-3.0-or-later
-
// SPDX-FileCopyrightText: 2017 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include
#include
#include
-#include
+#include
#include "common/logging/log.h"
#include "ui_compatdb.h"
#include "yuzu/compatdb.h"
diff --git a/src/yuzu/configuration/configure_web.cpp b/src/yuzu/configuration/configure_web.cpp
index 7a693be10c..15a0029901 100644
--- a/src/yuzu/configuration/configure_web.cpp
+++ b/src/yuzu/configuration/configure_web.cpp
@@ -14,7 +14,7 @@
#include
#endif
-#include
+#include
#include "common/settings.h"
#include "ui_configure_web.h"
#include "qt_common/uisettings.h"
diff --git a/src/yuzu/data_dialog.cpp b/src/yuzu/data_dialog.cpp
index d7c937e7ed..87d81e4f43 100644
--- a/src/yuzu/data_dialog.cpp
+++ b/src/yuzu/data_dialog.cpp
@@ -4,16 +4,12 @@
#include "data_dialog.h"
#include "frontend_common/data_manager.h"
#include "qt_common/qt_content_util.h"
-#include "qt_common/qt_frontend_util.h"
-#include "qt_common/qt_progress_dialog.h"
#include "qt_common/qt_string_lookup.h"
#include "ui_data_dialog.h"
#include
-#include
#include
-#include
-#include
+#include
DataDialog::DataDialog(QWidget *parent)
: QDialog(parent)
@@ -53,41 +49,25 @@ DataWidget::DataWidget(FrontendCommon::DataManager::DataDir data_dir,
ui->tooltip->setText(QtCommon::StringLookup::Lookup(tooltip));
- ui->clear->setIcon(QIcon::fromTheme(QStringLiteral("user-trash")));
+ ui->clear->setIcon(QIcon::fromTheme(QStringLiteral("trash")));
ui->open->setIcon(QIcon::fromTheme(QStringLiteral("folder")));
- ui->upload->setIcon(QIcon::fromTheme(QStringLiteral("upload")));
- ui->download->setIcon(QIcon::fromTheme(QStringLiteral("download")));
connect(ui->clear, &QPushButton::clicked, this, &DataWidget::clear);
connect(ui->open, &QPushButton::clicked, this, &DataWidget::open);
- connect(ui->upload, &QPushButton::clicked, this, &DataWidget::upload);
- connect(ui->download, &QPushButton::clicked, this, &DataWidget::download);
scan();
}
-void DataWidget::clear()
-{
+void DataWidget::clear() {
QtCommon::Content::ClearDataDir(m_dir);
scan();
}
-void DataWidget::open()
-{
+void DataWidget::open() {
QDesktopServices::openUrl(QUrl::fromLocalFile(
QString::fromStdString(FrontendCommon::DataManager::GetDataDir(m_dir))));
}
-void DataWidget::upload()
-{
- QtCommon::Content::ExportDataDir(m_dir);
-}
-
-void DataWidget::download()
-{
- QtCommon::Content::ImportDataDir(m_dir, std::bind(&DataWidget::scan, this));
-}
-
void DataWidget::scan() {
ui->size->setText(tr("Calculating..."));
diff --git a/src/yuzu/data_dialog.h b/src/yuzu/data_dialog.h
index 8a64659965..9f367d6049 100644
--- a/src/yuzu/data_dialog.h
+++ b/src/yuzu/data_dialog.h
@@ -37,9 +37,6 @@ public:
public slots:
void clear();
void open();
- void upload();
- void download();
-
void scan();
private:
diff --git a/src/yuzu/data_widget.ui b/src/yuzu/data_widget.ui
index 99010d8856..ed67078fa1 100644
--- a/src/yuzu/data_widget.ui
+++ b/src/yuzu/data_widget.ui
@@ -13,8 +13,8 @@
Form
-
- -
+
+
-
-
@@ -50,8 +50,14 @@
- -
-
+
-
+
+
+ QLayout::SizeConstraint::SetFixedSize
+
+
+ 25
+
-
@@ -63,7 +69,7 @@
52
- 47
+ 42
@@ -71,10 +77,14 @@
QPushButton {
-max-width: 50px;
-max-height: 45px;
-min-width: 50px;
-min-height: 45px;
+ border-style: solid;
+ border-width:1px;
+ border-radius:25px;
+ border-color: transparent;
+ max-width:50px;
+ max-height:40px;
+ min-width:50px;
+ min-height:40px;
}
@@ -82,8 +92,8 @@ min-height: 45px;
- 28
- 28
+ 24
+ 24
@@ -99,7 +109,7 @@ min-height: 45px;
52
- 47
+ 42
@@ -107,10 +117,14 @@ min-height: 45px;
QPushButton {
-max-width: 50px;
-max-height: 45px;
-min-width: 50px;
-min-height: 45px;
+ border-style: solid;
+ border-width:1px;
+ border-radius:25px;
+ border-color: transparent;
+ max-width:50px;
+ max-height:40px;
+ min-width:50px;
+ min-height:40px;
}
@@ -118,80 +132,8 @@ min-height: 45px;
- 28
- 28
-
-
-
-
- -
-
-
-
- 1
- 1
-
-
-
-
- 52
- 47
-
-
-
- Export all data in this directory. This may take a while!
-
-
- QPushButton {
-max-width: 50px;
-max-height: 45px;
-min-width: 50px;
-min-height: 45px;
-}
-
-
-
-
-
-
- 28
- 28
-
-
-
-
- -
-
-
-
- 1
- 1
-
-
-
-
- 52
- 47
-
-
-
- Import data for this directory. This may take a while, and will delete ALL EXISTING DATA!
-
-
- QPushButton {
-max-width: 50px;
-max-height: 45px;
-min-width: 50px;
-min-height: 45px;
-}
-
-
-
-
-
-
- 28
- 28
+ 24
+ 24
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 21c92c495f..b6dded447c 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -3939,10 +3939,6 @@ void GMainWindow::OnEdenDependencies() {
void GMainWindow::OnDataDialog() {
DataDialog dataDialog(this);
dataDialog.exec();
-
- // refresh stuff in case it was cleared
- OnGameListRefresh();
-
}
void GMainWindow::OnToggleFilterBar() {
@@ -4485,15 +4481,11 @@ void GMainWindow::SetFirmwareVersion() {
if (result.IsError() || !CheckFirmwarePresence()) {
LOG_INFO(Frontend, "Installed firmware: No firmware available");
- ui->menu_Applets->setEnabled(false);
- ui->menu_Create_Shortcuts->setEnabled(false);
firmware_label->setVisible(false);
return;
}
firmware_label->setVisible(true);
- ui->menu_Applets->setEnabled(true);
- ui->menu_Create_Shortcuts->setEnabled(true);
const std::string display_version(firmware_data.display_version.data());
const std::string display_title(firmware_data.display_title.data());
diff --git a/src/yuzu/multiplayer/chat_room.cpp b/src/yuzu/multiplayer/chat_room.cpp
index 53beda0f8e..4c2c41ea2a 100644
--- a/src/yuzu/multiplayer/chat_room.cpp
+++ b/src/yuzu/multiplayer/chat_room.cpp
@@ -16,7 +16,7 @@
#include
#include
#include
-#include
+#include
#include "common/logging/log.h"
#include "network/announce_multiplayer_session.h"
#include "ui_chat_room.h"
diff --git a/src/yuzu/multiplayer/client_room.cpp b/src/yuzu/multiplayer/client_room.cpp
index 4e995c044f..93d6662c1e 100644
--- a/src/yuzu/multiplayer/client_room.cpp
+++ b/src/yuzu/multiplayer/client_room.cpp
@@ -10,7 +10,7 @@
#include
#include
#include
-#include
+#include
#include "common/logging/log.h"
#include "network/announce_multiplayer_session.h"
#include "ui_client_room.h"
diff --git a/src/yuzu/multiplayer/direct_connect.cpp b/src/yuzu/multiplayer/direct_connect.cpp
index 6291979fe6..deac3b9e59 100644
--- a/src/yuzu/multiplayer/direct_connect.cpp
+++ b/src/yuzu/multiplayer/direct_connect.cpp
@@ -9,7 +9,7 @@
#include
#include
#include
-#include
+#include
#include "common/settings.h"
#include "core/core.h"
#include "core/internal_network/network_interface.h"
diff --git a/src/yuzu/multiplayer/host_room.cpp b/src/yuzu/multiplayer/host_room.cpp
index cc163a5420..4dd3958550 100644
--- a/src/yuzu/multiplayer/host_room.cpp
+++ b/src/yuzu/multiplayer/host_room.cpp
@@ -12,7 +12,7 @@
#include
#include
#include
-#include
+#include
#include "common/logging/log.h"
#include "common/settings.h"
#include "core/core.h"
diff --git a/src/yuzu/multiplayer/lobby.cpp b/src/yuzu/multiplayer/lobby.cpp
index e8daa0c6eb..84723041df 100644
--- a/src/yuzu/multiplayer/lobby.cpp
+++ b/src/yuzu/multiplayer/lobby.cpp
@@ -6,7 +6,7 @@
#include
#include
-#include
+#include
#include "common/logging/log.h"
#include "common/settings.h"
#include "core/core.h"