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()) {
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 
102 std::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()) {
110  case RenderSettings::SDL:
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
145 std::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()) {
151  case RenderSettings::SDL:
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 
186 gl::ivec2 SDLVideoSystem::getWindowSize()
187 {
188  int factor = renderSettings.getScaleFactor();
189  switch (renderSettings.getRenderer()) {
190  case RenderSettings::SDL:
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:
198  UNREACHABLE;
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 
221 void 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.repaint(*surf);
233  surf->saveScreenshot(filename);
234  }
235 }
236 
238 {
239  screen->updateWindowTitle();
240 }
241 
243 {
244  return screen.get();
245 }
246 
248 {
249  SDL_ShowCursor(show ? SDL_ENABLE : SDL_DISABLE);
250 }
251 
253 {
254  display.repaint();
255 }
256 
257 void SDLVideoSystem::resize()
258 {
259  auto& rtScheduler = reactor.getRTScheduler();
260  auto& eventDistributor = reactor.getEventDistributor();
261  auto& inputEventGenerator = reactor.getInputEventGenerator();
262 
263  auto [width, height] = getWindowSize();
264  // Destruct existing output surface before creating a new one.
265  screen.reset();
266 
267  switch (renderSettings.getRenderer()) {
268  case RenderSettings::SDL:
269  screen = std::make_unique<SDLVisibleSurface>(
270  width, height, display, rtScheduler,
271  eventDistributor, inputEventGenerator,
272  reactor.getCliComm(), *this);
273  break;
274 #if COMPONENT_GL
276  screen = std::make_unique<SDLGLVisibleSurface>(
277  width, height, display, rtScheduler,
278  eventDistributor, inputEventGenerator,
279  reactor.getCliComm(), *this);
280  break;
281 #endif
282  default:
283  UNREACHABLE;
284  }
285 }
286 
287 void SDLVideoSystem::update(const Setting& subject)
288 {
289  if (&subject == &renderSettings.getScaleFactorSetting()) {
290  // TODO: This is done via checkSettings instead,
291  // but is that still needed?
292  //resize();
293  } else {
294  UNREACHABLE;
295  }
296 }
297 
298 int SDLVideoSystem::signalEvent(const std::shared_ptr<const Event>& /*event*/)
299 {
300  // TODO: Currently window size depends only on scale factor.
301  // Maybe in the future it will be handled differently.
302  //auto& resizeEvent = checked_cast<const ResizeEvent&>(event);
303  //resize(resizeEvent.getX(), resizeEvent.getY());
304  //resize();
305  return 0;
306 }
307 
308 } // namespace openmsx
openmsx::SDLVideoSystem::getOutputSurface
OutputSurface * getOutputSurface() override
TODO.
Definition: SDLVideoSystem.cc:242
openmsx::ScopedLayerHider
Definition: Layer.hh:92
openmsx::SDLVideoSystem::createV9990Rasterizer
std::unique_ptr< V9990Rasterizer > createV9990Rasterizer(V9990 &vdp) override
Create the V9990 rasterizer selected by the current renderer setting.
Definition: SDLVideoSystem.cc:102
openmsx::Display::getOSDGUI
OSDGUI & getOSDGUI()
Definition: Display.hh:45
IntegerSetting.hh
openmsx::Subject::detach
void detach(Observer< T > &observer)
Definition: Subject.hh:56
Display.hh
openmsx::SDLVideoSystem::createRasterizer
std::unique_ptr< Rasterizer > createRasterizer(VDP &vdp) override
Create the rasterizer selected by the current renderer setting.
Definition: SDLVideoSystem.cc:61
openmsx::VDP
Unified implementation of MSX Video Display Processors (VDPs).
Definition: VDP.hh:61
VDP.hh
openmsx::SDLVideoSystem::updateWindowTitle
void updateWindowTitle() override
Called when the window title string has changed.
Definition: SDLVideoSystem.cc:237
openmsx::RenderSettings::getScaleFactorSetting
IntegerSetting & getScaleFactorSetting()
The current scaling factor.
Definition: RenderSettings.hh:119
openmsx::Reactor::getEventDistributor
EventDistributor & getEventDistributor()
Definition: Reactor.hh:81
openmsx::Subject::attach
void attach(Observer< T > &observer)
Definition: Subject.hh:50
openmsx::SDLVideoSystem::~SDLVideoSystem
~SDLVideoSystem() override
Deactivates this video system.
Definition: SDLVideoSystem.cc:49
openmsx::LaserdiscPlayer
Definition: LaserdiscPlayer.hh:25
gl::vecN
Definition: gl_vec.hh:35
openmsx::RenderSettings::SDLGL_PP
@ SDLGL_PP
Definition: RenderSettings.hh:27
openmsx::RenderSettings::getScaleFactor
int getScaleFactor() const
Definition: RenderSettings.hh:120
openmsx::Reactor
Contains the main loop of openMSX.
Definition: Reactor.hh:66
Reactor.hh
UNREACHABLE
#define UNREACHABLE
Definition: unreachable.hh:38
openmsx::SDLVideoSystem::showCursor
void showCursor(bool show) override
Definition: SDLVideoSystem.cc:247
SDLVisibleSurface.hh
V9990.hh
openmsx::MSXMotherBoard
Definition: MSXMotherBoard.hh:59
EventDistributor.hh
openmsx::Reactor::getInputEventGenerator
InputEventGenerator & getInputEventGenerator()
Definition: Reactor.hh:84
SDLGLVisibleSurface.hh
openmsx::filename
constexpr const char *const filename
Definition: FirmwareSwitch.cc:10
openmsx::OPENMSX_RESIZE_EVENT
@ OPENMSX_RESIZE_EVENT
Definition: Event.hh:30
openmsx::MSXDevice::getMotherBoard
MSXMotherBoard & getMotherBoard() const
Get the mother board this device belongs to.
Definition: MSXDevice.cc:75
build-info.hh
LaserdiscPlayer.hh
openmsx::SDLVideoSystem::takeScreenShot
void takeScreenShot(const std::string &filename, bool withOsd) override
Take a screenshot.
Definition: SDLVideoSystem.cc:221
RenderSettings.hh
openmsx::SDLVideoSystem::flush
void flush() override
Finish pending drawing operations and make them visible to the user.
Definition: SDLVideoSystem.cc:216
FBPostProcessor.hh
openmsx::RenderSettings::getRenderer
RendererID getRenderer() const
Definition: RenderSettings.hh:111
components.hh
openmsx::SDLVideoSystem::repaint
void repaint() override
Definition: SDLVideoSystem.cc:252
openmsx::RenderSettings::SDL
@ SDL
Definition: RenderSettings.hh:27
openmsx::MSXDevice::getName
virtual std::string getName() const
Returns a human-readable name for this device.
Definition: MSXDevice.cc:381
openmsx::RenderSettings::getFullScreen
bool getFullScreen() const
Definition: RenderSettings.hh:68
openmsx::SDLVideoSystem::checkSettings
bool checkSettings() override
Requests that this renderer checks its settings against the current RenderSettings.
Definition: SDLVideoSystem.cc:205
SDLRasterizer.hh
openmsx::Reactor::getCliComm
CliComm & getCliComm()
Definition: Reactor.cc:306
openmsx::SDLVideoSystem::createLDRasterizer
std::unique_ptr< LDRasterizer > createLDRasterizer(LaserdiscPlayer &ld) override
Definition: SDLVideoSystem.cc:145
openmsx::OutputSurface
A frame buffer where pixels can be written to.
Definition: OutputSurface.hh:19
LDSDLRasterizer.hh
openmsx::Display::repaint
void repaint()
Redraw the display.
Definition: Display.cc:327
openmsx::EventDistributor::registerEventListener
void registerEventListener(EventType type, EventListener &listener, Priority priority=OTHER)
Registers a given object to receive certain events.
Definition: EventDistributor.cc:23
openmsx::Display::addLayer
void addLayer(Layer &layer)
Definition: Display.cc:376
unreachable.hh
openmsx::LaserdiscPlayer::getMotherBoard
MSXMotherBoard & getMotherBoard()
Definition: LaserdiscPlayer.hh:47
openmsx::EventDistributor::unregisterEventListener
void unregisterEventListener(EventType type, EventListener &listener)
Unregisters a previously registered event listener.
Definition: EventDistributor.cc:35
V9990SDLRasterizer.hh
openmsx::SDLVideoSystem::SDLVideoSystem
SDLVideoSystem(Reactor &reactor, CommandConsole &console)
Activates this video system.
Definition: SDLVideoSystem.cc:29
openmsx
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
SDLVideoSystem.hh
openmsx::Reactor::getRTScheduler
RTScheduler & getRTScheduler()
Definition: Reactor.hh:80
openmsx::Display::removeLayer
void removeLayer(Layer &layer)
Definition: Display.cc:384
openmsx::V9990
Implementation of the Yamaha V9990 VDP as used in the GFX9000 cartridge by Sunrise.
Definition: V9990.hh:30
openmsx::CommandConsole
Definition: CommandConsole.hh:64
GLPostProcessor.hh