PostProcessing.cpp 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068
  1. // Copyright 2014 Dolphin Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "VideoCommon/PostProcessing.h"
  4. #include <sstream>
  5. #include <string>
  6. #include <string_view>
  7. #include <fmt/format.h>
  8. #include "Common/Assert.h"
  9. #include "Common/CommonPaths.h"
  10. #include "Common/CommonTypes.h"
  11. #include "Common/FileSearch.h"
  12. #include "Common/FileUtil.h"
  13. #include "Common/IniFile.h"
  14. #include "Common/Logging/Log.h"
  15. #include "Common/MsgHandler.h"
  16. #include "Common/StringUtil.h"
  17. #include "VideoCommon/AbstractFramebuffer.h"
  18. #include "VideoCommon/AbstractGfx.h"
  19. #include "VideoCommon/AbstractPipeline.h"
  20. #include "VideoCommon/AbstractShader.h"
  21. #include "VideoCommon/AbstractTexture.h"
  22. #include "VideoCommon/FramebufferManager.h"
  23. #include "VideoCommon/Present.h"
  24. #include "VideoCommon/ShaderCache.h"
  25. #include "VideoCommon/VertexManagerBase.h"
  26. #include "VideoCommon/VideoCommon.h"
  27. #include "VideoCommon/VideoConfig.h"
  28. namespace VideoCommon
  29. {
  30. static const char s_empty_pixel_shader[] = "void main() { SetOutput(Sample()); }\n";
  31. static const char s_default_pixel_shader_name[] = "default_pre_post_process";
  32. // Keep the highest quality possible to avoid losing quality on subtle gamma conversions.
  33. // RGBA16F should have enough quality even if we store colors in gamma space on it.
  34. static const AbstractTextureFormat s_intermediary_buffer_format = AbstractTextureFormat::RGBA16F;
  35. static bool LoadShaderFromFile(const std::string& shader, const std::string& sub_dir,
  36. std::string& out_code)
  37. {
  38. std::string path = File::GetUserPath(D_SHADERS_IDX) + sub_dir + shader + ".glsl";
  39. if (!File::Exists(path))
  40. {
  41. // Fallback to shared user dir
  42. path = File::GetSysDirectory() + SHADERS_DIR DIR_SEP + sub_dir + shader + ".glsl";
  43. }
  44. if (!File::ReadFileToString(path, out_code))
  45. {
  46. out_code = "";
  47. ERROR_LOG_FMT(VIDEO, "Post-processing shader not found: {}", path);
  48. return false;
  49. }
  50. return true;
  51. }
  52. PostProcessingConfiguration::PostProcessingConfiguration() = default;
  53. PostProcessingConfiguration::~PostProcessingConfiguration() = default;
  54. void PostProcessingConfiguration::LoadShader(const std::string& shader)
  55. {
  56. // Load the shader from the configuration if there isn't one sent to us.
  57. m_current_shader = shader;
  58. if (shader.empty())
  59. {
  60. LoadDefaultShader();
  61. return;
  62. }
  63. std::string sub_dir = "";
  64. if (g_Config.stereo_mode == StereoMode::Anaglyph)
  65. {
  66. sub_dir = ANAGLYPH_DIR DIR_SEP;
  67. }
  68. else if (g_Config.stereo_mode == StereoMode::Passive)
  69. {
  70. sub_dir = PASSIVE_DIR DIR_SEP;
  71. }
  72. std::string code;
  73. if (!LoadShaderFromFile(shader, sub_dir, code))
  74. {
  75. LoadDefaultShader();
  76. return;
  77. }
  78. LoadOptions(code);
  79. // Note that this will build the shaders with the custom options values users
  80. // might have set in the settings
  81. LoadOptionsConfiguration();
  82. m_current_shader_code = code;
  83. }
  84. void PostProcessingConfiguration::LoadDefaultShader()
  85. {
  86. m_options.clear();
  87. m_any_options_dirty = false;
  88. m_current_shader = "";
  89. m_current_shader_code = s_empty_pixel_shader;
  90. }
  91. void PostProcessingConfiguration::LoadOptions(const std::string& code)
  92. {
  93. const std::string config_start_delimiter = "[configuration]";
  94. const std::string config_end_delimiter = "[/configuration]";
  95. size_t configuration_start = code.find(config_start_delimiter);
  96. size_t configuration_end = code.find(config_end_delimiter);
  97. m_options.clear();
  98. m_any_options_dirty = true;
  99. if (configuration_start == std::string::npos || configuration_end == std::string::npos)
  100. {
  101. // Issue loading configuration or there isn't one.
  102. return;
  103. }
  104. std::string configuration_string =
  105. code.substr(configuration_start + config_start_delimiter.size(),
  106. configuration_end - configuration_start - config_start_delimiter.size());
  107. std::istringstream in(configuration_string);
  108. struct GLSLStringOption
  109. {
  110. std::string m_type;
  111. std::vector<std::pair<std::string, std::string>> m_options;
  112. };
  113. std::vector<GLSLStringOption> option_strings;
  114. GLSLStringOption* current_strings = nullptr;
  115. while (!in.eof())
  116. {
  117. std::string line_str;
  118. if (std::getline(in, line_str))
  119. {
  120. std::string_view line = line_str;
  121. #ifndef _WIN32
  122. // Check for CRLF eol and convert it to LF
  123. if (!line.empty() && line.at(line.size() - 1) == '\r')
  124. line.remove_suffix(1);
  125. #endif
  126. if (!line.empty())
  127. {
  128. if (line[0] == '[')
  129. {
  130. size_t endpos = line.find("]");
  131. if (endpos != std::string::npos)
  132. {
  133. // New section!
  134. std::string_view sub = line.substr(1, endpos - 1);
  135. option_strings.push_back({std::string(sub)});
  136. current_strings = &option_strings.back();
  137. }
  138. }
  139. else
  140. {
  141. if (current_strings)
  142. {
  143. std::string key, value;
  144. Common::IniFile::ParseLine(line, &key, &value);
  145. if (!(key.empty() && value.empty()))
  146. current_strings->m_options.emplace_back(key, value);
  147. }
  148. }
  149. }
  150. }
  151. }
  152. for (const auto& it : option_strings)
  153. {
  154. ConfigurationOption option;
  155. option.m_dirty = true;
  156. if (it.m_type == "OptionBool")
  157. option.m_type = ConfigurationOption::OptionType::Bool;
  158. else if (it.m_type == "OptionRangeFloat")
  159. option.m_type = ConfigurationOption::OptionType::Float;
  160. else if (it.m_type == "OptionRangeInteger")
  161. option.m_type = ConfigurationOption::OptionType::Integer;
  162. for (const auto& string_option : it.m_options)
  163. {
  164. if (string_option.first == "GUIName")
  165. {
  166. option.m_gui_name = string_option.second;
  167. }
  168. else if (string_option.first == "OptionName")
  169. {
  170. option.m_option_name = string_option.second;
  171. }
  172. else if (string_option.first == "DependentOption")
  173. {
  174. option.m_dependent_option = string_option.second;
  175. }
  176. else if (string_option.first == "MinValue" || string_option.first == "MaxValue" ||
  177. string_option.first == "DefaultValue" || string_option.first == "StepAmount")
  178. {
  179. std::vector<s32>* output_integer = nullptr;
  180. std::vector<float>* output_float = nullptr;
  181. if (string_option.first == "MinValue")
  182. {
  183. output_integer = &option.m_integer_min_values;
  184. output_float = &option.m_float_min_values;
  185. }
  186. else if (string_option.first == "MaxValue")
  187. {
  188. output_integer = &option.m_integer_max_values;
  189. output_float = &option.m_float_max_values;
  190. }
  191. else if (string_option.first == "DefaultValue")
  192. {
  193. output_integer = &option.m_integer_values;
  194. output_float = &option.m_float_values;
  195. }
  196. else if (string_option.first == "StepAmount")
  197. {
  198. output_integer = &option.m_integer_step_values;
  199. output_float = &option.m_float_step_values;
  200. }
  201. if (option.m_type == ConfigurationOption::OptionType::Bool)
  202. {
  203. TryParse(string_option.second, &option.m_bool_value);
  204. }
  205. else if (option.m_type == ConfigurationOption::OptionType::Integer)
  206. {
  207. TryParseVector(string_option.second, output_integer);
  208. if (output_integer->size() > 4)
  209. output_integer->erase(output_integer->begin() + 4, output_integer->end());
  210. }
  211. else if (option.m_type == ConfigurationOption::OptionType::Float)
  212. {
  213. TryParseVector(string_option.second, output_float);
  214. if (output_float->size() > 4)
  215. output_float->erase(output_float->begin() + 4, output_float->end());
  216. }
  217. }
  218. }
  219. m_options[option.m_option_name] = option;
  220. }
  221. }
  222. void PostProcessingConfiguration::LoadOptionsConfiguration()
  223. {
  224. Common::IniFile ini;
  225. ini.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX));
  226. std::string section = m_current_shader + "-options";
  227. // We already expect all the options to be marked as "dirty" when we reach here
  228. for (auto& it : m_options)
  229. {
  230. switch (it.second.m_type)
  231. {
  232. case ConfigurationOption::OptionType::Bool:
  233. ini.GetOrCreateSection(section)->Get(it.second.m_option_name, &it.second.m_bool_value,
  234. it.second.m_bool_value);
  235. break;
  236. case ConfigurationOption::OptionType::Integer:
  237. {
  238. std::string value;
  239. ini.GetOrCreateSection(section)->Get(it.second.m_option_name, &value);
  240. if (!value.empty())
  241. {
  242. auto integer_values = it.second.m_integer_values;
  243. if (TryParseVector(value, &integer_values))
  244. {
  245. it.second.m_integer_values = integer_values;
  246. }
  247. }
  248. }
  249. break;
  250. case ConfigurationOption::OptionType::Float:
  251. {
  252. std::string value;
  253. ini.GetOrCreateSection(section)->Get(it.second.m_option_name, &value);
  254. if (!value.empty())
  255. {
  256. auto float_values = it.second.m_float_values;
  257. if (TryParseVector(value, &float_values))
  258. {
  259. it.second.m_float_values = float_values;
  260. }
  261. }
  262. }
  263. break;
  264. }
  265. }
  266. }
  267. void PostProcessingConfiguration::SaveOptionsConfiguration()
  268. {
  269. Common::IniFile ini;
  270. ini.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX));
  271. std::string section = m_current_shader + "-options";
  272. for (auto& it : m_options)
  273. {
  274. switch (it.second.m_type)
  275. {
  276. case ConfigurationOption::OptionType::Bool:
  277. {
  278. ini.GetOrCreateSection(section)->Set(it.second.m_option_name, it.second.m_bool_value);
  279. }
  280. break;
  281. case ConfigurationOption::OptionType::Integer:
  282. {
  283. std::string value;
  284. for (size_t i = 0; i < it.second.m_integer_values.size(); ++i)
  285. {
  286. value += fmt::format("{}{}", it.second.m_integer_values[i],
  287. i == (it.second.m_integer_values.size() - 1) ? "" : ", ");
  288. }
  289. ini.GetOrCreateSection(section)->Set(it.second.m_option_name, value);
  290. }
  291. break;
  292. case ConfigurationOption::OptionType::Float:
  293. {
  294. std::ostringstream value;
  295. value.imbue(std::locale("C"));
  296. for (size_t i = 0; i < it.second.m_float_values.size(); ++i)
  297. {
  298. value << it.second.m_float_values[i];
  299. if (i != (it.second.m_float_values.size() - 1))
  300. value << ", ";
  301. }
  302. ini.GetOrCreateSection(section)->Set(it.second.m_option_name, value.str());
  303. }
  304. break;
  305. }
  306. }
  307. ini.Save(File::GetUserPath(F_DOLPHINCONFIG_IDX));
  308. }
  309. void PostProcessingConfiguration::SetOptionf(const std::string& option, int index, float value)
  310. {
  311. auto it = m_options.find(option);
  312. it->second.m_float_values[index] = value;
  313. it->second.m_dirty = true;
  314. m_any_options_dirty = true;
  315. }
  316. void PostProcessingConfiguration::SetOptioni(const std::string& option, int index, s32 value)
  317. {
  318. auto it = m_options.find(option);
  319. it->second.m_integer_values[index] = value;
  320. it->second.m_dirty = true;
  321. m_any_options_dirty = true;
  322. }
  323. void PostProcessingConfiguration::SetOptionb(const std::string& option, bool value)
  324. {
  325. auto it = m_options.find(option);
  326. it->second.m_bool_value = value;
  327. it->second.m_dirty = true;
  328. m_any_options_dirty = true;
  329. }
  330. PostProcessing::PostProcessing()
  331. {
  332. m_timer.Start();
  333. }
  334. PostProcessing::~PostProcessing()
  335. {
  336. m_timer.Stop();
  337. }
  338. static std::vector<std::string> GetShaders(const std::string& sub_dir = "")
  339. {
  340. std::vector<std::string> paths =
  341. Common::DoFileSearch({File::GetUserPath(D_SHADERS_IDX) + sub_dir,
  342. File::GetSysDirectory() + SHADERS_DIR DIR_SEP + sub_dir},
  343. {".glsl"});
  344. std::vector<std::string> result;
  345. for (std::string path : paths)
  346. {
  347. std::string name;
  348. SplitPath(path, nullptr, &name, nullptr);
  349. if (name == s_default_pixel_shader_name)
  350. continue;
  351. result.push_back(name);
  352. }
  353. return result;
  354. }
  355. std::vector<std::string> PostProcessing::GetShaderList()
  356. {
  357. return GetShaders();
  358. }
  359. std::vector<std::string> PostProcessing::GetAnaglyphShaderList()
  360. {
  361. return GetShaders(ANAGLYPH_DIR DIR_SEP);
  362. }
  363. std::vector<std::string> PostProcessing::GetPassiveShaderList()
  364. {
  365. return GetShaders(PASSIVE_DIR DIR_SEP);
  366. }
  367. bool PostProcessing::Initialize(AbstractTextureFormat format)
  368. {
  369. m_framebuffer_format = format;
  370. // CompilePixelShader() must be run first if configuration options are used.
  371. // Otherwise the UBO has a different member list between vertex and pixel
  372. // shaders, which is a link error on some backends.
  373. if (!CompilePixelShader() || !CompileVertexShader() || !CompilePipeline())
  374. return false;
  375. return true;
  376. }
  377. void PostProcessing::RecompileShader()
  378. {
  379. // Note: for simplicity we already recompile all the shaders
  380. // and pipelines even if there might not be need to.
  381. m_default_pipeline.reset();
  382. m_pipeline.reset();
  383. m_default_pixel_shader.reset();
  384. m_pixel_shader.reset();
  385. m_default_vertex_shader.reset();
  386. m_vertex_shader.reset();
  387. if (!CompilePixelShader())
  388. return;
  389. if (!CompileVertexShader())
  390. return;
  391. CompilePipeline();
  392. }
  393. void PostProcessing::RecompilePipeline()
  394. {
  395. m_default_pipeline.reset();
  396. m_pipeline.reset();
  397. CompilePipeline();
  398. }
  399. bool PostProcessing::IsColorCorrectionActive() const
  400. {
  401. // We can skip the color correction pass if none of these settings are on
  402. // (it might have still helped with gamma correct sampling, but it's not worth running it).
  403. return g_ActiveConfig.color_correction.bCorrectColorSpace ||
  404. g_ActiveConfig.color_correction.bCorrectGamma ||
  405. m_framebuffer_format == AbstractTextureFormat::RGBA16F;
  406. }
  407. bool PostProcessing::NeedsIntermediaryBuffer() const
  408. {
  409. // If we have no user selected post process shader,
  410. // there's no point in having an intermediary buffer doing nothing.
  411. return !m_config.GetShader().empty();
  412. }
  413. void PostProcessing::BlitFromTexture(const MathUtil::Rectangle<int>& dst,
  414. const MathUtil::Rectangle<int>& src,
  415. const AbstractTexture* src_tex, int src_layer)
  416. {
  417. if (g_gfx->GetCurrentFramebuffer()->GetColorFormat() != m_framebuffer_format)
  418. {
  419. m_framebuffer_format = g_gfx->GetCurrentFramebuffer()->GetColorFormat();
  420. RecompilePipeline();
  421. }
  422. // By default all source layers will be copied into the respective target layers
  423. const bool copy_all_layers = src_layer < 0;
  424. src_layer = std::max(src_layer, 0);
  425. MathUtil::Rectangle<int> src_rect = src;
  426. g_gfx->SetSamplerState(0, RenderState::GetLinearSamplerState());
  427. g_gfx->SetSamplerState(1, RenderState::GetPointSamplerState());
  428. g_gfx->SetTexture(0, src_tex);
  429. g_gfx->SetTexture(1, src_tex);
  430. const bool needs_color_correction = IsColorCorrectionActive();
  431. // Rely on the default (bi)linear sampler with the default mode
  432. // (it might not be gamma corrected).
  433. const bool needs_resampling =
  434. g_ActiveConfig.output_resampling_mode > OutputResamplingMode::Default;
  435. const bool needs_intermediary_buffer = NeedsIntermediaryBuffer();
  436. const bool needs_default_pipeline = needs_color_correction || needs_resampling;
  437. const AbstractPipeline* final_pipeline = m_pipeline.get();
  438. std::vector<u8>* uniform_staging_buffer = &m_default_uniform_staging_buffer;
  439. bool default_uniform_staging_buffer = true;
  440. const MathUtil::Rectangle<int> present_rect = g_presenter->GetTargetRectangle();
  441. // Intermediary pass.
  442. // We draw to a high quality intermediary texture for a couple reasons:
  443. // -Consistently do high quality gamma corrected resampling (upscaling/downscaling)
  444. // -Keep quality for gamma and gamut conversions, and HDR output
  445. // (low bit depths lose too much quality with gamma conversions)
  446. // -Keep the post process phase in linear space, to better operate with colors
  447. if (m_default_pipeline && needs_default_pipeline && needs_intermediary_buffer)
  448. {
  449. AbstractFramebuffer* const previous_framebuffer = g_gfx->GetCurrentFramebuffer();
  450. // We keep the min number of layers as the render target,
  451. // as in case of OpenGL, the source FBX will have two layers,
  452. // but we will render onto two separate frame buffers (one by one),
  453. // so it would be a waste to allocate two layers (see "bUsesExplictQuadBuffering").
  454. const u32 target_layers = copy_all_layers ? src_tex->GetLayers() : 1;
  455. const u32 target_width =
  456. needs_resampling ? present_rect.GetWidth() : static_cast<u32>(src_rect.GetWidth());
  457. const u32 target_height =
  458. needs_resampling ? present_rect.GetHeight() : static_cast<u32>(src_rect.GetHeight());
  459. if (!m_intermediary_frame_buffer || !m_intermediary_color_texture ||
  460. m_intermediary_color_texture->GetWidth() != target_width ||
  461. m_intermediary_color_texture->GetHeight() != target_height ||
  462. m_intermediary_color_texture->GetLayers() != target_layers)
  463. {
  464. const TextureConfig intermediary_color_texture_config(
  465. target_width, target_height, 1, target_layers, src_tex->GetSamples(),
  466. s_intermediary_buffer_format, AbstractTextureFlag_RenderTarget,
  467. AbstractTextureType::Texture_2DArray);
  468. m_intermediary_color_texture = g_gfx->CreateTexture(intermediary_color_texture_config,
  469. "Intermediary post process texture");
  470. m_intermediary_frame_buffer =
  471. g_gfx->CreateFramebuffer(m_intermediary_color_texture.get(), nullptr);
  472. }
  473. g_gfx->SetFramebuffer(m_intermediary_frame_buffer.get());
  474. FillUniformBuffer(src_rect, src_tex, src_layer, g_gfx->GetCurrentFramebuffer()->GetRect(),
  475. present_rect, uniform_staging_buffer->data(), !default_uniform_staging_buffer,
  476. true);
  477. g_vertex_manager->UploadUtilityUniforms(uniform_staging_buffer->data(),
  478. static_cast<u32>(uniform_staging_buffer->size()));
  479. g_gfx->SetViewportAndScissor(g_gfx->ConvertFramebufferRectangle(
  480. m_intermediary_color_texture->GetRect(), m_intermediary_frame_buffer.get()));
  481. g_gfx->SetPipeline(m_default_pipeline.get());
  482. g_gfx->Draw(0, 3);
  483. g_gfx->SetFramebuffer(previous_framebuffer);
  484. src_rect = m_intermediary_color_texture->GetRect();
  485. src_tex = m_intermediary_color_texture.get();
  486. g_gfx->SetTexture(0, src_tex);
  487. g_gfx->SetTexture(1, src_tex);
  488. // The "m_intermediary_color_texture" has already copied
  489. // from the specified source layer onto its first one.
  490. // If we query for a layer that the source texture doesn't have,
  491. // it will fall back on the first one anyway.
  492. src_layer = 0;
  493. uniform_staging_buffer = &m_uniform_staging_buffer;
  494. default_uniform_staging_buffer = false;
  495. }
  496. else
  497. {
  498. // If we have no custom user shader selected, and color correction
  499. // is active, directly run the fixed pipeline shader instead of
  500. // doing two passes, with the second one doing nothing useful.
  501. if (m_default_pipeline && needs_default_pipeline)
  502. {
  503. final_pipeline = m_default_pipeline.get();
  504. }
  505. else
  506. {
  507. uniform_staging_buffer = &m_uniform_staging_buffer;
  508. default_uniform_staging_buffer = false;
  509. }
  510. m_intermediary_frame_buffer.reset();
  511. m_intermediary_color_texture.reset();
  512. }
  513. // TODO: ideally we'd do the user selected post process pass in the intermediary buffer in linear
  514. // space (instead of gamma space), so the shaders could act more accurately (and sample in linear
  515. // space), though that would break the look of some of current post processes we have, and thus is
  516. // better avoided for now.
  517. // Final pass, either a user selected shader or the default (fixed) shader.
  518. if (final_pipeline)
  519. {
  520. FillUniformBuffer(src_rect, src_tex, src_layer, g_gfx->GetCurrentFramebuffer()->GetRect(),
  521. present_rect, uniform_staging_buffer->data(), !default_uniform_staging_buffer,
  522. false);
  523. g_vertex_manager->UploadUtilityUniforms(uniform_staging_buffer->data(),
  524. static_cast<u32>(uniform_staging_buffer->size()));
  525. g_gfx->SetViewportAndScissor(
  526. g_gfx->ConvertFramebufferRectangle(dst, g_gfx->GetCurrentFramebuffer()));
  527. g_gfx->SetPipeline(final_pipeline);
  528. g_gfx->Draw(0, 3);
  529. }
  530. }
  531. std::string PostProcessing::GetUniformBufferHeader(bool user_post_process) const
  532. {
  533. std::ostringstream ss;
  534. u32 unused_counter = 1;
  535. ss << "UBO_BINDING(std140, 1) uniform PSBlock {\n";
  536. // Builtin uniforms:
  537. ss << " float4 resolution;\n"; // Source resolution
  538. ss << " float4 target_resolution;\n";
  539. ss << " float4 window_resolution;\n";
  540. // How many horizontal and vertical stereo views do we have? (set to 1 when we use layers instead)
  541. ss << " int2 stereo_views;\n";
  542. ss << " float4 src_rect;\n";
  543. // The first (but not necessarily only) source layer we target
  544. ss << " int src_layer;\n";
  545. ss << " uint time;\n";
  546. ss << " int graphics_api;\n";
  547. // If true, it's an intermediary buffer (including the first), if false, it's the final one
  548. ss << " int intermediary_buffer;\n";
  549. ss << " int resampling_method;\n";
  550. ss << " int correct_color_space;\n";
  551. ss << " int game_color_space;\n";
  552. ss << " int correct_gamma;\n";
  553. ss << " float game_gamma;\n";
  554. ss << " int sdr_display_gamma_sRGB;\n";
  555. ss << " float sdr_display_custom_gamma;\n";
  556. ss << " int linear_space_output;\n";
  557. ss << " int hdr_output;\n";
  558. ss << " float hdr_paper_white_nits;\n";
  559. ss << " float hdr_sdr_white_nits;\n";
  560. if (user_post_process)
  561. {
  562. ss << "\n";
  563. // Custom options/uniforms
  564. for (const auto& it : m_config.GetOptions())
  565. {
  566. if (it.second.m_type == PostProcessingConfiguration::ConfigurationOption::OptionType::Bool)
  567. {
  568. ss << fmt::format(" int {};\n", it.first);
  569. for (u32 i = 0; i < 3; i++)
  570. ss << " int ubo_align_" << unused_counter++ << "_;\n";
  571. }
  572. else if (it.second.m_type ==
  573. PostProcessingConfiguration::ConfigurationOption::OptionType::Integer)
  574. {
  575. u32 count = static_cast<u32>(it.second.m_integer_values.size());
  576. if (count == 1)
  577. ss << fmt::format(" int {};\n", it.first);
  578. else
  579. ss << fmt::format(" int{} {};\n", count, it.first);
  580. for (u32 i = count; i < 4; i++)
  581. ss << " int ubo_align_" << unused_counter++ << "_;\n";
  582. }
  583. else if (it.second.m_type ==
  584. PostProcessingConfiguration::ConfigurationOption::OptionType::Float)
  585. {
  586. u32 count = static_cast<u32>(it.second.m_float_values.size());
  587. if (count == 1)
  588. ss << fmt::format(" float {};\n", it.first);
  589. else
  590. ss << fmt::format(" float{} {};\n", count, it.first);
  591. for (u32 i = count; i < 4; i++)
  592. ss << " float ubo_align_" << unused_counter++ << "_;\n";
  593. }
  594. }
  595. }
  596. ss << "};\n\n";
  597. return ss.str();
  598. }
  599. std::string PostProcessing::GetHeader(bool user_post_process) const
  600. {
  601. std::ostringstream ss;
  602. ss << GetUniformBufferHeader(user_post_process);
  603. ss << "SAMPLER_BINDING(0) uniform sampler2DArray samp0;\n";
  604. ss << "SAMPLER_BINDING(1) uniform sampler2DArray samp1;\n";
  605. if (g_ActiveConfig.backend_info.bSupportsGeometryShaders)
  606. {
  607. ss << "VARYING_LOCATION(0) in VertexData {\n";
  608. ss << " float3 v_tex0;\n";
  609. ss << "};\n";
  610. }
  611. else
  612. {
  613. ss << "VARYING_LOCATION(0) in float3 v_tex0;\n";
  614. }
  615. ss << "FRAGMENT_OUTPUT_LOCATION(0) out float4 ocol0;\n";
  616. ss << R"(
  617. float4 Sample() { return texture(samp0, v_tex0); }
  618. float4 SampleLocation(float2 location) { return texture(samp0, float3(location, float(v_tex0.z))); }
  619. float4 SampleLayer(int layer) { return texture(samp0, float3(v_tex0.xy, float(layer))); }
  620. #define SampleOffset(offset) textureOffset(samp0, v_tex0, offset)
  621. float2 GetTargetResolution()
  622. {
  623. return target_resolution.xy;
  624. }
  625. float2 GetInvTargetResolution()
  626. {
  627. return target_resolution.zw;
  628. }
  629. float2 GetWindowResolution()
  630. {
  631. return window_resolution.xy;
  632. }
  633. float2 GetInvWindowResolution()
  634. {
  635. return window_resolution.zw;
  636. }
  637. float2 GetResolution()
  638. {
  639. return resolution.xy;
  640. }
  641. float2 GetInvResolution()
  642. {
  643. return resolution.zw;
  644. }
  645. float2 GetCoordinates()
  646. {
  647. return v_tex0.xy;
  648. }
  649. float GetLayer()
  650. {
  651. return v_tex0.z;
  652. }
  653. uint GetTime()
  654. {
  655. return time;
  656. }
  657. void SetOutput(float4 color)
  658. {
  659. ocol0 = color;
  660. }
  661. #define GetOption(x) (x)
  662. #define OptionEnabled(x) ((x) != 0)
  663. #define OptionDisabled(x) ((x) == 0)
  664. )";
  665. return ss.str();
  666. }
  667. std::string PostProcessing::GetFooter() const
  668. {
  669. return {};
  670. }
  671. static std::string GetVertexShaderBody()
  672. {
  673. std::ostringstream ss;
  674. if (g_ActiveConfig.backend_info.bSupportsGeometryShaders)
  675. {
  676. ss << "VARYING_LOCATION(0) out VertexData {\n";
  677. ss << " float3 v_tex0;\n";
  678. ss << "};\n";
  679. }
  680. else
  681. {
  682. ss << "VARYING_LOCATION(0) out float3 v_tex0;\n";
  683. }
  684. ss << "#define id gl_VertexID\n";
  685. ss << "#define opos gl_Position\n";
  686. ss << "void main() {\n";
  687. ss << " v_tex0 = float3(float((id << 1) & 2), float(id & 2), 0.0f);\n";
  688. ss << " opos = float4(v_tex0.xy * float2(2.0f, -2.0f) + float2(-1.0f, 1.0f), 0.0f, 1.0f);\n";
  689. ss << " v_tex0 = float3(src_rect.xy + (src_rect.zw * v_tex0.xy), float(src_layer));\n";
  690. // Vulkan Y needs to be inverted on every pass
  691. if (g_ActiveConfig.backend_info.api_type == APIType::Vulkan)
  692. {
  693. ss << " opos.y = -opos.y;\n";
  694. }
  695. // OpenGL Y needs to be inverted in all passes except the last one
  696. else if (g_ActiveConfig.backend_info.api_type == APIType::OpenGL)
  697. {
  698. ss << " if (intermediary_buffer != 0)\n";
  699. ss << " opos.y = -opos.y;\n";
  700. }
  701. ss << "}\n";
  702. return ss.str();
  703. }
  704. bool PostProcessing::CompileVertexShader()
  705. {
  706. std::ostringstream ss_default;
  707. ss_default << GetUniformBufferHeader(false);
  708. ss_default << GetVertexShaderBody();
  709. m_default_vertex_shader = g_gfx->CreateShaderFromSource(ShaderStage::Vertex, ss_default.str(),
  710. "Default post-processing vertex shader");
  711. std::ostringstream ss;
  712. ss << GetUniformBufferHeader(true);
  713. ss << GetVertexShaderBody();
  714. m_vertex_shader =
  715. g_gfx->CreateShaderFromSource(ShaderStage::Vertex, ss.str(), "Post-processing vertex shader");
  716. if (!m_default_vertex_shader || !m_vertex_shader)
  717. {
  718. PanicAlertFmt("Failed to compile post-processing vertex shader");
  719. m_default_vertex_shader.reset();
  720. m_vertex_shader.reset();
  721. return false;
  722. }
  723. return true;
  724. }
  725. struct BuiltinUniforms
  726. {
  727. // bools need to be represented as "s32"
  728. std::array<float, 4> source_resolution;
  729. std::array<float, 4> target_resolution;
  730. std::array<float, 4> window_resolution;
  731. std::array<float, 4> stereo_views;
  732. std::array<float, 4> src_rect;
  733. s32 src_layer;
  734. u32 time;
  735. s32 graphics_api;
  736. s32 intermediary_buffer;
  737. s32 resampling_method;
  738. s32 correct_color_space;
  739. s32 game_color_space;
  740. s32 correct_gamma;
  741. float game_gamma;
  742. s32 sdr_display_gamma_sRGB;
  743. float sdr_display_custom_gamma;
  744. s32 linear_space_output;
  745. s32 hdr_output;
  746. float hdr_paper_white_nits;
  747. float hdr_sdr_white_nits;
  748. };
  749. size_t PostProcessing::CalculateUniformsSize(bool user_post_process) const
  750. {
  751. // Allocate a vec4 for each uniform to simplify allocation.
  752. return sizeof(BuiltinUniforms) +
  753. (user_post_process ? m_config.GetOptions().size() : 0) * sizeof(float) * 4;
  754. }
  755. void PostProcessing::FillUniformBuffer(const MathUtil::Rectangle<int>& src,
  756. const AbstractTexture* src_tex, int src_layer,
  757. const MathUtil::Rectangle<int>& dst,
  758. const MathUtil::Rectangle<int>& wnd, u8* buffer,
  759. bool user_post_process, bool intermediary_buffer)
  760. {
  761. const float rcp_src_width = 1.0f / src_tex->GetWidth();
  762. const float rcp_src_height = 1.0f / src_tex->GetHeight();
  763. BuiltinUniforms builtin_uniforms;
  764. builtin_uniforms.source_resolution = {static_cast<float>(src_tex->GetWidth()),
  765. static_cast<float>(src_tex->GetHeight()), rcp_src_width,
  766. rcp_src_height};
  767. builtin_uniforms.target_resolution = {
  768. static_cast<float>(dst.GetWidth()), static_cast<float>(dst.GetHeight()),
  769. 1.0f / static_cast<float>(dst.GetWidth()), 1.0f / static_cast<float>(dst.GetHeight())};
  770. builtin_uniforms.window_resolution = {
  771. static_cast<float>(wnd.GetWidth()), static_cast<float>(wnd.GetHeight()),
  772. 1.0f / static_cast<float>(wnd.GetWidth()), 1.0f / static_cast<float>(wnd.GetHeight())};
  773. builtin_uniforms.src_rect = {static_cast<float>(src.left) * rcp_src_width,
  774. static_cast<float>(src.top) * rcp_src_height,
  775. static_cast<float>(src.GetWidth()) * rcp_src_width,
  776. static_cast<float>(src.GetHeight()) * rcp_src_height};
  777. builtin_uniforms.src_layer = static_cast<s32>(src_layer);
  778. builtin_uniforms.time = static_cast<u32>(m_timer.ElapsedMs());
  779. builtin_uniforms.graphics_api = static_cast<s32>(g_ActiveConfig.backend_info.api_type);
  780. builtin_uniforms.intermediary_buffer = static_cast<s32>(intermediary_buffer);
  781. builtin_uniforms.resampling_method = static_cast<s32>(g_ActiveConfig.output_resampling_mode);
  782. // Color correction related uniforms.
  783. // These are mainly used by the "m_default_pixel_shader",
  784. // but should also be accessible to all other shaders.
  785. builtin_uniforms.correct_color_space = g_ActiveConfig.color_correction.bCorrectColorSpace;
  786. builtin_uniforms.game_color_space =
  787. static_cast<int>(g_ActiveConfig.color_correction.game_color_space);
  788. builtin_uniforms.correct_gamma = g_ActiveConfig.color_correction.bCorrectGamma;
  789. builtin_uniforms.game_gamma = g_ActiveConfig.color_correction.fGameGamma;
  790. builtin_uniforms.sdr_display_gamma_sRGB = g_ActiveConfig.color_correction.bSDRDisplayGammaSRGB;
  791. builtin_uniforms.sdr_display_custom_gamma =
  792. g_ActiveConfig.color_correction.fSDRDisplayCustomGamma;
  793. // scRGB (RGBA16F) expects linear values as opposed to sRGB gamma
  794. builtin_uniforms.linear_space_output = m_framebuffer_format == AbstractTextureFormat::RGBA16F;
  795. // Implies ouput values can be beyond the 0-1 range
  796. builtin_uniforms.hdr_output = m_framebuffer_format == AbstractTextureFormat::RGBA16F;
  797. builtin_uniforms.hdr_paper_white_nits = g_ActiveConfig.color_correction.fHDRPaperWhiteNits;
  798. // A value of 1 1 1 usually matches 80 nits in HDR
  799. builtin_uniforms.hdr_sdr_white_nits = 80.f;
  800. std::memcpy(buffer, &builtin_uniforms, sizeof(builtin_uniforms));
  801. buffer += sizeof(builtin_uniforms);
  802. // Don't include the custom pp shader options if they are not necessary,
  803. // having mismatching uniforms between different shaders can cause issues on some backends
  804. if (!user_post_process)
  805. return;
  806. for (auto& it : m_config.GetOptions())
  807. {
  808. union
  809. {
  810. u32 as_bool[4];
  811. s32 as_int[4];
  812. float as_float[4];
  813. } value = {};
  814. switch (it.second.m_type)
  815. {
  816. case PostProcessingConfiguration::ConfigurationOption::OptionType::Bool:
  817. value.as_bool[0] = it.second.m_bool_value ? 1 : 0;
  818. break;
  819. case PostProcessingConfiguration::ConfigurationOption::OptionType::Integer:
  820. ASSERT(it.second.m_integer_values.size() <= 4);
  821. std::copy_n(it.second.m_integer_values.begin(), it.second.m_integer_values.size(),
  822. value.as_int);
  823. break;
  824. case PostProcessingConfiguration::ConfigurationOption::OptionType::Float:
  825. ASSERT(it.second.m_float_values.size() <= 4);
  826. std::copy_n(it.second.m_float_values.begin(), it.second.m_float_values.size(),
  827. value.as_float);
  828. break;
  829. }
  830. it.second.m_dirty = false;
  831. std::memcpy(buffer, &value, sizeof(value));
  832. buffer += sizeof(value);
  833. }
  834. m_config.SetDirty(false);
  835. }
  836. bool PostProcessing::CompilePixelShader()
  837. {
  838. m_default_pixel_shader.reset();
  839. m_pixel_shader.reset();
  840. // Generate GLSL and compile the new shaders:
  841. std::string default_pixel_shader_code;
  842. if (LoadShaderFromFile(s_default_pixel_shader_name, "", default_pixel_shader_code))
  843. {
  844. m_default_pixel_shader = g_gfx->CreateShaderFromSource(
  845. ShaderStage::Pixel, GetHeader(false) + default_pixel_shader_code + GetFooter(),
  846. "Default post-processing pixel shader");
  847. // We continue even if all of this failed, it doesn't matter
  848. m_default_uniform_staging_buffer.resize(CalculateUniformsSize(false));
  849. }
  850. else
  851. {
  852. m_default_uniform_staging_buffer.resize(0);
  853. }
  854. m_config.LoadShader(g_ActiveConfig.sPostProcessingShader);
  855. m_pixel_shader = g_gfx->CreateShaderFromSource(
  856. ShaderStage::Pixel, GetHeader(true) + m_config.GetShaderCode() + GetFooter(),
  857. fmt::format("User post-processing pixel shader: {}", m_config.GetShader()));
  858. if (!m_pixel_shader)
  859. {
  860. PanicAlertFmt("Failed to compile user post-processing shader {}", m_config.GetShader());
  861. // Use default shader.
  862. m_config.LoadDefaultShader();
  863. m_pixel_shader = g_gfx->CreateShaderFromSource(
  864. ShaderStage::Pixel, GetHeader(true) + m_config.GetShaderCode() + GetFooter(),
  865. "Default user post-processing pixel shader");
  866. if (!m_pixel_shader)
  867. {
  868. m_uniform_staging_buffer.resize(0);
  869. return false;
  870. }
  871. }
  872. m_uniform_staging_buffer.resize(CalculateUniformsSize(true));
  873. return true;
  874. }
  875. static bool UseGeometryShaderForPostProcess(bool is_intermediary_buffer)
  876. {
  877. // We only return true on stereo modes that need to copy
  878. // both source texture layers into the target texture layers.
  879. // Any other case is handled manually with multiple copies, thus
  880. // it doesn't need a geom shader.
  881. switch (g_ActiveConfig.stereo_mode)
  882. {
  883. case StereoMode::QuadBuffer:
  884. return !g_ActiveConfig.backend_info.bUsesExplictQuadBuffering;
  885. case StereoMode::Anaglyph:
  886. case StereoMode::Passive:
  887. return is_intermediary_buffer;
  888. case StereoMode::SBS:
  889. case StereoMode::TAB:
  890. case StereoMode::Off:
  891. default:
  892. return false;
  893. }
  894. }
  895. bool PostProcessing::CompilePipeline()
  896. {
  897. // Not needed. Some backends don't like making pipelines with no targets,
  898. // and in any case, we don't need to render anything if that happened.
  899. if (m_framebuffer_format == AbstractTextureFormat::Undefined)
  900. return true;
  901. // If this is true, the "m_default_pipeline" won't be the only one that runs
  902. const bool needs_intermediary_buffer = NeedsIntermediaryBuffer();
  903. AbstractPipelineConfig config = {};
  904. config.vertex_shader = m_default_vertex_shader.get();
  905. // This geometry shader will take care of reading both layer 0 and 1 on the source texture,
  906. // and writing to both layer 0 and 1 on the render target.
  907. config.geometry_shader = UseGeometryShaderForPostProcess(needs_intermediary_buffer) ?
  908. g_shader_cache->GetTexcoordGeometryShader() :
  909. nullptr;
  910. config.pixel_shader = m_default_pixel_shader.get();
  911. config.rasterization_state = RenderState::GetNoCullRasterizationState(PrimitiveType::Triangles);
  912. config.depth_state = RenderState::GetNoDepthTestingDepthState();
  913. config.blending_state = RenderState::GetNoBlendingBlendState();
  914. config.framebuffer_state = RenderState::GetColorFramebufferState(
  915. needs_intermediary_buffer ? s_intermediary_buffer_format : m_framebuffer_format);
  916. config.usage = AbstractPipelineUsage::Utility;
  917. // We continue even if it failed, it will be skipped later on
  918. if (config.pixel_shader)
  919. m_default_pipeline = g_gfx->CreatePipeline(config);
  920. config.vertex_shader = m_vertex_shader.get();
  921. config.geometry_shader = UseGeometryShaderForPostProcess(false) ?
  922. g_shader_cache->GetTexcoordGeometryShader() :
  923. nullptr;
  924. config.pixel_shader = m_pixel_shader.get();
  925. config.framebuffer_state = RenderState::GetColorFramebufferState(m_framebuffer_format);
  926. m_pipeline = g_gfx->CreatePipeline(config);
  927. if (!m_pipeline)
  928. return false;
  929. return true;
  930. }
  931. } // namespace VideoCommon