openMSX
PixelRenderer.cc
Go to the documentation of this file.
1 /*
2 TODO:
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 "FinishFrameEvent.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 
32 namespace openmsx {
33 
34 void 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 
80 void 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 {
125  // In case of loadstate we can't yet query any state from the VDP
126  // (because that object is not yet fully deserialized). But
127  // VDP::serialize() will call Renderer::reInit() again when it is
128  // safe to query.
129  reInit();
130 
131  finishFrameDuration = 0;
132  frameSkipCounter = 999; // force drawing of frame
133  prevRenderFrame = false;
134 
135  renderSettings.getMaxFrameSkipSetting().attach(*this);
136  renderSettings.getMinFrameSkipSetting().attach(*this);
137 }
138 
140 {
141  renderSettings.getMinFrameSkipSetting().detach(*this);
142  renderSettings.getMaxFrameSkipSetting().detach(*this);
143 }
144 
146 {
147  return rasterizer->getPostProcessor();
148 }
149 
151 {
152  // Don't draw before frameStart() is called.
153  // This for example can happen after a loadstate or after switching
154  // renderer in the middle of a frame.
155  renderFrame = false;
156 
157  rasterizer->reset();
158  displayEnabled = vdp.isDisplayEnabled();
159 }
160 
161 void PixelRenderer::updateDisplayEnabled(bool enabled, EmuTime::param time)
162 {
163  sync(time, true);
164  displayEnabled = enabled;
165 }
166 
167 void 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 
221 void 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() &&
247  !vdp.getMotherBoard().isFastForwarding()) {
248  eventDistributor.distributeEvent(
249  std::make_shared<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 
405 static inline 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 
424 inline 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 (int i = 0; i < 4; i++) {
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 (int i = 0; i < 4; i++) {
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;
486  case DisplayMode::GRAPHIC5: {
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 
513 void 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 
524 void 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 
532 void 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 
554 void 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  int limitX, limitY;
560  switch (accuracy) {
562  limitX = limitTicks % VDP::TICKS_PER_LINE;
563  limitY = limitTicks / VDP::TICKS_PER_LINE;
564  break;
565  }
568  // Note: I'm not sure the rounding point is optimal.
569  // It used to be based on the left margin, but that doesn't work
570  // because the margin can change which leads to a line being
571  // rendered even though the time doesn't advance.
572  limitX = 0;
573  limitY =
574  (limitTicks + VDP::TICKS_PER_LINE - 400) / VDP::TICKS_PER_LINE;
575  break;
576  }
577  default:
578  UNREACHABLE;
579  limitX = limitY = 0; // avoid warning
580  }
581 
582  // Stop here if there is nothing to render.
583  // This ensures that no pixels are rendered in a series of updates that
584  // happen at exactly the same time; the VDP subsystem states may be
585  // inconsistent until all updates are performed.
586  // Also it is a small performance optimisation.
587  if (limitX == nextX && limitY == nextY) return;
588 
589  if (displayEnabled) {
590  if (vdp.spritesEnabled()) {
591  // Update sprite checking, so that rasterizer can call getSprites.
592  spriteChecker.checkUntil(time);
593  }
594 
595  // Calculate start and end of borders in ticks since start of line.
596  // The 0..7 extra horizontal scroll low pixels should be drawn in
597  // border color. These will be drawn together with the border,
598  // but sprites above these pixels are clipped at the actual border
599  // rather than the end of the border colored area.
600  // TODO: Move these calculations and getDisplayLeft() to VDP.
601  int borderL = vdp.getLeftBorder();
602  int displayL =
603  vdp.isBorderMasked() ? borderL : vdp.getLeftBackground();
604  int borderR = vdp.getRightBorder();
605 
606  // It's important that right border is drawn last (after left
607  // border and display area). See comment in SDLRasterizer::drawBorder().
608  // Left border.
609  subdivide(nextX, nextY, limitX, limitY,
610  0, displayL, DRAW_BORDER);
611  // Display area.
612  subdivide(nextX, nextY, limitX, limitY,
613  displayL, borderR, DRAW_DISPLAY);
614  // Right border.
615  subdivide(nextX, nextY, limitX, limitY,
616  borderR, VDP::TICKS_PER_LINE, DRAW_BORDER);
617  } else {
618  subdivide(nextX, nextY, limitX, limitY,
619  0, VDP::TICKS_PER_LINE, DRAW_BORDER);
620  }
621 
622  nextX = limitX;
623  nextY = limitY;
624 }
625 
626 void PixelRenderer::update(const Setting& setting)
627 {
628  assert(&setting == one_of(&renderSettings.getMinFrameSkipSetting(),
629  &renderSettings.getMaxFrameSkipSetting()));
630  (void)setting;
631  // Force drawing of frame.
632  frameSkipCounter = 999;
633 }
634 
635 } // namespace openmsx
one_of.hh
openmsx::adjust
constexpr AdjustTables adjust
Definition: Y8950.cc:204
VideoSystem.hh
openmsx::PixelRenderer::frameStart
void frameStart(EmuTime::param time) override
Signals the start of a new frame.
Definition: PixelRenderer.cc:167
IntegerSetting.hh
openmsx::Subject::detach
void detach(Observer< T > &observer)
Definition: Subject.hh:56
Timer.hh
Display.hh
openmsx::VDP
Unified implementation of MSX Video Display Processors (VDPs).
Definition: VDP.hh:61
openmsx::RenderSettings::ACC_LINE
@ ACC_LINE
Definition: RenderSettings.hh:32
openmsx::PixelRenderer::reInit
void reInit() override
Reinitialise Renderer state.
Definition: PixelRenderer.cc:150
openmsx::PixelRenderer::updateBorderMask
void updateBorderMask(bool masked, EmuTime::param time) override
Informs the renderer of a horizontal scroll change: the border mask has been enabled/disabled.
Definition: PixelRenderer.cc:269
openmsx::VDP::getHorizontalScrollLow
byte getHorizontalScrollLow() const
Gets the current horizontal scroll lower bits.
Definition: VDP.hh:289
openmsx::RenderSettings::getMaxFrameSkipSetting
IntegerSetting & getMaxFrameSkipSetting()
The current max frameskip.
Definition: RenderSettings.hh:59
openmsx::VDP::isInterlaced
bool isInterlaced() const
Get interlace status.
Definition: VDP.hh:344
openmsx::SpriteChecker::checkUntil
void checkUntil(EmuTime::param time)
Update sprite checking until specified line.
Definition: SpriteChecker.hh:169
openmsx::VDP::getEvenOdd
bool getEvenOdd() const
Is the even or odd field being displayed?
Definition: VDP.hh:381
VDP.hh
openmsx::DisplayMode::GRAPHIC3
@ GRAPHIC3
Definition: DisplayMode.hh:33
openmsx::DisplayMode::GRAPHIC6
@ GRAPHIC6
Definition: DisplayMode.hh:37
openmsx::DisplayMode::GRAPHIC2
@ GRAPHIC2
Definition: DisplayMode.hh:30
openmsx::VDP::isBorderMasked
bool isBorderMasked() const
Gets the current border mask setting.
Definition: VDP.hh:307
openmsx::PixelRenderer::getPostProcessor
PostProcessor * getPostProcessor() const override
See VDP::getPostProcessor.
Definition: PixelRenderer.cc:145
VideoSourceSetting.hh
openmsx::VDP::getBackgroundColor
int getBackgroundColor() const
Gets the current background color.
Definition: VDP.hh:204
openmsx::PixelRenderer::~PixelRenderer
~PixelRenderer() override
Definition: PixelRenderer.cc:139
openmsx::Timer::getTime
uint64_t getTime()
Get current (real) time in us.
Definition: Timer.cc:7
openmsx::VRAMWindow::isInside
bool isInside(unsigned address) const
Test whether an address is inside this window.
Definition: VDPVRAM.hh:296
openmsx::VDP::getTicksPerFrame
int getTicksPerFrame() const
Gets the number of VDP clockticks (21MHz) per frame.
Definition: VDP.hh:497
openmsx::PixelRenderer::updateVerticalScroll
void updateVerticalScroll(int scroll, EmuTime::param time) override
Informs the renderer of a vertical scroll change.
Definition: PixelRenderer.cc:353
openmsx::Subject::attach
void attach(Observer< T > &observer)
Definition: Subject.hh:50
openmsx::VDP::spritesEnabled
bool spritesEnabled() const
Are sprites enabled?
Definition: VDP.hh:256
openmsx::RenderSettings::getDisableSprites
bool getDisableSprites() const
Disable sprite rendering?
Definition: RenderSettings.hh:131
openmsx::DisplayMode::getBase
constexpr byte getBase() const
Get the base dispay mode as an integer: M5..M1 combined.
Definition: DisplayMode.hh:115
openmsx::PixelRenderer::updatePatternBase
void updatePatternBase(int addr, EmuTime::param time) override
Informs the renderer of a pattern table base address change.
Definition: PixelRenderer.cc:387
openmsx::VDP::getDisplayMode
DisplayMode getDisplayMode() const
Get the display mode the VDP is in.
Definition: VDP.hh:141
openmsx::PixelRenderer::updateWindow
void updateWindow(bool enabled, EmuTime::param time) override
Informs the observer that the entire VRAM window will change.
Definition: PixelRenderer.cc:524
openmsx::DisplayMode::GRAPHIC7
@ GRAPHIC7
Definition: DisplayMode.hh:38
openmsx::DisplayMode
Represents a VDP display mode.
Definition: DisplayMode.hh:15
openmsx::MSXMotherBoard::isFastForwarding
bool isFastForwarding() const
Definition: MSXMotherBoard.hh:96
openmsx::PixelRenderer::updateBackgroundColor
void updateBackgroundColor(int color, EmuTime::param time) override
Informs the renderer of a VDP background color change.
Definition: PixelRenderer.cc:302
openmsx::RenderSettings::getDeinterlace
bool getDeinterlace() const
Deinterlacing [on, off].
Definition: RenderSettings.hh:53
openmsx::PixelRenderer::updateMultiPage
void updateMultiPage(bool multiPage, EmuTime::param time) override
Informs the renderer of a horizontal scroll change: the multi page setting has changed.
Definition: PixelRenderer.cc:276
openmsx::PixelRenderer::updateSuperimposing
void updateSuperimposing(const RawFrame *videoSource, EmuTime::param time) override
Informs the renderer of a VDP superimposing change.
Definition: PixelRenderer.cc:289
RealTime.hh
openmsx::VDPVRAM::colorTable
VRAMWindow colorTable
Definition: VDPVRAM.hh:667
openmsx::PixelRenderer::updateHorizontalScrollLow
void updateHorizontalScrollLow(byte scroll, EmuTime::param time) override
Informs the renderer of a horizontal scroll change: the lower scroll value has changed.
Definition: PixelRenderer.cc:256
Reactor.hh
openmsx::PixelRenderer::frameEnd
void frameEnd(EmuTime::param time) override
Signals the end of a frame.
Definition: PixelRenderer.cc:221
openmsx::PixelRenderer::PixelRenderer
PixelRenderer(VDP &vdp, Display &display)
Definition: PixelRenderer.cc:112
SpriteChecker.hh
UNREACHABLE
#define UNREACHABLE
Definition: unreachable.hh:38
openmsx::VDP::isDisplayEnabled
bool isDisplayEnabled() const
Is the display enabled? Both the regular border and forced blanking by clearing the display enable bi...
Definition: VDP.hh:248
openmsx::PixelRenderer::updatePalette
void updatePalette(int index, int grb, EmuTime::param time) override
Informs the renderer of a VDP palette change.
Definition: PixelRenderer.cc:331
openmsx::VDP::isFastBlinkEnabled
bool isFastBlinkEnabled() const
Get 'fast-blink' status.
Definition: VDP.hh:358
openmsx::SpeedManager::getSpeed
double getSpeed() const
Return the desired ratio between emutime and real time.
Definition: SpeedManager.hh:26
openmsx::RenderSettings::getMinFrameSkipSetting
IntegerSetting & getMinFrameSkipSetting()
The current min frameskip.
Definition: RenderSettings.hh:63
openmsx::VDP::getLineZero
int getLineZero() const
Get the absolute line number of display line zero.
Definition: VDP.hh:325
one_of
Definition: one_of.hh:7
EventDistributor.hh
PostProcessor.hh
openmsx::RenderSettings::getAccuracy
Accuracy getAccuracy() const
Accuracy [screen, line, pixel].
Definition: RenderSettings.hh:50
openmsx::MSXDevice::getMotherBoard
MSXMotherBoard & getMotherBoard() const
Get the mother board this device belongs to.
Definition: MSXDevice.cc:75
openmsx::PixelRenderer::updateNameBase
void updateNameBase(int addr, EmuTime::param time) override
Informs the renderer of a name table base address change.
Definition: PixelRenderer.cc:381
openmsx::DisplayMode::GRAPHIC5
@ GRAPHIC5
Definition: DisplayMode.hh:36
openmsx::VideoSourceSetting::getSource
int getSource() noexcept
Definition: VideoSourceSetting.cc:35
openmsx::PostProcessor
Abstract base class for post processors.
Definition: PostProcessor.hh:29
openmsx::PixelRenderer::updateColorBase
void updateColorBase(int addr, EmuTime::param time) override
Informs the renderer of a color table base address change.
Definition: PixelRenderer.cc:393
openmsx::VDPVRAM::sync
void sync(EmuTime::param time)
Update VRAM state to specified moment in time.
Definition: VDPVRAM.hh:400
openmsx::ThrottleManager::isThrottled
bool isThrottled() const
Ask if throttling is enabled.
Definition: ThrottleManager.hh:29
openmsx::RawFrame
A video frame as output by the VDP scanline conversion unit, before any postprocessing filters are ap...
Definition: RawFrame.hh:25
RenderSettings.hh
FinishFrameEvent.hh
ThrottleManager.hh
GlobalSettings.hh
openmsx::PixelRenderer::updateTransparency
void updateTransparency(bool enabled, EmuTime::param time) override
Informs the renderer of a VDP transparency enable/disable change.
Definition: PixelRenderer.cc:282
openmsx::DisplayMode::isTextMode
constexpr bool isTextMode() const
Is the current mode a text mode? Text1 and Text2 are text modes.
Definition: DisplayMode.hh:130
openmsx::PixelRenderer::updateSpritesEnabled
void updateSpritesEnabled(bool enabled, EmuTime::param time) override
Informs the renderer of a VDP sprites enabled change.
Definition: PixelRenderer.cc:399
Rasterizer.hh
openmsx::VDP::isMultiPageScrolling
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
openmsx::VDP::getRightBorder
int getRightBorder() const
Gets the number of VDP clockticks between start of line and the start of the right border.
Definition: VDP.hh:547
openmsx::VDP::getLeftSprites
int getLeftSprites() const
Gets the number of VDP clockticks between start of line and the start of the sprite plane.
Definition: VDP.hh:529
openmsx::VDP::getTicksThisFrame
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:462
openmsx::VDPVRAM::nameTable
VRAMWindow nameTable
Definition: VDPVRAM.hh:666
openmsx::PixelRenderer::updateBlinkForegroundColor
void updateBlinkForegroundColor(int color, EmuTime::param time) override
Informs the renderer of a VDP blink foreground color change.
Definition: PixelRenderer.cc:309
openmsx::VDP::getLeftBackground
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:557
openmsx::VDP::isEvenOddEnabled
bool isEvenOddEnabled() const
Get even/odd page alternation status.
Definition: VDP.hh:373
openmsx::RenderSettings::getMinFrameSkip
int getMinFrameSkip() const
Definition: RenderSettings.hh:64
openmsx::RenderSettings::ACC_SCREEN
@ ACC_SCREEN
Definition: RenderSettings.hh:32
openmsx::PixelRenderer::updateHorizontalScrollHigh
void updateHorizontalScrollHigh(byte scroll, EmuTime::param time) override
Informs the renderer of a horizontal scroll change: the higher scroll value has changed.
Definition: PixelRenderer.cc:263
openmsx::Display
Represents the output window/screen of openMSX.
Definition: Display.hh:31
openmsx::MSXMotherBoard::isActive
bool isActive() const
Definition: MSXMotherBoard.hh:95
openmsx::RenderSettings::getMaxFrameSkip
int getMaxFrameSkip() const
Definition: RenderSettings.hh:60
openmsx::PixelRenderer::updateDisplayMode
void updateDisplayMode(DisplayMode mode, EmuTime::param time) override
Informs the renderer of a VDP display mode change.
Definition: PixelRenderer.cc:366
openmsx::VDP::getVerticalScroll
byte getVerticalScroll() const
Gets the current vertical scroll (line displayed at Y=0).
Definition: VDP.hh:280
VDPVRAM.hh
openmsx::mask
constexpr nibble mask[4][13]
Definition: RP5C01.cc:33
openmsx::PixelRenderer::updateForegroundColor
void updateForegroundColor(int color, EmuTime::param time) override
Informs the renderer of a VDP foreground color change.
Definition: PixelRenderer.cc:296
gl::max
vecN< N, T > max(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:292
openmsx::VDP::getEvenOddMask
int getEvenOddMask() const
Expresses the state of even/odd page interchange in a mask on the line number.
Definition: VDP.hh:396
openmsx::DisplayMode::GRAPHIC4
@ GRAPHIC4
Definition: DisplayMode.hh:35
PixelRenderer.hh
openmsx::VRAMWindow::getMask
int getMask() const
Gets the mask for this window.
Definition: VDPVRAM.hh:146
openmsx::PixelRenderer::updateBlinkBackgroundColor
void updateBlinkBackgroundColor(int color, EmuTime::param time) override
Informs the renderer of a VDP blink background color change.
Definition: PixelRenderer.cc:315
openmsx::VDPVRAM::patternTable
VRAMWindow patternTable
Definition: VDPVRAM.hh:668
unreachable.hh
openmsx::RealTime::timeLeft
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:67
openmsx::PixelRenderer::updateHorizontalAdjust
void updateHorizontalAdjust(int adjust, EmuTime::param time) override
Informs the renderer of a horizontal adjust change.
Definition: PixelRenderer.cc:359
openmsx::VDP::getLeftBorder
int getLeftBorder() const
Gets the number of VDP clockticks between start of line and the end of the left border.
Definition: VDP.hh:540
openmsx::DisplayMode::getByte
constexpr byte getByte() const
Get the dispay mode as a byte: YAE YJK M5..M1 combined.
Definition: DisplayMode.hh:101
openmsx::PixelRenderer::updateBlinkState
void updateBlinkState(bool enabled, EmuTime::param time) override
Informs the renderer of a VDP blinking state change.
Definition: PixelRenderer.cc:321
openmsx::VDP::TICKS_PER_LINE
static constexpr int TICKS_PER_LINE
Number of VDP clock ticks per line.
Definition: VDP.hh:72
SpeedManager.hh
openmsx::PixelRenderer::updateDisplayEnabled
void updateDisplayEnabled(bool enabled, EmuTime::param time) override
Informs the renderer of a VDP display enabled change.
Definition: PixelRenderer.cc:161
openmsx
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
MSXMotherBoard.hh
openmsx::PixelRenderer::updateVRAM
void updateVRAM(unsigned offset, EmuTime::param time) override
Informs the observer of a change in VRAM contents.
Definition: PixelRenderer.cc:513
openmsx::EventDistributor::distributeEvent
void distributeEvent(const EventPtr &event)
Schedule the given event for delivery.
Definition: EventDistributor.cc:44
openmsx::RenderSettings::ACC_PIXEL
@ ACC_PIXEL
Definition: RenderSettings.hh:32