openMSX
SDLVideoSystem.cc
Go to the documentation of this file.
1#include "SDLVideoSystem.hh"
3#include "SDLRasterizer.hh"
5#include "FBPostProcessor.hh"
6#include "Reactor.hh"
7#include "Display.hh"
8#include "RenderSettings.hh"
9#include "IntegerSetting.hh"
10#include "EventDistributor.hh"
11#include "VDP.hh"
12#include "V9990.hh"
13#include "build-info.hh"
14#include "unreachable.hh"
15#include <memory>
16
17#include "components.hh"
18#if COMPONENT_GL
20#include "GLPostProcessor.hh"
21#endif
22#if COMPONENT_LASERDISC
23#include "LaserdiscPlayer.hh"
24#include "LDSDLRasterizer.hh"
25#endif
26
27namespace openmsx {
28
30 : reactor(reactor_)
31 , display(reactor.getDisplay())
32 , renderSettings(reactor.getDisplay().getRenderSettings())
33{
34 resize();
35
36 consoleLayer = screen->createConsoleLayer(reactor, console);
37 snowLayer = screen->createSnowLayer();
38 osdGuiLayer = screen->createOSDGUILayer(display.getOSDGUI());
39 display.addLayer(*consoleLayer);
40 display.addLayer(*snowLayer);
41 display.addLayer(*osdGuiLayer);
42
43 renderSettings.getScaleFactorSetting().attach(*this);
44
46 EventType::RESIZE, *this);
47}
48
50{
52 EventType::RESIZE, *this);
53
54 renderSettings.getScaleFactorSetting().detach(*this);
55
56 display.removeLayer(*osdGuiLayer);
57 display.removeLayer(*snowLayer);
58 display.removeLayer(*consoleLayer);
59}
60
61std::unique_ptr<Rasterizer> SDLVideoSystem::createRasterizer(VDP& vdp)
62{
63 std::string videoSource = (vdp.getName() == "VDP")
64 ? "MSX" // for backwards compatibility
65 : vdp.getName();
66 auto& motherBoard = vdp.getMotherBoard();
67 switch (renderSettings.getRenderer()) {
69 switch (screen->getPixelFormat().getBytesPerPixel()) {
70#if HAVE_16BPP
71 case 2:
72 return std::make_unique<SDLRasterizer<uint16_t>>(
73 vdp, display, *screen,
74 std::make_unique<FBPostProcessor<uint16_t>>(
75 motherBoard, display, *screen,
76 videoSource, 640, 240, true));
77#endif
78#if HAVE_32BPP
79 case 4:
80 return std::make_unique<SDLRasterizer<uint32_t>>(
81 vdp, display, *screen,
82 std::make_unique<FBPostProcessor<uint32_t>>(
83 motherBoard, display, *screen,
84 videoSource, 640, 240, true));
85#endif
86 default:
87 UNREACHABLE; return nullptr;
88 }
89#if COMPONENT_GL
91 return std::make_unique<SDLRasterizer<uint32_t>>(
92 vdp, display, *screen,
93 std::make_unique<GLPostProcessor>(
94 motherBoard, display, *screen,
95 videoSource, 640, 240, true));
96#endif
97 default:
98 UNREACHABLE; return nullptr;
99 }
100}
101
102std::unique_ptr<V9990Rasterizer> SDLVideoSystem::createV9990Rasterizer(
103 V9990& vdp)
104{
105 std::string videoSource = (vdp.getName() == "Sunrise GFX9000")
106 ? "GFX9000" // for backwards compatibility
107 : vdp.getName();
108 MSXMotherBoard& motherBoard = vdp.getMotherBoard();
109 switch (renderSettings.getRenderer()) {
111 switch (screen->getPixelFormat().getBytesPerPixel()) {
112#if HAVE_16BPP
113 case 2:
114 return std::make_unique<V9990SDLRasterizer<uint16_t>>(
115 vdp, display, *screen,
116 std::make_unique<FBPostProcessor<uint16_t>>(
117 motherBoard, display, *screen,
118 videoSource, 1280, 240, true));
119#endif
120#if HAVE_32BPP
121 case 4:
122 return std::make_unique<V9990SDLRasterizer<uint32_t>>(
123 vdp, display, *screen,
124 std::make_unique<FBPostProcessor<uint32_t>>(
125 motherBoard, display, *screen,
126 videoSource, 1280, 240, true));
127#endif
128 default:
129 UNREACHABLE; return nullptr;
130 }
131#if COMPONENT_GL
133 return std::make_unique<V9990SDLRasterizer<uint32_t>>(
134 vdp, display, *screen,
135 std::make_unique<GLPostProcessor>(
136 motherBoard, display, *screen,
137 videoSource, 1280, 240, true));
138#endif
139 default:
140 UNREACHABLE; return nullptr;
141 }
142}
143
144#if COMPONENT_LASERDISC
145std::unique_ptr<LDRasterizer> SDLVideoSystem::createLDRasterizer(
146 LaserdiscPlayer& ld)
147{
148 std::string videoSource = "Laserdisc"; // TODO handle multiple???
149 MSXMotherBoard& motherBoard = ld.getMotherBoard();
150 switch (renderSettings.getRenderer()) {
152 switch (screen->getPixelFormat().getBytesPerPixel()) {
153#if HAVE_16BPP
154 case 2:
155 return std::make_unique<LDSDLRasterizer<uint16_t>>(
156 *screen,
157 std::make_unique<FBPostProcessor<uint16_t>>(
158 motherBoard, display, *screen,
159 videoSource, 640, 480, false));
160#endif
161#if HAVE_32BPP
162 case 4:
163 return std::make_unique<LDSDLRasterizer<uint32_t>>(
164 *screen,
165 std::make_unique<FBPostProcessor<uint32_t>>(
166 motherBoard, display, *screen,
167 videoSource, 640, 480, false));
168#endif
169 default:
170 UNREACHABLE; return nullptr;
171 }
172#if COMPONENT_GL
174 return std::make_unique<LDSDLRasterizer<uint32_t>>(
175 *screen,
176 std::make_unique<GLPostProcessor>(
177 motherBoard, display, *screen,
178 videoSource, 640, 480, false));
179#endif
180 default:
181 UNREACHABLE; return nullptr;
182 }
183}
184#endif
185
186gl::ivec2 SDLVideoSystem::getWindowSize()
187{
188 int factor = renderSettings.getScaleFactor();
189 switch (renderSettings.getRenderer()) {
191 // We don't have 4x software scalers yet.
192 if (factor > 3) factor = 3;
193 break;
195 // All scale factors are supported.
196 break;
197 default:
199 }
200 return {320 * factor, 240 * factor};
201}
202
203// TODO: If we can switch video system at any time (not just frame end),
204// is this polling approach necessary at all?
206{
207 // Check resolution.
208 if (getWindowSize() != screen->getLogicalSize()) {
209 return false;
210 }
211
212 // Check fullscreen.
213 return screen->setFullScreen(renderSettings.getFullScreen());
214}
215
217{
218 screen->finish();
219}
220
221void SDLVideoSystem::takeScreenShot(const std::string& filename, bool withOsd)
222{
223 if (withOsd) {
224 // we can directly save current content as screenshot
225 screen->saveScreenshot(filename);
226 } else {
227 // we first need to re-render to an off-screen surface
228 // with OSD layers disabled
229 ScopedLayerHider hideConsole(*consoleLayer);
230 ScopedLayerHider hideOsd(*osdGuiLayer);
231 std::unique_ptr<OutputSurface> surf = screen->createOffScreenSurface();
232 display.repaintImpl(*surf);
233 surf->saveScreenshot(filename);
234 }
235}
236
238{
239 screen->updateWindowTitle();
240}
241
243{
244 int mouseX, mouseY;
245 SDL_GetMouseState(&mouseX, &mouseY);
246 return {mouseX, mouseY};
247}
248
250{
251 return screen.get();
252}
253
255{
256 SDL_ShowCursor(show ? SDL_ENABLE : SDL_DISABLE);
257}
258
260{
261 return SDL_ShowCursor(SDL_QUERY) == SDL_ENABLE;
262}
263
265{
266 std::string result;
267 if (char* text = SDL_GetClipboardText()) {
268 result = text;
269 SDL_free(text);
270 }
271 return result;
272}
273
275{
276 if (SDL_SetClipboardText(text.c_str()) != 0) {
277 const char* err = SDL_GetError();
278 SDL_ClearError();
279 throw CommandException(err);
280 }
281}
282
284{
285 // With SDL we can simply repaint the display directly.
286 display.repaintImpl();
287}
288
289void SDLVideoSystem::resize()
290{
291 auto& rtScheduler = reactor.getRTScheduler();
292 auto& eventDistributor = reactor.getEventDistributor();
293 auto& inputEventGenerator = reactor.getInputEventGenerator();
294
295 auto [width, height] = getWindowSize();
296 // Destruct existing output surface before creating a new one.
297 screen.reset();
298
299 switch (renderSettings.getRenderer()) {
301 screen = std::make_unique<SDLVisibleSurface>(
302 width, height, display, rtScheduler,
303 eventDistributor, inputEventGenerator,
304 reactor.getCliComm(), *this);
305 break;
306#if COMPONENT_GL
308 screen = std::make_unique<SDLGLVisibleSurface>(
309 width, height, display, rtScheduler,
310 eventDistributor, inputEventGenerator,
311 reactor.getCliComm(), *this);
312 break;
313#endif
314 default:
316 }
317}
318
319void SDLVideoSystem::update(const Setting& subject) noexcept
320{
321 if (&subject == &renderSettings.getScaleFactorSetting()) {
322 // TODO: This is done via checkSettings instead,
323 // but is that still needed?
324 //resize();
325 } else {
327 }
328}
329
330int SDLVideoSystem::signalEvent(const Event& /*event*/) noexcept
331{
332 // TODO: Currently window size depends only on scale factor.
333 // Maybe in the future it will be handled differently.
334 //const auto& resizeEvent = get<ResizeEvent>(event);
335 //resize(resizeEvent.getX(), resizeEvent.getY());
336 //resize();
337 return 0;
338}
339
340} // namespace openmsx
void repaintImpl()
Definition: Display.cc:329
OSDGUI & getOSDGUI()
Definition: Display.hh:45
void removeLayer(Layer &layer)
Definition: Display.cc:393
void addLayer(Layer &layer)
Definition: Display.cc:385
void unregisterEventListener(EventType type, EventListener &listener)
Unregisters a previously registered event listener.
void registerEventListener(EventType type, EventListener &listener, Priority priority=OTHER)
Registers a given object to receive certain events.
MSXMotherBoard & getMotherBoard()
MSXMotherBoard & getMotherBoard() const
Get the mother board this device belongs to.
Definition: MSXDevice.cc:71
virtual const std::string & getName() const
Returns a human-readable name for this device.
Definition: MSXDevice.cc:376
A frame buffer where pixels can be written to.
Contains the main loop of openMSX.
Definition: Reactor.hh:68
CliComm & getCliComm()
Definition: Reactor.cc:312
RTScheduler & getRTScheduler()
Definition: Reactor.hh:81
EventDistributor & getEventDistributor()
Definition: Reactor.hh:82
InputEventGenerator & getInputEventGenerator()
Definition: Reactor.hh:85
IntegerSetting & getScaleFactorSetting()
The current scaling factor.
RendererID getRenderer() const
bool getCursorEnabled() override
SDLVideoSystem(Reactor &reactor, CommandConsole &console)
Activates this video system.
void repaint() override
Requests a repaint of the output surface.
void setClipboardText(zstring_view text) override
void showCursor(bool show) override
gl::ivec2 getMouseCoord() override
Returns the current mouse pointer coordinates.
std::unique_ptr< V9990Rasterizer > createV9990Rasterizer(V9990 &vdp) override
Create the V9990 rasterizer selected by the current renderer setting.
~SDLVideoSystem() override
Deactivates this video system.
bool checkSettings() override
Requests that this renderer checks its settings against the current RenderSettings.
OutputSurface * getOutputSurface() override
TODO.
void takeScreenShot(const std::string &filename, bool withOsd) override
Take a screenshot.
std::unique_ptr< LDRasterizer > createLDRasterizer(LaserdiscPlayer &ld) override
void updateWindowTitle() override
Called when the window title string has changed.
std::string getClipboardText() override
void flush() override
Finish pending drawing operations and make them visible to the user.
std::unique_ptr< Rasterizer > createRasterizer(VDP &vdp) override
Create the rasterizer selected by the current renderer setting.
void detach(Observer< T > &observer)
Definition: Subject.hh:56
void attach(Observer< T > &observer)
Definition: Subject.hh:50
Implementation of the Yamaha V9990 VDP as used in the GFX9000 cartridge by Sunrise.
Definition: V9990.hh:32
Unified implementation of MSX Video Display Processors (VDPs).
Definition: VDP.hh:63
Like std::string_view, but with the extra guarantee that it refers to a zero-terminated string.
Definition: zstring_view.hh:22
constexpr const char * c_str() const
Definition: zstring_view.hh:49
This file implemented 3 utility functions:
Definition: Autofire.cc:9
constexpr const char *const filename
#define UNREACHABLE
Definition: unreachable.hh:38