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{
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,
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 {
429 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
430 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
431
433 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
434 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
435
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
450{
451 areBuffersInitialized = false;
452}
453
454
456{
458}
459
460
461void ANTIALIASING_SMAA::DrawBuffer( GLuint buffer )
462{
463 // draw to internal buffer
465}
466
467
469{
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 //
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 //
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 //
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
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