diff --git a/app_pojavlauncher/build.gradle b/app_pojavlauncher/build.gradle index c36dda831..5f674bc53 100644 --- a/app_pojavlauncher/build.gradle +++ b/app_pojavlauncher/build.gradle @@ -68,6 +68,9 @@ android { versionCode getDateSeconds() versionName getVersionName() multiDexEnabled true //important + ndk { + abiFilters 'arm64-v8a' + } } buildTypes { @@ -109,6 +112,7 @@ android { enableSplit = false } } + buildToolsVersion '30.0.2' } diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/JREUtils.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/JREUtils.java index 0656801e5..275288959 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/JREUtils.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/JREUtils.java @@ -226,6 +226,7 @@ public class JREUtils { if(LOCAL_RENDERER != null) { envMap.put("POJAV_RENDERER", LOCAL_RENDERER); } + if(LOCAL_RENDERER.equals("opengles3_angle_vulkan")) envMap.put("POJAVEXEC_EGL","libEGL_angle.so"); // use ANGLE egl envMap.put("AWTSTUB_WIDTH", Integer.toString(CallbackBridge.windowWidth > 0 ? CallbackBridge.windowWidth : CallbackBridge.physicalWidth)); envMap.put("AWTSTUB_HEIGHT", Integer.toString(CallbackBridge.windowHeight > 0 ? CallbackBridge.windowHeight : CallbackBridge.physicalHeight)); @@ -415,6 +416,7 @@ public class JREUtils { case "opengles3": renderLibrary = "libgl4es_115.so"; break; case "vulkan_zink": renderLibrary = "libOSMesa_8.so"; break; case "opengles3_vgpu" : renderLibrary = "libvgpu.so"; break; + case "opengles3_angle_vulkan" : renderLibrary = "libtinywrapper.so"; break; default: Log.w("RENDER_LIBRARY", "No renderer selected, defaulting to opengles2"); renderLibrary = "libgl4es_114.so"; diff --git a/app_pojavlauncher/src/main/jni/Android.mk b/app_pojavlauncher/src/main/jni/Android.mk index 60f17eb7d..1a0815504 100644 --- a/app_pojavlauncher/src/main/jni/Android.mk +++ b/app_pojavlauncher/src/main/jni/Android.mk @@ -24,6 +24,18 @@ LOCAL_CONLYFLAGS := -std=c11 LOCAL_LDLIBS := -llog include $(BUILD_SHARED_LIBRARY) +include $(CLEAR_VARS) +LOCAL_MODULE := angle_gles2 +LOCAL_SRC_FILES := tinywrapper/angle-gles/$(TARGET_ARCH_ABI)/libGLESv2_angle.so +include $(PREBUILT_SHARED_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := tinywrapper +LOCAL_SHARED_LIBRARIES := angle_gles2 +LOCAL_SRC_FILES := tinywrapper/main.c tinywrapper/string_utils.c +LOCAL_C_INCLUDES := $(LOCAL_PATH)/tinywrapper +include $(BUILD_SHARED_LIBRARY) + include $(CLEAR_VARS) # Link GLESv2 for test LOCAL_LDLIBS := -ldl -llog -landroid diff --git a/app_pojavlauncher/src/main/jni/tinywrapper/angle-gles/arm64-v8a/libGLESv2_angle.so b/app_pojavlauncher/src/main/jni/tinywrapper/angle-gles/arm64-v8a/libGLESv2_angle.so new file mode 100644 index 000000000..63794ebcf Binary files /dev/null and b/app_pojavlauncher/src/main/jni/tinywrapper/angle-gles/arm64-v8a/libGLESv2_angle.so differ diff --git a/app_pojavlauncher/src/main/jni/tinywrapper/main.c b/app_pojavlauncher/src/main/jni/tinywrapper/main.c new file mode 100644 index 000000000..add69b25a --- /dev/null +++ b/app_pojavlauncher/src/main/jni/tinywrapper/main.c @@ -0,0 +1,201 @@ +//#import +#include +#include + +#include "GL/gl.h" +#include "GLES3/gl32.h" +#include "string_utils.h" + +#define LOOKUP_FUNC(func) \ + if (!gles_##func) { \ + gles_##func = dlsym(RTLD_NEXT, #func); \ + } if (!gles_##func) { \ + gles_##func = dlsym(RTLD_DEFAULT, #func); \ + } + +int proxy_width, proxy_height, proxy_intformat, maxTextureSize; + +void glBindFragDataLocationEXT(GLuint program, GLuint colorNumber, const char * name); + +void(*gles_glGetTexLevelParameteriv)(GLenum target, GLint level, GLenum pname, GLint *params); +void(*gles_glShaderSource)(GLuint shader, GLsizei count, const GLchar * const *string, const GLint *length); +void(*gles_glTexImage2D)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *data); + +void glBindFragDataLocation(GLuint program, GLuint colorNumber, const char * name) { + glBindFragDataLocationEXT(program, colorNumber, name); +} + +void glClearDepth(GLdouble depth) { + glClearDepthf(depth); +} + +void *glMapBuffer(GLenum target, GLenum access) { + // Use: GL_EXT_map_buffer_range + + GLenum access_range; + GLint length; + + switch (target) { + // GL 4.2 + case GL_ATOMIC_COUNTER_BUFFER: + + // GL 4.3 + case GL_DISPATCH_INDIRECT_BUFFER: + case GL_SHADER_STORAGE_BUFFER : + + // GL 4.4 + case GL_QUERY_BUFFER: + printf("ERROR: glMapBuffer unsupported target=0x%x", target); + break; // not supported for now + + case GL_DRAW_INDIRECT_BUFFER: + case GL_TEXTURE_BUFFER: + printf("ERROR: glMapBuffer unimplemented target=0x%x", target); + break; + } + + switch (access) { + case GL_READ_ONLY: + access_range = GL_MAP_READ_BIT; + break; + + case GL_WRITE_ONLY: + access_range = GL_MAP_WRITE_BIT; + break; + + case GL_READ_WRITE: + access_range = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT; + break; + } + + glGetBufferParameteriv(target, GL_BUFFER_SIZE, &length); + return glMapBufferRange(target, 0, length, access_range); +} + +void glShaderSource(GLuint shader, GLsizei count, const GLchar * const *string, const GLint *length) { + LOOKUP_FUNC(glShaderSource) + + // DBG(printf("glShaderSource(%d, %d, %p, %p)\n", shader, count, string, length);) + char *source = NULL; + char *converted; + + // get the size of the shader sources and than concatenate in a single string + int l = 0; + for (int i=0; i= 0)?length[i]:strlen(string[i]); + if (source) free(source); + source = calloc(1, l+1); + if(length) { + for (int i=0; i= 0) + strncat(source, string[i], length[i]); + else + strcat(source, string[i]); + } + } else { + for (int i=0; i 120 + converted[10] = '2'; + } else if (converted[10] - '0' < 6) { + // 130, 140, 150 -> 330 + converted[9] = converted[10] = '3'; + } + } + // remove "core", is it safe? + if (!strncmp(&converted[13], "core", 4)) { + strncpy(&converted[13], "\n//c", 4); + } + } else { + converted = calloc(1, strlen(source) + 13); + strcpy(converted, "#version 120\n"); + strcpy(&converted[13], strdup(source)); + } + + int convertedLen = strlen(converted); + +#ifdef __APPLE__ + // patch OptiFine 1.17.x + if (FindString(converted, "\nuniform mat4 textureMatrix = mat4(1.0);")) { + InplaceReplace(converted, &convertedLen, "\nuniform mat4 textureMatrix = mat4(1.0);", "\n#define textureMatrix mat4(1.0)"); + } +#endif + + // some needed exts + const char* extensions = + "#extension GL_EXT_blend_func_extended : enable\n" + // For OptiFine (see patch above) + "#extension GL_EXT_shader_non_constant_global_initializers : enable\n"; + converted = InplaceInsert(GetLine(converted, 1), extensions, converted, &convertedLen); + + gles_glShaderSource(shader, 1, (const GLchar * const*)((converted)?(&converted):(&source)), NULL); + + free(source); + free(converted); +} + +int isProxyTexture(GLenum target) { + switch (target) { + case GL_PROXY_TEXTURE_1D: + case GL_PROXY_TEXTURE_2D: + case GL_PROXY_TEXTURE_3D: + case GL_PROXY_TEXTURE_RECTANGLE_ARB: + return 1; + } + return 0; +} + +static int inline nlevel(int size, int level) { + if(size) { + size>>=level; + if(!size) size=1; + } + return size; +} + +void glGetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint *params) { + LOOKUP_FUNC(glGetTexLevelParameteriv) + // NSLog("glGetTexLevelParameteriv(%x, %d, %x, %p)", target, level, pname, params); + if (isProxyTexture(target)) { + switch (pname) { + case GL_TEXTURE_WIDTH: + (*params) = nlevel(proxy_width,level); + break; + case GL_TEXTURE_HEIGHT: + (*params) = nlevel(proxy_height,level); + break; + case GL_TEXTURE_INTERNAL_FORMAT: + (*params) = proxy_intformat; + break; + } + } else { + gles_glGetTexLevelParameteriv(target, level, pname, params); + } +} + +void glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *data) { + LOOKUP_FUNC(glTexImage2D) + if (isProxyTexture(target)) { + if (!maxTextureSize) { + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); + // maxTextureSize = 16384; + // NSLog(@"Maximum texture size: %d", maxTextureSize); + } + proxy_width = ((width<maxTextureSize)?0:width; + proxy_height = ((height<maxTextureSize)?0:height; + proxy_intformat = internalformat; + // swizzle_internalformat((GLenum *) &internalformat, format, type); + } else { + gles_glTexImage2D(target, level, internalformat, width, height, border, format, type, data); + } +} diff --git a/app_pojavlauncher/src/main/jni/tinywrapper/string_utils.c b/app_pojavlauncher/src/main/jni/tinywrapper/string_utils.c new file mode 100644 index 000000000..992573945 --- /dev/null +++ b/app_pojavlauncher/src/main/jni/tinywrapper/string_utils.c @@ -0,0 +1,234 @@ +#include +#include +#include + +#include "string_utils.h" + +const char* AllSeparators = " \t\n\r.,;()[]{}-<>+*/%&\\\"'^$=!:?"; + +char* ResizeIfNeeded(char* pBuffer, int *size, int addsize); + +char* InplaceReplace(char* pBuffer, int* size, const char* S, const char* D) +{ + int lS = strlen(S), lD = strlen(D); + pBuffer = ResizeIfNeeded(pBuffer, size, (lD-lS)*CountString(pBuffer, S)); + char* p = pBuffer; + while((p = strstr(p, S))) + { + // found an occurence of S + // check if good to replace, strchr also found '\0' :) + if(strchr(AllSeparators, p[lS])!=NULL && (p==pBuffer || strchr(AllSeparators, p[-1])!=NULL)) { + // move out rest of string + memmove(p+lD, p+lS, strlen(p)-lS+1); + // replace + memcpy(p, D, strlen(D)); + // next + p+=lD; + } else p+=lS; + } + + return pBuffer; +} + +char* InplaceInsert(char* pBuffer, const char* S, char* master, int* size) +{ + char* m = ResizeIfNeeded(master, size, strlen(S)); + if(m!=master) { + pBuffer += (m-master); + master = m; + } + char* p = pBuffer; + int lS = strlen(S), ll = strlen(pBuffer); + memmove(p+lS, p, ll+1); + memcpy(p, S, lS); + + return master; +} + +char* GetLine(char* pBuffer, int num) +{ + char *p = pBuffer; + while(num-- && (p=strstr(p, "\n"))) p+=strlen("\n"); + return (p)?p:pBuffer; +} + +int CountLine(const char* pBuffer) +{ + int n=0; + const char* p = pBuffer; + while((p=strstr(p, "\n"))) { + p+=strlen("\n"); + n++; + } + return n; +} + +int GetLineFor(const char* pBuffer, const char* S) +{ + int n=0; + const char* p = pBuffer; + const char* end = FindString(pBuffer, S); + if(!end) + return 0; + while((p=strstr(p, "\n"))) { + p+=strlen("\n"); + n++; + if(p>=end) + return n; + } + return n; +} + +int CountString(const char* pBuffer, const char* S) +{ + const char* p = pBuffer; + int lS = strlen(S); + int n = 0; + while((p = strstr(p, S))) + { + // found an occurence of S + // check if good to count, strchr also found '\0' :) + if(strchr(AllSeparators, p[lS])!=NULL && (p==pBuffer || strchr(AllSeparators, p[-1])!=NULL)) + n++; + p+=lS; + } + return n; +} + +const char* FindString(const char* pBuffer, const char* S) +{ + const char* p = pBuffer; + int lS = strlen(S); + while((p = strstr(p, S))) + { + // found an occurence of S + // check if good to count, strchr also found '\0' :) + if(strchr(AllSeparators, p[lS])!=NULL && (p==pBuffer || strchr(AllSeparators, p[-1])!=NULL)) + return p; + p+=lS; + } + return NULL; +} + +char* FindStringNC(char* pBuffer, const char* S) +{ + char* p = pBuffer; + int lS = strlen(S); + while((p = strstr(p, S))) + { + // found an occurence of S + // check if good to count, strchr also found '\0' :) + if(strchr(AllSeparators, p[lS])!=NULL && (p==pBuffer || strchr(AllSeparators, p[-1])!=NULL)) + return p; + p+=lS; + } + return NULL; +} + +char* ResizeIfNeeded(char* pBuffer, int *size, int addsize) { + char* p = pBuffer; + int newsize = strlen(pBuffer)+addsize+1; + if (newsize>*size) { + newsize += 100; + p = (char*)realloc(pBuffer, newsize); + *size=newsize; + } + return p; +} + +char* Append(char* pBuffer, int* size, const char* S) { + char* p =pBuffer; + p = ResizeIfNeeded(pBuffer, size, strlen(S)); + strcat(p, S); + return p; +} + +int isBlank(char c) { + switch(c) { + case ' ': + case '\t': + case '\n': + case '\r': + case ':': + case ',': + case ';': + case '/': + return 1; + default: + return 0; + } +} +char* StrNext(char *pBuffer, const char* S) { + if(!pBuffer) return NULL; + char *p = strstr(pBuffer, S); + return (p)?p:(p+strlen(S)); +} + +char* NextStr(char* pBuffer) { + if(!pBuffer) return NULL; + while(isBlank(*pBuffer)) + ++pBuffer; + return pBuffer; +} + +char* NextBlank(char* pBuffer) { + if(!pBuffer) return NULL; + while(!isBlank(*pBuffer)) + ++pBuffer; + return pBuffer; +} + +char* NextLine(char* pBuffer) { + if(!pBuffer) return NULL; + while(*pBuffer && *pBuffer!='\n') + ++pBuffer; + return pBuffer; +} + +const char* GetNextStr(char* pBuffer) { + static char buff[100] = {0}; + buff[0] = '\0'; + if(!pBuffer) return NULL; + char* p1 = NextStr(pBuffer); + if(!p1) return buff; + char* p2 = NextBlank(p1); + if(!p2) return buff; + int i=0; + while(p1!=p2 && i<99) + buff[i++] = *(p1++); + buff[i] = '\0'; + return buff; +} + +int CountStringSimple(char* pBuffer, const char* S) +{ + char* p = pBuffer; + int lS = strlen(S); + int n = 0; + while((p = strstr(p, S))) + { + // found an occurence of S + n++; + p+=lS; + } + return n; +} + +char* InplaceReplaceSimple(char* pBuffer, int* size, const char* S, const char* D) +{ + int lS = strlen(S), lD = strlen(D); + pBuffer = ResizeIfNeeded(pBuffer, size, (lD-lS)*CountStringSimple(pBuffer, S)); + char* p = pBuffer; + while((p = strstr(p, S))) + { + // found an occurence of S + // move out rest of string + memmove(p+lD, p+lS, strlen(p)-lS+1); + // replace + memcpy(p, D, strlen(D)); + // next + p+=lD; + } + + return pBuffer; +} \ No newline at end of file diff --git a/app_pojavlauncher/src/main/jni/tinywrapper/string_utils.h b/app_pojavlauncher/src/main/jni/tinywrapper/string_utils.h new file mode 100644 index 000000000..c0431806a --- /dev/null +++ b/app_pojavlauncher/src/main/jni/tinywrapper/string_utils.h @@ -0,0 +1,29 @@ +#ifndef _GL4ES_STRING_UTILS_H_ +#define _GL4ES_STRING_UTILS_H_ + +extern const char* AllSeparators; + +const char* FindString(const char* pBuffer, const char* S); +char* FindStringNC(char* pBuffer, const char* S); +int CountString(const char* pBuffer, const char* S); +char* ResizeIfNeeded(char* pBuffer, int *size, int addsize); +char* InplaceReplace(char* pBuffer, int* size, const char* S, const char* D); +char* Append(char* pBuffer, int* size, const char* S); +char* InplaceInsert(char* pBuffer, const char* S, char* master, int* size); +char* GetLine(char* pBuffer, int num); +int CountLine(const char* pBuffer); +int GetLineFor(const char* pBuffer, const char* S); // get the line number for 1st occurent of S in pBuffer +char* StrNext(char *pBuffer, const char* S); // mostly as strstr, but go after the substring if found +//"blank" (space, tab, cr, lf,":", ",", ";", ".", "/") +char* NextStr(char* pBuffer); // go to next non "blank" +char* NextBlank(char* pBuffer); // go to next "blank" +char* NextLine(char* pBuffer); // go to next new line (crlf not included) + +const char* GetNextStr(char* pBuffer); // get a (static) copy of next str (until next separator), can be a simple number or separator also + +// those function don't try to be smart with separators... +int CountStringSimple(char* pBuffer, const char* S); +char* InplaceReplaceSimple(char* pBuffer, int* size, const char* S, const char* D); + + +#endif // _GL4ES_STRING_UTILS_H_ \ No newline at end of file diff --git a/app_pojavlauncher/src/main/jniLibs/arm64-v8a/libEGL_angle.so b/app_pojavlauncher/src/main/jniLibs/arm64-v8a/libEGL_angle.so new file mode 100644 index 000000000..c2969f6d2 Binary files /dev/null and b/app_pojavlauncher/src/main/jniLibs/arm64-v8a/libEGL_angle.so differ diff --git a/app_pojavlauncher/src/main/res/values/headings_array.xml b/app_pojavlauncher/src/main/res/values/headings_array.xml index 42e6ceb9e..911c647cb 100644 --- a/app_pojavlauncher/src/main/res/values/headings_array.xml +++ b/app_pojavlauncher/src/main/res/values/headings_array.xml @@ -13,6 +13,7 @@ @string/mcl_setting_renderer_gles3_5 @string/mcl_setting_renderer_vulkan_zink @string/mcl_setting_renderer_vgpu + TINYWRAPPER ANGLE VULKAN @@ -21,5 +22,6 @@ opengles3 vulkan_zink opengles3_vgpu + opengles3_angle_vulkan diff --git a/build.gradle b/build.gradle index 96e2354eb..a137c2c92 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build:gradle:4.2.2' + classpath 'com.android.tools.build:gradle:7.0.2' // NOTE: Do not place syour application dependencies here; they belong // in the individual module build.gradle files diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 631e20c11..f1ac91ddc 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip