early-access version 3607
This commit is contained in:
parent
4b0bc86485
commit
fb62880b38
11 changed files with 2039 additions and 177 deletions
|
@ -1,7 +1,7 @@
|
||||||
yuzu emulator early access
|
yuzu emulator early access
|
||||||
=============
|
=============
|
||||||
|
|
||||||
This is the source code for early-access 3606.
|
This is the source code for early-access 3607.
|
||||||
|
|
||||||
## Legal Notice
|
## Legal Notice
|
||||||
|
|
||||||
|
|
|
@ -3,18 +3,14 @@
|
||||||
|
|
||||||
#if __cpp_lib_chrono >= 201907L
|
#if __cpp_lib_chrono >= 201907L
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#else
|
|
||||||
#include <ctime>
|
|
||||||
#include <limits>
|
|
||||||
#endif
|
#endif
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <fmt/chrono.h>
|
|
||||||
#include <fmt/core.h>
|
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/fs/path_util.h"
|
#include "common/fs/path_util.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
|
#include "common/time_zone.h"
|
||||||
|
|
||||||
namespace Settings {
|
namespace Settings {
|
||||||
|
|
||||||
|
@ -22,83 +18,22 @@ Values values;
|
||||||
static bool configuring_global = true;
|
static bool configuring_global = true;
|
||||||
|
|
||||||
std::string GetTimeZoneString() {
|
std::string GetTimeZoneString() {
|
||||||
static constexpr std::array timezones{
|
|
||||||
"GMT", "GMT", "CET", "CST6CDT", "Cuba", "EET", "Egypt", "Eire",
|
|
||||||
"EST", "EST5EDT", "GB", "GB-Eire", "GMT", "GMT+0", "GMT-0", "GMT0",
|
|
||||||
"Greenwich", "Hongkong", "HST", "Iceland", "Iran", "Israel", "Jamaica", "Japan",
|
|
||||||
"Kwajalein", "Libya", "MET", "MST", "MST7MDT", "Navajo", "NZ", "NZ-CHAT",
|
|
||||||
"Poland", "Portugal", "PRC", "PST8PDT", "ROC", "ROK", "Singapore", "Turkey",
|
|
||||||
"UCT", "Universal", "UTC", "W-SU", "WET", "Zulu",
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto time_zone_index = static_cast<std::size_t>(values.time_zone_index.GetValue());
|
const auto time_zone_index = static_cast<std::size_t>(values.time_zone_index.GetValue());
|
||||||
ASSERT(time_zone_index < timezones.size());
|
ASSERT(time_zone_index < Common::TimeZone::GetTimeZoneStrings().size());
|
||||||
|
|
||||||
std::string location_name;
|
std::string location_name;
|
||||||
switch (time_zone_index) {
|
if (time_zone_index == 0) { // Auto
|
||||||
case 0: { // Auto
|
|
||||||
#if __cpp_lib_chrono >= 201907L
|
#if __cpp_lib_chrono >= 201907L
|
||||||
const struct std::chrono::tzdb& time_zone_data = std::chrono::get_tzdb();
|
const struct std::chrono::tzdb& time_zone_data = std::chrono::get_tzdb();
|
||||||
const std::chrono::time_zone* current_zone = time_zone_data.current_zone();
|
const std::chrono::time_zone* current_zone = time_zone_data.current_zone();
|
||||||
std::string_view current_zone_name = current_zone->name();
|
std::string_view current_zone_name = current_zone->name();
|
||||||
location_name = current_zone_name;
|
location_name = current_zone_name;
|
||||||
#elif defined(MINGW)
|
|
||||||
// MinGW has broken strftime -- https://sourceforge.net/p/mingw-w64/bugs/793/
|
|
||||||
// e.g. fmt::format("{:%z}") -- returns "Eastern Daylight Time" when it should be "-0400"
|
|
||||||
location_name = timezones[0];
|
|
||||||
break;
|
|
||||||
#else
|
#else
|
||||||
static constexpr std::array offsets{
|
location_name = Common::TimeZone::FindSystemTimeZone();
|
||||||
0, 0, 3600, -21600, -19768, 7200, 7509, -1521, -18000, -18000,
|
|
||||||
-75, -75, 0, 0, 0, 0, 0, 27402, -36000, -968,
|
|
||||||
12344, 8454, -18430, 33539, 40160, 3164, 3600, -25200, -25200, -25196,
|
|
||||||
41944, 44028, 5040, -2205, 29143, -28800, 29160, 30472, 24925, 6952,
|
|
||||||
0, 0, 0, 9017, 0, 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
static constexpr std::array dst{
|
|
||||||
false, false, true, true, true, true, true, true, false, true, true, true,
|
|
||||||
false, false, false, false, false, true, false, false, true, true, true, true,
|
|
||||||
false, true, true, false, true, true, true, true, true, true, true, true,
|
|
||||||
true, true, true, true, false, false, false, true, true, false,
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto now = std::time(nullptr);
|
|
||||||
const struct std::tm& local = *std::localtime(&now);
|
|
||||||
const std::string clock_offset_s = fmt::format("{:%z}", local);
|
|
||||||
if (clock_offset_s.empty()) {
|
|
||||||
location_name = timezones[0];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
const int hours_offset = std::stoi(clock_offset_s) / 100;
|
|
||||||
const int minutes_offset = std::stoi(clock_offset_s) - hours_offset * 100;
|
|
||||||
const int system_offset =
|
|
||||||
hours_offset * 3600 + minutes_offset * 60 - (local.tm_isdst ? 3600 : 0);
|
|
||||||
|
|
||||||
int min = std::numeric_limits<int>::max();
|
|
||||||
int min_index = -1;
|
|
||||||
for (u32 i = 2; i < offsets.size(); i++) {
|
|
||||||
// Skip if system is celebrating DST but considered time zone does not
|
|
||||||
if (local.tm_isdst && !dst[i]) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto offset = offsets[i];
|
|
||||||
const int difference = std::abs(std::abs(offset) - std::abs(system_offset));
|
|
||||||
if (difference < min) {
|
|
||||||
min = difference;
|
|
||||||
min_index = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
location_name = timezones[min_index];
|
|
||||||
#endif
|
#endif
|
||||||
break;
|
} else {
|
||||||
|
location_name = Common::TimeZone::GetTimeZoneStrings()[time_zone_index];
|
||||||
}
|
}
|
||||||
default:
|
|
||||||
location_name = timezones[time_zone_index];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return location_name;
|
return location_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,12 +4,29 @@
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <fmt/chrono.h>
|
||||||
|
#include <fmt/core.h>
|
||||||
|
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
|
#include "common/settings.h"
|
||||||
#include "common/time_zone.h"
|
#include "common/time_zone.h"
|
||||||
|
|
||||||
namespace Common::TimeZone {
|
namespace Common::TimeZone {
|
||||||
|
|
||||||
|
// Time zone strings
|
||||||
|
constexpr std::array timezones{
|
||||||
|
"GMT", "GMT", "CET", "CST6CDT", "Cuba", "EET", "Egypt", "Eire",
|
||||||
|
"EST", "EST5EDT", "GB", "GB-Eire", "GMT", "GMT+0", "GMT-0", "GMT0",
|
||||||
|
"Greenwich", "Hongkong", "HST", "Iceland", "Iran", "Israel", "Jamaica", "Japan",
|
||||||
|
"Kwajalein", "Libya", "MET", "MST", "MST7MDT", "Navajo", "NZ", "NZ-CHAT",
|
||||||
|
"Poland", "Portugal", "PRC", "PST8PDT", "ROC", "ROK", "Singapore", "Turkey",
|
||||||
|
"UCT", "Universal", "UTC", "W-SU", "WET", "Zulu",
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::array<const char*, 46>& GetTimeZoneStrings() {
|
||||||
|
return timezones;
|
||||||
|
}
|
||||||
|
|
||||||
std::string GetDefaultTimeZone() {
|
std::string GetDefaultTimeZone() {
|
||||||
return "GMT";
|
return "GMT";
|
||||||
}
|
}
|
||||||
|
@ -18,10 +35,7 @@ static std::string GetOsTimeZoneOffset() {
|
||||||
const std::time_t t{std::time(nullptr)};
|
const std::time_t t{std::time(nullptr)};
|
||||||
const std::tm tm{*std::localtime(&t)};
|
const std::tm tm{*std::localtime(&t)};
|
||||||
|
|
||||||
std::stringstream ss;
|
return fmt::format("{:%z}", tm);
|
||||||
ss << std::put_time(&tm, "%z"); // Get the current timezone offset, e.g. "-400", as a string
|
|
||||||
|
|
||||||
return ss.str();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ConvertOsTimeZoneOffsetToInt(const std::string& timezone) {
|
static int ConvertOsTimeZoneOffsetToInt(const std::string& timezone) {
|
||||||
|
@ -45,4 +59,58 @@ std::chrono::seconds GetCurrentOffsetSeconds() {
|
||||||
return std::chrono::seconds{seconds};
|
return std::chrono::seconds{seconds};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string FindSystemTimeZone() {
|
||||||
|
#if defined(MINGW)
|
||||||
|
// MinGW has broken strftime -- https://sourceforge.net/p/mingw-w64/bugs/793/
|
||||||
|
// e.g. fmt::format("{:%z}") -- returns "Eastern Daylight Time" when it should be "-0400"
|
||||||
|
return timezones[0];
|
||||||
|
#else
|
||||||
|
// Time zone offset in seconds from GMT
|
||||||
|
constexpr std::array offsets{
|
||||||
|
0, 0, 3600, -21600, -19768, 7200, 7509, -1521, -18000, -18000, -75, -75,
|
||||||
|
0, 0, 0, 0, 0, 27402, -36000, -968, 12344, 8454, -18430, 33539,
|
||||||
|
40160, 3164, 3600, -25200, -25200, -25196, 41944, 44028, 5040, -2205, 29143, -28800,
|
||||||
|
29160, 30472, 24925, 6952, 0, 0, 0, 9017, 0, 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
// If the time zone recognizes Daylight Savings Time
|
||||||
|
constexpr std::array dst{
|
||||||
|
false, false, true, true, true, true, true, true, false, true, true, true,
|
||||||
|
false, false, false, false, false, true, false, false, true, true, true, true,
|
||||||
|
false, true, true, false, true, true, true, true, true, true, true, true,
|
||||||
|
true, true, true, true, false, false, false, true, true, false,
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::string system_time_zone_cached{};
|
||||||
|
if (!system_time_zone_cached.empty()) {
|
||||||
|
return system_time_zone_cached;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto now = std::time(nullptr);
|
||||||
|
const struct std::tm& local = *std::localtime(&now);
|
||||||
|
|
||||||
|
const s64 system_offset = GetCurrentOffsetSeconds().count() - (local.tm_isdst ? 3600 : 0);
|
||||||
|
|
||||||
|
int min = std::numeric_limits<int>::max();
|
||||||
|
int min_index = -1;
|
||||||
|
for (u32 i = 2; i < offsets.size(); i++) {
|
||||||
|
// Skip if system is celebrating DST but considered time zone does not
|
||||||
|
if (local.tm_isdst && !dst[i]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto offset = offsets[i];
|
||||||
|
const int difference =
|
||||||
|
static_cast<int>(std::abs(std::abs(offset) - std::abs(system_offset)));
|
||||||
|
if (difference < min) {
|
||||||
|
min = difference;
|
||||||
|
min_index = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
system_time_zone_cached = GetTimeZoneStrings()[min_index];
|
||||||
|
return system_time_zone_cached;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Common::TimeZone
|
} // namespace Common::TimeZone
|
||||||
|
|
|
@ -3,15 +3,21 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace Common::TimeZone {
|
namespace Common::TimeZone {
|
||||||
|
|
||||||
|
[[nodiscard]] const std::array<const char*, 46>& GetTimeZoneStrings();
|
||||||
|
|
||||||
/// Gets the default timezone, i.e. "GMT"
|
/// Gets the default timezone, i.e. "GMT"
|
||||||
[[nodiscard]] std::string GetDefaultTimeZone();
|
[[nodiscard]] std::string GetDefaultTimeZone();
|
||||||
|
|
||||||
/// Gets the offset of the current timezone (from the default), in seconds
|
/// Gets the offset of the current timezone (from the default), in seconds
|
||||||
[[nodiscard]] std::chrono::seconds GetCurrentOffsetSeconds();
|
[[nodiscard]] std::chrono::seconds GetCurrentOffsetSeconds();
|
||||||
|
|
||||||
|
/// Searches time zone offsets for the closest offset to the system time zone
|
||||||
|
[[nodiscard]] std::string FindSystemTimeZone();
|
||||||
|
|
||||||
} // namespace Common::TimeZone
|
} // namespace Common::TimeZone
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -125,7 +125,14 @@ Result TimeZoneContentManager::GetTimeZoneInfoFile(const std::string& location_n
|
||||||
|
|
||||||
vfs_file = zoneinfo_dir->GetFileRelative(location_name);
|
vfs_file = zoneinfo_dir->GetFileRelative(location_name);
|
||||||
if (!vfs_file) {
|
if (!vfs_file) {
|
||||||
LOG_ERROR(Service_Time, "{:016X} has no file \"{}\"! Using default timezone.",
|
LOG_WARNING(Service_Time, "{:016X} has no file \"{}\"! Using system timezone.",
|
||||||
|
time_zone_binary_titleid, location_name);
|
||||||
|
const std::string system_time_zone{Common::TimeZone::FindSystemTimeZone()};
|
||||||
|
vfs_file = zoneinfo_dir->GetFile(system_time_zone);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!vfs_file) {
|
||||||
|
LOG_WARNING(Service_Time, "{:016X} has no file \"{}\"! Using default timezone.",
|
||||||
time_zone_binary_titleid, location_name);
|
time_zone_binary_titleid, location_name);
|
||||||
vfs_file = zoneinfo_dir->GetFile(Common::TimeZone::GetDefaultTimeZone());
|
vfs_file = zoneinfo_dir->GetFile(Common::TimeZone::GetDefaultTimeZone());
|
||||||
}
|
}
|
||||||
|
|
|
@ -155,7 +155,7 @@ void ImageBase::CheckAliasState() {
|
||||||
flags &= ~ImageFlagBits::Alias;
|
flags &= ~ImageFlagBits::Alias;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddImageAlias(ImageBase& lhs, ImageBase& rhs, ImageId lhs_id, ImageId rhs_id) {
|
bool AddImageAlias(ImageBase& lhs, ImageBase& rhs, ImageId lhs_id, ImageId rhs_id) {
|
||||||
static constexpr auto OPTIONS = RelaxedOptions::Size | RelaxedOptions::Format;
|
static constexpr auto OPTIONS = RelaxedOptions::Size | RelaxedOptions::Format;
|
||||||
ASSERT(lhs.info.type == rhs.info.type);
|
ASSERT(lhs.info.type == rhs.info.type);
|
||||||
std::optional<SubresourceBase> base;
|
std::optional<SubresourceBase> base;
|
||||||
|
@ -169,7 +169,7 @@ void AddImageAlias(ImageBase& lhs, ImageBase& rhs, ImageId lhs_id, ImageId rhs_i
|
||||||
}
|
}
|
||||||
if (!base) {
|
if (!base) {
|
||||||
LOG_ERROR(HW_GPU, "Image alias should have been flipped");
|
LOG_ERROR(HW_GPU, "Image alias should have been flipped");
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
const PixelFormat lhs_format = lhs.info.format;
|
const PixelFormat lhs_format = lhs.info.format;
|
||||||
const PixelFormat rhs_format = rhs.info.format;
|
const PixelFormat rhs_format = rhs.info.format;
|
||||||
|
@ -248,12 +248,13 @@ void AddImageAlias(ImageBase& lhs, ImageBase& rhs, ImageId lhs_id, ImageId rhs_i
|
||||||
}
|
}
|
||||||
ASSERT(lhs_alias.copies.empty() == rhs_alias.copies.empty());
|
ASSERT(lhs_alias.copies.empty() == rhs_alias.copies.empty());
|
||||||
if (lhs_alias.copies.empty()) {
|
if (lhs_alias.copies.empty()) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
lhs.aliased_images.push_back(std::move(lhs_alias));
|
lhs.aliased_images.push_back(std::move(lhs_alias));
|
||||||
rhs.aliased_images.push_back(std::move(rhs_alias));
|
rhs.aliased_images.push_back(std::move(rhs_alias));
|
||||||
lhs.flags &= ~ImageFlagBits::IsRescalable;
|
lhs.flags &= ~ImageFlagBits::IsRescalable;
|
||||||
rhs.flags &= ~ImageFlagBits::IsRescalable;
|
rhs.flags &= ~ImageFlagBits::IsRescalable;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace VideoCommon
|
} // namespace VideoCommon
|
||||||
|
|
|
@ -142,6 +142,6 @@ struct ImageAllocBase {
|
||||||
std::vector<ImageId> images;
|
std::vector<ImageId> images;
|
||||||
};
|
};
|
||||||
|
|
||||||
void AddImageAlias(ImageBase& lhs, ImageBase& rhs, ImageId lhs_id, ImageId rhs_id);
|
bool AddImageAlias(ImageBase& lhs, ImageBase& rhs, ImageId lhs_id, ImageId rhs_id);
|
||||||
|
|
||||||
} // namespace VideoCommon
|
} // namespace VideoCommon
|
||||||
|
|
|
@ -1312,17 +1312,18 @@ ImageId TextureCache<P>::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, VA
|
||||||
const size_t size_bytes = CalculateGuestSizeInBytes(new_info);
|
const size_t size_bytes = CalculateGuestSizeInBytes(new_info);
|
||||||
const bool broken_views = runtime.HasBrokenTextureViewFormats();
|
const bool broken_views = runtime.HasBrokenTextureViewFormats();
|
||||||
const bool native_bgr = runtime.HasNativeBgr();
|
const bool native_bgr = runtime.HasNativeBgr();
|
||||||
boost::container::small_vector<ImageId, 4> overlap_ids;
|
join_overlap_ids.clear();
|
||||||
std::unordered_set<ImageId> overlaps_found;
|
join_overlaps_found.clear();
|
||||||
boost::container::small_vector<ImageId, 4> left_aliased_ids;
|
join_left_aliased_ids.clear();
|
||||||
boost::container::small_vector<ImageId, 4> right_aliased_ids;
|
join_right_aliased_ids.clear();
|
||||||
std::unordered_set<ImageId> ignore_textures;
|
join_ignore_textures.clear();
|
||||||
boost::container::small_vector<ImageId, 4> bad_overlap_ids;
|
join_bad_overlap_ids.clear();
|
||||||
boost::container::small_vector<ImageId, 4> all_siblings;
|
join_copies_to_do.clear();
|
||||||
|
join_alias_indices.clear();
|
||||||
const bool this_is_linear = info.type == ImageType::Linear;
|
const bool this_is_linear = info.type == ImageType::Linear;
|
||||||
const auto region_check = [&](ImageId overlap_id, ImageBase& overlap) {
|
const auto region_check = [&](ImageId overlap_id, ImageBase& overlap) {
|
||||||
if (True(overlap.flags & ImageFlagBits::Remapped)) {
|
if (True(overlap.flags & ImageFlagBits::Remapped)) {
|
||||||
ignore_textures.insert(overlap_id);
|
join_ignore_textures.insert(overlap_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const bool overlap_is_linear = overlap.info.type == ImageType::Linear;
|
const bool overlap_is_linear = overlap.info.type == ImageType::Linear;
|
||||||
|
@ -1332,11 +1333,11 @@ ImageId TextureCache<P>::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, VA
|
||||||
if (this_is_linear && overlap_is_linear) {
|
if (this_is_linear && overlap_is_linear) {
|
||||||
if (info.pitch == overlap.info.pitch && gpu_addr == overlap.gpu_addr) {
|
if (info.pitch == overlap.info.pitch && gpu_addr == overlap.gpu_addr) {
|
||||||
// Alias linear images with the same pitch
|
// Alias linear images with the same pitch
|
||||||
left_aliased_ids.push_back(overlap_id);
|
join_left_aliased_ids.push_back(overlap_id);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
overlaps_found.insert(overlap_id);
|
join_overlaps_found.insert(overlap_id);
|
||||||
static constexpr bool strict_size = true;
|
static constexpr bool strict_size = true;
|
||||||
const std::optional<OverlapResult> solution = ResolveOverlap(
|
const std::optional<OverlapResult> solution = ResolveOverlap(
|
||||||
new_info, gpu_addr, cpu_addr, overlap, strict_size, broken_views, native_bgr);
|
new_info, gpu_addr, cpu_addr, overlap, strict_size, broken_views, native_bgr);
|
||||||
|
@ -1344,33 +1345,33 @@ ImageId TextureCache<P>::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, VA
|
||||||
gpu_addr = solution->gpu_addr;
|
gpu_addr = solution->gpu_addr;
|
||||||
cpu_addr = solution->cpu_addr;
|
cpu_addr = solution->cpu_addr;
|
||||||
new_info.resources = solution->resources;
|
new_info.resources = solution->resources;
|
||||||
overlap_ids.push_back(overlap_id);
|
join_overlap_ids.push_back(overlap_id);
|
||||||
all_siblings.push_back(overlap_id);
|
join_copies_to_do.emplace_back(JoinCopy{false, overlap_id});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
static constexpr auto options = RelaxedOptions::Size | RelaxedOptions::Format;
|
static constexpr auto options = RelaxedOptions::Size | RelaxedOptions::Format;
|
||||||
const ImageBase new_image_base(new_info, gpu_addr, cpu_addr);
|
const ImageBase new_image_base(new_info, gpu_addr, cpu_addr);
|
||||||
if (IsSubresource(new_info, overlap, gpu_addr, options, broken_views, native_bgr)) {
|
if (IsSubresource(new_info, overlap, gpu_addr, options, broken_views, native_bgr)) {
|
||||||
left_aliased_ids.push_back(overlap_id);
|
join_left_aliased_ids.push_back(overlap_id);
|
||||||
overlap.flags |= ImageFlagBits::Alias;
|
overlap.flags |= ImageFlagBits::Alias;
|
||||||
all_siblings.push_back(overlap_id);
|
join_copies_to_do.emplace_back(JoinCopy{true, overlap_id});
|
||||||
} else if (IsSubresource(overlap.info, new_image_base, overlap.gpu_addr, options,
|
} else if (IsSubresource(overlap.info, new_image_base, overlap.gpu_addr, options,
|
||||||
broken_views, native_bgr)) {
|
broken_views, native_bgr)) {
|
||||||
right_aliased_ids.push_back(overlap_id);
|
join_right_aliased_ids.push_back(overlap_id);
|
||||||
overlap.flags |= ImageFlagBits::Alias;
|
overlap.flags |= ImageFlagBits::Alias;
|
||||||
all_siblings.push_back(overlap_id);
|
join_copies_to_do.emplace_back(JoinCopy{true, overlap_id});
|
||||||
} else {
|
} else {
|
||||||
bad_overlap_ids.push_back(overlap_id);
|
join_bad_overlap_ids.push_back(overlap_id);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
ForEachImageInRegion(cpu_addr, size_bytes, region_check);
|
ForEachImageInRegion(cpu_addr, size_bytes, region_check);
|
||||||
const auto region_check_gpu = [&](ImageId overlap_id, ImageBase& overlap) {
|
const auto region_check_gpu = [&](ImageId overlap_id, ImageBase& overlap) {
|
||||||
if (!overlaps_found.contains(overlap_id)) {
|
if (!join_overlaps_found.contains(overlap_id)) {
|
||||||
if (True(overlap.flags & ImageFlagBits::Remapped)) {
|
if (True(overlap.flags & ImageFlagBits::Remapped)) {
|
||||||
ignore_textures.insert(overlap_id);
|
join_ignore_textures.insert(overlap_id);
|
||||||
}
|
}
|
||||||
if (overlap.gpu_addr == gpu_addr && overlap.guest_size_bytes == size_bytes) {
|
if (overlap.gpu_addr == gpu_addr && overlap.guest_size_bytes == size_bytes) {
|
||||||
ignore_textures.insert(overlap_id);
|
join_ignore_textures.insert(overlap_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1378,11 +1379,11 @@ ImageId TextureCache<P>::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, VA
|
||||||
|
|
||||||
bool can_rescale = info.rescaleable;
|
bool can_rescale = info.rescaleable;
|
||||||
bool any_rescaled = false;
|
bool any_rescaled = false;
|
||||||
for (const ImageId sibling_id : all_siblings) {
|
for (const auto& copy : join_copies_to_do) {
|
||||||
if (!can_rescale) {
|
if (!can_rescale) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Image& sibling = slot_images[sibling_id];
|
Image& sibling = slot_images[copy.id];
|
||||||
can_rescale &= ImageCanRescale(sibling);
|
can_rescale &= ImageCanRescale(sibling);
|
||||||
any_rescaled |= True(sibling.flags & ImageFlagBits::Rescaled);
|
any_rescaled |= True(sibling.flags & ImageFlagBits::Rescaled);
|
||||||
}
|
}
|
||||||
|
@ -1390,13 +1391,13 @@ ImageId TextureCache<P>::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, VA
|
||||||
can_rescale &= any_rescaled;
|
can_rescale &= any_rescaled;
|
||||||
|
|
||||||
if (can_rescale) {
|
if (can_rescale) {
|
||||||
for (const ImageId sibling_id : all_siblings) {
|
for (const auto& copy : join_copies_to_do) {
|
||||||
Image& sibling = slot_images[sibling_id];
|
Image& sibling = slot_images[copy.id];
|
||||||
ScaleUp(sibling);
|
ScaleUp(sibling);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (const ImageId sibling_id : all_siblings) {
|
for (const auto& copy : join_copies_to_do) {
|
||||||
Image& sibling = slot_images[sibling_id];
|
Image& sibling = slot_images[copy.id];
|
||||||
ScaleDown(sibling);
|
ScaleDown(sibling);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1408,7 +1409,7 @@ ImageId TextureCache<P>::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, VA
|
||||||
new_image.flags |= ImageFlagBits::Sparse;
|
new_image.flags |= ImageFlagBits::Sparse;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const ImageId overlap_id : ignore_textures) {
|
for (const ImageId overlap_id : join_ignore_textures) {
|
||||||
Image& overlap = slot_images[overlap_id];
|
Image& overlap = slot_images[overlap_id];
|
||||||
if (True(overlap.flags & ImageFlagBits::GpuModified)) {
|
if (True(overlap.flags & ImageFlagBits::GpuModified)) {
|
||||||
UNIMPLEMENTED();
|
UNIMPLEMENTED();
|
||||||
|
@ -1429,14 +1430,58 @@ ImageId TextureCache<P>::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, VA
|
||||||
ScaleDown(new_image);
|
ScaleDown(new_image);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ranges::sort(overlap_ids, [this](const ImageId lhs, const ImageId rhs) {
|
std::ranges::sort(join_copies_to_do, [this](const JoinCopy& lhs, const JoinCopy& rhs) {
|
||||||
const ImageBase& lhs_image = slot_images[lhs];
|
const ImageBase& lhs_image = slot_images[lhs.id];
|
||||||
const ImageBase& rhs_image = slot_images[rhs];
|
const ImageBase& rhs_image = slot_images[rhs.id];
|
||||||
return lhs_image.modification_tick < rhs_image.modification_tick;
|
return lhs_image.modification_tick < rhs_image.modification_tick;
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const ImageId overlap_id : overlap_ids) {
|
ImageBase& new_image_base = new_image;
|
||||||
Image& overlap = slot_images[overlap_id];
|
for (const ImageId aliased_id : join_right_aliased_ids) {
|
||||||
|
ImageBase& aliased = slot_images[aliased_id];
|
||||||
|
size_t alias_index = new_image_base.aliased_images.size();
|
||||||
|
if (!AddImageAlias(new_image_base, aliased, new_image_id, aliased_id)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
join_alias_indices.emplace(aliased_id, alias_index);
|
||||||
|
new_image.flags |= ImageFlagBits::Alias;
|
||||||
|
}
|
||||||
|
for (const ImageId aliased_id : join_left_aliased_ids) {
|
||||||
|
ImageBase& aliased = slot_images[aliased_id];
|
||||||
|
size_t alias_index = new_image_base.aliased_images.size();
|
||||||
|
if (!AddImageAlias(aliased, new_image_base, aliased_id, new_image_id)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
join_alias_indices.emplace(aliased_id, alias_index);
|
||||||
|
new_image.flags |= ImageFlagBits::Alias;
|
||||||
|
}
|
||||||
|
for (const ImageId aliased_id : join_bad_overlap_ids) {
|
||||||
|
ImageBase& aliased = slot_images[aliased_id];
|
||||||
|
aliased.overlapping_images.push_back(new_image_id);
|
||||||
|
new_image.overlapping_images.push_back(aliased_id);
|
||||||
|
if (aliased.info.resources.levels == 1 && aliased.overlapping_images.size() > 1) {
|
||||||
|
aliased.flags |= ImageFlagBits::BadOverlap;
|
||||||
|
}
|
||||||
|
if (new_image.info.resources.levels == 1 && new_image.overlapping_images.size() > 1) {
|
||||||
|
new_image.flags |= ImageFlagBits::BadOverlap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& copy_object : join_copies_to_do) {
|
||||||
|
Image& overlap = slot_images[copy_object.id];
|
||||||
|
if (copy_object.is_alias) {
|
||||||
|
if (False(overlap.flags & ImageFlagBits::GpuModified)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const auto alias_pointer = join_alias_indices.find(copy_object.id);
|
||||||
|
if (alias_pointer == join_alias_indices.end()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const AliasedImage& aliased = new_image.aliased_images[alias_pointer->second];
|
||||||
|
CopyImage(new_image_id, aliased.id, aliased.copies);
|
||||||
|
new_image.modification_tick = overlap.modification_tick;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (True(overlap.flags & ImageFlagBits::GpuModified)) {
|
if (True(overlap.flags & ImageFlagBits::GpuModified)) {
|
||||||
new_image.flags |= ImageFlagBits::GpuModified;
|
new_image.flags |= ImageFlagBits::GpuModified;
|
||||||
const auto& resolution = Settings::values.resolution_info;
|
const auto& resolution = Settings::values.resolution_info;
|
||||||
|
@ -1449,35 +1494,15 @@ ImageId TextureCache<P>::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, VA
|
||||||
} else {
|
} else {
|
||||||
runtime.CopyImage(new_image, overlap, std::move(copies));
|
runtime.CopyImage(new_image, overlap, std::move(copies));
|
||||||
}
|
}
|
||||||
|
new_image.modification_tick = overlap.modification_tick;
|
||||||
}
|
}
|
||||||
if (True(overlap.flags & ImageFlagBits::Tracked)) {
|
if (True(overlap.flags & ImageFlagBits::Tracked)) {
|
||||||
UntrackImage(overlap, overlap_id);
|
UntrackImage(overlap, copy_object.id);
|
||||||
}
|
|
||||||
UnregisterImage(overlap_id);
|
|
||||||
DeleteImage(overlap_id);
|
|
||||||
}
|
|
||||||
ImageBase& new_image_base = new_image;
|
|
||||||
for (const ImageId aliased_id : right_aliased_ids) {
|
|
||||||
ImageBase& aliased = slot_images[aliased_id];
|
|
||||||
AddImageAlias(new_image_base, aliased, new_image_id, aliased_id);
|
|
||||||
new_image.flags |= ImageFlagBits::Alias;
|
|
||||||
}
|
|
||||||
for (const ImageId aliased_id : left_aliased_ids) {
|
|
||||||
ImageBase& aliased = slot_images[aliased_id];
|
|
||||||
AddImageAlias(aliased, new_image_base, aliased_id, new_image_id);
|
|
||||||
new_image.flags |= ImageFlagBits::Alias;
|
|
||||||
}
|
|
||||||
for (const ImageId aliased_id : bad_overlap_ids) {
|
|
||||||
ImageBase& aliased = slot_images[aliased_id];
|
|
||||||
aliased.overlapping_images.push_back(new_image_id);
|
|
||||||
new_image.overlapping_images.push_back(aliased_id);
|
|
||||||
if (aliased.info.resources.levels == 1 && aliased.overlapping_images.size() > 1) {
|
|
||||||
aliased.flags |= ImageFlagBits::BadOverlap;
|
|
||||||
}
|
|
||||||
if (new_image.info.resources.levels == 1 && new_image.overlapping_images.size() > 1) {
|
|
||||||
new_image.flags |= ImageFlagBits::BadOverlap;
|
|
||||||
}
|
}
|
||||||
|
UnregisterImage(copy_object.id);
|
||||||
|
DeleteImage(copy_object.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
RegisterImage(new_image_id);
|
RegisterImage(new_image_id);
|
||||||
return new_image_id;
|
return new_image_id;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,9 @@
|
||||||
#include <span>
|
#include <span>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <boost/container/small_vector.hpp>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
@ -477,6 +479,20 @@ private:
|
||||||
|
|
||||||
Common::ThreadWorker texture_decode_worker{1, "TextureDecoder"};
|
Common::ThreadWorker texture_decode_worker{1, "TextureDecoder"};
|
||||||
std::vector<std::unique_ptr<AsyncDecodeContext>> async_decodes;
|
std::vector<std::unique_ptr<AsyncDecodeContext>> async_decodes;
|
||||||
|
|
||||||
|
// Join caching
|
||||||
|
boost::container::small_vector<ImageId, 4> join_overlap_ids;
|
||||||
|
std::unordered_set<ImageId> join_overlaps_found;
|
||||||
|
boost::container::small_vector<ImageId, 4> join_left_aliased_ids;
|
||||||
|
boost::container::small_vector<ImageId, 4> join_right_aliased_ids;
|
||||||
|
std::unordered_set<ImageId> join_ignore_textures;
|
||||||
|
boost::container::small_vector<ImageId, 4> join_bad_overlap_ids;
|
||||||
|
struct JoinCopy {
|
||||||
|
bool is_alias;
|
||||||
|
ImageId id;
|
||||||
|
};
|
||||||
|
boost::container::small_vector<JoinCopy, 4> join_copies_to_do;
|
||||||
|
std::unordered_map<ImageId, size_t> join_alias_indices;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace VideoCommon
|
} // namespace VideoCommon
|
||||||
|
|
|
@ -473,11 +473,12 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
|
||||||
}
|
}
|
||||||
if (extensions.push_descriptor && is_intel_anv) {
|
if (extensions.push_descriptor && is_intel_anv) {
|
||||||
const u32 version = (properties.properties.driverVersion << 3) >> 3;
|
const u32 version = (properties.properties.driverVersion << 3) >> 3;
|
||||||
if (version >= VK_MAKE_API_VERSION(0, 22, 3, 0)) {
|
if (version >= VK_MAKE_API_VERSION(0, 22, 3, 0) &&
|
||||||
|
version < VK_MAKE_API_VERSION(0, 23, 2, 0)) {
|
||||||
// Disable VK_KHR_push_descriptor due to
|
// Disable VK_KHR_push_descriptor due to
|
||||||
// mesa/mesa/-/commit/ff91c5ca42bc80aa411cb3fd8f550aa6fdd16bdc
|
// mesa/mesa/-/commit/ff91c5ca42bc80aa411cb3fd8f550aa6fdd16bdc
|
||||||
LOG_WARNING(Render_Vulkan,
|
LOG_WARNING(Render_Vulkan,
|
||||||
"ANV drivers 22.3.0 and later have broken VK_KHR_push_descriptor");
|
"ANV drivers 22.3.0 to 23.1.0 have broken VK_KHR_push_descriptor");
|
||||||
extensions.push_descriptor = false;
|
extensions.push_descriptor = false;
|
||||||
loaded_extensions.erase(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
|
loaded_extensions.erase(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue