KiCad PCB EDA Suite
antialiasing.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 (C) 2016 Kicad Developers, see change_log.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23 
26 #include <gal/opengl/utils.h>
27 
28 #include <tuple>
29 
30 #include "gl_builtin_shaders.h"
31 #include "SmaaAreaTex.h"
32 #include "SmaaSearchTex.h"
33 
34 using namespace KIGFX;
35 
36 // =========================
37 // ANTIALIASING_NONE
38 // =========================
39 
41  : compositor( aCompositor )
42 {
43 }
44 
45 
47 {
48  // Nothing to initialize
49  return true;
50 }
51 
52 
54 {
55  return compositor->GetScreenSize();
56 }
57 
58 
59 void ANTIALIASING_NONE::DrawBuffer( GLuint buffer )
60 {
62 }
63 
64 
66 {
67  // Nothing to present, draw_buffer already drew to the screen
68 }
69 
70 
72 {
73  // Nothing to do
74 }
75 
76 
78 {
79  // Nothing to do
80 }
81 
82 
84 {
86 }
87 
88 
89 namespace {
90 
91  void draw_fullscreen_primitive()
92  {
93  glMatrixMode( GL_MODELVIEW );
94  glPushMatrix();
95  glLoadIdentity();
96  glMatrixMode( GL_PROJECTION );
97  glPushMatrix();
98  glLoadIdentity();
99 
100 
101  glBegin( GL_TRIANGLES );
102  glTexCoord2f( 0.0f, 1.0f );
103  glVertex2f( -1.0f, 1.0f );
104  glTexCoord2f( 0.0f, 0.0f );
105  glVertex2f( -1.0f, -1.0f );
106  glTexCoord2f( 1.0f, 1.0f );
107  glVertex2f( 1.0f, 1.0f );
108 
109  glTexCoord2f( 1.0f, 1.0f );
110  glVertex2f( 1.0f, 1.0f );
111  glTexCoord2f( 0.0f, 0.0f );
112  glVertex2f( -1.0f, -1.0f );
113  glTexCoord2f( 1.0f, 0.0f );
114  glVertex2f( 1.0f, -1.0f );
115  glEnd();
116 
117  glPopMatrix();
118  glMatrixMode( GL_MODELVIEW );
119  glPopMatrix();
120  }
121 
122 }
123 
124 // =========================
125 // ANTIALIASING_SUPERSAMPLING
126 // =========================
127 
129  SUPERSAMPLING_MODE aMode )
130  : compositor( aCompositor ), mode( aMode ), ssaaMainBuffer( 0 ),
131  areBuffersCreated( false ), areShadersCreated( false )
132 {
133 }
134 
135 
137 {
139  {
140  x4_shader.reset( new SHADER() );
143  x4_shader->Link();
144  checkGlError( "linking supersampling x4 shader" );
145 
146  GLint source_parameter = x4_shader->AddParameter( "source" ); checkGlError( "getting pass 1 colorTex" );
147 
148  x4_shader->Use(); checkGlError( "using pass 1 shader" );
149  x4_shader->SetParameter( source_parameter, 0 ); checkGlError( "setting colorTex uniform" );
150  x4_shader->Deactivate(); checkGlError( "deactivating pass 2 shader" );
151 
152  areShadersCreated = true;
153  }
154 
156  {
157  x4_shader.reset();
158  areShadersCreated = false;
159  }
160 
161  if( !areBuffersCreated )
162  {
164  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
165  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
166 
167  areBuffersCreated = true;
168  }
169 
170  return true;
171 }
172 
173 
175 {
176  unsigned int factor = ( mode == SUPERSAMPLING_MODE::X2 ) ? 2 : 4;
177  return compositor->GetScreenSize() * factor;
178 }
179 
180 
182 {
185 }
186 
187 
189 {
190  compositor->DrawBuffer( aBuffer, ssaaMainBuffer );
191 }
192 
193 
195 {
196  glDisable( GL_BLEND );
197  glDisable( GL_DEPTH_TEST );
198  glActiveTexture( GL_TEXTURE0 );
199  glBindTexture( GL_TEXTURE_2D, compositor->GetBufferTexture( ssaaMainBuffer ) );
201 
203  {
204  x4_shader->Use();
205  checkGlError( "activating supersampling x4 shader" );
206  }
207 
208  draw_fullscreen_primitive();
209 
211  {
212  x4_shader->Deactivate();
213  checkGlError( "deactivating supersampling x4 shader" );
214  }
215 }
216 
217 
219 {
220  areBuffersCreated = false;
221 }
222 
223 
225 {
227 }
228 
229 // ===============================
230 // ANTIALIASING_SMAA
231 // ===============================
232 
234  : areBuffersInitialized( false ), shadersLoaded( false ),
235  quality( aQuality ), compositor( aCompositor )
236 {
237  smaaBaseBuffer = 0;
238  smaaEdgesBuffer = 0;
239  smaaBlendBuffer = 0;
240  smaaAreaTex = 0;
241  smaaSearchTex = 0;
242 
243  pass_1_metrics = 0;
244  pass_2_metrics = 0;
245  pass_3_metrics = 0;
246 }
247 
248 
250 {
251  return compositor->GetScreenSize();
252 }
253 
254 
256 {
257  // Load constant textures
258  glEnable( GL_TEXTURE_2D );
259  glActiveTexture( GL_TEXTURE0 );
260 
261  glGenTextures( 1, &smaaAreaTex );
262  glBindTexture( GL_TEXTURE_2D, smaaAreaTex );
263  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
264  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
265  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
266  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
267  glTexImage2D( GL_TEXTURE_2D, 0, GL_RG8, AREATEX_WIDTH, AREATEX_HEIGHT, 0, GL_RG, GL_UNSIGNED_BYTE, areaTexBytes );
268  checkGlError( "loading smaa area tex" );
269 
270  glGenTextures( 1, &smaaSearchTex );
271  glBindTexture( GL_TEXTURE_2D, smaaSearchTex );
272  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
273  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
274  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
275  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
276  glTexImage2D( GL_TEXTURE_2D, 0, GL_R8, SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT, 0, GL_RED, GL_UNSIGNED_BYTE, searchTexBytes );
277  checkGlError( "loading smaa search tex" );
278 
279  std::string quality_string;
280 
281  if( quality == SMAA_QUALITY::HIGH )
282  {
283  quality_string = "#define SMAA_PRESET_HIGH\n";
284  }
285  else
286  {
287  quality_string = "#define SMAA_PRESET_ULTRA\n";
288  }
289 
290 
291  // set up shaders
292  std::string vert_preamble( R"SHADER(
293 #version 120
294 #define SMAA_GLSL_2_1
295 #define SMAA_INCLUDE_VS 1
296 #define SMAA_INCLUDE_PS 0
297 uniform vec4 SMAA_RT_METRICS;
298 )SHADER" );
299 
300  std::string frag_preamble( R"SHADER(
301 #version 120
302 #define SMAA_GLSL_2_1
303 #define SMAA_INCLUDE_VS 0
304 #define SMAA_INCLUDE_PS 1
305 uniform vec4 SMAA_RT_METRICS;
306 )SHADER" );
307 
308  std::string smaa_source =
310  + std::string( BUILTIN_SHADERS::smaa_base_shader_p2 )
311  + std::string( BUILTIN_SHADERS::smaa_base_shader_p3 )
312  + std::string( BUILTIN_SHADERS::smaa_base_shader_p4 );
313 
314  //
315  // Set up pass 1 Shader
316  //
317  pass_1_shader.reset( new SHADER() );
318  pass_1_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_VERTEX, vert_preamble,
319  quality_string, smaa_source, BUILTIN_SHADERS::smaa_pass_1_vertex_shader );
320  pass_1_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_FRAGMENT, frag_preamble,
321  quality_string, smaa_source, BUILTIN_SHADERS::smaa_pass_1_fragment_shader );
322  pass_1_shader->Link();
323  checkGlError( "linking pass 1 shader" );
324 
325  GLint smaaColorTexParameter = pass_1_shader->AddParameter( "colorTex" ); checkGlError( "pass1: getting colorTex uniform" );
326  pass_1_metrics = pass_1_shader->AddParameter( "SMAA_RT_METRICS" ); checkGlError( "pass1: getting metrics uniform" );
327 
328  pass_1_shader->Use(); checkGlError( "pass1: using shader" );
329  pass_1_shader->SetParameter( smaaColorTexParameter, 0 ); checkGlError( "pass1: setting colorTex uniform" );
330  pass_1_shader->Deactivate(); checkGlError( "pass1: deactivating shader" );
331 
332  //
333  // set up pass 2 shader
334  //
335  pass_2_shader.reset( new SHADER() );
336  pass_2_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_VERTEX, vert_preamble,
337  quality_string, smaa_source, BUILTIN_SHADERS::smaa_pass_2_vertex_shader );
338  pass_2_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_FRAGMENT, frag_preamble,
339  quality_string, smaa_source, BUILTIN_SHADERS::smaa_pass_2_fragment_shader );
340  pass_2_shader->Link();
341  checkGlError( "linking pass 2 shader" );
342 
343  GLint smaaEdgesTexParameter = pass_2_shader->AddParameter( "edgesTex" ); checkGlError( "pass2: getting colorTex uniform" );
344  GLint smaaAreaTexParameter = pass_2_shader->AddParameter( "areaTex" ); checkGlError( "pass2: getting areaTex uniform" );
345  GLint smaaSearchTexParameter = pass_2_shader->AddParameter( "searchTex" ); checkGlError( "pass2: getting searchTex uniform" );
346  pass_2_metrics = pass_2_shader->AddParameter( "SMAA_RT_METRICS" ); checkGlError( "pass2: getting metrics uniform" );
347 
348  pass_2_shader->Use(); checkGlError( "pass2: using shader" );
349  pass_2_shader->SetParameter( smaaEdgesTexParameter, 0 ); checkGlError( "pass2: setting colorTex uniform" );
350  pass_2_shader->SetParameter( smaaAreaTexParameter, 1 ); checkGlError( "pass2: setting areaTex uniform" );
351  pass_2_shader->SetParameter( smaaSearchTexParameter, 3 ); checkGlError( "pass2: setting searchTex uniform" );
352  pass_2_shader->Deactivate(); checkGlError( "pass2: deactivating shader" );
353 
354  //
355  // set up pass 3 shader
356  //
357  pass_3_shader.reset( new SHADER() );
358  pass_3_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_VERTEX, vert_preamble,
359  quality_string, smaa_source, BUILTIN_SHADERS::smaa_pass_3_vertex_shader );
360  pass_3_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_FRAGMENT, frag_preamble,
361  quality_string, smaa_source, BUILTIN_SHADERS::smaa_pass_3_fragment_shader );
362  pass_3_shader->Link();
363 
364  GLint smaaP3ColorTexParameter = pass_3_shader->AddParameter( "colorTex" ); checkGlError( "pass3: getting colorTex uniform" );
365  GLint smaaBlendTexParameter = pass_3_shader->AddParameter( "blendTex" ); checkGlError( "pass3: getting blendTex uniform" );
366  pass_3_metrics = pass_3_shader->AddParameter( "SMAA_RT_METRICS" ); checkGlError( "pass3: getting metrics uniform" );
367 
368  pass_3_shader->Use(); checkGlError( "pass3: using shader" );
369  pass_3_shader->SetParameter( smaaP3ColorTexParameter, 0 ); checkGlError( "pass3: setting colorTex uniform" );
370  pass_3_shader->SetParameter( smaaBlendTexParameter, 1 ); checkGlError( "pass3: setting blendTex uniform" );
371  pass_3_shader->Deactivate(); checkGlError( "pass3: deactivating shader" );
372 
373  shadersLoaded = true;
374 }
375 
376 
378 {
379  auto dims = compositor->GetScreenSize();
380 
381  pass_1_shader->Use(); checkGlError( "pass1: using shader" );
382  pass_1_shader->SetParameter( pass_1_metrics,
383  1.f / float( dims.x ), 1.f / float( dims.y ), float( dims.x ), float( dims.y ) ); checkGlError( "pass1: setting metrics uniform" );
384  pass_1_shader->Deactivate(); checkGlError( "pass1: deactivating shader" );
385 
386  pass_2_shader->Use(); checkGlError( "pass2: using shader" );
387  pass_2_shader->SetParameter( pass_2_metrics,
388  1.f / float( dims.x ), 1.f / float( dims.y ), float( dims.x ), float( dims.y ) ); checkGlError( "pass2: setting metrics uniform" );
389  pass_2_shader->Deactivate(); checkGlError( "pass2: deactivating shader" );
390 
391  pass_3_shader->Use(); checkGlError( "pass3: using shader" );
392  pass_3_shader->SetParameter( pass_3_metrics,
393  1.f / float( dims.x ), 1.f / float( dims.y ), float( dims.x ), float( dims.y ) ); checkGlError( "pass3: setting metrics uniform" );
394  pass_3_shader->Deactivate(); checkGlError( "pass3: deactivating shader" );
395 }
396 
397 
399 {
400  if( !shadersLoaded )
401  loadShaders();
402 
403  if( !areBuffersInitialized )
404  {
406  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
407  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
408 
410  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
411  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
412 
414  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
415  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
416 
417  updateUniforms();
418  areBuffersInitialized = true;
419  }
420 
421  // Nothing to initialize
422  return true;
423 }
424 
425 
427 {
428  areBuffersInitialized = false;
429 }
430 
431 
433 {
435 }
436 
437 
438 void ANTIALIASING_SMAA::DrawBuffer( GLuint buffer )
439 {
440  // draw to internal buffer
442 }
443 
444 
446 {
449 }
450 
451 
452 namespace {
453  void draw_fullscreen_triangle()
454  {
455  glMatrixMode( GL_MODELVIEW );
456  glPushMatrix();
457  glLoadIdentity();
458  glMatrixMode( GL_PROJECTION );
459  glPushMatrix();
460  glLoadIdentity();
461 
462  glBegin( GL_TRIANGLES );
463  glTexCoord2f( 0.0f, 1.0f );
464  glVertex2f( -1.0f, 1.0f );
465  glTexCoord2f( 0.0f, -1.0f );
466  glVertex2f( -1.0f, -3.0f );
467  glTexCoord2f( 2.0f, 1.0f );
468  glVertex2f( 3.0f, 1.0f );
469  glEnd();
470 
471  glPopMatrix();
472  glMatrixMode( GL_MODELVIEW );
473  glPopMatrix();
474  }
475 }
476 
477 
479 {
480  auto sourceTexture = compositor->GetBufferTexture( smaaBaseBuffer );
481 
482  glDisable( GL_BLEND );
483  glDisable( GL_DEPTH_TEST );
484  glEnable( GL_TEXTURE_2D );
485 
486  //
487  // pass 1: main-buffer -> smaaEdgesBuffer
488  //
491 
492  glActiveTexture( GL_TEXTURE0 );
493  glBindTexture( GL_TEXTURE_2D, sourceTexture ); checkGlError( "binding colorTex" );
494  pass_1_shader->Use(); checkGlError( "using smaa pass 1 shader" );
495  draw_fullscreen_triangle();
496  pass_1_shader->Deactivate();
497 
498  //
499  // pass 2: smaaEdgesBuffer -> smaaBlendBuffer
500  //
503 
504  auto edgesTex = compositor->GetBufferTexture( smaaEdgesBuffer );
505 
506  glActiveTexture( GL_TEXTURE0 );
507  glBindTexture( GL_TEXTURE_2D, edgesTex );
508  glActiveTexture( GL_TEXTURE1 );
509  glBindTexture( GL_TEXTURE_2D, smaaAreaTex );
510  glActiveTexture( GL_TEXTURE3 );
511  glBindTexture( GL_TEXTURE_2D, smaaSearchTex );
512 
513  pass_2_shader->Use();
514  draw_fullscreen_triangle();
515  pass_2_shader->Deactivate();
516 
517  //
518  // pass 3: colorTex + BlendBuffer -> output
519  //
522  auto blendTex = compositor->GetBufferTexture( smaaBlendBuffer );
523 
524  glActiveTexture( GL_TEXTURE0 );
525  glBindTexture( GL_TEXTURE_2D, sourceTexture );
526  glActiveTexture( GL_TEXTURE1 );
527  glBindTexture( GL_TEXTURE_2D, blendTex );
528 
529  pass_3_shader->Use();
530  draw_fullscreen_triangle();
531  pass_3_shader->Deactivate();
532 }
SUPERSAMPLING_MODE
Definition: antialiasing.h:73
VECTOR2U GetInternalBufferSize() override
void Present() override
virtual void DrawBuffer(unsigned int aBufferHandle) override
Function DrawBuffer() draws the selected buffer to the output buffer.
Class CAIRO_GAL is the cairo implementation of the graphics abstraction layer.
Definition: class_module.h:58
ANTIALIASING_NONE(OPENGL_COMPOSITOR *aCompositor)
#define SEARCHTEX_WIDTH
Copyright (C) 2013 Jorge Jimenez (jorge@iryoku.com) Copyright (C) 2013 Jose I.
Definition: SmaaSearchTex.h:33
#define AREATEX_HEIGHT
Definition: SmaaAreaTex.h:34
const char smaa_pass_3_fragment_shader[]
unsigned int smaaEdgesBuffer
Definition: antialiasing.h:132
Fragment shader.
Definition: shader.h:45
VECTOR2U GetInternalBufferSize() override
int checkGlError(const std::string &aInfo, bool aThrow)
Checks if one of recent OpenGL operations has failed.
Definition: utils.cpp:30
unsigned int smaaSearchTex
Definition: antialiasing.h:137
void DrawBuffer(GLuint aBuffer) override
static const unsigned int DIRECT_RENDERING
Class that handles multitarget rendering (ie.
std::unique_ptr< SHADER > x4_shader
Definition: antialiasing.h:102
OPENGL_COMPOSITOR * compositor
Definition: antialiasing.h:70
VECTOR2U GetInternalBufferSize() override
void DrawBuffer(GLuint buffer) override
#define AREATEX_WIDTH
Copyright (C) 2013 Jorge Jimenez (jorge@iryoku.com) Copyright (C) 2013 Jose I.
Definition: SmaaAreaTex.h:33
static const unsigned char searchTexBytes[]
Stored in R8 format.
Definition: SmaaSearchTex.h:43
const char smaa_base_shader_p4[]
virtual void ClearBuffer() override
Function ClearBuffer() clears the selected buffer (set by the SetBuffer() function).
void DrawBuffer(GLuint) override
const char smaa_pass_1_fragment_shader[]
#define SEARCHTEX_HEIGHT
Definition: SmaaSearchTex.h:34
const unsigned char areaTexBytes[]
Stored in R8G8 format.
Definition: SmaaAreaTex.h:43
ANTIALIASING_SUPERSAMPLING(OPENGL_COMPOSITOR *aCompositor, SUPERSAMPLING_MODE aMode)
const char smaa_pass_2_fragment_shader[]
unsigned int smaaBlendBuffer
Definition: antialiasing.h:133
Vertex shader.
Definition: shader.h:44
virtual void SetBuffer(unsigned int aBufferHandle) override
Function SetBuffer() sets the selected buffer as the rendering target.
Class SHADER provides the access to the OpenGL shaders.
Definition: shader.h:74
OPENGL_COMPOSITOR * compositor
Definition: antialiasing.h:95
std::unique_ptr< SHADER > pass_2_shader
Definition: antialiasing.h:144
VECTOR2U GetScreenSize() const
std::unique_ptr< SHADER > pass_3_shader
Definition: antialiasing.h:147
GLenum GetBufferTexture(unsigned int aBufferHandle)
const char smaa_base_shader_p3[]
unsigned int CreateBuffer() override
virtual unsigned int CreateBuffer() override
Function CreateBuffer() prepares a new buffer that may be used as a rendering target.
std::unique_ptr< SHADER > pass_1_shader
Definition: antialiasing.h:141
OPENGL_COMPOSITOR * compositor
Definition: antialiasing.h:151
unsigned int CreateBuffer() override
ANTIALIASING_SMAA(OPENGL_COMPOSITOR *aCompositor, SMAA_QUALITY aQuality)
unsigned int CreateBuffer() override
void OnLostBuffers() override
void OnLostBuffers() override
unsigned int smaaBaseBuffer
Definition: antialiasing.h:131