diff --git a/ltw/src/main/tinywrapper/Android.mk b/ltw/src/main/tinywrapper/Android.mk index 1b13df0..3eba31a 100644 --- a/ltw/src/main/tinywrapper/Android.mk +++ b/ltw/src/main/tinywrapper/Android.mk @@ -383,6 +383,7 @@ LOCAL_CFLAGS += -DHAVE_OPENGL LOCAL_CFLAGS += -DHAVE_OPENGL_ES_1 LOCAL_CFLAGS += -DHAVE_OPENGL_ES_2 LOCAL_CFLAGS += -fvisibility=hidden +LOCAL_LDFLAGS := -ffunction-sections -fdata-sections include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) @@ -402,9 +403,13 @@ LOCAL_SRC_FILES := \ vertexattrib.c \ swizzle.c \ license_notice.c \ + env.c \ vgpu_shaderconv/shaderconv.c \ unordered_map/unordered_map.c \ unordered_map/int_hash.c LOCAL_STATIC_LIBRARIES := glsl_optimizer +LOCAL_LDFLAGS := -ffunction-sections -fdata-sections -Wl,--version-script=$(LOCAL_PATH)/version.script +# Comment for debugging +LOCAL_LDFLAGS += -flto -Wl,--gc-sections LOCAL_LDLIBS := -llog -lEGL include $(BUILD_SHARED_LIBRARY) \ No newline at end of file diff --git a/ltw/src/main/tinywrapper/basevertex.c b/ltw/src/main/tinywrapper/basevertex.c index bfff4ae..0d37598 100644 --- a/ltw/src/main/tinywrapper/basevertex.c +++ b/ltw/src/main/tinywrapper/basevertex.c @@ -1,6 +1,6 @@ /** * Created by: artDev - * Copyright (c) 2025 artDev, SerpentSpirale, PojavLauncherTeam, Digital Genesis LLC. + * Copyright (c) 2025 artDev, SerpentSpirale, CADIndie. * For use under LGPL-3.0 */ #include diff --git a/ltw/src/main/tinywrapper/basevertex.h b/ltw/src/main/tinywrapper/basevertex.h index 7703644..bd9a215 100644 --- a/ltw/src/main/tinywrapper/basevertex.h +++ b/ltw/src/main/tinywrapper/basevertex.h @@ -1,6 +1,6 @@ /** * Created by: artDev - * Copyright (c) 2025 artDev, SerpentSpirale, PojavLauncherTeam, Digital Genesis LLC. + * Copyright (c) 2025 artDev, SerpentSpirale, CADIndie. * For use under LGPL-3.0 */ diff --git a/ltw/src/main/tinywrapper/egl.c b/ltw/src/main/tinywrapper/egl.c index 9264023..81a00e0 100644 --- a/ltw/src/main/tinywrapper/egl.c +++ b/ltw/src/main/tinywrapper/egl.c @@ -1,11 +1,12 @@ /** * Created by: artDev - * Copyright (c) 2025 artDev, SerpentSpirale, PojavLauncherTeam, Digital Genesis LLC. + * Copyright (c) 2025 artDev, SerpentSpirale, CADIndie. * For use under LGPL-3.0 */ #include "egl.h" #include "unordered_map/int_hash.h" #include "string_utils.h" +#include "env.h" #include thread_local context_t *current_context; @@ -110,7 +111,12 @@ void build_extension_string(context_t* context) { int length; init_extra_extensions(context, &length); if(context->buffer_storage) { - add_extra_extension(context, &length, "GL_ARB_buffer_storage"); + if(!env_istrue("LTW_HIDE_BUFFER_STORAGE")) + add_extra_extension(context, &length, "GL_ARB_buffer_storage"); + else printf("LTW: The buffer storage extension is hidden.\n"); + } + if(context->buffer_texture_ext || context->es32) { + add_extra_extension(context, &length, "ARB_texture_buffer_object"); } // More extensions are possible, but will need way more wraps and tracking. fin_extra_extensions(context, length); @@ -139,6 +145,7 @@ static void find_esversion(context_t* context) { const char* extensions = (const char*) es3_functions.glGetString(GL_EXTENSIONS); if(strstr(extensions, "GL_EXT_buffer_storage")) context->buffer_storage = true; + if(strstr(extensions, "GL_EXT_texture_buffer")) context->buffer_texture_ext = true; build_extension_string(context); diff --git a/ltw/src/main/tinywrapper/egl.h b/ltw/src/main/tinywrapper/egl.h index b10dac7..f4a5695 100644 --- a/ltw/src/main/tinywrapper/egl.h +++ b/ltw/src/main/tinywrapper/egl.h @@ -1,6 +1,6 @@ /** * Created by: artDev - * Copyright (c) 2025 artDev, SerpentSpirale, PojavLauncherTeam, Digital Genesis LLC. + * Copyright (c) 2025 artDev, SerpentSpirale, CADIndie. * For use under LGPL-3.0 */ @@ -60,7 +60,8 @@ typedef struct { typedef struct { EGLContext phys_context; bool context_rdy; - bool es31, es32, buffer_storage; + bool es31, es32, buffer_storage, buffer_texture_ext; + bool force_depth32_fallback; GLint shader_version; basevertex_renderer_t basevertex; GLuint multidraw_element_buffer; diff --git a/ltw/src/main/tinywrapper/env.c b/ltw/src/main/tinywrapper/env.c new file mode 100644 index 0000000..507692a --- /dev/null +++ b/ltw/src/main/tinywrapper/env.c @@ -0,0 +1,17 @@ +// +// Created by maks on 12.07.2025. +// +#include "env.h" +#include +#include "libraryinternal.h" + +INTERNAL bool env_istrue_d(const char* name, bool _default) { + const char* env = getenv(name); + if(env == NULL) return _default; + return *env == '1'; +} + +INTERNAL bool env_istrue(const char* name) { + const char* env = getenv(name); + return env != NULL && *env == '1'; +} \ No newline at end of file diff --git a/ltw/src/main/tinywrapper/env.h b/ltw/src/main/tinywrapper/env.h new file mode 100644 index 0000000..ed75b62 --- /dev/null +++ b/ltw/src/main/tinywrapper/env.h @@ -0,0 +1,13 @@ +// +// Created by maks on 12.07.2025. +// + +#ifndef GL4ES_WRAPPER_ENV_H +#define GL4ES_WRAPPER_ENV_H + +#include + +bool env_istrue(const char* name); +bool env_istrue_d(const char* name, bool _default); + +#endif //GL4ES_WRAPPER_ENV_H diff --git a/ltw/src/main/tinywrapper/es3_extended.h b/ltw/src/main/tinywrapper/es3_extended.h index 6068671..8765d0b 100644 --- a/ltw/src/main/tinywrapper/es3_extended.h +++ b/ltw/src/main/tinywrapper/es3_extended.h @@ -1,6 +1,6 @@ /** * Created by: artDev - * Copyright (c) 2025 artDev, SerpentSpirale, PojavLauncherTeam, Digital Genesis LLC. + * Copyright (c) 2025 artDev, SerpentSpirale, CADIndie. * For use under LGPL-3.0 */ @@ -11,4 +11,8 @@ GLESFUNC(glMultiDrawElementsEXT,PFNGLMULTIDRAWELEMENTSEXTPROC) GLESFUNC(glGetTexLevelParameteriv,PFNGLGETTEXLEVELPARAMETERIVPROC) GLESFUNC(glGetTexLevelParameterfv,PFNGLGETTEXLEVELPARAMETERFVPROC) GLESFUNC(glDrawElementsBaseVertex, PFNGLDRAWELEMENTSBASEVERTEXPROC) -GLESFUNC(glBufferStorageEXT, PFNGLBUFFERSTORAGEEXTPROC) \ No newline at end of file +GLESFUNC(glBufferStorageEXT, PFNGLBUFFERSTORAGEEXTPROC) +GLESFUNC(glTexBuffer, PFNGLTEXBUFFERPROC); +GLESFUNC(glTexBufferRange, PFNGLTEXBUFFERRANGEPROC); +GLESFUNC(glTexBufferEXT, PFNGLTEXBUFFEREXTPROC) +GLESFUNC(glTexBufferRangeEXT, PFNGLTEXBUFFERRANGEEXTPROC) \ No newline at end of file diff --git a/ltw/src/main/tinywrapper/es3_functions.h b/ltw/src/main/tinywrapper/es3_functions.h index 90fdf82..91ca264 100644 --- a/ltw/src/main/tinywrapper/es3_functions.h +++ b/ltw/src/main/tinywrapper/es3_functions.h @@ -1,6 +1,6 @@ /** * Created by: artDev - * Copyright (c) 2025 artDev, SerpentSpirale, PojavLauncherTeam, Digital Genesis LLC. + * Copyright (c) 2025 artDev, SerpentSpirale, CADIndie. * For use under LGPL-3.0 */ diff --git a/ltw/src/main/tinywrapper/es3_overrides.h b/ltw/src/main/tinywrapper/es3_overrides.h index b89ec33..67f1115 100644 --- a/ltw/src/main/tinywrapper/es3_overrides.h +++ b/ltw/src/main/tinywrapper/es3_overrides.h @@ -1,6 +1,6 @@ /** * Created by: artDev - * Copyright (c) 2025 artDev, SerpentSpirale, PojavLauncherTeam, Digital Genesis LLC. + * Copyright (c) 2025 artDev, SerpentSpirale, CADIndie. * For use under LGPL-3.0 */ void glClearDepth(double depth); @@ -40,6 +40,11 @@ GLESOVERRIDE(glGetTexLevelParameteriv) GLESOVERRIDE(glGetTexLevelParameterfv) GLESOVERRIDE(glCreateShader) GLESOVERRIDE(glDeleteShader) +GLESOVERRIDE(glCreateProgram) +GLESOVERRIDE(glDeleteProgram) +GLESOVERRIDE(glLinkProgram) +GLESOVERRIDE(glAttachShader) +GLESOVERRIDE(glGetShaderiv) GLESOVERRIDE(glShaderSource) GLESOVERRIDE(glTexImage2D) GLESOVERRIDE(glDebugMessageControl) @@ -61,6 +66,7 @@ GLESOVERRIDE(glFramebufferTextureLayer) GLESOVERRIDE(glFramebufferRenderbuffer) GLESOVERRIDE(glGetFramebufferAttachmentParameteriv) GLESOVERRIDE(glDrawBuffers) +GLESOVERRIDE(glDrawBuffer) GLESOVERRIDE(glClearBufferiv) GLESOVERRIDE(glClearBufferuiv) GLESOVERRIDE(glClearBufferfv) @@ -121,4 +127,8 @@ GLESOVERRIDE(glTexParameteriv) GLESOVERRIDE(glTexParameterIiv) GLESOVERRIDE(glTexParameterIuiv) GLESOVERRIDE(glRenderbufferStorage) -GLESOVERRIDE(glGetError) \ No newline at end of file +GLESOVERRIDE(glGetError) +GLESOVERRIDE(glTexBuffer) +GLESOVERRIDE(glTexBufferRange) +GLESOVERRIDE(glMapBufferRange) +GLESOVERRIDE(glFlushMappedBufferRange) \ No newline at end of file diff --git a/ltw/src/main/tinywrapper/framebuffer.c b/ltw/src/main/tinywrapper/framebuffer.c index 2222d30..10691b2 100644 --- a/ltw/src/main/tinywrapper/framebuffer.c +++ b/ltw/src/main/tinywrapper/framebuffer.c @@ -1,6 +1,6 @@ /** * Created by: artDev - * Copyright (c) 2025 artDev, SerpentSpirale, PojavLauncherTeam, Digital Genesis LLC. + * Copyright (c) 2025 artDev, SerpentSpirale, CADIndie. * For use under LGPL-3.0 */ diff --git a/ltw/src/main/tinywrapper/glformats.c b/ltw/src/main/tinywrapper/glformats.c index 8c91974..262a041 100644 --- a/ltw/src/main/tinywrapper/glformats.c +++ b/ltw/src/main/tinywrapper/glformats.c @@ -1,10 +1,11 @@ /** * Created by: artDev - * Copyright (c) 2025 artDev, SerpentSpirale, PojavLauncherTeam, Digital Genesis LLC. + * Copyright (c) 2025 artDev, SerpentSpirale, CADIndie. * For use under LGPL-3.0 */ #include +#include "egl.h" #include "glformats.h" #include "libraryinternal.h" #include "GL/gl.h" @@ -71,12 +72,58 @@ static GLint pick_rg_internalformat(GLenum* type, bool* convert) { } } -void pick_color_renderable_format(GLint* internalformat, GLenum* type, GLenum* format) { - -} +void pick_format(GLint *internalformat, GLenum* type, GLenum* format) { + // Workarounds! + switch (*internalformat) { + // Two legacy GL formats. From testing, OptiFine wants these to be floats. + case GL_RGBA12: + case GL_RGBA16: + *internalformat = GL_RGBA16F; + break; + // Always use 32-bit float depth for GL_DEPTH_COMPONENT, because the 16-bit depth buffer + // causes z-fighting in the distance + case GL_DEPTH_COMPONENT: + *internalformat = GL_DEPTH_COMPONENT32F; + break; + // This appears to be one of the legacy formats from the FPE days, and is not even + // listed in the format tables in 3.3 core. Still, MC uses it for the depth buffers. + case GL_DEPTH_COMPONENT32: + *internalformat = GL_DEPTH_COMPONENT32F; + break; + // Unsized depth-stencil. Not sure what uses it but we'll fall back to 24-bit + 8-bit stencil + case GL_DEPTH_STENCIL: + *internalformat = GL_DEPTH24_STENCIL8; + break; + // Color-renderability workarounds. Yes, those probably decrease performance but they sure do improve compatibility with shaderpacks! + // Ideally these should only be used on framebuffers, but whatever. + // In GL, the SNORM formats are color-renderable and support signed normalized values from -1 to 1. + // Sadly, the only alternative format with the same capabilities that *is* color-renderable in ES is 16-bit float. + // So, switch to that. + case GL_R8_SNORM: + *internalformat = GL_R16F; + case GL_RG8_SNORM: + *internalformat = GL_RG16F; + case GL_RGBA8_SNORM: + *internalformat = GL_RGBA16F; + break; + // Fun fact: the only color renderable formats in GLES that have 3 components are + // GL_R11F_G11F_B10F and GL_RGB8. And only GL_R11F_G11F_B10F supports signed values. + case GL_RGB8I: + case GL_RGB16I: + case GL_RGB32I: + case GL_RGB8_SNORM: + case GL_RGB12: + case GL_RGB16: + case GL_RGB16F: + case GL_RGB32F: + *internalformat = GL_R11F_G11F_B10F; + case GL_RGB8UI: + *internalformat = GL_RGB8; + break; + } -void pick_format(GLint internalformat, GLenum* type, GLenum* format) { - switch (internalformat) { + // GLES 3.2 format table + switch (*internalformat) { // Unsized formats. In this case we always prefer the "byte" versions of them (meaning 32bit/24bit color) case GL_RGB: *format=GL_RGB; *type = GL_UNSIGNED_BYTE; break; case GL_RGBA: *format=GL_RGBA; *type = GL_UNSIGNED_BYTE; break; @@ -133,25 +180,33 @@ void pick_format(GLint internalformat, GLenum* type, GLenum* format) { case GL_RGBA16I: *format=GL_RGBA_INTEGER; *type=GL_SHORT; break; case GL_RGBA32I: *format=GL_RGBA_INTEGER; *type=GL_INT; break; case GL_RGBA32UI: *format=GL_RGBA_INTEGER; *type=GL_UNSIGNED_INT; break; - // Sized depth formats. Unsized formats handled before this function + // Sized depth formats case GL_DEPTH_COMPONENT16: *format = GL_DEPTH_COMPONENT; *type = GL_UNSIGNED_SHORT; break; case GL_DEPTH_COMPONENT24: *format = GL_DEPTH_COMPONENT; *type = GL_UNSIGNED_INT; break; case GL_DEPTH_COMPONENT32F: *format = GL_DEPTH_COMPONENT; *type = GL_FLOAT; break; case GL_DEPTH24_STENCIL8: *format = GL_DEPTH_STENCIL; *type = GL_UNSIGNED_INT_24_8; break; case GL_DEPTH32F_STENCIL8: *format = GL_DEPTH_STENCIL; *type = GL_FLOAT_32_UNSIGNED_INT_24_8_REV; break; case GL_STENCIL_INDEX8: *format = GL_STENCIL_INDEX; *type = GL_UNSIGNED_BYTE; break; + default: + printf("LTW: pick_format fallthrough: %x\n", *internalformat); } + } INTERNAL void pick_internalformat(GLint *internalformat, GLenum* type, GLenum* format, GLvoid const** data) { + if(*data == NULL) { + // Appears that desktop GL completely discards type and format without data. Pick a correct (sized if unsized is unavailable) + // format for the d + pick_format(internalformat, type, format); + return; + } // Compared to OpenGL ES, desktop OpenGL implicitly supports way more depth/RGB formats without explicit sizing. // This function converts appropriate unsized formats to sized ones according to the type. bool convert_data; switch (*internalformat) { case GL_DEPTH_COMPONENT32: - // 1.21.5 workaround: fix internalformat (not handled in ES drivers cause it's from GL 1.4) - // Work around by selecting the equivalent type (for float) or 24-bit (for int) + // Select the equivalent type (32f for float, 24 for int) if(*type == GL_FLOAT) { *internalformat = GL_DEPTH_COMPONENT32F; } else { @@ -264,12 +319,6 @@ INTERNAL void pick_internalformat(GLint *internalformat, GLenum* type, GLenum* f } break; } - // GL applications do not have to supply valid data to "type" and "format" fields if they are not uploading any data - // So automatically pick the best options from ones available. - if(*data == NULL) { - pick_format(*internalformat, type, format); - return; - } if(*data != NULL && convert_data) { printf("LTW: we don't support format conversion at the moment. Sorry!\n"); } diff --git a/ltw/src/main/tinywrapper/glformats.h b/ltw/src/main/tinywrapper/glformats.h index d632f7d..5b8ae5a 100644 --- a/ltw/src/main/tinywrapper/glformats.h +++ b/ltw/src/main/tinywrapper/glformats.h @@ -1,6 +1,6 @@ /** * Created by: artDev - * Copyright (c) 2025 artDev, SerpentSpirale, PojavLauncherTeam, Digital Genesis LLC. + * Copyright (c) 2025 artDev, SerpentSpirale, CADIndie. * For use under LGPL-3.0 */ diff --git a/ltw/src/main/tinywrapper/glsl_optimizer/src/code/GlslConvert.cpp b/ltw/src/main/tinywrapper/glsl_optimizer/src/code/GlslConvert.cpp index 3ab4f87..bdf7e39 100644 --- a/ltw/src/main/tinywrapper/glsl_optimizer/src/code/GlslConvert.cpp +++ b/ltw/src/main/tinywrapper/glsl_optimizer/src/code/GlslConvert.cpp @@ -388,7 +388,9 @@ void GlslConvert::InitContext(struct gl_context* ctx, ApiTarget api, int vGlslVe ctx->Const.Program[MESA_SHADER_COMPUTE].MaxAtomicBuffers = 8; ctx->Const.Program[MESA_SHADER_COMPUTE].MaxAtomicCounters = 8; ctx->Const.Program[MESA_SHADER_COMPUTE].MaxImageUniforms = 8; - ctx->Const.Program[MESA_SHADER_COMPUTE].MaxUniformBlocks = 12; + ctx->Const.Program[MESA_SHADER_COMPUTE].MaxUniformBlocks = 64; + ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxUniformBlocks = 64; + ctx->Const.Program[MESA_SHADER_VERTEX].MaxUniformBlocks = 64; switch (ctx->Const.GLSLVersion) { case 100: @@ -505,7 +507,6 @@ void GlslConvert::InitContext(struct gl_context* ctx, ApiTarget api, int vGlslVe ctx->Const.Program[MESA_SHADER_VERTEX].MaxCombinedUniformComponents = 1024; ctx->Const.Program[MESA_SHADER_VERTEX].MaxInputComponents = 0; /* not used */ ctx->Const.Program[MESA_SHADER_VERTEX].MaxOutputComponents = 64; - ctx->Const.Program[MESA_SHADER_VERTEX].MaxUniformBlocks = 4; ctx->Const.Program[MESA_SHADER_GEOMETRY].MaxTextureImageUnits = 16; ctx->Const.Program[MESA_SHADER_GEOMETRY].MaxUniformComponents = 1024; @@ -513,7 +514,6 @@ void GlslConvert::InitContext(struct gl_context* ctx, ApiTarget api, int vGlslVe ctx->Const.Program[MESA_SHADER_GEOMETRY].MaxInputComponents = ctx->Const.Program[MESA_SHADER_VERTEX].MaxOutputComponents; ctx->Const.Program[MESA_SHADER_GEOMETRY].MaxOutputComponents = 128; - ctx->Const.Program[MESA_SHADER_GEOMETRY].MaxUniformBlocks = 4; ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxTextureImageUnits = 16; ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxUniformComponents = 1024; @@ -521,7 +521,6 @@ void GlslConvert::InitContext(struct gl_context* ctx, ApiTarget api, int vGlslVe ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxInputComponents = ctx->Const.Program[MESA_SHADER_GEOMETRY].MaxOutputComponents; ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxOutputComponents = 0; /* not used */ - ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxUniformBlocks = 4; ctx->Const.MaxCombinedTextureImageUnits = ctx->Const.Program[MESA_SHADER_VERTEX].MaxTextureImageUnits diff --git a/ltw/src/main/tinywrapper/glsl_optimizer/src/code/ir_print_glsl_visitor.cpp b/ltw/src/main/tinywrapper/glsl_optimizer/src/code/ir_print_glsl_visitor.cpp index 481a49e..264f3bc 100644 --- a/ltw/src/main/tinywrapper/glsl_optimizer/src/code/ir_print_glsl_visitor.cpp +++ b/ltw/src/main/tinywrapper/glsl_optimizer/src/code/ir_print_glsl_visitor.cpp @@ -8,6 +8,7 @@ #include "../util/macros.h" #include "../util/hash_table.h" #include "../util/u_string.h" +#include "../compiler/glsl/ast.h" const char* const precision[] = { "", "highp ", "mediump ", "lowp " }; @@ -125,6 +126,89 @@ void IR_TO_GLSL::print_type_post(sbuffer& str, const glsl_type* t, bool arraySiz } } +const char* str_primtype(GLenum type, bool out) { + if(!out) switch (type) { + case GL_POINTS: return "points"; + case GL_LINE_STRIP: + case GL_LINES: return "lines"; + case GL_LINE_STRIP_ADJACENCY: + case GL_LINES_ADJACENCY: return "lines_adjacency"; + case GL_TRIANGLE_STRIP: + case GL_TRIANGLE_FAN: + case GL_TRIANGLES: return "triangles"; + case GL_TRIANGLE_STRIP_ADJACENCY: + case GL_TRIANGLES_ADJACENCY: return "triangles_adjacency"; + default: + printf("Unhandled geom shader input primtype: %x\n", type); + return "unknown"; + } + else switch(type) { + case GL_POINTS: return "points"; + case GL_LINE_STRIP: return "line_strip"; + case GL_TRIANGLE_STRIP: return "triangle_strip"; + default: + printf("Unhandled geom shader output primtype: %x\n", type); + return "unknown"; + } +} + +bool should_print_layout(const ast_type_qualifier* qual) { + return qual->flags.q.prim_type || + qual->flags.q.max_vertices || + qual->flags.q.local_size; +} + +void print_layout(sbuffer& str, struct _mesa_glsl_parse_state* state, ast_type_qualifier* qual, bool out) { + bool first = true; +#define I_LAYOUT_QUALIFIER(cmp_op, block) \ + if(cmp_op) { \ + if(!first) str.append(","); \ + else first = false; \ + block \ + } +#define LAYOUT_QUALIFIER(name, block) I_LAYOUT_QUALIFIER(qual->flags.q.name, block) +#define LAYOUT_QUALIFIER_MASK(name, bit, block) I_LAYOUT_QUALIFIER(qual->flags.q.name & (bit), block) + str.append("layout("); + LAYOUT_QUALIFIER(prim_type,{ + str.append("%s", str_primtype(qual->prim_type, out)); + }) + LAYOUT_QUALIFIER(max_vertices,{ + unsigned qual_max_vertices = !0; + qual->max_vertices->process_qualifier_constant(state, "max_vertices", + &qual_max_vertices, true); + str.append("max_vertices=%u", qual_max_vertices); + }) + LAYOUT_QUALIFIER_MASK(local_size, 1 << 0, { + str.append("local_size_x=", state->cs_input_local_size[0]); + }) + LAYOUT_QUALIFIER_MASK(local_size, 1 << 1, { + str.append("local_size_y=", state->cs_input_local_size[1]); + }) + LAYOUT_QUALIFIER_MASK(local_size, 1 << 2, { + str.append("local_size_z=", state->cs_input_local_size[2]); + }) + str.append(") "); +} + +void nan_check_warn() { + static bool warned = false; + if(warned) return; + printf("LTW shader optimizer will emit NaN checks for fragment outputs. This may lead to loss of performance.\n"); + warned = true; +} + +void print_nan_check_funcs(sbuffer& str) { + nan_check_warn(); + const char* nan_check_func = + "%1$s _ltw_removenan(%1$s colorVal) {\n" + " return mix(colorVal, %1$s(%2$s), isnan(colorVal));\n" + "}\n"; + str.append(nan_check_func, "float", "0.0"); + str.append(nan_check_func, "vec2", "0.0,0.0"); + str.append(nan_check_func, "vec3", "0.0,0.0,0.0"); + str.append(nan_check_func, "vec4", "0.0,0.0,0.0,1.0"); +} + // DANGER, the function allocates a new string // DO NOT FORGET TO FREE IT char * IR_TO_GLSL::Convert( @@ -132,6 +216,7 @@ char * IR_TO_GLSL::Convert( struct _mesa_glsl_parse_state* state) { sbuffer res; + bool shader_nan_check = false; if (state) { @@ -173,11 +258,35 @@ char * IR_TO_GLSL::Convert( res.append("#extension GL_EXT_texture_array : enable\n"); // Search for internal GL variables and enable extensions based on them + bool uses_buffer_sampler = false; + bool sampler2d_highp = false; foreach_in_list(ir_instruction, ir, instructions) { // Skip non-variables if(ir->ir_type != ir_type_variable) continue; auto* var = (ir_variable*)ir; + + const char* type = var->type->name; + if(type != nullptr) { + // Check for buffer texture samplers. Need to enable (and/or set precision) for them + if(!uses_buffer_sampler && (strstr(type, "samplerBuffer") != nullptr || strstr(type, "imageBuffer") != nullptr)) { + uses_buffer_sampler = true; + if(state->es_shader && state->language_version < 320) { + res.append("#extension GL_EXT_texture_buffer : enable\n"); + } + } + // Check if shampler2DShadow is used in this shader. If yes, we need to explicitly enable high + // precision for all 2D samplers, to make shadows on Mali look good. + if(!sampler2d_highp && (strstr(type, "sampler2DShadow") != nullptr)) { + sampler2d_highp = true; + } + } + // Check for interpolation type. Need to enable the noperspective interpolation extension + // if used. + if(var->data.interpolation == glsl_interp_mode::INTERP_MODE_NOPERSPECTIVE && !state->NV_shader_noperspective_interpolation_enable) { + state->NV_shader_noperspective_interpolation_enable = true; + res.append("#extension GL_NV_shader_noperspective_interpolation : enable\n"); + } // Skip non-internal variables if(strstr(var->name, "gl_") != var->name) continue; const char* name = var->name; @@ -190,12 +299,16 @@ char * IR_TO_GLSL::Convert( } if(print_precision) { - res.append("precision %s float;\nprecision %s int;\n", "highp", "highp"); + const char* sampler2d_precision = "lowp"; + if(sampler2d_highp) sampler2d_precision = "highp"; + res.append("precision %1$s float;\n" + "precision %1$s int;\n" + "precision %2$s sampler2D;\n", "highp", sampler2d_precision); res.append("precision %1$s sampler3D;\n" "precision %1$s samplerCubeShadow;\n" - "precision %1$s sampler2DShadow;\n" - "precision %1$s sampler2DArray;\n" - "precision %1$s sampler2DArrayShadow;\n" + "precision %2$s sampler2DShadow;\n" + "precision %2$s sampler2DArray;\n" + "precision %2$s sampler2DArrayShadow;\n" "precision %1$s isampler2D;\n" "precision %1$s isampler3D;\n" "precision %1$s isamplerCube;\n" @@ -203,7 +316,15 @@ char * IR_TO_GLSL::Convert( "precision %1$s usampler2D;\n" "precision %1$s usampler3D;\n" "precision %1$s usamplerCube;\n" - "precision %1$s usampler2DArray;\n", "lowp"); + "precision %1$s usampler2DArray;\n", "lowp", sampler2d_precision); + if(uses_buffer_sampler) { + res.append("precision %1$s samplerBuffer;\n" + "precision %1$s isamplerBuffer;\n" + "precision %1$s usamplerBuffer;\n" + "precision %1$s imageBuffer;\n" + "precision %1$s iimageBuffer;\n" + "precision %1$s uimageBuffer;\n", "lowp"); + } } for (unsigned i = 0; i < state->num_user_structures; i++) @@ -219,9 +340,24 @@ char * IR_TO_GLSL::Convert( } res.append("};\n"); } + if(should_print_layout(state->in_qualifier)) { + print_layout(res, state, state->in_qualifier, false); + res.append("in;\n"); + } + if(should_print_layout(state->out_qualifier)) { + print_layout(res, state, state->out_qualifier, true); + res.append("out;\n"); + } + const char* nan_check_env = getenv("LTW_SHADERCONV_CHECKNAN"); + bool emit_nan_check = nan_check_env != nullptr && *nan_check_env == '1'; + if(emit_nan_check && state->stage == MESA_SHADER_FRAGMENT) { + print_nan_check_funcs(res); + shader_nan_check = true; + } } global_print_tracker global; + global.enable_nan_check = shader_nan_check; int uses_texlod_impl = 0; int uses_texlodproj_impl = 0; loop_state* ls = analyze_loop_variables(instructions); @@ -263,9 +399,6 @@ char * IR_TO_GLSL::Convert( return res.c_str_take_ownership(); } -const char* IR_TO_GLSL::processed_uniform_blocks[64] = { 0 }; -int IR_TO_GLSL::num_uniform_blocks = 0; - IR_TO_GLSL::IR_TO_GLSL( sbuffer& str, global_print_tracker* vGlobals, @@ -434,7 +567,11 @@ IR_TO_GLSL::visit(ir_variable* ir) const int binding_base = (this->state->stage == MESA_SHADER_VERTEX ? (int)VERT_ATTRIB_GENERIC0 : (int)FRAG_RESULT_DATA0); const int location = ir->data.location - binding_base; snprintf(loc, sizeof(loc), "layout(location=%d) ", location); - } + } else if(!ir->data.explicit_location && ir->data.mode == ir_var_shader_out && this->state->stage == MESA_SHADER_FRAGMENT) { + generated_source.append("/* LTW INSERT LOCATION "); + print_var_name(ir); + generated_source.append(" LTW */"); + } else if (ir->data.location != -1) { snprintf(loc, sizeof(loc), "location=%i ", ir->data.location); @@ -691,10 +828,10 @@ const char* const operator_glsl_strs[] = { "double", //"u2d", "bool",// "d2b", "f162b", - "bitcast_i2f", - "bitcast_f2i", - "bitcast_u2f", - "bitcast_f2u", + "intBitsToFloat", + "floatBitsToInt", + "uintBitsToFloat", + "floatBitsToUint", "bitcast_u642d", "bitcast_i642d", "bitcast_d2u64", @@ -1489,6 +1626,11 @@ IR_TO_GLSL::emit_assignment_part(ir_dereference* lhs, ir_rvalue* rhs, unsigned w generated_source.append(" = "); + bool rhs_nan_check = global->enable_nan_check && + lhs->variable_referenced()->data.mode == ir_var_shader_out && + lhsType->is_float(); + if(rhs_nan_check) generated_source.append("_ltw_removenan("); + bool typeMismatch = !dstIndex && (lhsType != rhsType); const bool addSwizzle = hasWriteMask && typeMismatch; if (typeMismatch) @@ -1506,6 +1648,8 @@ IR_TO_GLSL::emit_assignment_part(ir_dereference* lhs, ir_rvalue* rhs, unsigned w if (addSwizzle) generated_source.append(".%s", mask); } + + if(rhs_nan_check) generated_source.append(")"); } // Try to print (X = X + const) as (X += const), mostly to satisfy @@ -1705,7 +1849,7 @@ void IR_TO_GLSL::print_float_checked(sbuffer& str, float f) { char float_dest[5]; snprintf(float_dest, 5, "%f", f); valid_float = strstr(float_dest, "nan") == nullptr && strstr(float_dest, "inf") == nullptr; - if (!valid_float) + if (!valid_float) { // Non-printable float. If we have bit conversions, we're fine. otherwise do hand-wavey things in print_float(). if ((state->es_shader && (state->language_version >= 300)) @@ -2120,7 +2264,7 @@ IR_TO_GLSL::visit(ir_loop_jump* ir) void IR_TO_GLSL::visit(ir_emit_vertex* ir) { - generated_source.append("emit-vertex-TODO"); + generated_source.append("EmitVertex();"); ir->stream->accept(this); generated_source.append("\n"); } @@ -2128,7 +2272,7 @@ IR_TO_GLSL::visit(ir_emit_vertex* ir) void IR_TO_GLSL::visit(ir_end_primitive* ir) { - generated_source.append("end-primitive-TODO"); + generated_source.append("EndPrimitive();"); ir->stream->accept(this); generated_source.append("\n"); } @@ -2136,24 +2280,24 @@ IR_TO_GLSL::visit(ir_end_primitive* ir) void IR_TO_GLSL::visit(ir_barrier*) { - generated_source.append("barrier-TODO\n"); + generated_source.append("barrier();\n"); } void IR_TO_GLSL::visit_uniform_block(ir_variable *ir) { const glsl_type* itype = ir->get_interface_type(); - for ( int i = 0; i < num_uniform_blocks; i++ ) + for ( int i = 0; i < global->num_uniform_blocks; i++ ) { - if ( itype->name == processed_uniform_blocks[i] ) + if ( itype->name == global->processed_uniform_blocks[i] ) { skipped_this_ir = true; return; } } - assert( num_uniform_blocks < sizeof( processed_uniform_blocks ) / sizeof( processed_uniform_blocks[0] ) ); + assert( global->num_uniform_blocks < sizeof( global->processed_uniform_blocks ) / sizeof( global->processed_uniform_blocks[0] ) ); - processed_uniform_blocks[num_uniform_blocks++] = itype->name; + global->processed_uniform_blocks[global->num_uniform_blocks++] = itype->name; const char* packing = nullptr; diff --git a/ltw/src/main/tinywrapper/glsl_optimizer/src/code/ir_print_glsl_visitor.h b/ltw/src/main/tinywrapper/glsl_optimizer/src/code/ir_print_glsl_visitor.h index 31b6736..e75f6d1 100644 --- a/ltw/src/main/tinywrapper/glsl_optimizer/src/code/ir_print_glsl_visitor.h +++ b/ltw/src/main/tinywrapper/glsl_optimizer/src/code/ir_print_glsl_visitor.h @@ -41,19 +41,20 @@ class IR_TO_GLSL : public ir_visitor global_print_tracker(); ~global_print_tracker(); + const char* processed_uniform_blocks[64] = { 0 }; + int num_uniform_blocks = 0; unsigned var_counter; hash_table* var_hash; exec_list global_assignements; void* mem_ctx; bool main_function_done; + bool enable_nan_check; }; public: static char * Convert( exec_list *instructions, struct _mesa_glsl_parse_state *state); - static const char* processed_uniform_blocks[64]; - static int num_uniform_blocks; static void print_type(sbuffer& str, const glsl_type *t, bool arraySize); static void print_type_post(sbuffer& str, const glsl_type *t, bool arraySize); diff --git a/ltw/src/main/tinywrapper/libraryinternal.h b/ltw/src/main/tinywrapper/libraryinternal.h index f562186..f776722 100644 --- a/ltw/src/main/tinywrapper/libraryinternal.h +++ b/ltw/src/main/tinywrapper/libraryinternal.h @@ -1,6 +1,6 @@ /** * Created by: artDev - * Copyright (c) 2025 artDev, SerpentSpirale, PojavLauncherTeam, Digital Genesis LLC. + * Copyright (c) 2025 artDev, SerpentSpirale, CADIndie. * For use under LGPL-3.0 */ diff --git a/ltw/src/main/tinywrapper/license_notice.c b/ltw/src/main/tinywrapper/license_notice.c index ee41632..fa4ca0b 100644 --- a/ltw/src/main/tinywrapper/license_notice.c +++ b/ltw/src/main/tinywrapper/license_notice.c @@ -1,9 +1,9 @@ /** * Created by: artDev - * Copyright (c) 2025 artDev, SerpentSpirale, PojavLauncherTeam, Digital Genesis LLC. + * Copyright (c) 2025 artDev, SerpentSpirale, CADIndie. * For use under LGPL-3.0 */ // Persistent notice that gets added into the final binary -const volatile char* LICENSE_NOTICE = "Copyright (c) 2025 artDev, SerpentSpirale, PojavLauncherTeam, Digital Genesis LLC. For use under LGPL-3.0. " +const volatile char* LICENSE_NOTICE = "Copyright (c) 2025 artDev, SerpentSpirale, CADIndie. For use under LGPL-3.0. " "Build date: "__DATE__" "__TIME__; \ No newline at end of file diff --git a/ltw/src/main/tinywrapper/main.c b/ltw/src/main/tinywrapper/main.c index dba9389..1899ad7 100644 --- a/ltw/src/main/tinywrapper/main.c +++ b/ltw/src/main/tinywrapper/main.c @@ -1,6 +1,6 @@ /** * Created by: artDev, DuyKhanhTran - * Copyright (c) 2025 artDev, SerpentSpirale, PojavLauncherTeam, Digital Genesis LLC. + * Copyright (c) 2025 artDev, SerpentSpirale, CADIndie. * For use under LGPL-3.0 */ #include @@ -18,6 +18,7 @@ #include "main.h" #include "swizzle.h" #include "libraryinternal.h" +#include "env.h" void glClearDepth(GLdouble depth) { if(!current_context) return; @@ -166,7 +167,7 @@ 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); + if(data != NULL) swizzle_process_upload(target, &format, &type); pick_internalformat(&internalformat, &type, &format, &data); es3_functions.glTexImage2D(target, level, internalformat, width, height, border, format, type, data); } @@ -202,12 +203,6 @@ void glTexParameteri( GLenum target, 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: - if(param == GL_LINEAR) param = GL_NEAREST; - break; - } es3_functions.glTexParameteri(target, pname, param); } @@ -266,15 +261,39 @@ void glRenderbufferStorage( GLenum target, es3_functions.glRenderbufferStorage(target, internalformat, width, height); } +static bool never_flush_buffers; +static bool coherent_dynamic_storage; void glBufferStorage(GLenum target, GLsizeiptr size, const void * data, GLbitfield flags) { if(!current_context || !current_context->buffer_storage) return; + // Enable coherence to make sure the buffers are synced without flushing. + if(never_flush_buffers && ((flags & GL_MAP_PERSISTENT_BIT) != 0)) { + flags |= GL_MAP_COHERENT_BIT; + } + // Force dynamic storage buffers to be coherent (for working around driver bugs) + if(coherent_dynamic_storage && (flags & GL_DYNAMIC_STORAGE_BIT) != 0) { + flags |= (GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT); + } es3_functions.glBufferStorageEXT(target, size, data, flags); } +void *glMapBufferRange( GLenum target, + GLintptr offset, + GLsizeiptr length, + GLbitfield access) { + if(never_flush_buffers) access &= ~GL_MAP_FLUSH_EXPLICIT_BIT; + return es3_functions.glMapBufferRange(target, offset, length, access); +} + +void glFlushMappedBufferRange( GLenum target, + GLintptr offset, + GLsizeiptr length) { + if(!never_flush_buffers) es3_functions.glFlushMappedBufferRange(target, offset, length); +} + const GLubyte* glGetStringi(GLenum name, GLuint index) { if(!current_context || name != GL_EXTENSIONS) return NULL; if(index < current_context->nextensions_es) { @@ -294,7 +313,7 @@ const GLubyte* glGetString(GLenum name) { case GL_SHADING_LANGUAGE_VERSION: return (const GLubyte*)"4.60 LTW"; case GL_VENDOR: - return (const GLubyte*)"PojavLauncherTeam & QuestCraft Developers"; + return (const GLubyte*)"artDev, SerpentSpirale, CADIndie"; case GL_EXTENSIONS: if(current_context->extensions_string != NULL) return (const GLubyte*)current_context->extensions_string; return (const GLubyte*)es3_functions.glGetString(GL_EXTENSIONS); @@ -303,8 +322,11 @@ const GLubyte* glGetString(GLenum name) { } } +static bool debug = false; + void glEnable(GLenum cap) { - if(!current_context || cap == GL_DEBUG_OUTPUT) return; + if(!current_context) return; + if(cap == GL_DEBUG_OUTPUT && !debug) return; es3_functions.glEnable(cap); } @@ -435,17 +457,49 @@ void glDeleteTextures(GLsizei n, const GLuint *textures) { } } -static bool noerror = false; +static bool buf_tex_trigger = false; -__attribute((constructor)) void init_noerror() { - const char* noerror_env = getenv("LIBGL_NOERROR"); - if(noerror_env == NULL) return; - noerror = (*noerror_env) != '0'; - if(!noerror) { - printf("LTW will NOT ignore GL errors. This may break mods, consider yourself warned.\n"); +void glTexBuffer(GLenum target, GLenum internalFormat, GLuint buffer) { + if(!current_context) return; + if(current_context->es32) es3_functions.glTexBuffer(target, internalFormat, buffer); + else if(current_context->buffer_texture_ext) es3_functions.glTexBufferEXT(target, internalFormat, buffer); + else if(!buf_tex_trigger) { + buf_tex_trigger = true; + printf("LTW: Buffer textures aren't supported on your device\n"); } } +void glTexBufferARB(GLenum target, GLenum internalFormat, GLuint buffer) { + glTexBuffer(target, internalFormat, buffer); +} + +void glTexBufferRange(GLenum target, GLenum internalFormat, GLuint buffer, GLintptr offset, GLsizeiptr size) { + if(!current_context) return; + if(current_context->es32) es3_functions.glTexBufferRange(target, internalFormat, buffer, offset, size); + else if(current_context->buffer_texture_ext) es3_functions.glTexBufferRangeEXT(target, internalFormat, buffer, offset, size); + else if(!buf_tex_trigger) { + buf_tex_trigger = true; + printf("LTW: Buffer textures aren't supported on your device\n"); + } +} + +void glTexBufferRangeARB(GLenum target, GLenum internalFormat, GLuint buffer, GLintptr offset, GLsizeiptr size) { + glTexBufferRange(target, internalFormat, buffer, offset, size); +} + +static bool noerror; + +__attribute((constructor)) void init_noerror() { + noerror = env_istrue("LIBGL_NOERROR"); + debug = env_istrue("LTW_DEBUG"); + never_flush_buffers = env_istrue_d("LTW_NEVER_FLUSH_BUFFERS", true); + coherent_dynamic_storage = env_istrue_d("LTW_COHERENT_DYNAMIC_STORAGE", true); + if(!noerror) printf("LTW will NOT ignore GL errors. This may break mods, consider yourself warned.\n"); + if(coherent_dynamic_storage) printf("LTW will force dynamic storage buffers to be coherent.\n"); + if(debug) printf("LTW will allow GL_DEBUG_OUTPUT to be enabled. Expect massive logs.\n"); + if(never_flush_buffers) printf("LTW will prevent all explicit buffer flushes.\n"); +} + GLenum glGetError() { if(noerror) return 0; else return es3_functions.glGetError(); diff --git a/ltw/src/main/tinywrapper/main.h b/ltw/src/main/tinywrapper/main.h index 7447f10..45300dd 100644 --- a/ltw/src/main/tinywrapper/main.h +++ b/ltw/src/main/tinywrapper/main.h @@ -1,6 +1,6 @@ /** * Created by: artDev - * Copyright (c) 2025 artDev, SerpentSpirale, PojavLauncherTeam, Digital Genesis LLC. + * Copyright (c) 2025 artDev, SerpentSpirale, CADIndie. * For use under LGPL-3.0 */ diff --git a/ltw/src/main/tinywrapper/multidraw.c b/ltw/src/main/tinywrapper/multidraw.c index c452cea..b3a33ae 100644 --- a/ltw/src/main/tinywrapper/multidraw.c +++ b/ltw/src/main/tinywrapper/multidraw.c @@ -1,6 +1,6 @@ /** * Created by: artDev - * Copyright (c) 2025 artDev, SerpentSpirale, PojavLauncherTeam, Digital Genesis LLC. + * Copyright (c) 2025 artDev, SerpentSpirale, CADIndie. * For use under LGPL-3.0 */ diff --git a/ltw/src/main/tinywrapper/of_buffer_copier.c b/ltw/src/main/tinywrapper/of_buffer_copier.c index 73827bc..2eaae00 100644 --- a/ltw/src/main/tinywrapper/of_buffer_copier.c +++ b/ltw/src/main/tinywrapper/of_buffer_copier.c @@ -1,6 +1,6 @@ /** * Created by: artDev - * Copyright (c) 2025 artDev, SerpentSpirale, PojavLauncherTeam, Digital Genesis LLC. + * Copyright (c) 2025 artDev, SerpentSpirale, CADIndie. * For use under LGPL-3.0 */ #include "proc.h" @@ -115,6 +115,36 @@ void glTexSubImage2D(GLenum target, es3_functions.glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, data); } +void texture_blit_framebuffer(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLint x, + GLint y, + GLsizei width, + GLsizei height, + bool depth) { + framebuffer_copier_t* copier = ¤t_context->framebuffer_copier; + if(!copier->ready) return; + + GLenum fb_attachment; + GLbitfield fb_blit_bit; + if(depth) { + fb_attachment = GL_DEPTH_ATTACHMENT; + fb_blit_bit = GL_DEPTH_BUFFER_BIT; + }else { + fb_attachment = GL_COLOR_ATTACHMENT0; + fb_blit_bit = GL_COLOR_BUFFER_BIT; + } + + GLint texture; + es3_functions.glGetIntegerv(get_textarget_query_param(target), &texture); + es3_functions.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, copier->destfb); + es3_functions.glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, fb_attachment, target, texture, level); + es3_functions.glBlitFramebuffer(x, y, width+x, height+y, xoffset, yoffset, width+xoffset, height+yoffset, fb_blit_bit, GL_NEAREST); + es3_functions.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, current_context->draw_framebuffer); +} + void glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, @@ -123,17 +153,21 @@ void glCopyTexSubImage2D(GLenum target, GLint y, GLsizei width, GLsizei height) { - es3_functions.glGetError(); - es3_functions.glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height); - // The QCOM driver is a pathological liar and emits wrong GL errors. Abuse this to decide when we actually need to at least try copying depth. - if(es3_functions.glGetError() == GL_INVALID_OPERATION) { - framebuffer_copier_t* copier = ¤t_context->framebuffer_copier; - if(!copier->ready) return; - GLint 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); - es3_functions.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, current_context->draw_framebuffer); + if(current_context->es31) { + GLint depthtype; + es3_functions.glGetTexLevelParameteriv(target, level, GL_TEXTURE_DEPTH_TYPE, &depthtype); + if(depthtype != GL_NONE) { + texture_blit_framebuffer(target, level, xoffset, yoffset, x, y, width, height, true); + }else { + texture_blit_framebuffer(target, level, xoffset, yoffset, x, y, width, height, false); + } + } else { + es3_functions.glGetError(); + es3_functions.glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height); + // The QCOM driver is a pathological liar and emits wrong GL errors. Abuse this to decide when we actually need to at least try copying depth. + if(es3_functions.glGetError() == GL_INVALID_OPERATION) { + texture_blit_framebuffer(target, level, xoffset, yoffset, x, y, width, height, true); + } } + } \ No newline at end of file diff --git a/ltw/src/main/tinywrapper/proc.c b/ltw/src/main/tinywrapper/proc.c index c3da9bb..eee2416 100644 --- a/ltw/src/main/tinywrapper/proc.c +++ b/ltw/src/main/tinywrapper/proc.c @@ -1,6 +1,6 @@ /** * Created by: artDev - * Copyright (c) 2025 artDev, SerpentSpirale, PojavLauncherTeam, Digital Genesis LLC. + * Copyright (c) 2025 artDev, SerpentSpirale, CADIndie. * For use under LGPL-3.0 */ #include diff --git a/ltw/src/main/tinywrapper/proc.h b/ltw/src/main/tinywrapper/proc.h index 1c957c7..15099cb 100644 --- a/ltw/src/main/tinywrapper/proc.h +++ b/ltw/src/main/tinywrapper/proc.h @@ -1,6 +1,6 @@ /** * Created by: artDev - * Copyright (c) 2025 artDev, SerpentSpirale, PojavLauncherTeam, Digital Genesis LLC. + * Copyright (c) 2025 artDev, SerpentSpirale, CADIndie. * For use under LGPL-3.0 */ diff --git a/ltw/src/main/tinywrapper/shader_wrapper.c b/ltw/src/main/tinywrapper/shader_wrapper.c index d35afee..3c1bd48 100644 --- a/ltw/src/main/tinywrapper/shader_wrapper.c +++ b/ltw/src/main/tinywrapper/shader_wrapper.c @@ -1,6 +1,6 @@ /** * Created by: artDev - * Copyright (c) 2025 artDev, SerpentSpirale, PojavLauncherTeam, Digital Genesis LLC. + * Copyright (c) 2025 artDev, SerpentSpirale, CADIndie. * For use under LGPL-3.0 */ @@ -71,8 +71,24 @@ void glBindFragDataLocation( GLuint program, } } -static void insert_fragout_pos(char* source, const char* name, GLuint pos) { - //TODO implement lol +void glGetShaderiv(GLuint shader, GLuint pname, GLint* params) { + if(!current_context) return; + shader_info_t* shader_info = unordered_map_get(current_context->shader_map, (void*)shader); + if(shader_info != NULL && shader_info->shader_type == GL_FRAGMENT_SHADER && pname == GL_COMPILE_STATUS) { + // HACK: ignore compile results for frag shaders, as some drivers may not compile them without explicit fragouts + // (which we add at link-time) + *params = GL_TRUE; + return; + } + es3_functions.glGetShaderiv(shader, pname, params); +} + +static void insert_fragout_pos(char* source, int* size, const char* name, GLuint pos) { + char src_string[256] = { 0 }; + char dst_string[256] = { 0 }; + snprintf(src_string, sizeof(src_string), "/* LTW INSERT LOCATION %s LTW */", name); + snprintf(dst_string, sizeof(dst_string), "layout(location = %u) ", pos); + gl4es_inplace_replace_simple(source, size, src_string, dst_string); } void glLinkProgram(GLuint program) { @@ -87,19 +103,21 @@ void glLinkProgram(GLuint program) { printf("LTWShdrWp: failed to patch frag data location due to missing shader info\n"); goto fallthrough; } - size_t nsrc_size = strlen(shader->source) + 1; + int nsrc_size = (int)(strlen(shader->source) + 1); char* new_source = malloc(nsrc_size); memcpy(new_source, shader->source, nsrc_size); bool changesMade = false; for(GLuint i = 0; i < MAX_DRAWBUFFERS; i++) { const char* colorbind = program_info->colorbindings[i]; if(colorbind == NULL) continue; - insert_fragout_pos(new_source, colorbind, i); + insert_fragout_pos(new_source, &nsrc_size, colorbind, i); changesMade = true; } if(!changesMade) { free(new_source); goto fallthrough; + }else { + //printf("\n\n\nShader Result POST PATCH\n%s\n\n\n", new_source); } const GLchar* const_source = (const GLchar*)new_source; GLuint patched_shader = es3_functions.glCreateShader(GL_FRAGMENT_SHADER); @@ -118,9 +136,10 @@ void glLinkProgram(GLuint program) { es3_functions.glGetShaderiv(patched_shader, GL_INFO_LOG_LENGTH, &logSize); GLchar log[logSize]; es3_functions.glGetShaderInfoLog(patched_shader, logSize, NULL, log); - printf("LTWShdrWp: failed to compile patched fragment shader, using default. Log:\n%s\n", log); + printf("LTWShdrWp: failed to compile patched fragment shader, using default. Log:\n\n%s\n\nShader content:\n\n%s\n\n", log, const_source); goto fallthrough; } + es3_functions.glDetachShader(program, program_info->frag_shader); es3_functions.glAttachShader(program, patched_shader); es3_functions.glLinkProgram(program); es3_functions.glDeleteShader(patched_shader); diff --git a/ltw/src/main/tinywrapper/string_utils.c b/ltw/src/main/tinywrapper/string_utils.c index cd57342..df964ed 100644 --- a/ltw/src/main/tinywrapper/string_utils.c +++ b/ltw/src/main/tinywrapper/string_utils.c @@ -4,6 +4,8 @@ #include "string_utils.h" +#pragma GCC visibility push(hidden) + const char* AllSeparators = " \t\n\r.,;()[]{}-<>+*/%&\\\"'^$=!:?"; char* gl4es_resize_if_needed(char* pBuffer, int *size, int addsize); @@ -300,3 +302,4 @@ char* gl4es_inplace_replace_simple(char* pBuffer, int* size, const char* S, cons return pBuffer; } +#pragma GCC visibility pop(hidden) \ No newline at end of file diff --git a/ltw/src/main/tinywrapper/stubs.c b/ltw/src/main/tinywrapper/stubs.c index 112457b..0486b3b 100644 --- a/ltw/src/main/tinywrapper/stubs.c +++ b/ltw/src/main/tinywrapper/stubs.c @@ -1,6 +1,6 @@ /** * Created by: artDev - * Copyright (c) 2025 artDev, SerpentSpirale, PojavLauncherTeam, Digital Genesis LLC. + * Copyright (c) 2025 artDev, SerpentSpirale, CADIndie. * For use under LGPL-3.0 */ diff --git a/ltw/src/main/tinywrapper/swizzle.c b/ltw/src/main/tinywrapper/swizzle.c index c6f23e3..9c1def1 100644 --- a/ltw/src/main/tinywrapper/swizzle.c +++ b/ltw/src/main/tinywrapper/swizzle.c @@ -1,6 +1,6 @@ /** * Created by: artDev - * Copyright (c) 2025 artDev, SerpentSpirale, PojavLauncherTeam, Digital Genesis LLC. + * Copyright (c) 2025 artDev, SerpentSpirale, CADIndie. * For use under LGPL-3.0 */ @@ -69,6 +69,9 @@ INTERNAL void swizzle_process_upload(GLenum target, GLenum* format, GLenum* type apply_goofy_order = true; *type = GL_UNSIGNED_BYTE; } + if((*type) == 0x8367) { + *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; diff --git a/ltw/src/main/tinywrapper/swizzle.h b/ltw/src/main/tinywrapper/swizzle.h index f5bc398..fe880d9 100644 --- a/ltw/src/main/tinywrapper/swizzle.h +++ b/ltw/src/main/tinywrapper/swizzle.h @@ -1,6 +1,6 @@ /** * Created by: artDev - * Copyright (c) 2025 artDev, SerpentSpirale, PojavLauncherTeam, Digital Genesis LLC. + * Copyright (c) 2025 artDev, SerpentSpirale, CADIndie. * For use under LGPL-3.0 */ diff --git a/ltw/src/main/tinywrapper/unordered_map/int_hash.c b/ltw/src/main/tinywrapper/unordered_map/int_hash.c index 0c8c37d..88e6c3d 100644 --- a/ltw/src/main/tinywrapper/unordered_map/int_hash.c +++ b/ltw/src/main/tinywrapper/unordered_map/int_hash.c @@ -1,6 +1,6 @@ /** * Created by: artDev - * Copyright (c) 2025 artDev, SerpentSpirale, PojavLauncherTeam, Digital Genesis LLC. + * Copyright (c) 2025 artDev, SerpentSpirale, CADIndie. * For use under LGPL-3.0 */ #include "int_hash.h" diff --git a/ltw/src/main/tinywrapper/unordered_map/int_hash.h b/ltw/src/main/tinywrapper/unordered_map/int_hash.h index 1f3a149..c2392b5 100644 --- a/ltw/src/main/tinywrapper/unordered_map/int_hash.h +++ b/ltw/src/main/tinywrapper/unordered_map/int_hash.h @@ -1,6 +1,6 @@ /** * Created by: artDev - * Copyright (c) 2025 artDev, SerpentSpirale, PojavLauncherTeam, Digital Genesis LLC. + * Copyright (c) 2025 artDev, SerpentSpirale, CADIndie. * For use under LGPL-3.0 */ diff --git a/ltw/src/main/tinywrapper/version.script b/ltw/src/main/tinywrapper/version.script new file mode 100644 index 0000000..8697714 --- /dev/null +++ b/ltw/src/main/tinywrapper/version.script @@ -0,0 +1,4 @@ +{ + global: gl*; egl*; + local: *; +}; \ No newline at end of file diff --git a/ltw/src/main/tinywrapper/vertexattrib.c b/ltw/src/main/tinywrapper/vertexattrib.c index d6d45b0..bfcc8e0 100644 --- a/ltw/src/main/tinywrapper/vertexattrib.c +++ b/ltw/src/main/tinywrapper/vertexattrib.c @@ -1,6 +1,6 @@ /** * Created by: artDev - * Copyright (c) 2025 artDev, SerpentSpirale, PojavLauncherTeam, Digital Genesis LLC. + * Copyright (c) 2025 artDev, SerpentSpirale, CADIndie. * For use under LGPL-3.0 */ diff --git a/ltw/src/main/tinywrapper/vgpu_shaderconv/shaderconv.c b/ltw/src/main/tinywrapper/vgpu_shaderconv/shaderconv.c index d03d794..9ab604a 100644 --- a/ltw/src/main/tinywrapper/vgpu_shaderconv/shaderconv.c +++ b/ltw/src/main/tinywrapper/vgpu_shaderconv/shaderconv.c @@ -1,6 +1,6 @@ /** * Created by: SerpentSpirale - * Copyright (c) 2025 SerpentSpirale, artDev, PojavLauncherTeam, Digital Genesis LLC. + * Copyright (c) 2025 SerpentSpirale, artDev, CADIndie. * For use under LGPL-3.0 */ #include diff --git a/ltw/src/main/tinywrapper/vgpu_shaderconv/shaderconv.h b/ltw/src/main/tinywrapper/vgpu_shaderconv/shaderconv.h index 63ac342..77abfd7 100644 --- a/ltw/src/main/tinywrapper/vgpu_shaderconv/shaderconv.h +++ b/ltw/src/main/tinywrapper/vgpu_shaderconv/shaderconv.h @@ -1,6 +1,6 @@ /** * Created by: SerpentSpirale - * Copyright (c) 2025 SerpentSpirale, artDev, PojavLauncherTeam, Digital Genesis LLC. + * Copyright (c) 2025 SerpentSpirale, artDev, CADIndie. * For use under LGPL-3.0 */