openMSX
SDLVideoSystem.cc
Go to the documentation of this file.
1 #include "SDLVideoSystem.hh"
2 #include "SDLVisibleSurface.hh"
3 #include "SDLRasterizer.hh"
4 #include "V9990SDLRasterizer.hh"
5 #include "FBPostProcessor.hh"
6 #include "Reactor.hh"
7 #include "Display.hh"
8 #include "RenderSettings.hh"
9 #include "BooleanSetting.hh"
10 #include "EnumSetting.hh"
11 #include "IntegerSetting.hh"
12 #include "EventDistributor.hh"
13 #include "InputEventGenerator.hh"
14 #include "VDP.hh"
15 #include "V9990.hh"
16 #include "build-info.hh"
17 #include "unreachable.hh"
18 #include "memory.hh"
19 #include <cassert>
20 
21 #ifdef _WIN32
22 #include "AltSpaceSuppressor.hh"
23 #include "win32-windowhandle.hh"
24 #endif
25 #include "components.hh"
26 #if COMPONENT_GL
27 #include "SDLGLVisibleSurface.hh"
28 #include "GLPostProcessor.hh"
29 #endif
30 #if COMPONENT_LASERDISC
31 #include "LaserdiscPlayer.hh"
32 #include "LDSDLRasterizer.hh"
33 #endif
34 
35 namespace openmsx {
36 
38  : reactor(reactor)
39  , display(reactor.getDisplay())
40  , renderSettings(reactor.getDisplay().getRenderSettings())
41 {
42  resize();
43 
44  consoleLayer = screen->createConsoleLayer(reactor, console);
45  snowLayer = screen->createSnowLayer(display);
46  osdGuiLayer = screen->createOSDGUILayer(display.getOSDGUI());
47  display.addLayer(*consoleLayer);
48  display.addLayer(*snowLayer);
49  display.addLayer(*osdGuiLayer);
50 
51  renderSettings.getScaleFactor().attach(*this);
52 
54  OPENMSX_RESIZE_EVENT, *this);
55 
56 #ifdef _WIN32
57  HWND hWnd = getWindowHandle();
58  assert(hWnd);
59  AltSpaceSuppressor::Start(hWnd);
60 #endif
61 }
62 
64 {
65 #ifdef _WIN32
66  // This needs to be done while the SDL window handle is still valid
67  assert(getWindowHandle());
68  AltSpaceSuppressor::Stop();
69 #endif
70 
72  OPENMSX_RESIZE_EVENT, *this);
73 
74  renderSettings.getScaleFactor().detach(*this);
75 
76  display.removeLayer(*osdGuiLayer);
77  display.removeLayer(*snowLayer);
78  display.removeLayer(*consoleLayer);
79 }
80 
81 std::unique_ptr<Rasterizer> SDLVideoSystem::createRasterizer(VDP& vdp)
82 {
83  std::string videoSource = (vdp.getName() == "VDP")
84  ? "MSX" // for backwards compatibility
85  : vdp.getName();
86  auto& motherBoard = vdp.getMotherBoard();
87  switch (renderSettings.getRenderer().getEnum()) {
91  switch (screen->getSDLFormat().BytesPerPixel) {
92 #if HAVE_16BPP
93  case 2:
94  return make_unique<SDLRasterizer<uint16_t>>(
95  vdp, display, *screen,
96  make_unique<FBPostProcessor<uint16_t>>(
97  motherBoard, display, *screen,
98  videoSource, 640, 240, true));
99 #endif
100 #if HAVE_32BPP
101  case 4:
102  return make_unique<SDLRasterizer<uint32_t>>(
103  vdp, display, *screen,
104  make_unique<FBPostProcessor<uint32_t>>(
105  motherBoard, display, *screen,
106  videoSource, 640, 240, true));
107 #endif
108  default:
109  UNREACHABLE; return nullptr;
110  }
111 #if COMPONENT_GL
113  return make_unique<SDLRasterizer<uint32_t>>(
114  vdp, display, *screen,
115  make_unique<GLPostProcessor>(
116  motherBoard, display, *screen,
117  videoSource, 640, 240, true));
118 #endif
119  default:
120  UNREACHABLE; return nullptr;
121  }
122 }
123 
124 std::unique_ptr<V9990Rasterizer> SDLVideoSystem::createV9990Rasterizer(
125  V9990& vdp)
126 {
127  std::string videoSource = (vdp.getName() == "Sunrise GFX9000")
128  ? "GFX9000" // for backwards compatibility
129  : vdp.getName();
130  MSXMotherBoard& motherBoard = vdp.getMotherBoard();
131  switch (renderSettings.getRenderer().getEnum()) {
135  switch (screen->getSDLFormat().BytesPerPixel) {
136 #if HAVE_16BPP
137  case 2:
138  return make_unique<V9990SDLRasterizer<uint16_t>>(
139  vdp, display, *screen,
140  make_unique<FBPostProcessor<uint16_t>>(
141  motherBoard, display, *screen,
142  videoSource, 1280, 240, true));
143 #endif
144 #if HAVE_32BPP
145  case 4:
146  return make_unique<V9990SDLRasterizer<uint32_t>>(
147  vdp, display, *screen,
148  make_unique<FBPostProcessor<uint32_t>>(
149  motherBoard, display, *screen,
150  videoSource, 1280, 240, true));
151 #endif
152  default:
153  UNREACHABLE; return nullptr;
154  }
155 #if COMPONENT_GL
157  return make_unique<V9990SDLRasterizer<uint32_t>>(
158  vdp, display, *screen,
159  make_unique<GLPostProcessor>(
160  motherBoard, display, *screen,
161  videoSource, 1280, 240, true));
162 #endif
163  default:
164  UNREACHABLE; return nullptr;
165  }
166 }
167 
168 #if COMPONENT_LASERDISC
169 std::unique_ptr<LDRasterizer> SDLVideoSystem::createLDRasterizer(
170  LaserdiscPlayer& ld)
171 {
172  std::string videoSource = "Laserdisc"; // TODO handle multiple???
173  MSXMotherBoard& motherBoard = ld.getMotherBoard();
174  switch (renderSettings.getRenderer().getEnum()) {
178  switch (screen->getSDLFormat().BytesPerPixel) {
179 #if HAVE_16BPP
180  case 2:
181  return make_unique<LDSDLRasterizer<uint16_t>>(
182  *screen,
183  make_unique<FBPostProcessor<uint16_t>>(
184  motherBoard, display, *screen,
185  videoSource, 640, 480, false));
186 #endif
187 #if HAVE_32BPP
188  case 4:
189  return make_unique<LDSDLRasterizer<uint32_t>>(
190  *screen,
191  make_unique<FBPostProcessor<uint32_t>>(
192  motherBoard, display, *screen,
193  videoSource, 640, 480, false));
194 #endif
195  default:
196  UNREACHABLE; return nullptr;
197  }
198 #if COMPONENT_GL
200  return make_unique<LDSDLRasterizer<uint32_t>>(
201  *screen,
202  make_unique<GLPostProcessor>(
203  motherBoard, display, *screen,
204  videoSource, 640, 480, false));
205 #endif
206  default:
207  UNREACHABLE; return nullptr;
208  }
209 }
210 #endif
211 
212 void SDLVideoSystem::getWindowSize(unsigned& width, unsigned& height)
213 {
214  unsigned factor = renderSettings.getScaleFactor().getInt();
215  switch (renderSettings.getRenderer().getEnum()) {
219  // We don't have 4x software scalers yet.
220  if (factor > 3) factor = 3;
221  break;
223  // All scale factors are supported.
224  break;
226  factor = 0;
227  break;
228  default:
229  UNREACHABLE;
230  }
231  width = 320 * factor;
232  height = 240 * factor;
233 }
234 
235 // TODO: If we can switch video system at any time (not just frame end),
236 // is this polling approach necessary at all?
238 {
239  // Check resolution.
240  unsigned width, height;
241  getWindowSize(width, height);
242  if (width != screen->getWidth() || height != screen->getHeight()) {
243  return false;
244  }
245 
246  // Check fullscreen.
247  const bool fullScreenTarget = renderSettings.getFullScreen().getBoolean();
248  return screen->setFullScreen(fullScreenTarget);
249 }
250 
252 {
253  screen->finish();
254 }
255 
256 void SDLVideoSystem::takeScreenShot(const std::string& filename, bool withOsd)
257 {
258  if (withOsd) {
259  // we can directly save current content as screenshot
260  screen->saveScreenshot(filename);
261  } else {
262  // we first need to re-render to an off-screen surface
263  // with OSD layers disabled
264  ScopedLayerHider hideConsole(*consoleLayer);
265  ScopedLayerHider hideOsd(*osdGuiLayer);
266  std::unique_ptr<OutputSurface> surf = screen->createOffScreenSurface();
267  display.repaint(*surf);
268  surf->saveScreenshot(filename);
269  }
270 }
271 
272 void SDLVideoSystem::setWindowTitle(const std::string& title)
273 {
274  screen->setWindowTitle(title);
275 }
276 
278 {
279  return screen.get();
280 }
281 
282 void SDLVideoSystem::resize()
283 {
284  auto& rtScheduler = reactor.getRTScheduler();
285  auto& eventDistributor = reactor.getEventDistributor();
286  auto& inputEventGenerator = reactor.getInputEventGenerator();
287 
288  unsigned width, height;
289  getWindowSize(width, height);
290  // Destruct existing output surface before creating a new one.
291  screen.reset();
292 
293  switch (renderSettings.getRenderer().getEnum()) {
295  screen = make_unique<SDLVisibleSurface>(
296  width, height, renderSettings, rtScheduler,
297  eventDistributor, inputEventGenerator,
298  reactor.getCliComm());
299  break;
300 #if COMPONENT_GL
302  screen = make_unique<SDLGLVisibleSurface>(
303  width, height, renderSettings, rtScheduler,
304  eventDistributor, inputEventGenerator,
305  reactor.getCliComm());
306  break;
308  screen = make_unique<SDLGLVisibleSurface>(
309  width, height, renderSettings, rtScheduler,
310  eventDistributor, inputEventGenerator,
311  reactor.getCliComm(),
313  break;
315  screen = make_unique<SDLGLVisibleSurface>(
316  width, height, renderSettings, rtScheduler,
317  eventDistributor, inputEventGenerator,
318  reactor.getCliComm(),
320  break;
321 #endif
322  default:
323  UNREACHABLE;
324  }
325  inputEventGenerator.reinit();
326 }
327 
328 void SDLVideoSystem::update(const Setting& subject)
329 {
330  if (&subject == &renderSettings.getScaleFactor()) {
331  // TODO: This is done via checkSettings instead,
332  // but is that still needed?
333  //resize();
334  } else {
335  UNREACHABLE;
336  }
337 }
338 
339 int SDLVideoSystem::signalEvent(const std::shared_ptr<const Event>& /*event*/)
340 {
341  // TODO: Currently window size depends only on scale factor.
342  // Maybe in the future it will be handled differently.
343  //auto& resizeEvent = checked_cast<const ResizeEvent&>(event);
344  //resize(resizeEvent.getX(), resizeEvent.getY());
345  //resize();
346  return 0;
347 }
348 
349 } // namespace openmsx
Implementation of the Yamaha V9990 VDP as used in the GFX9000 cartridge by Sunrise.
Definition: V9990.hh:29
Contains the main loop of openMSX.
Definition: Reactor.hh:62
virtual void takeScreenShot(const std::string &filename, bool withOsd)
Take a screenshot.
void registerEventListener(EventType type, EventListener &listener, Priority priority=OTHER)
Registers a given object to receive certain events.
void addLayer(Layer &layer)
Definition: Display.cc:399
virtual std::unique_ptr< V9990Rasterizer > createV9990Rasterizer(V9990 &vdp)
Create the V9990 rasterizer selected by the current renderer setting.
RendererFactory::RendererSetting & getRenderer() const
The current renderer.
void unregisterEventListener(EventType type, EventListener &listener)
Unregisters a previously registered event listener.
MSXMotherBoard & getMotherBoard()
virtual OutputSurface * getOutputSurface()
TODO.
A frame buffer where pixels can be written to.
InputEventGenerator & getInputEventGenerator()
Definition: Reactor.hh:82
EventDistributor & getEventDistributor()
Definition: Reactor.hh:79
void attach(Observer< T > &observer)
Definition: Subject.hh:52
void repaint()
Redraw the display.
Definition: Display.cc:350
RTScheduler & getRTScheduler()
Definition: Reactor.hh:78
void removeLayer(Layer &layer)
Definition: Display.cc:408
MSXMotherBoard & getMotherBoard() const
Get the mother board this device belongs to.
Definition: MSXDevice.cc:78
virtual std::string getName() const
Returns a human-readable name for this device.
Definition: MSXDevice.cc:374
virtual void flush()
Finish pending drawing operations and make them visible to the user.
OSDGUI & getOSDGUI() const
Definition: Display.hh:46
virtual std::unique_ptr< LDRasterizer > createLDRasterizer(LaserdiscPlayer &ld)
IntegerSetting & getScaleFactor() const
The current scaling factor.
eventDistributor(eventDistributor_)
Unified implementation of MSX Video Display Processors (VDPs).
Definition: VDP.hh:66
virtual void setWindowTitle(const std::string &title)
Change the window title.
virtual std::unique_ptr< Rasterizer > createRasterizer(VDP &vdp)
Create the rasterizer selected by the current renderer setting.
BooleanSetting & getFullScreen() const
Full screen [on, off].
void detach(Observer< T > &observer)
Definition: Subject.hh:58
CliComm & getCliComm()
Definition: Reactor.cc:268
SDLVideoSystem(Reactor &reactor, CommandConsole &console)
Activates this video system.
virtual bool checkSettings()
Requests that this renderer checks its settings against the current RenderSettings.
virtual ~SDLVideoSystem()
Deactivates this video system.
#define UNREACHABLE
Definition: unreachable.hh:56