/*---------------------------------------------------------------------------* Project: NintendoWare File: demo_CommandListSwapper.cpp Copyright (C)2009-2011 Nintendo/HAL Laboratory, Inc. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo and/or its licensed developers and are protected by national and international copyright laws. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. The content herein is highly confidential and should be handled accordingly. $Revision: 31311 $ *---------------------------------------------------------------------------*/ #include #include #include #include namespace nw { namespace demo { CommandListSwapper* CommandListSwapper::s_CommandListSwapper = NULL; const s64 CommandListSwapper::COMMAND_LIST_WAIT_TIME_OUT = 500; //---------------------------------------- CommandListSwapper* CommandListSwapper::Create( os::IAllocator* allocator, CommandListSwapper::Description& description) { void* memory = allocator->Alloc(sizeof(CommandListSwapper)); NW_NULL_ASSERT(memory); CommandListSwapper* swapper = new(memory) CommandListSwapper(allocator, description); return swapper; } //---------------------------------------- CommandListSwapper::CommandListSwapper( os::IAllocator* allocator, CommandListSwapper::Description& description) : m_Allocator(allocator), m_CommandLists(description.commandListCount, allocator), m_BoundIndex(0), m_RunningIndex(0), m_IsRunning(false), m_GpuProfilingEntries(description.maxGpuProfilingEntryCount, allocator), m_GpuProfilingResults(description.maxGpuProfilingEntryCount, allocator), m_ReusableCommandLists(), m_ReusableBufferOffset(0), m_ReusableBufferSize(0), m_ReusableRequestId(0), m_ReusableRequestSize(0), m_DumpCommandListBuffer(NULL) { m_CommandLists.resize(description.commandListCount); CommandListArray::iterator listEnd = m_CommandLists.end(); for (CommandListArray::iterator commandList = m_CommandLists.begin(); commandList != listEnd; ++commandList) { nngxGenCmdlists(1, &(*commandList)); nngxBindCmdlist(*commandList); nngxCmdlistStorage(description.bufferSize, description.requestCount); nngxSetCmdlistParameteri(NN_GX_CMDLIST_RUN_MODE, NN_GX_CMDLIST_SERIAL_RUN); nngxSetCmdlistCallback(CommandListSwapper::CommandListCallback); } if (description.reusableBufferSize > 0 && description.reusableRequestCount > 0) { m_ReusableCommandLists = CommandListArray(description.commandListCount, allocator), m_ReusableCommandLists.resize(description.commandListCount); CommandListArray::iterator cacheEnd = m_ReusableCommandLists.end(); for (CommandListArray::iterator commandList = m_ReusableCommandLists.begin(); commandList != cacheEnd; ++commandList) { nngxGenCmdlists(1, &(*commandList)); nngxBindCmdlist(*commandList); nngxCmdlistStorage(description.reusableBufferSize, description.reusableRequestCount); nngxSetCmdlistParameteri(NN_GX_CMDLIST_RUN_MODE, NN_GX_CMDLIST_SERIAL_RUN); } } m_DumpCommandListBuffer = static_cast(m_Allocator->Alloc(description.bufferSize)); nn::os::Tick timeoutTick = static_cast(nn::fnd::TimeSpan::FromMilliSeconds(COMMAND_LIST_WAIT_TIME_OUT)); nngxSetTimeout(static_cast(timeoutTick), CommandListSwapper::TimeoutWaitCommandListDone); s_CommandListSwapper = this; } //---------------------------------------- void CommandListSwapper::Destroy() { os::IAllocator* allocator = this->m_Allocator; NW_NULL_ASSERT(m_DumpCommandListBuffer); os::SafeFree(m_DumpCommandListBuffer, allocator); void* memory = static_cast(this); this->~CommandListSwapper(); allocator->Free(memory); } //---------------------------------------- void CommandListSwapper::Bind() { nngxBindCmdlist(this->GetCommandListId()); } //---------------------------------------- void CommandListSwapper::RunAsync() { m_GpuProfilingEntries.swap( m_GpuProfilingResults ); m_RunningIndex = m_BoundIndex; m_IsRunning = true; if (! nw::demo::DebugUtility::IsCpuProfilingMode()) { nngxRunCmdlist(); } } //---------------------------------------- void CommandListSwapper::Swap() { ++this->m_BoundIndex; if (this->m_CommandLists.size() <= this->m_BoundIndex) { this->m_BoundIndex = 0; } if (this->m_CommandLists.size() > 1) { ResetGpuProfiling(); } } //---------------------------------------- void CommandListSwapper::WaitDone() { if (!m_IsRunning) { return; } nngxBindCmdlist(m_CommandLists[m_RunningIndex]); nngxSplitDrawCmdlist(); nngxWaitCmdlistDone(); nngxStopCmdlist(); nngxClearCmdlist(); Bind(); m_IsRunning = false; NW_GL_ASSERT(); CalcGpuProfilingCostTime(); if (this->m_CommandLists.size() == 1) { ResetGpuProfiling(); } } //---------------------------------------- void CommandListSwapper::ResetGpuProfiling() { m_GpuProfilingEntries.clear(); } //---------------------------------------- s32 CommandListSwapper::AddGpuProfilingStartPoint(bool IsInTotal) { if (!m_GpuProfilingEntries.push_back( GpuProfilingEntry() )) { return -1; } GpuProfilingEntry& gpuProfilingEntry = m_GpuProfilingEntries.back(); GLuint id = RegisterCallback(); gpuProfilingEntry.beginId = id; gpuProfilingEntry.isInTotal = IsInTotal; return m_GpuProfilingEntries.size() - 1; } //---------------------------------------- void CommandListSwapper::SetGpuProfilingEndPoint(u32 profilingId) { NW_ASSERT(profilingId < m_GpuProfilingEntries.size()); m_GpuProfilingEntries[profilingId].endId = RegisterCallback(); } //---------------------------------------- GLuint CommandListSwapper::RegisterCallback() { GLint requestCount = 0; nngxGetCmdlistParameteri(NN_GX_CMDLIST_USED_REQCOUNT, &requestCount); if (requestCount == 0) { // コマンドリクエストが無い場合はコマンドバッファを区切ることでコマンドリクエストを追加する。 nngxSplitDrawCmdlist(); nngxGetCmdlistParameteri(NN_GX_CMDLIST_USED_REQCOUNT, &requestCount); } nngxEnableCmdlistCallback( requestCount ); return requestCount; } //---------------------------------------- void CommandListSwapper::CalcGpuProfilingCostTime() { GpuProfilingEntryArray::iterator end = m_GpuProfilingResults.end(); for (GpuProfilingEntryArray::iterator gpuProfilingEntry = m_GpuProfilingResults.begin(); gpuProfilingEntry != end; ++gpuProfilingEntry) { const s64 span = nn::os::Tick(gpuProfilingEntry->endTick - gpuProfilingEntry->beginTick) .ToTimeSpan() .GetMicroSeconds(); gpuProfilingEntry->costTime = static_cast(span) / 1000.0f; } } //---------------------------------------- f32 CommandListSwapper::GetGpuProfilingCostTime(u32 profilingId) { if (profilingId < m_GpuProfilingResults.size()) { return m_GpuProfilingResults[profilingId].costTime; } else { return 0.0f; } } //---------------------------------------- f32 CommandListSwapper::GetGpuProfilingTotalCostTime() { f32 total = 0.0f; GpuProfilingEntryArray::iterator end = m_GpuProfilingResults.end(); for (GpuProfilingEntryArray::iterator gpuProfilingEntry = m_GpuProfilingResults.begin(); gpuProfilingEntry != end; ++gpuProfilingEntry) { if (gpuProfilingEntry->isInTotal) { total += gpuProfilingEntry->costTime; } } return total; } //---------------------------------------- void CommandListSwapper::SetGpuProfilingTick(GLint id) { s64 tick = static_cast(nn::os::Tick::GetSystemCurrent()); size_t size = m_GpuProfilingResults.size(); for (u32 i = 0 ; i < size ; ++i) { if (m_GpuProfilingResults[i].beginId == id) { m_GpuProfilingResults[i].beginTick = tick; } if (m_GpuProfilingResults[i].endId == id) { m_GpuProfilingResults[i].endTick = tick; } } } //---------------------------------------- void CommandListSwapper::CommandListCallback(GLint id) { if ( s_CommandListSwapper ) { s_CommandListSwapper->SetGpuProfilingTick(id); } } //---------------------------------------- void CommandListSwapper::StartCommandSave() { NW_ASSERT( !m_ReusableCommandLists.empty() ); nngxBindCmdlist(m_ReusableCommandLists[m_BoundIndex]); nngxClearCmdlist(); nngxStartCmdlistSave(); NW_GL_ASSERT(); } //---------------------------------------- void CommandListSwapper::EndCommandSave() { NW_ASSERT( !m_ReusableCommandLists.empty() ); nngxSplitDrawCmdlist(); NW_GL_ASSERT(); nngxStopCmdlistSave( &m_ReusableBufferOffset, &m_ReusableBufferSize, &m_ReusableRequestId, &m_ReusableRequestSize); NW_GL_ASSERT(); Bind(); } //---------------------------------------- void CommandListSwapper::ReuseCommand(bool isCopyBuffer) { NW_ASSERT( !m_ReusableCommandLists.empty() ); nngxUseSavedCmdlist( m_ReusableCommandLists[m_BoundIndex], m_ReusableBufferOffset, m_ReusableBufferSize, m_ReusableRequestId, m_ReusableRequestSize, 0, isCopyBuffer ? GL_TRUE : GL_FALSE); NW_GL_ASSERT(); } //---------------------------------------- int CommandListSwapper::GetCommandBufferSize() const { GLint bufferSize; nngxGetCmdlistParameteri(NN_GX_CMDLIST_USED_BUFSIZE, &bufferSize); NW_GL_ASSERT(); return static_cast(bufferSize); } //---------------------------------------- int CommandListSwapper::GetReusableCommandBufferSize() const { GLint bufferSize; GLint boundId; nngxGetCmdlistParameteri(NN_GX_CMDLIST_BINDING, &boundId); nngxBindCmdlist(m_ReusableCommandLists[m_BoundIndex]); nngxGetCmdlistParameteri(NN_GX_CMDLIST_USED_BUFSIZE, &bufferSize); nngxBindCmdlist(boundId); NW_GL_ASSERT(); return static_cast(bufferSize); } //---------------------------------------- void CommandListSwapper::TimeoutWaitCommandListDone() { if ( s_CommandListSwapper ) { s_CommandListSwapper->DumpCommandListParameter(); } } //---------------------------------------- void CommandListSwapper::DumpCommandListParameter() { NW_DEV_LOG("[CommandListSwapper::WaitDone] nngxWaitCmdlistDone Timeout!\n"); NW_DEV_LOG("(Timeout: %lld [msec])\n", COMMAND_LIST_WAIT_TIME_OUT); // コマンドリストの実行状態です。 s32 paramIsRunning; nngxGetCmdlistParameteri(NN_GX_CMDLIST_IS_RUNNING, ¶mIsRunning); NW_DEV_LOG("Running Command List : %s\n", (paramIsRunning ? "true" : "false")); // カレントにバインドされているコマンドリストオブジェクトのIDです。 s32 paramBinding; nngxGetCmdlistParameteri(NN_GX_CMDLIST_BINDING, ¶mBinding); NW_DEV_LOG("Binding ID : %d\n", paramBinding); // 3Dコマンドバッファの先頭アドレスです。 s32 paramBufAddr; nngxGetCmdlistParameteri(NN_GX_CMDLIST_TOP_BUFADDR, ¶mBufAddr); NW_DEV_LOG("Top address of 3D command buffer : 0x%08x\n", paramBufAddr); // コマンドリクエストのリクエストキュー用データ領域の先頭アドレスです。 s32 paramRequestAddr; nngxGetCmdlistParameteri(NN_GX_CMDLIST_TOP_REQADDR, ¶mRequestAddr); NW_DEV_LOG("Top address of command request buffer : 0x%08x\n", paramRequestAddr); // 3Dコマンドバッファの最大サイズです。 s32 paramMaxBufSize; nngxGetCmdlistParameteri(NN_GX_CMDLIST_MAX_BUFSIZE, ¶mMaxBufSize); NW_DEV_LOG("Max 3D command buffer size : %d [byte(s)]\n", paramMaxBufSize); // コマンドリクエスト最大サイズです。 s32 paramMaxRequestCount; nngxGetCmdlistParameteri(NN_GX_CMDLIST_MAX_REQCOUNT, ¶mMaxRequestCount); NW_DEV_LOG("Max command request count : %d\n", paramMaxRequestCount); // 蓄積された3Dコマンドバッファのバイトサイズです。 int paramUsedBufSize; nngxGetCmdlistParameteri(NN_GX_CMDLIST_USED_BUFSIZE, ¶mUsedBufSize); NW_DEV_LOG("Used buffer size : %d [byte(s)]\n", paramUsedBufSize); // 蓄積されたコマンドリクエストの個数です。 int paramUsedRequestCount; nngxGetCmdlistParameteri(NN_GX_CMDLIST_USED_REQCOUNT, ¶mUsedRequestCount); NW_DEV_LOG("Used command request count : %d\n", paramUsedRequestCount); // 実行済みの3Dコマンドバッファのバイトサイズです。 int paramRunBufSize; nngxGetCmdlistParameteri(NN_GX_CMDLIST_RUN_BUFSIZE, ¶mRunBufSize); NW_DEV_LOG("Run buffer size : %d [byte(s)]\n", paramRunBufSize); // 実行済みのコマンドリクエストの個数です。 int paramRunRequestCount; nngxGetCmdlistParameteri(NN_GX_CMDLIST_RUN_REQCOUNT, ¶mRunRequestCount); NW_DEV_LOG("Run command request count : %d\n", paramRunRequestCount); // 次に実行されるコマンドリクエストのコマンドの種類です。 int paramNextRequestType; nngxGetCmdlistParameteri(NN_GX_CMDLIST_NEXT_REQTYPE, ¶mNextRequestType); NW_DEV_LOG("Next command request type : "); switch(paramNextRequestType) { case NN_GX_CMDLIST_REQTYPE_DMA: NW_DEV_LOG("NN_GX_CMDLIST_REQTYPE_DMA\n"); break; case NN_GX_CMDLIST_REQTYPE_RUN3D: NW_DEV_LOG("NN_GX_CMDLIST_REQTYPE_RUN3D\n"); break; case NN_GX_CMDLIST_REQTYPE_FILLMEM: NW_DEV_LOG("NN_GX_CMDLIST_REQTYPE_FILLMEM\n"); break; case NN_GX_CMDLIST_REQTYPE_POSTTRANS: NW_DEV_LOG("NN_GX_CMDLIST_REQTYPE_POSTTRANS\n"); break; case NN_GX_CMDLIST_REQTYPE_COPYTEX: NW_DEV_LOG("NN_GX_CMDLIST_REQTYPE_COPYTEX\n"); break; default: NW_DEV_LOG("unknown\n"); break; } // ハードウェアの状態を示す32ビットのデータです。 s32 paramState; nngxGetCmdlistParameteri(NN_GX_CMDLIST_HW_STATE, ¶mState); NW_DEV_LOG("Hardware state : 0x%08x\n", paramState); NW_DEV_LOG("\n"); NW_DEV_LOG("Dump run command list:"); s32 size = nngxExportCmdlist(paramBinding, 0, paramRunBufSize, 0, paramRunRequestCount, 0, 0); nngxExportCmdlist(paramBinding, 0, paramRunBufSize, 0, paramRunRequestCount, size, m_DumpCommandListBuffer); for (int i = 0; i < size / 4; ++i) { if (i % 8 == 0) { NW_DEV_LOG("\n"); } NW_DEV_LOG( "0x%02x%02x%02x%02x ", m_DumpCommandListBuffer[i * 4 + 0], m_DumpCommandListBuffer[i * 4 + 1], m_DumpCommandListBuffer[i * 4 + 2], m_DumpCommandListBuffer[i * 4 + 3] ); } NW_DEV_LOG("\n"); } } // demo } // nw