Compare commits

...

3 Commits

Author SHA1 Message Date
03c7c50d48 Trampoline
Some checks failed
CI / Build (AMD64, Server) (push) Failing after 7m39s
CI / Build (AMD64, Client) (push) Failing after 11m40s
CI / Build (ARM64, Server) (push) Failing after 8m50s
CI / Build (ARM64, Client) (push) Failing after 13m21s
CI / Build (ARMHF, Client) (push) Has been cancelled
CI / Build (ARMHF, Server) (push) Has been cancelled
CI / Test (Client) (push) Has been cancelled
CI / Test (Server) (push) Has been cancelled
CI / Build Example Mods (push) Has been cancelled
CI / Release (push) Has been cancelled
2024-05-11 21:14:14 -04:00
f15625ff79 UI Tweaks 2024-05-10 19:50:28 -04:00
e2d32cad21 Add QEMU Patch 2024-05-10 18:58:39 -04:00
29 changed files with 1028 additions and 2358 deletions

View File

@ -152,7 +152,7 @@ if(BUILD_NATIVE_COMPONENTS)
set(ARM_OPTIONS "${MCPI_OPTIONS}")
list(APPEND ARM_OPTIONS "-DMCPI_BUILD_MODE:STRING=arm")
list(APPEND ARM_OPTIONS "-DCMAKE_INSTALL_MESSAGE:STRING=NEVER")
list(APPEND ARM_OPTIONS "-DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>/install")
list(APPEND ARM_OPTIONS "-DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>")
if(NOT MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN)
if(DEFINED CMAKE_TOOLCHAIN_FILE)
list(APPEND ARM_OPTIONS "-DCMAKE_TOOLCHAIN_FILE:FILEPATH=${CMAKE_TOOLCHAIN_FILE}")
@ -166,7 +166,9 @@ if(BUILD_NATIVE_COMPONENTS)
DOWNLOAD_COMMAND ""
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}"
CMAKE_CACHE_ARGS ${ARM_OPTIONS}
INSTALL_COMMAND "${CMAKE_COMMAND}" "-E" "rm" "-rf" "<INSTALL_DIR>/install"
INSTALL_COMMAND
"${CMAKE_COMMAND}" "-E"
"rm" "-rf" "<INSTALL_DIR>/${MCPI_INSTALL_DIR}"
COMMAND
"${CMAKE_COMMAND}" "-E" "env"
"DESTDIR="
@ -178,5 +180,5 @@ if(BUILD_NATIVE_COMPONENTS)
)
# Install
ExternalProject_Get_Property(arm-components INSTALL_DIR)
install(DIRECTORY "${INSTALL_DIR}/install/${MCPI_INSTALL_DIR}/" DESTINATION "${MCPI_INSTALL_DIR}")
install(DIRECTORY "${INSTALL_DIR}/${MCPI_INSTALL_DIR}/" DESTINATION "${MCPI_INSTALL_DIR}")
endif()

View File

@ -23,21 +23,31 @@ endif()
# Media Layer
if(NOT MCPI_HEADLESS_MODE)
set(DEFAULT_USE_MEDIA_LAYER_PROXY FALSE)
set(DEFAULT_USE_MEDIA_LAYER_TRAMPOLINE FALSE)
if(BUILD_NATIVE_COMPONENTS AND NOT IS_ARM_TARGETING)
set(DEFAULT_USE_MEDIA_LAYER_PROXY TRUE)
set(DEFAULT_USE_MEDIA_LAYER_TRAMPOLINE TRUE)
endif()
mcpi_option(USE_MEDIA_LAYER_PROXY "Whether To Enable The Media Layer Proxy" BOOL "${DEFAULT_USE_MEDIA_LAYER_PROXY}")
mcpi_option(USE_MEDIA_LAYER_TRAMPOLINE "Whether To Enable The Media Layer Trampoline (Requires QEMU)" BOOL "${DEFAULT_USE_MEDIA_LAYER_TRAMPOLINE}")
mcpi_option(USE_GLES1_COMPATIBILITY_LAYER "Whether To Enable The GLESv1_CM Compatibility Layer" BOOL TRUE)
else()
set(MCPI_USE_MEDIA_LAYER_PROXY FALSE)
set(MCPI_USE_MEDIA_LAYER_TRAMPOLINE FALSE)
endif()
if(MCPI_USE_MEDIA_LAYER_PROXY)
if(MCPI_USE_MEDIA_LAYER_TRAMPOLINE)
set(BUILD_MEDIA_LAYER_CORE "${BUILD_NATIVE_COMPONENTS}")
else()
set(BUILD_MEDIA_LAYER_CORE "${BUILD_ARM_COMPONENTS}")
endif()
# QEMU
if(BUILD_NATIVE_COMPONENTS)
include(CheckSymbolExists)
check_symbol_exists("__ARM_ARCH" "" MCPI_IS_ARM32_OR_ARM64_TARGETING)
set(MCPI_USE_QEMU TRUE)
if(MCPI_IS_ARM32_OR_ARM64_TARGETING AND NOT MCPI_USE_MEDIA_LAYER_TRAMPOLINE)
set(MCPI_USE_QEMU FALSE)
endif()
endif()
# Specify Variant Name
set(MCPI_VARIANT_NAME "minecraft-pi-reborn")
if(MCPI_SERVER_MODE)
@ -67,13 +77,3 @@ mcpi_option(APP_TITLE "App Title" STRING "${DEFAULT_APP_TITLE}")
# Skin Server
mcpi_option(SKIN_SERVER "Skin Server" STRING "https://raw.githubusercontent.com/MCPI-Revival/Skins/data")
# QEMU
if(BUILD_NATIVE_COMPONENTS)
include(CheckSymbolExists)
check_symbol_exists("__ARM_ARCH" "" MCPI_IS_ARM32_OR_ARM64_TARGETING)
set(MCPI_USE_QEMU TRUE)
if(MCPI_IS_ARM32_OR_ARM64_TARGETING)
set(MCPI_USE_QEMU FALSE)
endif()
endif()

View File

@ -6,9 +6,9 @@ project(qemu)
set(QEMU_VERSION "8.2.1")
# Flatpak Support
set(QEMU_PATCH "")
set(QEMU_FLATPAK_PATCH "")
if(MCPI_IS_FLATPAK_BUILD)
set(QEMU_PATCH "sed" "-i" "s/libdrm/libdrm-dis/g" "<SOURCE_DIR>/meson.build")
set(QEMU_FLATPAK_PATCH "sed" "-i" "s/libdrm/libdrm-dis/g" "<SOURCE_DIR>/meson.build")
endif()
# Build
@ -19,6 +19,7 @@ if(DEFINED ENV{PKG_CONFIG_LIBDIR})
endif()
ExternalProject_Add(qemu
URL "${CMAKE_CURRENT_SOURCE_DIR}/../../archives/qemu-${QEMU_VERSION}.tar.xz"
# Configure Build
CONFIGURE_COMMAND
"${CMAKE_COMMAND}" "-E" "env"
${PKGCONFIG_ENV}
@ -33,12 +34,16 @@ ExternalProject_Add(qemu
"--target-list=arm-linux-user"
"--without-default-features"
USES_TERMINAL_CONFIGURE TRUE
BUILD_COMMAND ninja "qemu-arm"
# Build Command
BUILD_COMMAND "ninja" "qemu-arm"
BUILD_BYPRODUCTS "<BINARY_DIR>/qemu-arm"
USES_TERMINAL_BUILD TRUE
# Disable Install/Test Commands
INSTALL_COMMAND ""
TEST_COMMAND ""
PATCH_COMMAND ${QEMU_PATCH}
BUILD_BYPRODUCTS "<BINARY_DIR>/qemu-arm"
# Patch Command
PATCH_COMMAND "patch" "-p1" "<" "${CMAKE_CURRENT_SOURCE_DIR}/trampoline.patch"
COMMAND ${QEMU_FLATPAK_PATCH}
)
# Install

56
dependencies/qemu/trampoline.patch vendored Normal file
View File

@ -0,0 +1,56 @@
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -17,6 +17,7 @@
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#define _ATFILE_SOURCE
+#include <dlfcn.h>
#include "qemu/osdep.h"
#include "qemu/cutils.h"
#include "qemu/path.h"
@@ -9070,6 +9071,17 @@ _syscall5(int, sys_move_mount, int, __from_dfd, const char *, __from_pathname,
int, __to_dfd, const char *, __to_pathname, unsigned int, flag)
#endif
+// g2h For Trampoline
+static CPUState *_trampoline_g2h_cpu = NULL;
+static void *_trampoline_g2h(uint32_t guest_addr) {
+ if (guest_addr == 0) {
+ return NULL;
+ }
+ return g2h(_trampoline_g2h_cpu, guest_addr);
+}
+// Trampoline Function
+typedef void (*_trampoline_t)(typeof(_trampoline_g2h) *g2h, uint32_t id, uint32_t *args);
+
/* This is an internal helper for do_syscall so that it is easier
* to have a single return point, so that actions, such as logging
* of syscall results, can be performed.
@@ -9095,6 +9107,27 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
void *p;
switch(num) {
+ case 0x1337: {
+ // Load Trampoline
+ static _trampoline_t _trampoline = NULL;
+ if (_trampoline == NULL) {
+ // Open Library
+ void *_trampoline_handle = dlopen("libmedia-layer-trampoline.so", RTLD_NOW);
+ // Load Function
+ if (_trampoline_handle != NULL) {
+ _trampoline = dlsym(_trampoline_handle, "trampoline");
+ }
+ }
+ if (_trampoline == NULL) {
+ // Failed To Load
+ qemu_log_mask(LOG_UNIMP, "Unable To Load Media Layer Trampoline: %s\n", dlerror());
+ return -TARGET_ENOSYS;
+ }
+ // Call Trampoline
+ _trampoline_g2h_cpu = cpu;
+ _trampoline(_trampoline_g2h, arg1, g2h(cpu, arg2));
+ return 0;
+ }
case TARGET_NR_exit:
/* In old applications this may be used to implement _exit(2).
However in threaded applications it is used for thread termination,

View File

@ -33,7 +33,7 @@ if(BUILD_MEDIA_LAYER_CORE)
add_subdirectory(core)
endif()
# Add Proxy
if(MCPI_USE_MEDIA_LAYER_PROXY OR BUILD_ARM_COMPONENTS)
add_subdirectory(proxy)
# Add Trampoline
if(MCPI_USE_MEDIA_LAYER_TRAMPOLINE OR BUILD_ARM_COMPONENTS)
add_subdirectory(trampoline)
endif()

View File

@ -1,10 +1,10 @@
#include <cstdlib>
#include <vector>
#include <SDL/SDL.h>
#include <media-layer/internal.h>
#include <media-layer/core.h>
#include <libreborn/libreborn.h>
// SDL Is Replaced With GLFW

View File

@ -435,13 +435,15 @@ static void glfw_controller_look(float x, float y) {
verify_controller_axis_value(y, CONTROLLER_LOOK_AXIS_THRESHOLD);
// Send Event
SDL_Event event;
event.type = SDL_MOUSEMOTION;
event.motion.x = last_mouse_x;
event.motion.y = last_mouse_y;
event.motion.xrel = x * CONTROLLER_LOOK_AXIS_SENSITIVITY;
event.motion.yrel = y * CONTROLLER_LOOK_AXIS_SENSITIVITY;
SDL_PushEvent(&event);
if (is_interactable) {
SDL_Event event;
event.type = SDL_MOUSEMOTION;
event.motion.x = last_mouse_x;
event.motion.y = last_mouse_y;
event.motion.xrel = x * CONTROLLER_LOOK_AXIS_SENSITIVITY;
event.motion.yrel = y * CONTROLLER_LOOK_AXIS_SENSITIVITY;
SDL_PushEvent(&event);
}
}
}

View File

@ -4,10 +4,8 @@
extern "C" {
#endif
// Internal Methods (Not Handled By Media Layer Proxy)
// Internal Methods
__attribute__((visibility("internal"))) void _media_handle_SDL_PollEvent();
__attribute__((visibility("internal"))) void _media_handle_SDL_Quit();
#ifdef __cplusplus
}

View File

@ -1,27 +0,0 @@
project(media-layer-proxy)
# Configuration
set(MEDIA_LAYER_PROXY_SRC src/common/common.c src/media-layer-core.c) # Media Layer Proxy Source
if(NOT MCPI_HEADLESS_MODE)
list(APPEND MEDIA_LAYER_PROXY_SRC src/GLESv1_CM.c)
endif()
# Build
if(BUILD_NATIVE_COMPONENTS)
# Build Media Layer Proxy Client
add_executable(media-layer-proxy-client src/client/client.cpp ${MEDIA_LAYER_PROXY_SRC})
target_link_libraries(media-layer-proxy-client media-layer-headers reborn-util media-layer-core GLESv1_CM)
target_compile_definitions(media-layer-proxy-client PRIVATE -DMEDIA_LAYER_PROXY_CLIENT)
# Install
install(TARGETS media-layer-proxy-client DESTINATION "${MCPI_BIN_DIR}")
elseif(BUILD_ARM_COMPONENTS)
# Build Media Layer Proxy Server
add_library(media-layer-core SHARED src/server/server.cpp ${MEDIA_LAYER_PROXY_SRC} $<TARGET_OBJECTS:media-layer-extras>)
target_link_libraries(media-layer-core media-layer-headers reborn-util)
target_compile_definitions(media-layer-core PRIVATE -DMEDIA_LAYER_PROXY_SERVER)
# Install
if(MCPI_USE_MEDIA_LAYER_PROXY)
install(TARGETS media-layer-core DESTINATION "${MCPI_LIB_DIR}")
endif()
install(TARGETS media-layer-core EXPORT sdk DESTINATION "${MCPI_SDK_LIB_DIR}")
endif()

File diff suppressed because it is too large Load Diff

View File

@ -1,107 +0,0 @@
#include <vector>
#include <cerrno>
#include <unistd.h>
#include <cstring>
#include <sys/prctl.h>
#include <csignal>
#include <exception>
#include "../common/common.h"
// Store Handlers
#define MAX_HANDLERS 100
static proxy_handler_t handlers[MAX_HANDLERS];
void _add_handler(unsigned char unique_id, proxy_handler_t handler) {
if (unique_id >= MAX_HANDLERS) {
PROXY_ERR("ID Too Big: %i", (int) unique_id);
}
if (handlers[unique_id] != NULL) {
PROXY_ERR("Duplicate ID: %i", (int) unique_id);
}
handlers[unique_id] = handler;
}
// Store Parent PID
static int parent_is_alive = 1;
static void sigusr1_handler(__attribute__((unused)) int sig) {
// Mark Parent As Dead
parent_is_alive = 0;
}
// Check State Of Proxy And Exit If Invalid
void _check_proxy_state() {
// Check Server State
if (!parent_is_alive) {
void_write_cache(); // Parent Is Dead, No Reason To Send A Dead Process Data
PROXY_ERR("Server Terminated");
}
}
// Exit Handler
static volatile int exit_requested = 0;
static void exit_handler(__attribute__((unused)) int signal_id) {
// Request Exit
exit_requested = 1;
}
// Main
int main(int argc, char *argv[]) {
// Set Debug Tag
reborn_debug_tag = PROXY_LOG_TAG;
// Install Signal Handlers
signal(SIGINT, SIG_IGN);
struct sigaction act_sigterm;
memset((void *) &act_sigterm, 0, sizeof (struct sigaction));
act_sigterm.sa_handler = &exit_handler;
sigaction(SIGTERM, &act_sigterm, NULL);
// Send Signal On Parent Death To Interrupt Connection Read/Write And Exit
prctl(PR_SET_PDEATHSIG, SIGUSR1);
struct sigaction sa;
memset((void *) &sa, 0, sizeof (struct sigaction));
sa.sa_flags = SA_NOCLDSTOP;
sa.sa_handler = &sigusr1_handler;
if (sigaction(SIGUSR1, &sa, NULL) == -1) {
PROXY_ERR("Unable To Install Signal Handler: %s", strerror(errno));
}
// Get Connection
if (argc != 3) {
PROXY_ERR("Invalid Arguments");
}
char *read_str = argv[1];
char *write_str = argv[2];
set_connection(atoi(read_str), atoi(write_str));
PROXY_INFO("Connected");
// Send Connection Message
write_string((char *) CONNECTED_MSG);
flush_write_cache();
// Loop
int running = is_connection_open();
while (running && !exit_requested) {
unsigned char unique_id = read_byte();
if (handlers[unique_id] != NULL) {
// Run Method
handlers[unique_id]();
// Check If Connection Is Still Open
if (!is_connection_open()) {
// Exit
running = 0;
} else {
// Flush Write Cache
flush_write_cache();
}
} else {
PROXY_ERR("Invalid Method ID: %i", (int) unique_id);
}
}
if (is_connection_open()) {
close_connection();
}
// Exit
PROXY_INFO("Stopped");
return 0;
}

View File

@ -1,13 +0,0 @@
#pragma once
#define PROXY_LOG_TAG "(Media Layer Proxy Client) "
typedef void (*proxy_handler_t)();
__attribute__((visibility("internal"))) void _add_handler(unsigned char id, proxy_handler_t handler);
#define CALL(unique_id, name, return_type, args) \
static void _run_##name (); \
__attribute__((constructor)) static void _init_##name() { \
_add_handler(unique_id, _run_##name); \
} \
static void _run_##name ()

View File

@ -1,245 +0,0 @@
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <math.h>
#include <sys/ioctl.h>
#include "common.h"
// Safely Send/Receive Data From The Connection
#define CHECK_CONNECTION() \
{ \
_check_proxy_state(); \
if (!is_connection_open()) { \
PROXY_ERR("Attempting To Access Closed Connection"); \
} \
}
// Buffer Reads
static void *_read_cache = NULL;
__attribute__((destructor)) static void _free_read_cache() {
if (_read_cache != NULL) {
free(_read_cache);
}
}
static size_t _read_cache_size = 0;
static size_t _read_cache_actual_size = 0;
static size_t _read_cache_position = 0;
#define max(a, b) (((a) > (b)) ? (a) : (b))
#define min(a, b) (((a) < (b)) ? (a) : (b))
void safe_read(void *buf, size_t len) {
// Check Data
if (buf == NULL) {
PROXY_ERR("Attempting To Read Into NULL Buffer");
}
// Setup
size_t to_read = len;
// Copy From Read Buffer
if (_read_cache != NULL && _read_cache_size > 0) {
char *read_cache = (void *) (((unsigned char *) _read_cache) + _read_cache_position);
size_t read_cache_size = _read_cache_size - _read_cache_position;
if (read_cache_size > 0) {
size_t to_copy = min(to_read, read_cache_size);
memcpy(buf, read_cache, to_copy);
to_read -= to_copy;
_read_cache_position += to_copy;
}
}
// Check If Done
if (to_read < 1) {
return;
}
if (_read_cache_position < _read_cache_size) {
IMPOSSIBLE();
}
// Flush Write Cache
flush_write_cache();
// Read Remaining Data
size_t to_read_to_cache = 0;
while (to_read_to_cache < 1) {
CHECK_CONNECTION();
int bytes_available;
if (ioctl(get_connection_read(), FIONREAD, &bytes_available) == -1) {
bytes_available = 0;
}
to_read_to_cache = max((size_t) bytes_available, to_read);
}
// Resize Buffer
_read_cache_position = 0;
_read_cache_size = to_read_to_cache;
if (_read_cache == NULL) {
_read_cache_actual_size = _read_cache_size;
_read_cache = malloc(_read_cache_actual_size);
} else if (_read_cache_size > _read_cache_actual_size) {
_read_cache_actual_size = _read_cache_size;
_read_cache = realloc(_read_cache, _read_cache_actual_size);
}
ALLOC_CHECK(_read_cache);
// Read Into Buffer
while (to_read_to_cache > 0) {
CHECK_CONNECTION();
ssize_t x = read(get_connection_read(), (void *) (((unsigned char *) _read_cache) + (_read_cache_size - to_read_to_cache)), to_read_to_cache);
if (x == -1 && errno != EINTR) {
PROXY_ERR("Failed Reading Data To Connection: %s", strerror(errno));
}
to_read_to_cache -= x;
}
// Copy Remaining Data
safe_read((void *) (((unsigned char *) buf) + (len - to_read)), to_read);
}
// Buffer Writes
static void *_write_cache = NULL;
__attribute__((destructor)) static void _free_write_cache() {
if (_write_cache != NULL) {
free(_write_cache);
}
}
static size_t _write_cache_size = 0;
static size_t _write_cache_position = 0;
void safe_write(void *buf, size_t len) {
// Check Data
if (buf == NULL) {
PROXY_ERR("Attempting To Send NULL Data");
}
// Expand Write Cache If Needed
size_t needed_size = _write_cache_position + len;
if (_write_cache == NULL) {
_write_cache_size = needed_size;
_write_cache = malloc(_write_cache_size);
} else if (needed_size > _write_cache_size) {
_write_cache_size = needed_size;
_write_cache = realloc(_write_cache, _write_cache_size);
}
ALLOC_CHECK(_write_cache);
// Copy Data
memcpy((void *) (((unsigned char *) _write_cache) + _write_cache_position), buf, len);
// Advance Position
_write_cache_position += len;
}
// Flush Write Cache
void flush_write_cache() {
// Check Cache
if (_write_cache == NULL || _write_cache_position < 1) {
// Nothing To Write
return;
}
// Check Connection
if (!is_connection_open()) {
// Connection Closed
return;
}
// Write & Reset
size_t to_write = _write_cache_position;
size_t old_write_cache_position = _write_cache_position;
_write_cache_position = 0;
while (to_write > 0) {
CHECK_CONNECTION();
ssize_t x = write(get_connection_write(), (void *) (((unsigned char *) _write_cache) + (old_write_cache_position - to_write)), to_write);
if (x == -1 && errno != EINTR) {
PROXY_ERR("Failed Writing Data To Connection: %s", strerror(errno));
}
to_write -= x;
}
}
void void_write_cache() {
_write_cache_position = 0;
}
// Read/Write 32-Bit Integers
uint32_t read_int() {
uint32_t ret = 0;
safe_read((void *) &ret, sizeof (ret));
return ret;
}
void write_int(uint32_t x) {
safe_write((void *) &x, sizeof (x));
}
// Read/Write Floats
float read_float() {
float ret = 0;
safe_read((void *) &ret, sizeof (ret));
return ret;
}
void write_float(float x) {
safe_write((void *) &x, sizeof (x));
}
// Read/Write Bytes
unsigned char read_byte() {
unsigned char ret = 0;
safe_read((void *) &ret, sizeof (ret));
return ret;
}
void write_byte(unsigned char x) {
safe_write((void *) &x, sizeof (x));
}
// Read/Write Strings
char *read_string() {
// Check NULL
unsigned char is_null = read_byte();
if (is_null) {
return NULL;
}
// Allocate String
unsigned char length = read_byte();
char *str = malloc((size_t) length + 1);
// Read String
safe_read((void *) str, length);
// Add Terminator
str[length] = '\0';
// Return String
return strdup(str);
}
#define MAX_STRING_SIZE 256
void write_string(const char *str) {
unsigned char is_null = str == NULL;
write_byte(is_null);
if (!is_null) {
int length = strlen(str);
if (length > MAX_STRING_SIZE) {
PROXY_ERR("Unable To Write String To Connection: Larger Than %i Bytes", MAX_STRING_SIZE);
}
write_byte((unsigned char) length);
safe_write((void *) str, length);
}
}
// Close Connection
void close_connection() {
// Flush Write Cache
flush_write_cache();
// Close
int state_changed = 0;
if (get_connection_read() != -1) {
close(get_connection_read());
state_changed = 1;
}
if (get_connection_write() != -1) {
close(get_connection_write());
state_changed = 1;
}
set_connection(-1, -1);
if (state_changed) {
PROXY_INFO("Connection Closed");
}
}
// Check If Connection Is Open
int is_connection_open() {
return get_connection_read() != -1 && get_connection_write() != -1;
}
// Pipe
static int _read = -1;
static int _write = -1;
// Set Pipe
void set_connection(int read, int write) {
_read = read;
_write = write;
}
// Get Pipe
int get_connection_read() {
return _read;
}
int get_connection_write() {
return _write;
}

View File

@ -1,62 +0,0 @@
#pragma once
#include <stdint.h>
#include <libreborn/libreborn.h>
#ifdef __cplusplus
extern "C" {
#endif
#if __BYTE_ORDER != __LITTLE_ENDIAN
#error "Only Little Endian Is Supported"
#endif
#if defined(MEDIA_LAYER_PROXY_SERVER)
#include "../server/server.h"
#elif defined(MEDIA_LAYER_PROXY_CLIENT)
#include "../client/client.h"
#else
#error "Invalid Configuration"
#endif
#define CONNECTED_MSG "Connected"
#define PROXY_INFO(format, ...) RAW_DEBUG(PROXY_LOG_TAG, format, ##__VA_ARGS__);
#define PROXY_ERR(format, ...) { close_connection(); ERR(PROXY_LOG_TAG format, ##__VA_ARGS__); }
// Safely Send/Receive Data From The Connection
__attribute__((visibility("internal"))) void safe_read(void *buf, size_t len);
__attribute__((visibility("internal"))) void safe_write(void *buf, size_t len);
__attribute__((visibility("internal"))) void flush_write_cache();
__attribute__((visibility("internal"))) void void_write_cache();
// Read/Write 32-Bit Integers
__attribute__((visibility("internal"))) uint32_t read_int();
__attribute__((visibility("internal"))) void write_int(uint32_t x);
// Read/Write Bytes
__attribute__((visibility("internal"))) unsigned char read_byte();
__attribute__((visibility("internal"))) void write_byte(unsigned char x);
// Read/Write Floats
__attribute__((visibility("internal"))) float read_float();
__attribute__((visibility("internal"))) void write_float(float x);
// Read/Write Strings
__attribute__((visibility("internal"))) char *read_string(); // Remember To free()
__attribute__((visibility("internal"))) void write_string(const char *str);
// Manipulate Connection
__attribute__((visibility("internal"))) void set_connection(int read, int write);
__attribute__((visibility("internal"))) int get_connection_read();
__attribute__((visibility("internal"))) int get_connection_write();
__attribute__((visibility("internal"))) void close_connection();
__attribute__((visibility("internal"))) int is_connection_open();
// Check State Of Proxy And Exit If Invalid
__attribute__((visibility("internal"))) void _check_proxy_state();
#ifdef __cplusplus
}
#endif

View File

@ -1,354 +0,0 @@
#include <stdint.h>
#include <SDL/SDL.h>
#include <libreborn/libreborn.h>
#include <media-layer/core.h>
#include <media-layer/audio.h>
#include <media-layer/internal.h>
#include "common/common.h"
// SDL Functions
CALL(0, SDL_Init, int, (uint32_t flags)) {
#if defined(MEDIA_LAYER_PROXY_SERVER)
// Lock Proxy
start_proxy_call();
// Arguments
write_int(flags);
// Get Return Value
int32_t ret = (int32_t) read_int();
// Release Proxy
end_proxy_call();
// Return
return ret;
#else
uint32_t flags = read_int();
// Run
int ret = SDL_Init(flags);
// Return Values
write_int((uint32_t) ret);
#endif
}
CALL(1, SDL_PollEvent, int, (SDL_Event *event)) {
#if defined(MEDIA_LAYER_PROXY_SERVER)
// Lock Proxy
start_proxy_call();
// No Arguments
// Get Return Value
int32_t ret = (int32_t) read_int();
if (ret) {
safe_read((void *) event, sizeof (SDL_Event));
}
// Release Proxy
end_proxy_call();
// Return Value
return ret;
#else
SDL_Event event;
// Run
int ret = (int32_t) SDL_PollEvent(&event);
// Return Values
write_int(ret);
if (ret) {
safe_write((void *) &event, sizeof (SDL_Event));
}
#endif
}
CALL(2, SDL_PushEvent, int, (SDL_Event *event)) {
#if defined(MEDIA_LAYER_PROXY_SERVER)
// Lock Proxy
start_proxy_call();
// Arguments
safe_write((void *) event, sizeof (SDL_Event));
// Get Return Value
int32_t ret = (int32_t) read_int();
// Release Proxy
end_proxy_call();
// Return Value
return ret;
#else
SDL_Event event;
safe_read((void *) &event, sizeof (SDL_Event));
// Run
int ret = SDL_PushEvent(&event);
// Return Value
write_int((uint32_t) ret);
#endif
}
CALL(3, SDL_WM_SetCaption, void, (const char *title, const char *icon)) {
#if defined(MEDIA_LAYER_PROXY_SERVER)
// Lock Proxy
start_proxy_call();
// Arguments
write_string((char *) title);
write_string((char *) icon);
// Release Proxy
end_proxy_call();
#else
char *title = read_string();
char *icon = read_string();
// Run
SDL_WM_SetCaption(title, icon);
// Free
free(title);
free(icon);
#endif
}
CALL(4, media_toggle_fullscreen, void, ()) {
#if defined(MEDIA_LAYER_PROXY_SERVER)
// Lock Proxy
start_proxy_call();
// Release Proxy
end_proxy_call();
#else
// Run
media_toggle_fullscreen();
#endif
}
CALL(5, SDL_WM_GrabInput, SDL_GrabMode, (SDL_GrabMode mode)) {
#if defined(MEDIA_LAYER_PROXY_SERVER)
// Lock Proxy
start_proxy_call();
// Arguments
write_int((uint32_t) mode);
// Get Return Value
SDL_GrabMode ret = (SDL_GrabMode) read_int();
// Release Proxy
end_proxy_call();
// Return Value
return ret;
#else
SDL_GrabMode mode = (SDL_GrabMode) read_int();
// Run
SDL_GrabMode ret = SDL_WM_GrabInput(mode);
// Return Value
write_int((uint32_t) ret);
#endif
}
CALL(6, SDL_ShowCursor, int, (int32_t toggle)) {
#if defined(MEDIA_LAYER_PROXY_SERVER)
// Lock Proxy
start_proxy_call();
// Arguments
write_int((uint32_t) toggle);
// Get Return Value
int32_t ret = (int32_t) read_int();
// Release Proxy
end_proxy_call();
// Return Value
return ret;
#else
int mode = (int) read_int();
// Run
int ret = SDL_ShowCursor(mode);
// Return Value
write_int((uint32_t) ret);
#endif
}
CALL(8, media_swap_buffers, void, ()) {
#if defined(MEDIA_LAYER_PROXY_SERVER)
// Lock Proxy
start_proxy_call();
// Release Proxy
end_proxy_call();
flush_write_cache();
#else
// Run
media_swap_buffers();
#endif
}
// This Method May Be Called In A Situation Where The Proxy Is Disconnected
CALL(9, media_cleanup, void, ()) {
#if defined(MEDIA_LAYER_PROXY_SERVER)
// Check Connection
if (is_connection_open()) {
// Lock Proxy
start_proxy_call();
// Block Until Cleanup Is Complete
flush_write_cache();
read_byte();
// Close The Connection
close_connection();
// Release Proxy
end_proxy_call();
}
#else
// Run
media_cleanup();
// Confirm Cleanup
write_byte(0);
// Close The Connection
close_connection();
#endif
}
CALL(10, media_get_framebuffer_size, void, (int *width, int *height)) {
#if defined(MEDIA_LAYER_PROXY_SERVER)
// Lock Proxy
start_proxy_call();
// Get Return Values
*width = (int) read_int();
*height = (int) read_int();
// Release Proxy
end_proxy_call();
#else
int width;
int height;
// Run
media_get_framebuffer_size(&width, &height);
// Return Values
write_int((uint32_t) width);
write_int((uint32_t) height);
#endif
}
CALL(59, media_audio_update, void, (float volume, float x, float y, float z, float yaw)) {
#if defined(MEDIA_LAYER_PROXY_SERVER)
// Lock Proxy
start_proxy_call();
// Arguments
write_float(volume);
write_float(x);
write_float(y);
write_float(z);
write_float(yaw);
// Release Proxy
end_proxy_call();
#else
float volume = read_float();
float x = read_float();
float y = read_float();
float z = read_float();
float yaw = read_float();
// Run
media_audio_update(volume, x, y, z, yaw);
#endif
}
CALL(60, media_audio_play, void, (const char *source, const char *name, float x, float y, float z, float pitch, float volume, int is_ui)) {
#if defined(MEDIA_LAYER_PROXY_SERVER)
// Lock Proxy
start_proxy_call();
// Arguments
write_string(source);
write_string(name);
write_float(x);
write_float(y);
write_float(z);
write_float(pitch);
write_float(volume);
write_int(is_ui);
// Release Proxy
end_proxy_call();
#else
char *source = read_string();
char *name = read_string();
float x = read_float();
float y = read_float();
float z = read_float();
float pitch = read_float();
float volume = read_float();
int is_ui = read_int();
// Run
media_audio_play(source, name, x, y, z, pitch, volume, is_ui);
// Free
free(source);
free(name);
#endif
}
CALL(62, media_set_interactable, void, (int is_interactable)) {
#if defined(MEDIA_LAYER_PROXY_SERVER)
// Lock Proxy
start_proxy_call();
// Arguments
write_int(is_interactable);
// Release Proxy
end_proxy_call();
#else
int is_interactable = read_int();
// Run
media_set_interactable(is_interactable);
#endif
}
CALL(63, media_disable_vsync, void, ()) {
#if defined(MEDIA_LAYER_PROXY_SERVER)
// Lock Proxy
start_proxy_call();
// Release Proxy
end_proxy_call();
#else
// Run
media_disable_vsync();
#endif
}
CALL(64, media_set_raw_mouse_motion_enabled, void, (int enabled)) {
#if defined(MEDIA_LAYER_PROXY_SERVER)
// Lock Proxy
start_proxy_call();
// Arguments
write_int(enabled);
// Release Proxy
end_proxy_call();
#else
int enabled = read_int();
// Run
media_set_raw_mouse_motion_enabled(enabled);
#endif
}
CALL(66, media_force_egl, void, ()) {
#if defined(MEDIA_LAYER_PROXY_SERVER)
// Lock Proxy
start_proxy_call();
// Release Proxy
end_proxy_call();
#else
// Run
media_force_egl();
#endif
}

View File

@ -1,170 +0,0 @@
#include <cerrno>
#include <cstring>
#include <unistd.h>
#include <csignal>
#include <sys/wait.h>
#include <fcntl.h>
#include <string>
#include <unordered_map>
#include <fstream>
#include <media-layer/core.h>
#include "../common/common.h"
// Track Client State
static int _client_is_alive = 0;
static int _client_status = 0;
static void update_client_state(int is_alive, int status) {
_client_is_alive = is_alive;
_client_status = status;
}
// Check State Of Proxy And Exit If Invalid
void _check_proxy_state() {
// Check Client State
if (!_client_is_alive) {
void_write_cache(); // Child Is Dead, No Reason To Send A Dead Process Data
char *exit_status = NULL;
get_exit_status_string(_client_status, &exit_status);
PROXY_ERR("Client Terminated%s", exit_status);
}
}
// Start Proxy Client
static pid_t _client_pid;
static void sigchld_handler(__attribute__((unused)) int sig) {
// Track
int status;
// Reap
int saved_errno = errno;
// Only waitpid() Proxy Client, Other Sub-Processes Are Handled By pclose()
if (waitpid(_client_pid, &status, WNOHANG) == _client_pid) {
// Handle Client Death
untrack_child(_client_pid);
update_client_state(0, status);
}
errno = saved_errno;
}
static void start_media_layer_proxy_client(int read, int write) {
// Reap Children
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_NOCLDSTOP;
sa.sa_handler = &sigchld_handler;
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
PROXY_ERR("Unable To Install Signal Handler: %s", strerror(errno));
}
// Fork And Start
pid_t ret = fork();
if (ret == -1) {
PROXY_ERR("Unable To Launch Client: %s", strerror(errno));
} else if (ret == 0) {
// Child Process
// Set Debug Tag
reborn_debug_tag = CHILD_PROCESS_TAG;
// Prepare Arguments
char *read_str = NULL;
safe_asprintf(&read_str, "%i", read);
char *write_str = NULL;
safe_asprintf(&write_str, "%i", write);
const char *argv[] = {"media-layer-proxy-client", read_str, write_str, NULL};
// Setup Environment
setup_exec_environment(0);
// Run
safe_execvpe(argv, (const char *const *) environ);
} else {
// Parent Process
_client_pid = ret;
track_child(_client_pid);
}
update_client_state(1, 0);
}
// Maximize Pipe Buffer Size
static void maximize_pipe_fd_size(int fd) {
// Read Maximum Pipe Size
std::ifstream max_size_file("/proc/sys/fs/pipe-max-size");
if (!max_size_file.good()) {
PROXY_ERR("%s", "Unable To Open Maximum Pipe Size File");
}
// Read One Line
int max_size;
std::string line;
if (std::getline(max_size_file, line) && line.size() > 0) {
max_size = std::stoi(line);
} else {
PROXY_ERR("%s", "Unable To Read Maximum Pipe Size File");
}
// Close
max_size_file.close();
// Set Maximum Pipe Size
errno = 0;
if (fcntl(fd, F_SETPIPE_SZ, max_size) < max_size) {
PROXY_ERR("Unable To Set Maximum Pipe Size: %s", errno != 0 ? strerror(errno) : "Unknown Error");
}
}
static void maximize_pipe_size(int pipe[2]) {
maximize_pipe_fd_size(pipe[0]);
maximize_pipe_fd_size(pipe[1]);
}
// Start Server
static int loaded = 0;
__attribute__((constructor)) void media_ensure_loaded() {
if (!loaded) {
loaded = 1;
// Log
PROXY_INFO("Starting...");
// Create Connection
int server_to_client_pipe[2];
safe_pipe2(server_to_client_pipe, 0);
maximize_pipe_size(server_to_client_pipe);
int client_to_server_pipe[2];
safe_pipe2(client_to_server_pipe, 0);
maximize_pipe_size(client_to_server_pipe);
// Set Connection
set_connection(client_to_server_pipe[0], server_to_client_pipe[1]);
// Start Client
start_media_layer_proxy_client(server_to_client_pipe[0], client_to_server_pipe[1]);
// Wait For Connection Message
char *str = read_string();
if (strcmp(str, CONNECTED_MSG) == 0) {
PROXY_INFO("Connected");
} else {
PROXY_ERR("Unable To Connect");
}
// Free
free(str);
}
}
// Assign Unique ID To Function
static std::unordered_map<std::string, unsigned char> &get_unique_ids() {
static std::unordered_map<std::string, unsigned char> unique_ids;
return unique_ids;
}
void _assign_unique_id(const char *name, unsigned char id) {
get_unique_ids()[name] = id;
}
unsigned char _get_unique_id(const char *name) {
return get_unique_ids()[name]; // Assume ID Exists
}
// Proxy Call Functions
void _start_proxy_call(unsigned char call_id) {
// Start Call
write_byte(call_id);
}
void end_proxy_call() {
}

View File

@ -1,27 +0,0 @@
#pragma once
#define PROXY_LOG_TAG "(Media Layer Proxy Server) "
// Assign Unique ID To Function
__attribute__((visibility("internal"))) void _assign_unique_id(const char *name, unsigned char id);
__attribute__((visibility("internal"))) unsigned char _get_unique_id(const char *name);
// Must Call After Every Call
__attribute__((visibility("internal"))) void _start_proxy_call(unsigned char call_id);
#define start_proxy_call() \
{ \
static int _loaded_id = 0; \
static unsigned char _call_id; \
if (!_loaded_id) { \
_loaded_id = 1; \
_call_id = _get_unique_id(__func__); \
} \
_start_proxy_call(_call_id); \
}
__attribute__((visibility("internal"))) void end_proxy_call();
#define CALL(unique_id, name, return_type, args) \
__attribute__((constructor)) static void _init_##name() { \
_assign_unique_id(#name, unique_id); \
} \
return_type name args

View File

@ -0,0 +1,30 @@
project(media-layer-trampoline)
# Configuration
set(MEDIA_LAYER_TRAMPOLINE_SRC src/media-layer-core.c) # Media Layer Trampoline Source
if(NOT MCPI_HEADLESS_MODE)
list(APPEND MEDIA_LAYER_TRAMPOLINE_SRC src/GLESv1_CM.c)
endif()
# Build
if(BUILD_NATIVE_COMPONENTS)
# Host Component
add_library(media-layer-trampoline src/host/host.c ${MEDIA_LAYER_TRAMPOLINE_SRC})
target_link_libraries(media-layer-trampoline reborn-util media-layer-core)
if(NOT MCPI_HEADLESS_MODE)
target_link_libraries(media-layer-trampoline GLESv1_CM)
endif()
target_compile_definitions(media-layer-trampoline PRIVATE -DMEDIA_LAYER_TRAMPOLINE_HOST)
# Install
install(TARGETS media-layer-trampoline DESTINATION "${MCPI_LIB_DIR}")
elseif(BUILD_ARM_COMPONENTS)
# Guest Component
add_library(media-layer-core SHARED src/guest/guest.c ${MEDIA_LAYER_TRAMPOLINE_SRC} $<TARGET_OBJECTS:media-layer-extras>)
target_link_libraries(media-layer-core media-layer-headers reborn-util)
target_compile_definitions(media-layer-core PRIVATE -DMEDIA_LAYER_TRAMPOLINE_GUEST)
# Install
if(MCPI_USE_MEDIA_LAYER_TRAMPOLINE)
install(TARGETS media-layer-core DESTINATION "${MCPI_LIB_DIR}")
endif()
install(TARGETS media-layer-core EXPORT sdk DESTINATION "${MCPI_SDK_LIB_DIR}")
endif()

View File

@ -0,0 +1,581 @@
#include <stdint.h>
#include <GLES/gl.h>
#include <libreborn/libreborn.h>
#include "common/common.h"
CALL(11, glFogfv, void, (GLenum pname, const GLfloat *params))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(pname, (uint32_t) params);
#else
GLenum pname = next_int();
GLfloat *params = next_ptr();
// Run
func(pname, params);
#endif
}
// 'pointer' Is Only Supported As An Integer, Not As An Actual Pointer
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
#define CALL_GL_POINTER(unique_id, name) \
CALL(unique_id, name, void, (GLint size, GLenum type, GLsizei stride, const void *pointer)) \
trampoline(size, type, stride, (uint32_t) pointer); \
}
#else
#define CALL_GL_POINTER(unique_id, name) \
CALL(unique_id, name, unused, unused) \
GLint size = next_int(); \
GLenum type = next_int(); \
GLsizei stride = next_int(); \
const void *pointer = (const void *) (uint64_t) next_int(); \
/* Run */ \
func(size, type, stride, pointer); \
}
#endif
CALL_GL_POINTER(12, glVertexPointer)
CALL(13, glLineWidth, void, (GLfloat width))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(pun_to(uint32_t, width));
#else
GLfloat width = next_float();
// Run
func(width);
#endif
}
CALL(14, glBlendFunc, void, (GLenum sfactor, GLenum dfactor))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(sfactor, dfactor);
#else
GLenum sfactor = next_int();
GLenum dfactor = next_int();
// Run
func(sfactor, dfactor);
#endif
}
CALL(15, glDrawArrays, void, (GLenum mode, GLint first, GLsizei count))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(mode, first, count);
#else
GLenum mode = next_int();
GLint first = next_int();
GLsizei count = next_int();
// Run
func(mode, first, count);
#endif
}
CALL(16, glColor4f, void, (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(pun_to(uint32_t, red), pun_to(uint32_t, green), pun_to(uint32_t, blue), pun_to(uint32_t, alpha));
#else
GLfloat red = next_float();
GLfloat green = next_float();
GLfloat blue = next_float();
GLfloat alpha = next_float();
// Run
func(red, green, blue, alpha);
#endif
}
CALL(17, glClear, void, (GLbitfield mask))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(mask);
#else
GLbitfield mask = next_int();
// Run
func(mask);
#endif
}
CALL(18, glBufferData, void, (GLenum target, GLsizeiptr size, const void *data, GLenum usage))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(target, size, (uint32_t) data, usage);
#else
GLenum target = next_int();
GLsizeiptr size = next_int();
const void *data = next_ptr();
GLenum usage = next_int();
// Run
func(target, size, data, usage);
#endif
}
CALL(19, glFogx, void, (GLenum pname, GLfixed param))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(pname, param);
#else
GLenum pname = next_int();
GLfixed param = next_int();
// Run
func(pname, param);
#endif
}
CALL(20, glFogf, void, (GLenum pname, GLfloat param))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(pname, pun_to(uint32_t, param));
#else
GLenum pname = next_int();
GLfloat param = next_float();
// Run
func(pname, param);
#endif
}
CALL(21, glMatrixMode, void, (GLenum mode))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(mode);
#else
GLenum mode = next_int();
// Run
func(mode);
#endif
}
CALL_GL_POINTER(22, glColorPointer)
CALL(23, glScissor, void, (GLint x, GLint y, GLsizei width, GLsizei height))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(x, y, width, height);
#else
GLint x = next_int();
GLint y = next_int();
GLsizei width = next_int();
GLsizei height = next_int();
// Run
func(x, y, width, height);
#endif
}
CALL(24, glTexParameteri, void, (GLenum target, GLenum pname, GLint param))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(target, pname, param);
#else
GLenum target = next_int();
GLenum pname = next_int();
GLint param = next_int();
// Run
func(target, pname, param);
#endif
}
CALL(25, glTexImage2D, void, (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(target, level, internalformat, width, height, border, format, type, (uint32_t) pixels);
#else
GLenum target = next_int();
GLint level = next_int();
GLint internalformat = next_int();
GLsizei width = next_int();
GLsizei height = next_int();
GLint border = next_int();
GLenum format = next_int();
GLenum type = next_int();
const void *pixels = next_ptr();
// Run
func(target, level, internalformat, width, height, border, format, type, pixels);
#endif
}
CALL(26, glEnable, void, (GLenum cap))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(cap);
#else
GLenum cap = next_int();
// Run
func(cap);
#endif
}
CALL(27, glEnableClientState, void, (GLenum array))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(array);
#else
GLenum array = next_int();
// Run
func(array);
#endif
}
CALL(28, glPolygonOffset, void, (GLfloat factor, GLfloat units))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(pun_to(uint32_t, factor), pun_to(uint32_t, units));
#else
GLfloat factor = next_float();
GLfloat units = next_float();
// Run
func(factor, units);
#endif
}
CALL_GL_POINTER(41, glTexCoordPointer)
CALL(29, glDisableClientState, void, (GLenum array))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(array);
#else
GLenum array = next_int();
// Run
func(array);
#endif
}
CALL(30, glDepthRangef, void, (GLclampf near, GLclampf far))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(pun_to(uint32_t, near), pun_to(uint32_t, far));
#else
GLclampf near = next_float();
GLclampf far = next_float();
// Run
func(near, far);
#endif
}
CALL(31, glDepthFunc, void, (GLenum func))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(func);
#else
GLenum func2 = next_int();
// Run
func(func2);
#endif
}
CALL(32, glBindBuffer, void, (GLenum target, GLuint buffer))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(target, buffer);
#else
GLenum target = next_int();
GLenum buffer = next_int();
// Run
func(target, buffer);
#endif
}
CALL(33, glClearColor, void, (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(pun_to(uint32_t, red), pun_to(uint32_t, green), pun_to(uint32_t, blue), pun_to(uint32_t, alpha));
#else
GLclampf red = next_float();
GLclampf green = next_float();
GLclampf blue = next_float();
GLclampf alpha = next_float();
// Run
func(red, green, blue, alpha);
#endif
}
CALL(34, glPopMatrix, void, ())
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline();
#else
// Run
func();
#endif
}
CALL(35, glLoadIdentity, void, ())
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline();
#else
// Run
func();
#endif
}
CALL(36, glScalef, void, (GLfloat x, GLfloat y, GLfloat z))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(pun_to(uint32_t, x), pun_to(uint32_t, y), pun_to(uint32_t, z));
#else
GLfloat x = next_float();
GLfloat y = next_float();
GLfloat z = next_float();
// Run
func(x, y, z);
#endif
}
CALL(37, glPushMatrix, void, ())
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline();
#else
// Run
func();
#endif
}
CALL(38, glDepthMask, void, (GLboolean flag))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(flag);
#else
GLboolean flag = next_int();
// Run
func(flag);
#endif
}
CALL(39, glHint, void, (GLenum target, GLenum mode))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(target, mode);
#else
GLenum target = next_int();
GLenum mode = next_int();
// Run
func(target, mode);
#endif
}
CALL(40, glMultMatrixf, void, (const GLfloat *m))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline((uint32_t) m);
#else
GLfloat *m = next_ptr();
// Run
func(m);
#endif
}
CALL(42, glDeleteBuffers, void, (GLsizei n, const GLuint *buffers))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(n, (uint32_t) buffers);
#else
GLsizei n = next_int();
GLuint *buffers = next_ptr();
// Run
func(n, buffers);
#endif
}
CALL(43, glColorMask, void, (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(red, green, blue, alpha);
#else
GLboolean red = next_int();
GLboolean green = next_int();
GLboolean blue = next_int();
GLboolean alpha = next_int();
// Run
func(red, green, blue, alpha);
#endif
}
CALL(44, glTexSubImage2D, void, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(target, level, xoffset, yoffset, width, height, format, type, (uint32_t) pixels);
#else
GLenum target = next_int();
GLint level = next_int();
GLint xoffset = next_int();
GLint yoffset = next_int();
GLsizei width = next_int();
GLsizei height = next_int();
GLenum format = next_int();
GLenum type = next_int();
const void *pixels = next_ptr();
// Run
func(target, level, xoffset, yoffset, width, height, format, type, pixels);
#endif
}
CALL(45, glGenTextures, void, (GLsizei n, GLuint *textures))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(n, (uint32_t) textures);
#else
GLsizei n = next_int();
GLuint *textures = next_ptr();
// Run
func(n, textures);
#endif
}
CALL(46, glDeleteTextures, void, (GLsizei n, const GLuint *textures))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(n, (uint32_t) textures);
#else
GLsizei n = next_int();
GLuint *textures = next_ptr();
// Run
func(n, textures);
#endif
}
CALL(47, glAlphaFunc, void, (GLenum func, GLclampf ref))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(func, pun_to(uint32_t, ref));
#else
GLenum func2 = next_int();
GLclampf ref = next_float();
// Run
func(func2, ref);
#endif
}
CALL(48, glGetFloatv, void, (GLenum pname, GLfloat *params))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(pname, (uint32_t) params);
#else
GLenum pname = next_int();
GLfloat *params = next_ptr();
// Run
func(pname, params);
#endif
}
CALL(49, glBindTexture, void, (GLenum target, GLuint texture))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(target, texture);
#else
GLenum target = next_int();
GLuint texture = next_int();
// Run
func(target, texture);
#endif
}
CALL(50, glTranslatef, void, (GLfloat x, GLfloat y, GLfloat z))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(pun_to(uint32_t, x), pun_to(uint32_t, y), pun_to(uint32_t, z));
#else
GLfloat x = next_float();
GLfloat y = next_float();
GLfloat z = next_float();
// Run
func(x, y, z);
#endif
}
CALL(51, glShadeModel, void, (GLenum mode))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(mode);
#else
GLenum mode = next_int();
// Run
func(mode);
#endif
}
CALL(52, glOrthof, void, (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat near, GLfloat far))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(pun_to(uint32_t, left), pun_to(uint32_t, right), pun_to(uint32_t, bottom), pun_to(uint32_t, top), pun_to(uint32_t, near), pun_to(uint32_t, far));
#else
GLfloat left = next_float();
GLfloat right = next_float();
GLfloat bottom = next_float();
GLfloat top = next_float();
GLfloat near = next_float();
GLfloat far = next_float();
// Run
func(left, right, bottom, top, near, far);
#endif
}
CALL(53, glDisable, void, (GLenum cap))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(cap);
#else
GLenum cap = next_int();
// Run
func(cap);
#endif
}
CALL(54, glCullFace, void, (GLenum mode))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(mode);
#else
GLenum mode = next_int();
// Run
func(mode);
#endif
}
CALL(55, glRotatef, void, (GLfloat angle, GLfloat x, GLfloat y, GLfloat z))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(pun_to(uint32_t, angle), pun_to(uint32_t, x), pun_to(uint32_t, y), pun_to(uint32_t, z));
#else
GLfloat angle = next_float();
GLfloat x = next_float();
GLfloat y = next_float();
GLfloat z = next_float();
// Run
func(angle, x, y, z);
#endif
}
CALL(56, glViewport, void, (GLint x, GLint y, GLsizei width, GLsizei height))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(x, y, width, height);
#else
GLint x = next_int();
GLint y = next_int();
GLsizei width = next_int();
GLsizei height = next_int();
// Run
func(x, y, width, height);
#endif
}
CALL(57, glNormal3f, void, (GLfloat nx, GLfloat ny, GLfloat nz))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(pun_to(uint32_t, nx), pun_to(uint32_t, ny), pun_to(uint32_t, nz));
#else
GLfloat nx = next_float();
GLfloat ny = next_float();
GLfloat nz = next_float();
// Run
func(nx, ny, nz);
#endif
}
CALL(58, glIsEnabled, GLboolean, (GLenum cap))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
return trampoline(cap);
#else
GLenum cap = next_int();
// Run
ret(func(cap));
#endif
}
CALL(61, glGetIntegerv, void, (GLenum pname, GLint *params))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(pname, (uint32_t) params);
#else
GLenum pname = next_int();
GLint *params = next_ptr();
// Run
func(pname, params);
#endif
}
CALL(65, glReadPixels, void, (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *data))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(x, y, width, height, format, type, (uint32_t) data);
#else
GLint x = next_int();
GLint y = next_int();
GLsizei width = next_int();
GLsizei height = next_int();
GLenum format = next_int();
GLenum type = next_int();
void *data = next_ptr();
// Run
func(x, y, width, height, format, type, data);
#endif
}
CALL(67, glGenBuffers, void, (GLsizei n, GLuint *buffers))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(n, (uint32_t) buffers);
#else
GLsizei n = next_int();
GLuint *buffers = next_ptr();
// Run
func(n, buffers);
#endif
}

View File

@ -0,0 +1,21 @@
#pragma once
#if __BYTE_ORDER != __LITTLE_ENDIAN
#error "Only Little Endian Is Supported"
#endif
#if defined(MEDIA_LAYER_TRAMPOLINE_HOST)
#include "../host/host.h"
#elif defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
#include "../guest/guest.h"
#else
#error "Invalid Configuration"
#endif
//#define pun_to(type, x) (*(type *) &(x))
#define pun_to(type, x) \
({ \
union { typeof(x) a; type b; } _pun; \
_pun.a = x; \
_pun.b; \
})

View File

@ -0,0 +1,15 @@
#include <unistd.h>
#include <libreborn/libreborn.h>
#include "guest.h"
uint32_t _trampoline(uint32_t id, uint32_t *args) {
// Make Syscall
long ret = syscall(0x1337 /* See trampoline.patch */, id, args);
if (ret == -1) {
// Error
ERR("Trampoline Error: %s", strerror(errno));
}
// Return
return args[0];
}

View File

@ -0,0 +1,12 @@
#pragma once
#include <stdint.h>
// Trampoline Function
uint32_t _trampoline(uint32_t id, uint32_t *args);
#define trampoline(...) _trampoline(_id, (uint32_t[]){__VA_ARGS__})
// Macro
#define CALL(unique_id, name, return_type, args) \
return_type name args { \
static unsigned char _id = unique_id;

View File

@ -0,0 +1,17 @@
#include <libreborn/libreborn.h>
#include "host.h"
// Registration
static handler_t *handlers[256];
void _add_handler(unsigned char id, handler_t *handler) {
if (handlers[id]) {
ERR("Conflicting Trampolines For ID: %i", (int) id);
}
handlers[id] = handler;
}
// Trampoline
void trampoline(g2h_t g2h, uint32_t id, uint32_t *args) {
handlers[id](g2h, args);
}

View File

@ -0,0 +1,27 @@
#pragma once
#include <stdint.h>
// Trampoline Function
typedef void *(*g2h_t)(uint32_t guest_addr);
void trampoline(g2h_t g2h, uint32_t id, uint32_t *args); // See trampoline.patch
// Macro
typedef void handler_t(g2h_t g2h, uint32_t *args);
__attribute__((visibility("internal"))) void _add_handler(unsigned char id, handler_t *handler);
#define CALL(unique_id, name, ignored1, ignored2) \
static handler_t _run_##name; \
__attribute__((constructor)) static void _init_##name() { \
_add_handler(unique_id, _run_##name); \
} \
static void _run_##name(__attribute__((unused)) g2h_t g2h, __attribute__((unused)) uint32_t *args) { \
__attribute__((unused)) int _current_arg = 0; \
static typeof(name) *func = name;
// Helper Macros
#define next_int() args[_current_arg++]
#define next_ptr() g2h(next_int())
#define next_float() pun_to(float, next_int())
#define ret(x) \
args[0] = x; \
return;

View File

@ -0,0 +1,188 @@
#include <stdint.h>
#include <SDL/SDL.h>
#include <libreborn/libreborn.h>
#include <media-layer/core.h>
#include <media-layer/audio.h>
#include "common/common.h"
// SDL Functions
CALL(0, SDL_Init, int, (uint32_t flags))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
return trampoline(flags);
#else
uint32_t flags = next_int();
// Run
ret(func(flags));
#endif
}
CALL(1, SDL_PollEvent, int, (SDL_Event *event))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
return trampoline((uint32_t) event);
#else
SDL_Event *event = next_ptr();
// Run
ret(func(event));
#endif
}
CALL(2, SDL_PushEvent, int, (SDL_Event *event))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
return trampoline((uint32_t) event);
#else
SDL_Event *event = next_ptr();
// Run
ret(func(event));
#endif
}
CALL(3, SDL_WM_SetCaption, void, (const char *title, const char *icon))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline((uint32_t) title, (uint32_t) icon);
#else
char *title = next_ptr();
char *icon = next_ptr();
// Run
func(title, icon);
#endif
}
CALL(4, media_toggle_fullscreen, void, ())
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline();
#else
// Run
func();
#endif
}
CALL(5, SDL_WM_GrabInput, SDL_GrabMode, (SDL_GrabMode mode))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
return trampoline(mode);
#else
SDL_GrabMode mode = next_int();
// Run
ret(func(mode));
#endif
}
CALL(6, SDL_ShowCursor, int, (int32_t toggle))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
return trampoline(toggle);
#else
int mode = next_int();
// Run
ret(func(mode));
#endif
}
CALL(8, media_swap_buffers, void, ())
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline();
#else
// Run
func();
#endif
}
CALL(9, media_cleanup, void, ())
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline();
#else
// Run
func();
#endif
}
CALL(10, media_get_framebuffer_size, void, (int *width, int *height))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline((uint32_t) width, (uint32_t) height);
#else
int *width = next_ptr();
int *height = next_ptr();
// Run
func(width, height);
#endif
}
CALL(59, media_audio_update, void, (float volume, float x, float y, float z, float yaw))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(pun_to(uint32_t, volume), pun_to(uint32_t, x), pun_to(uint32_t, y), pun_to(uint32_t, z), pun_to(uint32_t, yaw));
#else
float volume = next_float();
float x = next_float();
float y = next_float();
float z = next_float();
float yaw = next_float();
// Run
func(volume, x, y, z, yaw);
#endif
}
CALL(60, media_audio_play, void, (const char *source, const char *name, float x, float y, float z, float pitch, float volume, int is_ui))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline((uint32_t) source, (uint32_t) name, pun_to(uint32_t, x), pun_to(uint32_t, y), pun_to(uint32_t, z), pun_to(uint32_t, pitch), pun_to(uint32_t, volume), is_ui);
#else
char *source = next_ptr();
char *name = next_ptr();
float x = next_float();
float y = next_float();
float z = next_float();
float pitch = next_float();
float volume = next_float();
int is_ui = next_int();
// Run
func(source, name, x, y, z, pitch, volume, is_ui);
#endif
}
CALL(62, media_set_interactable, void, (int is_interactable))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(is_interactable);
#else
int is_interactable = next_int();
// Run
func(is_interactable);
#endif
}
CALL(63, media_disable_vsync, void, ())
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline();
#else
// Run
func();
#endif
}
CALL(64, media_set_raw_mouse_motion_enabled, void, (int enabled))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline(enabled);
#else
int enabled = next_int();
// Run
func(enabled);
#endif
}
CALL(66, media_force_egl, void, ())
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline();
#else
// Run
func();
#endif
}
CALL(68, media_ensure_loaded, void, ())
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST)
trampoline();
#else
// Run
func();
#endif
}

View File

@ -6,6 +6,7 @@
extern "C" {
int32_t misc_get_real_selected_slot(Player *player);
void misc_render_background(int color, Minecraft *minecraft, int x, int y, int width, int height);
typedef void (*misc_update_function_Minecraft_t)(Minecraft *obj);
void misc_run_on_update(misc_update_function_Minecraft_t function); // obj == Minecraft *

View File

@ -1,17 +1,13 @@
// Config Needs To Load First
#include <libreborn/libreborn.h>
#include "game-mode-internal.h"
// Game Mode UI Code Is Useless In Headless Mode
#ifndef MCPI_HEADLESS_MODE
#include <string>
#include <set>
#include <symbols/minecraft.h>
#include <libreborn/libreborn.h>
#include <mods/text-input-box/TextInputScreen.h>
#include <mods/touch/touch.h>
#include <mods/misc/misc.h>
#include "game-mode-internal.h"
// Strings
#define GAME_MODE_STR(mode) ("Game Mode: " mode)
@ -36,6 +32,9 @@ CUSTOM_VTABLE(create_world_screen, Screen) {
static int inner_padding = 4;
static int description_padding = 4;
static int title_padding = 8;
static int button_height = 24;
static int content_y_offset_top = (title_padding * 2) + line_height;
static int content_y_offset_bottom = button_height + (bottom_padding * 2);
// Init
static Screen_init_t original_init = vtable->init;
vtable->init = [](Screen *super) {
@ -79,7 +78,8 @@ CUSTOM_VTABLE(create_world_screen, Screen) {
static Screen_render_t original_render = vtable->render;
vtable->render = [](Screen *super, int x, int y, float param_1) {
// Background
super->vtable->renderBackground(super);
misc_render_background(80, super->minecraft, 0, 0, super->width, super->height);
misc_render_background(32, super->minecraft, 0, content_y_offset_top, super->width, super->height - content_y_offset_top - content_y_offset_bottom);
// Call Original Method
original_render(super, x, y, param_1);
// Title
@ -98,15 +98,15 @@ CUSTOM_VTABLE(create_world_screen, Screen) {
CreateWorldScreen *self = (CreateWorldScreen *) super;
// Height/Width
int width = 120;
int height = 24;
int height = button_height;
self->create->width = self->back->width = self->game_mode->width = width;
int seed_width = self->game_mode->width;
int name_width = width * 1.5f;
self->create->height = self->back->height = self->game_mode->height = height;
int text_box_height = self->game_mode->height;
// Find Center Y
int top = (title_padding * 2) + line_height;
int bottom = super->height - self->create->height - (bottom_padding * 2);
int top = content_y_offset_top;
int bottom = super->height - content_y_offset_bottom;
int center_y = ((bottom - top) / 2) + top;
center_y -= (description_padding + line_height) / 2;
// X/Y
@ -254,9 +254,4 @@ void _init_game_mode_ui() {
// Hijack Create World Button
overwrite_virtual_calls(SelectWorldScreen_tick, SelectWorldScreen_tick_injection);
overwrite_virtual_calls(Touch_SelectWorldScreen_tick, Touch_SelectWorldScreen_tick_injection);
}
#else
void _init_game_mode_ui() {
}
#endif
}

View File

@ -3,6 +3,7 @@
#include <libreborn/libreborn.h>
#include <symbols/minecraft.h>
#include <GLES/gl.h>
#include <mods/misc/misc.h>
#include "misc-internal.h"
@ -139,6 +140,26 @@ static void Gui_handleKeyPressed_injection(Gui_handleKeyPressed_t original, Gui
original(self, key);
}
// Render Fancy Background
void misc_render_background(int color, Minecraft *minecraft, int x, int y, int width, int height) {
// https://github.com/ReMinecraftPE/mcpe/blob/f0d65eaecec1b3fe9c2f2b251e114a890c54ab77/source/client/gui/components/RolledSelectionList.cpp#L169-L179
glColor4f(1, 1, 1, 1);
std::string texture = "gui/background.png";
minecraft->textures->loadAndBindTexture(&texture);
Tesselator *t = &Tesselator_instance;
t->begin(7);
t->color(color, color, color, 255);
float x1 = x;
float x2 = x + width;
float y1 = y;
float y2 = y + height;
t->vertexUV(x1, y2, 0.0f, x1 / 32.0f, y2 / 32.0f);
t->vertexUV(x2, y2, 0.0f, x2 / 32.0f, y2 / 32.0f);
t->vertexUV(x2, y1, 0.0f, x2 / 32.0f, y1 / 32.0f);
t->vertexUV(x1, y1, 0.0f, x1 / 32.0f, y1 / 32.0f);
t->draw();
}
// Init
void _init_misc_api() {
// Handle Custom Update Behavior

View File

@ -3,7 +3,7 @@
#include <GLES/gl.h>
#include <mods/touch/touch.h>
#include <mods/home/home.h>
#include <mods/misc/misc.h>
#include "options-internal.h"
@ -150,25 +150,6 @@ static void open_url(const std::string &url) {
}
}
// Render Fancy Background
static void render_background(Minecraft *minecraft, int x, int y, int width, int height) {
// https://github.com/ReMinecraftPE/mcpe/blob/f0d65eaecec1b3fe9c2f2b251e114a890c54ab77/source/client/gui/components/RolledSelectionList.cpp#L169-L179
std::string texture = "gui/background.png";
minecraft->textures->loadAndBindTexture(&texture);
Tesselator *t = &Tesselator_instance;
t->begin(7);
t->color(32, 32, 32, 255);
float x1 = x;
float x2 = x + width;
float y1 = y;
float y2 = y + height;
t->vertexUV(x1, y2, 0.0f, x1 / 32.0f, y2 / 32.0f);
t->vertexUV(x2, y2, 0.0f, x2 / 32.0f, y2 / 32.0f);
t->vertexUV(x2, y1, 0.0f, x2 / 32.0f, y1 / 32.0f);
t->vertexUV(x1, y1, 0.0f, x1 / 32.0f, y1 / 32.0f);
t->draw();
}
// Create VTable
CUSTOM_VTABLE(info_screen, Screen) {
// Buttons
@ -207,9 +188,8 @@ CUSTOM_VTABLE(info_screen, Screen) {
static Screen_render_t original_render = vtable->render;
vtable->render = [](Screen *self, int x, int y, float param_1) {
// Background
self->vtable->renderBackground(self);
// Gradient
render_background(self->minecraft, 0, content_y_offset_top, self->width, content_height);
misc_render_background(80, self->minecraft, 0, 0, self->width, self->height);
misc_render_background(32, self->minecraft, 0, content_y_offset_top, self->width, content_height);
// Call Original Method
original_render(self, x, y, param_1);
// Title