Timing for CPU inner frame and GPU inner frame addedshared-context
@@ -863,6 +863,11 @@ void updateFPS(struct FPScounter* fps, float frameTime) | |||
#define AVG_SIZE 20 | |||
void renderFPS(struct NVGcontext* vg, float x, float y, struct FPScounter* fps) | |||
{ | |||
renderFPSEx(vg,x,y,fps,RENDER_FPS,NULL); | |||
} | |||
void renderFPSEx(struct NVGcontext* vg, float x, float y, struct FPScounter* fps, enum FPSRenderStyle style, const char* name) | |||
{ | |||
int i, head; | |||
float avg, w, h; | |||
@@ -886,29 +891,60 @@ void renderFPS(struct NVGcontext* vg, float x, float y, struct FPScounter* fps) | |||
nvgBeginPath(vg); | |||
nvgMoveTo(vg, x, y+h); | |||
for (i = 0; i < FPS_HISTORY_COUNT; i++) { | |||
float v = 1.0f / (0.00001f + fps->values[(fps->head+i) % FPS_HISTORY_COUNT]); | |||
if (v > 80.0f) v = 80.0f; | |||
float vx = x + ((float)i/(FPS_HISTORY_COUNT-1)) * w; | |||
float vy = y + h - ((v / 80.0f) * h); | |||
nvgLineTo(vg, vx, vy); | |||
} | |||
if( RENDER_FPS == style ) | |||
{ | |||
for (i = 0; i < FPS_HISTORY_COUNT; i++) { | |||
float v = 1.0f / (0.00001f + fps->values[(fps->head+i) % FPS_HISTORY_COUNT]); | |||
if (v > 80.0f) v = 80.0f; | |||
float vx = x + ((float)i/(FPS_HISTORY_COUNT-1)) * w; | |||
float vy = y + h - ((v / 80.0f) * h); | |||
nvgLineTo(vg, vx, vy); | |||
} | |||
} | |||
else | |||
{ | |||
for (i = 0; i < FPS_HISTORY_COUNT; i++) { | |||
float v = fps->values[(fps->head+i) % FPS_HISTORY_COUNT] * 1000.0f; | |||
if (v > 20.0f) v = 20.0f; | |||
float vx = x + ((float)i/(FPS_HISTORY_COUNT-1)) * w; | |||
float 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"); | |||
nvgFontSize(vg, 18.0f); | |||
nvgTextAlign(vg,NVG_ALIGN_RIGHT|NVG_ALIGN_MIDDLE); | |||
nvgFillColor(vg, nvgRGBA(240,240,240,255)); | |||
sprintf(str, "%.2f FPS", 1.0f / avg); | |||
nvgText(vg, x+w-5,y+h/2, str, NULL); | |||
if( RENDER_FPS == style ) { | |||
nvgFontSize(vg, 18.0f); | |||
nvgTextAlign(vg,NVG_ALIGN_RIGHT|NVG_ALIGN_MIDDLE); | |||
nvgFillColor(vg, nvgRGBA(240,240,240,255)); | |||
sprintf(str, "%.2f FPS", 1.0f / avg); | |||
nvgText(vg, x+w-5,y+h/2, str, NULL); | |||
nvgFontSize(vg, 15.0f); | |||
nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE); | |||
nvgFillColor(vg, nvgRGBA(240,240,240,160)); | |||
sprintf(str, "%.2f ms", avg * 1000.0f); | |||
nvgText(vg, x+5,y+h/2, str, NULL); | |||
} | |||
else { | |||
nvgFontSize(vg, 18.0f); | |||
nvgTextAlign(vg,NVG_ALIGN_RIGHT|NVG_ALIGN_MIDDLE); | |||
nvgFillColor(vg, nvgRGBA(240,240,240,255)); | |||
sprintf(str, "%.2f ms", avg * 1000.0f); | |||
nvgText(vg, x+w-5,y+h/2, str, NULL); | |||
if( name ) | |||
{ | |||
nvgFontSize(vg, 20.0f); | |||
nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE); | |||
nvgFillColor(vg, nvgRGBA(240,240,240,160)); | |||
nvgText(vg, x+5,y+h/2, name, NULL); | |||
} | |||
} | |||
nvgFontSize(vg, 15.0f); | |||
nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE); | |||
nvgFillColor(vg, nvgRGBA(240,240,240,160)); | |||
sprintf(str, "%.2f ms", avg * 1000.0f); | |||
nvgText(vg, x+5,y+h/2, str, NULL); | |||
} | |||
@@ -17,6 +17,10 @@ void freeDemoData(struct NVGcontext* vg, struct DemoData* data); | |||
void renderDemo(struct NVGcontext* vg, float mx, float my, float width, float height, float t, int blowup, struct DemoData* data); | |||
#define FPS_HISTORY_COUNT 100 | |||
enum FPSRenderStyle { | |||
RENDER_FPS, | |||
RENDER_MS, | |||
}; | |||
struct FPScounter | |||
{ | |||
float values[FPS_HISTORY_COUNT]; | |||
@@ -25,6 +29,7 @@ struct FPScounter | |||
void initFPS(struct FPScounter* fps); | |||
void updateFPS(struct FPScounter* fps, float frameTime); | |||
void renderFPSEx(struct NVGcontext* vg, float x, float y, struct FPScounter* fps, enum FPSRenderStyle style, const char* name ); | |||
void renderFPS(struct NVGcontext* vg, float x, float y, struct FPScounter* fps); | |||
#ifdef __cplusplus | |||
@@ -31,7 +31,6 @@ | |||
#include "nanovg_gl3buf.h" | |||
#include "demo.h" | |||
void errorcb(int error, const char* desc) | |||
{ | |||
printf("GLFW error %d: %s\n", error, desc); | |||
@@ -49,13 +48,19 @@ static void key(GLFWwindow* window, int key, int scancode, int action, int mods) | |||
blowup = !blowup; | |||
} | |||
enum numqueries { | |||
NUM_QUERIES = 5 | |||
}; | |||
int main() | |||
{ | |||
GLFWwindow* window; | |||
struct DemoData data; | |||
struct NVGcontext* vg = NULL; | |||
struct FPScounter fps; | |||
double prevt = 0; | |||
struct FPScounter fps, cpuTimes, gpuTimes; | |||
double prevt = 0, cpuTime = 0; | |||
int timerquery = GL_FALSE, currquery = 0, retquery = 0; | |||
GLuint timerqueryid[NUM_QUERIES]; | |||
if (!glfwInit()) { | |||
printf("Failed to init GLFW."); | |||
@@ -63,6 +68,8 @@ int main() | |||
} | |||
initFPS(&fps); | |||
initFPS(&cpuTimes); | |||
initFPS(&gpuTimes); | |||
glfwSetErrorCallback(errorcb); | |||
#ifndef _WIN32 // don't require this on win32, and works with more cards | |||
@@ -108,6 +115,11 @@ int main() | |||
glfwSwapInterval(0); | |||
timerquery = glfwExtensionSupported("GL_ARB_timer_query"); | |||
if( timerquery ) { | |||
glGenQueries(NUM_QUERIES, timerqueryid); | |||
} | |||
glfwSetTime(0); | |||
prevt = glfwGetTime(); | |||
@@ -122,6 +134,11 @@ int main() | |||
dt = t - prevt; | |||
prevt = t; | |||
updateFPS(&fps, dt); | |||
updateFPS(&cpuTimes, cpuTime); | |||
if( timerquery ) { | |||
glBeginQuery(GL_TIME_ELAPSED, timerqueryid[currquery % NUM_QUERIES] ); | |||
currquery = ++currquery; | |||
} | |||
glfwGetCursorPos(window, &mx, &my); | |||
glfwGetWindowSize(window, &winWidth, &winHeight); | |||
@@ -143,11 +160,33 @@ int main() | |||
renderDemo(vg, mx,my, winWidth,winHeight, t, blowup, &data); | |||
renderFPS(vg, 5,5, &fps); | |||
renderFPSEx(vg, 310,5, &cpuTimes, RENDER_MS, "CPU Time"); | |||
renderFPSEx(vg, 615,5, &gpuTimes, RENDER_MS, "GPU Time"); | |||
nvgEndFrame(vg); | |||
glEnable(GL_DEPTH_TEST); | |||
// Measure the CPU time taken excluding swap buffers (as the swap may wait for GPU) | |||
cpuTime = glfwGetTime() - t; | |||
if( timerquery ) { | |||
GLint available = 1; | |||
glEndQuery(GL_TIME_ELAPSED); | |||
while( available && retquery <= currquery ) { | |||
// check for results if there are any | |||
glGetQueryObjectiv(timerqueryid[retquery % NUM_QUERIES], GL_QUERY_RESULT_AVAILABLE, &available); | |||
if( available ) { | |||
GLuint64 timeElapsed = 0; | |||
double gpuTime; | |||
glGetQueryObjectui64v(timerqueryid[retquery % NUM_QUERIES], GL_QUERY_RESULT, &timeElapsed); | |||
retquery = ++retquery ; | |||
gpuTime = (double)timeElapsed * 1e-9; | |||
updateFPS(&gpuTimes, (float)gpuTime); | |||
} | |||
} | |||
} | |||
glfwSwapBuffers(window); | |||
glfwPollEvents(); | |||
} | |||