From 75abce1b803957aa696fa3ea8d3168d4888f333e Mon Sep 17 00:00:00 2001 From: artdeell Date: Mon, 2 Dec 2024 17:41:38 +0300 Subject: [PATCH] Implement swizzler for BGRA/"wrong order" uploads --- .../artdeell/gl4eswrapper/MainActivity.java | 1 + app/src/main/tinywrapper/Android.mk | 1 + app/src/main/tinywrapper/egl.c | 5 + app/src/main/tinywrapper/egl.h | 14 +-- app/src/main/tinywrapper/main.c | 60 +++++++++-- app/src/main/tinywrapper/of_buffer_copier.c | 23 +--- app/src/main/tinywrapper/swizzle.c | 102 ++++++++++++++++++ app/src/main/tinywrapper/swizzle.h | 13 +++ 8 files changed, 187 insertions(+), 32 deletions(-) create mode 100644 app/src/main/tinywrapper/swizzle.c create mode 100644 app/src/main/tinywrapper/swizzle.h diff --git a/app/src/main/java/git/artdeell/gl4eswrapper/MainActivity.java b/app/src/main/java/git/artdeell/gl4eswrapper/MainActivity.java index 7f5bcfe..9a794f9 100644 --- a/app/src/main/java/git/artdeell/gl4eswrapper/MainActivity.java +++ b/app/src/main/java/git/artdeell/gl4eswrapper/MainActivity.java @@ -32,6 +32,7 @@ public class MainActivity extends Activity { } String copyCommand = "cp " + copySrc + "/* "+copyDst+"/"; try { + Runtime.getRuntime().exec("am force-stop "+targetAppInfo.packageName); ProcessBuilder processBuilder = new ProcessBuilder("su", "-c", copyCommand); Process process = processBuilder.start(); int errorCode = process.waitFor(); diff --git a/app/src/main/tinywrapper/Android.mk b/app/src/main/tinywrapper/Android.mk index 081f7c6..5132f54 100644 --- a/app/src/main/tinywrapper/Android.mk +++ b/app/src/main/tinywrapper/Android.mk @@ -400,6 +400,7 @@ LOCAL_SRC_FILES := \ stubs.c \ multidraw.c \ vertexattrib.c \ + swizzle.c \ vgpu_shaderconv/shaderconv.c \ unordered_map/unordered_map.c \ unordered_map/int_hash.c diff --git a/app/src/main/tinywrapper/egl.c b/app/src/main/tinywrapper/egl.c index 5a45132..c5f41bf 100644 --- a/app/src/main/tinywrapper/egl.c +++ b/app/src/main/tinywrapper/egl.c @@ -30,6 +30,8 @@ static bool init_context(context_t* tw_context) { if(!tw_context->framebuffer_map) goto fail_dealloc; tw_context->program_map = alloc_intmap_safe(); if(!tw_context->program_map) goto fail_dealloc; + tw_context->texture_swztrack_map = alloc_intmap_safe(); + if(!tw_context->texture_swztrack_map) goto fail_dealloc; for(int i = 0; i < MAX_BOUND_BASEBUFFERS; i++) { unordered_map *map = alloc_intmap_safe(); if(!map) goto fail_dealloc; @@ -48,6 +50,8 @@ static bool init_context(context_t* tw_context) { unordered_map_free(tw_context->framebuffer_map); if(tw_context->program_map) unordered_map_free(tw_context->program_map); + if(tw_context->texture_swztrack_map) + unordered_map_free(tw_context->texture_swztrack_map); fail: return false; } @@ -56,6 +60,7 @@ static void free_context(context_t* tw_context) { unordered_map_free(tw_context->shader_map); unordered_map_free(tw_context->program_map); unordered_map_free(tw_context->framebuffer_map); + unordered_map_free(tw_context->texture_swztrack_map); if(tw_context->extensions_string != NULL) free(tw_context->extensions_string); if(tw_context->nextras != 0 && tw_context->extra_extensions_array != NULL) { for(int i = 0; i < tw_context->nextras; i++) { diff --git a/app/src/main/tinywrapper/egl.h b/app/src/main/tinywrapper/egl.h index 60075d5..60faffc 100644 --- a/app/src/main/tinywrapper/egl.h +++ b/app/src/main/tinywrapper/egl.h @@ -14,6 +14,8 @@ #define MAX_BOUND_BASEBUFFERS 4 #define MAX_DRAWBUFFERS 8 #define MAX_FBTARGETS 8 +#define MAX_TMUS 8 +#define MAX_TEXTARGETS 8 typedef struct { bool ready; @@ -48,11 +50,10 @@ typedef struct { } framebuffer_copier_t; typedef struct { - GLint internalformat; - GLenum format; - GLenum type; - GLsizei width, height; -} texture_t; + GLenum original_swizzle[4]; + GLboolean goofy_byte_order; + GLboolean upload_bgra; +} texture_swizzle_track_t; typedef struct { EGLContext phys_context; @@ -65,7 +66,7 @@ typedef struct { unordered_map* shader_map; unordered_map* program_map; unordered_map* framebuffer_map; - unordered_map* texture_map; + unordered_map* texture_swztrack_map; unordered_map* bound_basebuffers[MAX_BOUND_BASEBUFFERS]; int proxy_width, proxy_height, proxy_intformat, maxTextureSize; GLint max_drawbuffers; @@ -81,5 +82,6 @@ typedef struct { extern thread_local context_t *current_context; extern void init_egl(); +extern GLenum get_textarget_query_param(GLenum target); #endif //POJAVLAUNCHER_EGL_H diff --git a/app/src/main/tinywrapper/main.c b/app/src/main/tinywrapper/main.c index b3b4997..ec4e355 100644 --- a/app/src/main/tinywrapper/main.c +++ b/app/src/main/tinywrapper/main.c @@ -12,6 +12,8 @@ #include "egl.h" #include "glformats.h" #include "main.h" +#include "swizzle.h" +#include "libraryinternal.h" void glClearDepth(GLdouble depth) { if(!current_context) return; @@ -58,7 +60,7 @@ void *glMapBuffer(GLenum target, GLenum access) { return es3_functions.glMapBufferRange(target, 0, length, access_range); } -int isProxyTexture(GLenum target) { +INTERNAL int isProxyTexture(GLenum target) { switch (target) { case GL_PROXY_TEXTURE_1D: case GL_PROXY_TEXTURE_2D: @@ -69,6 +71,35 @@ int isProxyTexture(GLenum target) { return 0; } +INTERNAL GLenum get_textarget_query_param(GLenum target) { + switch (target) { + case GL_TEXTURE_2D: + return GL_TEXTURE_BINDING_2D; + case GL_TEXTURE_2D_MULTISAMPLE: + return GL_TEXTURE_BINDING_2D_MULTISAMPLE; + case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: + return GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY; + case GL_TEXTURE_3D: + return GL_TEXTURE_BINDING_3D; + case GL_TEXTURE_2D_ARRAY: + return GL_TEXTURE_BINDING_2D_ARRAY; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP: + return GL_TEXTURE_BINDING_CUBE_MAP; + case GL_TEXTURE_CUBE_MAP_ARRAY: + return GL_TEXTURE_BINDING_CUBE_MAP_ARRAY; + case GL_TEXTURE_BUFFER: + return GL_TEXTURE_BUFFER_BINDING; + default: + return 0; + } +} + static int inline nlevel(int size, int level) { if(size) { size>>=level; @@ -131,15 +162,16 @@ void glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei widt current_context->proxy_height = ((height<current_context->maxTextureSize)?0:height; current_context->proxy_intformat = internalformat; } else { + swizzle_process_upload(target, &format, &type); pick_internalformat(&internalformat, &type, &format, &data); es3_functions.glTexImage2D(target, level, internalformat, width, height, border, format, type, data); } } -bool filter_params_integer(GLenum target, GLenum pname, GLint param) { +INTERNAL bool filter_params_integer(GLenum target, GLenum pname, GLint param) { return true; } -bool filter_params_float(GLenum target, GLenum pname, GLfloat param) { +INTERNAL bool filter_params_float(GLenum target, GLenum pname, GLfloat param) { if(pname == GL_TEXTURE_LOD_BIAS) { if(param != 0.0f) { static bool lodbias_trigger = false; @@ -165,6 +197,7 @@ void glTexParameteri( GLenum target, if(!current_context) return; if(!filter_params_integer(target, pname, param)) return; if(!filter_params_float(target, pname, (GLfloat)param)) return; + swizzle_process_swizzle_param(target, pname, ¶m); switch (pname) { case GL_TEXTURE_MIN_FILTER: case GL_TEXTURE_MAG_FILTER: @@ -188,6 +221,7 @@ void glTexParameteriv( GLenum target, if(!current_context) return; if(!filter_params_integer(target, pname, *params)) return; if(!filter_params_float(target, pname, (GLfloat)*params)) return; + swizzle_process_swizzle_param(target, pname, params); es3_functions.glTexParameteriv(target, pname, params); } static bool trigger_gltexparameteri = false; @@ -202,8 +236,9 @@ void glTexParameterIiv( GLenum target, } return; } - es3_functions.glTexParameteriv(target, pname, params); + swizzle_process_swizzle_param(target, pname, params); } + void glTexParameterIuiv( GLenum target, GLenum pname, const GLuint * params) { @@ -215,7 +250,7 @@ void glTexParameterIuiv( GLenum target, } return; } - es3_functions.glTexParameteriv(target, pname, (const GLint*)params); + swizzle_process_swizzle_param(target, pname, params); } void glRenderbufferStorage( GLenum target, @@ -269,7 +304,7 @@ void glEnable(GLenum cap) { es3_functions.glEnable(cap); } -int get_buffer_index(GLenum buffer) { +INTERNAL int get_buffer_index(GLenum buffer) { switch (buffer) { case GL_ARRAY_BUFFER: return 0; case GL_COPY_READ_BUFFER: return 1; @@ -284,7 +319,7 @@ int get_buffer_index(GLenum buffer) { } } -int get_base_buffer_index(GLenum buffer) { +INTERNAL int get_base_buffer_index(GLenum buffer) { switch (buffer) { case GL_ATOMIC_COUNTER_BUFFER: return 0; case GL_SHADER_STORAGE_BUFFER: return 1; @@ -294,7 +329,7 @@ int get_base_buffer_index(GLenum buffer) { } } -GLenum get_base_buffer_enum(int buffer_index) { +INTERNAL GLenum get_base_buffer_enum(int buffer_index) { switch (buffer_index) { case 0: return GL_ATOMIC_COUNTER_BUFFER; case 1: return GL_SHADER_STORAGE_BUFFER; @@ -387,6 +422,15 @@ void glDepthRange(GLdouble nearVal, es3_functions.glDepthRangef((GLfloat)nearVal, (GLfloat)farVal); } +void glDeleteTextures(GLsizei n, const GLuint *textures) { + if(!current_context) return; + es3_functions.glDeleteTextures(n, textures); + for(int i = 0; i < n; i++) { + void* tracker = unordered_map_remove(current_context->texture_swztrack_map, (void*)textures[i]); + free(tracker); + } +} + void glDebugMessageControl( GLenum source, GLenum type, GLenum severity, diff --git a/app/src/main/tinywrapper/of_buffer_copier.c b/app/src/main/tinywrapper/of_buffer_copier.c index 6893d08..9a8591a 100644 --- a/app/src/main/tinywrapper/of_buffer_copier.c +++ b/app/src/main/tinywrapper/of_buffer_copier.c @@ -4,6 +4,7 @@ #include "proc.h" #include "egl.h" #include +#include "swizzle.h" void buffer_copier_init(context_t* context) { framebuffer_copier_t* copier = &context->framebuffer_copier; while(es3_functions.glGetError() != 0) {} @@ -37,26 +38,11 @@ static void buffer_copier_store(GLint x, GLint y, GLsizei w, GLsizei h) { es3_functions.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, current_context->draw_framebuffer); } -static GLenum get_target_query_param(GLenum target) { - switch (target) { - case GL_TEXTURE_2D: return GL_TEXTURE_BINDING_2D; - case GL_TEXTURE_CUBE_MAP_POSITIVE_X: - case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: - case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: - return GL_TEXTURE_BINDING_CUBE_MAP; - default: - return GL_NONE; - } -} - static void buffer_copier_release(GLenum target, GLint level, GLint x, GLint y, GLsizei w, GLsizei h) { framebuffer_copier_t* copier = ¤t_context->framebuffer_copier; if(!copier->ready) return; GLint current_texbind; - GLenum target_query = get_target_query_param(target); + GLenum target_query = get_textarget_query_param(target); if(target_query == GL_NONE) return; es3_functions.glGetIntegerv(target_query, ¤t_texbind); es3_functions.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, copier->destfb); @@ -77,7 +63,7 @@ void glGetTexImage( GLenum target, if(format != GL_RGBA && format != GL_RGBA_INTEGER && type != GL_UNSIGNED_BYTE && type != GL_UNSIGNED_INT && type != GL_INT && type != GL_FLOAT) goto unsupported; framebuffer_copier_t* copier = ¤t_context->framebuffer_copier; GLint texture; - es3_functions.glGetIntegerv(get_target_query_param(target), &texture); + es3_functions.glGetIntegerv(get_textarget_query_param(target), &texture); es3_functions.glBindFramebuffer(GL_READ_FRAMEBUFFER, copier->tempfb); es3_functions.glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, texture, level); GLint w, h; @@ -116,6 +102,7 @@ void glTexSubImage2D(GLenum target, GLenum type, const void * data) { if(!current_context) return; + swizzle_process_upload(target, &format, &type); if(format == GL_DEPTH_COMPONENT) { framebuffer_copier_t* copier = ¤t_context->framebuffer_copier; if(width == copier->depthWidth && height == copier->depthHeight && copier->depthData == data) { @@ -141,7 +128,7 @@ void glCopyTexSubImage2D(GLenum target, framebuffer_copier_t* copier = ¤t_context->framebuffer_copier; if(!copier->ready) return; GLint texture; - es3_functions.glGetIntegerv(get_target_query_param(target), &texture); + es3_functions.glGetIntegerv(get_textarget_query_param(target), &texture); es3_functions.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, copier->destfb); es3_functions.glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, target, texture, level); es3_functions.glBlitFramebuffer(x, y, width+x, height+y, xoffset, yoffset, width+xoffset, height+yoffset, GL_DEPTH_BUFFER_BIT, GL_NEAREST); diff --git a/app/src/main/tinywrapper/swizzle.c b/app/src/main/tinywrapper/swizzle.c new file mode 100644 index 0000000..2b0a74c --- /dev/null +++ b/app/src/main/tinywrapper/swizzle.c @@ -0,0 +1,102 @@ +// +// Created by maks on 30.11.2024. +// +#include "proc.h" +#include "egl.h" +#include +#include "libraryinternal.h" +//#include + +#define GL_TEXTURE_SWIZZLE_RGBA 0x8E46 + +static void swizzle_process_bgra(GLenum* swizzle) { + GLenum red_src = swizzle[0]; + GLenum blue_src = swizzle[2]; + swizzle[0] = blue_src; + swizzle[2] = red_src; +} + +static void swizzle_process_endianness(GLenum* swizzle) { + GLenum orig_swizzle[4]; + memcpy(orig_swizzle, swizzle, 4 * sizeof(GLenum)); + swizzle[0] = orig_swizzle[3]; + swizzle[1] = orig_swizzle[2]; + swizzle[2] = orig_swizzle[1]; + swizzle[3] = orig_swizzle[0]; +} + +static texture_swizzle_track_t* get_swizzle_track(GLenum target) { + GLint texture; + GLenum getter = get_textarget_query_param(target); + if(getter == 0) return NULL; + es3_functions.glGetIntegerv(getter, &texture); + texture_swizzle_track_t* track = unordered_map_get(current_context->texture_swztrack_map, (void*)texture); + if(track == NULL) { + track = malloc(sizeof(texture_swizzle_track_t)); + es3_functions.glGetTexParameteriv(target, GL_TEXTURE_SWIZZLE_R, (GLint*)&track->original_swizzle[0]); + es3_functions.glGetTexParameteriv(target, GL_TEXTURE_SWIZZLE_G, (GLint*)&track->original_swizzle[1]); + es3_functions.glGetTexParameteriv(target, GL_TEXTURE_SWIZZLE_B, (GLint*)&track->original_swizzle[2]); + es3_functions.glGetTexParameteriv(target, GL_TEXTURE_SWIZZLE_A, (GLint*)&track->original_swizzle[3]); + unordered_map_put(current_context->texture_swztrack_map, (void*)texture, track); + } + return track; +} + +static void apply_swizzles(GLenum target, texture_swizzle_track_t* track) { + GLenum new_swizzle[4]; + memcpy(new_swizzle, track->original_swizzle, 4 * sizeof(GLenum)); + if(track->goofy_byte_order) swizzle_process_endianness(new_swizzle); + if(track->upload_bgra) swizzle_process_bgra(new_swizzle); + es3_functions.glTexParameteri(target, GL_TEXTURE_SWIZZLE_R, new_swizzle[0]); + es3_functions.glTexParameteri(target, GL_TEXTURE_SWIZZLE_G, new_swizzle[1]); + es3_functions.glTexParameteri(target, GL_TEXTURE_SWIZZLE_B, new_swizzle[2]); + es3_functions.glTexParameteri(target, GL_TEXTURE_SWIZZLE_A, new_swizzle[3]); +} + +INTERNAL void swizzle_process_upload(GLenum target, GLenum* format, GLenum* type) { + texture_swizzle_track_t* track = get_swizzle_track(target); + if(track == NULL) return; + bool apply_upload_bgra = false; + bool apply_goofy_order = false; + if((*format) == GL_BGRA_EXT) { + apply_upload_bgra = true; + *format = GL_RGBA; + } + if((*type) == 0x8035) { + apply_goofy_order = true; + *type = GL_UNSIGNED_BYTE; + } + if(apply_goofy_order != track->goofy_byte_order || apply_upload_bgra != track->upload_bgra) { + track->goofy_byte_order = apply_goofy_order; + track->upload_bgra = apply_upload_bgra; + apply_swizzles(target, track); + } +} + +INTERNAL void swizzle_process_swizzle_param(GLenum target, GLenum swizzle_param, const GLenum* swizzle) { + switch (swizzle_param) { + case GL_TEXTURE_SWIZZLE_R: + case GL_TEXTURE_SWIZZLE_G: + case GL_TEXTURE_SWIZZLE_B: + case GL_TEXTURE_SWIZZLE_A: + case GL_TEXTURE_SWIZZLE_RGBA: + break; + default: + return; + } + texture_swizzle_track_t* track = get_swizzle_track(target); + if(track == NULL) return; + switch(swizzle_param) { + case GL_TEXTURE_SWIZZLE_R: + case GL_TEXTURE_SWIZZLE_G: + case GL_TEXTURE_SWIZZLE_B: + case GL_TEXTURE_SWIZZLE_A: + track->original_swizzle[swizzle_param - GL_TEXTURE_SWIZZLE_R] = *swizzle; + apply_swizzles(target, track); + break; + case GL_TEXTURE_SWIZZLE_RGBA: + memcpy(track->original_swizzle, swizzle, 4 * sizeof(GLenum)); + apply_swizzles(target, track); + break; + } +} \ No newline at end of file diff --git a/app/src/main/tinywrapper/swizzle.h b/app/src/main/tinywrapper/swizzle.h new file mode 100644 index 0000000..577e945 --- /dev/null +++ b/app/src/main/tinywrapper/swizzle.h @@ -0,0 +1,13 @@ +// +// Created by maks on 30.11.2024. +// + +#ifndef GL4ES_WRAPPER_SWIZZLE_H +#define GL4ES_WRAPPER_SWIZZLE_H + +#include "egl.h" + +void swizzle_process_upload(GLenum target, GLenum *format, GLenum *type); +void swizzle_process_swizzle_param(GLenum target, GLenum swizzle_param, const GLenum* swizzle); + +#endif //GL4ES_WRAPPER_SWIZZLE_H