1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     demo_CommandCache.cpp
4 
5   Copyright (C)2009-2012 Nintendo Co., Ltd.  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   $Rev: 46365 $
14  *---------------------------------------------------------------------------*/
15 
16 #include "demo/CommandCache/demo_CommandCache.h"
17 
18 namespace demo
19 {
20 
21     namespace detail
22     {
VertexShaderUniformMatrix(void)23         VertexShaderUniformMatrix::VertexShaderUniformMatrix(void) :
24         m_Valid(false),
25         m_RegisterIndex(0)
26         {
27             for (u32 i = 0; i < 4; i++)
28             {
29                 for (u32 j = 0; j < 4; j++)
30                 {
31                     m_Offset[i][j] = 0;
32                 }
33             }
34         }
35 
~VertexShaderUniformMatrix()36         VertexShaderUniformMatrix::~VertexShaderUniformMatrix()
37         {
38         }
39 
Initialize(void)40         void VertexShaderUniformMatrix::Initialize(void)
41         {
42             m_Valid = false;
43             m_RegisterIndex = 0;
44             for (u32 i = 0; i < 4; i++)
45             {
46                 for (u32 j = 0; j < 4; j++)
47                 {
48                     m_Offset[i][j] = 0;
49                 }
50             }
51         }
52 
Finalize(void)53         void VertexShaderUniformMatrix::Finalize(void)
54         {
55         }
56     }
57 
58     /* ------------------------------------------------------------------------
59         CommandCache class  member functions
60     ------------------------------------------------------------------------ */
61 
CommandCache(void)62     CommandCache::CommandCache(void) :
63     m_State(COMMAND_CACHE_UNINITIALIZED),
64     m_CommandListSize(0x100000), m_CommandListRequestNum(32),
65     m_CopyCommandBuffer(GL_TRUE), m_StateMask(0),
66     m_TotalModelNum(0), m_ModelIndex(0),
67     m_CurrentCommandListId(0),
68     m_CommandListId(0),
69     m_CommandBufferOffset(0),
70     m_CommandBufferSize(0),
71     m_CommandRequestBeginId(0), m_CommandRequestSize(0),
72     m_CommandBufferAddr(NULL)
73     {
74         for (u32 modelIndex = 0; modelIndex < DEMO_MAX_COMMAND_CACHE_MODELS_NUM; modelIndex++)
75         {
76             m_CommandBufferStartOffsetArray[modelIndex] = 0;
77 
78             for (u32 matrixIndex = 0; matrixIndex < DEMO_MAX_COMMAND_CACHE_MATRIX_NUM; matrixIndex++)
79             {
80                 m_VertexShaderUniformMatrixArray2d[modelIndex][matrixIndex].Initialize();
81             }
82         }
83     }
84 
~CommandCache()85     CommandCache::~CommandCache()
86     {
87         CommandCache::Finalize();
88     }
89 
Initialize(const u32 CommandListSize,const u32 RequestNum,const GLboolean copyCommandBuffer,const GLbitfield stateMask,const u32 totalModelNum)90     void CommandCache::Initialize(const u32 CommandListSize, const u32 RequestNum,
91             const GLboolean copyCommandBuffer, const GLbitfield stateMask,
92             const u32 totalModelNum)
93     {
94         if ( totalModelNum >= DEMO_MAX_COMMAND_CACHE_MODELS_NUM )
95         {
96             NN_TPANIC_("totalModelNum(%d) is too large. (Max = %d)\n",
97                 totalModelNum, DEMO_MAX_COMMAND_CACHE_MODELS_NUM);
98         }
99 
100         m_ModelIndex = 0;
101 
102         m_CommandListSize = CommandListSize;
103         m_CommandListRequestNum = RequestNum;
104         m_TotalModelNum = totalModelNum;
105         m_CopyCommandBuffer = copyCommandBuffer;
106         m_StateMask = stateMask;
107 
108         m_State = COMMAND_CACHE_INITIALIZED;
109     }
110 
Finalize(void)111     void CommandCache::Finalize(void)
112     {
113         DEMO_ASSERT_GL_ERROR();
114 
115         if ( m_CommandListId != 0 )
116         {
117             nngxDeleteCmdlists(1, &m_CommandListId);
118             m_CommandListId = 0;
119 
120             DEMO_ASSERT_GL_ERROR();
121         }
122 
123         for (u32 modelIndex = 0; modelIndex < DEMO_MAX_COMMAND_CACHE_MODELS_NUM; modelIndex++)
124         {
125             m_CommandBufferStartOffsetArray[modelIndex] = 0;
126 
127             for (u32 matrixIndex = 0; matrixIndex < DEMO_MAX_COMMAND_CACHE_MATRIX_NUM; matrixIndex++)
128             {
129                 m_VertexShaderUniformMatrixArray2d[modelIndex][matrixIndex].Initialize();
130             }
131         }
132 
133         m_State = COMMAND_CACHE_FINALIZED;
134     }
135 
SetVSUniformMatrixRegisterIndex(const u32 modelIndex,const u32 uniformMatrixIndex,const u32 registerIndex)136     void CommandCache::SetVSUniformMatrixRegisterIndex(const u32 modelIndex,
137         const u32 uniformMatrixIndex, const u32 registerIndex)
138     {
139         if (! ( modelIndex < m_TotalModelNum ))
140         {
141             NN_TPANIC_("modelIndex(%d) must be < m_TotalModelNum(%d).\n",
142                 modelIndex, m_TotalModelNum);
143         }
144 
145         if (! ( uniformMatrixIndex < DEMO_MAX_COMMAND_CACHE_MATRIX_NUM ) )
146         {
147             NN_TPANIC_("uniformMatrixIndex(%d) must be < DEMO_MAX_COMMAND_CACHE_MATRIX_NUM(%d).\n",
148                 uniformMatrixIndex, DEMO_MAX_COMMAND_CACHE_MATRIX_NUM);
149         }
150 
151         m_VertexShaderUniformMatrixArray2d[modelIndex][uniformMatrixIndex].m_Valid = true;
152         m_VertexShaderUniformMatrixArray2d[modelIndex][uniformMatrixIndex].m_RegisterIndex = registerIndex;
153     }
154 
BeginSave(void)155     void CommandCache::BeginSave(void)
156     {
157         if ( m_State != COMMAND_CACHE_INITIALIZED )
158         {
159             NN_TPANIC_("m_State != COMMAND_CACHE_INITIALIZED.\n");
160         }
161 
162         DEMO_ASSERT_GL_ERROR();
163 
164         // Saves ID of the command list currently bound.
165         nngxGetCmdlistParameteri(NN_GX_CMDLIST_BINDING, (GLint*)&m_CurrentCommandListId);
166 
167         // Allocates command list at the save destination.
168         nngxGenCmdlists(1, &m_CommandListId);
169         nngxBindCmdlist(m_CommandListId);
170         nngxCmdlistStorage(m_CommandListSize, m_CommandListRequestNum);
171 
172         // Starts saving the command list.
173         nngxStartCmdlistSave();
174 
175         m_State = COMMAND_CACHE_BEGIN_SAVE;
176 
177         DEMO_ASSERT_GL_ERROR();
178     }
179 
SaveCommandBufferStartOffset(const u32 modelIndex)180     void CommandCache::SaveCommandBufferStartOffset(const u32 modelIndex)
181     {
182         if ( m_State != COMMAND_CACHE_BEGIN_SAVE )
183         {
184             NN_TPANIC_("m_State != COMMAND_CACHE_BEGIN_SAVE.\n");
185         }
186 
187         if ( modelIndex < m_TotalModelNum )
188         {
189             nngxGetCmdlistParameteri(NN_GX_CMDLIST_USED_BUFSIZE,
190                 &m_CommandBufferStartOffsetArray[m_ModelIndex]);
191             m_ModelIndex += 1;
192         }
193         else
194         {
195             NN_TPANIC_("modelIndex(%d) must be < m_TotalModelNum(%d)\n",
196                 modelIndex, m_TotalModelNum);
197         }
198     }
199 
EndSave(void)200     void CommandCache::EndSave(void)
201     {
202         DEMO_ASSERT_GL_ERROR();
203 
204         if ( m_State != COMMAND_CACHE_BEGIN_SAVE )
205         {
206             NN_TPANIC_("m_State != COMMAND_CACHE_BEGIN_SAVE.\n");
207         }
208 
209         if ( m_ModelIndex == 0 )
210         {
211             NN_TPANIC_("SaveCommandBufferStartOffset() must be called more than once.\n");
212         }
213 
214         if (! m_CopyCommandBuffer )
215         {
216             nngxSplitDrawCmdlist();
217         }
218 
219         DEMO_ASSERT_GL_ERROR();
220 
221         // Ends saving the command list.
222         nngxStopCmdlistSave(&m_CommandBufferOffset, &m_CommandBufferSize,
223             &m_CommandRequestBeginId, &m_CommandRequestSize);
224 
225         DEMO_ASSERT_GL_ERROR();
226 
227         // Gets the start address of the 3D command buffer of the save destination command list.
228         nngxGetCmdlistParameteri(NN_GX_CMDLIST_TOP_BUFADDR, (GLint*)&m_CommandBufferAddr);
229         // Add the byte offset for the save start address to it.
230         m_CommandBufferAddr += m_CommandBufferOffset;
231 
232         DEMO_ASSERT_GL_ERROR();
233 
234         for (u32 modelIndex = 0; modelIndex < m_TotalModelNum; modelIndex++)
235         {
236             // Gets the matrix offset value for the 3D command buffer of the save destination command list.
237             for (u32 uniformMatrixIndex = 0; uniformMatrixIndex < DEMO_MAX_COMMAND_CACHE_MATRIX_NUM; uniformMatrixIndex++)
238             {
239                 if ( m_VertexShaderUniformMatrixArray2d[modelIndex][uniformMatrixIndex].m_Valid )
240                 {
241                     for (u32 index = 0; index < 4; index++)
242                     {
243                         demo::detail::GetVSUniformOffset(m_CommandBufferAddr,
244                             m_CommandBufferStartOffsetArray[modelIndex] - m_CommandBufferOffset,
245                             m_CommandBufferSize,
246                             m_VertexShaderUniformMatrixArray2d[modelIndex][uniformMatrixIndex].m_RegisterIndex + index,
247                             &m_VertexShaderUniformMatrixArray2d[modelIndex][uniformMatrixIndex].m_Offset[index][0]);
248                     }
249                 }
250             }
251         }
252 
253         m_ModelIndex = 0;
254 
255         // Bind the command list again.
256         nngxBindCmdlist(m_CurrentCommandListId);
257 
258         m_State = COMMAND_CACHE_END_SAVE;
259 
260         DEMO_ASSERT_GL_ERROR();
261     }
262 
UpdateVSUniformMatrix(const u32 modelIndex,const u32 uniformMatrixIndex,const nn::math::MTX44 & matrix)263     void CommandCache::UpdateVSUniformMatrix(const u32 modelIndex, const u32 uniformMatrixIndex, const nn::math::MTX44& matrix)
264     {
265         if ( m_State != COMMAND_CACHE_END_SAVE )
266         {
267             NN_TPANIC_("m_State != COMMAND_CACHE_END_SAVE.\n");
268         }
269 
270         if (! ( modelIndex < m_TotalModelNum ))
271         {
272             NN_TPANIC_("modelIndex(%d) must be < m_TotalModelNum(%d).\n",
273                 modelIndex, m_TotalModelNum);
274         }
275 
276         if (! (uniformMatrixIndex < DEMO_MAX_COMMAND_CACHE_MATRIX_NUM ))
277         {
278             NN_TPANIC_("uniformMatrixIndex(%d) must be < DEMO_MAX_COMMAND_CACHE_MATRIX_NUM(%d)\n",
279                 uniformMatrixIndex, DEMO_MAX_COMMAND_CACHE_MATRIX_NUM);
280         }
281 
282         GLfloat matrixArray[16];
283         for (u32 index = 0; index < 16; index++)
284         {
285             matrixArray[index] = matrix.m[index & 3][index >> 2];
286         }
287 
288         for (u32 index = 0; index < 4; index++)
289         {
290             *(reinterpret_cast<u32*>(&m_CommandBufferAddr[m_VertexShaderUniformMatrixArray2d[modelIndex][uniformMatrixIndex].m_Offset[index][3]])) =
291                 *(reinterpret_cast<u32*>(&matrixArray[0 + index]));
292             *(reinterpret_cast<u32*>(&m_CommandBufferAddr[m_VertexShaderUniformMatrixArray2d[modelIndex][uniformMatrixIndex].m_Offset[index][2]])) =
293                 *(reinterpret_cast<u32*>(&matrixArray[4 + index]));
294             *(reinterpret_cast<u32*>(&m_CommandBufferAddr[m_VertexShaderUniformMatrixArray2d[modelIndex][uniformMatrixIndex].m_Offset[index][1]])) =
295                 *(reinterpret_cast<u32*>(&matrixArray[8 + index]));
296             *(reinterpret_cast<u32*>(&m_CommandBufferAddr[m_VertexShaderUniformMatrixArray2d[modelIndex][uniformMatrixIndex].m_Offset[index][0]])) =
297                 *(reinterpret_cast<u32*>(&matrixArray[12 + index]));
298         }
299     }
300 
Append(void)301     void CommandCache::Append(void)
302     {
303         DEMO_ASSERT_GL_ERROR();
304 
305         if ( m_State != COMMAND_CACHE_END_SAVE )
306         {
307             NN_TPANIC_("m_State != COMMAND_CACHE_END_SAVE.\n");
308         }
309 
310         // Adds the saved command list to the current command list.
311         nngxUseSavedCmdlist(m_CommandListId,
312             m_CommandBufferOffset, m_CommandBufferSize,
313             m_CommandRequestBeginId, m_CommandRequestSize, m_StateMask, m_CopyCommandBuffer);
314 
315         DEMO_ASSERT_GL_ERROR();
316     }
317 
Print(void)318     void CommandCache::Print(void)
319     {
320         if ( m_State == COMMAND_CACHE_UNINITIALIZED )
321         {
322             NN_LOG("CommandCache : State = COMMAND_CACHE_UNINITIALIZED\n");
323         }
324         else if ( m_State == COMMAND_CACHE_INITIALIZED )
325         {
326             NN_LOG("CommandCache : State = COMMAND_CACHE_INITIALIZED\n");
327         }
328         else if ( m_State == COMMAND_CACHE_FINALIZED )
329         {
330             NN_LOG("CommandCache : State = COMMAND_CACHE_FINALIZED\n");
331         }
332         else if ( m_State == COMMAND_CACHE_BEGIN_SAVE )
333         {
334             NN_LOG("CommandCache : State = COMMAND_CACHE_BEGIN_SAVE\n");
335         }
336         else if ( m_State == COMMAND_CACHE_END_SAVE )
337         {
338             NN_LOG("CommandCache : State = COMMAND_CACHE_END_SAVE \n");
339         }
340 
341         NN_LOG("  commandListId  = %d\n", m_CommandListId);
342         if ( m_CopyCommandBuffer )
343         {
344             NN_LOG("  Copy 3d command buffer\n");
345         }
346         else
347         {
348             NN_LOG("  Refer 3d command buffer\n");
349         }
350         NN_LOG("  bufferOffset   = %d, bufferSize  = %d\n", m_CommandBufferOffset, m_CommandBufferSize);
351         NN_LOG("  requestBeginId = %d, requestSize = %d\n", m_CommandRequestBeginId, m_CommandRequestSize);
352         NN_LOG("  modelIndex = %d, totalModelNum = %d\n", m_ModelIndex, m_TotalModelNum);
353     }
354 
355     namespace detail
356     {
GetVSUniformOffset(u8 * bufferAddress,const u32 startOffset,const GLsizei bufferSize,const u32 uniformFloatRegIndex,u32 * uniformOffsetArray)357         void GetVSUniformOffset(u8* bufferAddress, const u32 startOffset,
358             const GLsizei bufferSize, const u32 uniformFloatRegIndex, u32* uniformOffsetArray)
359         {
360             u32 const_current_addr = 0xffffffff;
361             u32 const_current_index = 0;
362             u32 const_f32_mode = 0;
363 
364             for (u32 i = 0; i < 4; i++)
365             {
366                 uniformOffsetArray[i] = 0xffffffff;
367             }
368 
369             for (u32 offset = startOffset; offset < bufferSize; )
370             {
371                 CommandBuffer3d* command;
372                 command = (CommandBuffer3d*)&bufferAddress[offset];
373 
374                 if ( command->size == 0 )
375                 {
376                     // single command
377                     if ( command->be )
378                     {
379                         if ( command->addr == VS_UNIFORM_FLOAT_REG_INDEX )
380                         {
381                             const_current_addr = command->data & 0xff;
382                             const_current_index = 0;
383                             const_f32_mode = (command->data & 0x80000000);
384                         }
385                         else if ( (command->addr >= VS_UNIFORM_FLOAT_REG_VALUE_BEGIN) && (command->addr <= VS_UNIFORM_FLOAT_REG_VALUE_END) )
386                         {
387                             if (const_current_addr == uniformFloatRegIndex)
388                             {
389                                 uniformOffsetArray[const_current_index] = offset;
390                                 if (const_current_index == 3)
391                                 {
392                                     break;
393                                 }
394                             }
395 
396                             ++const_current_index;
397                             if (const_f32_mode ? (const_current_index == 4) : (const_current_index == 3))
398                             {
399                                 const_current_addr++;
400                                 const_current_index = 0;
401                             }
402                         }
403                     }
404                    offset += 8;
405                 }
406                 else
407                 {
408                     // burst command
409                     if (command->be)
410                     {
411                         if (command->seq)
412                         {
413                             // sequencial mode
414                             if (!((VS_UNIFORM_FLOAT_REG_INDEX > command->addr + command->size) || command->addr > VS_UNIFORM_FLOAT_REG_VALUE_END))
415                             {
416                                 u32 i = 0;
417                                 for (i = 0; i < command->size + 1; i++)
418                                 {
419                                     unsigned addr = command->addr + i;
420                                     if (addr == VS_UNIFORM_FLOAT_REG_INDEX)
421                                     {
422                                         const_current_addr = ((i == 0) ? command->data : bufferAddress[offset + 4 + 4 * i]) & 0xff;
423                                         const_current_index = 0;
424                                         const_f32_mode = (((i == 0) ? command->data : bufferAddress[offset + 4 + 4 * i]) & 0x80000000);
425                                     }
426                                     else if ( (addr >= VS_UNIFORM_FLOAT_REG_VALUE_BEGIN) && (addr <= VS_UNIFORM_FLOAT_REG_VALUE_END) )
427                                     {
428                                         if (const_current_addr == uniformFloatRegIndex)
429                                         {
430                                             uniformOffsetArray[const_current_index] = (i == 0) ? offset : (offset + 4 + 4 * i);
431                                             if (const_current_index == 3)
432                                             {
433                                                 break;
434                                             }
435                                         }
436                                         ++const_current_index;
437                                         if (const_f32_mode ? (const_current_index == 4) : (const_current_index == 3))
438                                         {
439                                             const_current_addr++;
440                                             const_current_index = 0;
441                                         }
442                                     }
443                                 }
444                                 if (i != command->size + 1)
445                                 {
446                                     break;
447                                 }
448                             }
449                         }
450                         else
451                         {
452                             // non sequencial mode
453                             if (command->addr == VS_UNIFORM_FLOAT_REG_INDEX)
454                             {
455                                 const_current_addr = (bufferAddress[offset + 4 + 4 * command->size]) & 0xff;
456                                 const_current_index = 0;
457                                 const_f32_mode = (bufferAddress[offset + 4 + 4 * command->size] & 0x80000000);
458                             }
459                             else if (command->addr >= VS_UNIFORM_FLOAT_REG_VALUE_BEGIN && command->addr <= VS_UNIFORM_FLOAT_REG_VALUE_END)
460                             {
461                                 u32 i = 0;
462                                 for (i = 0; i < command->size + 1; i++)
463                                 {
464                                     if (const_current_addr == uniformFloatRegIndex)
465                                     {
466                                         uniformOffsetArray[const_current_index] = (i == 0) ? offset : (offset + 4 + 4 * i);
467                                         if (const_current_index == 3)
468                                         {
469                                             break;
470                                         }
471                                     }
472                                     ++const_current_index;
473                                     if (const_f32_mode ? (const_current_index == 4) : (const_current_index == 3))
474                                     {
475                                         const_current_addr++;
476                                         const_current_index = 0;
477                                     }
478                                 }
479 
480                                 if (i != command->size + 1)
481                                 {
482                                     break;
483                                 }
484                             }
485                         }
486                     }
487                     offset += (command->size + 1) * 4 + 4;
488                     if (offset & 4)
489                     {
490                         offset += 4;
491                     }
492                 }
493             }
494         }
495     }
496 
PrintCurrentCmdlist(void)497     void PrintCurrentCmdlist(void)
498     {
499         GLint bufferSize = 0;
500         nngxGetCmdlistParameteri(NN_GX_CMDLIST_USED_BUFSIZE, &bufferSize);
501 
502         GLint maxBufferSize = 0;
503         nngxGetCmdlistParameteri(NN_GX_CMDLIST_MAX_BUFSIZE, &maxBufferSize);
504 
505         GLint reqCount = 0;
506         nngxGetCmdlistParameteri(NN_GX_CMDLIST_USED_REQCOUNT, &reqCount);
507 
508         GLint maxReqCount = 0;
509         nngxGetCmdlistParameteri(NN_GX_CMDLIST_MAX_REQCOUNT, &maxReqCount);
510 
511         NN_LOG("CommandList information\n");
512         NN_LOG("  bufferSize = %d/%d\n", bufferSize, maxBufferSize);
513         NN_LOG("  reqCount = %d/%d\n", reqCount, maxReqCount);
514     }
515 
516 }
517