39 , screenShotCmd(reactor_.getCommandController())
40 , fpsInfo(reactor_.getOpenMSXInfoCommand())
41 , osdGui(reactor_.getCommandController(), *this)
43 , renderSettings(reactor.getCommandController())
44 , commandConsole(reactor.getGlobalCommandController(),
45 reactor.getEventDistributor(), *this)
48 repeat(NUM_FRAME_DURATIONS, [&] {
50 frameDurationSum += 20;
94 assert(listeners.empty());
101 assert(!switchInProgress);
103 switchInProgress =
true;
115 return videoSystem ? videoSystem->getOutputSurface() :
nullptr;
118void Display::resetVideoSystem()
133 assert(!
contains(listeners, &listener));
134 listeners.push_back(&listener);
145 return (it != layers.end()) ? *it :
nullptr;
148Display::Layers::iterator Display::baseLayer()
152 auto it =
end(layers);
154 if (it ==
begin(layers)) {
167void Display::executeRT()
172int Display::signalEvent(
const Event& event)
175 [&](
const FinishFrameEvent&
e) {
176 if (
e.needRender()) {
179 Event::create<FrameDrawnEvent>());
182 [&](
const SwitchRendererEvent& ) {
185 [&](
const MachineLoadedEvent& ) {
186 videoSystem->updateWindowTitle();
188 [&](
const ExposeEvent& ) {
193 [&](
const FocusEvent&
e) {
211 ad_printf(
"Setting renderFrozen to %d", !
e.getGain());
212 renderFrozen = !
e.getGain();
215 [](
const EventBase&) { }
224 strAppend(title,
" [", BUILD_FLAVOUR,
']');
227 if (
const HardwareConfig* machine = motherboard->getMachineConfig()) {
228 const auto& config = machine->getConfig();
230 config.getChild(
"info").getChildData(
"manufacturer"),
' ',
231 config.getChild(
"info").getChildData(
"code"));
239 if (&
setting == &renderSettings.getRendererSetting()) {
240 checkRendererSwitch();
241 }
else if (&
setting == &renderSettings.getFullScreenSetting()) {
242 checkRendererSwitch();
243 }
else if (&
setting == &renderSettings.getScaleFactorSetting()) {
244 checkRendererSwitch();
250void Display::checkRendererSwitch()
252 if (switchInProgress) {
259 if ((newRenderer != currentRenderer) ||
261 currentRenderer = newRenderer;
265 switchInProgress =
true;
267 Event::create<SwitchRendererEvent>());
271void Display::doRendererSwitch()
273 assert(switchInProgress);
275 bool success =
false;
280 }
catch (MSXException&
e) {
283 "Couldn't activate renderer ",
284 rendererSetting.getString(),
285 ": ",
e.getMessage());
288 errorMsg +=
"\nTrying to switch to SDL renderer instead...";
293 auto curVal = scaleFactorSetting.
getInt();
297 " (and I have no other ideas to try...)");
299 strAppend(errorMsg,
"\nTrying to decrease scale_factor setting from ",
300 curVal,
" to ", curVal - 1,
"...");
301 scaleFactorSetting.setInt(curVal - 1);
307 switchInProgress =
false;
310void Display::doRendererSwitch2()
312 for (
auto& l : listeners) {
313 l->preVideoSystemChange();
319 for (
auto& l : listeners) {
320 l->postVideoSystemChange();
326 if (switchInProgress) {
341 if (
OutputSurface* surface = videoSystem->getOutputSurface()) {
343 videoSystem->flush();
349 auto duration = now - prevTimeStamp;
351 frameDurationSum += duration - frameDurations.
removeBack();
357 for (
auto it = baseLayer(); it !=
end(layers); ++it) {
359 (*it)->paint(surface);
368 videoSystem->repaint();
382 int z = layer.
getZ();
384 layers.insert(it, &layer);
393void Display::updateZ(
Layer& layer)
noexcept
404Display::ScreenShotCmd::ScreenShotCmd(CommandController& commandController_)
405 : Command(commandController_,
"screenshot")
409void Display::ScreenShotCmd::execute(std::span<const TclObject> tokens, TclObject& result)
411 std::string_view prefix =
"openmsx";
412 bool rawShot =
false;
413 bool msxOnly =
false;
414 bool doubleSize =
false;
415 bool withOsd =
false;
420 flagArg(
"-doublesize", doubleSize),
423 auto arguments =
parseTclArgs(getInterpreter(), tokens.subspan(1), info);
425 auto& display =
OUTER(Display, screenShotCmd);
427 display.getCliComm().printWarning(
428 "The -msxonly option has been deprecated and will "
429 "be removed in a future release. Instead, use the "
430 "-raw option for the same effect.");
433 if (doubleSize && !rawShot) {
434 throw CommandException(
"-doublesize option can only be used in "
435 "combination with -raw");
437 if (rawShot && withOsd) {
438 throw CommandException(
"-with-osd cannot be used in "
439 "combination with -raw");
442 std::string_view fname;
443 switch (arguments.size()) {
448 fname = arguments[0].getString();
454 fname,
"screenshots", prefix,
".png");
459 display.getVideoSystem().takeScreenShot(filename, withOsd);
460 }
catch (MSXException&
e) {
461 throw CommandException(
462 "Failed to take screenshot: ",
e.getMessage());
465 auto* videoLayer =
dynamic_cast<VideoLayer*
>(
466 display.findActiveLayer());
468 throw CommandException(
469 "Current renderer doesn't support taking screenshots.");
471 unsigned height = doubleSize ? 480 : 240;
473 videoLayer->takeRawScreenShot(height, filename);
474 }
catch (MSXException&
e) {
475 throw CommandException(
476 "Failed to take screenshot: ",
e.getMessage());
480 display.getCliComm().printInfo(
"Screen saved to ", filename);
484string Display::ScreenShotCmd::help(std::span<const TclObject> )
const
487 return "screenshot Write screenshot to file \"openmsxNNNN.png\"\n"
488 "screenshot <filename> Write screenshot to indicated file\n"
489 "screenshot -prefix foo Write screenshot to file \"fooNNNN.png\"\n"
490 "screenshot -raw 320x240 raw screenshot (of MSX screen only)\n"
491 "screenshot -raw -doublesize 640x480 raw screenshot (of MSX screen only)\n"
492 "screenshot -with-osd Include OSD elements in the screenshot\n"
493 "screenshot -no-sprites Don't include sprites in the screenshot\n";
496void Display::ScreenShotCmd::tabCompletion(std::vector<string>& tokens)
const
498 using namespace std::literals;
499 static constexpr std::array extra = {
500 "-prefix"sv,
"-raw"sv,
"-doublesize"sv,
"-with-osd"sv,
"-no-sprites"sv,
508Display::FpsInfoTopic::FpsInfoTopic(InfoCommand& openMSXInfoCommand)
509 : InfoTopic(openMSXInfoCommand,
"fps")
513void Display::FpsInfoTopic::execute(std::span<const TclObject> ,
514 TclObject& result)
const
516 auto& display =
OUTER(Display, fpsInfo);
517 result = 1000000.0f * Display::NUM_FRAME_DURATIONS / narrow_cast<float>(display.frameDurationSum);
520string Display::FpsInfoTopic::help(std::span<const TclObject> )
const
522 return "Returns the current rendering speed in frames per second.";
constexpr T & removeBack()
constexpr void addFront(const T &element)
void printWarning(std::string_view message)
std::string getWindowTitle()
void repaint()
Redraw the display.
void detach(VideoSystemChangeListener &listener)
CliComm & getCliComm() const
void removeLayer(Layer &layer)
VideoSystem & getVideoSystem()
Display(Reactor &reactor)
void attach(VideoSystemChangeListener &listener)
void repaintDelayed(uint64_t delta)
Layer * findActiveLayer() const
OutputSurface * getOutputSurface()
void addLayer(Layer &layer)
void unregisterEventListener(EventType type, EventListener &listener)
Unregisters a previously registered event listener.
void distributeEvent(Event &&event)
Schedule the given event for delivery.
void registerEventListener(EventType type, EventListener &listener, Priority priority=OTHER)
Registers a given object to receive certain events.
int getInt() const noexcept
Interface for display layers.
@ COVER_FULL
Layer fully covers the screen: any underlying layers are invisible.
@ COVER_NONE
Layer is not visible, that is completely transparent.
void setDisplay(LayerListener &display_)
Store pointer to Display.
ZIndex getZ() const
Query the Z-index of this layer.
A frame buffer where pixels can be written to.
void scheduleRT(uint64_t delta)
Contains the main loop of openMSX.
MSXMotherBoard * getMotherBoard() const
EventDistributor & getEventDistributor()
RendererSetting & getRendererSetting()
The current renderer.
BooleanSetting & getFullScreenSetting()
Full screen [on, off].
IntegerSetting & getScaleFactorSetting()
The current scaling factor.
RendererID getRenderer() const
void detach(Observer< T > &observer)
void attach(Observer< T > &observer)
static std::string full()
static const bool RELEASE
string parseCommandFileArgument(string_view argument, string_view directory, string_view prefix, string_view extension)
Helper function for parsing filename arguments in Tcl commands.
std::unique_ptr< VideoSystem > createVideoSystem(Reactor &reactor)
Create the video system required by the current renderer setting.
uint64_t getTime()
Get current (real) time in us.
This file implemented 3 utility functions:
auto visit(Visitor &&visitor, const Event &event)
ArgsInfo valueArg(std::string_view name, T &value)
std::vector< TclObject > parseTclArgs(Interpreter &interp, std::span< const TclObject > inArgs, std::span< const ArgsInfo > table)
FileContext userFileContext(string_view savePath)
ArgsInfo flagArg(std::string_view name, bool &flag)
auto find_if(InputRange &&range, UnaryPredicate pred)
#define OUTER(type, member)
void move_pop_back(VECTOR &v, typename VECTOR::iterator it)
Erase the pointed to element from the given vector.
auto rfind_unguarded(RANGE &range, const VAL &val, Proj proj={})
Similar to the find(_if)_unguarded functions above, but searches from the back to front.
constexpr bool contains(ITER first, ITER last, const VAL &val)
Check if a range contains a given value, using linear search.
std::string strCat(Ts &&...ts)
void strAppend(std::string &result, Ts &&...ts)
constexpr void repeat(T n, Op op)
Repeat the given operation 'op' 'n' times.
constexpr auto begin(const zstring_view &x)
constexpr auto end(const zstring_view &x)