一、起因:
之前我用agg封装实现了一个类似GDI+的接口(AGGDI+)。但是测试下来,大部分情况下效率要低于GDI+。这使我怀疑AGG官方所宣称的其所具有的高性能表现。然而,在那个同样是封装AGG实现GDI+的AggPlus中的测试表明:AGG的效率某些情况下超过GDI+10倍之多。显然我是难以相信AGG在效率上的这种优势的。于是下决心对AGG和GDI+的图形渲染效率进行比较。
二、比较的具体细节:
首先,我决定先比较下两者在光珊化速度上的表现。同时由于AGG宣称其反走样技术的优质和高效,所以决定先只比较反走样模式下,两者渲染多边形的效率。同时,对颜色混合的过程也进行了简单的测试。主要针对非alpha混合和alpha混合两种模式下的填充进行比对。比较过程如下:
1、agg和gdi+生成同样大小的32位位图(可调整长宽)
2、根据位图大小生成位图范围内的随机的多边形(多边形边数和个数可调整)
3、根据多边形个数生成同样个数的随机颜色(带alpha和不带alpha的)
4、开始计时
5、agg或者gdi+分别使用rasterizer和graphics进行光栅化和填充
6、结束计时
7、agg或者gdi+分别保存渲染得到的图片
测试的具体环境:由于gdi+似乎是用vc7或者vc8编译生成的。所以我在vc2005下运行了测试程序。当然,在vc6下也是可以的。只是vc6的优化做得不够好。同时在c++代码编译方面有几个bug(当然,为了避免这些bug,代码已经修改是可以在vc6下编译运行的)。
核心测试代码如下:
// ------------------------------------------------------------TestAggRender
template <class PolygonSource, class ColorSource>
double TestAggRender(const PolygonSource& polygons,
const ColorSource& colors,
bool bAa = true,
bool bFillEvenOdd = true)
{
typedef typename PolygonSource::polygon_type PolygonType;
agg::pixel_map bmp;
bmp.create(PolygonType::PolygonRangeRight - PolygonType::PolygonRangeLeft,
PolygonType::PolygonRangeBottom - PolygonType::PolygonRangeTop, agg::org_color32, 255);
agg::rendering_buffer rbuf(bmp.buf(), bmp.width(), bmp.height(), -bmp.stride());
agg::pixfmt_bgra32 pixfmt(rbuf);
agg::renderer_base<agg::pixfmt_bgra32> renb(pixfmt);
WinClockRecorder recorder;
recorder.BeginRecord();
if (bAa)
{
for (unsigned i = 0; i < polygons.Count(); ++i)
{
typedef typename PolygonSource::polygon_type PolygonType;
typedef typename PolygonType::point_type PointType;
const PolygonType& polygon = polygons[i];
const PointType& pt0 = polygon[0];
agg::rasterizer_scanline_aa<> ras;
ras.filling_rule(bFillEvenOdd ? agg::fill_even_odd : agg::fill_non_zero);
ras.move_to_d(pt0.X(), pt0.Y());
for (unsigned j = 1; j < PolygonType::PolygonSides; ++j)
{
const PointType& pt = polygon[j];
ras.line_to_d(pt.X(), pt.Y());
}
agg::render_scanlines_aa_solid(ras, agg::scanline_p8(), renb,
agg::rgba8(colors.GetR(i), colors.GetG(i), colors.GetB(i), colors.GetA(i)));
}
}
else
{
}
double ret = recorder.EndRecord();
char szFileName[256] = {'\0'};
sprintf(szFileName, "%s%d_%d_%d_%d_%f_agg.bmp", agg_folder,
polygons.Count(), PolygonType::PolygonSides, bAa, bFillEvenOdd, ret);
bmp.save_as_bmp(szFileName);
bmp.destroy();
Sleep(7);
return ret;
}
template <class PolygonSource, class ColorSource>
double TestGdipRender(const PolygonSource& polygons,
const ColorSource& colors,
bool bAa = true,
bool bFillEvenOdd = true)
{
using namespace Gdiplus;
typedef typename PolygonSource::polygon_type PolygonType;
Bitmap bmp(PolygonType::PolygonRangeRight - PolygonType::PolygonRangeLeft,
PolygonType::PolygonRangeBottom - PolygonType::PolygonRangeTop);
Graphics g(&bmp);
g.Clear(Color::White);
WinClockRecorder recorder;
recorder.BeginRecord();
if (bAa)
{
g.SetSmoothingMode(SmoothingModeHighQuality);
}
for (unsigned i = 0; i < polygons.Count(); ++i)
{
typedef typename PolygonSource::polygon_type PolygonType;
typedef typename PolygonType::point_type PointType;
const PolygonType& polygon = polygons[i];
const PointType& pt0 = polygon[0];
GraphicsPath path(bFillEvenOdd ? FillModeAlternate : FillModeWinding);
for (unsigned j = 0; j < PolygonType::PolygonSides; ++j)
{
const PointType& pt = polygon[j];
path.AddLines(&PointF((REAL)pt.X(),(REAL)pt.Y()), 1);
}
g.FillPath(&SolidBrush(Color(colors.GetA(i), colors.GetR(i),
colors.GetG(i), colors.GetB(i))), &path);
}
double ret = recorder.EndRecord();
wchar_t szFileName[256] = {'\0'};
swprintf(szFileName, L"%s%d_%d_%d_%d_%f_gdip.bmp", gdip_folder,
polygons.Count(), PolygonType::PolygonSides, bAa, bFillEvenOdd, ret);
CLSID bmpClsid;
GetEncoderClsid(L"image/bmp", &bmpClsid);
bmp.Save(szFileName, &bmpClsid, NULL);
Sleep(7);
return ret;
}
三、结果
AGG的表现整体来说超过gdi+。尤其在没有使用aplha混合的时候,效率优势较为明显。但是肯定没有AggPlus所宣称的10倍的优势。(微软的工程师估计会很有意见,呵呵。)
四、不足
这次测试的面还是比较偏。没有考虑到裁剪以及坐标系的转换等渲染参数(反走样、填充模式、坐标系转换、alpha混合模式)的设置以及其他画刷(线性渐变,图案填充等)。