Reviving this 3 years-old thread for a cause...
So I finally worked out why my game was jerky, even if it was reportedly running at 60fps on my powerful-CPU underpowered-GPU configuration (i7-965 vs GT9600). Then, the crashes started when I pressed Alt-TAB while on fullscreen mode (DeviceLost).
Then I found this post who said to listen for RenderSystem events :
http://www.ogre3d.org/forums/viewtopic. ... 98#p360298
Then I changed FlushGPUBuffer to this:
Code: Select all
#ifndef __GPUCOMMANDBUFFERFLUSH_H__
#define __GPUCOMMANDBUFFERFLUSH_H__
#include "OgrePrerequisites.h"
#include "OgreFrameListener.h"
namespace Ogre
{
/** Helper class which can assist you in making sure the -GPU command
buffer is regularly flushed, so in cases where the -CPU is outpacing the
-GPU we do not hit a situation where the -CPU suddenly has to stall to
wait for more space in the buffer.
*/
class GpuCommandBufferFlush : public FrameListener, public Ogre::RenderSystem::Listener
{
protected:
bool mUseOcclusionQuery;
typedef std::vector<HardwareOcclusionQuery*> HOQList;
HOQList mHOQList;
size_t mMaxQueuedFrames;
size_t mCurrentFrame;
bool mStartPull;
bool mStarted;
bool waitingForDeviceRestore;
bool isDeviceLost;
bool isRenderSystemSListening;
public:
GpuCommandBufferFlush();
virtual ~GpuCommandBufferFlush();
void start(size_t maxQueuedFrames = 2);
void stop();
bool frameStarted(const FrameEvent& evt);
bool frameEnded(const FrameEvent& evt);
virtual void eventOccurred(const Ogre::String& eventName, const Ogre::NameValuePairList* parameters = 0);
};
}
#endif
Code: Select all
#include "Stdafx.h"
#include "OgreGpuCommandBufferFlush.h"
#include "OgreRoot.h"
#include "OgreRenderSystem.h"
#include "OgreHardwareOcclusionQuery.h"
namespace Ogre
{
//---------------------------------------------------------------------
GpuCommandBufferFlush::GpuCommandBufferFlush()
: mUseOcclusionQuery(true)
, mMaxQueuedFrames(2)
, mCurrentFrame(0)
, mStartPull(false)
, mStarted(false)
, waitingForDeviceRestore(false)
, isDeviceLost(false)
, isRenderSystemSListening(false)
{
}
//---------------------------------------------------------------------
GpuCommandBufferFlush::~GpuCommandBufferFlush()
{
stop();
RenderSystem* rsys;
Ogre::Root* root;
if ( isRenderSystemSListening && (root = Root::getSingletonPtr()) && (rsys = root->getRenderSystem()) )
rsys->removeListener(this);
}
//---------------------------------------------------------------------
void GpuCommandBufferFlush::eventOccurred(const Ogre::String& eventName, const Ogre::NameValuePairList* parameters)
{
std::cout << "GpuCommandBufferFlush eventOccurred=" << eventName << "=" << parameters << "\n";
if (eventName == "DeviceLost") {
isDeviceLost = true;
stop();
} else if (eventName == "DeviceRestored") {
isDeviceLost = false;
if (waitingForDeviceRestore) {
std::cout << "DEVICE FINALLY RESTORED!!!\n";
start();
}
}
}
//---------------------------------------------------------------------
void GpuCommandBufferFlush::start(size_t maxQueuedFrames)
{
if (isDeviceLost) {
std::cout << "MUST WAIT FOR DEVICE TO RESTORE!!!\n";
waitingForDeviceRestore = true;
return;
}
stop();
RenderSystem* rsys;
Ogre::Root* root;
if ( !(root = Root::getSingletonPtr()) || !(rsys = root->getRenderSystem()) )
return;
mMaxQueuedFrames = maxQueuedFrames;
mUseOcclusionQuery = rsys->getCapabilities()->hasCapability(RSC_HWOCCLUSION);
mCurrentFrame = 0;
mStartPull = false;
if (mUseOcclusionQuery)
{
for (size_t i = 0; i < mMaxQueuedFrames; ++i)
{
HardwareOcclusionQuery* hoq = rsys->createHardwareOcclusionQuery();
mHOQList.push_back(hoq);
}
}
if (!isRenderSystemSListening) {
isRenderSystemSListening = true;
rsys->addListener(this);
}
root->addFrameListener(this);
mStarted = true;
std::cout << "FRIGGIN START\n";
}
//---------------------------------------------------------------------
void GpuCommandBufferFlush::stop()
{
waitingForDeviceRestore = false;
RenderSystem* rsys;
Ogre::Root* root;
if ( !mStarted || !(root = Root::getSingletonPtr()) || !(rsys = root->getRenderSystem()) )
return;
for (HOQList::iterator i = mHOQList.begin(); i != mHOQList.end(); ++i)
{
rsys->destroyHardwareOcclusionQuery(*i);
}
mHOQList.clear();
root->removeFrameListener(this);
mStarted = false;
std::cout << "FRIGGIN STOP\n";
}
//---------------------------------------------------------------------
bool GpuCommandBufferFlush::frameStarted(const FrameEvent& evt)
{
if (mUseOcclusionQuery)
{
mHOQList[mCurrentFrame]->beginOcclusionQuery();
}
return true;
}
//---------------------------------------------------------------------
bool GpuCommandBufferFlush::frameEnded(const FrameEvent& evt)
{
if (mUseOcclusionQuery)
{
if(mHOQList[mCurrentFrame]->isStillOutstanding())
mHOQList[mCurrentFrame]->endOcclusionQuery();
}
mCurrentFrame = (mCurrentFrame + 1) % mMaxQueuedFrames;
// If we've wrapped around, time to start pulling
if (mCurrentFrame == 0)
mStartPull = true;
if (mStartPull)
{
unsigned int dummy;
mHOQList[mCurrentFrame]->pullOcclusionQuery(&dummy);
}
return true;
}
//---------------------------------------------------------------------
}
AND I stop/start the flushing in my main code as soon as the app loses/gains focus respectively!
Now, I managed to Alt-TAB about 14 times with no crash, when
Ogre suddenly crashed with a message like this:
"Could not restore device because there is not enough RAM"
Now, I don't expect anyone to Alt-TAB 15 times in practice,
but with only 10 days to release, I desperately have to know why/how this crash still occured. Withdrawing FlushGPUBuffers altogether is currently not a consideration because the stuttering is really too bad!
PS. BTW, I haven't found anything related to this in Ogre1.9! No Flush, no OgreGpuCommandBufferFlush...
Many, many. Many. Thanks in advance