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  */
49 swap(VertexDataBuffer &other) {
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 }
Similar to MutexHolder, but for a light mutex.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
void deallocate_array(void *ptr)
Deallocates memory, subtracting it from the total amount of memory allocated for this type.
Definition: typeHandle.cxx:141
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
A collection of VertexDataPages, which can be used to allocate new VertexDataBlock objects.
VertexDataBlock * alloc(size_t size)
Allocates and returns a new VertexDataBuffer of the requested size.
A block of bytes that stores the actual raw vertex data referenced by a GeomVertexArrayData object.
void swap(VertexDataBuffer &other)
Swaps the data buffers between this one and the other one.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.