35void PixelRenderer::draw(
36 int startX,
int startY,
int endX,
int endY, DrawType drawType,
bool atEnd)
38 if (drawType == DRAW_BORDER) {
39 rasterizer->drawBorder(startX, startY, endX, endY);
41 assert(drawType == DRAW_DISPLAY);
46 int displayY = startY - zero;
52 displayY = (displayY & 7) | (textModeCounter * 8);
53 if (atEnd && (drawType == DRAW_DISPLAY)) {
54 int low = std::max(0, (startY - zero)) / 8;
55 int high = std::max(0, (endY - zero)) / 8;
56 textModeCounter += (high - low);
61 int displayWidth = (endX - (startX & ~1)) / 2;
62 int displayHeight = endY - startY;
64 assert(0 <= displayX);
65 assert(displayX + displayWidth <= 512);
67 rasterizer->drawDisplay(
70 displayWidth, displayHeight
73 rasterizer->drawSprites(
75 displayX / 2, displayY,
76 (displayWidth + 1) / 2, displayHeight);
81void PixelRenderer::subdivide(
82 int startX,
int startY,
int endX,
int endY,
int clipL,
int clipR,
87 bool atEnd = (startY != endY) || (endX >= clipR);
89 draw(startX, startY, (atEnd ? clipR : endX),
90 startY + 1, drawType, atEnd);
92 if (startY == endY)
return;
96 bool drawLast =
false;
99 }
else if (endX > clipL) {
104 draw(clipL, startY, clipR, endY, drawType,
true);
110 if (drawLast) draw(clipL, endY, endX, endY + 1, drawType,
false);
114 : vdp(vdp_), vram(vdp.getVRAM())
115 , eventDistributor(vdp.getReactor().getEventDistributor())
116 , realTime(vdp.getMotherBoard().getRealTime())
118 vdp.getReactor().getGlobalSettings().getSpeedManager())
120 vdp.getReactor().getGlobalSettings().getThrottleManager())
121 , renderSettings(display.getRenderSettings())
122 , videoSourceSetting(vdp.getMotherBoard().getVideoSource())
123 , spriteChecker(vdp.getSpriteChecker())
124 , rasterizer(display.getVideoSystem().createRasterizer(vdp))
144 return rasterizer->getPostProcessor();
162 displayEnabled = enabled;
167 if (!rasterizer->isActive()) {
168 frameSkipCounter = 999.0f;
170 prevRenderFrame =
false;
175 prevRenderFrame = renderFrame;
179 paintFrame = prevRenderFrame;
184 auto counter = narrow_cast<int>(frameSkipCounter);
191 unsigned(finishFrameDuration), time);
193 frameSkipCounter += 1.0f / float(speedManager.
getSpeed());
201 frameSkipCounter = std::remainder(frameSkipCounter, 1.0f);
202 }
else if (!rasterizer->isRecording()) {
208 rasterizer->frameStart(time);
227 rasterizer->frameEnd();
229 auto current = narrow_cast<float>(time2 - time1);
230 const float ALPHA = 0.2f;
231 finishFrameDuration = finishFrameDuration * (1 - ALPHA) +
241 lastPaintTime = time2;
247 rasterizer->getPostProcessor()->getVideoSource(),
254 byte scroll, EmuTime::param time)
256 if (displayEnabled) sync(time);
257 rasterizer->setHorizontalScrollLow(scroll);
261 byte , EmuTime::param time)
263 if (displayEnabled) sync(time);
267 bool masked, EmuTime::param time)
269 if (displayEnabled) sync(time);
270 rasterizer->setBorderMask(masked);
274 bool , EmuTime::param time)
276 if (displayEnabled) sync(time);
280 bool enabled, EmuTime::param time)
282 if (displayEnabled) sync(time);
283 rasterizer->setTransparency(enabled);
287 const RawFrame* videoSource, EmuTime::param time)
289 if (displayEnabled) sync(time);
290 rasterizer->setSuperimposeVideoFrame(videoSource);
294 byte , EmuTime::param time)
296 if (displayEnabled) sync(time);
300 byte color, EmuTime::param time)
303 rasterizer->setBackgroundColor(color);
307 byte , EmuTime::param time)
309 if (displayEnabled) sync(time);
313 byte , EmuTime::param time)
315 if (displayEnabled) sync(time);
319 bool , EmuTime::param )
329 unsigned index,
int grb, EmuTime::param time)
331 if (displayEnabled) {
338 if (index ==
one_of(uint8_t(bgColor & 3), uint8_t(bgColor >> 2))) {
347 rasterizer->setPalette(index, grb);
351 int , EmuTime::param time)
353 if (displayEnabled) sync(time);
357 int adjust, EmuTime::param time)
359 if (displayEnabled) sync(time);
360 rasterizer->setHorizontalAdjust(adjust);
375 rasterizer->setDisplayMode(mode);
379 unsigned , EmuTime::param time)
381 if (displayEnabled) sync(time);
385 unsigned , EmuTime::param time)
387 if (displayEnabled) sync(time);
391 unsigned , EmuTime::param time)
393 if (displayEnabled) sync(time);
397 bool , EmuTime::param time
399 if (displayEnabled) sync(time);
402static constexpr bool overlap(
410 if (displayY0 <= displayY1) {
411 if ((vramLine1 > displayY0) && (vramLine0 <= displayY1)) {
415 if (vramLine1 > displayY0)
return true;
416 if (vramLine0 <= displayY1)
return true;
421bool PixelRenderer::checkSync(
unsigned offset, EmuTime::param time)
const
428 if (!displayEnabled)
return false;
437 int displayY0 = (nextY + deltaY) & 255;
438 int displayY1 = (limitY + deltaY) & 255;
444 unsigned vramQuarter = (offset & 0x1800) >> 11;
446 for (
auto i :
xrange(4)) {
447 if ((i & mask) == vramQuarter
448 && overlap(displayY0, displayY1, i * 64, (i + 1) * 64)) {
458 unsigned vramQuarter = (offset & 0x1800) >> 11;
460 for (
auto i :
xrange(4)) {
461 if ((i & mask) == vramQuarter
462 && overlap(displayY0, displayY1, i * 64, (i + 1) * 64)) {
472 int vramLine = narrow<int>(((offset & 0x3FF) / 32) * 8);
473 if (overlap(displayY0, displayY1, vramLine, vramLine + 8)) {
493 return (offset & 0x18000) == visiblePage
494 || (offset & 0x18000) == (visiblePage & 0x10000);
496 return (offset & 0x18000) == visiblePage;
514 if (renderFrame && displayEnabled && checkSync(offset, time)) {
527void PixelRenderer::sync(EmuTime::param time,
bool force)
529 if (!renderFrame)
return;
549void PixelRenderer::renderUntil(EmuTime::param time)
554 auto [limitX, limitY] = [&]() -> std::pair<int, int> {
578 if (limitX == nextX && limitY == nextY)
return;
580 if (displayEnabled) {
600 subdivide(nextX, nextY, limitX, limitY,
601 0, displayL, DRAW_BORDER);
603 subdivide(nextX, nextY, limitX, limitY,
604 displayL, borderR, DRAW_DISPLAY);
606 subdivide(nextX, nextY, limitX, limitY,
609 subdivide(nextX, nextY, limitX, limitY,
617void PixelRenderer::update(
const Setting&
setting)
noexcept
619 assert(&
setting ==
one_of(&renderSettings.getMinFrameSkipSetting(),
620 &renderSettings.getMaxFrameSkipSetting()));
623 frameSkipCounter = 999;
Represents a VDP display mode.
constexpr byte getBase() const
Get the base display mode as an integer: M5..M1 combined.
static constexpr uint8_t GRAPHIC3
static constexpr uint8_t GRAPHIC4
static constexpr uint8_t GRAPHIC5
static constexpr uint8_t GRAPHIC7
static constexpr uint8_t GRAPHIC6
constexpr bool isTextMode() const
Is the current mode a text mode? Text1 and Text2 are text modes.
static constexpr uint8_t GRAPHIC2
constexpr byte getByte() const
Get the display mode as a byte: YAE YJK M5..M1 combined.
Represents the output window/screen of openMSX.
void distributeEvent(Event &&event)
Schedule the given event for delivery.
This event is send when a device (v99x8, v9990, video9000, laserdisc) reaches the end of a frame.
MSXMotherBoard & getMotherBoard() const
Get the mother board this device belongs to.
bool isFastForwarding() const
void updateSuperimposing(const RawFrame *videoSource, EmuTime::param time) override
Informs the renderer of a VDP superimposing change.
void updateWindow(bool enabled, EmuTime::param time) override
Informs the observer that the entire VRAM window will change.
PostProcessor * getPostProcessor() const override
See VDP::getPostProcessor.
void updateColorBase(unsigned addr, EmuTime::param time) override
Informs the renderer of a color table base address change.
void updateBorderMask(bool masked, EmuTime::param time) override
Informs the renderer of a horizontal scroll change: the border mask has been enabled/disabled.
void updateVerticalScroll(int scroll, EmuTime::param time) override
Informs the renderer of a vertical scroll change.
void updateBlinkState(bool enabled, EmuTime::param time) override
Informs the renderer of a VDP blinking state change.
void updateTransparency(bool enabled, EmuTime::param time) override
Informs the renderer of a VDP transparency enable/disable change.
void updateDisplayMode(DisplayMode mode, EmuTime::param time) override
Informs the renderer of a VDP display mode change.
void updateHorizontalAdjust(int adjust, EmuTime::param time) override
Informs the renderer of a horizontal adjust change.
PixelRenderer(VDP &vdp, Display &display)
void updateVRAM(unsigned offset, EmuTime::param time) override
Informs the observer of a change in VRAM contents.
void frameEnd(EmuTime::param time) override
Signals the end of a frame.
void updateSpritesEnabled(bool enabled, EmuTime::param time) override
Informs the renderer of a VDP sprites enabled change.
void updateHorizontalScrollHigh(byte scroll, EmuTime::param time) override
Informs the renderer of a horizontal scroll change: the higher scroll value has changed.
void frameStart(EmuTime::param time) override
Signals the start of a new frame.
void updateBackgroundColor(byte color, EmuTime::param time) override
Informs the renderer of a VDP background color change.
void updateHorizontalScrollLow(byte scroll, EmuTime::param time) override
Informs the renderer of a horizontal scroll change: the lower scroll value has changed.
void updatePatternBase(unsigned addr, EmuTime::param time) override
Informs the renderer of a pattern table base address change.
~PixelRenderer() override
void updateMultiPage(bool multiPage, EmuTime::param time) override
Informs the renderer of a horizontal scroll change: the multi page setting has changed.
void reInit() override
Reinitialize Renderer state.
void updateNameBase(unsigned addr, EmuTime::param time) override
Informs the renderer of a name table base address change.
void updatePalette(unsigned index, int grb, EmuTime::param time) override
Informs the renderer of a VDP palette change.
void updateBlinkBackgroundColor(byte color, EmuTime::param time) override
Informs the renderer of a VDP blink background color change.
void updateForegroundColor(byte color, EmuTime::param time) override
Informs the renderer of a VDP foreground color change.
void updateDisplayEnabled(bool enabled, EmuTime::param time) override
Informs the renderer of a VDP display enabled change.
void updateBlinkForegroundColor(byte color, EmuTime::param time) override
Informs the renderer of a VDP blink foreground color change.
A post processor builds the frame that is displayed from the MSX frame, while applying effects such a...
A video frame as output by the VDP scanline conversion unit, before any postprocessing filters are ap...
bool timeLeft(uint64_t us, EmuTime::param time) const
Check that there is enough real time left before we reach as certain point in emulated time.
bool getDeinterlace() const
IntegerSetting & getMinFrameSkipSetting()
The current min frameskip.
Accuracy getAccuracy() const
int getMinFrameSkip() const
int getMaxFrameSkip() const
bool getDisableSprites() const
IntegerSetting & getMaxFrameSkipSetting()
The current max frameskip.
double getSpeed() const
Return the desired ratio between EmuTime and real time.
void checkUntil(EmuTime::param time)
Update sprite checking until specified line.
void detach(Observer< T > &observer)
void attach(Observer< T > &observer)
bool isThrottled() const
Ask if throttling is enabled.
void sync(EmuTime::param time)
Update VRAM state to specified moment in time.
Unified implementation of MSX Video Display Processors (VDPs).
bool getEvenOdd() const
Is the even or odd field being displayed?
unsigned getEvenOddMask() const
Expresses the state of even/odd page interchange in a mask on the line number.
bool spritesEnabled() const
Are sprites enabled?
int getLeftBackground() const
Gets the number of VDP clock ticks between start of line and the time when the background pixel with ...
bool isEvenOddEnabled() const
Get even/odd page alternation status.
bool isFastBlinkEnabled() const
Get 'fast-blink' status.
bool isBorderMasked() const
Gets the current border mask setting.
static constexpr int TICKS_PER_LINE
Number of VDP clock ticks per line.
int getTicksPerFrame() const
Gets the number of VDP clock ticks (21MHz) per frame.
int getRightBorder() const
Gets the number of VDP clock ticks between start of line and the start of the right border.
DisplayMode getDisplayMode() const
Get the display mode the VDP is in.
int getLineZero() const
Get the absolute line number of display line zero.
byte getBackgroundColor() const
Gets the current background color.
byte getVerticalScroll() const
Gets the current vertical scroll (line displayed at Y=0).
bool isMultiPageScrolling() const
Is multi page scrolling enabled? It is considered enabled if both the multi page scrolling flag is en...
int getLeftBorder() const
Gets the number of VDP clock ticks between start of line and the end of the left border.
bool isInterlaced() const
Get interlace status.
bool isDisplayEnabled() const
Is the display enabled? Both the regular border and forced blanking by clearing the display enable bi...
int getTicksThisFrame(EmuTime::param time) const
Gets the number of VDP clock ticks (21MHz) elapsed between a given time and the start of this frame.
byte getHorizontalScrollLow() const
Gets the current horizontal scroll lower bits.
int getLeftSprites() const
Gets the number of VDP clock ticks between start of line and the start of the sprite plane.
bool isInside(unsigned address) const
Test whether an address is inside this window.
unsigned getMask() const
Gets the mask for this window.
uint64_t getTime()
Get current (real) time in us.
This file implemented 3 utility functions:
constexpr auto xrange(T e)