FixCallCost::FixCallCost(TracePart* part, FixPool* pool, TraceFunctionSource* functionSource, unsigned int line, Addr addr, TracePartCall* partCall, SubCost callCount, FixString& s) { if (0) qDebug("Got FixCallCost (addr 0x%s, line %d): calls %s", qPrintable(addr.toString()), line, qPrintable(callCount.pretty())); int maxCount = part->eventTypeMapping()->count(); _part = part; _functionSource = functionSource; _line = line; _addr = addr; _cost = (SubCost*) pool->reserve(sizeof(SubCost) * (maxCount+1)); s.stripSpaces(); int i = 0; while(i<maxCount) { if (!s.stripUInt64(_cost[i])) break; i++; } _count = i; if (!pool->allocateReserved(sizeof(SubCost) * (_count+1) )) _count = 0; else _cost[_count] = callCount; _nextCostOfPartCall = partCall ? partCall->setFirstFixCallCost(this) : 0; }
FixCost::FixCost(TracePart* part, FixPool* pool, TraceFunctionSource* functionSource, PositionSpec& pos, TracePartFunction* partFunction, FixString& s) { int maxCount = part->eventTypeMapping()->count(); _part = part; _functionSource = functionSource; _pos = pos; _cost = (SubCost*) pool->reserve(sizeof(SubCost) * maxCount); s.stripSpaces(); int i = 0; while(i<maxCount) { if (!s.stripUInt64(_cost[i])) break; i++; } _count = i; if (!pool->allocateReserved(sizeof(SubCost) * _count)) _count = 0; _nextCostOfPartFunction = partFunction ? partFunction->setFirstFixCost(this) : 0; }
// update each subcost to be maximum of old and given costs void ProfileCostArray::maxCost(EventTypeMapping* mapping, FixString & s) { if (!mapping) return; s.stripSpaces(); if (s.isEmpty()) return; reserve(mapping->set()->realCount()); SubCost v; if (mapping->isIdentity()) { int i = 0; while(i<mapping->count()) { if (!s.stripUInt64(v)) break; if (i<_count) { if (v>_cost[i]) _cost[i] = v; } else _cost[i] = v; i++; } if (i > _count) _count = i; } else { int i = 0, maxIndex = 0, index; while(1) { if (!s.stripUInt64(v)) break; index = mapping->realIndex(i); if (maxIndex<index) maxIndex=index; if (index == ProfileCostArray::InvalidIndex) break; if (index<_count) { if (v>_cost[index]) _cost[index] = v; } else _cost[index] = v; i++; } if (maxIndex >= _count) { /* we have to set all costs of unused indexes in the interval * [_count;maxIndex] to zero */ for(i=mapping->nextUnused(_count-1); i<=maxIndex; i=mapping->nextUnused(i)) _cost[i] = 0; _count = maxIndex+1; } } Q_ASSERT(_count <= _allocCount); invalidate(); #if TRACE_DEBUG _dirty = false; // do not recurse ! qDebug("%s\n now %s", qPrintable( fullName() ), qPrintable(ProfileCostArray::costString(0))); _dirty = true; // because of invalidate() #endif }
bool FixString::stripName(FixString& s) { if (_len==0) return false; // first char has to be a letter or "_" if (!QChar(*_str).isLetter() && (*_str != '_')) return false; int newLen = 1; const char* newStr = _str; _str++; _len--; while(_len>0) { if (!QChar(*_str).isLetterOrNumber() && (*_str != '_')) break; newLen++; _str++; _len--; } s.set(newStr, newLen); return true; }
void ProfileCostArray::set(EventTypeMapping* mapping, FixString & s) { if (!mapping) return; s.stripSpaces(); if (s.isEmpty()) { clear(); return; } reserve(mapping->set()->realCount()); if (mapping->isIdentity()) { int i = 0; while(i<mapping->count()) { if (!s.stripUInt64(_cost[i])) break; i++; } _count = i; } else { int i = 0, maxIndex = 0, index; while(1) { index = mapping->realIndex(i); if (maxIndex<index) maxIndex=index; if (index == ProfileCostArray::InvalidIndex) break; if (!s.stripUInt64(_cost[index])) break; i++; } // we have to set all costs of unused indexes till maxIndex to zero for(i=mapping->firstUnused(); i<=maxIndex; i=mapping->nextUnused(i)) _cost[i] = 0; _count = maxIndex+1; } Q_ASSERT(_count <= _allocCount); invalidate(); }
bool FixFile::nextLine(FixString& str) { if (_currentLeft == 0) return false; unsigned left = _currentLeft; char* current = _current; while(left>0) { if (*current == 0 || *current == '\n') break; current++; left--; } if (0) { char tmp[200]; int l = _currentLeft-left; if (l>199) l = 199; strncpy(tmp, _current, l); tmp[l] = 0; qDebug("[FixFile::nextLine] At %lu, len %u: '%s'", (unsigned long) (_current - _base), _currentLeft-left, tmp); } int len = _currentLeft-left; // get rid of any carriage return at end if ((len>0) && (*(current-1) == '\r')) len--; str.set(_current, len); if ((left > 0) && (*current == '\n')) { current++; left--; } _current = current; _currentLeft = left; return true; }
/** * The main import function... */ int CachegrindLoader::loadInternal(TraceData* data, QIODevice* device, const QString& filename) { if (!data || !device) return 0; _data = data; _filename = filename; _lineNo = 0; loadStart(_filename); FixFile file(device, _filename); if (!file.exists()) { loadFinished(QStringLiteral("File does not exist")); return 0; } int statusProgress = 0; #if USE_FIXCOST // FixCost Memory Pool FixPool* pool = _data->fixPool(); #endif _part = 0; partsAdded = 0; prepareNewPart(); FixString line; char c; // current position nextLineType = SelfCost; // default if there is no "positions:" line hasLineInfo = true; hasAddrInfo = false; while (file.nextLine(line)) { _lineNo++; #if TRACE_LOADER qDebug() << "[CachegrindLoader] " << _filename << ":" << _lineNo << " - '" << QString(line) << "'"; #endif // if we cannot strip a character, this was an empty line if (!line.first(c)) continue; if (c <= '9') { if (c == '#') continue; // parse position(s) if (!parsePosition(line, currentPos)) { error(QStringLiteral("Invalid position specification '%1'").arg(line)); continue; } // go through after big switch } else { // if (c > '9') line.stripFirst(c); /* in order of probability */ switch(c) { case 'f': // fl= if (line.stripPrefix("l=")) { setFile(line); // this is the default for new functions currentFunctionFile = currentFile; continue; } // fi=, fe= if (line.stripPrefix("i=") || line.stripPrefix("e=")) { setFile(line); continue; } // fn= if (line.stripPrefix("n=")) { if (currentFile != currentFunctionFile) currentFile = currentFunctionFile; setFunction(line); // on a new function, update status int progress = (int)(100.0 * file.current() / file.len() +.5); if (progress != statusProgress) { statusProgress = progress; /* When this signal is connected, it most probably * should lead to GUI update. Thus, when multiple * "long operations" (like file loading) are in progress, * this can temporarly switch to another operation. */ loadProgress(statusProgress); } continue; } break; case 'c': // cob= if (line.stripPrefix("ob=")) { setCalledObject(line); continue; } // cfi= / cfl= if (line.stripPrefix("fl=") || line.stripPrefix("fi=")) { setCalledFile(line); continue; } // cfn= if (line.stripPrefix("fn=")) { setCalledFunction(line); continue; } // calls= if (line.stripPrefix("alls=")) { // ignore long lines... line.stripUInt64(currentCallCount); nextLineType = CallCost; continue; } // cmd: if (line.stripPrefix("md:")) { QString command = QString(line).trimmed(); if (!_data->command().isEmpty() && _data->command() != command) { error(QStringLiteral("Redefined command, was '%1'").arg(_data->command())); } _data->setCommand(command); continue; } // creator: if (line.stripPrefix("reator:")) { // ignore ... continue; } break; case 'j': // jcnd= if (line.stripPrefix("cnd=")) { bool valid; valid = line.stripUInt64(jumpsFollowed) && line.stripPrefix("/") && line.stripUInt64(jumpsExecuted) && parsePosition(line, targetPos); if (!valid) { error(QStringLiteral("Invalid line after 'jcnd'")); } else nextLineType = CondJump; continue; } if (line.stripPrefix("ump=")) { bool valid; valid = line.stripUInt64(jumpsExecuted) && parsePosition(line, targetPos); if (!valid) { error(QStringLiteral("Invalid line after 'jump'")); } else nextLineType = BoringJump; continue; } // jfi= if (line.stripPrefix("fi=")) { currentJumpToFile = compressedFile(line); continue; } // jfn= if (line.stripPrefix("fn=")) { if (!currentJumpToFile) { // !=0 as functions needs file currentJumpToFile = currentFile; } currentJumpToFunction = compressedFunction(line, currentJumpToFile, currentObject); continue; } break; case 'o': // ob= if (line.stripPrefix("b=")) { setObject(line); continue; } break; case '#': continue; case 'a': // "arch: arm" if (line.stripPrefix("rch: arm")) { TraceData::Arch a = _data->architecture(); if ((a != TraceData::ArchUnknown) && (a != TraceData::ArchARM)) { error(QStringLiteral("Redefined architecture!")); } _data->setArchitecture(TraceData::ArchARM); continue; } break; case 't': // totals: if (line.stripPrefix("otals:")) continue; // thread: if (line.stripPrefix("hread:")) { prepareNewPart(); _part->setThreadID(QString(line).toInt()); continue; } // timeframe (BB): if (line.stripPrefix("imeframe (BB):")) { _part->setTimeframe(line); continue; } break; case 'd': // desc: if (line.stripPrefix("esc:")) { line.stripSurroundingSpaces(); // desc: Trigger: if (line.stripPrefix("Trigger:")) { _part->setTrigger(line); } continue; } break; case 'e': // events: if (line.stripPrefix("vents:")) { prepareNewPart(); mapping = _data->eventTypes()->createMapping(line); _part->setEventMapping(mapping); continue; } // event:<name>[=<formula>][:<long name>] if (line.stripPrefix("vent:")) { line.stripSurroundingSpaces(); FixString e, f, l; if (!line.stripName(e)) { error(QStringLiteral("Invalid event")); continue; } line.stripSpaces(); if (!line.stripFirst(c)) continue; if (c=='=') f = line.stripUntil(':'); line.stripSpaces(); // add to known cost types if (line.isEmpty()) line = e; EventType::add(new EventType(e,line,f)); continue; } break; case 'p': // part: if (line.stripPrefix("art:")) { prepareNewPart(); _part->setPartNumber(QString(line).toInt()); continue; } // pid: if (line.stripPrefix("id:")) { prepareNewPart(); _part->setProcessID(QString(line).toInt()); continue; } // positions: if (line.stripPrefix("ositions:")) { prepareNewPart(); QString positions(line); hasLineInfo = positions.contains(QStringLiteral("line")); hasAddrInfo = positions.contains(QStringLiteral("instr")); continue; } break; case 'v': // version: if (line.stripPrefix("ersion:")) { // ignore for now continue; } break; case 's': // summary: if (line.stripPrefix("ummary:")) { if (!mapping) { error(QStringLiteral("No event line found. Skipping file")); delete _part; return false; } _part->totals()->set(mapping, line); continue; } case 'r': // rcalls= (deprecated) if (line.stripPrefix("calls=")) { // handle like normal calls: we need the sum of call count // recursive cost is discarded in cycle detection line.stripUInt64(currentCallCount); nextLineType = CallCost; warning(QStringLiteral("Old file format using deprecated 'rcalls'")); continue; } break; default: break; } error(QStringLiteral("Invalid line '%1%2'").arg(c).arg(line)); continue; } if (!mapping) { error(QStringLiteral("No event line found. Skipping file")); delete _part; return false; } // for a cost line, we always need a current function ensureFunction(); if (!currentFunctionSource || (currentFunctionSource->file() != currentFile)) { currentFunctionSource = currentFunction->sourceFile(currentFile, true); } #if !USE_FIXCOST if (hasAddrInfo) { if (!currentInstr || (currentInstr->addr() != currentPos.fromAddr)) { currentInstr = currentFunction->instr(currentPos.fromAddr, true); if (!currentInstr) { error(QString("Invalid address '%1'").arg(currentPos.fromAddr.toString())); continue; } currentPartInstr = currentInstr->partInstr(_part, currentPartFunction); } } if (hasLineInfo) { if (!currentLine || (currentLine->lineno() != currentPos.fromLine)) { currentLine = currentFunctionSource->line(currentPos.fromLine, true); currentPartLine = currentLine->partLine(_part, currentPartFunction); } if (hasAddrInfo && currentInstr) currentInstr->setLine(currentLine); } #endif #if TRACE_LOADER qDebug() << _filename << ":" << _lineNo; qDebug() << " currentInstr " << (currentInstr ? qPrintable(currentInstr->toString()) : "."); qDebug() << " currentLine " << (currentLine ? qPrintable(currentLine->toString()) : ".") << "( file " << currentFile->name() << ")"; qDebug() << " currentFunction " << qPrintable(currentFunction->prettyName()); qDebug() << " currentCalled " << (currentCalledFunction ? qPrintable(currentCalledFunction->prettyName()) : "."); #endif // create cost item if (nextLineType == SelfCost) { #if USE_FIXCOST new (pool) FixCost(_part, pool, currentFunctionSource, currentPos, currentPartFunction, line); #else if (hasAddrInfo) { TracePartInstr* partInstr; partInstr = currentInstr->partInstr(_part, currentPartFunction); if (hasLineInfo) { // we need to set <line> back after reading for the line int l = line.len(); const char* s = line.ascii(); partInstr->addCost(mapping, line); line.set(s,l); } else partInstr->addCost(mapping, line); } if (hasLineInfo) { TracePartLine* partLine; partLine = currentLine->partLine(_part, currentPartFunction); partLine->addCost(mapping, line); } #endif if (!line.isEmpty()) { error(QStringLiteral("Garbage at end of cost line ('%1')").arg(line)); } } else if (nextLineType == CallCost) { nextLineType = SelfCost; TraceCall* calling = currentFunction->calling(currentCalledFunction); TracePartCall* partCalling = calling->partCall(_part, currentPartFunction, currentCalledPartFunction); #if USE_FIXCOST FixCallCost* fcc; fcc = new (pool) FixCallCost(_part, pool, currentFunctionSource, hasLineInfo ? currentPos.fromLine : 0, hasAddrInfo ? currentPos.fromAddr : Addr(0), partCalling, currentCallCount, line); fcc->setMax(_data->callMax()); _data->updateMaxCallCount(fcc->callCount()); #else if (hasAddrInfo) { TraceInstrCall* instrCall; TracePartInstrCall* partInstrCall; instrCall = calling->instrCall(currentInstr); partInstrCall = instrCall->partInstrCall(_part, partCalling); partInstrCall->addCallCount(currentCallCount); if (hasLineInfo) { // we need to set <line> back after reading for the line int l = line.len(); const char* s = line.ascii(); partInstrCall->addCost(mapping, line); line.set(s,l); } else partInstrCall->addCost(mapping, line); // update maximum of call cost _data->callMax()->maxCost(partInstrCall); _data->updateMaxCallCount(partInstrCall->callCount()); } if (hasLineInfo) { TraceLineCall* lineCall; TracePartLineCall* partLineCall; lineCall = calling->lineCall(currentLine); partLineCall = lineCall->partLineCall(_part, partCalling); partLineCall->addCallCount(currentCallCount); partLineCall->addCost(mapping, line); // update maximum of call cost _data->callMax()->maxCost(partLineCall); _data->updateMaxCallCount(partLineCall->callCount()); } #endif currentCalledFile = 0; currentCalledPartFile = 0; currentCalledObject = 0; currentCalledPartObject = 0; currentCallCount = 0; if (!line.isEmpty()) { error(QStringLiteral("Garbage at end of call cost line ('%1')").arg(line)); } } else { // (nextLineType == BoringJump || nextLineType == CondJump) TraceFunctionSource* targetSource; if (!currentJumpToFunction) currentJumpToFunction = currentFunction; targetSource = (currentJumpToFile) ? currentJumpToFunction->sourceFile(currentJumpToFile, true) : currentFunctionSource; #if USE_FIXCOST new (pool) FixJump(_part, pool, /* source */ hasLineInfo ? currentPos.fromLine : 0, hasAddrInfo ? currentPos.fromAddr : 0, currentPartFunction, currentFunctionSource, /* target */ hasLineInfo ? targetPos.fromLine : 0, hasAddrInfo ? targetPos.fromAddr : Addr(0), currentJumpToFunction, targetSource, (nextLineType == CondJump), jumpsExecuted, jumpsFollowed); #else if (hasAddrInfo) { TraceInstr* jumpToInstr; TraceInstrJump* instrJump; TracePartInstrJump* partInstrJump; jumpToInstr = currentJumpToFunction->instr(targetPos.fromAddr, true); instrJump = currentInstr->instrJump(jumpToInstr, (nextLineType == CondJump)); partInstrJump = instrJump->partInstrJump(_part); partInstrJump->addExecutedCount(jumpsExecuted); if (nextLineType == CondJump) partInstrJump->addFollowedCount(jumpsFollowed); } if (hasLineInfo) { TraceLine* jumpToLine; TraceLineJump* lineJump; TracePartLineJump* partLineJump; jumpToLine = targetSource->line(targetPos.fromLine, true); lineJump = currentLine->lineJump(jumpToLine, (nextLineType == CondJump)); partLineJump = lineJump->partLineJump(_part); partLineJump->addExecutedCount(jumpsExecuted); if (nextLineType == CondJump) partLineJump->addFollowedCount(jumpsFollowed); } #endif if (0) { qDebug() << _filename << ":" << _lineNo << " - jump from 0x" << currentPos.fromAddr.toString() << " (line " << currentPos.fromLine << ") to 0x" << targetPos.fromAddr.toString() << " (line " << targetPos.fromLine << ")"; if (nextLineType == BoringJump) qDebug() << " Boring Jump, count " << jumpsExecuted.pretty(); else qDebug() << " Cond. Jump, followed " << jumpsFollowed.pretty() << ", executed " << jumpsExecuted.pretty(); } nextLineType = SelfCost; currentJumpToFunction = 0; currentJumpToFile = 0; if (!line.isEmpty()) { error(QStringLiteral("Garbage at end of jump cost line ('%1')").arg(line)); } } } loadFinished(); if (mapping) { _part->invalidate(); _part->totals()->clear(); _part->totals()->addCost(_part); data->addPart(_part); partsAdded++; } else { delete _part; } device->close(); return partsAdded; }
/** * Return false if this is no position specification */ bool CachegrindLoader::parsePosition(FixString& line, PositionSpec& newPos) { char c; uint diff; if (hasAddrInfo) { if (!line.first(c)) return false; if (c == '*') { // nothing changed line.stripFirst(c); newPos.fromAddr = currentPos.fromAddr; newPos.toAddr = currentPos.toAddr; } else if (c == '+') { line.stripFirst(c); line.stripUInt(diff, false); newPos.fromAddr = currentPos.fromAddr + diff; newPos.toAddr = newPos.fromAddr; } else if (c == '-') { line.stripFirst(c); line.stripUInt(diff, false); newPos.fromAddr = currentPos.fromAddr - diff; newPos.toAddr = newPos.fromAddr; } else if (c >= '0') { uint64 v; line.stripUInt64(v, false); newPos.fromAddr = Addr(v); newPos.toAddr = newPos.fromAddr; } else return false; // Range specification if (line.first(c)) { if (c == '+') { line.stripFirst(c); line.stripUInt(diff); newPos.toAddr = newPos.fromAddr + diff; } else if ((c == '-') || (c == ':')) { line.stripFirst(c); uint64 v; line.stripUInt64(v); newPos.toAddr = Addr(v); } } line.stripSpaces(); #if TRACE_LOADER if (newPos.fromAddr == newPos.toAddr) qDebug() << " Got Addr " << newPos.fromAddr.toString(); else qDebug() << " Got AddrRange " << newPos.fromAddr.toString() << ":" << newPos.toAddr.toString(); #endif } if (hasLineInfo) { if (!line.first(c)) return false; if (c > '9') return false; else if (c == '*') { // nothing changed line.stripFirst(c); newPos.fromLine = currentPos.fromLine; newPos.toLine = currentPos.toLine; } else if (c == '+') { line.stripFirst(c); line.stripUInt(diff, false); newPos.fromLine = currentPos.fromLine + diff; newPos.toLine = newPos.fromLine; } else if (c == '-') { line.stripFirst(c); line.stripUInt(diff, false); if (currentPos.fromLine < diff) { error(QStringLiteral("Negative line number %1") .arg((int)currentPos.fromLine - (int)diff)); diff = currentPos.fromLine; } newPos.fromLine = currentPos.fromLine - diff; newPos.toLine = newPos.fromLine; } else if (c >= '0') { line.stripUInt(newPos.fromLine, false); newPos.toLine = newPos.fromLine; } else return false; // Range specification if (line.first(c)) { if (c == '+') { line.stripFirst(c); line.stripUInt(diff); newPos.toLine = newPos.fromLine + diff; } else if ((c == '-') || (c == ':')) { line.stripFirst(c); line.stripUInt(newPos.toLine); } } line.stripSpaces(); #if TRACE_LOADER if (newPos.fromLine == newPos.toLine) qDebug() << " Got Line " << newPos.fromLine; else qDebug() << " Got LineRange " << newPos.fromLine << ":" << newPos.toLine; #endif } return true; }
void TestStage::onRender( float dFrame ) { glDisable( GL_DEPTH_TEST ); glDisable( GL_CULL_FACE ); glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT ); glEnable( GL_STENCIL_TEST ); GameWindow& window = Global::getDrawEngine()->getWindow(); int w = window.getWidth(); int h = window.getHeight(); for ( LightList::iterator iter = lights.begin(), itEnd = lights.end(); iter != itEnd ; ++iter ) { Light& light = *iter; #if 1 glColorMask(false, false, false, false); glStencilFunc(GL_ALWAYS, 1, 1); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); for( BlockList::iterator iter = blocks.begin(), itEnd = blocks.end(); iter != itEnd ; ++iter ) { Block& block = *iter; renderPolyShadow( light , block.pos , block.getVertices() , block.getVertexNum() ); } glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); glStencilFunc(GL_EQUAL, 0, 1); glColorMask(true, true, true, true); #endif glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glUseProgram(program); glUniform2f( loc_lightLocation , light.pos.x , light.pos.y ); glUniform3f( loc_lightColor , light.color.x , light.color.y , light.color.z ); glUniform3f( loc_lightAttenuation , 0 , 1 / 5.0 , 0 ); glBegin( GL_QUADS ); glVertex2i( 0 , 0 ); glVertex2i( w , 0 ); glVertex2i( w , h ); glVertex2i( 0 , h ); glEnd(); glUseProgram(0); glDisable(GL_BLEND); glClear(GL_STENCIL_BUFFER_BIT); } glDisable( GL_STENCIL_TEST ); GLGraphics2D& g = ::Global::getDrawEngine()->getGLGraphics(); g.beginRender(); RenderUtility::setFont( g , FONT_S8 ); FixString< 256 > str; Vec2i pos = Vec2i( 10 , 10 ); g.drawText( pos , str.format( "Lights Num = %u" , lights.size() ) ); g.endRender(); }
void Game::run() { using std::cout; using std::endl; int prevTime = Platform::getTickCount(); int64 timeFrame = Platform::getTickCount(); int frameCount = 0; IText* text = IText::create( mFonts[0] , 18 , Color(255,255,25) ); static int const NUM_FPS_SAMPLES = 12; float fpsSamples[NUM_FPS_SAMPLES]; int NumFramePerSample = 10; std::fill_n( fpsSamples , NUM_FPS_SAMPLES , 60.0f ); int idxSample = 0; while( !mNeedEnd ) { int64 curTime = Platform::getTickCount(); float deltaT = ( curTime - prevTime ) / 1000.0f; prevTime = curTime; while ( mStageAdd ) { if( mbRemovePrevStage ) { mStageStack.back()->onExit(); delete mStageStack.back(); mStageStack.pop_back(); cout << "Old stage deleted." << endl; } GameStage* stage = mStageAdd; mStageAdd = NULL; mStageStack.push_back( stage ); cout << "Setup new state..." << endl; if ( !stage->onInit() ) { cout << "Stage Can't Init !" << endl; } cout << "Stage Init !" << endl; } GameStage* stage = mStageStack.back(); mSoundMgr->update( deltaT ); stage->onUpdate( deltaT ); if ( mRenderSystem->prevRender() ) { stage->onRender(); ++frameCount; if ( frameCount > NumFramePerSample ) { int64 temp = Platform::getTickCount(); fpsSamples[idxSample] = 1000.0f * ( frameCount ) / ( temp - timeFrame ); timeFrame = temp; frameCount = 0; ++idxSample; if ( idxSample == NUM_FPS_SAMPLES ) idxSample = 0; mFPS = 0; for (int i = 0; i < NUM_FPS_SAMPLES; i++) mFPS += fpsSamples[i]; mFPS /= NUM_FPS_SAMPLES; #if 0 std::cout << "FPS =" << mFPS << std::endl; #endif } FixString< 256 > str; str.format( "FPS = %f" , mFPS ); text->setString( str.c_str() ); mRenderSystem->drawText( text , Vec2i( getGame()->getScreenSize().x - 100 , 10 ) , TEXT_SIDE_LEFT | TEXT_SIDE_TOP ); mRenderSystem->postRender(); } if( stage->needStop() ) { mStageStack.pop_back(); stage->onExit(); delete stage; cout << "Stage Exit !" << endl; } if( mStageStack.empty() ) mNeedEnd=true; } text->release(); }