1 /*---------------------------------------------------------------------------*
2   Project: NintendoWare
3   File   : demo_CommandListSwapper.cpp
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: 23208 $
14  *---------------------------------------------------------------------------*/
15 
16 #include <nw/demo/demo_CommandListSwapper.h>
17 #include <nw/demo/demo_DebugUtility.h>
18 
19 #include <nw/os/os_Memory.h>
20 #include <nn/os/os_Tick.h>
21 
22 namespace nw
23 {
24 namespace demo
25 {
26 
27 CommandListSwapper* CommandListSwapper::s_CommandListSwapper = NULL;
28 
29 //----------------------------------------
30 CommandListSwapper*
Create(os::IAllocator * allocator,CommandListSwapper::Description & description)31 CommandListSwapper::Create(
32     os::IAllocator* allocator,
33     CommandListSwapper::Description& description)
34 {
35     void* memory = allocator->Alloc(sizeof(CommandListSwapper));
36 
37     NW_NULL_ASSERT(memory);
38 
39     CommandListSwapper* swapper = new(memory) CommandListSwapper(allocator, description);
40 
41     return swapper;
42 }
43 
44 //----------------------------------------
CommandListSwapper(os::IAllocator * allocator,CommandListSwapper::Description & description)45 CommandListSwapper::CommandListSwapper(
46     os::IAllocator* allocator,
47     CommandListSwapper::Description& description)
48 : m_Allocator(allocator),
49   m_CommandLists(description.commandListCount, allocator),
50   m_BoundIndex(0),
51   m_RunningIndex(0),
52   m_IsRunning(false),
53   m_GpuProfilingEntries(description.maxGpuProfilingEntryCount, allocator),
54   m_GpuProfilingResults(description.maxGpuProfilingEntryCount, allocator),
55   m_ReusableCommandLists(),
56   m_ReusableBufferOffset(0),
57   m_ReusableBufferSize(0),
58   m_ReusableRequestId(0),
59   m_ReusableRequestSize(0)
60 {
61     m_CommandLists.resize(description.commandListCount);
62     CommandListArray::iterator listEnd = m_CommandLists.end();
63     for (CommandListArray::iterator commandList = m_CommandLists.begin();
64         commandList != listEnd; ++commandList)
65     {
66         nngxGenCmdlists(1, &(*commandList));
67         nngxBindCmdlist(*commandList);
68         nngxCmdlistStorage(description.bufferSize, description.requestCount);
69         nngxSetCmdlistParameteri(NN_GX_CMDLIST_RUN_MODE, NN_GX_CMDLIST_SERIAL_RUN);
70         nngxSetCmdlistCallback(CommandListSwapper::CommandListCallback);
71     }
72 
73     if (description.reusableBufferSize > 0 && description.reusableRequestCount > 0)
74     {
75         m_ReusableCommandLists = CommandListArray(description.commandListCount, allocator),
76         m_ReusableCommandLists.resize(description.commandListCount);
77         CommandListArray::iterator cacheEnd = m_ReusableCommandLists.end();
78         for (CommandListArray::iterator commandList = m_ReusableCommandLists.begin();
79             commandList != cacheEnd; ++commandList)
80         {
81             nngxGenCmdlists(1, &(*commandList));
82             nngxBindCmdlist(*commandList);
83             nngxCmdlistStorage(description.reusableBufferSize, description.reusableRequestCount);
84             nngxSetCmdlistParameteri(NN_GX_CMDLIST_RUN_MODE, NN_GX_CMDLIST_SERIAL_RUN);
85         }
86     }
87     s_CommandListSwapper = this;
88 }
89 
90 //----------------------------------------
91 void
Destroy()92 CommandListSwapper::Destroy()
93 {
94     os::IAllocator* allocator = this->m_Allocator;
95 
96     void* memory = static_cast<void*>(this);
97     this->~CommandListSwapper();
98 
99     allocator->Free(memory);
100 }
101 
102 //----------------------------------------
103 void
Bind()104 CommandListSwapper::Bind()
105 {
106     nngxBindCmdlist(this->GetCommandListId());
107 }
108 //----------------------------------------
109 void
RunAsync()110 CommandListSwapper::RunAsync()
111 {
112     m_GpuProfilingEntries.swap( m_GpuProfilingResults );
113 
114     m_RunningIndex = m_BoundIndex;
115     m_IsRunning = true;
116 
117     if (! nw::demo::DebugUtility::IsCpuProfilingMode())
118     {
119         nngxRunCmdlist();
120     }
121 }
122 
123 //----------------------------------------
124 void
Swap()125 CommandListSwapper::Swap()
126 {
127     ++this->m_BoundIndex;
128     if (this->m_CommandLists.size() <= this->m_BoundIndex)
129     {
130         this->m_BoundIndex = 0;
131     }
132     if (this->m_CommandLists.size() > 1)
133     {
134         ResetGpuProfiling();
135     }
136 }
137 
138 //----------------------------------------
139 void
WaitDone()140 CommandListSwapper::WaitDone()
141 {
142     if (!m_IsRunning)
143     {
144         return;
145     }
146 
147     nngxBindCmdlist(m_CommandLists[m_RunningIndex]);
148     nngxSplitDrawCmdlist();
149     nngxWaitCmdlistDone();
150     nngxStopCmdlist();
151     nngxClearCmdlist();
152     Bind();
153     m_IsRunning = false;
154 
155     CalcGpuProfilingCostTime();
156     if (this->m_CommandLists.size() == 1)
157     {
158         ResetGpuProfiling();
159     }
160 }
161 
162 //----------------------------------------
163 void
ResetGpuProfiling()164 CommandListSwapper::ResetGpuProfiling()
165 {
166     m_GpuProfilingEntries.clear();
167 }
168 
169 //----------------------------------------
170 s32
AddGpuProfilingStartPoint(bool IsInTotal)171 CommandListSwapper::AddGpuProfilingStartPoint(bool IsInTotal)
172 {
173     if (!m_GpuProfilingEntries.push_back( GpuProfilingEntry() ))
174     {
175         return -1;
176     }
177 
178     GpuProfilingEntry& gpuProfilingEntry = m_GpuProfilingEntries.back();
179 
180     GLuint id = RegisterCallback();
181 
182     gpuProfilingEntry.beginId = id;
183     gpuProfilingEntry.isInTotal = IsInTotal;
184 
185     return m_GpuProfilingEntries.size() - 1;
186 }
187 
188 //----------------------------------------
189 void
SetGpuProfilingEndPoint(u32 profilingId)190 CommandListSwapper::SetGpuProfilingEndPoint(u32 profilingId)
191 {
192     NW_ASSERT(profilingId < m_GpuProfilingEntries.size());
193 
194     m_GpuProfilingEntries[profilingId].endId = RegisterCallback();
195 }
196 
197 //----------------------------------------
198 GLuint
RegisterCallback()199 CommandListSwapper::RegisterCallback()
200 {
201     GLint requestCount = 0;
202     nngxGetCmdlistParameteri(NN_GX_CMDLIST_USED_REQCOUNT, &requestCount);
203     if (requestCount == 0)
204     {
205         // コマンドリクエストが無い場合はコマンドバッファを区切ることでコマンドリクエストを追加する。
206         nngxSplitDrawCmdlist();
207         nngxGetCmdlistParameteri(NN_GX_CMDLIST_USED_REQCOUNT, &requestCount);
208     }
209     nngxEnableCmdlistCallback( requestCount );
210 
211     return requestCount;
212 }
213 
214 
215 //----------------------------------------
216 void
CalcGpuProfilingCostTime()217 CommandListSwapper::CalcGpuProfilingCostTime()
218 {
219     GpuProfilingEntryArray::iterator end = m_GpuProfilingResults.end();
220     for (GpuProfilingEntryArray::iterator gpuProfilingEntry = m_GpuProfilingResults.begin();
221         gpuProfilingEntry != end; ++gpuProfilingEntry)
222     {
223         const s64 span =
224             nn::os::Tick(gpuProfilingEntry->endTick - gpuProfilingEntry->beginTick)
225             .ToTimeSpan()
226             .GetMicroSeconds();
227 
228         gpuProfilingEntry->costTime = static_cast<float>(span) / 1000.0f;
229     }
230 }
231 
232 //----------------------------------------
233 f32
GetGpuProfilingCostTime(u32 profilingId)234 CommandListSwapper::GetGpuProfilingCostTime(u32 profilingId)
235 {
236     if (profilingId < m_GpuProfilingResults.size())
237     {
238         return m_GpuProfilingResults[profilingId].costTime;
239     }
240     else
241     {
242         return 0.0f;
243     }
244 }
245 
246 //----------------------------------------
247 f32
GetGpuProfilingTotalCostTime()248 CommandListSwapper::GetGpuProfilingTotalCostTime()
249 {
250     f32 total = 0.0f;
251 
252     GpuProfilingEntryArray::iterator end = m_GpuProfilingResults.end();
253     for (GpuProfilingEntryArray::iterator gpuProfilingEntry = m_GpuProfilingResults.begin();
254         gpuProfilingEntry != end; ++gpuProfilingEntry)
255     {
256         if (gpuProfilingEntry->isInTotal)
257         {
258             total += gpuProfilingEntry->costTime;
259         }
260     }
261 
262     return total;
263 }
264 
265 //----------------------------------------
266 void
SetGpuProfilingTick(GLint id)267 CommandListSwapper::SetGpuProfilingTick(GLint id)
268 {
269     s64 tick = static_cast<s64>(nn::os::Tick::GetSystemCurrent());
270 
271     size_t size = m_GpuProfilingResults.size();
272 
273     for (u32 i = 0 ; i < size ; ++i)
274     {
275         if (m_GpuProfilingResults[i].beginId == id)
276         {
277             m_GpuProfilingResults[i].beginTick = tick;
278         }
279         if (m_GpuProfilingResults[i].endId == id)
280         {
281             m_GpuProfilingResults[i].endTick = tick;
282         }
283     }
284 }
285 
286 //----------------------------------------
287 void
CommandListCallback(GLint id)288 CommandListSwapper::CommandListCallback(GLint id)
289 {
290     if ( s_CommandListSwapper )
291     {
292         s_CommandListSwapper->SetGpuProfilingTick(id);
293     }
294 }
295 
296 //----------------------------------------
297 void
StartCommandSave()298 CommandListSwapper::StartCommandSave()
299 {
300     NW_ASSERT( !m_ReusableCommandLists.empty() );
301 
302     nngxBindCmdlist(m_ReusableCommandLists[m_BoundIndex]);
303     nngxClearCmdlist();
304     nngxStartCmdlistSave();
305     NW_GL_ASSERT();
306 }
307 
308 //----------------------------------------
309 void
EndCommandSave()310 CommandListSwapper::EndCommandSave()
311 {
312     NW_ASSERT( !m_ReusableCommandLists.empty() );
313 
314     nngxSplitDrawCmdlist();
315     NW_GL_ASSERT();
316 
317     nngxStopCmdlistSave(
318         &m_ReusableBufferOffset,
319         &m_ReusableBufferSize,
320         &m_ReusableRequestId,
321         &m_ReusableRequestSize);
322     NW_GL_ASSERT();
323 
324     Bind();
325 }
326 
327 //----------------------------------------
328 void
ReuseCommand(bool isCopyBuffer)329 CommandListSwapper::ReuseCommand(bool isCopyBuffer)
330 {
331     NW_ASSERT( !m_ReusableCommandLists.empty() );
332 
333     nngxUseSavedCmdlist(
334         m_ReusableCommandLists[m_BoundIndex],
335         m_ReusableBufferOffset,
336         m_ReusableBufferSize,
337         m_ReusableRequestId,
338         m_ReusableRequestSize,
339         0,
340         isCopyBuffer ? GL_TRUE : GL_FALSE);
341     NW_GL_ASSERT();
342 }
343 
344 //----------------------------------------
345 int
GetCommandBufferSize() const346 CommandListSwapper::GetCommandBufferSize() const
347 {
348     GLint bufferSize;
349 
350     nngxGetCmdlistParameteri(NN_GX_CMDLIST_USED_BUFSIZE, &bufferSize);
351     NW_GL_ASSERT();
352 
353     return static_cast<int>(bufferSize);
354 }
355 
356 //----------------------------------------
357 int
GetReusableCommandBufferSize() const358 CommandListSwapper::GetReusableCommandBufferSize() const
359 {
360     GLint bufferSize;
361     GLint boundId;
362 
363     nngxGetCmdlistParameteri(NN_GX_CMDLIST_BINDING, &boundId);
364 
365     nngxBindCmdlist(m_ReusableCommandLists[m_BoundIndex]);
366 
367     nngxGetCmdlistParameteri(NN_GX_CMDLIST_USED_BUFSIZE, &bufferSize);
368 
369     nngxBindCmdlist(boundId);
370 
371     NW_GL_ASSERT();
372 
373     return static_cast<int>(bufferSize);
374 }
375 
376 
377 
378 
379 } // demo
380 } // nw
381 
382 
383