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