From a28b333899b665696873e62c96e5f20bbd0a51d2 Mon Sep 17 00:00:00 2001 From: bjorn Date: Fri, 29 Mar 2019 16:49:41 +0900 Subject: [PATCH] Split draw data stream into two streams; Also the max number of draws can be hardcoded to 256 now. --- src/graphics/graphics.c | 68 ++++++++++++++++++++++------------------- src/graphics/graphics.h | 14 ++++----- src/graphics/opengl.c | 6 +--- src/resources/shaders.c | 14 +++------ 4 files changed, 49 insertions(+), 53 deletions(-) diff --git a/src/graphics/graphics.c b/src/graphics/graphics.c index d907f2e8..f8919d68 100644 --- a/src/graphics/graphics.c +++ b/src/graphics/graphics.c @@ -34,9 +34,11 @@ static const uint32_t BUFFER_COUNTS[] = { [STREAM_INDEX] = 1 << 16, [STREAM_DRAW_ID] = (1 << 16) - 1, #ifdef LOVR_WEBGL // Temporarily work around bug where big UBOs don't work - [STREAM_DRAW_DATA] = 768 + [STREAM_TRANSFORM] = MAX_DRAWS, + [STREAM_COLOR] = MAX_DRAWS #else - [STREAM_DRAW_DATA] = 256 * MAX_BATCHES * 2 + [STREAM_TRANSFORM] = MAX_DRAWS * MAX_BATCHES * 2, + [STREAM_COLOR] = MAX_DRAWS * MAX_BATCHES * 2 #endif }; @@ -44,14 +46,16 @@ static const size_t BUFFER_STRIDES[] = { [STREAM_VERTEX] = 8 * sizeof(float), [STREAM_INDEX] = sizeof(uint16_t), [STREAM_DRAW_ID] = sizeof(uint8_t), - [STREAM_DRAW_DATA] = sizeof(DrawData) + [STREAM_TRANSFORM] = 16 * sizeof(float), + [STREAM_COLOR] = 4 * sizeof(float) }; static const BufferType BUFFER_TYPES[] = { [STREAM_VERTEX] = BUFFER_VERTEX, [STREAM_INDEX] = BUFFER_INDEX, [STREAM_DRAW_ID] = BUFFER_GENERIC, - [STREAM_DRAW_DATA] = BUFFER_UNIFORM + [STREAM_TRANSFORM] = BUFFER_UNIFORM, + [STREAM_COLOR] = BUFFER_UNIFORM }; static void lovrGraphicsInitBuffers() { @@ -59,16 +63,12 @@ static void lovrGraphicsInitBuffers() { state.buffers[i] = lovrBufferCreate(BUFFER_COUNTS[i] * BUFFER_STRIDES[i], NULL, BUFFER_TYPES[i], USAGE_STREAM, false); } - // Compute the max number of draws per batch, since the hard cap of 256 won't always fit in a UBO - int maxBlockSize = lovrGpuGetLimits()->blockSize; - state.maxDraws = MIN(maxBlockSize / sizeof(DrawData) / 64 * 64, 256); - // The identity buffer is used for autoinstanced meshes and instanced primitives and maps the // instance ID to a vertex attribute. Its contents never change, so they are initialized here. - state.identityBuffer = lovrBufferCreate(256, NULL, BUFFER_VERTEX, USAGE_STATIC, false); + state.identityBuffer = lovrBufferCreate(MAX_DRAWS, NULL, BUFFER_VERTEX, USAGE_STATIC, false); uint8_t* id = lovrBufferMap(state.identityBuffer, 0); - for (int i = 0; i < 256; i++) id[i] = i; - lovrBufferFlushRange(state.identityBuffer, 0, 256); + for (int i = 0; i < MAX_DRAWS; i++) id[i] = i; + lovrBufferFlushRange(state.identityBuffer, 0, MAX_DRAWS); Buffer* vertexBuffer = state.buffers[STREAM_VERTEX]; size_t stride = BUFFER_STRIDES[STREAM_VERTEX]; @@ -498,7 +498,7 @@ void lovrGraphicsBatch(BatchRequest* req) { for (int i = state.batchCount - 1; i >= 0; i--) { Batch* b = &state.batches[i]; - if (b->cursors[STREAM_DRAW_DATA].count >= state.maxDraws) { continue; } + if (b->count >= MAX_DRAWS) { continue; } if (!areBatchParamsEqual(req->type, b->type, &req->params, &b->params)) { continue; } if (b->canvas == canvas && b->shader == shader && !memcmp(&b->pipeline, pipeline, sizeof(Pipeline)) && b->material == material) { batch = b; @@ -516,7 +516,7 @@ void lovrGraphicsBatch(BatchRequest* req) { if (!req->instanced || !batch) { *(req->vertices) = lovrGraphicsMapBuffer(STREAM_VERTEX, req->vertexCount); uint8_t* ids = lovrGraphicsMapBuffer(STREAM_DRAW_ID, req->vertexCount); - memset(ids, batch ? batch->cursors[STREAM_DRAW_DATA].count : 0, req->vertexCount * sizeof(uint8_t)); + memset(ids, batch ? batch->count : 0, req->vertexCount * sizeof(uint8_t)); if (req->indexCount > 0) { *(req->indices) = lovrGraphicsMapBuffer(STREAM_INDEX, req->indexCount); @@ -526,7 +526,9 @@ void lovrGraphicsBatch(BatchRequest* req) { // Start a new batch if (!batch) { - DrawData* drawData = lovrGraphicsMapBuffer(STREAM_DRAW_DATA, state.maxDraws); + float* transforms = lovrGraphicsMapBuffer(STREAM_TRANSFORM, MAX_DRAWS); + Color* colors = lovrGraphicsMapBuffer(STREAM_COLOR, MAX_DRAWS); + batch = &state.batches[state.batchCount++]; *batch = (Batch) { .type = req->type, @@ -536,34 +538,34 @@ void lovrGraphicsBatch(BatchRequest* req) { .shader = shader, .pipeline = *pipeline, .material = material, - .cursors[STREAM_VERTEX].start = state.cursors[STREAM_VERTEX], - .cursors[STREAM_INDEX].start = state.cursors[STREAM_INDEX], - .cursors[STREAM_DRAW_ID].start = state.cursors[STREAM_DRAW_ID], - .cursors[STREAM_DRAW_DATA].start = state.cursors[STREAM_DRAW_DATA], - .drawData = drawData, + .transforms = transforms, + .colors = colors, .instanced = req->instanced }; - state.cursors[STREAM_DRAW_DATA] += state.maxDraws; - } + for (int i = 0; i < MAX_BUFFER_ROLES; i++) { + batch->cursors[i].start = state.cursors[i]; + } - int drawId = batch->cursors[STREAM_DRAW_DATA].count; + state.cursors[STREAM_TRANSFORM] += MAX_DRAWS; + state.cursors[STREAM_COLOR] += MAX_DRAWS; + } // Transform if (req->transform) { float transform[16]; mat4_multiply(mat4_init(transform, state.transforms[state.transform]), req->transform); - memcpy(batch->drawData[drawId].transform, transform, 16 * sizeof(float)); + memcpy(&batch->transforms[16 * batch->count], transform, 16 * sizeof(float)); } else { - memcpy(batch->drawData[drawId].transform, state.transforms[state.transform], 16 * sizeof(float)); + memcpy(&batch->transforms[16 * batch->count], state.transforms[state.transform], 16 * sizeof(float)); } // Color Color color = state.color; gammaCorrectColor(&color); - batch->drawData[drawId].color = color; + batch->colors[batch->count] = color; - if (!req->instanced || drawId == 0) { + if (!req->instanced || batch->count == 0) { batch->cursors[STREAM_VERTEX].count += req->vertexCount; batch->cursors[STREAM_INDEX].count += req->indexCount; batch->cursors[STREAM_DRAW_ID].count += req->vertexCount; @@ -573,7 +575,9 @@ void lovrGraphicsBatch(BatchRequest* req) { state.cursors[STREAM_DRAW_ID] += req->vertexCount; } - batch->cursors[STREAM_DRAW_DATA].count++; + batch->cursors[STREAM_TRANSFORM].count++; + batch->cursors[STREAM_COLOR].count++; + batch->count++; } void lovrGraphicsFlush() { @@ -589,7 +593,7 @@ void lovrGraphicsFlush() { Batch* batch = &state.batches[b]; BatchParams* params = &batch->params; Mesh* mesh = batch->type == BATCH_MESH ? params->mesh.object : (batch->instanced ? state.instancedMesh : state.mesh); - int instances = batch->instanced ? batch->cursors[STREAM_DRAW_DATA].count : 1; + int instances = batch->instanced ? batch->cursors[STREAM_TRANSFORM].count : 1; // Flush buffers for (int i = 0; i < MAX_BUFFER_ROLES; i++) { @@ -599,9 +603,9 @@ void lovrGraphicsFlush() { } } - // Bind UBO - size_t drawDataOffset = batch->cursors[STREAM_DRAW_DATA].start * BUFFER_STRIDES[STREAM_DRAW_DATA]; - lovrShaderSetBlock(batch->shader, "lovrDrawData", state.buffers[STREAM_DRAW_DATA], drawDataOffset, state.maxDraws * BUFFER_STRIDES[STREAM_DRAW_DATA], ACCESS_READ); + // Bind UBOs + lovrShaderSetBlock(batch->shader, "lovrModelBlock", state.buffers[STREAM_TRANSFORM], batch->cursors[STREAM_TRANSFORM].start * BUFFER_STRIDES[STREAM_TRANSFORM], MAX_DRAWS * BUFFER_STRIDES[STREAM_TRANSFORM], ACCESS_READ); + lovrShaderSetBlock(batch->shader, "lovrColorBlock", state.buffers[STREAM_COLOR], batch->cursors[STREAM_COLOR].start * BUFFER_STRIDES[STREAM_COLOR], MAX_DRAWS * BUFFER_STRIDES[STREAM_COLOR], ACCESS_READ); // Uniforms lovrMaterialBind(batch->material, batch->shader); @@ -621,7 +625,7 @@ void lovrGraphicsFlush() { instances = params->mesh.instances; } else { lovrMeshSetAttributeEnabled(mesh, "lovrDrawID", true); - instances = batch->cursors[STREAM_DRAW_DATA].count; + instances = batch->count; } } else { bool indexed = batch->cursors[STREAM_INDEX].count > 0; diff --git a/src/graphics/graphics.h b/src/graphics/graphics.h index 59399a93..c23e492c 100644 --- a/src/graphics/graphics.h +++ b/src/graphics/graphics.h @@ -14,6 +14,7 @@ #define MAX_TRANSFORMS 64 #define MAX_BATCHES 16 +#define MAX_DRAWS 256 #define MAX_LOCKS 4 typedef void (*StencilCallback)(void* userdata); @@ -99,7 +100,8 @@ typedef enum { STREAM_VERTEX, STREAM_INDEX, STREAM_DRAW_ID, - STREAM_DRAW_DATA, + STREAM_TRANSFORM, + STREAM_COLOR, MAX_BUFFER_ROLES } BufferRole; @@ -155,11 +157,10 @@ typedef struct { Shader* shader; Pipeline pipeline; Material* material; - DrawData* drawData; - struct { - uint32_t start; - uint32_t count; - } cursors[MAX_BUFFER_ROLES]; + mat4 transforms; + Color* colors; + struct { uint32_t start; uint32_t count; } cursors[MAX_BUFFER_ROLES]; + uint32_t count; bool instanced; } Batch; @@ -182,7 +183,6 @@ typedef struct { Pipeline pipeline; float pointSize; Shader* shader; - uint32_t maxDraws; Mesh* mesh; Mesh* instancedMesh; Buffer* identityBuffer; diff --git a/src/graphics/opengl.c b/src/graphics/opengl.c index 7f982c7e..93b130a1 100644 --- a/src/graphics/opengl.c +++ b/src/graphics/opengl.c @@ -1869,13 +1869,9 @@ Shader* lovrShaderInitGraphics(Shader* shader, const char* vertexSource, const c "#extension GL_ARB_fragment_layer_viewport : require\n" "#define SINGLEPASS 1\n" : "#define SINGLEPASS 0\n"; - size_t maxDraws = MIN(state.limits.blockSize / (20 * sizeof(float)) / 64 * 64, 256); - char maxDrawSource[32]; - snprintf(maxDrawSource, 31, "#define MAX_DRAWS %zu\n", maxDraws); - // Vertex vertexSource = vertexSource == NULL ? lovrDefaultVertexShader : vertexSource; - const char* vertexSources[] = { vertexHeader, vertexSinglepass, maxDrawSource, lovrShaderVertexPrefix, vertexSource, lovrShaderVertexSuffix }; + const char* vertexSources[] = { vertexHeader, vertexSinglepass, lovrShaderVertexPrefix, vertexSource, lovrShaderVertexSuffix }; GLuint vertexShader = compileShader(GL_VERTEX_SHADER, vertexSources, sizeof(vertexSources) / sizeof(vertexSources[0])); // Fragment diff --git a/src/resources/shaders.c b/src/resources/shaders.c index 8d600018..2c5d0118 100644 --- a/src/resources/shaders.c +++ b/src/resources/shaders.c @@ -3,9 +3,10 @@ const char* lovrShaderVertexPrefix = "" "#define VERTEX VERTEX \n" "#define MAX_BONES 48 \n" +"#define MAX_DRAWS 256 \n" "#define lovrView lovrViews[lovrViewportIndex] \n" "#define lovrProjection lovrProjections[lovrViewportIndex] \n" -"#define lovrModel lovrDraws[lovrDrawID].model \n" +"#define lovrModel lovrModels[lovrDrawID] \n" "#define lovrTransform (lovrView * lovrModel) \n" "#define lovrNormalMatrix mat3(transpose(inverse(lovrTransform))) \n" "#define lovrInstanceID (gl_InstanceID / lovrViewportCount) \n" @@ -26,13 +27,8 @@ const char* lovrShaderVertexPrefix = "" "out vec2 texCoord; \n" "out vec4 vertexColor; \n" "out vec4 lovrColor; \n" -"struct DrawData { \n" -" mat4 model; \n" -" vec4 color; \n" -"}; \n" -"layout(std140) uniform lovrDrawData { \n" -" DrawData lovrDraws[MAX_DRAWS]; \n" -"}; \n" +"layout(std140) uniform lovrModelBlock { mat4 lovrModels[MAX_DRAWS]; }; \n" +"layout(std140) uniform lovrColorBlock { vec4 lovrColors[MAX_DRAWS]; }; \n" "uniform mat4 lovrViews[2]; \n" "uniform mat4 lovrProjections[2]; \n" "uniform mat3 lovrMaterialTransform; \n" @@ -50,7 +46,7 @@ const char* lovrShaderVertexSuffix = "" "void main() { \n" " texCoord = (lovrMaterialTransform * vec3(lovrTexCoord, 1.)).xy; \n" " vertexColor = lovrVertexColor; \n" -" lovrColor = lovrDraws[lovrDrawID].color; \n" +" lovrColor = lovrColors[lovrDrawID]; \n" "#if SINGLEPASS \n" " gl_ViewportIndex = gl_InstanceID % lovrViewportCount; \n" "#endif \n"