Panda3D
|
00001 // Filename: pipelineCyclerTrueImpl.cxx 00002 // Created by: drose (31Jan06) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "pipelineCyclerTrueImpl.h" 00016 00017 #ifdef THREADED_PIPELINE 00018 00019 #include "config_pipeline.h" 00020 #include "pipeline.h" 00021 00022 //////////////////////////////////////////////////////////////////// 00023 // Function: PipelineCyclerTrueImpl::Constructor 00024 // Access: Public 00025 // Description: 00026 //////////////////////////////////////////////////////////////////// 00027 PipelineCyclerTrueImpl:: 00028 PipelineCyclerTrueImpl(CycleData *initial_data, Pipeline *pipeline) : 00029 _pipeline(pipeline), 00030 _dirty(false), 00031 _lock(this) 00032 { 00033 if (_pipeline == (Pipeline *)NULL) { 00034 _pipeline = Pipeline::get_render_pipeline(); 00035 } 00036 00037 _num_stages = _pipeline->get_num_stages(); 00038 _data = new CycleDataNode[_num_stages]; 00039 for (int i = 0; i < _num_stages; ++i) { 00040 _data[i]._cdata = initial_data; 00041 } 00042 00043 _pipeline->add_cycler(this); 00044 } 00045 00046 //////////////////////////////////////////////////////////////////// 00047 // Function: PipelineCyclerTrueImpl::Copy Constructor 00048 // Access: Public 00049 // Description: 00050 //////////////////////////////////////////////////////////////////// 00051 PipelineCyclerTrueImpl:: 00052 PipelineCyclerTrueImpl(const PipelineCyclerTrueImpl ©) : 00053 _pipeline(copy._pipeline), 00054 _dirty(false), 00055 _lock(this) 00056 { 00057 ReMutexHolder holder(_lock); 00058 ReMutexHolder holder2(copy._lock); 00059 00060 _num_stages = _pipeline->get_num_stages(); 00061 nassertv(_num_stages == copy._num_stages); 00062 _data = new CycleDataNode[_num_stages]; 00063 00064 // It's no longer critically important that we preserve pointerwise 00065 // equivalence between different stages in the copy, but it doesn't 00066 // cost much and might be a little more efficient, so we do it 00067 // anyway. 00068 typedef pmap<CycleData *, PT(CycleData) > Pointers; 00069 Pointers pointers; 00070 00071 for (int i = 0; i < _num_stages; ++i) { 00072 PT(CycleData) &new_pt = pointers[copy._data[i]._cdata]; 00073 if (new_pt == NULL) { 00074 new_pt = copy._data[i]._cdata->make_copy(); 00075 } 00076 _data[i]._cdata = new_pt.p(); 00077 } 00078 00079 _pipeline->add_cycler(this); 00080 if (copy._dirty) { 00081 _pipeline->add_dirty_cycler(this); 00082 } 00083 } 00084 00085 //////////////////////////////////////////////////////////////////// 00086 // Function: PipelineCyclerTrueImpl::Copy Assignment 00087 // Access: Public 00088 // Description: 00089 //////////////////////////////////////////////////////////////////// 00090 void PipelineCyclerTrueImpl:: 00091 operator = (const PipelineCyclerTrueImpl ©) { 00092 ReMutexHolder holder1(_lock); 00093 ReMutexHolder holder2(copy._lock); 00094 nassertv(get_parent_type() == copy.get_parent_type()); 00095 00096 typedef pmap<CycleData *, PT(CycleData) > Pointers; 00097 Pointers pointers; 00098 00099 for (int i = 0; i < _num_stages; ++i) { 00100 PT(CycleData) &new_pt = pointers[copy._data[i]._cdata]; 00101 if (new_pt == NULL) { 00102 new_pt = copy._data[i]._cdata->make_copy(); 00103 } 00104 _data[i]._cdata = new_pt.p(); 00105 } 00106 00107 if (copy._dirty && !_dirty) { 00108 _pipeline->add_dirty_cycler(this); 00109 } 00110 } 00111 00112 //////////////////////////////////////////////////////////////////// 00113 // Function: PipelineCyclerTrueImpl::Destructor 00114 // Access: Public 00115 // Description: 00116 //////////////////////////////////////////////////////////////////// 00117 PipelineCyclerTrueImpl:: 00118 ~PipelineCyclerTrueImpl() { 00119 ReMutexHolder holder(_lock); 00120 00121 _pipeline->remove_cycler(this); 00122 00123 delete[] _data; 00124 _data = NULL; 00125 _num_stages = 0; 00126 } 00127 00128 //////////////////////////////////////////////////////////////////// 00129 // Function: PipelineCyclerTrueImpl::write_stage 00130 // Access: Public 00131 // Description: Returns a pointer suitable for writing to the nth 00132 // stage of the pipeline. This is for special 00133 // applications that need to update the entire pipeline 00134 // at once (for instance, to remove an invalid pointer). 00135 // This pointer should later be released with 00136 // release_write_stage(). 00137 //////////////////////////////////////////////////////////////////// 00138 CycleData *PipelineCyclerTrueImpl:: 00139 write_stage(int pipeline_stage, Thread *current_thread) { 00140 _lock.acquire(current_thread); 00141 00142 #ifndef NDEBUG 00143 nassertd(pipeline_stage >= 0 && pipeline_stage < _num_stages) { 00144 _lock.release(); 00145 return NULL; 00146 } 00147 #endif // NDEBUG 00148 00149 CycleData *old_data = _data[pipeline_stage]._cdata; 00150 00151 // We only perform copy-on-write if this is the first CycleData 00152 // requested for write mode from this thread. (We will never have 00153 // outstanding writes for multiple threads, because we hold the 00154 // CyclerMutex during the entire lifetime of write() .. release()). 00155 if (_data[pipeline_stage]._writes_outstanding == 0) { 00156 // Only the node reference count is considered an important count 00157 // for copy-on-write purposes. A standard reference of other than 1 00158 // just means that some code (other that the PipelineCycler) has a 00159 // pointer, which is safe to modify. 00160 if (old_data->get_node_ref_count() != 1) { 00161 // Copy-on-write. 00162 _data[pipeline_stage]._cdata = old_data->make_copy(); 00163 if (pipeline_cat.is_debug()) { 00164 pipeline_cat.debug() 00165 << "Copy-on-write a: " << old_data << " becomes " 00166 << _data[pipeline_stage]._cdata << "\n"; 00167 //nassertr(false, NULL); 00168 } 00169 00170 // Now we have differences between some of the data pointers, so 00171 // we're "dirty". Mark it so. 00172 if (!_dirty && _num_stages != 1) { 00173 _pipeline->add_dirty_cycler(this); 00174 } 00175 } 00176 } 00177 00178 ++(_data[pipeline_stage]._writes_outstanding); 00179 return _data[pipeline_stage]._cdata; 00180 } 00181 00182 //////////////////////////////////////////////////////////////////// 00183 // Function: PipelineCyclerTrueImpl::write_stage_upstream 00184 // Access: Public 00185 // Description: This special variant on write_stage() will 00186 // automatically propagate changes back to upstream 00187 // pipeline stages. See write_upstream(). 00188 //////////////////////////////////////////////////////////////////// 00189 CycleData *PipelineCyclerTrueImpl:: 00190 write_stage_upstream(int pipeline_stage, bool force_to_0, Thread *current_thread) { 00191 _lock.acquire(current_thread); 00192 00193 #ifndef NDEBUG 00194 nassertd(pipeline_stage >= 0 && pipeline_stage < _num_stages) { 00195 _lock.release(); 00196 return NULL; 00197 } 00198 #endif // NDEBUG 00199 00200 CycleData *old_data = _data[pipeline_stage]._cdata; 00201 00202 if (old_data->get_ref_count() != 1 || force_to_0) { 00203 // Count the number of references before the current stage, and 00204 // the number of references remaining other than those. 00205 int external_count = old_data->get_ref_count() - 1; 00206 int k = pipeline_stage - 1; 00207 while (k >= 0 && _data[k]._cdata == old_data) { 00208 --k; 00209 --external_count; 00210 } 00211 00212 // We only perform copy-on-write if this is the first CycleData 00213 // requested for write mode from this thread. (We will never have 00214 // outstanding writes for multiple threads, because we hold the 00215 // CyclerMutex during the entire lifetime of write() 00216 // .. release()). 00217 if (external_count > 0 && _data[pipeline_stage]._writes_outstanding == 0) { 00218 // There are references other than the ones before this stage in 00219 // the pipeline; perform a copy-on-write. 00220 PT(CycleData) new_data = old_data->make_copy(); 00221 if (pipeline_cat.is_debug()) { 00222 pipeline_cat.debug() 00223 << "Copy-on-write b: " << old_data << " becomes " 00224 << new_data << "\n"; 00225 //nassertr(false, NULL); 00226 } 00227 00228 k = pipeline_stage - 1; 00229 while (k >= 0 && (_data[k]._cdata == old_data || force_to_0)) { 00230 nassertr(_data[k]._writes_outstanding == 0, NULL); 00231 _data[k]._cdata = new_data.p(); 00232 --k; 00233 } 00234 00235 _data[pipeline_stage]._cdata = new_data; 00236 00237 if (k >= 0 || pipeline_stage + 1 < _num_stages) { 00238 // Now we have differences between some of the data pointers, 00239 // which makes us "dirty". 00240 if (!_dirty) { 00241 _pipeline->add_dirty_cycler(this); 00242 } 00243 } 00244 00245 } else if (k >= 0 && force_to_0) { 00246 // There are no external pointers, so no need to copy-on-write, 00247 // but the current pointer doesn't go all the way back. Make it 00248 // do so. 00249 while (k >= 0) { 00250 nassertr(_data[k]._writes_outstanding == 0, NULL); 00251 _data[k]._cdata = old_data; 00252 --k; 00253 } 00254 } 00255 } 00256 00257 ++(_data[pipeline_stage]._writes_outstanding); 00258 return _data[pipeline_stage]._cdata; 00259 } 00260 00261 //////////////////////////////////////////////////////////////////// 00262 // Function: PipelineCyclerTrueImpl::cycle 00263 // Access: Private 00264 // Description: Cycles the data between frames. This is only called 00265 // from Pipeline::cycle(), and presumably it is only 00266 // called if the cycler is "dirty". 00267 // 00268 // At the conclusion of this method, the cycler should 00269 // clear its dirty flag if it is no longer "dirty"--that 00270 // is, if all of the pipeline pointers are the same. 00271 // 00272 // The return value is the CycleData pointer which fell 00273 // off the end of the cycle. If this is allowed to 00274 // destruct immediately, there may be side-effects that 00275 // cascade through the system, so the caller may choose 00276 // to hold the pointer until it can safely be released 00277 // later. 00278 //////////////////////////////////////////////////////////////////// 00279 PT(CycleData) PipelineCyclerTrueImpl:: 00280 cycle() { 00281 PT(CycleData) last_val = _data[_num_stages - 1]._cdata.p(); 00282 nassertr(_lock.debug_is_locked(), last_val); 00283 nassertr(_dirty, last_val); 00284 00285 int i; 00286 for (i = _num_stages - 1; i > 0; --i) { 00287 nassertr(_data[i]._writes_outstanding == 0, last_val); 00288 _data[i]._cdata = _data[i - 1]._cdata; 00289 } 00290 00291 for (i = 1; i < _num_stages; ++i) { 00292 if (_data[i]._cdata != _data[i - 1]._cdata) { 00293 // Still dirty. 00294 return last_val; 00295 } 00296 } 00297 00298 // No longer dirty. 00299 _dirty = false; 00300 return last_val; 00301 } 00302 00303 //////////////////////////////////////////////////////////////////// 00304 // Function: PipelineCyclerTrueImpl::set_num_stages 00305 // Access: Private 00306 // Description: Changes the number of stages in the cycler. This is 00307 // only called from Pipeline::set_num_stages(); 00308 //////////////////////////////////////////////////////////////////// 00309 void PipelineCyclerTrueImpl:: 00310 set_num_stages(int num_stages) { 00311 nassertv(_lock.debug_is_locked()); 00312 00313 if (num_stages <= _num_stages) { 00314 // Don't bother to reallocate the array smaller; we just won't use 00315 // the rest of the array. 00316 for (int i = _num_stages; i < num_stages; ++i) { 00317 nassertv(_data[i]._writes_outstanding == 0); 00318 _data[i]._cdata.clear(); 00319 } 00320 00321 _num_stages = num_stages; 00322 00323 00324 } else { 00325 // To increase the array, we must reallocate it larger. 00326 CycleDataNode *new_data = new CycleDataNode[num_stages]; 00327 int i; 00328 for (i = 0; i < _num_stages; ++i) { 00329 nassertv(_data[i]._writes_outstanding == 0); 00330 new_data[i]._cdata = _data[i]._cdata; 00331 } 00332 for (i = _num_stages; i < num_stages; ++i) { 00333 new_data[i]._cdata = _data[_num_stages - 1]._cdata; 00334 } 00335 delete[] _data; 00336 00337 _num_stages = num_stages; 00338 _data = new_data; 00339 } 00340 } 00341 00342 #ifdef DEBUG_THREADS 00343 //////////////////////////////////////////////////////////////////// 00344 // Function: PipelineCyclerTrueImpl::CyclerMutex::output 00345 // Access: Public, Virtual 00346 // Description: 00347 //////////////////////////////////////////////////////////////////// 00348 void PipelineCyclerTrueImpl::CyclerMutex:: 00349 output(ostream &out) const { 00350 out << "CyclerMutex "; 00351 _cycler->cheat()->output(out); 00352 } 00353 #endif // DEBUG_THREADS 00354 00355 #endif // THREADED_PIPELINE 00356 00357