You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

534 lines
18 KiB

  1. /*
  2. * This program source code file is part of KICAD, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2016 Kicad Developers, see change_log.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. #include <gal/opengl/antialiasing.h>
  24. #include <gal/opengl/opengl_compositor.h>
  25. #include <gal/opengl/utils.h>
  26. #include <gal/color4d.h>
  27. #include <memory>
  28. #include <tuple>
  29. #include "gl_builtin_shaders.h"
  30. #include "SmaaAreaTex.h"
  31. #include "SmaaSearchTex.h"
  32. using namespace KIGFX;
  33. // =========================
  34. // ANTIALIASING_NONE
  35. // =========================
  36. ANTIALIASING_NONE::ANTIALIASING_NONE( OPENGL_COMPOSITOR* aCompositor )
  37. : compositor( aCompositor )
  38. {
  39. }
  40. bool ANTIALIASING_NONE::Init()
  41. {
  42. // Nothing to initialize
  43. return true;
  44. }
  45. VECTOR2U ANTIALIASING_NONE::GetInternalBufferSize()
  46. {
  47. return compositor->GetScreenSize();
  48. }
  49. void ANTIALIASING_NONE::DrawBuffer( GLuint buffer )
  50. {
  51. compositor->DrawBuffer( buffer, OPENGL_COMPOSITOR::DIRECT_RENDERING );
  52. }
  53. void ANTIALIASING_NONE::Present()
  54. {
  55. // Nothing to present, draw_buffer already drew to the screen
  56. }
  57. void ANTIALIASING_NONE::OnLostBuffers()
  58. {
  59. // Nothing to do
  60. }
  61. void ANTIALIASING_NONE::Begin()
  62. {
  63. // Nothing to do
  64. }
  65. unsigned int ANTIALIASING_NONE::CreateBuffer()
  66. {
  67. return compositor->CreateBuffer( compositor->GetScreenSize() );
  68. }
  69. namespace {
  70. void draw_fullscreen_primitive()
  71. {
  72. glMatrixMode( GL_MODELVIEW );
  73. glPushMatrix();
  74. glLoadIdentity();
  75. glMatrixMode( GL_PROJECTION );
  76. glPushMatrix();
  77. glLoadIdentity();
  78. glBegin( GL_TRIANGLES );
  79. glTexCoord2f( 0.0f, 1.0f );
  80. glVertex2f( -1.0f, 1.0f );
  81. glTexCoord2f( 0.0f, 0.0f );
  82. glVertex2f( -1.0f, -1.0f );
  83. glTexCoord2f( 1.0f, 1.0f );
  84. glVertex2f( 1.0f, 1.0f );
  85. glTexCoord2f( 1.0f, 1.0f );
  86. glVertex2f( 1.0f, 1.0f );
  87. glTexCoord2f( 0.0f, 0.0f );
  88. glVertex2f( -1.0f, -1.0f );
  89. glTexCoord2f( 1.0f, 0.0f );
  90. glVertex2f( 1.0f, -1.0f );
  91. glEnd();
  92. glPopMatrix();
  93. glMatrixMode( GL_MODELVIEW );
  94. glPopMatrix();
  95. }
  96. }
  97. // =========================
  98. // ANTIALIASING_SUPERSAMPLING
  99. // =========================
  100. ANTIALIASING_SUPERSAMPLING::ANTIALIASING_SUPERSAMPLING( OPENGL_COMPOSITOR* aCompositor,
  101. SUPERSAMPLING_MODE aMode )
  102. : compositor( aCompositor ), mode( aMode ), ssaaMainBuffer( 0 ),
  103. areBuffersCreated( false ), areShadersCreated( false )
  104. {
  105. }
  106. bool ANTIALIASING_SUPERSAMPLING::Init()
  107. {
  108. if( mode == SUPERSAMPLING_MODE::X4 && !areShadersCreated )
  109. {
  110. x4_shader = std::make_unique<SHADER>( );
  111. x4_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_VERTEX, BUILTIN_SHADERS::ssaa_x4_vertex_shader );
  112. x4_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_FRAGMENT, BUILTIN_SHADERS::ssaa_x4_fragment_shader );
  113. x4_shader->Link();
  114. checkGlError( "linking supersampling x4 shader" );
  115. GLint source_parameter = x4_shader->AddParameter( "source" ); checkGlError( "getting pass 1 colorTex" );
  116. x4_shader->Use(); checkGlError( "using pass 1 shader" );
  117. x4_shader->SetParameter( source_parameter, 0 ); checkGlError( "setting colorTex uniform" );
  118. x4_shader->Deactivate(); checkGlError( "deactivating pass 2 shader" );
  119. areShadersCreated = true;
  120. }
  121. if( areShadersCreated && mode != SUPERSAMPLING_MODE::X4 )
  122. {
  123. x4_shader.reset();
  124. areShadersCreated = false;
  125. }
  126. if( !areBuffersCreated )
  127. {
  128. ssaaMainBuffer = compositor->CreateBuffer();
  129. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  130. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
  131. areBuffersCreated = true;
  132. }
  133. return true;
  134. }
  135. VECTOR2U ANTIALIASING_SUPERSAMPLING::GetInternalBufferSize()
  136. {
  137. unsigned int factor = ( mode == SUPERSAMPLING_MODE::X2 ) ? 2 : 4;
  138. return compositor->GetScreenSize() * factor;
  139. }
  140. void ANTIALIASING_SUPERSAMPLING::Begin()
  141. {
  142. compositor->SetBuffer( ssaaMainBuffer );
  143. compositor->ClearBuffer( COLOR4D::BLACK );
  144. }
  145. void ANTIALIASING_SUPERSAMPLING::DrawBuffer( GLuint aBuffer )
  146. {
  147. compositor->DrawBuffer( aBuffer, ssaaMainBuffer );
  148. }
  149. void ANTIALIASING_SUPERSAMPLING::Present()
  150. {
  151. glDisable( GL_BLEND );
  152. glDisable( GL_DEPTH_TEST );
  153. glActiveTexture( GL_TEXTURE0 );
  154. glBindTexture( GL_TEXTURE_2D, compositor->GetBufferTexture( ssaaMainBuffer ) );
  155. compositor->SetBuffer( OPENGL_COMPOSITOR::DIRECT_RENDERING );
  156. if( mode == SUPERSAMPLING_MODE::X4 )
  157. {
  158. x4_shader->Use();
  159. checkGlError( "activating supersampling x4 shader" );
  160. }
  161. draw_fullscreen_primitive();
  162. if( mode == SUPERSAMPLING_MODE::X4 )
  163. {
  164. x4_shader->Deactivate();
  165. checkGlError( "deactivating supersampling x4 shader" );
  166. }
  167. }
  168. void ANTIALIASING_SUPERSAMPLING::OnLostBuffers()
  169. {
  170. areBuffersCreated = false;
  171. }
  172. unsigned int ANTIALIASING_SUPERSAMPLING::CreateBuffer()
  173. {
  174. return compositor->CreateBuffer( GetInternalBufferSize() );
  175. }
  176. // ===============================
  177. // ANTIALIASING_SMAA
  178. // ===============================
  179. ANTIALIASING_SMAA::ANTIALIASING_SMAA( OPENGL_COMPOSITOR* aCompositor, SMAA_QUALITY aQuality )
  180. : areBuffersInitialized( false ), shadersLoaded( false ),
  181. quality( aQuality ), compositor( aCompositor )
  182. {
  183. smaaBaseBuffer = 0;
  184. smaaEdgesBuffer = 0;
  185. smaaBlendBuffer = 0;
  186. smaaAreaTex = 0;
  187. smaaSearchTex = 0;
  188. pass_1_metrics = 0;
  189. pass_2_metrics = 0;
  190. pass_3_metrics = 0;
  191. }
  192. VECTOR2U ANTIALIASING_SMAA::GetInternalBufferSize()
  193. {
  194. return compositor->GetScreenSize();
  195. }
  196. void ANTIALIASING_SMAA::loadShaders()
  197. {
  198. // Load constant textures
  199. glEnable( GL_TEXTURE_2D );
  200. glActiveTexture( GL_TEXTURE0 );
  201. glGenTextures( 1, &smaaAreaTex );
  202. glBindTexture( GL_TEXTURE_2D, smaaAreaTex );
  203. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
  204. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
  205. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
  206. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  207. glTexImage2D( GL_TEXTURE_2D, 0, GL_RG8, AREATEX_WIDTH, AREATEX_HEIGHT, 0, GL_RG, GL_UNSIGNED_BYTE, areaTexBytes );
  208. checkGlError( "loading smaa area tex" );
  209. glGenTextures( 1, &smaaSearchTex );
  210. glBindTexture( GL_TEXTURE_2D, smaaSearchTex );
  211. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
  212. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
  213. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
  214. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  215. glTexImage2D( GL_TEXTURE_2D, 0, GL_R8, SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT, 0, GL_RED, GL_UNSIGNED_BYTE, searchTexBytes );
  216. checkGlError( "loading smaa search tex" );
  217. std::string quality_string;
  218. if( quality == SMAA_QUALITY::HIGH )
  219. {
  220. quality_string = "#define SMAA_PRESET_HIGH\n";
  221. }
  222. else
  223. {
  224. quality_string = "#define SMAA_PRESET_ULTRA\n";
  225. }
  226. // set up shaders
  227. std::string vert_preamble( R"SHADER(
  228. #version 120
  229. #define SMAA_GLSL_2_1
  230. #define SMAA_INCLUDE_VS 1
  231. #define SMAA_INCLUDE_PS 0
  232. uniform vec4 SMAA_RT_METRICS;
  233. )SHADER" );
  234. std::string frag_preamble( R"SHADER(
  235. #version 120
  236. #define SMAA_GLSL_2_1
  237. #define SMAA_INCLUDE_VS 0
  238. #define SMAA_INCLUDE_PS 1
  239. uniform vec4 SMAA_RT_METRICS;
  240. )SHADER" );
  241. std::string smaa_source =
  242. std::string( BUILTIN_SHADERS::smaa_base_shader_p1 )
  243. + std::string( BUILTIN_SHADERS::smaa_base_shader_p2 )
  244. + std::string( BUILTIN_SHADERS::smaa_base_shader_p3 )
  245. + std::string( BUILTIN_SHADERS::smaa_base_shader_p4 );
  246. //
  247. // Set up pass 1 Shader
  248. //
  249. pass_1_shader = std::make_unique<SHADER>( );
  250. pass_1_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_VERTEX, vert_preamble,
  251. quality_string, smaa_source, BUILTIN_SHADERS::smaa_pass_1_vertex_shader );
  252. pass_1_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_FRAGMENT, frag_preamble,
  253. quality_string, smaa_source, BUILTIN_SHADERS::smaa_pass_1_fragment_shader );
  254. pass_1_shader->Link();
  255. checkGlError( "linking pass 1 shader" );
  256. GLint smaaColorTexParameter = pass_1_shader->AddParameter( "colorTex" ); checkGlError( "pass1: getting colorTex uniform" );
  257. pass_1_metrics = pass_1_shader->AddParameter( "SMAA_RT_METRICS" ); checkGlError( "pass1: getting metrics uniform" );
  258. pass_1_shader->Use(); checkGlError( "pass1: using shader" );
  259. pass_1_shader->SetParameter( smaaColorTexParameter, 0 ); checkGlError( "pass1: setting colorTex uniform" );
  260. pass_1_shader->Deactivate(); checkGlError( "pass1: deactivating shader" );
  261. //
  262. // set up pass 2 shader
  263. //
  264. pass_2_shader = std::make_unique<SHADER>( );
  265. pass_2_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_VERTEX, vert_preamble,
  266. quality_string, smaa_source, BUILTIN_SHADERS::smaa_pass_2_vertex_shader );
  267. pass_2_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_FRAGMENT, frag_preamble,
  268. quality_string, smaa_source, BUILTIN_SHADERS::smaa_pass_2_fragment_shader );
  269. pass_2_shader->Link();
  270. checkGlError( "linking pass 2 shader" );
  271. GLint smaaEdgesTexParameter = pass_2_shader->AddParameter( "edgesTex" ); checkGlError( "pass2: getting colorTex uniform" );
  272. GLint smaaAreaTexParameter = pass_2_shader->AddParameter( "areaTex" ); checkGlError( "pass2: getting areaTex uniform" );
  273. GLint smaaSearchTexParameter = pass_2_shader->AddParameter( "searchTex" ); checkGlError( "pass2: getting searchTex uniform" );
  274. pass_2_metrics = pass_2_shader->AddParameter( "SMAA_RT_METRICS" ); checkGlError( "pass2: getting metrics uniform" );
  275. pass_2_shader->Use(); checkGlError( "pass2: using shader" );
  276. pass_2_shader->SetParameter( smaaEdgesTexParameter, 0 ); checkGlError( "pass2: setting colorTex uniform" );
  277. pass_2_shader->SetParameter( smaaAreaTexParameter, 1 ); checkGlError( "pass2: setting areaTex uniform" );
  278. pass_2_shader->SetParameter( smaaSearchTexParameter, 3 ); checkGlError( "pass2: setting searchTex uniform" );
  279. pass_2_shader->Deactivate(); checkGlError( "pass2: deactivating shader" );
  280. //
  281. // set up pass 3 shader
  282. //
  283. pass_3_shader = std::make_unique<SHADER>( );
  284. pass_3_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_VERTEX, vert_preamble,
  285. quality_string, smaa_source, BUILTIN_SHADERS::smaa_pass_3_vertex_shader );
  286. pass_3_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_FRAGMENT, frag_preamble,
  287. quality_string, smaa_source, BUILTIN_SHADERS::smaa_pass_3_fragment_shader );
  288. pass_3_shader->Link();
  289. GLint smaaP3ColorTexParameter = pass_3_shader->AddParameter( "colorTex" ); checkGlError( "pass3: getting colorTex uniform" );
  290. GLint smaaBlendTexParameter = pass_3_shader->AddParameter( "blendTex" ); checkGlError( "pass3: getting blendTex uniform" );
  291. pass_3_metrics = pass_3_shader->AddParameter( "SMAA_RT_METRICS" ); checkGlError( "pass3: getting metrics uniform" );
  292. pass_3_shader->Use(); checkGlError( "pass3: using shader" );
  293. pass_3_shader->SetParameter( smaaP3ColorTexParameter, 0 ); checkGlError( "pass3: setting colorTex uniform" );
  294. pass_3_shader->SetParameter( smaaBlendTexParameter, 1 ); checkGlError( "pass3: setting blendTex uniform" );
  295. pass_3_shader->Deactivate(); checkGlError( "pass3: deactivating shader" );
  296. shadersLoaded = true;
  297. }
  298. void ANTIALIASING_SMAA::updateUniforms()
  299. {
  300. auto dims = compositor->GetScreenSize();
  301. pass_1_shader->Use(); checkGlError( "pass1: using shader" );
  302. pass_1_shader->SetParameter( pass_1_metrics,
  303. 1.f / float( dims.x ), 1.f / float( dims.y ), float( dims.x ), float( dims.y ) ); checkGlError( "pass1: setting metrics uniform" );
  304. pass_1_shader->Deactivate(); checkGlError( "pass1: deactivating shader" );
  305. pass_2_shader->Use(); checkGlError( "pass2: using shader" );
  306. pass_2_shader->SetParameter( pass_2_metrics,
  307. 1.f / float( dims.x ), 1.f / float( dims.y ), float( dims.x ), float( dims.y ) ); checkGlError( "pass2: setting metrics uniform" );
  308. pass_2_shader->Deactivate(); checkGlError( "pass2: deactivating shader" );
  309. pass_3_shader->Use(); checkGlError( "pass3: using shader" );
  310. pass_3_shader->SetParameter( pass_3_metrics,
  311. 1.f / float( dims.x ), 1.f / float( dims.y ), float( dims.x ), float( dims.y ) ); checkGlError( "pass3: setting metrics uniform" );
  312. pass_3_shader->Deactivate(); checkGlError( "pass3: deactivating shader" );
  313. }
  314. bool ANTIALIASING_SMAA::Init()
  315. {
  316. if( !shadersLoaded )
  317. loadShaders();
  318. if( !areBuffersInitialized )
  319. {
  320. smaaBaseBuffer = compositor->CreateBuffer();
  321. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  322. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
  323. smaaEdgesBuffer = compositor->CreateBuffer();
  324. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  325. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
  326. smaaBlendBuffer = compositor->CreateBuffer();
  327. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  328. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
  329. updateUniforms();
  330. areBuffersInitialized = true;
  331. }
  332. // Nothing to initialize
  333. return true;
  334. }
  335. void ANTIALIASING_SMAA::OnLostBuffers()
  336. {
  337. areBuffersInitialized = false;
  338. }
  339. unsigned int ANTIALIASING_SMAA::CreateBuffer()
  340. {
  341. return compositor->CreateBuffer( compositor->GetScreenSize() );
  342. }
  343. void ANTIALIASING_SMAA::DrawBuffer( GLuint buffer )
  344. {
  345. // draw to internal buffer
  346. compositor->DrawBuffer( buffer, smaaBaseBuffer );
  347. }
  348. void ANTIALIASING_SMAA::Begin()
  349. {
  350. compositor->SetBuffer( smaaBaseBuffer );
  351. compositor->ClearBuffer( COLOR4D::BLACK );
  352. }
  353. namespace {
  354. void draw_fullscreen_triangle()
  355. {
  356. glMatrixMode( GL_MODELVIEW );
  357. glPushMatrix();
  358. glLoadIdentity();
  359. glMatrixMode( GL_PROJECTION );
  360. glPushMatrix();
  361. glLoadIdentity();
  362. glBegin( GL_TRIANGLES );
  363. glTexCoord2f( 0.0f, 1.0f );
  364. glVertex2f( -1.0f, 1.0f );
  365. glTexCoord2f( 0.0f, -1.0f );
  366. glVertex2f( -1.0f, -3.0f );
  367. glTexCoord2f( 2.0f, 1.0f );
  368. glVertex2f( 3.0f, 1.0f );
  369. glEnd();
  370. glPopMatrix();
  371. glMatrixMode( GL_MODELVIEW );
  372. glPopMatrix();
  373. }
  374. }
  375. void ANTIALIASING_SMAA::Present()
  376. {
  377. auto sourceTexture = compositor->GetBufferTexture( smaaBaseBuffer );
  378. glDisable( GL_BLEND );
  379. glDisable( GL_DEPTH_TEST );
  380. glEnable( GL_TEXTURE_2D );
  381. //
  382. // pass 1: main-buffer -> smaaEdgesBuffer
  383. //
  384. compositor->SetBuffer( smaaEdgesBuffer );
  385. compositor->ClearBuffer( COLOR4D::BLACK );
  386. glActiveTexture( GL_TEXTURE0 );
  387. glBindTexture( GL_TEXTURE_2D, sourceTexture ); checkGlError( "binding colorTex" );
  388. pass_1_shader->Use(); checkGlError( "using smaa pass 1 shader" );
  389. draw_fullscreen_triangle();
  390. pass_1_shader->Deactivate();
  391. //
  392. // pass 2: smaaEdgesBuffer -> smaaBlendBuffer
  393. //
  394. compositor->SetBuffer( smaaBlendBuffer );
  395. compositor->ClearBuffer( COLOR4D::BLACK );
  396. auto edgesTex = compositor->GetBufferTexture( smaaEdgesBuffer );
  397. glActiveTexture( GL_TEXTURE0 );
  398. glBindTexture( GL_TEXTURE_2D, edgesTex );
  399. glActiveTexture( GL_TEXTURE1 );
  400. glBindTexture( GL_TEXTURE_2D, smaaAreaTex );
  401. glActiveTexture( GL_TEXTURE3 );
  402. glBindTexture( GL_TEXTURE_2D, smaaSearchTex );
  403. pass_2_shader->Use();
  404. draw_fullscreen_triangle();
  405. pass_2_shader->Deactivate();
  406. //
  407. // pass 3: colorTex + BlendBuffer -> output
  408. //
  409. compositor->SetBuffer( OPENGL_COMPOSITOR::DIRECT_RENDERING );
  410. compositor->ClearBuffer( COLOR4D::BLACK );
  411. auto blendTex = compositor->GetBufferTexture( smaaBlendBuffer );
  412. glActiveTexture( GL_TEXTURE0 );
  413. glBindTexture( GL_TEXTURE_2D, sourceTexture );
  414. glActiveTexture( GL_TEXTURE1 );
  415. glBindTexture( GL_TEXTURE_2D, blendTex );
  416. pass_3_shader->Use();
  417. draw_fullscreen_triangle();
  418. pass_3_shader->Deactivate();
  419. }