SDLVideoSystem.cc 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  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. #include "components.hh"
  17. #if COMPONENT_GL
  18. #include "SDLGLVisibleSurface.hh"
  19. #include "GLPostProcessor.hh"
  20. #endif
  21. #if COMPONENT_LASERDISC
  22. #include "LaserdiscPlayer.hh"
  23. #include "LDSDLRasterizer.hh"
  24. #endif
  25. namespace openmsx {
  26. SDLVideoSystem::SDLVideoSystem(Reactor& reactor_, CommandConsole& console)
  27. : reactor(reactor_)
  28. , display(reactor.getDisplay())
  29. , renderSettings(reactor.getDisplay().getRenderSettings())
  30. {
  31. resize();
  32. consoleLayer = screen->createConsoleLayer(reactor, console);
  33. snowLayer = screen->createSnowLayer();
  34. osdGuiLayer = screen->createOSDGUILayer(display.getOSDGUI());
  35. display.addLayer(*consoleLayer);
  36. display.addLayer(*snowLayer);
  37. display.addLayer(*osdGuiLayer);
  38. renderSettings.getScaleFactorSetting().attach(*this);
  39. reactor.getEventDistributor().registerEventListener(
  40. OPENMSX_RESIZE_EVENT, *this);
  41. }
  42. SDLVideoSystem::~SDLVideoSystem()
  43. {
  44. reactor.getEventDistributor().unregisterEventListener(
  45. OPENMSX_RESIZE_EVENT, *this);
  46. renderSettings.getScaleFactorSetting().detach(*this);
  47. display.removeLayer(*osdGuiLayer);
  48. display.removeLayer(*snowLayer);
  49. display.removeLayer(*consoleLayer);
  50. }
  51. std::unique_ptr<Rasterizer> SDLVideoSystem::createRasterizer(VDP& vdp)
  52. {
  53. std::string videoSource = (vdp.getName() == "VDP")
  54. ? "MSX" // for backwards compatibility
  55. : vdp.getName();
  56. auto& motherBoard = vdp.getMotherBoard();
  57. switch (renderSettings.getRenderer()) {
  58. case RenderSettings::SDL:
  59. switch (screen->getPixelFormat().getBytesPerPixel()) {
  60. #if HAVE_16BPP
  61. case 2:
  62. return std::make_unique<SDLRasterizer<uint16_t>>(
  63. vdp, display, *screen,
  64. std::make_unique<FBPostProcessor<uint16_t>>(
  65. motherBoard, display, *screen,
  66. videoSource, 640, 240, true));
  67. #endif
  68. #if HAVE_32BPP
  69. case 4:
  70. return std::make_unique<SDLRasterizer<uint32_t>>(
  71. vdp, display, *screen,
  72. std::make_unique<FBPostProcessor<uint32_t>>(
  73. motherBoard, display, *screen,
  74. videoSource, 640, 240, true));
  75. #endif
  76. default:
  77. UNREACHABLE; return nullptr;
  78. }
  79. #if COMPONENT_GL
  80. case RenderSettings::SDLGL_PP:
  81. return std::make_unique<SDLRasterizer<uint32_t>>(
  82. vdp, display, *screen,
  83. std::make_unique<GLPostProcessor>(
  84. motherBoard, display, *screen,
  85. videoSource, 640, 240, true));
  86. #endif
  87. default:
  88. UNREACHABLE; return nullptr;
  89. }
  90. }
  91. std::unique_ptr<V9990Rasterizer> SDLVideoSystem::createV9990Rasterizer(
  92. V9990& vdp)
  93. {
  94. std::string videoSource = (vdp.getName() == "Sunrise GFX9000")
  95. ? "GFX9000" // for backwards compatibility
  96. : vdp.getName();
  97. MSXMotherBoard& motherBoard = vdp.getMotherBoard();
  98. switch (renderSettings.getRenderer()) {
  99. case RenderSettings::SDL:
  100. switch (screen->getPixelFormat().getBytesPerPixel()) {
  101. #if HAVE_16BPP
  102. case 2:
  103. return std::make_unique<V9990SDLRasterizer<uint16_t>>(
  104. vdp, display, *screen,
  105. std::make_unique<FBPostProcessor<uint16_t>>(
  106. motherBoard, display, *screen,
  107. videoSource, 1280, 240, true));
  108. #endif
  109. #if HAVE_32BPP
  110. case 4:
  111. return std::make_unique<V9990SDLRasterizer<uint32_t>>(
  112. vdp, display, *screen,
  113. std::make_unique<FBPostProcessor<uint32_t>>(
  114. motherBoard, display, *screen,
  115. videoSource, 1280, 240, true));
  116. #endif
  117. default:
  118. UNREACHABLE; return nullptr;
  119. }
  120. #if COMPONENT_GL
  121. case RenderSettings::SDLGL_PP:
  122. return std::make_unique<V9990SDLRasterizer<uint32_t>>(
  123. vdp, display, *screen,
  124. std::make_unique<GLPostProcessor>(
  125. motherBoard, display, *screen,
  126. videoSource, 1280, 240, true));
  127. #endif
  128. default:
  129. UNREACHABLE; return nullptr;
  130. }
  131. }
  132. #if COMPONENT_LASERDISC
  133. std::unique_ptr<LDRasterizer> SDLVideoSystem::createLDRasterizer(
  134. LaserdiscPlayer& ld)
  135. {
  136. std::string videoSource = "Laserdisc"; // TODO handle multiple???
  137. MSXMotherBoard& motherBoard = ld.getMotherBoard();
  138. switch (renderSettings.getRenderer()) {
  139. case RenderSettings::SDL:
  140. switch (screen->getPixelFormat().getBytesPerPixel()) {
  141. #if HAVE_16BPP
  142. case 2:
  143. return std::make_unique<LDSDLRasterizer<uint16_t>>(
  144. *screen,
  145. std::make_unique<FBPostProcessor<uint16_t>>(
  146. motherBoard, display, *screen,
  147. videoSource, 640, 480, false));
  148. #endif
  149. #if HAVE_32BPP
  150. case 4:
  151. return std::make_unique<LDSDLRasterizer<uint32_t>>(
  152. *screen,
  153. std::make_unique<FBPostProcessor<uint32_t>>(
  154. motherBoard, display, *screen,
  155. videoSource, 640, 480, false));
  156. #endif
  157. default:
  158. UNREACHABLE; return nullptr;
  159. }
  160. #if COMPONENT_GL
  161. case RenderSettings::SDLGL_PP:
  162. return std::make_unique<LDSDLRasterizer<uint32_t>>(
  163. *screen,
  164. std::make_unique<GLPostProcessor>(
  165. motherBoard, display, *screen,
  166. videoSource, 640, 480, false));
  167. #endif
  168. default:
  169. UNREACHABLE; return nullptr;
  170. }
  171. }
  172. #endif
  173. gl::ivec2 SDLVideoSystem::getWindowSize()
  174. {
  175. int factor = renderSettings.getScaleFactor();
  176. switch (renderSettings.getRenderer()) {
  177. case RenderSettings::SDL:
  178. // We don't have 4x software scalers yet.
  179. if (factor > 3) factor = 3;
  180. break;
  181. case RenderSettings::SDLGL_PP:
  182. // All scale factors are supported.
  183. break;
  184. default:
  185. UNREACHABLE;
  186. }
  187. return {320 * factor, 240 * factor};
  188. }
  189. // TODO: If we can switch video system at any time (not just frame end),
  190. // is this polling approach necessary at all?
  191. bool SDLVideoSystem::checkSettings()
  192. {
  193. // Check resolution.
  194. if (getWindowSize() != screen->getLogicalSize()) {
  195. return false;
  196. }
  197. // Check fullscreen.
  198. return screen->setFullScreen(renderSettings.getFullScreen());
  199. }
  200. void SDLVideoSystem::flush()
  201. {
  202. screen->finish();
  203. }
  204. void SDLVideoSystem::takeScreenShot(const std::string& filename, bool withOsd)
  205. {
  206. if (withOsd) {
  207. // we can directly save current content as screenshot
  208. screen->saveScreenshot(filename);
  209. } else {
  210. // we first need to re-render to an off-screen surface
  211. // with OSD layers disabled
  212. ScopedLayerHider hideConsole(*consoleLayer);
  213. ScopedLayerHider hideOsd(*osdGuiLayer);
  214. std::unique_ptr<OutputSurface> surf = screen->createOffScreenSurface();
  215. display.repaint(*surf);
  216. surf->saveScreenshot(filename);
  217. }
  218. }
  219. void SDLVideoSystem::updateWindowTitle()
  220. {
  221. screen->updateWindowTitle();
  222. }
  223. OutputSurface* SDLVideoSystem::getOutputSurface()
  224. {
  225. return screen.get();
  226. }
  227. void SDLVideoSystem::showCursor(bool show)
  228. {
  229. SDL_ShowCursor(show ? SDL_ENABLE : SDL_DISABLE);
  230. }
  231. void SDLVideoSystem::repaint()
  232. {
  233. display.repaint();
  234. }
  235. void SDLVideoSystem::resize()
  236. {
  237. auto& rtScheduler = reactor.getRTScheduler();
  238. auto& eventDistributor = reactor.getEventDistributor();
  239. auto& inputEventGenerator = reactor.getInputEventGenerator();
  240. auto [width, height] = getWindowSize();
  241. // Destruct existing output surface before creating a new one.
  242. screen.reset();
  243. switch (renderSettings.getRenderer()) {
  244. case RenderSettings::SDL:
  245. screen = std::make_unique<SDLVisibleSurface>(
  246. width, height, display, rtScheduler,
  247. eventDistributor, inputEventGenerator,
  248. reactor.getCliComm(), *this);
  249. break;
  250. #if COMPONENT_GL
  251. case RenderSettings::SDLGL_PP:
  252. screen = std::make_unique<SDLGLVisibleSurface>(
  253. width, height, display, rtScheduler,
  254. eventDistributor, inputEventGenerator,
  255. reactor.getCliComm(), *this);
  256. break;
  257. #endif
  258. default:
  259. UNREACHABLE;
  260. }
  261. }
  262. void SDLVideoSystem::update(const Setting& subject)
  263. {
  264. if (&subject == &renderSettings.getScaleFactorSetting()) {
  265. // TODO: This is done via checkSettings instead,
  266. // but is that still needed?
  267. //resize();
  268. } else {
  269. UNREACHABLE;
  270. }
  271. }
  272. int SDLVideoSystem::signalEvent(const std::shared_ptr<const Event>& /*event*/)
  273. {
  274. // TODO: Currently window size depends only on scale factor.
  275. // Maybe in the future it will be handled differently.
  276. //auto& resizeEvent = checked_cast<const ResizeEvent&>(event);
  277. //resize(resizeEvent.getX(), resizeEvent.getY());
  278. //resize();
  279. return 0;
  280. }
  281. } // namespace openmsx