1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     demo_CommandListSwapper.cpp
4 
5   Copyright (C)2009-2011 Nintendo/HAL Laboratory, Inc.  All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain proprietary
8   information of Nintendo and/or its licensed developers and are protected by
9   national and international copyright laws. They may not be disclosed to third
10   parties or copied or duplicated in any form, in whole or in part, without the
11   prior written consent of Nintendo.
12 
13   The content herein is highly confidential and should be handled accordingly.
14 
15   $Revision: 31311 $
16  *---------------------------------------------------------------------------*/
17 
18 #include <nw/demo/demo_CommandListSwapper.h>
19 #include <nw/demo/demo_DebugUtility.h>
20 
21 #include <nw/os/os_Memory.h>
22 #include <nn/os/os_Tick.h>
23 
24 namespace nw
25 {
26 namespace demo
27 {
28 
29 CommandListSwapper* CommandListSwapper::s_CommandListSwapper = NULL;
30 const s64 CommandListSwapper::COMMAND_LIST_WAIT_TIME_OUT = 500;
31 
32 //----------------------------------------
33 CommandListSwapper*
Create(os::IAllocator * allocator,CommandListSwapper::Description & description)34 CommandListSwapper::Create(
35     os::IAllocator* allocator,
36     CommandListSwapper::Description& description)
37 {
38     void* memory = allocator->Alloc(sizeof(CommandListSwapper));
39 
40     NW_NULL_ASSERT(memory);
41 
42     CommandListSwapper* swapper = new(memory) CommandListSwapper(allocator, description);
43 
44     return swapper;
45 }
46 
47 //----------------------------------------
CommandListSwapper(os::IAllocator * allocator,CommandListSwapper::Description & description)48 CommandListSwapper::CommandListSwapper(
49     os::IAllocator* allocator,
50     CommandListSwapper::Description& description)
51 : m_Allocator(allocator),
52   m_CommandLists(description.commandListCount, allocator),
53   m_BoundIndex(0),
54   m_RunningIndex(0),
55   m_IsRunning(false),
56   m_GpuProfilingEntries(description.maxGpuProfilingEntryCount, allocator),
57   m_GpuProfilingResults(description.maxGpuProfilingEntryCount, allocator),
58   m_ReusableCommandLists(),
59   m_ReusableBufferOffset(0),
60   m_ReusableBufferSize(0),
61   m_ReusableRequestId(0),
62   m_ReusableRequestSize(0),
63   m_DumpCommandListBuffer(NULL)
64 {
65     m_CommandLists.resize(description.commandListCount);
66     CommandListArray::iterator listEnd = m_CommandLists.end();
67     for (CommandListArray::iterator commandList = m_CommandLists.begin();
68         commandList != listEnd; ++commandList)
69     {
70         nngxGenCmdlists(1, &(*commandList));
71         nngxBindCmdlist(*commandList);
72         nngxCmdlistStorage(description.bufferSize, description.requestCount);
73         nngxSetCmdlistParameteri(NN_GX_CMDLIST_RUN_MODE, NN_GX_CMDLIST_SERIAL_RUN);
74         nngxSetCmdlistCallback(CommandListSwapper::CommandListCallback);
75     }
76 
77     if (description.reusableBufferSize > 0 && description.reusableRequestCount > 0)
78     {
79         m_ReusableCommandLists = CommandListArray(description.commandListCount, allocator),
80         m_ReusableCommandLists.resize(description.commandListCount);
81         CommandListArray::iterator cacheEnd = m_ReusableCommandLists.end();
82         for (CommandListArray::iterator commandList = m_ReusableCommandLists.begin();
83             commandList != cacheEnd; ++commandList)
84         {
85             nngxGenCmdlists(1, &(*commandList));
86             nngxBindCmdlist(*commandList);
87             nngxCmdlistStorage(description.reusableBufferSize, description.reusableRequestCount);
88             nngxSetCmdlistParameteri(NN_GX_CMDLIST_RUN_MODE, NN_GX_CMDLIST_SERIAL_RUN);
89         }
90     }
91 
92     m_DumpCommandListBuffer = static_cast<u8*>(m_Allocator->Alloc(description.bufferSize));
93     nn::os::Tick timeoutTick =
94         static_cast<nn::os::Tick>(nn::fnd::TimeSpan::FromMilliSeconds(COMMAND_LIST_WAIT_TIME_OUT));
95     nngxSetTimeout(static_cast<s64>(timeoutTick), CommandListSwapper::TimeoutWaitCommandListDone);
96 
97     s_CommandListSwapper = this;
98 }
99 
100 //----------------------------------------
101 void
Destroy()102 CommandListSwapper::Destroy()
103 {
104     os::IAllocator* allocator = this->m_Allocator;
105 
106     NW_NULL_ASSERT(m_DumpCommandListBuffer);
107 
108     os::SafeFree(m_DumpCommandListBuffer, allocator);
109 
110     void* memory = static_cast<void*>(this);
111     this->~CommandListSwapper();
112 
113     allocator->Free(memory);
114 }
115 
116 //----------------------------------------
117 void
Bind()118 CommandListSwapper::Bind()
119 {
120     nngxBindCmdlist(this->GetCommandListId());
121 }
122 //----------------------------------------
123 void
RunAsync()124 CommandListSwapper::RunAsync()
125 {
126     m_GpuProfilingEntries.swap( m_GpuProfilingResults );
127 
128     m_RunningIndex = m_BoundIndex;
129     m_IsRunning = true;
130 
131     if (! nw::demo::DebugUtility::IsCpuProfilingMode())
132     {
133         nngxRunCmdlist();
134     }
135 }
136 
137 //----------------------------------------
138 void
Swap()139 CommandListSwapper::Swap()
140 {
141     ++this->m_BoundIndex;
142     if (this->m_CommandLists.size() <= this->m_BoundIndex)
143     {
144         this->m_BoundIndex = 0;
145     }
146     if (this->m_CommandLists.size() > 1)
147     {
148         ResetGpuProfiling();
149     }
150 }
151 
152 //----------------------------------------
153 void
WaitDone()154 CommandListSwapper::WaitDone()
155 {
156     if (!m_IsRunning)
157     {
158         return;
159     }
160 
161     nngxBindCmdlist(m_CommandLists[m_RunningIndex]);
162     nngxSplitDrawCmdlist();
163     nngxWaitCmdlistDone();
164     nngxStopCmdlist();
165     nngxClearCmdlist();
166     Bind();
167     m_IsRunning = false;
168 
169     NW_GL_ASSERT();
170 
171     CalcGpuProfilingCostTime();
172     if (this->m_CommandLists.size() == 1)
173     {
174         ResetGpuProfiling();
175     }
176 }
177 
178 //----------------------------------------
179 void
ResetGpuProfiling()180 CommandListSwapper::ResetGpuProfiling()
181 {
182     m_GpuProfilingEntries.clear();
183 }
184 
185 //----------------------------------------
186 s32
AddGpuProfilingStartPoint(bool IsInTotal)187 CommandListSwapper::AddGpuProfilingStartPoint(bool IsInTotal)
188 {
189     if (!m_GpuProfilingEntries.push_back( GpuProfilingEntry() ))
190     {
191         return -1;
192     }
193 
194     GpuProfilingEntry& gpuProfilingEntry = m_GpuProfilingEntries.back();
195 
196     GLuint id = RegisterCallback();
197 
198     gpuProfilingEntry.beginId = id;
199     gpuProfilingEntry.isInTotal = IsInTotal;
200 
201     return m_GpuProfilingEntries.size() - 1;
202 }
203 
204 //----------------------------------------
205 void
SetGpuProfilingEndPoint(u32 profilingId)206 CommandListSwapper::SetGpuProfilingEndPoint(u32 profilingId)
207 {
208     NW_ASSERT(profilingId < m_GpuProfilingEntries.size());
209 
210     m_GpuProfilingEntries[profilingId].endId = RegisterCallback();
211 }
212 
213 //----------------------------------------
214 GLuint
RegisterCallback()215 CommandListSwapper::RegisterCallback()
216 {
217     GLint requestCount = 0;
218     nngxGetCmdlistParameteri(NN_GX_CMDLIST_USED_REQCOUNT, &requestCount);
219     if (requestCount == 0)
220     {
221         // コマンドリクエストが無い場合はコマンドバッファを区切ることでコマンドリクエストを追加する。
222         nngxSplitDrawCmdlist();
223         nngxGetCmdlistParameteri(NN_GX_CMDLIST_USED_REQCOUNT, &requestCount);
224     }
225     nngxEnableCmdlistCallback( requestCount );
226 
227     return requestCount;
228 }
229 
230 
231 //----------------------------------------
232 void
CalcGpuProfilingCostTime()233 CommandListSwapper::CalcGpuProfilingCostTime()
234 {
235     GpuProfilingEntryArray::iterator end = m_GpuProfilingResults.end();
236     for (GpuProfilingEntryArray::iterator gpuProfilingEntry = m_GpuProfilingResults.begin();
237         gpuProfilingEntry != end; ++gpuProfilingEntry)
238     {
239         const s64 span =
240             nn::os::Tick(gpuProfilingEntry->endTick - gpuProfilingEntry->beginTick)
241             .ToTimeSpan()
242             .GetMicroSeconds();
243 
244         gpuProfilingEntry->costTime = static_cast<float>(span) / 1000.0f;
245     }
246 }
247 
248 //----------------------------------------
249 f32
GetGpuProfilingCostTime(u32 profilingId)250 CommandListSwapper::GetGpuProfilingCostTime(u32 profilingId)
251 {
252     if (profilingId < m_GpuProfilingResults.size())
253     {
254         return m_GpuProfilingResults[profilingId].costTime;
255     }
256     else
257     {
258         return 0.0f;
259     }
260 }
261 
262 //----------------------------------------
263 f32
GetGpuProfilingTotalCostTime()264 CommandListSwapper::GetGpuProfilingTotalCostTime()
265 {
266     f32 total = 0.0f;
267 
268     GpuProfilingEntryArray::iterator end = m_GpuProfilingResults.end();
269     for (GpuProfilingEntryArray::iterator gpuProfilingEntry = m_GpuProfilingResults.begin();
270         gpuProfilingEntry != end; ++gpuProfilingEntry)
271     {
272         if (gpuProfilingEntry->isInTotal)
273         {
274             total += gpuProfilingEntry->costTime;
275         }
276     }
277 
278     return total;
279 }
280 
281 //----------------------------------------
282 void
SetGpuProfilingTick(GLint id)283 CommandListSwapper::SetGpuProfilingTick(GLint id)
284 {
285     s64 tick = static_cast<s64>(nn::os::Tick::GetSystemCurrent());
286 
287     size_t size = m_GpuProfilingResults.size();
288 
289     for (u32 i = 0 ; i < size ; ++i)
290     {
291         if (m_GpuProfilingResults[i].beginId == id)
292         {
293             m_GpuProfilingResults[i].beginTick = tick;
294         }
295         if (m_GpuProfilingResults[i].endId == id)
296         {
297             m_GpuProfilingResults[i].endTick = tick;
298         }
299     }
300 }
301 
302 //----------------------------------------
303 void
CommandListCallback(GLint id)304 CommandListSwapper::CommandListCallback(GLint id)
305 {
306     if ( s_CommandListSwapper )
307     {
308         s_CommandListSwapper->SetGpuProfilingTick(id);
309     }
310 }
311 
312 //----------------------------------------
313 void
StartCommandSave()314 CommandListSwapper::StartCommandSave()
315 {
316     NW_ASSERT( !m_ReusableCommandLists.empty() );
317 
318     nngxBindCmdlist(m_ReusableCommandLists[m_BoundIndex]);
319     nngxClearCmdlist();
320     nngxStartCmdlistSave();
321     NW_GL_ASSERT();
322 }
323 
324 //----------------------------------------
325 void
EndCommandSave()326 CommandListSwapper::EndCommandSave()
327 {
328     NW_ASSERT( !m_ReusableCommandLists.empty() );
329 
330     nngxSplitDrawCmdlist();
331     NW_GL_ASSERT();
332 
333     nngxStopCmdlistSave(
334         &m_ReusableBufferOffset,
335         &m_ReusableBufferSize,
336         &m_ReusableRequestId,
337         &m_ReusableRequestSize);
338     NW_GL_ASSERT();
339 
340     Bind();
341 }
342 
343 //----------------------------------------
344 void
ReuseCommand(bool isCopyBuffer)345 CommandListSwapper::ReuseCommand(bool isCopyBuffer)
346 {
347     NW_ASSERT( !m_ReusableCommandLists.empty() );
348 
349     nngxUseSavedCmdlist(
350         m_ReusableCommandLists[m_BoundIndex],
351         m_ReusableBufferOffset,
352         m_ReusableBufferSize,
353         m_ReusableRequestId,
354         m_ReusableRequestSize,
355         0,
356         isCopyBuffer ? GL_TRUE : GL_FALSE);
357     NW_GL_ASSERT();
358 }
359 
360 //----------------------------------------
361 int
GetCommandBufferSize() const362 CommandListSwapper::GetCommandBufferSize() const
363 {
364     GLint bufferSize;
365 
366     nngxGetCmdlistParameteri(NN_GX_CMDLIST_USED_BUFSIZE, &bufferSize);
367     NW_GL_ASSERT();
368 
369     return static_cast<int>(bufferSize);
370 }
371 
372 //----------------------------------------
373 int
GetReusableCommandBufferSize() const374 CommandListSwapper::GetReusableCommandBufferSize() const
375 {
376     GLint bufferSize;
377     GLint boundId;
378 
379     nngxGetCmdlistParameteri(NN_GX_CMDLIST_BINDING, &boundId);
380 
381     nngxBindCmdlist(m_ReusableCommandLists[m_BoundIndex]);
382 
383     nngxGetCmdlistParameteri(NN_GX_CMDLIST_USED_BUFSIZE, &bufferSize);
384 
385     nngxBindCmdlist(boundId);
386 
387     NW_GL_ASSERT();
388 
389     return static_cast<int>(bufferSize);
390 }
391 
392 //----------------------------------------
393 void
TimeoutWaitCommandListDone()394 CommandListSwapper::TimeoutWaitCommandListDone()
395 {
396     if ( s_CommandListSwapper )
397     {
398         s_CommandListSwapper->DumpCommandListParameter();
399     }
400 }
401 
402 //----------------------------------------
403 void
DumpCommandListParameter()404 CommandListSwapper::DumpCommandListParameter()
405 {
406     NW_DEV_LOG("[CommandListSwapper::WaitDone] nngxWaitCmdlistDone Timeout!\n");
407     NW_DEV_LOG("(Timeout: %lld [msec])\n", COMMAND_LIST_WAIT_TIME_OUT);
408 
409     // コマンドリストの実行状態です。
410     s32 paramIsRunning;
411     nngxGetCmdlistParameteri(NN_GX_CMDLIST_IS_RUNNING, &paramIsRunning);
412     NW_DEV_LOG("Running Command List       : %s\n", (paramIsRunning ? "true" : "false"));
413 
414     // カレントにバインドされているコマンドリストオブジェクトのIDです。
415     s32 paramBinding;
416     nngxGetCmdlistParameteri(NN_GX_CMDLIST_BINDING, &paramBinding);
417     NW_DEV_LOG("Binding ID                 : %d\n", paramBinding);
418 
419     // 3Dコマンドバッファの先頭アドレスです。
420     s32 paramBufAddr;
421     nngxGetCmdlistParameteri(NN_GX_CMDLIST_TOP_BUFADDR, &paramBufAddr);
422     NW_DEV_LOG("Top address of 3D command buffer      : 0x%08x\n", paramBufAddr);
423 
424     // コマンドリクエストのリクエストキュー用データ領域の先頭アドレスです。
425     s32 paramRequestAddr;
426     nngxGetCmdlistParameteri(NN_GX_CMDLIST_TOP_REQADDR, &paramRequestAddr);
427     NW_DEV_LOG("Top address of command request buffer : 0x%08x\n", paramRequestAddr);
428 
429     // 3Dコマンドバッファの最大サイズです。
430     s32 paramMaxBufSize;
431     nngxGetCmdlistParameteri(NN_GX_CMDLIST_MAX_BUFSIZE, &paramMaxBufSize);
432     NW_DEV_LOG("Max 3D command buffer size : %d [byte(s)]\n", paramMaxBufSize);
433 
434     // コマンドリクエスト最大サイズです。
435     s32 paramMaxRequestCount;
436     nngxGetCmdlistParameteri(NN_GX_CMDLIST_MAX_REQCOUNT, &paramMaxRequestCount);
437     NW_DEV_LOG("Max command request count  : %d\n", paramMaxRequestCount);
438 
439     // 蓄積された3Dコマンドバッファのバイトサイズです。
440     int paramUsedBufSize;
441     nngxGetCmdlistParameteri(NN_GX_CMDLIST_USED_BUFSIZE, &paramUsedBufSize);
442     NW_DEV_LOG("Used buffer size           : %d [byte(s)]\n", paramUsedBufSize);
443 
444     // 蓄積されたコマンドリクエストの個数です。
445     int paramUsedRequestCount;
446     nngxGetCmdlistParameteri(NN_GX_CMDLIST_USED_REQCOUNT, &paramUsedRequestCount);
447     NW_DEV_LOG("Used command request count : %d\n", paramUsedRequestCount);
448 
449     // 実行済みの3Dコマンドバッファのバイトサイズです。
450     int paramRunBufSize;
451     nngxGetCmdlistParameteri(NN_GX_CMDLIST_RUN_BUFSIZE, &paramRunBufSize);
452     NW_DEV_LOG("Run buffer size            : %d [byte(s)]\n", paramRunBufSize);
453 
454     // 実行済みのコマンドリクエストの個数です。
455     int paramRunRequestCount;
456     nngxGetCmdlistParameteri(NN_GX_CMDLIST_RUN_REQCOUNT, &paramRunRequestCount);
457     NW_DEV_LOG("Run command request count  : %d\n", paramRunRequestCount);
458 
459     // 次に実行されるコマンドリクエストのコマンドの種類です。
460     int paramNextRequestType;
461     nngxGetCmdlistParameteri(NN_GX_CMDLIST_NEXT_REQTYPE, &paramNextRequestType);
462     NW_DEV_LOG("Next command request type  : ");
463     switch(paramNextRequestType)
464     {
465     case NN_GX_CMDLIST_REQTYPE_DMA:
466         NW_DEV_LOG("NN_GX_CMDLIST_REQTYPE_DMA\n");
467         break;
468     case NN_GX_CMDLIST_REQTYPE_RUN3D:
469         NW_DEV_LOG("NN_GX_CMDLIST_REQTYPE_RUN3D\n");
470         break;
471     case NN_GX_CMDLIST_REQTYPE_FILLMEM:
472         NW_DEV_LOG("NN_GX_CMDLIST_REQTYPE_FILLMEM\n");
473         break;
474     case NN_GX_CMDLIST_REQTYPE_POSTTRANS:
475         NW_DEV_LOG("NN_GX_CMDLIST_REQTYPE_POSTTRANS\n");
476         break;
477     case NN_GX_CMDLIST_REQTYPE_COPYTEX:
478         NW_DEV_LOG("NN_GX_CMDLIST_REQTYPE_COPYTEX\n");
479         break;
480     default:
481         NW_DEV_LOG("unknown\n");
482         break;
483     }
484 
485     // ハードウェアの状態を示す32ビットのデータです。
486     s32 paramState;
487     nngxGetCmdlistParameteri(NN_GX_CMDLIST_HW_STATE, &paramState);
488     NW_DEV_LOG("Hardware state             : 0x%08x\n", paramState);
489 
490     NW_DEV_LOG("\n");
491     NW_DEV_LOG("Dump run command list:");
492 
493     s32 size = nngxExportCmdlist(paramBinding, 0, paramRunBufSize, 0, paramRunRequestCount, 0, 0);
494     nngxExportCmdlist(paramBinding, 0, paramRunBufSize, 0, paramRunRequestCount, size, m_DumpCommandListBuffer);
495 
496     for (int i = 0; i < size / 4; ++i)
497     {
498         if (i % 8 == 0)
499         {
500             NW_DEV_LOG("\n");
501         }
502 
503         NW_DEV_LOG(
504             "0x%02x%02x%02x%02x ",
505             m_DumpCommandListBuffer[i * 4 + 0],
506             m_DumpCommandListBuffer[i * 4 + 1],
507             m_DumpCommandListBuffer[i * 4 + 2],
508             m_DumpCommandListBuffer[i * 4 + 3]
509         );
510     }
511 
512     NW_DEV_LOG("\n");
513 }
514 
515 } // demo
516 } // nw
517 
518 
519