openMSX
Video9000.cc
Go to the documentation of this file.
1#include "Video9000.hh"
2#include "VDP.hh"
3#include "V9990.hh"
4#include "Reactor.hh"
5#include "Display.hh"
6#include "PostProcessor.hh"
7#include "EventDistributor.hh"
8#include "Event.hh"
9#include "MSXMotherBoard.hh"
10#include "VideoSourceSetting.hh"
11#include "CommandException.hh"
12#include "serialize.hh"
13
14namespace openmsx {
15
17 : MSXDevice(config)
18 , VideoLayer(getMotherBoard(), getName())
19 , videoSourceSetting(getMotherBoard().getVideoSource())
20{
21 // we can't set activeLayer yet
24 getReactor().getDisplay().attach(*this);
25}
26
28{
30 auto refs = getReferences(); // make copy
31 bool error = false;
32 if (refs.size() != 2) error = true;
33 if (!error && !dynamic_cast<VDP*>(refs[0])) {
34 std::swap(refs[0], refs[1]); // try reverse order
35 }
36 if (!error) vdp = dynamic_cast<VDP* >(refs[0]);
37 if (!error) v9990 = dynamic_cast<V9990*>(refs[1]);
38 if (error || !vdp || !v9990) {
39 throw MSXException(
40 "Invalid Video9000 configuration: "
41 "need reference to VDP and V9990 device.");
42 }
43}
44
51
52void Video9000::reset(EmuTime::param time)
53{
54 Video9000::writeIO(0x6f, 0x10, time);
55}
56
57void Video9000::writeIO(word /*port*/, byte newValue, EmuTime::param /*time*/)
58{
59 if (newValue == value) return;
60 value = newValue;
61 recalculate();
62}
63
64void Video9000::recalculate()
65{
66 int video9000id = getVideoSource();
67 v99x8Layer = vdp ->getPostProcessor();
68 v9990Layer = v9990->getPostProcessor();
69 assert(!!v99x8Layer == !!v9990Layer); // either both or neither
70
71 // ...0.... -> only V9990
72 // ...10... -> only V99x8
73 // ...11... -> superimpose
74 bool showV99x8 = ((value & 0x10) == 0x10);
75 bool showV9990 = ((value & 0x18) != 0x10);
76 assert(showV99x8 || showV9990);
78 if (v99x8Layer) v99x8Layer->setVideo9000Active(
79 video9000id,
80 showV99x8 ? (showV9990 ? BACK : FRONT) : NO);
81 if (v9990Layer) v9990Layer->setVideo9000Active(
82 video9000id, showV9990 ? FRONT : NO);
83 activeLayer = showV9990 ? v9990Layer : v99x8Layer;
84 // activeLayer==nullptr is possible for renderer=none
85 recalculateVideoSource();
86}
87
88void Video9000::recalculateVideoSource()
89{
90 // Disable superimpose when gfx9000 layer is selected. That way you
91 // can look at the gfx9000-only output even when the video9000 software
92 // enabled superimpose mode (mostly useful for debugging).
93 bool superimpose = ((value & 0x18) == 0x18);
95 superimpose && (videoSourceSetting.getSource() == getVideoSource()));
96}
97
98void Video9000::preVideoSystemChange() noexcept
99{
100 activeLayer = nullptr; // will be recalculated on next paint()
101}
102
103void Video9000::postVideoSystemChange() noexcept
104{
105 // We can't yet re-initialize 'activeLayer' here because the
106 // new v99x8/v9990 layer may not be created yet.
107}
108
109void Video9000::paint(OutputSurface& output)
110{
111 if (!activeLayer) {
112 recalculate();
113 }
114 // activeLayer==nullptr is possible for renderer=none, but in that case
115 // the paint() method will never be called.
116 activeLayer->paint(output);
117}
118
119void Video9000::takeRawScreenShot(unsigned height, const std::string& filename)
120{
121 auto* layer = dynamic_cast<VideoLayer*>(activeLayer);
122 if (!layer) {
123 throw CommandException("TODO");
124 }
125 layer->takeRawScreenShot(height, filename);
126}
127
128bool Video9000::signalEvent(const Event& event)
129{
130 int video9000id = getVideoSource();
131
132 assert(getType(event) == EventType::FINISH_FRAME);
133 const auto& ffe = get_event<FinishFrameEvent>(event);
134 if (ffe.isSkipped()) return false;
135 if (videoSourceSetting.getSource() != video9000id) return false;
136
137 bool superimpose = ((value & 0x18) == 0x18);
138 if (superimpose && v99x8Layer && v9990Layer &&
139 (ffe.getSource() == v99x8Layer->getVideoSource())) {
140 // inform V9990 about the new V99x8 frame
141 v9990Layer->setSuperimposeVdpFrame(v99x8Layer->getPaintFrame());
142 }
143
144 bool showV9990 = ((value & 0x18) != 0x10); // v9990 or superimpose
145 if (( showV9990 && v9990Layer && (ffe.getSource() == v9990Layer->getVideoSource())) ||
146 (!showV9990 && v99x8Layer && (ffe.getSource() == v99x8Layer->getVideoSource()))) {
148 FinishFrameEvent(video9000id, video9000id, false));
149 }
150 return false;
151}
152
153void Video9000::update(const Setting& setting) noexcept
154{
156 if (&setting == &videoSourceSetting) {
157 recalculateVideoSource();
158 }
159}
160
161template<typename Archive>
162void Video9000::serialize(Archive& ar, unsigned /*version*/)
163{
164 ar.template serializeBase<MSXDevice>(*this);
165 ar.serialize("value", value);
166 if constexpr (Archive::IS_LOADER) {
167 recalculate();
168 }
169}
172
173} // namespace openmsx
BaseSetting * setting
#define REGISTER_MSXDEVICE(CLASS, NAME)
Definition MSXDevice.hh:356
void detach(VideoSystemChangeListener &listener)
Definition Display.cc:121
void attach(VideoSystemChangeListener &listener)
Definition Display.cc:115
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=Priority::OTHER)
Registers a given object to receive certain events.
virtual void paint(OutputSurface &output)=0
Paint this layer.
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX.
Definition MSXDevice.hh:36
virtual void init()
Definition MSXDevice.cc:44
Reactor & getReactor() const
Definition MSXDevice.cc:145
const Devices & getReferences() const
Get the device references that are specified for this device.
Definition MSXDevice.cc:119
void setSuperimposeVdpFrame(const FrameSource *vdpSource)
Set the VDP frame on which to superimpose the 'normal' output of this PostProcessor.
FrameSource * getPaintFrame() const
Get the frame that would be displayed.
Display & getDisplay()
Definition Reactor.hh:93
EventDistributor & getEventDistributor()
Definition Reactor.hh:89
Implementation of the Yamaha V9990 VDP as used in the GFX9000 cartridge by Sunrise.
Definition V9990.hh:35
void setExternalVideoSource(bool enable)
Is there an external video source available to superimpose on.
Definition V9990.hh:151
PostProcessor * getPostProcessor() const
Used by Video9000 to be able to couple the VDP and V9990 output.
Definition V9990.cc:110
Unified implementation of MSX Video Display Processors (VDPs).
Definition VDP.hh:67
PostProcessor * getPostProcessor() const
Used by Video9000 to be able to couple the VDP and V9990 output.
Definition VDP.cc:247
Video9000(const DeviceConfig &config)
Definition Video9000.cc:16
void reset(EmuTime::param time) override
This method is called on reset.
Definition Video9000.cc:52
~Video9000() override
Definition Video9000.cc:45
void init() override
Definition Video9000.cc:27
void serialize(Archive &ar, unsigned version)
Definition Video9000.cc:162
void writeIO(word port, byte value, EmuTime::param time) override
Write a byte to a given IO port at a certain time to this device.
Definition Video9000.cc:57
int getVideoSource() const
Returns the ID for this VideoLayer.
Definition VideoLayer.cc:40
void setVideo9000Active(int video9000Source_, Video9000Active active)
Definition VideoLayer.hh:44
void update(const Setting &setting) noexcept override
Definition VideoLayer.cc:49
This file implemented 3 utility functions:
Definition Autofire.cc:11
uint16_t word
16 bit unsigned integer
Definition openmsx.hh:29
EventType getType(const Event &event)
Definition Event.hh:517
std::variant< KeyUpEvent, KeyDownEvent, MouseMotionEvent, MouseButtonUpEvent, MouseButtonDownEvent, MouseWheelEvent, JoystickAxisMotionEvent, JoystickHatEvent, JoystickButtonUpEvent, JoystickButtonDownEvent, OsdControlReleaseEvent, OsdControlPressEvent, WindowEvent, TextEvent, FileDropEvent, QuitEvent, FinishFrameEvent, CliCommandEvent, GroupEvent, BootEvent, FrameDrawnEvent, BreakEvent, SwitchRendererEvent, TakeReverseSnapshotEvent, AfterTimedEvent, MachineLoadedEvent, MachineActivatedEvent, MachineDeactivatedEvent, MidiInReaderEvent, MidiInWindowsEvent, MidiInCoreMidiEvent, MidiInCoreMidiVirtualEvent, MidiInALSAEvent, Rs232TesterEvent, Rs232NetEvent, ImGuiDelayedActionEvent, ImGuiActiveEvent > Event
Definition Event.hh:445
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)