@@ -99,7 +99,7 @@ Streaming::TileUpdateManagerBase::~TileUpdateManagerBase()
99
99
100
100
101
101
// -----------------------------------------------------------------------------
102
- // kick off thread that continuously streams tiles
102
+ // kick off threads that continuously streams tiles
103
103
// gives StreamingResources opportunities to update feedback
104
104
// -----------------------------------------------------------------------------
105
105
void Streaming::TileUpdateManagerBase::StartThreads ()
@@ -115,127 +115,138 @@ void Streaming::TileUpdateManagerBase::StartThreads()
115
115
{
116
116
DebugPrint (L" Created Feedback Thread\n " );
117
117
118
- // NOTE: expects the streaming resource array size to be unchanged during thread lifetime
118
+ ProcessFeedbackThread ();
119
119
120
- // array of indices to resources that need tiles loaded/evicted
121
- std::vector<UINT> staleResources;
122
- staleResources.reserve (m_streamingResources.size ());
120
+ DebugPrint (L" Destroyed ProcessFeedback Thread\n " );
121
+ });
123
122
124
- // flags to prevent duplicates in the staleResources array
125
- std::vector<BYTE> pending (m_streamingResources.size (), 0 );
123
+ m_updateResidencyThread = std::thread ([&]
124
+ {
125
+ DebugPrint (L" Created UpdateResidency Thread\n " );
126
126
127
- UINT64 previousFrameFenceValue = m_frameFenceValue;
127
+ // continuously modify residency maps as a result of gpu completion events
128
+ // FIXME? probably not enough work to deserve it's own thread
129
+ // Note that UpdateMinMipMap() exits quickly if nothing to do
128
130
while (m_threadsRunning)
129
131
{
130
- // prioritize loading packed mips, as objects shouldn't be displayed until packed mips load
131
- bool expected = true ;
132
- if (m_havePackedMipsToLoad. compare_exchange_weak (expected, false ) )
132
+ m_residencyChangedFlag. Wait ();
133
+
134
+ for ( auto p : m_streamingResources )
133
135
{
134
- for (auto p : m_streamingResources)
135
- {
136
- if (!p->InitPackedMips ())
137
- {
138
- m_havePackedMipsToLoad = true ;
139
- }
140
- }
141
- if (m_havePackedMipsToLoad)
142
- {
143
- continue ; // still working on loading packed mips. don't move on to other streaming tasks yet.
144
- }
136
+ p->UpdateMinMipMap ();
145
137
}
138
+ }
139
+ DebugPrint (L" Destroyed UpdateResidency Thread\n " );
140
+ });
141
+ }
146
142
147
- // DEBUG: verify that no streaming resources have been added/removed during thread lifetime
148
- ASSERT (m_streamingResources.size () == pending.size ());
143
+ // -----------------------------------------------------------------------------
144
+ // per frame, call StreamingResource::ProcessFeedback()
145
+ // expects the no change in # of streaming resources during thread lifetime
146
+ // -----------------------------------------------------------------------------
147
+ void Streaming::TileUpdateManagerBase::ProcessFeedbackThread ()
148
+ {
149
+ // array of indices to resources that need tiles loaded/evicted
150
+ std::vector<UINT> staleResources;
151
+ staleResources.reserve (m_streamingResources.size ());
149
152
150
- UINT64 frameFenceValue = m_frameFence->GetCompletedValue ();
153
+ // flags to prevent duplicates in the staleResources array
154
+ std::vector<BYTE> pending (m_streamingResources.size (), 0 );
151
155
152
- // Only process feedback buffers once per frame
153
- if (previousFrameFenceValue != frameFenceValue)
156
+ UINT64 previousFrameFenceValue = m_frameFenceValue;
157
+ while (m_threadsRunning)
158
+ {
159
+ // prioritize loading packed mips, as objects shouldn't be displayed until packed mips load
160
+ bool expected = true ;
161
+ if (m_havePackedMipsToLoad.compare_exchange_weak (expected, false ))
162
+ {
163
+ for (auto p : m_streamingResources)
164
+ {
165
+ if (!p->InitPackedMips ())
154
166
{
155
- previousFrameFenceValue = frameFenceValue;
156
-
157
- auto startTime = m_cpuTimer.GetTime ();
158
- UINT j = 0 ;
159
- for (auto p : m_streamingResources)
160
- {
161
- // early exit, important for application exit or TUM::Finish() when adding/deleting objects
162
- if (!m_threadsRunning)
163
- {
164
- break ;
165
- }
166
-
167
- p->ProcessFeedback (frameFenceValue);
168
- if (p->IsStale () && !pending[j])
169
- {
170
- staleResources.push_back (j);
171
- pending[j] = 1 ;
172
- }
173
- j++;
174
- }
175
- m_processFeedbackTime += UINT64 (m_cpuTimer.GetTime () - startTime);
167
+ m_havePackedMipsToLoad = true ;
176
168
}
169
+ }
170
+ if (m_havePackedMipsToLoad)
171
+ {
172
+ Sleep (2 );
173
+ continue ; // still working on loading packed mips. don't move on to other streaming tasks yet.
174
+ }
175
+ }
177
176
178
- // continuously push uploads and evictions
179
- bool uploadRequested = false ;
180
- for (UINT i = 0 ; i < staleResources.size (); )
181
- {
182
- // exit loop if we ran out of UpdateLists or application exiting
183
- if ((!m_pDataUploader->UpdateListAvailable ()) || (!m_threadsRunning))
184
- {
185
- break ;
186
- }
187
-
188
- UINT resourceIndex = staleResources[i];
189
- auto p = m_streamingResources[resourceIndex];
190
- bool tilesQueued = p->QueueTiles ();
191
- uploadRequested = uploadRequested || tilesQueued;
192
-
193
- // if all loads/evictions handled, remove from staleResource list
194
- if (!p->IsStale ())
195
- {
196
- pending[resourceIndex] = 0 ; // clear the flag that prevents duplicates
197
- // compact the array by swapping this entry with the last
198
- staleResources[i] = staleResources.back ();
199
- staleResources.resize (staleResources.size () - 1 );
200
- }
201
- else
202
- {
203
- i++;
204
- }
205
- }
177
+ // DEBUG: verify that no streaming resources have been added/removed during thread lifetime
178
+ ASSERT (m_streamingResources.size () == pending.size ());
206
179
207
- // if uploads were queued, tell the file streamer to signal the corresponding fence
208
- if (uploadRequested)
180
+ UINT64 frameFenceValue = m_frameFence->GetCompletedValue ();
181
+
182
+ // Only process feedback buffers once per frame
183
+ if (previousFrameFenceValue != frameFenceValue)
184
+ {
185
+ previousFrameFenceValue = frameFenceValue;
186
+
187
+ auto startTime = m_cpuTimer.GetTime ();
188
+ UINT j = 0 ;
189
+ for (auto p : m_streamingResources)
190
+ {
191
+ // early exit, important for application exit or TUM::Finish() when adding/deleting objects
192
+ if (!m_threadsRunning)
209
193
{
210
- m_pDataUploader-> SignalFileStreamer () ;
194
+ break ;
211
195
}
212
196
213
- // nothing to do? wait for next frame
214
- if (( 0 == staleResources. size ()) && m_threadsRunning )
197
+ p-> ProcessFeedback (frameFenceValue);
198
+ if (p-> IsStale () && !pending[j] )
215
199
{
216
- m_processFeedbackFlag.Wait ();
200
+ staleResources.push_back (j);
201
+ pending[j] = 1 ;
217
202
}
203
+ j++;
218
204
}
219
- DebugPrint (L" Destroyed ProcessFeedback Thread\n " );
220
- });
205
+ // add the amount of time we just spent processing feedback for a single frame
206
+ m_processFeedbackTime += UINT64 (m_cpuTimer.GetTime () - startTime);
207
+ }
221
208
222
- m_updateResidencyThread = std::thread ([&]
209
+ // push uploads and evictions for stale resources
210
+ bool uploadRequested = false ; // remember if any work was queued so we can signal afterwards
211
+ UINT newStaleSize = 0 ; // track number of stale resources, then resize the array to the updated number
212
+ for (UINT i = 0 ; i < staleResources.size (); i++)
223
213
{
224
- DebugPrint ( L" Created UpdateResidency Thread \n " );
225
- // continuously modify residency maps as a result of gpu completion events
226
- // FIXME? probably not enough work to deserve it's own thread
227
- // Note that UpdateMinMipMap() exits quickly if nothing to do
228
- while ( m_threadsRunning)
214
+
215
+ UINT resourceIndex = staleResources[i];
216
+ auto p = m_streamingResources[resourceIndex];
217
+
218
+ if (m_pDataUploader-> UpdateListAvailable () && m_threadsRunning)
229
219
{
230
- m_residencyChangedFlag.Wait ();
220
+ uploadRequested = p->QueueTiles () || uploadRequested;
221
+ }
231
222
232
- for (auto p : m_streamingResources)
233
- {
234
- p->UpdateMinMipMap ();
235
- }
223
+ // if all loads/evictions handled, remove from staleResource list
224
+ if (p->IsStale ())
225
+ {
226
+ // compact, removing non-stale resource indices while retaining oldest-first ordering
227
+ staleResources[newStaleSize] = resourceIndex;
228
+ newStaleSize++;
236
229
}
237
- DebugPrint (L" Destroyed UpdateResidency Thread\n " );
238
- });
230
+ else
231
+ {
232
+ pending[resourceIndex] = 0 ; // clear the flag that prevents duplicates
233
+ }
234
+ }
235
+
236
+ staleResources.resize (newStaleSize);
237
+
238
+ // if uploads were queued, tell the file streamer to signal the corresponding fence
239
+ if (uploadRequested)
240
+ {
241
+ m_pDataUploader->SignalFileStreamer ();
242
+ }
243
+
244
+ // nothing to do? wait for next frame
245
+ if ((0 == staleResources.size ()) && m_threadsRunning)
246
+ {
247
+ m_processFeedbackFlag.Wait ();
248
+ }
249
+ }
239
250
}
240
251
241
252
// -----------------------------------------------------------------------------
0 commit comments