Panda3D
geomVertexArrayData.cxx
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.cxx
10  * @author drose
11  * @date 2005-03-17
12  */
13 
14 #include "geomVertexArrayData.h"
15 #include "geom.h"
17 #include "reversedNumericData.h"
18 #include "bamReader.h"
19 #include "bamWriter.h"
20 #include "pset.h"
21 #include "config_gobj.h"
22 #include "pStatTimer.h"
23 #include "configVariableInt.h"
24 #include "simpleAllocator.h"
25 #include "vertexDataBuffer.h"
26 #include "texture.h"
27 
28 using std::max;
29 using std::min;
30 
31 ConfigVariableInt max_independent_vertex_data
32 ("max-independent-vertex-data", -1,
33  PRC_DESC("Specifies the maximum number of bytes of all vertex data "
34  "that is independent of the paging system. This is an "
35  "initial buffer before max-ram-vertex-data, specifically "
36  "designed for vertex datas that are dynamic in nature and "
37  "may change size or be created and destroyed frequently."));
38 
39 ConfigVariableInt vertex_data_page_size
40 ("vertex-data-page-size", 262144,
41  PRC_DESC("The number of bytes to allocate at a time for vertex data. "
42  "This also controls the page size that is compressed or written "
43  "to disk when vertex data pages are evicted from memory."));
44 
45 SimpleLru GeomVertexArrayData::_independent_lru("independent", max_independent_vertex_data);
46 SimpleLru GeomVertexArrayData::_small_lru("small", max_independent_vertex_data);
47 
48 VertexDataBook GeomVertexArrayData::_book(vertex_data_page_size);
49 
50 
51 TypeHandle GeomVertexArrayData::_type_handle;
52 TypeHandle GeomVertexArrayData::CData::_type_handle;
53 TypeHandle GeomVertexArrayDataHandle::_type_handle;
54 
55 ALLOC_DELETED_CHAIN_DEF(GeomVertexArrayDataHandle);
56 
57 /**
58  * Constructs an invalid object. This is only used when reading from the bam
59  * file.
60  */
61 GeomVertexArrayData::
62 GeomVertexArrayData() : SimpleLruPage(0) {
63  _contexts = nullptr;
64 
65  // Can't put it in the LRU until it has been read in and made valid.
66 }
67 
68 /**
69  * Required to implement CopyOnWriteObject.
70  */
71 PT(CopyOnWriteObject) GeomVertexArrayData::
72 make_cow_copy() {
73  return new GeomVertexArrayData(*this);
74 }
75 
76 /**
77  *
78  */
79 GeomVertexArrayData::
80 GeomVertexArrayData(const GeomVertexArrayFormat *array_format,
81  GeomVertexArrayData::UsageHint usage_hint) :
82  SimpleLruPage(0),
83  _array_format(array_format),
84  _cycler(CData(usage_hint)),
85  _contexts(nullptr)
86 {
87  set_lru_size(0);
88  nassertv(_array_format->is_registered());
89 }
90 
91 /**
92  *
93  */
94 GeomVertexArrayData::
95 GeomVertexArrayData(const GeomVertexArrayData &copy) :
96  CopyOnWriteObject(copy),
97  SimpleLruPage(copy),
98  _array_format(copy._array_format),
99  _cycler(copy._cycler),
100  _contexts(nullptr)
101 {
102  copy.mark_used_lru();
103 
104  set_lru_size(get_data_size_bytes());
105  nassertv(_array_format->is_registered());
106 }
107 
108 /**
109  * The copy assignment operator is not pipeline-safe. This will completely
110  * obliterate all stages of the pipeline, so don't do it for a
111  * GeomVertexArrayData that is actively being used for rendering.
112  */
115  CopyOnWriteObject::operator = (copy);
116  SimpleLruPage::operator = (copy);
117 
118  copy.mark_used_lru();
119 
120  _array_format = copy._array_format;
121  _cycler = copy._cycler;
122 
123  OPEN_ITERATE_ALL_STAGES(_cycler) {
124  CDStageWriter cdata(_cycler, pipeline_stage);
125  cdata->_modified = Geom::get_next_modified();
126  }
127  CLOSE_ITERATE_ALL_STAGES(_cycler);
128 
129  nassertv(_array_format->is_registered());
130 }
131 
132 /**
133  *
134  */
135 GeomVertexArrayData::
136 ~GeomVertexArrayData() {
137  release_all();
138 }
139 
140 /**
141  * Returns 0 if the two arrays are equivalent, even if they are not the same
142  * pointer.
143  */
145 compare_to(const GeomVertexArrayData &other) const {
146  Thread *current_thread = Thread::get_current_thread();
147 
148  CPT(GeomVertexArrayDataHandle) handle = get_handle(current_thread);
149  CPT(GeomVertexArrayDataHandle) other_handle = other.get_handle(current_thread);
150 
151  if (handle->get_usage_hint() != other_handle->get_usage_hint()) {
152  return (int)handle->get_usage_hint() - (int)other_handle->get_usage_hint();
153  }
154  if (handle->get_array_format() != other_handle->get_array_format()) {
155  return handle->get_array_format() < other_handle->get_array_format() ? -1 : 1;
156  }
157  if (handle->get_data_size_bytes() != other_handle->get_data_size_bytes()) {
158  return (int)handle->get_data_size_bytes() - (int)other_handle->get_data_size_bytes();
159  }
160  return memcmp(handle->get_read_pointer(true),
161  other_handle->get_read_pointer(true),
162  handle->get_data_size_bytes());
163 }
164 
165 /**
166  * Changes the UsageHint hint for this array. See get_usage_hint().
167  *
168  * Don't call this in a downstream thread unless you don't mind it blowing
169  * away other changes you might have recently made in an upstream thread.
170  */
172 set_usage_hint(GeomVertexArrayData::UsageHint usage_hint) {
173  CDWriter cdata(_cycler, true);
174  cdata->_usage_hint = usage_hint;
175  cdata->_modified = Geom::get_next_modified();
176 }
177 
178 /**
179  *
180  */
181 void GeomVertexArrayData::
182 output(std::ostream &out) const {
183  out << get_num_rows() << " rows: " << *get_array_format();
184 }
185 
186 /**
187  *
188  */
189 void GeomVertexArrayData::
190 write(std::ostream &out, int indent_level) const {
191  _array_format->write_with_data(out, indent_level, this);
192 }
193 
194 /**
195  * Indicates that the data should be enqueued to be prepared in the indicated
196  * prepared_objects at the beginning of the next frame. This will ensure the
197  * data is already loaded into the GSG if it is expected to be rendered soon.
198  *
199  * Use this function instead of prepare_now() to preload datas from a user
200  * interface standpoint.
201  */
203 prepare(PreparedGraphicsObjects *prepared_objects) {
204  prepared_objects->enqueue_vertex_buffer(this);
205 }
206 
207 /**
208  * Returns true if the data has already been prepared or enqueued for
209  * preparation on the indicated GSG, false otherwise.
210  */
212 is_prepared(PreparedGraphicsObjects *prepared_objects) const {
213  if (_contexts == nullptr) {
214  return false;
215  }
216  Contexts::const_iterator ci;
217  ci = _contexts->find(prepared_objects);
218  if (ci != _contexts->end()) {
219  return true;
220  }
221  return prepared_objects->is_vertex_buffer_queued(this);
222 }
223 
224 /**
225  * Creates a context for the data on the particular GSG, if it does not
226  * already exist. Returns the new (or old) VertexBufferContext. This assumes
227  * that the GraphicsStateGuardian is the currently active rendering context
228  * and that it is ready to accept new datas. If this is not necessarily the
229  * case, you should use prepare() instead.
230  *
231  * Normally, this is not called directly except by the GraphicsStateGuardian;
232  * a data does not need to be explicitly prepared by the user before it may be
233  * rendered.
234  */
238  if (_contexts == nullptr) {
239  _contexts = new Contexts;
240  }
241  Contexts::const_iterator ci;
242  ci = _contexts->find(prepared_objects);
243  if (ci != _contexts->end()) {
244  return (*ci).second;
245  }
246 
247  VertexBufferContext *vbc = prepared_objects->prepare_vertex_buffer_now(this, gsg);
248  if (vbc != nullptr) {
249  (*_contexts)[prepared_objects] = vbc;
250  }
251  return vbc;
252 }
253 
254 /**
255  * Frees the data context only on the indicated object, if it exists there.
256  * Returns true if it was released, false if it had not been prepared.
257  */
259 release(PreparedGraphicsObjects *prepared_objects) {
260  if (_contexts != nullptr) {
261  Contexts::iterator ci;
262  ci = _contexts->find(prepared_objects);
263  if (ci != _contexts->end()) {
264  VertexBufferContext *vbc = (*ci).second;
265  prepared_objects->release_vertex_buffer(vbc);
266  return true;
267  }
268  }
269 
270  // Maybe it wasn't prepared yet, but it's about to be.
271  return prepared_objects->dequeue_vertex_buffer(this);
272 }
273 
274 /**
275  * Frees the context allocated on all objects for which the data has been
276  * declared. Returns the number of contexts which have been freed.
277  */
280  int num_freed = 0;
281 
282  if (_contexts != nullptr) {
283  // We have to traverse a copy of the _contexts list, because the
284  // PreparedGraphicsObjects object will call clear_prepared() in response
285  // to each release_vertex_buffer(), and we don't want to be modifying the
286  // _contexts list while we're traversing it.
287  Contexts temp = *_contexts;
288  num_freed = (int)_contexts->size();
289 
290  Contexts::const_iterator ci;
291  for (ci = temp.begin(); ci != temp.end(); ++ci) {
292  PreparedGraphicsObjects *prepared_objects = (*ci).first;
293  VertexBufferContext *vbc = (*ci).second;
294  prepared_objects->release_vertex_buffer(vbc);
295  }
296 
297  // Now that we've called release_vertex_buffer() on every known context,
298  // the _contexts list should have completely emptied itself.
299  nassertr(_contexts == nullptr, num_freed);
300  }
301 
302  return num_freed;
303 }
304 
305 /**
306  * Marks that an epoch has passed in each LRU. Asks the LRU's to consider
307  * whether they should perform evictions.
308  */
311  _independent_lru.begin_epoch();
312  VertexDataPage::get_global_lru(VertexDataPage::RC_resident)->begin_epoch();
313  VertexDataPage::get_global_lru(VertexDataPage::RC_compressed)->begin_epoch();
314 }
315 
316 /**
317  * Evicts the page from the LRU. Called internally when the LRU determines
318  * that it is full. May also be called externally when necessary to
319  * explicitly evict the page.
320  *
321  * It is legal for this method to either evict the page as requested, do
322  * nothing (in which case the eviction will be requested again at the next
323  * epoch), or requeue itself on the tail of the queue (in which case the
324  * eviction will be requested again much later).
325  */
328  dequeue_lru();
329  CDWriter cdata(_cycler, true);
330  cdata->_buffer.page_out(_book);
331 }
332 
333 /**
334  * Removes the indicated PreparedGraphicsObjects table from the data array's
335  * table, without actually releasing the data array. This is intended to be
336  * called only from PreparedGraphicsObjects::release_vertex_buffer(); it
337  * should never be called by user code.
338  */
339 void GeomVertexArrayData::
340 clear_prepared(PreparedGraphicsObjects *prepared_objects) {
341  nassertv(_contexts != nullptr);
342 
343  Contexts::iterator ci;
344  ci = _contexts->find(prepared_objects);
345  if (ci != _contexts->end()) {
346  _contexts->erase(ci);
347  if (_contexts->empty()) {
348  delete _contexts;
349  _contexts = nullptr;
350  }
351  } else {
352  // If this assertion fails, clear_prepared() was given a prepared_objects
353  // which the data array didn't know about.
354  nassert_raise("unknown PreparedGraphicsObjects");
355  }
356 }
357 
358 /**
359  * Fills a new data array with all numeric values expressed in the indicated
360  * array reversed, byte-for-byte, to convert littleendian to bigendian and
361  * vice-versa.
362  */
363 void GeomVertexArrayData::
364 reverse_data_endianness(unsigned char *dest, const unsigned char *source,
365  size_t size) {
366  int num_columns = _array_format->get_num_columns();
367 
368  // Walk through each row of the data.
369  for (size_t pi = 0; pi < size; pi += _array_format->get_stride()) {
370  // For each row, visit all of the columns; and for each column, visit all
371  // of the components of that column.
372  for (int ci = 0; ci < num_columns; ++ci) {
373  const GeomVertexColumn *col = _array_format->get_column(ci);
374  int component_bytes = col->get_component_bytes();
375  if (component_bytes > 1) {
376  // Get the index of the beginning of the column.
377  size_t ci = pi + col->get_start();
378 
379  int num_components = col->get_num_components();
380  for (int cj = 0; cj < num_components; ++cj) {
381  // Reverse the bytes of each component.
382  ReversedNumericData nd(source + ci, component_bytes);
383  nd.store_value(dest + ci, component_bytes);
384  ci += component_bytes;
385  }
386  }
387  }
388  }
389 }
390 
391 /**
392  * Tells the BamReader how to create objects of type GeomVertexArrayData.
393  */
396  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
397 }
398 
399 /**
400  * Writes the contents of this object to the datagram for shipping out to a
401  * Bam file.
402  */
406 
407  manager->write_pointer(dg, _array_format);
408  manager->write_cdata(dg, _cycler, this);
409 }
410 
411 /**
412  * Called by CData::fillin to read the raw data of the array from the
413  * indicated datagram.
414  */
415 PTA_uchar GeomVertexArrayData::
417  size_t size = scan.get_uint32();
418  PTA_uchar data = PTA_uchar::empty_array(size, get_class_type());
419  const unsigned char *source_data =
420  (const unsigned char *)scan.get_datagram().get_data();
421  memcpy(data, source_data + scan.get_current_index(), size);
422  scan.skip_bytes(size);
423 
424  return data;
425 }
426 
427 /**
428  * Receives an array of pointers, one for each time manager->read_pointer()
429  * was called in fillin(). Returns the number of pointers processed.
430  */
433  int pi = CopyOnWriteObject::complete_pointers(p_list, manager);
434 
435  _array_format = DCAST(GeomVertexArrayFormat, p_list[pi++]);
436 
437  return pi;
438 }
439 
440 /**
441  * Called by the BamReader to perform any final actions needed for setting up
442  * the object after all objects have been read and all pointers have been
443  * completed.
444  */
446 finalize(BamReader *manager) {
447  // Now we need to register the format that we have read from the bam file
448  // (since it doesn't come out of the bam file automatically registered).
449  // This may change the format's pointer, which we should then update our own
450  // data to reflect. But since this may cause the unregistered object to
451  // destruct, we have to also tell the BamReader to return the new object
452  // from now on.
453 
454  CDWriter cdata(_cycler, true);
455 
456  CPT(GeomVertexArrayFormat) new_array_format =
457  GeomVertexArrayFormat::register_format(_array_format);
458 
459  manager->change_pointer(_array_format, new_array_format);
460  _array_format = new_array_format;
461 
462  PT(BamAuxData) aux_data = (BamAuxData *)manager->get_aux_data(this, "");
463  if (aux_data != nullptr) {
464  if (aux_data->_endian_reversed) {
465  // Now is the time to endian-reverse the data.
466  VertexDataBuffer new_buffer(cdata->_buffer.get_size());
467  reverse_data_endianness(new_buffer.get_write_pointer(), cdata->_buffer.get_read_pointer(true), cdata->_buffer.get_size());
468  cdata->_buffer.swap(new_buffer);
469  }
470  }
471 
472  set_lru_size(cdata->_buffer.get_size());
473 }
474 
475 /**
476  * This function is called by the BamReader's factory when a new object of
477  * type GeomVertexArrayData is encountered in the Bam file. It should create
478  * the GeomVertexArrayData and extract its information from the file.
479  */
480 TypedWritable *GeomVertexArrayData::
481 make_from_bam(const FactoryParams &params) {
483  DatagramIterator scan;
484  BamReader *manager;
485 
486  parse_params(params, scan, manager);
487  object->fillin(scan, manager);
488  manager->register_finalize(object);
489 
490  return object;
491 }
492 
493 /**
494  * This internal function is called by make_from_bam to read in all of the
495  * relevant data from the BamFile for the new GeomVertexArrayData.
496  */
497 void GeomVertexArrayData::
498 fillin(DatagramIterator &scan, BamReader *manager) {
499  CopyOnWriteObject::fillin(scan, manager);
500 
501  manager->read_pointer(scan);
502  manager->read_cdata(scan, _cycler, this);
503 }
504 
505 /**
506  *
507  */
508 GeomVertexArrayData::CData::
509 ~CData() {
510 }
511 
512 /**
513  *
514  */
515 CycleData *GeomVertexArrayData::CData::
516 make_copy() const {
517  return new CData(*this);
518 }
519 
520 /**
521  * Writes the contents of this object to the datagram for shipping out to a
522  * Bam file.
523  */
524 void GeomVertexArrayData::CData::
525 write_datagram(BamWriter *manager, Datagram &dg, void *extra_data) const {
526  GeomVertexArrayData *array_data = (GeomVertexArrayData *)extra_data;
527  dg.add_uint8(_usage_hint);
528 
529  dg.add_uint32(_buffer.get_size());
530 
531  if (manager->get_file_endian() == BamWriter::BE_native) {
532  // For native endianness, we only have to write the data directly.
533  dg.append_data(_buffer.get_read_pointer(true), _buffer.get_size());
534 
535  } else {
536  // Otherwise, we have to convert it.
537  unsigned char *new_data = (unsigned char *)alloca(_buffer.get_size());
538  array_data->reverse_data_endianness(new_data, _buffer.get_read_pointer(true), _buffer.get_size());
539  dg.append_data(new_data, _buffer.get_size());
540  }
541 }
542 
543 /**
544  * This internal function is called by make_from_bam to read in all of the
545  * relevant data from the BamFile for the new GeomVertexArrayData.
546  */
547 void GeomVertexArrayData::CData::
548 fillin(DatagramIterator &scan, BamReader *manager, void *extra_data) {
549  GeomVertexArrayData *array_data = (GeomVertexArrayData *)extra_data;
550  _usage_hint = (UsageHint)scan.get_uint8();
551 
552  if (manager->get_file_minor_ver() < 8) {
553  // Before bam version 6.8, the array data was a PTA_uchar.
554  PTA_uchar new_data;
555  READ_PTA(manager, scan, array_data->read_raw_data, new_data);
556  _buffer.unclean_realloc(new_data.size());
557  _buffer.set_size(new_data.size());
558  memcpy(_buffer.get_write_pointer(), &new_data[0], new_data.size());
559 
560  } else {
561  // Now, the array data is just stored directly.
562  size_t size = scan.get_uint32();
563  _buffer.unclean_realloc(size);
564  _buffer.set_size(size);
565 
566  const unsigned char *source_data =
567  (const unsigned char *)scan.get_datagram().get_data();
568  memcpy(_buffer.get_write_pointer(), source_data + scan.get_current_index(), size);
569  scan.skip_bytes(size);
570  }
571 
572  bool endian_reversed = false;
573 
574  if (manager->get_file_endian() != BamReader::BE_native) {
575  // For non-native endian files, we have to convert the data.
576 
577  if (array_data->_array_format == nullptr) {
578  // But we can't do that until we've completed the _array_format pointer,
579  // which tells us how to convert it.
580  endian_reversed = true;
581  } else {
582  // Since we have the _array_format pointer now, we can reverse it
583  // immediately (and we should, to support threaded CData updates).
584  VertexDataBuffer new_buffer(_buffer.get_size());
585  array_data->reverse_data_endianness(new_buffer.get_write_pointer(), _buffer.get_read_pointer(true), _buffer.get_size());
586  _buffer.swap(new_buffer);
587  }
588  }
589 
590  if (endian_reversed) {
591  PT(BamAuxData) aux_data = new BamAuxData;
592  aux_data->_endian_reversed = endian_reversed;
593  manager->set_aux_data(array_data, "", aux_data);
594  }
595 
596  array_data->set_lru_size(_buffer.get_size());
597 
598  _modified = Geom::get_next_modified();
599 }
600 
601 /**
602  * Returns a writable pointer to the beginning of the actual data stream.
603  */
604 unsigned char *GeomVertexArrayDataHandle::
606  nassertr(_writable, nullptr);
607  mark_used();
608  _cdata->_modified = Geom::get_next_modified();
609  return _cdata->_buffer.get_write_pointer();
610 }
611 
612 /**
613  *
614  */
615 bool GeomVertexArrayDataHandle::
616 set_num_rows(int n) {
617  nassertr(_writable, false);
618  mark_used();
619 
620  int stride = _object->_array_format->get_stride();
621  size_t new_size = n * stride;
622  size_t orig_size = _cdata->_buffer.get_size();
623 
624  if (gobj_cat.is_spam()) {
625  gobj_cat.spam()
626  << _object << ".set_num_rows(" << n << "), size = " << new_size << "\n";
627  }
628 
629  if (new_size != orig_size) {
630  size_t orig_reserved_size = _cdata->_buffer.get_reserved_size();
631  if (new_size > orig_reserved_size) {
632  // Add more rows. Go up to the next power of two bytes, mainly to
633  // reduce the number of allocs needed.
634  size_t new_reserved_size = (size_t)Texture::up_to_power_2((int)new_size);
635  nassertr(new_reserved_size >= new_size, false);
636 
637  _cdata->_buffer.clean_realloc(new_reserved_size);
638 
639  } else if (new_size == 0) {
640  // If we set the number of rows to 0, go ahead and clear the buffer
641  // altogether, and let the user build it up again from nothing, to try
642  // to reduce frivolous memory waste.
643  _cdata->_buffer.clear();
644  }
645 
646  _cdata->_buffer.set_size(new_size);
647 
648  // Now ensure that the newly-added rows are initialized to 0.
649  if (new_size > orig_size) {
650  memset(_cdata->_buffer.get_write_pointer() + orig_size, 0,
651  new_size - orig_size);
652  }
653 
654  _cdata->_modified = Geom::get_next_modified();
655 
656  if (get_current_thread()->get_pipeline_stage() == 0) {
657  _object->set_lru_size(_cdata->_buffer.get_size());
658  }
659 
660  nassertr(get_num_rows() == n, true);
661  return true;
662  }
663 
664  nassertr(get_num_rows() == n, false);
665  return false;
666 }
667 
668 /**
669  *
670  */
671 bool GeomVertexArrayDataHandle::
672 unclean_set_num_rows(int n) {
673  nassertr(_writable, false);
674  mark_used();
675 
676  int stride = _object->_array_format->get_stride();
677  size_t new_size = n * stride;
678  size_t orig_size = _cdata->_buffer.get_size();
679  size_t orig_reserved_size = _cdata->_buffer.get_reserved_size();
680 
681  if (new_size != orig_size || new_size != orig_reserved_size) {
682  // Since this is unclean_set_num_rows(), we won't be using it to
683  // incrementally increase the array; instead, it will generally be used
684  // only to create an array initially. So it makes sense to set the
685  // reserved size to precisely the same as the target size.
686 
687  _cdata->_buffer.unclean_realloc(new_size);
688  _cdata->_buffer.set_size(new_size);
689 
690  // No need to fill to zero or copy the old buffer, since this is
691  // unclean_set_num_rows().
692 
693  if (new_size != orig_size) {
694  _cdata->_modified = Geom::get_next_modified();
695 
696  if (get_current_thread()->get_pipeline_stage() == 0) {
697  _object->set_lru_size(_cdata->_buffer.get_size());
698  }
699  }
700  return true;
701  }
702 
703  return false;
704 }
705 
706 /**
707  *
708  */
709 bool GeomVertexArrayDataHandle::
710 reserve_num_rows(int n) {
711  nassertr(_writable, false);
712  mark_used();
713 
714  int stride = _object->_array_format->get_stride();
715  size_t new_reserved_size = n * stride;
716  new_reserved_size = max(_cdata->_buffer.get_size(), new_reserved_size);
717  size_t orig_reserved_size = _cdata->_buffer.get_reserved_size();
718 
719  if (gobj_cat.is_debug()) {
720  gobj_cat.debug()
721  << _object << ".reserve_num_rows(" << n << "), size = " << new_reserved_size << "\n";
722  }
723 
724  if (new_reserved_size != orig_reserved_size) {
725  // We allow the user to set the alloc point smaller with this call,
726  // assuming the user knows what he's doing. This allows the user to
727  // reduce wasted memory after completely filling up a buffer.
728  _cdata->_buffer.clean_realloc(new_reserved_size);
729  return true;
730  }
731 
732  return false;
733 }
734 
735 /**
736  * Copies the entire data array from the other object.
737  */
740  nassertv(_writable);
741  other->mark_used();
742 
743  size_t size = other->_cdata->_buffer.get_size();
744  const unsigned char *source = other->_cdata->_buffer.get_read_pointer(true);
745 
746  copy_data_from(source, size);
747 }
748 
749 /**
750  * Copies a portion of the data array from the other object into a portion of
751  * the data array of this object. If to_size != from_size, the size of this
752  * data array is adjusted accordingly.
753  */
755 copy_subdata_from(size_t to_start, size_t to_size,
756  const GeomVertexArrayDataHandle *other,
757  size_t from_start, size_t from_size) {
758  other->mark_used();
759 
760  const VertexDataBuffer &from_buffer = other->_cdata->_buffer;
761  size_t from_buffer_orig_size = from_buffer.get_size();
762  from_start = min(from_start, from_buffer_orig_size);
763  from_size = min(from_size, from_buffer_orig_size - from_start);
764 
765  copy_subdata_from(to_start, to_size,
766  other->get_read_pointer(true),
767  from_start, from_size);
768 }
769 
770 /**
771  * Copies the entire data array from the buffer.
772  */
774 copy_data_from(const unsigned char *source, size_t size) {
775  nassertv(_writable);
776  mark_used();
777 
778  _cdata->_buffer.unclean_realloc(size);
779  _cdata->_buffer.set_size(size);
780 
781  unsigned char *dest = _cdata->_buffer.get_write_pointer();
782  memcpy(dest, source, size);
783 
784  _cdata->_modified = Geom::get_next_modified();
785 
786  if (get_current_thread()->get_pipeline_stage() == 0) {
787  _object->set_lru_size(_cdata->_buffer.get_size());
788  }
789 }
790 
791 /**
792  * Copies a portion of the data array from the buffer into a portion of the
793  * data array of this object. If to_size != from_size, the size of this data
794  * array is adjusted accordingly.
795  */
797 copy_subdata_from(size_t to_start, size_t to_size,
798  const unsigned char *source,
799  size_t from_start, size_t from_size) {
800  nassertv(_writable);
801  mark_used();
802 
803  VertexDataBuffer &to_buffer = _cdata->_buffer;
804  size_t to_buffer_orig_size = to_buffer.get_size();
805  to_start = min(to_start, to_buffer_orig_size);
806  to_size = min(to_size, to_buffer_orig_size - to_start);
807 
808  if (from_size < to_size) {
809  // Reduce the array.
810  unsigned char *pointer = to_buffer.get_write_pointer();
811  memmove(pointer + to_start + to_size,
812  pointer + to_start + from_size,
813  to_buffer_orig_size - (to_start + to_size));
814  to_buffer.set_size(to_buffer_orig_size + from_size - to_size);
815 
816  } else if (to_size < from_size) {
817  // Expand the array.
818  size_t needed_size = to_buffer_orig_size + from_size - to_size;
819  size_t to_buffer_orig_reserved_size = to_buffer.get_reserved_size();
820  if (needed_size > to_buffer_orig_reserved_size) {
821  size_t new_reserved_size = (size_t)Texture::up_to_power_2((int)needed_size);
822  to_buffer.clean_realloc(new_reserved_size);
823  }
824  to_buffer.set_size(needed_size);
825 
826  unsigned char *pointer = to_buffer.get_write_pointer();
827  memmove(pointer + to_start + to_size,
828  pointer + to_start + from_size,
829  to_buffer_orig_size - (to_start + to_size));
830  }
831 
832  // Now copy the data.
833  memcpy(to_buffer.get_write_pointer() + to_start,
834  source + from_start, from_size);
835  _cdata->_modified = Geom::get_next_modified();
836 
837  if (get_current_thread()->get_pipeline_stage() == 0) {
838  _object->set_lru_size(_cdata->_buffer.get_size());
839  }
840 }
841 
842 /**
843  * Replaces the entire raw data array with the contents of the indicated
844  * string. This is primarily for the benefit of high-level languages like
845  * Python.
846  */
848 set_data(const vector_uchar &data) {
849  nassertv(_writable);
850  mark_used();
851 
852  _cdata->_buffer.unclean_realloc(data.size());
853  _cdata->_buffer.set_size(data.size());
854  memcpy(_cdata->_buffer.get_write_pointer(), data.data(), data.size());
855 
856  _cdata->_modified = Geom::get_next_modified();
857 
858  if (get_current_thread()->get_pipeline_stage() == 0) {
859  _object->set_lru_size(_cdata->_buffer.get_size());
860  }
861 }
862 
863 /**
864  * Replaces a portion of the data array from the indicated string. If size !=
865  * data.size(), the size of this data array is adjusted accordingly.
866  *
867  * This is primarily for the benefit of high-level languages like Python.
868  */
870 set_subdata(size_t start, size_t size, const vector_uchar &data) {
871  nassertv(_writable);
872  mark_used();
873 
874  VertexDataBuffer &to_buffer = _cdata->_buffer;
875  size_t to_buffer_orig_size = to_buffer.get_size();
876  start = min(start, to_buffer_orig_size);
877  size = min(size, to_buffer_orig_size - start);
878 
879  size_t from_size = data.size();
880 
881  if (from_size < size) {
882  // Reduce the array.
883  unsigned char *pointer = to_buffer.get_write_pointer();
884  memmove(pointer + start + from_size,
885  pointer + start + size,
886  to_buffer_orig_size - (start + size));
887  to_buffer.set_size(to_buffer_orig_size + from_size - size);
888 
889  } else if (size < from_size) {
890  // Expand the array.
891  size_t needed_size = to_buffer_orig_size + from_size - size;
892  size_t to_buffer_orig_reserved_size = to_buffer.get_reserved_size();
893  if (needed_size > to_buffer_orig_reserved_size) {
894  size_t new_reserved_size = (size_t)Texture::up_to_power_2((int)needed_size);
895  to_buffer.clean_realloc(new_reserved_size);
896  }
897  to_buffer.set_size(needed_size);
898 
899  unsigned char *pointer = to_buffer.get_write_pointer();
900  memmove(pointer + start + from_size,
901  pointer + start + size,
902  to_buffer_orig_size - (start + size));
903  }
904 
905  // Now copy the data.
906  memcpy(to_buffer.get_write_pointer() + start, data.data(), from_size);
907  _cdata->_modified = Geom::get_next_modified();
908 
909  if (get_current_thread()->get_pipeline_stage() == 0) {
910  _object->set_lru_size(_cdata->_buffer.get_size());
911  }
912 }
GeomVertexArrayData::write_datagram
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
Definition: geomVertexArrayData.cxx:404
PreparedGraphicsObjects
A table of objects that are saved within the graphics context for reference by handle later.
Definition: preparedGraphicsObjects.h:58
GeomVertexColumn::get_start
int get_start() const
Returns the byte within the array record at which this column starts.
Definition: geomVertexColumn.I:133
VertexBufferContext
This is a special class object that holds all the information returned by a particular GSG to indicat...
Definition: vertexBufferContext.h:33
GeomVertexArrayData
This is the data for one array of a GeomVertexData structure.
Definition: geomVertexArrayData.h:58
VertexDataBuffer::get_reserved_size
size_t get_reserved_size() const
Returns the total number of bytes "reserved" in the buffer.
Definition: vertexDataBuffer.I:121
CycleData
A single page of data maintained by a PipelineCycler.
Definition: cycleData.h:47
GeomVertexArrayData::lru_epoch
static void lru_epoch()
Marks that an epoch has passed in each LRU.
Definition: geomVertexArrayData.cxx:310
GeomVertexArrayDataHandle::mark_used
void mark_used() const
Marks the array data recently-used.
Definition: geomVertexArrayData.I:548
VertexDataBuffer
A block of bytes that stores the actual raw vertex data referenced by a GeomVertexArrayData object.
Definition: vertexDataBuffer.h:52
vertexDataBuffer.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomVertexArrayData::release
bool release(PreparedGraphicsObjects *prepared_objects)
Frees the data context only on the indicated object, if it exists there.
Definition: geomVertexArrayData.cxx:259
PreparedGraphicsObjects::is_vertex_buffer_queued
bool is_vertex_buffer_queued(const GeomVertexArrayData *data) const
Returns true if the vertex buffer has been queued on this GSG, false otherwise.
Definition: preparedGraphicsObjects.cxx:899
GeomVertexArrayData::finalize
virtual void finalize(BamReader *manager)
Called by the BamReader to perform any final actions needed for setting up the object after all objec...
Definition: geomVertexArrayData.cxx:446
config_gobj.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomVertexArrayData::prepare_now
VertexBufferContext * prepare_now(PreparedGraphicsObjects *prepared_objects, GraphicsStateGuardianBase *gsg)
Creates a context for the data on the particular GSG, if it does not already exist.
Definition: geomVertexArrayData.cxx:236
DatagramIterator::get_current_index
size_t get_current_index() const
Returns the current position within the datagram of the next piece of data to extract.
Definition: datagramIterator.I:471
GeomVertexArrayData::register_with_read_factory
static void register_with_read_factory()
Tells the BamReader how to create objects of type GeomVertexArrayData.
Definition: geomVertexArrayData.cxx:395
SimpleLru::begin_epoch
void begin_epoch()
Marks the end of the previous epoch and the beginning of the next one.
Definition: simpleLru.I:77
VertexDataBuffer::get_size
size_t get_size() const
Returns the number of bytes in the buffer.
Definition: vertexDataBuffer.I:109
VertexDataBook
A collection of VertexDataPages, which can be used to allocate new VertexDataBlock objects.
Definition: vertexDataBook.h:30
GeomVertexArrayData::release_all
int release_all()
Frees the context allocated on all objects for which the data has been declared.
Definition: geomVertexArrayData.cxx:279
Datagram::add_uint8
void add_uint8(uint8_t value)
Adds an unsigned 8-bit integer to the datagram.
Definition: datagram.I:50
DatagramIterator
A class to retrieve the individual data elements previously stored in a Datagram.
Definition: datagramIterator.h:27
pmap
This is our own Panda specialization on the default STL map.
Definition: pmap.h:49
Texture::up_to_power_2
static int up_to_power_2(int value)
Returns the smallest power of 2 greater than or equal to value.
Definition: texture.cxx:1983
TypedWritable::complete_pointers
virtual int complete_pointers(TypedWritable **p_list, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin().
Definition: typedWritable.cxx:81
BamReader
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
preparedGraphicsObjects.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomVertexArrayData::get_array_format
get_array_format
Returns the format object that describes this array.
Definition: geomVertexArrayData.h:76
pStatTimer.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PreparedGraphicsObjects::prepare_vertex_buffer_now
VertexBufferContext * prepare_vertex_buffer_now(GeomVertexArrayData *data, GraphicsStateGuardianBase *gsg)
Immediately creates a new VertexBufferContext for the indicated data and returns it.
Definition: preparedGraphicsObjects.cxx:1053
BamWriter
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
BamWriter::write_pointer
void write_pointer(Datagram &packet, const TypedWritable *dest)
The interface for writing a pointer to another object to a Bam file.
Definition: bamWriter.cxx:317
GeomVertexArrayDataHandle::copy_subdata_from
void copy_subdata_from(size_t to_start, size_t to_size, const GeomVertexArrayDataHandle *other, size_t from_start, size_t from_size)
Copies a portion of the data array from the other object into a portion of the data array of this obj...
Definition: geomVertexArrayData.cxx:755
GeomVertexArrayDataHandle::set_data
void set_data(const vector_uchar &data)
Replaces the entire raw data array with the contents of the indicated string.
Definition: geomVertexArrayData.cxx:848
VertexDataBuffer::clean_realloc
void clean_realloc(size_t reserved_size)
Changes the "reserved" size of the buffer, preserving its data (except for any data beyond the new en...
Definition: vertexDataBuffer.I:153
BamReader::get_factory
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:177
PreparedGraphicsObjects::release_vertex_buffer
void release_vertex_buffer(VertexBufferContext *vbc)
Indicates that a data context, created by a previous call to prepare_vertex_buffer(),...
Definition: preparedGraphicsObjects.cxx:946
bamReader.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Geom::get_next_modified
static UpdateSeq get_next_modified()
Returns a monotonically increasing sequence.
Definition: geom.cxx:1324
VertexDataPage::get_global_lru
static SimpleLru * get_global_lru(RamClass rclass)
Returns a pointer to the global LRU object that manages the VertexDataPage's with the indicated RamCl...
Definition: vertexDataPage.I:83
TypedWritable
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
Datagram
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
SimpleLruPage::mark_used_lru
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
GeomVertexArrayDataHandle::get_read_pointer
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...
Definition: geomVertexArrayData.I:420
Thread::get_current_thread
get_current_thread
Returns a pointer to the currently-executing Thread object.
Definition: thread.h:109
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
BamReader::get_file_endian
get_file_endian
Returns the endian preference indicated by the Bam file currently being read.
Definition: bamReader.h:159
BamReader::register_finalize
void register_finalize(TypedWritable *whom)
Should be called by an object reading itself from the Bam file to indicate that this particular objec...
Definition: bamReader.cxx:808
configVariableInt.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomVertexArrayData::operator=
void operator=(const GeomVertexArrayData &copy)
The copy assignment operator is not pipeline-safe.
Definition: geomVertexArrayData.cxx:114
GeomVertexColumn::get_component_bytes
int get_component_bytes() const
Returns the number of bytes used by each component (that is, by one element of the numeric type).
Definition: geomVertexColumn.I:162
GeomVertexArrayDataHandle::set_subdata
void set_subdata(size_t start, size_t size, const vector_uchar &data)
Replaces a portion of the data array from the indicated string.
Definition: geomVertexArrayData.cxx:870
GeomVertexArrayData::complete_pointers
virtual int complete_pointers(TypedWritable **plist, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin().
Definition: geomVertexArrayData.cxx:432
DatagramIterator::get_datagram
const Datagram & get_datagram() const
Return the datagram of this iterator.
Definition: datagramIterator.I:462
BamReader::read_cdata
void read_cdata(DatagramIterator &scan, PipelineCyclerBase &cycler)
Reads in the indicated CycleData object.
Definition: bamReader.cxx:695
FactoryParams
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
GeomVertexArrayData::get_num_rows
int get_num_rows() const
Returns the number of rows stored in the array, based on the number of bytes and the stride.
Definition: geomVertexArrayData.I:47
CycleDataWriter
This template class calls PipelineCycler::write() in the constructor and PipelineCycler::release_writ...
Definition: cycleDataWriter.h:34
GeomVertexArrayData::set_usage_hint
set_usage_hint
Changes the UsageHint hint for this array.
Definition: geomVertexArrayData.h:80
TypedWritable::write_datagram
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
Definition: typedWritable.cxx:54
BamWriter::get_file_endian
get_file_endian
Returns the endian preference indicated by the Bam file currently being written.
Definition: bamWriter.h:93
reversedNumericData.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomVertexArrayData::compare_to
int compare_to(const GeomVertexArrayData &other) const
Returns 0 if the two arrays are equivalent, even if they are not the same pointer.
Definition: geomVertexArrayData.cxx:145
CopyOnWriteObject
This base class provides basic reference counting, but also can be used with a CopyOnWritePointer to ...
Definition: copyOnWriteObject.h:41
ReversedNumericData
NativeNumericData and ReversedNumericData work together to provide a sneaky interface for automatical...
Definition: reversedNumericData.h:42
BamReader::change_pointer
bool change_pointer(const TypedWritable *orig_pointer, const TypedWritable *new_pointer)
Indicates that an object recently read from the bam stream should be replaced with a new object.
Definition: bamReader.cxx:464
geom.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PT
PT(CopyOnWriteObject) GeomVertexArrayData
Required to implement CopyOnWriteObject.
Definition: geomVertexArrayData.cxx:71
GeomVertexArrayDataHandle
This data object is returned by GeomVertexArrayData::get_handle() or modify_handle().
Definition: geomVertexArrayData.h:250
Factory::register_factory
void register_factory(TypeHandle handle, CreateFunc *func, void *user_data=nullptr)
Registers a new kind of thing the Factory will be able to create.
Definition: factory.I:73
PreparedGraphicsObjects::enqueue_vertex_buffer
void enqueue_vertex_buffer(GeomVertexArrayData *data)
Indicates that a buffer would like to be put on the list to be prepared when the GSG is next ready to...
Definition: preparedGraphicsObjects.cxx:888
BamWriter::write_cdata
void write_cdata(Datagram &packet, const PipelineCyclerBase &cycler)
Writes out the indicated CycleData object.
Definition: bamWriter.cxx:425
CycleDataStageWriter
This class is similar to CycleDataWriter, except it allows writing to a particular stage of the pipel...
Definition: cycleDataStageWriter.h:31
GeomVertexArrayData::get_usage_hint
get_usage_hint
Returns the usage hint that describes to the rendering backend how often the vertex data will be modi...
Definition: geomVertexArrayData.h:80
GeomVertexArrayData::evict_lru
virtual void evict_lru()
Evicts the page from the LRU.
Definition: geomVertexArrayData.cxx:327
GeomVertexColumn::get_num_components
int get_num_components() const
Returns the number of components of the column: the number of instances of the NumericType in each el...
Definition: geomVertexColumn.I:87
PreparedGraphicsObjects::dequeue_vertex_buffer
bool dequeue_vertex_buffer(GeomVertexArrayData *data)
Removes a buffer from the queued list of data arrays to be prepared.
Definition: preparedGraphicsObjects.cxx:916
Datagram::add_uint32
void add_uint32(uint32_t value)
Adds an unsigned 32-bit integer to the datagram.
Definition: datagram.I:94
texture.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
BamReader::set_aux_data
void set_aux_data(TypedWritable *obj, const std::string &name, AuxData *data)
Associates an arbitrary block of data with the indicated object (or NULL), and the indicated name.
Definition: bamReader.cxx:167
GeomVertexArrayData::read_raw_data
PTA_uchar read_raw_data(BamReader *manager, DatagramIterator &source)
Called by CData::fillin to read the raw data of the array from the indicated datagram.
Definition: geomVertexArrayData.cxx:416
VertexDataBuffer::set_size
void set_size(size_t size)
Changes the size of the buffer.
Definition: vertexDataBuffer.I:131
BamReader::read_pointer
bool read_pointer(DatagramIterator &scan)
The interface for reading a pointer to another object from a Bam file.
Definition: bamReader.cxx:610
GeomVertexArrayData::is_prepared
bool is_prepared(PreparedGraphicsObjects *prepared_objects) const
Returns true if the data has already been prepared or enqueued for preparation on the indicated GSG,...
Definition: geomVertexArrayData.cxx:212
VertexDataBuffer::get_write_pointer
unsigned char * get_write_pointer()
Returns a writable pointer to the raw data.
Definition: vertexDataBuffer.I:92
pset.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
BamReader::get_aux_data
AuxData * get_aux_data(TypedWritable *obj, const std::string &name) const
Returns the pointer previously associated with the bam reader by a previous call to set_aux_data(),...
Definition: bamReader.cxx:189
DatagramIterator::skip_bytes
void skip_bytes(size_t size)
Skips over the indicated number of bytes in the datagram.
Definition: datagramIterator.I:423
GraphicsStateGuardianBase
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
Definition: graphicsStateGuardianBase.h:110
GeomVertexColumn
This defines how a single column is interleaved within a vertex array stored within a Geom.
Definition: geomVertexColumn.h:37
BamReader::get_file_minor_ver
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being read.
Definition: bamReader.I:83
SimpleLruPage
One atomic piece that may be managed by a SimpleLru chain.
Definition: simpleLru.h:65
DatagramIterator::get_uint8
uint8_t get_uint8()
Extracts an unsigned 8-bit integer.
Definition: datagramIterator.I:72
DatagramIterator::get_uint32
uint32_t get_uint32()
Extracts an unsigned 32-bit integer.
Definition: datagramIterator.I:164
TypedWritable::fillin
virtual void fillin(DatagramIterator &scan, BamReader *manager)
This internal function is intended to be called by each class's make_from_bam() method to read in all...
Definition: typedWritable.cxx:103
SimpleLru
An implementation of a very simple LRU algorithm.
Definition: simpleLru.h:28
bamWriter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
ConfigVariableInt
This is a convenience class to specialize ConfigVariable as an integer type.
Definition: configVariableInt.h:24
Thread
A thread; that is, a lightweight process.
Definition: thread.h:46
SimpleLruPage::dequeue_lru
void dequeue_lru()
Removes the page from its SimpleLru.
Definition: simpleLru.I:134
Datagram::append_data
void append_data(const void *data, size_t size)
Appends some more raw data to the end of the datagram.
Definition: datagram.cxx:129
Datagram::get_data
const void * get_data() const
Returns a pointer to the beginning of the datagram's data.
Definition: datagram.I:327
parse_params
void parse_params(const FactoryParams &params, DatagramIterator &scan, BamReader *&manager)
Takes in a FactoryParams, passed from a WritableFactory into any TypedWritable's make function,...
Definition: bamReader.I:275
GeomVertexArrayFormat
This describes the structure of a single array within a Geom data.
Definition: geomVertexArrayFormat.h:47
GeomVertexArrayData::prepare
void prepare(PreparedGraphicsObjects *prepared_objects)
Indicates that the data should be enqueued to be prepared in the indicated prepared_objects at the be...
Definition: geomVertexArrayData.cxx:203
geomVertexArrayData.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomVertexArrayDataHandle::get_write_pointer
unsigned char * get_write_pointer()
Returns a writable pointer to the beginning of the actual data stream.
Definition: geomVertexArrayData.cxx:605
simpleAllocator.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomVertexArrayDataHandle::copy_data_from
void copy_data_from(const GeomVertexArrayDataHandle *other)
Copies the entire data array from the other object.
Definition: geomVertexArrayData.cxx:739