Привет всем читателям!

Я продолжаю тему программного эмулятора для PlayStation 1, PlayStation 2 и PlayStation Portable — Omega Red. Более подробно:


Данную новость я написал в связи с решением портировать часть кода разрабатываемого мной эмулятора на Android — ARM64 платформу. Поспешу предупредить, что скачать и запустить не получиться — проект только на начальной стадии развития. Однако, для тех читателей, кто не лишён профессионального любопытства — добро пожаловать под кат.

P.S. Новая версия эмулятора для Windows OS (с поддержкой гемпадов по старому протоколу — DirectInput8) доступна по ссылке: Omega Red.

Для любопытствующих — проект был инициирован больше года назад и мой интерес к нему возгарался и затухал циклически. Но лишь недавно мне удалось закончить первый этап — добиться корректной компиляции и линковки кода.

Основой портирования я решил взять центральное ядро эмулятора PCSX2, переписанное мной в форме отдельной динамически загружаемой библиотеки (подробно «Красный Омега PS2 эмулятор»). Стартовая версия библиотеки была написана для Windows OS на Microsoft Visual Studio — как результат, существует объективная проблема в совместимости сред разработки-компиляции и совместимости сред выполнения кода библиотек. Длительная работа с библиотекой ядра эмулятора позволила разработать паттерн алгоритма внешнего исполняемого кода по отношению библиотеке через разработанный API.

Первой задачей было написание кода для этого алгоритма на Java для Android. Программный код достаточно сложен по причине наличия большого количества функций «обратного» вызова — библиотека ядра эмулятора включает три программных потока исполнения кода и они потребуют данных для обработки — БИОСа, данных геймпадов, загрузки плагинов. В коде для Windows OS на WPF C# задача реализации «обратного» вызова проста через встроенный механизм маршалинга данных. Но для Java виртуальной машины маршалинг данных из нативного кода С++ в виртуальную машину и обратно становиться крупной проблемой. Для этого я определил отдельный С++ файл AndroidInterface.cpp в PCSX2Lib с определением Java Native интерфейсов в следующем виде:

extern "C"
JNIEXPORT void JNICALL
Java_com_xirexel_omegared_PCSX2_PCSX2LibNative_NativeSetElfPathFunc(JNIEnv *env,
																		   jobject instance,
																		   jstring a_config_) {
	const char *a_config = env->GetStringUTFChars(a_config_, 0);

	PCSX2_Hle_SetElfPathFunc(a_config);

	env->ReleaseStringUTFChars(a_config_, a_config);
}

Загрузка нативного кода происходит стандартным образом:

public final class PCSX2LibNative {

    static {
        System.loadLibrary("PCSX2Lib");
    }

Вызов Java методов из С++ кода имеет следующий вид:

static void callOnePtrTwoIntBoolean(const std::string& aMethodCallback, unsigned char* arg1, int arg2, int arg3, bool arg4)
{
	if(s_JavaVM == nullptr)
		return;

	JNIEnv* l_Env = nullptr;


	const jint get_res = s_JavaVM->GetEnv(reinterpret_cast<void**>(&l_Env), JNI_VERSION_1_6);

	if (get_res == JNI_EDETACHED) {
		if (s_JavaVM->AttachCurrentThread(&l_Env, NULL) != 0) {
			return;
		}
	} else if (get_res != JNI_OK) {
		return;
	}

	jclass l_PCSX2LibNative = l_Env->GetObjectClass(g_PCSX2LibNative);

	jmethodID methodId=l_Env->GetMethodID(l_PCSX2LibNative, aMethodCallback.data(), "(Ljava/nio/ByteBuffer;IZ)V");

	jobject l_buffer = l_Env->NewDirectByteBuffer(arg1, arg3);

	l_Env->CallVoidMethod(g_PCSX2LibNative, methodId, l_buffer, arg2, arg4);
}

Второй задачей было создание CMake скрипта для корректной компиляции нативного кода для Android проекта. Получилось следующее:

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.4.1)


set (EXTEND_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Extend)
set (PCSX2LIB_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../PCSX2Lib)
set (PCSX2_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../../pcsx2)
set (FRAMEWORK_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../Common/Framework)
set (UTILITIES_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../Common/Utilities)
set (MEMORYMANAGER_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../Common/MemoryManager)
set (PUGIXML_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../Common/PugiXML)
set (FRAMEWORK_UTILITIES_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../Common/Framework/Utilities)
set (PCSX2_UTILITIES_SRC_DIR ${PCSX2_DIR}/../common/src/Utilities)
set (PTHREADS_INC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../Common/pthreads4w/include)
set (LIBAIO_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libaio/src)
set (MODULES_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../Modules)


add_definitions(-DDISABLE_RECORDING -DPUGIXML_WCHAR_MODE)

if(${ANDROID_ABI} STREQUAL "x86")
    add_definitions(-DANDROID_ABI_X86)
endif()

if(
(${ANDROID_ABI} STREQUAL "x86")
)

    message(ANDROID_ABI = ${ANDROID_ABI})

    set(SVU_ZEROREC_SRC
            ${CMAKE_CURRENT_SOURCE_DIR}/CPU/x86/aVUzerorec.S
            )



    add_subdirectory(libaio)
    add_subdirectory(Framework)
    add_subdirectory(Utilities)
    add_subdirectory(Emitters)
    add_subdirectory(MemoryManager)
    add_subdirectory(PugiXML)
    add_subdirectory(PCSX2Lib)
    add_subdirectory(Modules)
    add_subdirectory(BiosControl)
endif()

Полагаю что читатели сразу поняли причину, почему проект невозможно загрузить на смартфон — нативный код компилируется только для процессоров х86 архитектуры.

В настоящий момент проект бесполезен почти полностью — но только почти. Текущий результат показал следующее:

  1. разработка отдельной библиотеки нативного кода для PCSX2 эмулятора было правильным решением, упростившем портирование на другую платформу;
  2. корректная компиляция и линковка кода указывает на совместимость кода PCSX2 эмулятора с библиотеками компиляции Android NDK.

Как очевидно, в настоящий момент проблемой является написание кода для ARM64 процессоров — проблема объективно сложная, но на мой взгляд решаемая. Для любителей повозиться с кодом — проект для среды разработки Android Studio доступен на GitHub: AndroidStudio.

В настоящий момент Windows OS версия программы доступна по ссылке: Omega Red и представлена на GitHub: OmegaRed.

Buy Me A Coffee.