more robust pstats for qpgeom stuff

This commit is contained in:
David Rose 2005-04-16 19:59:21 +00:00
parent fef197285b
commit c83feafc70
15 changed files with 373 additions and 177 deletions

View File

@ -32,6 +32,7 @@
#include "mutexHolder.h"
#include "cullFaceAttrib.h"
#include "string_utils.h"
#include "qpgeomCacheManager.h"
#if defined(WIN32)
#define WINDOWS_LEAN_AND_MEAN
@ -500,6 +501,9 @@ render_frame() {
CullTraverser::_nodes_pcollector.clear_level();
CullTraverser::_geom_nodes_pcollector.clear_level();
CullTraverser::_geoms_pcollector.clear_level();
qpGeomCacheManager::_geom_cache_record_pcollector.clear_level();
qpGeomCacheManager::_geom_cache_erase_pcollector.clear_level();
qpGeomCacheManager::_geom_cache_evict_pcollector.clear_level();
_transform_states_pcollector.set_level(TransformState::get_num_states());
_render_states_pcollector.set_level(RenderState::get_num_states());

View File

@ -49,9 +49,12 @@ PStatCollector GraphicsStateGuardian::_total_texusage_pcollector("Texture usage"
PStatCollector GraphicsStateGuardian::_active_texusage_pcollector("Texture usage:Active");
PStatCollector GraphicsStateGuardian::_texture_count_pcollector("Prepared Textures");
PStatCollector GraphicsStateGuardian::_active_texture_count_pcollector("Prepared Textures:Active");
PStatCollector GraphicsStateGuardian::_total_buffer_count_pcollector("Vertex buffer count");
PStatCollector GraphicsStateGuardian::_active_vertex_buffer_count_pcollector("Vertex buffer count:Active vertex");
PStatCollector GraphicsStateGuardian::_active_index_buffer_count_pcollector("Vertex buffer count:Active index");
PStatCollector GraphicsStateGuardian::_vertex_buffer_switch_pcollector("Vertex buffer switch:Vertex");
PStatCollector GraphicsStateGuardian::_index_buffer_switch_pcollector("Vertex buffer switch:Index");
PStatCollector GraphicsStateGuardian::_load_vertex_buffer_pcollector("Draw:Transfer data:Vertex buffer");
PStatCollector GraphicsStateGuardian::_load_index_buffer_pcollector("Draw:Transfer data:Index buffer");
PStatCollector GraphicsStateGuardian::_load_texture_pcollector("Draw:Transfer data:Texture");
PStatCollector GraphicsStateGuardian::_data_transferred_pcollector("Data transferred");
PStatCollector GraphicsStateGuardian::_total_geom_pcollector("Prepared Geoms");
PStatCollector GraphicsStateGuardian::_active_geom_pcollector("Prepared Geoms:Active");
PStatCollector GraphicsStateGuardian::_total_buffers_pcollector("Vertex buffer size");
@ -63,6 +66,11 @@ PStatCollector GraphicsStateGuardian::_total_texmem_pcollector("Texture memory")
PStatCollector GraphicsStateGuardian::_used_texmem_pcollector("Texture memory:In use");
PStatCollector GraphicsStateGuardian::_texmgrmem_total_pcollector("Texture manager");
PStatCollector GraphicsStateGuardian::_texmgrmem_resident_pcollector("Texture manager:Resident");
PStatCollector GraphicsStateGuardian::_primitive_batches_pcollector("Primitive batches");
PStatCollector GraphicsStateGuardian::_primitive_batches_tristrip_pcollector("Primitive batches:Triangle strips");
PStatCollector GraphicsStateGuardian::_primitive_batches_trifan_pcollector("Primitive batches:Triangle fans");
PStatCollector GraphicsStateGuardian::_primitive_batches_tri_pcollector("Primitive batches:Triangles");
PStatCollector GraphicsStateGuardian::_primitive_batches_other_pcollector("Primitive batches:Other");
PStatCollector GraphicsStateGuardian::_vertices_tristrip_pcollector("Vertices:Triangle strips");
PStatCollector GraphicsStateGuardian::_vertices_trifan_pcollector("Vertices:Triangle fans");
PStatCollector GraphicsStateGuardian::_vertices_tri_pcollector("Vertices:Triangles");
@ -1541,14 +1549,19 @@ init_frame_pstats() {
_current_vertex_buffers.clear();
_current_index_buffers.clear();
_active_texusage_pcollector.clear_level();
_data_transferred_pcollector.clear_level();
_active_geom_pcollector.clear_level();
_active_geom_node_pcollector.clear_level();
_active_vertex_buffers_pcollector.clear_level();
_active_index_buffers_pcollector.clear_level();
_active_vertex_buffer_count_pcollector.clear_level();
_active_index_buffer_count_pcollector.clear_level();
_vertex_buffer_switch_pcollector.clear_level();
_index_buffer_switch_pcollector.clear_level();
// Also clear out our other counters while we're here.
_primitive_batches_pcollector.clear_level();
_primitive_batches_tristrip_pcollector.clear_level();
_primitive_batches_trifan_pcollector.clear_level();
_primitive_batches_tri_pcollector.clear_level();
_primitive_batches_other_pcollector.clear_level();
_vertices_tristrip_pcollector.clear_level();
_vertices_trifan_pcollector.clear_level();
_vertices_tri_pcollector.clear_level();
@ -1607,12 +1620,10 @@ add_to_geom_record(GeomContext *gc) {
void GraphicsStateGuardian::
add_to_vertex_buffer_record(VertexBufferContext *vbc) {
if (vbc != (VertexBufferContext *)NULL) {
int delta = vbc->get_data()->get_data_size_bytes() - vbc->get_data_size_bytes();
_total_buffers_pcollector.add_level(delta);
if (PStatClient::is_connected()) {
_vertex_buffer_switch_pcollector.add_level(1);
if (_current_vertex_buffers.insert(vbc).second) {
_active_vertex_buffers_pcollector.add_level(vbc->get_data()->get_data_size_bytes());
_active_vertex_buffer_count_pcollector.add_level(1);
}
}
}
@ -1629,16 +1640,47 @@ add_to_vertex_buffer_record(VertexBufferContext *vbc) {
void GraphicsStateGuardian::
add_to_index_buffer_record(IndexBufferContext *ibc) {
if (ibc != (IndexBufferContext *)NULL) {
int delta = ibc->get_data()->get_data_size_bytes() - ibc->get_data_size_bytes();
_total_buffers_pcollector.add_level(delta);
if (PStatClient::is_connected()) {
_index_buffer_switch_pcollector.add_level(1);
if (_current_index_buffers.insert(ibc).second) {
_active_index_buffers_pcollector.add_level(ibc->get_data()->get_data_size_bytes());
_active_index_buffer_count_pcollector.add_level(1);
}
}
}
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsStateGuardian::add_to_total_buffer_record
// Access: Protected
// Description: Records that the indicated data array has been loaded
// this frame. This function is only used to update the
// PStats total_buffers collector; it gets
// compiled out if we aren't using PStats.
////////////////////////////////////////////////////////////////////
void GraphicsStateGuardian::
add_to_total_buffer_record(VertexBufferContext *vbc) {
if (vbc != (VertexBufferContext *)NULL) {
int delta = vbc->get_data()->get_data_size_bytes() - vbc->get_data_size_bytes();
_total_buffers_pcollector.add_level(delta);
}
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsStateGuardian::add_to_total_buffer_record
// Access: Protected
// Description: Records that the indicated data array has been loaded
// this frame. This function is only used to update the
// PStats total_buffers collector; it gets
// compiled out if we aren't using PStats.
////////////////////////////////////////////////////////////////////
void GraphicsStateGuardian::
add_to_total_buffer_record(IndexBufferContext *ibc) {
if (ibc != (IndexBufferContext *)NULL) {
int delta = ibc->get_data()->get_data_size_bytes() - ibc->get_data_size_bytes();
_total_buffers_pcollector.add_level(delta);
}
}
#endif // DO_PSTATS
////////////////////////////////////////////////////////////////////

View File

@ -240,6 +240,8 @@ protected:
void add_to_geom_record(GeomContext *gc);
void add_to_vertex_buffer_record(VertexBufferContext *vbc);
void add_to_index_buffer_record(IndexBufferContext *ibc);
void add_to_total_buffer_record(VertexBufferContext *vbc);
void add_to_total_buffer_record(IndexBufferContext *ibc);
pset<TextureContext *> _current_textures;
pset<GeomContext *> _current_geoms;
@ -251,7 +253,9 @@ protected:
INLINE void add_to_geom_record(GeomContext *) { }
INLINE void record_state_change(TypeHandle) { }
INLINE void add_to_vertex_buffer_record(VertexBufferContext *) { }
INLINE void add_to_index_buffer_record(IndexBufferContext *i) { }
INLINE void add_to_index_buffer_record(IndexBufferContext *) { }
INLINE void add_to_total_buffer_record(VertexBufferContext *) { };
INLINE void add_to_total_buffer_record(IndexBufferContext *) { };
#endif
static CPT(RenderState) get_unlit_state();
@ -334,9 +338,12 @@ public:
static PStatCollector _active_texusage_pcollector;
static PStatCollector _texture_count_pcollector;
static PStatCollector _active_texture_count_pcollector;
static PStatCollector _total_buffer_count_pcollector;
static PStatCollector _active_vertex_buffer_count_pcollector;
static PStatCollector _active_index_buffer_count_pcollector;
static PStatCollector _vertex_buffer_switch_pcollector;
static PStatCollector _index_buffer_switch_pcollector;
static PStatCollector _load_vertex_buffer_pcollector;
static PStatCollector _load_index_buffer_pcollector;
static PStatCollector _load_texture_pcollector;
static PStatCollector _data_transferred_pcollector;
static PStatCollector _total_geom_pcollector;
static PStatCollector _active_geom_pcollector;
static PStatCollector _total_buffers_pcollector;
@ -348,6 +355,11 @@ public:
static PStatCollector _used_texmem_pcollector;
static PStatCollector _texmgrmem_total_pcollector;
static PStatCollector _texmgrmem_resident_pcollector;
static PStatCollector _primitive_batches_pcollector;
static PStatCollector _primitive_batches_tristrip_pcollector;
static PStatCollector _primitive_batches_trifan_pcollector;
static PStatCollector _primitive_batches_tri_pcollector;
static PStatCollector _primitive_batches_other_pcollector;
static PStatCollector _vertices_tristrip_pcollector;
static PStatCollector _vertices_trifan_pcollector;
static PStatCollector _vertices_tri_pcollector;

View File

@ -2738,6 +2738,7 @@ begin_draw_primitives(const qpGeom *geom, const qpGeomMunger *munger,
void DXGraphicsStateGuardian8::
draw_triangles(const qpGeomTriangles *primitive) {
_vertices_tri_pcollector.add_level(primitive->get_num_vertices());
_primitive_batches_tri_pcollector.add_level(1);
if (_vbuffer_active) {
IndexBufferContext *ibc = ((qpGeomPrimitive *)primitive)->prepare_now(get_prepared_objects(), this);
nassertv(ibc != (IndexBufferContext *)NULL);
@ -2779,6 +2780,7 @@ draw_tristrips(const qpGeomTristrips *primitive) {
// One long triangle strip, connected by the degenerate vertices
// that have already been set up within the primitive.
_vertices_tristrip_pcollector.add_level(primitive->get_num_vertices());
_primitive_batches_tristrip_pcollector.add_level(1);
if (_vbuffer_active) {
IndexBufferContext *ibc = ((qpGeomPrimitive *)primitive)->prepare_now(get_prepared_objects(), this);
nassertv(ibc != (IndexBufferContext *)NULL);
@ -2804,6 +2806,7 @@ draw_tristrips(const qpGeomTristrips *primitive) {
// degenerate vertices.
CPTA_int ends = primitive->get_ends();
int index_stride = primitive->get_index_stride();
_primitive_batches_tristrip_pcollector.add_level(ends.size());
qpGeomVertexReader mins(primitive->get_mins(), 0);
qpGeomVertexReader maxs(primitive->get_maxs(), 0);
@ -2866,6 +2869,7 @@ draw_trifans(const qpGeomTrifans *primitive) {
// with degenerate vertices, so no worries about that.
CPTA_int ends = primitive->get_ends();
int index_stride = primitive->get_index_stride();
_primitive_batches_trifan_pcollector.add_level(ends.size());
qpGeomVertexReader mins(primitive->get_mins(), 0);
qpGeomVertexReader maxs(primitive->get_maxs(), 0);
@ -2920,6 +2924,7 @@ draw_trifans(const qpGeomTrifans *primitive) {
void DXGraphicsStateGuardian8::
draw_lines(const qpGeomLines *primitive) {
_vertices_other_pcollector.add_level(primitive->get_num_vertices());
_primitive_batches_other_pcollector.add_level(1);
if (_vbuffer_active) {
IndexBufferContext *ibc = ((qpGeomPrimitive *)primitive)->prepare_now(get_prepared_objects(), this);
nassertv(ibc != (IndexBufferContext *)NULL);
@ -3193,9 +3198,8 @@ VertexBufferContext *DXGraphicsStateGuardian8::
prepare_vertex_buffer(qpGeomVertexArrayData *data) {
DXVertexBufferContext8 *dvbc = new DXVertexBufferContext8(data);
if (vertex_buffers) {
if (vertex_buffers && data->get_usage_hint() != qpGeom::UH_client) {
dvbc->create_vbuffer(*_pScrn);
dvbc->mark_loaded();
if (dxgsg8_cat.is_debug()) {
dxgsg8_cat.debug()
@ -3232,6 +3236,7 @@ apply_vertex_buffer(VertexBufferContext *vbc) {
dvbc->upload_data();
}
add_to_total_buffer_record(dvbc);
dvbc->mark_loaded();
}
@ -3278,7 +3283,6 @@ prepare_index_buffer(qpGeomPrimitive *data) {
DXIndexBufferContext8 *dibc = new DXIndexBufferContext8(data);
dibc->create_ibuffer(*_pScrn);
dibc->mark_loaded();
if (dxgsg8_cat.is_debug()) {
dxgsg8_cat.debug()
@ -3315,6 +3319,7 @@ apply_index_buffer(IndexBufferContext *ibc) {
dibc->upload_data();
}
add_to_total_buffer_record(dibc);
dibc->mark_loaded();
}

View File

@ -19,6 +19,8 @@
#include "dxIndexBufferContext8.h"
#include "qpgeomPrimitive.h"
#include "config_dxgsg8.h"
#include "graphicsStateGuardian.h"
#include "pStatTimer.h"
#include <d3dx8.h>
TypeHandle DXIndexBufferContext8::_type_handle;
@ -90,6 +92,7 @@ create_ibuffer(DXScreenData &scrn) {
void DXIndexBufferContext8::
upload_data() {
nassertv(_ibuffer != NULL);
PStatTimer timer(GraphicsStateGuardian::_load_index_buffer_pcollector);
int data_size = get_data()->get_data_size_bytes();
@ -107,6 +110,7 @@ upload_data() {
return;
}
GraphicsStateGuardian::_data_transferred_pcollector.add_level(data_size);
memcpy(local_pointer, get_data()->get_data(), data_size);
_ibuffer->Unlock();

View File

@ -21,7 +21,7 @@
#include "dxTextureContext8.h"
#include "config_dxgsg8.h"
#include "dxGraphicsStateGuardian8.h"
//#include "pnmImage.h"
#include "pStatTimer.h"
#include <d3dx8tex.h>
//#define FORCE_16bpp_1555
@ -559,22 +559,6 @@ IDirect3DTexture8 *DXTextureContext8::CreateTexture(DXScreenData &scrn) {
dxgsg8_cat.debug() << "Scaling "<< _tex->get_name() << " ("<< dwOrigWidth<<"," <<dwOrigHeight << ") => ("<< TargetWidth<<"," << TargetHeight << ") to meet HW square texture reqmt\n";
#endif
}
/*
// we now use D3DXLoadSurfFromMem to do resizing as well as fmt conversion
if(bShrinkOriginal) {
// need 2 add checks for errors
PNMImage pnmi_src;
PNMImage *pnmi = new PNMImage(TargetWidth, TargetHeight, cNumColorChannels);
_texture->store(pnmi_src);
pnmi->quick_filter_from(pnmi_src,0,0);
_texture->load(*pnmi); // violates device independence of pixbufs
dwOrigWidth = (DWORD)_texture->get_x_size();
dwOrigHeight = (DWORD)_texture->get_y_size();
delete pnmi;
}
*/
char *szErrorMsg;
@ -931,128 +915,133 @@ IDirect3DTexture8 *DXTextureContext8::CreateTexture(DXScreenData &scrn) {
HRESULT DXTextureContext8::
FillDDSurfTexturePixels(void) {
HRESULT hr=E_FAIL;
assert(IS_VALID_PTR(_texture));
HRESULT hr=E_FAIL;
assert(IS_VALID_PTR(_texture));
CPTA_uchar image = _texture->get_ram_image();
if (image.is_null()) {
// The texture doesn't have an image to load. That's ok; it
// might be a texture we've rendered to by frame buffer
// operations or something.
return S_OK;
CPTA_uchar image = _texture->get_ram_image();
if (image.is_null()) {
// The texture doesn't have an image to load. That's ok; it
// might be a texture we've rendered to by frame buffer
// operations or something.
return S_OK;
}
PStatTimer timer(GraphicsStateGuardian::_load_texture_pcollector);
assert(IS_VALID_PTR(_pD3DTexture8));
DWORD OrigWidth = (DWORD) _texture->get_x_size();
DWORD OrigHeight = (DWORD) _texture->get_y_size();
DWORD cNumColorChannels = _texture->get_num_components();
D3DFORMAT SrcFormat=_PixBufD3DFmt;
BYTE *pPixels=(BYTE*)image.p();
int component_width = _texture->get_component_width();
assert(IS_VALID_PTR(pPixels));
IDirect3DSurface8 *pMipLevel0;
hr=_pD3DTexture8->GetSurfaceLevel(0,&pMipLevel0);
if(FAILED(hr)) {
dxgsg8_cat.error() << "FillDDSurfaceTexturePixels failed for "<< _tex->get_name() <<", GetSurfaceLevel failed" << D3DERRORSTRING(hr);
return E_FAIL;
}
RECT SrcSize;
SrcSize.left = SrcSize.top = 0;
SrcSize.right = OrigWidth;
SrcSize.bottom = OrigHeight;
UINT SrcPixBufRowByteLength=OrigWidth*cNumColorChannels;
DWORD Lev0Filter,MipFilterFlags;
bool bUsingTempPixBuf=false;
// need filtering if size changes, (also if bitdepth reduced (need dithering)??)
Lev0Filter = D3DX_FILTER_LINEAR ; //| D3DX_FILTER_DITHER; //dithering looks ugly on i810 for 4444 textures
// D3DXLoadSurfaceFromMemory will load black luminance and we want full white,
// so convert to explicit luminance-alpha format
if (_PixBufD3DFmt==D3DFMT_A8) {
// alloc buffer for explicit D3DFMT_A8L8
USHORT *pTempPixBuf=new USHORT[OrigWidth*OrigHeight];
if(!IS_VALID_PTR(pTempPixBuf)) {
dxgsg8_cat.error() << "FillDDSurfaceTexturePixels couldnt alloc mem for temp pixbuf!\n";
goto exit_FillDDSurf;
}
assert(IS_VALID_PTR(_pD3DTexture8));
DWORD OrigWidth = (DWORD) _texture->get_x_size();
DWORD OrigHeight = (DWORD) _texture->get_y_size();
DWORD cNumColorChannels = _texture->get_num_components();
D3DFORMAT SrcFormat=_PixBufD3DFmt;
BYTE *pPixels=(BYTE*)image.p();
int component_width = _texture->get_component_width();
assert(IS_VALID_PTR(pPixels));
IDirect3DSurface8 *pMipLevel0;
hr=_pD3DTexture8->GetSurfaceLevel(0,&pMipLevel0);
if(FAILED(hr)) {
dxgsg8_cat.error() << "FillDDSurfaceTexturePixels failed for "<< _tex->get_name() <<", GetSurfaceLevel failed" << D3DERRORSTRING(hr);
return E_FAIL;
bUsingTempPixBuf=true;
USHORT *pOutPix=pTempPixBuf;
BYTE *pSrcPix=pPixels + component_width - 1;
for (UINT y = 0; y < OrigHeight; y++) {
for (UINT x = 0;
x < OrigWidth;
x++, pSrcPix += component_width, pOutPix++) {
// add full white, which is our interpretation of alpha-only
// (similar to default adding full opaque alpha 0xFF to
// RGB-only textures)
*pOutPix = ((*pSrcPix) << 8 ) | 0xFF;
}
}
RECT SrcSize;
SrcSize.left = SrcSize.top = 0;
SrcSize.right = OrigWidth;
SrcSize.bottom = OrigHeight;
UINT SrcPixBufRowByteLength=OrigWidth*cNumColorChannels;
DWORD Lev0Filter,MipFilterFlags;
bool bUsingTempPixBuf=false;
// need filtering if size changes, (also if bitdepth reduced (need dithering)??)
Lev0Filter = D3DX_FILTER_LINEAR ; //| D3DX_FILTER_DITHER; //dithering looks ugly on i810 for 4444 textures
// D3DXLoadSurfaceFromMemory will load black luminance and we want full white,
// so convert to explicit luminance-alpha format
if (_PixBufD3DFmt==D3DFMT_A8) {
// alloc buffer for explicit D3DFMT_A8L8
USHORT *pTempPixBuf=new USHORT[OrigWidth*OrigHeight];
if(!IS_VALID_PTR(pTempPixBuf)) {
dxgsg8_cat.error() << "FillDDSurfaceTexturePixels couldnt alloc mem for temp pixbuf!\n";
goto exit_FillDDSurf;
}
bUsingTempPixBuf=true;
USHORT *pOutPix=pTempPixBuf;
BYTE *pSrcPix=pPixels + component_width - 1;
for (UINT y = 0; y < OrigHeight; y++) {
for (UINT x = 0;
x < OrigWidth;
x++, pSrcPix += component_width, pOutPix++) {
// add full white, which is our interpretation of alpha-only
// (similar to default adding full opaque alpha 0xFF to
// RGB-only textures)
*pOutPix = ((*pSrcPix) << 8 ) | 0xFF;
}
}
SrcFormat=D3DFMT_A8L8;
SrcPixBufRowByteLength=OrigWidth*sizeof(USHORT);
pPixels=(BYTE*)pTempPixBuf;
} else if (component_width != 1) {
// Convert from 16-bit per channel (or larger) format down to
// 8-bit per channel. This throws away precision in the
// original image, but dx8 doesn't support high-precision images
// anyway.
int num_components = _texture->get_num_components();
int num_pixels = OrigWidth * OrigHeight * num_components;
BYTE *pTempPixBuf = new BYTE[num_pixels];
if(!IS_VALID_PTR(pTempPixBuf)) {
dxgsg8_cat.error() << "FillDDSurfaceTexturePixels couldnt alloc mem for temp pixbuf!\n";
goto exit_FillDDSurf;
}
bUsingTempPixBuf=true;
BYTE *pSrcPix = pPixels + component_width - 1;
for (int i = 0; i < num_pixels; i++) {
pTempPixBuf[i] = *pSrcPix;
pSrcPix += component_width;
}
pPixels=(BYTE*)pTempPixBuf;
SrcFormat=D3DFMT_A8L8;
SrcPixBufRowByteLength=OrigWidth*sizeof(USHORT);
pPixels=(BYTE*)pTempPixBuf;
} else if (component_width != 1) {
// Convert from 16-bit per channel (or larger) format down to
// 8-bit per channel. This throws away precision in the
// original image, but dx8 doesn't support high-precision images
// anyway.
int num_components = _texture->get_num_components();
int num_pixels = OrigWidth * OrigHeight * num_components;
BYTE *pTempPixBuf = new BYTE[num_pixels];
if(!IS_VALID_PTR(pTempPixBuf)) {
dxgsg8_cat.error() << "FillDDSurfaceTexturePixels couldnt alloc mem for temp pixbuf!\n";
goto exit_FillDDSurf;
}
// filtering may be done here if texture if targetsize!=origsize
hr=D3DXLoadSurfaceFromMemory(pMipLevel0,(PALETTEENTRY*)NULL,(RECT*)NULL,(LPCVOID)pPixels,SrcFormat,
SrcPixBufRowByteLength,(PALETTEENTRY*)NULL,&SrcSize,Lev0Filter,(D3DCOLOR)0x0);
if(FAILED(hr)) {
dxgsg8_cat.error() << "FillDDSurfaceTexturePixels failed for "<< _tex->get_name() <<", D3DXLoadSurfFromMem failed" << D3DERRORSTRING(hr);
goto exit_FillDDSurf;
bUsingTempPixBuf=true;
BYTE *pSrcPix = pPixels + component_width - 1;
for (int i = 0; i < num_pixels; i++) {
pTempPixBuf[i] = *pSrcPix;
pSrcPix += component_width;
}
if(_bHasMipMaps) {
if(!dx_use_triangle_mipgen_filter)
MipFilterFlags = D3DX_FILTER_BOX;
else MipFilterFlags = D3DX_FILTER_TRIANGLE;
pPixels=(BYTE*)pTempPixBuf;
}
// filtering may be done here if texture if targetsize!=origsize
#ifdef DO_PSTATS
GraphicsStateGuardian::_data_transferred_pcollector.add_level(SrcPixBufRowByteLength * OrigHeight);
#endif
hr=D3DXLoadSurfaceFromMemory(pMipLevel0,(PALETTEENTRY*)NULL,(RECT*)NULL,(LPCVOID)pPixels,SrcFormat,
SrcPixBufRowByteLength,(PALETTEENTRY*)NULL,&SrcSize,Lev0Filter,(D3DCOLOR)0x0);
if(FAILED(hr)) {
dxgsg8_cat.error() << "FillDDSurfaceTexturePixels failed for "<< _tex->get_name() <<", D3DXLoadSurfFromMem failed" << D3DERRORSTRING(hr);
goto exit_FillDDSurf;
}
if(_bHasMipMaps) {
if(!dx_use_triangle_mipgen_filter)
MipFilterFlags = D3DX_FILTER_BOX;
else MipFilterFlags = D3DX_FILTER_TRIANGLE;
// MipFilterFlags|= D3DX_FILTER_DITHER;
hr=D3DXFilterTexture(_pD3DTexture8,(PALETTEENTRY*)NULL,0,MipFilterFlags);
if(FAILED(hr)) {
dxgsg8_cat.error() << "FillDDSurfaceTexturePixels failed for "<< _tex->get_name() <<", D3DXFilterTex failed" << D3DERRORSTRING(hr);
goto exit_FillDDSurf;
}
hr=D3DXFilterTexture(_pD3DTexture8,(PALETTEENTRY*)NULL,0,MipFilterFlags);
if(FAILED(hr)) {
dxgsg8_cat.error() << "FillDDSurfaceTexturePixels failed for "<< _tex->get_name() <<", D3DXFilterTex failed" << D3DERRORSTRING(hr);
goto exit_FillDDSurf;
}
}
exit_FillDDSurf:
if(bUsingTempPixBuf) {
SAFE_DELETE_ARRAY(pPixels);
}
RELEASE(pMipLevel0,dxgsg8,"FillDDSurf MipLev0 texture ptr",RELEASE_ONCE);
return hr;
if(bUsingTempPixBuf) {
SAFE_DELETE_ARRAY(pPixels);
}
RELEASE(pMipLevel0,dxgsg8,"FillDDSurf MipLev0 texture ptr",RELEASE_ONCE);
return hr;
}
//-----------------------------------------------------------------------------

View File

@ -19,6 +19,8 @@
#include "dxVertexBufferContext8.h"
#include "qpgeomVertexArrayData.h"
#include "qpgeomVertexArrayFormat.h"
#include "graphicsStateGuardian.h"
#include "pStatTimer.h"
#include "internalName.h"
#include "config_dxgsg8.h"
#include <d3dx8.h>
@ -182,6 +184,7 @@ create_vbuffer(DXScreenData &scrn) {
void DXVertexBufferContext8::
upload_data() {
nassertv(_vbuffer != NULL);
PStatTimer timer(GraphicsStateGuardian::_load_vertex_buffer_pcollector);
int data_size = get_data()->get_data_size_bytes();
@ -199,6 +202,7 @@ upload_data() {
return;
}
GraphicsStateGuardian::_data_transferred_pcollector.add_level(data_size);
memcpy(local_pointer, get_data()->get_data(), data_size);
_vbuffer->Unlock();

View File

@ -75,9 +75,9 @@
TypeHandle CLP(GraphicsStateGuardian)::_type_handle;
#ifdef DO_PSTATS
PStatCollector CLP(GraphicsStateGuardian)::_load_display_list_pcollector("Draw:Transfer data:Display lists");
PStatCollector CLP(GraphicsStateGuardian)::_primitive_batches_display_list_pcollector("Primitive batches:Display lists");
PStatCollector CLP(GraphicsStateGuardian)::_vertices_display_list_pcollector("Vertices:Display lists");
#endif
static void
issue_vertex_gl(const Geom *geom, Geom::VertexIterator &viterator,
@ -1054,6 +1054,7 @@ begin_frame() {
#ifdef DO_PSTATS
_vertices_display_list_pcollector.clear_level();
_primitive_batches_display_list_pcollector.clear_level();
#endif
_actual_display_region = NULL;
@ -2316,6 +2317,7 @@ begin_draw_primitives(const qpGeom *geom, const qpGeomMunger *munger,
GLP(CallList)(_geom_display_list);
#ifdef DO_PSTATS
_vertices_display_list_pcollector.add_level(ggc->_num_verts);
_primitive_batches_display_list_pcollector.add_level(1);
#endif
// And now we don't need to do anything else for this geom.
@ -2323,7 +2325,11 @@ begin_draw_primitives(const qpGeom *geom, const qpGeomMunger *munger,
end_draw_primitives();
return false;
}
// Since we start this collector explicitly, we have to be sure to
// stop it again.
_load_display_list_pcollector.start();
if (GLCAT.is_debug()) {
GLCAT.debug()
<< "compiling display list " << _geom_display_list << "\n";
@ -2335,7 +2341,7 @@ begin_draw_primitives(const qpGeom *geom, const qpGeomMunger *munger,
GLP(NewList)(_geom_display_list, GL_COMPILE_AND_EXECUTE);
} else {
GLP(NewList)(_geom_display_list, GL_COMPILE);
}
}
#ifdef DO_PSTATS
// Count up the number of vertices used by primitives in the Geom,
@ -2480,6 +2486,7 @@ begin_draw_primitives(const qpGeom *geom, const qpGeomMunger *munger,
void CLP(GraphicsStateGuardian)::
draw_triangles(const qpGeomTriangles *primitive) {
_vertices_tri_pcollector.add_level(primitive->get_num_vertices());
_primitive_batches_tri_pcollector.add_level(1);
const unsigned char *client_pointer = setup_primitive(primitive);
_glDrawRangeElements(GL_TRIANGLES,
@ -2505,6 +2512,7 @@ draw_tristrips(const qpGeomTristrips *primitive) {
// One long triangle strip, connected by the degenerate vertices
// that have already been set up within the primitive.
_vertices_tristrip_pcollector.add_level(primitive->get_num_vertices());
_primitive_batches_tristrip_pcollector.add_level(1);
_glDrawRangeElements(GL_TRIANGLE_STRIP,
primitive->get_min_vertex(),
primitive->get_max_vertex(),
@ -2523,6 +2531,7 @@ draw_tristrips(const qpGeomTristrips *primitive) {
nassertv(primitive->get_mins()->get_num_rows() == (int)ends.size() &&
primitive->get_maxs()->get_num_rows() == (int)ends.size());
_primitive_batches_tristrip_pcollector.add_level(ends.size());
unsigned int start = 0;
for (size_t i = 0; i < ends.size(); i++) {
_vertices_tristrip_pcollector.add_level(ends[i] - start);
@ -2557,6 +2566,7 @@ draw_trifans(const qpGeomTrifans *primitive) {
nassertv(primitive->get_mins()->get_num_rows() == (int)ends.size() &&
primitive->get_maxs()->get_num_rows() == (int)ends.size());
_primitive_batches_trifan_pcollector.add_level(ends.size());
unsigned int start = 0;
for (size_t i = 0; i < ends.size(); i++) {
_vertices_trifan_pcollector.add_level(ends[i] - start);
@ -2578,6 +2588,7 @@ draw_trifans(const qpGeomTrifans *primitive) {
void CLP(GraphicsStateGuardian)::
draw_lines(const qpGeomLines *primitive) {
_vertices_other_pcollector.add_level(primitive->get_num_vertices());
_primitive_batches_other_pcollector.add_level(1);
const unsigned char *client_pointer = setup_primitive(primitive);
_glDrawRangeElements(GL_LINES,
@ -2607,6 +2618,7 @@ draw_linestrips(const qpGeomLinestrips *primitive) {
void CLP(GraphicsStateGuardian)::
draw_points(const qpGeomPoints *primitive) {
_vertices_other_pcollector.add_level(primitive->get_num_vertices());
_primitive_batches_other_pcollector.add_level(1);
const unsigned char *client_pointer = setup_primitive(primitive);
_glDrawRangeElements(GL_POINTS,
@ -2631,9 +2643,12 @@ end_draw_primitives() {
if (_geom_display_list != 0) {
// If we were building a display list, close it now.
GLP(EndList)();
_load_display_list_pcollector.stop();
if (!CLP(compile_and_execute)) {
GLP(CallList)(_geom_display_list);
}
_primitive_batches_display_list_pcollector.add_level(1);
}
_geom_display_list = 0;
@ -2908,21 +2923,24 @@ apply_vertex_buffer(VertexBufferContext *vbc) {
add_to_vertex_buffer_record(gvbc);
if (gvbc->was_modified()) {
PStatTimer timer(_load_vertex_buffer_pcollector);
int num_bytes = gvbc->get_data()->get_data_size_bytes();
if (GLCAT.is_spam()) {
GLCAT.spam()
<< "copying " << gvbc->get_data()->get_data_size_bytes()
<< "copying " << num_bytes
<< " bytes into vertex buffer " << gvbc->_index << "\n";
}
if (gvbc->changed_size() || gvbc->changed_usage_hint()) {
_glBufferData(GL_ARRAY_BUFFER, gvbc->get_data()->get_data_size_bytes(),
_glBufferData(GL_ARRAY_BUFFER, num_bytes,
gvbc->get_data()->get_data(),
get_usage(gvbc->get_data()->get_usage_hint()));
} else {
_glBufferSubData(GL_ARRAY_BUFFER, 0, gvbc->get_data_size_bytes(),
_glBufferSubData(GL_ARRAY_BUFFER, 0, num_bytes,
gvbc->get_data()->get_data());
}
_data_transferred_pcollector.add_level(num_bytes);
add_to_total_buffer_record(gvbc);
gvbc->mark_loaded();
}
@ -3042,21 +3060,24 @@ apply_index_buffer(IndexBufferContext *ibc) {
add_to_index_buffer_record(gibc);
if (gibc->was_modified()) {
PStatTimer timer(_load_index_buffer_pcollector);
int num_bytes = gibc->get_data()->get_data_size_bytes();
if (GLCAT.is_spam()) {
GLCAT.spam()
<< "copying " << gibc->get_data()->get_data_size_bytes()
<< "copying " << num_bytes
<< " bytes into index buffer " << gibc->_index << "\n";
}
if (gibc->changed_size() || gibc->changed_usage_hint()) {
_glBufferData(GL_ELEMENT_ARRAY_BUFFER, gibc->get_data()->get_data_size_bytes(),
_glBufferData(GL_ELEMENT_ARRAY_BUFFER, num_bytes,
gibc->get_data()->get_data(),
get_usage(gibc->get_data()->get_usage_hint()));
} else {
_glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, gibc->get_data_size_bytes(),
_glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, num_bytes,
gibc->get_data()->get_data());
}
_data_transferred_pcollector.add_level(num_bytes);
add_to_total_buffer_record(gibc);
gibc->mark_loaded();
}
@ -4646,6 +4667,7 @@ upload_texture_image(CLP(TextureContext) *gtc,
// Unsupported target (e.g. 3-d texturing on GL 1.1).
return false;
}
PStatTimer timer(_load_texture_pcollector);
if (uses_mipmaps) {
#ifndef NDEBUG
@ -4660,6 +4682,9 @@ upload_texture_image(CLP(TextureContext) *gtc,
// We only need to build the mipmaps by hand if the GL
// doesn't support generating them automatically.
bool success = true;
#ifdef DO_PSTATS
_data_transferred_pcollector.add_level(get_external_texture_bytes(width, height, depth, external_format, component_type) * 4 / 3);
#endif
switch (target) {
case GL_TEXTURE_1D:
GLUP(Build1DMipmaps)(target, internal_format, width,
@ -4698,6 +4723,9 @@ upload_texture_image(CLP(TextureContext) *gtc,
gtc->_height != height ||
gtc->_depth != depth) {
// We need to reload a new image.
#ifdef DO_PSTATS
_data_transferred_pcollector.add_level(get_external_texture_bytes(width, height, depth, external_format, component_type));
#endif
switch (target) {
case GL_TEXTURE_1D:
GLP(TexImage1D)(target, 0, internal_format,
@ -5033,6 +5061,75 @@ get_internal_image_format(Texture::Format format) {
}
}
////////////////////////////////////////////////////////////////////
// Function: GLGraphicsStateGuardian::get_external_texture_bytes
// Access: Protected, Static
// Description: Computes the number of bytes that should be in the
// "external", or local, texture buffer before
// transferring to OpenGL. This is just used for
// sending data to PStats.
////////////////////////////////////////////////////////////////////
int CLP(GraphicsStateGuardian)::
get_external_texture_bytes(int width, int height, int depth,
GLint external_format, GLenum component_type) {
int num_components;
switch (external_format) {
case GL_COLOR_INDEX:
case GL_STENCIL_INDEX:
case GL_DEPTH_COMPONENT:
case GL_RED:
case GL_GREEN:
case GL_BLUE:
case GL_ALPHA:
case GL_LUMINANCE:
num_components = 1;
break;
case GL_LUMINANCE_ALPHA:
num_components = 2;
break;
case GL_BGR:
case GL_RGB:
num_components = 3;
break;
case GL_BGRA:
case GL_RGBA:
num_components = 4;
break;
default:
GLCAT.error()
<< "Unexpected external_format in get_external_texture_bytes(): "
<< hex << external_format << dec << "\n";
num_components = 3;
}
int component_width;
switch (component_type) {
case GL_UNSIGNED_BYTE:
component_width = 1;
break;
case GL_UNSIGNED_SHORT:
component_width = 2;
break;
case GL_FLOAT:
component_width = 4;
break;
default:
GLCAT.error()
<< "Unexpected component_type in get_external_texture_bytes(): "
<< hex << component_type << dec << "\n";
component_width = 1;
}
return width * height * depth * num_components * component_width;
}
////////////////////////////////////////////////////////////////////
// Function: GLGraphicsStateGuardian::get_texture_apply_mode_type
// Access: Protected, Static
@ -6322,11 +6419,17 @@ build_phony_mipmap_level(int level, int x_size, int y_size) {
} else {
GLenum internal_format = get_internal_image_format(tex->get_format());
GLenum external_format = get_external_image_format(tex->get_format());
GLenum type = get_component_type(tex->get_component_type());
GLenum component_type = get_component_type(tex->get_component_type());
#ifdef DO_PSTATS
int num_bytes =
get_external_texture_bytes(tex->get_x_size(), tex->get_y_size(), 1,
external_format, component_type);
_data_transferred_pcollector.add_level(num_bytes);
#endif
GLP(TexImage2D)(GL_TEXTURE_2D, level, internal_format,
tex->get_x_size(), tex->get_y_size(), 0,
external_format, type, tex->get_ram_image());
external_format, component_type, tex->get_ram_image());
}
}

View File

@ -251,6 +251,9 @@ protected:
static GLenum get_component_type(Texture::ComponentType component_type);
GLint get_external_image_format(Texture::Format format) const;
static GLint get_internal_image_format(Texture::Format format);
static int get_external_texture_bytes(int width, int height, int depth,
GLint external_format,
GLenum component_type);
static GLint get_texture_apply_mode_type(TextureStage::Mode am);
static GLint get_texture_combine_type(TextureStage::CombineMode cm);
static GLint get_texture_src_type(TextureStage::CombineSource cs);
@ -392,6 +395,8 @@ public:
typedef pvector<GLuint> DeletedDisplayLists;
DeletedDisplayLists _deleted_display_lists;
static PStatCollector _load_display_list_pcollector;
static PStatCollector _primitive_batches_display_list_pcollector;
static PStatCollector _vertices_display_list_pcollector;
public:

View File

@ -28,7 +28,6 @@
PStatCollector PreparedGraphicsObjects::_total_texusage_pcollector("Texture usage");
PStatCollector PreparedGraphicsObjects::_total_buffers_pcollector("Vertex buffer size");
PStatCollector PreparedGraphicsObjects::_total_buffer_count_pcollector("Vertex buffer count");
////////////////////////////////////////////////////////////////////
// Function: PreparedGraphicsObjects::Constructor
@ -83,7 +82,7 @@ PreparedGraphicsObjects::
vbci != _prepared_vertex_buffers.end();
++vbci) {
VertexBufferContext *vbc = (*vbci);
_total_texusage_pcollector.sub_level(vbc->get_data_size_bytes());
_total_buffers_pcollector.sub_level(vbc->get_data_size_bytes());
vbc->_data->clear_prepared(this);
}
@ -96,7 +95,7 @@ PreparedGraphicsObjects::
ibci != _prepared_index_buffers.end();
++ibci) {
IndexBufferContext *ibc = (*ibci);
_total_texusage_pcollector.sub_level(ibc->get_data_size_bytes());
_total_buffers_pcollector.sub_level(ibc->get_data_size_bytes());
ibc->_data->clear_prepared(this);
}
@ -450,7 +449,6 @@ release_vertex_buffer(VertexBufferContext *vbc) {
vbc->_data->clear_prepared(this);
_total_buffers_pcollector.sub_level(vbc->get_data_size_bytes());
_total_buffer_count_pcollector.sub_level(1);
// We have to set the Data pointer to NULL at this point, since
// the Data itself might destruct at any time after it has been
@ -484,7 +482,6 @@ release_all_vertex_buffers() {
VertexBufferContext *vbc = (*vbci);
vbc->_data->clear_prepared(this);
_total_buffers_pcollector.sub_level(vbc->get_data_size_bytes());
_total_buffer_count_pcollector.sub_level(1);
vbc->_data = (qpGeomVertexArrayData *)NULL;
_released_vertex_buffers.insert(vbc);
@ -535,7 +532,6 @@ prepare_vertex_buffer_now(qpGeomVertexArrayData *data, GraphicsStateGuardianBase
// GraphicsStateGuardian::add_to_vertex_buffer_record(); we don't need to
// count it again here.
//_total_buffers_pcollector.add_level(vbc->get_data_size_bytes());
_total_buffer_count_pcollector.add_level(1);
}
return vbc;
@ -600,7 +596,6 @@ release_index_buffer(IndexBufferContext *ibc) {
ibc->_data->clear_prepared(this);
_total_buffers_pcollector.sub_level(ibc->get_data_size_bytes());
_total_buffer_count_pcollector.sub_level(1);
// We have to set the Data pointer to NULL at this point, since
// the Data itself might destruct at any time after it has been
@ -634,7 +629,6 @@ release_all_index_buffers() {
IndexBufferContext *ibc = (*ibci);
ibc->_data->clear_prepared(this);
_total_buffers_pcollector.sub_level(ibc->get_data_size_bytes());
_total_buffer_count_pcollector.sub_level(1);
ibc->_data = (qpGeomPrimitive *)NULL;
_released_index_buffers.insert(ibc);
@ -685,7 +679,6 @@ prepare_index_buffer_now(qpGeomPrimitive *data, GraphicsStateGuardianBase *gsg)
// GraphicsStateGuardian::add_to_index_buffer_record(); we don't need to
// count it again here.
//_total_buffers_pcollector.add_level(ibc->get_data_size_bytes());
_total_buffer_count_pcollector.add_level(1);
}
return ibc;

View File

@ -116,7 +116,6 @@ private:
static PStatCollector _total_texusage_pcollector;
static PStatCollector _total_buffers_pcollector;
static PStatCollector _total_buffer_count_pcollector;
friend class GraphicsStateGuardian;
};

View File

@ -54,6 +54,8 @@ record() {
insert_before(cache_mgr->_list);
cache_mgr->_total_size += _result_size;
cache_mgr->_geom_cache_size_pcollector.set_level(cache_mgr->_total_size);
cache_mgr->_geom_cache_record_pcollector.add_level(1);
// Increment our own reference count while we're in the queue, just
// so we don't have to play games with it later--this is inner-loop
@ -91,6 +93,8 @@ erase() {
remove_from_list();
cache_mgr->_total_size -= _result_size;
cache_mgr->_geom_cache_size_pcollector.set_level(cache_mgr->_total_size);
cache_mgr->_geom_cache_erase_pcollector.add_level(1);
return this;
}

View File

@ -22,6 +22,11 @@
qpGeomCacheManager *qpGeomCacheManager::_global_ptr = NULL;
PStatCollector qpGeomCacheManager::_geom_cache_size_pcollector("Geom cache size");
PStatCollector qpGeomCacheManager::_geom_cache_record_pcollector("Geom cache operations:record");
PStatCollector qpGeomCacheManager::_geom_cache_erase_pcollector("Geom cache operations:erase");
PStatCollector qpGeomCacheManager::_geom_cache_evict_pcollector("Geom cache operations:evict");
////////////////////////////////////////////////////////////////////
// Function: qpGeomCacheManager::Constructor
// Access: Protected
@ -88,5 +93,7 @@ evict_old_entries() {
_total_size -= entry->_result_size;
entry->remove_from_list();
_geom_cache_evict_pcollector.add_level(1);
}
_geom_cache_size_pcollector.set_level(_total_size);
}

View File

@ -22,6 +22,7 @@
#include "pandabase.h"
#include "config_gobj.h"
#include "pmutex.h"
#include "pStatCollector.h"
class qpGeomCacheEntry;
@ -83,6 +84,13 @@ private:
qpGeomCacheEntry *_list;
static qpGeomCacheManager *_global_ptr;
public:
static PStatCollector _geom_cache_size_pcollector;
static PStatCollector _geom_cache_record_pcollector;
static PStatCollector _geom_cache_erase_pcollector;
static PStatCollector _geom_cache_evict_pcollector;
friend class qpGeomCacheEntry;
};

View File

@ -141,6 +141,11 @@ static TimeCollectorProperties time_properties[] = {
{ 1, "Draw:Flip:Begin", { 0.3, 0.3, 0.9 } },
{ 1, "Draw:Flip:End", { 0.9, 0.3, 0.6 } },
{ 1, "Draw:Bins", { 0.3, 0.6, 0.0 } },
{ 1, "Draw:Transfer data", { 0.8, 0.0, 0.6 } },
{ 1, "Draw:Transfer data:Vertex buffer", { 0.0, 0.1, 0.9 } },
{ 1, "Draw:Transfer data:Index buffer", { 0.1, 0.9, 0.0 } },
{ 1, "Draw:Transfer data:Texture", { 0.9, 0.0, 0.1 } },
{ 1, "Draw:Transfer data:Display lists", { 0.5, 0.0, 0.9 } },
{ 0, "Draw:Primitive", { 0.0, 0.0, 0.5 } },
{ 0, NULL }
};
@ -161,9 +166,21 @@ static LevelCollectorProperties level_properties[] = {
{ 1, "Vertex buffer size", { 0.0, 0.0, 1.0 }, "MB", 12, 1048576 },
{ 1, "Vertex buffer size:Active vertex", { 1.0, 0.0, 0.5 } },
{ 1, "Vertex buffer size:Active index" , { 0.5, 0.6, 1.0 } },
{ 1, "Vertex buffer count", { 0.0, 0.6, 0.8 }, "", 500 },
{ 1, "Vertex buffer count:Active vertex", { 0.8, 0.0, 0.6 } },
{ 1, "Vertex buffer count:Active index", { 0.8, 0.6, 0.3 } },
{ 1, "Vertex buffer switch", { 0.0, 0.6, 0.8 }, "", 500 },
{ 1, "Vertex buffer switch:Vertex", { 0.8, 0.0, 0.6 } },
{ 1, "Vertex buffer switch:Index", { 0.8, 0.6, 0.3 } },
{ 1, "Geom cache size", { 1.0, 0.8, 0.6 }, "MB", 12, 1048576 },
{ 1, "Geom cache operations", { 1.0, 0.8, 0.6 }, "", 500 },
{ 1, "Geom cache operations:record", { 0.2, 0.4, 0.8 } },
{ 1, "Geom cache operations:erase", { 0.4, 0.8, 0.2 } },
{ 1, "Geom cache operations:evict", { 0.8, 0.2, 0.4 } },
{ 1, "Data transferred", { 0.0, 0.2, 0.4 }, "MB", 12, 1048576 },
{ 1, "Primitive batches", { 0.2, 0.5, 0.9 }, "", 500 },
{ 1, "Primitive batches:Other", { 0.2, 0.2, 0.2 } },
{ 1, "Primitive batches:Triangles", { 0.8, 0.8, 0.8 } },
{ 1, "Primitive batches:Triangle fans", { 0.8, 0.5, 0.2 } },
{ 1, "Primitive batches:Triangle strips",{ 0.2, 0.5, 0.8 } },
{ 1, "Primitive batches:Display lists", { 0.8, 0.5, 1.0 } },
{ 1, "Vertices", { 0.5, 0.2, 0.0 }, "K", 10, 1000 },
{ 1, "Vertices:Other", { 0.2, 0.2, 0.2 } },
{ 1, "Vertices:Triangles", { 0.8, 0.8, 0.8 } },