Panda3D
 All Classes Functions Variables Enumerations
vertexDataBuffer.cxx
1 // Filename: vertexDataBuffer.cxx
2 // Created by: drose (14May07)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "vertexDataBuffer.h"
16 #include "config_gobj.h"
17 #include "pStatTimer.h"
18 
19 TypeHandle VertexDataBuffer::_type_handle;
20 
21 ////////////////////////////////////////////////////////////////////
22 // Function: VertexDataBuffer::Copy Assignment Operator
23 // Access: Public
24 // Description:
25 ////////////////////////////////////////////////////////////////////
26 void VertexDataBuffer::
27 operator = (const VertexDataBuffer &copy) {
28  LightMutexHolder holder(_lock);
29  LightMutexHolder holder2(copy._lock);
30 
31  if (_resident_data != (unsigned char *)NULL) {
32  nassertv(_reserved_size != 0);
33  get_class_type().dec_memory_usage(TypeHandle::MC_array, (int)_reserved_size);
34  PANDA_FREE_ARRAY(_resident_data);
35  _resident_data = NULL;
36  }
37  if (copy._resident_data != (unsigned char *)NULL && copy._size != 0) {
38  // We only allocate _size bytes, not the full _reserved_size
39  // allocated by the original copy.
40  get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)copy._size);
41  _resident_data = (unsigned char *)PANDA_MALLOC_ARRAY(copy._size);
42  memcpy(_resident_data, copy._resident_data, copy._size);
43  }
44  _size = copy._size;
45  _reserved_size = copy._size;
46  _block = copy._block;
47  nassertv(_reserved_size >= _size);
48 }
49 
50 ////////////////////////////////////////////////////////////////////
51 // Function: VertexDataBuffer::swap
52 // Access: Public
53 // Description: Swaps the data buffers between this one and the other
54 // one.
55 ////////////////////////////////////////////////////////////////////
58  LightMutexHolder holder(_lock);
59  LightMutexHolder holder2(other._lock);
60 
61  unsigned char *resident_data = _resident_data;
62  size_t size = _size;
63  size_t reserved_size = _reserved_size;
64  PT(VertexDataBlock) block = _block;
65 
66  _resident_data = other._resident_data;
67  _size = other._size;
68  _reserved_size = other._reserved_size;
69  _block = other._block;
70 
71  other._resident_data = resident_data;
72  other._size = size;
73  other._reserved_size = reserved_size;
74  other._block = block;
75  nassertv(_reserved_size >= _size);
76 }
77 
78 ////////////////////////////////////////////////////////////////////
79 // Function: VertexDataBuffer::do_clean_realloc
80 // Access: Private
81 // Description: Changes the reserved size of the buffer, preserving
82 // its data (except for any data beyond the new end of
83 // the buffer, if the buffer is being reduced). If the
84 // buffer is expanded, the new data is uninitialized.
85 //
86 // Assumes the lock is already held.
87 ////////////////////////////////////////////////////////////////////
88 void VertexDataBuffer::
89 do_clean_realloc(size_t reserved_size) {
90  if (reserved_size != _reserved_size) {
91  if (reserved_size == 0 || _size == 0) {
92  do_unclean_realloc(reserved_size);
93  return;
94  }
95 
96  if (gobj_cat.is_debug()) {
97  gobj_cat.debug()
98  << this << ".clean_realloc(" << reserved_size << ")\n";
99  }
100 
101  // Page in if we're currently paged out.
102  if (_reserved_size != 0 && _resident_data == (unsigned char *)NULL) {
103  do_page_in();
104  }
105 
106  get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)reserved_size - (int)_reserved_size);
107  if (_reserved_size == 0) {
108  nassertv(_resident_data == (unsigned char *)NULL);
109  _resident_data = (unsigned char *)PANDA_MALLOC_ARRAY(reserved_size);
110  } else {
111  nassertv(_resident_data != (unsigned char *)NULL);
112  _resident_data = (unsigned char *)PANDA_REALLOC_ARRAY(_resident_data, reserved_size);
113  }
114  nassertv(_resident_data != (unsigned char *)NULL);
115  _reserved_size = reserved_size;
116  }
117 
118  _size = min(_size, _reserved_size);
119 }
120 
121 ////////////////////////////////////////////////////////////////////
122 // Function: VertexDataBuffer::do_unclean_realloc
123 // Access: Private
124 // Description: Changes the reserved size of the buffer, without
125 // regard to preserving its data. This implicitly
126 // resets the size to 0.
127 //
128 // Assumes the lock is already held.
129 ////////////////////////////////////////////////////////////////////
130 void VertexDataBuffer::
131 do_unclean_realloc(size_t reserved_size) {
132  if (reserved_size != _reserved_size || _resident_data == (unsigned char *)NULL) {
133  if (gobj_cat.is_debug()) {
134  gobj_cat.debug()
135  << this << ".unclean_realloc(" << reserved_size << ")\n";
136  }
137 
138  // If we're paged out, discard the page.
139  _block = NULL;
140 
141  if (_resident_data != (unsigned char *)NULL) {
142  nassertv(_reserved_size != 0);
143 
144  get_class_type().dec_memory_usage(TypeHandle::MC_array, (int)_reserved_size);
145  PANDA_FREE_ARRAY(_resident_data);
146  _resident_data = NULL;
147  _reserved_size = 0;
148  }
149 
150  if (reserved_size != 0) {
151  get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)reserved_size);
152  nassertv(_resident_data == (unsigned char *)NULL);
153  _resident_data = (unsigned char *)PANDA_MALLOC_ARRAY(reserved_size);
154  }
155 
156  _reserved_size = reserved_size;
157  }
158 
159  _size = 0;
160 }
161 
162 ////////////////////////////////////////////////////////////////////
163 // Function: VertexDataBuffer::do_page_out
164 // Access: Private
165 // Description: Moves the buffer out of independent memory and puts
166 // it on a page in the indicated book. The buffer may
167 // still be directly accessible as long as its page
168 // remains resident. Any subsequent attempt to rewrite
169 // the buffer will implicitly move it off of the page
170 // and back into independent memory.
171 //
172 // Assumes the lock is already held.
173 ////////////////////////////////////////////////////////////////////
174 void VertexDataBuffer::
175 do_page_out(VertexDataBook &book) {
176  if (_block != (VertexDataBlock *)NULL || _reserved_size == 0) {
177  // We're already paged out.
178  return;
179  }
180  nassertv(_resident_data != (unsigned char *)NULL);
181 
182  if (_size == 0) {
183  // It's an empty buffer. Just deallocate it; don't bother to
184  // create a block.
185  get_class_type().dec_memory_usage(TypeHandle::MC_array, (int)_reserved_size);
186  PANDA_FREE_ARRAY(_resident_data);
187  _resident_data = NULL;
188  _reserved_size = 0;
189 
190  } else {
191  // It's a nonempty buffer, so write _size bytes (but not the full
192  // _reserved_size bytes) to a block.
193  _block = book.alloc(_size);
194  nassertv(_block != (VertexDataBlock *)NULL);
195  unsigned char *pointer = _block->get_pointer(true);
196  nassertv(pointer != (unsigned char *)NULL);
197  memcpy(pointer, _resident_data, _size);
198 
199  get_class_type().dec_memory_usage(TypeHandle::MC_array, (int)_reserved_size);
200  PANDA_FREE_ARRAY(_resident_data);
201  _resident_data = NULL;
202 
203  _reserved_size = _size;
204  }
205  nassertv(_reserved_size >= _size);
206 }
207 
208 ////////////////////////////////////////////////////////////////////
209 // Function: VertexDataBuffer::do_page_in
210 // Access: Private
211 // Description: Moves the buffer off of its current page and into
212 // independent memory. If the page is not already
213 // resident, it is forced resident first.
214 //
215 // Assumes the lock is already held.
216 ////////////////////////////////////////////////////////////////////
217 void VertexDataBuffer::
218 do_page_in() {
219  if (_resident_data != (unsigned char *)NULL || _reserved_size == 0) {
220  // We're already paged in.
221  return;
222  }
223 
224  nassertv(_block != (VertexDataBlock *)NULL);
225  nassertv(_reserved_size == _size);
226 
227  get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)_size);
228  _resident_data = (unsigned char *)PANDA_MALLOC_ARRAY(_size);
229  nassertv(_resident_data != (unsigned char *)NULL);
230 
231  memcpy(_resident_data, _block->get_pointer(true), _size);
232 }
A block of bytes that stores the actual raw vertex data referenced by a GeomVertexArrayData object...
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...
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85