Panda3D
|
00001 // Filename: geomVertexArrayData.cxx 00002 // Created by: drose (17Mar05) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "geomVertexArrayData.h" 00016 #include "geom.h" 00017 #include "preparedGraphicsObjects.h" 00018 #include "reversedNumericData.h" 00019 #include "bamReader.h" 00020 #include "bamWriter.h" 00021 #include "pset.h" 00022 #include "config_gobj.h" 00023 #include "pStatTimer.h" 00024 #include "configVariableInt.h" 00025 #include "simpleAllocator.h" 00026 #include "vertexDataBuffer.h" 00027 #include "texture.h" 00028 00029 ConfigVariableInt max_independent_vertex_data 00030 ("max-independent-vertex-data", -1, 00031 PRC_DESC("Specifies the maximum number of bytes of all vertex data " 00032 "that is independent of the paging system. This is an " 00033 "initial buffer before max-ram-vertex-data, specifically " 00034 "designed for vertex datas that are dynamic in nature and " 00035 "may change size or be created and destroyed frequently.")); 00036 00037 ConfigVariableInt vertex_data_page_size 00038 ("vertex-data-page-size", 262144, 00039 PRC_DESC("The number of bytes to allocate at a time for vertex data. " 00040 "This also controls the page size that is compressed or written " 00041 "to disk when vertex data pages are evicted from memory.")); 00042 00043 SimpleLru GeomVertexArrayData::_independent_lru("independent", max_independent_vertex_data); 00044 SimpleLru GeomVertexArrayData::_small_lru("small", max_independent_vertex_data); 00045 00046 VertexDataBook GeomVertexArrayData::_book(vertex_data_page_size); 00047 00048 00049 TypeHandle GeomVertexArrayData::_type_handle; 00050 TypeHandle GeomVertexArrayData::CData::_type_handle; 00051 TypeHandle GeomVertexArrayDataHandle::_type_handle; 00052 00053 ALLOC_DELETED_CHAIN_DEF(GeomVertexArrayDataHandle); 00054 00055 //////////////////////////////////////////////////////////////////// 00056 // Function: GeomVertexArrayData::Default Constructor 00057 // Access: Private 00058 // Description: Constructs an invalid object. This is only used when 00059 // reading from the bam file. 00060 //////////////////////////////////////////////////////////////////// 00061 GeomVertexArrayData:: 00062 GeomVertexArrayData() : SimpleLruPage(0) { 00063 _contexts = NULL; 00064 00065 // Can't put it in the LRU until it has been read in and made valid. 00066 } 00067 00068 //////////////////////////////////////////////////////////////////// 00069 // Function: GeomVertexArrayData::make_cow_copy 00070 // Access: Protected, Virtual 00071 // Description: Required to implement CopyOnWriteObject. 00072 //////////////////////////////////////////////////////////////////// 00073 PT(CopyOnWriteObject) GeomVertexArrayData:: 00074 make_cow_copy() { 00075 return new GeomVertexArrayData(*this); 00076 } 00077 00078 //////////////////////////////////////////////////////////////////// 00079 // Function: GeomVertexArrayData::Constructor 00080 // Access: Published 00081 // Description: 00082 //////////////////////////////////////////////////////////////////// 00083 GeomVertexArrayData:: 00084 GeomVertexArrayData(const GeomVertexArrayFormat *array_format, 00085 GeomVertexArrayData::UsageHint usage_hint) : 00086 SimpleLruPage(0), 00087 _array_format(array_format) 00088 { 00089 OPEN_ITERATE_ALL_STAGES(_cycler) { 00090 CDStageWriter cdata(_cycler, pipeline_stage); 00091 cdata->_usage_hint = usage_hint; 00092 } 00093 CLOSE_ITERATE_ALL_STAGES(_cycler); 00094 00095 _contexts = NULL; 00096 00097 set_lru_size(0); 00098 nassertv(_array_format->is_registered()); 00099 } 00100 00101 //////////////////////////////////////////////////////////////////// 00102 // Function: GeomVertexArrayData::Copy Constructor 00103 // Access: Published 00104 // Description: 00105 //////////////////////////////////////////////////////////////////// 00106 GeomVertexArrayData:: 00107 GeomVertexArrayData(const GeomVertexArrayData ©) : 00108 CopyOnWriteObject(copy), 00109 SimpleLruPage(copy), 00110 _array_format(copy._array_format), 00111 _cycler(copy._cycler) 00112 { 00113 _contexts = NULL; 00114 00115 copy.mark_used_lru(); 00116 00117 set_lru_size(get_data_size_bytes()); 00118 nassertv(_array_format->is_registered()); 00119 } 00120 00121 //////////////////////////////////////////////////////////////////// 00122 // Function: GeomVertexArrayData::Copy Assignment Operator 00123 // Access: Published 00124 // Description: The copy assignment operator is not pipeline-safe. 00125 // This will completely obliterate all stages of the 00126 // pipeline, so don't do it for a GeomVertexArrayData 00127 // that is actively being used for rendering. 00128 //////////////////////////////////////////////////////////////////// 00129 void GeomVertexArrayData:: 00130 operator = (const GeomVertexArrayData ©) { 00131 CopyOnWriteObject::operator = (copy); 00132 SimpleLruPage::operator = (copy); 00133 00134 copy.mark_used_lru(); 00135 00136 _array_format = copy._array_format; 00137 _cycler = copy._cycler; 00138 00139 OPEN_ITERATE_ALL_STAGES(_cycler) { 00140 CDStageWriter cdata(_cycler, pipeline_stage); 00141 cdata->_modified = Geom::get_next_modified(); 00142 } 00143 CLOSE_ITERATE_ALL_STAGES(_cycler); 00144 00145 nassertv(_array_format->is_registered()); 00146 } 00147 00148 //////////////////////////////////////////////////////////////////// 00149 // Function: GeomVertexArrayData::Destructor 00150 // Access: Published, Virtual 00151 // Description: 00152 //////////////////////////////////////////////////////////////////// 00153 GeomVertexArrayData:: 00154 ~GeomVertexArrayData() { 00155 release_all(); 00156 } 00157 00158 //////////////////////////////////////////////////////////////////// 00159 // Function: GeomVertexArrayData::compare_to 00160 // Access: Published 00161 // Description: Returns 0 if the two arrays are equivalent, even if 00162 // they are not the same pointer. 00163 //////////////////////////////////////////////////////////////////// 00164 int GeomVertexArrayData:: 00165 compare_to(const GeomVertexArrayData &other) const { 00166 Thread *current_thread = Thread::get_current_thread(); 00167 00168 CPT(GeomVertexArrayDataHandle) handle = get_handle(current_thread); 00169 CPT(GeomVertexArrayDataHandle) other_handle = other.get_handle(current_thread); 00170 00171 if (handle->get_usage_hint() != other_handle->get_usage_hint()) { 00172 return (int)handle->get_usage_hint() - (int)other_handle->get_usage_hint(); 00173 } 00174 if (handle->get_array_format() != other_handle->get_array_format()) { 00175 return handle->get_array_format() < other_handle->get_array_format() ? -1 : 1; 00176 } 00177 if (handle->get_data_size_bytes() != other_handle->get_data_size_bytes()) { 00178 return (int)handle->get_data_size_bytes() - (int)other_handle->get_data_size_bytes(); 00179 } 00180 return memcmp(handle->get_read_pointer(true), 00181 other_handle->get_read_pointer(true), 00182 handle->get_data_size_bytes()); 00183 } 00184 00185 //////////////////////////////////////////////////////////////////// 00186 // Function: GeomVertexArrayData::set_usage_hint 00187 // Access: Published 00188 // Description: Changes the UsageHint hint for this array. See 00189 // get_usage_hint(). 00190 // 00191 // Don't call this in a downstream thread unless you 00192 // don't mind it blowing away other changes you might 00193 // have recently made in an upstream thread. 00194 //////////////////////////////////////////////////////////////////// 00195 void GeomVertexArrayData:: 00196 set_usage_hint(GeomVertexArrayData::UsageHint usage_hint) { 00197 CDWriter cdata(_cycler, true); 00198 cdata->_usage_hint = usage_hint; 00199 cdata->_modified = Geom::get_next_modified(); 00200 } 00201 00202 //////////////////////////////////////////////////////////////////// 00203 // Function: GeomVertexArrayData::output 00204 // Access: Published 00205 // Description: 00206 //////////////////////////////////////////////////////////////////// 00207 void GeomVertexArrayData:: 00208 output(ostream &out) const { 00209 out << get_num_rows() << " rows: " << *get_array_format(); 00210 } 00211 00212 //////////////////////////////////////////////////////////////////// 00213 // Function: GeomVertexArrayData::write 00214 // Access: Published 00215 // Description: 00216 //////////////////////////////////////////////////////////////////// 00217 void GeomVertexArrayData:: 00218 write(ostream &out, int indent_level) const { 00219 _array_format->write_with_data(out, indent_level, this); 00220 } 00221 00222 //////////////////////////////////////////////////////////////////// 00223 // Function: GeomVertexArrayData::prepare 00224 // Access: Public 00225 // Description: Indicates that the data should be enqueued to be 00226 // prepared in the indicated prepared_objects at the 00227 // beginning of the next frame. This will ensure the 00228 // data is already loaded into the GSG if it is expected 00229 // to be rendered soon. 00230 // 00231 // Use this function instead of prepare_now() to preload 00232 // datas from a user interface standpoint. 00233 //////////////////////////////////////////////////////////////////// 00234 void GeomVertexArrayData:: 00235 prepare(PreparedGraphicsObjects *prepared_objects) { 00236 prepared_objects->enqueue_vertex_buffer(this); 00237 } 00238 00239 //////////////////////////////////////////////////////////////////// 00240 // Function: GeomVertexArrayData::is_prepared 00241 // Access: Published 00242 // Description: Returns true if the data has already been prepared 00243 // or enqueued for preparation on the indicated GSG, 00244 // false otherwise. 00245 //////////////////////////////////////////////////////////////////// 00246 bool GeomVertexArrayData:: 00247 is_prepared(PreparedGraphicsObjects *prepared_objects) const { 00248 if (_contexts == (Contexts *)NULL) { 00249 return false; 00250 } 00251 Contexts::const_iterator ci; 00252 ci = _contexts->find(prepared_objects); 00253 if (ci != _contexts->end()) { 00254 return true; 00255 } 00256 return prepared_objects->is_vertex_buffer_queued(this); 00257 } 00258 00259 //////////////////////////////////////////////////////////////////// 00260 // Function: GeomVertexArrayData::prepare_now 00261 // Access: Public 00262 // Description: Creates a context for the data on the particular 00263 // GSG, if it does not already exist. Returns the new 00264 // (or old) VertexBufferContext. This assumes that the 00265 // GraphicsStateGuardian is the currently active 00266 // rendering context and that it is ready to accept new 00267 // datas. If this is not necessarily the case, you 00268 // should use prepare() instead. 00269 // 00270 // Normally, this is not called directly except by the 00271 // GraphicsStateGuardian; a data does not need to be 00272 // explicitly prepared by the user before it may be 00273 // rendered. 00274 //////////////////////////////////////////////////////////////////// 00275 VertexBufferContext *GeomVertexArrayData:: 00276 prepare_now(PreparedGraphicsObjects *prepared_objects, 00277 GraphicsStateGuardianBase *gsg) { 00278 if (_contexts == (Contexts *)NULL) { 00279 _contexts = new Contexts; 00280 } 00281 Contexts::const_iterator ci; 00282 ci = _contexts->find(prepared_objects); 00283 if (ci != _contexts->end()) { 00284 return (*ci).second; 00285 } 00286 00287 VertexBufferContext *vbc = prepared_objects->prepare_vertex_buffer_now(this, gsg); 00288 if (vbc != (VertexBufferContext *)NULL) { 00289 (*_contexts)[prepared_objects] = vbc; 00290 } 00291 return vbc; 00292 } 00293 00294 //////////////////////////////////////////////////////////////////// 00295 // Function: GeomVertexArrayData::release 00296 // Access: Public 00297 // Description: Frees the data context only on the indicated object, 00298 // if it exists there. Returns true if it was released, 00299 // false if it had not been prepared. 00300 //////////////////////////////////////////////////////////////////// 00301 bool GeomVertexArrayData:: 00302 release(PreparedGraphicsObjects *prepared_objects) { 00303 if (_contexts != (Contexts *)NULL) { 00304 Contexts::iterator ci; 00305 ci = _contexts->find(prepared_objects); 00306 if (ci != _contexts->end()) { 00307 VertexBufferContext *vbc = (*ci).second; 00308 prepared_objects->release_vertex_buffer(vbc); 00309 return true; 00310 } 00311 } 00312 00313 // Maybe it wasn't prepared yet, but it's about to be. 00314 return prepared_objects->dequeue_vertex_buffer(this); 00315 } 00316 00317 //////////////////////////////////////////////////////////////////// 00318 // Function: GeomVertexArrayData::release_all 00319 // Access: Public 00320 // Description: Frees the context allocated on all objects for which 00321 // the data has been declared. Returns the number of 00322 // contexts which have been freed. 00323 //////////////////////////////////////////////////////////////////// 00324 int GeomVertexArrayData:: 00325 release_all() { 00326 int num_freed = 0; 00327 00328 if (_contexts != (Contexts *)NULL) { 00329 // We have to traverse a copy of the _contexts list, because the 00330 // PreparedGraphicsObjects object will call clear_prepared() in response 00331 // to each release_vertex_buffer(), and we don't want to be modifying the 00332 // _contexts list while we're traversing it. 00333 Contexts temp = *_contexts; 00334 num_freed = (int)_contexts->size(); 00335 00336 Contexts::const_iterator ci; 00337 for (ci = temp.begin(); ci != temp.end(); ++ci) { 00338 PreparedGraphicsObjects *prepared_objects = (*ci).first; 00339 VertexBufferContext *vbc = (*ci).second; 00340 prepared_objects->release_vertex_buffer(vbc); 00341 } 00342 00343 // Now that we've called release_vertex_buffer() on every known context, 00344 // the _contexts list should have completely emptied itself. 00345 nassertr(_contexts == NULL, num_freed); 00346 } 00347 00348 return num_freed; 00349 } 00350 00351 //////////////////////////////////////////////////////////////////// 00352 // Function: GeomVertexArrayData::lru_epoch 00353 // Access: Published, Static 00354 // Description: Marks that an epoch has passed in each LRU. Asks the 00355 // LRU's to consider whether they should perform 00356 // evictions. 00357 //////////////////////////////////////////////////////////////////// 00358 void GeomVertexArrayData:: 00359 lru_epoch() { 00360 _independent_lru.begin_epoch(); 00361 VertexDataPage::get_global_lru(VertexDataPage::RC_resident)->begin_epoch(); 00362 VertexDataPage::get_global_lru(VertexDataPage::RC_compressed)->begin_epoch(); 00363 } 00364 00365 //////////////////////////////////////////////////////////////////// 00366 // Function: GeomVertexArrayData::evict_lru 00367 // Access: Public, Virtual 00368 // Description: Evicts the page from the LRU. Called internally when 00369 // the LRU determines that it is full. May also be 00370 // called externally when necessary to explicitly evict 00371 // the page. 00372 // 00373 // It is legal for this method to either evict the page 00374 // as requested, do nothing (in which case the eviction 00375 // will be requested again at the next epoch), or 00376 // requeue itself on the tail of the queue (in which 00377 // case the eviction will be requested again much 00378 // later). 00379 //////////////////////////////////////////////////////////////////// 00380 void GeomVertexArrayData:: 00381 evict_lru() { 00382 dequeue_lru(); 00383 CDWriter cdata(_cycler, true); 00384 cdata->_buffer.page_out(_book); 00385 } 00386 00387 //////////////////////////////////////////////////////////////////// 00388 // Function: GeomVertexArrayData::clear_prepared 00389 // Access: Private 00390 // Description: Removes the indicated PreparedGraphicsObjects table 00391 // from the data array's table, without actually 00392 // releasing the data array. This is intended to be 00393 // called only from 00394 // PreparedGraphicsObjects::release_vertex_buffer(); it should 00395 // never be called by user code. 00396 //////////////////////////////////////////////////////////////////// 00397 void GeomVertexArrayData:: 00398 clear_prepared(PreparedGraphicsObjects *prepared_objects) { 00399 nassertv(_contexts != (Contexts *)NULL); 00400 00401 Contexts::iterator ci; 00402 ci = _contexts->find(prepared_objects); 00403 if (ci != _contexts->end()) { 00404 _contexts->erase(ci); 00405 if (_contexts->empty()) { 00406 delete _contexts; 00407 _contexts = NULL; 00408 } 00409 } else { 00410 // If this assertion fails, clear_prepared() was given a 00411 // prepared_objects which the data array didn't know about. 00412 nassertv(false); 00413 } 00414 } 00415 00416 //////////////////////////////////////////////////////////////////// 00417 // Function: GeomVertexArrayData::reverse_data_endianness 00418 // Access: Private 00419 // Description: Fills a new data array with all numeric values 00420 // expressed in the indicated array reversed, 00421 // byte-for-byte, to convert littleendian to bigendian 00422 // and vice-versa. 00423 //////////////////////////////////////////////////////////////////// 00424 void GeomVertexArrayData:: 00425 reverse_data_endianness(unsigned char *dest, const unsigned char *source, 00426 size_t size) { 00427 int num_columns = _array_format->get_num_columns(); 00428 00429 // Walk through each row of the data. 00430 for (size_t pi = 0; pi < size; pi += _array_format->get_stride()) { 00431 // For each row, visit all of the columns; and for each column, 00432 // visit all of the components of that column. 00433 for (int ci = 0; ci < num_columns; ++ci) { 00434 const GeomVertexColumn *col = _array_format->get_column(ci); 00435 int component_bytes = col->get_component_bytes(); 00436 if (component_bytes > 1) { 00437 // Get the index of the beginning of the column. 00438 size_t ci = pi + col->get_start(); 00439 00440 int num_components = col->get_num_components(); 00441 for (int cj = 0; cj < num_components; ++cj) { 00442 // Reverse the bytes of each component. 00443 ReversedNumericData nd(source + ci, component_bytes); 00444 nd.store_value(dest + ci, component_bytes); 00445 ci += component_bytes; 00446 } 00447 } 00448 } 00449 } 00450 } 00451 00452 //////////////////////////////////////////////////////////////////// 00453 // Function: GeomVertexArrayData::register_with_read_factory 00454 // Access: Public, Static 00455 // Description: Tells the BamReader how to create objects of type 00456 // GeomVertexArrayData. 00457 //////////////////////////////////////////////////////////////////// 00458 void GeomVertexArrayData:: 00459 register_with_read_factory() { 00460 BamReader::get_factory()->register_factory(get_class_type(), make_from_bam); 00461 } 00462 00463 //////////////////////////////////////////////////////////////////// 00464 // Function: GeomVertexArrayData::write_datagram 00465 // Access: Public, Virtual 00466 // Description: Writes the contents of this object to the datagram 00467 // for shipping out to a Bam file. 00468 //////////////////////////////////////////////////////////////////// 00469 void GeomVertexArrayData:: 00470 write_datagram(BamWriter *manager, Datagram &dg) { 00471 CopyOnWriteObject::write_datagram(manager, dg); 00472 00473 manager->write_pointer(dg, _array_format); 00474 manager->write_cdata(dg, _cycler, this); 00475 } 00476 00477 //////////////////////////////////////////////////////////////////// 00478 // Function: GeomVertexArrayData::read_raw_data 00479 // Access: Public 00480 // Description: Called by CData::fillin to read the raw data 00481 // of the array from the indicated datagram. 00482 //////////////////////////////////////////////////////////////////// 00483 PTA_uchar GeomVertexArrayData:: 00484 read_raw_data(BamReader *manager, DatagramIterator &scan) { 00485 size_t size = scan.get_uint32(); 00486 PTA_uchar data = PTA_uchar::empty_array(size, get_class_type()); 00487 const unsigned char *source_data = 00488 (const unsigned char *)scan.get_datagram().get_data(); 00489 memcpy(data, source_data + scan.get_current_index(), size); 00490 scan.skip_bytes(size); 00491 00492 return data; 00493 } 00494 00495 //////////////////////////////////////////////////////////////////// 00496 // Function: GeomVertexArrayData::complete_pointers 00497 // Access: Public, Virtual 00498 // Description: Receives an array of pointers, one for each time 00499 // manager->read_pointer() was called in fillin(). 00500 // Returns the number of pointers processed. 00501 //////////////////////////////////////////////////////////////////// 00502 int GeomVertexArrayData:: 00503 complete_pointers(TypedWritable **p_list, BamReader *manager) { 00504 int pi = CopyOnWriteObject::complete_pointers(p_list, manager); 00505 00506 _array_format = DCAST(GeomVertexArrayFormat, p_list[pi++]); 00507 00508 return pi; 00509 } 00510 00511 //////////////////////////////////////////////////////////////////// 00512 // Function: GeomVertexArrayData::finalize 00513 // Access: Public, Virtual 00514 // Description: Called by the BamReader to perform any final actions 00515 // needed for setting up the object after all objects 00516 // have been read and all pointers have been completed. 00517 //////////////////////////////////////////////////////////////////// 00518 void GeomVertexArrayData:: 00519 finalize(BamReader *manager) { 00520 // Now we need to register the format that we have read from the bam 00521 // file (since it doesn't come out of the bam file automatically 00522 // registered). This may change the format's pointer, which we 00523 // should then update our own data to reflect. But since this may 00524 // cause the unregistered object to destruct, we have to also tell 00525 // the BamReader to return the new object from now on. 00526 00527 CDWriter cdata(_cycler, true); 00528 00529 CPT(GeomVertexArrayFormat) new_array_format = 00530 GeomVertexArrayFormat::register_format(_array_format); 00531 00532 manager->change_pointer(_array_format, new_array_format); 00533 _array_format = new_array_format; 00534 00535 PT(BamAuxData) aux_data = (BamAuxData *)manager->get_aux_data(this, ""); 00536 if (aux_data != (BamAuxData *)NULL) { 00537 if (aux_data->_endian_reversed) { 00538 // Now is the time to endian-reverse the data. 00539 VertexDataBuffer new_buffer(cdata->_buffer.get_size()); 00540 reverse_data_endianness(new_buffer.get_write_pointer(), cdata->_buffer.get_read_pointer(true), cdata->_buffer.get_size()); 00541 cdata->_buffer.swap(new_buffer); 00542 } 00543 } 00544 00545 set_lru_size(cdata->_buffer.get_size()); 00546 } 00547 00548 //////////////////////////////////////////////////////////////////// 00549 // Function: GeomVertexArrayData::make_from_bam 00550 // Access: Protected, Static 00551 // Description: This function is called by the BamReader's factory 00552 // when a new object of type GeomVertexArrayData is encountered 00553 // in the Bam file. It should create the GeomVertexArrayData 00554 // and extract its information from the file. 00555 //////////////////////////////////////////////////////////////////// 00556 TypedWritable *GeomVertexArrayData:: 00557 make_from_bam(const FactoryParams ¶ms) { 00558 GeomVertexArrayData *object = new GeomVertexArrayData; 00559 DatagramIterator scan; 00560 BamReader *manager; 00561 00562 parse_params(params, scan, manager); 00563 object->fillin(scan, manager); 00564 manager->register_finalize(object); 00565 00566 return object; 00567 } 00568 00569 //////////////////////////////////////////////////////////////////// 00570 // Function: GeomVertexArrayData::fillin 00571 // Access: Protected 00572 // Description: This internal function is called by make_from_bam to 00573 // read in all of the relevant data from the BamFile for 00574 // the new GeomVertexArrayData. 00575 //////////////////////////////////////////////////////////////////// 00576 void GeomVertexArrayData:: 00577 fillin(DatagramIterator &scan, BamReader *manager) { 00578 CopyOnWriteObject::fillin(scan, manager); 00579 00580 manager->read_pointer(scan); 00581 manager->read_cdata(scan, _cycler, this); 00582 } 00583 00584 //////////////////////////////////////////////////////////////////// 00585 // Function: GeomVertexArrayData::CData::Destructor 00586 // Access: Public, Virtual 00587 // Description: 00588 //////////////////////////////////////////////////////////////////// 00589 GeomVertexArrayData::CData:: 00590 ~CData() { 00591 } 00592 00593 //////////////////////////////////////////////////////////////////// 00594 // Function: GeomVertexArrayData::CData::make_copy 00595 // Access: Public, Virtual 00596 // Description: 00597 //////////////////////////////////////////////////////////////////// 00598 CycleData *GeomVertexArrayData::CData:: 00599 make_copy() const { 00600 return new CData(*this); 00601 } 00602 00603 //////////////////////////////////////////////////////////////////// 00604 // Function: GeomVertexArrayData::CData::write_datagram 00605 // Access: Public, Virtual 00606 // Description: Writes the contents of this object to the datagram 00607 // for shipping out to a Bam file. 00608 //////////////////////////////////////////////////////////////////// 00609 void GeomVertexArrayData::CData:: 00610 write_datagram(BamWriter *manager, Datagram &dg, void *extra_data) const { 00611 GeomVertexArrayData *array_data = (GeomVertexArrayData *)extra_data; 00612 dg.add_uint8(_usage_hint); 00613 00614 dg.add_uint32(_buffer.get_size()); 00615 00616 if (manager->get_file_endian() == BamWriter::BE_native) { 00617 // For native endianness, we only have to write the data directly. 00618 dg.append_data(_buffer.get_read_pointer(true), _buffer.get_size()); 00619 00620 } else { 00621 // Otherwise, we have to convert it. 00622 unsigned char *new_data = (unsigned char *)alloca(_buffer.get_size()); 00623 array_data->reverse_data_endianness(new_data, _buffer.get_read_pointer(true), _buffer.get_size()); 00624 dg.append_data(new_data, _buffer.get_size()); 00625 } 00626 } 00627 00628 //////////////////////////////////////////////////////////////////// 00629 // Function: GeomVertexArrayData::CData::fillin 00630 // Access: Public, Virtual 00631 // Description: This internal function is called by make_from_bam to 00632 // read in all of the relevant data from the BamFile for 00633 // the new GeomVertexArrayData. 00634 //////////////////////////////////////////////////////////////////// 00635 void GeomVertexArrayData::CData:: 00636 fillin(DatagramIterator &scan, BamReader *manager, void *extra_data) { 00637 GeomVertexArrayData *array_data = (GeomVertexArrayData *)extra_data; 00638 _usage_hint = (UsageHint)scan.get_uint8(); 00639 00640 if (manager->get_file_minor_ver() < 8) { 00641 // Before bam version 6.8, the array data was a PTA_uchar. 00642 PTA_uchar new_data; 00643 READ_PTA(manager, scan, array_data->read_raw_data, new_data); 00644 _buffer.unclean_realloc(new_data.size()); 00645 _buffer.set_size(new_data.size()); 00646 memcpy(_buffer.get_write_pointer(), &new_data[0], new_data.size()); 00647 00648 } else { 00649 // Now, the array data is just stored directly. 00650 size_t size = scan.get_uint32(); 00651 _buffer.unclean_realloc(size); 00652 _buffer.set_size(size); 00653 00654 const unsigned char *source_data = 00655 (const unsigned char *)scan.get_datagram().get_data(); 00656 memcpy(_buffer.get_write_pointer(), source_data + scan.get_current_index(), size); 00657 scan.skip_bytes(size); 00658 } 00659 00660 bool endian_reversed = false; 00661 00662 if (manager->get_file_endian() != BamReader::BE_native) { 00663 // For non-native endian files, we have to convert the data. 00664 00665 if (array_data->_array_format == (GeomVertexArrayFormat *)NULL) { 00666 // But we can't do that until we've completed the _array_format 00667 // pointer, which tells us how to convert it. 00668 endian_reversed = true; 00669 } else { 00670 // Since we have the _array_format pointer now, we can reverse 00671 // it immediately (and we should, to support threaded CData 00672 // updates). 00673 VertexDataBuffer new_buffer(_buffer.get_size()); 00674 array_data->reverse_data_endianness(new_buffer.get_write_pointer(), _buffer.get_read_pointer(true), _buffer.get_size()); 00675 _buffer.swap(new_buffer); 00676 } 00677 } 00678 00679 if (endian_reversed) { 00680 PT(BamAuxData) aux_data = new BamAuxData; 00681 aux_data->_endian_reversed = endian_reversed; 00682 manager->set_aux_data(array_data, "", aux_data); 00683 } 00684 00685 array_data->set_lru_size(_buffer.get_size()); 00686 00687 _modified = Geom::get_next_modified(); 00688 } 00689 00690 //////////////////////////////////////////////////////////////////// 00691 // Function: GeomVertexArrayDataHandle::get_write_pointer 00692 // Access: Public 00693 // Description: Returns a writable pointer to the beginning of the 00694 // actual data stream. 00695 //////////////////////////////////////////////////////////////////// 00696 unsigned char *GeomVertexArrayDataHandle:: 00697 get_write_pointer() { 00698 nassertr(_writable, NULL); 00699 mark_used(); 00700 _cdata->_modified = Geom::get_next_modified(); 00701 return _cdata->_buffer.get_write_pointer(); 00702 } 00703 00704 //////////////////////////////////////////////////////////////////// 00705 // Function: GeomVertexArrayDataHandle::set_num_rows 00706 // Access: Public 00707 // Description: 00708 //////////////////////////////////////////////////////////////////// 00709 bool GeomVertexArrayDataHandle:: 00710 set_num_rows(int n) { 00711 nassertr(_writable, false); 00712 mark_used(); 00713 00714 int stride = _object->_array_format->get_stride(); 00715 size_t new_size = n * stride; 00716 size_t orig_size = _cdata->_buffer.get_size(); 00717 00718 if (gobj_cat.is_spam()) { 00719 gobj_cat.spam() 00720 << _object << ".set_num_rows(" << n << "), size = " << new_size << "\n"; 00721 } 00722 00723 if (new_size != orig_size) { 00724 size_t orig_reserved_size = _cdata->_buffer.get_reserved_size(); 00725 if (new_size > orig_reserved_size) { 00726 // Add more rows. Go up to the next power of two bytes, mainly 00727 // to reduce the number of allocs needed. 00728 size_t new_reserved_size = (size_t)Texture::up_to_power_2((int)new_size); 00729 nassertr(new_reserved_size >= new_size, false); 00730 00731 _cdata->_buffer.clean_realloc(new_reserved_size); 00732 00733 } else if (new_size == 0) { 00734 // If we set the number of rows to 0, go ahead and clear the 00735 // buffer altogether, and let the user build it up again from 00736 // nothing, to try to reduce frivolous memory waste. 00737 _cdata->_buffer.clear(); 00738 } 00739 00740 _cdata->_buffer.set_size(new_size); 00741 00742 // Now ensure that the newly-added rows are initialized to 0. 00743 if (new_size > orig_size) { 00744 memset(_cdata->_buffer.get_write_pointer() + orig_size, 0, 00745 new_size - orig_size); 00746 } 00747 00748 _cdata->_modified = Geom::get_next_modified(); 00749 00750 if (get_current_thread()->get_pipeline_stage() == 0) { 00751 _object->set_lru_size(_cdata->_buffer.get_size()); 00752 } 00753 00754 nassertr(get_num_rows() == n, true); 00755 return true; 00756 } 00757 00758 nassertr(get_num_rows() == n, false); 00759 return false; 00760 } 00761 00762 //////////////////////////////////////////////////////////////////// 00763 // Function: GeomVertexArrayDataHandle::unclean_set_num_rows 00764 // Access: Public 00765 // Description: 00766 //////////////////////////////////////////////////////////////////// 00767 bool GeomVertexArrayDataHandle:: 00768 unclean_set_num_rows(int n) { 00769 nassertr(_writable, false); 00770 mark_used(); 00771 00772 int stride = _object->_array_format->get_stride(); 00773 size_t new_size = n * stride; 00774 size_t orig_size = _cdata->_buffer.get_size(); 00775 size_t orig_reserved_size = _cdata->_buffer.get_reserved_size(); 00776 00777 if (new_size != orig_size || new_size != orig_reserved_size) { 00778 // Since this is unclean_set_num_rows(), we won't be using it to 00779 // incrementally increase the array; instead, it will generally be 00780 // used only to create an array initially. So it makes sense to 00781 // set the reserved size to precisely the same as the target size. 00782 00783 _cdata->_buffer.unclean_realloc(new_size); 00784 _cdata->_buffer.set_size(new_size); 00785 00786 // No need to fill to zero or copy the old buffer, since this is 00787 // unclean_set_num_rows(). 00788 00789 if (new_size != orig_size) { 00790 _cdata->_modified = Geom::get_next_modified(); 00791 00792 if (get_current_thread()->get_pipeline_stage() == 0) { 00793 _object->set_lru_size(_cdata->_buffer.get_size()); 00794 } 00795 } 00796 return true; 00797 } 00798 00799 return false; 00800 } 00801 00802 //////////////////////////////////////////////////////////////////// 00803 // Function: GeomVertexArrayDataHandle::reserve_num_rows 00804 // Access: Public 00805 // Description: 00806 //////////////////////////////////////////////////////////////////// 00807 bool GeomVertexArrayDataHandle:: 00808 reserve_num_rows(int n) { 00809 nassertr(_writable, false); 00810 mark_used(); 00811 00812 int stride = _object->_array_format->get_stride(); 00813 size_t new_reserved_size = n * stride; 00814 new_reserved_size = max(_cdata->_buffer.get_size(), new_reserved_size); 00815 size_t orig_reserved_size = _cdata->_buffer.get_reserved_size(); 00816 00817 if (gobj_cat.is_debug()) { 00818 gobj_cat.debug() 00819 << _object << ".reserve_num_rows(" << n << "), size = " << new_reserved_size << "\n"; 00820 } 00821 00822 if (new_reserved_size != orig_reserved_size) { 00823 // We allow the user to set the alloc point smaller with this 00824 // call, assuming the user knows what he's doing. This allows the 00825 // user to reduce wasted memory after completely filling up a 00826 // buffer. 00827 _cdata->_buffer.clean_realloc(new_reserved_size); 00828 return true; 00829 } 00830 00831 return false; 00832 } 00833 00834 //////////////////////////////////////////////////////////////////// 00835 // Function: GeomVertexArrayDataHandle::copy_data_from 00836 // Access: Public 00837 // Description: Copies the entire data array from the other object. 00838 //////////////////////////////////////////////////////////////////// 00839 void GeomVertexArrayDataHandle:: 00840 copy_data_from(const GeomVertexArrayDataHandle *other) { 00841 nassertv(_writable); 00842 mark_used(); 00843 other->mark_used(); 00844 00845 size_t size = other->_cdata->_buffer.get_size(); 00846 _cdata->_buffer.unclean_realloc(size); 00847 _cdata->_buffer.set_size(size); 00848 00849 unsigned char *dest = _cdata->_buffer.get_write_pointer(); 00850 const unsigned char *source = other->_cdata->_buffer.get_read_pointer(true); 00851 memcpy(dest, source, size); 00852 00853 _cdata->_modified = Geom::get_next_modified(); 00854 00855 if (get_current_thread()->get_pipeline_stage() == 0) { 00856 _object->set_lru_size(_cdata->_buffer.get_size()); 00857 } 00858 } 00859 00860 //////////////////////////////////////////////////////////////////// 00861 // Function: GeomVertexArrayDataHandle::copy_subdata_from 00862 // Access: Public 00863 // Description: Copies a portion of the data array from the other 00864 // object into a portion of the data array of this 00865 // object. If to_size != from_size, the size of this 00866 // data array is adjusted accordingly. 00867 //////////////////////////////////////////////////////////////////// 00868 void GeomVertexArrayDataHandle:: 00869 copy_subdata_from(size_t to_start, size_t to_size, 00870 const GeomVertexArrayDataHandle *other, 00871 size_t from_start, size_t from_size) { 00872 nassertv(_writable); 00873 mark_used(); 00874 other->mark_used(); 00875 00876 VertexDataBuffer &to_buffer = _cdata->_buffer; 00877 size_t to_buffer_orig_size = to_buffer.get_size(); 00878 to_start = min(to_start, to_buffer_orig_size); 00879 to_size = min(to_size, to_buffer_orig_size - to_start); 00880 00881 const VertexDataBuffer &from_buffer = other->_cdata->_buffer; 00882 size_t from_buffer_orig_size = from_buffer.get_size(); 00883 from_start = min(from_start, from_buffer_orig_size); 00884 from_size = min(from_size, from_buffer_orig_size - from_start); 00885 00886 if (from_size < to_size) { 00887 // Reduce the array. 00888 unsigned char *pointer = to_buffer.get_write_pointer(); 00889 memmove(pointer + to_start + to_size, 00890 pointer + to_start + from_size, 00891 to_buffer_orig_size - (to_start + to_size)); 00892 to_buffer.set_size(to_buffer_orig_size + from_size - to_size); 00893 00894 } else if (to_size < from_size) { 00895 // Expand the array. 00896 size_t needed_size = to_buffer_orig_size + from_size - to_size; 00897 size_t to_buffer_orig_reserved_size = to_buffer.get_reserved_size(); 00898 if (needed_size > to_buffer_orig_reserved_size) { 00899 size_t new_reserved_size = (size_t)Texture::up_to_power_2((int)needed_size); 00900 to_buffer.clean_realloc(new_reserved_size); 00901 } 00902 to_buffer.set_size(needed_size); 00903 00904 unsigned char *pointer = to_buffer.get_write_pointer(); 00905 memmove(pointer + to_start + to_size, 00906 pointer + to_start + from_size, 00907 to_buffer_orig_size - (to_start + to_size)); 00908 } 00909 00910 // Now copy the data. 00911 memcpy(to_buffer.get_write_pointer() + to_start, 00912 other->get_read_pointer(true) + from_start, 00913 from_size); 00914 _cdata->_modified = Geom::get_next_modified(); 00915 00916 if (get_current_thread()->get_pipeline_stage() == 0) { 00917 _object->set_lru_size(_cdata->_buffer.get_size()); 00918 } 00919 } 00920 00921 //////////////////////////////////////////////////////////////////// 00922 // Function: GeomVertexArrayDataHandle::set_data 00923 // Access: Public 00924 // Description: Replaces the entire raw data array with the contents 00925 // of the indicated string. This is primarily for the 00926 // benefit of high-level languages like Python. 00927 //////////////////////////////////////////////////////////////////// 00928 void GeomVertexArrayDataHandle:: 00929 set_data(const string &data) { 00930 nassertv(_writable); 00931 mark_used(); 00932 00933 _cdata->_buffer.unclean_realloc(data.size()); 00934 _cdata->_buffer.set_size(data.size()); 00935 memcpy(_cdata->_buffer.get_write_pointer(), data.data(), data.size()); 00936 00937 _cdata->_modified = Geom::get_next_modified(); 00938 00939 if (get_current_thread()->get_pipeline_stage() == 0) { 00940 _object->set_lru_size(_cdata->_buffer.get_size()); 00941 } 00942 } 00943 00944 //////////////////////////////////////////////////////////////////// 00945 // Function: GeomVertexArrayDataHandle::set_subdata 00946 // Access: Public 00947 // Description: Replaces a portion of the data array from the 00948 // indicated string. If size != data.size(), the size 00949 // of this data array is adjusted accordingly. 00950 // 00951 // This is primarily for the benefit of high-level 00952 // languages like Python. 00953 //////////////////////////////////////////////////////////////////// 00954 void GeomVertexArrayDataHandle:: 00955 set_subdata(size_t start, size_t size, const string &data) { 00956 nassertv(_writable); 00957 mark_used(); 00958 00959 VertexDataBuffer &to_buffer = _cdata->_buffer; 00960 size_t to_buffer_orig_size = to_buffer.get_size(); 00961 start = min(start, to_buffer_orig_size); 00962 size = min(size, to_buffer_orig_size - start); 00963 00964 size_t from_size = data.size(); 00965 00966 if (from_size < size) { 00967 // Reduce the array. 00968 unsigned char *pointer = to_buffer.get_write_pointer(); 00969 memmove(pointer + start + from_size, 00970 pointer + start + size, 00971 to_buffer_orig_size - (start + size)); 00972 to_buffer.set_size(to_buffer_orig_size + from_size - size); 00973 00974 } else if (size < from_size) { 00975 // Expand the array. 00976 size_t needed_size = to_buffer_orig_size + from_size - size; 00977 size_t to_buffer_orig_reserved_size = to_buffer.get_reserved_size(); 00978 if (needed_size > to_buffer_orig_reserved_size) { 00979 size_t new_reserved_size = (size_t)Texture::up_to_power_2((int)needed_size); 00980 to_buffer.clean_realloc(new_reserved_size); 00981 } 00982 to_buffer.set_size(needed_size); 00983 00984 unsigned char *pointer = to_buffer.get_write_pointer(); 00985 memmove(pointer + start + from_size, 00986 pointer + start + size, 00987 to_buffer_orig_size - (start + size)); 00988 } 00989 00990 // Now copy the data. 00991 memcpy(to_buffer.get_write_pointer() + start, data.data(), from_size); 00992 _cdata->_modified = Geom::get_next_modified(); 00993 00994 if (get_current_thread()->get_pipeline_stage() == 0) { 00995 _object->set_lru_size(_cdata->_buffer.get_size()); 00996 } 00997 }