KiCad PCB EDA Suite
Loading...
Searching...
No Matches
gpu_manager.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 2013-2017 CERN
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * @author Maciej Suminski <[email protected]>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 */
22
27#include <gal/opengl/shader.h>
28#include <gal/opengl/utils.h>
30
31#include <core/profile.h>
32
33#include <typeinfo>
34#include <confirm.h>
35#include <trace_helpers.h>
36
37#ifdef KICAD_GAL_PROFILE
38#include <core/profile.h>
39#include <wx/log.h>
40#endif /* KICAD_GAL_PROFILE */
41
42using namespace KIGFX;
43
45{
46 if( aContainer->IsCached() )
47 return new GPU_CACHED_MANAGER( aContainer );
48 else
49 return new GPU_NONCACHED_MANAGER( aContainer );
50}
51
52
54 m_isDrawing( false ),
55 m_container( aContainer ),
56 m_shader( nullptr ),
57 m_shaderAttrib( 0 ),
58 m_enableDepthTest( true )
59{
60}
61
62
66
67
69{
70 m_shader = &aShader;
71 m_shaderAttrib = m_shader->GetAttribute( "a_shaderParams" );
72
73 if( m_shaderAttrib == -1 )
74 {
75 DisplayError( nullptr, wxT( "Could not get the shader attribute location" ) );
76 }
77}
78
79
80// Cached manager
82 GPU_MANAGER( aContainer ),
83 m_buffersInitialized( false ),
85 m_totalHuge( 0 ),
86 m_totalNormal( 0 ),
87 m_indexBufSize( 0 ),
90{
91}
92
93
97
98
100{
101 wxASSERT( !m_isDrawing );
102
103 m_curVrangeSize = 0;
105 m_indexBufSize = 0;
106 m_vranges.clear();
107
108 m_isDrawing = true;
109}
110
111
113{
114 // Hot path: don't use wxASSERT
115 assert( m_isDrawing );
116
117 unsigned int offset = aItem->GetOffset();
118 unsigned int size = aItem->GetSize();
119
120 if( size == 0 )
121 return;
122
123 if( size <= 1000 )
124 {
125 m_totalNormal += size;
126 m_vranges.emplace_back( offset, offset + size - 1, false );
127 m_curVrangeSize += size;
128 }
129 else
130 {
131 m_totalHuge += size;
132 m_vranges.emplace_back( offset, offset + size - 1, true );
134 m_curVrangeSize = 0;
135 }
136}
137
138
140{
141 wxASSERT( m_isDrawing );
142
143 CACHED_CONTAINER* cached = static_cast<CACHED_CONTAINER*>( m_container );
144
145 if( cached->IsMapped() )
146 cached->Unmap();
147
150
152
154 glEnable( GL_DEPTH_TEST );
155 else
156 glDisable( GL_DEPTH_TEST );
157
158 // Prepare buffers
159 glEnableClientState( GL_VERTEX_ARRAY );
160 glEnableClientState( GL_COLOR_ARRAY );
161
162 // Bind vertices data buffers
163 glBindBuffer( GL_ARRAY_BUFFER, cached->GetBufferHandle() );
164 glVertexPointer( COORD_STRIDE, GL_FLOAT, VERTEX_SIZE, (GLvoid*) COORD_OFFSET );
165 glColorPointer( COLOR_STRIDE, GL_UNSIGNED_BYTE, VERTEX_SIZE, (GLvoid*) COLOR_OFFSET );
166
167 if( m_shader != nullptr ) // Use shader if applicable
168 {
169 m_shader->Use();
170 glEnableVertexAttribArray( m_shaderAttrib );
171 glVertexAttribPointer( m_shaderAttrib, SHADER_STRIDE, GL_FLOAT, GL_FALSE, VERTEX_SIZE,
172 (GLvoid*) SHADER_OFFSET );
173 }
174
175 PROF_TIMER cntDraw( "gl-draw-elements" );
176
177 int n_ranges = m_vranges.size();
178 int n = 0;
179 GLuint* iptr = m_indices.get();
180 GLuint icnt = 0;
181
182 int drawCalls = 0;
183
184 while( n < n_ranges )
185 {
186 VRANGE* cur = &m_vranges[n];
187
188 if( cur->m_isContinuous )
189 {
190 if( icnt > 0 )
191 {
192 glDrawElements( GL_TRIANGLES, icnt, GL_UNSIGNED_INT, m_indices.get() );
193 drawCalls++;
194 }
195
196 icnt = 0;
197 iptr = m_indices.get();
198
199 glDrawArrays( GL_TRIANGLES, cur->m_start, cur->m_end - cur->m_start + 1 );
200 drawCalls++;
201 }
202 else
203 {
204 for( GLuint i = cur->m_start; i <= cur->m_end; i++ )
205 {
206 *iptr++ = i;
207 icnt++;
208 }
209 }
210
211 n++;
212 }
213
214 if( icnt > 0 )
215 {
216 glDrawElements( GL_TRIANGLES, icnt, GL_UNSIGNED_INT, m_indices.get() );
217 drawCalls++;
218 }
219
220 (void) drawCalls; // silence warning
221 cntDraw.Stop();
222
223#ifdef KICAD_GAL_PROFILE
224 wxLogTrace( traceGalProfile,
225 "Cached manager size: VBO size %u iranges %zu max elt size %u drawcalls %u",
226 cached->AllItemsSize(), m_vranges.size(), m_indexBufMaxSize, drawCalls );
227 wxLogTrace( traceGalProfile, "Timing: %s", cntDraw.to_string() );
228#endif
229
230 glBindBuffer( GL_ARRAY_BUFFER, 0 );
231 cached->ClearDirty();
232
233 // Deactivate vertex array
234 glDisableClientState( GL_COLOR_ARRAY );
235 glDisableClientState( GL_VERTEX_ARRAY );
236
237 if( m_shader != nullptr )
238 {
239 glDisableVertexAttribArray( m_shaderAttrib );
240 m_shader->Deactivate();
241 }
242
243 m_isDrawing = false;
244}
245
246
247void GPU_CACHED_MANAGER::resizeIndices( unsigned int aNewSize )
248{
249 if( aNewSize > m_indicesCapacity )
250 {
251 m_indicesCapacity = aNewSize;
252 m_indices.reset( new GLuint[m_indicesCapacity] );
253 }
254}
255
256
257// Noncached manager
262
263
265{
266 // Nothing has to be prepared
267}
268
269
271{
272 wxASSERT_MSG( false, wxT( "Not implemented yet" ) );
273}
274
275
277{
278#ifdef KICAD_GAL_PROFILE
279 PROF_TIMER totalRealTime;
280#endif /* KICAD_GAL_PROFILE */
281
282 if( m_container->GetSize() == 0 )
283 return;
284
285 VERTEX* vertices = m_container->GetAllVertices();
286 GLfloat* coordinates = (GLfloat*) ( vertices );
287 GLubyte* colors = (GLubyte*) ( vertices ) + COLOR_OFFSET;
288
290 glEnable( GL_DEPTH_TEST );
291 else
292 glDisable( GL_DEPTH_TEST );
293
294 // Prepare buffers
295 glEnableClientState( GL_VERTEX_ARRAY );
296 glEnableClientState( GL_COLOR_ARRAY );
297
298 glVertexPointer( COORD_STRIDE, GL_FLOAT, VERTEX_SIZE, coordinates );
299 glColorPointer( COLOR_STRIDE, GL_UNSIGNED_BYTE, VERTEX_SIZE, colors );
300
301 if( m_shader != nullptr ) // Use shader if applicable
302 {
303 GLfloat* shaders = (GLfloat*) ( vertices ) + SHADER_OFFSET / sizeof( GLfloat );
304
305 m_shader->Use();
306 glEnableVertexAttribArray( m_shaderAttrib );
307 glVertexAttribPointer( m_shaderAttrib, SHADER_STRIDE, GL_FLOAT, GL_FALSE, VERTEX_SIZE,
308 shaders );
309 }
310
311 glDrawArrays( GL_TRIANGLES, 0, m_container->GetSize() );
312
313#ifdef KICAD_GAL_PROFILE
314 wxLogTrace( traceGalProfile, wxT( "Noncached manager size: %d" ), m_container->GetSize() );
315#endif /* KICAD_GAL_PROFILE */
316
317 // Deactivate vertex array
318 glDisableClientState( GL_COLOR_ARRAY );
319 glDisableClientState( GL_VERTEX_ARRAY );
320
321 if( m_shader != nullptr )
322 {
323 glDisableVertexAttribArray( m_shaderAttrib );
324 m_shader->Deactivate();
325 }
326
327 m_container->Clear();
328
329#ifdef KICAD_GAL_PROFILE
330 totalRealTime.Stop();
331 wxLogTrace( traceGalProfile, wxT( "GPU_NONCACHED_MANAGER::EndDrawing(): %.1f ms" ),
332 totalRealTime.msecs() );
333#endif /* KICAD_GAL_PROFILE */
334}
335
336void GPU_MANAGER::EnableDepthTest( bool aEnabled )
337{
338 m_enableDepthTest = aEnabled;
339}
Class to store VERTEX instances with caching.
virtual unsigned int GetBufferHandle() const =0
Return handle to the vertex buffer.
virtual unsigned int AllItemsSize() const
virtual bool IsMapped() const =0
Return true if vertex buffer is currently mapped.
virtual void Unmap() override=0
Finish the vertices updates stage.
int m_totalHuge
Number of regular VRANGEs (small items) pooled into single draw call.
std::vector< VRANGE > m_vranges
Number of huge VRANGEs (i.e. large zones) with separate draw calls.
unsigned int m_indexBufMaxSize
Size of the current VRANGE.
unsigned int m_indicesCapacity
Ranges of visible vertex indices to render.
~GPU_CACHED_MANAGER()
Prepare the stored data to be drawn.
GPU_CACHED_MANAGER(VERTEX_CONTAINER *aContainer)
virtual void DrawIndices(const VERTEX_ITEM *aItem) override
Clear the container after drawing routines.
virtual void BeginDrawing() override
Make the GPU draw given range of vertices.
bool m_buffersInitialized
Pointer to the current indices buffer.
int m_totalNormal
Current size of index buffer.
boost::scoped_array< GLuint > m_indices
Current indices buffer size.
unsigned int m_indexBufSize
Maximum size taken by the index buffer for all frames rendered so far.
void resizeIndices(unsigned int aNewSize)
< Resizes the indices buffer to aNewSize if necessary
virtual void EndDrawing() override
Map vertex buffer stored in GPU memory.
GPU_MANAGER(VERTEX_CONTAINER *aContainer)
Drawing status flag.
int m_shaderAttrib
true: enable Z test when drawing
Definition gpu_manager.h:91
virtual void SetShader(SHADER &aShader)
Allow using shaders with the stored data.
void EnableDepthTest(bool aEnabled)
Enable/disable Z buffer depth test.
VERTEX_CONTAINER * m_container
Shader handling.
Definition gpu_manager.h:85
bool m_isDrawing
Container that stores vertices data.
Definition gpu_manager.h:82
static GPU_MANAGER * MakeManager(VERTEX_CONTAINER *aContainer)
SHADER * m_shader
Location of shader attributes (for glVertexAttribPointer)
Definition gpu_manager.h:88
virtual void BeginDrawing() override
Make the GPU draw given range of vertices.
GPU_NONCACHED_MANAGER(VERTEX_CONTAINER *aContainer)
Prepare the stored data to be drawn.
virtual void EndDrawing() override
Clear the container after drawing routines.
virtual void DrawIndices(const VERTEX_ITEM *aItem) override
Clear the container after drawing routines.
Provide the access to the OpenGL shaders.
Definition shader.h:73
virtual bool IsCached() const =0
Return true if the container caches vertex data in RAM or video memory.
void ClearDirty()
Clear the dirty flag to prevent reuploading vertices to the GPU memory.
unsigned int GetOffset() const
Return data offset in the container.
Definition vertex_item.h:64
unsigned int GetSize() const
Return information about number of vertices stored.
Definition vertex_item.h:54
A small class to help profiling.
Definition profile.h:46
void Stop()
Save the time when this function was called, and set the counter stane to stop.
Definition profile.h:86
std::string to_string()
Definition profile.h:153
double msecs(bool aSinceLast=false)
Definition profile.h:147
void DisplayError(wxWindow *aParent, const wxString &aText)
Display an error or warning message box with aMessage.
Definition confirm.cpp:192
This file is part of the common library.
const wxChar *const traceGalProfile
Flag to enable debug output of GAL performance profiling.
The Cairo implementation of the graphics abstraction layer.
Definition eda_group.h:29
static constexpr size_t COLOR_OFFSET
static constexpr size_t COORD_OFFSET
static constexpr size_t VERTEX_SIZE
static constexpr size_t SHADER_OFFSET
static constexpr size_t COLOR_STRIDE
static constexpr size_t SHADER_STRIDE
static constexpr size_t COORD_STRIDE
Class to store instances of VERTEX without caching.
wxLogTrace helper definitions.
Class to handle an item held in a container.