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 (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
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 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
197{
198 areBuffersCreated = false;
199}
200
201
203{
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, edge_detect_shader );
310 pass_1_shader->Link();
311 checkGlError( "linking pass 1 shader", __FILE__, __LINE__ );
312
313 GLint smaaColorTexParameter = pass_1_shader->AddParameter( "colorTex" );
314 checkGlError( "pass1: getting colorTex uniform", __FILE__, __LINE__ );
315 pass_1_metrics = pass_1_shader->AddParameter( "SMAA_RT_METRICS" );
316 checkGlError( "pass1: getting metrics uniform", __FILE__, __LINE__ );
317
318 pass_1_shader->Use();
319 checkGlError( "pass1: using shader", __FILE__, __LINE__ );
320 pass_1_shader->SetParameter( smaaColorTexParameter, 0 );
321 checkGlError( "pass1: setting colorTex uniform", __FILE__, __LINE__ );
322 pass_1_shader->Deactivate();
323 checkGlError( "pass1: deactivating shader", __FILE__, __LINE__ );
324
325 //
326 // set up pass 2 shader
327 //
328 pass_2_shader = std::make_unique<SHADER>();
329 pass_2_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_VERTEX, vert_preamble, quality_string,
330 BUILTIN_SHADERS::glsl_smaa_base,
331 BUILTIN_SHADERS::glsl_smaa_pass_2_vert );
332 pass_2_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_FRAGMENT, frag_preamble,
333 quality_string, BUILTIN_SHADERS::glsl_smaa_base,
334 BUILTIN_SHADERS::glsl_smaa_pass_2_frag );
335 pass_2_shader->Link();
336 checkGlError( "linking pass 2 shader", __FILE__, __LINE__ );
337
338 GLint smaaEdgesTexParameter = pass_2_shader->AddParameter( "edgesTex" );
339 checkGlError( "pass2: getting colorTex uniform", __FILE__, __LINE__ );
340 GLint smaaAreaTexParameter = pass_2_shader->AddParameter( "areaTex" );
341 checkGlError( "pass2: getting areaTex uniform", __FILE__, __LINE__ );
342 GLint smaaSearchTexParameter = pass_2_shader->AddParameter( "searchTex" );
343 checkGlError( "pass2: getting searchTex uniform", __FILE__, __LINE__ );
344 pass_2_metrics = pass_2_shader->AddParameter( "SMAA_RT_METRICS" );
345 checkGlError( "pass2: getting metrics uniform", __FILE__, __LINE__ );
346
347 pass_2_shader->Use();
348 checkGlError( "pass2: using shader", __FILE__, __LINE__ );
349 pass_2_shader->SetParameter( smaaEdgesTexParameter, 0 );
350 checkGlError( "pass2: setting colorTex uniform", __FILE__, __LINE__ );
351 pass_2_shader->SetParameter( smaaAreaTexParameter, 1 );
352 checkGlError( "pass2: setting areaTex uniform", __FILE__, __LINE__ );
353 pass_2_shader->SetParameter( smaaSearchTexParameter, 3 );
354 checkGlError( "pass2: setting searchTex uniform", __FILE__, __LINE__ );
355 pass_2_shader->Deactivate();
356 checkGlError( "pass2: deactivating shader", __FILE__, __LINE__ );
357
358 //
359 // set up pass 3 shader
360 //
361 pass_3_shader = std::make_unique<SHADER>();
362 pass_3_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_VERTEX, vert_preamble, quality_string,
363 BUILTIN_SHADERS::glsl_smaa_base,
364 BUILTIN_SHADERS::glsl_smaa_pass_3_vert );
365 pass_3_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_FRAGMENT, frag_preamble,
366 quality_string, BUILTIN_SHADERS::glsl_smaa_base,
367 BUILTIN_SHADERS::glsl_smaa_pass_3_frag );
368 pass_3_shader->Link();
369
370 GLint smaaP3ColorTexParameter = pass_3_shader->AddParameter( "colorTex" );
371 checkGlError( "pass3: getting colorTex uniform", __FILE__, __LINE__ );
372 GLint smaaBlendTexParameter = pass_3_shader->AddParameter( "blendTex" );
373 checkGlError( "pass3: getting blendTex uniform", __FILE__, __LINE__ );
374 pass_3_metrics = pass_3_shader->AddParameter( "SMAA_RT_METRICS" );
375 checkGlError( "pass3: getting metrics uniform", __FILE__, __LINE__ );
376
377 pass_3_shader->Use();
378 checkGlError( "pass3: using shader", __FILE__, __LINE__ );
379 pass_3_shader->SetParameter( smaaP3ColorTexParameter, 0 );
380 checkGlError( "pass3: setting colorTex uniform", __FILE__, __LINE__ );
381 pass_3_shader->SetParameter( smaaBlendTexParameter, 1 );
382 checkGlError( "pass3: setting blendTex uniform", __FILE__, __LINE__ );
383 pass_3_shader->Deactivate();
384 checkGlError( "pass3: deactivating shader", __FILE__, __LINE__ );
385
386 shadersLoaded = true;
387}
388
389
391{
392 auto dims = compositor->GetScreenSize();
393
394 pass_1_shader->Use();
395 checkGlError( "pass1: using shader", __FILE__, __LINE__ );
396 pass_1_shader->SetParameter( pass_1_metrics, 1.f / float( dims.x ), 1.f / float( dims.y ),
397 float( dims.x ), float( dims.y ) );
398 checkGlError( "pass1: setting metrics uniform", __FILE__, __LINE__ );
399 pass_1_shader->Deactivate();
400 checkGlError( "pass1: deactivating shader", __FILE__, __LINE__ );
401
402 pass_2_shader->Use();
403 checkGlError( "pass2: using shader", __FILE__, __LINE__ );
404 pass_2_shader->SetParameter( pass_2_metrics, 1.f / float( dims.x ), 1.f / float( dims.y ),
405 float( dims.x ), float( dims.y ) );
406 checkGlError( "pass2: setting metrics uniform", __FILE__, __LINE__ );
407 pass_2_shader->Deactivate();
408 checkGlError( "pass2: deactivating shader", __FILE__, __LINE__ );
409
410 pass_3_shader->Use();
411 checkGlError( "pass3: using shader", __FILE__, __LINE__ );
412 pass_3_shader->SetParameter( pass_3_metrics, 1.f / float( dims.x ), 1.f / float( dims.y ),
413 float( dims.x ), float( dims.y ) );
414 checkGlError( "pass3: setting metrics uniform", __FILE__, __LINE__ );
415 pass_3_shader->Deactivate();
416 checkGlError( "pass3: deactivating shader", __FILE__, __LINE__ );
417}
418
419
421{
422 if( !shadersLoaded )
423 loadShaders();
424
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
436 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
437 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
438
441 }
442
443 // Nothing to initialize
444 return true;
445}
446
447
449{
450 areBuffersInitialized = false;
451}
452
453
455{
457}
458
459
460void ANTIALIASING_SMAA::DrawBuffer( GLuint buffer )
461{
462 // draw to internal buffer
464}
465
466
468{
471}
472
473
474namespace
475{
476void draw_fullscreen_triangle()
477{
478 glMatrixMode( GL_MODELVIEW );
479 glPushMatrix();
480 glLoadIdentity();
481 glMatrixMode( GL_PROJECTION );
482 glPushMatrix();
483 glLoadIdentity();
484
485 glBegin( GL_TRIANGLES );
486 glTexCoord2f( 0.0f, 1.0f );
487 glVertex2f( -1.0f, 1.0f );
488 glTexCoord2f( 0.0f, -1.0f );
489 glVertex2f( -1.0f, -3.0f );
490 glTexCoord2f( 2.0f, 1.0f );
491 glVertex2f( 3.0f, 1.0f );
492 glEnd();
493
494 glPopMatrix();
495 glMatrixMode( GL_MODELVIEW );
496 glPopMatrix();
497}
498} // namespace
499
500
502{
503 auto sourceTexture = compositor->GetBufferTexture( smaaBaseBuffer );
504
505 glDisable( GL_BLEND );
506 glDisable( GL_DEPTH_TEST );
507 glEnable( GL_TEXTURE_2D );
508
509 //
510 // pass 1: main-buffer -> smaaEdgesBuffer
511 //
514
515 glActiveTexture( GL_TEXTURE0 );
516 glBindTexture( GL_TEXTURE_2D, sourceTexture );
517 checkGlError( "binding colorTex", __FILE__, __LINE__ );
518 pass_1_shader->Use();
519 checkGlError( "using smaa pass 1 shader", __FILE__, __LINE__ );
520 draw_fullscreen_triangle();
521 pass_1_shader->Deactivate();
522
523 //
524 // pass 2: smaaEdgesBuffer -> smaaBlendBuffer
525 //
528
529 auto edgesTex = compositor->GetBufferTexture( smaaEdgesBuffer );
530
531 glActiveTexture( GL_TEXTURE0 );
532 glBindTexture( GL_TEXTURE_2D, edgesTex );
533 glActiveTexture( GL_TEXTURE1 );
534 glBindTexture( GL_TEXTURE_2D, smaaAreaTex );
535 glActiveTexture( GL_TEXTURE3 );
536 glBindTexture( GL_TEXTURE_2D, smaaSearchTex );
537
538 pass_2_shader->Use();
539 draw_fullscreen_triangle();
540 pass_2_shader->Deactivate();
541
542 //
543 // pass 3: colorTex + BlendBuffer -> output
544 //
547 auto blendTex = compositor->GetBufferTexture( smaaBlendBuffer );
548
549 glActiveTexture( GL_TEXTURE0 );
550 glBindTexture( GL_TEXTURE_2D, sourceTexture );
551 glActiveTexture( GL_TEXTURE1 );
552 glBindTexture( GL_TEXTURE_2D, blendTex );
553
554 glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE );
555
556 pass_3_shader->Use();
557 draw_fullscreen_triangle();
558 pass_3_shader->Deactivate();
559
560 glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
561}
#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
VECTOR2I GetInternalBufferSize() override
ANTIALIASING_NONE(OPENGL_COMPOSITOR *aCompositor)
void Present() override
OPENGL_COMPOSITOR * compositor
Definition: antialiasing.h:70
void OnLostBuffers() override
ANTIALIASING_SMAA(OPENGL_COMPOSITOR *aCompositor)
OPENGL_COMPOSITOR * compositor
Definition: antialiasing.h:138
unsigned int smaaEdgesBuffer
Definition: antialiasing.h:120
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
VECTOR2I GetInternalBufferSize() 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
VECTOR2I GetInternalBufferSize() override
unsigned int CreateBuffer() override
void DrawBuffer(GLuint) override
OPENGL_COMPOSITOR * compositor
Definition: antialiasing.h:90
ANTIALIASING_SUPERSAMPLING(OPENGL_COMPOSITOR *aCompositor)
static const COLOR4D BLACK
Definition: color4d.h:402
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:247
@ 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