KiCad PCB EDA Suite
cached_container.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2013-2016 CERN
5  * @author Maciej Suminski <maciej.suminski@cern.ch>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
34 #include <gal/opengl/vertex_item.h>
35 #include <gal/opengl/shader.h>
36 #include <gal/opengl/utils.h>
37 
38 #include <confirm.h>
39 #include <list>
40 #include <cassert>
41 
42 #ifdef __WXDEBUG__
43 #include <wx/log.h>
44 #include <profile.h>
45 #endif /* __WXDEBUG__ */
46 
47 using namespace KIGFX;
48 
49 CACHED_CONTAINER::CACHED_CONTAINER( unsigned int aSize ) :
50  VERTEX_CONTAINER( aSize ), m_item( NULL ),
51  m_chunkSize( 0 ), m_chunkOffset( 0 ), m_isMapped( false ),
52  m_isInitialized( false ), m_glBufferHandle( -1 )
53 {
54  // In the beginning there is only free space
55  m_freeChunks.insert( std::make_pair( aSize, 0 ) );
56 }
57 
58 
60 {
61  if( m_isMapped )
62  Unmap();
63 
64  if( m_isInitialized )
65  {
66  glDeleteBuffers( 1, &m_glBufferHandle );
67  }
68 }
69 
70 
72 {
73  assert( aItem != NULL );
74 
75  unsigned int itemSize = aItem->GetSize();
76  m_item = aItem;
77  m_chunkSize = itemSize;
78  m_useCopyBuffer = GLEW_ARB_copy_buffer;
79 
80  // Get the previously set offset if the item was stored previously
81  m_chunkOffset = itemSize > 0 ? aItem->GetOffset() : -1;
82 
83 #if CACHED_CONTAINER_TEST > 1
84  wxLogDebug( wxT( "Adding/editing item 0x%08lx (size %d)" ), (long) m_item, itemSize );
85 #endif
86 }
87 
88 
90 {
91  assert( m_item != NULL );
92 
93  unsigned int itemSize = m_item->GetSize();
94 
95  // Finishing the previously edited item
96  if( itemSize < m_chunkSize )
97  {
98  // There is some not used but reserved memory left, so we should return it to the pool
99  int itemOffset = m_item->GetOffset();
100 
101  // Add the not used memory back to the pool
102  addFreeChunk( itemOffset + itemSize, m_chunkSize - itemSize );
103  // mergeFreeChunks(); // veery slow and buggy
104  }
105 
106  if( itemSize > 0 )
107  m_items.insert( m_item );
108 
109  m_item = NULL;
110  m_chunkSize = 0;
111  m_chunkOffset = 0;
112 
113 #if CACHED_CONTAINER_TEST > 1
114  wxLogDebug( wxT( "Finishing item 0x%08lx (size %d)" ), (long) m_item, itemSize );
115  test();
116 #endif
117 }
118 
119 
120 VERTEX* CACHED_CONTAINER::Allocate( unsigned int aSize )
121 {
122  assert( m_item != NULL );
123  assert( m_isMapped );
124 
125  if( m_failed )
126  return NULL;
127 
128  unsigned int itemSize = m_item->GetSize();
129  unsigned int newSize = itemSize + aSize;
130 
131  if( newSize > m_chunkSize )
132  {
133  // There is not enough space in the currently reserved chunk, so we have to resize it
134  if( !reallocate( newSize ) )
135  {
136  m_failed = true;
137  return NULL;
138  }
139  }
140 
141  VERTEX* reserved = &m_vertices[m_chunkOffset + itemSize];
142 
143  // Now the item officially possesses the memory chunk
144  m_item->setSize( newSize );
145 
146  // The content has to be updated
147  m_dirty = true;
148 
149 #if CACHED_CONTAINER_TEST > 0
150  test();
151 #endif
152 #if CACHED_CONTAINER_TEST > 2
153  showFreeChunks();
154  showUsedChunks();
155 #endif
156 
157  return reserved;
158 }
159 
160 
162 {
163  assert( aItem != NULL );
164  assert( m_items.find( aItem ) != m_items.end() || aItem->GetSize() == 0 );
165 
166  int size = aItem->GetSize();
167 
168  if( size == 0 )
169  return; // Item is not stored here
170 
171  int offset = aItem->GetOffset();
172 
173 #if CACHED_CONTAINER_TEST > 1
174  wxLogDebug( wxT( "Removing 0x%08lx (size %d offset %d)" ), (long) aItem, size, offset );
175 #endif
176 
177  // Insert a free memory chunk entry in the place where item was stored
178  addFreeChunk( offset, size );
179 
180  // Indicate that the item is not stored in the container anymore
181  aItem->setSize( 0 );
182 
183  m_items.erase( aItem );
184 
185 #if CACHED_CONTAINER_TEST > 0
186  test();
187 #endif
188 
189  // This dynamic memory freeing optimize memory usage, but in fact can create
190  // out of memory issues because freeing and reallocation large chuncks of memory
191  // can create memory fragmentation and no room to reallocate large chuncks
192  // after many free/reallocate cycles during a session using the same complex board
193  // So it can be disable.
194  // Currently: it is disable to avoid "out of memory" issues
195 #if 0
196  // Dynamic memory freeing, there is no point in holding
197  // a large amount of memory when there is no use for it
198  if( m_freeSpace > ( 0.75 * m_currentSize ) && m_currentSize > m_initialSize )
199  {
201  }
202 #endif
203 }
204 
205 
207 {
209  m_failed = false;
210 
211  // Set the size of all the stored VERTEX_ITEMs to 0, so it is clear that they are not held
212  // in the container anymore
213  for( ITEMS::iterator it = m_items.begin(); it != m_items.end(); ++it )
214  {
215  ( *it )->setSize( 0 );
216  }
217 
218  m_items.clear();
219 
220  // Now there is only free space left
221  m_freeChunks.clear();
222  m_freeChunks.insert( std::make_pair( m_freeSpace, 0 ) );
223 }
224 
225 
227 {
228  assert( !IsMapped() );
229 
230  if( !m_isInitialized )
231  init();
232 
233  glBindBuffer( GL_ARRAY_BUFFER, m_glBufferHandle );
234  m_vertices = static_cast<VERTEX*>( glMapBuffer( GL_ARRAY_BUFFER, GL_READ_WRITE ) );
235  checkGlError( "mapping vertices buffer" );
236 
237  m_isMapped = true;
238 }
239 
240 
242 {
243  assert( IsMapped() );
244 
245  glUnmapBuffer( GL_ARRAY_BUFFER );
246  checkGlError( "unmapping vertices buffer" );
247  glBindBuffer( GL_ARRAY_BUFFER, 0 );
248  m_vertices = NULL;
249  checkGlError( "unbinding vertices buffer" );
250 
251  m_isMapped = false;
252 }
253 
254 
256 {
257  glGenBuffers( 1, &m_glBufferHandle );
258  glBindBuffer( GL_ARRAY_BUFFER, m_glBufferHandle );
259  glBufferData( GL_ARRAY_BUFFER, m_currentSize * VertexSize, NULL, GL_DYNAMIC_DRAW );
260  glBindBuffer( GL_ARRAY_BUFFER, 0 );
261  checkGlError( "allocating video memory for cached container" );
262 
263  m_isInitialized = true;
264 }
265 
266 
267 bool CACHED_CONTAINER::reallocate( unsigned int aSize )
268 {
269  assert( aSize > 0 );
270  assert( m_isMapped );
271 
272  unsigned int itemSize = m_item->GetSize();
273 
274 #if CACHED_CONTAINER_TEST > 2
275  wxLogDebug( wxT( "Resize %p from %d to %d" ), m_item, itemSize, aSize );
276 #endif
277 
278  // Find a free space chunk >= aSize
279  FREE_CHUNK_MAP::iterator newChunk = m_freeChunks.lower_bound( aSize );
280 
281  // Is there enough space to store vertices?
282  if( newChunk == m_freeChunks.end() )
283  {
284  bool result;
285 
286  // Would it be enough to double the current space?
287  if( aSize < m_freeSpace + m_currentSize )
288  {
289  // Yes: exponential growing
290  result = defragmentResize( m_currentSize * 2 );
291  }
292  else
293  {
294  // No: grow to the nearest greater power of 2
295  result = defragmentResize( pow( 2, ceil( log2( m_currentSize * 2 + aSize ) ) ) );
296  }
297 
298  if( !result )
299  return false;
300 
301  newChunk = m_freeChunks.lower_bound( aSize );
302  assert( newChunk != m_freeChunks.end() );
303  }
304 
305  // Parameters of the allocated chunk
306  unsigned int newChunkSize = getChunkSize( *newChunk );
307  unsigned int newChunkOffset = getChunkOffset( *newChunk );
308 
309  assert( newChunkSize >= aSize );
310  assert( newChunkOffset < m_currentSize );
311 
312  // Check if the item was previously stored in the container
313  if( itemSize > 0 )
314  {
315 #if CACHED_CONTAINER_TEST > 3
316  wxLogDebug( wxT( "Moving 0x%08x from 0x%08x to 0x%08x" ),
317  (int) m_item, oldChunkOffset, newChunkOffset );
318 #endif
319  // The item was reallocated, so we have to copy all the old data to the new place
320  memcpy( &m_vertices[newChunkOffset], &m_vertices[m_chunkOffset], itemSize * VertexSize );
321 
322  // Free the space used by the previous chunk
323  addFreeChunk( m_chunkOffset, m_chunkSize );
324  }
325 
326  // Remove the new allocated chunk from the free space pool
327  m_freeChunks.erase( newChunk );
328  m_freeSpace -= newChunkSize;
329 
330  m_chunkSize = newChunkSize;
331  m_chunkOffset = newChunkOffset;
332 
334 
335  return true;
336 }
337 
338 
340 {
341  if( m_freeChunks.size() <= 1 ) // There are no chunks that can be merged
342  return;
343 
344 #ifdef __WXDEBUG__
345  PROF_COUNTER totalTime;
346 #endif /* __WXDEBUG__ */
347 
348  // Reversed free chunks map - this one stores chunk size with its offset as the key
349  std::list<CHUNK> freeChunks;
350 
351  FREE_CHUNK_MAP::const_iterator it, it_end;
352 
353  for( it = m_freeChunks.begin(), it_end = m_freeChunks.end(); it != it_end; ++it )
354  {
355  freeChunks.push_back( std::make_pair( it->second, it->first ) );
356  }
357 
358  m_freeChunks.clear();
359  freeChunks.sort();
360 
361  std::list<CHUNK>::const_iterator itf, itf_end;
362  unsigned int offset = freeChunks.front().first;
363  unsigned int size = freeChunks.front().second;
364  freeChunks.pop_front();
365 
366  for( itf = freeChunks.begin(), itf_end = freeChunks.end(); itf != itf_end; ++itf )
367  {
368  if( itf->first == offset + size )
369  {
370  // These chunks can be merged, so just increase the current chunk size and go on
371  size += itf->second;
372  }
373  else
374  {
375  // These chunks cannot be merged
376  // So store the previous one
377  m_freeChunks.insert( std::make_pair( size, offset ) );
378  // and let's check the next chunk
379  offset = itf->first;
380  size = itf->second;
381 
382  }
383  }
384 
385  // Add the last one
386  m_freeChunks.insert( std::make_pair( size, offset ) );
387 
388 #ifdef __WXDEBUG__
389  totalTime.Stop();
390  wxLogDebug( "Merged free chunks / %.1f ms", totalTime.msecs() );
391 #endif /* __WXDEBUG__ */
392 #if CACHED_CONTAINER_TEST > 0
393  test();
394 #endif
395 }
396 
397 
398 bool CACHED_CONTAINER::defragmentResize( unsigned int aNewSize )
399 {
400  if( !m_useCopyBuffer )
401  return defragmentResizeMemcpy( aNewSize );
402 
403  assert( IsMapped() );
404 
405  wxLogTrace( "GAL_CACHED_CONTAINER",
406  wxT( "Resizing & defragmenting container from %d to %d" ), m_currentSize, aNewSize );
407 
408  // No shrinking if we cannot fit all the data
409  if( usedSpace() > aNewSize )
410  return false;
411 
412 #ifdef __WXDEBUG__
413  PROF_COUNTER totalTime;
414 #endif /* __WXDEBUG__ */
415 
416  GLuint newBuffer;
417 
418  // glCopyBufferSubData requires a buffer to be unmapped
419  glUnmapBuffer( GL_ARRAY_BUFFER );
420 
421  // Create the destination buffer
422  glGenBuffers( 1, &newBuffer );
423 
424  // It would be best to use GL_COPY_WRITE_BUFFER here,
425  // but it is not available everywhere
426 #ifdef __WXDEBUG__
427  GLint eaBuffer = -1;
428  glGetIntegerv( GL_ELEMENT_ARRAY_BUFFER_BINDING, &eaBuffer );
429  assert( eaBuffer == 0 );
430 #endif /* __WXDEBUG__ */
431  glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, newBuffer );
432  glBufferData( GL_ELEMENT_ARRAY_BUFFER, aNewSize * VertexSize, NULL, GL_DYNAMIC_DRAW );
433  checkGlError( "creating buffer during defragmentation" );
434 
435  ITEMS::iterator it, it_end;
436  int newOffset = 0;
437 
438  // Defragmentation
439  for( it = m_items.begin(), it_end = m_items.end(); it != it_end; ++it )
440  {
441  VERTEX_ITEM* item = *it;
442  int itemOffset = item->GetOffset();
443  int itemSize = item->GetSize();
444 
445  // Move an item to the new container
446  glCopyBufferSubData( GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER,
447  itemOffset * VertexSize, newOffset * VertexSize, itemSize * VertexSize );
448 
449  // Update new offset
450  item->setOffset( newOffset );
451 
452  // Move to the next free space
453  newOffset += itemSize;
454  }
455 
456  // Move the current item and place it at the end
457  if( m_item->GetSize() > 0 )
458  {
459  glCopyBufferSubData( GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER,
460  m_item->GetOffset() * VertexSize, newOffset * VertexSize,
461  m_item->GetSize() * VertexSize );
462 
463  m_item->setOffset( newOffset );
464  m_chunkOffset = newOffset;
465  }
466 
467  // Cleanup
468  glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
469  glBindBuffer( GL_ARRAY_BUFFER, 0 );
470  // Previously we have unmapped the array buffer, now when it is also
471  // unbound, it may be officially marked as unmapped
472  m_isMapped = false;
473  glDeleteBuffers( 1, &m_glBufferHandle );
474 
475  // Switch to the new vertex buffer
476  m_glBufferHandle = newBuffer;
477  Map();
478  checkGlError( "switching buffers during defragmentation" );
479 
480 #ifdef __WXDEBUG__
481  totalTime.Stop();
482 
483  wxLogTrace( "GAL_CACHED_CONTAINER",
484  "Defragmented container storing %d vertices / %.1f ms",
485  m_currentSize - m_freeSpace, totalTime.msecs() );
486 #endif /* __WXDEBUG__ */
487 
488  m_freeSpace += ( aNewSize - m_currentSize );
489  m_currentSize = aNewSize;
490 
491  // Now there is only one big chunk of free memory
492  m_freeChunks.clear();
493  m_freeChunks.insert( std::make_pair( m_freeSpace, m_currentSize - m_freeSpace ) );
494 
495  return true;
496 }
497 
498 
499 bool CACHED_CONTAINER::defragmentResizeMemcpy( unsigned int aNewSize )
500 {
501  assert( IsMapped() );
502 
503  wxLogTrace( "GAL_CACHED_CONTAINER",
504  wxT( "Resizing & defragmenting container (memcpy) from %d to %d" ),
505  m_currentSize, aNewSize );
506 
507  // No shrinking if we cannot fit all the data
508  if( usedSpace() > aNewSize )
509  return false;
510 
511 #ifdef __WXDEBUG__
512  PROF_COUNTER totalTime;
513 #endif /* __WXDEBUG__ */
514 
515  GLuint newBuffer;
516  VERTEX* newBufferMem;
517 
518  // Create the destination buffer
519  glGenBuffers( 1, &newBuffer );
520 
521  // It would be best to use GL_COPY_WRITE_BUFFER here,
522  // but it is not available everywhere
523 #ifdef __WXDEBUG__
524  GLint eaBuffer = -1;
525  glGetIntegerv( GL_ELEMENT_ARRAY_BUFFER_BINDING, &eaBuffer );
526  assert( eaBuffer == 0 );
527 #endif /* __WXDEBUG__ */
528  glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, newBuffer );
529  glBufferData( GL_ELEMENT_ARRAY_BUFFER, aNewSize * VertexSize, NULL, GL_DYNAMIC_DRAW );
530  newBufferMem = static_cast<VERTEX*>( glMapBuffer( GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY ) );
531  checkGlError( "creating buffer during defragmentation" );
532 
533  // Defragmentation
534  ITEMS::iterator it, it_end;
535  int newOffset = 0;
536 
537  for( it = m_items.begin(), it_end = m_items.end(); it != it_end; ++it )
538  {
539  VERTEX_ITEM* item = *it;
540  int itemOffset = item->GetOffset();
541  int itemSize = item->GetSize();
542 
543  // Move an item to the new container
544  memcpy( &newBufferMem[newOffset], &m_vertices[itemOffset], itemSize * VertexSize );
545 
546  // Update new offset
547  item->setOffset( newOffset );
548 
549  // Move to the next free space
550  newOffset += itemSize;
551  }
552 
553  // Move the current item and place it at the end
554  if( m_item->GetSize() > 0 )
555  {
556  memcpy( &newBufferMem[newOffset], &m_vertices[m_item->GetOffset()],
557  m_item->GetSize() * VertexSize );
558  m_item->setOffset( newOffset );
559  m_chunkOffset = newOffset;
560  }
561 
562  // Cleanup
563  glUnmapBuffer( GL_ELEMENT_ARRAY_BUFFER );
564  glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
565  Unmap();
566  glDeleteBuffers( 1, &m_glBufferHandle );
567 
568  // Switch to the new vertex buffer
569  m_glBufferHandle = newBuffer;
570  Map();
571  checkGlError( "switching buffers during defragmentation" );
572 
573 #ifdef __WXDEBUG__
574  totalTime.Stop();
575 
576  wxLogTrace( "GAL_CACHED_CONTAINER",
577  "Defragmented container storing %d vertices / %.1f ms",
578  m_currentSize - m_freeSpace, totalTime.msecs() );
579 #endif /* __WXDEBUG__ */
580 
581  m_freeSpace += ( aNewSize - m_currentSize );
582  m_currentSize = aNewSize;
583 
584  // Now there is only one big chunk of free memory
585  m_freeChunks.clear();
586  m_freeChunks.insert( std::make_pair( m_freeSpace, m_currentSize - m_freeSpace ) );
587 
588  return true;
589 }
590 
591 
592 void CACHED_CONTAINER::addFreeChunk( unsigned int aOffset, unsigned int aSize )
593 {
594  assert( aOffset + aSize <= m_currentSize );
595  assert( aSize > 0 );
596 
597  m_freeChunks.insert( std::make_pair( aSize, aOffset ) );
598  m_freeSpace += aSize;
599 }
600 
601 
603 {
604 #ifdef __WXDEBUG__
605  FREE_CHUNK_MAP::iterator it;
606 
607  wxLogDebug( wxT( "Free chunks:" ) );
608 
609  for( it = m_freeChunks.begin(); it != m_freeChunks.end(); ++it )
610  {
611  unsigned int offset = getChunkOffset( *it );
612  unsigned int size = getChunkSize( *it );
613  assert( size > 0 );
614 
615  wxLogDebug( wxT( "[0x%08x-0x%08x] (size %d)" ),
616  offset, offset + size - 1, size );
617  }
618 #endif /* __WXDEBUG__ */
619 }
620 
621 
623 {
624 #ifdef __WXDEBUG__
625  ITEMS::iterator it;
626 
627  wxLogDebug( wxT( "Used chunks:" ) );
628 
629  for( it = m_items.begin(); it != m_items.end(); ++it )
630  {
631  VERTEX_ITEM* item = *it;
632  unsigned int offset = item->GetOffset();
633  unsigned int size = item->GetSize();
634  assert( size > 0 );
635 
636  wxLogDebug( wxT( "[0x%08x-0x%08x] @ 0x%p (size %d)" ),
637  offset, offset + size - 1, item, size );
638  }
639 #endif /* __WXDEBUG__ */
640 }
641 
642 
644 {
645 #ifdef __WXDEBUG__
646  // Free space check
647  unsigned int freeSpace = 0;
648  FREE_CHUNK_MAP::iterator itf;
649 
650  for( itf = m_freeChunks.begin(); itf != m_freeChunks.end(); ++itf )
651  freeSpace += getChunkSize( *itf );
652 
653  assert( freeSpace == m_freeSpace );
654 
655  // Used space check
656  unsigned int usedSpace = 0;
657  ITEMS::iterator itr;
658  for( itr = m_items.begin(); itr != m_items.end(); ++itr )
659  usedSpace += ( *itr )->GetSize();
660 
661  // If we have a chunk assigned, then there must be an item edited
662  assert( m_chunkSize == 0 || m_item );
663 
664  // Currently reserved chunk is also counted as used
665  usedSpace += m_chunkSize;
666 
667  assert( ( m_freeSpace + usedSpace ) == m_currentSize );
668 
669  // Overlapping check TODO
670 #endif /* __WXDEBUG__ */
671 }
672 
const size_t VertexSize
Definition: vertex_common.h:57
void Stop()
save the time when this function was called, and set the counter stane to stop
Definition: profile.h:82
unsigned int usedSpace() const
Function usedSpace() returns size of the used memory space.
unsigned int m_initialSize
Actual storage memory (should be handled using malloc/realloc/free to speed up resizing) ...
void showFreeChunks()
Debug & test functions.
int getChunkSize(const CHUNK &aChunk) const
Function getChunkSize() returns size of the given chunk.
void addFreeChunk(unsigned int aOffset, unsigned int aSize)
Function addFreeChunk Adds a chunk marked as free.
Class CAIRO_GAL is the cairo implementation of the graphics abstraction layer.
Definition: class_module.h:56
bool m_isInitialized
Flag saying if the vertex buffer is initialized
This file is part of the common library.
bool defragmentResizeMemcpy(unsigned int aNewSize)
Class to control vertex container and GPU with possibility of emulating old-style OpenGL 1...
void init()
Function init() performs the GL vertex buffer initialization.
unsigned int m_currentSize
Store the initial size, so it can be resized to this on Clear()
int checkGlError(const std::string &aInfo, bool aThrow)
Checks if one of recent OpenGL operations has failed.
Definition: utils.cpp:30
unsigned int m_chunkSize
Properties of currently modified chunk & item
Class to store instances of VERTEX with caching.
The class PROF_COUNTER is a small class to help profiling.
Definition: profile.h:45
virtual void SetItem(VERTEX_ITEM *aItem) override
>
VERTEX * m_vertices
State flags.
void setSize(unsigned int aSize)
Function SetSize() Sets data size in the container.
Definition: vertex_item.h:96
bool m_useCopyBuffer
Flag saying whether it is safe to use glCopyBufferSubData
ITEMS m_items
Stored VERTEX_ITEMs
VERTEX_ITEM * m_item
Currently modified item
virtual void FinishItem() override
>
unsigned int m_freeSpace
How big is the current container, expressed in vertices.
CACHED_CONTAINER(unsigned int aSize=defaultInitSize)
unsigned int getChunkOffset(const CHUNK &aChunk) const
Function getChunkOffset() returns offset of the chunk.
void setOffset(unsigned int aOffset)
Function SetOffset() Sets data offset in the container.
Definition: vertex_item.h:86
void mergeFreeChunks()
Function mergeFreeChunks() looks for consecutive free memory chunks and merges them, decreasing fragmentation of memory.
virtual void Clear() override
>
unsigned int GetOffset() const
Function GetOffset() Returns data offset in the container.
Definition: vertex_item.h:65
bool defragmentResize(unsigned int aNewSize)
Function defragmentResize() removes empty spaces between chunks and optionally resizes the container...
virtual VERTEX * Allocate(unsigned int aSize) override
>
FREE_CHUNK_MAP m_freeChunks
Stores size & offset of free chunks.
double msecs() const
Definition: profile.h:121
unsigned int m_glBufferHandle
Vertex buffer handle
bool reallocate(unsigned int aSize)
Function reallocate() resizes the chunk that stores the current item to the given size...
Class to handle an item held in a container.
unsigned int GetSize() const
Function GetSize() Returns information about number of vertices stored.
Definition: vertex_item.h:55
bool m_isMapped
Flag saying if vertex buffer is currently mapped
bool IsMapped() const
Function IsMapped() returns true if vertex buffer is currently mapped.
virtual void Delete(VERTEX_ITEM *aItem) override
>