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 <maciej.suminski@cern.ch>
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 
34 #include <typeinfo>
35 #include <confirm.h>
36 #include <trace_helpers.h>
37 
38 #ifdef KICAD_GAL_PROFILE
39 #include <profile.h>
40 #include <wx/log.h>
41 #endif /* KICAD_GAL_PROFILE */
42 
43 using namespace KIGFX;
44 
46 {
47  if( aContainer->IsCached() )
48  return new GPU_CACHED_MANAGER( aContainer );
49  else
50  return new GPU_NONCACHED_MANAGER( aContainer );
51 }
52 
53 
55  m_isDrawing( false ),
56  m_container( aContainer ),
57  m_shader( nullptr ),
58  m_shaderAttrib( 0 ),
59  m_enableDepthTest( true )
60 {
61 }
62 
63 
65 {
66 }
67 
68 
70 {
71  m_shader = &aShader;
72  m_shaderAttrib = m_shader->GetAttribute( "attrShaderParams" );
73 
74  if( m_shaderAttrib == -1 )
75  {
76  DisplayError( nullptr, wxT( "Could not get the shader attribute location" ) );
77  }
78 }
79 
80 
81 // Cached manager
83  GPU_MANAGER( aContainer ),
84  m_buffersInitialized( false ),
85  m_indicesPtr( nullptr ),
86  m_indicesBuffer( 0 ),
87  m_indicesSize( 0 ),
88  m_indicesCapacity( 0 )
89 {
90  // Allocate the biggest possible buffer for indices
91  resizeIndices( aContainer->GetSize() );
92 }
93 
94 
96 {
98  {
99  if( glBindBuffer )
100  glBindBuffer( GL_ARRAY_BUFFER, 0 );
101 
102  if( glDeleteBuffers )
103  glDeleteBuffers( 1, &m_indicesBuffer );
104  }
105 }
106 
107 
109 {
110  wxASSERT( !m_isDrawing );
111 
112  if( !m_buffersInitialized )
113  {
114  glGenBuffers( 1, &m_indicesBuffer );
115  checkGlError( "generating vertices buffer", __FILE__, __LINE__ );
116  m_buffersInitialized = true;
117  }
118 
119  if( m_container->IsDirty() )
121 
122  // Number of vertices to be drawn in the EndDrawing()
123  m_indicesSize = 0;
124  // Set the indices pointer to the beginning of the indices-to-draw buffer
125  m_indicesPtr = m_indices.get();
126 
127  m_isDrawing = true;
128 }
129 
130 
131 void GPU_CACHED_MANAGER::DrawIndices( unsigned int aOffset, unsigned int aSize )
132 {
133  wxASSERT( m_isDrawing );
134 
135  // Copy indices of items that should be drawn to GPU memory
136  for( unsigned int i = aOffset; i < aOffset + aSize; *m_indicesPtr++ = i++ )
137  ;
138 
139  m_indicesSize += aSize;
140 }
141 
142 
144 {
145  wxASSERT( m_isDrawing );
146 
147  for( unsigned int i = 0; i < m_indicesSize; *m_indicesPtr++ = i++ )
148  ;
149 
151 }
152 
153 
155 {
156 #ifdef KICAD_GAL_PROFILE
157  PROF_COUNTER totalRealTime;
158 #endif /* KICAD_GAL_PROFILE */
159 
160  wxASSERT( m_isDrawing );
161 
162  CACHED_CONTAINER* cached = static_cast<CACHED_CONTAINER*>( m_container );
163 
164  if( cached->IsMapped() )
165  cached->Unmap();
166 
167  if( m_indicesSize == 0 )
168  {
169  m_isDrawing = false;
170  return;
171  }
172 
173  if( m_enableDepthTest )
174  glEnable( GL_DEPTH_TEST );
175  else
176  glDisable( GL_DEPTH_TEST );
177 
178  // Prepare buffers
179  glEnableClientState( GL_VERTEX_ARRAY );
180  glEnableClientState( GL_COLOR_ARRAY );
181 
182  // Bind vertices data buffers
183  glBindBuffer( GL_ARRAY_BUFFER, cached->GetBufferHandle() );
184  glVertexPointer( COORD_STRIDE, GL_FLOAT, VERTEX_SIZE, (GLvoid*) COORD_OFFSET );
185  glColorPointer( COLOR_STRIDE, GL_UNSIGNED_BYTE, VERTEX_SIZE, (GLvoid*) COLOR_OFFSET );
186 
187  if( m_shader != nullptr ) // Use shader if applicable
188  {
189  m_shader->Use();
190  glEnableVertexAttribArray( m_shaderAttrib );
191  glVertexAttribPointer( m_shaderAttrib, SHADER_STRIDE, GL_FLOAT, GL_FALSE, VERTEX_SIZE,
192  (GLvoid*) SHADER_OFFSET );
193  }
194 
195  glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_indicesBuffer );
196  glBufferData( GL_ELEMENT_ARRAY_BUFFER, m_indicesSize * sizeof( int ), (GLvoid*) m_indices.get(),
197  GL_DYNAMIC_DRAW );
198 
199  glDrawElements( GL_TRIANGLES, m_indicesSize, GL_UNSIGNED_INT, nullptr );
200 
201 #ifdef KICAD_GAL_PROFILE
202  wxLogTrace( traceGalProfile, wxT( "Cached manager size: %d" ), m_indicesSize );
203 #endif /* KICAD_GAL_PROFILE */
204 
205  glBindBuffer( GL_ARRAY_BUFFER, 0 );
206  glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
207  cached->ClearDirty();
208 
209  // Deactivate vertex array
210  glDisableClientState( GL_COLOR_ARRAY );
211  glDisableClientState( GL_VERTEX_ARRAY );
212 
213  if( m_shader != nullptr )
214  {
215  glDisableVertexAttribArray( m_shaderAttrib );
216  m_shader->Deactivate();
217  }
218 
219  m_isDrawing = false;
220 
221 #ifdef KICAD_GAL_PROFILE
222  totalRealTime.Stop();
223  wxLogTrace( traceGalProfile, wxT( "GPU_CACHED_MANAGER::EndDrawing(): %.1f ms" ),
224  totalRealTime.msecs() );
225 #endif /* KICAD_GAL_PROFILE */
226 }
227 
228 
229 void GPU_CACHED_MANAGER::resizeIndices( unsigned int aNewSize )
230 {
231  if( aNewSize > m_indicesCapacity )
232  {
233  m_indicesCapacity = aNewSize;
234  m_indices.reset( new GLuint[m_indicesCapacity] );
235  }
236 }
237 
238 
239 // Noncached manager
241  GPU_MANAGER( aContainer )
242 {
243 }
244 
245 
247 {
248  // Nothing has to be prepared
249 }
250 
251 
252 void GPU_NONCACHED_MANAGER::DrawIndices( unsigned int aOffset, unsigned int aSize )
253 {
254  wxASSERT_MSG( false, wxT( "Not implemented yet" ) );
255 }
256 
257 
259 {
260  // This is the default use case, nothing has to be done
261  // The real rendering takes place in the EndDrawing() function
262 }
263 
264 
266 {
267 #ifdef KICAD_GAL_PROFILE
268  PROF_COUNTER totalRealTime;
269 #endif /* KICAD_GAL_PROFILE */
270 
271  if( m_container->GetSize() == 0 )
272  return;
273 
274  VERTEX* vertices = m_container->GetAllVertices();
275  GLfloat* coordinates = (GLfloat*) ( vertices );
276  GLubyte* colors = (GLubyte*) ( vertices ) + COLOR_OFFSET;
277 
278  if( m_enableDepthTest )
279  glEnable( GL_DEPTH_TEST );
280  else
281  glDisable( GL_DEPTH_TEST );
282 
283  // Prepare buffers
284  glEnableClientState( GL_VERTEX_ARRAY );
285  glEnableClientState( GL_COLOR_ARRAY );
286 
287  glVertexPointer( COORD_STRIDE, GL_FLOAT, VERTEX_SIZE, coordinates );
288  glColorPointer( COLOR_STRIDE, GL_UNSIGNED_BYTE, VERTEX_SIZE, colors );
289 
290  if( m_shader != nullptr ) // Use shader if applicable
291  {
292  GLfloat* shaders = (GLfloat*) ( vertices ) + SHADER_OFFSET / sizeof( GLfloat );
293 
294  m_shader->Use();
295  glEnableVertexAttribArray( m_shaderAttrib );
296  glVertexAttribPointer( m_shaderAttrib, SHADER_STRIDE, GL_FLOAT, GL_FALSE, VERTEX_SIZE,
297  shaders );
298  }
299 
300  glDrawArrays( GL_TRIANGLES, 0, m_container->GetSize() );
301 
302 #ifdef KICAD_GAL_PROFILE
303  wxLogTrace( traceGalProfile, wxT( "Noncached manager size: %d" ), m_container->GetSize() );
304 #endif /* KICAD_GAL_PROFILE */
305 
306  // Deactivate vertex array
307  glDisableClientState( GL_COLOR_ARRAY );
308  glDisableClientState( GL_VERTEX_ARRAY );
309 
310  if( m_shader != nullptr )
311  {
312  glDisableVertexAttribArray( m_shaderAttrib );
313  m_shader->Deactivate();
314  }
315 
316  m_container->Clear();
317 
318 #ifdef KICAD_GAL_PROFILE
319  totalRealTime.Stop();
320  wxLogTrace( traceGalProfile, wxT( "GPU_NONCACHED_MANAGER::EndDrawing(): %.1f ms" ),
321  totalRealTime.msecs() );
322 #endif /* KICAD_GAL_PROFILE */
323 }
324 
325 void GPU_MANAGER::EnableDepthTest( bool aEnabled )
326 {
327  m_enableDepthTest = aEnabled;
328 }
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:247
virtual ~GPU_MANAGER()
Definition: gpu_manager.cpp:64
static constexpr size_t COORD_STRIDE
Definition: vertex_common.h:72
bool IsDirty() const
Return information about the container cache state.
virtual void SetShader(SHADER &aShader)
Allow using shaders with the stored data.
Definition: gpu_manager.cpp:69
virtual void Clear()=0
Remove all data stored in the container and restores its original state.
unsigned int m_indicesCapacity
Definition: gpu_manager.h:149
The Cairo implementation of the graphics abstraction layer.
Definition: color4d.cpp:191
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:98
void Use()
Use the shader.
Definition: shader.h:126
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.
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
bool m_buffersInitialized
Pointer to the current indices buffer.
Definition: gpu_manager.h:134
A small class to help profiling.
Definition: profile.h:45
VERTEX_CONTAINER * m_container
Shader handling.
Definition: gpu_manager.h:92
virtual unsigned int GetBufferHandle() const =0
Return handle to the vertex buffer.
virtual void EndDrawing() override
Clear the container after drawing routines.
unsigned int m_indicesSize
Current indices buffer size.
Definition: gpu_manager.h:146
virtual void DrawIndices(unsigned int aOffset, unsigned int aSize) override
Make the GPU draw all the vertices stored in the container.
Class to store VERTEX instances with caching.
GLuint m_indicesBuffer
Number of indices stored in the indices buffer.
Definition: gpu_manager.h:143
VERTEX * GetAllVertices() const
Return pointer to the vertices stored in the container.
static constexpr size_t SHADER_OFFSET
Definition: vertex_common.h:79
GLuint * m_indicesPtr
Handle to indices buffer.
Definition: gpu_manager.h:140
GPU_NONCACHED_MANAGER(VERTEX_CONTAINER *aContainer)
Prepare the stored data to be drawn.
Class to handle uploading vertices and indices to GPU in drawing purposes.
Definition: gpu_manager.h:43
virtual void DrawAll() override
Clear the container after drawing routines.
virtual void BeginDrawing() override
Make the GPU draw given range of vertices.
static GPU_MANAGER * MakeManager(VERTEX_CONTAINER *aContainer)
Definition: gpu_manager.cpp:45
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:82
virtual void DrawAll() override
Clear the container after drawing routines.
virtual void EndDrawing() override
Map vertex buffer stored in GPU memory.
bool m_isDrawing
Container that stores vertices data.
Definition: gpu_manager.h:89
Class to store instances of VERTEX without caching.
virtual void DrawIndices(unsigned int aOffset, unsigned int aSize) override
Make the GPU draw all the vertices stored in the container.
static constexpr size_t VERTEX_SIZE
Definition: vertex_common.h:67
static constexpr size_t COLOR_OFFSET
Definition: vertex_common.h:74
SHADER * m_shader
Location of shader attributes (for glVertexAttribPointer)
Definition: gpu_manager.h:95
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:54
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:95
boost::scoped_array< GLuint > m_indices
Pointer to the first free cell in the indices buffer.
Definition: gpu_manager.h:137
void ClearDirty()
Clear the dirty flag to prevent reuploading vertices to the GPU memory.
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