[Optimization] (multidraw, compute): miniature draw command ssbo

This commit is contained in:
Swung0x48 2025-04-24 20:35:30 +08:00
parent da9d3952c0
commit 079fcaa06b
2 changed files with 74 additions and 8 deletions

View File

@ -71,6 +71,67 @@ void prepare_indirect_buffer(const GLsizei *counts, GLenum type, const void *con
GLES.glUnmapBuffer(GL_DRAW_INDIRECT_BUFFER);
}
static bool g_drawssbo_inited = false;
static GLsizei g_drawssbo_size = 0;
GLuint g_drawssbo = 0;
void prepare_compute_drawcmd_ssbo(const GLsizei *counts, GLenum type, const void *const *indices,
GLsizei primcount, const GLint *basevertex) {
if (!g_drawssbo_inited) {
GLES.glGenBuffers(1, &g_drawssbo);
GLES.glBindBuffer(GL_DRAW_INDIRECT_BUFFER, g_drawssbo);
g_drawssbo_size = 1;
GLES.glBufferData(GL_DRAW_INDIRECT_BUFFER,
g_drawssbo_size * sizeof(drawcmd_compute_t), NULL, GL_DYNAMIC_DRAW);
g_drawssbo_inited = true;
}
if (g_drawssbo_size < primcount) {
size_t sz = g_drawssbo_size;
LOG_D("Before resize: %d", sz)
// 2-exponential to reduce reallocation
while (sz < primcount)
sz *= 2;
GLES.glBufferData(GL_DRAW_INDIRECT_BUFFER,
sz * sizeof(drawcmd_compute_t), NULL, GL_DYNAMIC_DRAW);
g_drawssbo_size = sz;
}
LOG_D("After resize: %d", g_drawssbo_size)
auto* pcmds = (drawcmd_compute_t*)
GLES.glMapBufferRange(GL_DRAW_INDIRECT_BUFFER,
0, primcount * sizeof(drawcmd_compute_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].baseVertex = basevertex ? basevertex[i] : 0;
}
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()
@ -250,11 +311,11 @@ R"(#version 310 es
layout(local_size_x = 64) in;
struct DrawCommand {
uint count;
uint instanceCount;
// uint count;
// uint instanceCount;
uint firstIndex;
int baseVertex;
uint reservedMustBeZero;
// uint reservedMustBeZero;
};
layout(std430, binding = 0) readonly buffer Input { uint in_indices[]; };
@ -295,7 +356,6 @@ void main() {
// Write out
out_indices[outIdx] = uint(int(in_indices[inIndex]) + cmd.baseVertex);
// out_indices[outIdx] = uint(cmd.baseVertex);
}
)";
@ -367,7 +427,8 @@ GLAPI GLAPIENTRY void mg_glMultiDrawElementsBaseVertex_compute(
// TODO: support `types` other than GL_UNSIGNED_INT
// Align compute shader input format with standard OpenGL indirect-draw format
prepare_indirect_buffer(counts, type, indices, primcount, basevertex);
// prepare_indirect_buffer(counts, type, indices, primcount, basevertex);
prepare_compute_drawcmd_ssbo(counts, type, indices, primcount, basevertex);
// Init compute buffers
if (!g_compute_inited) {
@ -381,8 +442,8 @@ GLAPI GLAPIENTRY void mg_glMultiDrawElementsBaseVertex_compute(
}
// Resize prefix sum buffer if needed
if (g_prefix_sum.size() < g_cmdbufsize)
g_prefix_sum.resize(g_cmdbufsize);
if (g_prefix_sum.size() < g_drawssbo_size)
g_prefix_sum.resize(g_drawssbo_size);
// Calculate prefix sum
g_prefix_sum[0] = counts[0];
@ -414,7 +475,7 @@ GLAPI GLAPIENTRY void mg_glMultiDrawElementsBaseVertex_compute(
// Bind buffers
GLES.glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, ibo);
CHECK_GL_ERROR_NO_INIT
GLES.glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, g_indirectbuffer);
GLES.glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, g_drawssbo);
CHECK_GL_ERROR_NO_INIT
GLES.glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, g_prefixsumbuffer);
CHECK_GL_ERROR_NO_INIT

View File

@ -28,6 +28,11 @@ struct draw_elements_indirect_command_t {
GLuint reservedMustBeZero;
};
struct drawcmd_compute_t {
GLuint firstIndex;
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);