1 /*---------------------------------------------------------------------------*
2 Project: NintendoWare
3 File: snd_DriverCommandManager.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 "precompiled.h"
19 #include <nw/snd/snd_DriverCommandManager.h>
20
21 namespace nw {
22 namespace snd {
23 namespace internal {
24
GetInstance()25 DriverCommandManager& DriverCommandManager::GetInstance()
26 {
27 static DriverCommandManager instance;
28 return instance;
29 }
30
GetInstanceForTaskThread()31 DriverCommandManager& DriverCommandManager::GetInstanceForTaskThread()
32 {
33 static DriverCommandManager instance;
34 return instance;
35 }
36
DriverCommandManager()37 DriverCommandManager::DriverCommandManager()
38 {
39 }
40
Initialize(void * commandBuffer,u32 commandBufferSize)41 void DriverCommandManager::Initialize( void* commandBuffer, u32 commandBufferSize )
42 {
43 m_CommandListBegin = NULL;
44 m_CommandListEnd = NULL;
45
46 m_CommandTag = 0;
47
48 m_CommandMemoryAreaBegin = 0;
49 m_CommandMemoryAreaEnd = 0;
50 m_CommandMemoryAreaZeroFlag = false;
51
52 m_CommandMemoryArea = static_cast<u32*>(commandBuffer);
53 m_CommandMemoryAreaSize = commandBufferSize / sizeof(m_CommandMemoryArea[0]);
54
55 m_SendCommandQueue.Initialize( m_SendCommandQueueBuffer, COMMAND_QUEUE_SIZE );
56 m_RecvCommandQueue.Initialize( m_RecvCommandQueueBuffer, COMMAND_QUEUE_SIZE );
57 }
58
Finalize()59 void DriverCommandManager::Finalize()
60 {
61 m_SendCommandQueue.Finalize();
62 m_RecvCommandQueue.Finalize();
63 }
64
AllocMemory(u32 count)65 void* DriverCommandManager::AllocMemory( u32 count )
66 {
67 NW_ASSERT( count <= m_CommandMemoryAreaSize );
68
69 void* ptr = TryAllocMemory( count );
70 if ( ptr != NULL ) return ptr;
71
72 RecvCommandReply();
73 ptr = TryAllocMemory( count );
74 if ( ptr != NULL ) return ptr;
75
76 // 強制フラッシュ
77 while( ptr == NULL )
78 {
79 u32 tag = FlushCommand( true );
80 WaitCommandReply( tag );
81 ptr = TryAllocMemory( count );
82 }
83
84 return ptr;
85 }
86
TryAllocMemory(u32 count)87 void* DriverCommandManager::TryAllocMemory( u32 count )
88 {
89 void* ptr = NULL;
90
91 if ( m_CommandMemoryAreaZeroFlag ) return NULL;
92
93 if ( m_CommandMemoryAreaEnd > m_CommandMemoryAreaBegin ) {
94 // 連続領域の場合
95 if ( m_CommandMemoryAreaBegin + count <= m_CommandMemoryAreaEnd ) {
96 ptr = &m_CommandMemoryArea[m_CommandMemoryAreaBegin];
97 m_CommandMemoryAreaBegin += count;
98 }
99 }
100 else {
101 // 非連続領域の場合
102 if ( m_CommandMemoryAreaBegin + count <= m_CommandMemoryAreaSize ) {
103 ptr = &m_CommandMemoryArea[m_CommandMemoryAreaBegin];
104 m_CommandMemoryAreaBegin += count;
105 }
106 else if ( count <= m_CommandMemoryAreaEnd ) {
107 ptr = &m_CommandMemoryArea[0];
108 m_CommandMemoryAreaBegin = count;
109 }
110 }
111
112 if ( ptr != NULL && m_CommandMemoryAreaBegin == m_CommandMemoryAreaEnd ) {
113 m_CommandMemoryAreaZeroFlag = true;
114 }
115 return ptr;
116 }
117
GetAllocatableCommandSize() const118 u32 DriverCommandManager::GetAllocatableCommandSize() const
119 {
120 if ( m_CommandMemoryAreaZeroFlag ) return 0;
121
122 if ( m_CommandMemoryAreaEnd > m_CommandMemoryAreaBegin ) {
123 // 連続領域の場合
124 return m_CommandMemoryAreaEnd - m_CommandMemoryAreaBegin;
125 }
126 else {
127 // 非連続領域の場合
128 return ut::Max(
129 m_CommandMemoryAreaSize - m_CommandMemoryAreaBegin,
130 m_CommandMemoryAreaEnd
131 );
132 }
133 }
134
PushCommand(DriverCommand * command)135 u32 DriverCommandManager::PushCommand( DriverCommand* command )
136 {
137 if ( m_CommandListEnd == NULL )
138 {
139 m_CommandListBegin = command;
140 m_CommandListEnd = command;
141 }
142 else
143 {
144 m_CommandListEnd->next = command;
145 m_CommandListEnd = command;
146 }
147
148 command->next = NULL;
149
150 return m_CommandTag;
151 }
152
153 //---------------------------------------------------------------------------
154 //! @brief コマンドをフラッシュします。
155 //!
156 //! forceFlagがtrueの時は、必ず処理を行います。
157 //! コマンドが1つも登録されていない場合は、ダミーのコマンドを発行します。
158 //! 受信側の処理が滞っている場合は、空くまで待ちます。
159 //!
160 //! forceFlagがfalseの時は、必要以上の処理は行いません。
161 //! コマンドが1つも登録されていない場合は、何もせずに返ります。
162 //! 受信側の処理が滞っている場合も、何もせずに返ります。
163 //! 何もせずに返った場合、返り値は0(無効値)になることに注意してください。
164 //!
165 //! @param[in] forceFlag フラッシュ処理を強制するかどうかのフラグです。
166 //!
167 //! @return コマンドタグを返します。
168 //! ただし、forceFlagがfalseの時に、コマンドフラッシュが
169 //! 行われない場合は、0(無効値)を返します。
170 //!
171 //---------------------------------------------------------------------------
FlushCommand(bool forceFlag)172 u32 DriverCommandManager::FlushCommand( bool forceFlag )
173 {
174 if ( m_CommandListBegin == NULL ) {
175 if ( ! forceFlag ) return 0;
176
177 // ダミーコマンド発行
178 DriverCommand* command = AllocCommand<DriverCommand>();
179 command->id = DRIVER_COMMAND_DUMMY;
180 PushCommand(command);
181 }
182
183 uptr msg = reinterpret_cast<uptr>(m_CommandListBegin);
184 u32 tag = m_CommandTag;
185
186 nn::os::DataMemoryBarrier();
187
188 if ( forceFlag )
189 {
190 m_SendCommandQueue.Enqueue( msg );
191 }
192 else
193 {
194 if ( ! m_SendCommandQueue.TryEnqueue( msg ) ) {
195 return 0;
196 }
197 }
198
199 m_CommandListBegin->tag = tag;
200 m_CommandTag++;
201
202 m_CommandListBegin = NULL;
203 m_CommandListEnd = NULL;
204
205 return tag;
206 }
207
FinalizeCommandList(DriverCommand * commandList)208 void DriverCommandManager::FinalizeCommandList( DriverCommand* commandList )
209 {
210 m_FinishCommandTag = commandList->tag;
211
212 DriverCommand* command = commandList;
213
214 while( command != NULL )
215 {
216 if ( command->next == NULL ) {
217 // コマンドメモリの解放
218 m_CommandMemoryAreaEnd = command->memory_next;
219 m_CommandMemoryAreaZeroFlag = false;
220 if ( m_CommandMemoryAreaBegin == m_CommandMemoryAreaEnd ) {
221 // メモリの分断化を解消
222 m_CommandMemoryAreaBegin = m_CommandMemoryAreaEnd = 0;
223 }
224 break;
225 }
226
227 command = command->next;
228 }
229 }
230
IsFinishCommand(u32 tag) const231 bool DriverCommandManager::IsFinishCommand( u32 tag ) const
232 {
233 static const u32 limit = (1 << ((sizeof(tag) * 8)-2) );
234
235 if ( tag < m_FinishCommandTag )
236 {
237 return ( m_FinishCommandTag - tag < limit );
238 }
239 else
240 {
241 return ( tag - m_FinishCommandTag < limit );
242 }
243 }
244
RecvCommandReply()245 void DriverCommandManager::RecvCommandReply()
246 {
247 uptr msg;
248 while( m_RecvCommandQueue.TryDequeue( &msg ) )
249 {
250 DriverCommand* commandList = reinterpret_cast<DriverCommand*>(msg);
251 FinalizeCommandList( commandList );
252 }
253 }
254
WaitCommandReply(u32 tag)255 void DriverCommandManager::WaitCommandReply( u32 tag )
256 {
257 while( true ) {
258 uptr msg = m_RecvCommandQueue.Dequeue();
259 DriverCommand* commandList = reinterpret_cast<DriverCommand*>(msg);
260 FinalizeCommandList( commandList );
261
262 if ( tag == commandList->tag ) break;
263 }
264 }
265
ProcessCommand()266 void DriverCommandManager::ProcessCommand()
267 {
268 uptr msg;
269 while( m_SendCommandQueue.TryDequeue( &msg ) )
270 {
271 DriverCommand* commandList = reinterpret_cast<DriverCommand*>(msg);
272
273 DriverCommand::ProcessCommandList( commandList );
274
275 nn::os::DataMemoryBarrier();
276
277 m_RecvCommandQueue.Enqueue( msg );
278 }
279 }
280
281 } // namespace nw::snd::internal
282 } // namespace nw::snd
283 } // namespace nw
284