15 #include "geomVertexArrayData.h"
17 #include "preparedGraphicsObjects.h"
18 #include "reversedNumericData.h"
19 #include "bamReader.h"
20 #include "bamWriter.h"
22 #include "config_gobj.h"
23 #include "pStatTimer.h"
24 #include "configVariableInt.h"
25 #include "simpleAllocator.h"
26 #include "vertexDataBuffer.h"
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."));
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."));
43 SimpleLru GeomVertexArrayData::_independent_lru(
"independent", max_independent_vertex_data);
44 SimpleLru GeomVertexArrayData::_small_lru(
"small", max_independent_vertex_data);
50 TypeHandle GeomVertexArrayData::CData::_type_handle;
51 TypeHandle GeomVertexArrayDataHandle::_type_handle;
84 GeomVertexArrayData(
const GeomVertexArrayFormat *array_format,
85 GeomVertexArrayData::UsageHint usage_hint) :
87 _array_format(array_format)
89 OPEN_ITERATE_ALL_STAGES(_cycler) {
90 CDStageWriter cdata(_cycler, pipeline_stage);
91 cdata->_usage_hint = usage_hint;
93 CLOSE_ITERATE_ALL_STAGES(_cycler);
98 nassertv(_array_format->is_registered());
106 GeomVertexArrayData::
110 _array_format(copy._array_format),
111 _cycler(copy._cycler)
117 set_lru_size(get_data_size_bytes());
118 nassertv(_array_format->is_registered());
131 CopyOnWriteObject::operator = (copy);
132 SimpleLruPage::operator = (copy);
136 _array_format = copy._array_format;
137 _cycler = copy._cycler;
139 OPEN_ITERATE_ALL_STAGES(_cycler) {
143 CLOSE_ITERATE_ALL_STAGES(_cycler);
145 nassertv(_array_format->is_registered());
153 GeomVertexArrayData::
154 ~GeomVertexArrayData() {
171 if (handle->get_usage_hint() != other_handle->get_usage_hint()) {
172 return (
int)handle->
get_usage_hint() - (int)other_handle->get_usage_hint();
174 if (handle->get_array_format() != other_handle->get_array_format()) {
175 return handle->get_array_format() < other_handle->get_array_format() ? -1 : 1;
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();
180 return memcmp(handle->get_read_pointer(
true),
181 other_handle->get_read_pointer(
true),
182 handle->get_data_size_bytes());
198 cdata->_usage_hint = usage_hint;
207 void GeomVertexArrayData::
208 output(ostream &out)
const {
217 void GeomVertexArrayData::
218 write(ostream &out,
int indent_level)
const {
219 _array_format->write_with_data(out, indent_level,
this);
248 if (_contexts == (
Contexts *)NULL) {
251 Contexts::const_iterator ci;
252 ci = _contexts->find(prepared_objects);
253 if (ci != _contexts->end()) {
278 if (_contexts == (
Contexts *)NULL) {
281 Contexts::const_iterator ci;
282 ci = _contexts->find(prepared_objects);
283 if (ci != _contexts->end()) {
289 (*_contexts)[prepared_objects] = vbc;
303 if (_contexts != (
Contexts *)NULL) {
304 Contexts::iterator ci;
305 ci = _contexts->find(prepared_objects);
306 if (ci != _contexts->end()) {
328 if (_contexts != (
Contexts *)NULL) {
334 num_freed = (int)_contexts->size();
336 Contexts::const_iterator ci;
337 for (ci = temp.begin(); ci != temp.end(); ++ci) {
345 nassertr(_contexts == NULL, num_freed);
384 cdata->_buffer.page_out(_book);
397 void GeomVertexArrayData::
399 nassertv(_contexts != (Contexts *)NULL);
401 Contexts::iterator ci;
402 ci = _contexts->find(prepared_objects);
403 if (ci != _contexts->end()) {
404 _contexts->erase(ci);
405 if (_contexts->empty()) {
424 void GeomVertexArrayData::
425 reverse_data_endianness(
unsigned char *dest,
const unsigned char *source,
427 int num_columns = _array_format->get_num_columns();
430 for (
size_t pi = 0; pi < size; pi += _array_format->get_stride()) {
433 for (
int ci = 0; ci < num_columns; ++ci) {
436 if (component_bytes > 1) {
441 for (
int cj = 0; cj < num_components; ++cj) {
444 nd.store_value(dest + ci, component_bytes);
445 ci += component_bytes;
486 PTA_uchar data = PTA_uchar::empty_array(size, get_class_type());
487 const unsigned char *source_data =
506 _array_format = DCAST(GeomVertexArrayFormat, p_list[pi++]);
529 CPT(GeomVertexArrayFormat) new_array_format =
530 GeomVertexArrayFormat::register_format(_array_format);
533 _array_format = new_array_format;
535 PT(BamAuxData) aux_data = (BamAuxData *)manager->
get_aux_data(
this,
"");
536 if (aux_data != (BamAuxData *)NULL) {
537 if (aux_data->_endian_reversed) {
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);
545 set_lru_size(cdata->_buffer.get_size());
562 parse_params(params, scan, manager);
563 object->fillin(scan, manager);
576 void GeomVertexArrayData::
589 GeomVertexArrayData::CData::
600 return new CData(*
this);
609 void GeomVertexArrayData::CData::
618 dg.
append_data(_buffer.get_read_pointer(
true), _buffer.get_size());
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());
635 void GeomVertexArrayData::CData::
638 _usage_hint = (UsageHint)scan.
get_uint8();
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());
651 _buffer.unclean_realloc(size);
652 _buffer.set_size(size);
654 const unsigned char *source_data =
656 memcpy(_buffer.get_write_pointer(), source_data + scan.
get_current_index(), size);
660 bool endian_reversed =
false;
665 if (array_data->_array_format == (GeomVertexArrayFormat *)NULL) {
668 endian_reversed =
true;
674 array_data->reverse_data_endianness(new_buffer.get_write_pointer(), _buffer.get_read_pointer(
true), _buffer.get_size());
675 _buffer.swap(new_buffer);
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);
685 array_data->set_lru_size(_buffer.get_size());
687 _modified =
Geom::get_next_modified();
697 get_write_pointer() {
698 nassertr(_writable, NULL);
701 return _cdata->_buffer.get_write_pointer();
709 bool GeomVertexArrayDataHandle::
710 set_num_rows(
int n) {
711 nassertr(_writable,
false);
714 int stride = _object->_array_format->get_stride();
715 size_t new_size = n * stride;
716 size_t orig_size = _cdata->_buffer.get_size();
718 if (gobj_cat.is_spam()) {
720 << _object <<
".set_num_rows(" << n <<
"), size = " << new_size <<
"\n";
723 if (new_size != orig_size) {
724 size_t orig_reserved_size = _cdata->_buffer.get_reserved_size();
725 if (new_size > orig_reserved_size) {
729 nassertr(new_reserved_size >= new_size,
false);
731 _cdata->_buffer.clean_realloc(new_reserved_size);
733 }
else if (new_size == 0) {
737 _cdata->_buffer.clear();
740 _cdata->_buffer.set_size(new_size);
743 if (new_size > orig_size) {
744 memset(_cdata->_buffer.get_write_pointer() + orig_size, 0,
745 new_size - orig_size);
750 if (get_current_thread()->get_pipeline_stage() == 0) {
751 _object->set_lru_size(_cdata->_buffer.get_size());
754 nassertr(get_num_rows() == n,
true);
758 nassertr(get_num_rows() == n,
false);
767 bool GeomVertexArrayDataHandle::
768 unclean_set_num_rows(
int n) {
769 nassertr(_writable,
false);
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();
777 if (new_size != orig_size || new_size != orig_reserved_size) {
783 _cdata->_buffer.unclean_realloc(new_size);
784 _cdata->_buffer.set_size(new_size);
789 if (new_size != orig_size) {
792 if (get_current_thread()->get_pipeline_stage() == 0) {
793 _object->set_lru_size(_cdata->_buffer.get_size());
807 bool GeomVertexArrayDataHandle::
808 reserve_num_rows(
int n) {
809 nassertr(_writable,
false);
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();
817 if (gobj_cat.is_debug()) {
819 << _object <<
".reserve_num_rows(" << n <<
"), size = " << new_reserved_size <<
"\n";
822 if (new_reserved_size != orig_reserved_size) {
827 _cdata->_buffer.clean_realloc(new_reserved_size);
844 size_t size = other->_cdata->_buffer.get_size();
845 const unsigned char *source = other->_cdata->_buffer.get_read_pointer(
true);
861 size_t from_start,
size_t from_size) {
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);
871 from_start, from_size);
884 _cdata->_buffer.unclean_realloc(size);
885 _cdata->_buffer.set_size(size);
887 unsigned char *dest = _cdata->_buffer.get_write_pointer();
888 memcpy(dest, source, size);
892 if (get_current_thread()->get_pipeline_stage() == 0) {
893 _object->set_lru_size(_cdata->_buffer.get_size());
907 const unsigned char *source,
908 size_t from_start,
size_t from_size) {
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);
917 if (from_size < to_size) {
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);
925 }
else if (to_size < from_size) {
927 size_t needed_size = to_buffer_orig_size + from_size - to_size;
929 if (needed_size > to_buffer_orig_reserved_size) {
936 memmove(pointer + to_start + to_size,
937 pointer + to_start + from_size,
938 to_buffer_orig_size - (to_start + to_size));
943 source + from_start, from_size);
946 if (get_current_thread()->get_pipeline_stage() == 0) {
947 _object->set_lru_size(_cdata->_buffer.get_size());
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());
969 if (get_current_thread()->get_pipeline_stage() == 0) {
970 _object->set_lru_size(_cdata->_buffer.get_size());
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);
994 size_t from_size = data.size();
996 if (from_size < size) {
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);
1004 }
else if (size < from_size) {
1006 size_t needed_size = to_buffer_orig_size + from_size - size;
1008 if (needed_size > to_buffer_orig_reserved_size) {
1015 memmove(pointer + start + from_size,
1016 pointer + start + size,
1017 to_buffer_orig_size - (start + size));
1024 if (get_current_thread()->get_pipeline_stage() == 0) {
1025 _object->set_lru_size(_cdata->_buffer.get_size());
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.
void add_uint8(PN_uint8 value)
Adds an unsigned 8-bit integer to the datagram.
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.
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.
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 ©)
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.
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
void read_cdata(DatagramIterator &scan, PipelineCyclerBase &cycler)
Reads in the indicated CycleData object.
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.
size_t get_reserved_size() const
Returns the total number of bytes "reserved" 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...
Base class for objects that can be written to and read from Bam files.
void write_cdata(Datagram &packet, const PipelineCyclerBase &cycler)
Writes out the indicated CycleData object.
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.
void begin_epoch()
Marks the end of the previous epoch and the beginning of the next one.
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 ...
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'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'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.
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 "reserved" 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()...
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->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...
One atomic piece that may be managed by a SimpleLru chain.
const GeomVertexArrayFormat * get_array_format() const
Returns the format object that describes this array.
A container for geometry primitives.
An instance of this class is passed to the Factory when requesting it to do its business and construc...
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...
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.
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.
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.
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
void mark_used() const
Marks the array data recently-used.
A thread; that is, a lightweight process.
void add_uint32(PN_uint32 value)
Adds an unsigned 32-bit integer to the datagram.
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.
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->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's data.
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.
TypeHandle is the identifier used to differentiate C++ class types.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
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.
void read_pointer(DatagramIterator &scan)
The interface for reading a pointer to another object from a Bam file.