Compare commits

..

4 Commits

Author SHA1 Message Date
CamilleLaVey f359a957d7 Actualizar src/android/app/build.gradle.kts 2026-07-27 03:51:51 +02:00
CamilleLaVey 412d7c4667 Meow dynos. 2026-07-26 21:51:16 +02:00
CamilleLaVey 6e3e5ba2a4 Play with Lizzie's and xbzk feelings about destroying support for dyno Android versions >:) 2026-07-26 21:51:16 +02:00
lizzie 2519329760 [android] enable usage of native ELF TLS
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-07-26 21:51:16 +02:00
17 changed files with 309 additions and 272 deletions
+1 -1
View File
@@ -65,7 +65,7 @@ android {
defaultConfig {
applicationId = "dev.eden.eden_emulator"
minSdk = 24
minSdk = 33
targetSdk = 36
versionName = getGitVersion()
versionCode = autoVersion
+97 -61
View File
@@ -20,96 +20,132 @@ struct RomMetadata {
std::vector<u8> icon;
bool isHomebrew;
};
static ankerl::unordered_dense::map<std::string, RomMetadata> m_rom_metadata_cache;
static RomMetadata CacheRomMetadata(const std::string& path) {
auto& instance = EmulationSession::GetInstance();
const auto file = Core::GetGameFileFromPath(instance.System().GetFilesystem(), path);
if (auto loader = Loader::GetLoader(instance.System(), file, 0, 0); loader) {
RomMetadata entry;
loader->ReadTitle(entry.title);
loader->ReadProgramId(entry.programId);
loader->ReadIcon(entry.icon);
ankerl::unordered_dense::map<std::string, RomMetadata> m_rom_metadata_cache;
const FileSys::PatchManager pm{
entry.programId,
instance.System().GetFileSystemController(),
instance.System().GetContentProvider()
};
const auto control = pm.GetControlMetadata();
RomMetadata CacheRomMetadata(const std::string& path) {
const auto file =
Core::GetGameFileFromPath(EmulationSession::GetInstance().System().GetFilesystem(), path);
auto loader = Loader::GetLoader(EmulationSession::GetInstance().System(), file, 0, 0);
if (control.first != nullptr) {
entry.developer = control.first->GetDeveloperName();
entry.version = control.first->GetVersionString();
RomMetadata entry;
loader->ReadTitle(entry.title);
loader->ReadProgramId(entry.programId);
loader->ReadIcon(entry.icon);
const FileSys::PatchManager pm{
entry.programId, EmulationSession::GetInstance().System().GetFileSystemController(),
EmulationSession::GetInstance().System().GetContentProvider()};
const auto control = pm.GetControlMetadata();
if (control.first != nullptr) {
entry.developer = control.first->GetDeveloperName();
entry.version = control.first->GetVersionString();
} else {
FileSys::NACP nacp;
if (loader->ReadControlData(nacp) == Loader::ResultStatus::Success) {
entry.developer = nacp.GetDeveloperName();
} else {
FileSys::NACP nacp{};
entry.developer = loader->ReadControlData(nacp) == Loader::ResultStatus::Success
? nacp.GetDeveloperName()
: "";
entry.version = "1.0.0";
entry.developer = "";
}
if (loader->GetFileType() == Loader::FileType::NRO) {
auto loader_nro = reinterpret_cast<Loader::AppLoader_NRO*>(loader.get());
entry.isHomebrew = loader_nro->IsHomebrew();
} else {
entry.isHomebrew = false;
}
m_rom_metadata_cache[path] = entry;
return entry;
entry.version = "1.0.0";
}
return {};
if (loader->GetFileType() == Loader::FileType::NRO) {
auto loader_nro = reinterpret_cast<Loader::AppLoader_NRO*>(loader.get());
entry.isHomebrew = loader_nro->IsHomebrew();
} else {
entry.isHomebrew = false;
}
m_rom_metadata_cache[path] = entry;
return entry;
}
static RomMetadata GetRomMetadata(const std::string& path, bool reload = false) {
if (reload)
RomMetadata GetRomMetadata(const std::string& path, bool reload = false) {
if (reload) {
return CacheRomMetadata(path);
if (auto it = m_rom_metadata_cache.find(path); it != m_rom_metadata_cache.end())
return it->second;
}
if (auto search = m_rom_metadata_cache.find(path); search != m_rom_metadata_cache.end()) {
return search->second;
}
return CacheRomMetadata(path);
}
extern "C" {
jboolean Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getIsValid(JNIEnv* env, jobject obj, jstring jpath) {
if (auto const file = EmulationSession::GetInstance().System().GetFilesystem()->OpenFile(Common::Android::GetJString(env, jpath), FileSys::OpenMode::Read); file) {
if (auto loader = Loader::GetLoader(EmulationSession::GetInstance().System(), file); loader) {
auto const file_type = loader->GetFileType();
if (file_type == Loader::FileType::Unknown || file_type == Loader::FileType::Error)
return false;
if ((file_type == Loader::FileType::NSP || file_type == Loader::FileType::XCI) && !Loader::IsBootableGameContainer(file, file_type))
return false;
u64 program_id = 0;
return loader->ReadProgramId(program_id) == Loader::ResultStatus::Success;
}
jboolean Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getIsValid(JNIEnv* env, jobject obj,
jstring jpath) {
const auto file = EmulationSession::GetInstance().System().GetFilesystem()->OpenFile(
Common::Android::GetJString(env, jpath), FileSys::OpenMode::Read);
if (!file) {
return false;
}
return false;
auto loader = Loader::GetLoader(EmulationSession::GetInstance().System(), file);
if (!loader) {
return false;
}
const auto file_type = loader->GetFileType();
if (file_type == Loader::FileType::Unknown || file_type == Loader::FileType::Error) {
return false;
}
if ((file_type == Loader::FileType::NSP || file_type == Loader::FileType::XCI) &&
!Loader::IsBootableGameContainer(file, file_type)) {
return false;
}
u64 program_id = 0;
Loader::ResultStatus res = loader->ReadProgramId(program_id);
if (res != Loader::ResultStatus::Success) {
return false;
}
return true;
}
jstring Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getTitle(JNIEnv* env, jobject obj, jstring jpath) {
return Common::Android::ToJString(env, GetRomMetadata(Common::Android::GetJString(env, jpath)).title);
jstring Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getTitle(JNIEnv* env, jobject obj,
jstring jpath) {
return Common::Android::ToJString(
env, GetRomMetadata(Common::Android::GetJString(env, jpath)).title);
}
jstring Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getProgramId(JNIEnv* env, jobject obj, jstring jpath) {
return Common::Android::ToJString(env, std::to_string(GetRomMetadata(Common::Android::GetJString(env, jpath)).programId));
jstring Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getProgramId(JNIEnv* env, jobject obj,
jstring jpath) {
return Common::Android::ToJString(
env, std::to_string(GetRomMetadata(Common::Android::GetJString(env, jpath)).programId));
}
jstring Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getDeveloper(JNIEnv* env, jobject obj, jstring jpath) {
return Common::Android::ToJString(env, GetRomMetadata(Common::Android::GetJString(env, jpath)).developer);
jstring Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getDeveloper(JNIEnv* env, jobject obj,
jstring jpath) {
return Common::Android::ToJString(
env, GetRomMetadata(Common::Android::GetJString(env, jpath)).developer);
}
jstring Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getVersion(JNIEnv* env, jobject obj, jstring jpath, jboolean jreload) {
return Common::Android::ToJString(env, GetRomMetadata(Common::Android::GetJString(env, jpath), jreload).version);
jstring Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getVersion(JNIEnv* env, jobject obj,
jstring jpath, jboolean jreload) {
return Common::Android::ToJString(
env, GetRomMetadata(Common::Android::GetJString(env, jpath), jreload).version);
}
jbyteArray Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getIcon(JNIEnv* env, jobject obj, jstring jpath) {
jbyteArray Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getIcon(JNIEnv* env, jobject obj,
jstring jpath) {
auto icon_data = GetRomMetadata(Common::Android::GetJString(env, jpath)).icon;
jbyteArray icon = env->NewByteArray(jsize(icon_data.size()));
env->SetByteArrayRegion(icon, 0, env->GetArrayLength(icon), reinterpret_cast<jbyte*>(icon_data.data()));
jbyteArray icon = env->NewByteArray(static_cast<jsize>(icon_data.size()));
env->SetByteArrayRegion(icon, 0, env->GetArrayLength(icon),
reinterpret_cast<jbyte*>(icon_data.data()));
return icon;
}
jboolean Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getIsHomebrew(JNIEnv* env, jobject obj, jstring jpath) {
return jboolean(GetRomMetadata(Common::Android::GetJString(env, jpath)).isHomebrew);
jboolean Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getIsHomebrew(JNIEnv* env, jobject obj,
jstring jpath) {
return static_cast<jboolean>(
GetRomMetadata(Common::Android::GetJString(env, jpath)).isHomebrew);
}
void Java_org_yuzu_yuzu_1emu_utils_GameMetadata_resetMetadata(JNIEnv* env, jobject obj) {
-8
View File
@@ -208,12 +208,4 @@ UUID UUID::MakeRandomRFC4122V4() {
return uuid;
}
UUID UUID::MakeRFC4122V5(std::span<u8, 20> sha1) {
UUID uuid{};
std::memcpy(&uuid.uuid, sha1.data(), sizeof(UUID));
uuid.uuid[8] = 0x80 | (uuid.uuid[8] & 0x3F);
uuid.uuid[6] = 0x50 | (uuid.uuid[6] & 0xF);
return uuid;
}
} // namespace Common
+20 -16
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -8,7 +5,6 @@
#include <array>
#include <functional>
#include <span>
#include <string>
#include "common/common_types.h"
@@ -90,20 +86,28 @@ struct UUID {
};
}
/// @brief Creates a random UUID.
/// @returns A random UUID.
[[nodiscard]] static UUID MakeRandom();
/**
* Creates a random UUID.
*
* @returns A random UUID.
*/
static UUID MakeRandom();
/// @brief Creates a random UUID with a seed.
/// @param seed A seed to initialize the Mersenne-Twister RNG
/// @returns A random UUID.
[[nodiscard]] static UUID MakeRandomWithSeed(u32 seed);
/**
* Creates a random UUID with a seed.
*
* @param seed A seed to initialize the Mersenne-Twister RNG
*
* @returns A random UUID.
*/
static UUID MakeRandomWithSeed(u32 seed);
/// @brief Creates a random UUID. The generated UUID is RFC 4122 Version 4 compliant.
/// @returns A random UUID that is RFC 4122 Version 4 compliant.
[[nodiscard]] static UUID MakeRandomRFC4122V4();
[[nodiscard]] static UUID MakeRFC4122V5(std::span<u8, 20> sha1);
/**
* Creates a random UUID. The generated UUID is RFC 4122 Version 4 compliant.
*
* @returns A random UUID that is RFC 4122 Version 4 compliant.
*/
static UUID MakeRandomRFC4122V4();
friend constexpr bool operator==(const UUID& lhs, const UUID& rhs) = default;
};
+16 -15
View File
@@ -274,22 +274,23 @@ public:
explicit NACP(VirtualFile file);
~NACP();
[[nodiscard]] const LanguageEntry& GetLanguageEntry() const;
[[nodiscard]] std::string GetApplicationName() const;
[[nodiscard]] std::string GetDeveloperName() const;
[[nodiscard]] u64 GetTitleId() const;
[[nodiscard]] u64 GetDLCBaseTitleId() const;
[[nodiscard]] std::string GetVersionString() const;
[[nodiscard]] u64 GetDefaultNormalSaveSize() const;
[[nodiscard]] u64 GetDefaultJournalSaveSize() const;
[[nodiscard]] u32 GetSupportedLanguages() const;
[[nodiscard]] std::vector<std::string> GetApplicationNames() const;
[[nodiscard]] std::vector<u8> GetRawBytes() const;
[[nodiscard]] bool GetUserAccountSwitchLock() const;
[[nodiscard]] u64 GetDeviceSaveDataSize() const;
[[nodiscard]] u32 GetParentalControlFlag() const;
[[nodiscard]] const std::array<u8, 0x20>& GetRatingAge() const;
const LanguageEntry& GetLanguageEntry() const;
std::string GetApplicationName() const;
std::string GetDeveloperName() const;
u64 GetTitleId() const;
u64 GetDLCBaseTitleId() const;
std::string GetVersionString() const;
u64 GetDefaultNormalSaveSize() const;
u64 GetDefaultJournalSaveSize() const;
u32 GetSupportedLanguages() const;
std::vector<std::string> GetApplicationNames() const;
std::vector<u8> GetRawBytes() const;
bool GetUserAccountSwitchLock() const;
u64 GetDeviceSaveDataSize() const;
u32 GetParentalControlFlag() const;
const std::array<u8, 0x20>& GetRatingAge() const;
private:
RawNACP raw{};
std::vector<LanguageEntry> language_entries;
};
-10
View File
@@ -1156,14 +1156,4 @@ PatchManager::Metadata PatchManager::ParseControlNCA(const NCA& nca) const {
return {std::move(nacp), icon_file};
}
[[nodiscard]] PatchManager::Metadata PatchManager::GetMetadataFromBaseOrUpdate(Core::System& system, u64 application_id) noexcept {
const FileSys::PatchManager pm{application_id, system.GetFileSystemController(), system.GetContentProvider()};
auto metadata = pm.GetControlMetadata();
if (metadata.first != nullptr)
return metadata;
const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(application_id), system.GetFileSystemController(), system.GetContentProvider()};
return pm_update.GetControlMetadata();
}
} // namespace FileSys
-3
View File
@@ -105,9 +105,6 @@ public:
// Version of GetControlMetadata that takes an arbitrary NCA
[[nodiscard]] Metadata ParseControlNCA(const NCA& nca) const;
/// @brief Gets NACP metadata (accounting for any patches or updates)
[[nodiscard]] static PatchManager::Metadata GetMetadataFromBaseOrUpdate(Core::System& system, u64 application_id) noexcept;
private:
[[nodiscard]] std::vector<VirtualFile> CollectPatches(const std::vector<VirtualDir>& patch_dirs,
const std::string& build_id) const;
@@ -4,8 +4,6 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <openssl/evp.h>
#include "common/settings.h"
#include "common/uuid.h"
#include "core/file_sys/control_metadata.h"
@@ -156,7 +154,20 @@ Result IApplicationFunctions::GetDesiredLanguage(Out<u64> out_language_code) {
// Default to 0 (all languages supported)
u32 supported_languages = 0;
const auto res = FileSys::PatchManager::GetMetadataFromBaseOrUpdate(system, m_applet->program_id);
const auto res = [this] {
const FileSys::PatchManager pm{m_applet->program_id, system.GetFileSystemController(),
system.GetContentProvider()};
auto metadata = pm.GetControlMetadata();
if (metadata.first != nullptr) {
return metadata;
}
const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(m_applet->program_id),
system.GetFileSystemController(),
system.GetContentProvider()};
return pm_update.GetControlMetadata();
}();
if (res.first != nullptr) {
supported_languages = res.first->GetSupportedLanguages();
}
@@ -194,7 +205,20 @@ Result IApplicationFunctions::SetTerminateResult(Result terminate_result) {
Result IApplicationFunctions::GetDisplayVersion(Out<DisplayVersion> out_display_version) {
LOG_DEBUG(Service_AM, "called");
const auto res = FileSys::PatchManager::GetMetadataFromBaseOrUpdate(system, m_applet->program_id);
const auto res = [this] {
const FileSys::PatchManager pm{m_applet->program_id, system.GetFileSystemController(),
system.GetContentProvider()};
auto metadata = pm.GetControlMetadata();
if (metadata.first != nullptr) {
return metadata;
}
const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(m_applet->program_id),
system.GetFileSystemController(),
system.GetContentProvider()};
return pm_update.GetControlMetadata();
}();
if (res.first != nullptr) {
const auto& version = res.first->GetVersionString();
std::memcpy(out_display_version->string.data(), version.data(),
@@ -323,21 +347,8 @@ Result IApplicationFunctions::NotifyRunning(Out<bool> out_became_running) {
}
Result IApplicationFunctions::GetPseudoDeviceId(Out<Common::UUID> out_pseudo_device_id) {
LOG_WARNING(Service_AM, "(stubbed)");
// This should be hashed with the device specific hash
// for now this will do
const auto res = FileSys::PatchManager::GetMetadataFromBaseOrUpdate(system, m_applet->program_id);
u8 hash[EVP_MAX_MD_SIZE];
unsigned int hash_len = 0;
auto const seed = res.first->raw.seed_for_pseudo_device_id;
EVP_MD_CTX *ctx = EVP_MD_CTX_new();
auto const algorithm = EVP_sha1();
EVP_DigestInit_ex(ctx, algorithm, nullptr);
EVP_DigestUpdate(ctx, &seed, sizeof(seed));
EVP_DigestFinal_ex(ctx, hash, &hash_len);
EVP_MD_CTX_free(ctx);
*out_pseudo_device_id = Common::UUID::MakeRFC4122V5(std::span<u8, 20>{hash, std::size(hash)});
LOG_WARNING(Service_AM, "(STUBBED) called");
*out_pseudo_device_id = {};
R_SUCCEED();
}
@@ -252,7 +252,19 @@ Result ILibraryAppletSelfAccessor::GetMainAppletApplicationDesiredLanguage(
// Default to 0 (all languages supported)
u32 supported_languages = 0;
const auto res = FileSys::PatchManager::GetMetadataFromBaseOrUpdate(system, identity.application_id);
const auto res = [this, identity] {
const FileSys::PatchManager pm{identity.application_id, system.GetFileSystemController(),
system.GetContentProvider()};
auto metadata = pm.GetControlMetadata();
if (metadata.first != nullptr) {
return metadata;
}
const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(identity.application_id),
system.GetFileSystemController(),
system.GetContentProvider()};
return pm_update.GetControlMetadata();
}();
if (res.first != nullptr) {
supported_languages = res.first->GetSupportedLanguages();
@@ -100,7 +100,6 @@ void EmulatedConsole::ReloadInput() {
motion.gyro = emulated_motion.GetGyroscope();
motion.rotation = emulated_motion.GetRotations();
motion.orientation = emulated_motion.GetOrientation();
motion.quaternion = emulated_motion.GetQuaternion();
motion.is_at_rest = !emulated_motion.IsMoving(motion_sensitivity);
// Unique index for identifying touch device source
+16 -16
View File
@@ -77,8 +77,14 @@ uvec4 local_buff;
uvec4 color_endpoint_data;
int color_bitsread = 0;
#define MAX_WEIGHT_VALUES 64
uint result_vector[MAX_WEIGHT_VALUES];
// Global "vector" to be pushed into when decoding
// At most will require BLOCK_WIDTH x BLOCK_HEIGHT in single plane mode
// At most will require BLOCK_WIDTH x BLOCK_HEIGHT x 2 in dual plane mode
// So the maximum would be 144 (12 x 12) elements, x 2 for two planes
#define DIVCEIL(number, divisor) (number + divisor - 1) / divisor
#define ARRAY_NUM_ELEMENTS 144
#define VECTOR_ARRAY_SIZE DIVCEIL(ARRAY_NUM_ELEMENTS * 2, 4)
uint result_vector[ARRAY_NUM_ELEMENTS * 2];
int result_index = 0;
uint result_vector_max_index;
@@ -486,7 +492,7 @@ void DecodeColorValues(uvec4 modes, uint num_partitions, uint color_data_bits, o
A = ReplicateBitTo9((bitval & 1));
switch (encoding) {
case JUST_BITS:
color_values[out_index++] = FastReplicateTo8(bitval, bitlen);
color_values[++out_index] = FastReplicateTo8(bitval, bitlen);
break;
case TRIT: {
D = QuintTritValue(val);
@@ -565,7 +571,7 @@ void DecodeColorValues(uvec4 modes, uint num_partitions, uint color_data_bits, o
uint T = (D * C) + B;
T ^= A;
T = (A & 0x80) | (T >> 2);
color_values[out_index++] = T;
color_values[++out_index] = T;
}
}
}
@@ -747,12 +753,12 @@ void ComputeEndpoints(out uvec4 ep1, out uvec4 ep2, uint color_endpoint_mode, ui
#define READ_UINT_VALUES(N) \
uvec4 V[2]; \
for (uint i = 0; i < N; i++) { \
V[i / 4][i % 4] = color_values[colvals_index++]; \
V[i / 4][i % 4] = color_values[++colvals_index]; \
}
#define READ_INT_VALUES(N) \
ivec4 V[2]; \
for (uint i = 0; i < N; i++) { \
V[i / 4][i % 4] = int(color_values[colvals_index++]); \
V[i / 4][i % 4] = int(color_values[++colvals_index]); \
}
switch (color_endpoint_mode) {
@@ -1219,10 +1225,6 @@ void DecompressBlock(ivec3 coord) {
FillError(coord);
return;
}
if (GetNumWeightValues(size_params, dual_plane) > MAX_WEIGHT_VALUES) {
FillError(coord);
return;
}
uint partition_index = 1;
uvec4 color_endpoint_mode = uvec4(0);
uint ced_pointer = 0;
@@ -1237,10 +1239,6 @@ void DecompressBlock(ivec3 coord) {
const uint base_mode = base_cem & 3;
const uint max_weight = DecodeMaxWeight(mode);
const uint weight_bits = GetPackedBitSize(size_params, dual_plane, max_weight);
if (weight_bits < 24 || weight_bits > 96) {
FillError(coord);
return;
}
uint remaining_bits = 128 - weight_bits - total_bitsread;
uint extra_cem_bits = 0;
if (base_mode > 0) {
@@ -1255,7 +1253,6 @@ void DecompressBlock(ivec3 coord) {
extra_cem_bits += 8;
break;
default:
FillError(coord);
return;
}
}
@@ -1265,7 +1262,6 @@ void DecompressBlock(ivec3 coord) {
if (remaining_bits > 128) {
// Bad data, more remaining bits than 4 bytes
// return early
FillError(coord);
return;
}
// Read color data...
@@ -1388,7 +1384,11 @@ void DecompressBlock(ivec3 coord) {
p = Cf / 65535.0f;
}
#ifdef VULKAN
imageStore(dest_image, coord + ivec3(i, j, 0), p.gbar);
#else
imageStore(dest_image, coord + ivec3(i, j, 0), clamp(p, 0.0f, 1.0f).gbar);
#endif
}
}
}
+76 -80
View File
@@ -417,6 +417,14 @@ void HLE_TransformFeedbackSetup::Execute(Core::System& system, Engines::Maxwell3
default: return std::monostate{};
}
}
[[nodiscard]] inline bool CanBeHLEProgram(u64 hash) noexcept {
switch (hash) {
#define HLE_MACRO_ELEM(HASH, TY, VAL) case HASH: return true;
HLE_MACRO_LIST
#undef HLE_MACRO_ELEM
default: return false;
}
}
void MacroInterpreterImpl::Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span<const u32> params, u32 method) {
Reset();
@@ -1337,92 +1345,80 @@ static void Dump(u64 hash, std::span<const u32> code, bool decompiled = false) {
macro_file.write(reinterpret_cast<const char*>(code.data()), code.size_bytes());
}
void MacroEngine::Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, u32 method,
std::span<const u32> parameters) {
const auto execute_variant = [&system, &maxwell3d, &parameters,
method](AnyCachedMacro& cached) {
if (std::holds_alternative<MacroInterpreterImpl>(cached) ||
std::holds_alternative<std::unique_ptr<DynamicCachedMacro>>(cached) ||
Settings::values.disable_macro_hle) {
maxwell3d.RefreshParameters();
}
if (auto program = std::get_if<HLE_DrawArraysIndirect>(&cached))
return program->Execute(system, maxwell3d, parameters, method);
if (auto program = std::get_if<HLE_DrawIndexedIndirect>(&cached))
return program->Execute(system, maxwell3d, parameters, method);
if (auto program = std::get_if<HLE_MultiDrawIndexedIndirectCount>(&cached))
return program->Execute(system, maxwell3d, parameters, method);
if (auto program = std::get_if<HLE_MultiLayerClear>(&cached))
return program->Execute(system, maxwell3d, parameters, method);
if (auto program = std::get_if<HLE_C713C83D8F63CCF3>(&cached))
return program->Execute(system, maxwell3d, parameters, method);
if (auto program = std::get_if<HLE_D7333D26E0A93EDE>(&cached))
return program->Execute(system, maxwell3d, parameters, method);
if (auto program = std::get_if<HLE_BindShader>(&cached))
return program->Execute(system, maxwell3d, parameters, method);
if (auto program = std::get_if<HLE_SetRasterBoundingBox>(&cached))
return program->Execute(system, maxwell3d, parameters, method);
if (auto program = std::get_if<HLE_ClearConstBuffer>(&cached))
return program->Execute(system, maxwell3d, parameters, method);
if (auto program = std::get_if<HLE_ClearMemory>(&cached))
return program->Execute(system, maxwell3d, parameters, method);
if (auto program = std::get_if<HLE_TransformFeedbackSetup>(&cached))
return program->Execute(system, maxwell3d, parameters, method);
if (auto program = std::get_if<HLE_DrawIndirectByteCount>(&cached))
return program->Execute(system, maxwell3d, parameters, method);
if (auto program = std::get_if<MacroInterpreterImpl>(&cached))
return program->Execute(system, maxwell3d, parameters, method);
if (auto program = std::get_if<std::unique_ptr<DynamicCachedMacro>>(&cached))
return program->get()->Execute(system, maxwell3d, parameters, method);
UNREACHABLE();
void MacroEngine::Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, u32 method, std::span<const u32> parameters) {
auto const execute_variant = [&system, &maxwell3d, &parameters, method](AnyCachedMacro& acm) {
if (auto a = std::get_if<HLE_DrawArraysIndirect>(&acm))
return a->Execute(system, maxwell3d, parameters, method);
if (auto a = std::get_if<HLE_DrawIndexedIndirect>(&acm))
return a->Execute(system, maxwell3d, parameters, method);
if (auto a = std::get_if<HLE_MultiDrawIndexedIndirectCount>(&acm))
return a->Execute(system, maxwell3d, parameters, method);
if (auto a = std::get_if<HLE_MultiLayerClear>(&acm))
return a->Execute(system, maxwell3d, parameters, method);
if (auto a = std::get_if<HLE_C713C83D8F63CCF3>(&acm))
return a->Execute(system, maxwell3d, parameters, method);
if (auto a = std::get_if<HLE_D7333D26E0A93EDE>(&acm))
return a->Execute(system, maxwell3d, parameters, method);
if (auto a = std::get_if<HLE_BindShader>(&acm))
return a->Execute(system, maxwell3d, parameters, method);
if (auto a = std::get_if<HLE_SetRasterBoundingBox>(&acm))
return a->Execute(system, maxwell3d, parameters, method);
if (auto a = std::get_if<HLE_ClearConstBuffer>(&acm))
return a->Execute(system, maxwell3d, parameters, method);
if (auto a = std::get_if<HLE_ClearMemory>(&acm))
return a->Execute(system, maxwell3d, parameters, method);
if (auto a = std::get_if<HLE_TransformFeedbackSetup>(&acm))
return a->Execute(system, maxwell3d, parameters, method);
if (auto a = std::get_if<HLE_DrawIndirectByteCount>(&acm))
return a->Execute(system, maxwell3d, parameters, method);
if (auto a = std::get_if<MacroInterpreterImpl>(&acm))
return a->Execute(system, maxwell3d, parameters, method);
if (auto a = std::get_if<std::unique_ptr<DynamicCachedMacro>>(&acm))
return a->get()->Execute(system, maxwell3d, parameters, method);
};
if (auto const it = macro_cache.find(method); it != macro_cache.end()) {
execute_variant(it->second.program);
return;
}
// Macro not compiled, check if it's uploaded and if so, compile it
std::span<const u32> code;
auto macro_code = uploaded_macro_code.find(method);
if (macro_code == uploaded_macro_code.end()) {
auto& ci = it->second;
if (!CanBeHLEProgram(ci.hash) || Settings::values.disable_macro_hle)
maxwell3d.RefreshParameters(); //LLE must reload parameters
execute_variant(ci.program);
} else {
// Macro not compiled, check if it's uploaded and if so, compile it
std::optional<u32> mid_method;
for (const auto& [method_base, uploaded_code] : uploaded_macro_code) {
if (method >= method_base && (method - method_base) < uploaded_code.size()) {
mid_method = method_base;
break;
const auto macro_code = uploaded_macro_code.find(method);
if (macro_code == uploaded_macro_code.end()) {
for (const auto& [method_base, code] : uploaded_macro_code) {
if (method >= method_base && (method - method_base) < code.size()) {
mid_method = method_base;
break;
}
}
if (!mid_method.has_value()) {
ASSERT_MSG(false, "Macro 0x{0:x} was not uploaded", method);
return;
}
}
if (!mid_method) {
ASSERT_MSG(false, "Macro 0x{0:x} was not uploaded", method);
return;
auto& ci = macro_cache[method];
if (mid_method) {
const auto& macro_cached = uploaded_macro_code[mid_method.value()];
const auto rebased_method = method - mid_method.value();
auto& code = uploaded_macro_code[method];
code.resize(macro_cached.size() - rebased_method);
std::memcpy(code.data(), macro_cached.data() + rebased_method, code.size() * sizeof(u32));
ci.hash = Common::HashValue(code);
ci.program = Compile(system, maxwell3d, code);
} else {
ci.program = Compile(system, maxwell3d, macro_code->second);
ci.hash = Common::HashValue(macro_code->second);
}
if (CanBeHLEProgram(ci.hash) && !Settings::values.disable_macro_hle) {
ci.program = GetHLEProgram(ci.hash);
} else {
maxwell3d.RefreshParameters();
}
execute_variant(ci.program);
if (Settings::values.dump_macros) {
Dump(ci.hash, macro_code->second, !std::holds_alternative<std::monostate>(ci.program));
}
const auto source = uploaded_macro_code.find(*mid_method);
ASSERT(source != uploaded_macro_code.end());
const auto rebased_method = method - *mid_method;
std::vector<u32> rebased_code(source->second.begin() + rebased_method,
source->second.end());
const auto [it, inserted] = uploaded_macro_code.emplace(method, std::move(rebased_code));
ASSERT(inserted);
code = it->second;
} else {
code = macro_code->second;
}
auto& ci = macro_cache[method];
ci.hash = Common::HashRange(code.begin(), code.end());
if (!Settings::values.disable_macro_hle) {
ci.program = GetHLEProgram(ci.hash);
}
if (std::holds_alternative<std::monostate>(ci.program)) {
ci.program = Compile(system, maxwell3d, code);
}
execute_variant(ci.program);
if (Settings::values.dump_macros) {
Dump(ci.hash, code, !std::holds_alternative<std::monostate>(ci.program));
}
}
@@ -144,6 +144,11 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
info.size.depth == 1;
}
[[nodiscard]] bool WillUseWidenedAstcFormat(const Device& device, const ImageInfo& info) {
return WillUseAcceleratedAstcDecode(device, info) &&
!VideoCore::Surface::IsPixelFormatSRGB(info.format);
}
[[nodiscard]] VkImageCreateInfo MakeImageCreateInfo(const Device& device, const ImageInfo& info,
std::optional<VkFormat> format_override = {}) {
auto format_info =
@@ -264,10 +269,6 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
}
}
[[nodiscard]] bool IsLdrAstcFormat(VkFormat format) {
return format >= VK_FORMAT_ASTC_4x4_UNORM_BLOCK && format <= VK_FORMAT_ASTC_12x12_SRGB_BLOCK;
}
[[nodiscard]] VkImageAspectFlags ImageViewAspectMask(const VideoCommon::ImageViewInfo& info) {
if (info.IsRenderTarget()) {
return ImageAspectMask(info.format);
@@ -1779,7 +1780,12 @@ Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu
: VideoCommon::ImageBase(info_, gpu_addr_, cpu_addr_), scheduler{&runtime_.scheduler},
runtime{&runtime_},
original_image(MakeImage(runtime_.device, runtime_.memory_allocator, info,
runtime->ViewFormats(info.format))),
WillUseWidenedAstcFormat(runtime_.device, info)
? std::span<const VkFormat>{}
: runtime->ViewFormats(info.format),
WillUseWidenedAstcFormat(runtime_.device, info)
? std::make_optional(VK_FORMAT_R32G32B32A32_SFLOAT)
: std::nullopt)),
aspect_mask(ImageAspectMask(info.format)) {
if (IsPixelFormatASTC(info.format) && !runtime->device.IsOptimalAstcSupported()) {
switch (Settings::values.accelerate_astc.GetValue()) {
@@ -1806,9 +1812,13 @@ Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu
}
current_image = &Image::original_image;
storage_image_views.resize(info.resources.levels);
if (WillUseAcceleratedAstcDecode(runtime->device, info)) {
if (IsPixelFormatASTC(info.format) && !runtime->device.IsOptimalAstcSupported() &&
Settings::values.astc_recompression.GetValue() ==
Settings::AstcRecompression::Uncompressed) {
const auto& device = runtime->device.GetLogical();
const VkFormat storage_format = VK_FORMAT_A8B8G8R8_UNORM_PACK32;
const VkFormat storage_format = WillUseWidenedAstcFormat(runtime->device, info)
? VK_FORMAT_R32G32B32A32_SFLOAT
: VK_FORMAT_A8B8G8R8_UNORM_PACK32;
for (s32 level = 0; level < info.resources.levels; ++level) {
storage_image_views[level] =
MakeStorageView(device, level, *original_image, storage_format);
@@ -2194,7 +2204,9 @@ VkImageView Image::StorageImageView(s32 level) noexcept {
auto format_info =
MaxwellToVK::SurfaceFormat(runtime->device, FormatType::Optimal, true, info.format);
if (WillUseAcceleratedAstcDecode(runtime->device, info)) {
format_info.format = VK_FORMAT_A8B8G8R8_UNORM_PACK32;
format_info.format = WillUseWidenedAstcFormat(runtime->device, info)
? VK_FORMAT_R32G32B32A32_SFLOAT
: VK_FORMAT_A8B8G8R8_UNORM_PACK32;
}
view = MakeStorageView(runtime->device.GetLogical(), level, *(this->*current_image),
format_info.format);
@@ -2370,7 +2382,11 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
SanitizeDepthStencilSwizzle(swizzle, device->SupportsDepthStencilSwizzleOne());
}
}
uses_widened_astc_format = WillUseWidenedAstcFormat(*device, image.info);
auto format_info = MaxwellToVK::SurfaceFormat(*device, FormatType::Optimal, true, format);
if (uses_widened_astc_format) {
format_info.format = VK_FORMAT_R32G32B32A32_SFLOAT;
}
if (device->ApiVersion() >= VK_API_VERSION_1_3) {
const VkFormatProperties3 properties3 =
device->GetPhysical().GetFormatProperties3(format_info.format);
@@ -2388,18 +2404,9 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
.pNext = nullptr,
.usage = clamped_view_usage,
};
const VkImageViewASTCDecodeModeEXT astc_decode_mode{
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_ASTC_DECODE_MODE_EXT,
.pNext = &image_view_usage,
.decodeMode = VK_FORMAT_R8G8B8A8_UNORM,
};
const void* view_next = &image_view_usage;
if (device->IsExtAstcDecodeModeSupported() && IsLdrAstcFormat(format_info.format)) {
view_next = &astc_decode_mode;
}
const VkImageViewCreateInfo create_info{
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.pNext = view_next,
.pNext = &image_view_usage,
.flags = 0,
.image = image.Handle(),
.viewType = VkImageViewType{},
@@ -2524,6 +2531,9 @@ VkImageView ImageView::StorageView(Shader::TextureType texture_type,
if (image_format == Shader::ImageFormat::Typeless) {
if (!typeless_storage_view) {
auto info = MaxwellToVK::SurfaceFormat(*device, FormatType::Optimal, true, format);
if (uses_widened_astc_format) {
info.format = VK_FORMAT_R32G32B32A32_SFLOAT;
}
typeless_storage_view = MakeView(info.format, VK_IMAGE_ASPECT_COLOR_BIT, texture_type);
}
return *typeless_storage_view;
@@ -436,6 +436,7 @@ private:
VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT;
u32 buffer_size = 0;
bool uses_widened_astc_format = false;
bool supports_depth_comparison = false;
};
-11
View File
@@ -1769,12 +1769,6 @@ static void DecompressBlock(std::span<const u8, 16> inBuf, const u32 blockWidth,
return;
}
if (weightParams.GetNumWeightValues() > 64) {
assert(false && "Too many weights in the weight grid");
FillError(outBuf, blockWidth, blockHeight);
return;
}
// Read num partitions
u32 nPartitions = strm.ReadBits<2>() + 1;
assert(nPartitions <= 4);
@@ -1811,11 +1805,6 @@ static void DecompressBlock(std::span<const u8, 16> inBuf, const u32 blockWidth,
// Remaining bits are color endpoint data...
u32 nWeightBits = weightParams.GetPackedBitSize();
if (nWeightBits < 24 || nWeightBits > 96) {
assert(false && "Invalid weight bit count");
FillError(outBuf, blockWidth, blockHeight);
return;
}
s32 remainingBits = 128 - nWeightBits - static_cast<int>(strm.GetBitsRead());
// Consider extra bits prior to texel data...
@@ -820,13 +820,14 @@ bool Device::ComputeIsOptimalAstcSupported() const {
if (!features.features.textureCompressionASTC_LDR) {
return false;
}
const VkFormatFeatureFlags format_feature_usage{
VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT |
VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT};
const auto format_feature_usage{VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT |
VK_FORMAT_FEATURE_BLIT_SRC_BIT |
VK_FORMAT_FEATURE_BLIT_DST_BIT |
VK_FORMAT_FEATURE_TRANSFER_SRC_BIT |
VK_FORMAT_FEATURE_TRANSFER_DST_BIT};
for (const auto format : astc_formats) {
const auto physical_format_properties{physical.GetFormatProperties(format)};
if ((physical_format_properties.optimalTilingFeatures & format_feature_usage) !=
format_feature_usage) {
if ((physical_format_properties.optimalTilingFeatures & format_feature_usage) == 0) {
return false;
}
}
+5 -7
View File
@@ -72,12 +72,13 @@ VK_DEFINE_HANDLE(VmaAllocator)
FEATURE(KHR, PipelineExecutableProperties, PIPELINE_EXECUTABLE_PROPERTIES, \
pipeline_executable_properties) \
FEATURE(KHR, WorkgroupMemoryExplicitLayout, WORKGROUP_MEMORY_EXPLICIT_LAYOUT, \
workgroup_memory_explicit_layout)
workgroup_memory_explicit_layout) \
FEATURE(EXT, TextureCompressionASTCHDR, TEXTURE_COMPRESSION_ASTC_HDR, \
texture_compression_astc_hdr)
// Define miscellaneous extensions which may be used by the implementation here.
#define FOR_EACH_VK_EXTENSION(EXTENSION) \
EXTENSION(EXT, ASTC_DECODE_MODE, astc_decode_mode) \
EXTENSION(EXT, CONDITIONAL_RENDERING, conditional_rendering) \
EXTENSION(EXT, CONSERVATIVE_RASTERIZATION, conservative_rasterization) \
EXTENSION(EXT, DEPTH_RANGE_UNRESTRICTED, depth_range_unrestricted) \
@@ -368,7 +369,8 @@ FN_MAX_LIMIT_LIST
}
bool IsOptimalAstcSupported() const {
return is_optimal_astc_supported;
return features.features.textureCompressionASTC_LDR &&
features.texture_compression_astc_hdr.textureCompressionASTC_HDR;
}
/// Returns true if BCn is natively supported.
@@ -814,10 +816,6 @@ FN_MAX_LIMIT_LIST
return extensions.conditional_rendering;
}
bool IsExtAstcDecodeModeSupported() const {
return extensions.astc_decode_mode;
}
bool HasTimelineSemaphore() const;
/// Returns true if the device supports VK_KHR_synchronization2.