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  * @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 
25 #include <gal/opengl/gpu_manager.h>
29 #include <gal/opengl/shader.h>
30 #include <gal/opengl/utils.h>
31 
32 #include <typeinfo>
33 #include <confirm.h>
34 
35 #ifdef __WXDEBUG__
36 #include <profile.h>
37 #include <wx/log.h>
38 #endif /* __WXDEBUG__ */
39 
40 using namespace KIGFX;
41 
43 {
44  if( aContainer->IsCached() )
45  return new GPU_CACHED_MANAGER( aContainer );
46  else
47  return new GPU_NONCACHED_MANAGER( aContainer );
48 }
49 
50 
52  m_isDrawing( false ), m_container( aContainer ), m_shader( NULL ), m_shaderAttrib( 0 ), m_enableDepthTest( true )
53 {
54 }
55 
56 
58 {
59 }
60 
61 
63 {
64  m_shader = &aShader;
65  m_shaderAttrib = m_shader->GetAttribute( "attrShaderParams" );
66 
67  if( m_shaderAttrib == -1 )
68  {
69  DisplayError( NULL, wxT( "Could not get the shader attribute location" ) );
70  }
71 }
72 
73 
74 // Cached manager
76  GPU_MANAGER( aContainer ), m_buffersInitialized( false ), m_indicesPtr( NULL ),
77  m_indicesBuffer( 0 ), m_indicesSize( 0 ), m_indicesCapacity( 0 )
78 {
79  // Allocate the biggest possible buffer for indices
80  resizeIndices( aContainer->GetSize() );
81 }
82 
83 
85 {
87  {
88  glBindBuffer( GL_ARRAY_BUFFER, 0 );
89  glDeleteBuffers( 1, &m_indicesBuffer );
90  }
91 }
92 
93 
95 {
96  wxASSERT( !m_isDrawing );
97 
99  {
100  glGenBuffers( 1, &m_indicesBuffer );
101  checkGlError( "generating vertices buffer" );
102  m_buffersInitialized = true;
103  }
104 
105  if( m_container->IsDirty() )
107 
108  // Number of vertices to be drawn in the EndDrawing()
109  m_indicesSize = 0;
110  // Set the indices pointer to the beginning of the indices-to-draw buffer
111  m_indicesPtr = m_indices.get();
112 
113  m_isDrawing = true;
114 }
115 
116 
117 void GPU_CACHED_MANAGER::DrawIndices( unsigned int aOffset, unsigned int aSize )
118 {
119  wxASSERT( m_isDrawing );
120 
121  // Copy indices of items that should be drawn to GPU memory
122  for( unsigned int i = aOffset; i < aOffset + aSize; *m_indicesPtr++ = i++ );
123 
124  m_indicesSize += aSize;
125 }
126 
127 
129 {
130  wxASSERT( m_isDrawing );
131 
132  for( unsigned int i = 0; i < m_indicesSize; *m_indicesPtr++ = i++ );
133 
134  m_indicesSize = m_container->GetSize();
135 }
136 
137 
139 {
140 #ifdef __WXDEBUG__
141  PROF_COUNTER totalRealTime;
142 #endif /* __WXDEBUG__ */
143 
144  wxASSERT( m_isDrawing );
145 
146  CACHED_CONTAINER* cached = static_cast<CACHED_CONTAINER*>( m_container );
147 
148  if( cached->IsMapped() )
149  cached->Unmap();
150 
151  if( m_indicesSize == 0 )
152  {
153  m_isDrawing = false;
154  return;
155  }
156 
157  if( m_enableDepthTest )
158  glEnable( GL_DEPTH_TEST );
159  else
160  glDisable( GL_DEPTH_TEST );
161 
162  // Prepare buffers
163  glEnableClientState( GL_VERTEX_ARRAY );
164  glEnableClientState( GL_COLOR_ARRAY );
165 
166  // Bind vertices data buffers
167  glBindBuffer( GL_ARRAY_BUFFER, cached->GetBufferHandle() );
168  glVertexPointer( COORD_STRIDE, GL_FLOAT, VERTEX_SIZE, (GLvoid*) COORD_OFFSET );
169  glColorPointer( COLOR_STRIDE, GL_UNSIGNED_BYTE, VERTEX_SIZE, (GLvoid*) COLOR_OFFSET );
170 
171  if( m_shader != NULL ) // Use shader if applicable
172  {
173  m_shader->Use();
174  glEnableVertexAttribArray( m_shaderAttrib );
175  glVertexAttribPointer( m_shaderAttrib, SHADER_STRIDE, GL_FLOAT, GL_FALSE,
176  VERTEX_SIZE, (GLvoid*) SHADER_OFFSET );
177  }
178 
179  glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_indicesBuffer );
180  glBufferData( GL_ELEMENT_ARRAY_BUFFER, m_indicesSize * sizeof(int),
181  (GLvoid*) m_indices.get(), GL_DYNAMIC_DRAW );
182 
183  glDrawElements( GL_TRIANGLES, m_indicesSize, GL_UNSIGNED_INT, 0 );
184 
185 #ifdef __WXDEBUG__
186  wxLogTrace( "GAL_PROFILE", wxT( "Cached manager size: %d" ), m_indicesSize );
187 #endif /* __WXDEBUG__ */
188 
189  glBindBuffer( GL_ARRAY_BUFFER, 0 );
190  glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
191  cached->ClearDirty();
192 
193  // Deactivate vertex array
194  glDisableClientState( GL_COLOR_ARRAY );
195  glDisableClientState( GL_VERTEX_ARRAY );
196 
197  if( m_shader != NULL )
198  {
199  glDisableVertexAttribArray( m_shaderAttrib );
200  m_shader->Deactivate();
201  }
202 
203  m_isDrawing = false;
204 
205 #ifdef __WXDEBUG__
206  totalRealTime.Stop();
207  wxLogTrace( "GAL_PROFILE",
208  wxT( "GPU_CACHED_MANAGER::EndDrawing(): %.1f ms" ), totalRealTime.msecs() );
209 #endif /* __WXDEBUG__ */
210 }
211 
212 
213 void GPU_CACHED_MANAGER::resizeIndices( unsigned int aNewSize )
214 {
215  if( aNewSize > m_indicesCapacity )
216  {
217  m_indicesCapacity = aNewSize;
218  m_indices.reset( new GLuint[m_indicesCapacity] );
219  }
220 }
221 
222 
223 // Noncached manager
225  GPU_MANAGER( aContainer )
226 {
227 }
228 
229 
231 {
232  // Nothing has to be prepared
233 }
234 
235 
236 void GPU_NONCACHED_MANAGER::DrawIndices( unsigned int aOffset, unsigned int aSize )
237 {
238  wxASSERT_MSG( false, wxT( "Not implemented yet" ) );
239 }
240 
241 
243 {
244  // This is the default use case, nothing has to be done
245  // The real rendering takes place in the EndDrawing() function
246 }
247 
248 
250 {
251 #ifdef __WXDEBUG__
252  PROF_COUNTER totalRealTime;
253 #endif /* __WXDEBUG__ */
254 
255  if( m_container->GetSize() == 0 )
256  return;
257 
258  VERTEX* vertices = m_container->GetAllVertices();
259  GLfloat* coordinates = (GLfloat*) ( vertices );
260  GLubyte* colors = (GLubyte*) ( vertices ) + COLOR_OFFSET;
261 
262  if( m_enableDepthTest )
263  glEnable( GL_DEPTH_TEST );
264  else
265  glDisable( GL_DEPTH_TEST );
266 
267  // Prepare buffers
268  glEnableClientState( GL_VERTEX_ARRAY );
269  glEnableClientState( GL_COLOR_ARRAY );
270 
271  glVertexPointer( COORD_STRIDE, GL_FLOAT, VERTEX_SIZE, coordinates );
272  glColorPointer( COLOR_STRIDE, GL_UNSIGNED_BYTE, VERTEX_SIZE, colors );
273 
274  if( m_shader != NULL ) // Use shader if applicable
275  {
276  GLfloat* shaders = (GLfloat*) ( vertices ) + SHADER_OFFSET / sizeof(GLfloat);
277 
278  m_shader->Use();
279  glEnableVertexAttribArray( m_shaderAttrib );
280  glVertexAttribPointer( m_shaderAttrib, SHADER_STRIDE, GL_FLOAT, GL_FALSE,
281  VERTEX_SIZE, shaders );
282  }
283 
284  glDrawArrays( GL_TRIANGLES, 0, m_container->GetSize() );
285 
286 #ifdef __WXDEBUG__
287  wxLogTrace( "GAL_PROFILE", wxT( "Noncached manager size: %d" ), m_container->GetSize() );
288 #endif /* __WXDEBUG__ */
289 
290  // Deactivate vertex array
291  glDisableClientState( GL_COLOR_ARRAY );
292  glDisableClientState( GL_VERTEX_ARRAY );
293 
294  if( m_shader != NULL )
295  {
296  glDisableVertexAttribArray( m_shaderAttrib );
297  m_shader->Deactivate();
298  }
299 
300  m_container->Clear();
301 
302 #ifdef __WXDEBUG__
303  totalRealTime.Stop();
304  wxLogTrace( "GAL_PROFILE",
305  wxT( "GPU_NONCACHED_MANAGER::EndDrawing(): %.1f ms" ), totalRealTime.msecs() );
306 #endif /* __WXDEBUG__ */
307 }
308 
309 void GPU_MANAGER::EnableDepthTest( bool aEnabled )
310 {
311  m_enableDepthTest = aEnabled;
312 }
void Stop()
save the time when this function was called, and set the counter stane to stop
Definition: profile.h:82
virtual ~GPU_MANAGER()
Definition: gpu_manager.cpp:57
static constexpr size_t COORD_STRIDE
Definition: vertex_common.h:68
virtual void SetShader(SHADER &aShader)
Function SetShader() Allows using shaders with the stored data.
Definition: gpu_manager.cpp:62
virtual void Clear()=0
Removes all data stored in the container and restores its original state.
VERTEX * GetAllVertices() const
Returns pointer to the vertices stored in the container.
unsigned int m_indicesCapacity
Current indices buffer size
Definition: gpu_manager.h:152
Class CAIRO_GAL is the cairo implementation of the graphics abstraction layer.
Definition: class_module.h:58
Data structure for vertices {X,Y,Z,R,G,B,A,shader&param}
Definition: vertex_common.h:56
This file is part of the common library.
int m_shaderAttrib
Location of shader attributes (for glVertexAttribPointer)
Definition: gpu_manager.h:101
void Use()
Use the shader.
Definition: shader.h:130
virtual bool IsCached() const =0
Returns true if the container caches vertex data in RAM or video memory.
int checkGlError(const std::string &aInfo, bool aThrow)
Checks if one of recent OpenGL operations has failed.
Definition: utils.cpp:30
bool m_buffersInitialized
Buffers initialization flag
Definition: gpu_manager.h:137
The class PROF_COUNTER is a small class to help profiling.
Definition: profile.h:45
VERTEX_CONTAINER * m_container
Container that stores vertices data.
Definition: gpu_manager.h:95
virtual unsigned int GetBufferHandle() const =0
Returns handle to the vertex buffer.
virtual void EndDrawing() override
>
unsigned int m_indicesSize
Number of indices stored in the indices buffer
Definition: gpu_manager.h:149
virtual void DrawIndices(unsigned int aOffset, unsigned int aSize) override
>
Class to store VERTEX instances with caching.
GLuint m_indicesBuffer
Handle to indices buffer
Definition: gpu_manager.h:146
static constexpr size_t SHADER_OFFSET
Definition: vertex_common.h:75
GLuint * m_indicesPtr
Pointer to the first free cell in the indices buffer
Definition: gpu_manager.h:143
bool IsDirty() const
Returns information about the container cache state.
GPU_NONCACHED_MANAGER(VERTEX_CONTAINER *aContainer)
Class to handle uploading vertices and indices to GPU in drawing purposes.
Definition: gpu_manager.h:42
virtual void DrawAll() override
>
virtual void BeginDrawing() override
>
Definition: gpu_manager.cpp:94
static GPU_MANAGER * MakeManager(VERTEX_CONTAINER *aContainer)
Definition: gpu_manager.cpp:42
void Deactivate()
Deactivate the shader and use the default OpenGL program.
Definition: shader.h:139
void EnableDepthTest(bool aEnabled)
Function EnableDepthTest() Enables/disables Z buffer depth test.
Class SHADER provides the access to the OpenGL shaders.
Definition: shader.h:74
int GetAttribute(const std::string &aAttributeName) const
Gets an attribute location.
Definition: shader.cpp:161
GPU_CACHED_MANAGER(VERTEX_CONTAINER *aContainer)
Definition: gpu_manager.cpp:75
virtual unsigned int GetSize() const
Function GetSize() returns amount of vertices currently stored in the container.
virtual void DrawAll() override
>
double msecs() const
Definition: profile.h:124
virtual void EndDrawing() override
>
bool m_isDrawing
Drawing status flag.
Definition: gpu_manager.h:92
Class to store instances of VERTEX without caching.
virtual void DrawIndices(unsigned int aOffset, unsigned int aSize) override
>
size_t i
Definition: json11.cpp:597
static constexpr size_t VERTEX_SIZE
Definition: vertex_common.h:63
static constexpr size_t COLOR_OFFSET
Definition: vertex_common.h:70
SHADER * m_shader
Shader handling
Definition: gpu_manager.h:98
static constexpr size_t SHADER_STRIDE
Definition: vertex_common.h:77
void resizeIndices(unsigned int aNewSize)
Resizes the indices buffer to aNewSize if necessary
GPU_MANAGER(VERTEX_CONTAINER *aContainer)
Definition: gpu_manager.cpp:51
virtual void BeginDrawing() override
>
bool m_enableDepthTest
true: enable Z test when drawing
Definition: gpu_manager.h:104
void DisplayError(wxWindow *parent, const wxString &text, int displaytime)
Function DisplayError displays an error or warning message box with aMessage.
Definition: confirm.cpp:245
virtual bool IsMapped() const =0
Returns true if vertex buffer is currently mapped.
boost::scoped_array< GLuint > m_indices
Pointer to the current indices buffer
Definition: gpu_manager.h:140
void ClearDirty()
Clears the dirty flag to prevent reuploading vertices to the GPU memory.
static VRML_COLOR colors[VRML_COLOR_LAST]
virtual void Unmap() override=0
>
static constexpr size_t COORD_OFFSET
Definition: vertex_common.h:66
static constexpr size_t COLOR_STRIDE
Definition: vertex_common.h:72