summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/common/logging/backend.cpp1
-rw-r--r--src/common/logging/filter.cpp1
-rw-r--r--src/common/logging/types.h1
-rw-r--r--src/common/lru_cache.h140
-rw-r--r--src/common/settings.cpp2
-rw-r--r--src/common/settings.h1
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/hle/service/ngct/ngct.cpp46
-rw-r--r--src/core/hle/service/ngct/ngct.h20
-rw-r--r--src/core/hle/service/nifm/nifm.cpp113
-rw-r--r--src/core/hle/service/service.cpp2
-rw-r--r--src/core/network/network_interface.cpp171
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp5
-rw-r--r--src/video_core/buffer_cache/buffer_base.h20
-rw-r--r--src/video_core/buffer_cache/buffer_cache.h61
-rw-r--r--src/video_core/command_classes/codecs/vp9.cpp1
-rw-r--r--src/video_core/command_classes/codecs/vp9_types.h85
-rw-r--r--src/video_core/renderer_vulkan/vk_blit_screen.cpp4
-rw-r--r--src/video_core/texture_cache/image_base.h2
-rw-r--r--src/video_core/texture_cache/texture_cache.h92
-rw-r--r--src/video_core/texture_cache/texture_cache_base.h8
-rw-r--r--src/video_core/textures/decoders.cpp8
-rw-r--r--src/yuzu/configuration/config.cpp2
-rw-r--r--src/yuzu/configuration/configure_graphics_advanced.cpp6
-rw-r--r--src/yuzu/configuration/configure_graphics_advanced.h1
-rw-r--r--src/yuzu/configuration/configure_graphics_advanced.ui10
-rw-r--r--src/yuzu_cmd/config.cpp1
27 files changed, 476 insertions, 330 deletions
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp
index 949384fd3..e40d117d6 100644
--- a/src/common/logging/backend.cpp
+++ b/src/common/logging/backend.cpp
@@ -18,6 +18,7 @@
#include "common/fs/fs_paths.h"
#include "common/fs/path_util.h"
#include "common/literals.h"
+#include "common/thread.h"
#include "common/logging/backend.h"
#include "common/logging/log.h"
diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp
index f055f0e11..42744c994 100644
--- a/src/common/logging/filter.cpp
+++ b/src/common/logging/filter.cpp
@@ -111,6 +111,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
SUB(Service, NCM) \
SUB(Service, NFC) \
SUB(Service, NFP) \
+ SUB(Service, NGCT) \
SUB(Service, NIFM) \
SUB(Service, NIM) \
SUB(Service, NPNS) \
diff --git a/src/common/logging/types.h b/src/common/logging/types.h
index 7ad0334fc..ddf9d27ca 100644
--- a/src/common/logging/types.h
+++ b/src/common/logging/types.h
@@ -81,6 +81,7 @@ enum class Class : u8 {
Service_NCM, ///< The NCM service
Service_NFC, ///< The NFC (Near-field communication) service
Service_NFP, ///< The NFP service
+ Service_NGCT, ///< The NGCT (No Good Content for Terra) service
Service_NIFM, ///< The NIFM (Network interface) service
Service_NIM, ///< The NIM service
Service_NPNS, ///< The NPNS service
diff --git a/src/common/lru_cache.h b/src/common/lru_cache.h
new file mode 100644
index 000000000..365488ba5
--- /dev/null
+++ b/src/common/lru_cache.h
@@ -0,0 +1,140 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2+ or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <deque>
+#include <memory>
+#include <type_traits>
+
+#include "common/common_types.h"
+
+namespace Common {
+
+template <class Traits>
+class LeastRecentlyUsedCache {
+ using ObjectType = typename Traits::ObjectType;
+ using TickType = typename Traits::TickType;
+
+ struct Item {
+ ObjectType obj;
+ TickType tick;
+ Item* next{};
+ Item* prev{};
+ };
+
+public:
+ LeastRecentlyUsedCache() : first_item{}, last_item{} {}
+ ~LeastRecentlyUsedCache() = default;
+
+ size_t Insert(ObjectType obj, TickType tick) {
+ const auto new_id = Build();
+ auto& item = item_pool[new_id];
+ item.obj = obj;
+ item.tick = tick;
+ Attach(item);
+ return new_id;
+ }
+
+ void Touch(size_t id, TickType tick) {
+ auto& item = item_pool[id];
+ if (item.tick >= tick) {
+ return;
+ }
+ item.tick = tick;
+ if (&item == last_item) {
+ return;
+ }
+ Detach(item);
+ Attach(item);
+ }
+
+ void Free(size_t id) {
+ auto& item = item_pool[id];
+ Detach(item);
+ item.prev = nullptr;
+ item.next = nullptr;
+ free_items.push_back(id);
+ }
+
+ template <typename Func>
+ void ForEachItemBelow(TickType tick, Func&& func) {
+ static constexpr bool RETURNS_BOOL =
+ std::is_same_v<std::invoke_result<Func, ObjectType>, bool>;
+ Item* iterator = first_item;
+ while (iterator) {
+ if (static_cast<s64>(tick) - static_cast<s64>(iterator->tick) < 0) {
+ return;
+ }
+ Item* next = iterator->next;
+ if constexpr (RETURNS_BOOL) {
+ if (func(iterator->obj)) {
+ return;
+ }
+ } else {
+ func(iterator->obj);
+ }
+ iterator = next;
+ }
+ }
+
+private:
+ size_t Build() {
+ if (free_items.empty()) {
+ const size_t item_id = item_pool.size();
+ auto& item = item_pool.emplace_back();
+ item.next = nullptr;
+ item.prev = nullptr;
+ return item_id;
+ }
+ const size_t item_id = free_items.front();
+ free_items.pop_front();
+ auto& item = item_pool[item_id];
+ item.next = nullptr;
+ item.prev = nullptr;
+ return item_id;
+ }
+
+ void Attach(Item& item) {
+ if (!first_item) {
+ first_item = &item;
+ }
+ if (!last_item) {
+ last_item = &item;
+ } else {
+ item.prev = last_item;
+ last_item->next = &item;
+ item.next = nullptr;
+ last_item = &item;
+ }
+ }
+
+ void Detach(Item& item) {
+ if (item.prev) {
+ item.prev->next = item.next;
+ }
+ if (item.next) {
+ item.next->prev = item.prev;
+ }
+ if (&item == first_item) {
+ first_item = item.next;
+ if (first_item) {
+ first_item->prev = nullptr;
+ }
+ }
+ if (&item == last_item) {
+ last_item = item.prev;
+ if (last_item) {
+ last_item->next = nullptr;
+ }
+ }
+ }
+
+ std::deque<Item> item_pool;
+ std::deque<size_t> free_items;
+ Item* first_item{};
+ Item* last_item{};
+};
+
+} // namespace Common
diff --git a/src/common/settings.cpp b/src/common/settings.cpp
index 996315999..fd3b639cd 100644
--- a/src/common/settings.cpp
+++ b/src/common/settings.cpp
@@ -59,7 +59,6 @@ void LogSettings() {
log_setting("Renderer_UseVsync", values.use_vsync.GetValue());
log_setting("Renderer_ShaderBackend", values.shader_backend.GetValue());
log_setting("Renderer_UseAsynchronousShaders", values.use_asynchronous_shaders.GetValue());
- log_setting("Renderer_UseGarbageCollection", values.use_caches_gc.GetValue());
log_setting("Renderer_AnisotropicFilteringLevel", values.max_anisotropy.GetValue());
log_setting("Audio_OutputEngine", values.sink_id.GetValue());
log_setting("Audio_EnableAudioStretching", values.enable_audio_stretching.GetValue());
@@ -143,7 +142,6 @@ void RestoreGlobalState(bool is_powered_on) {
values.shader_backend.SetGlobal(true);
values.use_asynchronous_shaders.SetGlobal(true);
values.use_fast_gpu_time.SetGlobal(true);
- values.use_caches_gc.SetGlobal(true);
values.bg_red.SetGlobal(true);
values.bg_green.SetGlobal(true);
values.bg_blue.SetGlobal(true);
diff --git a/src/common/settings.h b/src/common/settings.h
index 20769d310..ec4d381e8 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -475,7 +475,6 @@ struct Values {
ShaderBackend::SPIRV, "shader_backend"};
Setting<bool> use_asynchronous_shaders{false, "use_asynchronous_shaders"};
Setting<bool> use_fast_gpu_time{true, "use_fast_gpu_time"};
- Setting<bool> use_caches_gc{false, "use_caches_gc"};
Setting<u8> bg_red{0, "bg_red"};
Setting<u8> bg_green{0, "bg_green"};
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index f5cf5c16a..87d47e2e5 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -452,6 +452,8 @@ add_library(core STATIC
hle/service/nfp/nfp.h
hle/service/nfp/nfp_user.cpp
hle/service/nfp/nfp_user.h
+ hle/service/ngct/ngct.cpp
+ hle/service/ngct/ngct.h
hle/service/nifm/nifm.cpp
hle/service/nifm/nifm.h
hle/service/nim/nim.cpp
diff --git a/src/core/hle/service/ngct/ngct.cpp b/src/core/hle/service/ngct/ngct.cpp
new file mode 100644
index 000000000..deb3abb28
--- /dev/null
+++ b/src/core/hle/service/ngct/ngct.cpp
@@ -0,0 +1,46 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included
+
+#include "common/string_util.h"
+#include "core/core.h"
+#include "core/hle/ipc_helpers.h"
+#include "core/hle/service/ngct/ngct.h"
+#include "core/hle/service/service.h"
+
+namespace Service::NGCT {
+
+class IService final : public ServiceFramework<IService> {
+public:
+ explicit IService(Core::System& system_) : ServiceFramework{system_, "ngct:u"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "Match"},
+ {1, &IService::Filter, "Filter"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+
+private:
+ void Filter(Kernel::HLERequestContext& ctx) {
+ const auto buffer = ctx.ReadBuffer();
+ const auto text = Common::StringFromFixedZeroTerminatedBuffer(
+ reinterpret_cast<const char*>(buffer.data()), buffer.size());
+
+ LOG_WARNING(Service_NGCT, "(STUBBED) called, text={}", text);
+
+ // Return the same string since we don't censor anything
+ ctx.WriteBuffer(buffer);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+ }
+};
+
+void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
+ std::make_shared<IService>(system)->InstallAsService(system.ServiceManager());
+}
+
+} // namespace Service::NGCT
diff --git a/src/core/hle/service/ngct/ngct.h b/src/core/hle/service/ngct/ngct.h
new file mode 100644
index 000000000..1f2a47b78
--- /dev/null
+++ b/src/core/hle/service/ngct/ngct.h
@@ -0,0 +1,20 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included
+
+#pragma once
+
+namespace Core {
+class System;
+}
+
+namespace Service::SM {
+class ServiceManager;
+}
+
+namespace Service::NGCT {
+
+/// Registers all NGCT services with the specified service manager.
+void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
+
+} // namespace Service::NGCT
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp
index 0a53c0c81..9decb9290 100644
--- a/src/core/hle/service/nifm/nifm.cpp
+++ b/src/core/hle/service/nifm/nifm.cpp
@@ -277,37 +277,45 @@ private:
void GetCurrentNetworkProfile(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
- const SfNetworkProfileData network_profile_data{
- .ip_setting_data{
- .ip_address_setting{
- .is_automatic{true},
- .current_address{192, 168, 1, 100},
- .subnet_mask{255, 255, 255, 0},
- .gateway{192, 168, 1, 1},
- },
- .dns_setting{
- .is_automatic{true},
- .primary_dns{1, 1, 1, 1},
- .secondary_dns{1, 0, 0, 1},
+ const auto net_iface = Network::GetSelectedNetworkInterface();
+
+ const SfNetworkProfileData network_profile_data = [&net_iface] {
+ if (!net_iface) {
+ return SfNetworkProfileData{};
+ }
+
+ return SfNetworkProfileData{
+ .ip_setting_data{
+ .ip_address_setting{
+ .is_automatic{true},
+ .current_address{Network::TranslateIPv4(net_iface->ip_address)},
+ .subnet_mask{Network::TranslateIPv4(net_iface->subnet_mask)},
+ .gateway{Network::TranslateIPv4(net_iface->gateway)},
+ },
+ .dns_setting{
+ .is_automatic{true},
+ .primary_dns{1, 1, 1, 1},
+ .secondary_dns{1, 0, 0, 1},
+ },
+ .proxy_setting{
+ .enabled{false},
+ .port{},
+ .proxy_server{},
+ .automatic_auth_enabled{},
+ .user{},
+ .password{},
+ },
+ .mtu{1500},
},
- .proxy_setting{
- .enabled{false},
- .port{},
- .proxy_server{},
- .automatic_auth_enabled{},
- .user{},
- .password{},
+ .uuid{0xdeadbeef, 0xdeadbeef},
+ .network_name{"yuzu Network"},
+ .wireless_setting_data{
+ .ssid_length{12},
+ .ssid{"yuzu Network"},
+ .passphrase{"yuzupassword"},
},
- .mtu{1500},
- },
- .uuid{0xdeadbeef, 0xdeadbeef},
- .network_name{"yuzu Network"},
- .wireless_setting_data{
- .ssid_length{12},
- .ssid{"yuzu Network"},
- .passphrase{"yuzupassword"},
- },
- };
+ };
+ }();
ctx.WriteBuffer(network_profile_data);
@@ -352,38 +360,33 @@ private:
LOG_WARNING(Service_NIFM, "(STUBBED) called");
struct IpConfigInfo {
- IpAddressSetting ip_address_setting;
- DnsSetting dns_setting;
+ IpAddressSetting ip_address_setting{};
+ DnsSetting dns_setting{};
};
static_assert(sizeof(IpConfigInfo) == sizeof(IpAddressSetting) + sizeof(DnsSetting),
"IpConfigInfo has incorrect size.");
- IpConfigInfo ip_config_info{
- .ip_address_setting{
- .is_automatic{true},
- .current_address{0, 0, 0, 0},
- .subnet_mask{255, 255, 255, 0},
- .gateway{192, 168, 1, 1},
- },
- .dns_setting{
- .is_automatic{true},
- .primary_dns{1, 1, 1, 1},
- .secondary_dns{1, 0, 0, 1},
- },
- };
+ const auto net_iface = Network::GetSelectedNetworkInterface();
- const auto iface = Network::GetSelectedNetworkInterface();
- if (iface) {
- ip_config_info.ip_address_setting =
- IpAddressSetting{.is_automatic{true},
- .current_address{Network::TranslateIPv4(iface->ip_address)},
- .subnet_mask{Network::TranslateIPv4(iface->subnet_mask)},
- .gateway{Network::TranslateIPv4(iface->gateway)}};
+ const IpConfigInfo ip_config_info = [&net_iface] {
+ if (!net_iface) {
+ return IpConfigInfo{};
+ }
- } else {
- LOG_ERROR(Service_NIFM,
- "Couldn't get host network configuration info, using default values");
- }
+ return IpConfigInfo{
+ .ip_address_setting{
+ .is_automatic{true},
+ .current_address{Network::TranslateIPv4(net_iface->ip_address)},
+ .subnet_mask{Network::TranslateIPv4(net_iface->subnet_mask)},
+ .gateway{Network::TranslateIPv4(net_iface->gateway)},
+ },
+ .dns_setting{
+ .is_automatic{true},
+ .primary_dns{1, 1, 1, 1},
+ .secondary_dns{1, 0, 0, 1},
+ },
+ };
+ }();
IPC::ResponseBuilder rb{ctx, 2 + (sizeof(IpConfigInfo) + 3) / sizeof(u32)};
rb.Push(ResultSuccess);
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index b3e50433b..065133166 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -46,6 +46,7 @@
#include "core/hle/service/ncm/ncm.h"
#include "core/hle/service/nfc/nfc.h"
#include "core/hle/service/nfp/nfp.h"
+#include "core/hle/service/ngct/ngct.h"
#include "core/hle/service/nifm/nifm.h"
#include "core/hle/service/nim/nim.h"
#include "core/hle/service/npns/npns.h"
@@ -271,6 +272,7 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system
NCM::InstallInterfaces(*sm, system);
NFC::InstallInterfaces(*sm, system);
NFP::InstallInterfaces(*sm, system);
+ NGCT::InstallInterfaces(*sm, system);
NIFM::InstallInterfaces(*sm, system);
NIM::InstallInterfaces(*sm, system);
NPNS::InstallInterfaces(*sm, system);
diff --git a/src/core/network/network_interface.cpp b/src/core/network/network_interface.cpp
index cecc9aa11..6811f21b1 100644
--- a/src/core/network/network_interface.cpp
+++ b/src/core/network/network_interface.cpp
@@ -37,73 +37,73 @@ std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
AF_INET, GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_INCLUDE_GATEWAYS,
nullptr, adapter_addresses.data(), &buf_size);
- if (ret == ERROR_BUFFER_OVERFLOW) {
- adapter_addresses.resize((buf_size / sizeof(IP_ADAPTER_ADDRESSES)) + 1);
- } else {
+ if (ret != ERROR_BUFFER_OVERFLOW) {
break;
}
+
+ adapter_addresses.resize((buf_size / sizeof(IP_ADAPTER_ADDRESSES)) + 1);
}
- if (ret == NO_ERROR) {
- std::vector<NetworkInterface> result;
+ if (ret != NO_ERROR) {
+ LOG_ERROR(Network, "Failed to get network interfaces with GetAdaptersAddresses");
+ return {};
+ }
- for (auto current_address = adapter_addresses.data(); current_address != nullptr;
- current_address = current_address->Next) {
- if (current_address->FirstUnicastAddress == nullptr ||
- current_address->FirstUnicastAddress->Address.lpSockaddr == nullptr) {
- continue;
- }
+ std::vector<NetworkInterface> result;
- if (current_address->OperStatus != IfOperStatusUp) {
- continue;
- }
+ for (auto current_address = adapter_addresses.data(); current_address != nullptr;
+ current_address = current_address->Next) {
+ if (current_address->FirstUnicastAddress == nullptr ||
+ current_address->FirstUnicastAddress->Address.lpSockaddr == nullptr) {
+ continue;
+ }
- const auto ip_addr = Common::BitCast<struct sockaddr_in>(
- *current_address->FirstUnicastAddress->Address.lpSockaddr)
- .sin_addr;
+ if (current_address->OperStatus != IfOperStatusUp) {
+ continue;
+ }
- ULONG mask = 0;
- if (ConvertLengthToIpv4Mask(current_address->FirstUnicastAddress->OnLinkPrefixLength,
- &mask) != NO_ERROR) {
- LOG_ERROR(Network, "Failed to convert IPv4 prefix length to subnet mask");
- continue;
- }
+ const auto ip_addr = Common::BitCast<struct sockaddr_in>(
+ *current_address->FirstUnicastAddress->Address.lpSockaddr)
+ .sin_addr;
- struct in_addr gateway = {.S_un{.S_addr{0}}};
- if (current_address->FirstGatewayAddress != nullptr &&
- current_address->FirstGatewayAddress->Address.lpSockaddr != nullptr) {
- gateway = Common::BitCast<struct sockaddr_in>(
- *current_address->FirstGatewayAddress->Address.lpSockaddr)
- .sin_addr;
- }
+ ULONG mask = 0;
+ if (ConvertLengthToIpv4Mask(current_address->FirstUnicastAddress->OnLinkPrefixLength,
+ &mask) != NO_ERROR) {
+ LOG_ERROR(Network, "Failed to convert IPv4 prefix length to subnet mask");
+ continue;
+ }
- result.push_back(NetworkInterface{
- .name{Common::UTF16ToUTF8(std::wstring{current_address->FriendlyName})},
- .ip_address{ip_addr},
- .subnet_mask = in_addr{.S_un{.S_addr{mask}}},
- .gateway = gateway});
+ struct in_addr gateway = {.S_un{.S_addr{0}}};
+ if (current_address->FirstGatewayAddress != nullptr &&
+ current_address->FirstGatewayAddress->Address.lpSockaddr != nullptr) {
+ gateway = Common::BitCast<struct sockaddr_in>(
+ *current_address->FirstGatewayAddress->Address.lpSockaddr)
+ .sin_addr;
}
- return result;
- } else {
- LOG_ERROR(Network, "Failed to get network interfaces with GetAdaptersAddresses");
- return {};
+ result.emplace_back(NetworkInterface{
+ .name{Common::UTF16ToUTF8(std::wstring{current_address->FriendlyName})},
+ .ip_address{ip_addr},
+ .subnet_mask = in_addr{.S_un{.S_addr{mask}}},
+ .gateway = gateway});
}
+
+ return result;
}
#else
std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
- std::vector<NetworkInterface> result;
-
struct ifaddrs* ifaddr = nullptr;
if (getifaddrs(&ifaddr) != 0) {
LOG_ERROR(Network, "Failed to get network interfaces with getifaddrs: {}",
std::strerror(errno));
- return result;
+ return {};
}
+ std::vector<NetworkInterface> result;
+
for (auto ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == nullptr || ifa->ifa_netmask == nullptr) {
continue;
@@ -117,55 +117,62 @@ std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
continue;
}
- std::uint32_t gateway{0};
+ u32 gateway{};
+
std::ifstream file{"/proc/net/route"};
- if (file.is_open()) {
+ if (!file.is_open()) {
+ LOG_ERROR(Network, "Failed to open \"/proc/net/route\"");
- // ignore header
- file.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
+ result.emplace_back(NetworkInterface{
+ .name{ifa->ifa_name},
+ .ip_address{Common::BitCast<struct sockaddr_in>(*ifa->ifa_addr).sin_addr},
+ .subnet_mask{Common::BitCast<struct sockaddr_in>(*ifa->ifa_netmask).sin_addr},
+ .gateway{in_addr{.s_addr = gateway}}});
+ continue;
+ }
- bool gateway_found = false;
+ // ignore header
+ file.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
- for (std::string line; std::getline(file, line);) {
- std::istringstream iss{line};
+ bool gateway_found = false;
- std::string iface_name{};
- iss >> iface_name;
- if (iface_name != ifa->ifa_name) {
- continue;
- }
+ for (std::string line; std::getline(file, line);) {
+ std::istringstream iss{line};
- iss >> std::hex;
+ std::string iface_name;
+ iss >> iface_name;
+ if (iface_name != ifa->ifa_name) {
+ continue;
+ }
- std::uint32_t dest{0};
- iss >> dest;
- if (dest != 0) {
- // not the default route
- continue;
- }
+ iss >> std::hex;
- iss >> gateway;
+ u32 dest{};
+ iss >> dest;
+ if (dest != 0) {
+ // not the default route
+ continue;
+ }
- std::uint16_t flags{0};
- iss >> flags;
+ iss >> gateway;
- // flag RTF_GATEWAY (defined in <linux/route.h>)
- if ((flags & 0x2) == 0) {
- continue;
- }
+ u16 flags{};
+ iss >> flags;
- gateway_found = true;
- break;
+ // flag RTF_GATEWAY (defined in <linux/route.h>)
+ if ((flags & 0x2) == 0) {
+ continue;
}
- if (!gateway_found) {
- gateway = 0;
- }
- } else {
- LOG_ERROR(Network, "Failed to open \"/proc/net/route\"");
+ gateway_found = true;
+ break;
}
- result.push_back(NetworkInterface{
+ if (!gateway_found) {
+ gateway = 0;
+ }
+
+ result.emplace_back(NetworkInterface{
.name{ifa->ifa_name},
.ip_address{Common::BitCast<struct sockaddr_in>(*ifa->ifa_addr).sin_addr},
.subnet_mask{Common::BitCast<struct sockaddr_in>(*ifa->ifa_netmask).sin_addr},
@@ -180,11 +187,11 @@ std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
#endif
std::optional<NetworkInterface> GetSelectedNetworkInterface() {
- const std::string& selected_network_interface = Settings::values.network_interface.GetValue();
+ const auto& selected_network_interface = Settings::values.network_interface.GetValue();
const auto network_interfaces = Network::GetAvailableNetworkInterfaces();
if (network_interfaces.size() == 0) {
LOG_ERROR(Network, "GetAvailableNetworkInterfaces returned no interfaces");
- return {};
+ return std::nullopt;
}
const auto res =
@@ -192,12 +199,12 @@ std::optional<NetworkInterface> GetSelectedNetworkInterface() {
return iface.name == selected_network_interface;
});
- if (res != network_interfaces.end()) {
- return *res;
- } else {
+ if (res == network_interfaces.end()) {
LOG_ERROR(Network, "Couldn't find selected interface \"{}\"", selected_network_interface);
- return {};
+ return std::nullopt;
}
+
+ return *res;
}
} // namespace Network
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp
index 14c77f162..9e54a17ee 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp
@@ -333,8 +333,9 @@ Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex) {
return ctx.OpBitcast(ctx.F32[1], ctx.OpISub(ctx.U32[1], index, base));
}
case IR::Attribute::FrontFace:
- return ctx.OpSelect(ctx.U32[1], ctx.OpLoad(ctx.U1, ctx.front_face),
- ctx.Const(std::numeric_limits<u32>::max()), ctx.u32_zero_value);
+ return ctx.OpSelect(ctx.F32[1], ctx.OpLoad(ctx.U1, ctx.front_face),
+ ctx.OpBitcast(ctx.F32[1], ctx.Const(std::numeric_limits<u32>::max())),
+ ctx.f32_zero_value);
case IR::Attribute::PointSpriteS:
return ctx.OpLoad(ctx.F32[1],
ctx.OpAccessChain(ctx.input_f32, ctx.point_coord, ctx.u32_zero_value));
diff --git a/src/video_core/buffer_cache/buffer_base.h b/src/video_core/buffer_cache/buffer_base.h
index c3318095c..be2113f5a 100644
--- a/src/video_core/buffer_cache/buffer_base.h
+++ b/src/video_core/buffer_cache/buffer_base.h
@@ -261,16 +261,6 @@ public:
stream_score += score;
}
- /// Sets the new frame tick
- void SetFrameTick(u64 new_frame_tick) noexcept {
- frame_tick = new_frame_tick;
- }
-
- /// Returns the new frame tick
- [[nodiscard]] u64 FrameTick() const noexcept {
- return frame_tick;
- }
-
/// Returns the likeliness of this being a stream buffer
[[nodiscard]] int StreamScore() const noexcept {
return stream_score;
@@ -307,6 +297,14 @@ public:
return words.size_bytes;
}
+ size_t getLRUID() const noexcept {
+ return lru_id;
+ }
+
+ void setLRUID(size_t lru_id_) {
+ lru_id = lru_id_;
+ }
+
private:
template <Type type>
u64* Array() noexcept {
@@ -603,9 +601,9 @@ private:
RasterizerInterface* rasterizer = nullptr;
VAddr cpu_addr = 0;
Words words;
- u64 frame_tick = 0;
BufferFlagBits flags{};
int stream_score = 0;
+ size_t lru_id = SIZE_MAX;
};
} // namespace VideoCommon
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h
index 3b43554f9..7bfd57369 100644
--- a/src/video_core/buffer_cache/buffer_cache.h
+++ b/src/video_core/buffer_cache/buffer_cache.h
@@ -20,6 +20,7 @@
#include "common/common_types.h"
#include "common/div_ceil.h"
#include "common/literals.h"
+#include "common/lru_cache.h"
#include "common/microprofile.h"
#include "common/scope_exit.h"
#include "common/settings.h"
@@ -330,7 +331,7 @@ private:
template <bool insert>
void ChangeRegister(BufferId buffer_id);
- void TouchBuffer(Buffer& buffer) const noexcept;
+ void TouchBuffer(Buffer& buffer, BufferId buffer_id) noexcept;
bool SynchronizeBuffer(Buffer& buffer, VAddr cpu_addr, u32 size);
@@ -428,7 +429,11 @@ private:
size_t immediate_buffer_capacity = 0;
std::unique_ptr<u8[]> immediate_buffer_alloc;
- typename SlotVector<Buffer>::Iterator deletion_iterator;
+ struct LRUItemParams {
+ using ObjectType = BufferId;
+ using TickType = u64;
+ };
+ Common::LeastRecentlyUsedCache<LRUItemParams> lru_cache;
u64 frame_tick = 0;
u64 total_used_memory = 0;
@@ -445,7 +450,6 @@ BufferCache<P>::BufferCache(VideoCore::RasterizerInterface& rasterizer_,
kepler_compute{kepler_compute_}, gpu_memory{gpu_memory_}, cpu_memory{cpu_memory_} {
// Ensure the first slot is used for the null buffer
void(slot_buffers.insert(runtime, NullBufferParams{}));
- deletion_iterator = slot_buffers.end();
common_ranges.clear();
}
@@ -454,20 +458,17 @@ void BufferCache<P>::RunGarbageCollector() {
const bool aggressive_gc = total_used_memory >= CRITICAL_MEMORY;
const u64 ticks_to_destroy = aggressive_gc ? 60 : 120;
int num_iterations = aggressive_gc ? 64 : 32;
- for (; num_iterations > 0; --num_iterations) {
- if (deletion_iterator == slot_buffers.end()) {
- deletion_iterator = slot_buffers.begin();
- }
- ++deletion_iterator;
- if (deletion_iterator == slot_buffers.end()) {
- break;
- }
- const auto [buffer_id, buffer] = *deletion_iterator;
- if (buffer->FrameTick() + ticks_to_destroy < frame_tick) {
- DownloadBufferMemory(*buffer);
- DeleteBuffer(buffer_id);
+ const auto clean_up = [this, &num_iterations](BufferId buffer_id) {
+ if (num_iterations == 0) {
+ return true;
}
- }
+ --num_iterations;
+ auto& buffer = slot_buffers[buffer_id];
+ DownloadBufferMemory(buffer);
+ DeleteBuffer(buffer_id);
+ return false;
+ };
+ lru_cache.ForEachItemBelow(frame_tick - ticks_to_destroy, clean_up);
}
template <class P>
@@ -485,7 +486,7 @@ void BufferCache<P>::TickFrame() {
const bool skip_preferred = hits * 256 < shots * 251;
uniform_buffer_skip_cache_size = skip_preferred ? DEFAULT_SKIP_CACHE_SIZE : 0;
- if (Settings::values.use_caches_gc.GetValue() && total_used_memory >= EXPECTED_MEMORY) {
+ if (total_used_memory >= EXPECTED_MEMORY) {
RunGarbageCollector();
}
++frame_tick;
@@ -954,7 +955,7 @@ bool BufferCache<P>::IsRegionCpuModified(VAddr addr, size_t size) {
template <class P>
void BufferCache<P>::BindHostIndexBuffer() {
Buffer& buffer = slot_buffers[index_buffer.buffer_id];
- TouchBuffer(buffer);
+ TouchBuffer(buffer, index_buffer.buffer_id);
const u32 offset = buffer.Offset(index_buffer.cpu_addr);
const u32 size = index_buffer.size;
SynchronizeBuffer(buffer, index_buffer.cpu_addr, size);
@@ -975,7 +976,7 @@ void BufferCache<P>::BindHostVertexBuffers() {
for (u32 index = 0; index < NUM_VERTEX_BUFFERS; ++index) {
const Binding& binding = vertex_buffers[index];
Buffer& buffer = slot_buffers[binding.buffer_id];
- TouchBuffer(buffer);
+ TouchBuffer(buffer, binding.buffer_id);
SynchronizeBuffer(buffer, binding.cpu_addr, binding.size);
if (!flags[Dirty::VertexBuffer0 + index]) {
continue;
@@ -1011,7 +1012,7 @@ void BufferCache<P>::BindHostGraphicsUniformBuffer(size_t stage, u32 index, u32
const VAddr cpu_addr = binding.cpu_addr;
const u32 size = std::min(binding.size, (*uniform_buffer_sizes)[stage][index]);
Buffer& buffer = slot_buffers[binding.buffer_id];
- TouchBuffer(buffer);
+ TouchBuffer(buffer, binding.buffer_id);
const bool use_fast_buffer = binding.buffer_id != NULL_BUFFER_ID &&
size <= uniform_buffer_skip_cache_size &&
!buffer.IsRegionGpuModified(cpu_addr, size);
@@ -1083,7 +1084,7 @@ void BufferCache<P>::BindHostGraphicsStorageBuffers(size_t stage) {
ForEachEnabledBit(enabled_storage_buffers[stage], [&](u32 index) {
const Binding& binding = storage_buffers[stage][index];
Buffer& buffer = slot_buffers[binding.buffer_id];
- TouchBuffer(buffer);
+ TouchBuffer(buffer, binding.buffer_id);
const u32 size = binding.size;
SynchronizeBuffer(buffer, binding.cpu_addr, size);
@@ -1128,7 +1129,7 @@ void BufferCache<P>::BindHostTransformFeedbackBuffers() {
for (u32 index = 0; index < NUM_TRANSFORM_FEEDBACK_BUFFERS; ++index) {
const Binding& binding = transform_feedback_buffers[index];
Buffer& buffer = slot_buffers[binding.buffer_id];
- TouchBuffer(buffer);
+ TouchBuffer(buffer, binding.buffer_id);
const u32 size = binding.size;
SynchronizeBuffer(buffer, binding.cpu_addr, size);
@@ -1148,7 +1149,7 @@ void BufferCache<P>::BindHostComputeUniformBuffers() {
ForEachEnabledBit(enabled_compute_uniform_buffer_mask, [&](u32 index) {
const Binding& binding = compute_uniform_buffers[index];
Buffer& buffer = slot_buffers[binding.buffer_id];
- TouchBuffer(buffer);
+ TouchBuffer(buffer, binding.buffer_id);
const u32 size = std::min(binding.size, (*compute_uniform_buffer_sizes)[index]);
SynchronizeBuffer(buffer, binding.cpu_addr, size);
@@ -1168,7 +1169,7 @@ void BufferCache<P>::BindHostComputeStorageBuffers() {
ForEachEnabledBit(enabled_compute_storage_buffers, [&](u32 index) {
const Binding& binding = compute_storage_buffers[index];
Buffer& buffer = slot_buffers[binding.buffer_id];
- TouchBuffer(buffer);
+ TouchBuffer(buffer, binding.buffer_id);
const u32 size = binding.size;
SynchronizeBuffer(buffer, binding.cpu_addr, size);
@@ -1513,11 +1514,11 @@ BufferId BufferCache<P>::CreateBuffer(VAddr cpu_addr, u32 wanted_size) {
const OverlapResult overlap = ResolveOverlaps(cpu_addr, wanted_size);
const u32 size = static_cast<u32>(overlap.end - overlap.begin);
const BufferId new_buffer_id = slot_buffers.insert(runtime, rasterizer, overlap.begin, size);
- TouchBuffer(slot_buffers[new_buffer_id]);
for (const BufferId overlap_id : overlap.ids) {
JoinOverlap(new_buffer_id, overlap_id, !overlap.has_stream_leap);
}
Register(new_buffer_id);
+ TouchBuffer(slot_buffers[new_buffer_id], new_buffer_id);
return new_buffer_id;
}
@@ -1534,12 +1535,14 @@ void BufferCache<P>::Unregister(BufferId buffer_id) {
template <class P>
template <bool insert>
void BufferCache<P>::ChangeRegister(BufferId buffer_id) {
- const Buffer& buffer = slot_buffers[buffer_id];
+ Buffer& buffer = slot_buffers[buffer_id];
const auto size = buffer.SizeBytes();
if (insert) {
total_used_memory += Common::AlignUp(size, 1024);
+ buffer.setLRUID(lru_cache.Insert(buffer_id, frame_tick));
} else {
total_used_memory -= Common::AlignUp(size, 1024);
+ lru_cache.Free(buffer.getLRUID());
}
const VAddr cpu_addr_begin = buffer.CpuAddr();
const VAddr cpu_addr_end = cpu_addr_begin + size;
@@ -1555,8 +1558,10 @@ void BufferCache<P>::ChangeRegister(BufferId buffer_id) {
}
template <class P>
-void BufferCache<P>::TouchBuffer(Buffer& buffer) const noexcept {
- buffer.SetFrameTick(frame_tick);
+void BufferCache<P>::TouchBuffer(Buffer& buffer, BufferId buffer_id) noexcept {
+ if (buffer_id != NULL_BUFFER_ID) {
+ lru_cache.Touch(buffer.getLRUID(), frame_tick);
+ }
}
template <class P>
diff --git a/src/video_core/command_classes/codecs/vp9.cpp b/src/video_core/command_classes/codecs/vp9.cpp
index 70030066a..d7e749485 100644
--- a/src/video_core/command_classes/codecs/vp9.cpp
+++ b/src/video_core/command_classes/codecs/vp9.cpp
@@ -742,6 +742,7 @@ VpxBitStreamWriter VP9::ComposeUncompressedHeader() {
uncomp_writer.WriteDeltaQ(current_frame_info.uv_dc_delta_q);
uncomp_writer.WriteDeltaQ(current_frame_info.uv_ac_delta_q);
+ ASSERT(!current_frame_info.segment_enabled);
uncomp_writer.WriteBit(false); // Segmentation enabled (TODO).
const s32 min_tile_cols_log2 = CalcMinLog2TileCols(current_frame_info.frame_size.width);
diff --git a/src/video_core/command_classes/codecs/vp9_types.h b/src/video_core/command_classes/codecs/vp9_types.h
index 87eafdb03..3b1ed4b3a 100644
--- a/src/video_core/command_classes/codecs/vp9_types.h
+++ b/src/video_core/command_classes/codecs/vp9_types.h
@@ -22,7 +22,7 @@ struct Vp9FrameDimensions {
};
static_assert(sizeof(Vp9FrameDimensions) == 0x8, "Vp9 Vp9FrameDimensions is an invalid size");
-enum FrameFlags : u32 {
+enum class FrameFlags : u32 {
IsKeyFrame = 1 << 0,
LastFrameIsKeyFrame = 1 << 1,
FrameSizeChanged = 1 << 2,
@@ -30,6 +30,7 @@ enum FrameFlags : u32 {
LastShowFrame = 1 << 4,
IntraOnly = 1 << 5,
};
+DECLARE_ENUM_FLAG_OPERATORS(FrameFlags)
enum class TxSize {
Tx4x4 = 0, // 4x4 transform
@@ -92,44 +93,34 @@ struct Vp9EntropyProbs {
static_assert(sizeof(Vp9EntropyProbs) == 0x7B4, "Vp9EntropyProbs is an invalid size");
struct Vp9PictureInfo {
- bool is_key_frame;
- bool intra_only;
- bool last_frame_was_key;
- bool frame_size_changed;
- bool error_resilient_mode;
- bool last_frame_shown;
- bool show_frame;
+ u32 bitstream_size;
+ std::array<u64, 4> frame_offsets;
std::array<s8, 4> ref_frame_sign_bias;
s32 base_q_index;
s32 y_dc_delta_q;
s32 uv_dc_delta_q;
s32 uv_ac_delta_q;
- bool lossless;
s32 transform_mode;
- bool allow_high_precision_mv;
s32 interp_filter;
s32 reference_mode;
- s8 comp_fixed_ref;
- std::array<s8, 2> comp_var_ref;
s32 log2_tile_cols;
s32 log2_tile_rows;
- bool segment_enabled;
- bool segment_map_update;
- bool segment_map_temporal_update;
- s32 segment_abs_delta;
- std::array<u32, 8> segment_feature_enable;
- std::array<std::array<s16, 4>, 8> segment_feature_data;
- bool mode_ref_delta_enabled;
- bool use_prev_in_find_mv_refs;
std::array<s8, 4> ref_deltas;
std::array<s8, 2> mode_deltas;
Vp9EntropyProbs entropy;
Vp9FrameDimensions frame_size;
u8 first_level;
u8 sharpness_level;
- u32 bitstream_size;
- std::array<u64, 4> frame_offsets;
- std::array<bool, 4> refresh_frame;
+ bool is_key_frame;
+ bool intra_only;
+ bool last_frame_was_key;
+ bool error_resilient_mode;
+ bool last_frame_shown;
+ bool show_frame;
+ bool lossless;
+ bool allow_high_precision_mv;
+ bool segment_enabled;
+ bool mode_ref_delta_enabled;
};
struct Vp9FrameContainer {
@@ -145,7 +136,7 @@ struct PictureInfo {
Vp9FrameDimensions golden_frame_size; ///< 0x50
Vp9FrameDimensions alt_frame_size; ///< 0x58
Vp9FrameDimensions current_frame_size; ///< 0x60
- u32 vp9_flags; ///< 0x68
+ FrameFlags vp9_flags; ///< 0x68
std::array<s8, 4> ref_frame_sign_bias; ///< 0x6C
u8 first_level; ///< 0x70
u8 sharpness_level; ///< 0x71
@@ -158,60 +149,43 @@ struct PictureInfo {
u8 allow_high_precision_mv; ///< 0x78
u8 interp_filter; ///< 0x79
u8 reference_mode; ///< 0x7A
- s8 comp_fixed_ref; ///< 0x7B
- std::array<s8, 2> comp_var_ref; ///< 0x7C
+ INSERT_PADDING_BYTES_NOINIT(3); ///< 0x7B
u8 log2_tile_cols; ///< 0x7E
u8 log2_tile_rows; ///< 0x7F
Segmentation segmentation; ///< 0x80
LoopFilter loop_filter; ///< 0xE4
- INSERT_PADDING_BYTES_NOINIT(5); ///< 0xEB
- u32 surface_params; ///< 0xF0
- INSERT_PADDING_WORDS_NOINIT(3); ///< 0xF4
+ INSERT_PADDING_BYTES_NOINIT(21); ///< 0xEB
[[nodiscard]] Vp9PictureInfo Convert() const {
return {
- .is_key_frame = (vp9_flags & FrameFlags::IsKeyFrame) != 0,
- .intra_only = (vp9_flags & FrameFlags::IntraOnly) != 0,
- .last_frame_was_key = (vp9_flags & FrameFlags::LastFrameIsKeyFrame) != 0,
- .frame_size_changed = (vp9_flags & FrameFlags::FrameSizeChanged) != 0,
- .error_resilient_mode = (vp9_flags & FrameFlags::ErrorResilientMode) != 0,
- .last_frame_shown = (vp9_flags & FrameFlags::LastShowFrame) != 0,
- .show_frame = true,
+ .bitstream_size = bitstream_size,
+ .frame_offsets{},
.ref_frame_sign_bias = ref_frame_sign_bias,
.base_q_index = base_q_index,
.y_dc_delta_q = y_dc_delta_q,
.uv_dc_delta_q = uv_dc_delta_q,
.uv_ac_delta_q = uv_ac_delta_q,
- .lossless = lossless != 0,
.transform_mode = tx_mode,
- .allow_high_precision_mv = allow_high_precision_mv != 0,
.interp_filter = interp_filter,
.reference_mode = reference_mode,
- .comp_fixed_ref = comp_fixed_ref,
- .comp_var_ref = comp_var_ref,
.log2_tile_cols = log2_tile_cols,
.log2_tile_rows = log2_tile_rows,
- .segment_enabled = segmentation.enabled != 0,
- .segment_map_update = segmentation.update_map != 0,
- .segment_map_temporal_update = segmentation.temporal_update != 0,
- .segment_abs_delta = segmentation.abs_delta,
- .segment_feature_enable = segmentation.feature_mask,
- .segment_feature_data = segmentation.feature_data,
- .mode_ref_delta_enabled = loop_filter.mode_ref_delta_enabled != 0,
- .use_prev_in_find_mv_refs = !(vp9_flags == (FrameFlags::ErrorResilientMode)) &&
- !(vp9_flags == (FrameFlags::FrameSizeChanged)) &&
- !(vp9_flags == (FrameFlags::IntraOnly)) &&
- (vp9_flags == (FrameFlags::LastShowFrame)) &&
- !(vp9_flags == (FrameFlags::LastFrameIsKeyFrame)),
.ref_deltas = loop_filter.ref_deltas,
.mode_deltas = loop_filter.mode_deltas,
.entropy{},
.frame_size = current_frame_size,
.first_level = first_level,
.sharpness_level = sharpness_level,
- .bitstream_size = bitstream_size,
- .frame_offsets{},
- .refresh_frame{},
+ .is_key_frame = True(vp9_flags & FrameFlags::IsKeyFrame),
+ .intra_only = True(vp9_flags & FrameFlags::IntraOnly),
+ .last_frame_was_key = True(vp9_flags & FrameFlags::LastFrameIsKeyFrame),
+ .error_resilient_mode = True(vp9_flags & FrameFlags::ErrorResilientMode),
+ .last_frame_shown = True(vp9_flags & FrameFlags::LastShowFrame),
+ .show_frame = true,
+ .lossless = lossless != 0,
+ .allow_high_precision_mv = allow_high_precision_mv != 0,
+ .segment_enabled = segmentation.enabled != 0,
+ .mode_ref_delta_enabled = loop_filter.mode_ref_delta_enabled != 0,
};
}
};
@@ -316,7 +290,6 @@ ASSERT_POSITION(last_frame_size, 0x48);
ASSERT_POSITION(first_level, 0x70);
ASSERT_POSITION(segmentation, 0x80);
ASSERT_POSITION(loop_filter, 0xE4);
-ASSERT_POSITION(surface_params, 0xF0);
#undef ASSERT_POSITION
#define ASSERT_POSITION(field_name, position) \
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
index 5c43b8acf..cb0580182 100644
--- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp
+++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
@@ -159,11 +159,13 @@ VkSemaphore VKBlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer,
const VAddr framebuffer_addr = framebuffer.address + framebuffer.offset;
const u8* const host_ptr = cpu_memory.GetPointer(framebuffer_addr);
- const size_t size_bytes = GetSizeInBytes(framebuffer);
// TODO(Rodrigo): Read this from HLE
constexpr u32 block_height_log2 = 4;
const u32 bytes_per_pixel = GetBytesPerPixel(framebuffer);
+ const u64 size_bytes{Tegra::Texture::CalculateSize(true, bytes_per_pixel,
+ framebuffer.stride, framebuffer.height,
+ 1, block_height_log2, 0)};
Tegra::Texture::UnswizzleTexture(
mapped_span.subspan(image_offset, size_bytes), std::span(host_ptr, size_bytes),
bytes_per_pixel, framebuffer.width, framebuffer.height, 1, block_height_log2, 0);
diff --git a/src/video_core/texture_cache/image_base.h b/src/video_core/texture_cache/image_base.h
index ff1feda9b..0c17a791b 100644
--- a/src/video_core/texture_cache/image_base.h
+++ b/src/video_core/texture_cache/image_base.h
@@ -80,7 +80,7 @@ struct ImageBase {
VAddr cpu_addr_end = 0;
u64 modification_tick = 0;
- u64 frame_tick = 0;
+ size_t lru_index = SIZE_MAX;
std::array<u32, MAX_MIP_LEVELS> mip_level_offsets{};
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index a087498ff..24b809242 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -5,7 +5,6 @@
#pragma once
#include "common/alignment.h"
-#include "common/settings.h"
#include "video_core/dirty_flags.h"
#include "video_core/texture_cache/samples_helper.h"
#include "video_core/texture_cache/texture_cache_base.h"
@@ -43,8 +42,6 @@ TextureCache<P>::TextureCache(Runtime& runtime_, VideoCore::RasterizerInterface&
void(slot_image_views.insert(runtime, NullImageParams{}));
void(slot_samplers.insert(runtime, sampler_descriptor));
- deletion_iterator = slot_images.begin();
-
if constexpr (HAS_DEVICE_MEMORY_INFO) {
const auto device_memory = runtime.GetDeviceLocalMemory();
const u64 possible_expected_memory = (device_memory * 3) / 10;
@@ -64,70 +61,38 @@ template <class P>
void TextureCache<P>::RunGarbageCollector() {
const bool high_priority_mode = total_used_memory >= expected_memory;
const bool aggressive_mode = total_used_memory >= critical_memory;
- const u64 ticks_to_destroy = high_priority_mode ? 60 : 100;
- int num_iterations = aggressive_mode ? 256 : (high_priority_mode ? 128 : 64);
- for (; num_iterations > 0; --num_iterations) {
- if (deletion_iterator == slot_images.end()) {
- deletion_iterator = slot_images.begin();
- if (deletion_iterator == slot_images.end()) {
- break;
- }
+ const u64 ticks_to_destroy = aggressive_mode ? 10ULL : high_priority_mode ? 25ULL : 100ULL;
+ size_t num_iterations = aggressive_mode ? 10000 : (high_priority_mode ? 100 : 5);
+ const auto clean_up = [this, &num_iterations, high_priority_mode](ImageId image_id) {
+ if (num_iterations == 0) {
+ return true;
}
- auto [image_id, image_tmp] = *deletion_iterator;
- Image* image = image_tmp; // fix clang error.
- const bool is_alias = True(image->flags & ImageFlagBits::Alias);
- const bool is_bad_overlap = True(image->flags & ImageFlagBits::BadOverlap);
- const bool must_download = image->IsSafeDownload();
- bool should_care = is_bad_overlap || is_alias || (high_priority_mode && !must_download);
- const u64 ticks_needed =
- is_bad_overlap
- ? ticks_to_destroy >> 4
- : ((should_care && aggressive_mode) ? ticks_to_destroy >> 1 : ticks_to_destroy);
- should_care |= aggressive_mode;
- if (should_care && image->frame_tick + ticks_needed < frame_tick) {
- if (is_bad_overlap) {
- const bool overlap_check = std::ranges::all_of(
- image->overlapping_images, [&, image](const ImageId& overlap_id) {
- auto& overlap = slot_images[overlap_id];
- return overlap.frame_tick >= image->frame_tick;
- });
- if (!overlap_check) {
- ++deletion_iterator;
- continue;
- }
- }
- if (!is_bad_overlap && must_download) {
- const bool alias_check = std::ranges::none_of(
- image->aliased_images, [&, image](const AliasedImage& alias) {
- auto& alias_image = slot_images[alias.id];
- return (alias_image.frame_tick < image->frame_tick) ||
- (alias_image.modification_tick < image->modification_tick);
- });
-
- if (alias_check) {
- auto map = runtime.DownloadStagingBuffer(image->unswizzled_size_bytes);
- const auto copies = FullDownloadCopies(image->info);
- image->DownloadMemory(map, copies);
- runtime.Finish();
- SwizzleImage(gpu_memory, image->gpu_addr, image->info, copies, map.mapped_span);
- }
- }
- if (True(image->flags & ImageFlagBits::Tracked)) {
- UntrackImage(*image, image_id);
- }
- UnregisterImage(image_id);
- DeleteImage(image_id);
- if (is_bad_overlap) {
- ++num_iterations;
- }
+ --num_iterations;
+ auto& image = slot_images[image_id];
+ const bool must_download = image.IsSafeDownload();
+ if (!high_priority_mode && must_download) {
+ return false;
}
- ++deletion_iterator;
- }
+ if (must_download) {
+ auto map = runtime.DownloadStagingBuffer(image.unswizzled_size_bytes);
+ const auto copies = FullDownloadCopies(image.info);
+ image.DownloadMemory(map, copies);
+ runtime.Finish();
+ SwizzleImage(gpu_memory, image.gpu_addr, image.info, copies, map.mapped_span);
+ }
+ if (True(image.flags & ImageFlagBits::Tracked)) {
+ UntrackImage(image, image_id);
+ }
+ UnregisterImage(image_id);
+ DeleteImage(image_id);
+ return false;
+ };
+ lru_cache.ForEachItemBelow(frame_tick - ticks_to_destroy, clean_up);
}
template <class P>
void TextureCache<P>::TickFrame() {
- if (Settings::values.use_caches_gc.GetValue() && total_used_memory > minimum_memory) {
+ if (total_used_memory > minimum_memory) {
RunGarbageCollector();
}
sentenced_images.Tick();
@@ -1078,6 +1043,8 @@ void TextureCache<P>::RegisterImage(ImageId image_id) {
tentative_size = EstimatedDecompressedSize(tentative_size, image.info.format);
}
total_used_memory += Common::AlignUp(tentative_size, 1024);
+ image.lru_index = lru_cache.Insert(image_id, frame_tick);
+
ForEachGPUPage(image.gpu_addr, image.guest_size_bytes,
[this, image_id](u64 page) { gpu_page_table[page].push_back(image_id); });
if (False(image.flags & ImageFlagBits::Sparse)) {
@@ -1115,6 +1082,7 @@ void TextureCache<P>::UnregisterImage(ImageId image_id) {
tentative_size = EstimatedDecompressedSize(tentative_size, image.info.format);
}
total_used_memory -= Common::AlignUp(tentative_size, 1024);
+ lru_cache.Free(image.lru_index);
const auto& clear_page_table =
[this, image_id](
u64 page,
@@ -1384,7 +1352,7 @@ void TextureCache<P>::PrepareImage(ImageId image_id, bool is_modification, bool
if (is_modification) {
MarkModification(image);
}
- image.frame_tick = frame_tick;
+ lru_cache.Touch(image.lru_index, frame_tick);
}
template <class P>
diff --git a/src/video_core/texture_cache/texture_cache_base.h b/src/video_core/texture_cache/texture_cache_base.h
index e4ae351cb..d7528ed24 100644
--- a/src/video_core/texture_cache/texture_cache_base.h
+++ b/src/video_core/texture_cache/texture_cache_base.h
@@ -14,6 +14,7 @@
#include "common/common_types.h"
#include "common/literals.h"
+#include "common/lru_cache.h"
#include "video_core/compatible_formats.h"
#include "video_core/delayed_destruction_ring.h"
#include "video_core/engines/fermi_2d.h"
@@ -370,6 +371,12 @@ private:
std::vector<ImageId> uncommitted_downloads;
std::queue<std::vector<ImageId>> committed_downloads;
+ struct LRUItemParams {
+ using ObjectType = ImageId;
+ using TickType = u64;
+ };
+ Common::LeastRecentlyUsedCache<LRUItemParams> lru_cache;
+
static constexpr size_t TICKS_TO_DESTROY = 6;
DelayedDestructionRing<Image, TICKS_TO_DESTROY> sentenced_images;
DelayedDestructionRing<ImageView, TICKS_TO_DESTROY> sentenced_image_view;
@@ -379,7 +386,6 @@ private:
u64 modification_tick = 0;
u64 frame_tick = 0;
- typename SlotVector<Image>::Iterator deletion_iterator;
};
} // namespace VideoCommon
diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp
index c010b9353..24e943e4c 100644
--- a/src/video_core/textures/decoders.cpp
+++ b/src/video_core/textures/decoders.cpp
@@ -63,14 +63,6 @@ void SwizzleImpl(std::span<u8> output, std::span<const u8> input, u32 width, u32
const u32 unswizzled_offset =
slice * pitch * height + line * pitch + column * BYTES_PER_PIXEL;
- if (const auto offset = (TO_LINEAR ? unswizzled_offset : swizzled_offset);
- offset >= input.size()) {
- // TODO(Rodrigo): This is an out of bounds access that should never happen. To
- // avoid crashing the emulator, break.
- ASSERT_MSG(false, "offset {} exceeds input size {}!", offset, input.size());
- break;
- }
-
u8* const dst = &output[TO_LINEAR ? swizzled_offset : unswizzled_offset];
const u8* const src = &input[TO_LINEAR ? unswizzled_offset : swizzled_offset];
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 377795326..85d292bcc 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -818,7 +818,6 @@ void Config::ReadRendererValues() {
ReadGlobalSetting(Settings::values.shader_backend);
ReadGlobalSetting(Settings::values.use_asynchronous_shaders);
ReadGlobalSetting(Settings::values.use_fast_gpu_time);
- ReadGlobalSetting(Settings::values.use_caches_gc);
ReadGlobalSetting(Settings::values.bg_red);
ReadGlobalSetting(Settings::values.bg_green);
ReadGlobalSetting(Settings::values.bg_blue);
@@ -1359,7 +1358,6 @@ void Config::SaveRendererValues() {
Settings::values.shader_backend.UsingGlobal());
WriteGlobalSetting(Settings::values.use_asynchronous_shaders);
WriteGlobalSetting(Settings::values.use_fast_gpu_time);
- WriteGlobalSetting(Settings::values.use_caches_gc);
WriteGlobalSetting(Settings::values.bg_red);
WriteGlobalSetting(Settings::values.bg_green);
WriteGlobalSetting(Settings::values.bg_blue);
diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp
index a31b8e192..bfd464061 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.cpp
+++ b/src/yuzu/configuration/configure_graphics_advanced.cpp
@@ -28,7 +28,6 @@ void ConfigureGraphicsAdvanced::SetConfiguration() {
ui->use_vsync->setChecked(Settings::values.use_vsync.GetValue());
ui->use_asynchronous_shaders->setChecked(Settings::values.use_asynchronous_shaders.GetValue());
- ui->use_caches_gc->setChecked(Settings::values.use_caches_gc.GetValue());
ui->use_fast_gpu_time->setChecked(Settings::values.use_fast_gpu_time.GetValue());
if (Settings::IsConfiguringGlobal()) {
@@ -55,8 +54,6 @@ void ConfigureGraphicsAdvanced::ApplyConfiguration() {
ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_shaders,
ui->use_asynchronous_shaders,
use_asynchronous_shaders);
- ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_caches_gc, ui->use_caches_gc,
- use_caches_gc);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_fast_gpu_time,
ui->use_fast_gpu_time, use_fast_gpu_time);
}
@@ -81,7 +78,6 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() {
ui->use_asynchronous_shaders->setEnabled(
Settings::values.use_asynchronous_shaders.UsingGlobal());
ui->use_fast_gpu_time->setEnabled(Settings::values.use_fast_gpu_time.UsingGlobal());
- ui->use_caches_gc->setEnabled(Settings::values.use_caches_gc.UsingGlobal());
ui->anisotropic_filtering_combobox->setEnabled(
Settings::values.max_anisotropy.UsingGlobal());
@@ -94,8 +90,6 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() {
use_asynchronous_shaders);
ConfigurationShared::SetColoredTristate(ui->use_fast_gpu_time,
Settings::values.use_fast_gpu_time, use_fast_gpu_time);
- ConfigurationShared::SetColoredTristate(ui->use_caches_gc, Settings::values.use_caches_gc,
- use_caches_gc);
ConfigurationShared::SetColoredComboBox(
ui->gpu_accuracy, ui->label_gpu_accuracy,
static_cast<int>(Settings::values.gpu_accuracy.GetValue(true)));
diff --git a/src/yuzu/configuration/configure_graphics_advanced.h b/src/yuzu/configuration/configure_graphics_advanced.h
index 7356e6916..13ba4ff6b 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.h
+++ b/src/yuzu/configuration/configure_graphics_advanced.h
@@ -37,5 +37,4 @@ private:
ConfigurationShared::CheckState use_vsync;
ConfigurationShared::CheckState use_asynchronous_shaders;
ConfigurationShared::CheckState use_fast_gpu_time;
- ConfigurationShared::CheckState use_caches_gc;
};
diff --git a/src/yuzu/configuration/configure_graphics_advanced.ui b/src/yuzu/configuration/configure_graphics_advanced.ui
index 4fe6b86ae..5891f8299 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.ui
+++ b/src/yuzu/configuration/configure_graphics_advanced.ui
@@ -97,16 +97,6 @@
</widget>
</item>
<item>
- <widget class="QCheckBox" name="use_caches_gc">
- <property name="toolTip">
- <string>Enables garbage collection for the GPU caches, this will try to keep VRAM within 3-4 GB by flushing the least used textures/buffers. May cause issues in a few games.</string>
- </property>
- <property name="text">
- <string>Enable GPU cache garbage collection (experimental)</string>
- </property>
- </widget>
- </item>
- <item>
<widget class="QWidget" name="af_layout" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_1">
<property name="leftMargin">
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index 4f14be524..757dd1ea0 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -468,7 +468,6 @@ void Config::ReadValues() {
ReadSetting("Renderer", Settings::values.use_nvdec_emulation);
ReadSetting("Renderer", Settings::values.accelerate_astc);
ReadSetting("Renderer", Settings::values.use_fast_gpu_time);
- ReadSetting("Renderer", Settings::values.use_caches_gc);
ReadSetting("Renderer", Settings::values.bg_red);
ReadSetting("Renderer", Settings::values.bg_green);