Compare commits

..

1 Commits

Author SHA1 Message Date
Eden CI bc50cc3988 Update dependencies
* openssl-cmake: 3.6.2 -> 4.0.1
* openssl: 3.6.2 -> 4.0.1
* boost: 1.90.0 -> 1.91.0
* fmt: 12.1.0 -> 12.2.0
* vulkan-validation-layers: 1.4.341.0 -> 1.4.350.1
* vulkan-memory-allocator: 3.3.0 -> 3.4.0
* httplib: 0.46.0 -> 0.48.0
* xbyak: 7.35.2 -> 7.37.4
* catch2: 3.13.0 -> 3.15.1
* simpleini: 4.25 -> 4.26
* sdl3: 3.4.8 -> 3.4.10
* libusb: 1.0.29 -> 1.0.30
* vulkan-headers: 1.4.345 -> 1.4.354
* vulkan-utility-libraries: 1.4.345 -> 1.4.354
2026-06-20 08:01:14 -04:00
25 changed files with 105 additions and 385 deletions
+10 -10
View File
@@ -9,8 +9,8 @@
},
"openssl-cmake": {
"repo": "jimmy-park/openssl-cmake",
"hash": "2cc185c924fd70e7d886257ca0caa42b3b8f7f712f2052b4f94dde74759e27022de76178460e18c9bdfc57c366583999e198fbb6052d4e7d91c099d15a0ca63e",
"git_version": "3.6.2",
"hash": "bc73a6c035f299711bb90e20b16fa3521e8ffdab32d8d17f9e7f5cde1ff5def37ec6f9e03de25c3466d18885815c0874331f56e592b8a2f7deeb484c69c5c621",
"git_version": "4.0.1",
"tag": "%VERSION%",
"bundled": true,
"options": [
@@ -28,8 +28,8 @@
"package": "OpenSSL",
"min_version": "3",
"version": "3",
"hash": "29002ce50cb95a4f4f1d0e9d3f684401fbd4eac34203dc2eef3b6334af5d44aa46bf788b63a6f5c139c383eafb7269ae87a58a9a3ad5912903b9773e545ccc0a",
"git_version": "3.6.2",
"hash": "2405891660b67e4cc01c7868e100f2766e1c6290120213ae62f775ef3d9610c3527bdc43d4c831260417450c74353b0693ae3e24cca3e99b02e4daa548b93904",
"git_version": "4.0.1",
"tag": "openssl-%VERSION%",
"patches": [
"0001-add-bundled-cert.patch"
@@ -40,8 +40,8 @@
"repo": "boostorg/boost",
"tag": "boost-%VERSION%",
"artifact": "%TAG%-cmake.tar.xz",
"hash": "6ae6e94664fe7f2fb01976b59b276ac5df8085c7503fa829d810fbfe495960cfec44fa2c36e2cb23480bc19c956ed199d4952b02639a00a6c07625d4e7130c2d",
"git_version": "1.90.0",
"hash": "935b3d516e996f6d25948ba8a54c1b7f70f7f0e3f517e36481fdf0196c2c5cfc2841f86e891f3df9517746b7fb605db47cdded1b8ff78d9482ddaa621db43a34",
"git_version": "1.91.0",
"version": "1.57",
"find_args": "CONFIG OPTIONAL_COMPONENTS headers context system fiber filesystem",
"patches": [
@@ -51,9 +51,9 @@
"fmt": {
"repo": "fmtlib/fmt",
"tag": "%VERSION%",
"hash": "f0da82c545b01692e9fd30fdfb613dbb8dd9716983dcd0ff19ac2a8d36f74beb5540ef38072fdecc1e34191b3682a8542ecbf3a61ef287dbba0a2679d4e023f2",
"hash": "5ac2ba0f54a484999ed5407d82b77aad170cea49a267decd2c0eedadf3b14413e2a83fcc8e9ca9c16640595e019b8636e160f72314d8be50653324e82ac745eb",
"version": "8",
"git_version": "12.1.0"
"git_version": "12.2.0"
},
"lz4": {
"name": "lz4",
@@ -126,9 +126,9 @@
"package": "VVL",
"repo": "KhronosGroup/Vulkan-ValidationLayers",
"tag": "vulkan-sdk-%VERSION%",
"git_version": "1.4.341.0",
"git_version": "1.4.350.1",
"artifact": "android-binaries-%VERSION%.zip",
"hash": "8812ae84cbe49e6a3418ade9c458d3be6d74a3dffd319d4502007b564d580998056e8190414368ec11b27bc83993c7a0dad713c31bcc3d9553b51243efee3753"
"hash": "1888eaaa4f0ccd7f3d1f0c6485ae5508f39e7b402ea8486d8243756d63073def569ddee75ea40b403cbfcb2ead515c410d2ff16ae48d8a4d6b4fbacbd78e24e4"
},
"quazip": {
"package": "QuaZip-Qt6",
+18 -18
View File
@@ -3,9 +3,9 @@
"package": "VulkanMemoryAllocator",
"repo": "GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator",
"tag": "v%VERSION%",
"hash": "deb5902ef8db0e329fbd5f3f4385eb0e26bdd9f14f3a2334823fb3fe18f36bc5d235d620d6e5f6fe3551ec3ea7038638899db8778c09f6d5c278f5ff95c3344b",
"hash": "563acbcd8912d10d92c23715eba7acf0e7c1683af36021f415b36f359c2cce065f3906e395c32282a8410ec5c8179fbcb6412935c6629a49357475d4b4410e2a",
"find_args": "CONFIG",
"git_version": "3.3.0"
"git_version": "3.4.0"
},
"sirit": {
"repo": "eden-emulator/sirit",
@@ -28,8 +28,8 @@
"httplib": {
"repo": "yhirose/cpp-httplib",
"tag": "v%VERSION%",
"hash": "159ed94965018f2a371d45a3bfc1961e5fb1549e501ded70a6b4532d7fe99d0579c18b5195aff6e35f96f399b426cea2650ec9fb75ef80d4c9edeccb51f2e6c9",
"git_version": "0.46.0",
"hash": "bc9474b0069b84b33f96790d48cee5b52eb1b9555ea6321ce878679c4469f1c56b87b34e74786e47d09cad5a00539cdd6726058bd0ffb2087255f02d7bdabe51",
"git_version": "0.48.0",
"find_args": "MODULE GLOBAL",
"patches": [
"0001-mingw.patch"
@@ -56,8 +56,8 @@
"package": "xbyak",
"repo": "herumi/xbyak",
"tag": "v%VERSION%",
"hash": "b6475276b2faaeb315734ea8f4f8bd87ededcee768961b39679bee547e7f3e98884d8b7851e176d861dab30a80a76e6ea302f8c111483607dde969b4797ea95a",
"git_version": "7.35.2"
"hash": "14a0a8e3a768e6256e220b5edfd783de5e89f36736ef62674c8532f2564df03719311db923a08d2c930491632f2f83e486c8264e9997b6394ef59d32cae3070b",
"git_version": "7.37.4"
},
"oaknut": {
"repo": "eden-emulator/oaknut",
@@ -139,9 +139,9 @@
"package": "Catch2",
"repo": "catchorg/Catch2",
"tag": "v%VERSION%",
"hash": "7eea385d79d88a5690cde131fe7ccda97d5c54ea09d6f515000d7bf07c828809d61c1ac99912c1ee507cf933f61c1c47ecdcc45df7850ffa82714034b0fccf35",
"hash": "2e32d3d41e4ef84d927eaaaff0a75eba8fd1e47a5ddeb6007b73934f9d1ac747bf9818d02d2cdfb6343830b5091ba4f3d66efc281fc376a4f0716753dd7c9a97",
"version": "3.0.1",
"git_version": "3.13.0",
"git_version": "3.15.1",
"patches": [
"0001-solaris-isnan-fix.patch"
]
@@ -157,16 +157,16 @@
"package": "SimpleIni",
"repo": "brofield/simpleini",
"tag": "v%VERSION%",
"hash": "b937c18a7b6277d77ca7ebfb216af4984810f77af4c32d101b7685369a4bd5eb61406223f82698e167e6311a728d07415ab59639fdf19eff71ad6dc2abfda989",
"hash": "a62c5748efe2473aae5bddab96ba9114d981a72f5b0d1a44d563daa085d5c231ed8c447794691d9bd67e1e0c6bfb44e4a8736be75fee59967d0c67ce3a59bb6e",
"find_args": "MODULE",
"git_version": "4.25"
"git_version": "4.26"
},
"sdl3": {
"package": "SDL3",
"repo": "libsdl-org/SDL",
"tag": "release-%VERSION%",
"hash": "df5a323af7ac366661a3c0e887969c72584d232f3cc211419d59b0487b620b6b2859d4549c9e8df002ee489290062e466fcfddf7edc0872a37b1f2845e81c0f3",
"git_version": "3.4.8",
"hash": "10a9c1fa4d6891c7387fa694b786a168f86b6e5447c6c522f85b739e33720e106ee879dfa9e6e537d5521b983cfbd4908927c555c4d3412735129a4231e16fe6",
"git_version": "3.4.10",
"version": "3.2.10"
},
"moltenvk": {
@@ -194,9 +194,9 @@
"libusb": {
"repo": "libusb/libusb",
"tag": "v%VERSION%",
"hash": "98c5f7940ff06b25c9aa65aa98e23de4c79a4c1067595f4c73cc145af23a1c286639e1ba11185cd91bab702081f307b973f08a4c9746576dc8d01b3620a3aeb5",
"hash": "3251c9f41e900efa13caf981483f46886c8434bf4c30f3fd3073921b06be9977cebcf4a18f7bc46db86e33d7f19752296377be9050abfb8d887ffeb377864647",
"find_args": "MODULE",
"git_version": "1.0.29",
"git_version": "1.0.30",
"patches": [
"0001-netbsd-gettime.patch"
]
@@ -229,15 +229,15 @@
"repo": "KhronosGroup/Vulkan-Headers",
"package": "VulkanHeaders",
"version": "1.4.317",
"hash": "d2846ea228415772645eea4b52a9efd33e6a563043dd3de059e798be6391a8f0ca089f455ae420ff22574939ed0f48ed7c6ff3d5a9987d5231dbf3b3f89b484b",
"git_version": "1.4.345",
"hash": "9f92c0a5fee856be4104e72180d1914ed819b77f680f8add13282c88239e3d4bf8891a738920b1e38b2f00b121c77120834a87b8c9aae6bf60c11a01b2a58492",
"git_version": "1.4.354",
"tag": "v%VERSION%"
},
"vulkan-utility-libraries": {
"repo": "KhronosGroup/Vulkan-Utility-Libraries",
"package": "VulkanUtilityLibraries",
"hash": "114f6b237a6dcba923ccc576befb5dea3f1c9b3a30de7dc741f234a831d1c2d52d8a224afb37dd57dffca67ac0df461eaaab6a5ab5e503b393f91c166680c3e1",
"git_version": "1.4.345",
"hash": "17a282a5eb72f905254eb62e2a4a4d6cfc3acca79f8323365e55cb9be903f75d752b6112bd016a6bec22690dcef91554cbcb2656130eccfc094ece05db0a445f",
"git_version": "1.4.354",
"tag": "v%VERSION%"
},
"frozen": {
+1 -1
View File
@@ -158,7 +158,7 @@ ENUM(GpuUnswizzleChunk, VeryLow, Low, Normal, Medium, High)
ENUM(TemperatureUnits, Celsius, Fahrenheit)
ENUM(ExtendedDynamicState, Disabled, EDS1, EDS2, EDS3);
ENUM(GpuLogLevel, Off, Errors, Standard, Verbose, All)
ENUM(GameListMode, TreeView, GridView, CarouselView);
ENUM(GameListMode, TreeView, GridView);
ENUM(SpeedMode, Standard, Turbo, Slow);
template <typename Type>
+1 -1
View File
@@ -207,7 +207,7 @@ struct Values {
// Game List
Setting<bool> show_add_ons{linkage, true, "show_add_ons", Category::UiGameList};
Setting<u32, true> game_icon_size{linkage, 64, 0, 512, "game_icon_size", Category::UiGameList};
Setting<u32, true> game_icon_size{linkage, 64, 8, 512, "game_icon_size", Category::UiGameList};
Setting<u32, true> folder_icon_size{linkage, 48, 8, 512, "folder_icon_size", Category::UiGameList};
Setting<u8> row_1_text_id{linkage, 3, "row_1_text_id", Category::UiGameList};
Setting<u8> row_2_text_id{linkage, 2, "row_2_text_id", Category::UiGameList};
-1
View File
@@ -165,7 +165,6 @@ public:
return QStringLiteral("%1\n %2").arg(row1, row2);
}
case Settings::GameListMode::GridView:
case Settings::GameListMode::CarouselView:
return row1;
default:
break;
+26 -22
View File
@@ -1619,33 +1619,36 @@ void BufferCache<P>::TouchBuffer(Buffer& buffer, BufferId buffer_id) noexcept {
template <class P>
bool BufferCache<P>::SynchronizeBuffer(Buffer& buffer, DAddr device_addr, u32 size) {
upload_copies.clear();
u64 total_size_bytes = 0;
u64 staging_offset = 0;
u64 largest_copy = 0;
const DAddr buffer_start = buffer.cpu_addr_cached;
memory_tracker.ForEachUploadRange(device_addr, size, [&](u64 device_addr_out, u64 range_size) {
upload_copies.push_back(BufferCopy{
.src_offset = total_size_bytes,
.dst_offset = device_addr_out - buffer_start,
.size = range_size,
DAddr buffer_start = buffer.CpuAddr();
auto push = [&](u64 start, u64 end) {
if (start >= end) {
return;
}
u64 sz = end - start;
upload_copies.push_back({
.src_offset = staging_offset,
.dst_offset = start - buffer_start,
.size = sz
});
total_size_bytes += range_size;
largest_copy = (std::max)(largest_copy, range_size);
staging_offset += sz;
largest_copy = (std::max)(largest_copy, sz);
};
memory_tracker.ForEachUploadRange(device_addr, size, [&](u64 addr, u64 range_size) {
u64 start = addr;
u64 end = addr + range_size;
gpu_modified_ranges.ForEachInRange(start, range_size, [&](u64 gstart, u64 gsize) {
u64 gend = gstart + gsize;
push(start, gstart);
start = (std::max)(start, gend);
});
push(start, end);
});
if (total_size_bytes == 0) {
if (upload_copies.empty()) {
return true;
}
u64 min_offset = (std::numeric_limits<u64>::max)();
u64 max_offset = 0;
for (const auto& copy : upload_copies) {
min_offset = (std::min)(min_offset, copy.dst_offset);
max_offset = (std::max)(max_offset, copy.dst_offset + copy.size);
}
const DAddr sync_addr = buffer.CpuAddr() + min_offset;
const u64 sync_size = max_offset - min_offset;
DownloadBufferMemory(buffer, sync_addr, sync_size);
const std::span<BufferCopy> copies_span(upload_copies.data(), upload_copies.size());
UploadMemory(buffer, total_size_bytes, largest_copy, copies_span);
any_buffer_uploaded = true;
UploadMemory(buffer, staging_offset, largest_copy, std::span(upload_copies));
return false;
}
@@ -1696,6 +1699,7 @@ void BufferCache<P>::MappedUploadMemory([[maybe_unused]] Buffer& buffer,
u8* const src_pointer = staging_pointer.data() + copy.src_offset;
const DAddr device_addr = buffer.CpuAddr() + copy.dst_offset;
device_memory.ReadBlockUnsafe(device_addr, src_pointer, copy.size);
// Apply the staging offset
copy.src_offset += upload_staging.offset;
}
@@ -62,9 +62,6 @@ void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, DynamicFe
extended_dynamic_state_2_logic_op.Assign(features.has_extended_dynamic_state_2_logic_op ? 1 : 0);
extended_dynamic_state_3_blend.Assign(features.has_extended_dynamic_state_3_blend ? 1 : 0);
extended_dynamic_state_3_enables.Assign(features.has_extended_dynamic_state_3_enables ? 1 : 0);
dynamic_state3_depth_clamp_enable.Assign(features.has_dynamic_state3_depth_clamp_enable ? 1 : 0);
dynamic_state3_logic_op_enable.Assign(features.has_dynamic_state3_logic_op_enable ? 1 : 0);
dynamic_state3_line_stipple_enable.Assign(features.has_dynamic_state3_line_stipple_enable ? 1 : 0);
dynamic_vertex_input.Assign(features.has_dynamic_vertex_input ? 1 : 0);
xfb_enabled.Assign(regs.transform_feedback_enabled != 0);
ndc_minus_one_to_one.Assign(regs.depth_mode == Maxwell::DepthMode::MinusOneToOne ? 1 : 0);
@@ -208,9 +208,6 @@ struct FixedPipelineState {
BitField<12, 2, u32> tessellation_spacing;
BitField<14, 1, u32> tessellation_clockwise;
BitField<15, 5, u32> patch_control_points_minus_one;
BitField<20, 1, u32> dynamic_state3_depth_clamp_enable;
BitField<21, 1, u32> dynamic_state3_logic_op_enable;
BitField<22, 1, u32> dynamic_state3_line_stipple_enable;
BitField<24, 4, Maxwell::PrimitiveTopology> topology;
BitField<28, 4, Tegra::Texture::MsaaMode> msaa_mode;
@@ -907,10 +907,10 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
// EDS3 - Enables (composite: per-feature)
if (key.state.extended_dynamic_state_3_enables) {
if (key.state.dynamic_state3_depth_clamp_enable) {
if (device.SupportsDynamicState3DepthClampEnable()) {
dynamic_states.push_back(VK_DYNAMIC_STATE_DEPTH_CLAMP_ENABLE_EXT);
}
if (key.state.dynamic_state3_logic_op_enable) {
if (device.SupportsDynamicState3LogicOpEnable()) {
dynamic_states.push_back(VK_DYNAMIC_STATE_LOGIC_OP_ENABLE_EXT);
}
if (device.SupportsDynamicState3LineRasterizationMode()) {
@@ -919,7 +919,7 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
if (device.SupportsDynamicState3ConservativeRasterizationMode()) {
dynamic_states.push_back(VK_DYNAMIC_STATE_CONSERVATIVE_RASTERIZATION_MODE_EXT);
}
if (key.state.dynamic_state3_line_stipple_enable) {
if (device.SupportsDynamicState3LineStippleEnable()) {
dynamic_states.push_back(VK_DYNAMIC_STATE_LINE_STIPPLE_ENABLE_EXT);
}
if (device.SupportsDynamicState3AlphaToCoverageEnable()) {
@@ -27,7 +27,6 @@
namespace Vulkan {
constexpr u64 MAX_PENDING_FLUSHES = 5;
void Scheduler::CommandChunk::ExecuteAll(vk::CommandBuffer cmdbuf,
vk::CommandBuffer upload_cmdbuf) {
@@ -116,18 +115,7 @@ Scheduler::Scheduler(const Device& device_, StateTracker& state_tracker_)
Scheduler::~Scheduler() = default;
u64 Scheduler::Flush(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore) {
// Prevent the CPU from getting too far ahead of the GPU by limiting pending flushes.
const bool should_throttle = Settings::IsGPULevelHigh();
if (should_throttle) {
const u64 current_tick = master_semaphore->CurrentTick();
const u64 gap = current_tick > last_submitted_tick ? current_tick - last_submitted_tick : 0;
const u64 step = (std::min)(MAX_PENDING_FLUSHES, gap);
const u64 new_tick = last_submitted_tick + step;
if (new_tick < current_tick) {
last_submitted_tick = new_tick;
master_semaphore->Wait(last_submitted_tick);
}
}
// When flushing, we only send data to the worker thread; no waiting is necessary.
const u64 signal_value = SubmitExecution(signal_semaphore, wait_semaphore);
AllocateNewContext();
return signal_value;
@@ -296,8 +296,6 @@ private:
double last_target_fps{};
u64 max_frame_count{};
u64 frame_counter{};
u64 last_submitted_tick = 0;
};
} // namespace Vulkan
@@ -27,17 +27,8 @@ using namespace Common::Literals;
// Maximum potential alignment of a Vulkan buffer
constexpr VkDeviceSize MAX_ALIGNMENT = 256;
// Stream buffer size in bytes
// *NIX drivers are more sensitive to increased buffers for streaming.
// Windows ones however, can intake bigger buffers and generally do not OOM.
// - GTX 960 on Windows will not OOM with 256mib
// - GT 1030 on ^NIX will OOM with 256mib
#ifdef _WIN32
constexpr VkDeviceSize MAX_STREAM_BUFFER_SIZE = 256_MiB;
#else
constexpr VkDeviceSize MAX_STREAM_BUFFER_SIZE = 128_MiB;
#endif
size_t GetStreamBufferSize(const Device& device) {
if (!device.HasDebuggingToolAttached()) {
@@ -55,13 +46,13 @@ size_t GetStreamBufferSize(const Device& device) {
// 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 <= MAX_STREAM_BUFFER_SIZE) {
if (size <= 256_MiB) {
size = size * 40 / 100;
}
} else {
size = MAX_STREAM_BUFFER_SIZE;
}
return Common::AlignUp(size, MAX_ALIGNMENT);
return (std::min)(Common::AlignUp(size, MAX_ALIGNMENT), MAX_STREAM_BUFFER_SIZE);
}
} // Anonymous namespace
+1 -3
View File
@@ -240,9 +240,7 @@ add_executable(yuzu
render/performance_overlay.h render/performance_overlay.cpp render/performance_overlay.ui
updater/update_dialog.h updater/update_dialog.cpp updater/update_dialog.ui
game/common.h
game/carousel.h game/carousel.cpp
)
game/common.h)
set_target_properties(yuzu PROPERTIES OUTPUT_NAME "eden")
-107
View File
@@ -1,107 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "qt_common/config/uisettings.h"
#include "qt_common/game_list/model.h"
#include "yuzu/game/common.h"
#include "yuzu/game/game_card.h"
#include "yuzu/game/carousel.h"
GameCarousel::GameCarousel(QWidget* parent) : QListView{parent} {
m_gameCard = new GameCard(this);
setItemDelegate(m_gameCard);
setViewMode(QListView::IconMode);
setMovement(QListView::Static);
setUniformItemSizes(true);
setSelectionMode(QAbstractItemView::SingleSelection);
setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setEditTriggers(QAbstractItemView::NoEditTriggers);
setContextMenuPolicy(Qt::CustomContextMenu);
setSpacing(10);
setWordWrap(true);
setTextElideMode(Qt::ElideRight);
setFlow(QListView::LeftToRight);
setWrapping(false);
}
void GameCarousel::SetModel(GameListModel* model) {
QListView::setModel(model);
UpdateIconSize();
}
void GameCarousel::ApplyFilter(const QString& edit_filter_text, GameListModel* model) {
int row_count = model->rowCount();
for (int i = 0; i < row_count; ++i) {
QStandardItem* item = model->item(i, 0);
if (!item)
continue;
if (Yuzu::FilterMatches(edit_filter_text, item)) {
setRowHidden(i, false);
} else {
setRowHidden(i, true);
}
}
}
void GameCarousel::UpdateIconSize() {
const u32 icon_size = UISettings::values.game_icon_size.GetValue();
int heightMargin = 0;
int widthMargin = 80;
// TODO(crueter): get rid of this nonsense
if (UISettings::values.show_game_name) {
switch (icon_size) {
case 128:
heightMargin = 65;
break;
case 0:
widthMargin = 120;
heightMargin = 120;
break;
case 64:
heightMargin = 77;
break;
case 32:
case 256:
heightMargin = 81;
break;
}
} else {
widthMargin = 24;
heightMargin = 24;
}
const int min_item_width = icon_size + widthMargin;
const int min_item_height = icon_size + heightMargin;
const int grid_height = std::max(min_item_height, viewport()->height());
QSize content_size(min_item_width, min_item_height);
QSize grid_size(min_item_width, grid_height);
if (gridSize() != grid_size) {
setUpdatesEnabled(false);
setGridSize(grid_size);
m_gameCard->setSize(grid_size, content_size, 0, 0);
setUpdatesEnabled(true);
}
}
QModelIndex GameCarousel::indexAt(const QPoint& point) const {
QModelIndex index = QListView::indexAt(point);
if (!index.isValid())
return {};
if (m_gameCard && !m_gameCard->hitTest(point, index, this, visualRect(index)))
return {};
return index;
}
-27
View File
@@ -1,27 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <QListView>
#include <QString>
class GameCard;
class GameListModel;
class QResizeEvent;
class GameCarousel : public QListView {
Q_OBJECT
public:
explicit GameCarousel(QWidget* parent = nullptr);
void SetModel(GameListModel* model);
void ApplyFilter(const QString& edit_filter_text, GameListModel* model);
void UpdateIconSize();
QModelIndex indexAt(const QPoint& point) const override;
private:
GameCard* m_gameCard = nullptr;
};
+15 -54
View File
@@ -18,16 +18,27 @@ void GameCard::paint(QPainter* painter, const QStyleOptionViewItem& option,
painter->save();
painter->setRenderHint(QPainter::Antialiasing);
constexpr int cardMargin = 8;
constexpr int cardCornerRadius = 10;
const QRect cardRect = getCardRect(option, index);
const int column = index.row() % m_columns;
const int cell_width = option.rect.width();
const int card_width = cell_width - m_padding;
const int row_width = m_columns * cell_width;
const int total_gap = row_width - cardMargin * 2 - m_columns * card_width;
const int gap = (m_columns > 1) ? (total_gap / (m_columns - 1)) : 0;
const int card_left = option.rect.left() - column * cell_width + cardMargin + column * (card_width + gap) + 4;
const QRect cardRect(card_left, option.rect.top() + 4, card_width - 8,
option.rect.height() - cardMargin);
QPalette palette = option.palette;
QColor backgroundColor = palette.window().color();
QColor borderColor = palette.dark().color();
QColor textColor = palette.text().color();
// highlight on select or hover
// highlight blue on select
if (option.state & QStyle::State_Selected) {
backgroundColor = palette.highlight().color();
borderColor = palette.highlight().color().lighter(150);
@@ -49,7 +60,7 @@ void GameCard::paint(QPainter* painter, const QStyleOptionViewItem& option,
scaled.scale(icon_size, icon_size, Qt::KeepAspectRatio);
iconRect = {cardRect.left() + (cardRect.width() - scaled.width()) / 2,
cardRect.top() + cardMargin - 1, scaled.width(), scaled.height()};
cardRect.top() + cardMargin, scaled.width(), scaled.height()};
painter->setRenderHint(QPainter::SmoothPixmapTransform, true);
@@ -83,62 +94,12 @@ void GameCard::paint(QPainter* painter, const QStyleOptionViewItem& option,
painter->restore();
}
QRect GameCard::getCardRect(const QStyleOptionViewItem& option, const QModelIndex& index) const {
const int cell_width = option.rect.width();
const int card_width = cell_width - m_padding;
int card_left, card_top, card_height;
if (m_columns >= 1) {
// grid mode
// center everything in-line, such that the leftmost and rightmost cards
// have ~ equal padding to the edge of the viewport
// spacing between each card is larger, but equal to each other
const int column = index.row() % m_columns;
const int row_width = m_columns * cell_width;
const int total_gap = row_width - cardMargin * 2 - m_columns * card_width;
const int gap = (m_columns > 1) ? (total_gap / (m_columns - 1)) : 0;
card_left =
option.rect.left() - column * cell_width + cardMargin + column * (card_width + gap) + 4;
// fill cell vertically
card_top = option.rect.top() + cardMargin;
card_height = option.rect.height() - cardMargin - 1;
} else {
// carousel mode
card_left = option.rect.left() + cardMargin + 4;
// the delegate itself takes up the full height, but the card itself
// gets centered
const int content_height = m_contentSize.height() - cardMargin;
const int cell_height = option.rect.height();
card_height = std::min(content_height, cell_height - cardMargin * 2) - 1;
card_top = option.rect.top() + (cell_height - card_height) / 2;
}
return QRect(card_left, card_top, card_width - cardMargin, card_height);
}
bool GameCard::hitTest(const QPoint& point, const QModelIndex& index, const QWidget* widget,
const QRect& cellRect) const {
QStyleOptionViewItem option;
option.initFrom(widget);
option.rect = cellRect;
return getCardRect(option, index).contains(point);
}
QSize GameCard::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const {
return m_size;
}
void GameCard::setSize(const QSize& newSize, const QSize& contentSize, const int padding,
const int columns) {
void GameCard::setSize(const QSize& newSize, const int padding, const int columns) {
m_size = newSize;
m_contentSize = contentSize;
m_padding = padding;
m_columns = columns;
}
+1 -9
View File
@@ -17,19 +17,11 @@ public:
void paint(QPainter* painter, const QStyleOptionViewItem& option,
const QModelIndex& index) const override;
QRect getCardRect(const QStyleOptionViewItem &option, const QModelIndex &index) const;
bool hitTest(const QPoint& point, const QModelIndex& index,
const QWidget* widget, const QRect& cellRect) const;
QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override;
void setSize(const QSize& newSize, const QSize& contentSize, const int padding, const int columns);
void setSize(const QSize& newSize, const int padding, const int columns);
private:
static constexpr int cardMargin = 8;
QSize m_size;
QSize m_contentSize;
int m_padding;
int m_columns;
};
+3 -10
View File
@@ -25,6 +25,8 @@ GameGrid::GameGrid(QWidget* parent) : QListView{parent} {
setEditTriggers(QAbstractItemView::NoEditTriggers);
setContextMenuPolicy(Qt::CustomContextMenu);
setGridSize(QSize(140, 160));
m_gameCard->setSize(gridSize(), 0, 4);
setSpacing(10);
setWordWrap(true);
@@ -95,17 +97,8 @@ void GameGrid::UpdateIconSize() {
setUpdatesEnabled(false);
setGridSize(grid_size);
m_gameCard->setSize(grid_size, grid_size, stretched_width - min_item_width, columns);
m_gameCard->setSize(grid_size, stretched_width - min_item_width, columns);
setUpdatesEnabled(true);
}
}
QModelIndex GameGrid::indexAt(const QPoint& point) const {
QModelIndex index = QListView::indexAt(point);
if (!index.isValid())
return {};
if (m_gameCard && !m_gameCard->hitTest(point, index, this, visualRect(index)))
return {};
return index;
}
+2 -2
View File
@@ -6,6 +6,8 @@
#include <QListView>
#include <QString>
#include "common/common_types.h"
class GameCard;
class GameListModel;
@@ -19,8 +21,6 @@ public:
void ApplyFilter(const QString& edit_filter_text, GameListModel* model);
void UpdateIconSize();
QModelIndex indexAt(const QPoint& point) const override;
private:
GameCard* m_gameCard = nullptr;
};
+13 -58
View File
@@ -20,7 +20,6 @@
#include <QScrollerProperties>
#include <QToolButton>
#include <QVariantAnimation>
#include <qlayoutitem.h>
#include "common/common_types.h"
#include "core/core.h"
@@ -32,7 +31,6 @@
#include "qt_common/qt_common.h"
#include "qt_common/util/game.h"
#include "yuzu/compatibility_list.h"
#include "yuzu/game/carousel.h"
#include "yuzu/game/game_grid.h"
#include "yuzu/game/game_list.h"
#include "yuzu/game/game_tree.h"
@@ -69,9 +67,6 @@ GameList::GameList(FileSys::VirtualFilesystem vfs_, FileSys::ManualContentProvid
connect(grid_view, &QListView::activated, this, &GameList::ValidateEntry);
connect(grid_view, &QListView::customContextMenuRequested, this, &GameList::PopupContextMenu);
connect(carousel_view, &QListView::activated, this, &GameList::ValidateEntry);
connect(carousel_view, &QListView::customContextMenuRequested, this, &GameList::PopupContextMenu);
connect(controller_navigation, &ControllerNavigation::TriggerKeyboardEvent, this,
[this](Qt::Key key) {
if (system.IsPoweredOn()) {
@@ -91,7 +86,6 @@ GameList::GameList(FileSys::VirtualFilesystem vfs_, FileSys::ManualContentProvid
connect(item_model, &GameListModel::SaveConfig, this, &GameList::SaveConfig);
connect(item_model, &GameListModel::PopulatingStarted, this, &GameList::OnPopulate);
// TODO: impl on grid/carousel
connect(tree_view, &GameTree::FilterResultReady, search_field,
[this](int visible, int total) { search_field->setFilterResult(visible, total); });
@@ -107,11 +101,12 @@ GameList::~GameList() {
void GameList::SetupViews() {
tree_view = new GameTree(this);
grid_view = new GameGrid(this);
carousel_view = new GameCarousel(this);
tree_view->SetModel(item_model);
grid_view->SetModel(item_model);
carousel_view->SetModel(item_model);
layout->addWidget(tree_view);
layout->addWidget(grid_view);
}
QString GameList::GetLastFilterResultItem() const {
@@ -143,16 +138,10 @@ void GameList::LoadCompatibilityList() {
void GameList::OnPopulate() {
m_currentView->setEnabled(false);
switch (game_list_mode) {
case Settings::GameListMode::TreeView:
tree_view->UpdateColumnVisibility(item_model);
break;
case Settings::GameListMode::GridView:
if (m_isTreeMode) {
grid_view->UpdateIconSize();
break;
case Settings::GameListMode::CarouselView:
carousel_view->UpdateIconSize();
break;
} else {
tree_view->UpdateColumnVisibility(item_model);
}
}
@@ -177,46 +166,26 @@ void GameList::UnloadController() {
}
void GameList::ResetViewMode() {
const auto mode = UISettings::values.game_list_mode.GetValue();
game_list_mode = mode;
if (m_currentView)
layout->removeWidget(m_currentView);
auto& setting = UISettings::values.game_list_mode;
bool newTreeMode = false;
switch (mode) {
switch (setting.GetValue()) {
case Settings::GameListMode::TreeView:
m_currentView = tree_view;
newTreeMode = true;
tree_view->setVisible(true);
grid_view->setVisible(false);
break;
case Settings::GameListMode::GridView:
m_currentView = grid_view;
newTreeMode = false;
break;
case Settings::GameListMode::CarouselView:
m_currentView = carousel_view;
newTreeMode = false;
grid_view->setVisible(true);
tree_view->setVisible(false);
break;
default:
UNREACHABLE();
}
tree_view->setVisible(false);
grid_view->setVisible(false);
carousel_view->setVisible(false);
tree_view->setEnabled(false);
grid_view->setEnabled(false);
carousel_view->setEnabled(false);
m_currentView->setVisible(true);
m_currentView->setEnabled(true);
layout->insertWidget(0, m_currentView);
auto view = m_currentView->viewport();
view->installEventFilter(this);
@@ -328,13 +297,11 @@ void GameList::OnPopulatingCompleted(const QStringList& watch_list) {
for (int i = 1; i < item_model->rowCount() - 1; ++i) {
children_total += item_model->item(i, 0)->rowCount();
}
search_field->setFilterResult(children_total, children_total);
if (children_total > 0) {
search_field->setFocus();
}
// TODO: carousel/grid impl.
item_model->sort(tree_view->header()->sortIndicatorSection(),
tree_view->header()->sortIndicatorOrder());
@@ -350,15 +317,8 @@ void GameList::RefreshExternalContent() {
}
void GameList::UpdateIconSizes() {
switch (game_list_mode) {
case Settings::GameListMode::GridView:
if (!m_isTreeMode) {
grid_view->UpdateIconSize();
break;
case Settings::GameListMode::CarouselView:
carousel_view->UpdateIconSize();
break;
case Settings::GameListMode::TreeView:
break;
}
}
@@ -752,11 +712,6 @@ bool GameList::eventFilter(QObject* obj, QEvent* event) {
return true;
}
if (obj == carousel_view->viewport() && event->type() == QEvent::Resize) {
carousel_view->UpdateIconSize();
return true;
}
return QWidget::eventFilter(obj, event);
}
+1 -6
View File
@@ -15,12 +15,12 @@
#include <QVBoxLayout>
#include <QVector>
#include <QWidget>
#include <qabstractitemview.h>
#include "common/common_types.h"
#include "core/core.h"
#include "frontend_common/play_time_manager.h"
#include "qt_common/config/uisettings.h"
#include "qt_common/game_list/model.h"
#include "qt_common/util/game.h"
#include "yuzu/compatibility_list.h"
@@ -38,9 +38,6 @@ class MainWindow;
enum class AmLaunchType;
enum class StartGameType;
class GameCarousel;
class QAbstractItemView;
namespace Core {
class System;
}
@@ -154,9 +151,7 @@ private:
GameTree* tree_view = nullptr;
GameGrid* grid_view = nullptr;
GameCarousel* carousel_view = nullptr;
GameListModel* item_model = nullptr;
Settings::GameListMode game_list_mode;
ControllerNavigation* controller_navigation = nullptr;
+2
View File
@@ -3,6 +3,8 @@
#pragma once
#include <QHeaderView>
#include <QString>
#include <QTreeView>
class GameListModel;
+1 -10
View File
@@ -45,7 +45,7 @@
<x>0</x>
<y>0</y>
<width>1280</width>
<height>23</height>
<height>22</height>
</rect>
</property>
<widget class="QMenu" name="menu_File">
@@ -111,7 +111,6 @@
</property>
<addaction name="action_Tree_View"/>
<addaction name="action_Grid_View"/>
<addaction name="action_Carousel_View"/>
</widget>
<widget class="QMenu" name="menuGame_Icon_Size">
<property name="title">
@@ -621,14 +620,6 @@
<string>Show &amp;Performance Overlay</string>
</property>
</action>
<action name="action_Carousel_View">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>&amp;Carousel View</string>
</property>
</action>
</widget>
<resources>
<include location="yuzu.qrc"/>
+4 -10
View File
@@ -1529,7 +1529,6 @@ void MainWindow::ConnectMenuEvents() {
connect_menu(ui->action_Grid_View, &MainWindow::SetGridView);
connect_menu(ui->action_Tree_View, &MainWindow::SetTreeView);
connect_menu(ui->action_Carousel_View, &MainWindow::SetCarouselView);
game_size_actions = new QActionGroup(this);
game_size_actions->setExclusive(true);
@@ -3318,10 +3317,9 @@ void MainWindow::ResetWindowSize1080() {
void MainWindow::SetGameListMode(Settings::GameListMode mode) {
ui->action_Grid_View->setChecked(mode == Settings::GameListMode::GridView);
ui->action_Tree_View->setChecked(mode == Settings::GameListMode::TreeView);
ui->action_Carousel_View->setChecked(mode == Settings::GameListMode::CarouselView);
UISettings::values.game_list_mode = mode;
ui->action_Show_Game_Name->setEnabled(mode != Settings::GameListMode::TreeView);
ui->action_Show_Game_Name->setEnabled(mode == Settings::GameListMode::GridView);
CheckIconSize();
game_list->ResetViewMode();
@@ -3335,15 +3333,11 @@ void MainWindow::SetTreeView() {
SetGameListMode(Settings::GameListMode::TreeView);
}
void MainWindow::SetCarouselView() {
SetGameListMode(Settings::GameListMode::CarouselView);
}
void MainWindow::CheckIconSize() {
// When in grid/carousel view mode, with text off
// there is no point in having icons turned off
// When in grid view mode, with text off
// there is no point in having icons turned off..
auto actions = game_size_actions->actions();
if (UISettings::values.game_list_mode.GetValue() != Settings::GameListMode::TreeView &&
if (UISettings::values.game_list_mode.GetValue() == Settings::GameListMode::GridView &&
!UISettings::values.show_game_name.GetValue()) {
u32 newSize = UISettings::values.game_icon_size.GetValue();
if (newSize == 0) {
-1
View File
@@ -410,7 +410,6 @@ private slots:
void SetGameListMode(Settings::GameListMode mode);
void SetGridView();
void SetTreeView();
void SetCarouselView();
void CheckIconSize();
void ToggleShowGameName();