openMSX
RenderSettings.cc
Go to the documentation of this file.
1 #include "RenderSettings.hh"
2 #include "CommandController.hh"
3 #include "CommandException.hh"
4 #include "Version.hh"
5 #include "stl.hh"
6 #include "unreachable.hh"
7 #include "build-info.hh"
8 #include "components.hh"
9 #include <algorithm>
10 #include <iostream>
11 #include <cmath>
12 
13 using namespace gl;
14 
15 namespace openmsx {
16 
17 EnumSetting<RenderSettings::ScaleAlgorithm>::Map RenderSettings::getScalerMap()
18 {
19  EnumSetting<ScaleAlgorithm>::Map scalerMap = { { "simple", SCALER_SIMPLE } };
20  if (MAX_SCALE_FACTOR > 1) {
21  append(scalerMap, {{"SaI", SCALER_SAI},
22  {"ScaleNx", SCALER_SCALE},
23  {"hq", SCALER_HQ},
24  {"hqlite", SCALER_HQLITE},
25  {"RGBtriplet", SCALER_RGBTRIPLET},
26  {"TV", SCALER_TV}});
27  if (!Version::RELEASE) {
28  // This scaler is not ready yet for the upcoming 0.8.1
29  // release, so disable it. As soon as it is ready we
30  // can remove this test.
31  scalerMap.emplace_back("MLAA", SCALER_MLAA);
32  }
33  }
34  return scalerMap;
35 }
36 
37 EnumSetting<RenderSettings::RendererID>::Map RenderSettings::getRendererMap()
38 {
39  EnumSetting<RendererID>::Map rendererMap = {
40  { "none", DUMMY },// TODO: only register when in CliComm mode
41  { "SDL", SDL } };
42 #if COMPONENT_GL
43  // compiled with OpenGL-2.0, still need to test whether
44  // it's available at run time, but cannot be done here
45  rendererMap.emplace_back("SDLGL-PP", SDLGL_PP);
46 #endif
47  return rendererMap;
48 }
49 
50 RenderSettings::RenderSettings(CommandController& commandController)
51  : accuracySetting(commandController,
52  "accuracy", "rendering accuracy", ACC_PIXEL,
53  EnumSetting<Accuracy>::Map{
54  {"screen", ACC_SCREEN},
55  {"line", ACC_LINE},
56  {"pixel", ACC_PIXEL}})
57 
58  , deinterlaceSetting(commandController,
59  "deinterlace", "deinterlacing on/off", true)
60 
61  , deflickerSetting(commandController,
62  "deflicker", "deflicker on/off", false)
63 
64  , maxFrameSkipSetting(commandController,
65  "maxframeskip", "set the max amount of frameskip", 3, 0, 100)
66 
67  , minFrameSkipSetting(commandController,
68  "minframeskip", "set the min amount of frameskip", 0, 0, 100)
69 
70  , fullScreenSetting(commandController,
71  "fullscreen", "full screen display on/off", false)
72 
73  , gammaSetting(commandController, "gamma",
74  "amount of gamma correction: low is dark, high is bright",
75  1.1, 0.1, 5.0)
76 
77  , brightnessSetting(commandController, "brightness",
78  "brightness video setting: "
79  "0 is normal, lower is darker, higher is brighter",
80  0.0, -100.0, 100.0)
81  , contrastSetting(commandController, "contrast",
82  "contrast video setting: "
83  "0 is normal, lower is less contrast, higher is more contrast",
84  0.0, -100.0, 100.0)
85 
86  , colorMatrixSetting(commandController,
87  "color_matrix",
88  "3x3 matrix to transform MSX RGB to host RGB, see manual for details",
89  "{ 1 0 0 } { 0 1 0 } { 0 0 1 }")
90 
91  , glowSetting(commandController,
92  "glow", "amount of afterglow effect: 0 = none, 100 = lots",
93  0, 0, 100)
94 
95  , noiseSetting(commandController,
96  "noise", "amount of noise to add to the frame",
97  0.0, 0.0, 100.0)
98 
99  , rendererSetting(commandController,
100  "renderer", "rendering back-end used to display the MSX screen",
101 #if COMPONENT_GL
102  SDLGL_PP,
103 #else
104  SDL,
105 #endif
106  getRendererMap())
107 
108  , horizontalBlurSetting(commandController,
109  "blur", "amount of horizontal blur effect: 0 = none, 100 = full",
110  50, 0, 100)
111 
112  , scaleAlgorithmSetting(
113  commandController, "scale_algorithm", "scale algorithm",
114  SCALER_SIMPLE, getScalerMap())
115 
116  , scaleFactorSetting(commandController,
117  "scale_factor", "scale factor",
119 
120  , scanlineAlphaSetting(commandController,
121  "scanline", "amount of scanline effect: 0 = none, 100 = full",
122  20, 0, 100)
123 
124  , limitSpritesSetting(commandController,
125  "limitsprites", "limit number of sprites per line "
126  "(on for realism, off to reduce sprite flashing)", true)
127 
128  , disableSpritesSetting(commandController,
129  "disablesprites", "disable sprite rendering",
130  false, Setting::DONT_SAVE)
131 
132  , cmdTimingSetting(commandController,
133  "cmdtiming", "VDP command timing", false,
134  EnumSetting<bool>::Map{{"real", false}, {"broken", true}},
136 
137  , tooFastAccessSetting(commandController,
138  "too_fast_vram_access",
139  "Should too fast VDP VRAM access be correctly emulated.\n"
140  "Possible values are:\n"
141  " real -> too fast accesses are dropped\n"
142  " ignore -> access speed is ignored, all accesses are executed",
143  false,
144  EnumSetting<bool>::Map{{"real", false }, {"ignore", true}},
146 
147  , displayDeformSetting(
148  commandController,
149  "display_deform", "Display deform (for the moment this only "
150  "works with the SDLGL-PP renderer)", DEFORM_NORMAL,
152  {"normal", DEFORM_NORMAL},
153  {"3d", DEFORM_3D}})
154 
155  , vSyncSetting(commandController,
156  "vsync", "Synchronize page flip with the host screen vertical sync:\n"
157  " on -> flip on host vsync: avoids tearing\n"
158  " off -> immediate flip: might be more fluent when host framerate"
159  " (typically 60Hz) differs from MSX framerate (50 or 60Hz)\n"
160  "Currently this only affects the SDLGL-PP renderer.",
161  true)
162 
163  // Many android devices are relatively low powered. Therefore use
164  // no stretch (value 320) as default for Android because it gives
165  // better performance
166  , horizontalStretchSetting(commandController,
167  "horizontal_stretch",
168  "Amount of horizontal stretch: this many MSX pixels will be "
169  "stretched over the complete width of the output screen.\n"
170  " 320 = no stretch\n"
171  " 256 = max stretch (no border visible anymore)\n"
172  " good values are 272 or 280\n"
173  "This setting has only effect when using the SDLGL-PP renderer.",
174  PLATFORM_ANDROID ? 320.0 : 280.0, 256.0, 320.0)
175 
176  , pointerHideDelaySetting(commandController,
177  "pointer_hide_delay",
178  "number of seconds after which the mouse pointer is hidden in the openMSX "
179  "window; negative = no hiding, 0 = immediately",
180  2.0, -1.0, 60.0)
181 
182  , interleaveBlackFrameSetting(commandController,
183  "interleave_black_frame",
184  "Insert a black frame in between each normal MSX frame. "
185  "Useful on (100Hz+) lightboost enabled monitors to reduce "
186  "motion blur and double frame artifacts.",
187  false)
188 {
189  brightnessSetting.attach(*this);
190  contrastSetting .attach(*this);
191  updateBrightnessAndContrast();
192 
193  auto& interp = commandController.getInterpreter();
194  colorMatrixSetting.setChecker([this, &interp](TclObject& newValue) {
195  try {
196  parseColorMatrix(interp, newValue);
197  } catch (CommandException& e) {
198  throw CommandException(
199  "Invalid color matrix: ", e.getMessage());
200  }
201  });
202  try {
203  parseColorMatrix(interp, colorMatrixSetting.getValue());
204  } catch (MSXException& e) {
205  std::cerr << e.getMessage() << '\n';
206  cmIdentity = true;
207  }
208 
209  // RendererSetting
210  // Make sure the value 'none' never gets saved in settings.xml.
211  // This happened in the following scenario:
212  // - During startup, the renderer is forced to the value 'none'.
213  // - If there's an error in the parsing of the command line (e.g.
214  // because an invalid option is passed) then openmsx will never
215  // get to the point where the actual renderer setting is restored
216  // - After the error, the classes are destructed, part of that is
217  // saving the current settings. But without extra care, this would
218  // save renderer=none
219  rendererSetting.setDontSaveValue(TclObject("none"));
220 
221  // A saved value 'none' can be very confusing. If so change it to default.
222  if (rendererSetting.getEnum() == DUMMY) {
223  rendererSetting.setValue(rendererSetting.getDefaultValue());
224  }
225  // set saved value as default
226  rendererSetting.setRestoreValue(rendererSetting.getValue());
227 
228  rendererSetting.setEnum(DUMMY); // always start hidden
229 }
230 
232 {
233  brightnessSetting.detach(*this);
234  contrastSetting .detach(*this);
235 }
236 
237 void RenderSettings::update(const Setting& setting)
238 {
239  if (&setting == &brightnessSetting) {
240  updateBrightnessAndContrast();
241  } else if (&setting == &contrastSetting) {
242  updateBrightnessAndContrast();
243  } else {
244  UNREACHABLE;
245  }
246 }
247 
248 void RenderSettings::updateBrightnessAndContrast()
249 {
250  float contrastValue = getContrast();
251  contrast = (contrastValue >= 0.0f) ? (1.0f + contrastValue / 25.0f)
252  : (1.0f + contrastValue / 125.0f);
253  brightness = (getBrightness() / 100.0f - 0.5f) * contrast + 0.5f;
254 }
255 
256 static float conv2(float x, float gamma)
257 {
258  return ::powf(std::min(std::max(0.0f, x), 1.0f), gamma);
259 }
260 
262 {
263  float c2 = c * contrast + brightness;
264  return conv2(c2, 1.0f / getGamma());
265 }
266 
268 {
269  auto [r, g, b] = colorMatrix * (rgb * contrast + vec3(brightness));
270  float gamma = 1.0f / getGamma();
271  return {conv2(r, gamma),
272  conv2(g, gamma),
273  conv2(b, gamma)};
274 }
275 
276 void RenderSettings::parseColorMatrix(Interpreter& interp, const TclObject& value)
277 {
278  if (value.getListLength(interp) != 3) {
279  throw CommandException("must have 3 rows");
280  }
281  bool identity = true;
282  for (int i = 0; i < 3; ++i) {
283  TclObject row = value.getListIndex(interp, i);
284  if (row.getListLength(interp) != 3) {
285  throw CommandException("each row must have 3 elements");
286  }
287  for (int j = 0; j < 3; ++j) {
288  TclObject element = row.getListIndex(interp, j);
289  float val = element.getDouble(interp);
290  colorMatrix[i][j] = val;
291  identity &= (val == (i == j ? 1.0f : 0.0f));
292  }
293  }
294  cmIdentity = identity;
295 }
296 
297 } // namespace openmsx
openmsx::EnumSetting
Definition: EnumSetting.hh:33
openmsx::CommandException
Definition: CommandException.hh:9
MIN_SCALE_FACTOR
#define MIN_SCALE_FACTOR
Definition: build-info.hh:20
openmsx::RenderSettings::transformComponent
float transformComponent(float c) const
Apply brightness, contrast and gamma transformation on the input color component.
Definition: RenderSettings.cc:261
gl::min
vecN< N, T > min(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:274
openmsx::RenderSettings::getGamma
float getGamma() const
Definition: RenderSettings.hh:72
openmsx::Subject::detach
void detach(Observer< T > &observer)
Definition: Subject.hh:56
openmsx::CommandController
Definition: CommandController.hh:18
openmsx::RenderSettings::ACC_LINE
@ ACC_LINE
Definition: RenderSettings.hh:32
openmsx::Setting::DONT_SAVE
@ DONT_SAVE
Definition: Setting.hh:127
openmsx::RenderSettings::transformRGB
gl::vec3 transformRGB(gl::vec3 rgb) const
Apply brightness, contrast and gamma transformation on the input color.
Definition: RenderSettings.cc:267
openmsx::TclObject::getListIndex
TclObject getListIndex(Interpreter &interp, unsigned index) const
Definition: TclObject.cc:134
openmsx::Setting
Definition: Setting.hh:120
openmsx::RenderSettings::Accuracy
Accuracy
Render accuracy: granularity of the rendered area.
Definition: RenderSettings.hh:32
gl
Definition: gl_mat.hh:24
gl::vecN
Definition: gl_vec.hh:36
openmsx::DUMMY
@ DUMMY
Definition: CPUCore.cc:204
Version.hh
COMPONENT_GL
#define COMPONENT_GL
Definition: components.hh:7
PLATFORM_ANDROID
#define PLATFORM_ANDROID
Definition: build-info.hh:17
CommandController.hh
UNREACHABLE
#define UNREACHABLE
Definition: unreachable.hh:38
openmsx::RenderSettings::getBrightness
float getBrightness() const
Definition: RenderSettings.hh:76
build-info.hh
openmsx::RenderSettings::~RenderSettings
~RenderSettings()
Definition: RenderSettings.cc:231
RenderSettings.hh
g
int g
Definition: ScopedAssign_test.cc:20
openmsx::YM2413Okazaki::RELEASE
@ RELEASE
Definition: YM2413Okazaki.hh:17
components.hh
gl::vec3
vecN< 3, float > vec3
Definition: gl_vec.hh:145
openmsx::x
constexpr KeyMatrixPosition x
Keyboard bindings.
Definition: Keyboard.cc:1419
openmsx::EnumSetting< ScaleAlgorithm >::Map
std::vector< std::pair< std::string, ScaleAlgorithm > > Map
Definition: EnumSetting.hh:35
openmsx::RenderSettings::ACC_SCREEN
@ ACC_SCREEN
Definition: RenderSettings.hh:32
openmsx::RenderSettings::getContrast
float getContrast() const
Definition: RenderSettings.hh:80
detail::append
void append(Result &)
Definition: stl.hh:335
gl::max
vecN< N, T > max(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:292
stl.hh
openmsx::TclObject
Definition: TclObject.hh:22
openmsx::TclObject::getListLength
unsigned getListLength(Interpreter &interp) const
Definition: TclObject.cc:116
MAX_SCALE_FACTOR
#define MAX_SCALE_FACTOR
Definition: build-info.hh:21
unreachable.hh
openmsx::Interpreter
Definition: Interpreter.hh:17
CommandException.hh
openmsx
This file implemented 3 utility functions:
Definition: Autofire.cc:5
openmsx::RenderSettings::ACC_PIXEL
@ ACC_PIXEL
Definition: RenderSettings.hh:32