Implement swizzler for BGRA/"wrong order" uploads

This commit is contained in:
artdeell 2024-12-02 17:41:38 +03:00
parent 10e68400ed
commit 75abce1b80
8 changed files with 187 additions and 32 deletions

View File

@ -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();

View File

@ -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

View File

@ -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++) {

View File

@ -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

View File

@ -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<<level)>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, &param);
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,

View File

@ -4,6 +4,7 @@
#include "proc.h"
#include "egl.h"
#include <stdbool.h>
#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 = &current_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, &current_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 = &current_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 = &current_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 = &current_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);

View File

@ -0,0 +1,102 @@
//
// Created by maks on 30.11.2024.
//
#include "proc.h"
#include "egl.h"
#include <string.h>
#include "libraryinternal.h"
//#include <GL/glext.h>
#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;
}
}

View File

@ -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