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