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 | #define AVG_SIZE 20 | ||||
void renderFPS(struct NVGcontext* vg, float x, float y, struct FPScounter* fps) | 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; | int i, head; | ||||
float avg, w, h; | float avg, w, h; | ||||
@@ -886,29 +891,60 @@ void renderFPS(struct NVGcontext* vg, float x, float y, struct FPScounter* fps) | |||||
nvgBeginPath(vg); | nvgBeginPath(vg); | ||||
nvgMoveTo(vg, x, y+h); | 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); | nvgLineTo(vg, x+w, y+h); | ||||
nvgFillColor(vg, nvgRGBA(255,192,0,128)); | nvgFillColor(vg, nvgRGBA(255,192,0,128)); | ||||
nvgFill(vg); | nvgFill(vg); | ||||
nvgFontFace(vg, "sans"); | 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); | 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 | #define FPS_HISTORY_COUNT 100 | ||||
enum FPSRenderStyle { | |||||
RENDER_FPS, | |||||
RENDER_MS, | |||||
}; | |||||
struct FPScounter | struct FPScounter | ||||
{ | { | ||||
float values[FPS_HISTORY_COUNT]; | float values[FPS_HISTORY_COUNT]; | ||||
@@ -25,6 +29,7 @@ struct FPScounter | |||||
void initFPS(struct FPScounter* fps); | void initFPS(struct FPScounter* fps); | ||||
void updateFPS(struct FPScounter* fps, float frameTime); | 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); | void renderFPS(struct NVGcontext* vg, float x, float y, struct FPScounter* fps); | ||||
#ifdef __cplusplus | #ifdef __cplusplus | ||||
@@ -31,7 +31,6 @@ | |||||
#include "nanovg_gl3buf.h" | #include "nanovg_gl3buf.h" | ||||
#include "demo.h" | #include "demo.h" | ||||
void errorcb(int error, const char* desc) | void errorcb(int error, const char* desc) | ||||
{ | { | ||||
printf("GLFW error %d: %s\n", error, 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; | blowup = !blowup; | ||||
} | } | ||||
enum numqueries { | |||||
NUM_QUERIES = 5 | |||||
}; | |||||
int main() | int main() | ||||
{ | { | ||||
GLFWwindow* window; | GLFWwindow* window; | ||||
struct DemoData data; | struct DemoData data; | ||||
struct NVGcontext* vg = NULL; | 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()) { | if (!glfwInit()) { | ||||
printf("Failed to init GLFW."); | printf("Failed to init GLFW."); | ||||
@@ -63,6 +68,8 @@ int main() | |||||
} | } | ||||
initFPS(&fps); | initFPS(&fps); | ||||
initFPS(&cpuTimes); | |||||
initFPS(&gpuTimes); | |||||
glfwSetErrorCallback(errorcb); | glfwSetErrorCallback(errorcb); | ||||
#ifndef _WIN32 // don't require this on win32, and works with more cards | #ifndef _WIN32 // don't require this on win32, and works with more cards | ||||
@@ -108,6 +115,11 @@ int main() | |||||
glfwSwapInterval(0); | glfwSwapInterval(0); | ||||
timerquery = glfwExtensionSupported("GL_ARB_timer_query"); | |||||
if( timerquery ) { | |||||
glGenQueries(NUM_QUERIES, timerqueryid); | |||||
} | |||||
glfwSetTime(0); | glfwSetTime(0); | ||||
prevt = glfwGetTime(); | prevt = glfwGetTime(); | ||||
@@ -122,6 +134,11 @@ int main() | |||||
dt = t - prevt; | dt = t - prevt; | ||||
prevt = t; | prevt = t; | ||||
updateFPS(&fps, dt); | updateFPS(&fps, dt); | ||||
updateFPS(&cpuTimes, cpuTime); | |||||
if( timerquery ) { | |||||
glBeginQuery(GL_TIME_ELAPSED, timerqueryid[currquery % NUM_QUERIES] ); | |||||
currquery = ++currquery; | |||||
} | |||||
glfwGetCursorPos(window, &mx, &my); | glfwGetCursorPos(window, &mx, &my); | ||||
glfwGetWindowSize(window, &winWidth, &winHeight); | glfwGetWindowSize(window, &winWidth, &winHeight); | ||||
@@ -143,11 +160,33 @@ int main() | |||||
renderDemo(vg, mx,my, winWidth,winHeight, t, blowup, &data); | renderDemo(vg, mx,my, winWidth,winHeight, t, blowup, &data); | ||||
renderFPS(vg, 5,5, &fps); | 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); | nvgEndFrame(vg); | ||||
glEnable(GL_DEPTH_TEST); | 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); | glfwSwapBuffers(window); | ||||
glfwPollEvents(); | glfwPollEvents(); | ||||
} | } | ||||