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, ¶mIsRunning);
412 NW_DEV_LOG("Running Command List : %s\n", (paramIsRunning ? "true" : "false"));
413
414 // カレントにバインドされているコマンドリストオブジェクトのIDです。
415 s32 paramBinding;
416 nngxGetCmdlistParameteri(NN_GX_CMDLIST_BINDING, ¶mBinding);
417 NW_DEV_LOG("Binding ID : %d\n", paramBinding);
418
419 // 3Dコマンドバッファの先頭アドレスです。
420 s32 paramBufAddr;
421 nngxGetCmdlistParameteri(NN_GX_CMDLIST_TOP_BUFADDR, ¶mBufAddr);
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, ¶mRequestAddr);
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, ¶mMaxBufSize);
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, ¶mMaxRequestCount);
437 NW_DEV_LOG("Max command request count : %d\n", paramMaxRequestCount);
438
439 // 蓄積された3Dコマンドバッファのバイトサイズです。
440 int paramUsedBufSize;
441 nngxGetCmdlistParameteri(NN_GX_CMDLIST_USED_BUFSIZE, ¶mUsedBufSize);
442 NW_DEV_LOG("Used buffer size : %d [byte(s)]\n", paramUsedBufSize);
443
444 // 蓄積されたコマンドリクエストの個数です。
445 int paramUsedRequestCount;
446 nngxGetCmdlistParameteri(NN_GX_CMDLIST_USED_REQCOUNT, ¶mUsedRequestCount);
447 NW_DEV_LOG("Used command request count : %d\n", paramUsedRequestCount);
448
449 // 実行済みの3Dコマンドバッファのバイトサイズです。
450 int paramRunBufSize;
451 nngxGetCmdlistParameteri(NN_GX_CMDLIST_RUN_BUFSIZE, ¶mRunBufSize);
452 NW_DEV_LOG("Run buffer size : %d [byte(s)]\n", paramRunBufSize);
453
454 // 実行済みのコマンドリクエストの個数です。
455 int paramRunRequestCount;
456 nngxGetCmdlistParameteri(NN_GX_CMDLIST_RUN_REQCOUNT, ¶mRunRequestCount);
457 NW_DEV_LOG("Run command request count : %d\n", paramRunRequestCount);
458
459 // 次に実行されるコマンドリクエストのコマンドの種類です。
460 int paramNextRequestType;
461 nngxGetCmdlistParameteri(NN_GX_CMDLIST_NEXT_REQTYPE, ¶mNextRequestType);
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, ¶mState);
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