34 void PixelRenderer::draw(
35 int startX,
int startY,
int endX,
int endY, DrawType drawType,
bool atEnd)
37 if (drawType == DRAW_BORDER) {
38 rasterizer->drawBorder(startX, startY, endX, endY);
40 assert(drawType == DRAW_DISPLAY);
45 int displayY = startY - zero;
51 displayY = (displayY & 7) | (textModeCounter * 8);
52 if (atEnd && (drawType == DRAW_DISPLAY)) {
53 int low =
std::max(0, (startY - zero)) / 8;
54 int high =
std::max(0, (endY - zero)) / 8;
55 textModeCounter += (high - low);
60 int displayWidth = (endX - (startX & ~1)) / 2;
61 int displayHeight = endY - startY;
63 assert(0 <= displayX);
64 assert(displayX + displayWidth <= 512);
66 rasterizer->drawDisplay(
69 displayWidth, displayHeight
72 rasterizer->drawSprites(
74 displayX / 2, displayY,
75 (displayWidth + 1) / 2, displayHeight);
80 void PixelRenderer::subdivide(
81 int startX,
int startY,
int endX,
int endY,
int clipL,
int clipR,
86 bool atEnd = (startY != endY) || (endX >= clipR);
88 draw(startX, startY, (atEnd ? clipR : endX),
89 startY + 1, drawType, atEnd);
91 if (startY == endY)
return;
95 bool drawLast =
false;
98 }
else if (endX > clipL) {
103 draw(clipL, startY, clipR, endY, drawType,
true);
109 if (drawLast) draw(clipL, endY, endX, endY + 1, drawType,
false);
113 : vdp(vdp_), vram(vdp.getVRAM())
114 , eventDistributor(vdp.getReactor().getEventDistributor())
115 , realTime(vdp.getMotherBoard().getRealTime())
117 vdp.getReactor().getGlobalSettings().getSpeedManager())
119 vdp.getReactor().getGlobalSettings().getThrottleManager())
120 , renderSettings(display.getRenderSettings())
121 , videoSourceSetting(vdp.getMotherBoard().getVideoSource())
122 , spriteChecker(vdp.getSpriteChecker())
123 , rasterizer(display.getVideoSystem().createRasterizer(vdp))
124 , finishFrameDuration(0)
125 , frameSkipCounter(999)
126 , prevRenderFrame(false)
146 return rasterizer->getPostProcessor();
164 displayEnabled = enabled;
169 if (!rasterizer->isActive()) {
170 frameSkipCounter = 999;
172 prevRenderFrame =
false;
177 prevRenderFrame = renderFrame;
181 paintFrame = prevRenderFrame;
186 int counter = int(frameSkipCounter);
193 unsigned(finishFrameDuration), time);
195 frameSkipCounter += 1.0f / float(speedManager.
getSpeed());
203 frameSkipCounter = std::remainder(frameSkipCounter, 1.0f);
204 }
else if (!rasterizer->isRecording()) {
210 rasterizer->frameStart(time);
229 rasterizer->frameEnd();
231 auto current = time2 - time1;
232 const float ALPHA = 0.2f;
233 finishFrameDuration = finishFrameDuration * (1 - ALPHA) +
243 lastPaintTime = time2;
249 Event::create<FinishFrameEvent>(
250 rasterizer->getPostProcessor()->getVideoSource(),
257 byte scroll, EmuTime::param time)
259 if (displayEnabled) sync(time);
260 rasterizer->setHorizontalScrollLow(scroll);
264 byte , EmuTime::param time)
266 if (displayEnabled) sync(time);
270 bool masked, EmuTime::param time)
272 if (displayEnabled) sync(time);
273 rasterizer->setBorderMask(masked);
277 bool , EmuTime::param time)
279 if (displayEnabled) sync(time);
283 bool enabled, EmuTime::param time)
285 if (displayEnabled) sync(time);
286 rasterizer->setTransparency(enabled);
290 const RawFrame* videoSource, EmuTime::param time)
292 if (displayEnabled) sync(time);
293 rasterizer->setSuperimposeVideoFrame(videoSource);
297 int , EmuTime::param time)
299 if (displayEnabled) sync(time);
303 int color, EmuTime::param time)
306 rasterizer->setBackgroundColor(color);
310 int , EmuTime::param time)
312 if (displayEnabled) sync(time);
316 int , EmuTime::param time)
318 if (displayEnabled) sync(time);
322 bool , EmuTime::param )
332 int index,
int grb, EmuTime::param time)
334 if (displayEnabled) {
341 if (index ==
one_of(bgColor & 3, bgColor >> 2)) {
350 rasterizer->setPalette(index, grb);
354 int , EmuTime::param time)
356 if (displayEnabled) sync(time);
360 int adjust, EmuTime::param time)
362 if (displayEnabled) sync(time);
363 rasterizer->setHorizontalAdjust(adjust);
378 rasterizer->setDisplayMode(mode);
382 int , EmuTime::param time)
384 if (displayEnabled) sync(time);
388 int , EmuTime::param time)
390 if (displayEnabled) sync(time);
394 int , EmuTime::param time)
396 if (displayEnabled) sync(time);
400 bool , EmuTime::param time
402 if (displayEnabled) sync(time);
405 static constexpr
bool overlap(
413 if (displayY0 <= displayY1) {
414 if (vramLine1 > displayY0) {
415 if (vramLine0 <= displayY1)
return true;
418 if (vramLine1 > displayY0)
return true;
419 if (vramLine0 <= displayY1)
return true;
424 inline bool PixelRenderer::checkSync(
int offset, EmuTime::param time)
431 if (!displayEnabled)
return false;
440 int displayY0 = (nextY + deltaY) & 255;
441 int displayY1 = (limitY + deltaY) & 255;
447 int vramQuarter = (offset & 0x1800) >> 11;
449 for (
auto i :
xrange(4)) {
450 if ((i &
mask) == vramQuarter
451 && overlap(displayY0, displayY1, i * 64, (i + 1) * 64)) {
461 int vramQuarter = (offset & 0x1800) >> 11;
463 for (
auto i :
xrange(4)) {
464 if ((i &
mask) == vramQuarter
465 && overlap(displayY0, displayY1, i * 64, (i + 1) * 64)) {
475 int vramLine = ((offset & 0x3FF) / 32) * 8;
476 if (overlap(displayY0, displayY1, vramLine, vramLine + 8)) {
496 return (offset & 0x18000) == visiblePage
497 || (offset & 0x18000) == (visiblePage & 0x10000);
499 return (offset & 0x18000) == visiblePage;
517 if (renderFrame && displayEnabled && checkSync(offset, time)) {
532 void PixelRenderer::sync(EmuTime::param time,
bool force)
534 if (!renderFrame)
return;
554 void PixelRenderer::renderUntil(EmuTime::param time)
559 auto [limitX, limitY] = [&]() -> std::pair<int, int> {
584 if (limitX == nextX && limitY == nextY)
return;
586 if (displayEnabled) {
606 subdivide(nextX, nextY, limitX, limitY,
607 0, displayL, DRAW_BORDER);
609 subdivide(nextX, nextY, limitX, limitY,
610 displayL, borderR, DRAW_DISPLAY);
612 subdivide(nextX, nextY, limitX, limitY,
615 subdivide(nextX, nextY, limitX, limitY,
623 void PixelRenderer::update(
const Setting&
setting) noexcept
625 assert(&
setting ==
one_of(&renderSettings.getMinFrameSkipSetting(),
626 &renderSettings.getMaxFrameSkipSetting()));
629 frameSkipCounter = 999;
Represents a VDP display mode.
constexpr byte getBase() const
Get the base dispay mode as an integer: M5..M1 combined.
constexpr bool isTextMode() const
Is the current mode a text mode? Text1 and Text2 are text modes.
constexpr byte getByte() const
Get the dispay 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.
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 updateForegroundColor(int color, EmuTime::param time) override
Informs the renderer of a VDP foreground color 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 updatePatternBase(int addr, EmuTime::param time) override
Informs the renderer of a pattern table base address change.
void updateVerticalScroll(int scroll, EmuTime::param time) override
Informs the renderer of a vertical scroll change.
void updateColorBase(int addr, EmuTime::param time) override
Informs the renderer of a color table base address 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 updateNameBase(int addr, EmuTime::param time) override
Informs the renderer of a name table base address 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 updatePalette(int index, int grb, EmuTime::param time) override
Informs the renderer of a VDP palette change.
void frameStart(EmuTime::param time) override
Signals the start of a new frame.
void updateBlinkBackgroundColor(int color, EmuTime::param time) override
Informs the renderer of a VDP blink 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.
~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 updateBackgroundColor(int color, EmuTime::param time) override
Informs the renderer of a VDP background color change.
void updateDisplayEnabled(bool enabled, EmuTime::param time) override
Informs the renderer of a VDP display enabled change.
void updateBlinkForegroundColor(int color, EmuTime::param time) override
Informs the renderer of a VDP blink foreground color change.
Abstract base class for post processors.
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)
Check that there is enough real time left before we reach as certain point in emulated time.
bool getDeinterlace() const
Deinterlacing [on, off].
IntegerSetting & getMinFrameSkipSetting()
The current min frameskip.
Accuracy getAccuracy() const
Accuracy [screen, line, pixel].
int getMinFrameSkip() const
int getMaxFrameSkip() const
bool getDisableSprites() const
Disable sprite rendering?
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?
int 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 clockticks between start of line and the time when the background pixel with X...
int getBackgroundColor() const
Gets the current background color.
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 clockticks (21MHz) per frame.
int getRightBorder() const
Gets the number of VDP clockticks 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 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 clockticks 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 clockticks between start of line and the start of the sprite plane.
int getMask() const
Gets the mask for this window.
bool isInside(unsigned address) const
Test whether an address is inside this window.
constexpr vecN< N, T > max(const vecN< N, T > &x, const vecN< N, T > &y)
uint64_t getTime()
Get current (real) time in us.
This file implemented 3 utility functions:
constexpr nibble mask[4][13]
constexpr auto xrange(T e)