#include "wx/dcclient.h"
#include "wx/dcmemory.h"
#include "wx/dcgraph.h"
+#include "wx/image.h"
+#include "wx/rawbmp.h"
#include "wx/stopwatch.h"
#include "wx/crt.h"
+#if wxUSE_GLCANVAS
+ #include "wx/glcanvas.h"
+ #ifdef _MSC_VER
+ #pragma comment(lib, "opengl32")
+ #endif
+#endif // wxUSE_GLCANVAS
+
+#if wxUSE_GLCANVAS
+
+GLuint g_texture;
+wxImage g_image;
+
+void InitializeTexture(int w, int h)
+{
+ glGenTextures(1, &g_texture);
+ glBindTexture(GL_TEXTURE_2D, g_texture);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+
+ g_image.Create(w, h, false /* don't clear */);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glTexImage2D(GL_TEXTURE_2D, 0,
+ GL_RGB, g_image.GetWidth(), g_image.GetHeight(), 0,
+ GL_RGB, GL_UNSIGNED_BYTE, g_image.GetData());
+}
+#endif // wxUSE_GLCANVAS
+
struct GraphicsBenchmarkOptions
{
GraphicsBenchmarkOptions()
width = 800;
height = 600;
- numLines = 10000;
+ numIters = 1000;
testBitmaps =
+ testImages =
testLines =
+ testRawBitmaps =
testRectangles = false;
usePaint =
useMemory = false;
useDC =
- useGC = false;
+ useGC =
+ useGL = false;
}
long mapMode,
penWidth,
width,
height,
- numLines;
+ numIters;
bool testBitmaps,
+ testImages,
testLines,
+ testRawBitmaps,
testRectangles;
bool usePaint,
useMemory;
bool useDC,
- useGC;
+ useGC,
+ useGL;
} opts;
class GraphicsBenchmarkFrame : public wxFrame
GraphicsBenchmarkFrame()
: wxFrame(NULL, wxID_ANY, "wxWidgets Graphics Benchmark")
{
- Connect(wxEVT_PAINT,
- wxPaintEventHandler(GraphicsBenchmarkFrame::OnPaint));
+ SetClientSize(opts.width, opts.height);
+
+#if wxUSE_GLCANVAS
+ m_glCanvas = NULL;
+
+ if ( opts.useGL )
+ {
+ m_glCanvas = new wxGLCanvas(this, wxID_ANY, NULL,
+ wxPoint(0, 0),
+ wxSize(opts.width, opts.height));
+ m_glContext = new wxGLContext(m_glCanvas);
+ m_glContext->SetCurrent(*m_glCanvas);
+
+ glViewport(0, 0, opts.width, opts.height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(-1, 1, -1, 1, -1, 1);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ InitializeTexture(opts.width, opts.height);
+
+ m_glCanvas->Connect(
+ wxEVT_PAINT,
+ wxPaintEventHandler(GraphicsBenchmarkFrame::OnGLRender),
+ NULL,
+ this
+ );
+ }
+ else // Not using OpenGL
+#endif // wxUSE_GLCANVAS
+ {
+ Connect(wxEVT_PAINT,
+ wxPaintEventHandler(GraphicsBenchmarkFrame::OnPaint));
+ }
+
+ Connect(wxEVT_SIZE, wxSizeEventHandler(GraphicsBenchmarkFrame::OnSize));
m_bitmap.Create(64, 64, 32);
Show();
- SetClientSize(opts.width, opts.height);
}
+#if wxUSE_GLCANVAS
+ virtual ~GraphicsBenchmarkFrame()
+ {
+ delete m_glContext;
+ }
+#endif // wxUSE_GLCANVAS
+
private:
+ // Just change the image in some (quick) way to show that it's really being
+ // updated on screen.
+ void UpdateRGB(unsigned char* data, int n)
+ {
+ for ( int y = 0; y < opts.height; ++y )
+ {
+ memset(data, n % 256, 3*opts.width);
+
+ data += 3*opts.width;
+ n++;
+ }
+ }
+
+#if wxUSE_GLCANVAS
+ void OnGLRender(wxPaintEvent& WXUNUSED(event))
+ {
+ m_glContext->SetCurrent(*m_glCanvas);
+ glEnable(GL_TEXTURE_2D);
+
+ glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ wxPrintf("Benchmarking %s: ", "OpenGL images");
+ fflush(stdout);
+
+ wxStopWatch sw;
+ for ( int n = 0; n < opts.numIters; n++ )
+ {
+ UpdateRGB(g_image.GetData(), n);
+
+ glTexSubImage2D(GL_TEXTURE_2D, 0,
+ 0, 0, opts.width, opts.height,
+ GL_RGB, GL_UNSIGNED_BYTE, g_image.GetData());
+ glBegin(GL_QUADS);
+ glTexCoord2f(0, 0);
+ glVertex2f(-1.0, -1.0);
+
+ glTexCoord2f(0, 1);
+ glVertex2f(-1.0, 1.0);
+
+ glTexCoord2f(1, 1);
+ glVertex2f(1.0, 1.0);
+
+ glTexCoord2f(1, 0);
+ glVertex2f(1.0, -1.0);
+ glEnd();
+
+ m_glCanvas->SwapBuffers();
+ }
+
+ const long t = sw.Time();
+
+ wxPrintf("%ld images done in %ldms = %gus/image or %ld FPS\n",
+ opts.numIters, t, (1000. * t)/opts.numIters,
+ (1000*opts.numIters + t - 1)/t);
+
+ wxTheApp->ExitMainLoop();
+ }
+#endif // wxUSE_GLCANVAS
+
void OnPaint(wxPaintEvent& WXUNUSED(event))
{
if ( opts.usePaint )
void BenchmarkAll(const wxString& msg, wxDC& dc)
{
+ BenchmarkBitmaps(msg, dc);
+ BenchmarkImages(msg, dc);
BenchmarkLines(msg, dc);
+ BenchmarkRawBitmaps(msg, dc);
BenchmarkRectangles(msg, dc);
- BenchmarkBitmaps(msg, dc);
}
void BenchmarkLines(const wxString& msg, wxDC& dc)
wxStopWatch sw;
int x = 0,
y = 0;
- for ( int n = 0; n < opts.numLines; n++ )
+ for ( int n = 0; n < opts.numIters; n++ )
{
int x1 = rand() % opts.width,
y1 = rand() % opts.height;
const long t = sw.Time();
wxPrintf("%ld lines done in %ldms = %gus/line\n",
- opts.numLines, t, (1000. * t)/opts.numLines);
+ opts.numIters, t, (1000. * t)/opts.numIters);
}
fflush(stdout);
wxStopWatch sw;
- for ( int n = 0; n < opts.numLines; n++ )
+ for ( int n = 0; n < opts.numIters; n++ )
{
int x = rand() % opts.width,
y = rand() % opts.height;
const long t = sw.Time();
wxPrintf("%ld rects done in %ldms = %gus/rect\n",
- opts.numLines, t, (1000. * t)/opts.numLines);
+ opts.numIters, t, (1000. * t)/opts.numIters);
}
void BenchmarkBitmaps(const wxString& msg, wxDC& dc)
fflush(stdout);
wxStopWatch sw;
- for ( int n = 0; n < opts.numLines; n++ )
+ for ( int n = 0; n < opts.numIters; n++ )
{
int x = rand() % opts.width,
y = rand() % opts.height;
const long t = sw.Time();
wxPrintf("%ld bitmaps done in %ldms = %gus/bitmap\n",
- opts.numLines, t, (1000. * t)/opts.numLines);
+ opts.numIters, t, (1000. * t)/opts.numIters);
+ }
+
+ void BenchmarkImages(const wxString& msg, wxDC& dc)
+ {
+ if ( !opts.testImages )
+ return;
+
+ if ( opts.mapMode != 0 )
+ dc.SetMapMode((wxMappingMode)opts.mapMode);
+
+ wxPrintf("Benchmarking %s: ", msg);
+ fflush(stdout);
+
+ wxImage image(wxSize(opts.width, opts.height), false /* don't clear */);
+
+ wxStopWatch sw;
+ for ( int n = 0; n < opts.numIters; n++ )
+ {
+ UpdateRGB(image.GetData(), n);
+ dc.DrawBitmap(image, 0, 0);
+ }
+
+ const long t = sw.Time();
+
+ wxPrintf("%ld images done in %ldms = %gus/image or %ld FPS\n",
+ opts.numIters, t, (1000. * t)/opts.numIters,
+ (1000*opts.numIters + t - 1)/t);
+ }
+
+ void BenchmarkRawBitmaps(const wxString& msg, wxDC& dc)
+ {
+ if ( !opts.testRawBitmaps )
+ return;
+
+ if ( opts.mapMode != 0 )
+ dc.SetMapMode((wxMappingMode)opts.mapMode);
+
+ wxPrintf("Benchmarking %s: ", msg);
+ fflush(stdout);
+
+ wxBitmap bitmap(opts.width, opts.height, 24);
+ wxNativePixelData data(bitmap);
+
+ wxStopWatch sw;
+ for ( int n = 0; n < opts.numIters; n++ )
+ {
+ unsigned char c = n % 256;
+ {
+ wxNativePixelData::Iterator p(data);
+ for ( int y = 0; y < opts.height; ++y )
+ {
+ wxNativePixelData::Iterator rowStart = p;
+
+ for ( int x = 0; x < opts.width; ++x )
+ {
+ p.Red() =
+ p.Green() =
+ p.Blue() = c;
+ ++p;
+ }
+
+ p = rowStart;
+ p.OffsetY(data, 1);
+ c++;
+ }
+ }
+
+ dc.DrawBitmap(bitmap, 0, 0);
+ }
+
+ const long t = sw.Time();
+
+ wxPrintf("%ld raw bitmaps done in %ldms = %gus/bitmap or %ld FPS\n",
+ opts.numIters, t, (1000. * t)/opts.numIters,
+ (1000*opts.numIters + t - 1)/t);
}
wxBitmap m_bitmap;
+#if wxUSE_GLCANVAS
+ wxGLCanvas* m_glCanvas;
+ wxGLContext* m_glContext;
+#endif // wxUSE_GLCANVAS
};
class GraphicsBenchmarkApp : public wxApp
static const wxCmdLineEntryDesc desc[] =
{
{ wxCMD_LINE_SWITCH, "", "bitmaps" },
+ { wxCMD_LINE_SWITCH, "", "images" },
{ wxCMD_LINE_SWITCH, "", "lines" },
+ { wxCMD_LINE_SWITCH, "", "rawbmp" },
{ wxCMD_LINE_SWITCH, "", "rectangles" },
{ wxCMD_LINE_SWITCH, "", "paint" },
{ wxCMD_LINE_SWITCH, "", "client" },
{ wxCMD_LINE_SWITCH, "", "memory" },
{ wxCMD_LINE_SWITCH, "", "dc" },
{ wxCMD_LINE_SWITCH, "", "gc" },
+#if wxUSE_GLCANVAS
+ { wxCMD_LINE_SWITCH, "", "gl" },
+#endif // wxUSE_GLCANVAS
{ wxCMD_LINE_OPTION, "m", "map-mode", "", wxCMD_LINE_VAL_NUMBER },
{ wxCMD_LINE_OPTION, "p", "pen-width", "", wxCMD_LINE_VAL_NUMBER },
{ wxCMD_LINE_OPTION, "w", "width", "", wxCMD_LINE_VAL_NUMBER },
{ wxCMD_LINE_OPTION, "h", "height", "", wxCMD_LINE_VAL_NUMBER },
- { wxCMD_LINE_OPTION, "L", "lines", "", wxCMD_LINE_VAL_NUMBER },
+ { wxCMD_LINE_OPTION, "I", "images", "", wxCMD_LINE_VAL_NUMBER },
+ { wxCMD_LINE_OPTION, "N", "number-of-iterations", "", wxCMD_LINE_VAL_NUMBER },
{ wxCMD_LINE_NONE },
};
return false;
if ( parser.Found("h", &opts.height) && opts.height < 1 )
return false;
- if ( parser.Found("L", &opts.numLines) && opts.numLines < 1 )
+ if ( parser.Found("N", &opts.numIters) && opts.numIters < 1 )
return false;
opts.testBitmaps = parser.Found("bitmaps");
+ opts.testImages = parser.Found("images");
opts.testLines = parser.Found("lines");
+ opts.testRawBitmaps = parser.Found("rawbmp");
opts.testRectangles = parser.Found("rectangles");
- if ( !(opts.testBitmaps || opts.testLines || opts.testRectangles) )
+ if ( !(opts.testBitmaps || opts.testImages || opts.testLines
+ || opts.testRawBitmaps || opts.testRectangles) )
{
// Do everything by default.
opts.testBitmaps =
+ opts.testImages =
opts.testLines =
+ opts.testRawBitmaps =
opts.testRectangles = true;
}
opts.useDC = parser.Found("dc");
opts.useGC = parser.Found("gc");
- if ( !(opts.useDC || opts.useGC) )
+#if wxUSE_GLCANVAS
+ opts.useGL = parser.Found("gl");
+ if ( opts.useGL )
+ {
+ if ( opts.useDC || opts.useGC )
+ {
+ wxLogError("Can't use both OpenGL and normal graphics.");
+ return false;
+ }
+ }
+ else // Not using OpenGL
+#endif // wxUSE_GLCANVAS
{
- opts.useDC =
- opts.useGC = true;
+ if ( !(opts.useDC || opts.useGC) )
+ {
+ opts.useDC =
+ opts.useGC = true;
+ }
}
return true;