Panda3D
Loading...
Searching...
No Matches
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 */
17INLINE PipelineCyclerDummyImpl::
18PipelineCyclerDummyImpl(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) {
27 }
28}
29
30/**
31 *
32 */
33INLINE PipelineCyclerDummyImpl::
34PipelineCyclerDummyImpl(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 */
46INLINE void PipelineCyclerDummyImpl::
47operator = (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 */
56INLINE 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 */
65INLINE void PipelineCyclerDummyImpl::
66acquire(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 */
75INLINE void PipelineCyclerDummyImpl::
76release() {
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 */
91INLINE const CycleData *PipelineCyclerDummyImpl::
92read_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 */
105INLINE const CycleData *PipelineCyclerDummyImpl::
106read(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 */
121INLINE void PipelineCyclerDummyImpl::
122increment_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 */
134INLINE void PipelineCyclerDummyImpl::
135release_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 */
155INLINE CycleData *PipelineCyclerDummyImpl::
156write(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 */
190CycleData *PipelineCyclerDummyImpl::
191write_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 */
202INLINE CycleData *PipelineCyclerDummyImpl::
203elevate_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 */
214INLINE CycleData *PipelineCyclerDummyImpl::
215elevate_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 */
225INLINE void PipelineCyclerDummyImpl::
226increment_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 */
238INLINE void PipelineCyclerDummyImpl::
239release_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 */
249INLINE int PipelineCyclerDummyImpl::
250get_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 */
259INLINE const CycleData *PipelineCyclerDummyImpl::
260read_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 */
274INLINE const CycleData *PipelineCyclerDummyImpl::
275read_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 */
290INLINE void PipelineCyclerDummyImpl::
291release_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 */
307INLINE CycleData *PipelineCyclerDummyImpl::
308write_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 */
321INLINE CycleData *PipelineCyclerDummyImpl::
322write_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 */
334INLINE CycleData *PipelineCyclerDummyImpl::
335elevate_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 */
347INLINE CycleData *PipelineCyclerDummyImpl::
348elevate_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 */
359INLINE void PipelineCyclerDummyImpl::
360release_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 */
371INLINE TypeHandle PipelineCyclerDummyImpl::
372get_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 */
382INLINE CycleData *PipelineCyclerDummyImpl::
383cheat() 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 */
391INLINE int PipelineCyclerDummyImpl::
392get_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 */
401INLINE int PipelineCyclerDummyImpl::
402get_write_count() const {
403 return _write_count;
404}
A single page of data maintained by a PipelineCycler.
Definition cycleData.h:50
This class manages a staged pipeline of data, for instance the render pipeline, so that each stage of...
Definition pipeline.h:38
static Pipeline * get_render_pipeline()
Returns a pointer to the global render pipeline.
Definition pipeline.I:18
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