- moved performance counter and drawing to separate file - tweaks to performance drawingshared-context
| @@ -849,102 +849,3 @@ void renderDemo(struct NVGcontext* vg, float mx, float my, float width, float he | |||||
| nvgRestore(vg); | nvgRestore(vg); | ||||
| } | } | ||||
| void initFPS(struct FPScounter* fps) | |||||
| { | |||||
| memset(fps, 0, sizeof(struct FPScounter)); | |||||
| } | |||||
| void updateFPS(struct FPScounter* fps, float frameTime) | |||||
| { | |||||
| fps->head = (fps->head+1) % FPS_HISTORY_COUNT; | |||||
| fps->values[fps->head] = 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; | |||||
| char str[64]; | |||||
| avg = 0; | |||||
| head = fps->head; | |||||
| for (i = 0; i < AVG_SIZE; i++) { | |||||
| avg += fps->values[head]; | |||||
| head = (head+FPS_HISTORY_COUNT-1) % FPS_HISTORY_COUNT; | |||||
| } | |||||
| avg /= (float)AVG_SIZE; | |||||
| w = 200; | |||||
| h = 30; | |||||
| 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( 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"); | |||||
| 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); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,5 +1,5 @@ | |||||
| #ifndef WIDGETS_H | |||||
| #define WIDGETS_H | |||||
| #ifndef DEMO_H | |||||
| #define DEMO_H | |||||
| #include "nanovg.h" | #include "nanovg.h" | ||||
| @@ -16,24 +16,8 @@ int loadDemoData(struct NVGcontext* vg, struct DemoData* data); | |||||
| void freeDemoData(struct NVGcontext* vg, struct DemoData* data); | 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 | |||||
| enum FPSRenderStyle { | |||||
| RENDER_FPS, | |||||
| RENDER_MS, | |||||
| }; | |||||
| struct FPScounter | |||||
| { | |||||
| float values[FPS_HISTORY_COUNT]; | |||||
| int head; | |||||
| }; | |||||
| 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 | #ifdef __cplusplus | ||||
| } | } | ||||
| #endif | #endif | ||||
| #endif // WIDGETS_H | |||||
| #endif // DEMO_H | |||||
| @@ -25,6 +25,7 @@ | |||||
| #define NANOVG_GL2_IMPLEMENTATION | #define NANOVG_GL2_IMPLEMENTATION | ||||
| #include "nanovg_gl2.h" | #include "nanovg_gl2.h" | ||||
| #include "demo.h" | #include "demo.h" | ||||
| #include "perf.h" | |||||
| void errorcb(int error, const char* desc) | void errorcb(int error, const char* desc) | ||||
| @@ -57,7 +58,7 @@ int main() | |||||
| return -1; | return -1; | ||||
| } | } | ||||
| initFPS(&fps); | |||||
| initFPS(&fps, FPS_RENDER_FPS, "Frame Time"); | |||||
| glfwSetErrorCallback(errorcb); | glfwSetErrorCallback(errorcb); | ||||
| @@ -30,14 +30,7 @@ | |||||
| //#include "nanovg_gl3.h" | //#include "nanovg_gl3.h" | ||||
| #include "nanovg_gl3buf.h" | #include "nanovg_gl3buf.h" | ||||
| #include "demo.h" | #include "demo.h" | ||||
| // 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 | |||||
| #include "perf.h" | |||||
| void errorcb(int error, const char* desc) | void errorcb(int error, const char* desc) | ||||
| { | { | ||||
| @@ -56,35 +49,30 @@ 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, cpuTimes, gpuTimes; | |||||
| struct GPUtimer gpuTimer; | |||||
| struct FPScounter fps, cpuGraph, gpuGraph; | |||||
| double prevt = 0, cpuTime = 0; | 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."); | ||||
| return -1; | return -1; | ||||
| } | } | ||||
| initFPS(&fps); | |||||
| initFPS(&cpuTimes); | |||||
| initFPS(&gpuTimes); | |||||
| initFPS(&fps, FPS_RENDER_FPS, "Frame Time"); | |||||
| initFPS(&cpuGraph, FPS_RENDER_MS, "CPU Time"); | |||||
| initFPS(&gpuGraph, FPS_RENDER_MS, "GPU Time"); | |||||
| 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 | ||||
| glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); | glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); | ||||
| glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); | glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); | ||||
| glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); | |||||
| glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); | |||||
| glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); | |||||
| glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); | |||||
| #endif | #endif | ||||
| #ifdef DEMO_MSAA | #ifdef DEMO_MSAA | ||||
| @@ -92,7 +80,7 @@ int main() | |||||
| #endif | #endif | ||||
| window = glfwCreateWindow(1000, 600, "NanoVG", NULL, NULL); | window = glfwCreateWindow(1000, 600, "NanoVG", NULL, NULL); | ||||
| // window = glfwCreateWindow(1000, 600, "NanoVG", glfwGetPrimaryMonitor(), NULL); | // window = glfwCreateWindow(1000, 600, "NanoVG", glfwGetPrimaryMonitor(), NULL); | ||||
| if (!window) { | |||||
| if (!window) { | |||||
| glfwTerminate(); | glfwTerminate(); | ||||
| return -1; | return -1; | ||||
| } | } | ||||
| @@ -102,7 +90,7 @@ int main() | |||||
| glfwMakeContextCurrent(window); | glfwMakeContextCurrent(window); | ||||
| #ifdef NANOVG_GLEW | #ifdef NANOVG_GLEW | ||||
| glewExperimental = GL_TRUE; | glewExperimental = GL_TRUE; | ||||
| if(glewInit() != GLEW_OK) { | |||||
| if(glewInit() != GLEW_OK) { | |||||
| printf("Could not init glew.\n"); | printf("Could not init glew.\n"); | ||||
| return -1; | return -1; | ||||
| } | } | ||||
| @@ -123,17 +111,7 @@ int main() | |||||
| glfwSwapInterval(0); | glfwSwapInterval(0); | ||||
| timerquery = glfwExtensionSupported("GL_ARB_timer_query"); | |||||
| if( timerquery ) { | |||||
| #ifndef GL_ARB_timer_query | |||||
| glGetQueryObjectui64v = (pfnGLGETQUERYOBJECTUI64V)glfwGetProcAddress("glGetQueryObjectui64v"); | |||||
| if( !glGetQueryObjectui64v ) | |||||
| { | |||||
| timerquery = GL_FALSE; | |||||
| } | |||||
| #endif | |||||
| glGenQueries(NUM_QUERIES, timerqueryid); | |||||
| } | |||||
| initGPUTimer(&gpuTimer); | |||||
| glfwSetTime(0); | glfwSetTime(0); | ||||
| prevt = glfwGetTime(); | prevt = glfwGetTime(); | ||||
| @@ -144,16 +122,14 @@ int main() | |||||
| int winWidth, winHeight; | int winWidth, winHeight; | ||||
| int fbWidth, fbHeight; | int fbWidth, fbHeight; | ||||
| float pxRatio; | float pxRatio; | ||||
| float gpuTimes[3]; | |||||
| int i, n; | |||||
| t = glfwGetTime(); | t = glfwGetTime(); | ||||
| dt = t - prevt; | dt = t - prevt; | ||||
| prevt = t; | prevt = t; | ||||
| updateFPS(&fps, dt); | |||||
| updateFPS(&cpuTimes, cpuTime); | |||||
| if( timerquery ) { | |||||
| glBeginQuery(GL_TIME_ELAPSED, timerqueryid[currquery % NUM_QUERIES] ); | |||||
| currquery = ++currquery; | |||||
| } | |||||
| startGPUTimer(&gpuTimer); | |||||
| glfwGetCursorPos(window, &mx, &my); | glfwGetCursorPos(window, &mx, &my); | ||||
| glfwGetWindowSize(window, &winWidth, &winHeight); | glfwGetWindowSize(window, &winWidth, &winHeight); | ||||
| @@ -174,34 +150,27 @@ int main() | |||||
| nvgBeginFrame(vg, winWidth, winHeight, pxRatio); | nvgBeginFrame(vg, winWidth, winHeight, pxRatio); | ||||
| 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"); | |||||
| renderFPS(vg, 5+200+5,5, &cpuGraph); | |||||
| if (gpuTimer.supported) | |||||
| renderFPS(vg, 5+200+5+200+5,5, &gpuGraph); | |||||
| 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); | |||||
| } | |||||
| } | |||||
| } | |||||
| // Measure the CPU time taken excluding swap buffers (as the swap may wait for GPU) | |||||
| cpuTime = glfwGetTime() - t; | |||||
| updateFPS(&fps, dt); | |||||
| updateFPS(&cpuGraph, cpuTime); | |||||
| // We may get multiple results. | |||||
| n = stopGPUTimer(&gpuTimer, gpuTimes, 3); | |||||
| for (i = 0; i < n; i++) | |||||
| updateFPS(&gpuGraph, gpuTimes[i]); | |||||
| glfwSwapBuffers(window); | glfwSwapBuffers(window); | ||||
| glfwPollEvents(); | glfwPollEvents(); | ||||
| } | } | ||||
| @@ -23,6 +23,7 @@ | |||||
| #define NANOVG_GLES2_IMPLEMENTATION | #define NANOVG_GLES2_IMPLEMENTATION | ||||
| #include "nanovg_gl2.h" | #include "nanovg_gl2.h" | ||||
| #include "demo.h" | #include "demo.h" | ||||
| #include "perf.h" | |||||
| void errorcb(int error, const char* desc) | void errorcb(int error, const char* desc) | ||||
| @@ -55,7 +56,7 @@ int main() | |||||
| return -1; | return -1; | ||||
| } | } | ||||
| initFPS(&fps); | |||||
| initFPS(&fps, FPS_RENDER_FPS, "Frame Time"); | |||||
| glfwSetErrorCallback(errorcb); | glfwSetErrorCallback(errorcb); | ||||
| @@ -23,6 +23,7 @@ | |||||
| #define NANOVG_GLES3_IMPLEMENTATION | #define NANOVG_GLES3_IMPLEMENTATION | ||||
| #include "nanovg_gl3.h" | #include "nanovg_gl3.h" | ||||
| #include "demo.h" | #include "demo.h" | ||||
| #include "perf.h" | |||||
| void errorcb(int error, const char* desc) | void errorcb(int error, const char* desc) | ||||
| @@ -55,7 +56,7 @@ int main() | |||||
| return -1; | return -1; | ||||
| } | } | ||||
| initFPS(&fps); | |||||
| initFPS(&fps, FPS_RENDER_FPS, "Frame Time"); | |||||
| glfwSetErrorCallback(errorcb); | glfwSetErrorCallback(errorcb); | ||||
| @@ -0,0 +1,168 @@ | |||||
| #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 | |||||
| #else | |||||
| #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(struct 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"); | |||||
| if (!glGetQueryObjectui64v) { | |||||
| timer->supported = GL_FALSE; | |||||
| return; | |||||
| } | |||||
| #endif | |||||
| glGenQueries(GPU_QUERY_COUNT, timer->queries); | |||||
| } | |||||
| } | |||||
| void startGPUTimer(struct GPUtimer* timer) | |||||
| { | |||||
| if (!timer->supported) | |||||
| return; | |||||
| glBeginQuery(GL_TIME_ELAPSED, timer->queries[timer->cur % GPU_QUERY_COUNT] ); | |||||
| timer->cur++; | |||||
| } | |||||
| int stopGPUTimer(struct GPUtimer* timer, float* times, int 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 initFPS(struct FPScounter* fps, int style, const char* name) | |||||
| { | |||||
| memset(fps, 0, sizeof(struct FPScounter)); | |||||
| fps->style = style; | |||||
| strncpy(fps->name, name, sizeof(fps->name)); | |||||
| fps->name[sizeof(fps->name)-1] = '\0'; | |||||
| } | |||||
| void updateFPS(struct FPScounter* fps, float frameTime) | |||||
| { | |||||
| fps->head = (fps->head+1) % FPS_HISTORY_COUNT; | |||||
| fps->values[fps->head] = frameTime; | |||||
| } | |||||
| #define AVG_SIZE 20 | |||||
| static float getAvg(struct FPScounter* fps) | |||||
| { | |||||
| int i, head = fps->head; | |||||
| float avg = 0; | |||||
| for (i = 0; i < AVG_SIZE; i++) { | |||||
| avg += fps->values[head]; | |||||
| head = (head+FPS_HISTORY_COUNT-1) % FPS_HISTORY_COUNT; | |||||
| } | |||||
| return avg / (float)AVG_SIZE; | |||||
| } | |||||
| void renderFPS(struct NVGcontext* vg, float x, float y, struct FPScounter* fps) | |||||
| { | |||||
| int i; | |||||
| float avg, w, h; | |||||
| char str[64]; | |||||
| avg = getAvg(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 == FPS_RENDER_FPS) { | |||||
| 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"); | |||||
| 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 == FPS_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 { | |||||
| 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); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,42 @@ | |||||
| #ifndef PERF_H | |||||
| #define PERF_H | |||||
| #include "nanovg.h" | |||||
| #ifdef __cplusplus | |||||
| extern "C" { | |||||
| #endif | |||||
| enum FPSrenderStyle { | |||||
| FPS_RENDER_FPS, | |||||
| FPS_RENDER_MS, | |||||
| }; | |||||
| #define FPS_HISTORY_COUNT 100 | |||||
| struct FPScounter { | |||||
| int style; | |||||
| char name[32]; | |||||
| float values[FPS_HISTORY_COUNT]; | |||||
| int head; | |||||
| }; | |||||
| void initFPS(struct FPScounter* fps, int style, const char* name); | |||||
| void updateFPS(struct FPScounter* fps, float frameTime); | |||||
| void renderFPS(struct NVGcontext* vg, float x, float y, struct FPScounter* fps); | |||||
| #define GPU_QUERY_COUNT 5 | |||||
| struct GPUtimer { | |||||
| int supported; | |||||
| int cur, ret; | |||||
| unsigned int queries[GPU_QUERY_COUNT]; | |||||
| }; | |||||
| void initGPUTimer(struct GPUtimer* timer); | |||||
| void startGPUTimer(struct GPUtimer* timer); | |||||
| int stopGPUTimer(struct GPUtimer* timer, float* times, int maxTimes); | |||||
| #ifdef __cplusplus | |||||
| } | |||||
| #endif | |||||
| #endif // PERF_H | |||||
| @@ -16,7 +16,7 @@ solution "nanovg" | |||||
| project "example_gl2" | project "example_gl2" | ||||
| kind "ConsoleApp" | kind "ConsoleApp" | ||||
| language "C" | language "C" | ||||
| files { "example/example_gl2.c", "example/demo.c" } | |||||
| files { "example/example_gl2.c", "example/demo.c", "example/perf.c" } | |||||
| includedirs { "src", "example" } | includedirs { "src", "example" } | ||||
| targetdir("build") | targetdir("build") | ||||
| links { "nanovg" } | links { "nanovg" } | ||||
| @@ -43,7 +43,7 @@ solution "nanovg" | |||||
| project "example_gl3" | project "example_gl3" | ||||
| kind "ConsoleApp" | kind "ConsoleApp" | ||||
| language "C" | language "C" | ||||
| files { "example/example_gl3.c", "example/demo.c" } | |||||
| files { "example/example_gl3.c", "example/demo.c", "example/perf.c" } | |||||
| includedirs { "src", "example" } | includedirs { "src", "example" } | ||||
| targetdir("build") | targetdir("build") | ||||
| links { "nanovg" } | links { "nanovg" } | ||||
| @@ -71,7 +71,7 @@ solution "nanovg" | |||||
| kind "ConsoleApp" | kind "ConsoleApp" | ||||
| language "C" | language "C" | ||||
| defines { "DEMO_MSAA" } | defines { "DEMO_MSAA" } | ||||
| files { "example/example_gl2.c", "example/demo.c" } | |||||
| files { "example/example_gl2.c", "example/demo.c", "example/perf.c" } | |||||
| includedirs { "src", "example" } | includedirs { "src", "example" } | ||||
| targetdir("build") | targetdir("build") | ||||
| links { "nanovg" } | links { "nanovg" } | ||||
| @@ -99,7 +99,7 @@ solution "nanovg" | |||||
| kind "ConsoleApp" | kind "ConsoleApp" | ||||
| language "C" | language "C" | ||||
| defines { "DEMO_MSAA" } | defines { "DEMO_MSAA" } | ||||
| files { "example/example_gl3.c", "example/demo.c" } | |||||
| files { "example/example_gl3.c", "example/demo.c", "example/perf.c" } | |||||
| includedirs { "src", "example" } | includedirs { "src", "example" } | ||||
| targetdir("build") | targetdir("build") | ||||
| links { "nanovg" } | links { "nanovg" } | ||||
| @@ -126,7 +126,7 @@ solution "nanovg" | |||||
| project "example_gles2" | project "example_gles2" | ||||
| kind "ConsoleApp" | kind "ConsoleApp" | ||||
| language "C" | language "C" | ||||
| files { "example/example_gles2.c", "example/demo.c" } | |||||
| files { "example/example_gles2.c", "example/demo.c", "example/perf.c" } | |||||
| includedirs { "src", "example" } | includedirs { "src", "example" } | ||||
| targetdir("build") | targetdir("build") | ||||
| links { "nanovg" } | links { "nanovg" } | ||||
| @@ -152,7 +152,7 @@ solution "nanovg" | |||||
| project "example_gles3" | project "example_gles3" | ||||
| kind "ConsoleApp" | kind "ConsoleApp" | ||||
| language "C" | language "C" | ||||
| files { "example/example_gles3.c", "example/demo.c" } | |||||
| files { "example/example_gles3.c", "example/demo.c", "example/perf.c" } | |||||
| includedirs { "src", "example" } | includedirs { "src", "example" } | ||||
| targetdir("build") | targetdir("build") | ||||
| links { "nanovg" } | links { "nanovg" } | ||||