[Feat] (...): Add "DrawElements" multi-draw mode.

This commit is contained in:
BZLZHH 2025-04-03 17:01:00 +08:00
parent 77450d6e4c
commit d609b8ceab
5 changed files with 134 additions and 38 deletions

View File

@ -42,7 +42,7 @@ void init_settings() {
enableExtComputeShader = 0;
if (enableCompatibleMode < 0 || enableCompatibleMode > 1)
enableCompatibleMode = 0;
if ((int)multidrawMode < 0 || (int)multidrawMode > 3)
if ((int)multidrawMode < 0 || (int)multidrawMode > 4)
multidrawMode = multidraw_mode_t::Auto;
// 1205
@ -138,6 +138,9 @@ void init_settings() {
case multidraw_mode_t::PreferMultidrawIndirect:
draw_mode_str = "Multidraw indirect";
break;
case multidraw_mode_t::DrawElements:
draw_mode_str = "DrawElements";
break;
case multidraw_mode_t::Auto:
draw_mode_str = "Auto";
break;
@ -166,8 +169,13 @@ void init_settings_post() {
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)")
if (indirect) {
global_settings.multidraw_mode = multidraw_mode_t::PreferIndirect;
LOG_V(" -> Indirect (OK)")
} else {
global_settings.multidraw_mode = multidraw_mode_t::DrawElements;
LOG_V(" -> DrawElements (Preferred not supported, falling back)")
}
break;
case multidraw_mode_t::PreferBaseVertex:
LOG_V("multidrawMode = PreferUnroll")
@ -177,20 +185,30 @@ void init_settings_post() {
} else if (multidraw) {
global_settings.multidraw_mode = multidraw_mode_t::PreferMultidrawIndirect;
LOG_V(" -> MultidrawIndirect (Preferred not supported, falling back)")
} else {
} else if (indirect) {
global_settings.multidraw_mode = multidraw_mode_t::PreferIndirect;
LOG_V(" -> Indirect (Preferred not supported, falling back)")
} else {
global_settings.multidraw_mode = multidraw_mode_t::DrawElements;
LOG_V(" -> DrawElements (Preferred not supported, falling back)")
}
break;
case multidraw_mode_t::DrawElements:
LOG_V("multidrawMode = DrawElements")
global_settings.multidraw_mode = multidraw_mode_t::DrawElements;
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 {
} else if (indirect) {
global_settings.multidraw_mode = multidraw_mode_t::PreferIndirect;
LOG_V(" -> Indirect")
LOG_V(" -> Indirect (Preferred not supported, falling back)")
} else {
global_settings.multidraw_mode = multidraw_mode_t::DrawElements;
LOG_V(" -> DrawElements (Preferred not supported, falling back)")
}
break;
}

View File

@ -15,7 +15,8 @@ enum class multidraw_mode_t: int {
Auto = 0,
PreferIndirect,
PreferBaseVertex,
PreferMultidrawIndirect
PreferMultidrawIndirect,
DrawElements
};
struct global_settings_t {
@ -25,7 +26,7 @@ struct global_settings_t {
int ext_compute_shader; // 0, 1
size_t max_glsl_cache_size; // 0~
int enable_compatible_mode; // 0, 1
multidraw_mode_t multidraw_mode; // 0, 1, 2, 3
multidraw_mode_t multidraw_mode; // 0, 1, 2, 3, 4
};
extern struct global_settings_t global_settings;

View File

@ -12,8 +12,6 @@ static bool g_indirect_cmds_inited = false;
static GLsizei g_cmdbufsize = 0;
GLuint g_indirectbuffer = 0;
#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) {
@ -74,6 +72,91 @@ void prepare_indirect_buffer(const GLsizei *counts, GLenum type, const void *con
GLES.glUnmapBuffer(GL_DRAW_INDIRECT_BUFFER);
}
void mg_glMultiDrawElementsBaseVertex_drawelements(GLenum mode, GLsizei* counts, GLenum type, const void* const* indices, GLsizei primcount, const GLint* basevertex) {
LOG()
GLint prevElementBuffer;
GLES.glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &prevElementBuffer);
for (GLsizei i = 0; i < primcount; ++i) {
if (counts[i] <= 0) continue;
GLsizei currentCount = counts[i];
const GLvoid *currentIndices = indices[i];
GLint currentBaseVertex = basevertex[i];
size_t indexSize;
switch (type) {
case GL_UNSIGNED_INT: indexSize = sizeof(GLuint); break;
case GL_UNSIGNED_SHORT: indexSize = sizeof(GLushort); break;
case GL_UNSIGNED_BYTE: indexSize = sizeof(GLubyte); break;
default: return;
}
GLuint tempBuffer;
GLES.glGenBuffers(1, &tempBuffer);
GLES.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, tempBuffer);
void *srcData = nullptr;
void *tempIndices = malloc(currentCount * indexSize);
if (!tempIndices) {
GLES.glDeleteBuffers(1, &tempBuffer);
continue;
}
if (prevElementBuffer != 0) {
GLES.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, prevElementBuffer);
srcData = GLES.glMapBufferRange(
GL_ELEMENT_ARRAY_BUFFER,
(GLintptr)currentIndices,
currentCount * indexSize,
GL_MAP_READ_BIT
);
if (!srcData) {
free(tempIndices);
GLES.glDeleteBuffers(1, &tempBuffer);
continue;
}
} else {
srcData = (void*)currentIndices;
}
switch (type) {
case GL_UNSIGNED_INT:
for (int j = 0; j < currentCount; ++j) {
((GLuint *)tempIndices)[j] = ((GLuint *)srcData)[j] + currentBaseVertex;
}
break;
case GL_UNSIGNED_SHORT:
for (int j = 0; j < currentCount; ++j) {
((GLushort *)tempIndices)[j] = ((GLushort *)srcData)[j] + currentBaseVertex;
}
break;
case GL_UNSIGNED_BYTE:
for (int j = 0; j < currentCount; ++j) {
((GLubyte *)tempIndices)[j] = ((GLubyte *)srcData)[j] + currentBaseVertex;
}
break;
}
if (prevElementBuffer != 0) {
GLES.glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
}
GLES.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, tempBuffer);
GLES.glBufferData(GL_ELEMENT_ARRAY_BUFFER, currentCount * indexSize, tempIndices, GL_STREAM_DRAW);
free(tempIndices);
GLES.glDrawElements(mode, currentCount, type, 0);
GLES.glDeleteBuffers(1, &tempBuffer);
}
GLES.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, prevElementBuffer);
CHECK_GL_ERROR
}
void mg_glMultiDrawElementsBaseVertex_indirect(GLenum mode, GLsizei* counts, GLenum type, const void* const* indices, GLsizei primcount, const GLint* basevertex) {
LOG()
@ -125,6 +208,19 @@ void mg_glMultiDrawElements_indirect(GLenum mode, const GLsizei *count, GLenum t
CHECK_GL_ERROR
}
void mg_glMultiDrawElements_drawelements(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 mg_glMultiDrawElements_multiindirect(GLenum mode, const GLsizei *count, GLenum type, const void *const *indices, GLsizei primcount) {
LOG()
@ -152,8 +248,6 @@ void mg_glMultiDrawElements_basevertex(GLenum mode, const GLsizei *count, GLenum
void glMultiDrawElementsBaseVertex(GLenum mode, GLsizei* counts, GLenum type, const void* const* indices, GLsizei primcount, const GLint* basevertex) {
LOG()
#ifdef DRAW_INDIRECT
if (!g_indirect_cmds_inited) {
GLES.glGenBuffers(1, &g_indirectbuffer);
GLES.glBindBuffer(GL_DRAW_INDIRECT_BUFFER, g_indirectbuffer);
@ -217,26 +311,12 @@ void glMultiDrawElementsBaseVertex(GLenum mode, GLsizei* counts, GLenum type, co
GLES.glDrawElementsIndirect(mode, type, offset);
}
#else
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]);
}
}
#endif
CHECK_GL_ERROR
}
void glMultiDrawElements(GLenum mode, const GLsizei* count, GLenum type, const void* const* indices, GLsizei primcount) {
LOG()
#ifdef DRAW_INDIRECT
if (!g_indirect_cmds_inited) {
GLES.glGenBuffers(1, &g_indirectbuffer);
GLES.glBindBuffer(GL_DRAW_INDIRECT_BUFFER, g_indirectbuffer);
@ -300,16 +380,6 @@ void glMultiDrawElements(GLenum mode, const GLsizei* count, GLenum type, const v
GLES.glDrawElementsIndirect(mode, type, offset);
}
#else
for (GLsizei i = 0; i < primcount; ++i) {
const GLsizei c = count[i];
if (c > 0) {
GLES.glDrawElements(mode, c, type, indices[i]);
}
}
#endif
}
// solve the crash error for ANGLE, but it will make Derivative Main with Optifine not work!

View File

@ -37,12 +37,16 @@ GLAPI GLAPIENTRY void mg_glMultiDrawElementsBaseVertex_multiindirect(GLenum mode
GLAPI GLAPIENTRY void mg_glMultiDrawElementsBaseVertex_basevertex(GLenum mode, GLsizei *counts, GLenum type, const void *const *indices, GLsizei primcount, const GLint *basevertex);
GLAPI GLAPIENTRY void mg_glMultiDrawElementsBaseVertex_drawelements(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_basevertex(GLenum mode, const GLsizei *count, GLenum type, const void *const *indices, GLsizei primcount);
GLAPI GLAPIENTRY void mg_glMultiDrawElements_drawelements(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);

View File

@ -33,6 +33,9 @@ void* get_multidraw_func(const char* name) {
case multidraw_mode_t::PreferMultidrawIndirect:
namestr += "_multiindirect";
break;
case multidraw_mode_t::DrawElements:
namestr += "_drawelements";
break;
default:
LOG_W("get_multidraw_func() cannot determine multidraw emulation mode!")
return nullptr;
@ -52,7 +55,7 @@ void *glXGetProcAddress(const char *name) {
if (!proc) {
fprintf(stderr, "Failed to get OpenGL function %s: %s\n", name, dlerror());
LOG_W("Failed to get OpenGL function: %s", (const char*)name);
LOG_W("Failed to get OpenGL function: %s", (const char*)name)
return NULL;
}
@ -70,7 +73,7 @@ void *glXGetProcAddressARB(const char *name) {
if (!proc) {
fprintf(stderr, "Failed to get OpenGL function %s: %s\n", name, dlerror());
LOG_W("Failed to get OpenGL function: %s", (const char*)name);
LOG_W("Failed to get OpenGL function: %s", (const char*)name)
return NULL;
}