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 #include <gal/color4d.h>
28 
29 #include <memory>
30 #include <tuple>
31 
32 #include "gl_builtin_shaders.h"
33 #include "SmaaAreaTex.h"
34 #include "SmaaSearchTex.h"
35 
36 using namespace KIGFX;
37 
38 // =========================
39 // ANTIALIASING_NONE
40 // =========================
41 
43  : compositor( aCompositor )
44 {
45 }
46 
47 
49 {
50  // Nothing to initialize
51  return true;
52 }
53 
54 
56 {
57  return compositor->GetScreenSize();
58 }
59 
60 
61 void ANTIALIASING_NONE::DrawBuffer( GLuint buffer )
62 {
64 }
65 
66 
68 {
69  // Nothing to present, draw_buffer already drew to the screen
70 }
71 
72 
74 {
75  // Nothing to do
76 }
77 
78 
80 {
81  // Nothing to do
82 }
83 
84 
86 {
88 }
89 
90 
91 namespace {
92 
93  void draw_fullscreen_primitive()
94  {
95  glMatrixMode( GL_MODELVIEW );
96  glPushMatrix();
97  glLoadIdentity();
98  glMatrixMode( GL_PROJECTION );
99  glPushMatrix();
100  glLoadIdentity();
101 
102 
103  glBegin( GL_TRIANGLES );
104  glTexCoord2f( 0.0f, 1.0f );
105  glVertex2f( -1.0f, 1.0f );
106  glTexCoord2f( 0.0f, 0.0f );
107  glVertex2f( -1.0f, -1.0f );
108  glTexCoord2f( 1.0f, 1.0f );
109  glVertex2f( 1.0f, 1.0f );
110 
111  glTexCoord2f( 1.0f, 1.0f );
112  glVertex2f( 1.0f, 1.0f );
113  glTexCoord2f( 0.0f, 0.0f );
114  glVertex2f( -1.0f, -1.0f );
115  glTexCoord2f( 1.0f, 0.0f );
116  glVertex2f( 1.0f, -1.0f );
117  glEnd();
118 
119  glPopMatrix();
120  glMatrixMode( GL_MODELVIEW );
121  glPopMatrix();
122  }
123 
124 }
125 
126 // =========================
127 // ANTIALIASING_SUPERSAMPLING
128 // =========================
129 
131  SUPERSAMPLING_MODE aMode )
132  : compositor( aCompositor ), mode( aMode ), ssaaMainBuffer( 0 ),
133  areBuffersCreated( false ), areShadersCreated( false )
134 {
135 }
136 
137 
139 {
141  {
142  x4_shader = std::make_unique<SHADER>( );
145  x4_shader->Link();
146  checkGlError( "linking supersampling x4 shader" );
147 
148  GLint source_parameter = x4_shader->AddParameter( "source" ); checkGlError( "getting pass 1 colorTex" );
149 
150  x4_shader->Use(); checkGlError( "using pass 1 shader" );
151  x4_shader->SetParameter( source_parameter, 0 ); checkGlError( "setting colorTex uniform" );
152  x4_shader->Deactivate(); checkGlError( "deactivating pass 2 shader" );
153 
154  areShadersCreated = true;
155  }
156 
158  {
159  x4_shader.reset();
160  areShadersCreated = false;
161  }
162 
163  if( !areBuffersCreated )
164  {
166  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
167  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
168 
169  areBuffersCreated = true;
170  }
171 
172  return true;
173 }
174 
175 
177 {
178  unsigned int factor = ( mode == SUPERSAMPLING_MODE::X2 ) ? 2 : 4;
179  return compositor->GetScreenSize() * factor;
180 }
181 
182 
184 {
187 }
188 
189 
191 {
192  compositor->DrawBuffer( aBuffer, ssaaMainBuffer );
193 }
194 
195 
197 {
198  glDisable( GL_BLEND );
199  glDisable( GL_DEPTH_TEST );
200  glActiveTexture( GL_TEXTURE0 );
201  glBindTexture( GL_TEXTURE_2D, compositor->GetBufferTexture( ssaaMainBuffer ) );
203 
205  {
206  x4_shader->Use();
207  checkGlError( "activating supersampling x4 shader" );
208  }
209 
210  draw_fullscreen_primitive();
211 
213  {
214  x4_shader->Deactivate();
215  checkGlError( "deactivating supersampling x4 shader" );
216  }
217 }
218 
219 
221 {
222  areBuffersCreated = false;
223 }
224 
225 
227 {
229 }
230 
231 // ===============================
232 // ANTIALIASING_SMAA
233 // ===============================
234 
236  : areBuffersInitialized( false ), shadersLoaded( false ),
237  quality( aQuality ), compositor( aCompositor )
238 {
239  smaaBaseBuffer = 0;
240  smaaEdgesBuffer = 0;
241  smaaBlendBuffer = 0;
242  smaaAreaTex = 0;
243  smaaSearchTex = 0;
244 
245  pass_1_metrics = 0;
246  pass_2_metrics = 0;
247  pass_3_metrics = 0;
248 }
249 
250 
252 {
253  return compositor->GetScreenSize();
254 }
255 
256 
258 {
259  // Load constant textures
260  glEnable( GL_TEXTURE_2D );
261  glActiveTexture( GL_TEXTURE0 );
262 
263  glGenTextures( 1, &smaaAreaTex );
264  glBindTexture( GL_TEXTURE_2D, smaaAreaTex );
265  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
266  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
267  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
268  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
269  glTexImage2D( GL_TEXTURE_2D, 0, GL_RG8, AREATEX_WIDTH, AREATEX_HEIGHT, 0, GL_RG, GL_UNSIGNED_BYTE, areaTexBytes );
270  checkGlError( "loading smaa area tex" );
271 
272  glGenTextures( 1, &smaaSearchTex );
273  glBindTexture( GL_TEXTURE_2D, smaaSearchTex );
274  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
275  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
276  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
277  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
278  glTexImage2D( GL_TEXTURE_2D, 0, GL_R8, SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT, 0, GL_RED, GL_UNSIGNED_BYTE, searchTexBytes );
279  checkGlError( "loading smaa search tex" );
280 
281  std::string quality_string;
282 
283  if( quality == SMAA_QUALITY::HIGH )
284  {
285  quality_string = "#define SMAA_PRESET_HIGH\n";
286  }
287  else
288  {
289  quality_string = "#define SMAA_PRESET_ULTRA\n";
290  }
291 
292 
293  // set up shaders
294  std::string vert_preamble( R"SHADER(
295 #version 120
296 #define SMAA_GLSL_2_1
297 #define SMAA_INCLUDE_VS 1
298 #define SMAA_INCLUDE_PS 0
299 uniform vec4 SMAA_RT_METRICS;
300 )SHADER" );
301 
302  std::string frag_preamble( R"SHADER(
303 #version 120
304 #define SMAA_GLSL_2_1
305 #define SMAA_INCLUDE_VS 0
306 #define SMAA_INCLUDE_PS 1
307 uniform vec4 SMAA_RT_METRICS;
308 )SHADER" );
309 
310  std::string smaa_source =
312  + std::string( BUILTIN_SHADERS::smaa_base_shader_p2 )
313  + std::string( BUILTIN_SHADERS::smaa_base_shader_p3 )
314  + std::string( BUILTIN_SHADERS::smaa_base_shader_p4 );
315 
316  //
317  // Set up pass 1 Shader
318  //
319  pass_1_shader = std::make_unique<SHADER>( );
320  pass_1_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_VERTEX, vert_preamble,
321  quality_string, smaa_source, BUILTIN_SHADERS::smaa_pass_1_vertex_shader );
322  pass_1_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_FRAGMENT, frag_preamble,
323  quality_string, smaa_source, BUILTIN_SHADERS::smaa_pass_1_fragment_shader );
324  pass_1_shader->Link();
325  checkGlError( "linking pass 1 shader" );
326 
327  GLint smaaColorTexParameter = pass_1_shader->AddParameter( "colorTex" ); checkGlError( "pass1: getting colorTex uniform" );
328  pass_1_metrics = pass_1_shader->AddParameter( "SMAA_RT_METRICS" ); checkGlError( "pass1: getting metrics uniform" );
329 
330  pass_1_shader->Use(); checkGlError( "pass1: using shader" );
331  pass_1_shader->SetParameter( smaaColorTexParameter, 0 ); checkGlError( "pass1: setting colorTex uniform" );
332  pass_1_shader->Deactivate(); checkGlError( "pass1: deactivating shader" );
333 
334  //
335  // set up pass 2 shader
336  //
337  pass_2_shader = std::make_unique<SHADER>( );
338  pass_2_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_VERTEX, vert_preamble,
339  quality_string, smaa_source, BUILTIN_SHADERS::smaa_pass_2_vertex_shader );
340  pass_2_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_FRAGMENT, frag_preamble,
341  quality_string, smaa_source, BUILTIN_SHADERS::smaa_pass_2_fragment_shader );
342  pass_2_shader->Link();
343  checkGlError( "linking pass 2 shader" );
344 
345  GLint smaaEdgesTexParameter = pass_2_shader->AddParameter( "edgesTex" ); checkGlError( "pass2: getting colorTex uniform" );
346  GLint smaaAreaTexParameter = pass_2_shader->AddParameter( "areaTex" ); checkGlError( "pass2: getting areaTex uniform" );
347  GLint smaaSearchTexParameter = pass_2_shader->AddParameter( "searchTex" ); checkGlError( "pass2: getting searchTex uniform" );
348  pass_2_metrics = pass_2_shader->AddParameter( "SMAA_RT_METRICS" ); checkGlError( "pass2: getting metrics uniform" );
349 
350  pass_2_shader->Use(); checkGlError( "pass2: using shader" );
351  pass_2_shader->SetParameter( smaaEdgesTexParameter, 0 ); checkGlError( "pass2: setting colorTex uniform" );
352  pass_2_shader->SetParameter( smaaAreaTexParameter, 1 ); checkGlError( "pass2: setting areaTex uniform" );
353  pass_2_shader->SetParameter( smaaSearchTexParameter, 3 ); checkGlError( "pass2: setting searchTex uniform" );
354  pass_2_shader->Deactivate(); checkGlError( "pass2: deactivating shader" );
355 
356  //
357  // set up pass 3 shader
358  //
359  pass_3_shader = std::make_unique<SHADER>( );
360  pass_3_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_VERTEX, vert_preamble,
361  quality_string, smaa_source, BUILTIN_SHADERS::smaa_pass_3_vertex_shader );
362  pass_3_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_FRAGMENT, frag_preamble,
363  quality_string, smaa_source, BUILTIN_SHADERS::smaa_pass_3_fragment_shader );
364  pass_3_shader->Link();
365 
366  GLint smaaP3ColorTexParameter = pass_3_shader->AddParameter( "colorTex" ); checkGlError( "pass3: getting colorTex uniform" );
367  GLint smaaBlendTexParameter = pass_3_shader->AddParameter( "blendTex" ); checkGlError( "pass3: getting blendTex uniform" );
368  pass_3_metrics = pass_3_shader->AddParameter( "SMAA_RT_METRICS" ); checkGlError( "pass3: getting metrics uniform" );
369 
370  pass_3_shader->Use(); checkGlError( "pass3: using shader" );
371  pass_3_shader->SetParameter( smaaP3ColorTexParameter, 0 ); checkGlError( "pass3: setting colorTex uniform" );
372  pass_3_shader->SetParameter( smaaBlendTexParameter, 1 ); checkGlError( "pass3: setting blendTex uniform" );
373  pass_3_shader->Deactivate(); checkGlError( "pass3: deactivating shader" );
374 
375  shadersLoaded = true;
376 }
377 
378 
380 {
381  auto dims = compositor->GetScreenSize();
382 
383  pass_1_shader->Use(); checkGlError( "pass1: using shader" );
384  pass_1_shader->SetParameter( pass_1_metrics,
385  1.f / float( dims.x ), 1.f / float( dims.y ), float( dims.x ), float( dims.y ) ); checkGlError( "pass1: setting metrics uniform" );
386  pass_1_shader->Deactivate(); checkGlError( "pass1: deactivating shader" );
387 
388  pass_2_shader->Use(); checkGlError( "pass2: using shader" );
389  pass_2_shader->SetParameter( pass_2_metrics,
390  1.f / float( dims.x ), 1.f / float( dims.y ), float( dims.x ), float( dims.y ) ); checkGlError( "pass2: setting metrics uniform" );
391  pass_2_shader->Deactivate(); checkGlError( "pass2: deactivating shader" );
392 
393  pass_3_shader->Use(); checkGlError( "pass3: using shader" );
394  pass_3_shader->SetParameter( pass_3_metrics,
395  1.f / float( dims.x ), 1.f / float( dims.y ), float( dims.x ), float( dims.y ) ); checkGlError( "pass3: setting metrics uniform" );
396  pass_3_shader->Deactivate(); checkGlError( "pass3: deactivating shader" );
397 }
398 
399 
401 {
402  if( !shadersLoaded )
403  loadShaders();
404 
405  if( !areBuffersInitialized )
406  {
408  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
409  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
410 
412  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
413  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
414 
416  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
417  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
418 
419  updateUniforms();
420  areBuffersInitialized = true;
421  }
422 
423  // Nothing to initialize
424  return true;
425 }
426 
427 
429 {
430  areBuffersInitialized = false;
431 }
432 
433 
435 {
437 }
438 
439 
440 void ANTIALIASING_SMAA::DrawBuffer( GLuint buffer )
441 {
442  // draw to internal buffer
444 }
445 
446 
448 {
451 }
452 
453 
454 namespace {
455  void draw_fullscreen_triangle()
456  {
457  glMatrixMode( GL_MODELVIEW );
458  glPushMatrix();
459  glLoadIdentity();
460  glMatrixMode( GL_PROJECTION );
461  glPushMatrix();
462  glLoadIdentity();
463 
464  glBegin( GL_TRIANGLES );
465  glTexCoord2f( 0.0f, 1.0f );
466  glVertex2f( -1.0f, 1.0f );
467  glTexCoord2f( 0.0f, -1.0f );
468  glVertex2f( -1.0f, -3.0f );
469  glTexCoord2f( 2.0f, 1.0f );
470  glVertex2f( 3.0f, 1.0f );
471  glEnd();
472 
473  glPopMatrix();
474  glMatrixMode( GL_MODELVIEW );
475  glPopMatrix();
476  }
477 }
478 
479 
481 {
482  auto sourceTexture = compositor->GetBufferTexture( smaaBaseBuffer );
483 
484  glDisable( GL_BLEND );
485  glDisable( GL_DEPTH_TEST );
486  glEnable( GL_TEXTURE_2D );
487 
488  //
489  // pass 1: main-buffer -> smaaEdgesBuffer
490  //
493 
494  glActiveTexture( GL_TEXTURE0 );
495  glBindTexture( GL_TEXTURE_2D, sourceTexture ); checkGlError( "binding colorTex" );
496  pass_1_shader->Use(); checkGlError( "using smaa pass 1 shader" );
497  draw_fullscreen_triangle();
498  pass_1_shader->Deactivate();
499 
500  //
501  // pass 2: smaaEdgesBuffer -> smaaBlendBuffer
502  //
505 
506  auto edgesTex = compositor->GetBufferTexture( smaaEdgesBuffer );
507 
508  glActiveTexture( GL_TEXTURE0 );
509  glBindTexture( GL_TEXTURE_2D, edgesTex );
510  glActiveTexture( GL_TEXTURE1 );
511  glBindTexture( GL_TEXTURE_2D, smaaAreaTex );
512  glActiveTexture( GL_TEXTURE3 );
513  glBindTexture( GL_TEXTURE_2D, smaaSearchTex );
514 
515  pass_2_shader->Use();
516  draw_fullscreen_triangle();
517  pass_2_shader->Deactivate();
518 
519  //
520  // pass 3: colorTex + BlendBuffer -> output
521  //
524  auto blendTex = compositor->GetBufferTexture( smaaBlendBuffer );
525 
526  glActiveTexture( GL_TEXTURE0 );
527  glBindTexture( GL_TEXTURE_2D, sourceTexture );
528  glActiveTexture( GL_TEXTURE1 );
529  glBindTexture( GL_TEXTURE_2D, blendTex );
530 
531  pass_3_shader->Use();
532  draw_fullscreen_triangle();
533  pass_3_shader->Deactivate();
534 }
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: color4d.cpp:175
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:47
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
static const COLOR4D BLACK
Definition: color4d.h:376
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[]
void DrawBuffer(GLuint) override
const char smaa_pass_1_fragment_shader[]
#define SEARCHTEX_HEIGHT
Definition: SmaaSearchTex.h:34
virtual void ClearBuffer(const COLOR4D &aColor) override
Function ClearBuffer() clears the selected buffer (set by the SetBuffer() function).
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:46
virtual void SetBuffer(unsigned int aBufferHandle) override
Function SetBuffer() sets the selected buffer as the rendering target.
OPENGL_COMPOSITOR * compositor
Definition: antialiasing.h:95
std::unique_ptr< SHADER > pass_2_shader
Definition: antialiasing.h:144
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