SDLVisibleSurface.cc 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. #include "SDLVisibleSurface.hh"
  2. #include "SDLOffScreenSurface.hh"
  3. #include "PNG.hh"
  4. #include "SDLSnow.hh"
  5. #include "OSDConsoleRenderer.hh"
  6. #include "OSDGUILayer.hh"
  7. #include "MSXException.hh"
  8. #include "unreachable.hh"
  9. #include "vla.hh"
  10. #include "build-info.hh"
  11. #include <cstdint>
  12. #include <memory>
  13. namespace openmsx {
  14. SDLVisibleSurface::SDLVisibleSurface(
  15. unsigned width, unsigned height,
  16. Display& display_,
  17. RTScheduler& rtScheduler_,
  18. EventDistributor& eventDistributor_,
  19. InputEventGenerator& inputEventGenerator_,
  20. CliComm& cliComm_,
  21. VideoSystem& videoSystem_)
  22. : SDLVisibleSurfaceBase(display_, rtScheduler_, eventDistributor_,
  23. inputEventGenerator_, cliComm_, videoSystem_)
  24. {
  25. int flags = 0;
  26. createSurface(width, height, flags);
  27. renderer.reset(SDL_CreateRenderer(window.get(), -1, 0));
  28. if (!renderer) {
  29. std::string err = SDL_GetError();
  30. throw InitException("Could not create renderer: " + err);
  31. }
  32. SDL_RenderSetLogicalSize(renderer.get(), width, height);
  33. setSDLRenderer(renderer.get());
  34. surface.reset(SDL_CreateRGBSurface(
  35. 0, width, height, 32,
  36. 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000));
  37. if (!surface) {
  38. std::string err = SDL_GetError();
  39. throw InitException("Could not create surface: " + err);
  40. }
  41. setSDLSurface(surface.get());
  42. texture.reset(SDL_CreateTexture(
  43. renderer.get(), SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING,
  44. width, height));
  45. if (!texture) {
  46. std::string err = SDL_GetError();
  47. throw InitException("Could not create texture: " + err);
  48. }
  49. setSDLPixelFormat(*surface->format);
  50. // In the SDL renderer logical size is the same as physical size.
  51. gl::ivec2 size(width, height);
  52. calculateViewPort(size, size);
  53. }
  54. void SDLVisibleSurface::flushFrameBuffer()
  55. {
  56. SDL_Renderer* render = getSDLRenderer();
  57. SDL_UpdateTexture(texture.get(), nullptr, surface->pixels, surface->pitch);
  58. SDL_RenderClear(render);
  59. SDL_RenderCopy(render, texture.get(), nullptr, nullptr);
  60. }
  61. void SDLVisibleSurface::finish()
  62. {
  63. SDL_RenderPresent(getSDLRenderer());
  64. }
  65. std::unique_ptr<Layer> SDLVisibleSurface::createSnowLayer()
  66. {
  67. switch (getPixelFormat().getBytesPerPixel()) {
  68. #if HAVE_16BPP
  69. case 2:
  70. return std::make_unique<SDLSnow<uint16_t>>(*this, getDisplay());
  71. #endif
  72. #if HAVE_32BPP
  73. case 4:
  74. return std::make_unique<SDLSnow<uint32_t>>(*this, getDisplay());
  75. #endif
  76. default:
  77. UNREACHABLE; return nullptr;
  78. }
  79. }
  80. std::unique_ptr<Layer> SDLVisibleSurface::createConsoleLayer(
  81. Reactor& reactor, CommandConsole& console)
  82. {
  83. const bool openGL = false;
  84. auto [width, height] = getLogicalSize();
  85. return std::make_unique<OSDConsoleRenderer>(
  86. reactor, console, width, height, openGL);
  87. }
  88. std::unique_ptr<Layer> SDLVisibleSurface::createOSDGUILayer(OSDGUI& gui)
  89. {
  90. return std::make_unique<SDLOSDGUILayer>(gui);
  91. }
  92. std::unique_ptr<OutputSurface> SDLVisibleSurface::createOffScreenSurface()
  93. {
  94. return std::make_unique<SDLOffScreenSurface>(*surface);
  95. }
  96. void SDLVisibleSurface::saveScreenshot(const std::string& filename)
  97. {
  98. saveScreenshotSDL(*this, filename);
  99. }
  100. void SDLVisibleSurface::saveScreenshotSDL(
  101. const SDLOutputSurface& output, const std::string& filename)
  102. {
  103. auto [width, height] = output.getLogicalSize();
  104. VLA(const void*, rowPointers, height);
  105. MemBuffer<uint8_t> buffer(width * height * 3);
  106. for (int i = 0; i < height; ++i) {
  107. rowPointers[i] = &buffer[width * 3 * i];
  108. }
  109. if (SDL_RenderReadPixels(
  110. output.getSDLRenderer(), nullptr,
  111. SDL_PIXELFORMAT_RGB24, buffer.data(), width * 3)) {
  112. throw MSXException("Couldn't acquire screenshot pixels: ", SDL_GetError());
  113. }
  114. PNG::save(width, height, rowPointers, filename);
  115. }
  116. void SDLVisibleSurface::clearScreen()
  117. {
  118. SDL_FillRect(surface.get(), nullptr, 0);
  119. }
  120. } // namespace openmsx