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  EventDistributor& eventDistributor = reactor.getEventDistributor();
285  InputEventGenerator& inputEventGenerator = reactor.getInputEventGenerator();
286 
287  unsigned width, height;
288  getWindowSize(width, height);
289  // Destruct existing output surface before creating a new one.
290  screen.reset();
291 
292  switch (renderSettings.getRenderer().getEnum()) {
294  screen = make_unique<SDLVisibleSurface>(
295  width, height, renderSettings,
296  eventDistributor, inputEventGenerator,
297  reactor.getCliComm());
298  break;
299 #if COMPONENT_GL
301  screen = make_unique<SDLGLVisibleSurface>(
302  width, height, renderSettings,
303  eventDistributor, inputEventGenerator,
304  reactor.getCliComm());
305  break;
307  screen = make_unique<SDLGLVisibleSurface>(
308  width, height, renderSettings,
309  eventDistributor, inputEventGenerator,
310  reactor.getCliComm(),
312  break;
314  screen = make_unique<SDLGLVisibleSurface>(
315  width, height, renderSettings,
316  eventDistributor, inputEventGenerator,
317  reactor.getCliComm(),
319  break;
320 #endif
321  default:
322  UNREACHABLE;
323  }
324  inputEventGenerator.reinit();
325 }
326 
327 void SDLVideoSystem::update(const Setting& subject)
328 {
329  if (&subject == &renderSettings.getScaleFactor()) {
330  // TODO: This is done via checkSettings instead,
331  // but is that still needed?
332  //resize();
333  } else {
334  UNREACHABLE;
335  }
336 }
337 
338 int SDLVideoSystem::signalEvent(const std::shared_ptr<const Event>& /*event*/)
339 {
340  // TODO: Currently window size depends only on scale factor.
341  // Maybe in the future it will be handled differently.
342  //auto& resizeEvent = checked_cast<const ResizeEvent&>(event);
343  //resize(resizeEvent.getX(), resizeEvent.getY());
344  //resize();
345  return 0;
346 }
347 
348 } // 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:414
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.
EventDistributor & getEventDistributor()
Definition: Reactor.cc:278
A frame buffer where pixels can be written to.
void attach(Observer< T > &observer)
Definition: Subject.hh:52
void repaint()
Redraw the display.
Definition: Display.cc:365
InputEventGenerator & getInputEventGenerator()
Definition: Reactor.cc:303
void removeLayer(Layer &layer)
Definition: Display.cc:423
MSXMotherBoard & getMotherBoard() const
Get the mother board this device belongs to.
Definition: MSXDevice.cc:83
virtual std::string getName() const
Returns a human-readable name for this device.
Definition: MSXDevice.cc:389
virtual void flush()
Finish pending drawing operations and make them visible to the user.
virtual std::unique_ptr< LDRasterizer > createLDRasterizer(LaserdiscPlayer &ld)
IntegerSetting & getScaleFactor() const
The current scaling factor.
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:293
OSDGUI & getOSDGUI() const
Definition: Display.cc:171
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