1 /*---------------------------------------------------------------------------* 2 Project: NintendoWare 3 File: demo_DebugUtility.h 4 5 Copyright (C)2009-2010 Nintendo Co., Ltd./HAL Laboratory, Inc. All rights reserved. 6 7 These coded instructions, statements, and computer programs contain 8 proprietary information of Nintendo of America Inc. and/or Nintendo 9 Company Ltd., and are protected by Federal copyright law. They may 10 not be disclosed to third parties or copied or duplicated in any form, 11 in whole or in part, without the prior written consent of Nintendo. 12 13 $Revision: 18943 $ 14 *---------------------------------------------------------------------------*/ 15 16 #ifndef NW_DEMO_DEBUGUTILITY_H_ 17 #define NW_DEMO_DEBUGUTILITY_H_ 18 19 //#include <nw/types.h> 20 21 #include <nw/dev/dev_Screenshot.h> 22 #include <nw/demo/demo_HioPacketChannel.h> 23 #include <nw/demo/demo_GraphicsDrawing.h> 24 #include <nw/demo/demo_GraphicsSystem.h> 25 #include <nw/demo/demo_Memory.h> 26 #include <nw/demo/demo_Utility.h> 27 28 namespace nw 29 { 30 31 namespace demo 32 { 33 34 //============================================================================ 35 //! @name ユーティリティ 36 //@{ 37 38 //--------------------------------------------------------------------------- 39 //! @brief デモのデバッグに使用するユーティリティ関数をまとめたクラスです。 40 //--------------------------------------------------------------------------- 41 class DebugUtility 42 { 43 private: 44 static const int NW_PROFILE_OUTPUT_INTERVAL = 600; 45 46 public: 47 //===================== 48 //! @name 負荷の表示 49 //@{ 50 51 //--------------------------------------------------------------------------- 52 //! @brief 負荷を表示を行います。 53 //! 54 //! graphicsDrawingのBeginDrawingString()をあらかじめ実行し、 55 //! DrawLoadMeter()後はFlushDrawing()を実行する必要があります。 56 //! 57 //! @param[in] renderSystem 負荷計算をしているRenderSystemです。 58 //! @param[in] graphicsDrawing 文字列表示に使うGraphicsDrawingです。 59 //! @param[in] refreshMeter trueにすると負荷表示が更新されます。 60 //--------------------------------------------------------------------------- 61 static void DrawLoadMeter( 62 nw::demo::RenderSystem* renderSystem, 63 nw::demo::GraphicsDrawing* graphicsDrawing, 64 bool refreshMeter 65 ); 66 67 //--------------------------------------------------------------------------- 68 //! @brief CPU パフォーマンス計測モードであるかを取得します。 69 //! 70 //! DBG スイッチを ON にすることで、CPUパフォーマンス計測モードになります。 71 //! 72 //! @return CPU パフォーマンス計測モードであれば true を返します。 73 //--------------------------------------------------------------------------- IsCpuProfilingMode()74 static bool IsCpuProfilingMode() 75 { 76 return s_IsForceCpuProfilingMode || nw::demo::PadFactory::GetPad()->IsButtonPress(nw::demo::Pad::BUTTON_DEBUG); 77 } 78 79 //@} 80 81 //===================== 82 //! @name スクリーンショットテスト 83 //@{ 84 85 //--------------------------------------------------------------------------- 86 //! @brief 自動テストを初期化します。 87 //! 88 //! NW_AUTOTESTが定義されていない場合は何も行われません。 89 //! 90 //! @param[in] allocator 初期化に使用するアロケーターです。 91 //! @param[in] deviceAllocator Host IO 接続に使用するデバイスアロケーターです。 92 //--------------------------------------------------------------------------- 93 static void InitializeAutoTest( 94 os::IAllocator* allocator, 95 os::IAllocator* deviceAllocator, 96 nw::demo::RenderSystem** renderSystem, 97 const u32* correctHashDisplay0 = NULL, 98 const u32* correctHashDisplay1 = NULL 99 ) 100 { 101 #if defined(NW_AUTO_TEST) 102 s_AutoTester = AutoTester::Create( 103 allocator, 104 deviceAllocator 105 ); 106 107 s_AutoTester->Initialize(5, false, renderSystem, correctHashDisplay0, correctHashDisplay1); 108 #else 109 NW_UNUSED_VARIABLE(allocator); 110 NW_UNUSED_VARIABLE(deviceAllocator); 111 NW_UNUSED_VARIABLE(renderSystem); 112 NW_UNUSED_VARIABLE(correctHashDisplay0); 113 NW_UNUSED_VARIABLE(correctHashDisplay1); 114 #endif 115 } 116 117 //--------------------------------------------------------------------------- 118 //! @brief 自動テストの終了処理を行います。 119 //! 120 //! NW_AUTOTESTが定義されていない場合は何も行われません。 121 //--------------------------------------------------------------------------- FinalizeAutoTest()122 static void FinalizeAutoTest() 123 { 124 #if defined(NW_AUTO_TEST) 125 nw::ut::SafeDestroy(s_AutoTester); 126 #endif 127 } 128 129 //--------------------------------------------------------------------------- 130 //! @brief 自動テストのフレームを進めます。 131 //--------------------------------------------------------------------------- AdvanceAutoTestFrame()132 static void AdvanceAutoTestFrame() 133 { 134 #if defined(NW_AUTO_TEST) 135 NW_ASSERT(s_AutoTester); 136 s_AutoTester->AdvanceFrame(); 137 #endif 138 if (!s_SilentMode) 139 { 140 if (s_ProfileCallCount % NW_PROFILE_OUTPUT_INTERVAL == 0) 141 { 142 NW_DUMP_PROFILE(); 143 } 144 else if (s_ProfileCallCount % NW_PROFILE_OUTPUT_INTERVAL == 1) 145 { 146 NW_CLEAR_PROFILE(); 147 } 148 s_ProfileCallCount++; 149 } 150 } 151 152 //@} 153 154 //===================== 155 //! @name メモリリーク検出 156 //@{ 157 158 //--------------------------------------------------------------------------- 159 //! @brief メモリリークの検出機能をリセットします。 160 //! 161 //! この関数が実行されると、その時点でのメモリ使用量を記憶します。 162 //! メモリリークを検出するためには TestMemoryLeak() 関数を実行してください。 163 //! 164 //! この関数を複数回実行すると、最後の実行のみが有効になります。 165 //! 166 //! @param[in] deviceAllocator 検出対象のデバイスメモリアロケータです。 167 //! @param[in] particleAllocator 検出対象のパーティクルメモリアロケータです。 168 //--------------------------------------------------------------------------- 169 static void ResetMemoryLeakTester(nw::demo::DemoAllocator * deviceAllocator,nw::demo::DemoAllocator * particleAllocator)170 ResetMemoryLeakTester( 171 nw::demo::DemoAllocator* deviceAllocator, 172 nw::demo::DemoAllocator* particleAllocator 173 ) 174 { 175 s_DeviceMemoryFreeSize = deviceAllocator->GetFreeSize(); 176 if (particleAllocator) 177 { 178 s_ParticleMemoryFreeSize = particleAllocator->GetFreeSize(); 179 } 180 } 181 182 //--------------------------------------------------------------------------- 183 //! @brief メモリリークを検出します。 184 //! 185 //! 最後に ResetMemoryLeakTester() が実行されたときとメモリ使用量を比べます。 186 //! メモリ使用量が ResetMemoryLeakTester() 実行時と一致しない場合はヒープのダンプを出力します。 187 //! 188 //! @param[in] deviceAllocator 検出対象のデバイスメモリアロケータです。 189 //! @param[in] particleAllocator 検出対象のパーティクルメモリアロケータです。 190 //! 191 //! @return メモリ使用量が ResetMemoryLeakTester() 実行時と一致する場合は true を、そうでない場合は false を返します。 192 //--------------------------------------------------------------------------- 193 static bool TestMemoryLeak(nw::demo::DemoAllocator * deviceAllocator,nw::demo::DemoAllocator * particleAllocator)194 TestMemoryLeak( 195 nw::demo::DemoAllocator* deviceAllocator, 196 nw::demo::DemoAllocator* particleAllocator 197 ) 198 { 199 bool result = true; 200 201 s32 mainLeakSize = s_DeviceMemoryFreeSize - deviceAllocator->GetFreeSize(); 202 s32 particleLeakSize = 0; 203 if (particleAllocator) 204 { 205 particleLeakSize = s_ParticleMemoryFreeSize - particleAllocator->GetFreeSize(); 206 } 207 208 if (!s_SilentMode) 209 { 210 if (mainLeakSize) 211 { 212 NW_DEV_LOG( 213 "######### Device Memory Leak Detected !! (%d bytes)\n", mainLeakSize); 214 deviceAllocator->Dump(); 215 result = false; 216 } 217 if (particleLeakSize) 218 { 219 NW_DEV_LOG( 220 "######### Particle Memory Leak Detected !! (%d bytes)\n", particleLeakSize); 221 particleAllocator->Dump(); 222 result = false; 223 } 224 } 225 226 #if defined(NW_AUTO_TEST) 227 if (s_AutoTester) 228 { 229 s_AutoTester->NotifyMemoryLeak(mainLeakSize, particleLeakSize); 230 } 231 #endif 232 233 return result; 234 } 235 236 //@} 237 238 //===================== 239 //! @name ログ出力制御 240 //@{ 241 242 //--------------------------------------------------------------------------- 243 //! @brief デバッグユーティリティクラスからのログへの出力を無効にします。 244 //! 245 //! isEnabled に true を指定すると、デバッグユーティリティはログへの出力を行わなくなります。 246 //! 247 //! @param isEnabled true を指定すると、ログへの出力を行わなくなります。 248 //--------------------------------------------------------------------------- SetSilentMode(bool isEnabled)249 static void SetSilentMode(bool isEnabled) {s_SilentMode = isEnabled;} 250 251 //@} 252 253 private: 254 static size_t s_DeviceMemoryFreeSize; 255 static size_t s_ParticleMemoryFreeSize; 256 static bool s_IsForceCpuProfilingMode; //!< 強制的に CPU パフォーマンス計測モードにするフラグです。 257 static bool s_SilentMode; //!< ログへの出力を止めます。 258 static int s_ProfileCallCount; 259 260 #if defined(NW_AUTO_TEST) 261 class AutoTester 262 { 263 public: 264 //! @brief 自動テスターを生成します。 265 static AutoTester* Create( 266 os::IAllocator* allocator, 267 os::IAllocator* deviceAllocator 268 ); 269 270 //! @brief 自動テスターを初期化します。 271 //! 272 //! Host IO を使用し、PC 側の自動テスターとの接続を試みます。 273 //! 接続に成功し、カスタムテストのシナリオを受信できれば、カスタムテストの初期化を行います。 274 //! 接続できなければ再試行することなく接続処理を終了し、デフォルトテストの初期化を行います。 275 //! そのため、カスタムテストを実行するためには、この関数が実行されるまでに PC 側のテスターを 276 //! 待機状態にしておく必要があります。 277 //! 278 //! needCustom に true を指定すると、カスタムテストの初期化に成功するまで PC 側への接続を試行し続けます。 279 //! それまで制御は戻りません。 280 //! 281 //! @param[in] channelNumber PC 側の自動テスターと接続するための Host IO のチャンネル番号です。 282 //! @param[in] needCustom カスタムテストを必ず実行する場合は true を指定します。 283 //! 284 //! @return カスタムテストが初期化されたら正の値を、デフォルトテストが初期化されたら 0 を、初期化に失敗したら負の値を返します。 285 int Initialize( 286 s32 channelNumber, 287 bool needCustom, 288 nw::demo::RenderSystem** renderSystem, 289 const u32* correctHashDisplay0, 290 const u32* correctHashDisplay1 291 ); 292 293 //! @brief 自動テスターの終了処理を行います。 294 void Finalize(); 295 296 //! @brief 自動テスターを破棄します。 297 void Destroy(); 298 299 //! @brief テストのフレームを進めます。 300 void AdvanceFrame(); 301 302 //! @brief メモリリークの検出結果を PC に通知します。 303 //! 304 //! カスタムテスト中であればメモリリーク情報のパケットを送信します。 305 //! 306 //! @param deviceLeakSize デバイスメモリのリーク量です。 307 //! @param particleLeakSize パーティクルメモリのリーク量です。 308 void NotifyMemoryLeak(s32 deviceLeakSize, s32 particleLeakSize); 309 310 private: 311 //! テストシナリオのイベント種です。 312 enum EventType 313 { 314 EVENT_SCREENSHOT = 1, //!< スクリーンショットの撮影と送信です。 315 EVENT_SET_PAD_STATUS, //!< デモパッドの状態指定です。 316 EVENT_BEACON, //!< ビーコン送信です。 317 EVENT_SEND_LOAD_METER, //!< 負荷情報の送信です。 318 EVENT_RESET_LOAD_METER, //!< 負荷情報のリセットです。 319 EVENT_TEST_DONE, //!< テスト完了パケットの送信です。 320 EVENT_SWITCH_CPU_PROFILING_MODE //!< CPU パフォーマンス計測モードの切り替えです。 321 }; 322 323 struct ScreenshotParam 324 { 325 enum DisplayFlag 326 { 327 DISPLAY_0 = 1, 328 DISPLAY_0_EXT, 329 DISPLAY_1, 330 DISPLAY_0_BOTH, 331 DISPLAY_ALL 332 }; 333 s32 display; 334 u32 hash[5]; // すべて 0 ならテストを行いません。 335 }; 336 337 struct SetPadStatusParam 338 { 339 u32 padStatus; 340 }; 341 342 struct BeaconParam 343 { 344 }; 345 346 struct SendLoadMeterParam 347 { 348 }; 349 350 struct ResetLoadMeterParam 351 { 352 }; 353 354 struct SwitchCpuProfilingModeParam 355 { 356 s32 isModeEnabled; 357 }; 358 359 struct TestEvent 360 { 361 s32 frameCount; 362 EventType eventType; 363 364 union 365 { 366 ScreenshotParam screenshot; 367 SetPadStatusParam setPadStatus; 368 BeaconParam beacon; 369 SendLoadMeterParam sendLoadMeter; 370 ResetLoadMeterParam resetLoadMeter; 371 SwitchCpuProfilingModeParam switchCpuProfilingMode; 372 } param; 373 }; 374 375 // 受信パケットの構造体です。 376 377 //! @brief テスト情報パケットのヘッダです。 378 struct TestInfoHeader 379 { 380 s32 packetType; 381 s32 eventCount; 382 char programName[64]; 383 enum { PACKET_TYPE_ID = 0x213FEB92 }; 384 TestInfoHeaderTestInfoHeader385 TestInfoHeader() 386 : packetType(PACKET_TYPE_ID), 387 eventCount(0) 388 {} 389 }; 390 391 //! @brief シナリオパケットのヘッダです。 392 struct ScenarioHeader 393 { 394 s32 packetType; 395 s32 eventCount; 396 enum { PACKET_TYPE_ID = 0x6794C4C8 }; 397 ScenarioHeaderScenarioHeader398 ScenarioHeader() 399 : packetType(PACKET_TYPE_ID), 400 eventCount(0) 401 {} 402 403 }; 404 405 // 送信パケットの構造体です。 406 407 //! @brief スクリーンショットパケットのヘッダです。 408 struct ScreenshotHeader 409 { 410 s32 packetType; 411 s32 frameCount; 412 s32 width; 413 s32 height; 414 s32 display; 415 416 enum { PACKET_TYPE_ID = 0x23848aa6 }; 417 ScreenshotHeaderScreenshotHeader418 ScreenshotHeader() 419 : packetType(PACKET_TYPE_ID), 420 frameCount(0), 421 width(0), 422 height(0) 423 {} 424 }; 425 426 //! @brief ビーコンパケットのヘッダです。 427 struct BeaconHeader 428 { 429 s32 packetType; 430 s32 frameCount; 431 432 enum { PACKET_TYPE_ID = 0x9538a79a }; 433 BeaconHeaderBeaconHeader434 BeaconHeader() 435 : packetType(PACKET_TYPE_ID), 436 frameCount(0) 437 {} 438 }; 439 440 //! @brief 負荷情報パケットのヘッダです。 441 struct LoadMeterHeader 442 { 443 s32 packetType; 444 s32 frameCount; 445 446 enum { PACKET_TYPE_ID = 0xc57c557 }; 447 LoadMeterHeaderLoadMeterHeader448 LoadMeterHeader() 449 : packetType(PACKET_TYPE_ID), 450 frameCount(0) 451 {} 452 }; 453 454 //! @brief 負荷情報パケットのデータ構造です。 455 struct LoadMeterData 456 { 457 s32 callCount; 458 s32 cpuTime; 459 s32 gpuTime; 460 s32 otherGpuTime; 461 s32 cmdSize; 462 }; 463 464 //! @brief メモリリーク情報パケットのヘッダです。 465 struct MemoryLeakHeader 466 { 467 s32 packetType; 468 s32 frameCount; 469 470 enum { PACKET_TYPE_ID = 0x4F1B0AD2 }; 471 MemoryLeakHeaderMemoryLeakHeader472 MemoryLeakHeader() 473 : packetType(PACKET_TYPE_ID), 474 frameCount(0) 475 {} 476 }; 477 478 //! @brief メモリリーク情報パケットのデータ構造です。 479 struct MemoryLeakData 480 { 481 s32 deviceLeakSize; 482 s32 particleLeakSize; 483 }; 484 485 //! @brief テスト終了通知パケットのヘッダです。 486 struct DoneHeader 487 { 488 s32 packetType; 489 s32 frameCount; 490 491 enum { PACKET_TYPE_ID = 0x916bbe7 }; 492 DoneHeaderDoneHeader493 DoneHeader() 494 : packetType(PACKET_TYPE_ID), 495 frameCount(0) 496 {} 497 }; 498 499 AutoTester( 500 os::IAllocator* allocator, 501 os::IAllocator* deviceAllocator 502 ); 503 ~AutoTester(); 504 505 void SendScreenshot(const ScreenshotParam& param); 506 void SetPadStatus(const SetPadStatusParam& param); 507 void SendBeacon(const BeaconParam& param); 508 void SendLoadMeter(const SendLoadMeterParam& param); 509 void NotifyDone(); 510 void SwitchCpuProfilingMode(const SwitchCpuProfilingModeParam& param); 511 512 os::IAllocator* m_Allocator; 513 os::IAllocator* m_DeviceAllocator; 514 515 nw::dev::ScreenshotManager* m_ScreenshotManager; 516 517 nw::demo::HioPacketChannel* m_HioPacketChannel; 518 519 s32 m_FrameCount; 520 521 nw::ut::MoveArray<TestEvent> m_Scenario; 522 nw::ut::MoveArray<TestEvent>::iterator m_CurrentEvent; 523 524 nw::demo::RenderSystem** m_RenderSystem; 525 }; 526 527 static AutoTester* s_AutoTester; 528 #else 529 class AutoTester 530 { 531 public: Create(os::IAllocator *,os::IAllocator *)532 static AutoTester* Create(os::IAllocator*,os::IAllocator*){return NULL;} Initialize(s32,bool,nw::demo::RenderSystem **,const u32 *,const u32 *)533 int Initialize(s32,bool,nw::demo::RenderSystem**,const u32*,const u32*){return -1;} Finalize()534 void Finalize(){} Destroy()535 void Destroy(){} AdvanceFrame()536 void AdvanceFrame(){} NotifyMemoryLeak(s32,s32)537 void NotifyMemoryLeak(s32, s32){} 538 }; 539 #endif 540 }; 541 542 //@} 543 544 namespace internal 545 { 546 547 548 //! @details :private 549 class DemoTestLoop 550 { 551 private: 552 static const int NW_PROFILE_MAX_REPORT = 60; 553 public: DemoTestLoop(nw::demo::DemoAllocator * deviceAllocator,nw::demo::DemoAllocator * particleAllocator,nw::demo::RenderSystem ** renderSystem,const u32 * hash1,const u32 * hash2)554 DemoTestLoop( 555 nw::demo::DemoAllocator* deviceAllocator, 556 nw::demo::DemoAllocator* particleAllocator, 557 nw::demo::RenderSystem** renderSystem, 558 const u32* hash1, 559 const u32* hash2 560 ) 561 : m_DeviceAllocator(deviceAllocator), 562 m_ParticleAllocator(particleAllocator), 563 m_ContinueFlag(true) 564 { 565 nw::demo::DebugUtility::InitializeAutoTest(m_DeviceAllocator, m_DeviceAllocator, renderSystem, hash1, hash2); 566 NW_INITIALIZE_PROFILE(NW_PROFILE_MAX_REPORT, m_DeviceAllocator); 567 #if defined(NW_DEBUG_CHECK_MEMORY_LEAK) 568 nw::demo::DebugUtility::ResetMemoryLeakTester(m_DeviceAllocator, m_ParticleAllocator); 569 #endif 570 } ~DemoTestLoop()571 ~DemoTestLoop() 572 { 573 NW_FINALIZE_PROFILE(m_DeviceAllocator); 574 nw::demo::DebugUtility::FinalizeAutoTest(); 575 } Continue()576 void Continue() { 577 #if defined(NW_DEBUG_CHECK_MEMORY_LEAK) 578 nw::demo::DebugUtility::TestMemoryLeak(m_DeviceAllocator, m_ParticleAllocator); 579 #else 580 m_ContinueFlag = false; 581 #endif 582 } IsContinuing()583 bool IsContinuing() { 584 #if defined(NW_DEBUG_CHECK_MEMORY_LEAK) 585 return ! ::nw::demo::internal::IsTerminatingImpl(); 586 #else 587 return m_ContinueFlag; 588 #endif 589 } 590 private: 591 nw::demo::DemoAllocator* m_DeviceAllocator; 592 nw::demo::DemoAllocator* m_ParticleAllocator; 593 bool m_ContinueFlag; 594 }; 595 596 } // namespace internal 597 598 //============================================================================ 599 //! @name デモプログラム支援 600 //@{ 601 602 #define NW_DEMO_TEST_LOOP(deviceAllocator, particleAllocator, renderSystem) \ 603 for ( \ 604 nw::demo::internal::DemoTestLoop demoTestLoop(deviceAllocator, particleAllocator, renderSystem, NULL, NULL) ; \ 605 demoTestLoop.IsContinuing() ; \ 606 demoTestLoop.Continue() ) 607 608 //@} 609 610 } // namespace demo 611 } // namespace nw 612 613 #endif // NW_DEMO_DEBUGUTILITY_H_ 614