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 NPT(CycleData)[_num_stages]; 00039 for (int i = 0; i < _num_stages; ++i) { 00040 _data[i] = 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 NPT(CycleData)[_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]]; 00073 if (new_pt == NULL) { 00074 new_pt = copy._data[i]->make_copy(); 00075 } 00076 _data[i] = 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]]; 00101 if (new_pt == NULL) { 00102 new_pt = copy._data[i]->make_copy(); 00103 } 00104 _data[i] = 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]; 00150 00151 // Only the node reference count is considered an important count 00152 // for copy-on-write purposes. A standard reference of other than 1 00153 // just means that some code (other that the PipelineCycler) has a 00154 // pointer, which is safe to modify. 00155 if (old_data->get_node_ref_count() != 1) { 00156 // Copy-on-write. 00157 _data[pipeline_stage] = old_data->make_copy(); 00158 00159 // Now we have differences between some of the data pointers, so 00160 // we're "dirty". Mark it so. 00161 if (!_dirty && _num_stages != 1) { 00162 _pipeline->add_dirty_cycler(this); 00163 } 00164 } 00165 00166 return _data[pipeline_stage]; 00167 } 00168 00169 //////////////////////////////////////////////////////////////////// 00170 // Function: PipelineCyclerTrueImpl::write_stage_upstream 00171 // Access: Public 00172 // Description: This special variant on write_stage() will 00173 // automatically propagate changes back to upstream 00174 // pipeline stages. See write_upstream(). 00175 //////////////////////////////////////////////////////////////////// 00176 CycleData *PipelineCyclerTrueImpl:: 00177 write_stage_upstream(int pipeline_stage, bool force_to_0, Thread *current_thread) { 00178 _lock.acquire(current_thread); 00179 00180 #ifndef NDEBUG 00181 nassertd(pipeline_stage >= 0 && pipeline_stage < _num_stages) { 00182 _lock.release(); 00183 return NULL; 00184 } 00185 #endif // NDEBUG 00186 00187 CycleData *old_data = _data[pipeline_stage]; 00188 00189 if (old_data->get_ref_count() != 1 || force_to_0) { 00190 // Count the number of references before the current stage, and 00191 // the number of references remaining other than those. 00192 int external_count = old_data->get_ref_count() - 1; 00193 int k = pipeline_stage - 1; 00194 while (k >= 0 && _data[k] == old_data) { 00195 --k; 00196 --external_count; 00197 } 00198 00199 if (external_count > 0) { 00200 // There are references other than the ones before this stage in 00201 // the pipeline; perform a copy-on-write. 00202 PT(CycleData) new_data = old_data->make_copy(); 00203 00204 k = pipeline_stage - 1; 00205 while (k >= 0 && (_data[k] == old_data || force_to_0)) { 00206 _data[k] = new_data.p(); 00207 --k; 00208 } 00209 00210 _data[pipeline_stage] = new_data; 00211 00212 if (k >= 0 || pipeline_stage + 1 < _num_stages) { 00213 // Now we have differences between some of the data pointers, 00214 // which makes us "dirty". 00215 if (!_dirty) { 00216 _pipeline->add_dirty_cycler(this); 00217 } 00218 } 00219 00220 } else if (k >= 0 && force_to_0) { 00221 // There are no external pointers, so no need to copy-on-write, 00222 // but the current pointer doesn't go all the way back. Make it 00223 // do so. 00224 while (k >= 0) { 00225 _data[k] = old_data; 00226 --k; 00227 } 00228 } 00229 } 00230 00231 return _data[pipeline_stage]; 00232 } 00233 00234 //////////////////////////////////////////////////////////////////// 00235 // Function: PipelineCyclerTrueImpl::cycle 00236 // Access: Private 00237 // Description: Cycles the data between frames. This is only called 00238 // from Pipeline::cycle(), and presumably it is only 00239 // called if the cycler is "dirty". 00240 // 00241 // At the conclusion of this method, the cycler should 00242 // clear its dirty flag if it is no longer "dirty"--that 00243 // is, if all of the pipeline pointers are the same. 00244 // 00245 // The return value is the CycleData pointer which fell 00246 // off the end of the cycle. If this is allowed to 00247 // destruct immediately, there may be side-effects that 00248 // cascade through the system, so the caller may choose 00249 // to hold the pointer until it can safely be released 00250 // later. 00251 //////////////////////////////////////////////////////////////////// 00252 PT(CycleData) PipelineCyclerTrueImpl:: 00253 cycle() { 00254 PT(CycleData) last_val = _data[_num_stages - 1].p(); 00255 nassertr(_lock.debug_is_locked(), last_val); 00256 nassertr(_dirty, last_val); 00257 00258 int i; 00259 for (i = _num_stages - 1; i > 0; --i) { 00260 _data[i] = _data[i - 1]; 00261 } 00262 00263 for (i = 1; i < _num_stages; ++i) { 00264 if (_data[i] != _data[i - 1]) { 00265 // Still dirty. 00266 return last_val; 00267 } 00268 } 00269 00270 // No longer dirty. 00271 _dirty = false; 00272 return last_val; 00273 } 00274 00275 //////////////////////////////////////////////////////////////////// 00276 // Function: PipelineCyclerTrueImpl::set_num_stages 00277 // Access: Private 00278 // Description: Changes the number of stages in the cycler. This is 00279 // only called from Pipeline::set_num_stages(); 00280 //////////////////////////////////////////////////////////////////// 00281 void PipelineCyclerTrueImpl:: 00282 set_num_stages(int num_stages) { 00283 nassertv(_lock.debug_is_locked()); 00284 00285 if (num_stages <= _num_stages) { 00286 // Don't bother to reallocate the array smaller; we just won't use 00287 // the rest of the array. 00288 for (int i = _num_stages; i < num_stages; ++i) { 00289 _data[i].clear(); 00290 } 00291 00292 _num_stages = num_stages; 00293 00294 00295 } else { 00296 // To increase the array, we must reallocate it larger. 00297 NPT(CycleData) *new_data = new NPT(CycleData)[num_stages]; 00298 int i; 00299 for (i = 0; i < _num_stages; ++i) { 00300 new_data[i] = _data[i]; 00301 } 00302 for (i = _num_stages; i < num_stages; ++i) { 00303 new_data[i] = _data[_num_stages - 1]; 00304 } 00305 delete[] _data; 00306 00307 _num_stages = num_stages; 00308 _data = new_data; 00309 } 00310 } 00311 00312 #ifdef DEBUG_THREADS 00313 //////////////////////////////////////////////////////////////////// 00314 // Function: PipelineCyclerTrueImpl::CyclerMutex::output 00315 // Access: Public, Virtual 00316 // Description: 00317 //////////////////////////////////////////////////////////////////// 00318 void PipelineCyclerTrueImpl::CyclerMutex:: 00319 output(ostream &out) const { 00320 out << "CyclerMutex "; 00321 _cycler->cheat()->output(out); 00322 } 00323 #endif // DEBUG_THREADS 00324 00325 #endif // THREADED_PIPELINE 00326 00327