Panda3D
geomVertexArrayData.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 geomVertexArrayData.I
10  * @author drose
11  * @date 2005-03-17
12  */
13 
14 /**
15  * Returns the format object that describes this array.
16  */
17 INLINE const GeomVertexArrayFormat *GeomVertexArrayData::
18 get_array_format() const {
19  return _array_format;
20 }
21 
22 /**
23  * Returns the usage hint that describes to the rendering backend how often
24  * the vertex data will be modified and/or rendered. See geomEnums.h.
25  */
26 INLINE GeomVertexArrayData::UsageHint GeomVertexArrayData::
27 get_usage_hint() const {
28  CDReader cdata(_cycler);
29  return cdata->_usage_hint;
30 }
31 
32 /**
33  * Returns true if the array has the named column, false otherwise. This is
34  * really just a shortcut for asking the same thing from the format.
35  */
36 INLINE bool GeomVertexArrayData::
37 has_column(const InternalName *name) const {
38  return _array_format->has_column(name);
39 }
40 
41 /**
42  * Returns the number of rows stored in the array, based on the number of
43  * bytes and the stride. This should be the same for all arrays within a
44  * given GeomVertexData object.
45  */
46 INLINE int GeomVertexArrayData::
47 get_num_rows() const {
48  CDReader cdata(_cycler);
49  nassertr(_array_format->get_stride() != 0, 0);
50  return cdata->_buffer.get_size() / _array_format->get_stride();
51 }
52 
53 /**
54  * Sets the length of the array to n rows.
55  *
56  * Normally, you would not call this directly, since all of the arrays in a
57  * particular GeomVertexData must have the same number of rows; instead, call
58  * GeomVertexData::set_num_rows().
59  *
60  * The return value is true if the number of rows was changed, false if the
61  * object already contained n rows (or if there was some error).
62  *
63  * The new vertex data is initialized to 0, including the "color" column (but
64  * see GeomVertexData::set_num_rows()).
65  *
66  * Don't call this in a downstream thread unless you don't mind it blowing
67  * away other changes you might have recently made in an upstream thread.
68  */
69 INLINE bool GeomVertexArrayData::
70 set_num_rows(int n) {
71  return modify_handle()->set_num_rows(n);
72 }
73 
74 /**
75  * This method behaves like set_num_rows(), except the new data is not
76  * initialized. Furthermore, after this call, *any* of the data in the
77  * GeomVertexArrayData may be uninitialized, including the earlier rows.
78  *
79  * Normally, you would not call this directly, since all of the arrays in a
80  * particular GeomVertexData must have the same number of rows; instead, call
81  * GeomVertexData::unclean_set_num_rows().
82  */
83 INLINE bool GeomVertexArrayData::
85  return modify_handle()->unclean_set_num_rows(n);
86 }
87 
88 /**
89  * This ensures that enough memory space for n rows is allocated, so that you
90  * may increase the number of rows to n without causing a new memory
91  * allocation. This is a performance optimization only; it is especially
92  * useful when you know ahead of time that you will be adding n rows to the
93  * data.
94  */
95 INLINE bool GeomVertexArrayData::
97  return modify_handle()->reserve_num_rows(n);
98 }
99 
100 /**
101  * Removes all of the rows in the array. Functionally equivalent to
102  * set_num_rows(0).
103  */
104 INLINE void GeomVertexArrayData::
106  return modify_handle()->clear_rows();
107 }
108 
109 /**
110  * Returns the number of bytes stored in the array.
111  */
112 INLINE size_t GeomVertexArrayData::
113 get_data_size_bytes() const {
114  CDReader cdata(_cycler);
115  return cdata->_buffer.get_size();
116 }
117 
118 /**
119  * Returns a sequence number which is guaranteed to change at least every time
120  * the array vertex data is modified.
121  */
122 INLINE UpdateSeq GeomVertexArrayData::
123 get_modified() const {
124  CDReader cdata(_cycler);
125  return cdata->_modified;
126 }
127 
128 /**
129  * Returns true if the vertex data is currently resident in memory. If this
130  * returns true, the next call to get_handle()->get_read_pointer() will
131  * probably not block. If this returns false, the vertex data will be brought
132  * back into memory shortly; try again later.
133  */
134 INLINE bool GeomVertexArrayData::
135 request_resident(Thread *current_thread) const {
136  const GeomVertexArrayData::CData *cdata = _cycler.read_unlocked(current_thread);
137 
138 #ifdef DO_PIPELINING
139  cdata->ref();
140 #endif
141 
142  cdata->_rw_lock.acquire();
143 
144  ((GeomVertexArrayData *)this)->mark_used();
145  bool is_resident = (cdata->_buffer.get_read_pointer(false) != nullptr);
146 
147  cdata->_rw_lock.release();
148 
149 #ifdef DO_PIPELINING
150  unref_delete((CycleData *)cdata);
151 #endif
152 
153  return is_resident;
154 }
155 
156 /**
157  * Returns an object that can be used to read the actual data bytes stored in
158  * the array. Calling this method locks the data, and will block any other
159  * threads attempting to read or write the data, until the returned object
160  * destructs.
161  */
162 INLINE CPT(GeomVertexArrayDataHandle) GeomVertexArrayData::
163 get_handle(Thread *current_thread) const {
164  return new GeomVertexArrayDataHandle(this, current_thread);
165 }
166 
167 /**
168  * Returns an object that can be used to read or write the actual data bytes
169  * stored in the array. Calling this method locks the data, and will block
170  * any other threads attempting to read or write the data, until the returned
171  * object destructs.
172  */
173 INLINE PT(GeomVertexArrayDataHandle) GeomVertexArrayData::
174 modify_handle(Thread *current_thread) {
175  return new GeomVertexArrayDataHandle(PT(GeomVertexArrayData)(this), current_thread);
176 }
177 
178 /**
179  * Returns a pointer to the global LRU object that manages the
180  * GeomVertexArrayData's that have not (yet) been paged out.
181  */
184  return &_independent_lru;
185 }
186 
187 /**
188  * Returns a pointer to the global LRU object that manages the
189  * GeomVertexArrayData's that are deemed too small to be paged out.
190  */
193  return &_small_lru;
194 }
195 
196 /**
197  * Returns the global VertexDataBook that will be used to allocate vertex data
198  * buffers.
199  */
202  return _book;
203 }
204 
205 /**
206  * Should be called when the size of the buffer changes.
207  */
208 INLINE void GeomVertexArrayData::
209 set_lru_size(size_t lru_size) {
210  SimpleLruPage::set_lru_size(lru_size);
211 
212  if ((int)lru_size <= vertex_data_small_size) {
213  SimpleLruPage::mark_used_lru(&_small_lru);
214  } else {
215  SimpleLruPage::mark_used_lru(&_independent_lru);
216  }
217 }
218 
219 /**
220  */
221 INLINE void GeomVertexArrayData::
222 mark_used() {
223  if ((int)get_lru_size() <= vertex_data_small_size) {
224  SimpleLruPage::mark_used_lru(&_small_lru);
225  } else {
226  SimpleLruPage::mark_used_lru(&_independent_lru);
227  }
228 }
229 
230 /**
231  *
232  */
233 INLINE GeomVertexArrayData::CData::
234 CData(UsageHint usage_hint) :
235  _usage_hint(usage_hint),
236  _rw_lock("GeomVertexArrayData::CData::_rw_lock")
237 {
238 }
239 
240 /**
241  *
242  */
243 INLINE GeomVertexArrayData::CData::
244 CData(GeomVertexArrayData::CData &&from) noexcept :
245  _usage_hint(std::move(from._usage_hint)),
246  _buffer(std::move(from._buffer)),
247  _modified(std::move(from._modified)),
248  _rw_lock("GeomVertexArrayData::CData::_rw_lock")
249 {
250 }
251 
252 /**
253  *
254  */
255 INLINE GeomVertexArrayData::CData::
256 CData(const GeomVertexArrayData::CData &copy) :
257  _usage_hint(copy._usage_hint),
258  _buffer(copy._buffer),
259  _modified(copy._modified),
260  _rw_lock("GeomVertexArrayData::CData::_rw_lock")
261 {
262 }
263 
264 /**
265  *
266  */
267 INLINE void GeomVertexArrayData::CData::
268 operator = (const GeomVertexArrayData::CData &copy) {
269  _usage_hint = copy._usage_hint;
270  _buffer = copy._buffer;
271  _modified = copy._modified;
272 }
273 
274 /**
275  *
276  */
277 INLINE GeomVertexArrayDataHandle::
278 GeomVertexArrayDataHandle(CPT(GeomVertexArrayData) object,
279  Thread *current_thread) :
280  _current_thread(current_thread),
281  _cdata((GeomVertexArrayData::CData *)object->_cycler.read_unlocked(current_thread)),
282  _writable(false)
283 {
284  _object.swap(object);
285 
286 #ifdef _DEBUG
287  nassertv(_object->test_ref_count_nonzero());
288 #endif // _DEBUG
289 #ifdef DO_PIPELINING
290  _cdata->ref();
291 #endif // DO_PIPELINING
292  // We must grab the lock *after* we have incremented the reference count,
293  // above.
294  _cdata->_rw_lock.acquire();
295 #ifdef DO_MEMORY_USAGE
296  MemoryUsage::update_type(this, get_class_type());
297 #endif
298 }
299 
300 /**
301  *
302  */
303 INLINE GeomVertexArrayDataHandle::
304 GeomVertexArrayDataHandle(const GeomVertexArrayData *object,
305  Thread *current_thread) :
306  _object((GeomVertexArrayData *)object),
307  _current_thread(current_thread),
308  _cdata((GeomVertexArrayData::CData *)object->_cycler.read_unlocked(current_thread)),
309  _writable(false)
310 {
311 #ifdef _DEBUG
312  nassertv(_object->test_ref_count_nonzero());
313 #endif // _DEBUG
314 #ifdef DO_PIPELINING
315  _cdata->ref();
316 #endif // DO_PIPELINING
317  // We must grab the lock *after* we have incremented the reference count,
318  // above.
319  _cdata->_rw_lock.acquire();
320 #ifdef DO_MEMORY_USAGE
321  MemoryUsage::update_type(this, get_class_type());
322 #endif
323 }
324 
325 /**
326  *
327  */
328 INLINE GeomVertexArrayDataHandle::
329 GeomVertexArrayDataHandle(PT(GeomVertexArrayData) object,
330  Thread *current_thread) :
331  _current_thread(current_thread),
332  _cdata(object->_cycler.write_upstream(true, current_thread)),
333  _writable(true)
334 {
335  _object.swap(object);
336 
337 #ifdef _DEBUG
338  nassertv(_object->test_ref_count_nonzero());
339 #endif // _DEBUG
340 #ifdef DO_PIPELINING
341  _cdata->ref();
342 #endif // DO_PIPELINING
343  // We must grab the lock *after* we have incremented the reference count,
344  // above.
345  _cdata->_rw_lock.acquire();
346 #ifdef DO_MEMORY_USAGE
347  MemoryUsage::update_type(this, get_class_type());
348 #endif
349 }
350 
351 /**
352  *
353  */
354 INLINE GeomVertexArrayDataHandle::
355 GeomVertexArrayDataHandle(GeomVertexArrayData *object,
356  Thread *current_thread) :
357  _object(object),
358  _current_thread(current_thread),
359  _cdata(object->_cycler.write_upstream(true, current_thread)),
360  _writable(true)
361 {
362 #ifdef _DEBUG
363  nassertv(_object->test_ref_count_nonzero());
364 #endif // _DEBUG
365 #ifdef DO_PIPELINING
366  _cdata->ref();
367 #endif // DO_PIPELINING
368  // We must grab the lock *after* we have incremented the reference count,
369  // above.
370  _cdata->_rw_lock.acquire();
371 #ifdef DO_MEMORY_USAGE
372  MemoryUsage::update_type(this, get_class_type());
373 #endif
374 }
375 
376 /**
377  *
378  */
379 INLINE GeomVertexArrayDataHandle::
380 ~GeomVertexArrayDataHandle() {
381 #ifdef _DEBUG
382  nassertv(_object->test_ref_count_nonzero());
383 #endif // _DEBUG
384 
385  if (_writable) {
386  _object->_cycler.release_write(_cdata);
387  }
388 
389  // We must release the lock *before* we decrement the reference count,
390  // below.
391  _cdata->_rw_lock.release();
392 
393 #ifdef DO_PIPELINING
394  unref_delete((CycleData *)_cdata);
395 #endif // DO_PIPELINING
396 
397 #ifdef _DEBUG
398  _object = nullptr;
399  _cdata = nullptr;
400 #endif // _DEBUG
401 }
402 
403 /**
404  *
405  */
406 INLINE Thread *GeomVertexArrayDataHandle::
407 get_current_thread() const {
408  return _current_thread;
409 }
410 
411 /**
412  * Returns a readable pointer to the beginning of the actual data stream, or
413  * NULL if the data is not currently resident. If the data is not currently
414  * resident, this will implicitly request it to become resident soon.
415  *
416  * If force is true, this method will never return NULL, but may block until
417  * the data is available.
418  */
419 INLINE const unsigned char *GeomVertexArrayDataHandle::
420 get_read_pointer(bool force) const {
421  mark_used();
422  return _cdata->_buffer.get_read_pointer(force);
423 }
424 
425 /**
426  *
427  */
428 INLINE const GeomVertexArrayData *GeomVertexArrayDataHandle::
429 get_object() const {
430  return _object;
431 }
432 
433 /**
434  *
435  */
436 INLINE GeomVertexArrayData *GeomVertexArrayDataHandle::
437 get_object() {
438  return _object;
439 }
440 
441 /**
442  *
443  */
444 INLINE const GeomVertexArrayFormat *GeomVertexArrayDataHandle::
445 get_array_format() const {
446  return _object->_array_format;
447 }
448 
449 /**
450  *
451  */
452 INLINE GeomVertexArrayDataHandle::UsageHint GeomVertexArrayDataHandle::
453 get_usage_hint() const {
454  return _cdata->_usage_hint;
455 }
456 
457 /**
458  *
459  */
460 INLINE int GeomVertexArrayDataHandle::
461 get_num_rows() const {
462  nassertr(_object->_array_format->get_stride() != 0, 0);
463  return get_data_size_bytes() / _object->_array_format->get_stride();
464 }
465 
466 /**
467  *
468  */
469 INLINE void GeomVertexArrayDataHandle::
470 clear_rows() {
471  set_num_rows(0);
472 }
473 
474 /**
475  *
476  */
477 INLINE size_t GeomVertexArrayDataHandle::
478 get_data_size_bytes() const {
479  return _cdata->_buffer.get_size();
480 }
481 
482 /**
483  *
484  */
485 INLINE UpdateSeq GeomVertexArrayDataHandle::
486 get_modified() const {
487  return _cdata->_modified;
488 }
489 
490 /**
491  * Returns true if the vertex data is currently resident in memory. If this
492  * returns true, the next call to get_handle()->get_read_pointer() will
493  * probably not block. If this returns false, the vertex data will be brought
494  * back into memory shortly; try again later.
495  */
496 INLINE bool GeomVertexArrayDataHandle::
498  return (get_read_pointer(false) != nullptr);
499 }
500 
501 /**
502  * Creates a context for the data on the particular GSG, if it does not
503  * already exist. Returns the new (or old) VertexBufferContext. This assumes
504  * that the GraphicsStateGuardian is the currently active rendering context
505  * and that it is ready to accept new datas. If this is not necessarily the
506  * case, you should use prepare() instead.
507  *
508  * Normally, this is not called directly except by the GraphicsStateGuardian;
509  * a data does not need to be explicitly prepared by the user before it may be
510  * rendered.
511  */
514  GraphicsStateGuardianBase *gsg) const {
515  return _object->prepare_now(prepared_objects, gsg);
516 }
517 
518 /**
519  * Returns the entire raw data of the GeomVertexArrayData object, formatted as
520  * a string. This is primarily for the benefit of high-level languages such
521  * as Python.
522  */
523 INLINE vector_uchar GeomVertexArrayDataHandle::
524 get_data() const {
525  mark_used();
526  const unsigned char *ptr = _cdata->_buffer.get_read_pointer(true);
527  return vector_uchar(ptr, ptr + _cdata->_buffer.get_size());
528 }
529 
530 /**
531  * Returns a subset of the raw data of the GeomVertexArrayData object,
532  * formatted as a string. This is primarily for the benefit of high-level
533  * languages such as Python.
534  */
535 INLINE vector_uchar GeomVertexArrayDataHandle::
536 get_subdata(size_t start, size_t size) const {
537  mark_used();
538  start = std::min(start, _cdata->_buffer.get_size());
539  size = std::min(size, _cdata->_buffer.get_size() - start);
540  const unsigned char *ptr = _cdata->_buffer.get_read_pointer(true) + start;
541  return vector_uchar(ptr, ptr + size);
542 }
543 
544 /**
545  * Marks the array data recently-used.
546  */
548 mark_used() const {
549  _object->mark_used();
550 }
551 
552 INLINE std::ostream &
553 operator << (std::ostream &out, const GeomVertexArrayData &obj) {
554  obj.output(out);
555  return out;
556 }
An implementation of a very simple LRU algorithm.
Definition: simpleLru.h:28
static SimpleLru * get_small_lru()
Returns a pointer to the global LRU object that manages the GeomVertexArrayData's that are deemed too...
bool has_column(const InternalName *name) const
Returns true if the array has the named column, false otherwise.
bool request_resident(Thread *current_thread=Thread::get_current_thread()) const
Returns true if the vertex data is currently resident in memory.
void mark_used_lru() const
To be called when the page is used; this will move it to the tail of the SimpleLru queue it is alread...
Definition: simpleLru.I:152
A single page of data maintained by a PipelineCycler.
Definition: cycleData.h:47
static VertexDataBook & get_book()
Returns the global VertexDataBook that will be used to allocate vertex data buffers.
size_t get_lru_size() const
Returns the size of this page as reported to the LRU, presumably in bytes.
Definition: simpleLru.I:171
This data object is returned by GeomVertexArrayData::get_handle() or modify_handle().
A table of objects that are saved within the graphics context for reference by handle later.
bool request_resident() const
Returns true if the vertex data is currently resident in memory.
void set_lru_size(size_t lru_size)
Specifies the size of this page, presumably in bytes, although any unit is possible.
Definition: simpleLru.I:180
This template class calls PipelineCycler::read_unlocked(), and then provides a transparent read-only ...
bool reserve_num_rows(int n)
This ensures that enough memory space for n rows is allocated, so that you may increase the number of...
CPT(GeomVertexArrayDataHandle) GeomVertexArrayData
Returns an object that can be used to read the actual data bytes stored in the array.
VertexBufferContext * prepare_now(PreparedGraphicsObjects *prepared_objects, GraphicsStateGuardianBase *gsg) const
Creates a context for the data on the particular GSG, if it does not already exist.
Encodes a string name in a hash table, mapping it to a pointer.
Definition: internalName.h:38
A collection of VertexDataPages, which can be used to allocate new VertexDataBlock objects.
static void update_type(ReferenceCount *ptr, TypeHandle type)
Associates the indicated type with the given pointer.
Definition: memoryUsage.I:55
const unsigned char * get_read_pointer(bool force) const
Returns a readable pointer to the beginning of the actual data stream, or NULL if the data is not cur...
static SimpleLru * get_independent_lru()
Returns a pointer to the global LRU object that manages the GeomVertexArrayData's that have not (yet)...
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
int get_num_rows() const
Returns the number of rows stored in the array, based on the number of bytes and the stride.
const CycleDataType * read_unlocked(Thread *current_thread) const
See PipelineCyclerBase::read_unlocked().
void mark_used() const
Marks the array data recently-used.
A thread; that is, a lightweight process.
Definition: thread.h:46
This is a special class object that holds all the information returned by a particular GSG to indicat...
This describes the structure of a single array within a Geom data.
bool unclean_set_num_rows(int n)
This method behaves like set_num_rows(), except the new data is not initialized.
void clear_rows()
Removes all of the rows in the array.
This is a sequence number that increments monotonically.
Definition: updateSeq.h:37
bool set_num_rows(int n)
Sets the length of the array to n rows.
vector_uchar get_data() const
Returns the entire raw data of the GeomVertexArrayData object, formatted as a string.
void unref_delete(RefCountType *ptr)
This global helper function will unref the given ReferenceCount object, and if the reference count re...
This is the data for one array of a GeomVertexData structure.
vector_uchar get_subdata(size_t start, size_t size) const
Returns a subset of the raw data of the GeomVertexArrayData object, formatted as a string.