Panda3D
vertexDataBuffer.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 vertexDataBuffer.cxx
10  * @author drose
11  * @date 2007-05-14
12  */
13 
14 #include "vertexDataBuffer.h"
15 #include "config_gobj.h"
16 #include "pStatTimer.h"
17 
18 TypeHandle VertexDataBuffer::_type_handle;
19 
20 /**
21  *
22  */
23 void VertexDataBuffer::
24 operator = (const VertexDataBuffer &copy) {
25  LightMutexHolder holder(_lock);
26  LightMutexHolder holder2(copy._lock);
27 
28  if (_resident_data != nullptr) {
29  nassertv(_reserved_size != 0);
30  get_class_type().deallocate_array(_resident_data);
31  _resident_data = nullptr;
32  }
33  if (copy._resident_data != nullptr && copy._size != 0) {
34  // We only allocate _size bytes, not the full _reserved_size allocated by
35  // the original copy.
36  _resident_data = (unsigned char *)get_class_type().allocate_array(copy._size);
37  memcpy(_resident_data, copy._resident_data, copy._size);
38  }
39  _size = copy._size;
40  _reserved_size = copy._size;
41  _block = copy._block;
42  nassertv(_reserved_size >= _size);
43 }
44 
45 /**
46  * Swaps the data buffers between this one and the other one.
47  */
50  LightMutexHolder holder(_lock);
51  LightMutexHolder holder2(other._lock);
52 
53  unsigned char *resident_data = _resident_data;
54  size_t size = _size;
55  size_t reserved_size = _reserved_size;
56 
57  _block.swap(other._block);
58 
59  _resident_data = other._resident_data;
60  _size = other._size;
61  _reserved_size = other._reserved_size;
62 
63  other._resident_data = resident_data;
64  other._size = size;
65  other._reserved_size = reserved_size;
66  nassertv(_reserved_size >= _size);
67 }
68 
69 /**
70  * Changes the reserved size of the buffer, preserving its data (except for
71  * any data beyond the new end of the buffer, if the buffer is being reduced).
72  * If the buffer is expanded, the new data is uninitialized.
73  *
74  * Assumes the lock is already held.
75  */
76 void VertexDataBuffer::
77 do_clean_realloc(size_t reserved_size) {
78  if (reserved_size != _reserved_size) {
79  if (reserved_size == 0 || _size == 0) {
80  do_unclean_realloc(reserved_size);
81  return;
82  }
83 
84  if (gobj_cat.is_debug()) {
85  gobj_cat.debug()
86  << this << ".clean_realloc(" << reserved_size << ")\n";
87  }
88 
89  // Page in if we're currently paged out.
90  if (_reserved_size != 0 && _resident_data == nullptr) {
91  do_page_in();
92  }
93 
94  if (_reserved_size == 0) {
95  nassertv(_resident_data == nullptr);
96  _resident_data = (unsigned char *)get_class_type().allocate_array(reserved_size);
97  } else {
98  nassertv(_resident_data != nullptr);
99  _resident_data = (unsigned char *)get_class_type().reallocate_array(_resident_data, reserved_size);
100  }
101  nassertv(_resident_data != nullptr);
102  _reserved_size = reserved_size;
103  }
104 
105  _size = std::min(_size, _reserved_size);
106 }
107 
108 /**
109  * Changes the reserved size of the buffer, without regard to preserving its
110  * data. This implicitly resets the size to 0.
111  *
112  * Assumes the lock is already held.
113  */
114 void VertexDataBuffer::
115 do_unclean_realloc(size_t reserved_size) {
116  if (reserved_size != _reserved_size || _resident_data == nullptr) {
117  if (gobj_cat.is_debug()) {
118  gobj_cat.debug()
119  << this << ".unclean_realloc(" << reserved_size << ")\n";
120  }
121 
122  // If we're paged out, discard the page.
123  _block = nullptr;
124 
125  if (_resident_data != nullptr) {
126  nassertv(_reserved_size != 0);
127 
128  get_class_type().deallocate_array(_resident_data);
129  _resident_data = nullptr;
130  _reserved_size = 0;
131  }
132 
133  if (reserved_size != 0) {
134  nassertv(_resident_data == nullptr);
135  _resident_data = (unsigned char *)get_class_type().allocate_array(reserved_size);
136  }
137 
138  _reserved_size = reserved_size;
139  }
140 
141  _size = 0;
142 }
143 
144 /**
145  * Moves the buffer out of independent memory and puts it on a page in the
146  * indicated book. The buffer may still be directly accessible as long as its
147  * page remains resident. Any subsequent attempt to rewrite the buffer will
148  * implicitly move it off of the page and back into independent memory.
149  *
150  * Assumes the lock is already held.
151  */
152 void VertexDataBuffer::
153 do_page_out(VertexDataBook &book) {
154  if (_block != nullptr || _reserved_size == 0) {
155  // We're already paged out.
156  return;
157  }
158  nassertv(_resident_data != nullptr);
159 
160  if (_size == 0) {
161  // It's an empty buffer. Just deallocate it; don't bother to create a
162  // block.
163  get_class_type().deallocate_array(_resident_data);
164  _resident_data = nullptr;
165  _reserved_size = 0;
166 
167  } else {
168  // It's a nonempty buffer, so write _size bytes (but not the full
169  // _reserved_size bytes) to a block.
170  _block = book.alloc(_size);
171  nassertv(_block != nullptr);
172  unsigned char *pointer = _block->get_pointer(true);
173  nassertv(pointer != nullptr);
174  memcpy(pointer, _resident_data, _size);
175 
176  get_class_type().deallocate_array(_resident_data);
177  _resident_data = nullptr;
178 
179  _reserved_size = _size;
180  }
181  nassertv(_reserved_size >= _size);
182 }
183 
184 /**
185  * Moves the buffer off of its current page and into independent memory. If
186  * the page is not already resident, it is forced resident first.
187  *
188  * Assumes the lock is already held.
189  */
190 void VertexDataBuffer::
191 do_page_in() {
192  if (_resident_data != nullptr || _reserved_size == 0) {
193  // We're already paged in.
194  return;
195  }
196 
197  nassertv(_block != nullptr);
198  nassertv(_reserved_size == _size);
199 
200  _resident_data = (unsigned char *)get_class_type().allocate_array(_size);
201  nassertv(_resident_data != nullptr);
202 
203  memcpy(_resident_data, _block->get_pointer(true), _size);
204 }
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void deallocate_array(void *ptr)
Deallocates memory, subtracting it from the total amount of memory allocated for this type.
Definition: typeHandle.cxx:141
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Similar to MutexHolder, but for a light mutex.
void swap(VertexDataBuffer &other)
Swaps the data buffers between this one and the other one.
A block of bytes that stores the actual raw vertex data referenced by a GeomVertexArrayData object.
VertexDataBlock * alloc(size_t size)
Allocates and returns a new VertexDataBuffer of the requested size.
A collection of VertexDataPages, which can be used to allocate new VertexDataBlock objects.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void * reallocate_array(void *ptr, size_t size)
Reallocates memory, adjusting the total amount of memory allocated for this type.
Definition: typeHandle.cxx:115
void * allocate_array(size_t size)
Allocates memory, adding it to the total amount of memory allocated for this type.
Definition: typeHandle.cxx:88
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81