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 Event::create<FinishFrameEvent>(
248 rasterizer->getPostProcessor()->getVideoSource(),
255 byte scroll, EmuTime::param time)
257 if (displayEnabled) sync(time);
258 rasterizer->setHorizontalScrollLow(scroll);
262 byte , EmuTime::param time)
264 if (displayEnabled) sync(time);
268 bool masked, EmuTime::param time)
270 if (displayEnabled) sync(time);
271 rasterizer->setBorderMask(masked);
275 bool , EmuTime::param time)
277 if (displayEnabled) sync(time);
281 bool enabled, EmuTime::param time)
283 if (displayEnabled) sync(time);
284 rasterizer->setTransparency(enabled);
288 const RawFrame* videoSource, EmuTime::param time)
290 if (displayEnabled) sync(time);
291 rasterizer->setSuperimposeVideoFrame(videoSource);
295 byte , EmuTime::param time)
297 if (displayEnabled) sync(time);
301 byte color, EmuTime::param time)
304 rasterizer->setBackgroundColor(color);
308 byte , EmuTime::param time)
310 if (displayEnabled) sync(time);
314 byte , EmuTime::param time)
316 if (displayEnabled) sync(time);
320 bool , EmuTime::param )
330 unsigned index,
int grb, EmuTime::param time)
332 if (displayEnabled) {
339 if (index ==
one_of(uint8_t(bgColor & 3), uint8_t(bgColor >> 2))) {
348 rasterizer->setPalette(index, grb);
352 int , EmuTime::param time)
354 if (displayEnabled) sync(time);
358 int adjust, EmuTime::param time)
360 if (displayEnabled) sync(time);
361 rasterizer->setHorizontalAdjust(adjust);
376 rasterizer->setDisplayMode(mode);
380 unsigned , EmuTime::param time)
382 if (displayEnabled) sync(time);
386 unsigned , EmuTime::param time)
388 if (displayEnabled) sync(time);
392 unsigned , EmuTime::param time)
394 if (displayEnabled) sync(time);
398 bool , EmuTime::param time
400 if (displayEnabled) sync(time);
403static constexpr bool overlap(
411 if (displayY0 <= displayY1) {
412 if (vramLine1 > displayY0) {
413 if (vramLine0 <= displayY1)
return true;
416 if (vramLine1 > displayY0)
return true;
417 if (vramLine0 <= displayY1)
return true;
422inline bool PixelRenderer::checkSync(
unsigned offset, EmuTime::param time)
429 if (!displayEnabled)
return false;
438 int displayY0 = (nextY + deltaY) & 255;
439 int displayY1 = (limitY + deltaY) & 255;
445 unsigned vramQuarter = (offset & 0x1800) >> 11;
447 for (
auto i :
xrange(4)) {
448 if ((i & mask) == vramQuarter
449 && overlap(displayY0, displayY1, i * 64, (i + 1) * 64)) {
459 unsigned vramQuarter = (offset & 0x1800) >> 11;
461 for (
auto i :
xrange(4)) {
462 if ((i & mask) == vramQuarter
463 && overlap(displayY0, displayY1, i * 64, (i + 1) * 64)) {
473 int vramLine = narrow<int>(((offset & 0x3FF) / 32) * 8);
474 if (overlap(displayY0, displayY1, vramLine, vramLine + 8)) {
494 return (offset & 0x18000) == visiblePage
495 || (offset & 0x18000) == (visiblePage & 0x10000);
497 return (offset & 0x18000) == visiblePage;
515 if (renderFrame && displayEnabled && checkSync(offset, time)) {
530void PixelRenderer::sync(EmuTime::param time,
bool force)
532 if (!renderFrame)
return;
552void PixelRenderer::renderUntil(EmuTime::param time)
557 auto [limitX, limitY] = [&]() -> std::pair<int, int> {
582 if (limitX == nextX && limitY == nextY)
return;
584 if (displayEnabled) {
604 subdivide(nextX, nextY, limitX, limitY,
605 0, displayL, DRAW_BORDER);
607 subdivide(nextX, nextY, limitX, limitY,
608 displayL, borderR, DRAW_DISPLAY);
610 subdivide(nextX, nextY, limitX, limitY,
613 subdivide(nextX, nextY, limitX, limitY,
621void PixelRenderer::update(
const Setting&
setting)
noexcept
623 assert(&
setting ==
one_of(&renderSettings.getMinFrameSkipSetting(),
624 &renderSettings.getMaxFrameSkipSetting()));
627 frameSkipCounter = 999;
Represents a VDP display mode.
constexpr byte getBase() const
Get the base display 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 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.
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.
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?
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.
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 auto xrange(T e)