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.

548 lines
18 KiB

  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. #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. {
  71. void draw_fullscreen_primitive()
  72. {
  73. glMatrixMode( GL_MODELVIEW );
  74. glPushMatrix();
  75. glLoadIdentity();
  76. glMatrixMode( GL_PROJECTION );
  77. glPushMatrix();
  78. glLoadIdentity();
  79. glBegin( GL_TRIANGLES );
  80. glTexCoord2f( 0.0f, 1.0f );
  81. glVertex2f( -1.0f, 1.0f );
  82. glTexCoord2f( 0.0f, 0.0f );
  83. glVertex2f( -1.0f, -1.0f );
  84. glTexCoord2f( 1.0f, 1.0f );
  85. glVertex2f( 1.0f, 1.0f );
  86. glTexCoord2f( 1.0f, 1.0f );
  87. glVertex2f( 1.0f, 1.0f );
  88. glTexCoord2f( 0.0f, 0.0f );
  89. glVertex2f( -1.0f, -1.0f );
  90. glTexCoord2f( 1.0f, 0.0f );
  91. glVertex2f( 1.0f, -1.0f );
  92. glEnd();
  93. glPopMatrix();
  94. glMatrixMode( GL_MODELVIEW );
  95. glPopMatrix();
  96. }
  97. } // namespace
  98. // =========================
  99. // ANTIALIASING_SUPERSAMPLING
  100. // =========================
  101. ANTIALIASING_SUPERSAMPLING::ANTIALIASING_SUPERSAMPLING( OPENGL_COMPOSITOR* aCompositor ) :
  102. compositor( aCompositor ),
  103. ssaaMainBuffer( 0 ), areBuffersCreated( false ), areShadersCreated( false )
  104. {
  105. }
  106. bool ANTIALIASING_SUPERSAMPLING::Init()
  107. {
  108. areShadersCreated = false;
  109. if( !areBuffersCreated )
  110. {
  111. ssaaMainBuffer = compositor->CreateBuffer();
  112. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  113. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
  114. areBuffersCreated = true;
  115. }
  116. return true;
  117. }
  118. VECTOR2U ANTIALIASING_SUPERSAMPLING::GetInternalBufferSize()
  119. {
  120. return compositor->GetScreenSize() * 2;
  121. }
  122. void ANTIALIASING_SUPERSAMPLING::Begin()
  123. {
  124. compositor->SetBuffer( ssaaMainBuffer );
  125. compositor->ClearBuffer( COLOR4D::BLACK );
  126. }
  127. void ANTIALIASING_SUPERSAMPLING::DrawBuffer( GLuint aBuffer )
  128. {
  129. compositor->DrawBuffer( aBuffer, ssaaMainBuffer );
  130. }
  131. void ANTIALIASING_SUPERSAMPLING::Present()
  132. {
  133. glDisable( GL_BLEND );
  134. glDisable( GL_DEPTH_TEST );
  135. glActiveTexture( GL_TEXTURE0 );
  136. glBindTexture( GL_TEXTURE_2D, compositor->GetBufferTexture( ssaaMainBuffer ) );
  137. compositor->SetBuffer( OPENGL_COMPOSITOR::DIRECT_RENDERING );
  138. draw_fullscreen_primitive();
  139. }
  140. void ANTIALIASING_SUPERSAMPLING::OnLostBuffers()
  141. {
  142. areBuffersCreated = false;
  143. }
  144. unsigned int ANTIALIASING_SUPERSAMPLING::CreateBuffer()
  145. {
  146. return compositor->CreateBuffer( GetInternalBufferSize() );
  147. }
  148. // ===============================
  149. // ANTIALIASING_SMAA
  150. // ===============================
  151. ANTIALIASING_SMAA::ANTIALIASING_SMAA( OPENGL_COMPOSITOR* aCompositor ) :
  152. areBuffersInitialized( false ),
  153. shadersLoaded( false ),
  154. compositor( aCompositor )
  155. {
  156. smaaBaseBuffer = 0;
  157. smaaEdgesBuffer = 0;
  158. smaaBlendBuffer = 0;
  159. smaaAreaTex = 0;
  160. smaaSearchTex = 0;
  161. pass_1_metrics = 0;
  162. pass_2_metrics = 0;
  163. pass_3_metrics = 0;
  164. }
  165. VECTOR2U ANTIALIASING_SMAA::GetInternalBufferSize()
  166. {
  167. return compositor->GetScreenSize();
  168. }
  169. void ANTIALIASING_SMAA::loadShaders()
  170. {
  171. // Load constant textures
  172. glEnable( GL_TEXTURE_2D );
  173. glActiveTexture( GL_TEXTURE0 );
  174. glGenTextures( 1, &smaaAreaTex );
  175. glBindTexture( GL_TEXTURE_2D, smaaAreaTex );
  176. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
  177. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
  178. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
  179. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  180. glTexImage2D( GL_TEXTURE_2D, 0, GL_RG8, AREATEX_WIDTH, AREATEX_HEIGHT, 0, GL_RG,
  181. GL_UNSIGNED_BYTE, areaTexBytes );
  182. checkGlError( "loading smaa area tex", __FILE__, __LINE__ );
  183. glGenTextures( 1, &smaaSearchTex );
  184. glBindTexture( GL_TEXTURE_2D, smaaSearchTex );
  185. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
  186. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
  187. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
  188. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  189. glTexImage2D( GL_TEXTURE_2D, 0, GL_R8, SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT, 0, GL_RED,
  190. GL_UNSIGNED_BYTE, searchTexBytes );
  191. checkGlError( "loading smaa search tex", __FILE__, __LINE__ );
  192. // Quality settings:
  193. // THRESHOLD: intended to exclude spurious edges in photorealistic game graphics
  194. // but in a high-contrast CAD application, all edges are intentional
  195. // should be set fairly low, so user color choices do not affect antialiasing
  196. // MAX_SEARCH_STEPS: steps of 2px, searched in H/V direction to discover true angle of edges
  197. // improves AA for lines close H/V but creates fuzzyness at junctions
  198. // MAX_SEARCH_STEPS_DIAG: steps of 1px, searched in diagonal direction
  199. // improves lines close to 45deg but turns small circles into octagons
  200. // CORNER_ROUNDING: SMAA can distinguish actual corners from aliasing jaggies,
  201. // we want to preserve those as much as possible
  202. // Edge Detection: In Eeschema, when a single pixel line changes color, edge detection using
  203. // color is too aggressive and leads to a white spot at the transition point
  204. std::string quality_string;
  205. const char* edge_detect_shader;
  206. // trades imperfect AA of shallow angles for a near artifact-free reproduction of fine features
  207. // jaggies are smoothed over max 5px (original step + 2px in both directions)
  208. quality_string = "#define SMAA_THRESHOLD 0.005\n"
  209. "#define SMAA_MAX_SEARCH_STEPS 1\n"
  210. "#define SMAA_MAX_SEARCH_STEPS_DIAG 2\n"
  211. "#define SMAA_LOCAL_CONTRAST_ADAPTATION_FACTOR 1.5\n"
  212. "#define SMAA_CORNER_ROUNDING 0\n";
  213. edge_detect_shader = BUILTIN_SHADERS::smaa_pass_1_fragment_shader_luma;
  214. // set up shaders
  215. std::string vert_preamble( R"SHADER(
  216. #version 120
  217. #define SMAA_GLSL_2_1
  218. #define SMAA_INCLUDE_VS 1
  219. #define SMAA_INCLUDE_PS 0
  220. uniform vec4 SMAA_RT_METRICS;
  221. )SHADER" );
  222. std::string frag_preamble( R"SHADER(
  223. #version 120
  224. #define SMAA_GLSL_2_1
  225. #define SMAA_INCLUDE_VS 0
  226. #define SMAA_INCLUDE_PS 1
  227. uniform vec4 SMAA_RT_METRICS;
  228. )SHADER" );
  229. std::string smaa_source = std::string( BUILTIN_SHADERS::smaa_base_shader_p1 )
  230. + std::string( BUILTIN_SHADERS::smaa_base_shader_p2 )
  231. + std::string( BUILTIN_SHADERS::smaa_base_shader_p3 )
  232. + std::string( BUILTIN_SHADERS::smaa_base_shader_p4 );
  233. //
  234. // Set up pass 1 Shader
  235. //
  236. pass_1_shader = std::make_unique<SHADER>();
  237. pass_1_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_VERTEX, vert_preamble, quality_string,
  238. smaa_source, BUILTIN_SHADERS::smaa_pass_1_vertex_shader );
  239. pass_1_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_FRAGMENT, frag_preamble,
  240. quality_string, smaa_source, edge_detect_shader );
  241. pass_1_shader->Link();
  242. checkGlError( "linking pass 1 shader", __FILE__, __LINE__ );
  243. GLint smaaColorTexParameter = pass_1_shader->AddParameter( "colorTex" );
  244. checkGlError( "pass1: getting colorTex uniform", __FILE__, __LINE__ );
  245. pass_1_metrics = pass_1_shader->AddParameter( "SMAA_RT_METRICS" );
  246. checkGlError( "pass1: getting metrics uniform", __FILE__, __LINE__ );
  247. pass_1_shader->Use();
  248. checkGlError( "pass1: using shader", __FILE__, __LINE__ );
  249. pass_1_shader->SetParameter( smaaColorTexParameter, 0 );
  250. checkGlError( "pass1: setting colorTex uniform", __FILE__, __LINE__ );
  251. pass_1_shader->Deactivate();
  252. checkGlError( "pass1: deactivating shader", __FILE__, __LINE__ );
  253. //
  254. // set up pass 2 shader
  255. //
  256. pass_2_shader = std::make_unique<SHADER>();
  257. pass_2_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_VERTEX, vert_preamble, quality_string,
  258. smaa_source, BUILTIN_SHADERS::smaa_pass_2_vertex_shader );
  259. pass_2_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_FRAGMENT, frag_preamble,
  260. quality_string, smaa_source,
  261. BUILTIN_SHADERS::smaa_pass_2_fragment_shader );
  262. pass_2_shader->Link();
  263. checkGlError( "linking pass 2 shader", __FILE__, __LINE__ );
  264. GLint smaaEdgesTexParameter = pass_2_shader->AddParameter( "edgesTex" );
  265. checkGlError( "pass2: getting colorTex uniform", __FILE__, __LINE__ );
  266. GLint smaaAreaTexParameter = pass_2_shader->AddParameter( "areaTex" );
  267. checkGlError( "pass2: getting areaTex uniform", __FILE__, __LINE__ );
  268. GLint smaaSearchTexParameter = pass_2_shader->AddParameter( "searchTex" );
  269. checkGlError( "pass2: getting searchTex uniform", __FILE__, __LINE__ );
  270. pass_2_metrics = pass_2_shader->AddParameter( "SMAA_RT_METRICS" );
  271. checkGlError( "pass2: getting metrics uniform", __FILE__, __LINE__ );
  272. pass_2_shader->Use();
  273. checkGlError( "pass2: using shader", __FILE__, __LINE__ );
  274. pass_2_shader->SetParameter( smaaEdgesTexParameter, 0 );
  275. checkGlError( "pass2: setting colorTex uniform", __FILE__, __LINE__ );
  276. pass_2_shader->SetParameter( smaaAreaTexParameter, 1 );
  277. checkGlError( "pass2: setting areaTex uniform", __FILE__, __LINE__ );
  278. pass_2_shader->SetParameter( smaaSearchTexParameter, 3 );
  279. checkGlError( "pass2: setting searchTex uniform", __FILE__, __LINE__ );
  280. pass_2_shader->Deactivate();
  281. checkGlError( "pass2: deactivating shader", __FILE__, __LINE__ );
  282. //
  283. // set up pass 3 shader
  284. //
  285. pass_3_shader = std::make_unique<SHADER>();
  286. pass_3_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_VERTEX, vert_preamble, quality_string,
  287. smaa_source, BUILTIN_SHADERS::smaa_pass_3_vertex_shader );
  288. pass_3_shader->LoadShaderFromStrings( KIGFX::SHADER_TYPE_FRAGMENT, frag_preamble,
  289. quality_string, smaa_source,
  290. BUILTIN_SHADERS::smaa_pass_3_fragment_shader );
  291. pass_3_shader->Link();
  292. GLint smaaP3ColorTexParameter = pass_3_shader->AddParameter( "colorTex" );
  293. checkGlError( "pass3: getting colorTex uniform", __FILE__, __LINE__ );
  294. GLint smaaBlendTexParameter = pass_3_shader->AddParameter( "blendTex" );
  295. checkGlError( "pass3: getting blendTex uniform", __FILE__, __LINE__ );
  296. pass_3_metrics = pass_3_shader->AddParameter( "SMAA_RT_METRICS" );
  297. checkGlError( "pass3: getting metrics uniform", __FILE__, __LINE__ );
  298. pass_3_shader->Use();
  299. checkGlError( "pass3: using shader", __FILE__, __LINE__ );
  300. pass_3_shader->SetParameter( smaaP3ColorTexParameter, 0 );
  301. checkGlError( "pass3: setting colorTex uniform", __FILE__, __LINE__ );
  302. pass_3_shader->SetParameter( smaaBlendTexParameter, 1 );
  303. checkGlError( "pass3: setting blendTex uniform", __FILE__, __LINE__ );
  304. pass_3_shader->Deactivate();
  305. checkGlError( "pass3: deactivating shader", __FILE__, __LINE__ );
  306. shadersLoaded = true;
  307. }
  308. void ANTIALIASING_SMAA::updateUniforms()
  309. {
  310. auto dims = compositor->GetScreenSize();
  311. pass_1_shader->Use();
  312. checkGlError( "pass1: using shader", __FILE__, __LINE__ );
  313. pass_1_shader->SetParameter( pass_1_metrics, 1.f / float( dims.x ), 1.f / float( dims.y ),
  314. float( dims.x ), float( dims.y ) );
  315. checkGlError( "pass1: setting metrics uniform", __FILE__, __LINE__ );
  316. pass_1_shader->Deactivate();
  317. checkGlError( "pass1: deactivating shader", __FILE__, __LINE__ );
  318. pass_2_shader->Use();
  319. checkGlError( "pass2: using shader", __FILE__, __LINE__ );
  320. pass_2_shader->SetParameter( pass_2_metrics, 1.f / float( dims.x ), 1.f / float( dims.y ),
  321. float( dims.x ), float( dims.y ) );
  322. checkGlError( "pass2: setting metrics uniform", __FILE__, __LINE__ );
  323. pass_2_shader->Deactivate();
  324. checkGlError( "pass2: deactivating shader", __FILE__, __LINE__ );
  325. pass_3_shader->Use();
  326. checkGlError( "pass3: using shader", __FILE__, __LINE__ );
  327. pass_3_shader->SetParameter( pass_3_metrics, 1.f / float( dims.x ), 1.f / float( dims.y ),
  328. float( dims.x ), float( dims.y ) );
  329. checkGlError( "pass3: setting metrics uniform", __FILE__, __LINE__ );
  330. pass_3_shader->Deactivate();
  331. checkGlError( "pass3: deactivating shader", __FILE__, __LINE__ );
  332. }
  333. bool ANTIALIASING_SMAA::Init()
  334. {
  335. if( !shadersLoaded )
  336. loadShaders();
  337. if( !areBuffersInitialized )
  338. {
  339. smaaBaseBuffer = compositor->CreateBuffer();
  340. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  341. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
  342. smaaEdgesBuffer = compositor->CreateBuffer();
  343. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  344. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
  345. smaaBlendBuffer = compositor->CreateBuffer();
  346. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  347. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
  348. updateUniforms();
  349. areBuffersInitialized = true;
  350. }
  351. // Nothing to initialize
  352. return true;
  353. }
  354. void ANTIALIASING_SMAA::OnLostBuffers()
  355. {
  356. areBuffersInitialized = false;
  357. }
  358. unsigned int ANTIALIASING_SMAA::CreateBuffer()
  359. {
  360. return compositor->CreateBuffer( compositor->GetScreenSize() );
  361. }
  362. void ANTIALIASING_SMAA::DrawBuffer( GLuint buffer )
  363. {
  364. // draw to internal buffer
  365. compositor->DrawBuffer( buffer, smaaBaseBuffer );
  366. }
  367. void ANTIALIASING_SMAA::Begin()
  368. {
  369. compositor->SetBuffer( smaaBaseBuffer );
  370. compositor->ClearBuffer( COLOR4D::BLACK );
  371. }
  372. namespace
  373. {
  374. void draw_fullscreen_triangle()
  375. {
  376. glMatrixMode( GL_MODELVIEW );
  377. glPushMatrix();
  378. glLoadIdentity();
  379. glMatrixMode( GL_PROJECTION );
  380. glPushMatrix();
  381. glLoadIdentity();
  382. glBegin( GL_TRIANGLES );
  383. glTexCoord2f( 0.0f, 1.0f );
  384. glVertex2f( -1.0f, 1.0f );
  385. glTexCoord2f( 0.0f, -1.0f );
  386. glVertex2f( -1.0f, -3.0f );
  387. glTexCoord2f( 2.0f, 1.0f );
  388. glVertex2f( 3.0f, 1.0f );
  389. glEnd();
  390. glPopMatrix();
  391. glMatrixMode( GL_MODELVIEW );
  392. glPopMatrix();
  393. }
  394. } // namespace
  395. void ANTIALIASING_SMAA::Present()
  396. {
  397. auto sourceTexture = compositor->GetBufferTexture( smaaBaseBuffer );
  398. glDisable( GL_BLEND );
  399. glDisable( GL_DEPTH_TEST );
  400. glEnable( GL_TEXTURE_2D );
  401. //
  402. // pass 1: main-buffer -> smaaEdgesBuffer
  403. //
  404. compositor->SetBuffer( smaaEdgesBuffer );
  405. compositor->ClearBuffer( COLOR4D::BLACK );
  406. glActiveTexture( GL_TEXTURE0 );
  407. glBindTexture( GL_TEXTURE_2D, sourceTexture );
  408. checkGlError( "binding colorTex", __FILE__, __LINE__ );
  409. pass_1_shader->Use();
  410. checkGlError( "using smaa pass 1 shader", __FILE__, __LINE__ );
  411. draw_fullscreen_triangle();
  412. pass_1_shader->Deactivate();
  413. //
  414. // pass 2: smaaEdgesBuffer -> smaaBlendBuffer
  415. //
  416. compositor->SetBuffer( smaaBlendBuffer );
  417. compositor->ClearBuffer( COLOR4D::BLACK );
  418. auto edgesTex = compositor->GetBufferTexture( smaaEdgesBuffer );
  419. glActiveTexture( GL_TEXTURE0 );
  420. glBindTexture( GL_TEXTURE_2D, edgesTex );
  421. glActiveTexture( GL_TEXTURE1 );
  422. glBindTexture( GL_TEXTURE_2D, smaaAreaTex );
  423. glActiveTexture( GL_TEXTURE3 );
  424. glBindTexture( GL_TEXTURE_2D, smaaSearchTex );
  425. pass_2_shader->Use();
  426. draw_fullscreen_triangle();
  427. pass_2_shader->Deactivate();
  428. //
  429. // pass 3: colorTex + BlendBuffer -> output
  430. //
  431. compositor->SetBuffer( OPENGL_COMPOSITOR::DIRECT_RENDERING );
  432. compositor->ClearBuffer( COLOR4D::BLACK );
  433. auto blendTex = compositor->GetBufferTexture( smaaBlendBuffer );
  434. glActiveTexture( GL_TEXTURE0 );
  435. glBindTexture( GL_TEXTURE_2D, sourceTexture );
  436. glActiveTexture( GL_TEXTURE1 );
  437. glBindTexture( GL_TEXTURE_2D, blendTex );
  438. pass_3_shader->Use();
  439. draw_fullscreen_triangle();
  440. pass_3_shader->Deactivate();
  441. }