Browse Source

Performance timer tweaks

- moved performance counter and drawing to separate file
- tweaks to performance drawing
shared-context
Mikko Mononen 11 years ago
parent
commit
1517841023
9 changed files with 255 additions and 188 deletions
  1. +0
    -99
      example/demo.c
  2. +3
    -19
      example/demo.h
  3. +2
    -1
      example/example_gl2.c
  4. +30
    -61
      example/example_gl3.c
  5. +2
    -1
      example/example_gles2.c
  6. +2
    -1
      example/example_gles3.c
  7. +168
    -0
      example/perf.c
  8. +42
    -0
      example/perf.h
  9. +6
    -6
      premake4.lua

+ 0
- 99
example/demo.c View File

@@ -849,102 +849,3 @@ void renderDemo(struct NVGcontext* vg, float mx, float my, float width, float he
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);
}
}


}


+ 3
- 19
example/demo.h View File

@@ -1,5 +1,5 @@
#ifndef WIDGETS_H
#define WIDGETS_H
#ifndef DEMO_H
#define DEMO_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 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
}
#endif

#endif // WIDGETS_H
#endif // DEMO_H

+ 2
- 1
example/example_gl2.c View File

@@ -25,6 +25,7 @@
#define NANOVG_GL2_IMPLEMENTATION
#include "nanovg_gl2.h"
#include "demo.h"
#include "perf.h"


void errorcb(int error, const char* desc)
@@ -57,7 +58,7 @@ int main()
return -1;
}

initFPS(&fps);
initFPS(&fps, FPS_RENDER_FPS, "Frame Time");

glfwSetErrorCallback(errorcb);



+ 30
- 61
example/example_gl3.c View File

@@ -30,14 +30,7 @@
//#include "nanovg_gl3.h"
#include "nanovg_gl3buf.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)
{
@@ -56,35 +49,30 @@ 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, cpuTimes, gpuTimes;
struct GPUtimer gpuTimer;
struct FPScounter fps, cpuGraph, gpuGraph;
double prevt = 0, cpuTime = 0;
int timerquery = GL_FALSE, currquery = 0, retquery = 0;
GLuint timerqueryid[NUM_QUERIES];

if (!glfwInit()) {
printf("Failed to init GLFW.");
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);
#ifndef _WIN32 // don't require this on win32, and works with more cards
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
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

#ifdef DEMO_MSAA
@@ -92,7 +80,7 @@ int main()
#endif
window = glfwCreateWindow(1000, 600, "NanoVG", NULL, NULL);
// window = glfwCreateWindow(1000, 600, "NanoVG", glfwGetPrimaryMonitor(), NULL);
if (!window) {
if (!window) {
glfwTerminate();
return -1;
}
@@ -102,7 +90,7 @@ int main()
glfwMakeContextCurrent(window);
#ifdef NANOVG_GLEW
glewExperimental = GL_TRUE;
if(glewInit() != GLEW_OK) {
if(glewInit() != GLEW_OK) {
printf("Could not init glew.\n");
return -1;
}
@@ -123,17 +111,7 @@ int main()

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);
prevt = glfwGetTime();
@@ -144,16 +122,14 @@ int main()
int winWidth, winHeight;
int fbWidth, fbHeight;
float pxRatio;
float gpuTimes[3];
int i, n;

t = glfwGetTime();
dt = t - prevt;
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);
glfwGetWindowSize(window, &winWidth, &winHeight);
@@ -174,34 +150,27 @@ int main()
nvgBeginFrame(vg, winWidth, winHeight, pxRatio);

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");
renderFPS(vg, 5+200+5,5, &cpuGraph);
if (gpuTimer.supported)
renderFPS(vg, 5+200+5+200+5,5, &gpuGraph);

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);
}
}

}
// 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);
glfwPollEvents();
}


+ 2
- 1
example/example_gles2.c View File

@@ -23,6 +23,7 @@
#define NANOVG_GLES2_IMPLEMENTATION
#include "nanovg_gl2.h"
#include "demo.h"
#include "perf.h"


void errorcb(int error, const char* desc)
@@ -55,7 +56,7 @@ int main()
return -1;
}

initFPS(&fps);
initFPS(&fps, FPS_RENDER_FPS, "Frame Time");

glfwSetErrorCallback(errorcb);



+ 2
- 1
example/example_gles3.c View File

@@ -23,6 +23,7 @@
#define NANOVG_GLES3_IMPLEMENTATION
#include "nanovg_gl3.h"
#include "demo.h"
#include "perf.h"


void errorcb(int error, const char* desc)
@@ -55,7 +56,7 @@ int main()
return -1;
}

initFPS(&fps);
initFPS(&fps, FPS_RENDER_FPS, "Frame Time");

glfwSetErrorCallback(errorcb);



+ 168
- 0
example/perf.c View File

@@ -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);
}
}

+ 42
- 0
example/perf.h View File

@@ -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

+ 6
- 6
premake4.lua View File

@@ -16,7 +16,7 @@ solution "nanovg"
project "example_gl2"
kind "ConsoleApp"
language "C"
files { "example/example_gl2.c", "example/demo.c" }
files { "example/example_gl2.c", "example/demo.c", "example/perf.c" }
includedirs { "src", "example" }
targetdir("build")
links { "nanovg" }
@@ -43,7 +43,7 @@ solution "nanovg"
project "example_gl3"
kind "ConsoleApp"
language "C"
files { "example/example_gl3.c", "example/demo.c" }
files { "example/example_gl3.c", "example/demo.c", "example/perf.c" }
includedirs { "src", "example" }
targetdir("build")
links { "nanovg" }
@@ -71,7 +71,7 @@ solution "nanovg"
kind "ConsoleApp"
language "C"
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" }
targetdir("build")
links { "nanovg" }
@@ -99,7 +99,7 @@ solution "nanovg"
kind "ConsoleApp"
language "C"
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" }
targetdir("build")
links { "nanovg" }
@@ -126,7 +126,7 @@ solution "nanovg"
project "example_gles2"
kind "ConsoleApp"
language "C"
files { "example/example_gles2.c", "example/demo.c" }
files { "example/example_gles2.c", "example/demo.c", "example/perf.c" }
includedirs { "src", "example" }
targetdir("build")
links { "nanovg" }
@@ -152,7 +152,7 @@ solution "nanovg"
project "example_gles3"
kind "ConsoleApp"
language "C"
files { "example/example_gles3.c", "example/demo.c" }
files { "example/example_gles3.c", "example/demo.c", "example/perf.c" }
includedirs { "src", "example" }
targetdir("build")
links { "nanovg" }


Loading…
Cancel
Save