Skip to content

Commit 8dfdcf1

Browse files
committed
Add order-preserving draw optimization
Between no merging of draw calls at all and aggressively merging draw commands in a way that the draw order differs from the submission order, there's the possibility of a conservative order-preserving optimization. This merges any contiguous sequence of draw calls that have the same batch key into a single vertex buffer and drawing them together. This reduces the number of GPU draw calls submitted, yielding decent frame rate gains.
1 parent b314bc3 commit 8dfdcf1

1 file changed

Lines changed: 41 additions & 4 deletions

File tree

engine/render/r_main.cpp

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ void Batch::Execute()
303303

304304
void r_layer_c::Render()
305305
{
306-
bool const optimize = renderer->r_layerOptimize->intVal == 1;
306+
int const optLevel = renderer->r_layerOptimize->intVal;
307307
bool const shuffle = renderer->r_layerShuffle->intVal == 1;
308308

309309
struct BatchKey {
@@ -369,11 +369,16 @@ void r_layer_c::Render()
369369
case r_layerCmd_s::QUAD: {
370370
Batch* batch{};
371371
auto I = batchIndices.find(currentKey);
372-
if (I != batchIndices.end() && optimize) {
372+
if (I != batchIndices.end() && optLevel == 1 && I->second == batches.size() - 1) {
373+
// Append to last batch if it matches our key.
374+
batch = &batches[I->second];
375+
}
376+
else if (I != batchIndices.end() && optLevel == 2) {
377+
// Fill earlier batches, even if it leads to order problems.
373378
batch = &batches[I->second];
374379
}
375380
else {
376-
batchIndices.insert(I, { currentKey, batches.size() });
381+
batchIndices.insert_or_assign(I, currentKey, batches.size());
377382
batchKeys.push_back(currentKey);
378383
batches.emplace_back(prog);
379384
batch = &batches.back();
@@ -416,12 +421,30 @@ void r_layer_c::Render()
416421
}
417422
}
418423

424+
bool showStats{};
425+
if (renderer->debugLayers) {
426+
if (ImGui::Begin("Layers", &renderer->debugLayers)) {
427+
GLint maxTextureUnits{};
428+
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
429+
ImGui::Text("Max texture units: %d", maxTextureUnits);
430+
ImGui::BulletText("Layer %d:%d - %d batches", layer, subLayer, numBatches);
431+
std::string heading = fmt::format("Layer {}:{}", layer, subLayer);
432+
showStats = ImGui::CollapsingHeader(heading.c_str(), ImGuiTreeNodeFlags_DefaultOpen);
433+
}
434+
}
419435
for (int i = 0; i < numBatches; ++i) {
420436
auto& batch = batches[batchPermutation[i]];
421437
auto& key = batchKeys[batchPermutation[i]];
438+
if (showStats) {
439+
ImGui::Text("Batch %d", batchPermutation[i]);
440+
ImGui::Text("%d verts", batch.vertices.size());
441+
}
422442
if (!lastKey || lastKey->viewport.x != key.viewport.x || lastKey->viewport.y != key.viewport.y ||
423443
lastKey->viewport.width != key.viewport.width || lastKey->viewport.height != key.viewport.height)
424444
{
445+
if (showStats) {
446+
ImGui::Text("New viewport %dx%d @ %d,%d", key.viewport.width, key.viewport.height, key.viewport.x, key.viewport.y);
447+
}
425448
auto& vid = renderer->sys->video->vid;
426449
float fbScaleX = vid.fbSize[0] / (float)vid.size[0];
427450
float fbScaleY = vid.fbSize[1] / (float)vid.size[1];
@@ -436,6 +459,14 @@ void r_layer_c::Render()
436459
glUniformMatrix4fv(mvpMatrixLoc, 1, GL_FALSE, mvpMatrix.data());
437460
}
438461
if (!lastKey || lastKey->blendMode != key.blendMode) {
462+
if (showStats) {
463+
static std::map<r_blendMode_e, char const*> const blendModeString{
464+
{RB_ALPHA, "RB_ALPHA"},
465+
{RB_PRE_ALPHA, "RB_PRE_ALPHA"},
466+
{RB_ADDITIVE, "RB_ADDITIVE"},
467+
};
468+
ImGui::Text("New blend mode %s", blendModeString.at((r_blendMode_e)key.blendMode));
469+
}
439470
switch (key.blendMode) {
440471
case RB_ALPHA:
441472
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@@ -449,6 +480,9 @@ void r_layer_c::Render()
449480
}
450481
}
451482
if (!lastKey || lastKey->tex != key.tex) {
483+
if (showStats) {
484+
ImGui::Text("New tex %d (%s)", key.tex->texId, key.tex->fileName.c_str());
485+
}
452486
key.tex->Bind();
453487
}
454488

@@ -457,6 +491,9 @@ void r_layer_c::Render()
457491
lastKey = key;
458492
}
459493
glUseProgram(0);
494+
if (renderer->debugLayers) {
495+
ImGui::End();
496+
}
460497

461498
for (int i = 0; i < numCmd; i++) {
462499
r_layerCmd_s* cmd = cmdList[i];
@@ -492,7 +529,7 @@ r_renderer_c::r_renderer_c(sys_IMain* sysHnd)
492529
r_compress = sys->con->Cvar_Add("r_compress", CV_ARCHIVE, "0");
493530
r_screenshotFormat = sys->con->Cvar_Add("r_screenshotFormat", CV_ARCHIVE, "jpg");
494531
r_layerDebug = sys->con->Cvar_Add("r_layerDebug", CV_ARCHIVE, "0");
495-
r_layerOptimize = sys->con->Cvar_Add("r_layerOptimize", CV_ARCHIVE | CV_CLAMP, "0", 0, 1);
532+
r_layerOptimize = sys->con->Cvar_Add("r_layerOptimize", CV_ARCHIVE | CV_CLAMP, "0", 0, 2);
496533
r_layerShuffle = sys->con->Cvar_Add("r_layerShuffle", CV_ARCHIVE | CV_CLAMP, "0", 0, 1);
497534

498535
Cmd_Add("screenshot", 0, "[<format>]", this, &r_renderer_c::C_Screenshot);

0 commit comments

Comments
 (0)