PostProcessing.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. // Copyright 2014 Dolphin Emulator Project
  2. // Licensed under GPLv2+
  3. // Refer to the license.txt file included.
  4. #include <string>
  5. #include "Common/CommonPaths.h"
  6. #include "Common/FileUtil.h"
  7. #include "Common/IniFile.h"
  8. #include "Common/StringUtil.h"
  9. #include "VideoCommon/PostProcessing.h"
  10. #include "VideoCommon/VideoConfig.h"
  11. static const char s_default_shader[] = "void main() { SetOutput(Sample()); }\n";
  12. PostProcessingShaderImplementation::PostProcessingShaderImplementation()
  13. {
  14. m_timer.Start();
  15. }
  16. PostProcessingShaderImplementation::~PostProcessingShaderImplementation()
  17. {
  18. m_timer.Stop();
  19. }
  20. std::string PostProcessingShaderConfiguration::LoadShader(std::string shader)
  21. {
  22. // Load the shader from the configuration if there isn't one sent to us.
  23. if (shader == "")
  24. shader = g_ActiveConfig.sPostProcessingShader;
  25. m_current_shader = shader;
  26. const std::string sub_dir = (g_Config.iStereoMode == STEREO_ANAGLYPH) ? ANAGLYPH_DIR DIR_SEP : "";
  27. // loading shader code
  28. std::string code;
  29. std::string path = File::GetUserPath(D_SHADERS_IDX) + sub_dir + shader + ".glsl";
  30. if (shader == "")
  31. {
  32. code = s_default_shader;
  33. }
  34. else
  35. {
  36. if (!File::Exists(path))
  37. {
  38. // Fallback to shared user dir
  39. path = File::GetSysDirectory() + SHADERS_DIR DIR_SEP + sub_dir + shader + ".glsl";
  40. }
  41. if (!File::ReadFileToString(path, code))
  42. {
  43. ERROR_LOG(VIDEO, "Post-processing shader not found: %s", path.c_str());
  44. code = s_default_shader;
  45. }
  46. }
  47. LoadOptions(code);
  48. LoadOptionsConfiguration();
  49. return code;
  50. }
  51. void PostProcessingShaderConfiguration::LoadOptions(const std::string& code)
  52. {
  53. const std::string config_start_delimiter = "[configuration]";
  54. const std::string config_end_delimiter = "[/configuration]";
  55. size_t configuration_start = code.find(config_start_delimiter);
  56. size_t configuration_end = code.find(config_end_delimiter);
  57. m_options.clear();
  58. m_any_options_dirty = true;
  59. if (configuration_start == std::string::npos ||
  60. configuration_end == std::string::npos)
  61. {
  62. // Issue loading configuration or there isn't one.
  63. return;
  64. }
  65. std::string configuration_string = code.substr(configuration_start + config_start_delimiter.size(),
  66. configuration_end - configuration_start - config_start_delimiter.size());
  67. std::istringstream in(configuration_string);
  68. struct GLSLStringOption
  69. {
  70. std::string m_type;
  71. std::vector<std::pair<std::string, std::string>> m_options;
  72. };
  73. std::vector<GLSLStringOption> option_strings;
  74. GLSLStringOption* current_strings = nullptr;
  75. while (!in.eof())
  76. {
  77. std::string line;
  78. if (std::getline(in, line))
  79. {
  80. #ifndef _WIN32
  81. // Check for CRLF eol and convert it to LF
  82. if (!line.empty() && line.at(line.size()-1) == '\r')
  83. {
  84. line.erase(line.size()-1);
  85. }
  86. #endif
  87. if (line.size() > 0)
  88. {
  89. if (line[0] == '[')
  90. {
  91. size_t endpos = line.find("]");
  92. if (endpos != std::string::npos)
  93. {
  94. // New section!
  95. std::string sub = line.substr(1, endpos - 1);
  96. option_strings.push_back({ sub });
  97. current_strings = &option_strings.back();
  98. }
  99. }
  100. else
  101. {
  102. if (current_strings)
  103. {
  104. std::string key, value;
  105. IniFile::ParseLine(line, &key, &value);
  106. if (!(key == "" && value == ""))
  107. current_strings->m_options.emplace_back(key, value);
  108. }
  109. }
  110. }
  111. }
  112. }
  113. for (const auto& it : option_strings)
  114. {
  115. ConfigurationOption option;
  116. option.m_dirty = true;
  117. if (it.m_type == "OptionBool")
  118. option.m_type = ConfigurationOption::OptionType::OPTION_BOOL;
  119. else if (it.m_type == "OptionRangeFloat")
  120. option.m_type = ConfigurationOption::OptionType::OPTION_FLOAT;
  121. else if (it.m_type == "OptionRangeInteger")
  122. option.m_type = ConfigurationOption::OptionType::OPTION_INTEGER;
  123. for (const auto& string_option : it.m_options)
  124. {
  125. if (string_option.first == "GUIName")
  126. {
  127. option.m_gui_name = string_option.second;
  128. }
  129. else if (string_option.first == "OptionName")
  130. {
  131. option.m_option_name = string_option.second;
  132. }
  133. else if (string_option.first == "DependentOption")
  134. {
  135. option.m_dependent_option = string_option.second;
  136. }
  137. else if (string_option.first == "MinValue" ||
  138. string_option.first == "MaxValue" ||
  139. string_option.first == "DefaultValue" ||
  140. string_option.first == "StepAmount")
  141. {
  142. std::vector<s32>* output_integer = nullptr;
  143. std::vector<float>* output_float = nullptr;
  144. if (string_option.first == "MinValue")
  145. {
  146. output_integer = &option.m_integer_min_values;
  147. output_float = &option.m_float_min_values;
  148. }
  149. else if (string_option.first == "MaxValue")
  150. {
  151. output_integer = &option.m_integer_max_values;
  152. output_float = &option.m_float_max_values;
  153. }
  154. else if (string_option.first == "DefaultValue")
  155. {
  156. output_integer = &option.m_integer_values;
  157. output_float = &option.m_float_values;
  158. }
  159. else if (string_option.first == "StepAmount")
  160. {
  161. output_integer = &option.m_integer_step_values;
  162. output_float = &option.m_float_step_values;
  163. }
  164. if (option.m_type == ConfigurationOption::OptionType::OPTION_BOOL)
  165. {
  166. TryParse(string_option.second, &option.m_bool_value);
  167. }
  168. else if (option.m_type == ConfigurationOption::OptionType::OPTION_INTEGER)
  169. {
  170. TryParseVector(string_option.second, output_integer);
  171. if (output_integer->size() > 4)
  172. output_integer->erase(output_integer->begin() + 4, output_integer->end());
  173. }
  174. else if (option.m_type == ConfigurationOption::OptionType::OPTION_FLOAT)
  175. {
  176. TryParseVector(string_option.second, output_float);
  177. if (output_float->size() > 4)
  178. output_float->erase(output_float->begin() + 4, output_float->end());
  179. }
  180. }
  181. }
  182. m_options[option.m_option_name] = option;
  183. }
  184. }
  185. void PostProcessingShaderConfiguration::LoadOptionsConfiguration()
  186. {
  187. IniFile ini;
  188. ini.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX));
  189. std::string section = m_current_shader + "-options";
  190. for (auto& it : m_options)
  191. {
  192. switch (it.second.m_type)
  193. {
  194. case ConfigurationOption::OptionType::OPTION_BOOL:
  195. ini.GetOrCreateSection(section)->Get(it.second.m_option_name, &it.second.m_bool_value, it.second.m_bool_value);
  196. break;
  197. case ConfigurationOption::OptionType::OPTION_INTEGER:
  198. {
  199. std::string value;
  200. ini.GetOrCreateSection(section)->Get(it.second.m_option_name, &value);
  201. if (value != "")
  202. TryParseVector(value, &it.second.m_integer_values);
  203. }
  204. break;
  205. case ConfigurationOption::OptionType::OPTION_FLOAT:
  206. {
  207. std::string value;
  208. ini.GetOrCreateSection(section)->Get(it.second.m_option_name, &value);
  209. if (value != "")
  210. TryParseVector(value, &it.second.m_float_values);
  211. }
  212. break;
  213. }
  214. }
  215. }
  216. void PostProcessingShaderConfiguration::SaveOptionsConfiguration()
  217. {
  218. IniFile ini;
  219. ini.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX));
  220. std::string section = m_current_shader + "-options";
  221. for (auto& it : m_options)
  222. {
  223. switch (it.second.m_type)
  224. {
  225. case ConfigurationOption::OptionType::OPTION_BOOL:
  226. {
  227. ini.GetOrCreateSection(section)->Set(it.second.m_option_name, it.second.m_bool_value);
  228. }
  229. break;
  230. case ConfigurationOption::OptionType::OPTION_INTEGER:
  231. {
  232. std::string value = "";
  233. for (size_t i = 0; i < it.second.m_integer_values.size(); ++i)
  234. value += StringFromFormat("%d%s", it.second.m_integer_values[i], i == (it.second.m_integer_values.size() - 1) ? "": ", ");
  235. ini.GetOrCreateSection(section)->Set(it.second.m_option_name, value);
  236. }
  237. break;
  238. case ConfigurationOption::OptionType::OPTION_FLOAT:
  239. {
  240. std::ostringstream value;
  241. value.imbue(std::locale("C"));
  242. for (size_t i = 0; i < it.second.m_float_values.size(); ++i)
  243. {
  244. value << it.second.m_float_values[i];
  245. if (i != (it.second.m_float_values.size() - 1))
  246. value << ", ";
  247. }
  248. ini.GetOrCreateSection(section)->Set(it.second.m_option_name, value.str());
  249. }
  250. break;
  251. }
  252. }
  253. ini.Save(File::GetUserPath(F_DOLPHINCONFIG_IDX));
  254. }
  255. void PostProcessingShaderConfiguration::ReloadShader()
  256. {
  257. m_current_shader = "";
  258. }
  259. void PostProcessingShaderConfiguration::SetOptionf(const std::string& option, int index, float value)
  260. {
  261. auto it = m_options.find(option);
  262. it->second.m_float_values[index] = value;
  263. it->second.m_dirty = true;
  264. m_any_options_dirty = true;
  265. }
  266. void PostProcessingShaderConfiguration::SetOptioni(const std::string& option, int index, s32 value)
  267. {
  268. auto it = m_options.find(option);
  269. it->second.m_integer_values[index] = value;
  270. it->second.m_dirty = true;
  271. m_any_options_dirty = true;
  272. }
  273. void PostProcessingShaderConfiguration::SetOptionb(const std::string& option, bool value)
  274. {
  275. auto it = m_options.find(option);
  276. it->second.m_bool_value = value;
  277. it->second.m_dirty = true;
  278. m_any_options_dirty = true;
  279. }