[Feat] (multidraw): switch different multidraw emulation routine

This commit is contained in:
Swung0x48 2025-03-31 15:20:45 +08:00
parent f11ba3f11b
commit eab666e44b
9 changed files with 273 additions and 5 deletions

View File

@ -26,6 +26,8 @@ void init_settings() {
int enableExtGL43 = success ? config_get_int("enableExtGL43") : 0; int enableExtGL43 = success ? config_get_int("enableExtGL43") : 0;
int enableExtComputeShader = success ? config_get_int("enableExtComputeShader") : 0; int enableExtComputeShader = success ? config_get_int("enableExtComputeShader") : 0;
int enableCompatibleMode = success ? config_get_int("enableCompatibleMode") : 0; int enableCompatibleMode = success ? config_get_int("enableCompatibleMode") : 0;
multidraw_mode_t multidrawMode = success ? (multidraw_mode_t)config_get_int("multidrawMode") : multidraw_mode_t::Auto;
// multidraw_mode_t multidrawMode = multidraw_mode_t::PreferUnroll;
size_t maxGlslCacheSize = 0; size_t maxGlslCacheSize = 0;
if (config_get_int("maxGlslCacheSize") > 0) if (config_get_int("maxGlslCacheSize") > 0)
maxGlslCacheSize = success ? config_get_int("maxGlslCacheSize") * 1024 * 1024 : 0; maxGlslCacheSize = success ? config_get_int("maxGlslCacheSize") * 1024 * 1024 : 0;
@ -40,6 +42,8 @@ void init_settings() {
enableExtComputeShader = 0; enableExtComputeShader = 0;
if (enableCompatibleMode < 0 || enableCompatibleMode > 1) if (enableCompatibleMode < 0 || enableCompatibleMode > 1)
enableCompatibleMode = 0; enableCompatibleMode = 0;
if ((int)multidrawMode < 0 || (int)multidrawMode > 3)
multidrawMode = multidraw_mode_t::Auto;
// 1205 // 1205
int fclVersion = 0; int fclVersion = 0;
@ -63,6 +67,7 @@ void init_settings() {
enableCompatibleMode = 0; enableCompatibleMode = 0;
} }
// Determining actual ANGLE mode
const char* gpuString = getGPUInfo(); const char* gpuString = getGPUInfo();
LOG_D("GPU: %s", gpuString) LOG_D("GPU: %s", gpuString)
@ -120,10 +125,73 @@ void init_settings() {
global_settings.enable_compatible_mode = enableCompatibleMode; global_settings.enable_compatible_mode = enableCompatibleMode;
global_settings.multidraw_mode = multidrawMode;
std::string draw_mode_str;
switch (global_settings.multidraw_mode) {
case multidraw_mode_t::PreferIndirect:
draw_mode_str = "Indirect";
break;
case multidraw_mode_t::PreferUnroll:
draw_mode_str = "Unroll";
break;
case multidraw_mode_t::PreferMultidrawIndirect:
draw_mode_str = "Multidraw indirect";
break;
case multidraw_mode_t::Auto:
draw_mode_str = "Auto";
break;
default:
draw_mode_str = "(Unknown)";
global_settings.multidraw_mode = multidraw_mode_t::Auto;
break;
}
LOG_V("[MobileGlues] Setting: enableAngle = %s", global_settings.angle ? "true" : "false") LOG_V("[MobileGlues] Setting: enableAngle = %s", global_settings.angle ? "true" : "false")
LOG_V("[MobileGlues] Setting: ignoreError = %i", global_settings.ignore_error) LOG_V("[MobileGlues] Setting: ignoreError = %i", global_settings.ignore_error)
LOG_V("[MobileGlues] Setting: enableExtComputeShader = %s", global_settings.ext_compute_shader ? "true" : "false") LOG_V("[MobileGlues] Setting: enableExtComputeShader = %s", global_settings.ext_compute_shader ? "true" : "false")
LOG_V("[MobileGlues] Setting: enableExtGL43 = %s", global_settings.ext_gl43 ? "true" : "false") LOG_V("[MobileGlues] Setting: enableExtGL43 = %s", global_settings.ext_gl43 ? "true" : "false")
LOG_V("[MobileGlues] Setting: maxGlslCacheSize = %i", global_settings.max_glsl_cache_size / 1024 / 1024) LOG_V("[MobileGlues] Setting: maxGlslCacheSize = %i", global_settings.max_glsl_cache_size / 1024 / 1024)
LOG_V("[MobileGlues] Setting: enableCompatibleMode = %s", global_settings.enable_compatible_mode ? "true" : "false") LOG_V("[MobileGlues] Setting: enableCompatibleMode = %s", global_settings.enable_compatible_mode ? "true" : "false")
LOG_V("[MobileGlues] Setting: multidrawMode = %s", draw_mode_str.c_str())
}
void init_settings_post() {
bool multidraw = g_gles_caps.GL_EXT_multi_draw_indirect;
bool basevertex =
g_gles_caps.GL_OES_draw_elements_base_vertex ||
(g_gles_caps.major == 3 && g_gles_caps.minor >= 2) || (g_gles_caps.major > 3);
bool indirect = (g_gles_caps.major == 3 && g_gles_caps.minor >= 1) || (g_gles_caps.major > 3);
switch (global_settings.multidraw_mode) {
case multidraw_mode_t::PreferIndirect:
LOG_V("multidrawMode = PreferIndirect")
global_settings.multidraw_mode = multidraw_mode_t::PreferIndirect;
LOG_V(" -> Indirect (OK)")
break;
case multidraw_mode_t::PreferUnroll:
LOG_V("multidrawMode = PreferUnroll")
if (basevertex) {
global_settings.multidraw_mode = multidraw_mode_t::PreferUnroll;
LOG_V(" -> Unroll (OK)")
} else if (multidraw) {
global_settings.multidraw_mode = multidraw_mode_t::PreferMultidrawIndirect;
LOG_V(" -> MultidrawIndirect (Preferred not supported, falling back)")
} else {
global_settings.multidraw_mode = multidraw_mode_t::PreferIndirect;
LOG_V(" -> Indirect (Preferred not supported, falling back)")
}
break;
case multidraw_mode_t::Auto:
default:
LOG_V("multidrawMode = Auto")
if (multidraw) {
global_settings.multidraw_mode = multidraw_mode_t::PreferMultidrawIndirect;
LOG_V(" -> MultidrawIndirect")
} else {
global_settings.multidraw_mode = multidraw_mode_t::PreferIndirect;
LOG_V(" -> Indirect")
}
break;
}
} }

View File

@ -11,6 +11,13 @@ extern "C" {
#include <__stddef_size_t.h> #include <__stddef_size_t.h>
enum class multidraw_mode_t: int {
Auto = 0,
PreferIndirect,
PreferUnroll,
PreferMultidrawIndirect
};
struct global_settings_t { struct global_settings_t {
int angle; // 0, 1 int angle; // 0, 1
int ignore_error; // 0, 1, 2 int ignore_error; // 0, 1, 2
@ -18,12 +25,14 @@ struct global_settings_t {
int ext_compute_shader; // 0, 1 int ext_compute_shader; // 0, 1
size_t max_glsl_cache_size; // 0~ size_t max_glsl_cache_size; // 0~
int enable_compatible_mode; // 0, 1 int enable_compatible_mode; // 0, 1
multidraw_mode_t multidraw_mode; // 0, 1, 2, 3
}; };
extern struct global_settings_t global_settings; extern struct global_settings_t global_settings;
void init_settings(); void init_settings();
void init_settings_post();
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -14,6 +14,141 @@ GLuint g_indirectbuffer = 0;
#define DRAW_INDIRECT #define DRAW_INDIRECT
void prepare_indirect_buffer(const GLsizei *counts, GLenum type, const void *const *indices,
GLsizei primcount, const GLint *basevertex) {
if (!g_indirect_cmds_inited) {
GLES.glGenBuffers(1, &g_indirectbuffer);
GLES.glBindBuffer(GL_DRAW_INDIRECT_BUFFER, g_indirectbuffer);
g_cmdbufsize = 1;
GLES.glBufferData(GL_DRAW_INDIRECT_BUFFER,
g_cmdbufsize * sizeof(draw_elements_indirect_command_t), NULL, GL_DYNAMIC_DRAW);
g_indirect_cmds_inited = true;
}
if (g_cmdbufsize < primcount) {
size_t sz = g_cmdbufsize;
LOG_D("Before resize: %d", sz)
// 2-exponential to reduce reallocation
while (sz < primcount)
sz *= 2;
GLES.glBufferData(GL_DRAW_INDIRECT_BUFFER,
sz * sizeof(draw_elements_indirect_command_t), NULL, GL_DYNAMIC_DRAW);
g_cmdbufsize = sz;
}
LOG_D("After resize: %d", g_cmdbufsize)
auto* pcmds = (draw_elements_indirect_command_t*)
GLES.glMapBufferRange(GL_DRAW_INDIRECT_BUFFER,
0, primcount * sizeof(draw_elements_indirect_command_t),
GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
GLsizei elementSize;
switch (type) {
case GL_UNSIGNED_BYTE:
elementSize = 1;
break;
case GL_UNSIGNED_SHORT:
elementSize = 2;
break;
case GL_UNSIGNED_INT:
elementSize = 4;
break;
default:
elementSize = 4;
}
for (GLsizei i = 0; i < primcount; ++i) {
auto byteOffset = reinterpret_cast<uintptr_t>(indices[i]);
pcmds[i].firstIndex = static_cast<GLuint>(byteOffset / elementSize);
pcmds[i].count = counts[i];
pcmds[i].instanceCount = 1;
pcmds[i].baseVertex = basevertex[i];
pcmds[i].reservedMustBeZero = 0;
}
GLES.glUnmapBuffer(GL_DRAW_INDIRECT_BUFFER);
}
void mg_glMultiDrawElementsBaseVertex_indirect(GLenum mode, GLsizei* counts, GLenum type, const void* const* indices, GLsizei primcount, const GLint* basevertex) {
LOG()
prepare_indirect_buffer(counts, type, indices, primcount, basevertex);
// Draw indirect!
for (GLsizei i = 0; i < primcount; ++i) {
const GLvoid* offset = reinterpret_cast<GLvoid*>(i * sizeof(draw_elements_indirect_command_t));
GLES.glDrawElementsIndirect(mode, type, offset);
}
CHECK_GL_ERROR
}
void mg_glMultiDrawElementsBaseVertex_multiindirect(GLenum mode, GLsizei* counts, GLenum type, const void* const* indices, GLsizei primcount, const GLint* basevertex) {
LOG()
prepare_indirect_buffer(counts, type, indices, primcount, basevertex);
// Multi-draw indirect!
GLES.glMultiDrawElementsIndirectEXT(mode, type, 0, primcount, 0);
CHECK_GL_ERROR
}
void mg_glMultiDrawElementsBaseVertex_unroll(GLenum mode, GLsizei* counts, GLenum type, const void* const* indices, GLsizei primcount, const GLint* basevertex) {
LOG()
for (GLsizei i = 0; i < primcount; ++i) {
const GLsizei count = counts[i];
if (count > 0) {
LOG_D("GLES.glDrawElementsBaseVertex, mode = %s, count = %d, type = %s, indices[i] = 0x%x, basevertex[i] = %d",
glEnumToString(mode), count, glEnumToString(type), indices[i], basevertex[i])
GLES.glDrawElementsBaseVertex(mode, count, type, indices[i], basevertex[i]);
}
}
CHECK_GL_ERROR
}
void mg_glMultiDrawElements_indirect(GLenum mode, const GLsizei *count, GLenum type, const void *const *indices, GLsizei primcount) {
LOG()
prepare_indirect_buffer(count, type, indices, primcount, 0);
// Draw indirect!
for (GLsizei i = 0; i < primcount; ++i) {
const GLvoid* offset = reinterpret_cast<GLvoid*>(i * sizeof(draw_elements_indirect_command_t));
GLES.glDrawElementsIndirect(mode, type, offset);
}
CHECK_GL_ERROR
}
void mg_glMultiDrawElements_multiindirect(GLenum mode, const GLsizei *count, GLenum type, const void *const *indices, GLsizei primcount) {
LOG()
prepare_indirect_buffer(count, type, indices, primcount, 0);
// Multi-draw indirect!
GLES.glMultiDrawElementsIndirectEXT(mode, type, 0, primcount, 0);
CHECK_GL_ERROR
}
void mg_glMultiDrawElements_unroll(GLenum mode, const GLsizei *count, GLenum type, const void *const *indices, GLsizei primcount) {
LOG()
for (GLsizei i = 0; i < primcount; ++i) {
const GLsizei c = count[i];
if (c > 0) {
GLES.glDrawElements(mode, c, type, indices[i]);
}
}
CHECK_GL_ERROR
}
void glMultiDrawElementsBaseVertex(GLenum mode, GLsizei* counts, GLenum type, const void* const* indices, GLsizei primcount, const GLint* basevertex) { void glMultiDrawElementsBaseVertex(GLenum mode, GLsizei* counts, GLenum type, const void* const* indices, GLsizei primcount, const GLint* basevertex) {
LOG() LOG()

View File

@ -31,6 +31,18 @@ struct draw_elements_indirect_command_t {
GLAPI GLAPIENTRY void glMultiDrawElementsBaseVertex(GLenum mode, GLsizei *counts, GLenum type, const void *const *indices, GLsizei primcount, const GLint *basevertex); GLAPI GLAPIENTRY void glMultiDrawElementsBaseVertex(GLenum mode, GLsizei *counts, GLenum type, const void *const *indices, GLsizei primcount, const GLint *basevertex);
GLAPI GLAPIENTRY void mg_glMultiDrawElementsBaseVertex_indirect(GLenum mode, GLsizei *counts, GLenum type, const void *const *indices, GLsizei primcount, const GLint *basevertex);
GLAPI GLAPIENTRY void mg_glMultiDrawElementsBaseVertex_multiindirect(GLenum mode, GLsizei *counts, GLenum type, const void *const *indices, GLsizei primcount, const GLint *basevertex);
GLAPI GLAPIENTRY void mg_glMultiDrawElementsBaseVertex_unroll(GLenum mode, GLsizei *counts, GLenum type, const void *const *indices, GLsizei primcount, const GLint *basevertex);
GLAPI GLAPIENTRY void mg_glMultiDrawElements_indirect(GLenum mode, const GLsizei *count, GLenum type, const void *const *indices, GLsizei primcount);
GLAPI GLAPIENTRY void mg_glMultiDrawElements_multiindirect(GLenum mode, const GLsizei *count, GLenum type, const void *const *indices, GLsizei primcount);
GLAPI GLAPIENTRY void mg_glMultiDrawElements_unroll(GLenum mode, const GLsizei *count, GLenum type, const void *const *indices, GLsizei primcount);
GLAPI GLAPIENTRY void glMultiDrawElements(GLenum mode, const GLsizei *count, GLenum type, const void *const *indices, GLsizei primcount); GLAPI GLAPIENTRY void glMultiDrawElements(GLenum mode, const GLsizei *count, GLenum type, const void *const *indices, GLsizei primcount);
GLAPI GLAPIENTRY void glDrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices); GLAPI GLAPIENTRY void glDrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices);

View File

@ -138,6 +138,9 @@ void InitGLESCapabilities() {
InitGLESBaseExtensions(); InitGLESBaseExtensions();
GLES.glGetIntegerv(GL_MAJOR_VERSION, &g_gles_caps.major);
GLES.glGetIntegerv(GL_MINOR_VERSION, &g_gles_caps.minor);
// int has_GL_EXT_buffer_storage = 0; // int has_GL_EXT_buffer_storage = 0;
// int has_GL_ARB_timer_query = 0; // int has_GL_ARB_timer_query = 0;
// int has_GL_QCOM_texture_lod_bias = 0; // int has_GL_QCOM_texture_lod_bias = 0;
@ -577,13 +580,13 @@ void init_target_gles() {
INIT_GLES_FUNC(glMultiDrawArraysIndirectEXT) INIT_GLES_FUNC(glMultiDrawArraysIndirectEXT)
INIT_GLES_FUNC(glMultiDrawElementsIndirectEXT) INIT_GLES_FUNC(glMultiDrawElementsIndirectEXT)
INIT_GLES_FUNC(glMultiDrawElementsBaseVertexEXT) INIT_GLES_FUNC(glMultiDrawElementsBaseVertexEXT)
INIT_GLES_FUNC(glBruh) // INIT_GLES_FUNC(glBruh)
LOG_D("glMultiDrawArraysIndirectEXT() @ 0x%x", GLES.glMultiDrawArraysIndirectEXT) LOG_D("glMultiDrawArraysIndirectEXT() @ 0x%x", GLES.glMultiDrawArraysIndirectEXT)
LOG_D("glMultiDrawElementsIndirectEXT() @ 0x%x", GLES.glMultiDrawElementsIndirectEXT) LOG_D("glMultiDrawElementsIndirectEXT() @ 0x%x", GLES.glMultiDrawElementsIndirectEXT)
LOG_D("glMultiDrawElementsBaseVertexEXT() @ 0x%x", GLES.glMultiDrawElementsBaseVertexEXT) LOG_D("glMultiDrawElementsBaseVertexEXT() @ 0x%x", GLES.glMultiDrawElementsBaseVertexEXT)
LOG_D("glBruh() @ 0x%x", GLES.glBruh) // LOG_D("glBruh() @ 0x%x", GLES.glBruh)
LOG_D("Initializing %s @ hardware", RENDERERNAME) LOG_D("Initializing %s @ hardware", RENDERERNAME)
set_hardware(); set_hardware();

View File

@ -137,6 +137,8 @@ extern "C" GLAPI GLAPIENTRY type name(__VA_ARGS__) { \
} }
struct gles_caps_t { struct gles_caps_t {
int major;
int minor;
int GL_EXT_buffer_storage; int GL_EXT_buffer_storage;
int GL_EXT_disjoint_timer_query; int GL_EXT_disjoint_timer_query;
int GL_QCOM_texture_lod_bias; int GL_QCOM_texture_lod_bias;

View File

@ -11,12 +11,44 @@
#include "../includes.h" #include "../includes.h"
#include "../gl/log.h" #include "../gl/log.h"
#include "../gl/envvars.h" #include "../gl/envvars.h"
#include "../config/settings.h"
#define DEBUG 0 #define DEBUG 0
void* get_multidraw_func(const char* name) {
std::string namestr = name;
if (namestr != "glMultiDrawElementsBaseVertex" && namestr != "glMultiDrawElements") {
return nullptr;
} else {
namestr = "mg_" + namestr;
}
switch (global_settings.multidraw_mode) {
case multidraw_mode_t::PreferIndirect:
namestr += "_indirect";
break;
case multidraw_mode_t::PreferUnroll:
namestr += "_unroll";
break;
case multidraw_mode_t::PreferMultidrawIndirect:
namestr += "_multiindirect";
break;
default:
LOG_W("get_multidraw_func() cannot determine multidraw emulation mode!")
return nullptr;
}
return dlsym(RTLD_DEFAULT, namestr.c_str());
}
void *glXGetProcAddress(const char *name) { void *glXGetProcAddress(const char *name) {
LOG() LOG()
void* proc = dlsym(RTLD_DEFAULT, (const char*)name); void* proc = nullptr;
proc = get_multidraw_func(name);
if (!proc)
proc = dlsym(RTLD_DEFAULT, (const char*)name);
if (!proc) { if (!proc) {
fprintf(stderr, "Failed to get OpenGL function %s: %s\n", name, dlerror()); fprintf(stderr, "Failed to get OpenGL function %s: %s\n", name, dlerror());
@ -29,7 +61,12 @@ void *glXGetProcAddress(const char *name) {
void *glXGetProcAddressARB(const char *name) { void *glXGetProcAddressARB(const char *name) {
LOG() LOG()
void* proc = dlsym(RTLD_DEFAULT, (const char*)name); void* proc = nullptr;
proc = get_multidraw_func(name);
if (!proc)
proc = dlsym(RTLD_DEFAULT, (const char*)name);
if (!proc) { if (!proc) {
fprintf(stderr, "Failed to get OpenGL function %s: %s\n", name, dlerror()); fprintf(stderr, "Failed to get OpenGL function %s: %s\n", name, dlerror());

View File

@ -76,6 +76,8 @@ void proc_init() {
init_target_egl(); init_target_egl();
init_target_gles(); init_target_gles();
init_settings_post();
init_libshaderconv(); init_libshaderconv();
#if PROFILING #if PROFILING

View File

@ -13,7 +13,7 @@
#define REVISION 2 #define REVISION 2
#define PATCH 0 #define PATCH 0
#define VERSION_TYPE VERSION_RELEASE #define VERSION_TYPE VERSION_DEVELOPMENT
#define VERSION_SUFFIX "" #define VERSION_SUFFIX ""