From 211bf265ffd9594f030edce82b2d2b72e98ea271 Mon Sep 17 00:00:00 2001 From: TheBrokenRail Date: Fri, 3 Jun 2022 22:25:22 -0400 Subject: [PATCH] Optimizations & Fixes --- launcher/src/bootstrap.c | 7 +- launcher/src/patchelf.c | 22 +-- launcher/src/patchelf.h | 4 +- media-layer/include/GLES/gl.h | 1 + media-layer/proxy/src/GLESv1_CM.c | 163 +++++++++++------- media-layer/proxy/src/client/client.cpp | 22 +-- media-layer/proxy/src/common/common.c | 69 +++++++- mods/src/compat/compat.c | 17 +- .../tools/generate-appimage-builder-yaml.js | 4 +- 9 files changed, 205 insertions(+), 104 deletions(-) diff --git a/launcher/src/bootstrap.c b/launcher/src/bootstrap.c index 787811ac..fb8bea1c 100644 --- a/launcher/src/bootstrap.c +++ b/launcher/src/bootstrap.c @@ -254,6 +254,7 @@ void bootstrap(int argc, char *argv[]) { } // Fix MCPI Dependencies + char new_mcpi_exe_path[] = MCPI_PATCHED_DIR "/XXXXXX"; { // Log DEBUG("Patching ELF Dependencies..."); @@ -273,7 +274,7 @@ void bootstrap(int argc, char *argv[]) { #endif // Patch - patch_mcpi_elf_dependencies(resolved_path, linker); + patch_mcpi_elf_dependencies(resolved_path, new_mcpi_exe_path, linker); // Free Linker Path if (linker != NULL) { @@ -281,7 +282,7 @@ void bootstrap(int argc, char *argv[]) { } // Verify - if (!starts_with(getenv("MCPI_EXECUTABLE_PATH"), "/tmp")) { + if (!starts_with(new_mcpi_exe_path, MCPI_PATCHED_DIR)) { IMPOSSIBLE(); } } @@ -391,7 +392,7 @@ void bootstrap(int argc, char *argv[]) { new_args[argv_start + argc] = NULL; // Set Executable Argument - new_args[argv_start] = getenv("MCPI_EXECUTABLE_PATH"); + new_args[argv_start] = new_mcpi_exe_path; // Non-ARM Systems Need QEMU #ifndef __ARM_ARCH diff --git a/launcher/src/patchelf.c b/launcher/src/patchelf.c index 0d737174..af897c00 100644 --- a/launcher/src/patchelf.c +++ b/launcher/src/patchelf.c @@ -8,23 +8,21 @@ #include "patchelf.h" // Duplicate MCPI Executable Into /tmp -#define TMP_DIR "/tmp/.minecraft-pi-patched" -static void duplicate_mcpi_executable(const char *original_path) { +static void duplicate_mcpi_executable(const char *original_path, char *new_path) { // Ensure Temporary Directory { // Check If It Exists struct stat tmp_stat; - int exists = stat(TMP_DIR, &tmp_stat) != 0 ? 0 : S_ISDIR(tmp_stat.st_mode); + int exists = stat(MCPI_PATCHED_DIR, &tmp_stat) != 0 ? 0 : S_ISDIR(tmp_stat.st_mode); if (!exists) { // Doesn't Exist - if (mkdir(TMP_DIR, S_IRUSR | S_IWUSR | S_IXUSR) != 0) { + if (mkdir(MCPI_PATCHED_DIR, S_IRUSR | S_IWUSR | S_IXUSR) != 0) { ERR("Unable To Create Temporary Folder: %s", strerror(errno)); } } } // Generate New File - char new_path[] = TMP_DIR "/XXXXXX"; int new_file_fd = mkstemp(new_path); if (new_file_fd == -1) { ERR("Unable To Create Temporary File: %s", strerror(errno)); @@ -33,7 +31,6 @@ static void duplicate_mcpi_executable(const char *original_path) { if (new_file == NULL) { ERR("Unable To Open Temporary File: %s", strerror(errno)); } - set_and_print_env("MCPI_EXECUTABLE_PATH", new_path); // Copy Original File { @@ -76,7 +73,7 @@ static void duplicate_mcpi_executable(const char *original_path) { "--remove-needed", "libX11.so.6", \ "--remove-needed", "libEGL.so", \ "--replace-needed", "libGLESv2.so", "libGLESv1_CM.so.1", \ - exe, \ + new_path, \ NULL \ }; \ int _macro_return_code = 0; \ @@ -86,12 +83,9 @@ static void duplicate_mcpi_executable(const char *original_path) { } \ _macro_return_code; \ }) -void patch_mcpi_elf_dependencies(const char *original_path, const char *linker) { +void patch_mcpi_elf_dependencies(const char *original_path, char *new_path, const char *linker) { // Duplicate MCPI executable into /tmp so it can be modified. - duplicate_mcpi_executable(original_path); - - // Get Path - char *exe = getenv("MCPI_EXECUTABLE_PATH"); + duplicate_mcpi_executable(original_path, new_path); // Run patchelf int return_code; @@ -107,8 +101,8 @@ void patch_mcpi_elf_dependencies(const char *original_path, const char *linker) } // Fix Permissions - if (chmod(exe, S_IRUSR | S_IXUSR) != 0) { - ERR("Unable To Set File Permissions: %s: %s", exe, strerror(errno)); + if (chmod(new_path, S_IRUSR | S_IXUSR) != 0) { + ERR("Unable To Set File Permissions: %s: %s", new_path, strerror(errno)); } } diff --git a/launcher/src/patchelf.h b/launcher/src/patchelf.h index 02d42bd6..4513109b 100644 --- a/launcher/src/patchelf.h +++ b/launcher/src/patchelf.h @@ -4,7 +4,9 @@ extern "C" { #endif -void patch_mcpi_elf_dependencies(const char *original_path, const char *linker); +#define MCPI_PATCHED_DIR "/tmp/.minecraft-pi-patched" + +void patch_mcpi_elf_dependencies(const char *original_path, char *new_path, const char *linker); char *patch_get_interpreter(const char *file); #ifdef __cplusplus diff --git a/media-layer/include/GLES/gl.h b/media-layer/include/GLES/gl.h index 10440043..286ec880 100644 --- a/media-layer/include/GLES/gl.h +++ b/media-layer/include/GLES/gl.h @@ -6,6 +6,7 @@ extern "C" { #define GL_FALSE 0 #define GL_ARRAY_BUFFER_BINDING 0x8894 +#define GL_ARRAY_BUFFER 0x8892 #define GL_TEXTURE_BINDING_2D 0x8069 #define GL_UNSIGNED_BYTE 0x1401 #define GL_FLOAT 0x1406 diff --git a/media-layer/proxy/src/GLESv1_CM.c b/media-layer/proxy/src/GLESv1_CM.c index d58f3f23..ed51303e 100644 --- a/media-layer/proxy/src/GLESv1_CM.c +++ b/media-layer/proxy/src/GLESv1_CM.c @@ -39,6 +39,21 @@ CALL(11, glFogfv, void, (GLenum pname, const GLfloat *params)) { #if defined(MEDIA_LAYER_PROXY_SERVER) #define CALL_GL_POINTER(unique_id, name) \ CALL(unique_id, name, void, (GLint size, GLenum type, GLsizei stride, const void *pointer)) { \ + /* Check */ \ + static int last_set = 0; \ + static GLint last_size; \ + static GLenum last_type; \ + static GLsizei last_stride; \ + static const void *last_pointer; \ + if (last_set && last_size == size && last_type == type && last_stride == stride && last_pointer == pointer) { \ + return; \ + } else { \ + last_set = 1; \ + last_size = size; \ + last_type = type; \ + last_stride = stride; \ + last_pointer = pointer; \ + } \ /* Lock Proxy */ \ start_proxy_call(); \ \ @@ -107,6 +122,31 @@ CALL(14, glBlendFunc, void, (GLenum sfactor, GLenum dfactor)) { #endif } +// Track Bindings +#if defined(MEDIA_LAYER_PROXY_SERVER) +static GLuint bound_buffer = 0; +static GLuint bound_texture = 0; +static unsigned char vertex_array_enabled = 0; +static unsigned char color_array_enabled = 0; +static unsigned char tex_coord_array_enabled = 0; +static unsigned char *get_array_enabled_pointer(GLenum array) { + switch (array) { + case GL_VERTEX_ARRAY: { + return &vertex_array_enabled; + } + case GL_COLOR_ARRAY: { + return &color_array_enabled; + } + case GL_TEXTURE_COORD_ARRAY: { + return &tex_coord_array_enabled; + } + default: { + ERR("Unsupported Array Pointer: %i", array); + } + } +} +#endif + CALL(15, glDrawArrays, void, (GLenum mode, GLint first, GLsizei count)) { #if defined(MEDIA_LAYER_PROXY_SERVER) // Lock Proxy @@ -116,6 +156,13 @@ CALL(15, glDrawArrays, void, (GLenum mode, GLint first, GLsizei count)) { write_int((uint32_t) mode); write_int((uint32_t) first); write_int((uint32_t) count); + write_int(bound_buffer); + write_int(bound_texture); + if (!vertex_array_enabled) { + IMPOSSIBLE(); + } + write_byte(color_array_enabled); + write_byte(tex_coord_array_enabled); // Release Proxy end_proxy_call(); @@ -123,7 +170,17 @@ CALL(15, glDrawArrays, void, (GLenum mode, GLint first, GLsizei count)) { GLenum mode = (GLenum) read_int(); GLint first = (GLint) read_int(); GLsizei count = (GLsizei) read_int(); + GLuint bound_buffer = (GLuint) read_int(); + GLuint bound_texture = (GLuint) read_int(); + unsigned char color_array_enabled = read_byte(); + unsigned char tex_coord_array_enabled = read_byte(); // Run + glBindBuffer(GL_ARRAY_BUFFER, bound_buffer); + glBindTexture(GL_TEXTURE_2D, bound_texture); + glEnableClientState(GL_VERTEX_ARRAY); +#define set_array_enabled(condition, enum) condition ? glEnableClientState(enum) : glDisableClientState(enum); + set_array_enabled(color_array_enabled, GL_COLOR_ARRAY); + set_array_enabled(tex_coord_array_enabled, GL_TEXTURE_COORD_ARRAY); glDrawArrays(mode, first, count); #endif } @@ -187,6 +244,7 @@ CALL(18, glBufferData, void, (GLenum target, GLsizeiptr size, const void *data, write_int((uint32_t) target); write_int((uint32_t) size); write_int((uint32_t) usage); + write_int(bound_buffer); // Write Data unsigned char is_null = data == NULL; write_byte(is_null); @@ -200,6 +258,7 @@ CALL(18, glBufferData, void, (GLenum target, GLsizeiptr size, const void *data, GLenum target = (GLenum) read_int(); GLsizeiptr size = (GLsizeiptr) read_int(); GLenum usage = (GLenum) read_int(); + GLuint bound_buffer = (GLuint) read_int(); // Load Data void *data = NULL; unsigned char is_null = read_byte(); @@ -223,6 +282,7 @@ CALL(18, glBufferData, void, (GLenum target, GLsizeiptr size, const void *data, safe_read(data, (size_t) size); } // Run + glBindBuffer(GL_ARRAY_BUFFER, bound_buffer); glBufferData(target, size, data, usage); #endif } @@ -316,6 +376,7 @@ CALL(24, glTexParameteri, void, (GLenum target, GLenum pname, GLint param)) { write_int((uint32_t) target); write_int((uint32_t) pname); write_int((uint32_t) param); + write_int(bound_texture); // Release Proxy end_proxy_call(); @@ -323,7 +384,9 @@ CALL(24, glTexParameteri, void, (GLenum target, GLenum pname, GLint param)) { GLenum target = (GLenum) read_int(); GLenum pname = (GLenum) read_int(); GLint param = (GLint) read_int(); + GLuint bound_texture = (GLuint) read_int(); // Run + glBindTexture(GL_TEXTURE_2D, bound_texture); glTexParameteri(target, pname, param); #endif } @@ -383,6 +446,7 @@ CALL(25, glTexImage2D, void, (GLenum target, GLint level, GLint internalformat, write_int((uint32_t) border); write_int((uint32_t) format); write_int((uint32_t) type); + write_int(bound_texture); write_byte(is_null); if (!is_null) { safe_write((void *) pixels, (size_t) size); @@ -399,6 +463,7 @@ CALL(25, glTexImage2D, void, (GLenum target, GLint level, GLint internalformat, GLint border = (GLint) read_int(); GLenum format = (GLenum) read_int(); GLenum type = (GLenum) read_int(); + GLuint bound_texture = (GLuint) read_int(); unsigned char is_null = read_byte(); void *pixels = NULL; if (!is_null) { @@ -408,6 +473,7 @@ CALL(25, glTexImage2D, void, (GLenum target, GLint level, GLint internalformat, safe_read(pixels, (size_t) size); } // Run + glBindTexture(GL_TEXTURE_2D, bound_texture); glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); // Free if (!is_null) { @@ -433,22 +499,17 @@ CALL(26, glEnable, void, (GLenum cap)) { #endif } -CALL(27, glEnableClientState, void, (GLenum array)) { #if defined(MEDIA_LAYER_PROXY_SERVER) - // Lock Proxy - start_proxy_call(); - - // Arguments - write_int((uint32_t) array); - - // Release Proxy - end_proxy_call(); -#else - GLenum array = (GLenum) read_int(); - // Run - glEnableClientState(array); -#endif +void glEnableClientState(GLenum array) { + // Set + unsigned char *enabled = get_array_enabled_pointer(array); + if (*enabled) { + return; + } else { + *enabled = 1; + } } +#endif CALL(28, glPolygonOffset, void, (GLfloat factor, GLfloat units)) { #if defined(MEDIA_LAYER_PROXY_SERVER) @@ -469,22 +530,17 @@ CALL(28, glPolygonOffset, void, (GLfloat factor, GLfloat units)) { #endif } -CALL(29, glDisableClientState, void, (GLenum array)) { #if defined(MEDIA_LAYER_PROXY_SERVER) - // Lock Proxy - start_proxy_call(); - - // Arguments - write_int((uint32_t) array); - - // Release Proxy - end_proxy_call(); -#else - GLenum array = (GLenum) read_int(); - // Run - glDisableClientState(array); -#endif +void glDisableClientState(GLenum array) { + // Set + unsigned char *enabled = get_array_enabled_pointer(array); + if (!*enabled) { + return; + } else { + *enabled = 0; + } } +#endif CALL(30, glDepthRangef, void, (GLclampf near, GLclampf far)) { #if defined(MEDIA_LAYER_PROXY_SERVER) @@ -522,24 +578,16 @@ CALL(31, glDepthFunc, void, (GLenum func)) { #endif } -CALL(32, glBindBuffer, void, (GLenum target, GLuint buffer)) { #if defined(MEDIA_LAYER_PROXY_SERVER) - // Lock Proxy - start_proxy_call(); - - // Arguments - write_int((uint32_t) target); - write_int((uint32_t) buffer); - - // Release Proxy - end_proxy_call(); -#else - GLenum target = (GLenum) read_int(); - GLuint buffer = (GLuint) read_int(); - // Run - glBindBuffer(target, buffer); -#endif +void glBindBuffer(GLenum target, GLuint buffer) { + // Set + if (target == GL_ARRAY_BUFFER) { + bound_buffer = buffer; + } else { + PROXY_ERR("Unsupported Buffer Binding: %u", target); + } } +#endif CALL(33, glClearColor, void, (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)) { #if defined(MEDIA_LAYER_PROXY_SERVER) @@ -748,6 +796,7 @@ CALL(44, glTexSubImage2D, void, (GLenum target, GLint level, GLint xoffset, GLin write_int((uint32_t) height); write_int((uint32_t) format); write_int((uint32_t) type); + write_int(bound_texture); write_byte(is_null); if (!is_null) { safe_write((void *) pixels, (size_t) size); @@ -764,6 +813,7 @@ CALL(44, glTexSubImage2D, void, (GLenum target, GLint level, GLint xoffset, GLin GLsizei height = (GLsizei) read_int(); GLenum format = (GLenum) read_int(); GLenum type = (GLenum) read_int(); + GLuint bound_texture = (GLuint) read_int(); unsigned char is_null = read_byte(); void *pixels = NULL; if (!is_null) { @@ -773,6 +823,7 @@ CALL(44, glTexSubImage2D, void, (GLenum target, GLint level, GLint xoffset, GLin safe_read(pixels, (size_t) size); } // Run + glBindTexture(GL_TEXTURE_2D, bound_texture); glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels); // Free if (!is_null) { @@ -887,24 +938,16 @@ CALL(48, glGetFloatv, void, (GLenum pname, GLfloat *params)) { #endif } -CALL(49, glBindTexture, void, (GLenum target, GLuint texture)) { #if defined(MEDIA_LAYER_PROXY_SERVER) - // Lock Proxy - start_proxy_call(); - - // Arguments - write_int((uint32_t) target); - write_int((uint32_t) texture); - - // Release Proxy - end_proxy_call(); -#else - GLenum target = (GLenum) read_int(); - GLuint texture = (GLuint) read_int(); - // Run - glBindTexture(target, texture); -#endif +void glBindTexture(GLenum target, GLuint texture) { + // Set + if (target == GL_TEXTURE_2D) { + bound_texture = texture; + } else { + PROXY_ERR("Unsupported Texture Binding: %u", target); + } } +#endif CALL(50, glTranslatef, void, (GLfloat x, GLfloat y, GLfloat z)) { #if defined(MEDIA_LAYER_PROXY_SERVER) diff --git a/media-layer/proxy/src/client/client.cpp b/media-layer/proxy/src/client/client.cpp index 15f1974b..ab4aabee 100644 --- a/media-layer/proxy/src/client/client.cpp +++ b/media-layer/proxy/src/client/client.cpp @@ -9,18 +9,15 @@ #include "../common/common.h" // Store Handlers -__attribute__((const)) static std::vector &get_handlers() { - static std::vector handlers; - return handlers; -} +static std::vector handlers; void _add_handler(unsigned char unique_id, proxy_handler_t handler) { - if (get_handlers().size() > unique_id && get_handlers()[unique_id] != NULL) { + if (handlers.size() > unique_id && handlers[unique_id] != NULL) { PROXY_ERR("Duplicate ID: %i", (int) unique_id); } - if (get_handlers().size() <= unique_id) { - get_handlers().resize(unique_id + 1); + if (handlers.size() <= unique_id) { + handlers.resize(unique_id + 1); } - get_handlers()[unique_id] = handler; + handlers[unique_id] = handler; } // Store Parent PID @@ -48,10 +45,7 @@ static void exit_handler(__attribute__((unused)) int signal_id) { // Main int main(int argc, char *argv[]) { // Install Signal Handlers - struct sigaction act_sigint; - memset((void *) &act_sigint, 0, sizeof (struct sigaction)); - act_sigint.sa_handler = &exit_handler; - sigaction(SIGINT, &act_sigint, NULL); + signal(SIGINT, SIG_IGN); struct sigaction act_sigterm; memset((void *) &act_sigterm, 0, sizeof (struct sigaction)); act_sigterm.sa_handler = &exit_handler; @@ -84,9 +78,9 @@ int main(int argc, char *argv[]) { int running = is_connection_open(); while (running && !exit_requested) { unsigned char unique_id = read_byte(); - if (get_handlers().size() > unique_id && get_handlers()[unique_id] != NULL) { + if (handlers.size() > unique_id && handlers[unique_id] != NULL) { // Run Method - get_handlers()[unique_id](); + handlers[unique_id](); // Check If Connection Is Still Open if (!is_connection_open()) { // Exit diff --git a/media-layer/proxy/src/common/common.c b/media-layer/proxy/src/common/common.c index e9ec77f4..9bebf3cb 100644 --- a/media-layer/proxy/src/common/common.c +++ b/media-layer/proxy/src/common/common.c @@ -1,6 +1,8 @@ #include #include #include +#include +#include #include "common.h" @@ -12,23 +14,80 @@ 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 - size_t to_read = len; - while (to_read > 0) { + // Read Remaining Data + size_t to_read_to_cache; + { + 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); + } + if (to_read_to_cache < 1) { + // Nothing To Read + return; + } + // 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 *) buf) + (len - to_read)), to_read); + 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 -= x; + 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; diff --git a/mods/src/compat/compat.c b/mods/src/compat/compat.c index 50e0e9c8..30d3f584 100644 --- a/mods/src/compat/compat.c +++ b/mods/src/compat/compat.c @@ -133,13 +133,18 @@ void init_compat() { __attribute__((destructor)) static void cleanup_temporary() { // Cleanup Executable { - const char *exe = getenv("MCPI_EXECUTABLE_PATH"); - // Check If Executable Is Temporary - if (exe != NULL && starts_with(exe, "/tmp")) { - // Cleanup Temporary File - if (unlink(exe) != 0) { - ERR("Unable To Cleanup Temporary File: %s", strerror(errno)); + char *exe = realpath("/proc/self/exe", NULL); + // Check If Successful + if (exe != NULL) { + // Check If Executable Is Temporary + if (starts_with(exe, "/tmp")) { + // Cleanup Temporary File + if (unlink(exe) != 0) { + ERR("Unable To Cleanup Temporary File: %s", strerror(errno)); + } } + // Free + free(exe); } } } diff --git a/scripts/tools/generate-appimage-builder-yaml.js b/scripts/tools/generate-appimage-builder-yaml.js index 38a7b33a..7b64e075 100755 --- a/scripts/tools/generate-appimage-builder-yaml.js +++ b/scripts/tools/generate-appimage-builder-yaml.js @@ -38,6 +38,7 @@ if (mode === 'client') { 'libgtk-3-0', 'libglib2.0-0', 'libgdk-pixbuf2.0-0', + 'librsvg2-common', 'shared-mime-info', 'libfreeimage3', 'libopenal1' @@ -59,7 +60,8 @@ const packageExclusions = [ 'librest-*', 'libcups2', 'libcolord2', - 'libmount1' + 'libmount1', + 'libwayland-*' ]; // APT