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 "FinishFrameEvent.hh"
9 #include "MSXMotherBoard.hh"
10 #include "VideoSourceSetting.hh"
11 #include "CommandException.hh"
12 #include "checked_cast.hh"
13 #include "serialize.hh"
14 
15 namespace openmsx {
16 
18  : MSXDevice(config)
19  , VideoLayer(getMotherBoard(), getName())
20  , videoSourceSetting(getMotherBoard().getVideoSource())
21 {
24  getReactor().getDisplay().attach(*this);
25 
26  activeLayer = nullptr; // we can't set activeLayer yet
27  v99x8Layer = nullptr;
28  v9990Layer = nullptr;
29  value = 0x10;
30 }
31 
33 {
35  auto refs = getReferences(); // make copy
36  bool error = false;
37  if (refs.size() != 2) error = true;
38  if (!error && !dynamic_cast<VDP*>(refs[0])) {
39  std::swap(refs[0], refs[1]); // try reverse order
40  }
41  if (!error) vdp = dynamic_cast<VDP* >(refs[0]);
42  if (!error) v9990 = dynamic_cast<V9990*>(refs[1]);
43  if (error || !vdp || !v9990) {
44  throw MSXException(
45  "Invalid Video9000 configuration: "
46  "need reference to VDP and V9990 device.");
47  }
48 }
49 
51 {
54  getReactor().getDisplay().detach(*this);
55 }
56 
57 void Video9000::reset(EmuTime::param time)
58 {
59  Video9000::writeIO(0x6f, 0x10, time);
60 }
61 
62 void Video9000::writeIO(word /*port*/, byte newValue, EmuTime::param /*time*/)
63 {
64  if (newValue == value) return;
65  value = newValue;
66  recalc();
67 }
68 
69 void Video9000::recalc()
70 {
71  int video9000id = getVideoSource();
72  v99x8Layer = vdp ->getPostProcessor();
73  v9990Layer = v9990->getPostProcessor();
74  assert(!!v99x8Layer == !!v9990Layer); // either both or neither
75 
76  // ...0.... -> only V9990
77  // ...10... -> only V99x8
78  // ...11... -> superimpose
79  bool showV99x8 = ((value & 0x10) == 0x10);
80  bool showV9990 = ((value & 0x18) != 0x10);
81  assert(showV99x8 || showV9990);
82  if (v99x8Layer) v99x8Layer->setVideo9000Active(
83  video9000id,
84  showV99x8 ? (showV9990 ? VideoLayer::ACTIVE_BACK
87  if (v9990Layer) v9990Layer->setVideo9000Active(
88  video9000id,
90  activeLayer = showV9990 ? v9990Layer : v99x8Layer;
91  // activeLayer==nullptr is possible for renderer=none
92  recalcVideoSource();
93 }
94 
95 void Video9000::recalcVideoSource()
96 {
97  // Disable superimpose when gfx9000 layer is selected. That way you
98  // can look at the gfx9000-only output even when the video9000 software
99  // enabled superimpose mode (mostly useful for debugging).
100  bool superimpose = ((value & 0x18) == 0x18);
101  v9990->setExternalVideoSource(
102  superimpose && (videoSourceSetting.getSource() == getVideoSource()));
103 }
104 
105 void Video9000::preVideoSystemChange()
106 {
107  activeLayer = nullptr; // will be recalculated on next paint()
108 }
109 
110 void Video9000::postVideoSystemChange()
111 {
112  // We can't yet re-initialize 'activeLayer' here because the
113  // new v99x8/v9990 layer may not be created yet.
114 }
115 
116 void Video9000::paint(OutputSurface& output)
117 {
118  if (!activeLayer) {
119  recalc();
120  }
121  // activeLayer==nullptr is possible for renderer=none, but in that case
122  // the paint() method will never be called.
123  activeLayer->paint(output);
124 }
125 
126 void Video9000::takeRawScreenShot(unsigned height, const std::string& filename)
127 {
128  auto* layer = dynamic_cast<VideoLayer*>(activeLayer);
129  if (!layer) {
130  throw CommandException("TODO");
131  }
132  layer->takeRawScreenShot(height, filename);
133 }
134 
135 int Video9000::signalEvent(const std::shared_ptr<const Event>& event)
136 {
137  int video9000id = getVideoSource();
138 
139  assert(event->getType() == OPENMSX_FINISH_FRAME_EVENT);
140  auto& ffe = checked_cast<const FinishFrameEvent&>(*event);
141  if (ffe.isSkipped()) return 0;
142  if (videoSourceSetting.getSource() != video9000id) return 0;
143 
144  bool superimpose = ((value & 0x18) == 0x18);
145  if (superimpose && v99x8Layer && v9990Layer &&
146  (ffe.getSource() == v99x8Layer->getVideoSource())) {
147  // inform V9990 about the new V99x8 frame
148  v9990Layer->setSuperimposeVdpFrame(v99x8Layer->getPaintFrame());
149  }
150 
151  bool showV9990 = ((value & 0x18) != 0x10); // v9990 or superimpose
152  if (( showV9990 && v9990Layer && (ffe.getSource() == v9990Layer->getVideoSource())) ||
153  (!showV9990 && v99x8Layer && (ffe.getSource() == v99x8Layer->getVideoSource()))) {
155  std::make_shared<FinishFrameEvent>(
156  video9000id, video9000id, false));
157  }
158  return 0;
159 }
160 
161 void Video9000::update(const Setting& setting)
162 {
163  VideoLayer::update(setting);
164  if (&setting == &videoSourceSetting) {
165  recalcVideoSource();
166  }
167 }
168 
169 template<typename Archive>
170 void Video9000::serialize(Archive& ar, unsigned /*version*/)
171 {
172  ar.template serializeBase<MSXDevice>(*this);
173  ar.serialize("value", value);
174  if (ar.isLoader()) {
175  recalc();
176  }
177 }
180 
181 } // namespace openmsx
openmsx::MSXDevice
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX.
Definition: MSXDevice.hh:32
openmsx::VideoLayer::ACTIVE_FRONT
@ ACTIVE_FRONT
Definition: VideoLayer.hh:41
openmsx::VideoLayer::setVideo9000Active
void setVideo9000Active(int video9000Source_, Video9000Active active)
Definition: VideoLayer.hh:42
openmsx::Video9000::serialize
void serialize(Archive &ar, unsigned version)
Definition: Video9000.cc:170
Display.hh
serialize.hh
openmsx::VDP
Unified implementation of MSX Video Display Processors (VDPs).
Definition: VDP.hh:63
openmsx::Reactor::getDisplay
Display & getDisplay()
Definition: Reactor.hh:85
openmsx::V9990::setExternalVideoSource
void setExternalVideoSource(bool enable)
Is there an external video source available to superimpose on.
Definition: V9990.hh:147
openmsx::DeviceConfig
Definition: DeviceConfig.hh:20
VDP.hh
openmsx::Display::attach
void attach(VideoSystemChangeListener &listener)
Definition: Display.cc:136
openmsx::Video9000::Video9000
Video9000(const DeviceConfig &config)
Definition: Video9000.cc:17
Video9000.hh
VideoSourceSetting.hh
openmsx::Reactor::getEventDistributor
EventDistributor & getEventDistributor()
Definition: Reactor.hh:81
openmsx::Layer::paint
virtual void paint(OutputSurface &output)=0
Paint this layer.
openmsx::MSXException
Definition: MSXException.hh:10
openmsx::EventDistributor
Definition: EventDistributor.hh:17
openmsx::VideoLayer
Definition: VideoLayer.hh:19
openmsx::REGISTER_MSXDEVICE
REGISTER_MSXDEVICE(ChakkariCopy, "ChakkariCopy")
openmsx::V9990::getPostProcessor
PostProcessor * getPostProcessor() const
Used by Video9000 to be able to couple the VDP and V9990 output.
Definition: V9990.cc:112
openmsx::VideoLayer::getVideoSource
int getVideoSource() const
Returns the ID for this videolayer.
Definition: VideoLayer.cc:41
openmsx::Video9000::init
void init() override
Definition: Video9000.cc:32
Reactor.hh
openmsx::Video9000
Definition: Video9000.hh:19
openmsx::Keys::getName
string getName(KeyCode keyCode)
Translate key code to key name.
Definition: Keys.cc:740
V9990.hh
openmsx::PostProcessor::setSuperimposeVdpFrame
void setSuperimposeVdpFrame(const FrameSource *vdpSource)
Set the VDP frame on which to superimpose the 'normal' output of this PostProcessor.
Definition: PostProcessor.hh:62
EventDistributor.hh
openmsx::filename
constexpr const char *const filename
Definition: FirmwareSwitch.cc:10
PostProcessor.hh
openmsx::VideoLayer::VideoLayer
VideoLayer(const VideoLayer &)=delete
openmsx::PostProcessor::getPaintFrame
FrameSource * getPaintFrame() const
Get the frame that would be displayed.
Definition: PostProcessor.hh:87
INSTANTIATE_SERIALIZE_METHODS
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:981
openmsx::VideoSourceSetting::getSource
int getSource() noexcept
Definition: VideoSourceSetting.cc:35
FinishFrameEvent.hh
openmsx::VideoLayer::ACTIVE_BACK
@ ACTIVE_BACK
Definition: VideoLayer.hh:41
openmsx::VideoLayer::INACTIVE
@ INACTIVE
Definition: VideoLayer.hh:41
openmsx::MSXDevice::getReferences
const Devices & getReferences() const
Get the device references that are specified for this device.
Definition: MSXDevice.cc:125
checked_cast.hh
openmsx::VDP::getPostProcessor
PostProcessor * getPostProcessor() const
Used by Video9000 to be able to couple the VDP and V9990 output.
Definition: VDP.cc:244
openmsx::word
uint16_t word
16 bit unsigned integer
Definition: openmsx.hh:29
openmsx::MSXDevice::init
virtual void init()
Definition: MSXDevice.cc:49
openmsx::Video9000::reset
void reset(EmuTime::param time) override
This method is called on reset.
Definition: Video9000.cc:57
openmsx::Video9000::~Video9000
~Video9000() override
Definition: Video9000.cc:50
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::OPENMSX_FINISH_FRAME_EVENT
@ OPENMSX_FINISH_FRAME_EVENT
Sent when VDP (V99x8 or V9990) reaches the end of a frame.
Definition: Event.hh:39
openmsx::EventDistributor::unregisterEventListener
void unregisterEventListener(EventType type, EventListener &listener)
Unregisters a previously registered event listener.
Definition: EventDistributor.cc:35
CommandException.hh
openmsx
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
openmsx::MSXDevice::getReactor
Reactor & getReactor() const
Definition: MSXDevice.cc:151
MSXMotherBoard.hh
openmsx::Video9000::writeIO
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:62
openmsx::VideoLayer::update
void update(const Setting &setting) override
Definition: VideoLayer.cc:50
openmsx::EventDistributor::distributeEvent
void distributeEvent(const EventPtr &event)
Schedule the given event for delivery.
Definition: EventDistributor.cc:44
openmsx::V9990
Implementation of the Yamaha V9990 VDP as used in the GFX9000 cartridge by Sunrise.
Definition: V9990.hh:31
openmsx::Display::detach
void detach(VideoSystemChangeListener &listener)
Definition: Display.cc:142