/ src / common / settings.h
settings.h
  1  // Copyright 2014 Citra Emulator Project
  2  // Licensed under GPLv2 or any later version
  3  // Refer to the license.txt file included.
  4  
  5  #pragma once
  6  
  7  #include <algorithm>
  8  #include <array>
  9  #include <atomic>
 10  #include <string>
 11  #include <unordered_map>
 12  #include <vector>
 13  #include "audio_core/input_details.h"
 14  #include "audio_core/sink_details.h"
 15  #include "common/common_types.h"
 16  #include "core/hle/service/cam/cam_params.h"
 17  
 18  namespace Settings {
 19  
 20  enum class GraphicsAPI {
 21      Software = 0,
 22      OpenGL = 1,
 23      Vulkan = 2,
 24  };
 25  
 26  enum class InitClock : u32 {
 27      SystemTime = 0,
 28      FixedTime = 1,
 29  };
 30  
 31  enum class InitTicks : u32 {
 32      Random = 0,
 33      Fixed = 1,
 34  };
 35  
 36  enum class LayoutOption : u32 {
 37      Default,
 38      SingleScreen,
 39      LargeScreen,
 40      SideScreen,
 41  #ifndef ANDROID
 42      SeparateWindows,
 43  #endif
 44      HybridScreen,
 45      // Similiar to default, but better for mobile devices in portrait mode. Top screen in clamped to
 46      // the top of the frame, and the bottom screen is enlarged to match the top screen.
 47      MobilePortrait,
 48  
 49      // Similiar to LargeScreen, but better for mobile devices in landscape mode. The screens are
 50      // clamped to the top of the frame, and the bottom screen is a bit bigger.
 51      MobileLandscape,
 52  };
 53  
 54  enum class StereoRenderOption : u32 {
 55      Off = 0,
 56      SideBySide = 1,
 57      Anaglyph = 2,
 58      Interlaced = 3,
 59      ReverseInterlaced = 4,
 60      CardboardVR = 5
 61  };
 62  
 63  // Which eye to render when 3d is off. 800px wide mode could be added here in the future, when
 64  // implemented
 65  enum class MonoRenderOption : u32 {
 66      LeftEye = 0,
 67      RightEye = 1,
 68  };
 69  
 70  enum class AudioEmulation : u32 {
 71      HLE = 0,
 72      LLE = 1,
 73      LLEMultithreaded = 2,
 74  };
 75  
 76  enum class TextureFilter : u32 {
 77      None = 0,
 78      Anime4K = 1,
 79      Bicubic = 2,
 80      ScaleForce = 3,
 81      xBRZ = 4,
 82      MMPX = 5,
 83  };
 84  
 85  enum class TextureSampling : u32 {
 86      GameControlled = 0,
 87      NearestNeighbor = 1,
 88      Linear = 2,
 89  };
 90  
 91  namespace NativeButton {
 92  
 93  enum Values {
 94      A,
 95      B,
 96      X,
 97      Y,
 98      Up,
 99      Down,
100      Left,
101      Right,
102      L,
103      R,
104      Start,
105      Select,
106      Debug,
107      Gpio14,
108  
109      ZL,
110      ZR,
111  
112      Home,
113      Power,
114  
115      NumButtons,
116  };
117  
118  constexpr int BUTTON_HID_BEGIN = A;
119  constexpr int BUTTON_IR_BEGIN = ZL;
120  constexpr int BUTTON_NS_BEGIN = Power;
121  
122  constexpr int BUTTON_HID_END = BUTTON_IR_BEGIN;
123  constexpr int BUTTON_IR_END = BUTTON_NS_BEGIN;
124  constexpr int BUTTON_NS_END = NumButtons;
125  
126  constexpr int NUM_BUTTONS_HID = BUTTON_HID_END - BUTTON_HID_BEGIN;
127  constexpr int NUM_BUTTONS_IR = BUTTON_IR_END - BUTTON_IR_BEGIN;
128  constexpr int NUM_BUTTONS_NS = BUTTON_NS_END - BUTTON_NS_BEGIN;
129  
130  static const std::array<const char*, NumButtons> mapping = {{
131      "button_a",
132      "button_b",
133      "button_x",
134      "button_y",
135      "button_up",
136      "button_down",
137      "button_left",
138      "button_right",
139      "button_l",
140      "button_r",
141      "button_start",
142      "button_select",
143      "button_debug",
144      "button_gpio14",
145      "button_zl",
146      "button_zr",
147      "button_home",
148      "button_power",
149  }};
150  
151  } // namespace NativeButton
152  
153  namespace NativeAnalog {
154  enum Values {
155      CirclePad,
156      CStick,
157      NumAnalogs,
158  };
159  
160  constexpr std::array<const char*, NumAnalogs> mapping = {{
161      "circle_pad",
162      "c_stick",
163  }};
164  } // namespace NativeAnalog
165  
166  /** The Setting class is a simple resource manager. It defines a label and default value alongside
167   * the actual value of the setting for simpler and less-error prone use with frontend
168   * configurations. Specifying a default value and label is required. A minimum and maximum range can
169   * be specified for sanitization.
170   */
171  template <typename Type, bool ranged = false>
172  class Setting {
173  protected:
174      Setting() = default;
175  
176      /**
177       * Only sets the setting to the given initializer, leaving the other members to their default
178       * initializers.
179       *
180       * @param global_val Initial value of the setting
181       */
182      explicit Setting(const Type& val) : value{val} {}
183  
184  public:
185      /**
186       * Sets a default value, label, and setting value.
187       *
188       * @param default_val Intial value of the setting, and default value of the setting
189       * @param name Label for the setting
190       */
191      explicit Setting(const Type& default_val, const std::string& name)
192          requires(!ranged)
193          : value{default_val}, default_value{default_val}, label{name} {}
194      virtual ~Setting() = default;
195  
196      /**
197       * Sets a default value, minimum value, maximum value, and label.
198       *
199       * @param default_val Intial value of the setting, and default value of the setting
200       * @param min_val Sets the minimum allowed value of the setting
201       * @param max_val Sets the maximum allowed value of the setting
202       * @param name Label for the setting
203       */
204      explicit Setting(const Type& default_val, const Type& min_val, const Type& max_val,
205                       const std::string& name)
206          requires(ranged)
207          : value{default_val},
208            default_value{default_val}, maximum{max_val}, minimum{min_val}, label{name} {}
209  
210      /**
211       *  Returns a reference to the setting's value.
212       *
213       * @returns A reference to the setting
214       */
215      [[nodiscard]] virtual const Type& GetValue() const {
216          return value;
217      }
218  
219      /**
220       * Sets the setting to the given value.
221       *
222       * @param val The desired value
223       */
224      virtual void SetValue(const Type& val) {
225          Type temp{ranged ? std::clamp(val, minimum, maximum) : val};
226          std::swap(value, temp);
227      }
228  
229      /**
230       * Returns the value that this setting was created with.
231       *
232       * @returns A reference to the default value
233       */
234      [[nodiscard]] const Type& GetDefault() const {
235          return default_value;
236      }
237  
238      /**
239       * Returns the label this setting was created with.
240       *
241       * @returns A reference to the label
242       */
243      [[nodiscard]] const std::string& GetLabel() const {
244          return label;
245      }
246  
247      /**
248       * Assigns a value to the setting.
249       *
250       * @param val The desired setting value
251       *
252       * @returns A reference to the setting
253       */
254      virtual const Type& operator=(const Type& val) {
255          Type temp{ranged ? std::clamp(val, minimum, maximum) : val};
256          std::swap(value, temp);
257          return value;
258      }
259  
260      /**
261       * Returns a reference to the setting.
262       *
263       * @returns A reference to the setting
264       */
265      explicit virtual operator const Type&() const {
266          return value;
267      }
268  
269  protected:
270      Type value{};               ///< The setting
271      const Type default_value{}; ///< The default value
272      const Type maximum{};       ///< Maximum allowed value of the setting
273      const Type minimum{};       ///< Minimum allowed value of the setting
274      const std::string label{};  ///< The setting's label
275  };
276  
277  /**
278   * The SwitchableSetting class is a slightly more complex version of the Setting class. This adds a
279   * custom setting to switch to when a guest application specifically requires it. The effect is that
280   * other components of the emulator can access the setting's intended value without any need for the
281   * component to ask whether the custom or global setting is needed at the moment.
282   *
283   * By default, the global setting is used.
284   */
285  template <typename Type, bool ranged = false>
286  class SwitchableSetting : virtual public Setting<Type, ranged> {
287  public:
288      /**
289       * Sets a default value, label, and setting value.
290       *
291       * @param default_val Intial value of the setting, and default value of the setting
292       * @param name Label for the setting
293       */
294      explicit SwitchableSetting(const Type& default_val, const std::string& name)
295          requires(!ranged)
296          : Setting<Type>{default_val, name} {}
297      virtual ~SwitchableSetting() = default;
298  
299      /**
300       * Sets a default value, minimum value, maximum value, and label.
301       *
302       * @param default_val Intial value of the setting, and default value of the setting
303       * @param min_val Sets the minimum allowed value of the setting
304       * @param max_val Sets the maximum allowed value of the setting
305       * @param name Label for the setting
306       */
307      explicit SwitchableSetting(const Type& default_val, const Type& min_val, const Type& max_val,
308                                 const std::string& name)
309          requires(ranged)
310          : Setting<Type, true>{default_val, min_val, max_val, name} {}
311  
312      /**
313       * Tells this setting to represent either the global or custom setting when other member
314       * functions are used.
315       *
316       * @param to_global Whether to use the global or custom setting.
317       */
318      void SetGlobal(bool to_global) {
319          use_global = to_global;
320      }
321  
322      /**
323       * Returns whether this setting is using the global setting or not.
324       *
325       * @returns The global state
326       */
327      [[nodiscard]] bool UsingGlobal() const {
328          return use_global;
329      }
330  
331      /**
332       * Returns either the global or custom setting depending on the values of this setting's global
333       * state or if the global value was specifically requested.
334       *
335       * @param need_global Request global value regardless of setting's state; defaults to false
336       *
337       * @returns The required value of the setting
338       */
339      [[nodiscard]] virtual const Type& GetValue() const override {
340          if (use_global) {
341              return this->value;
342          }
343          return custom;
344      }
345      [[nodiscard]] virtual const Type& GetValue(bool need_global) const {
346          if (use_global || need_global) {
347              return this->value;
348          }
349          return custom;
350      }
351  
352      /**
353       * Sets the current setting value depending on the global state.
354       *
355       * @param val The new value
356       */
357      void SetValue(const Type& val) override {
358          Type temp{ranged ? std::clamp(val, this->minimum, this->maximum) : val};
359          if (use_global) {
360              std::swap(this->value, temp);
361          } else {
362              std::swap(custom, temp);
363          }
364      }
365  
366      /**
367       * Assigns the current setting value depending on the global state.
368       *
369       * @param val The new value
370       *
371       * @returns A reference to the current setting value
372       */
373      const Type& operator=(const Type& val) override {
374          Type temp{ranged ? std::clamp(val, this->minimum, this->maximum) : val};
375          if (use_global) {
376              std::swap(this->value, temp);
377              return this->value;
378          }
379          std::swap(custom, temp);
380          return custom;
381      }
382  
383      /**
384       * Returns the current setting value depending on the global state.
385       *
386       * @returns A reference to the current setting value
387       */
388      virtual explicit operator const Type&() const override {
389          if (use_global) {
390              return this->value;
391          }
392          return custom;
393      }
394  
395  protected:
396      bool use_global{true}; ///< The setting's global state
397      Type custom{};         ///< The custom value of the setting
398  };
399  
400  struct InputProfile {
401      std::string name;
402      std::array<std::string, NativeButton::NumButtons> buttons;
403      std::array<std::string, NativeAnalog::NumAnalogs> analogs;
404      std::string motion_device;
405      std::string touch_device;
406      bool use_touch_from_button;
407      int touch_from_button_map_index;
408      std::string udp_input_address;
409      u16 udp_input_port;
410      u8 udp_pad_index;
411  };
412  
413  struct TouchFromButtonMap {
414      std::string name;
415      std::vector<std::string> buttons;
416  };
417  
418  /// A special region value indicating that citra will automatically select a region
419  /// value to fit the region lockout info of the game
420  static constexpr s32 REGION_VALUE_AUTO_SELECT = -1;
421  
422  struct Values {
423      // Controls
424      InputProfile current_input_profile;       ///< The current input profile
425      int current_input_profile_index;          ///< The current input profile index
426      std::vector<InputProfile> input_profiles; ///< The list of input profiles
427      std::vector<TouchFromButtonMap> touch_from_button_maps;
428  
429      SwitchableSetting<bool> enable_gamemode{true, "enable_gamemode"};
430  
431      // Core
432      Setting<bool> use_cpu_jit{true, "use_cpu_jit"};
433      SwitchableSetting<s32, true> cpu_clock_percentage{100, 5, 400, "cpu_clock_percentage"};
434      SwitchableSetting<bool> is_new_3ds{true, "is_new_3ds"};
435      SwitchableSetting<bool> lle_applets{false, "lle_applets"};
436  
437      // Data Storage
438      Setting<bool> use_virtual_sd{true, "use_virtual_sd"};
439      Setting<bool> use_custom_storage{false, "use_custom_storage"};
440  
441      // System
442      SwitchableSetting<s32> region_value{REGION_VALUE_AUTO_SELECT, "region_value"};
443      Setting<InitClock> init_clock{InitClock::SystemTime, "init_clock"};
444      Setting<u64> init_time{946681277ULL, "init_time"};
445      Setting<s64> init_time_offset{0, "init_time_offset"};
446      Setting<InitTicks> init_ticks_type{InitTicks::Random, "init_ticks_type"};
447      Setting<s64> init_ticks_override{0, "init_ticks_override"};
448      Setting<bool> plugin_loader_enabled{false, "plugin_loader"};
449      Setting<bool> allow_plugin_loader{true, "allow_plugin_loader"};
450  
451      // Renderer
452      SwitchableSetting<GraphicsAPI, true> graphics_api {
453  #if defined(ENABLE_OPENGL)
454          GraphicsAPI::OpenGL,
455  #elif defined(ENABLE_VULKAN)
456          GraphicsAPI::Vulkan,
457  #elif defined(ENABLE_SOFTWARE_RENDERER)
458          GraphicsAPI::Software,
459  #else
460  // TODO: Add a null renderer backend for this, perhaps.
461  #error "At least one renderer must be enabled."
462  #endif
463              GraphicsAPI::Software, GraphicsAPI::Vulkan, "graphics_api"
464      };
465      SwitchableSetting<u32> physical_device{0, "physical_device"};
466      Setting<bool> use_gles{false, "use_gles"};
467      Setting<bool> renderer_debug{false, "renderer_debug"};
468      Setting<bool> dump_command_buffers{false, "dump_command_buffers"};
469      SwitchableSetting<bool> spirv_shader_gen{true, "spirv_shader_gen"};
470      SwitchableSetting<bool> async_shader_compilation{false, "async_shader_compilation"};
471      SwitchableSetting<bool> async_presentation{true, "async_presentation"};
472      SwitchableSetting<bool> use_hw_shader{true, "use_hw_shader"};
473      SwitchableSetting<bool> use_disk_shader_cache{true, "use_disk_shader_cache"};
474      SwitchableSetting<bool> shaders_accurate_mul{true, "shaders_accurate_mul"};
475      SwitchableSetting<bool> use_vsync_new{true, "use_vsync_new"};
476      Setting<bool> use_shader_jit{true, "use_shader_jit"};
477      SwitchableSetting<u32, true> resolution_factor{1, 0, 10, "resolution_factor"};
478      SwitchableSetting<u16, true> frame_limit{100, 0, 1000, "frame_limit"};
479      SwitchableSetting<TextureFilter> texture_filter{TextureFilter::None, "texture_filter"};
480      SwitchableSetting<TextureSampling> texture_sampling{TextureSampling::GameControlled,
481                                                          "texture_sampling"};
482  
483      SwitchableSetting<LayoutOption> layout_option{LayoutOption::Default, "layout_option"};
484      SwitchableSetting<bool> swap_screen{false, "swap_screen"};
485      SwitchableSetting<bool> upright_screen{false, "upright_screen"};
486      SwitchableSetting<float, true> large_screen_proportion{4.f, 1.f, 16.f,
487                                                             "large_screen_proportion"};
488      Setting<bool> custom_layout{false, "custom_layout"};
489      Setting<u16> custom_top_left{0, "custom_top_left"};
490      Setting<u16> custom_top_top{0, "custom_top_top"};
491      Setting<u16> custom_top_right{400, "custom_top_right"};
492      Setting<u16> custom_top_bottom{240, "custom_top_bottom"};
493      Setting<u16> custom_bottom_left{40, "custom_bottom_left"};
494      Setting<u16> custom_bottom_top{240, "custom_bottom_top"};
495      Setting<u16> custom_bottom_right{360, "custom_bottom_right"};
496      Setting<u16> custom_bottom_bottom{480, "custom_bottom_bottom"};
497      Setting<u16> custom_second_layer_opacity{100, "custom_second_layer_opacity"};
498  
499      SwitchableSetting<float> bg_red{0.f, "bg_red"};
500      SwitchableSetting<float> bg_green{0.f, "bg_green"};
501      SwitchableSetting<float> bg_blue{0.f, "bg_blue"};
502  
503      SwitchableSetting<StereoRenderOption> render_3d{StereoRenderOption::Off, "render_3d"};
504      SwitchableSetting<u32> factor_3d{0, "factor_3d"};
505      SwitchableSetting<MonoRenderOption> mono_render_option{MonoRenderOption::LeftEye,
506                                                             "mono_render_option"};
507  
508      Setting<u32> cardboard_screen_size{85, "cardboard_screen_size"};
509      Setting<s32> cardboard_x_shift{0, "cardboard_x_shift"};
510      Setting<s32> cardboard_y_shift{0, "cardboard_y_shift"};
511  
512      SwitchableSetting<bool> filter_mode{true, "filter_mode"};
513      SwitchableSetting<std::string> pp_shader_name{"none (builtin)", "pp_shader_name"};
514      SwitchableSetting<std::string> anaglyph_shader_name{"dubois (builtin)", "anaglyph_shader_name"};
515  
516      SwitchableSetting<bool> dump_textures{false, "dump_textures"};
517      SwitchableSetting<bool> custom_textures{false, "custom_textures"};
518      SwitchableSetting<bool> preload_textures{false, "preload_textures"};
519      SwitchableSetting<bool> async_custom_loading{true, "async_custom_loading"};
520  
521      // Audio
522      bool audio_muted;
523      SwitchableSetting<AudioEmulation> audio_emulation{AudioEmulation::HLE, "audio_emulation"};
524      SwitchableSetting<bool> enable_audio_stretching{true, "enable_audio_stretching"};
525      SwitchableSetting<float, true> volume{1.f, 0.f, 1.f, "volume"};
526      Setting<AudioCore::SinkType> output_type{AudioCore::SinkType::Auto, "output_type"};
527      Setting<std::string> output_device{"auto", "output_device"};
528      Setting<AudioCore::InputType> input_type{AudioCore::InputType::Auto, "input_type"};
529      Setting<std::string> input_device{"auto", "input_device"};
530  
531      // Camera
532      std::array<std::string, Service::CAM::NumCameras> camera_name;
533      std::array<std::string, Service::CAM::NumCameras> camera_config;
534      std::array<int, Service::CAM::NumCameras> camera_flip;
535  
536      // Debugging
537      bool record_frame_times;
538      std::unordered_map<std::string, bool> lle_modules;
539      Setting<bool> delay_start_for_lle_modules{true, "delay_start_for_lle_modules"};
540      Setting<bool> use_gdbstub{false, "use_gdbstub"};
541      Setting<u16> gdbstub_port{24689, "gdbstub_port"};
542  
543      // Miscellaneous
544      Setting<std::string> log_filter{"*:Info", "log_filter"};
545  
546      // Video Dumping
547      std::string output_format;
548      std::string format_options;
549  
550      std::string video_encoder;
551      std::string video_encoder_options;
552      u64 video_bitrate;
553  
554      std::string audio_encoder;
555      std::string audio_encoder_options;
556      u64 audio_bitrate;
557  };
558  
559  extern Values values;
560  
561  bool IsConfiguringGlobal();
562  void SetConfiguringGlobal(bool is_global);
563  
564  float Volume();
565  
566  void LogSettings();
567  
568  // Restore the global state of all applicable settings in the Values struct
569  void RestoreGlobalState(bool is_powered_on);
570  
571  // Input profiles
572  void LoadProfile(int index);
573  void SaveProfile(int index);
574  void CreateProfile(std::string name);
575  void DeleteProfile(int index);
576  void RenameCurrentProfile(std::string new_name);
577  
578  } // namespace Settings