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 {
209 out << get_num_rows() <<
" rows: " << *get_array_format();
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);
360 _independent_lru.begin_epoch();
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) {
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;
685 array_data->set_lru_size(_buffer.get_size());
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.
size_t get_size() const
Returns the number of bytes in the buffer.
An implementation of a very simple LRU algorithm.
int compare_to(const GeomVertexArrayData &other) const
Returns 0 if the two arrays are equivalent, even if they are not the same pointer.
void add_uint8(PN_uint8 value)
Adds an unsigned 8-bit integer to the datagram.
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.
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.
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...
const Datagram & get_datagram() const
Return the datagram of this iterator.
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.
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.
bool is_vertex_buffer_queued(const GeomVertexArrayData *data) const
Returns true if the vertex buffer has been queued on this GSG, false otherwise.
BamEndian get_file_endian() const
Returns the endian preference indicated by the Bam file currently being written.
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.
BamEndian get_file_endian() const
Returns the endian preference indicated by the Bam file currently being read.
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...
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.
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being read.
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.
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...
virtual void evict_lru()
Evicts the page from the LRU.
size_t get_current_index() const
Returns the current position within the datagram of the next piece of data to extract.
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()...
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.
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.
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...
size_t get_reserved_size() const
Returns the total number of bytes "reserved" in the buffer.
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...
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...
bool is_prepared(PreparedGraphicsObjects *prepared_objects) const
Returns true if the data has already been prepared or enqueued for preparation on the indicated GSG...
unsigned char * get_write_pointer()
Returns a writable pointer to the beginning of the actual data stream.
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...
int get_start() const
Returns the byte within the array record at which this column starts.
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...
int get_component_bytes() const
Returns the number of bytes used by each component (that is, by one element of the numeric type)...
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.
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()...
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...
UsageHint get_usage_hint() const
Returns the usage hint that describes to the rendering backend how often the vertex data will be modi...
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.
static void register_with_read_factory()
Tells the BamReader how to create objects of type GeomVertexArrayData.
A class to retrieve the individual data elements previously stored in a Datagram. ...
TypeHandle is the identifier used to differentiate C++ class types.
int get_num_components() const
Returns the number of components of the column: the number of instances of the NumericType in each el...
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
void set_aux_data(TypedWritable *obj, const string &name, AuxData *data)
Associates an arbitrary block of data with the indicated object (or NULL), and the indicated name...
void store_value(void *dest, size_t length) const
Copies the data, with byte reversal if appropriate, into the indicated numeric variable, whose address and sizeof are given.
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...
const void * get_data() const
Returns a pointer to the beginning of the datagram's data.
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.