KiCad PCB EDA Suite
KIGFX::CACHED_CONTAINER_GPU Class Reference

Specialization of CACHED_CONTAINER that stores data in video memory via memory mapping. More...

#include <cached_container_gpu.h>

Inheritance diagram for KIGFX::CACHED_CONTAINER_GPU:
KIGFX::CACHED_CONTAINER KIGFX::VERTEX_CONTAINER

Public Member Functions

 CACHED_CONTAINER_GPU (unsigned int aSize=DEFAULT_SIZE)
 
 ~CACHED_CONTAINER_GPU ()
 
unsigned int GetBufferHandle () const override
 Return handle to the vertex buffer. More...
 
bool IsMapped () const override
 Prepare the container for vertices updates. More...
 
void Map () override
 Finish the vertices updates stage. More...
 
void Unmap () override
 Finish the vertices updates stage. More...
 
virtual unsigned int AllItemsSize () const override
 
bool IsCached () const override
 Return true if the container caches vertex data in RAM or video memory. More...
 
virtual void SetItem (VERTEX_ITEM *aItem) override
 Clean up after adding an item. More...
 
virtual void FinishItem () override
 Clean up after adding an item. More...
 
virtual VERTEXAllocate (unsigned int aSize) override
 Return allocated space for the requested number of vertices associated with the current item (set with SetItem()). More...
 
virtual void Delete (VERTEX_ITEM *aItem) override
 Remove all data stored in the container and restores its original state. More...
 
virtual void Clear () override
 Remove all data stored in the container and restores its original state. More...
 
VERTEXGetAllVertices () const
 Return pointer to the vertices stored in the container. More...
 
virtual VERTEXGetVertices (unsigned int aOffset) const
 Return vertices stored at the specific offset. More...
 
virtual unsigned int GetSize () const
 Return amount of vertices currently stored in the container. More...
 
bool IsDirty () const
 Return information about the container cache state. More...
 
void SetDirty ()
 Set the dirty flag, so vertices in the container are going to be reuploaded to the GPU on the next frame. More...
 
void ClearDirty ()
 Clear the dirty flag to prevent reuploading vertices to the GPU memory. More...
 

Static Public Member Functions

static VERTEX_CONTAINERMakeContainer (bool aCached)
 Return a pointer to a new container of an appropriate type. More...
 

Protected Types

typedef std::pair< unsigned int, unsigned int > CHUNK
 < Maps size of free memory chunks to their offsets More...
 
typedef std::multimap< unsigned int, unsigned int > FREE_CHUNK_MAP
 
typedef std::set< VERTEX_ITEM * > ITEMS
 List of all the stored items. More...
 

Protected Member Functions

bool defragmentResize (unsigned int aNewSize) override
 Remove empty spaces between chunks and optionally resizes the container. More...
 
bool defragmentResizeMemcpy (unsigned int aNewSize)
 Flag saying if vertex buffer is currently mapped. More...
 
bool reallocate (unsigned int aSize)
 Resize the chunk that stores the current item to the given size. More...
 
void defragment (VERTEX *aTarget)
 Transfer all stored data to a new buffer, removing empty spaces between the data chunks in the container. More...
 
void mergeFreeChunks ()
 Look for consecutive free memory chunks and merges them, decreasing fragmentation of memory. More...
 
int getChunkSize (const CHUNK &aChunk) const
 Return the size of a chunk. More...
 
unsigned int getChunkOffset (const CHUNK &aChunk) const
 Return the offset of a chunk. More...
 
void addFreeChunk (unsigned int aOffset, unsigned int aSize)
 Add a chunk marked as a free space. More...
 
unsigned int usedSpace () const
 Return size of the used memory space. More...
 

Protected Attributes

bool m_isMapped
 Vertex buffer handle. More...
 
unsigned int m_glBufferHandle
 Flag saying whether it is safe to use glCopyBufferSubData. More...
 
bool m_useCopyBuffer
 
FREE_CHUNK_MAP m_freeChunks
 Stored VERTEX_ITEMs. More...
 
ITEMS m_items
 Currently modified item. More...
 
VERTEX_ITEMm_item
 Properties of currently modified chunk & item. More...
 
unsigned int m_chunkSize
 
unsigned int m_chunkOffset
 Maximal vertex index number stored in the container. More...
 
unsigned int m_maxIndex
 
unsigned int m_freeSpace
 Current container size, expressed in vertices. More...
 
unsigned int m_currentSize
 Store the initial size, so it can be resized to this on Clear() More...
 
unsigned int m_initialSize
 Actual storage memory. More...
 
VERTEXm_vertices
 
bool m_failed
 
bool m_dirty
 Default initial size of a container (expressed in vertices) More...
 

Static Protected Attributes

static constexpr unsigned int DEFAULT_SIZE = 1048576
 

Private Member Functions

void showFreeChunks ()
 Debug & test functions. More...
 
void showUsedChunks ()
 
void test ()
 

Detailed Description

Specialization of CACHED_CONTAINER that stores data in video memory via memory mapping.

Definition at line 38 of file cached_container_gpu.h.

Member Typedef Documentation

◆ CHUNK

typedef std::pair<unsigned int, unsigned int> KIGFX::CACHED_CONTAINER::CHUNK
protectedinherited

< Maps size of free memory chunks to their offsets

Definition at line 101 of file cached_container.h.

◆ FREE_CHUNK_MAP

typedef std::multimap<unsigned int, unsigned int> KIGFX::CACHED_CONTAINER::FREE_CHUNK_MAP
protectedinherited

Definition at line 102 of file cached_container.h.

◆ ITEMS

typedef std::set<VERTEX_ITEM*> KIGFX::CACHED_CONTAINER::ITEMS
protectedinherited

List of all the stored items.

Definition at line 105 of file cached_container.h.

Constructor & Destructor Documentation

◆ CACHED_CONTAINER_GPU()

CACHED_CONTAINER_GPU::CACHED_CONTAINER_GPU ( unsigned int  aSize = DEFAULT_SIZE)

Definition at line 52 of file cached_container_gpu.cpp.

52 :
53 CACHED_CONTAINER( aSize ),
54 m_isMapped( false ),
56{
57 m_useCopyBuffer = GLEW_ARB_copy_buffer;
58
59 wxString vendor( glGetString( GL_VENDOR ) );
60
61 // workaround for intel GPU drivers:
62 // disable glCopyBuffer, causes crashes/freezes on certain driver versions
63 // Note, Intel's GL_VENDOR string varies depending on GPU/driver generation
64 // But generally always starts with Intel at least
65 if( vendor.StartsWith( "Intel" ) || vendor.Contains( "etnaviv" ) )
66 {
67 m_useCopyBuffer = false;
68 }
69
70 KI_TRACE( traceGalProfile, "VBO initial size: %d\n", m_currentSize );
71
72 glGenBuffers( 1, &m_glBufferHandle );
73 glBindBuffer( GL_ARRAY_BUFFER, m_glBufferHandle );
74 glBufferData( GL_ARRAY_BUFFER, m_currentSize * VERTEX_SIZE, nullptr, GL_DYNAMIC_DRAW );
75 glBindBuffer( GL_ARRAY_BUFFER, 0 );
76 checkGlError( "allocating video memory for cached container", __FILE__, __LINE__ );
77}
bool m_isMapped
Vertex buffer handle.
unsigned int m_glBufferHandle
Flag saying whether it is safe to use glCopyBufferSubData.
CACHED_CONTAINER(unsigned int aSize=DEFAULT_SIZE)
unsigned int m_currentSize
Store the initial size, so it can be resized to this on Clear()
const wxChar *const traceGalProfile
Flag to enable debug output of GAL performance profiling.
static constexpr size_t VERTEX_SIZE
Definition: vertex_common.h:67
#define KI_TRACE(aWhat,...)
int checkGlError(const std::string &aInfo, const char *aFile, int aLine, bool aThrow)
Check if a recent OpenGL operation has failed.
Definition: utils.cpp:45

References checkGlError(), KI_TRACE, KIGFX::VERTEX_CONTAINER::m_currentSize, m_glBufferHandle, m_useCopyBuffer, traceGalProfile, and KIGFX::VERTEX_SIZE.

◆ ~CACHED_CONTAINER_GPU()

CACHED_CONTAINER_GPU::~CACHED_CONTAINER_GPU ( )

Definition at line 80 of file cached_container_gpu.cpp.

81{
82 if( m_isMapped )
83 Unmap();
84
85 if( glDeleteBuffers )
86 glDeleteBuffers( 1, &m_glBufferHandle );
87}
void Unmap() override
Finish the vertices updates stage.

References m_glBufferHandle, m_isMapped, and Unmap().

Member Function Documentation

◆ addFreeChunk()

void CACHED_CONTAINER::addFreeChunk ( unsigned int  aOffset,
unsigned int  aSize 
)
protectedinherited

Add a chunk marked as a free space.

Store size & offset of free chunks.

Definition at line 360 of file cached_container.cpp.

361{
362 assert( aOffset + aSize <= m_currentSize );
363 assert( aSize > 0 );
364
365 m_freeChunks.insert( std::make_pair( aSize, aOffset ) );
366 m_freeSpace += aSize;
367}
FREE_CHUNK_MAP m_freeChunks
Stored VERTEX_ITEMs.
unsigned int m_freeSpace
Current container size, expressed in vertices.

References KIGFX::VERTEX_CONTAINER::m_currentSize, KIGFX::CACHED_CONTAINER::m_freeChunks, and KIGFX::VERTEX_CONTAINER::m_freeSpace.

Referenced by KIGFX::CACHED_CONTAINER::Delete(), KIGFX::CACHED_CONTAINER::FinishItem(), and KIGFX::CACHED_CONTAINER::reallocate().

◆ AllItemsSize()

unsigned int CACHED_CONTAINER_GPU::AllItemsSize ( ) const
overridevirtual

Reimplemented from KIGFX::CACHED_CONTAINER.

Definition at line 300 of file cached_container_gpu.cpp.

301{
302 unsigned int size = 0;
303
304 for( const auto& item : m_items )
305 {
306 size += item->GetSize();
307 }
308
309 return size;
310}
ITEMS m_items
Currently modified item.

References KIGFX::CACHED_CONTAINER::m_items.

Referenced by defragmentResize(), and defragmentResizeMemcpy().

◆ Allocate()

VERTEX * CACHED_CONTAINER::Allocate ( unsigned int  aSize)
overridevirtualinherited

Return allocated space for the requested number of vertices associated with the current item (set with SetItem()).

The allocated space is added at the end of the chunk used by the current item and may serve to store new vertices.

Parameters
aSizeis the number of vertices to be allocated.
Returns
Pointer to the allocated space.
Exceptions
bad_allocexception if allocation fails. Erase the data related to an item.
Parameters
aItemis the item to be erased.

Implements KIGFX::VERTEX_CONTAINER.

Definition at line 107 of file cached_container.cpp.

108{
109 assert( m_item != nullptr );
110 assert( IsMapped() );
111
112 if( m_failed )
113 return nullptr;
114
115 unsigned int itemSize = m_item->GetSize();
116 unsigned int newSize = itemSize + aSize;
117
118 if( newSize > m_chunkSize )
119 {
120 // There is not enough space in the currently reserved chunk, so we have to resize it
121 if( !reallocate( newSize ) )
122 {
123 m_failed = true;
124 return nullptr;
125 }
126 }
127
128 VERTEX* reserved = &m_vertices[m_chunkOffset + itemSize];
129
130 // Now the item officially possesses the memory chunk
131 m_item->setSize( newSize );
132
133 // The content has to be updated
134 m_dirty = true;
135
136#if CACHED_CONTAINER_TEST > 0
137 test();
138#endif
139#if CACHED_CONTAINER_TEST > 2
142#endif
143
144 return reserved;
145}
unsigned int m_chunkOffset
Maximal vertex index number stored in the container.
void showFreeChunks()
Debug & test functions.
VERTEX_ITEM * m_item
Properties of currently modified chunk & item.
virtual bool IsMapped() const =0
Return true if vertex buffer is currently mapped.
bool reallocate(unsigned int aSize)
Resize the chunk that stores the current item to the given size.
bool m_dirty
Default initial size of a container (expressed in vertices)
void setSize(unsigned int aSize)
Set data size in the container.
Definition: vertex_item.h:94
unsigned int GetSize() const
Return information about number of vertices stored.
Definition: vertex_item.h:58

References KIGFX::VERTEX_ITEM::GetSize(), KIGFX::CACHED_CONTAINER::IsMapped(), KIGFX::CACHED_CONTAINER::m_chunkOffset, KIGFX::CACHED_CONTAINER::m_chunkSize, KIGFX::VERTEX_CONTAINER::m_dirty, KIGFX::VERTEX_CONTAINER::m_failed, KIGFX::CACHED_CONTAINER::m_item, KIGFX::VERTEX_CONTAINER::m_vertices, KIGFX::CACHED_CONTAINER::reallocate(), KIGFX::VERTEX_ITEM::setSize(), KIGFX::CACHED_CONTAINER::showFreeChunks(), KIGFX::CACHED_CONTAINER::showUsedChunks(), and KIGFX::CACHED_CONTAINER::test().

◆ Clear()

void CACHED_CONTAINER::Clear ( )
overridevirtualinherited

Remove all data stored in the container and restores its original state.

Implements KIGFX::VERTEX_CONTAINER.

Definition at line 189 of file cached_container.cpp.

190{
192 m_maxIndex = 0;
193 m_failed = false;
194
195 // Set the size of all the stored VERTEX_ITEMs to 0, so it is clear that they are not held
196 // in the container anymore
197 for( ITEMS::iterator it = m_items.begin(); it != m_items.end(); ++it )
198 ( *it )->setSize( 0 );
199
200 m_items.clear();
201
202 // Now there is only free space left
203 m_freeChunks.clear();
204 m_freeChunks.insert( std::make_pair( m_freeSpace, 0 ) );
205}

References KIGFX::VERTEX_CONTAINER::m_currentSize, KIGFX::VERTEX_CONTAINER::m_failed, KIGFX::CACHED_CONTAINER::m_freeChunks, KIGFX::VERTEX_CONTAINER::m_freeSpace, KIGFX::CACHED_CONTAINER::m_items, and KIGFX::CACHED_CONTAINER::m_maxIndex.

◆ ClearDirty()

void KIGFX::VERTEX_CONTAINER::ClearDirty ( )
inlineinherited

Clear the dirty flag to prevent reuploading vertices to the GPU memory.

Definition at line 152 of file vertex_container.h.

153 {
154 m_dirty = false;
155 }

References KIGFX::VERTEX_CONTAINER::m_dirty.

Referenced by KIGFX::GPU_CACHED_MANAGER::EndDrawing().

◆ defragment()

void CACHED_CONTAINER::defragment ( VERTEX aTarget)
protectedinherited

Transfer all stored data to a new buffer, removing empty spaces between the data chunks in the container.

Parameters
aTargetis the destination for the defragmented data.

Definition at line 272 of file cached_container.cpp.

273{
274 // Defragmentation
275 ITEMS::iterator it, it_end;
276 int newOffset = 0;
277
278 for( VERTEX_ITEM* item : m_items )
279 {
280 int itemOffset = item->GetOffset();
281 int itemSize = item->GetSize();
282
283 // Move an item to the new container
284 memcpy( &aTarget[newOffset], &m_vertices[itemOffset], itemSize * VERTEX_SIZE );
285
286 // Update new offset
287 item->setOffset( newOffset );
288
289 // Move to the next free space
290 newOffset += itemSize;
291 }
292
293 // Move the current item and place it at the end
294 if( m_item->GetSize() > 0 )
295 {
296 memcpy( &aTarget[newOffset], &m_vertices[m_item->GetOffset()],
298 m_item->setOffset( newOffset );
299 m_chunkOffset = newOffset;
300 }
301
303}
unsigned int usedSpace() const
Return size of the used memory space.
void setOffset(unsigned int aOffset)
Set data offset in the container.
Definition: vertex_item.h:84
unsigned int GetOffset() const
Return data offset in the container.
Definition: vertex_item.h:68

References KIGFX::VERTEX_ITEM::GetOffset(), KIGFX::VERTEX_ITEM::GetSize(), KIGFX::CACHED_CONTAINER::m_chunkOffset, KIGFX::CACHED_CONTAINER::m_item, KIGFX::CACHED_CONTAINER::m_items, KIGFX::CACHED_CONTAINER::m_maxIndex, KIGFX::VERTEX_CONTAINER::m_vertices, KIGFX::VERTEX_ITEM::setOffset(), KIGFX::VERTEX_CONTAINER::usedSpace(), and KIGFX::VERTEX_SIZE.

Referenced by KIGFX::CACHED_CONTAINER_RAM::defragmentResize(), and defragmentResizeMemcpy().

◆ defragmentResize()

bool CACHED_CONTAINER_GPU::defragmentResize ( unsigned int  aNewSize)
overrideprotectedvirtual

Remove empty spaces between chunks and optionally resizes the container.

After the operation there is continuous space for storing vertices at the end of the container.

Parameters
aNewSizeis the new size of container, expressed in number of vertices.
Returns
false in case of failure (e.g. memory shortage).

Implements KIGFX::CACHED_CONTAINER.

Definition at line 129 of file cached_container_gpu.cpp.

130{
131 if( !m_useCopyBuffer )
132 return defragmentResizeMemcpy( aNewSize );
133
134 wxCHECK( IsMapped(), false );
135
136 wxLogTrace( traceGalCachedContainerGpu,
137 wxT( "Resizing & defragmenting container from %d to %d" ), m_currentSize,
138 aNewSize );
139
140 // No shrinking if we cannot fit all the data
141 if( usedSpace() > aNewSize )
142 return false;
143
144#ifdef KICAD_GAL_PROFILE
145 PROF_COUNTER totalTime;
146#endif /* KICAD_GAL_PROFILE */
147
148 GLuint newBuffer;
149
150 // glCopyBufferSubData requires a buffer to be unmapped
151 glUnmapBuffer( GL_ARRAY_BUFFER );
152
153 // Create a new destination buffer
154 glGenBuffers( 1, &newBuffer );
155
156 // It would be best to use GL_COPY_WRITE_BUFFER here,
157 // but it is not available everywhere
158#ifdef KICAD_GAL_PROFILE
159 GLint eaBuffer = -1;
160 glGetIntegerv( GL_ELEMENT_ARRAY_BUFFER_BINDING, &eaBuffer );
161 wxASSERT( eaBuffer == 0 );
162#endif /* KICAD_GAL_PROFILE */
163 glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, newBuffer );
164 glBufferData( GL_ELEMENT_ARRAY_BUFFER, aNewSize * VERTEX_SIZE, nullptr, GL_DYNAMIC_DRAW );
165 checkGlError( "creating buffer during defragmentation", __FILE__, __LINE__ );
166
167 ITEMS::iterator it, it_end;
168 int newOffset = 0;
169
170 // Defragmentation
171 for( it = m_items.begin(), it_end = m_items.end(); it != it_end; ++it )
172 {
173 VERTEX_ITEM* item = *it;
174 int itemOffset = item->GetOffset();
175 int itemSize = item->GetSize();
176
177 // Move an item to the new container
178 glCopyBufferSubData( GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER, itemOffset * VERTEX_SIZE,
179 newOffset * VERTEX_SIZE, itemSize * VERTEX_SIZE );
180
181 // Update new offset
182 item->setOffset( newOffset );
183
184 // Move to the next free space
185 newOffset += itemSize;
186 }
187
188 // Move the current item and place it at the end
189 if( m_item->GetSize() > 0 )
190 {
191 glCopyBufferSubData( GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER,
192 m_item->GetOffset() * VERTEX_SIZE, newOffset * VERTEX_SIZE,
194
195 m_item->setOffset( newOffset );
196 m_chunkOffset = newOffset;
197 }
198
199 // Cleanup
200 glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
201 glBindBuffer( GL_ARRAY_BUFFER, 0 );
202
203 // Previously we have unmapped the array buffer, now when it is also
204 // unbound, it may be officially marked as unmapped
205 m_isMapped = false;
206 glDeleteBuffers( 1, &m_glBufferHandle );
207
208 // Switch to the new vertex buffer
209 m_glBufferHandle = newBuffer;
210 Map();
211 checkGlError( "switching buffers during defragmentation", __FILE__, __LINE__ );
212
213#ifdef KICAD_GAL_PROFILE
214 totalTime.Stop();
215
216 wxLogTrace( traceGalCachedContainerGpu, "Defragmented container storing %d vertices / %.1f ms",
217 m_currentSize - m_freeSpace, totalTime.msecs() );
218#endif /* KICAD_GAL_PROFILE */
219
220 m_freeSpace += ( aNewSize - m_currentSize );
221 m_currentSize = aNewSize;
222
223 KI_TRACE( traceGalProfile, "VBO size %d used %d\n", m_currentSize, AllItemsSize() );
224
225 // Now there is only one big chunk of free memory
226 m_freeChunks.clear();
227 m_freeChunks.insert( std::make_pair( m_freeSpace, m_currentSize - m_freeSpace ) );
228
229 return true;
230}
void Map() override
Finish the vertices updates stage.
virtual unsigned int AllItemsSize() const override
bool IsMapped() const override
Prepare the container for vertices updates.
bool defragmentResizeMemcpy(unsigned int aNewSize)
Flag saying if vertex buffer is currently mapped.
A thread-safe event counter.
Definition: profile.h:226
static const wxChar *const traceGalCachedContainerGpu
Flag to enable debug output of the GAL OpenGL GPU cached container.

References AllItemsSize(), checkGlError(), defragmentResizeMemcpy(), KIGFX::VERTEX_ITEM::GetOffset(), KIGFX::VERTEX_ITEM::GetSize(), IsMapped(), KI_TRACE, KIGFX::CACHED_CONTAINER::m_chunkOffset, KIGFX::VERTEX_CONTAINER::m_currentSize, KIGFX::CACHED_CONTAINER::m_freeChunks, KIGFX::VERTEX_CONTAINER::m_freeSpace, m_glBufferHandle, m_isMapped, KIGFX::CACHED_CONTAINER::m_item, KIGFX::CACHED_CONTAINER::m_items, m_useCopyBuffer, Map(), KIGFX::VERTEX_ITEM::setOffset(), traceGalCachedContainerGpu, traceGalProfile, KIGFX::VERTEX_CONTAINER::usedSpace(), and KIGFX::VERTEX_SIZE.

◆ defragmentResizeMemcpy()

bool CACHED_CONTAINER_GPU::defragmentResizeMemcpy ( unsigned int  aNewSize)
protected

Flag saying if vertex buffer is currently mapped.

Definition at line 233 of file cached_container_gpu.cpp.

234{
235 wxCHECK( IsMapped(), false );
236
237 wxLogTrace( traceGalCachedContainerGpu,
238 wxT( "Resizing & defragmenting container (memcpy) from %d to %d" ), m_currentSize,
239 aNewSize );
240
241 // No shrinking if we cannot fit all the data
242 if( usedSpace() > aNewSize )
243 return false;
244
245#ifdef KICAD_GAL_PROFILE
246 PROF_COUNTER totalTime;
247#endif /* KICAD_GAL_PROFILE */
248
249 GLuint newBuffer;
250 VERTEX* newBufferMem;
251
252 // Create the destination buffer
253 glGenBuffers( 1, &newBuffer );
254
255 // It would be best to use GL_COPY_WRITE_BUFFER here,
256 // but it is not available everywhere
257#ifdef KICAD_GAL_PROFILE
258 GLint eaBuffer = -1;
259 glGetIntegerv( GL_ELEMENT_ARRAY_BUFFER_BINDING, &eaBuffer );
260 wxASSERT( eaBuffer == 0 );
261#endif /* KICAD_GAL_PROFILE */
262 glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, newBuffer );
263 glBufferData( GL_ELEMENT_ARRAY_BUFFER, aNewSize * VERTEX_SIZE, nullptr, GL_DYNAMIC_DRAW );
264 newBufferMem = static_cast<VERTEX*>( glMapBuffer( GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY ) );
265 checkGlError( "creating buffer during defragmentation", __FILE__, __LINE__ );
266
267 defragment( newBufferMem );
268
269 // Cleanup
270 glUnmapBuffer( GL_ELEMENT_ARRAY_BUFFER );
271 glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
272 Unmap();
273 glDeleteBuffers( 1, &m_glBufferHandle );
274
275 // Switch to the new vertex buffer
276 m_glBufferHandle = newBuffer;
277 Map();
278 checkGlError( "switching buffers during defragmentation", __FILE__, __LINE__ );
279
280#ifdef KICAD_GAL_PROFILE
281 totalTime.Stop();
282
283 wxLogTrace( traceGalCachedContainerGpu, "Defragmented container storing %d vertices / %.1f ms",
284 m_currentSize - m_freeSpace, totalTime.msecs() );
285#endif /* KICAD_GAL_PROFILE */
286
287 m_freeSpace += ( aNewSize - m_currentSize );
288 m_currentSize = aNewSize;
289
290 KI_TRACE( traceGalProfile, "VBO size %d used: %d \n", m_currentSize, AllItemsSize() );
291
292 // Now there is only one big chunk of free memory
293 m_freeChunks.clear();
294 m_freeChunks.insert( std::make_pair( m_freeSpace, m_currentSize - m_freeSpace ) );
295
296 return true;
297}
void defragment(VERTEX *aTarget)
Transfer all stored data to a new buffer, removing empty spaces between the data chunks in the contai...

References AllItemsSize(), checkGlError(), KIGFX::CACHED_CONTAINER::defragment(), IsMapped(), KI_TRACE, KIGFX::VERTEX_CONTAINER::m_currentSize, KIGFX::CACHED_CONTAINER::m_freeChunks, KIGFX::VERTEX_CONTAINER::m_freeSpace, m_glBufferHandle, Map(), traceGalCachedContainerGpu, traceGalProfile, Unmap(), KIGFX::VERTEX_CONTAINER::usedSpace(), and KIGFX::VERTEX_SIZE.

Referenced by defragmentResize().

◆ Delete()

void CACHED_CONTAINER::Delete ( VERTEX_ITEM aItem)
overridevirtualinherited

Remove all data stored in the container and restores its original state.

Implements KIGFX::VERTEX_CONTAINER.

Definition at line 148 of file cached_container.cpp.

149{
150 assert( aItem != nullptr );
151 assert( m_items.find( aItem ) != m_items.end() || aItem->GetSize() == 0 );
152
153 int size = aItem->GetSize();
154
155 if( size == 0 )
156 return; // Item is not stored here
157
158 int offset = aItem->GetOffset();
159
160 // Insert a free memory chunk entry in the place where item was stored
161 addFreeChunk( offset, size );
162
163 // Indicate that the item is not stored in the container anymore
164 aItem->setSize( 0 );
165
166 m_items.erase( aItem );
167
168#if CACHED_CONTAINER_TEST > 0
169 test();
170#endif
171
172 // This dynamic memory freeing optimize memory usage, but in fact can create
173 // out of memory issues because freeing and reallocation large chunks of memory
174 // can create memory fragmentation and no room to reallocate large chunks
175 // after many free/reallocate cycles during a session using the same complex board
176 // So it can be disable.
177 // Currently: it is disable to avoid "out of memory" issues
178#if 0
179 // Dynamic memory freeing, there is no point in holding
180 // a large amount of memory when there is no use for it
182 {
184 }
185#endif
186}
void addFreeChunk(unsigned int aOffset, unsigned int aSize)
Add a chunk marked as a free space.
virtual bool defragmentResize(unsigned int aNewSize)=0
Remove empty spaces between chunks and optionally resizes the container.
unsigned int m_initialSize
Actual storage memory.

References KIGFX::CACHED_CONTAINER::addFreeChunk(), KIGFX::CACHED_CONTAINER::defragmentResize(), KIGFX::VERTEX_ITEM::GetOffset(), KIGFX::VERTEX_ITEM::GetSize(), KIGFX::VERTEX_CONTAINER::m_currentSize, KIGFX::VERTEX_CONTAINER::m_freeSpace, KIGFX::VERTEX_CONTAINER::m_initialSize, KIGFX::CACHED_CONTAINER::m_items, KIGFX::VERTEX_ITEM::setSize(), and KIGFX::CACHED_CONTAINER::test().

◆ FinishItem()

void CACHED_CONTAINER::FinishItem ( )
overridevirtualinherited

Clean up after adding an item.

Reimplemented from KIGFX::VERTEX_CONTAINER.

Definition at line 75 of file cached_container.cpp.

76{
77 assert( m_item != nullptr );
78
79 unsigned int itemSize = m_item->GetSize();
80
81 // Finishing the previously edited item
82 if( itemSize < m_chunkSize )
83 {
84 // There is some not used but reserved memory left, so we should return it to the pool
85 int itemOffset = m_item->GetOffset();
86
87 // Add the not used memory back to the pool
88 addFreeChunk( itemOffset + itemSize, m_chunkSize - itemSize );
89 // mergeFreeChunks(); // veery slow and buggy
90
91 m_maxIndex = std::max( itemOffset + itemSize, m_maxIndex );
92 }
93
94 if( itemSize > 0 )
95 m_items.insert( m_item );
96
97 m_item = nullptr;
98 m_chunkSize = 0;
99 m_chunkOffset = 0;
100
101#if CACHED_CONTAINER_TEST > 1
102 test();
103#endif
104}

References KIGFX::CACHED_CONTAINER::addFreeChunk(), KIGFX::VERTEX_ITEM::GetOffset(), KIGFX::VERTEX_ITEM::GetSize(), KIGFX::CACHED_CONTAINER::m_chunkOffset, KIGFX::CACHED_CONTAINER::m_chunkSize, KIGFX::CACHED_CONTAINER::m_item, KIGFX::CACHED_CONTAINER::m_items, KIGFX::CACHED_CONTAINER::m_maxIndex, and KIGFX::CACHED_CONTAINER::test().

◆ GetAllVertices()

VERTEX * KIGFX::VERTEX_CONTAINER::GetAllVertices ( ) const
inlineinherited

Return pointer to the vertices stored in the container.

Definition at line 107 of file vertex_container.h.

108 {
109 return m_vertices;
110 }

References KIGFX::VERTEX_CONTAINER::m_vertices.

Referenced by KIGFX::GPU_NONCACHED_MANAGER::EndDrawing().

◆ GetBufferHandle()

unsigned int KIGFX::CACHED_CONTAINER_GPU::GetBufferHandle ( ) const
inlineoverridevirtual

Return handle to the vertex buffer.

It might be negative if the buffer is not initialized.

Implements KIGFX::CACHED_CONTAINER.

Definition at line 44 of file cached_container_gpu.h.

45 {
46 return m_glBufferHandle;
47 }

References m_glBufferHandle.

◆ getChunkOffset()

unsigned int KIGFX::CACHED_CONTAINER::getChunkOffset ( const CHUNK aChunk) const
inlineprotectedinherited

Return the offset of a chunk.

Parameters
aChunkis the chunk.

Definition at line 157 of file cached_container.h.

158 {
159 return aChunk.second;
160 }

Referenced by KIGFX::CACHED_CONTAINER::reallocate().

◆ getChunkSize()

int KIGFX::CACHED_CONTAINER::getChunkSize ( const CHUNK aChunk) const
inlineprotectedinherited

Return the size of a chunk.

Parameters
aChunkis the chunk.

Definition at line 147 of file cached_container.h.

148 {
149 return aChunk.first;
150 }

Referenced by KIGFX::CACHED_CONTAINER::reallocate(), and KIGFX::CACHED_CONTAINER::test().

◆ GetSize()

virtual unsigned int KIGFX::VERTEX_CONTAINER::GetSize ( ) const
inlinevirtualinherited

Return amount of vertices currently stored in the container.

Reimplemented in KIGFX::NONCACHED_CONTAINER.

Definition at line 125 of file vertex_container.h.

126 {
127 return m_currentSize;
128 }

References KIGFX::VERTEX_CONTAINER::m_currentSize.

Referenced by KIGFX::GPU_NONCACHED_MANAGER::EndDrawing().

◆ GetVertices()

virtual VERTEX * KIGFX::VERTEX_CONTAINER::GetVertices ( unsigned int  aOffset) const
inlinevirtualinherited

Return vertices stored at the specific offset.

Parameters
aOffsetis the offset.

Definition at line 117 of file vertex_container.h.

118 {
119 return &m_vertices[aOffset];
120 }

References KIGFX::VERTEX_CONTAINER::m_vertices.

◆ IsCached()

bool KIGFX::CACHED_CONTAINER::IsCached ( ) const
inlineoverridevirtualinherited

Return true if the container caches vertex data in RAM or video memory.

Otherwise it is a single batch draw which is later discarded.

Implements KIGFX::VERTEX_CONTAINER.

Definition at line 52 of file cached_container.h.

53 {
54 return true;
55 }

◆ IsDirty()

bool KIGFX::VERTEX_CONTAINER::IsDirty ( ) const
inlineinherited

Return information about the container cache state.

Returns
True in case the vertices have to be reuploaded.

Definition at line 135 of file vertex_container.h.

136 {
137 return m_dirty;
138 }

References KIGFX::VERTEX_CONTAINER::m_dirty.

◆ IsMapped()

bool KIGFX::CACHED_CONTAINER_GPU::IsMapped ( ) const
inlineoverridevirtual

Prepare the container for vertices updates.

Implements KIGFX::CACHED_CONTAINER.

Definition at line 49 of file cached_container_gpu.h.

References m_isMapped.

Referenced by defragmentResize(), defragmentResizeMemcpy(), Map(), and Unmap().

◆ MakeContainer()

VERTEX_CONTAINER * VERTEX_CONTAINER::MakeContainer ( bool  aCached)
staticinherited

Return a pointer to a new container of an appropriate type.

Definition at line 42 of file vertex_container.cpp.

43{
44 if( aCached )
45 {
46 const char* vendor = (const char*) glGetString( GL_VENDOR );
47
48 // Open source drivers do not cope well with GPU memory mapping,
49 // so the vertex data has to be kept in RAM
50 if( strstr( vendor, "X.Org" ) || strstr( vendor, "nouveau" ) )
51 return new CACHED_CONTAINER_RAM;
52 else
53 return new CACHED_CONTAINER_GPU;
54 }
55
56 return new NONCACHED_CONTAINER;
57}
Specialization of CACHED_CONTAINER that stores data in video memory via memory mapping.
Specialization of CACHED_CONTAINER that stores data in RAM.

Referenced by KIGFX::VERTEX_MANAGER::VERTEX_MANAGER().

◆ Map()

void CACHED_CONTAINER_GPU::Map ( )
overridevirtual

Finish the vertices updates stage.

Implements KIGFX::CACHED_CONTAINER.

Definition at line 90 of file cached_container_gpu.cpp.

91{
92 wxCHECK( !IsMapped(), /*void*/ );
93
94 // OpenGL version might suddenly stop being available in Windows when an RDP session is started
95 if( !glBindBuffer )
96 throw std::runtime_error( "OpenGL no longer available!" );
97
98 glBindBuffer( GL_ARRAY_BUFFER, m_glBufferHandle );
99 m_vertices = static_cast<VERTEX*>( glMapBuffer( GL_ARRAY_BUFFER, GL_READ_WRITE ) );
100
101 if( checkGlError( "mapping vertices buffer", __FILE__, __LINE__ ) == GL_NO_ERROR )
102 m_isMapped = true;
103}

References checkGlError(), IsMapped(), m_glBufferHandle, m_isMapped, and KIGFX::VERTEX_CONTAINER::m_vertices.

Referenced by defragmentResize(), and defragmentResizeMemcpy().

◆ mergeFreeChunks()

void CACHED_CONTAINER::mergeFreeChunks ( )
protectedinherited

Look for consecutive free memory chunks and merges them, decreasing fragmentation of memory.

Definition at line 306 of file cached_container.cpp.

307{
308 if( m_freeChunks.size() <= 1 ) // There are no chunks that can be merged
309 return;
310
311#ifdef KICAD_GAL_PROFILE
312 PROF_COUNTER totalTime;
313#endif /* KICAD_GAL_PROFILE */
314
315 // Reversed free chunks map - this one stores chunk size with its offset as the key
316 std::list<CHUNK> freeChunks;
317
318 FREE_CHUNK_MAP::const_iterator it, it_end;
319
320 for( it = m_freeChunks.begin(), it_end = m_freeChunks.end(); it != it_end; ++it )
321 {
322 freeChunks.emplace_back( it->second, it->first );
323 }
324
325 m_freeChunks.clear();
326 freeChunks.sort();
327
328 std::list<CHUNK>::const_iterator itf, itf_end;
329 unsigned int offset = freeChunks.front().first;
330 unsigned int size = freeChunks.front().second;
331 freeChunks.pop_front();
332
333 for( itf = freeChunks.begin(), itf_end = freeChunks.end(); itf != itf_end; ++itf )
334 {
335 if( itf->first == offset + size )
336 {
337 // These chunks can be merged, so just increase the current chunk size and go on
338 size += itf->second;
339 }
340 else
341 {
342 // These chunks cannot be merged
343 // So store the previous one
344 m_freeChunks.insert( std::make_pair( size, offset ) );
345 // and let's check the next chunk
346 offset = itf->first;
347 size = itf->second;
348 }
349 }
350
351 // Add the last one
352 m_freeChunks.insert( std::make_pair( size, offset ) );
353
354#if CACHED_CONTAINER_TEST > 0
355 test();
356#endif
357}

References KIGFX::CACHED_CONTAINER::m_freeChunks, and KIGFX::CACHED_CONTAINER::test().

◆ reallocate()

bool CACHED_CONTAINER::reallocate ( unsigned int  aSize)
protectedinherited

Resize the chunk that stores the current item to the given size.

The current item has its offset adjusted after the call, and the new chunk parameters are stored in m_chunkOffset and m_chunkSize.

Parameters
aSizeis the requested chunk size.
Returns
true in case of success, false otherwise.

Definition at line 208 of file cached_container.cpp.

209{
210 assert( aSize > 0 );
211 assert( IsMapped() );
212
213 unsigned int itemSize = m_item->GetSize();
214
215 // Find a free space chunk >= aSize
216 FREE_CHUNK_MAP::iterator newChunk = m_freeChunks.lower_bound( aSize );
217
218 // Is there enough space to store vertices?
219 if( newChunk == m_freeChunks.end() )
220 {
221 bool result;
222
223 // Would it be enough to double the current space?
224 if( aSize < m_freeSpace + m_currentSize )
225 {
226 // Yes: exponential growing
227 result = defragmentResize( m_currentSize * 2 );
228 }
229 else
230 {
231 // No: grow to the nearest greater power of 2
232 result = defragmentResize( pow( 2, ceil( log2( m_currentSize * 2 + aSize ) ) ) );
233 }
234
235 if( !result )
236 return false;
237
238 newChunk = m_freeChunks.lower_bound( aSize );
239 assert( newChunk != m_freeChunks.end() );
240 }
241
242 // Parameters of the allocated chunk
243 unsigned int newChunkSize = getChunkSize( *newChunk );
244 unsigned int newChunkOffset = getChunkOffset( *newChunk );
245
246 assert( newChunkSize >= aSize );
247 assert( newChunkOffset < m_currentSize );
248
249 // Check if the item was previously stored in the container
250 if( itemSize > 0 )
251 {
252 // The item was reallocated, so we have to copy all the old data to the new place
253 memcpy( &m_vertices[newChunkOffset], &m_vertices[m_chunkOffset], itemSize * VERTEX_SIZE );
254
255 // Free the space used by the previous chunk
257 }
258
259 // Remove the new allocated chunk from the free space pool
260 m_freeChunks.erase( newChunk );
261 m_freeSpace -= newChunkSize;
262
263 m_chunkSize = newChunkSize;
264 m_chunkOffset = newChunkOffset;
265
267
268 return true;
269}
int getChunkSize(const CHUNK &aChunk) const
Return the size of a chunk.
unsigned int getChunkOffset(const CHUNK &aChunk) const
Return the offset of a chunk.

References KIGFX::CACHED_CONTAINER::addFreeChunk(), KIGFX::CACHED_CONTAINER::defragmentResize(), KIGFX::CACHED_CONTAINER::getChunkOffset(), KIGFX::CACHED_CONTAINER::getChunkSize(), KIGFX::VERTEX_ITEM::GetSize(), KIGFX::CACHED_CONTAINER::IsMapped(), KIGFX::CACHED_CONTAINER::m_chunkOffset, KIGFX::CACHED_CONTAINER::m_chunkSize, KIGFX::VERTEX_CONTAINER::m_currentSize, KIGFX::CACHED_CONTAINER::m_freeChunks, KIGFX::VERTEX_CONTAINER::m_freeSpace, KIGFX::CACHED_CONTAINER::m_item, KIGFX::VERTEX_CONTAINER::m_vertices, KIGFX::VERTEX_ITEM::setOffset(), and KIGFX::VERTEX_SIZE.

Referenced by KIGFX::CACHED_CONTAINER::Allocate().

◆ SetDirty()

void KIGFX::VERTEX_CONTAINER::SetDirty ( )
inlineinherited

Set the dirty flag, so vertices in the container are going to be reuploaded to the GPU on the next frame.

Definition at line 144 of file vertex_container.h.

145 {
146 m_dirty = true;
147 }

References KIGFX::VERTEX_CONTAINER::m_dirty.

◆ SetItem()

void CACHED_CONTAINER::SetItem ( VERTEX_ITEM aItem)
overridevirtualinherited

Clean up after adding an item.

Implements KIGFX::VERTEX_CONTAINER.

Definition at line 62 of file cached_container.cpp.

63{
64 assert( aItem != nullptr );
65
66 unsigned int itemSize = aItem->GetSize();
67 m_item = aItem;
68 m_chunkSize = itemSize;
69
70 // Get the previously set offset if the item was stored previously
71 m_chunkOffset = itemSize > 0 ? aItem->GetOffset() : -1;
72}

References KIGFX::VERTEX_ITEM::GetOffset(), KIGFX::VERTEX_ITEM::GetSize(), KIGFX::CACHED_CONTAINER::m_chunkOffset, KIGFX::CACHED_CONTAINER::m_chunkSize, and KIGFX::CACHED_CONTAINER::m_item.

◆ showFreeChunks()

void CACHED_CONTAINER::showFreeChunks ( )
privateinherited

Debug & test functions.

Definition at line 370 of file cached_container.cpp.

371{
372}

Referenced by KIGFX::CACHED_CONTAINER::Allocate().

◆ showUsedChunks()

void CACHED_CONTAINER::showUsedChunks ( )
privateinherited

Definition at line 375 of file cached_container.cpp.

376{
377}

Referenced by KIGFX::CACHED_CONTAINER::Allocate().

◆ test()

void CACHED_CONTAINER::test ( )
privateinherited

Definition at line 380 of file cached_container.cpp.

381{
382#ifdef KICAD_GAL_PROFILE
383 // Free space check
384 unsigned int freeSpace = 0;
385 FREE_CHUNK_MAP::iterator itf;
386
387 for( itf = m_freeChunks.begin(); itf != m_freeChunks.end(); ++itf )
388 freeSpace += getChunkSize( *itf );
389
390 assert( freeSpace == m_freeSpace );
391
392 // Used space check
393 unsigned int used_space = 0;
394 ITEMS::iterator itr;
395
396 for( itr = m_items.begin(); itr != m_items.end(); ++itr )
397 used_space += ( *itr )->GetSize();
398
399 // If we have a chunk assigned, then there must be an item edited
400 assert( m_chunkSize == 0 || m_item );
401
402 // Currently reserved chunk is also counted as used
403 used_space += m_chunkSize;
404
405 assert( ( m_freeSpace + used_space ) == m_currentSize );
406
407 // Overlapping check TODO
408#endif /* KICAD_GAL_PROFILE */
409}

References KIGFX::CACHED_CONTAINER::getChunkSize(), KIGFX::CACHED_CONTAINER::m_chunkSize, KIGFX::VERTEX_CONTAINER::m_currentSize, KIGFX::CACHED_CONTAINER::m_freeChunks, KIGFX::VERTEX_CONTAINER::m_freeSpace, KIGFX::CACHED_CONTAINER::m_item, and KIGFX::CACHED_CONTAINER::m_items.

Referenced by KIGFX::CACHED_CONTAINER::Allocate(), KIGFX::CACHED_CONTAINER::Delete(), KIGFX::CACHED_CONTAINER::FinishItem(), and KIGFX::CACHED_CONTAINER::mergeFreeChunks().

◆ Unmap()

void CACHED_CONTAINER_GPU::Unmap ( )
overridevirtual

Finish the vertices updates stage.

Implements KIGFX::CACHED_CONTAINER.

Definition at line 106 of file cached_container_gpu.cpp.

107{
108 wxCHECK( IsMapped(), /*void*/ );
109
110 // This gets called from ~CACHED_CONTAINER_GPU. To avoid throwing an exception from
111 // the dtor, catch it here instead.
112 try
113 {
114 glUnmapBuffer( GL_ARRAY_BUFFER );
115 checkGlError( "unmapping vertices buffer", __FILE__, __LINE__ );
116 glBindBuffer( GL_ARRAY_BUFFER, 0 );
117 m_vertices = nullptr;
118 checkGlError( "unbinding vertices buffer", __FILE__, __LINE__ );
119 }
120 catch( const std::runtime_error& err )
121 {
122 wxLogError( wxT( "OpenGL did not shut down properly.\n\n%s" ), err.what() );
123 }
124
125 m_isMapped = false;
126}

References checkGlError(), IsMapped(), m_isMapped, and KIGFX::VERTEX_CONTAINER::m_vertices.

Referenced by defragmentResizeMemcpy(), and ~CACHED_CONTAINER_GPU().

◆ usedSpace()

unsigned int KIGFX::VERTEX_CONTAINER::usedSpace ( ) const
inlineprotectedinherited

Return size of the used memory space.

Returns
Size of the used memory space (expressed as a number of vertices). Free space left in the container, expressed in vertices

Definition at line 165 of file vertex_container.h.

References KIGFX::VERTEX_CONTAINER::m_currentSize, and KIGFX::VERTEX_CONTAINER::m_freeSpace.

Referenced by KIGFX::CACHED_CONTAINER::defragment(), defragmentResize(), KIGFX::CACHED_CONTAINER_RAM::defragmentResize(), and defragmentResizeMemcpy().

Member Data Documentation

◆ DEFAULT_SIZE

constexpr unsigned int KIGFX::VERTEX_CONTAINER::DEFAULT_SIZE = 1048576
staticconstexprprotectedinherited

Definition at line 187 of file vertex_container.h.

◆ m_chunkOffset

unsigned int KIGFX::CACHED_CONTAINER::m_chunkOffset
protectedinherited

◆ m_chunkSize

◆ m_currentSize

◆ m_dirty

bool KIGFX::VERTEX_CONTAINER::m_dirty
protectedinherited

◆ m_failed

bool KIGFX::VERTEX_CONTAINER::m_failed
protectedinherited

◆ m_freeChunks

◆ m_freeSpace

◆ m_glBufferHandle

unsigned int KIGFX::CACHED_CONTAINER_GPU::m_glBufferHandle
protected

Flag saying whether it is safe to use glCopyBufferSubData.

Definition at line 80 of file cached_container_gpu.h.

Referenced by CACHED_CONTAINER_GPU(), defragmentResize(), defragmentResizeMemcpy(), GetBufferHandle(), Map(), and ~CACHED_CONTAINER_GPU().

◆ m_initialSize

unsigned int KIGFX::VERTEX_CONTAINER::m_initialSize
protectedinherited

Actual storage memory.

Definition at line 177 of file vertex_container.h.

Referenced by KIGFX::CACHED_CONTAINER::Delete().

◆ m_isMapped

bool KIGFX::CACHED_CONTAINER_GPU::m_isMapped
protected

Vertex buffer handle.

Definition at line 77 of file cached_container_gpu.h.

Referenced by defragmentResize(), IsMapped(), Map(), Unmap(), and ~CACHED_CONTAINER_GPU().

◆ m_item

◆ m_items

◆ m_maxIndex

unsigned int KIGFX::CACHED_CONTAINER::m_maxIndex
protectedinherited

◆ m_useCopyBuffer

bool KIGFX::CACHED_CONTAINER_GPU::m_useCopyBuffer
protected

Definition at line 83 of file cached_container_gpu.h.

Referenced by CACHED_CONTAINER_GPU(), and defragmentResize().

◆ m_vertices


The documentation for this class was generated from the following files: