[android] Add detailed system information dialog (#2995)
Thanks to https://github.com/RPCSX/rpcsx for their CPU information detecting code which was used as reference here. Co-authored-by: crueter <crueter@eden-emu.dev> Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2995 Reviewed-by: MaranBr <maranbr@eden-emu.dev> Reviewed-by: Caio Oliveira <caiooliveirafarias0@gmail.com> Reviewed-by: crueter <crueter@eden-emu.dev> Co-authored-by: kleidis <kleidis1@protonmail.com> Co-committed-by: kleidis <kleidis1@protonmail.com>
This commit is contained in:
parent
6b01977005
commit
b9655669b3
|
|
@ -200,6 +200,18 @@ object NativeLibrary {
|
|||
|
||||
external fun logSettings()
|
||||
|
||||
/**
|
||||
* Returns Vulkan driver version / API version / GPU model
|
||||
*/
|
||||
external fun getVulkanDriverVersion(): String
|
||||
external fun getVulkanApiVersion(): String
|
||||
external fun getGpuModel(): String
|
||||
|
||||
/**
|
||||
* Returns a summary of detailed information about the CPU.
|
||||
*/
|
||||
external fun getCpuSummary(): String
|
||||
|
||||
/**
|
||||
* Checks for available updates.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -230,6 +230,17 @@ class HomeSettingsFragment : Fragment() {
|
|||
{ openFileManager() }
|
||||
)
|
||||
)
|
||||
add(
|
||||
HomeSetting(
|
||||
R.string.system_information,
|
||||
R.string.system_information_description,
|
||||
R.drawable.ic_system,
|
||||
{
|
||||
SystemInfoDialogFragment.newInstance()
|
||||
.show(parentFragmentManager, SystemInfoDialogFragment.TAG)
|
||||
}
|
||||
)
|
||||
)
|
||||
add(
|
||||
HomeSetting(
|
||||
R.string.about,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,108 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.fragments
|
||||
|
||||
import android.app.ActivityManager
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import org.yuzu.yuzu_emu.NativeLibrary
|
||||
import org.yuzu.yuzu_emu.R
|
||||
import org.yuzu.yuzu_emu.databinding.DialogSystemInfoBinding
|
||||
|
||||
class SystemInfoDialogFragment : DialogFragment() {
|
||||
private var _binding: DialogSystemInfoBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
_binding = DialogSystemInfoBinding.inflate(layoutInflater)
|
||||
|
||||
populateSystemInfo()
|
||||
|
||||
val dialog = MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(R.string.system_information)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.create()
|
||||
|
||||
dialog.setView(binding.root)
|
||||
|
||||
return dialog
|
||||
}
|
||||
|
||||
private fun populateSystemInfo() {
|
||||
val systemInfo = buildString {
|
||||
// General Device Info
|
||||
appendLine("=== ${getString(R.string.general_information)} ===")
|
||||
appendLine("${getString(R.string.device_manufacturer)}: ${Build.MANUFACTURER}")
|
||||
appendLine("${getString(R.string.device_model)}: ${Build.MODEL}")
|
||||
appendLine("${getString(R.string.device_name)}: ${Build.DEVICE}")
|
||||
appendLine("${getString(R.string.product)}: ${Build.PRODUCT}")
|
||||
appendLine("${getString(R.string.hardware)}: ${Build.HARDWARE}")
|
||||
appendLine("${getString(R.string.supported_abis)}: ${Build.SUPPORTED_ABIS.joinToString(", ")}")
|
||||
appendLine("${getString(R.string.android_version)}: ${Build.VERSION.RELEASE} (API ${Build.VERSION.SDK_INT})")
|
||||
appendLine("${getString(R.string.android_security_patch)}: ${Build.VERSION.SECURITY_PATCH}")
|
||||
appendLine("${getString(R.string.build_id)}: ${Build.ID}")
|
||||
|
||||
appendLine()
|
||||
appendLine("=== ${getString(R.string.cpu_info)} ===")
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && Build.SOC_MODEL.isNotBlank()) {
|
||||
appendLine("${getString(R.string.soc)} ${Build.SOC_MODEL}")
|
||||
}
|
||||
|
||||
val cpuSummary = NativeLibrary.getCpuSummary()
|
||||
if (cpuSummary.isNotEmpty() && cpuSummary != "Unknown") {
|
||||
appendLine(cpuSummary)
|
||||
}
|
||||
|
||||
appendLine()
|
||||
|
||||
// GPU Info
|
||||
appendLine("=== ${getString(R.string.gpu_information)} ===")
|
||||
try {
|
||||
val gpuModel = NativeLibrary.getGpuModel()
|
||||
appendLine("${getString(R.string.gpu_model)}: $gpuModel")
|
||||
|
||||
val vulkanApi = NativeLibrary.getVulkanApiVersion()
|
||||
appendLine("Vulkan API: $vulkanApi")
|
||||
|
||||
val vulkanDriver = NativeLibrary.getVulkanDriverVersion()
|
||||
appendLine("${getString(R.string.vulkan_driver_version)}: $vulkanDriver")
|
||||
} catch (e: Exception) {
|
||||
appendLine("${getString(R.string.error_getting_emulator_info)}: ${e.message}")
|
||||
}
|
||||
appendLine()
|
||||
|
||||
// Memory Info
|
||||
appendLine("=== ${getString(R.string.memory_info)} ===")
|
||||
|
||||
val activityManager =
|
||||
requireContext().getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
|
||||
val memInfo = ActivityManager.MemoryInfo()
|
||||
activityManager.getMemoryInfo(memInfo)
|
||||
val totalDeviceRam = memInfo.totalMem / (1024 * 1024)
|
||||
|
||||
appendLine("${getString(R.string.total_memory)}: $totalDeviceRam MB")
|
||||
}
|
||||
|
||||
binding.textSystemInfo.text = systemInfo
|
||||
}
|
||||
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
_binding = null
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TAG = "SystemInfoDialogFragment"
|
||||
|
||||
fun newInstance(): SystemInfoDialogFragment {
|
||||
return SystemInfoDialogFragment()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,11 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.utils
|
||||
import org.yuzu.yuzu_emu.NativeLibrary
|
||||
|
||||
import android.os.Build
|
||||
|
||||
|
|
@ -25,6 +29,15 @@ object Log {
|
|||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R) {
|
||||
info("SoC Manufacturer - ${Build.SOC_MANUFACTURER}")
|
||||
info("SoC Model - ${Build.SOC_MODEL}")
|
||||
NativeLibrary.getCpuSummary().split('\n').forEach {
|
||||
info("CPU Info - $it")
|
||||
}
|
||||
}
|
||||
NativeLibrary.getVulkanDriverVersion().split('\n').forEach {
|
||||
info("Vulkan Driver: - $it")
|
||||
}
|
||||
NativeLibrary.getVulkanApiVersion().split('\n').forEach {
|
||||
info("Vulkan API Version: - $it")
|
||||
}
|
||||
info("Total System Memory - ${MemoryUtil.getDeviceRAM()}")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,13 +8,21 @@
|
|||
#include "video_core/vulkan_common/vma.h"
|
||||
|
||||
#include <codecvt>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <locale>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <dlfcn.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <iostream>
|
||||
#ifdef ARCHITECTURE_arm64
|
||||
#include <adrenotools/driver.h>
|
||||
#endif
|
||||
|
|
@ -465,6 +473,205 @@ static Core::SystemResultStatus RunEmulation(const std::string& filepath,
|
|||
return Core::SystemResultStatus::Success;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct CpuPartInfo {
|
||||
u32 vendor;
|
||||
u32 part;
|
||||
const char* name;
|
||||
};
|
||||
|
||||
constexpr CpuPartInfo s_cpu_list[] = {
|
||||
// ARM - 0x41
|
||||
{0x41, 0xd01, "Cortex-A32"},
|
||||
{0x41, 0xd02, "Cortex-A34"},
|
||||
{0x41, 0xd04, "Cortex-A35"},
|
||||
{0x41, 0xd03, "Cortex-A53"},
|
||||
{0x41, 0xd05, "Cortex-A55"},
|
||||
{0x41, 0xd46, "Cortex-A510"},
|
||||
{0x41, 0xd80, "Cortex-A520"},
|
||||
{0x41, 0xd88, "Cortex-A520AE"},
|
||||
{0x41, 0xd07, "Cortex-A57"},
|
||||
{0x41, 0xd06, "Cortex-A65"},
|
||||
{0x41, 0xd43, "Cortex-A65AE"},
|
||||
{0x41, 0xd08, "Cortex-A72"},
|
||||
{0x41, 0xd09, "Cortex-A73"},
|
||||
{0x41, 0xd0a, "Cortex-A75"},
|
||||
{0x41, 0xd0b, "Cortex-A76"},
|
||||
{0x41, 0xd0e, "Cortex-A76AE"},
|
||||
{0x41, 0xd0d, "Cortex-A77"},
|
||||
{0x41, 0xd41, "Cortex-A78"},
|
||||
{0x41, 0xd42, "Cortex-A78AE"},
|
||||
{0x41, 0xd4b, "Cortex-A78C"},
|
||||
{0x41, 0xd47, "Cortex-A710"},
|
||||
{0x41, 0xd4d, "Cortex-A715"},
|
||||
{0x41, 0xd81, "Cortex-A720"},
|
||||
{0x41, 0xd89, "Cortex-A720AE"},
|
||||
{0x41, 0xd87, "Cortex-A725"},
|
||||
{0x41, 0xd44, "Cortex-X1"},
|
||||
{0x41, 0xd4c, "Cortex-X1C"},
|
||||
{0x41, 0xd48, "Cortex-X2"},
|
||||
{0x41, 0xd4e, "Cortex-X3"},
|
||||
{0x41, 0xd82, "Cortex-X4"},
|
||||
{0x41, 0xd85, "Cortex-X925"},
|
||||
{0x41, 0xd4a, "Neoverse E1"},
|
||||
{0x41, 0xd0c, "Neoverse N1"},
|
||||
{0x41, 0xd49, "Neoverse N2"},
|
||||
{0x41, 0xd8e, "Neoverse N3"},
|
||||
{0x41, 0xd40, "Neoverse V1"},
|
||||
{0x41, 0xd4f, "Neoverse V2"},
|
||||
{0x41, 0xd84, "Neoverse V3"},
|
||||
{0x41, 0xd83, "Neoverse V3AE"},
|
||||
// Qualcomm - 0x51
|
||||
{0x51, 0x201, "Kryo"},
|
||||
{0x51, 0x205, "Kryo"},
|
||||
{0x51, 0x211, "Kryo"},
|
||||
{0x51, 0x800, "Kryo 385 Gold"},
|
||||
{0x51, 0x801, "Kryo 385 Silver"},
|
||||
{0x51, 0x802, "Kryo 485 Gold"},
|
||||
{0x51, 0x803, "Kryo 485 Silver"},
|
||||
{0x51, 0x804, "Kryo 680 Prime"},
|
||||
{0x51, 0x805, "Kryo 680 Gold"},
|
||||
{0x51, 0x06f, "Krait"},
|
||||
{0x51, 0xc00, "Falkor"},
|
||||
{0x51, 0xc01, "Saphira"},
|
||||
{0x51, 0x001, "Oryon"},
|
||||
};
|
||||
|
||||
const char* find_cpu_name(u32 vendor, u32 part) {
|
||||
for (const auto& cpu : s_cpu_list) {
|
||||
if (cpu.vendor == vendor && cpu.part == part) {
|
||||
return cpu.name;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
u64 read_midr_sysfs(u32 cpu_id) {
|
||||
char path[128];
|
||||
std::snprintf(path, sizeof(path), "/sys/devices/system/cpu/cpu%u/regs/identification/midr_el1", cpu_id);
|
||||
|
||||
FILE* f = std::fopen(path, "r");
|
||||
if (!f) return 0;
|
||||
|
||||
char value[32];
|
||||
if (!std::fgets(value, sizeof(value), f)) {
|
||||
std::fclose(f);
|
||||
return 0;
|
||||
}
|
||||
std::fclose(f);
|
||||
|
||||
return std::strtoull(value, nullptr, 16);
|
||||
}
|
||||
|
||||
std::pair<u32, std::string> get_pretty_cpus() {
|
||||
std::map<u64, int> core_layout;
|
||||
u32 valid_cpus = 0;
|
||||
for (u32 i = 0; i < std::thread::hardware_concurrency(); ++i) {
|
||||
const auto midr = read_midr_sysfs(i);
|
||||
if (midr == 0) break;
|
||||
|
||||
valid_cpus++;
|
||||
core_layout[midr]++;
|
||||
}
|
||||
|
||||
std::string cpus;
|
||||
|
||||
if (!core_layout.empty()) {
|
||||
const CpuPartInfo* lowest_part = nullptr;
|
||||
u32 lowest_part_id = 0xFFFFFFFF;
|
||||
|
||||
for (const auto& [midr, count] : core_layout) {
|
||||
const auto vendor = (midr >> 24) & 0xff;
|
||||
const auto part = (midr >> 4) & 0xfff;
|
||||
|
||||
if (!cpus.empty()) cpus += " + ";
|
||||
cpus += fmt::format("{}x {}", count, find_cpu_name(vendor, part));
|
||||
}
|
||||
}
|
||||
|
||||
return {valid_cpus, cpus};
|
||||
}
|
||||
|
||||
std::string get_arm_cpu_name() {
|
||||
std::map<u64, int> core_layout;
|
||||
for (u32 i = 0; i < std::thread::hardware_concurrency(); ++i) {
|
||||
const auto midr = read_midr_sysfs(i);
|
||||
if (midr == 0) break;
|
||||
|
||||
core_layout[midr]++;
|
||||
}
|
||||
|
||||
if (!core_layout.empty()) {
|
||||
const CpuPartInfo* lowest_part = nullptr;
|
||||
u32 lowest_part_id = 0xFFFFFFFF;
|
||||
|
||||
for (const auto& [midr, count] : core_layout) {
|
||||
const auto vendor = (midr >> 24) & 0xff;
|
||||
const auto part = (midr >> 4) & 0xfff;
|
||||
|
||||
for (const auto& cpu : s_cpu_list) {
|
||||
if (cpu.vendor == vendor && cpu.part == part) {
|
||||
if (cpu.part < lowest_part_id) {
|
||||
lowest_part_id = cpu.part;
|
||||
lowest_part = &cpu;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (lowest_part) {
|
||||
return lowest_part->name;
|
||||
}
|
||||
}
|
||||
|
||||
FILE* f = std::fopen("/proc/cpuinfo", "r");
|
||||
if (!f) return "";
|
||||
|
||||
char buf[512];
|
||||
std::string result;
|
||||
|
||||
auto trim = [](std::string& s) {
|
||||
const auto start = s.find_first_not_of(" \t\r\n");
|
||||
const auto end = s.find_last_not_of(" \t\r\n");
|
||||
s = (start == std::string::npos) ? "" : s.substr(start, end - start + 1);
|
||||
};
|
||||
|
||||
while (std::fgets(buf, sizeof(buf), f)) {
|
||||
std::string line(buf);
|
||||
if (line.find("Hardware") == 0) {
|
||||
auto pos = line.find(':');
|
||||
if (pos != std::string::npos) {
|
||||
result = line.substr(pos + 1);
|
||||
trim(result);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
std::fclose(f);
|
||||
|
||||
if (!result.empty()) {
|
||||
std::transform(result.begin(), result.end(), result.begin(), ::tolower);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const char* fallback_cpu_detection() {
|
||||
static std::string s_result = []() -> std::string {
|
||||
std::string result = get_arm_cpu_name();
|
||||
if (result.empty()) {
|
||||
return "Cortex-A34";
|
||||
}
|
||||
return result;
|
||||
}();
|
||||
|
||||
return s_result.c_str();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" {
|
||||
|
||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceChanged(JNIEnv* env, jobject instance,
|
||||
|
|
@ -694,6 +901,209 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getGpuDriver(JNIEnv* env, jobject
|
|||
env, EmulationSession::GetInstance().System().GPU().Renderer().GetDeviceVendor());
|
||||
}
|
||||
|
||||
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getCpuSummary(JNIEnv* env, jobject /*jobj*/) {
|
||||
get_arm_cpu_name();
|
||||
constexpr const char* CPUINFO_PATH = "/proc/cpuinfo";
|
||||
|
||||
auto trim = [](std::string& s) {
|
||||
const auto start = s.find_first_not_of(" \t\r\n");
|
||||
const auto end = s.find_last_not_of(" \t\r\n");
|
||||
s = (start == std::string::npos) ? "" : s.substr(start, end - start + 1);
|
||||
};
|
||||
|
||||
auto to_lower = [](std::string s) {
|
||||
for (auto& c : s) c = std::tolower(c);
|
||||
return s;
|
||||
};
|
||||
|
||||
try {
|
||||
std::string result;
|
||||
std::pair<u32, std::string> pretty_cpus = get_pretty_cpus();
|
||||
u32 threads = pretty_cpus.first;
|
||||
std::string cpus = pretty_cpus.second;
|
||||
|
||||
fmt::format_to(std::back_inserter(result), "CPUs: {}\n{} Threads",
|
||||
cpus, threads);
|
||||
|
||||
FILE* f = std::fopen(CPUINFO_PATH, "r");
|
||||
if (!f) return Common::Android::ToJString(env, result);
|
||||
|
||||
char buf[512];
|
||||
|
||||
if (f) {
|
||||
std::set<std::string> feature_set;
|
||||
while (std::fgets(buf, sizeof(buf), f)) {
|
||||
std::string line(buf);
|
||||
if (line.find("Features") == 0 || line.find("features") == 0) {
|
||||
auto pos = line.find(':');
|
||||
if (pos != std::string::npos) {
|
||||
std::string feat_line = line.substr(pos + 1);
|
||||
trim(feat_line);
|
||||
|
||||
std::istringstream iss(feat_line);
|
||||
std::string feature;
|
||||
while (iss >> feature) {
|
||||
feature_set.insert(to_lower(feature));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
std::fclose(f);
|
||||
|
||||
bool has_neon = feature_set.count("neon") || feature_set.count("asimd");
|
||||
bool has_fp = feature_set.count("fp") || feature_set.count("vfp");
|
||||
bool has_sve = feature_set.count("sve");
|
||||
bool has_sve2 = feature_set.count("sve2");
|
||||
bool has_crypto = feature_set.count("aes") || feature_set.count("sha1") ||
|
||||
feature_set.count("sha2") || feature_set.count("pmull");
|
||||
bool has_dotprod = feature_set.count("asimddp") || feature_set.count("dotprod");
|
||||
bool has_i8mm = feature_set.count("i8mm");
|
||||
bool has_bf16 = feature_set.count("bf16");
|
||||
bool has_atomics = feature_set.count("atomics") || feature_set.count("lse");
|
||||
|
||||
std::string features;
|
||||
if (has_neon || has_fp) {
|
||||
features += "NEON";
|
||||
if (has_dotprod) features += "+DP";
|
||||
if (has_i8mm) features += "+I8MM";
|
||||
if (has_bf16) features += "+BF16";
|
||||
}
|
||||
|
||||
if (has_sve) {
|
||||
if (!features.empty()) features += " | ";
|
||||
features += "SVE";
|
||||
if (has_sve2) features += "2";
|
||||
}
|
||||
|
||||
if (has_crypto) {
|
||||
if (!features.empty()) features += " | ";
|
||||
features += "Crypto";
|
||||
}
|
||||
|
||||
if (has_atomics) {
|
||||
if (!features.empty()) features += " | ";
|
||||
features += "LSE";
|
||||
}
|
||||
|
||||
if (!features.empty()) {
|
||||
result += "\nFeatures: " + features;
|
||||
}
|
||||
}
|
||||
|
||||
fmt::format_to(std::back_inserter(result), "\nLLVM CPU: {}", fallback_cpu_detection());
|
||||
|
||||
return Common::Android::ToJString(env, result);
|
||||
} catch (...) {
|
||||
return Common::Android::ToJString(env, "Unknown");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
constexpr u32 VENDOR_QUALCOMM = 0x5143;
|
||||
constexpr u32 VENDOR_ARM = 0x13B5;
|
||||
|
||||
VkPhysicalDeviceProperties GetVulkanDeviceProperties() {
|
||||
Common::DynamicLibrary library;
|
||||
if (!library.Open("libvulkan.so")) {
|
||||
return {};
|
||||
}
|
||||
|
||||
Vulkan::vk::InstanceDispatch dld;
|
||||
// TODO: warn the user that Vulkan is unavailable rather than hard crash
|
||||
const auto instance = Vulkan::CreateInstance(library, dld, VK_API_VERSION_1_1);
|
||||
const auto physical_devices = instance.EnumeratePhysicalDevices();
|
||||
if (physical_devices.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const Vulkan::vk::PhysicalDevice physical_device(physical_devices[0], dld);
|
||||
return physical_device.GetProperties();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getVulkanDriverVersion(JNIEnv* env, jobject jobj) {
|
||||
try {
|
||||
const auto props = GetVulkanDeviceProperties();
|
||||
if (props.deviceID == 0) {
|
||||
return Common::Android::ToJString(env, "N/A");
|
||||
}
|
||||
|
||||
const u32 driver_version = props.driverVersion;
|
||||
const u32 vendor_id = props.vendorID;
|
||||
|
||||
if (driver_version == 0) {
|
||||
return Common::Android::ToJString(env, "N/A");
|
||||
}
|
||||
|
||||
std::string version_str;
|
||||
|
||||
if (vendor_id == VENDOR_QUALCOMM) {
|
||||
const u32 major = (driver_version >> 24) << 2;
|
||||
const u32 minor = (driver_version >> 12) & 0xFFF;
|
||||
const u32 patch = driver_version & 0xFFF;
|
||||
version_str = fmt::format("{}.{}.{}", major, minor, patch);
|
||||
}
|
||||
else if (vendor_id == VENDOR_ARM) {
|
||||
u32 major = VK_API_VERSION_MAJOR(driver_version);
|
||||
u32 minor = VK_API_VERSION_MINOR(driver_version);
|
||||
u32 patch = VK_API_VERSION_PATCH(driver_version);
|
||||
|
||||
// ARM custom encoding for newer drivers
|
||||
if (major > 10) {
|
||||
major = (driver_version >> 22) & 0x3FF;
|
||||
minor = (driver_version >> 12) & 0x3FF;
|
||||
patch = driver_version & 0xFFF;
|
||||
}
|
||||
version_str = fmt::format("{}.{}.{}", major, minor, patch);
|
||||
}
|
||||
// Standard Vulkan version encoding for other vendors
|
||||
else {
|
||||
const u32 major = VK_API_VERSION_MAJOR(driver_version);
|
||||
const u32 minor = VK_API_VERSION_MINOR(driver_version);
|
||||
const u32 patch = VK_API_VERSION_PATCH(driver_version);
|
||||
version_str = fmt::format("{}.{}.{}", major, minor, patch);
|
||||
}
|
||||
|
||||
return Common::Android::ToJString(env, version_str);
|
||||
} catch (...) {
|
||||
return Common::Android::ToJString(env, "N/A");
|
||||
}
|
||||
}
|
||||
|
||||
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getVulkanApiVersion(JNIEnv* env, jobject jobj) {
|
||||
try {
|
||||
const auto props = GetVulkanDeviceProperties();
|
||||
if (props.deviceID == 0) {
|
||||
return Common::Android::ToJString(env, "N/A");
|
||||
}
|
||||
|
||||
const u32 api_version = props.apiVersion;
|
||||
const u32 major = VK_API_VERSION_MAJOR(api_version);
|
||||
const u32 minor = VK_API_VERSION_MINOR(api_version);
|
||||
const u32 patch = VK_API_VERSION_PATCH(api_version);
|
||||
const u32 variant = VK_API_VERSION_VARIANT(api_version);
|
||||
|
||||
// Include variant if non-zero (rare on Android)
|
||||
const std::string version_str = variant > 0
|
||||
? fmt::format("{}.{}.{}.{}", variant, major, minor, patch)
|
||||
: fmt::format("{}.{}.{}", major, minor, patch);
|
||||
|
||||
return Common::Android::ToJString(env, version_str);
|
||||
} catch (...) {
|
||||
return Common::Android::ToJString(env, "N/A");
|
||||
}
|
||||
}
|
||||
|
||||
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getGpuModel(JNIEnv* env, jobject jobj) {
|
||||
const auto props = GetVulkanDeviceProperties();
|
||||
if (props.deviceID == 0) {
|
||||
return Common::Android::ToJString(env, "Unknown");
|
||||
}
|
||||
|
||||
return Common::Android::ToJString(env, props.deviceName);
|
||||
}
|
||||
|
||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_applySettings(JNIEnv* env, jobject jobj) {
|
||||
EmulationSession::GetInstance().System().ApplySettings();
|
||||
EmulationSession::GetInstance().System().HIDCore().ReloadInputDevices();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
app:cardElevation="0dp"
|
||||
app:cardBackgroundColor="?attr/colorSurfaceVariant">
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxHeight="400dp"
|
||||
android:padding="12dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_system_info"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="monospace"
|
||||
android:textAppearance="?attr/textAppearanceBodySmall"
|
||||
android:textColor="?attr/colorOnSurfaceVariant"
|
||||
android:textIsSelectable="true" />
|
||||
|
||||
</ScrollView>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
</LinearLayout>
|
||||
|
|
@ -299,6 +299,25 @@
|
|||
<string name="permission_denied_description">You denied this permission too many times and now you have to manually grant it in system settings.</string>
|
||||
<string name="about">About</string>
|
||||
<string name="about_description">Build version, credits, and more</string>
|
||||
<string name="system_information">System Information</string>
|
||||
<string name="system_information_description">View detailed device information</string>
|
||||
<string name="device_manufacturer">Manufacturer</string>
|
||||
<string name="device_model">Model</string>
|
||||
<string name="product">Product</string>
|
||||
<string name="android_version">Android Version</string>
|
||||
<string name="android_security_patch">Security Patch</string>
|
||||
<string name="build_id">Build ID</string>
|
||||
<string name="general_information">General Information</string>
|
||||
<string name="hardware">Hardware</string>
|
||||
<string name="supported_abis">Supported ABIs</string>
|
||||
<string name="cpu_info">CPU Information</string>
|
||||
<string name="gpu_information">GPU Information</string>
|
||||
<string name="vulkan_driver_version">Vulkan Driver Version</string>
|
||||
<string name="error_getting_emulator_info">Error getting emulator info</string>
|
||||
<string name="memory_info">Memory Information</string>
|
||||
<string name="total_memory">Total Memory</string>
|
||||
<string name="soc">SOC:</string>
|
||||
|
||||
<string name="warning_help">Help</string>
|
||||
<string name="warning">Warning</string>
|
||||
<string name="warning_skip">Skip</string>
|
||||
|
|
@ -656,7 +675,7 @@
|
|||
<string name="installing">Installing…</string>
|
||||
<string name="latest">Latest</string>
|
||||
<string name="recommended_driver">Recommended Driver:</string>
|
||||
<string name="gpu_model">GPU Model:</string>
|
||||
<string name="gpu_model">GPU Model</string>
|
||||
<string name="unsupported_gpu">Unsupported GPU</string>
|
||||
<string name="unsupported_gpu_warning">Your GPU does not support driver injection. Attempting to set custom drivers is not recommended.</string>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue