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