openMSX
PixelRenderer.cc
Go to the documentation of this file.
1/*
2TODO:
3- Implement blinking (of page mask) in bitmap modes.
4*/
5
6#include "PixelRenderer.hh"
7#include "Rasterizer.hh"
8#include "PostProcessor.hh"
9#include "Display.hh"
10#include "VideoSystem.hh"
11#include "RenderSettings.hh"
12#include "VideoSourceSetting.hh"
13#include "IntegerSetting.hh"
14#include "VDP.hh"
15#include "VDPVRAM.hh"
16#include "SpriteChecker.hh"
17#include "EventDistributor.hh"
18#include "Event.hh"
19#include "RealTime.hh"
20#include "SpeedManager.hh"
21#include "ThrottleManager.hh"
22#include "GlobalSettings.hh"
23#include "MSXMotherBoard.hh"
24#include "Reactor.hh"
25#include "Timer.hh"
26#include "one_of.hh"
27#include "unreachable.hh"
28#include <algorithm>
29#include <cassert>
30#include <cmath>
31
32namespace openmsx {
33
34void PixelRenderer::draw(
35 int startX, int startY, int endX, int endY, DrawType drawType, bool atEnd)
36{
37 if (drawType == DRAW_BORDER) {
38 rasterizer->drawBorder(startX, startY, endX, endY);
39 } else {
40 assert(drawType == DRAW_DISPLAY);
41
42 // Calculate display coordinates.
43 int zero = vdp.getLineZero();
44 int displayX = (startX - vdp.getLeftSprites()) / 2;
45 int displayY = startY - zero;
46 if (!vdp.getDisplayMode().isTextMode()) {
47 displayY += vdp.getVerticalScroll();
48 } else {
49 // this is not what the real VDP does, but it is good
50 // enough for "Boring scroll" demo part of "Relax"
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);
56 }
57 }
58
59 displayY &= 255; // Page wrap.
60 int displayWidth = (endX - (startX & ~1)) / 2;
61 int displayHeight = endY - startY;
62
63 assert(0 <= displayX);
64 assert(displayX + displayWidth <= 512);
65
66 rasterizer->drawDisplay(
67 startX, startY,
68 displayX - vdp.getHorizontalScrollLow() * 2, displayY,
69 displayWidth, displayHeight
70 );
71 if (vdp.spritesEnabled() && !renderSettings.getDisableSprites()) {
72 rasterizer->drawSprites(
73 startX, startY,
74 displayX / 2, displayY,
75 (displayWidth + 1) / 2, displayHeight);
76 }
77 }
78}
79
80void PixelRenderer::subdivide(
81 int startX, int startY, int endX, int endY, int clipL, int clipR,
82 DrawType drawType)
83{
84 // Partial first line.
85 if (startX > clipL) {
86 bool atEnd = (startY != endY) || (endX >= clipR);
87 if (startX < clipR) {
88 draw(startX, startY, (atEnd ? clipR : endX),
89 startY + 1, drawType, atEnd);
90 }
91 if (startY == endY) return;
92 startY++;
93 }
94 // Partial last line.
95 bool drawLast = false;
96 if (endX >= clipR) {
97 endY++;
98 } else if (endX > clipL) {
99 drawLast = true;
100 }
101 // Full middle lines.
102 if (startY < endY) {
103 draw(clipL, startY, clipR, endY, drawType, true);
104 }
105 // Actually draw last line if necessary.
106 // The point of keeping top-to-bottom draw order is that it increases
107 // the locality of memory references, which generally improves cache
108 // hit rates.
109 if (drawLast) draw(clipL, endY, endX, endY + 1, drawType, false);
110}
111
113 : vdp(vdp_), vram(vdp.getVRAM())
114 , eventDistributor(vdp.getReactor().getEventDistributor())
115 , realTime(vdp.getMotherBoard().getRealTime())
116 , speedManager(
117 vdp.getReactor().getGlobalSettings().getSpeedManager())
118 , throttleManager(
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) // force drawing of frame
126 , prevRenderFrame(false)
127{
128 // In case of loadstate we can't yet query any state from the VDP
129 // (because that object is not yet fully deserialized). But
130 // VDP::serialize() will call Renderer::reInit() again when it is
131 // safe to query.
132 reInit();
133
134 renderSettings.getMaxFrameSkipSetting().attach(*this);
135 renderSettings.getMinFrameSkipSetting().attach(*this);
136}
137
139{
140 renderSettings.getMinFrameSkipSetting().detach(*this);
141 renderSettings.getMaxFrameSkipSetting().detach(*this);
142}
143
145{
146 return rasterizer->getPostProcessor();
147}
148
150{
151 // Don't draw before frameStart() is called.
152 // This for example can happen after a loadstate or after switching
153 // renderer in the middle of a frame.
154 renderFrame = false;
155 paintFrame = false;
156
157 rasterizer->reset();
158 displayEnabled = vdp.isDisplayEnabled();
159}
160
161void PixelRenderer::updateDisplayEnabled(bool enabled, EmuTime::param time)
162{
163 sync(time, true);
164 displayEnabled = enabled;
165}
166
167void PixelRenderer::frameStart(EmuTime::param time)
168{
169 if (!rasterizer->isActive()) {
170 frameSkipCounter = 999;
171 renderFrame = false;
172 prevRenderFrame = false;
173 paintFrame = false;
174 return;
175 }
176
177 prevRenderFrame = renderFrame;
178 if (vdp.isInterlaced() && renderSettings.getDeinterlace()
179 && vdp.getEvenOdd() && vdp.isEvenOddEnabled()) {
180 // Deinterlaced odd frame: do same as even frame.
181 paintFrame = prevRenderFrame;
182 } else if (throttleManager.isThrottled()) {
183 // Note: min/maxFrameSkip control the number of skipped frames, but
184 // for every series of skipped frames there is also one painted
185 // frame, so our boundary checks are offset by one.
186 int counter = int(frameSkipCounter);
187 if (counter < renderSettings.getMinFrameSkip()) {
188 paintFrame = false;
189 } else if (counter > renderSettings.getMaxFrameSkip()) {
190 paintFrame = true;
191 } else {
192 paintFrame = realTime.timeLeft(
193 unsigned(finishFrameDuration), time);
194 }
195 frameSkipCounter += 1.0f / float(speedManager.getSpeed());
196 } else {
197 // We need to render a frame every now and then,
198 // to show the user what is happening.
199 paintFrame = (Timer::getTime() - lastPaintTime) >= 100000; // 10 fps
200 }
201
202 if (paintFrame) {
203 frameSkipCounter = std::remainder(frameSkipCounter, 1.0f);
204 } else if (!rasterizer->isRecording()) {
205 renderFrame = false;
206 return;
207 }
208 renderFrame = true;
209
210 rasterizer->frameStart(time);
211
212 accuracy = renderSettings.getAccuracy();
213
214 nextX = 0;
215 nextY = 0;
216 // This is not what the real VDP does, but it is good enough
217 // for the "Boring scroll" demo part of ANMA's "Relax" demo.
218 textModeCounter = 0;
219}
220
221void PixelRenderer::frameEnd(EmuTime::param time)
222{
223 if (renderFrame) {
224 // Render changes from this last frame.
225 sync(time, true);
226
227 // Let underlying graphics system finish rendering this frame.
228 auto time1 = Timer::getTime();
229 rasterizer->frameEnd();
230 auto time2 = Timer::getTime();
231 auto current = time2 - time1;
232 const float ALPHA = 0.2f;
233 finishFrameDuration = finishFrameDuration * (1 - ALPHA) +
234 current * ALPHA;
235
236 if (vdp.isInterlaced() && vdp.isEvenOddEnabled()
237 && renderSettings.getDeinterlace() && !prevRenderFrame) {
238 // Don't paint in deinterlace mode when previous frame
239 // was not rendered.
240 paintFrame = false;
241 }
242 if (paintFrame) {
243 lastPaintTime = time2;
244 }
245 }
246 if (vdp.getMotherBoard().isActive() &&
248 eventDistributor.distributeEvent(
249 Event::create<FinishFrameEvent>(
250 rasterizer->getPostProcessor()->getVideoSource(),
251 videoSourceSetting.getSource(),
252 !paintFrame));
253 }
254}
255
257 byte scroll, EmuTime::param time)
258{
259 if (displayEnabled) sync(time);
260 rasterizer->setHorizontalScrollLow(scroll);
261}
262
264 byte /*scroll*/, EmuTime::param time)
265{
266 if (displayEnabled) sync(time);
267}
268
270 bool masked, EmuTime::param time)
271{
272 if (displayEnabled) sync(time);
273 rasterizer->setBorderMask(masked);
274}
275
277 bool /*multiPage*/, EmuTime::param time)
278{
279 if (displayEnabled) sync(time);
280}
281
283 bool enabled, EmuTime::param time)
284{
285 if (displayEnabled) sync(time);
286 rasterizer->setTransparency(enabled);
287}
288
290 const RawFrame* videoSource, EmuTime::param time)
291{
292 if (displayEnabled) sync(time);
293 rasterizer->setSuperimposeVideoFrame(videoSource);
294}
295
297 int /*color*/, EmuTime::param time)
298{
299 if (displayEnabled) sync(time);
300}
301
303 int color, EmuTime::param time)
304{
305 sync(time);
306 rasterizer->setBackgroundColor(color);
307}
308
310 int /*color*/, EmuTime::param time)
311{
312 if (displayEnabled) sync(time);
313}
314
316 int /*color*/, EmuTime::param time)
317{
318 if (displayEnabled) sync(time);
319}
320
322 bool /*enabled*/, EmuTime::param /*time*/)
323{
324 // TODO: When the sync call is enabled, the screen flashes on
325 // every call to this method.
326 // I don't know why exactly, but it's probably related to
327 // being called at frame start.
328 //sync(time);
329}
330
332 int index, int grb, EmuTime::param time)
333{
334 if (displayEnabled) {
335 sync(time);
336 } else {
337 // Only sync if border color changed.
338 DisplayMode mode = vdp.getDisplayMode();
339 if (mode.getBase() == DisplayMode::GRAPHIC5) {
340 int bgColor = vdp.getBackgroundColor();
341 if (index == one_of(bgColor & 3, bgColor >> 2)) {
342 sync(time);
343 }
344 } else if (mode.getByte() != DisplayMode::GRAPHIC7) {
345 if (index == vdp.getBackgroundColor()) {
346 sync(time);
347 }
348 }
349 }
350 rasterizer->setPalette(index, grb);
351}
352
354 int /*scroll*/, EmuTime::param time)
355{
356 if (displayEnabled) sync(time);
357}
358
360 int adjust, EmuTime::param time)
361{
362 if (displayEnabled) sync(time);
363 rasterizer->setHorizontalAdjust(adjust);
364}
365
367 DisplayMode mode, EmuTime::param time)
368{
369 // Sync if in display area or if border drawing process changes.
370 DisplayMode oldMode = vdp.getDisplayMode();
371 if (displayEnabled
372 || oldMode.getByte() == DisplayMode::GRAPHIC5
373 || oldMode.getByte() == DisplayMode::GRAPHIC7
374 || mode.getByte() == DisplayMode::GRAPHIC5
375 || mode.getByte() == DisplayMode::GRAPHIC7) {
376 sync(time, true);
377 }
378 rasterizer->setDisplayMode(mode);
379}
380
382 int /*addr*/, EmuTime::param time)
383{
384 if (displayEnabled) sync(time);
385}
386
388 int /*addr*/, EmuTime::param time)
389{
390 if (displayEnabled) sync(time);
391}
392
394 int /*addr*/, EmuTime::param time)
395{
396 if (displayEnabled) sync(time);
397}
398
400 bool /*enabled*/, EmuTime::param time
401) {
402 if (displayEnabled) sync(time);
403}
404
405static constexpr bool overlap(
406 int displayY0, // start of display region, inclusive
407 int displayY1, // end of display region, exclusive
408 int vramLine0, // start of VRAM region, inclusive
409 int vramLine1 // end of VRAM region, exclusive
410 // Note: Display region can wrap around: 256 -> 0.
411 // VRAM region cannot wrap around.
412) {
413 if (displayY0 <= displayY1) {
414 if (vramLine1 > displayY0) {
415 if (vramLine0 <= displayY1) return true;
416 }
417 } else {
418 if (vramLine1 > displayY0) return true;
419 if (vramLine0 <= displayY1) return true;
420 }
421 return false;
422}
423
424inline bool PixelRenderer::checkSync(int offset, EmuTime::param time)
425{
426 // TODO: Because range is entire VRAM, offset == address.
427
428 // If display is disabled, VRAM changes will not affect the
429 // renderer output, therefore sync is not necessary.
430 // TODO: Have bitmapVisibleWindow disabled in this case.
431 if (!displayEnabled) return false;
432 //if (frameSkipCounter != 0) return false; // TODO
433 if (accuracy == RenderSettings::ACC_SCREEN) return false;
434
435 // Calculate what display lines are scanned between current
436 // renderer time and update-to time.
437 // Note: displayY1 is inclusive.
438 int deltaY = vdp.getVerticalScroll() - vdp.getLineZero();
439 int limitY = vdp.getTicksThisFrame(time) / VDP::TICKS_PER_LINE;
440 int displayY0 = (nextY + deltaY) & 255;
441 int displayY1 = (limitY + deltaY) & 255;
442
443 switch(vdp.getDisplayMode().getBase()) {
446 if (vram.colorTable.isInside(offset)) {
447 int vramQuarter = (offset & 0x1800) >> 11;
448 int mask = (vram.colorTable.getMask() & 0x1800) >> 11;
449 for (auto i : xrange(4)) {
450 if ((i & mask) == vramQuarter
451 && overlap(displayY0, displayY1, i * 64, (i + 1) * 64)) {
452 /*fprintf(stderr,
453 "color table: %05X %04X - quarter %d\n",
454 offset, offset & 0x1FFF, i
455 );*/
456 return true;
457 }
458 }
459 }
460 if (vram.patternTable.isInside(offset)) {
461 int vramQuarter = (offset & 0x1800) >> 11;
462 int mask = (vram.patternTable.getMask() & 0x1800) >> 11;
463 for (auto i : xrange(4)) {
464 if ((i & mask) == vramQuarter
465 && overlap(displayY0, displayY1, i * 64, (i + 1) * 64)) {
466 /*fprintf(stderr,
467 "pattern table: %05X %04X - quarter %d\n",
468 offset, offset & 0x1FFF, i
469 );*/
470 return true;
471 }
472 }
473 }
474 if (vram.nameTable.isInside(offset)) {
475 int vramLine = ((offset & 0x3FF) / 32) * 8;
476 if (overlap(displayY0, displayY1, vramLine, vramLine + 8)) {
477 /*fprintf(stderr,
478 "name table: %05X %03X - line %d\n",
479 offset, offset & 0x3FF, vramLine
480 );*/
481 return true;
482 }
483 }
484 return false;
487 if (vdp.isFastBlinkEnabled()) {
488 // TODO could be improved
489 return true;
490 }
491 // Is the address inside the visual page(s)?
492 // TODO: Also look at which lines are touched inside pages.
493 int visiblePage = vram.nameTable.getMask()
494 & (0x10000 | (vdp.getEvenOddMask() << 7));
495 if (vdp.isMultiPageScrolling()) {
496 return (offset & 0x18000) == visiblePage
497 || (offset & 0x18000) == (visiblePage & 0x10000);
498 } else {
499 return (offset & 0x18000) == visiblePage;
500 }
501 }
504 return true; // TODO: Implement better detection.
505 default:
506 // Range unknown; assume full range.
507 return vram.nameTable.isInside(offset)
508 || vram.colorTable.isInside(offset)
509 || vram.patternTable.isInside(offset);
510 }
511}
512
513void PixelRenderer::updateVRAM(unsigned offset, EmuTime::param time)
514{
515 // Note: No need to sync if display is disabled, because then the
516 // output does not depend on VRAM (only on background color).
517 if (renderFrame && displayEnabled && checkSync(offset, time)) {
518 //fprintf(stderr, "vram sync @ line %d\n",
519 // vdp.getTicksThisFrame(time) / VDP::TICKS_PER_LINE);
520 renderUntil(time);
521 }
522}
523
524void PixelRenderer::updateWindow(bool /*enabled*/, EmuTime::param /*time*/)
525{
526 // The bitmapVisibleWindow has moved to a different area.
527 // This update is redundant: Renderer will be notified in another way
528 // as well (updateDisplayEnabled or updateNameBase, for example).
529 // TODO: Can this be used as the main update method instead?
530}
531
532void PixelRenderer::sync(EmuTime::param time, bool force)
533{
534 if (!renderFrame) return;
535
536 // Synchronisation is done in two phases:
537 // 1. update VRAM
538 // 2. update other subsystems
539 // Note that as part of step 1, type 2 updates can be triggered.
540 // Executing step 2 takes care of the subsystem changes that occur
541 // after the last VRAM update.
542 // This scheme makes sure type 2 routines such as renderUntil and
543 // checkUntil are not re-entered, which was causing major pain in
544 // the past.
545 // TODO: I wonder if it's possible to enforce this synchronisation
546 // scheme at a higher level. Probably. But how...
547 //if ((frameSkipCounter == 0) && TODO
548 if (accuracy != RenderSettings::ACC_SCREEN || force) {
549 vram.sync(time);
550 renderUntil(time);
551 }
552}
553
554void PixelRenderer::renderUntil(EmuTime::param time)
555{
556 // Translate from time to pixel position.
557 int limitTicks = vdp.getTicksThisFrame(time);
558 assert(limitTicks <= vdp.getTicksPerFrame());
559 auto [limitX, limitY] = [&]() -> std::pair<int, int> {
560 switch (accuracy) {
562 return {limitTicks % VDP::TICKS_PER_LINE,
563 limitTicks / VDP::TICKS_PER_LINE};
564 }
567 // Note: I'm not sure the rounding point is optimal.
568 // It used to be based on the left margin, but that doesn't work
569 // because the margin can change which leads to a line being
570 // rendered even though the time doesn't advance.
571 return {0,
572 (limitTicks + VDP::TICKS_PER_LINE - 400) / VDP::TICKS_PER_LINE};
573 default:
575 return {0, 0}; // avoid warning
576 }
577 }();
578
579 // Stop here if there is nothing to render.
580 // This ensures that no pixels are rendered in a series of updates that
581 // happen at exactly the same time; the VDP subsystem states may be
582 // inconsistent until all updates are performed.
583 // Also it is a small performance optimisation.
584 if (limitX == nextX && limitY == nextY) return;
585
586 if (displayEnabled) {
587 if (vdp.spritesEnabled()) {
588 // Update sprite checking, so that rasterizer can call getSprites.
589 spriteChecker.checkUntil(time);
590 }
591
592 // Calculate start and end of borders in ticks since start of line.
593 // The 0..7 extra horizontal scroll low pixels should be drawn in
594 // border color. These will be drawn together with the border,
595 // but sprites above these pixels are clipped at the actual border
596 // rather than the end of the border colored area.
597 // TODO: Move these calculations and getDisplayLeft() to VDP.
598 int borderL = vdp.getLeftBorder();
599 int displayL =
600 vdp.isBorderMasked() ? borderL : vdp.getLeftBackground();
601 int borderR = vdp.getRightBorder();
602
603 // It's important that right border is drawn last (after left
604 // border and display area). See comment in SDLRasterizer::drawBorder().
605 // Left border.
606 subdivide(nextX, nextY, limitX, limitY,
607 0, displayL, DRAW_BORDER);
608 // Display area.
609 subdivide(nextX, nextY, limitX, limitY,
610 displayL, borderR, DRAW_DISPLAY);
611 // Right border.
612 subdivide(nextX, nextY, limitX, limitY,
613 borderR, VDP::TICKS_PER_LINE, DRAW_BORDER);
614 } else {
615 subdivide(nextX, nextY, limitX, limitY,
616 0, VDP::TICKS_PER_LINE, DRAW_BORDER);
617 }
618
619 nextX = limitX;
620 nextY = limitY;
621}
622
623void PixelRenderer::update(const Setting& setting) noexcept
624{
625 assert(&setting == one_of(&renderSettings.getMinFrameSkipSetting(),
626 &renderSettings.getMaxFrameSkipSetting()));
627 (void)setting;
628 // Force drawing of frame.
629 frameSkipCounter = 999;
630}
631
632} // namespace openmsx
BaseSetting * setting
Definition: Interpreter.cc:27
Definition: one_of.hh:7
Represents a VDP display mode.
Definition: DisplayMode.hh:16
constexpr byte getBase() const
Get the base dispay mode as an integer: M5..M1 combined.
Definition: DisplayMode.hh:107
constexpr bool isTextMode() const
Is the current mode a text mode? Text1 and Text2 are text modes.
Definition: DisplayMode.hh:122
constexpr byte getByte() const
Get the display mode as a byte: YAE YJK M5..M1 combined.
Definition: DisplayMode.hh:93
Represents the output window/screen of openMSX.
Definition: Display.hh:33
void distributeEvent(Event &&event)
Schedule the given event for delivery.
MSXMotherBoard & getMotherBoard() const
Get the mother board this device belongs to.
Definition: MSXDevice.cc:71
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.
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...
Definition: RawFrame.hh:15
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.
Definition: RealTime.cc:65
bool getDeinterlace() const
Deinterlacing [on, off].
IntegerSetting & getMinFrameSkipSetting()
The current min frameskip.
Accuracy getAccuracy() const
Accuracy [screen, line, pixel].
bool getDisableSprites() const
Disable sprite rendering?
IntegerSetting & getMaxFrameSkipSetting()
The current max frameskip.
double getSpeed() const
Return the desired ratio between emutime and real time.
Definition: SpeedManager.hh:26
void checkUntil(EmuTime::param time)
Update sprite checking until specified line.
void detach(Observer< T > &observer)
Definition: Subject.hh:56
void attach(Observer< T > &observer)
Definition: Subject.hh:50
bool isThrottled() const
Ask if throttling is enabled.
VRAMWindow colorTable
Definition: VDPVRAM.hh:669
void sync(EmuTime::param time)
Update VRAM state to specified moment in time.
Definition: VDPVRAM.hh:401
VRAMWindow patternTable
Definition: VDPVRAM.hh:670
VRAMWindow nameTable
Definition: VDPVRAM.hh:668
Unified implementation of MSX Video Display Processors (VDPs).
Definition: VDP.hh:63
bool getEvenOdd() const
Is the even or odd field being displayed?
Definition: VDP.hh:381
int getEvenOddMask() const
Expresses the state of even/odd page interchange in a mask on the line number.
Definition: VDP.hh:396
bool spritesEnabled() const
Are sprites enabled?
Definition: VDP.hh:256
int getLeftBackground() const
Gets the number of VDP clockticks between start of line and the time when the background pixel with X...
Definition: VDP.hh:561
int getBackgroundColor() const
Gets the current background color.
Definition: VDP.hh:204
bool isEvenOddEnabled() const
Get even/odd page alternation status.
Definition: VDP.hh:373
bool isFastBlinkEnabled() const
Get 'fast-blink' status.
Definition: VDP.hh:358
bool isBorderMasked() const
Gets the current border mask setting.
Definition: VDP.hh:307
static constexpr int TICKS_PER_LINE
Number of VDP clock ticks per line.
Definition: VDP.hh:72
int getTicksPerFrame() const
Gets the number of VDP clockticks (21MHz) per frame.
Definition: VDP.hh:501
int getRightBorder() const
Gets the number of VDP clockticks between start of line and the start of the right border.
Definition: VDP.hh:551
DisplayMode getDisplayMode() const
Get the display mode the VDP is in.
Definition: VDP.hh:141
int getLineZero() const
Get the absolute line number of display line zero.
Definition: VDP.hh:325
byte getVerticalScroll() const
Gets the current vertical scroll (line displayed at Y=0).
Definition: VDP.hh:280
bool isMultiPageScrolling() const
Is multi page scrolling enabled? It is considered enabled if both the multi page scrolling flag is en...
Definition: VDP.hh:317
int getLeftBorder() const
Gets the number of VDP clockticks between start of line and the end of the left border.
Definition: VDP.hh:544
bool isInterlaced() const
Get interlace status.
Definition: VDP.hh:344
bool isDisplayEnabled() const
Is the display enabled? Both the regular border and forced blanking by clearing the display enable bi...
Definition: VDP.hh:248
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.
Definition: VDP.hh:466
byte getHorizontalScrollLow() const
Gets the current horizontal scroll lower bits.
Definition: VDP.hh:289
int getLeftSprites() const
Gets the number of VDP clockticks between start of line and the start of the sprite plane.
Definition: VDP.hh:533
int getMask() const
Gets the mask for this window.
Definition: VDPVRAM.hh:145
bool isInside(unsigned address) const
Test whether an address is inside this window.
Definition: VDPVRAM.hh:296
constexpr vecN< N, T > max(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:283
uint64_t getTime()
Get current (real) time in us.
Definition: Timer.cc:7
This file implemented 3 utility functions:
Definition: Autofire.cc:9
constexpr nibble mask[4][13]
Definition: RP5C01.cc:34
#define UNREACHABLE
Definition: unreachable.hh:38
constexpr auto xrange(T e)
Definition: xrange.hh:133