mirror of
https://github.com/amwatson/CitraVR.git
synced 2024-09-20 03:11:40 +02:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
624cb422e1
15 changed files with 250 additions and 79 deletions
9
externals/CMakeLists.txt
vendored
9
externals/CMakeLists.txt
vendored
|
@ -294,12 +294,21 @@ endif()
|
||||||
add_library(httplib INTERFACE)
|
add_library(httplib INTERFACE)
|
||||||
if(USE_SYSTEM_CPP_HTTPLIB)
|
if(USE_SYSTEM_CPP_HTTPLIB)
|
||||||
find_package(CppHttp 0.14.1)
|
find_package(CppHttp 0.14.1)
|
||||||
|
# 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)
|
if(CppHttp_FOUND)
|
||||||
target_link_libraries(httplib INTERFACE httplib::httplib)
|
target_link_libraries(httplib INTERFACE httplib::httplib)
|
||||||
else()
|
else()
|
||||||
message(STATUS "Cpp-httplib not found or not suitable version! Falling back to bundled...")
|
message(STATUS "Cpp-httplib not found or not suitable version! Falling back to bundled...")
|
||||||
target_include_directories(httplib SYSTEM INTERFACE ./httplib)
|
target_include_directories(httplib SYSTEM INTERFACE ./httplib)
|
||||||
endif()
|
endif()
|
||||||
|
endif()
|
||||||
else()
|
else()
|
||||||
target_include_directories(httplib SYSTEM INTERFACE ./httplib)
|
target_include_directories(httplib SYSTEM INTERFACE ./httplib)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -9,10 +9,13 @@ import android.app.Application
|
||||||
import android.app.NotificationChannel
|
import android.app.NotificationChannel
|
||||||
import android.app.NotificationManager
|
import android.app.NotificationManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.os.Build
|
||||||
import org.citra.citra_emu.utils.DirectoryInitialization
|
import org.citra.citra_emu.utils.DirectoryInitialization
|
||||||
import org.citra.citra_emu.utils.DocumentsTree
|
import org.citra.citra_emu.utils.DocumentsTree
|
||||||
import org.citra.citra_emu.utils.GpuDriverHelper
|
import org.citra.citra_emu.utils.GpuDriverHelper
|
||||||
import org.citra.citra_emu.utils.PermissionsHandler
|
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() {
|
open class CitraApplication : Application() {
|
||||||
private fun createNotificationChannel() {
|
private fun createNotificationChannel() {
|
||||||
|
@ -53,9 +56,20 @@ open class CitraApplication : Application() {
|
||||||
}
|
}
|
||||||
|
|
||||||
NativeLibrary.logDeviceInfo()
|
NativeLibrary.logDeviceInfo()
|
||||||
|
logDeviceInfo()
|
||||||
createNotificationChannel()
|
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 {
|
companion object {
|
||||||
private var application: CitraApplication? = null
|
private var application: CitraApplication? = null
|
||||||
|
|
||||||
|
|
|
@ -425,12 +425,12 @@ object NativeLibrary {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setEmulationActivity(emulationActivity: EmulationActivity?) {
|
fun setEmulationActivity(emulationActivity: EmulationActivity?) {
|
||||||
Log.verbose("[NativeLibrary] Registering EmulationActivity.")
|
Log.debug("[NativeLibrary] Registering EmulationActivity.")
|
||||||
sEmulationActivity = WeakReference(emulationActivity)
|
sEmulationActivity = WeakReference(emulationActivity)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun clearEmulationActivity() {
|
fun clearEmulationActivity() {
|
||||||
Log.verbose("[NativeLibrary] Unregistering EmulationActivity.")
|
Log.debug("[NativeLibrary] Unregistering EmulationActivity.")
|
||||||
sEmulationActivity.clear()
|
sEmulationActivity.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -94,14 +94,14 @@ object DirectoryInitialization {
|
||||||
val dataPath = PermissionsHandler.citraDirectory
|
val dataPath = PermissionsHandler.citraDirectory
|
||||||
if (dataPath.toString().isNotEmpty()) {
|
if (dataPath.toString().isNotEmpty()) {
|
||||||
userPath = dataPath.toString()
|
userPath = dataPath.toString()
|
||||||
Log.debug("[DirectoryInitialization] User Dir: $userPath")
|
android.util.Log.d("[Citra Frontend]", "[DirectoryInitialization] User Dir: $userPath")
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun copyAsset(asset: String, output: File, overwrite: Boolean, context: Context) {
|
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 {
|
try {
|
||||||
if (!output.exists() || overwrite) {
|
if (!output.exists() || overwrite) {
|
||||||
val inputStream = context.assets.open(asset)
|
val inputStream = context.assets.open(asset)
|
||||||
|
@ -121,7 +121,7 @@ object DirectoryInitialization {
|
||||||
overwrite: Boolean,
|
overwrite: Boolean,
|
||||||
context: Context
|
context: Context
|
||||||
) {
|
) {
|
||||||
Log.verbose("[DirectoryInitialization] Copying Folder $assetFolder to $outputFolder")
|
Log.debug("[DirectoryInitialization] Copying Folder $assetFolder to $outputFolder")
|
||||||
try {
|
try {
|
||||||
var createdFolder = false
|
var createdFolder = false
|
||||||
for (file in context.assets.list(assetFolder)!!) {
|
for (file in context.assets.list(assetFolder)!!) {
|
||||||
|
|
|
@ -4,34 +4,17 @@
|
||||||
|
|
||||||
package org.citra.citra_emu.utils
|
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 {
|
object Log {
|
||||||
// Tracks whether we should share the old log or the current log
|
// Tracks whether we should share the old log or the current log
|
||||||
var gameLaunched = false
|
var gameLaunched = false
|
||||||
private const val TAG = "Citra Frontend"
|
|
||||||
|
|
||||||
fun verbose(message: String?) {
|
external fun debug(message: String)
|
||||||
if (BuildConfig.DEBUG) {
|
|
||||||
Log.v(TAG, message!!)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun debug(message: String?) {
|
external fun warning(message: String)
|
||||||
if (BuildConfig.DEBUG) {
|
|
||||||
Log.d(TAG, message!!)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
|
@ -28,6 +28,7 @@ add_library(citra-android SHARED
|
||||||
ndk_motion.cpp
|
ndk_motion.cpp
|
||||||
ndk_motion.h
|
ndk_motion.h
|
||||||
system_save_game.cpp
|
system_save_game.cpp
|
||||||
|
native_log.cpp
|
||||||
# VR-specific
|
# VR-specific
|
||||||
vr/OpenXR.cpp
|
vr/OpenXR.cpp
|
||||||
vr/gl/Egl.cpp
|
vr/gl/Egl.cpp
|
||||||
|
|
30
src/android/app/src/main/jni/native_log.cpp
Normal file
30
src/android/app/src/main/jni/native_log.cpp
Normal 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"
|
|
@ -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_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>
|
<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 -->
|
<!-- Theme Modes -->
|
||||||
<string name="change_theme_mode">Change Theme Mode</string>
|
<string name="change_theme_mode">Change Theme Mode</string>
|
||||||
<string name="theme_mode_follow_system">Follow System</string>
|
<string name="theme_mode_follow_system">Follow System</string>
|
||||||
|
|
|
@ -298,9 +298,9 @@ void Source::ParseConfig(SourceConfiguration::Configuration& config,
|
||||||
b.buffer_id,
|
b.buffer_id,
|
||||||
state.mono_or_stereo,
|
state.mono_or_stereo,
|
||||||
state.format,
|
state.format,
|
||||||
true,
|
true, // from_queue
|
||||||
{}, // 0 in u32_dsp
|
0, // play_position
|
||||||
false,
|
false, // has_played
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
LOG_TRACE(Audio_DSP, "enqueuing queued {} addr={:#010x} len={} id={}", i,
|
LOG_TRACE(Audio_DSP, "enqueuing queued {} addr={:#010x} len={} id={}", i,
|
||||||
|
@ -321,7 +321,11 @@ void Source::ParseConfig(SourceConfiguration::Configuration& config,
|
||||||
void Source::GenerateFrame() {
|
void Source::GenerateFrame() {
|
||||||
current_frame.fill({});
|
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.enabled = false;
|
||||||
state.buffer_update = true;
|
state.buffer_update = true;
|
||||||
state.last_buffer_id = state.current_buffer_id;
|
state.last_buffer_id = state.current_buffer_id;
|
||||||
|
@ -330,8 +334,6 @@ void Source::GenerateFrame() {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t frame_position = 0;
|
std::size_t frame_position = 0;
|
||||||
|
|
||||||
state.current_sample_number = state.next_sample_number;
|
|
||||||
while (frame_position < current_frame.size()) {
|
while (frame_position < current_frame.size()) {
|
||||||
if (state.current_buffer.empty() && !DequeueBuffer()) {
|
if (state.current_buffer.empty() && !DequeueBuffer()) {
|
||||||
break;
|
break;
|
||||||
|
@ -358,7 +360,7 @@ void Source::GenerateFrame() {
|
||||||
}
|
}
|
||||||
// TODO(jroweboy): Keep track of frame_position independently so that it doesn't lose precision
|
// TODO(jroweboy): Keep track of frame_position independently so that it doesn't lose precision
|
||||||
// over time
|
// 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);
|
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
|
// 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.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_physical_address = buf.physical_address;
|
||||||
state.current_buffer_id = buf.buffer_id;
|
state.current_buffer_id = buf.buffer_id;
|
||||||
state.last_buffer_id = 0;
|
state.last_buffer_id = 0;
|
||||||
|
@ -420,8 +421,17 @@ bool Source::DequeueBuffer() {
|
||||||
state.input_queue.push(buf);
|
state.input_queue.push(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_TRACE(Audio_DSP, "source_id={} buffer_id={} from_queue={} current_buffer.size()={}",
|
// Because our interpolation consumes samples instead of using an index,
|
||||||
source_id, buf.buffer_id, buf.from_queue, state.current_buffer.size());
|
// 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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,7 +87,7 @@ private:
|
||||||
Format format;
|
Format format;
|
||||||
|
|
||||||
bool from_queue;
|
bool from_queue;
|
||||||
u32_dsp play_position; // = 0;
|
u32 play_position; // = 0;
|
||||||
bool has_played; // = false;
|
bool has_played; // = false;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -136,7 +136,6 @@ private:
|
||||||
// Current buffer
|
// Current buffer
|
||||||
|
|
||||||
u32 current_sample_number = 0;
|
u32 current_sample_number = 0;
|
||||||
u32 next_sample_number = 0;
|
|
||||||
PAddr current_buffer_physical_address = 0;
|
PAddr current_buffer_physical_address = 0;
|
||||||
AudioInterp::StereoBuffer16 current_buffer = {};
|
AudioInterp::StereoBuffer16 current_buffer = {};
|
||||||
|
|
||||||
|
@ -171,7 +170,6 @@ private:
|
||||||
ar& mono_or_stereo;
|
ar& mono_or_stereo;
|
||||||
ar& format;
|
ar& format;
|
||||||
ar& current_sample_number;
|
ar& current_sample_number;
|
||||||
ar& next_sample_number;
|
|
||||||
ar& current_buffer_physical_address;
|
ar& current_buffer_physical_address;
|
||||||
ar& current_buffer;
|
ar& current_buffer;
|
||||||
ar& buffer_update;
|
ar& buffer_update;
|
||||||
|
|
|
@ -3197,8 +3197,10 @@ int main(int argc, char* argv[]) {
|
||||||
QApplication::setHighDpiScaleFactorRoundingPolicy(rounding_policy);
|
QApplication::setHighDpiScaleFactorRoundingPolicy(rounding_policy);
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
std::string bin_path = FileUtil::GetBundleDirectory() + DIR_SEP + "..";
|
auto bundle_dir = FileUtil::GetBundleDirectory();
|
||||||
chdir(bin_path.c_str());
|
if (bundle_dir) {
|
||||||
|
FileUtil::SetCurrentDir(bundle_dir.value() + "..");
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ENABLE_OPENGL
|
#ifdef ENABLE_OPENGL
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// The user data dir
|
// The user data dir
|
||||||
#define ROOT_DIR "."
|
|
||||||
#define USERDATA_DIR "user"
|
#define USERDATA_DIR "user"
|
||||||
#ifdef USER_DIR
|
#ifdef USER_DIR
|
||||||
#define EMU_DATA_DIR USER_DIR
|
#define EMU_DATA_DIR USER_DIR
|
||||||
|
|
|
@ -634,6 +634,10 @@ std::optional<std::string> GetCurrentDir() {
|
||||||
std::string strDir = dir;
|
std::string strDir = dir;
|
||||||
#endif
|
#endif
|
||||||
free(dir);
|
free(dir);
|
||||||
|
|
||||||
|
if (!strDir.ends_with(DIR_SEP)) {
|
||||||
|
strDir += DIR_SEP;
|
||||||
|
}
|
||||||
return strDir;
|
return strDir;
|
||||||
} // namespace FileUtil
|
} // namespace FileUtil
|
||||||
|
|
||||||
|
@ -646,17 +650,36 @@ bool SetCurrentDir(const std::string& directory) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
std::string GetBundleDirectory() {
|
std::optional<std::string> GetBundleDirectory() {
|
||||||
CFURLRef BundleRef;
|
|
||||||
char AppBundlePath[MAXPATHLEN];
|
|
||||||
// Get the main bundle for the app
|
// Get the main bundle for the app
|
||||||
BundleRef = CFBundleCopyBundleURL(CFBundleGetMainBundle());
|
CFBundleRef bundle_ref = CFBundleGetMainBundle();
|
||||||
CFStringRef BundlePath = CFURLCopyFileSystemPath(BundleRef, kCFURLPOSIXPathStyle);
|
if (!bundle_ref) {
|
||||||
CFStringGetFileSystemRepresentation(BundlePath, AppBundlePath, sizeof(AppBundlePath));
|
return {};
|
||||||
CFRelease(BundleRef);
|
}
|
||||||
CFRelease(BundlePath);
|
|
||||||
|
|
||||||
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
|
#endif
|
||||||
|
|
||||||
|
@ -732,22 +755,6 @@ static const std::string& GetHomeDirectory() {
|
||||||
}
|
}
|
||||||
#endif
|
#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 {
|
namespace {
|
||||||
std::unordered_map<UserPath, std::string> g_paths;
|
std::unordered_map<UserPath, std::string> g_paths;
|
||||||
std::unordered_map<UserPath, std::string> g_default_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::ConfigDir, user_path + CONFIG_DIR DIR_SEP);
|
||||||
g_paths.emplace(UserPath::CacheDir, user_path + CACHE_DIR DIR_SEP);
|
g_paths.emplace(UserPath::CacheDir, user_path + CACHE_DIR DIR_SEP);
|
||||||
#else
|
#else
|
||||||
if (FileUtil::Exists(ROOT_DIR DIR_SEP USERDATA_DIR)) {
|
auto current_dir = FileUtil::GetCurrentDir();
|
||||||
user_path = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP;
|
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::ConfigDir, user_path + CONFIG_DIR DIR_SEP);
|
||||||
g_paths.emplace(UserPath::CacheDir, user_path + CACHE_DIR DIR_SEP);
|
g_paths.emplace(UserPath::CacheDir, user_path + CACHE_DIR DIR_SEP);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -193,11 +193,8 @@ void SetCurrentRomPath(const std::string& path);
|
||||||
// Update the Global Path with the new value
|
// Update the Global Path with the new value
|
||||||
void UpdateUserPath(UserPath path, const std::string& filename);
|
void UpdateUserPath(UserPath path, const std::string& filename);
|
||||||
|
|
||||||
// Returns the path to where the sys file are
|
|
||||||
[[nodiscard]] std::string GetSysDirectory();
|
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
[[nodiscard]] std::string GetBundleDirectory();
|
[[nodiscard]] std::optional<std::string> GetBundleDirectory();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
Loading…
Reference in a new issue