Merge remote-tracking branch 'upstream/master'

This commit is contained in:
amwatson 2024-02-19 16:47:40 -06:00
commit 624cb422e1
15 changed files with 250 additions and 79 deletions

View file

@ -294,11 +294,20 @@ endif()
add_library(httplib INTERFACE)
if(USE_SYSTEM_CPP_HTTPLIB)
find_package(CppHttp 0.14.1)
if(CppHttp_FOUND)
target_link_libraries(httplib INTERFACE httplib::httplib)
else()
message(STATUS "Cpp-httplib not found or not suitable version! Falling back to bundled...")
# Detect if system cpphttplib is a shared library
# this breaks building as Citra relies on functions that are moved
# into the shared object.
get_target_property(HTTP_LIBS httplib::httplib INTERFACE_LINK_LIBRARIES)
if(HTTP_LIBS)
message(WARNING "Shared cpp-http (${HTTP_LIBS}) not supported. Falling back to bundled...")
target_include_directories(httplib SYSTEM INTERFACE ./httplib)
else()
if(CppHttp_FOUND)
target_link_libraries(httplib INTERFACE httplib::httplib)
else()
message(STATUS "Cpp-httplib not found or not suitable version! Falling back to bundled...")
target_include_directories(httplib SYSTEM INTERFACE ./httplib)
endif()
endif()
else()
target_include_directories(httplib SYSTEM INTERFACE ./httplib)

View file

@ -9,10 +9,13 @@ import android.app.Application
import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Context
import android.os.Build
import org.citra.citra_emu.utils.DirectoryInitialization
import org.citra.citra_emu.utils.DocumentsTree
import org.citra.citra_emu.utils.GpuDriverHelper
import org.citra.citra_emu.utils.PermissionsHandler
import org.citra.citra_emu.utils.Log
import org.citra.citra_emu.utils.MemoryUtil
open class CitraApplication : Application() {
private fun createNotificationChannel() {
@ -53,9 +56,20 @@ open class CitraApplication : Application() {
}
NativeLibrary.logDeviceInfo()
logDeviceInfo()
createNotificationChannel()
}
fun logDeviceInfo() {
Log.info("Device Manufacturer - ${Build.MANUFACTURER}")
Log.info("Device Model - ${Build.MODEL}")
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R) {
Log.info("SoC Manufacturer - ${Build.SOC_MANUFACTURER}")
Log.info("SoC Model - ${Build.SOC_MODEL}")
}
Log.info("Total System Memory - ${MemoryUtil.getDeviceRAM()}")
}
companion object {
private var application: CitraApplication? = null

View file

@ -425,12 +425,12 @@ object NativeLibrary {
}
fun setEmulationActivity(emulationActivity: EmulationActivity?) {
Log.verbose("[NativeLibrary] Registering EmulationActivity.")
Log.debug("[NativeLibrary] Registering EmulationActivity.")
sEmulationActivity = WeakReference(emulationActivity)
}
fun clearEmulationActivity() {
Log.verbose("[NativeLibrary] Unregistering EmulationActivity.")
Log.debug("[NativeLibrary] Unregistering EmulationActivity.")
sEmulationActivity.clear()
}

View file

@ -94,14 +94,14 @@ object DirectoryInitialization {
val dataPath = PermissionsHandler.citraDirectory
if (dataPath.toString().isNotEmpty()) {
userPath = dataPath.toString()
Log.debug("[DirectoryInitialization] User Dir: $userPath")
android.util.Log.d("[Citra Frontend]", "[DirectoryInitialization] User Dir: $userPath")
return true
}
return false
}
private fun copyAsset(asset: String, output: File, overwrite: Boolean, context: Context) {
Log.verbose("[DirectoryInitialization] Copying File $asset to $output")
Log.debug("[DirectoryInitialization] Copying File $asset to $output")
try {
if (!output.exists() || overwrite) {
val inputStream = context.assets.open(asset)
@ -121,7 +121,7 @@ object DirectoryInitialization {
overwrite: Boolean,
context: Context
) {
Log.verbose("[DirectoryInitialization] Copying Folder $assetFolder to $outputFolder")
Log.debug("[DirectoryInitialization] Copying Folder $assetFolder to $outputFolder")
try {
var createdFolder = false
for (file in context.assets.list(assetFolder)!!) {

View file

@ -4,34 +4,17 @@
package org.citra.citra_emu.utils
import android.util.Log
import org.citra.citra_emu.BuildConfig
/**
* Contains methods that call through to [android.util.Log], but
* with the same TAG automatically provided. Also no-ops VERBOSE and DEBUG log
* levels in release builds.
*/
object Log {
// Tracks whether we should share the old log or the current log
var gameLaunched = false
private const val TAG = "Citra Frontend"
fun verbose(message: String?) {
if (BuildConfig.DEBUG) {
Log.v(TAG, message!!)
}
}
external fun debug(message: String)
fun debug(message: String?) {
if (BuildConfig.DEBUG) {
Log.d(TAG, message!!)
}
}
external fun warning(message: String)
fun info(message: String?) = Log.i(TAG, message!!)
external fun info(message: String)
fun warning(message: String?) = Log.w(TAG, message!!)
external fun error(message: String)
fun error(message: String?) = Log.e(TAG, message!!)
external fun critical(message: String)
}

View file

@ -0,0 +1,108 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.citra.citra_emu.utils
import android.app.ActivityManager
import android.content.Context
import android.os.Build
import org.citra.citra_emu.CitraApplication
import org.citra.citra_emu.R
import java.util.Locale
import kotlin.math.ceil
object MemoryUtil {
private val context get() = CitraApplication.appContext
private val Float.hundredths: String
get() = String.format(Locale.ROOT, "%.2f", this)
const val Kb: Float = 1024F
const val Mb = Kb * 1024
const val Gb = Mb * 1024
const val Tb = Gb * 1024
const val Pb = Tb * 1024
const val Eb = Pb * 1024
fun bytesToSizeUnit(size: Float, roundUp: Boolean = false): String =
when {
size < Kb -> {
context.getString(
R.string.memory_formatted,
size.hundredths,
context.getString(R.string.memory_byte_shorthand)
)
}
size < Mb -> {
context.getString(
R.string.memory_formatted,
if (roundUp) ceil(size / Kb) else (size / Kb).hundredths,
context.getString(R.string.memory_kilobyte)
)
}
size < Gb -> {
context.getString(
R.string.memory_formatted,
if (roundUp) ceil(size / Mb) else (size / Mb).hundredths,
context.getString(R.string.memory_megabyte)
)
}
size < Tb -> {
context.getString(
R.string.memory_formatted,
if (roundUp) ceil(size / Gb) else (size / Gb).hundredths,
context.getString(R.string.memory_gigabyte)
)
}
size < Pb -> {
context.getString(
R.string.memory_formatted,
if (roundUp) ceil(size / Tb) else (size / Tb).hundredths,
context.getString(R.string.memory_terabyte)
)
}
size < Eb -> {
context.getString(
R.string.memory_formatted,
if (roundUp) ceil(size / Pb) else (size / Pb).hundredths,
context.getString(R.string.memory_petabyte)
)
}
else -> {
context.getString(
R.string.memory_formatted,
if (roundUp) ceil(size / Eb) else (size / Eb).hundredths,
context.getString(R.string.memory_exabyte)
)
}
}
val totalMemory: Float
get() {
val memInfo = ActivityManager.MemoryInfo()
with(context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager) {
getMemoryInfo(memInfo)
}
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
memInfo.advertisedMem.toFloat()
} else {
memInfo.totalMem.toFloat()
}
}
fun isLessThan(minimum: Int, size: Float): Boolean =
when (size) {
Kb -> totalMemory < Mb && totalMemory < minimum
Mb -> totalMemory < Gb && (totalMemory / Mb) < minimum
Gb -> totalMemory < Tb && (totalMemory / Gb) < minimum
Tb -> totalMemory < Pb && (totalMemory / Tb) < minimum
Pb -> totalMemory < Eb && (totalMemory / Pb) < minimum
Eb -> totalMemory / Eb < minimum
else -> totalMemory < Kb && totalMemory < minimum
}
// Devices are unlikely to have 0.5GB increments of memory so we'll just round up to account for
// the potential error created by memInfo.totalMem
fun getDeviceRAM(): String = bytesToSizeUnit(totalMemory, true)
}

View file

@ -28,6 +28,7 @@ add_library(citra-android SHARED
ndk_motion.cpp
ndk_motion.h
system_save_game.cpp
native_log.cpp
# VR-specific
vr/OpenXR.cpp
vr/gl/Egl.cpp

View file

@ -0,0 +1,30 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <common/logging/log.h>
#include <jni.h>
#include "android_common/android_common.h"
extern "C" {
void Java_org_citra_citra_1emu_utils_Log_debug(JNIEnv* env, jobject obj, jstring jmessage) {
LOG_DEBUG(Frontend, "{}", GetJString(env, jmessage));
}
void Java_org_citra_citra_1emu_utils_Log_warning(JNIEnv* env, jobject obj, jstring jmessage) {
LOG_WARNING(Frontend, "{}", GetJString(env, jmessage));
}
void Java_org_citra_citra_1emu_utils_Log_info(JNIEnv* env, jobject obj, jstring jmessage) {
LOG_INFO(Frontend, "{}", GetJString(env, jmessage));
}
void Java_org_citra_citra_1emu_utils_Log_error(JNIEnv* env, jobject obj, jstring jmessage) {
LOG_ERROR(Frontend, "{}", GetJString(env, jmessage));
}
void Java_org_citra_citra_1emu_utils_Log_critical(JNIEnv* env, jobject obj, jstring jmessage) {
LOG_CRITICAL(Frontend, "{}", GetJString(env, jmessage));
}
} // extern "C"

View file

@ -442,6 +442,17 @@
<string name="cia_install_error_encrypted">\"%s\" must be decrypted before being used with CitraVR.\n A real 3DS is required</string>
<string name="cia_install_error_unknown">An unknown error occurred while installing \"%s\".\n Please see the log for more details</string>
<!-- Memory Sizes -->
<string name="memory_formatted">%1$s %2$s</string>
<string name="memory_byte">Byte</string>
<string name="memory_byte_shorthand">B</string>
<string name="memory_kilobyte">KB</string>
<string name="memory_megabyte">MB</string>
<string name="memory_gigabyte">GB</string>
<string name="memory_terabyte">TB</string>
<string name="memory_petabyte">PB</string>
<string name="memory_exabyte">EB</string>
<!-- Theme Modes -->
<string name="change_theme_mode">Change Theme Mode</string>
<string name="theme_mode_follow_system">Follow System</string>

View file

@ -298,9 +298,9 @@ void Source::ParseConfig(SourceConfiguration::Configuration& config,
b.buffer_id,
state.mono_or_stereo,
state.format,
true,
{}, // 0 in u32_dsp
false,
true, // from_queue
0, // play_position
false, // has_played
});
}
LOG_TRACE(Audio_DSP, "enqueuing queued {} addr={:#010x} len={} id={}", i,
@ -321,7 +321,11 @@ void Source::ParseConfig(SourceConfiguration::Configuration& config,
void Source::GenerateFrame() {
current_frame.fill({});
if (state.current_buffer.empty() && !DequeueBuffer()) {
if (state.current_buffer.empty()) {
// TODO(SachinV): Should dequeue happen at the end of the frame generation?
if (DequeueBuffer()) {
return;
}
state.enabled = false;
state.buffer_update = true;
state.last_buffer_id = state.current_buffer_id;
@ -330,8 +334,6 @@ void Source::GenerateFrame() {
}
std::size_t frame_position = 0;
state.current_sample_number = state.next_sample_number;
while (frame_position < current_frame.size()) {
if (state.current_buffer.empty() && !DequeueBuffer()) {
break;
@ -358,7 +360,7 @@ void Source::GenerateFrame() {
}
// TODO(jroweboy): Keep track of frame_position independently so that it doesn't lose precision
// over time
state.next_sample_number += static_cast<u32>(frame_position * state.rate_multiplier);
state.current_sample_number += static_cast<u32>(frame_position * state.rate_multiplier);
state.filters.ProcessFrame(current_frame);
}
@ -409,7 +411,6 @@ bool Source::DequeueBuffer() {
// the first playthrough starts at play_position, loops start at the beginning of the buffer
state.current_sample_number = (!buf.has_played) ? buf.play_position : 0;
state.next_sample_number = state.current_sample_number;
state.current_buffer_physical_address = buf.physical_address;
state.current_buffer_id = buf.buffer_id;
state.last_buffer_id = 0;
@ -420,8 +421,17 @@ bool Source::DequeueBuffer() {
state.input_queue.push(buf);
}
LOG_TRACE(Audio_DSP, "source_id={} buffer_id={} from_queue={} current_buffer.size()={}",
source_id, buf.buffer_id, buf.from_queue, state.current_buffer.size());
// Because our interpolation consumes samples instead of using an index,
// let's just consume the samples up to the current sample number.
state.current_buffer.erase(
state.current_buffer.begin(),
std::next(state.current_buffer.begin(), state.current_sample_number));
LOG_TRACE(Audio_DSP,
"source_id={} buffer_id={} from_queue={} current_buffer.size()={}, "
"buf.has_played={}, buf.play_position={}",
source_id, buf.buffer_id, buf.from_queue, state.current_buffer.size(), buf.has_played,
buf.play_position);
return true;
}

View file

@ -87,8 +87,8 @@ private:
Format format;
bool from_queue;
u32_dsp play_position; // = 0;
bool has_played; // = false;
u32 play_position; // = 0;
bool has_played; // = false;
private:
template <class Archive>
@ -136,7 +136,6 @@ private:
// Current buffer
u32 current_sample_number = 0;
u32 next_sample_number = 0;
PAddr current_buffer_physical_address = 0;
AudioInterp::StereoBuffer16 current_buffer = {};
@ -171,7 +170,6 @@ private:
ar& mono_or_stereo;
ar& format;
ar& current_sample_number;
ar& next_sample_number;
ar& current_buffer_physical_address;
ar& current_buffer;
ar& buffer_update;

View file

@ -3197,8 +3197,10 @@ int main(int argc, char* argv[]) {
QApplication::setHighDpiScaleFactorRoundingPolicy(rounding_policy);
#ifdef __APPLE__
std::string bin_path = FileUtil::GetBundleDirectory() + DIR_SEP + "..";
chdir(bin_path.c_str());
auto bundle_dir = FileUtil::GetBundleDirectory();
if (bundle_dir) {
FileUtil::SetCurrentDir(bundle_dir.value() + "..");
}
#endif
#ifdef ENABLE_OPENGL

View file

@ -13,7 +13,6 @@
#endif
// The user data dir
#define ROOT_DIR "."
#define USERDATA_DIR "user"
#ifdef USER_DIR
#define EMU_DATA_DIR USER_DIR

View file

@ -634,6 +634,10 @@ std::optional<std::string> GetCurrentDir() {
std::string strDir = dir;
#endif
free(dir);
if (!strDir.ends_with(DIR_SEP)) {
strDir += DIR_SEP;
}
return strDir;
} // namespace FileUtil
@ -646,17 +650,36 @@ bool SetCurrentDir(const std::string& directory) {
}
#if defined(__APPLE__)
std::string GetBundleDirectory() {
CFURLRef BundleRef;
char AppBundlePath[MAXPATHLEN];
std::optional<std::string> GetBundleDirectory() {
// Get the main bundle for the app
BundleRef = CFBundleCopyBundleURL(CFBundleGetMainBundle());
CFStringRef BundlePath = CFURLCopyFileSystemPath(BundleRef, kCFURLPOSIXPathStyle);
CFStringGetFileSystemRepresentation(BundlePath, AppBundlePath, sizeof(AppBundlePath));
CFRelease(BundleRef);
CFRelease(BundlePath);
CFBundleRef bundle_ref = CFBundleGetMainBundle();
if (!bundle_ref) {
return {};
}
return AppBundlePath;
CFURLRef bundle_url_ref = CFBundleCopyBundleURL(bundle_ref);
if (!bundle_url_ref) {
return {};
}
SCOPE_EXIT({ CFRelease(bundle_url_ref); });
CFStringRef bundle_path_ref = CFURLCopyFileSystemPath(bundle_url_ref, kCFURLPOSIXPathStyle);
if (!bundle_path_ref) {
return {};
}
SCOPE_EXIT({ CFRelease(bundle_path_ref); });
char app_bundle_path[MAXPATHLEN];
if (!CFStringGetFileSystemRepresentation(bundle_path_ref, app_bundle_path,
sizeof(app_bundle_path))) {
return {};
}
std::string path_str(app_bundle_path);
if (!path_str.ends_with(DIR_SEP)) {
path_str += DIR_SEP;
}
return path_str;
}
#endif
@ -732,22 +755,6 @@ static const std::string& GetHomeDirectory() {
}
#endif
std::string GetSysDirectory() {
std::string sysDir;
#if defined(__APPLE__)
sysDir = GetBundleDirectory();
sysDir += DIR_SEP;
sysDir += SYSDATA_DIR;
#else
sysDir = SYSDATA_DIR;
#endif
sysDir += DIR_SEP;
LOG_DEBUG(Common_Filesystem, "Setting to {}:", sysDir);
return sysDir;
}
namespace {
std::unordered_map<UserPath, std::string> g_paths;
std::unordered_map<UserPath, std::string> g_default_paths;
@ -777,8 +784,10 @@ void SetUserPath(const std::string& path) {
g_paths.emplace(UserPath::ConfigDir, user_path + CONFIG_DIR DIR_SEP);
g_paths.emplace(UserPath::CacheDir, user_path + CACHE_DIR DIR_SEP);
#else
if (FileUtil::Exists(ROOT_DIR DIR_SEP USERDATA_DIR)) {
user_path = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP;
auto current_dir = FileUtil::GetCurrentDir();
if (current_dir.has_value() &&
FileUtil::Exists(current_dir.value() + USERDATA_DIR DIR_SEP)) {
user_path = current_dir.value() + USERDATA_DIR DIR_SEP;
g_paths.emplace(UserPath::ConfigDir, user_path + CONFIG_DIR DIR_SEP);
g_paths.emplace(UserPath::CacheDir, user_path + CACHE_DIR DIR_SEP);
} else {

View file

@ -193,11 +193,8 @@ void SetCurrentRomPath(const std::string& path);
// Update the Global Path with the new value
void UpdateUserPath(UserPath path, const std::string& filename);
// Returns the path to where the sys file are
[[nodiscard]] std::string GetSysDirectory();
#ifdef __APPLE__
[[nodiscard]] std::string GetBundleDirectory();
[[nodiscard]] std::optional<std::string> GetBundleDirectory();
#endif
#ifdef _WIN32