KiCad PCB EDA Suite
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 (C) 2021 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, you may find one here:
21  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
22  * or you may search the http://www.gnu.org website for the version 2 license,
23  * or you may write to the Free Software Foundation, Inc.,
24  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25  */
26 
27 #include <gal/opengl/gpu_manager.h>
31 #include <gal/opengl/shader.h>
32 #include <gal/opengl/utils.h>
33 #include <gal/opengl/vertex_item.h>
34 
35 #include <profile.h>
36 
37 #include <typeinfo>
38 #include <confirm.h>
39 #include <trace_helpers.h>
40 
41 #ifdef KICAD_GAL_PROFILE
42 #include <profile.h>
43 #include <wx/log.h>
44 #endif /* KICAD_GAL_PROFILE */
45 
46 using namespace KIGFX;
47 
49 {
50  if( aContainer->IsCached() )
51  return new GPU_CACHED_MANAGER( aContainer );
52  else
53  return new GPU_NONCACHED_MANAGER( aContainer );
54 }
55 
56 
58  m_isDrawing( false ),
59  m_container( aContainer ),
60  m_shader( nullptr ),
61  m_shaderAttrib( 0 ),
62  m_enableDepthTest( true )
63 {
64 }
65 
66 
68 {
69 }
70 
71 
73 {
74  m_shader = &aShader;
75  m_shaderAttrib = m_shader->GetAttribute( "attrShaderParams" );
76 
77  if( m_shaderAttrib == -1 )
78  {
79  DisplayError( nullptr, wxT( "Could not get the shader attribute location" ) );
80  }
81 }
82 
83 
84 // Cached manager
86  GPU_MANAGER( aContainer ),
87  m_buffersInitialized( false ),
88  m_indicesCapacity( 0 ),
89  m_totalHuge( 0 ),
90  m_totalNormal( 0 ),
91  m_indexBufSize( 0 ),
92  m_indexBufMaxSize( 0 ),
93  m_curVrangeSize( 0 )
94 {
95 }
96 
97 
99 {
100 }
101 
102 
104 {
105  wxASSERT( !m_isDrawing );
106 
107  m_curVrangeSize = 0;
108  m_indexBufMaxSize = 0;
109  m_indexBufSize = 0;
110  m_vranges.clear();
111 
112  m_isDrawing = true;
113 }
114 
115 
117 {
118  wxASSERT( m_isDrawing );
119 
120  unsigned int offset = aItem->GetOffset();
121  unsigned int size = aItem->GetSize();
122 
123  if( size > 1000 )
124  {
125  m_totalHuge += size;
126  m_vranges.emplace_back( offset, offset + size - 1, true );
128  m_curVrangeSize = 0;
129  }
130  else if ( size > 0 )
131  {
132  m_totalNormal += size;
133  m_vranges.emplace_back( offset, offset + size - 1, false );
134  m_curVrangeSize += size;
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 
153  if( m_enableDepthTest )
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_COUNTER 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  n++;
211  }
212 
213  if( icnt > 0 )
214  {
215  glDrawElements( GL_TRIANGLES, icnt, GL_UNSIGNED_INT, m_indices.get() );
216  drawCalls++;
217  }
218 
219  cntDraw.Stop();
220 
222  "Cached manager size: VBO size %u iranges %llu max elt size %u drawcalls %u\n",
223  cached->AllItemsSize(), m_vranges.size(), m_indexBufMaxSize, drawCalls );
224  KI_TRACE( traceGalProfile, "Timing: %s\n", cntDraw.to_string() );
225 
226  glBindBuffer( GL_ARRAY_BUFFER, 0 );
227  cached->ClearDirty();
228 
229  // Deactivate vertex array
230  glDisableClientState( GL_COLOR_ARRAY );
231  glDisableClientState( GL_VERTEX_ARRAY );
232 
233  if( m_shader != nullptr )
234  {
235  glDisableVertexAttribArray( m_shaderAttrib );
236  m_shader->Deactivate();
237  }
238 
239  m_isDrawing = false;
240 }
241 
242 
243 void GPU_CACHED_MANAGER::resizeIndices( unsigned int aNewSize )
244 {
245  if( aNewSize > m_indicesCapacity )
246  {
247  m_indicesCapacity = aNewSize;
248  m_indices.reset( new GLuint[m_indicesCapacity] );
249  }
250 }
251 
252 
253 // Noncached manager
255  GPU_MANAGER( aContainer )
256 {
257 }
258 
259 
261 {
262  // Nothing has to be prepared
263 }
264 
265 
267 {
268  wxASSERT_MSG( false, wxT( "Not implemented yet" ) );
269 }
270 
271 
273 {
274 #ifdef KICAD_GAL_PROFILE
275  PROF_COUNTER totalRealTime;
276 #endif /* KICAD_GAL_PROFILE */
277 
278  if( m_container->GetSize() == 0 )
279  return;
280 
281  VERTEX* vertices = m_container->GetAllVertices();
282  GLfloat* coordinates = (GLfloat*) ( vertices );
283  GLubyte* colors = (GLubyte*) ( vertices ) + COLOR_OFFSET;
284 
285  if( m_enableDepthTest )
286  glEnable( GL_DEPTH_TEST );
287  else
288  glDisable( GL_DEPTH_TEST );
289 
290  // Prepare buffers
291  glEnableClientState( GL_VERTEX_ARRAY );
292  glEnableClientState( GL_COLOR_ARRAY );
293 
294  glVertexPointer( COORD_STRIDE, GL_FLOAT, VERTEX_SIZE, coordinates );
295  glColorPointer( COLOR_STRIDE, GL_UNSIGNED_BYTE, VERTEX_SIZE, colors );
296 
297  if( m_shader != nullptr ) // Use shader if applicable
298  {
299  GLfloat* shaders = (GLfloat*) ( vertices ) + SHADER_OFFSET / sizeof( GLfloat );
300 
301  m_shader->Use();
302  glEnableVertexAttribArray( m_shaderAttrib );
303  glVertexAttribPointer( m_shaderAttrib, SHADER_STRIDE, GL_FLOAT, GL_FALSE, VERTEX_SIZE,
304  shaders );
305  }
306 
307  glDrawArrays( GL_TRIANGLES, 0, m_container->GetSize() );
308 
309 #ifdef KICAD_GAL_PROFILE
310  wxLogTrace( traceGalProfile, wxT( "Noncached manager size: %d" ), m_container->GetSize() );
311 #endif /* KICAD_GAL_PROFILE */
312 
313  // Deactivate vertex array
314  glDisableClientState( GL_COLOR_ARRAY );
315  glDisableClientState( GL_VERTEX_ARRAY );
316 
317  if( m_shader != nullptr )
318  {
319  glDisableVertexAttribArray( m_shaderAttrib );
320  m_shader->Deactivate();
321  }
322 
323  m_container->Clear();
324 
325 #ifdef KICAD_GAL_PROFILE
326  totalRealTime.Stop();
327  wxLogTrace( traceGalProfile, wxT( "GPU_NONCACHED_MANAGER::EndDrawing(): %.1f ms" ),
328  totalRealTime.msecs() );
329 #endif /* KICAD_GAL_PROFILE */
330 }
331 
332 void GPU_MANAGER::EnableDepthTest( bool aEnabled )
333 {
334  m_enableDepthTest = aEnabled;
335 }
void Stop()
Save the time when this function was called, and set the counter stane to stop.
Definition: profile.h:85
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:279
virtual ~GPU_MANAGER()
Definition: gpu_manager.cpp:67
static constexpr size_t COORD_STRIDE
Definition: vertex_common.h:72
virtual void SetShader(SHADER &aShader)
Allow using shaders with the stored data.
Definition: gpu_manager.cpp:72
std::string to_string()
Definition: profile.h:152
virtual void Clear()=0
Remove all data stored in the container and restores its original state.
unsigned int m_indicesCapacity
Ranges of visible vertex indices to render.
Definition: gpu_manager.h:147
The Cairo implementation of the graphics abstraction layer.
Definition: color4d.cpp:236
int GetAttribute(const std::string &aAttributeName) const
Get an attribute location.
Definition: shader.cpp:172
This file is part of the common library.
double msecs(bool aSinceLast=false)
Definition: profile.h:146
int m_shaderAttrib
true: enable Z test when drawing
Definition: gpu_manager.h:95
void Use()
Use the shader.
Definition: shader.h:126
unsigned int GetSize() const
Return information about number of vertices stored.
Definition: vertex_item.h:58
virtual bool IsCached() const =0
Return true if the container caches vertex data in RAM or video memory.
const wxChar *const traceGalProfile
Flag to enable debug output of GAL performance profiling.
unsigned int m_indexBufMaxSize
Size of the current VRANGE.
Definition: gpu_manager.h:162
A small class to help profiling.
Definition: profile.h:45
virtual void DrawIndices(const VERTEX_ITEM *aItem) override
Clear the container after drawing routines.
virtual unsigned int AllItemsSize() const
VERTEX_CONTAINER * m_container
Shader handling.
Definition: gpu_manager.h:89
virtual unsigned int GetBufferHandle() const =0
Return handle to the vertex buffer.
virtual void EndDrawing() override
Clear the container after drawing routines.
Class to store VERTEX instances with caching.
VERTEX * GetAllVertices() const
Return pointer to the vertices stored in the container.
static constexpr size_t SHADER_OFFSET
Definition: vertex_common.h:79
int m_totalNormal
Current size of index buffer.
Definition: gpu_manager.h:156
int m_totalHuge
Number of regular VRANGEs (small items) pooled into single draw call.
Definition: gpu_manager.h:153
GPU_NONCACHED_MANAGER(VERTEX_CONTAINER *aContainer)
Prepare the stored data to be drawn.
std::vector< VRANGE > m_vranges
Number of huge VRANGEs (i.e. large zones) with separate draw calls.
Definition: gpu_manager.h:150
Class to handle uploading vertices and indices to GPU in drawing purposes.
Definition: gpu_manager.h:45
virtual void BeginDrawing() override
Make the GPU draw given range of vertices.
static GPU_MANAGER * MakeManager(VERTEX_CONTAINER *aContainer)
Definition: gpu_manager.cpp:48
wxLogTrace helper definitions.
void Deactivate()
Deactivate the shader and use the default OpenGL program.
Definition: shader.h:135
void EnableDepthTest(bool aEnabled)
Enable/disable Z buffer depth test.
Provide the access to the OpenGL shaders.
Definition: shader.h:76
GPU_CACHED_MANAGER(VERTEX_CONTAINER *aContainer)
Definition: gpu_manager.cpp:85
virtual void EndDrawing() override
Map vertex buffer stored in GPU memory.
bool m_isDrawing
Container that stores vertices data.
Definition: gpu_manager.h:86
Class to store instances of VERTEX without caching.
Class to handle an item held in a container.
unsigned int m_indexBufSize
Maximum size taken by the index buffer for all frames rendered so far.
Definition: gpu_manager.h:159
static constexpr size_t VERTEX_SIZE
Definition: vertex_common.h:67
unsigned int GetOffset() const
Return data offset in the container.
Definition: vertex_item.h:68
#define KI_TRACE(...)
static constexpr size_t COLOR_OFFSET
Definition: vertex_common.h:74
SHADER * m_shader
Location of shader attributes (for glVertexAttribPointer)
Definition: gpu_manager.h:92
static constexpr size_t SHADER_STRIDE
Definition: vertex_common.h:81
void resizeIndices(unsigned int aNewSize)
< Resizes the indices buffer to aNewSize if necessary
GPU_MANAGER(VERTEX_CONTAINER *aContainer)
Drawing status flag.
Definition: gpu_manager.cpp:57
virtual unsigned int GetSize() const
Return amount of vertices currently stored in the container.
virtual void BeginDrawing() override
Make the GPU draw given range of vertices.
virtual bool IsMapped() const =0
Return true if vertex buffer is currently mapped.
~GPU_CACHED_MANAGER()
Prepare the stored data to be drawn.
Definition: gpu_manager.cpp:98
unsigned int m_curVrangeSize
Definition: gpu_manager.h:165
boost::scoped_array< GLuint > m_indices
Current indices buffer size.
Definition: gpu_manager.h:144
void ClearDirty()
Clear the dirty flag to prevent reuploading vertices to the GPU memory.
virtual void DrawIndices(const VERTEX_ITEM *aItem) override
Clear the container after drawing routines.
virtual void Unmap() override=0
Finish the vertices updates stage.
static constexpr size_t COORD_OFFSET
Definition: vertex_common.h:70
static constexpr size_t COLOR_STRIDE
Definition: vertex_common.h:76