openMSX
RenderSettings.cc
Go to the documentation of this file.
1#include "RenderSettings.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
13using namespace gl;
14
15namespace openmsx {
16
17EnumSetting<RenderSettings::ScaleAlgorithm>::Map RenderSettings::getScalerMap()
18{
19 EnumSetting<ScaleAlgorithm>::Map scalerMap = { { "simple", SCALER_SIMPLE } };
20 if constexpr (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
37EnumSetting<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
51 : accuracySetting(commandController,
52 "accuracy", "rendering accuracy", ACC_PIXEL,
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}},
135 Setting::DONT_SAVE)
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}},
145 Setting::DONT_SAVE)
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
231RenderSettings::~RenderSettings()
232{
233 brightnessSetting.detach(*this);
234 contrastSetting .detach(*this);
235}
236
237void RenderSettings::update(const Setting& setting) noexcept
238{
239 if (&setting == &brightnessSetting) {
240 updateBrightnessAndContrast();
241 } else if (&setting == &contrastSetting) {
242 updateBrightnessAndContrast();
243 } else {
245 }
246}
247
248void 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
256static float conv2(float x, float gamma)
257{
258 return ::powf(std::clamp(x, 0.0f, 1.0f), gamma);
259}
260
261float RenderSettings::transformComponent(float c) const
262{
263 float c2 = c * contrast + brightness;
264 return conv2(c2, 1.0f / getGamma());
265}
266
267vec3 RenderSettings::transformRGB(vec3 rgb) const
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
276void 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 (auto i : xrange(3)) {
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 (auto j : xrange(3)) {
288 TclObject element = row.getListIndex(interp, j);
289 float val = element.getFloat(interp);
290 colorMatrix[j][i] = val;
291 identity &= (val == (i == j ? 1.0f : 0.0f));
292 }
293 }
294 cmIdentity = identity;
295}
296
297} // namespace openmsx
BaseSetting * setting
Definition: Interpreter.cc:28
int g
#define MIN_SCALE_FACTOR
Definition: build-info.hh:20
#define PLATFORM_ANDROID
Definition: build-info.hh:17
#define MAX_SCALE_FACTOR
Definition: build-info.hh:21
EnumSettingBase::Map Map
Definition: EnumSetting.hh:56
Accuracy
Render accuracy: granularity of the rendered area.
RenderSettings(CommandController &commandController)
unsigned getListLength(Interpreter &interp) const
Definition: TclObject.cc:134
TclObject getListIndex(Interpreter &interp, unsigned index) const
Definition: TclObject.cc:152
static const bool RELEASE
Definition: Version.hh:12
#define COMPONENT_GL
Definition: components.hh:7
constexpr double e
Definition: Math.hh:20
void append(Result &)
Definition: stl.hh:290
Definition: gl_mat.hh:23
vecN< 3, float > vec3
Definition: gl_vec.hh:150
constexpr vecN< N, T > min(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:266
constexpr vecN< N, T > clamp(const vecN< N, T > &x, const vecN< N, T > &minVal, const vecN< N, T > &maxVal)
Definition: gl_vec.hh:293
This file implemented 3 utility functions:
Definition: Autofire.cc:9
@ DUMMY
Definition: CPUCore.cc:213
#define UNREACHABLE
Definition: unreachable.hh:38
constexpr auto xrange(T e)
Definition: xrange.hh:133