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 "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
19 #include "SDLGLVisibleSurface.hh"
20 #include "GLPostProcessor.hh"
21 #endif
22 #if COMPONENT_LASERDISC
23 #include "LaserdiscPlayer.hh"
24 #include "LDSDLRasterizer.hh"
25 #endif
26 
27 namespace 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  OPENMSX_RESIZE_EVENT, *this);
47 }
48 
50 {
52  OPENMSX_RESIZE_EVENT, *this);
53 
54  renderSettings.getScaleFactorSetting().detach(*this);
55 
56  display.removeLayer(*osdGuiLayer);
57  display.removeLayer(*snowLayer);
58  display.removeLayer(*consoleLayer);
59 }
60 
61 std::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()) {
71  switch (screen->getSDLFormat().BytesPerPixel) {
72 #if HAVE_16BPP
73  case 2:
74  return std::make_unique<SDLRasterizer<uint16_t>>(
75  vdp, display, *screen,
76  std::make_unique<FBPostProcessor<uint16_t>>(
77  motherBoard, display, *screen,
78  videoSource, 640, 240, true));
79 #endif
80 #if HAVE_32BPP
81  case 4:
82  return std::make_unique<SDLRasterizer<uint32_t>>(
83  vdp, display, *screen,
84  std::make_unique<FBPostProcessor<uint32_t>>(
85  motherBoard, display, *screen,
86  videoSource, 640, 240, true));
87 #endif
88  default:
89  UNREACHABLE; return nullptr;
90  }
91 #if COMPONENT_GL
93  return std::make_unique<SDLRasterizer<uint32_t>>(
94  vdp, display, *screen,
95  std::make_unique<GLPostProcessor>(
96  motherBoard, display, *screen,
97  videoSource, 640, 240, true));
98 #endif
99  default:
100  UNREACHABLE; return nullptr;
101  }
102 }
103 
104 std::unique_ptr<V9990Rasterizer> SDLVideoSystem::createV9990Rasterizer(
105  V9990& vdp)
106 {
107  std::string videoSource = (vdp.getName() == "Sunrise GFX9000")
108  ? "GFX9000" // for backwards compatibility
109  : vdp.getName();
110  MSXMotherBoard& motherBoard = vdp.getMotherBoard();
111  switch (renderSettings.getRenderer()) {
112  case RenderSettings::SDL:
115  switch (screen->getSDLFormat().BytesPerPixel) {
116 #if HAVE_16BPP
117  case 2:
118  return std::make_unique<V9990SDLRasterizer<uint16_t>>(
119  vdp, display, *screen,
120  std::make_unique<FBPostProcessor<uint16_t>>(
121  motherBoard, display, *screen,
122  videoSource, 1280, 240, true));
123 #endif
124 #if HAVE_32BPP
125  case 4:
126  return std::make_unique<V9990SDLRasterizer<uint32_t>>(
127  vdp, display, *screen,
128  std::make_unique<FBPostProcessor<uint32_t>>(
129  motherBoard, display, *screen,
130  videoSource, 1280, 240, true));
131 #endif
132  default:
133  UNREACHABLE; return nullptr;
134  }
135 #if COMPONENT_GL
137  return std::make_unique<V9990SDLRasterizer<uint32_t>>(
138  vdp, display, *screen,
139  std::make_unique<GLPostProcessor>(
140  motherBoard, display, *screen,
141  videoSource, 1280, 240, true));
142 #endif
143  default:
144  UNREACHABLE; return nullptr;
145  }
146 }
147 
148 #if COMPONENT_LASERDISC
149 std::unique_ptr<LDRasterizer> SDLVideoSystem::createLDRasterizer(
150  LaserdiscPlayer& ld)
151 {
152  std::string videoSource = "Laserdisc"; // TODO handle multiple???
153  MSXMotherBoard& motherBoard = ld.getMotherBoard();
154  switch (renderSettings.getRenderer()) {
155  case RenderSettings::SDL:
158  switch (screen->getSDLFormat().BytesPerPixel) {
159 #if HAVE_16BPP
160  case 2:
161  return std::make_unique<LDSDLRasterizer<uint16_t>>(
162  *screen,
163  std::make_unique<FBPostProcessor<uint16_t>>(
164  motherBoard, display, *screen,
165  videoSource, 640, 480, false));
166 #endif
167 #if HAVE_32BPP
168  case 4:
169  return std::make_unique<LDSDLRasterizer<uint32_t>>(
170  *screen,
171  std::make_unique<FBPostProcessor<uint32_t>>(
172  motherBoard, display, *screen,
173  videoSource, 640, 480, false));
174 #endif
175  default:
176  UNREACHABLE; return nullptr;
177  }
178 #if COMPONENT_GL
180  return std::make_unique<LDSDLRasterizer<uint32_t>>(
181  *screen,
182  std::make_unique<GLPostProcessor>(
183  motherBoard, display, *screen,
184  videoSource, 640, 480, false));
185 #endif
186  default:
187  UNREACHABLE; return nullptr;
188  }
189 }
190 #endif
191 
192 gl::ivec2 SDLVideoSystem::getWindowSize()
193 {
194  int factor = renderSettings.getScaleFactor();
195  switch (renderSettings.getRenderer()) {
196  case RenderSettings::SDL:
199  // We don't have 4x software scalers yet.
200  if (factor > 3) factor = 3;
201  break;
203  // All scale factors are supported.
204  break;
206  factor = 0;
207  break;
208  default:
209  UNREACHABLE;
210  }
211  return {320 * factor, 240 * factor};
212 }
213 
214 // TODO: If we can switch video system at any time (not just frame end),
215 // is this polling approach necessary at all?
217 {
218  // Check resolution.
219  if (getWindowSize() != screen->getLogicalSize()) {
220  return false;
221  }
222 
223  // Check fullscreen.
224  return screen->setFullScreen(renderSettings.getFullScreen());
225 }
226 
228 {
229  screen->finish();
230 }
231 
232 void SDLVideoSystem::takeScreenShot(const std::string& filename, bool withOsd)
233 {
234  if (withOsd) {
235  // we can directly save current content as screenshot
236  screen->saveScreenshot(filename);
237  } else {
238  // we first need to re-render to an off-screen surface
239  // with OSD layers disabled
240  ScopedLayerHider hideConsole(*consoleLayer);
241  ScopedLayerHider hideOsd(*osdGuiLayer);
242  std::unique_ptr<OutputSurface> surf = screen->createOffScreenSurface();
243  display.repaint(*surf);
244  surf->saveScreenshot(filename);
245  }
246 }
247 
249 {
250  screen->updateWindowTitle();
251 }
252 
254 {
255  return screen.get();
256 }
257 
258 void SDLVideoSystem::resize()
259 {
260  auto& rtScheduler = reactor.getRTScheduler();
261  auto& eventDistributor = reactor.getEventDistributor();
262  auto& inputEventGenerator = reactor.getInputEventGenerator();
263 
264  auto windowSize = getWindowSize();
265  unsigned width = windowSize[0];
266  unsigned height = windowSize[1];
267  // Destruct existing output surface before creating a new one.
268  screen.reset();
269 
270  switch (renderSettings.getRenderer()) {
271  case RenderSettings::SDL:
272  screen = std::make_unique<SDLVisibleSurface>(
273  width, height, display, rtScheduler,
274  eventDistributor, inputEventGenerator,
275  reactor.getCliComm());
276  break;
277 #if COMPONENT_GL
279  screen = std::make_unique<SDLGLVisibleSurface>(
280  width, height, display, rtScheduler,
281  eventDistributor, inputEventGenerator,
282  reactor.getCliComm());
283  break;
285  screen = std::make_unique<SDLGLVisibleSurface>(
286  width, height, display, rtScheduler,
287  eventDistributor, inputEventGenerator,
288  reactor.getCliComm(),
290  break;
292  screen = std::make_unique<SDLGLVisibleSurface>(
293  width, height, display, rtScheduler,
294  eventDistributor, inputEventGenerator,
295  reactor.getCliComm(),
297  break;
298 #endif
299  default:
300  UNREACHABLE;
301  }
302 }
303 
304 void SDLVideoSystem::update(const Setting& subject)
305 {
306  if (&subject == &renderSettings.getScaleFactorSetting()) {
307  // TODO: This is done via checkSettings instead,
308  // but is that still needed?
309  //resize();
310  } else {
311  UNREACHABLE;
312  }
313 }
314 
315 int SDLVideoSystem::signalEvent(const std::shared_ptr<const Event>& /*event*/)
316 {
317  // TODO: Currently window size depends only on scale factor.
318  // Maybe in the future it will be handled differently.
319  //auto& resizeEvent = checked_cast<const ResizeEvent&>(event);
320  //resize(resizeEvent.getX(), resizeEvent.getY());
321  //resize();
322  return 0;
323 }
324 
325 } // 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:64
std::unique_ptr< V9990Rasterizer > createV9990Rasterizer(V9990 &vdp) override
Create the V9990 rasterizer selected by the current renderer setting.
void registerEventListener(EventType type, EventListener &listener, Priority priority=OTHER)
Registers a given object to receive certain events.
void addLayer(Layer &layer)
Definition: Display.cc:376
void unregisterEventListener(EventType type, EventListener &listener)
Unregisters a previously registered event listener.
MSXMotherBoard & getMotherBoard()
virtual std::string getName() const
Returns a human-readable name for this device.
Definition: MSXDevice.cc:374
A frame buffer where pixels can be written to.
OSDGUI & getOSDGUI()
Definition: Display.hh:45
InputEventGenerator & getInputEventGenerator()
Definition: Reactor.hh:82
EventDistributor & getEventDistributor()
Definition: Reactor.hh:79
bool checkSettings() override
Requests that this renderer checks its settings against the current RenderSettings.
void attach(Observer< T > &observer)
Definition: Subject.hh:45
~SDLVideoSystem() override
Deactivates this video system.
void repaint()
Redraw the display.
Definition: Display.cc:327
RTScheduler & getRTScheduler()
Definition: Reactor.hh:78
void removeLayer(Layer &layer)
Definition: Display.cc:384
void takeScreenShot(const std::string &filename, bool withOsd) override
Take a screenshot.
std::unique_ptr< Rasterizer > createRasterizer(VDP &vdp) override
Create the rasterizer selected by the current renderer setting.
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
MSXMotherBoard & getMotherBoard() const
Get the mother board this device belongs to.
Definition: MSXDevice.cc:77
OutputSurface * getOutputSurface() override
TODO.
Unified implementation of MSX Video Display Processors (VDPs).
Definition: VDP.hh:61
RendererID getRenderer() const
void detach(Observer< T > &observer)
Definition: Subject.hh:51
CliComm & getCliComm()
Definition: Reactor.cc:280
SDLVideoSystem(Reactor &reactor, CommandConsole &console)
Activates this video system.
void updateWindowTitle() override
Called when the window title string has changed.
void flush() override
Finish pending drawing operations and make them visible to the user.
IntegerSetting & getScaleFactorSetting()
The current scaling factor.
#define UNREACHABLE
Definition: unreachable.hh:38