void DetailedTimersDemo::timeDemo( hkDemo* demo, int iterations, const char* fileName ) { // // Time the demo // hkMonitorStreamFrameInfo frameInfo; # ifdef HK_PS2 frameInfo.m_indexOfTimer0 = 1; frameInfo.m_indexOfTimer1 = 0; // Assume that each instruction cache miss cost around 35 cycles. // So we can see how much of our overall time is spent waiting for the // memory system frameInfo.m_timerFactor0 = 35.0f / 300.f; frameInfo.m_timerFactor1 = 1.0f / 300.f; frameInfo.m_heading = "usec: IcachePenalty (assuming 35 cycle penalty)"; # else frameInfo.m_indexOfTimer0 = 0; frameInfo.m_indexOfTimer1 = -1; frameInfo.m_heading = "usecs"; frameInfo.m_timerFactor0 = 1e6f / hkReal(hkStopwatch::getTicksPerSecond()); # endif int demoIdx = hkDemoDatabase::getInstance().findDemo( TEST_DEMO_FULLPATH ); HK_ASSERT2(0x654e432e, demoIdx != -1, "Demo does not exist" ); const bool isPhysicsDemo = (HK_DEMO_TYPE_PHYSICS == hkDemoDatabase::getInstance().getDemos()[ demoIdx ].m_demoTypeFlags); // // Setup some memory to store all the timer information // for all frames // int numThreads = 1; if( isPhysicsDemo ) { hkCpuJobThreadPool* mtUtil = (hkCpuJobThreadPool*)static_cast<hkDefaultPhysicsDemo*>(demo)->m_jobThreadPool; if (mtUtil) { numThreads += mtUtil->getNumThreads(); } } hkMonitorStreamAnalyzer streamAnalyzer( 10000000, numThreads ); for (int i = 0; i < iterations; i++ ) { // // Setup the timerinfo and memory on a per frame bases // hkMonitorStream& stream = hkMonitorStream::getInstance(); stream.resize( 2 * 1024 * 1024 ); // 2 meg for timer info per frame stream.reset(); // // Start timers // # ifdef HK_PS2 scePcStart( SCE_PC_CTE | SCE_PC_U0 | SCE_PC_U1 | SCE_PC0_ICACHE_MISS | SCE_PC1_CPU_CYCLE, 0 ,0 ); # endif // // Step the demo // demo->stepDemo(); // // Stop timers. This is necessary as a timer overflow on PlayStation(R)2 causes an exception // # ifdef HK_PS2 scePcStop() ; # endif // // Analyze the per frame info and copy the data over to the multi frame buffer // if( numThreads > 1 ) { hkCpuJobThreadPool* mtUtil = (hkCpuJobThreadPool*)static_cast<hkDefaultPhysicsDemo*>(demo)->m_jobThreadPool; // Loop through each thread. Capture the frame details from the local // stream analyzer in each thread. for (int t = 0; t < mtUtil->getNumThreads(); ++t) { hkCpuJobThreadPool::WorkerThreadData& data = mtUtil->m_workerThreads[t]; if (data.m_monitorStreamBegin != data.m_monitorStreamEnd ) { frameInfo.m_threadId = t + 1; streamAnalyzer.captureFrameDetails( data.m_monitorStreamBegin,data.m_monitorStreamEnd, frameInfo ); } } } frameInfo.m_threadId = 0; streamAnalyzer.captureFrameDetails(stream.getStart(), stream.getEnd(), frameInfo ); } // // Write the results to a file // { // Disable double conversion check - we know this will fail pushDoubleConversionCheck(false); hkReferencedObject::lockAll(); hkOstream ostr (fileName); ostr << TEST_DEMO_NAME " Timers: \n"; streamAnalyzer.writeStatistics( ostr ); hkReferencedObject::unlockAll(); popDoubleConversionCheck(); } }
hkDemo::Result BasicMovementDemo::stepDemo() { // for PlayStation(R)2 metrowerks pushDoubleConversionCheck( false ); // Display current settings { char buf[255]; for (int i=0; i< NUM_ANIMS; i++) { hkString::sprintf(buf, "anim%d: %0.3f", i, m_control[i]->getWeight()); const int h = m_env->m_window->getHeight(); m_env->m_textDisplay->outputText( buf, 20, h-70+16*i, curveCols[i], 1); } } popDoubleConversionCheck(); // Handle the keys { bool jumping = (m_control[1]->getWeight() > 0.001f); if (!jumping) { hkVector4 upVec(0,0,1); hkReal up, turn; up = m_env->m_gamePad->getStickPosY( 1 ); // 1 is the only one on PSP const hkBool upPressed = (up > 0.0f); const hkBool easeIn = (m_control[0]->getEaseStatus() == hkaDefaultAnimationControl::EASING_IN ) || ( m_control[0]->getEaseStatus() == hkaDefaultAnimationControl::EASED_IN ); if ( easeIn && ( !upPressed )) { // Ease in stand m_control[0]->easeOut( 0.9f ); } else if (( !easeIn ) && upPressed ) { // Ease in walk cycle m_control[0]->easeIn( 0.9f ); } turn = m_env->m_gamePad->getStickPosX(1); turn *= -5.0f * HK_REAL_PI / 180.0f * m_control[0]->getWeight(); hkQuaternion q; q.setAxisAngle(upVec, turn); m_currentMotion.m_rotation.mul(q); } else { hkReal remaining = m_control[1]->getAnimationBinding()->m_animation->m_duration - m_control[1]->getLocalTime(); // If we've played through then fade out const hkBool easeIn = (m_control[1]->getEaseStatus() == hkaDefaultAnimationControl::EASING_IN ) || ( m_control[1]->getEaseStatus() == hkaDefaultAnimationControl::EASED_IN ); if ( easeIn && (remaining < 0.2f)) { m_control[1]->easeOut( remaining ); m_control[0]->setLocalTime( m_control[0]->getAnimationBinding()->m_animation->m_duration - remaining ); m_control[0]->easeIn( remaining ); } } if (m_env->m_gamePad->wasButtonPressed( HKG_PAD_BUTTON_2) && !jumping) { // Reset jump animation and play m_control[1]->setLocalTime(0.0f); m_control[1]->easeIn( 0.1f ); m_control[0]->easeOut( 0.1f ); } if (m_env->m_gamePad->wasButtonPressed( HKG_PAD_BUTTON_1)) { m_currentMotion.setIdentity(); } } // Grab accumulated motion { hkQsTransform deltaMotion; deltaMotion.setIdentity(); m_skeletonInstance->getDeltaReferenceFrame( m_timestep, deltaMotion); hkQsTransform temp; temp.setMul(m_currentMotion, deltaMotion); m_currentMotion = temp; } const int boneCount = m_skeleton->m_numBones; // Advance the active animations m_skeletonInstance->stepDeltaTime( 1.0f / 60.0f ); // Sample the active animations and combine into a single pose hkaPose pose (m_skeleton); m_skeletonInstance->sampleAndCombineAnimations( pose.accessUnsyncedPoseLocalSpace().begin(), pose.getFloatSlotValues().begin() ); AnimationUtils::drawPose( pose, hkQsTransform::getIdentity() ); // Construct the composite world transform hkLocalArray<hkTransform> compositeWorldInverse( boneCount ); compositeWorldInverse.setSize( boneCount ); // Convert accumlated info to graphics matrix hkTransform graphicsTransform; m_currentMotion.copyToTransform(graphicsTransform); // Skin the meshes { const hkArray<hkQsTransform>& poseInWorld = pose.getSyncedPoseModelSpace(); for (int i=0; i < m_numSkinBindings; i++) { // assumes either a straight map (null map) or a single one (1 palette) hkInt16* usedBones = m_skinBindings[i]->m_mappings? m_skinBindings[i]->m_mappings[0].m_mapping : HK_NULL; int numUsedBones = usedBones? m_skinBindings[i]->m_mappings[0].m_numMapping : boneCount; // Multiply through by the bind pose inverse world inverse matrices for (int p=0; p < numUsedBones; p++) { int boneIndex = usedBones? usedBones[p] : p; compositeWorldInverse[p].setMul( poseInWorld[ boneIndex ], m_skinBindings[i]->m_boneFromSkinMeshTransforms[ boneIndex ] ); } AnimationUtils::skinMesh( *m_skinBindings[i]->m_mesh, graphicsTransform, compositeWorldInverse.begin(), *m_env->m_sceneConverter ); } } return hkDemo::DEMO_OK; }