Panda3D
pipelineCyclerDummyImpl.I
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file pipelineCyclerDummyImpl.I
10  * @author drose
11  * @date 2006-01-31
12  */
13 
14 /**
15  *
16  */
17 INLINE PipelineCyclerDummyImpl::
18 PipelineCyclerDummyImpl(CycleData *initial_data, Pipeline *pipeline) :
19  _data(initial_data),
20  _pipeline(pipeline),
21  _read_count(0),
22  _write_count(0),
23  _locked(false)
24 {
25  if (_pipeline == nullptr) {
26  _pipeline = Pipeline::get_render_pipeline();
27  }
28 }
29 
30 /**
31  *
32  */
33 INLINE PipelineCyclerDummyImpl::
34 PipelineCyclerDummyImpl(const PipelineCyclerDummyImpl &copy) :
35  _data(copy._data->make_copy()),
36  _pipeline(copy._pipeline),
37  _read_count(0),
38  _write_count(0),
39  _locked(false)
40 {
41 }
42 
43 /**
44  *
45  */
46 INLINE void PipelineCyclerDummyImpl::
47 operator = (const PipelineCyclerDummyImpl &copy) {
48  nassertv(_read_count == 0 && _write_count == 0);
49  _data = copy._data->make_copy();
50  _pipeline = copy._pipeline;
51 }
52 
53 /**
54  *
55  */
56 INLINE PipelineCyclerDummyImpl::
57 ~PipelineCyclerDummyImpl() {
58  nassertv(_read_count == 0 && _write_count == 0 && !_locked);
59 }
60 
61 /**
62  * Grabs an overall lock on the cycler. Release it with a call to release().
63  * This lock should be held while walking the list of stages.
64  */
65 INLINE void PipelineCyclerDummyImpl::
66 acquire(Thread *) {
67  TAU_PROFILE("void PipelineCyclerDummyImpl::acquire(Thread *)", " ", TAU_USER);
68  nassertv(!_locked);
69  _locked = true;
70 }
71 
72 /**
73  * Release the overall lock on the cycler that was grabbed via acquire().
74  */
75 INLINE void PipelineCyclerDummyImpl::
76 release() {
77  TAU_PROFILE("void PipelineCyclerDummyImpl::release()", " ", TAU_USER);
78  nassertv(_locked);
79  _locked = false;
80 }
81 
82 /**
83  * Returns a const CycleData pointer, filled with the data for the current
84  * stage of the pipeline as seen by this thread. No lock is made on the
85  * contents; there is no guarantee that some other thread won't modify this
86  * object's data while you are working on it. (However, the data within the
87  * returned CycleData object itself is safe from modification; if another
88  * thread modifies the data, it will perform a copy-on-write, and thereby
89  * change the pointer stored within the object.)
90  */
91 INLINE const CycleData *PipelineCyclerDummyImpl::
92 read_unlocked(Thread *current_thread) const {
93  TAU_PROFILE("const CycleData *PipelineCyclerDummyImpl::read_unlocked()", " ", TAU_USER);
94  return _data;
95 }
96 
97 /**
98  * Returns a const CycleData pointer, filled with the data for the current
99  * stage of the pipeline as seen by this thread. This pointer should
100  * eventually be released by calling release_read().
101  *
102  * There should be no outstanding write pointers on the data when this
103  * function is called.
104  */
105 INLINE const CycleData *PipelineCyclerDummyImpl::
106 read(Thread *) const {
107  TAU_PROFILE("const CycleData *PipelineCyclerDummyImpl::read()", " ", TAU_USER);
108  // This function isn't truly const, but it doesn't change the data in any
109  // meaningful way, so we pretend it is.
110  ((PipelineCyclerDummyImpl *)this)->_read_count++;
111 
112  // It's not an error to grab a read pointer while someone else holds a read
113  // or a write pointer.
114  return _data;
115 }
116 
117 /**
118  * Increments the count on a pointer previously retrieved by read(); now the
119  * pointer will need to be released twice.
120  */
121 INLINE void PipelineCyclerDummyImpl::
122 increment_read(const CycleData *pointer) const {
123  TAU_PROFILE("void PipelineCyclerDummyImpl::increment_read(const CycleData *)", " ", TAU_USER);
124  // This function isn't truly const, but it doesn't change the data in any
125  // meaningful way, so we pretend it is.
126  nassertv(pointer == _data);
127  nassertv(_read_count > 0);
128  ((PipelineCyclerDummyImpl *)this)->_read_count++;
129 }
130 
131 /**
132  * Releases a pointer previously obtained via a call to read().
133  */
134 INLINE void PipelineCyclerDummyImpl::
135 release_read(const CycleData *pointer) const {
136  TAU_PROFILE("void PipelineCyclerDummyImpl::release_read(const CycleData *)", " ", TAU_USER);
137  // This function isn't truly const, but it doesn't change the data in any
138  // meaningful way, so we pretend it is.
139  nassertv(pointer == _data);
140  nassertv(_read_count > 0);
141  ((PipelineCyclerDummyImpl *)this)->_read_count--;
142 }
143 
144 /**
145  * Returns a non-const CycleData pointer, filled with a unique copy of the
146  * data for the current stage of the pipeline as seen by this thread. This
147  * pointer may now be used to write to the data, and that copy of the data
148  * will be propagated to all later stages of the pipeline. This pointer
149  * should eventually be released by calling release_write().
150  *
151  * There may only be one outstanding write pointer on a given stage at a time,
152  * and if there is a write pointer there may be no read pointers on the same
153  * stage (but see elevate_read).
154  */
155 INLINE CycleData *PipelineCyclerDummyImpl::
156 write(Thread *current_thread) {
157  TAU_PROFILE("CycleData *PipelineCyclerDummyImpl::write()", " ", TAU_USER);
158  _write_count++;
159 
160  // It's an error to grab a write pointer while someone else holds a read
161  // pointer, because doing so may invalidate the read pointer.
162  nassertr(_read_count == 0, _data);
163 
164  // It's not an error to do this while someone else holds a write pointer,
165  // however.
166 
167  return _data;
168 }
169 
170 /**
171  * This special variant on write() will automatically propagate changes back
172  * to upstream pipeline stages. If force_to_0 is false, then it propagates
173  * back only as long as the CycleData pointers are equivalent, guaranteeing
174  * that it does not modify upstream data (other than the modification that
175  * will be performed by the code that returns this pointer). This is
176  * particularly appropriate for minor updates, where it doesn't matter much if
177  * the update is lost, such as storing a cached value.
178  *
179  * If force_to_0 is dummy, then the CycleData pointer for the current pipeline
180  * stage is propagated all the way back up to stage 0; after this call, there
181  * will be only one CycleData pointer that is duplicated in all stages between
182  * stage 0 and the current stage. This may undo some recent changes that were
183  * made independently at pipeline stage 0 (or any other upstream stage).
184  * However, it guarantees that the change that is to be applied at this
185  * pipeline stage will stick. This is slightly dangerous because of the risk
186  * of losing upstream changes; generally, this should only be done when you
187  * are confident that there are no upstream changes to be lost (for instance,
188  * for an object that has been recently created).
189  */
190 CycleData *PipelineCyclerDummyImpl::
191 write_upstream(bool, Thread *) {
192  TAU_PROFILE("CycleData *PipelineCyclerDummyImpl::write_upstream(bool)", " ", TAU_USER);
193  _write_count++;
194  return _data;
195 }
196 
197 /**
198  * Elevates a currently-held read pointer into a write pointer. This may or
199  * may not change the value of the pointer. It is only valid to do this if
200  * this is the only currently-outstanding read pointer on the current stage.
201  */
202 INLINE CycleData *PipelineCyclerDummyImpl::
203 elevate_read(const CycleData *pointer, Thread *current_thread) {
204  TAU_PROFILE("CycleData *PipelineCyclerDummyImpl::elevate_read(const CycleData *)", " ", TAU_USER);
205  release_read(pointer);
206  return write(current_thread);
207 }
208 
209 /**
210  * Elevates a currently-held read pointer into a write pointer, like
211  * elevate_read(), but also propagates the pointer back to upstream stages,
212  * like write_upstream().
213  */
214 INLINE CycleData *PipelineCyclerDummyImpl::
215 elevate_read_upstream(const CycleData *pointer, bool force_to_0, Thread *current_thread) {
216  TAU_PROFILE("CycleData *PipelineCyclerDummyImpl::elevate_read_upstream(const CycleData *, bool)", " ", TAU_USER);
217  release_read(pointer);
218  return write_upstream(force_to_0, current_thread);
219 }
220 
221 /**
222  * Increments the count on a pointer previously retrieved by write(); now the
223  * pointer will need to be released twice.
224  */
225 INLINE void PipelineCyclerDummyImpl::
226 increment_write(CycleData *pointer) const {
227  TAU_PROFILE("void PipelineCyclerDummyImpl::increment_write(CycleData *)", " ", TAU_USER);
228  // This function isn't truly const, but it doesn't change the data in any
229  // meaningful way, so we pretend it is.
230  nassertv(pointer == _data);
231  nassertv(_write_count > 0);
232  ((PipelineCyclerDummyImpl *)this)->_write_count++;
233 }
234 
235 /**
236  * Releases a pointer previously obtained via a call to write().
237  */
238 INLINE void PipelineCyclerDummyImpl::
239 release_write(CycleData *pointer) {
240  TAU_PROFILE("void PipelineCyclerDummyImpl::release_write(CycleData *)", " ", TAU_USER);
241  nassertv(pointer == _data);
242  nassertv(_write_count > 0);
243  _write_count--;
244 }
245 
246 /**
247  * Returns the number of stages in the pipeline.
248  */
249 INLINE int PipelineCyclerDummyImpl::
250 get_num_stages() {
251  return 1;
252 }
253 
254 /**
255  * Returns a const CycleData pointer, filled with the data for the indicated
256  * stage of the pipeline. As in read_unlocked(), no lock is held on the
257  * returned pointer.
258  */
259 INLINE const CycleData *PipelineCyclerDummyImpl::
260 read_stage_unlocked(int pipeline_stage) const {
261  TAU_PROFILE("const CycleData *PipelineCyclerDummyImpl::read_stage_unlocked(int)", " ", TAU_USER);
262  nassertr(pipeline_stage == 0, nullptr);
263  return _data;
264 }
265 
266 /**
267  * Returns a const CycleData pointer, filled with the data for the indicated
268  * stage of the pipeline. This pointer should eventually be released by
269  * calling release_read_stage().
270  *
271  * There should be no outstanding write pointers on the data when this
272  * function is called.
273  */
274 INLINE const CycleData *PipelineCyclerDummyImpl::
275 read_stage(int pipeline_stage, Thread *) const {
276  TAU_PROFILE("const CycleData *PipelineCyclerDummyImpl::read_stage(int, Thread *)", " ", TAU_USER);
277  // This function isn't truly const, but it doesn't change the data in any
278  // meaningful way, so we pretend it is.
279  nassertr(pipeline_stage == 0, nullptr);
280  ((PipelineCyclerDummyImpl *)this)->_read_count++;
281 
282  // It's not an error to grab a read pointer while someone else holds a read
283  // or a write pointer.
284  return _data;
285 }
286 
287 /**
288  * Releases a pointer previously obtained via a call to read_stage().
289  */
290 INLINE void PipelineCyclerDummyImpl::
291 release_read_stage(int pipeline_stage, const CycleData *pointer) const {
292  TAU_PROFILE("void PipelineCyclerDummyImpl::release_read_stage(int, const CycleData *)", " ", TAU_USER);
293  // This function isn't truly const, but it doesn't change the data in any
294  // meaningful way, so we pretend it is.
295  nassertv(pipeline_stage == 0);
296  nassertv(pointer == _data);
297  nassertv(_read_count > 0);
298  ((PipelineCyclerDummyImpl *)this)->_read_count--;
299 }
300 
301 /**
302  * Returns a pointer suitable for writing to the nth stage of the pipeline.
303  * This is for special applications that need to update the entire pipeline at
304  * once (for instance, to remove an invalid pointer). This pointer should
305  * later be released with release_write_stage().
306  */
307 INLINE CycleData *PipelineCyclerDummyImpl::
308 write_stage(int pipeline_stage, Thread *) {
309  TAU_PROFILE("CycleData *PipelineCyclerDummyImpl::write_stage(int)", " ", TAU_USER);
310  nassertr(pipeline_stage == 0, nullptr);
311  _write_count++;
312  return _data;
313 }
314 
315 /**
316  * Returns a pointer suitable for writing to the nth stage of the pipeline.
317  * This is for special applications that need to update the entire pipeline at
318  * once (for instance, to remove an invalid pointer). This pointer should
319  * later be released with release_write_stage().
320  */
321 INLINE CycleData *PipelineCyclerDummyImpl::
322 write_stage_upstream(int pipeline_stage, bool, Thread *) {
323  TAU_PROFILE("CycleData *PipelineCyclerDummyImpl::write_stage_upstream(int)", " ", TAU_USER);
324  nassertr(pipeline_stage == 0, nullptr);
325  _write_count++;
326  return _data;
327 }
328 
329 /**
330  * Elevates a currently-held read pointer into a write pointer. This may or
331  * may not change the value of the pointer. It is only valid to do this if
332  * this is the only currently-outstanding read pointer on the current stage.
333  */
334 INLINE CycleData *PipelineCyclerDummyImpl::
335 elevate_read_stage(int pipeline_stage, const CycleData *pointer, Thread *current_thread) {
336  TAU_PROFILE("CycleData *PipelineCyclerDummyImpl::elevate_read_stage(int, CycleData *)", " ", TAU_USER);
337  nassertr(pipeline_stage == 0, nullptr);
338  release_read(pointer);
339  return write(current_thread);
340 }
341 
342 /**
343  * Elevates a currently-held read pointer into a write pointer. This may or
344  * may not change the value of the pointer. It is only valid to do this if
345  * this is the only currently-outstanding read pointer on the current stage.
346  */
347 INLINE CycleData *PipelineCyclerDummyImpl::
348 elevate_read_stage_upstream(int pipeline_stage, const CycleData *pointer,
349  bool, Thread *current_thread) {
350  TAU_PROFILE("CycleData *PipelineCyclerDummyImpl::elevate_read_stage(int, CycleData *)", " ", TAU_USER);
351  nassertr(pipeline_stage == 0, nullptr);
352  release_read(pointer);
353  return write(current_thread);
354 }
355 
356 /**
357  * Releases a pointer previously obtained via a call to write_stage().
358  */
359 INLINE void PipelineCyclerDummyImpl::
360 release_write_stage(int pipeline_stage, CycleData *pointer) {
361  TAU_PROFILE("void PipelineCyclerDummyImpl::release_write_stage(int, CycleData *)", " ", TAU_USER);
362  nassertv(pipeline_stage == 0 && pointer == _data);
363  nassertv(_write_count > 0);
364  _write_count--;
365 }
366 
367 /**
368  * Returns the type of object that owns this cycler, as reported by
369  * CycleData::get_parent_type().
370  */
371 INLINE TypeHandle PipelineCyclerDummyImpl::
372 get_parent_type() const {
373  return _data->get_parent_type();
374 }
375 
376 /**
377  * Returns a pointer without counting it. This is only intended for use as
378  * the return value for certain nassertr() functions, so the application can
379  * recover after a failure to manage the read and write pointers correctly.
380  * You should never call this function directly.
381  */
382 INLINE CycleData *PipelineCyclerDummyImpl::
383 cheat() const {
384  return _data;
385 }
386 
387 /**
388  * Returns the number of handles currently outstanding to read the current
389  * stage of the data. This should only be used for debugging purposes.
390  */
391 INLINE int PipelineCyclerDummyImpl::
392 get_read_count() const {
393  return _read_count;
394 }
395 
396 /**
397  * Returns the number of handles currently outstanding to read the current
398  * stage of the data. This will normally only be either 0 or 1. This should
399  * only be used for debugging purposes.
400  */
401 INLINE int PipelineCyclerDummyImpl::
402 get_write_count() const {
403  return _write_count;
404 }
A single page of data maintained by a PipelineCycler.
Definition: cycleData.h:47
static Pipeline * get_render_pipeline()
Returns a pointer to the global render pipeline.
Definition: pipeline.I:18
This class manages a staged pipeline of data, for instance the render pipeline, so that each stage of...
Definition: pipeline.h:38
A thread; that is, a lightweight process.
Definition: thread.h:46
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81