77#define GLAD_GLES2_IMPLEMENTATION
88#include " r_local.h"
99
10+ #include < array>
1011#include < fmt/chrono.h>
1112#include < map>
1213#include < numeric>
1314#include < random>
15+ #include < sodium.h>
1416#include < sstream>
1517#include < vector>
1618
@@ -424,9 +426,6 @@ void r_layer_c::Render()
424426 bool showStats{};
425427 if (renderer->debugLayers ) {
426428 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);
430429 ImGui::BulletText (" Layer %d:%d - %d batches" , layer, subLayer, numBatches);
431430 std::string heading = fmt::format (" Layer {}:{}" , layer, subLayer);
432431 showStats = ImGui::CollapsingHeader (heading.c_str (), ImGuiTreeNodeFlags_DefaultOpen);
@@ -509,6 +508,19 @@ void r_layer_c::Render()
509508 }
510509}
511510
511+ void r_layer_c::Discard ()
512+ {
513+ for (int i = 0 ; i < numCmd; i++) {
514+ r_layerCmd_s* cmd = cmdList[i];
515+ if (renderer->layerCmdBinCount == renderer->layerCmdBinSize ) {
516+ renderer->layerCmdBinSize <<= 1 ;
517+ trealloc (renderer->layerCmdBin , renderer->layerCmdBinSize );
518+ }
519+ renderer->layerCmdBin [renderer->layerCmdBinCount ++] = cmd;
520+ }
521+ numCmd = 0 ;
522+ }
523+
512524// =====================
513525// r_IRenderer Interface
514526// =====================
@@ -531,6 +543,7 @@ r_renderer_c::r_renderer_c(sys_IMain* sysHnd)
531543 r_layerDebug = sys->con ->Cvar_Add (" r_layerDebug" , CV_ARCHIVE , " 0" );
532544 r_layerOptimize = sys->con ->Cvar_Add (" r_layerOptimize" , CV_ARCHIVE | CV_CLAMP , " 0" , 0 , 2 );
533545 r_layerShuffle = sys->con ->Cvar_Add (" r_layerShuffle" , CV_ARCHIVE | CV_CLAMP , " 0" , 0 , 1 );
546+ r_elideFrames = sys->con ->Cvar_Add (" r_elideFrames" , CV_ARCHIVE | CV_CLAMP , " 1" , 0 , 1 );
534547
535548 Cmd_Add (" screenshot" , 0 , " [<format>]" , this , &r_renderer_c::C_Screenshot);
536549}
@@ -884,9 +897,6 @@ void r_renderer_c::BeginFrame()
884897 }
885898 }
886899
887- glBindFramebuffer (GL_FRAMEBUFFER , rttMain.framebuffer );
888- glClear (GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
889-
890900 curLayer = layerList[0 ];
891901
892902 SetViewport ();
@@ -912,6 +922,22 @@ static int layerCompFunc(const void* va, const void* vb)
912922 }
913923}
914924
925+ void CVarSliderInt (char const * label, conVar_c* cvar) {
926+ int curOpt = cvar->intVal ;
927+ if (ImGui::SliderInt (label, &curOpt, cvar->min , cvar->max , " %d" , ImGuiSliderFlags_AlwaysClamp | ImGuiSliderFlags_NoInput)) {
928+ if (curOpt != cvar->intVal ) {
929+ cvar->Set (curOpt);
930+ }
931+ }
932+ }
933+
934+ void CVarCheckbox (char const * label, conVar_c* cvar) {
935+ bool checked = cvar->intVal == 1 ;
936+ if (ImGui::Checkbox (label, &checked)) {
937+ cvar->intVal = +checked;
938+ }
939+ }
940+
915941void r_renderer_c::EndFrame ()
916942{
917943 static bool showDemo = false ;
@@ -957,12 +983,10 @@ void r_renderer_c::EndFrame()
957983 if (debugLayers) {
958984 if (ImGui::Begin (" Layers" , &debugLayers)) {
959985 ImGui::Text (" Layers: %d" , numLayer);
960- int curOpt = r_layerOptimize->intVal ;
961- if (ImGui::SliderInt (" Optimization" , &curOpt, r_layerOptimize->min , r_layerOptimize->max , " %d" , ImGuiSliderFlags_AlwaysClamp | ImGuiSliderFlags_NoInput)) {
962- if (curOpt != r_layerOptimize->intVal ) {
963- r_layerOptimize->Set (curOpt);
964- }
965- }
986+ ImGui::Text (" %d out of %d frames drawn, %d saved." , drawnFrames, totalFrames, savedFrames);
987+ CVarSliderInt (" Optimization" , r_layerOptimize);
988+ CVarCheckbox (" Elide identical frames" , r_elideFrames);
989+
966990 int totalCmd{};
967991 if (ImGui::BeginTable (" Layer stats" , 4 , ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit)) {
968992 ImGui::TableSetupColumn (" Index" );
@@ -988,8 +1012,74 @@ void r_renderer_c::EndFrame()
9881012 }
9891013 ImGui::End ();
9901014 }
991- for (int l = 0 ; l < numLayer; l++) {
992- layerSort[l]->Render ();
1015+
1016+ if (elideFrames != !!r_elideFrames->intVal ) {
1017+ elideFrames = !!r_elideFrames->intVal ;
1018+ lastFrameHash.clear ();
1019+ }
1020+
1021+ std::vector<uint8_t > commandDigest (crypto_shorthash_bytes ());
1022+ if (elideFrames) {
1023+ {
1024+ std::vector<char > commandBytes;
1025+ commandBytes.reserve (1ull << 24 );
1026+ auto hash_primitive = [&](auto & x) {
1027+ auto p = (uint8_t const *)&x;
1028+ commandBytes.insert (commandBytes.end (), p, p + sizeof (x));
1029+ };
1030+ for (auto lIdx = 0 ; lIdx < numLayer; ++lIdx) {
1031+ auto layer = layerSort[lIdx];
1032+ hash_primitive (layer->layer );
1033+ hash_primitive (layer->subLayer );
1034+ for (auto cIdx = 0 ; cIdx < layer->numCmd ; ++cIdx) {
1035+ auto cmd = layer->cmdList [cIdx];
1036+ hash_primitive (cmd->cmd );
1037+ switch (cmd->cmd ) {
1038+ case r_layerCmd_s::VIEWPORT : {
1039+ hash_primitive (cmd->viewport );
1040+ } break ;
1041+ case r_layerCmd_s::BLEND : {
1042+ hash_primitive (cmd->blendMode );
1043+ } break ;
1044+ case r_layerCmd_s::BIND : {
1045+ // not safe around handle/ID reuse but probably good enough
1046+ hash_primitive (cmd->tex );
1047+ hash_primitive (cmd->tex ->texId );
1048+ auto status = cmd->tex ->status .load ();
1049+ hash_primitive (status);
1050+ } break ;
1051+ case r_layerCmd_s::COLOR : {
1052+ for (auto comp : cmd->col ) {
1053+ hash_primitive (comp);
1054+ }
1055+ } break ;
1056+ case r_layerCmd_s::QUAD : {
1057+ hash_primitive (cmd->quad );
1058+ } break ;
1059+ }
1060+ }
1061+ }
1062+ static std::vector<uint8_t > const commandKey (crypto_shorthash_keybytes ());
1063+ crypto_shorthash ((unsigned char *)commandDigest.data (), (unsigned char const *)commandBytes.data (), commandBytes.size (), (unsigned char const *)commandKey.data ());
1064+ }
1065+ }
1066+
1067+ ++totalFrames;
1068+ if (!elideFrames || lastFrameHash != commandDigest) {
1069+ lastFrameHash = commandDigest;
1070+ ++drawnFrames;
1071+
1072+ glBindFramebuffer (GL_FRAMEBUFFER , rttMain.framebuffer );
1073+ glClear (GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
1074+ for (int l = 0 ; l < numLayer; l++) {
1075+ layerSort[l]->Render ();
1076+ }
1077+ }
1078+ else {
1079+ ++savedFrames;
1080+ for (int l = 0 ; l < numLayer; l++) {
1081+ layerSort[l]->Discard ();
1082+ }
9931083 }
9941084 delete[] layerSort;
9951085
0 commit comments