Keep stats on hw buffer uploads

This commit is contained in:
sfan5 2024-08-27 12:09:08 +02:00
parent 39970fed38
commit fa4529b4f1
8 changed files with 53 additions and 88 deletions

@ -114,6 +114,15 @@ const c8 *const FogTypeNames[] = {
0, 0,
}; };
struct SFrameStats {
//! Count of primitives drawn
u32 PrimitivesDrawn = 0;
//! Number of hardware buffers uploaded (new or updated)
u32 HWBuffersUploaded = 0;
//! Sum of uploaded hardware buffer size
u32 HWBuffersUploadedSize = 0;
};
//! Interface to driver which is able to perform 2d and 3d graphics functions. //! Interface to driver which is able to perform 2d and 3d graphics functions.
/** This interface is one of the most important interfaces of /** This interface is one of the most important interfaces of
the Irrlicht Engine: All rendering and texture manipulation is done with the Irrlicht Engine: All rendering and texture manipulation is done with
@ -194,12 +203,6 @@ public:
*/ */
virtual const io::IAttributes &getDriverAttributes() const = 0; virtual const io::IAttributes &getDriverAttributes() const = 0;
//! Check if the driver was recently reset.
/** For d3d devices you will need to recreate the RTTs if the
driver was reset. Should be queried right after beginScene().
*/
virtual bool checkDriverReset() = 0;
//! Sets transformation matrices. //! Sets transformation matrices.
/** \param state Transformation type to be set, e.g. view, /** \param state Transformation type to be set, e.g. view,
world, or projection. world, or projection.
@ -855,12 +858,8 @@ public:
\return Approximate amount of frames per second drawn. */ \return Approximate amount of frames per second drawn. */
virtual s32 getFPS() const = 0; virtual s32 getFPS() const = 0;
//! Returns amount of primitives (mostly triangles) which were drawn in the last frame. //! Return some statistics about the last frame
/** Together with getFPS() very useful method for statistics. virtual SFrameStats getFrameStats() const = 0;
\param mode Defines if the primitives drawn are accumulated or
counted per frame.
\return Amount of primitives drawn in the last frame. */
virtual u32 getPrimitiveCountDrawn(u32 mode = 0) const = 0;
//! Gets name of this video driver. //! Gets name of this video driver.
/** \return Returns the name of the video driver, e.g. in case /** \return Returns the name of the video driver, e.g. in case

@ -11,53 +11,22 @@ namespace video
{ {
CFPSCounter::CFPSCounter() : CFPSCounter::CFPSCounter() :
FPS(60), Primitive(0), StartTime(0), FramesCounted(0), FPS(0), StartTime(0), FramesCounted(0)
PrimitivesCounted(0), PrimitiveAverage(0), PrimitiveTotal(0)
{ {
} }
//! returns current fps
s32 CFPSCounter::getFPS() const
{
return FPS;
}
//! returns current primitive count
u32 CFPSCounter::getPrimitive() const
{
return Primitive;
}
//! returns average primitive count of last period
u32 CFPSCounter::getPrimitiveAverage() const
{
return PrimitiveAverage;
}
//! returns accumulated primitive count since start
u32 CFPSCounter::getPrimitiveTotal() const
{
return PrimitiveTotal;
}
//! to be called every frame //! to be called every frame
void CFPSCounter::registerFrame(u32 now, u32 primitivesDrawn) void CFPSCounter::registerFrame(u32 now)
{ {
++FramesCounted; ++FramesCounted;
PrimitiveTotal += primitivesDrawn;
PrimitivesCounted += primitivesDrawn;
Primitive = primitivesDrawn;
const u32 milliseconds = now - StartTime; const u32 milliseconds = now - StartTime;
if (milliseconds >= 1500) { if (milliseconds >= 1500) {
const f32 invMilli = core::reciprocal((f32)milliseconds); const f32 invMilli = core::reciprocal((f32)milliseconds);
FPS = core::ceil32((1000 * FramesCounted) * invMilli); FPS = core::ceil32((1000 * FramesCounted) * invMilli);
PrimitiveAverage = core::ceil32((1000 * PrimitivesCounted) * invMilli);
FramesCounted = 0; FramesCounted = 0;
PrimitivesCounted = 0;
StartTime = now; StartTime = now;
} }
} }

@ -17,29 +17,15 @@ public:
CFPSCounter(); CFPSCounter();
//! returns current fps //! returns current fps
s32 getFPS() const; s32 getFPS() const { return FPS; }
//! returns primitive count
u32 getPrimitive() const;
//! returns average primitive count of last period
u32 getPrimitiveAverage() const;
//! returns accumulated primitive count since start
u32 getPrimitiveTotal() const;
//! to be called every frame //! to be called every frame
void registerFrame(u32 now, u32 primitive); void registerFrame(u32 now);
private: private:
s32 FPS; s32 FPS;
u32 Primitive;
u32 StartTime; u32 StartTime;
u32 FramesCounted; u32 FramesCounted;
u32 PrimitivesCounted;
u32 PrimitiveAverage;
u32 PrimitiveTotal;
}; };
} // end namespace video } // end namespace video

@ -53,7 +53,7 @@ public:
//! constructor //! constructor
CNullDriver::CNullDriver(io::IFileSystem *io, const core::dimension2d<u32> &screenSize) : CNullDriver::CNullDriver(io::IFileSystem *io, const core::dimension2d<u32> &screenSize) :
SharedRenderTarget(0), CurrentRenderTarget(0), CurrentRenderTargetSize(0, 0), FileSystem(io), MeshManipulator(0), SharedRenderTarget(0), CurrentRenderTarget(0), CurrentRenderTargetSize(0, 0), FileSystem(io), MeshManipulator(0),
ViewPort(0, 0, 0, 0), ScreenSize(screenSize), PrimitivesDrawn(0), MinVertexCountForVBO(500), ViewPort(0, 0, 0, 0), ScreenSize(screenSize), MinVertexCountForVBO(500),
TextureCreationFlags(0), OverrideMaterial2DEnabled(false), AllowZWriteOnTransparent(false) TextureCreationFlags(0), OverrideMaterial2DEnabled(false), AllowZWriteOnTransparent(false)
{ {
#ifdef _DEBUG #ifdef _DEBUG
@ -222,13 +222,13 @@ void CNullDriver::deleteAllTextures()
bool CNullDriver::beginScene(u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil, const SExposedVideoData &videoData, core::rect<s32> *sourceRect) bool CNullDriver::beginScene(u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil, const SExposedVideoData &videoData, core::rect<s32> *sourceRect)
{ {
PrimitivesDrawn = 0; FrameStats = {};
return true; return true;
} }
bool CNullDriver::endScene() bool CNullDriver::endScene()
{ {
FPSCounter.registerFrame(os::Timer::getRealTime(), PrimitivesDrawn); FPSCounter.registerFrame(os::Timer::getRealTime());
updateAllHardwareBuffers(); updateAllHardwareBuffers();
updateAllOcclusionQueries(); updateAllOcclusionQueries();
return true; return true;
@ -605,7 +605,7 @@ void CNullDriver::drawVertexPrimitiveList(const void *vertices, u32 vertexCount,
{ {
if ((iType == EIT_16BIT) && (vertexCount > 65536)) if ((iType == EIT_16BIT) && (vertexCount > 65536))
os::Printer::log("Too many vertices for 16bit index type, render artifacts may occur."); os::Printer::log("Too many vertices for 16bit index type, render artifacts may occur.");
PrimitivesDrawn += primitiveCount; FrameStats.PrimitivesDrawn += primitiveCount;
} }
//! draws a vertex primitive list in 2d //! draws a vertex primitive list in 2d
@ -613,7 +613,7 @@ void CNullDriver::draw2DVertexPrimitiveList(const void *vertices, u32 vertexCoun
{ {
if ((iType == EIT_16BIT) && (vertexCount > 65536)) if ((iType == EIT_16BIT) && (vertexCount > 65536))
os::Printer::log("Too many vertices for 16bit index type, render artifacts may occur."); os::Printer::log("Too many vertices for 16bit index type, render artifacts may occur.");
PrimitivesDrawn += primitiveCount; FrameStats.PrimitivesDrawn += primitiveCount;
} }
//! Draws a 3d line. //! Draws a 3d line.
@ -743,12 +743,9 @@ s32 CNullDriver::getFPS() const
return FPSCounter.getFPS(); return FPSCounter.getFPS();
} }
//! returns amount of primitives (mostly triangles) were drawn in the last frame. SFrameStats CNullDriver::getFrameStats() const
//! very useful method for statistics.
u32 CNullDriver::getPrimitiveCountDrawn(u32 param) const
{ {
return (0 == param) ? FPSCounter.getPrimitive() : (1 == param) ? FPSCounter.getPrimitiveAverage() return FrameStats;
: FPSCounter.getPrimitiveTotal();
} }
//! Sets the dynamic ambient light color. The default color is //! Sets the dynamic ambient light color. The default color is

@ -195,9 +195,7 @@ public:
// get current frames per second value // get current frames per second value
s32 getFPS() const override; s32 getFPS() const override;
//! returns amount of primitives (mostly triangles) were drawn in the last frame. SFrameStats getFrameStats() const override;
//! very useful method for statistics.
u32 getPrimitiveCountDrawn(u32 param = 0) const override;
//! \return Returns the name of the video driver. Example: In case of the DIRECT3D8 //! \return Returns the name of the video driver. Example: In case of the DIRECT3D8
//! driver, it would return "Direct3D8.1". //! driver, it would return "Direct3D8.1".
@ -538,8 +536,6 @@ public:
virtual void convertColor(const void *sP, ECOLOR_FORMAT sF, s32 sN, virtual void convertColor(const void *sP, ECOLOR_FORMAT sF, s32 sN,
void *dP, ECOLOR_FORMAT dF) const override; void *dP, ECOLOR_FORMAT dF) const override;
bool checkDriverReset() override { return false; }
protected: protected:
//! deletes all textures //! deletes all textures
void deleteAllTextures(); void deleteAllTextures();
@ -570,6 +566,12 @@ protected:
// prints renderer version // prints renderer version
void printVersion(); void printVersion();
inline void accountHWBufferUpload(u32 size)
{
FrameStats.HWBuffersUploaded++;
FrameStats.HWBuffersUploadedSize += size;
}
inline bool getWriteZBuffer(const SMaterial &material) const inline bool getWriteZBuffer(const SMaterial &material) const
{ {
switch (material.ZWriteEnable) { switch (material.ZWriteEnable) {
@ -696,8 +698,8 @@ protected:
core::matrix4 TransformationMatrix; core::matrix4 TransformationMatrix;
CFPSCounter FPSCounter; CFPSCounter FPSCounter;
SFrameStats FrameStats;
u32 PrimitivesDrawn;
u32 MinVertexCountForVBO; u32 MinVertexCountForVBO;
u32 TextureCreationFlags; u32 TextureCreationFlags;

@ -266,6 +266,8 @@ bool COpenGLDriver::updateVertexHardwareBuffer(SHWBufferLink_opengl *HWBuffer)
const E_VERTEX_TYPE vType = mb->getVertexType(); const E_VERTEX_TYPE vType = mb->getVertexType();
const u32 vertexSize = getVertexPitchFromType(vType); const u32 vertexSize = getVertexPitchFromType(vType);
accountHWBufferUpload(vertexSize * vertexCount);
const c8 *vbuf = static_cast<const c8 *>(vertices); const c8 *vbuf = static_cast<const c8 *>(vertices);
core::array<c8> buffer; core::array<c8> buffer;
if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra]) { if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra]) {
@ -367,6 +369,8 @@ bool COpenGLDriver::updateIndexHardwareBuffer(SHWBufferLink_opengl *HWBuffer)
} }
} }
accountHWBufferUpload(indexCount * indexSize);
// get or create buffer // get or create buffer
bool newBuffer = false; bool newBuffer = false;
if (!HWBuffer->vbo_indicesID) { if (!HWBuffer->vbo_indicesID) {

@ -255,10 +255,7 @@ bool COpenGL3DriverBase::genericDriverInit(const core::dimension2d<u32> &screenS
DriverAttributes->setAttribute("MaxTextures", (s32)Feature.MaxTextureUnits); DriverAttributes->setAttribute("MaxTextures", (s32)Feature.MaxTextureUnits);
DriverAttributes->setAttribute("MaxSupportedTextures", (s32)Feature.MaxTextureUnits); DriverAttributes->setAttribute("MaxSupportedTextures", (s32)Feature.MaxTextureUnits);
// DriverAttributes->setAttribute("MaxLights", MaxLights);
DriverAttributes->setAttribute("MaxAnisotropy", MaxAnisotropy); DriverAttributes->setAttribute("MaxAnisotropy", MaxAnisotropy);
// DriverAttributes->setAttribute("MaxAuxBuffers", MaxAuxBuffers);
// DriverAttributes->setAttribute("MaxMultipleRenderTargets", MaxMultipleRenderTargets);
DriverAttributes->setAttribute("MaxIndices", (s32)MaxIndices); DriverAttributes->setAttribute("MaxIndices", (s32)MaxIndices);
DriverAttributes->setAttribute("MaxTextureSize", (s32)MaxTextureSize); DriverAttributes->setAttribute("MaxTextureSize", (s32)MaxTextureSize);
DriverAttributes->setAttribute("MaxTextureLODBias", MaxTextureLODBias); DriverAttributes->setAttribute("MaxTextureLODBias", MaxTextureLODBias);
@ -493,6 +490,7 @@ bool COpenGL3DriverBase::updateVertexHardwareBuffer(SHWBufferLink_opengl *HWBuff
const void *buffer = vertices; const void *buffer = vertices;
size_t bufferSize = vertexSize * vertexCount; size_t bufferSize = vertexSize * vertexCount;
accountHWBufferUpload(bufferSize);
// get or create buffer // get or create buffer
bool newBuffer = false; bool newBuffer = false;
@ -551,6 +549,9 @@ bool COpenGL3DriverBase::updateIndexHardwareBuffer(SHWBufferLink_opengl *HWBuffe
} }
} }
const size_t bufferSize = indexCount * indexSize;
accountHWBufferUpload(bufferSize);
// get or create buffer // get or create buffer
bool newBuffer = false; bool newBuffer = false;
if (!HWBuffer->vbo_indicesID) { if (!HWBuffer->vbo_indicesID) {
@ -558,7 +559,7 @@ bool COpenGL3DriverBase::updateIndexHardwareBuffer(SHWBufferLink_opengl *HWBuffe
if (!HWBuffer->vbo_indicesID) if (!HWBuffer->vbo_indicesID)
return false; return false;
newBuffer = true; newBuffer = true;
} else if (HWBuffer->vbo_indicesSize < indexCount * indexSize) { } else if (HWBuffer->vbo_indicesSize < bufferSize) {
newBuffer = true; newBuffer = true;
} }
@ -566,16 +567,16 @@ bool COpenGL3DriverBase::updateIndexHardwareBuffer(SHWBufferLink_opengl *HWBuffe
// copy data to graphics card // copy data to graphics card
if (!newBuffer) if (!newBuffer)
GL.BufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, indexCount * indexSize, indices); GL.BufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, bufferSize, indices);
else { else {
HWBuffer->vbo_indicesSize = indexCount * indexSize; HWBuffer->vbo_indicesSize = bufferSize;
GLenum usage = GL_STATIC_DRAW; GLenum usage = GL_STATIC_DRAW;
if (HWBuffer->Mapped_Index == scene::EHM_STREAM) if (HWBuffer->Mapped_Index == scene::EHM_STREAM)
usage = GL_STREAM_DRAW; usage = GL_STREAM_DRAW;
else if (HWBuffer->Mapped_Index == scene::EHM_DYNAMIC) else if (HWBuffer->Mapped_Index == scene::EHM_DYNAMIC)
usage = GL_DYNAMIC_DRAW; usage = GL_DYNAMIC_DRAW;
GL.BufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * indexSize, indices, usage); GL.BufferData(GL_ELEMENT_ARRAY_BUFFER, bufferSize, indices, usage);
} }
GL.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); GL.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
@ -589,22 +590,24 @@ bool COpenGL3DriverBase::updateHardwareBuffer(SHWBufferLink *HWBuffer)
if (!HWBuffer) if (!HWBuffer)
return false; return false;
auto *b = static_cast<SHWBufferLink_opengl *>(HWBuffer);
if (HWBuffer->Mapped_Vertex != scene::EHM_NEVER) { if (HWBuffer->Mapped_Vertex != scene::EHM_NEVER) {
if (HWBuffer->ChangedID_Vertex != HWBuffer->MeshBuffer->getChangedID_Vertex() || !static_cast<SHWBufferLink_opengl *>(HWBuffer)->vbo_verticesID) { if (HWBuffer->ChangedID_Vertex != HWBuffer->MeshBuffer->getChangedID_Vertex() || !b->vbo_verticesID) {
HWBuffer->ChangedID_Vertex = HWBuffer->MeshBuffer->getChangedID_Vertex(); HWBuffer->ChangedID_Vertex = HWBuffer->MeshBuffer->getChangedID_Vertex();
if (!updateVertexHardwareBuffer(static_cast<SHWBufferLink_opengl *>(HWBuffer))) if (!updateVertexHardwareBuffer(b))
return false; return false;
} }
} }
if (HWBuffer->Mapped_Index != scene::EHM_NEVER) { if (HWBuffer->Mapped_Index != scene::EHM_NEVER) {
if (HWBuffer->ChangedID_Index != HWBuffer->MeshBuffer->getChangedID_Index() || !static_cast<SHWBufferLink_opengl *>(HWBuffer)->vbo_indicesID) { if (HWBuffer->ChangedID_Index != HWBuffer->MeshBuffer->getChangedID_Index() || !b->vbo_indicesID) {
HWBuffer->ChangedID_Index = HWBuffer->MeshBuffer->getChangedID_Index(); HWBuffer->ChangedID_Index = HWBuffer->MeshBuffer->getChangedID_Index();
if (!updateIndexHardwareBuffer((SHWBufferLink_opengl *)HWBuffer)) if (!updateIndexHardwareBuffer(b))
return false; return false;
} }
} }

@ -1953,6 +1953,11 @@ void Game::updateProfilers(const RunStats &stats, const FpsControl &draw_times,
g_profiler->graphAdd("Sleep [us]", draw_times.sleep_time); g_profiler->graphAdd("Sleep [us]", draw_times.sleep_time);
g_profiler->graphSet("FPS", 1.0f / dtime); g_profiler->graphSet("FPS", 1.0f / dtime);
auto stats2 = driver->getFrameStats();
g_profiler->avg("Irr: primitives drawn", stats2.PrimitivesDrawn);
g_profiler->avg("Irr: buffers uploaded", stats2.HWBuffersUploaded);
g_profiler->avg("Irr: buffers uploaded (bytes)", stats2.HWBuffersUploadedSize);
} }
void Game::updateStats(RunStats *stats, const FpsControl &draw_times, void Game::updateStats(RunStats *stats, const FpsControl &draw_times,