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-2021 Kicad Developers, see AUTHORS.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 <glsl_smaa_base.h>
33#include <glsl_smaa_pass_1_frag_color.h>
34#include <glsl_smaa_pass_1_frag_luma.h>
35#include <glsl_smaa_pass_1_vert.h>
36#include <glsl_smaa_pass_2_frag.h>
37#include <glsl_smaa_pass_2_vert.h>
38#include <glsl_smaa_pass_3_frag.h>
39#include <glsl_smaa_pass_3_vert.h>
40#include "SmaaAreaTex.h"
41#include "SmaaSearchTex.h"
42
43using namespace KIGFX;
44
45// =========================
46// ANTIALIASING_NONE
47// =========================
48
49ANTIALIASING_NONE::ANTIALIASING_NONE( OPENGL_COMPOSITOR* aCompositor ) :
50 compositor( aCompositor )
51{
52}
53
54
56{
57 // Nothing to initialize
58 return true;
59}
60
61
63{
64 return compositor->GetScreenSize();
65}
66
67
68void ANTIALIASING_NONE::DrawBuffer( GLuint buffer )
69{
71}
72
73
75{
76 // Nothing to present, draw_buffer already drew to the screen
77}
78
79
81{
82 // Nothing to do
83}
84
85
87{
88 // Nothing to do
89}
90
91
93{
95}
96
97
98namespace
99{
100void draw_fullscreen_primitive()
101{
102 glMatrixMode( GL_MODELVIEW );
103 glPushMatrix();
104 glLoadIdentity();
105 glMatrixMode( GL_PROJECTION );
106 glPushMatrix();
107 glLoadIdentity();
108
109
110 glBegin( GL_TRIANGLES );
111 glTexCoord2f( 0.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, 1.0f );
116 glVertex2f( 1.0f, 1.0f );
117
118 glTexCoord2f( 1.0f, 1.0f );
119 glVertex2f( 1.0f, 1.0f );
120 glTexCoord2f( 0.0f, 0.0f );
121 glVertex2f( -1.0f, -1.0f );
122 glTexCoord2f( 1.0f, 0.0f );
123 glVertex2f( 1.0f, -1.0f );
124 glEnd();
125
126 glPopMatrix();
127 glMatrixMode( GL_MODELVIEW );
128 glPopMatrix();
129}
130
131} // namespace
132
133// =========================
134// ANTIALIASING_SUPERSAMPLING
135// =========================
136
138 compositor( aCompositor ),
139 ssaaMainBuffer( 0 ), areBuffersCreated( false ), areShadersCreated( false )
140{
141}
142
143
145{
146 areShadersCreated = false;
147
148 if( !areBuffersCreated )
149 {
151 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
152 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
153
154 areBuffersCreated = true;
155 }
156
157 return true;
158}
159
160
162{
163 return compositor->GetScreenSize() * 2;
164}
165
166
168{
171}
172
173
175{
177}
178
179
181{
182 glDisable( GL_BLEND );
183 glDisable( GL_DEPTH_TEST );
184 glActiveTexture( GL_TEXTURE0 );
185 glBindTexture( GL_TEXTURE_2D, compositor->GetBufferTexture( ssaaMainBuffer ) );
187
188 draw_fullscreen_primitive();
189}
190
191
193{
194 areBuffersCreated = false;
195}
196
197
199{
201}
202
203// ===============================
204// ANTIALIASING_SMAA
205// ===============================
206
208 areBuffersInitialized( false ),
209 shadersLoaded( false ),
210 compositor( aCompositor )
211{
212 smaaBaseBuffer = 0;
213 smaaEdgesBuffer = 0;
214 smaaBlendBuffer = 0;
215 smaaAreaTex = 0;
216 smaaSearchTex = 0;
217
218 pass_1_metrics = 0;
219 pass_2_metrics = 0;
220 pass_3_metrics = 0;
221}
222
223
225{
226 return compositor->GetScreenSize();
227}
228
229
231{
232 // Load constant textures
233 glEnable( GL_TEXTURE_2D );
234 glActiveTexture( GL_TEXTURE0 );
235
236 glGenTextures( 1, &smaaAreaTex );
237 glBindTexture( GL_TEXTURE_2D, smaaAreaTex );
238 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
239 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
240 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
241 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
242 glTexImage2D( GL_TEXTURE_2D, 0, GL_RG8, AREATEX_WIDTH, AREATEX_HEIGHT, 0, GL_RG,
243 GL_UNSIGNED_BYTE, areaTexBytes );
244 checkGlError( "loading smaa area tex", __FILE__, __LINE__ );
245
246 glGenTextures( 1, &smaaSearchTex );
247 glBindTexture( GL_TEXTURE_2D, smaaSearchTex );
248 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
249 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
250 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
251 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
252 glTexImage2D( GL_TEXTURE_2D, 0, GL_R8, SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT, 0, GL_RED,
253 GL_UNSIGNED_BYTE, searchTexBytes );
254 checkGlError( "loading smaa search tex", __FILE__, __LINE__ );
255
256 // Quality settings:
257 // THRESHOLD: intended to exclude spurious edges in photorealistic game graphics
258 // but in a high-contrast CAD application, all edges are intentional
259 // should be set fairly low, so user color choices do not affect antialiasing
260 // MAX_SEARCH_STEPS: steps of 2px, searched in H/V direction to discover true angle of edges
261 // improves AA for lines close H/V but creates fuzzyness at junctions
262 // MAX_SEARCH_STEPS_DIAG: steps of 1px, searched in diagonal direction
263 // improves lines close to 45deg but turns small circles into octagons
264 // CORNER_ROUNDING: SMAA can distinguish actual corners from aliasing jaggies,
265 // we want to preserve those as much as possible
266 // Edge Detection: In Eeschema, when a single pixel line changes color, edge detection using
267 // color is too aggressive and leads to a white spot at the transition point
268 std::string quality_string;
269 std::string edge_detect_shader;
270
271 // trades imperfect AA of shallow angles for a near artifact-free reproduction of fine features
272 // jaggies are smoothed over max 5px (original step + 2px in both directions)
273 quality_string = "#define SMAA_THRESHOLD 0.005\n"
274 "#define SMAA_MAX_SEARCH_STEPS 1\n"
275 "#define SMAA_MAX_SEARCH_STEPS_DIAG 2\n"
276 "#define SMAA_LOCAL_CONTRAST_ADAPTATION_FACTOR 1.5\n"
277 "#define SMAA_CORNER_ROUNDING 0\n";
278 edge_detect_shader = BUILTIN_SHADERS::glsl_smaa_pass_1_frag_luma;
279
280 // set up shaders
281 std::string vert_preamble( R"SHADER(
282#version 120
283#define SMAA_GLSL_2_1
284#define SMAA_INCLUDE_VS 1
285#define SMAA_INCLUDE_PS 0
286uniform vec4 SMAA_RT_METRICS;
287)SHADER" );
288
289 std::string frag_preamble( R"SHADER(
290#version 120
291#define SMAA_GLSL_2_1
292#define SMAA_INCLUDE_VS 0
293#define SMAA_INCLUDE_PS 1
294uniform vec4 SMAA_RT_METRICS;
295)SHADER" );
296
297 //
298 // Set up pass 1 Shader
299 //
300 pass_1_shader = std::make_unique<SHADER>();
301 pass_1_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_VERTEX, vert_preamble, quality_string,
302 BUILTIN_SHADERS::glsl_smaa_base,
303 BUILTIN_SHADERS::glsl_smaa_pass_1_vert );
304 pass_1_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_FRAGMENT, frag_preamble,
305 quality_string, BUILTIN_SHADERS::glsl_smaa_base, edge_detect_shader );
306 pass_1_shader->Link();
307 checkGlError( "linking pass 1 shader", __FILE__, __LINE__ );
308
309 GLint smaaColorTexParameter = pass_1_shader->AddParameter( "colorTex" );
310 checkGlError( "pass1: getting colorTex uniform", __FILE__, __LINE__ );
311 pass_1_metrics = pass_1_shader->AddParameter( "SMAA_RT_METRICS" );
312 checkGlError( "pass1: getting metrics uniform", __FILE__, __LINE__ );
313
314 pass_1_shader->Use();
315 checkGlError( "pass1: using shader", __FILE__, __LINE__ );
316 pass_1_shader->SetParameter( smaaColorTexParameter, 0 );
317 checkGlError( "pass1: setting colorTex uniform", __FILE__, __LINE__ );
318 pass_1_shader->Deactivate();
319 checkGlError( "pass1: deactivating shader", __FILE__, __LINE__ );
320
321 //
322 // set up pass 2 shader
323 //
324 pass_2_shader = std::make_unique<SHADER>();
325 pass_2_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_VERTEX, vert_preamble, quality_string,
326 BUILTIN_SHADERS::glsl_smaa_base,
327 BUILTIN_SHADERS::glsl_smaa_pass_2_vert );
328 pass_2_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_FRAGMENT, frag_preamble,
329 quality_string, BUILTIN_SHADERS::glsl_smaa_base,
330 BUILTIN_SHADERS::glsl_smaa_pass_2_frag );
331 pass_2_shader->Link();
332 checkGlError( "linking pass 2 shader", __FILE__, __LINE__ );
333
334 GLint smaaEdgesTexParameter = pass_2_shader->AddParameter( "edgesTex" );
335 checkGlError( "pass2: getting colorTex uniform", __FILE__, __LINE__ );
336 GLint smaaAreaTexParameter = pass_2_shader->AddParameter( "areaTex" );
337 checkGlError( "pass2: getting areaTex uniform", __FILE__, __LINE__ );
338 GLint smaaSearchTexParameter = pass_2_shader->AddParameter( "searchTex" );
339 checkGlError( "pass2: getting searchTex uniform", __FILE__, __LINE__ );
340 pass_2_metrics = pass_2_shader->AddParameter( "SMAA_RT_METRICS" );
341 checkGlError( "pass2: getting metrics uniform", __FILE__, __LINE__ );
342
343 pass_2_shader->Use();
344 checkGlError( "pass2: using shader", __FILE__, __LINE__ );
345 pass_2_shader->SetParameter( smaaEdgesTexParameter, 0 );
346 checkGlError( "pass2: setting colorTex uniform", __FILE__, __LINE__ );
347 pass_2_shader->SetParameter( smaaAreaTexParameter, 1 );
348 checkGlError( "pass2: setting areaTex uniform", __FILE__, __LINE__ );
349 pass_2_shader->SetParameter( smaaSearchTexParameter, 3 );
350 checkGlError( "pass2: setting searchTex uniform", __FILE__, __LINE__ );
351 pass_2_shader->Deactivate();
352 checkGlError( "pass2: deactivating shader", __FILE__, __LINE__ );
353
354 //
355 // set up pass 3 shader
356 //
357 pass_3_shader = std::make_unique<SHADER>();
358 pass_3_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_VERTEX, vert_preamble, quality_string,
359 BUILTIN_SHADERS::glsl_smaa_base,
360 BUILTIN_SHADERS::glsl_smaa_pass_3_vert );
361 pass_3_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_FRAGMENT, frag_preamble,
362 quality_string, BUILTIN_SHADERS::glsl_smaa_base,
363 BUILTIN_SHADERS::glsl_smaa_pass_3_frag );
364 pass_3_shader->Link();
365
366 GLint smaaP3ColorTexParameter = pass_3_shader->AddParameter( "colorTex" );
367 checkGlError( "pass3: getting colorTex uniform", __FILE__, __LINE__ );
368 GLint smaaBlendTexParameter = pass_3_shader->AddParameter( "blendTex" );
369 checkGlError( "pass3: getting blendTex uniform", __FILE__, __LINE__ );
370 pass_3_metrics = pass_3_shader->AddParameter( "SMAA_RT_METRICS" );
371 checkGlError( "pass3: getting metrics uniform", __FILE__, __LINE__ );
372
373 pass_3_shader->Use();
374 checkGlError( "pass3: using shader", __FILE__, __LINE__ );
375 pass_3_shader->SetParameter( smaaP3ColorTexParameter, 0 );
376 checkGlError( "pass3: setting colorTex uniform", __FILE__, __LINE__ );
377 pass_3_shader->SetParameter( smaaBlendTexParameter, 1 );
378 checkGlError( "pass3: setting blendTex uniform", __FILE__, __LINE__ );
379 pass_3_shader->Deactivate();
380 checkGlError( "pass3: deactivating shader", __FILE__, __LINE__ );
381
382 shadersLoaded = true;
383}
384
385
387{
388 auto dims = compositor->GetScreenSize();
389
390 pass_1_shader->Use();
391 checkGlError( "pass1: using shader", __FILE__, __LINE__ );
392 pass_1_shader->SetParameter( pass_1_metrics, 1.f / float( dims.x ), 1.f / float( dims.y ),
393 float( dims.x ), float( dims.y ) );
394 checkGlError( "pass1: setting metrics uniform", __FILE__, __LINE__ );
395 pass_1_shader->Deactivate();
396 checkGlError( "pass1: deactivating shader", __FILE__, __LINE__ );
397
398 pass_2_shader->Use();
399 checkGlError( "pass2: using shader", __FILE__, __LINE__ );
400 pass_2_shader->SetParameter( pass_2_metrics, 1.f / float( dims.x ), 1.f / float( dims.y ),
401 float( dims.x ), float( dims.y ) );
402 checkGlError( "pass2: setting metrics uniform", __FILE__, __LINE__ );
403 pass_2_shader->Deactivate();
404 checkGlError( "pass2: deactivating shader", __FILE__, __LINE__ );
405
406 pass_3_shader->Use();
407 checkGlError( "pass3: using shader", __FILE__, __LINE__ );
408 pass_3_shader->SetParameter( pass_3_metrics, 1.f / float( dims.x ), 1.f / float( dims.y ),
409 float( dims.x ), float( dims.y ) );
410 checkGlError( "pass3: setting metrics uniform", __FILE__, __LINE__ );
411 pass_3_shader->Deactivate();
412 checkGlError( "pass3: deactivating shader", __FILE__, __LINE__ );
413}
414
415
417{
418 if( !shadersLoaded )
419 loadShaders();
420
422 {
424 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
425 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
426
428 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
429 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
430
432 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
433 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
434
437 }
438
439 // Nothing to initialize
440 return true;
441}
442
443
445{
446 areBuffersInitialized = false;
447}
448
449
451{
453}
454
455
456void ANTIALIASING_SMAA::DrawBuffer( GLuint buffer )
457{
458 // draw to internal buffer
460}
461
462
464{
467}
468
469
470namespace
471{
472void draw_fullscreen_triangle()
473{
474 glMatrixMode( GL_MODELVIEW );
475 glPushMatrix();
476 glLoadIdentity();
477 glMatrixMode( GL_PROJECTION );
478 glPushMatrix();
479 glLoadIdentity();
480
481 glBegin( GL_TRIANGLES );
482 glTexCoord2f( 0.0f, 1.0f );
483 glVertex2f( -1.0f, 1.0f );
484 glTexCoord2f( 0.0f, -1.0f );
485 glVertex2f( -1.0f, -3.0f );
486 glTexCoord2f( 2.0f, 1.0f );
487 glVertex2f( 3.0f, 1.0f );
488 glEnd();
489
490 glPopMatrix();
491 glMatrixMode( GL_MODELVIEW );
492 glPopMatrix();
493}
494} // namespace
495
496
498{
499 auto sourceTexture = compositor->GetBufferTexture( smaaBaseBuffer );
500
501 glDisable( GL_BLEND );
502 glDisable( GL_DEPTH_TEST );
503 glEnable( GL_TEXTURE_2D );
504
505 //
506 // pass 1: main-buffer -> smaaEdgesBuffer
507 //
510
511 glActiveTexture( GL_TEXTURE0 );
512 glBindTexture( GL_TEXTURE_2D, sourceTexture );
513 checkGlError( "binding colorTex", __FILE__, __LINE__ );
514 pass_1_shader->Use();
515 checkGlError( "using smaa pass 1 shader", __FILE__, __LINE__ );
516 draw_fullscreen_triangle();
517 pass_1_shader->Deactivate();
518
519 //
520 // pass 2: smaaEdgesBuffer -> smaaBlendBuffer
521 //
524
525 auto edgesTex = compositor->GetBufferTexture( smaaEdgesBuffer );
526
527 glActiveTexture( GL_TEXTURE0 );
528 glBindTexture( GL_TEXTURE_2D, edgesTex );
529 glActiveTexture( GL_TEXTURE1 );
530 glBindTexture( GL_TEXTURE_2D, smaaAreaTex );
531 glActiveTexture( GL_TEXTURE3 );
532 glBindTexture( GL_TEXTURE_2D, smaaSearchTex );
533
534 pass_2_shader->Use();
535 draw_fullscreen_triangle();
536 pass_2_shader->Deactivate();
537
538 //
539 // pass 3: colorTex + BlendBuffer -> output
540 //
543 auto blendTex = compositor->GetBufferTexture( smaaBlendBuffer );
544
545 glActiveTexture( GL_TEXTURE0 );
546 glBindTexture( GL_TEXTURE_2D, sourceTexture );
547 glActiveTexture( GL_TEXTURE1 );
548 glBindTexture( GL_TEXTURE_2D, blendTex );
549
550 pass_3_shader->Use();
551 draw_fullscreen_triangle();
552 pass_3_shader->Deactivate();
553}
#define AREATEX_HEIGHT
Definition: SmaaAreaTex.h:34
const unsigned char areaTexBytes[]
Stored in R8G8 format.
Definition: SmaaAreaTex.h:43
#define AREATEX_WIDTH
Copyright (C) 2013 Jorge Jimenez ([email protected]) Copyright (C) 2013 Jose I.
Definition: SmaaAreaTex.h:33
#define SEARCHTEX_HEIGHT
Definition: SmaaSearchTex.h:34
static const unsigned char searchTexBytes[]
Stored in R8 format.
Definition: SmaaSearchTex.h:43
#define SEARCHTEX_WIDTH
Copyright (C) 2013 Jorge Jimenez ([email protected]) Copyright (C) 2013 Jose I.
Definition: SmaaSearchTex.h:33
void DrawBuffer(GLuint aBuffer) override
unsigned int CreateBuffer() override
void Present() override
OPENGL_COMPOSITOR * compositor
Definition: antialiasing.h:70
void OnLostBuffers() override
VECTOR2U GetInternalBufferSize() override
ANTIALIASING_SMAA(OPENGL_COMPOSITOR *aCompositor)
OPENGL_COMPOSITOR * compositor
Definition: antialiasing.h:138
unsigned int smaaEdgesBuffer
Definition: antialiasing.h:120
VECTOR2U GetInternalBufferSize() override
unsigned int smaaBaseBuffer
Definition: antialiasing.h:119
unsigned int smaaBlendBuffer
Definition: antialiasing.h:121
unsigned int smaaSearchTex
Definition: antialiasing.h:125
void DrawBuffer(GLuint buffer) override
std::unique_ptr< SHADER > pass_1_shader
Definition: antialiasing.h:129
void OnLostBuffers() override
std::unique_ptr< SHADER > pass_3_shader
Definition: antialiasing.h:135
std::unique_ptr< SHADER > pass_2_shader
Definition: antialiasing.h:132
unsigned int CreateBuffer() override
unsigned int CreateBuffer() override
VECTOR2U GetInternalBufferSize() override
void DrawBuffer(GLuint) override
OPENGL_COMPOSITOR * compositor
Definition: antialiasing.h:90
ANTIALIASING_SUPERSAMPLING(OPENGL_COMPOSITOR *aCompositor)
static const COLOR4D BLACK
Definition: color4d.h:394
static const unsigned int DIRECT_RENDERING
virtual void ClearBuffer(const COLOR4D &aColor) override
Clear the selected buffer (set by the SetBuffer() function).
virtual void DrawBuffer(unsigned int aBufferHandle) override
Draw the selected buffer to the output buffer.
GLenum GetBufferTexture(unsigned int aBufferHandle)
virtual void SetBuffer(unsigned int aBufferHandle) override
Set the selected buffer as the rendering target.
virtual unsigned int CreateBuffer() override
Prepare a new buffer that may be used as a rendering target.
The Cairo implementation of the graphics abstraction layer.
Definition: color4d.cpp:266
@ SHADER_TYPE_VERTEX
Vertex shader.
Definition: shader.h:46
@ SHADER_TYPE_FRAGMENT
Fragment shader.
Definition: shader.h:47
Handle multitarget rendering (ie.
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