00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
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
00024
00025
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
00048
00049
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
00065
00066
00067
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
00087
00088
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
00114
00115
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
00130
00131
00132
00133
00134
00135
00136
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
00152
00153
00154
00155 if (_data[pipeline_stage]._writes_outstanding == 0) {
00156
00157
00158
00159
00160 if (old_data->get_node_ref_count() != 1) {
00161
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
00168 }
00169
00170
00171
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
00184
00185
00186
00187
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
00204
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
00213
00214
00215
00216
00217 if (external_count > 0 && _data[pipeline_stage]._writes_outstanding == 0) {
00218
00219
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
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
00239
00240 if (!_dirty) {
00241 _pipeline->add_dirty_cycler(this);
00242 }
00243 }
00244
00245 } else if (k >= 0 && force_to_0) {
00246
00247
00248
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
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
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
00294 return last_val;
00295 }
00296 }
00297
00298
00299 _dirty = false;
00300 return last_val;
00301 }
00302
00303
00304
00305
00306
00307
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
00315
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
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
00345
00346
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