LCOV - code coverage report
Current view: top level - engine/render - rendertimers.cpp (source / functions) Hit Total Coverage
Test: Libprimis Test Coverage Lines: 0 83 0.0 %
Date: 2024-11-22 05:07:59 Functions: 0 7 0.0 %

          Line data    Source code
       1             : /* rendertimers.cpp: renderer functionality used for displaying rendering stats
       2             :  * while the program is running
       3             :  *
       4             :  * timers can be created with designated start/stop points in the code; sub-ms
       5             :  * times needed for accurate diagnosis possible (each frame is ~16.6ms @ 60Hz)
       6             :  *
       7             :  * used in rendergl.cpp
       8             :  */
       9             : #include "../libprimis-headers/cube.h"
      10             : #include "../../shared/geomexts.h"
      11             : #include "../../shared/glexts.h"
      12             : 
      13             : #include "rendergl.h"
      14             : #include "rendertext.h"
      15             : #include "renderttf.h"
      16             : #include "renderva.h"
      17             : 
      18             : #include "interface/control.h"
      19             : 
      20             : void cleanuptimers();                              //needed for timer script gvar
      21           0 : VARFN(timer, usetimers, 0, 0, 1, cleanuptimers()); //toggles logging timer information & rendering it
      22             : VAR(frametimer, 0, 0, 1);                          //toggles timing how long each frame takes (and rendering it to timer ui)
      23             : 
      24             : struct timer
      25             : {
      26             :     enum
      27             :     {
      28             :         Timer_MaxQuery = 4          //max number of gl queries
      29             :     };
      30             :     const char *name;               //name the timer reports as
      31             :     bool gpu;                       //whether the timer is for gpu time (true) or cpu time
      32             :     std::array<GLuint, Timer_MaxQuery> query; //gpu query information
      33             :     int waiting;                    //internal bitmask for queries
      34             :     uint starttime;                 //time the timer was started (in terms of ms since game started)
      35             :     float result,                   //raw value of the timer, -1 if no info available
      36             :           print;                    //the time the timer displays: ms per frame for whatever object
      37             : };
      38             : 
      39             : //locally relevant functionality
      40             : namespace
      41             : {
      42             :     std::vector<timer> timers;
      43             :     std::vector<uint> timerorder;
      44             :     uint timercycle = 0;
      45             : 
      46           0 :     timer *findtimer(const char *name, bool gpu) //also creates a new timer if none found
      47             :     {
      48           0 :         for(uint i = 0; i < timers.size(); i++)
      49             :         {
      50           0 :             if(!std::strcmp(timers[i].name, name) && timers[i].gpu == gpu)
      51             :             {
      52           0 :                 timerorder.erase(std::find(timerorder.begin(), timerorder.end(), i));
      53           0 :                 timerorder.push_back(i);
      54           0 :                 return &timers[i];
      55             :             }
      56             :         }
      57           0 :         timerorder.push_back(timers.size());
      58           0 :         timers.emplace_back();
      59           0 :         timer &t = timers.back();
      60           0 :         t.name = name;
      61           0 :         t.gpu = gpu;
      62           0 :         t.query.fill(0);
      63           0 :         if(gpu)
      64             :         {
      65           0 :             glGenQueries(timer::Timer_MaxQuery, t.query.data());
      66             :         }
      67           0 :         t.waiting = 0;
      68           0 :         t.starttime = 0;
      69           0 :         t.result = -1;
      70           0 :         t.print = -1;
      71           0 :         return &t;
      72             :     }
      73             : }
      74             : 
      75             : //externally relevant functionality
      76             : 
      77             : //used to start a timer in some part of the code, cannot be used outside of rendering part
      78             : /**
      79             :  * @brief activates a timer that starts its query from a given point in the code
      80             :  *
      81             :  * Creates a new timer if necessary.
      82             :  *
      83             :  * @param name The name of the timer to use
      84             :  * @param gpu Toggles timing GPU rendering time
      85             :  *
      86             :  * @return a pointer to the relevant timer
      87             :  */
      88           0 : timer *begintimer(const char *name, bool gpu)
      89             : {
      90           0 :     if(!usetimers || inbetweenframes || (gpu && (!hasTQ || deferquery)))
      91             :     {
      92           0 :         return nullptr;
      93             :     }
      94           0 :     timer *t = findtimer(name, gpu);
      95           0 :     if(t->gpu)
      96             :     {
      97           0 :         deferquery++;
      98           0 :         glBeginQuery(GL_TIME_ELAPSED_EXT, t->query[timercycle]);
      99           0 :         t->waiting |= 1<<timercycle;
     100             :     }
     101             :     else
     102             :     {
     103           0 :         t->starttime = getclockmillis();
     104             :     }
     105           0 :     return t;
     106             : }
     107             : 
     108             : //used to end a timer started by begintimer(), needs to be included sometime after begintimer
     109             : //the part between begintimer() and endtimer() is what gets timed
     110           0 : void endtimer(timer *t)
     111             : {
     112           0 :     if(!t)
     113             :     {
     114           0 :         return;
     115             :     }
     116           0 :     if(t->gpu)
     117             :     {
     118           0 :         glEndQuery(GL_TIME_ELAPSED_EXT);
     119           0 :         deferquery--;
     120             :     }
     121             :     else
     122             :     {
     123           0 :         t->result = std::max(static_cast<float>(getclockmillis() - t->starttime), 0.0f);
     124             :     }
     125             : }
     126             : 
     127             : //foreach timer, query what time has passed since last update
     128           0 : void synctimers()
     129             : {
     130           0 :     timercycle = (timercycle + 1) % timer::Timer_MaxQuery;
     131             : 
     132           0 :     for(timer& t : timers)
     133             :     {
     134           0 :         if(t.waiting&(1<<timercycle))
     135             :         {
     136           0 :             GLint available = 0;
     137           0 :             while(!available)
     138             :             {
     139           0 :                 glGetQueryObjectiv(t.query[timercycle], GL_QUERY_RESULT_AVAILABLE, &available);
     140             :             }
     141           0 :             GLuint64EXT result = 0;
     142           0 :             glGetQueryObjectui64v(t.query[timercycle], GL_QUERY_RESULT, &result);
     143           0 :             t.result = std::max(static_cast<float>(result) * 1e-6f, 0.0f);
     144           0 :             t.waiting &= ~(1<<timercycle);
     145             :         }
     146             :         else
     147             :         {
     148           0 :             t.result = -1;
     149             :         }
     150             :     }
     151           0 : }
     152             : 
     153             : /**
     154             :  * @brief deletes the elements in the timers global vector
     155             :  *
     156             :  * Deletes the elements in the `timer` global variable. If any GPU queries are active,
     157             :  * they are cancelled so as not to waste the GPU's time
     158             :  */
     159           0 : void cleanuptimers()
     160             : {
     161           0 :     for(const timer& t : timers)
     162             :     {
     163           0 :         if(t.gpu)
     164             :         {
     165           0 :             glDeleteQueries(timer::Timer_MaxQuery, t.query.data());
     166             :         }
     167             :     }
     168           0 :     timers.clear();
     169           0 :     timerorder.clear();
     170           0 : }
     171             : 
     172             : /*
     173             :  * draws timers to the screen using hardcoded text
     174             :  *
     175             :  * if frametimer gvar is enabled, also shows the overall frame time
     176             :  * otherwise, prints out all timer information available
     177             :  */
     178           0 : void printtimers(int conw, int conh, int framemillis)
     179             : {
     180           0 :     if(!frametimer && !usetimers)
     181             :     {
     182           0 :         return;
     183             :     }
     184             :     static int lastprint = 0;
     185           0 :     int offset = 0;
     186           0 :     if(frametimer)
     187             :     {
     188             :         static int printmillis = 0;
     189           0 :         if(totalmillis - lastprint >= 200)
     190             :         {
     191           0 :             printmillis = framemillis;
     192             :         }
     193             :         char framestring[200];
     194           0 :         constexpr int size = 42;
     195           0 :         std::sprintf(framestring, "frame time %i ms", printmillis);
     196           0 :         ttr.fontsize(size);
     197           0 :         ttr.renderttf(framestring, {0xFF, 0xFF, 0xFF, 0}, conw-20*size, size*3/2+offset*9*size/8);
     198             :         //draw_textf("frame time %i ms", conw-20*FONTH, conh-FONTH*3/2-offset*9*FONTH/8, printmillis);
     199           0 :         offset++;
     200             :     }
     201           0 :     if(usetimers)
     202             :     {
     203           0 :         for(int i : timerorder)
     204             :         {
     205           0 :             timer &t = timers[i];
     206           0 :             if(t.print < 0 ? t.result >= 0 : totalmillis - lastprint >= 200)
     207             :             {
     208           0 :                 t.print = t.result;
     209             :             }
     210           0 :             if(t.print < 0 || (t.gpu && !(t.waiting&(1<<timercycle))))
     211             :             {
     212           0 :                 continue;
     213             :             }
     214             :             char framestring[200];
     215           0 :             constexpr int size = 42;
     216           0 :             std::sprintf(framestring, "%s%s %5.2f ms", t.name, t.gpu ? "" : " (cpu)", t.print);
     217           0 :             ttr.fontsize(size);
     218           0 :             ttr.renderttf(framestring, {0xFF, 0xFF, 0xFF, 0}, conw-20*size, size*3/2+offset*9*size/8);
     219             : 
     220             :             //draw_textf("%s%s %5.2f ms", conw-20*FONTH, conh-FONTH*3/2-offset*9*FONTH/8, t.name, t.gpu ? "" : " (cpu)", t.print);
     221           0 :             offset++;
     222             :         }
     223             :     }
     224           0 :     if(totalmillis - lastprint >= 200)
     225             :     {
     226           0 :         lastprint = totalmillis;
     227             :     }
     228             : }

Generated by: LCOV version 1.14