187 lines
4.8 KiB
C
187 lines
4.8 KiB
C
|
#include "perf.h"
|
||
|
#include <stdio.h>
|
||
|
#include <string.h>
|
||
|
#include <math.h>
|
||
|
#ifdef NANOVG_GLEW
|
||
|
# include <GL/glew.h>
|
||
|
#endif
|
||
|
#include <GLFW/glfw3.h>
|
||
|
#include "nanovg.h"
|
||
|
|
||
|
#ifdef _MSC_VER
|
||
|
#define snprintf _snprintf
|
||
|
#elif !defined(__MINGW32__)
|
||
|
#include <iconv.h>
|
||
|
#endif
|
||
|
|
||
|
// timer query support
|
||
|
#ifndef GL_ARB_timer_query
|
||
|
#define GL_TIME_ELAPSED 0x88BF
|
||
|
//typedef void (APIENTRY *pfnGLGETQUERYOBJECTUI64V)(GLuint id, GLenum pname, GLuint64* params);
|
||
|
//pfnGLGETQUERYOBJECTUI64V glGetQueryObjectui64v = 0;
|
||
|
#endif
|
||
|
|
||
|
void initGPUTimer(GPUtimer* timer)
|
||
|
{
|
||
|
memset(timer, 0, sizeof(*timer));
|
||
|
|
||
|
/* timer->supported = glfwExtensionSupported("GL_ARB_timer_query");
|
||
|
if (timer->supported) {
|
||
|
#ifndef GL_ARB_timer_query
|
||
|
glGetQueryObjectui64v = (pfnGLGETQUERYOBJECTUI64V)glfwGetProcAddress("glGetQueryObjectui64v");
|
||
|
printf("glGetQueryObjectui64v=%p\n", glGetQueryObjectui64v);
|
||
|
if (!glGetQueryObjectui64v) {
|
||
|
timer->supported = GL_FALSE;
|
||
|
return;
|
||
|
}
|
||
|
#endif
|
||
|
glGenQueries(GPU_QUERY_COUNT, timer->queries);
|
||
|
}*/
|
||
|
}
|
||
|
|
||
|
void startGPUTimer(GPUtimer* timer)
|
||
|
{
|
||
|
if (!timer->supported)
|
||
|
return;
|
||
|
glBeginQuery(GL_TIME_ELAPSED, timer->queries[timer->cur % GPU_QUERY_COUNT] );
|
||
|
timer->cur++;
|
||
|
}
|
||
|
|
||
|
int stopGPUTimer(GPUtimer* timer, float* times, int maxTimes)
|
||
|
{
|
||
|
NVG_NOTUSED(times);
|
||
|
NVG_NOTUSED(maxTimes);
|
||
|
GLint available = 1;
|
||
|
int n = 0;
|
||
|
if (!timer->supported)
|
||
|
return 0;
|
||
|
|
||
|
glEndQuery(GL_TIME_ELAPSED);
|
||
|
while (available && timer->ret <= timer->cur) {
|
||
|
// check for results if there are any
|
||
|
glGetQueryObjectiv(timer->queries[timer->ret % GPU_QUERY_COUNT], GL_QUERY_RESULT_AVAILABLE, &available);
|
||
|
if (available) {
|
||
|
/* GLuint64 timeElapsed = 0;
|
||
|
glGetQueryObjectui64v(timer->queries[timer->ret % GPU_QUERY_COUNT], GL_QUERY_RESULT, &timeElapsed);
|
||
|
timer->ret++;
|
||
|
if (n < maxTimes) {
|
||
|
times[n] = (float)((double)timeElapsed * 1e-9);
|
||
|
n++;
|
||
|
}*/
|
||
|
}
|
||
|
}
|
||
|
return n;
|
||
|
}
|
||
|
|
||
|
|
||
|
void initGraph(PerfGraph* fps, int style, const char* name)
|
||
|
{
|
||
|
memset(fps, 0, sizeof(PerfGraph));
|
||
|
fps->style = style;
|
||
|
strncpy(fps->name, name, sizeof(fps->name));
|
||
|
fps->name[sizeof(fps->name)-1] = '\0';
|
||
|
}
|
||
|
|
||
|
void updateGraph(PerfGraph* fps, float frameTime)
|
||
|
{
|
||
|
fps->head = (fps->head+1) % GRAPH_HISTORY_COUNT;
|
||
|
fps->values[fps->head] = frameTime;
|
||
|
}
|
||
|
|
||
|
float getGraphAverage(PerfGraph* fps)
|
||
|
{
|
||
|
int i;
|
||
|
float avg = 0;
|
||
|
for (i = 0; i < GRAPH_HISTORY_COUNT; i++) {
|
||
|
avg += fps->values[i];
|
||
|
}
|
||
|
return avg / (float)GRAPH_HISTORY_COUNT;
|
||
|
}
|
||
|
|
||
|
void renderGraph(NVGcontext* vg, float x, float y, PerfGraph* fps)
|
||
|
{
|
||
|
int i;
|
||
|
float avg, w, h;
|
||
|
char str[64];
|
||
|
|
||
|
avg = getGraphAverage(fps);
|
||
|
|
||
|
w = 200;
|
||
|
h = 35;
|
||
|
|
||
|
nvgBeginPath(vg);
|
||
|
nvgRect(vg, x,y, w,h);
|
||
|
nvgFillColor(vg, nvgRGBA(0,0,0,128));
|
||
|
nvgFill(vg);
|
||
|
|
||
|
nvgBeginPath(vg);
|
||
|
nvgMoveTo(vg, x, y+h);
|
||
|
if (fps->style == GRAPH_RENDER_FPS) {
|
||
|
for (i = 0; i < GRAPH_HISTORY_COUNT; i++) {
|
||
|
float v = 1.0f / (0.00001f + fps->values[(fps->head+i) % GRAPH_HISTORY_COUNT]);
|
||
|
float vx, vy;
|
||
|
if (v > 80.0f) v = 80.0f;
|
||
|
vx = x + ((float)i/(GRAPH_HISTORY_COUNT-1)) * w;
|
||
|
vy = y + h - ((v / 80.0f) * h);
|
||
|
nvgLineTo(vg, vx, vy);
|
||
|
}
|
||
|
} else if (fps->style == GRAPH_RENDER_PERCENT) {
|
||
|
for (i = 0; i < GRAPH_HISTORY_COUNT; i++) {
|
||
|
float v = fps->values[(fps->head+i) % GRAPH_HISTORY_COUNT] * 1.0f;
|
||
|
float vx, vy;
|
||
|
if (v > 100.0f) v = 100.0f;
|
||
|
vx = x + ((float)i/(GRAPH_HISTORY_COUNT-1)) * w;
|
||
|
vy = y + h - ((v / 100.0f) * h);
|
||
|
nvgLineTo(vg, vx, vy);
|
||
|
}
|
||
|
} else {
|
||
|
for (i = 0; i < GRAPH_HISTORY_COUNT; i++) {
|
||
|
float v = fps->values[(fps->head+i) % GRAPH_HISTORY_COUNT] * 1000.0f;
|
||
|
float vx, vy;
|
||
|
if (v > 20.0f) v = 20.0f;
|
||
|
vx = x + ((float)i/(GRAPH_HISTORY_COUNT-1)) * w;
|
||
|
vy = y + h - ((v / 20.0f) * h);
|
||
|
nvgLineTo(vg, vx, vy);
|
||
|
}
|
||
|
}
|
||
|
nvgLineTo(vg, x+w, y+h);
|
||
|
nvgFillColor(vg, nvgRGBA(255,192,0,128));
|
||
|
nvgFill(vg);
|
||
|
|
||
|
nvgFontFace(vg, "sans");
|
||
|
|
||
|
if (fps->name[0] != '\0') {
|
||
|
nvgFontSize(vg, 14.0f);
|
||
|
nvgTextAlign(vg, NVG_ALIGN_LEFT|NVG_ALIGN_TOP);
|
||
|
nvgFillColor(vg, nvgRGBA(240,240,240,192));
|
||
|
nvgText(vg, x+3,y+1, fps->name, NULL);
|
||
|
}
|
||
|
|
||
|
if (fps->style == GRAPH_RENDER_FPS) {
|
||
|
nvgFontSize(vg, 18.0f);
|
||
|
nvgTextAlign(vg,NVG_ALIGN_RIGHT|NVG_ALIGN_TOP);
|
||
|
nvgFillColor(vg, nvgRGBA(240,240,240,255));
|
||
|
sprintf(str, "%.2f FPS", 1.0f / avg);
|
||
|
nvgText(vg, x+w-3,y+1, str, NULL);
|
||
|
|
||
|
nvgFontSize(vg, 15.0f);
|
||
|
nvgTextAlign(vg,NVG_ALIGN_RIGHT|NVG_ALIGN_BOTTOM);
|
||
|
nvgFillColor(vg, nvgRGBA(240,240,240,160));
|
||
|
sprintf(str, "%.2f ms", avg * 1000.0f);
|
||
|
nvgText(vg, x+w-3,y+h-1, str, NULL);
|
||
|
}
|
||
|
else if (fps->style == GRAPH_RENDER_PERCENT) {
|
||
|
nvgFontSize(vg, 18.0f);
|
||
|
nvgTextAlign(vg,NVG_ALIGN_RIGHT|NVG_ALIGN_TOP);
|
||
|
nvgFillColor(vg, nvgRGBA(240,240,240,255));
|
||
|
sprintf(str, "%.1f %%", avg * 1.0f);
|
||
|
nvgText(vg, x+w-3,y+1, str, NULL);
|
||
|
} else {
|
||
|
nvgFontSize(vg, 18.0f);
|
||
|
nvgTextAlign(vg,NVG_ALIGN_RIGHT|NVG_ALIGN_TOP);
|
||
|
nvgFillColor(vg, nvgRGBA(240,240,240,255));
|
||
|
sprintf(str, "%.2f ms", avg * 1000.0f);
|
||
|
nvgText(vg, x+w-3,y+1, str, NULL);
|
||
|
}
|
||
|
}
|