wxWidgets/tests/benchmarks/graphics.cpp
Vadim Zeitlin bfeae1922d Minor optimizations in GetMultiLineTextExtent()
Handle the case of a single line string specially, it's faster to do
this than use slow loop over all characters.

Also avoid constructing the string with the characters to measure one by
one and do it all at once instead.

Add a possibility to benchmark GetMultiLineTextExtent() rather than
GetTextExtent() in the graphics benchmark.
2020-06-10 23:41:24 +02:00

1030 lines
29 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Name: graphics.cpp
// Purpose: Some benchmarks for measuring graphics operations performance
// Author: Vadim Zeitlin
// Created: 2008-04-13
// Copyright: (c) 2008 Vadim Zeitlin <vadim@wxwidgets.org>
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#include "wx/app.h"
#include "wx/frame.h"
#include "wx/cmdline.h"
#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()
{
mapMode = 0;
penWidth = 0;
penStyle = wxPENSTYLE_INVALID;
width = 800;
height = 600;
numIters = 1000;
testBitmaps =
testImages =
testLines =
testRawBitmaps =
testRectangles =
testCircles =
testEllipses =
testTextExtent =
testMultiLineTextExtent =
testPartialTextExtents = false;
usePaint =
useClient =
useMemory = false;
useDC =
useGC =
useGL = false;
renderer = Default;
}
long mapMode,
penWidth,
width,
height,
numIters;
wxPenStyle penStyle;
bool testBitmaps,
testImages,
testLines,
testRawBitmaps,
testRectangles,
testCircles,
testEllipses,
testTextExtent,
testMultiLineTextExtent,
testPartialTextExtents;
bool usePaint,
useClient,
useMemory;
bool useDC,
useGC,
useGL;
#ifdef __WXMSW__
enum GraphicsRenderer { Default, GDIPlus, Direct2D, Cairo };
#else
enum GraphicsRenderer { Default };
#endif // __WXMSW__ / !__WXMSW__
GraphicsRenderer renderer;
} opts;
class GraphicsBenchmarkFrame : public wxFrame
{
public:
GraphicsBenchmarkFrame()
: wxFrame(NULL, wxID_ANY, "wxWidgets Graphics Benchmark")
{
SetClientSize(opts.width, opts.height);
#if wxUSE_GLCANVAS
m_glCanvas = NULL;
m_glContext = 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_bitmapARGB.Create(64, 64, 32);
#if defined(__WXMSW__) || defined(__WXOSX__)
m_bitmapARGB.UseAlpha(true);
#endif // __WXMSW__ || _WXOSX__
m_bitmapRGB.Create(64, 64, 24);
wxBitmap bmpMask(64, 64, 1);
{
wxMemoryDC dc(bmpMask);
dc.SetBackground(*wxBLACK_BRUSH);
dc.Clear();
}
m_bitmapARGBwithMask.Create(64, 64, 32);
#if defined(__WXMSW__) || defined(__WXOSX__)
m_bitmapARGBwithMask.UseAlpha(true);
#endif // __WXMSW__ || __WXOSX__
m_bitmapARGBwithMask.SetMask(new wxMask(bmpMask));
m_bitmapRGBwithMask.Create(64, 64, 24);
m_bitmapRGBwithMask.SetMask(new wxMask(bmpMask));
m_renderer = NULL;
if ( opts.useGC )
{
#ifdef __WXMSW__
if ( opts.renderer == GraphicsBenchmarkOptions::GDIPlus )
m_renderer = wxGraphicsRenderer::GetGDIPlusRenderer();
else if ( opts.renderer == GraphicsBenchmarkOptions::Direct2D )
m_renderer = wxGraphicsRenderer::GetDirect2DRenderer();
else if ( opts.renderer == GraphicsBenchmarkOptions::Cairo )
m_renderer = wxGraphicsRenderer::GetCairoRenderer();
// Check if selected renderer is operational.
if ( m_renderer )
{
wxBitmap bmp(16, 16);
wxMemoryDC memDC(bmp);
wxGraphicsContext* gc = m_renderer->CreateContext(memDC);
if ( !gc )
{
wxPrintf("Couldn't initialize '%s' graphics renderer.\n", m_renderer->GetName().c_str());
m_renderer = NULL;
}
delete gc;
}
#endif // __WXMSW__
if( !m_renderer )
m_renderer = wxGraphicsRenderer::GetDefaultRenderer();
}
Show();
}
#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 )
{
{
wxPaintDC dc(this);
wxGCDC gcdc;
if ( m_renderer )
{
wxGraphicsContext* gc = m_renderer->CreateContext(dc);
gcdc.SetGraphicsContext(gc);
}
BenchmarkDCAndGC("paint", dc, gcdc);
}
// Since some renderers use back buffers and hence
// drawing results are not displayed when the test
// is running then wait a second after graphics
// contents is commited to DC to present the output.
wxSleep(1);
}
if ( opts.useClient )
{
{
wxClientDC dc(this);
wxGCDC gcdc;
if ( m_renderer )
{
wxGraphicsContext* gc = m_renderer->CreateContext(dc);
gcdc.SetGraphicsContext(gc);
}
BenchmarkDCAndGC("client", dc, gcdc);
}
// Since some renderers use back buffers and hence
// drawing results are not displayed when the test
// is running then wait a second after graphics
// contents is commited to DC to present the output.
wxSleep(1);
}
if ( opts.useMemory )
{
{
wxBitmap bmp(opts.width, opts.height);
wxMemoryDC dc(bmp);
wxGCDC gcdc;
if ( m_renderer )
{
wxGraphicsContext* gc = m_renderer->CreateContext(dc);
gcdc.SetGraphicsContext(gc);
}
BenchmarkDCAndGC("default memory", dc, gcdc);
}
{
wxBitmap bmp(opts.width, opts.height, 24);
wxMemoryDC dc(bmp);
wxGCDC gcdc;
if ( m_renderer )
{
wxGraphicsContext* gc = m_renderer->CreateContext(dc);
gcdc.SetGraphicsContext(gc);
}
BenchmarkDCAndGC("RGB memory", dc, gcdc);
}
{
#if defined(__WXMSW__) || defined(__WXOSX__)
wxBitmap bmp(opts.width, opts.height, 32);
bmp.UseAlpha(false);
wxMemoryDC dc(bmp);
wxGCDC gcdc;
if ( m_renderer )
{
wxGraphicsContext* gc = m_renderer->CreateContext(dc);
gcdc.SetGraphicsContext(gc);
}
BenchmarkDCAndGC("0RGB memory", dc, gcdc);
#endif // __WXMSW__ ||__WXOSX__
}
{
wxBitmap bmp(opts.width, opts.height, 32);
#if defined(__WXMSW__) || defined(__WXOSX__)
bmp.UseAlpha(true);
#endif // __WXMSW__ || __WXOSX__
wxMemoryDC dc(bmp);
wxGCDC gcdc;
if ( m_renderer )
{
wxGraphicsContext* gc = m_renderer->CreateContext(dc);
gcdc.SetGraphicsContext(gc);
}
BenchmarkDCAndGC("ARGB memory", dc, gcdc);
}
}
wxTheApp->ExitMainLoop();
}
void BenchmarkDCAndGC(const char* dckind, wxDC& dc, wxGCDC& gcdc)
{
if ( opts.useDC )
{
BenchmarkAll(wxString::Format("%6s DC", dckind), dc);
}
else if ( opts.useGC && gcdc.IsOk() )
{
wxString rendName = gcdc.GetGraphicsContext()->GetRenderer()->GetName();
BenchmarkAll(wxString::Format("%6s GC (%s)", dckind, rendName.c_str()), gcdc);
}
}
void BenchmarkAll(const wxString& msg, wxDC& dc)
{
BenchmarkBitmaps(msg, dc);
BenchmarkImages(msg, dc);
BenchmarkLines(msg, dc);
BenchmarkRawBitmaps(msg, dc);
BenchmarkRectangles(msg, dc);
BenchmarkRoundedRectangles(msg, dc);
BenchmarkCircles(msg, dc);
BenchmarkEllipses(msg, dc);
BenchmarkTextExtent(msg, dc);
BenchmarkPartialTextExtents(msg, dc);
}
void SetupDC(wxDC& dc)
{
if ( opts.mapMode != 0 )
dc.SetMapMode((wxMappingMode)opts.mapMode);
if ( opts.penWidth != 0 )
dc.SetPen(wxPen(*wxWHITE, opts.penWidth));
if ( opts.penStyle != wxPENSTYLE_INVALID )
{
wxPen pen = dc.GetPen();
if ( !pen.IsOk() )
pen = wxPen(*wxWHITE, 1);
pen.SetStyle(opts.penStyle);
dc.SetPen(pen);
}
}
void BenchmarkLines(const wxString& msg, wxDC& dc)
{
if ( !opts.testLines )
return;
SetupDC(dc);
wxPrintf("Benchmarking %s: ", msg);
fflush(stdout);
wxStopWatch sw;
int x0 = 0,
y0 = 0;
for ( int n = 0; n < opts.numIters; n++ )
{
int x1 = rand() % opts.width,
y1 = rand() % opts.height;
dc.DrawLine(x0, y0, x1, y1);
x0 = x1;
y0 = y1;
}
const long t = sw.Time();
wxPrintf("%ld lines done in %ldms = %gus/line\n",
opts.numIters, t, (1000. * t)/opts.numIters);
// Horizontal lines
wxPrintf("Benchmarking %s: ", msg);
fflush(stdout);
sw.Start();
x0 = 0;
for ( int n = 0; n < opts.numIters; n++ )
{
int x1 = rand() % opts.width;
int y = rand() % opts.height;
dc.DrawLine(x0, y, x1, y);
x0 = x1;
}
const long t2 = sw.Time();
wxPrintf("%ld horizontal lines done in %ldms = %gus/line\n",
opts.numIters, t2, (1000. * t2) / opts.numIters);
// Vertical lines
wxPrintf("Benchmarking %s: ", msg);
fflush(stdout);
sw.Start();
y0 = 0;
for ( int n = 0; n < opts.numIters; n++ )
{
int x = rand() % opts.width;
int y1 = rand() % opts.height;
dc.DrawLine(x, y0, x, y1);
y0 = y1;
}
const long t3 = sw.Time();
wxPrintf("%ld vertical lines done in %ldms = %gus/line\n",
opts.numIters, t3, (1000. * t3) / opts.numIters);
// Cross hair
wxPrintf("Benchmarking %s: ", msg);
fflush(stdout);
sw.Start();
for ( int n = 0; n < opts.numIters; n++ )
{
x0 = rand() % opts.width;
y0 = rand() % opts.height;
dc.CrossHair(x0, y0);
}
const long t4 = sw.Time();
wxPrintf("%ld cross hairs done in %ldms = %gus/line\n",
opts.numIters, t4, (1000. * t4) / (2*opts.numIters));
}
void BenchmarkRectangles(const wxString& msg, wxDC& dc)
{
if ( !opts.testRectangles )
return;
SetupDC(dc);
dc.SetBrush( *wxRED_BRUSH );
wxPrintf("Benchmarking %s: ", msg);
fflush(stdout);
wxStopWatch sw;
for ( int n = 0; n < opts.numIters; n++ )
{
int x = rand() % opts.width,
y = rand() % opts.height;
dc.DrawRectangle(x, y, 32, 32);
}
const long t = sw.Time();
wxPrintf("%ld rects done in %ldms = %gus/rect\n",
opts.numIters, t, (1000. * t)/opts.numIters);
}
void BenchmarkRoundedRectangles(const wxString& msg, wxDC& dc)
{
if ( !opts.testRectangles )
return;
SetupDC(dc);
dc.SetBrush( *wxCYAN_BRUSH );
wxPrintf("Benchmarking %s: ", msg);
fflush(stdout);
wxStopWatch sw;
for ( int n = 0; n < opts.numIters; n++ )
{
int x = rand() % opts.width,
y = rand() % opts.height;
dc.DrawRoundedRectangle(x, y, 48, 32, 8);
}
const long t = sw.Time();
wxPrintf("%ld rounded rects done in %ldms = %gus/rect\n",
opts.numIters, t, (1000. * t)/opts.numIters);
}
void BenchmarkCircles(const wxString& msg, wxDC& dc)
{
if ( !opts.testCircles )
return;
SetupDC(dc);
dc.SetBrush( *wxGREEN_BRUSH );
wxPrintf("Benchmarking %s: ", msg);
fflush(stdout);
wxStopWatch sw;
for ( long n = 0; n < opts.numIters; n++ )
{
int x = rand() % opts.width,
y = rand() % opts.height;
dc.DrawCircle(x, y, 32);
}
const long t = sw.Time();
wxPrintf("%ld circles done in %ldms = %gus/circle\n",
opts.numIters, t, (1000. * t)/opts.numIters);
}
void BenchmarkEllipses(const wxString& msg, wxDC& dc)
{
if ( !opts.testEllipses )
return;
SetupDC(dc);
dc.SetBrush( *wxBLUE_BRUSH );
wxPrintf("Benchmarking %s: ", msg);
fflush(stdout);
wxStopWatch sw;
for ( long n = 0; n < opts.numIters; n++ )
{
int x = rand() % opts.width,
y = rand() % opts.height;
dc.DrawEllipse(x, y, 48, 32);
}
const long t = sw.Time();
wxPrintf("%ld ellipses done in %ldms = %gus/ellipse\n",
opts.numIters, t, (1000. * t)/opts.numIters);
}
void BenchmarkTextExtent(const wxString& msg, wxDC& dc)
{
if ( !opts.testTextExtent )
return;
SetupDC(dc);
wxPrintf("Benchmarking %s: ", msg);
fflush(stdout);
const wxString str("The quick brown fox jumps over the lazy dog");
wxSize size;
wxStopWatch sw;
for ( long n = 0; n < opts.numIters; n++ )
{
if ( opts.testMultiLineTextExtent )
size += dc.GetMultiLineTextExtent(str);
else
size += dc.GetTextExtent(str);
}
const long t = sw.Time();
wxPrintf("%ld text extent measures done in %ldms = %gus/call\n",
opts.numIters, t, (1000. * t)/opts.numIters);
}
void BenchmarkPartialTextExtents(const wxString& msg, wxDC& dc)
{
if ( !opts.testPartialTextExtents )
return;
SetupDC(dc);
wxPrintf("Benchmarking %s: ", msg);
fflush(stdout);
const wxString str("The quick brown fox jumps over the lazy dog");
wxArrayInt widths;
wxStopWatch sw;
for ( long n = 0; n < opts.numIters; n++ )
{
if ( !dc.GetPartialTextExtents(str, widths) )
{
wxPrintf("ERROR: GetPartialTextExtents() failed\n");
return;
}
}
const long t = sw.Time();
wxPrintf("%ld partial text extents measures done in %ldms = %gus/call\n",
opts.numIters, t, (1000. * t)/opts.numIters);
}
void BenchmarkBitmaps(const wxString& msg, wxDC& dc)
{
if ( !opts.testBitmaps )
return;
SetupDC(dc);
wxPrintf("Benchmarking %s: ", msg);
fflush(stdout);
wxStopWatch sw;
for ( int n = 0; n < opts.numIters; n++ )
{
int x = rand() % opts.width,
y = rand() % opts.height;
dc.DrawBitmap(m_bitmapARGB, x, y, true);
}
const long t = sw.Time();
wxPrintf("%ld ARGB bitmaps done in %ldms = %gus/bitmap\n",
opts.numIters, t, (1000. * t)/opts.numIters);
wxPrintf("Benchmarking %s: ", msg);
fflush(stdout);
sw.Start();
for ( int n = 0; n < opts.numIters; n++ )
{
int x = rand() % opts.width,
y = rand() % opts.height;
dc.DrawBitmap(m_bitmapRGB, x, y, true);
}
const long t2 = sw.Time();
wxPrintf("%ld RGB bitmaps done in %ldms = %gus/bitmap\n",
opts.numIters, t2, (1000. * t2)/opts.numIters);
wxPrintf("Benchmarking %s: ", msg);
fflush(stdout);
sw.Start();
for ( int n = 0; n < opts.numIters; n++ )
{
int x = rand() % opts.width,
y = rand() % opts.height;
dc.DrawBitmap(m_bitmapARGBwithMask, x, y, true);
}
const long t3 = sw.Time();
wxPrintf("%ld ARGB bitmaps with mask done in %ldms = %gus/bitmap\n",
opts.numIters, t3, (1000. * t3) / opts.numIters);
wxPrintf("Benchmarking %s: ", msg);
fflush(stdout);
sw.Start();
for ( int n = 0; n < opts.numIters; n++ )
{
int x = rand() % opts.width,
y = rand() % opts.height;
dc.DrawBitmap(m_bitmapRGBwithMask, x, y, true);
}
const long t4 = sw.Time();
wxPrintf("%ld RGB bitmaps with mask done in %ldms = %gus/bitmap\n",
opts.numIters, t4, (1000. * t4) / 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_bitmapARGB;
wxBitmap m_bitmapRGB;
wxBitmap m_bitmapARGBwithMask;
wxBitmap m_bitmapRGBwithMask;
#if wxUSE_GLCANVAS
wxGLCanvas* m_glCanvas;
wxGLContext* m_glContext;
#endif // wxUSE_GLCANVAS
wxGraphicsRenderer* m_renderer;
};
class GraphicsBenchmarkApp : public wxApp
{
public:
virtual void OnInitCmdLine(wxCmdLineParser& parser)
{
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, "", "circles" },
{ wxCMD_LINE_SWITCH, "", "ellipses" },
{ wxCMD_LINE_SWITCH, "", "textextent" },
{ wxCMD_LINE_SWITCH, "", "multilinetextextent" },
{ wxCMD_LINE_SWITCH, "", "partialtextextents" },
{ 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, "s", "pen-style", "solid | dot | long_dash | short_dash", wxCMD_LINE_VAL_STRING },
{ wxCMD_LINE_OPTION, "w", "width", "", wxCMD_LINE_VAL_NUMBER },
{ wxCMD_LINE_OPTION, "h", "height", "", wxCMD_LINE_VAL_NUMBER },
{ wxCMD_LINE_OPTION, "I", "images", "", wxCMD_LINE_VAL_NUMBER },
{ wxCMD_LINE_OPTION, "N", "number-of-iterations", "", wxCMD_LINE_VAL_NUMBER },
#ifdef __WXMSW__
{ wxCMD_LINE_OPTION, "r", "renderer", "gdiplus | direct2d | cairo", wxCMD_LINE_VAL_STRING },
#endif // __WXMSW__
{ wxCMD_LINE_NONE },
};
parser.SetDesc(desc);
}
virtual bool OnCmdLineParsed(wxCmdLineParser& parser)
{
if ( parser.Found("m", &opts.mapMode) &&
(opts.mapMode < 1 || opts.mapMode > wxMM_METRIC) )
return false;
if ( parser.Found("p", &opts.penWidth) && opts.penWidth < 1 )
return false;
wxString penStyle;
if ( parser.Found("pen-style", &penStyle) )
{
if ( !penStyle.empty() )
{
if ( penStyle == wxS("solid") )
{
opts.penStyle = wxPENSTYLE_SOLID;
}
else if ( penStyle == wxS("dot") )
{
opts.penStyle = wxPENSTYLE_DOT;
}
else if ( penStyle == wxS("long_dash") )
{
opts.penStyle = wxPENSTYLE_LONG_DASH;
}
else if ( penStyle == wxS("short_dash") )
{
opts.penStyle = wxPENSTYLE_SHORT_DASH;
}
else
{
wxLogError(wxS("Unsupported pen style."));
return false;
}
}
}
if ( parser.Found("w", &opts.width) && opts.width < 1 )
return false;
if ( parser.Found("h", &opts.height) && opts.height < 1 )
return false;
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");
opts.testCircles = parser.Found("circles");
opts.testEllipses = parser.Found("ellipses");
opts.testTextExtent = parser.Found("textextent");
opts.testMultiLineTextExtent = parser.Found("multilinetextextent");
opts.testPartialTextExtents = parser.Found("partialtextextents");
if ( !(opts.testBitmaps || opts.testImages || opts.testLines
|| opts.testRawBitmaps || opts.testRectangles
|| opts.testCircles || opts.testEllipses
|| opts.testTextExtent || opts.testPartialTextExtents) )
{
// Do everything by default.
opts.testBitmaps =
opts.testImages =
opts.testLines =
opts.testRawBitmaps =
opts.testRectangles =
opts.testCircles =
opts.testEllipses =
opts.testTextExtent =
opts.testPartialTextExtents = true;
}
opts.usePaint = parser.Found("paint");
opts.useClient = parser.Found("client");
opts.useMemory = parser.Found("memory");
if ( !(opts.usePaint || opts.useClient || opts.useMemory) )
{
opts.usePaint =
opts.useClient =
opts.useMemory = true;
}
opts.useDC = parser.Found("dc");
opts.useGC = parser.Found("gc");
#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
{
if ( !(opts.useDC || opts.useGC) )
{
opts.useDC =
opts.useGC = true;
}
}
opts.renderer = GraphicsBenchmarkOptions::Default;
#ifdef __WXMSW__
wxString rendererName;
if ( parser.Found("renderer", &rendererName) )
{
if ( !opts.useGC )
{
wxLogError("Renderer can be specified only when using graphics.");
return false;
}
if ( !rendererName.empty() )
{
if ( rendererName == wxS("gdiplus") )
{
opts.renderer = GraphicsBenchmarkOptions::GDIPlus;
}
else if ( rendererName == wxS("direct2d") )
{
opts.renderer = GraphicsBenchmarkOptions::Direct2D;
}
else if ( rendererName == wxS("cairo") )
{
opts.renderer = GraphicsBenchmarkOptions::Cairo;
}
else
{
wxLogError( wxS("Unknown renderer name.") );
return false;
}
}
}
#endif // __WXMSW__
return true;
}
virtual bool OnInit()
{
if ( !wxApp::OnInit() )
return false;
new GraphicsBenchmarkFrame;
return true;
}
};
wxIMPLEMENT_APP_CONSOLE(GraphicsBenchmarkApp);