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, see <https://www.gnu.org/licenses/>.
18 */
19
22#include <gal/opengl/utils.h>
23#include <gal/color4d.h>
24
25#include <memory>
26#include <tuple>
27
28#include <glsl_smaa_base.h>
29#include <glsl_smaa_pass_1_frag_color.h>
30#include <glsl_smaa_pass_1_frag_luma.h>
31#include <glsl_smaa_pass_1_vert.h>
32#include <glsl_smaa_pass_2_frag.h>
33#include <glsl_smaa_pass_2_vert.h>
34#include <glsl_smaa_pass_3_frag.h>
35#include <glsl_smaa_pass_3_vert.h>
36#include "SmaaAreaTex.h"
37#include "SmaaSearchTex.h"
38
39using namespace KIGFX;
40
41// =========================
42// ANTIALIASING_NONE
43// =========================
44
46 compositor( aCompositor )
47{
48}
49
50
52{
53 // Nothing to initialize
54 return true;
55}
56
57
59{
60 return compositor->GetScreenSize();
61}
62
63
64void ANTIALIASING_NONE::DrawBuffer( GLuint buffer )
65{
67}
68
69
71{
72 // Nothing to present, draw_buffer already drew to the screen
73}
74
75
77{
78 // Nothing to do
79}
80
81
83{
84 // Nothing to do
85}
86
87
89{
90 return compositor->CreateBuffer( compositor->GetScreenSize() );
91}
92
93
94namespace
95{
96void draw_fullscreen_primitive()
97{
98 glMatrixMode( GL_MODELVIEW );
99 glPushMatrix();
100 glLoadIdentity();
101 glMatrixMode( GL_PROJECTION );
102 glPushMatrix();
103 glLoadIdentity();
104
105
106 glBegin( GL_TRIANGLES );
107 glTexCoord2f( 0.0f, 1.0f );
108 glVertex2f( -1.0f, 1.0f );
109 glTexCoord2f( 0.0f, 0.0f );
110 glVertex2f( -1.0f, -1.0f );
111 glTexCoord2f( 1.0f, 1.0f );
112 glVertex2f( 1.0f, 1.0f );
113
114 glTexCoord2f( 1.0f, 1.0f );
115 glVertex2f( 1.0f, 1.0f );
116 glTexCoord2f( 0.0f, 0.0f );
117 glVertex2f( -1.0f, -1.0f );
118 glTexCoord2f( 1.0f, 0.0f );
119 glVertex2f( 1.0f, -1.0f );
120 glEnd();
121
122 glPopMatrix();
123 glMatrixMode( GL_MODELVIEW );
124 glPopMatrix();
125}
126
127} // namespace
128
129// =========================
130// ANTIALIASING_SUPERSAMPLING
131// =========================
132
138
139
141{
142 areShadersCreated = false;
143
144 if( !areBuffersCreated )
145 {
146 ssaaMainBuffer = compositor->CreateBuffer();
147 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
148 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
149
150 areBuffersCreated = true;
151 }
152
153 return true;
154}
155
156
158{
159 return compositor->GetScreenSize() * 2;
160}
161
162
164{
165 compositor->SetBuffer( ssaaMainBuffer );
166 compositor->ClearBuffer( COLOR4D::BLACK );
167}
168
169
171{
172 compositor->DrawBuffer( aBuffer, ssaaMainBuffer );
173}
174
175
177{
178 glDisable( GL_BLEND );
179 glDisable( GL_DEPTH_TEST );
180 glActiveTexture( GL_TEXTURE0 );
181 glBindTexture( GL_TEXTURE_2D, compositor->GetBufferTexture( ssaaMainBuffer ) );
183
184 glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE );
185
186 draw_fullscreen_primitive();
187
188 glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
189}
190
191
196
197
199{
200 return compositor->CreateBuffer( GetInternalBufferSize() );
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,
306 edge_detect_shader );
307 pass_1_shader->Link();
308 checkGlError( "linking pass 1 shader", __FILE__, __LINE__ );
309
310 GLint smaaColorTexParameter = pass_1_shader->AddParameter( "colorTex" );
311 checkGlError( "pass1: getting colorTex uniform", __FILE__, __LINE__ );
312 pass_1_metrics = pass_1_shader->AddParameter( "SMAA_RT_METRICS" );
313 checkGlError( "pass1: getting metrics uniform", __FILE__, __LINE__ );
314
315 pass_1_shader->Use();
316 checkGlError( "pass1: using shader", __FILE__, __LINE__ );
317 pass_1_shader->SetParameter( smaaColorTexParameter, 0 );
318 checkGlError( "pass1: setting colorTex uniform", __FILE__, __LINE__ );
319 pass_1_shader->Deactivate();
320 checkGlError( "pass1: deactivating shader", __FILE__, __LINE__ );
321
322 //
323 // set up pass 2 shader
324 //
325 pass_2_shader = std::make_unique<SHADER>();
326 pass_2_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_VERTEX, vert_preamble, quality_string,
327 BUILTIN_SHADERS::glsl_smaa_base,
328 BUILTIN_SHADERS::glsl_smaa_pass_2_vert );
329 pass_2_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_FRAGMENT, frag_preamble,
330 quality_string, BUILTIN_SHADERS::glsl_smaa_base,
331 BUILTIN_SHADERS::glsl_smaa_pass_2_frag );
332 pass_2_shader->Link();
333 checkGlError( "linking pass 2 shader", __FILE__, __LINE__ );
334
335 GLint smaaEdgesTexParameter = pass_2_shader->AddParameter( "edgesTex" );
336 checkGlError( "pass2: getting colorTex uniform", __FILE__, __LINE__ );
337 GLint smaaAreaTexParameter = pass_2_shader->AddParameter( "areaTex" );
338 checkGlError( "pass2: getting areaTex uniform", __FILE__, __LINE__ );
339 GLint smaaSearchTexParameter = pass_2_shader->AddParameter( "searchTex" );
340 checkGlError( "pass2: getting searchTex uniform", __FILE__, __LINE__ );
341 pass_2_metrics = pass_2_shader->AddParameter( "SMAA_RT_METRICS" );
342 checkGlError( "pass2: getting metrics uniform", __FILE__, __LINE__ );
343
344 pass_2_shader->Use();
345 checkGlError( "pass2: using shader", __FILE__, __LINE__ );
346 pass_2_shader->SetParameter( smaaEdgesTexParameter, 0 );
347 checkGlError( "pass2: setting colorTex uniform", __FILE__, __LINE__ );
348 pass_2_shader->SetParameter( smaaAreaTexParameter, 1 );
349 checkGlError( "pass2: setting areaTex uniform", __FILE__, __LINE__ );
350 pass_2_shader->SetParameter( smaaSearchTexParameter, 3 );
351 checkGlError( "pass2: setting searchTex uniform", __FILE__, __LINE__ );
352 pass_2_shader->Deactivate();
353 checkGlError( "pass2: deactivating shader", __FILE__, __LINE__ );
354
355 //
356 // set up pass 3 shader
357 //
358 pass_3_shader = std::make_unique<SHADER>();
359 pass_3_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_VERTEX, vert_preamble, quality_string,
360 BUILTIN_SHADERS::glsl_smaa_base,
361 BUILTIN_SHADERS::glsl_smaa_pass_3_vert );
362 pass_3_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_FRAGMENT, frag_preamble,
363 quality_string, BUILTIN_SHADERS::glsl_smaa_base,
364 BUILTIN_SHADERS::glsl_smaa_pass_3_frag );
365 pass_3_shader->Link();
366
367 GLint smaaP3ColorTexParameter = pass_3_shader->AddParameter( "colorTex" );
368 checkGlError( "pass3: getting colorTex uniform", __FILE__, __LINE__ );
369 GLint smaaBlendTexParameter = pass_3_shader->AddParameter( "blendTex" );
370 checkGlError( "pass3: getting blendTex uniform", __FILE__, __LINE__ );
371 pass_3_metrics = pass_3_shader->AddParameter( "SMAA_RT_METRICS" );
372 checkGlError( "pass3: getting metrics uniform", __FILE__, __LINE__ );
373
374 pass_3_shader->Use();
375 checkGlError( "pass3: using shader", __FILE__, __LINE__ );
376 pass_3_shader->SetParameter( smaaP3ColorTexParameter, 0 );
377 checkGlError( "pass3: setting colorTex uniform", __FILE__, __LINE__ );
378 pass_3_shader->SetParameter( smaaBlendTexParameter, 1 );
379 checkGlError( "pass3: setting blendTex uniform", __FILE__, __LINE__ );
380 pass_3_shader->Deactivate();
381 checkGlError( "pass3: deactivating shader", __FILE__, __LINE__ );
382
383 shadersLoaded = true;
384}
385
386
388{
389 auto dims = compositor->GetScreenSize();
390
391 pass_1_shader->Use();
392 checkGlError( "pass1: using shader", __FILE__, __LINE__ );
393 pass_1_shader->SetParameter( pass_1_metrics, 1.f / float( dims.x ), 1.f / float( dims.y ),
394 float( dims.x ), float( dims.y ) );
395 checkGlError( "pass1: setting metrics uniform", __FILE__, __LINE__ );
396 pass_1_shader->Deactivate();
397 checkGlError( "pass1: deactivating shader", __FILE__, __LINE__ );
398
399 pass_2_shader->Use();
400 checkGlError( "pass2: using shader", __FILE__, __LINE__ );
401 pass_2_shader->SetParameter( pass_2_metrics, 1.f / float( dims.x ), 1.f / float( dims.y ),
402 float( dims.x ), float( dims.y ) );
403 checkGlError( "pass2: setting metrics uniform", __FILE__, __LINE__ );
404 pass_2_shader->Deactivate();
405 checkGlError( "pass2: deactivating shader", __FILE__, __LINE__ );
406
407 pass_3_shader->Use();
408 checkGlError( "pass3: using shader", __FILE__, __LINE__ );
409 pass_3_shader->SetParameter( pass_3_metrics, 1.f / float( dims.x ), 1.f / float( dims.y ),
410 float( dims.x ), float( dims.y ) );
411 checkGlError( "pass3: setting metrics uniform", __FILE__, __LINE__ );
412 pass_3_shader->Deactivate();
413 checkGlError( "pass3: deactivating shader", __FILE__, __LINE__ );
414}
415
416
418{
419 if( !shadersLoaded )
420 loadShaders();
421
423 {
424 smaaBaseBuffer = compositor->CreateBuffer();
425 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
426 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
427
428 smaaEdgesBuffer = 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 smaaBlendBuffer = 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
438 }
439
440 // Nothing to initialize
441 return true;
442}
443
444
449
450
452{
453 return compositor->CreateBuffer( compositor->GetScreenSize() );
454}
455
456
457void ANTIALIASING_SMAA::DrawBuffer( GLuint buffer )
458{
459 // draw to internal buffer
460 compositor->DrawBuffer( buffer, smaaBaseBuffer );
461}
462
463
465{
466 compositor->SetBuffer( smaaBaseBuffer );
467 compositor->ClearBuffer( COLOR4D::BLACK );
468}
469
470
471namespace
472{
473void draw_fullscreen_triangle()
474{
475 glMatrixMode( GL_MODELVIEW );
476 glPushMatrix();
477 glLoadIdentity();
478 glMatrixMode( GL_PROJECTION );
479 glPushMatrix();
480 glLoadIdentity();
481
482 glBegin( GL_TRIANGLES );
483 glTexCoord2f( 0.0f, 1.0f );
484 glVertex2f( -1.0f, 1.0f );
485 glTexCoord2f( 0.0f, -1.0f );
486 glVertex2f( -1.0f, -3.0f );
487 glTexCoord2f( 2.0f, 1.0f );
488 glVertex2f( 3.0f, 1.0f );
489 glEnd();
490
491 glPopMatrix();
492 glMatrixMode( GL_MODELVIEW );
493 glPopMatrix();
494}
495} // namespace
496
497
499{
500 auto sourceTexture = compositor->GetBufferTexture( smaaBaseBuffer );
501
502 glDisable( GL_BLEND );
503 glDisable( GL_DEPTH_TEST );
504 glEnable( GL_TEXTURE_2D );
505
506 //
507 // pass 1: main-buffer -> smaaEdgesBuffer
508 //
509 compositor->SetBuffer( smaaEdgesBuffer );
510 compositor->ClearBuffer( COLOR4D::BLACK );
511
512 glActiveTexture( GL_TEXTURE0 );
513 glBindTexture( GL_TEXTURE_2D, sourceTexture );
514 checkGlError( "binding colorTex", __FILE__, __LINE__ );
515 pass_1_shader->Use();
516 checkGlError( "using smaa pass 1 shader", __FILE__, __LINE__ );
517 draw_fullscreen_triangle();
518 pass_1_shader->Deactivate();
519
520 //
521 // pass 2: smaaEdgesBuffer -> smaaBlendBuffer
522 //
523 compositor->SetBuffer( smaaBlendBuffer );
524 compositor->ClearBuffer( COLOR4D::BLACK );
525
526 auto edgesTex = compositor->GetBufferTexture( smaaEdgesBuffer );
527
528 glActiveTexture( GL_TEXTURE0 );
529 glBindTexture( GL_TEXTURE_2D, edgesTex );
530 glActiveTexture( GL_TEXTURE1 );
531 glBindTexture( GL_TEXTURE_2D, smaaAreaTex );
532 glActiveTexture( GL_TEXTURE3 );
533 glBindTexture( GL_TEXTURE_2D, smaaSearchTex );
534
535 pass_2_shader->Use();
536 draw_fullscreen_triangle();
537 pass_2_shader->Deactivate();
538
539 //
540 // pass 3: colorTex + BlendBuffer -> output
541 //
543 compositor->ClearBuffer( COLOR4D::BLACK );
544 auto blendTex = compositor->GetBufferTexture( smaaBlendBuffer );
545
546 glActiveTexture( GL_TEXTURE0 );
547 glBindTexture( GL_TEXTURE_2D, sourceTexture );
548 glActiveTexture( GL_TEXTURE1 );
549 glBindTexture( GL_TEXTURE_2D, blendTex );
550
551 glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE );
552
553 pass_3_shader->Use();
554 draw_fullscreen_triangle();
555 pass_3_shader->Deactivate();
556
557 glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
558}
#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:29
@ SHADER_TYPE_VERTEX
Vertex shader.
Definition shader.h:42
@ SHADER_TYPE_FRAGMENT
Fragment shader.
Definition shader.h:43
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:44
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683