KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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 The 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
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{
94 return compositor->CreateBuffer( compositor->GetScreenSize() );
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
142
143
145{
146 areShadersCreated = false;
147
148 if( !areBuffersCreated )
149 {
150 ssaaMainBuffer = compositor->CreateBuffer();
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{
169 compositor->SetBuffer( ssaaMainBuffer );
170 compositor->ClearBuffer( COLOR4D::BLACK );
171}
172
173
175{
176 compositor->DrawBuffer( aBuffer, ssaaMainBuffer );
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 glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE );
189
190 draw_fullscreen_primitive();
191
192 glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
193}
194
195
200
201
203{
204 return compositor->CreateBuffer( GetInternalBufferSize() );
205}
206
207// ===============================
208// ANTIALIASING_SMAA
209// ===============================
210
212 areBuffersInitialized( false ),
213 shadersLoaded( false ),
214 compositor( aCompositor )
215{
216 smaaBaseBuffer = 0;
217 smaaEdgesBuffer = 0;
218 smaaBlendBuffer = 0;
219 smaaAreaTex = 0;
220 smaaSearchTex = 0;
221
222 pass_1_metrics = 0;
223 pass_2_metrics = 0;
224 pass_3_metrics = 0;
225}
226
227
229{
230 return compositor->GetScreenSize();
231}
232
233
235{
236 // Load constant textures
237 glEnable( GL_TEXTURE_2D );
238 glActiveTexture( GL_TEXTURE0 );
239
240 glGenTextures( 1, &smaaAreaTex );
241 glBindTexture( GL_TEXTURE_2D, smaaAreaTex );
242 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
243 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
244 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
245 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
246 glTexImage2D( GL_TEXTURE_2D, 0, GL_RG8, AREATEX_WIDTH, AREATEX_HEIGHT, 0, GL_RG,
247 GL_UNSIGNED_BYTE, areaTexBytes );
248 checkGlError( "loading smaa area tex", __FILE__, __LINE__ );
249
250 glGenTextures( 1, &smaaSearchTex );
251 glBindTexture( GL_TEXTURE_2D, smaaSearchTex );
252 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
253 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
254 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
255 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
256 glTexImage2D( GL_TEXTURE_2D, 0, GL_R8, SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT, 0, GL_RED,
257 GL_UNSIGNED_BYTE, searchTexBytes );
258 checkGlError( "loading smaa search tex", __FILE__, __LINE__ );
259
260 // Quality settings:
261 // THRESHOLD: intended to exclude spurious edges in photorealistic game graphics
262 // but in a high-contrast CAD application, all edges are intentional
263 // should be set fairly low, so user color choices do not affect antialiasing
264 // MAX_SEARCH_STEPS: steps of 2px, searched in H/V direction to discover true angle of edges
265 // improves AA for lines close H/V but creates fuzzyness at junctions
266 // MAX_SEARCH_STEPS_DIAG: steps of 1px, searched in diagonal direction
267 // improves lines close to 45deg but turns small circles into octagons
268 // CORNER_ROUNDING: SMAA can distinguish actual corners from aliasing jaggies,
269 // we want to preserve those as much as possible
270 // Edge Detection: In Eeschema, when a single pixel line changes color, edge detection using
271 // color is too aggressive and leads to a white spot at the transition point
272 std::string quality_string;
273 std::string edge_detect_shader;
274
275 // trades imperfect AA of shallow angles for a near artifact-free reproduction of fine features
276 // jaggies are smoothed over max 5px (original step + 2px in both directions)
277 quality_string = "#define SMAA_THRESHOLD 0.005\n"
278 "#define SMAA_MAX_SEARCH_STEPS 1\n"
279 "#define SMAA_MAX_SEARCH_STEPS_DIAG 2\n"
280 "#define SMAA_LOCAL_CONTRAST_ADAPTATION_FACTOR 1.5\n"
281 "#define SMAA_CORNER_ROUNDING 0\n";
282 edge_detect_shader = BUILTIN_SHADERS::glsl_smaa_pass_1_frag_luma;
283
284 // set up shaders
285 std::string vert_preamble( R"SHADER(
286#version 120
287#define SMAA_GLSL_2_1
288#define SMAA_INCLUDE_VS 1
289#define SMAA_INCLUDE_PS 0
290uniform vec4 SMAA_RT_METRICS;
291)SHADER" );
292
293 std::string frag_preamble( R"SHADER(
294#version 120
295#define SMAA_GLSL_2_1
296#define SMAA_INCLUDE_VS 0
297#define SMAA_INCLUDE_PS 1
298uniform vec4 SMAA_RT_METRICS;
299)SHADER" );
300
301 //
302 // Set up pass 1 Shader
303 //
304 pass_1_shader = std::make_unique<SHADER>();
305 pass_1_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_VERTEX, vert_preamble, quality_string,
306 BUILTIN_SHADERS::glsl_smaa_base,
307 BUILTIN_SHADERS::glsl_smaa_pass_1_vert );
308 pass_1_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_FRAGMENT, frag_preamble,
309 quality_string, BUILTIN_SHADERS::glsl_smaa_base,
310 edge_detect_shader );
311 pass_1_shader->Link();
312 checkGlError( "linking pass 1 shader", __FILE__, __LINE__ );
313
314 GLint smaaColorTexParameter = pass_1_shader->AddParameter( "colorTex" );
315 checkGlError( "pass1: getting colorTex uniform", __FILE__, __LINE__ );
316 pass_1_metrics = pass_1_shader->AddParameter( "SMAA_RT_METRICS" );
317 checkGlError( "pass1: getting metrics uniform", __FILE__, __LINE__ );
318
319 pass_1_shader->Use();
320 checkGlError( "pass1: using shader", __FILE__, __LINE__ );
321 pass_1_shader->SetParameter( smaaColorTexParameter, 0 );
322 checkGlError( "pass1: setting colorTex uniform", __FILE__, __LINE__ );
323 pass_1_shader->Deactivate();
324 checkGlError( "pass1: deactivating shader", __FILE__, __LINE__ );
325
326 //
327 // set up pass 2 shader
328 //
329 pass_2_shader = std::make_unique<SHADER>();
330 pass_2_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_VERTEX, vert_preamble, quality_string,
331 BUILTIN_SHADERS::glsl_smaa_base,
332 BUILTIN_SHADERS::glsl_smaa_pass_2_vert );
333 pass_2_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_FRAGMENT, frag_preamble,
334 quality_string, BUILTIN_SHADERS::glsl_smaa_base,
335 BUILTIN_SHADERS::glsl_smaa_pass_2_frag );
336 pass_2_shader->Link();
337 checkGlError( "linking pass 2 shader", __FILE__, __LINE__ );
338
339 GLint smaaEdgesTexParameter = pass_2_shader->AddParameter( "edgesTex" );
340 checkGlError( "pass2: getting colorTex uniform", __FILE__, __LINE__ );
341 GLint smaaAreaTexParameter = pass_2_shader->AddParameter( "areaTex" );
342 checkGlError( "pass2: getting areaTex uniform", __FILE__, __LINE__ );
343 GLint smaaSearchTexParameter = pass_2_shader->AddParameter( "searchTex" );
344 checkGlError( "pass2: getting searchTex uniform", __FILE__, __LINE__ );
345 pass_2_metrics = pass_2_shader->AddParameter( "SMAA_RT_METRICS" );
346 checkGlError( "pass2: getting metrics uniform", __FILE__, __LINE__ );
347
348 pass_2_shader->Use();
349 checkGlError( "pass2: using shader", __FILE__, __LINE__ );
350 pass_2_shader->SetParameter( smaaEdgesTexParameter, 0 );
351 checkGlError( "pass2: setting colorTex uniform", __FILE__, __LINE__ );
352 pass_2_shader->SetParameter( smaaAreaTexParameter, 1 );
353 checkGlError( "pass2: setting areaTex uniform", __FILE__, __LINE__ );
354 pass_2_shader->SetParameter( smaaSearchTexParameter, 3 );
355 checkGlError( "pass2: setting searchTex uniform", __FILE__, __LINE__ );
356 pass_2_shader->Deactivate();
357 checkGlError( "pass2: deactivating shader", __FILE__, __LINE__ );
358
359 //
360 // set up pass 3 shader
361 //
362 pass_3_shader = std::make_unique<SHADER>();
363 pass_3_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_VERTEX, vert_preamble, quality_string,
364 BUILTIN_SHADERS::glsl_smaa_base,
365 BUILTIN_SHADERS::glsl_smaa_pass_3_vert );
366 pass_3_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_FRAGMENT, frag_preamble,
367 quality_string, BUILTIN_SHADERS::glsl_smaa_base,
368 BUILTIN_SHADERS::glsl_smaa_pass_3_frag );
369 pass_3_shader->Link();
370
371 GLint smaaP3ColorTexParameter = pass_3_shader->AddParameter( "colorTex" );
372 checkGlError( "pass3: getting colorTex uniform", __FILE__, __LINE__ );
373 GLint smaaBlendTexParameter = pass_3_shader->AddParameter( "blendTex" );
374 checkGlError( "pass3: getting blendTex uniform", __FILE__, __LINE__ );
375 pass_3_metrics = pass_3_shader->AddParameter( "SMAA_RT_METRICS" );
376 checkGlError( "pass3: getting metrics uniform", __FILE__, __LINE__ );
377
378 pass_3_shader->Use();
379 checkGlError( "pass3: using shader", __FILE__, __LINE__ );
380 pass_3_shader->SetParameter( smaaP3ColorTexParameter, 0 );
381 checkGlError( "pass3: setting colorTex uniform", __FILE__, __LINE__ );
382 pass_3_shader->SetParameter( smaaBlendTexParameter, 1 );
383 checkGlError( "pass3: setting blendTex uniform", __FILE__, __LINE__ );
384 pass_3_shader->Deactivate();
385 checkGlError( "pass3: deactivating shader", __FILE__, __LINE__ );
386
387 shadersLoaded = true;
388}
389
390
392{
393 auto dims = compositor->GetScreenSize();
394
395 pass_1_shader->Use();
396 checkGlError( "pass1: using shader", __FILE__, __LINE__ );
397 pass_1_shader->SetParameter( pass_1_metrics, 1.f / float( dims.x ), 1.f / float( dims.y ),
398 float( dims.x ), float( dims.y ) );
399 checkGlError( "pass1: setting metrics uniform", __FILE__, __LINE__ );
400 pass_1_shader->Deactivate();
401 checkGlError( "pass1: deactivating shader", __FILE__, __LINE__ );
402
403 pass_2_shader->Use();
404 checkGlError( "pass2: using shader", __FILE__, __LINE__ );
405 pass_2_shader->SetParameter( pass_2_metrics, 1.f / float( dims.x ), 1.f / float( dims.y ),
406 float( dims.x ), float( dims.y ) );
407 checkGlError( "pass2: setting metrics uniform", __FILE__, __LINE__ );
408 pass_2_shader->Deactivate();
409 checkGlError( "pass2: deactivating shader", __FILE__, __LINE__ );
410
411 pass_3_shader->Use();
412 checkGlError( "pass3: using shader", __FILE__, __LINE__ );
413 pass_3_shader->SetParameter( pass_3_metrics, 1.f / float( dims.x ), 1.f / float( dims.y ),
414 float( dims.x ), float( dims.y ) );
415 checkGlError( "pass3: setting metrics uniform", __FILE__, __LINE__ );
416 pass_3_shader->Deactivate();
417 checkGlError( "pass3: deactivating shader", __FILE__, __LINE__ );
418}
419
420
422{
423 if( !shadersLoaded )
424 loadShaders();
425
427 {
428 smaaBaseBuffer = compositor->CreateBuffer();
429 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
430 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
431
432 smaaEdgesBuffer = compositor->CreateBuffer();
433 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
434 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
435
436 smaaBlendBuffer = compositor->CreateBuffer();
437 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
438 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
439
442 }
443
444 // Nothing to initialize
445 return true;
446}
447
448
453
454
456{
457 return compositor->CreateBuffer( compositor->GetScreenSize() );
458}
459
460
461void ANTIALIASING_SMAA::DrawBuffer( GLuint buffer )
462{
463 // draw to internal buffer
464 compositor->DrawBuffer( buffer, smaaBaseBuffer );
465}
466
467
469{
470 compositor->SetBuffer( smaaBaseBuffer );
471 compositor->ClearBuffer( COLOR4D::BLACK );
472}
473
474
475namespace
476{
477void draw_fullscreen_triangle()
478{
479 glMatrixMode( GL_MODELVIEW );
480 glPushMatrix();
481 glLoadIdentity();
482 glMatrixMode( GL_PROJECTION );
483 glPushMatrix();
484 glLoadIdentity();
485
486 glBegin( GL_TRIANGLES );
487 glTexCoord2f( 0.0f, 1.0f );
488 glVertex2f( -1.0f, 1.0f );
489 glTexCoord2f( 0.0f, -1.0f );
490 glVertex2f( -1.0f, -3.0f );
491 glTexCoord2f( 2.0f, 1.0f );
492 glVertex2f( 3.0f, 1.0f );
493 glEnd();
494
495 glPopMatrix();
496 glMatrixMode( GL_MODELVIEW );
497 glPopMatrix();
498}
499} // namespace
500
501
503{
504 auto sourceTexture = compositor->GetBufferTexture( smaaBaseBuffer );
505
506 glDisable( GL_BLEND );
507 glDisable( GL_DEPTH_TEST );
508 glEnable( GL_TEXTURE_2D );
509
510 //
511 // pass 1: main-buffer -> smaaEdgesBuffer
512 //
513 compositor->SetBuffer( smaaEdgesBuffer );
514 compositor->ClearBuffer( COLOR4D::BLACK );
515
516 glActiveTexture( GL_TEXTURE0 );
517 glBindTexture( GL_TEXTURE_2D, sourceTexture );
518 checkGlError( "binding colorTex", __FILE__, __LINE__ );
519 pass_1_shader->Use();
520 checkGlError( "using smaa pass 1 shader", __FILE__, __LINE__ );
521 draw_fullscreen_triangle();
522 pass_1_shader->Deactivate();
523
524 //
525 // pass 2: smaaEdgesBuffer -> smaaBlendBuffer
526 //
527 compositor->SetBuffer( smaaBlendBuffer );
528 compositor->ClearBuffer( COLOR4D::BLACK );
529
530 auto edgesTex = compositor->GetBufferTexture( smaaEdgesBuffer );
531
532 glActiveTexture( GL_TEXTURE0 );
533 glBindTexture( GL_TEXTURE_2D, edgesTex );
534 glActiveTexture( GL_TEXTURE1 );
535 glBindTexture( GL_TEXTURE_2D, smaaAreaTex );
536 glActiveTexture( GL_TEXTURE3 );
537 glBindTexture( GL_TEXTURE_2D, smaaSearchTex );
538
539 pass_2_shader->Use();
540 draw_fullscreen_triangle();
541 pass_2_shader->Deactivate();
542
543 //
544 // pass 3: colorTex + BlendBuffer -> output
545 //
547 compositor->ClearBuffer( COLOR4D::BLACK );
548 auto blendTex = compositor->GetBufferTexture( smaaBlendBuffer );
549
550 glActiveTexture( GL_TEXTURE0 );
551 glBindTexture( GL_TEXTURE_2D, sourceTexture );
552 glActiveTexture( GL_TEXTURE1 );
553 glBindTexture( GL_TEXTURE_2D, blendTex );
554
555 glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE );
556
557 pass_3_shader->Use();
558 draw_fullscreen_triangle();
559 pass_3_shader->Deactivate();
560
561 glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
562}
#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
static const unsigned char searchTexBytes[]
Stored in R8 format.
#define SEARCHTEX_WIDTH
Copyright (C) 2013 Jorge Jimenez ([email protected]) Copyright (C) 2013 Jose I.
void DrawBuffer(GLuint aBuffer) override
unsigned int CreateBuffer() override
VECTOR2I GetInternalBufferSize() override
ANTIALIASING_NONE(OPENGL_COMPOSITOR *aCompositor)
OPENGL_COMPOSITOR * compositor
void OnLostBuffers() override
ANTIALIASING_SMAA(OPENGL_COMPOSITOR *aCompositor)
OPENGL_COMPOSITOR * compositor
void DrawBuffer(GLuint buffer) override
VECTOR2I GetInternalBufferSize() override
std::unique_ptr< SHADER > pass_1_shader
void OnLostBuffers() override
std::unique_ptr< SHADER > pass_3_shader
std::unique_ptr< SHADER > pass_2_shader
unsigned int CreateBuffer() override
VECTOR2I GetInternalBufferSize() override
unsigned int CreateBuffer() override
ANTIALIASING_SUPERSAMPLING(OPENGL_COMPOSITOR *aCompositor)
static const COLOR4D BLACK
Definition color4d.h:402
static const unsigned int DIRECT_RENDERING
The Cairo implementation of the graphics abstraction layer.
Definition eda_group.h:33
@ 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
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695