openMSX
SDLRasterizer.cc
Go to the documentation of this file.
1 #include "SDLRasterizer.hh"
2 #include "VDP.hh"
3 #include "VDPVRAM.hh"
4 #include "RawFrame.hh"
5 #include "Display.hh"
6 #include "Renderer.hh"
7 #include "RenderSettings.hh"
8 #include "PostProcessor.hh"
9 #include "MemoryOps.hh"
10 #include "OutputSurface.hh"
11 #include "enumerate.hh"
12 #include "one_of.hh"
13 #include "xrange.hh"
14 #include "build-info.hh"
15 #include "components.hh"
16 #include <algorithm>
17 #include <cassert>
18 #include <cstdint>
19 #include <memory>
20 
21 using namespace gl;
22 
23 namespace openmsx {
24 
27 constexpr int TICKS_LEFT_BORDER = 100 + 102;
28 
33 constexpr int TICKS_VISIBLE_MIDDLE =
34  TICKS_LEFT_BORDER + (VDP::TICKS_PER_LINE - TICKS_LEFT_BORDER - 27) / 2;
35 
42 static constexpr int translateX(int absoluteX, bool narrow)
43 {
44  int maxX = narrow ? 640 : 320;
45  if (absoluteX == VDP::TICKS_PER_LINE) return maxX;
46 
47  // Note: The ROUND_MASK forces the ticks to a pixel (2-tick) boundary.
48  // If this is not done, rounding errors will occur.
49  const int ROUND_MASK = narrow ? ~1 : ~3;
50  int screenX =
51  ((absoluteX - (TICKS_VISIBLE_MIDDLE & ROUND_MASK))
52  >> (narrow ? 1 : 2))
53  + maxX / 2;
54  return std::max(screenX, 0);
55 }
56 
57 template<typename Pixel>
58 inline void SDLRasterizer<Pixel>::renderBitmapLine(Pixel* buf, unsigned vramLine)
59 {
60  if (vdp.getDisplayMode().isPlanar()) {
61  auto [vramPtr0, vramPtr1] =
62  vram.bitmapCacheWindow.getReadAreaPlanar(vramLine * 256, 256);
63  bitmapConverter.convertLinePlanar(buf, vramPtr0, vramPtr1);
64  } else {
65  const byte* vramPtr =
66  vram.bitmapCacheWindow.getReadArea(vramLine * 128, 128);
67  bitmapConverter.convertLine(buf, vramPtr);
68  }
69 }
70 
71 template<typename Pixel>
73  VDP& vdp_, Display& display, OutputSurface& screen_,
74  std::unique_ptr<PostProcessor> postProcessor_)
75  : vdp(vdp_), vram(vdp.getVRAM())
76  , screen(screen_)
77  , postProcessor(std::move(postProcessor_))
78  , workFrame(std::make_unique<RawFrame>(screen.getPixelFormat(), 640, 240))
79  , renderSettings(display.getRenderSettings())
80  , characterConverter(vdp, palFg, palBg)
81  , bitmapConverter(palFg, PALETTE256, V9958_COLORS)
82  , spriteConverter(vdp.getSpriteChecker())
83 {
84  // Init the palette.
85  precalcPalette();
86 
87  // Initialize palette (avoid UMR)
88  if (!vdp.isMSX1VDP()) {
89  for (auto i : xrange(16)) {
90  palFg[i] = palFg[i + 16] = palBg[i] =
91  V9938_COLORS[0][0][0];
92  }
93  }
94 
95  renderSettings.getGammaSetting() .attach(*this);
96  renderSettings.getBrightnessSetting() .attach(*this);
97  renderSettings.getContrastSetting() .attach(*this);
98  renderSettings.getColorMatrixSetting().attach(*this);
99 }
100 
101 template<typename Pixel>
103 {
104  renderSettings.getColorMatrixSetting().detach(*this);
105  renderSettings.getGammaSetting() .detach(*this);
106  renderSettings.getBrightnessSetting() .detach(*this);
107  renderSettings.getContrastSetting() .detach(*this);
108 }
109 
110 template<typename Pixel>
112 {
113  return postProcessor.get();
114 }
115 
116 template<typename Pixel>
118 {
119  return postProcessor->needRender() &&
120  vdp.getMotherBoard().isActive() &&
121  !vdp.getMotherBoard().isFastForwarding();
122 }
123 
124 template<typename Pixel>
126 {
127  // Init renderer state.
128  setDisplayMode(vdp.getDisplayMode());
129  spriteConverter.setTransparency(vdp.getTransparency());
130 
131  resetPalette();
132 }
133 
134 template<typename Pixel>
136 {
137  if (!vdp.isMSX1VDP()) {
138  // Reset the palette.
139  for (auto i : xrange(16)) {
140  setPalette(i, vdp.getPalette(i));
141  }
142  }
143 }
144 
145 template<typename Pixel>
147 {
148  postProcessor->setSuperimposeVideoFrame(videoSource);
149  precalcColorIndex0(vdp.getDisplayMode(), vdp.getTransparency(),
150  videoSource, vdp.getBackgroundColor());
151 }
152 
153 template<typename Pixel>
154 void SDLRasterizer<Pixel>::frameStart(EmuTime::param time)
155 {
156  workFrame = postProcessor->rotateFrames(std::move(workFrame), time);
157  workFrame->init(
158  vdp.isInterlaced() ? (vdp.getEvenOdd() ? FrameSource::FIELD_ODD
161 
162  // Calculate line to render at top of screen.
163  // Make sure the display area is centered.
164  // 240 - 212 = 28 lines available for top/bottom border; 14 each.
165  // NTSC: display at [32..244),
166  // PAL: display at [59..271).
167  lineRenderTop = vdp.isPalTiming() ? 59 - 14 : 32 - 14;
168 }
169 
170 template<typename Pixel>
172 {
173 }
174 
175 template<typename Pixel>
177 {
178  if (mode.isBitmapMode()) {
179  bitmapConverter.setDisplayMode(mode);
180  } else {
181  characterConverter.setDisplayMode(mode);
182  }
183  precalcColorIndex0(mode, vdp.getTransparency(),
184  vdp.isSuperimposing(), vdp.getBackgroundColor());
185  spriteConverter.setDisplayMode(mode);
186  spriteConverter.setPalette(mode.getByte() == DisplayMode::GRAPHIC7
187  ? palGraphic7Sprites : palBg);
188 
189 }
190 
191 template<typename Pixel>
192 void SDLRasterizer<Pixel>::setPalette(int index, int grb)
193 {
194  // Update SDL colors in palette.
195  Pixel newColor = V9938_COLORS[(grb >> 4) & 7][grb >> 8][grb & 7];
196  palFg[index ] = newColor;
197  palFg[index + 16] = newColor;
198  palBg[index ] = newColor;
199  bitmapConverter.palette16Changed();
200 
201  precalcColorIndex0(vdp.getDisplayMode(), vdp.getTransparency(),
202  vdp.isSuperimposing(), vdp.getBackgroundColor());
203 }
204 
205 template<typename Pixel>
207 {
208  if (vdp.getDisplayMode().getByte() != DisplayMode::GRAPHIC7) {
209  precalcColorIndex0(vdp.getDisplayMode(), vdp.getTransparency(),
210  vdp.isSuperimposing(), index);
211  }
212 }
213 
214 template<typename Pixel>
216 {
217 }
218 
219 template<typename Pixel>
221 {
222 }
223 
224 template<typename Pixel>
226 {
227 }
228 
229 template<typename Pixel>
231 {
232  spriteConverter.setTransparency(enabled);
233  precalcColorIndex0(vdp.getDisplayMode(), enabled,
234  vdp.isSuperimposing(), vdp.getBackgroundColor());
235 }
236 
237 template<typename Pixel>
239 {
240  if (vdp.isMSX1VDP()) {
241  // Fixed palette.
242  const auto palette = vdp.getMSX1Palette();
243  for (auto i : xrange(16)) {
244  const auto rgb = palette[i];
245  palFg[i] = palFg[i + 16] = palBg[i] =
246  screen.mapKeyedRGB<Pixel>(
247  renderSettings.transformRGB(
248  vec3(rgb[0], rgb[1], rgb[2]) / 255.0f));
249  }
250  } else {
251  if (vdp.hasYJK()) {
252  // Precalculate palette for V9958 colors.
253  if (renderSettings.isColorMatrixIdentity()) {
254  // Most users use the "normal" monitor type; making this a
255  // special case speeds up palette precalculation a lot.
256  int intensity[32];
257  for (auto [i, r] : enumerate(intensity)) {
258  r = int(255 * renderSettings.transformComponent(i / 31.0));
259  }
260  for (auto [rgb, col] : enumerate(V9958_COLORS)) {
261  col = screen.mapKeyedRGB255<Pixel>(ivec3(
262  intensity[(rgb >> 10) & 31],
263  intensity[(rgb >> 5) & 31],
264  intensity[(rgb >> 0) & 31]));
265  }
266  } else {
267  for (auto r : xrange(32)) {
268  for (auto g : xrange(32)) {
269  for (auto b : xrange(32)) {
270  V9958_COLORS[(r << 10) + (g << 5) + b] =
271  screen.mapKeyedRGB<Pixel>(
272  renderSettings.transformRGB(
273  vec3(r, g, b) / 31.0f));
274  }
275  }
276  }
277  }
278  // Precalculate palette for V9938 colors.
279  // Based on comparing red and green gradients, using palette and
280  // YJK, in SCREEN11 on a real turbo R.
281  for (auto r3 : xrange(8)) {
282  int r5 = (r3 << 2) | (r3 >> 1);
283  for (auto g3 : xrange(8)) {
284  int g5 = (g3 << 2) | (g3 >> 1);
285  for (auto b3 : xrange(8)) {
286  int b5 = (b3 << 2) | (b3 >> 1);
287  V9938_COLORS[r3][g3][b3] =
288  V9958_COLORS[(r5 << 10) + (g5 << 5) + b5];
289  }
290  }
291  }
292  } else {
293  // Precalculate palette for V9938 colors.
294  if (renderSettings.isColorMatrixIdentity()) {
295  int intensity[8];
296  for (auto [i, r] : enumerate(intensity)) {
297  r = int(255 * renderSettings.transformComponent(i / 7.0f));
298  }
299  for (auto r : xrange(8)) {
300  for (auto g : xrange(8)) {
301  for (auto b : xrange(8)) {
302  V9938_COLORS[r][g][b] =
303  screen.mapKeyedRGB255<Pixel>(ivec3(
304  intensity[r],
305  intensity[g],
306  intensity[b]));
307  }
308  }
309  }
310  } else {
311  for (auto r : xrange(8)) {
312  for (auto g : xrange(8)) {
313  for (auto b : xrange(8)) {
314  V9938_COLORS[r][g][b] =
315  screen.mapKeyedRGB<Pixel>(
316  renderSettings.transformRGB(
317  vec3(r, g, b) / 7.0f));;
318  }
319  }
320  }
321  }
322  }
323  // Precalculate Graphic 7 bitmap palette.
324  for (auto i : xrange(256)) {
325  PALETTE256[i] = V9938_COLORS
326  [(i & 0x1C) >> 2]
327  [(i & 0xE0) >> 5]
328  [(i & 0x03) == 3 ? 7 : (i & 0x03) * 2];
329  }
330  // Precalculate Graphic 7 sprite palette.
331  for (auto i : xrange(16)) {
332  uint16_t grb = Renderer::GRAPHIC7_SPRITE_PALETTE[i];
333  palGraphic7Sprites[i] =
334  V9938_COLORS[(grb >> 4) & 7][grb >> 8][grb & 7];
335  }
336  }
337 }
338 
339 template<typename Pixel>
340 void SDLRasterizer<Pixel>::precalcColorIndex0(DisplayMode mode,
341  bool transparency, const RawFrame* superimposing, byte bgcolorIndex)
342 {
343  // Graphic7 mode doesn't use transparency.
344  if (mode.getByte() == DisplayMode::GRAPHIC7) {
345  transparency = false;
346  }
347 
348  int tpIndex = transparency ? bgcolorIndex : 0;
349  if (mode.getBase() != DisplayMode::GRAPHIC5) {
350  Pixel c = (superimposing && (bgcolorIndex == 0))
351  ? screen.getKeyColor<Pixel>()
352  : palBg[tpIndex];
353 
354  if (palFg[0] != c) {
355  palFg[0] = c;
356  bitmapConverter.palette16Changed();
357  }
358  } else {
359  // TODO: superimposing
360  if ((palFg[ 0] != palBg[tpIndex >> 2]) ||
361  (palFg[16] != palBg[tpIndex & 3])) {
362  palFg[ 0] = palBg[tpIndex >> 2];
363  palFg[16] = palBg[tpIndex & 3];
364  bitmapConverter.palette16Changed();
365  }
366  }
367 }
368 
369 template<typename Pixel>
370 std::pair<Pixel, Pixel> SDLRasterizer<Pixel>::getBorderColors()
371 {
372  DisplayMode mode = vdp.getDisplayMode();
373  int bgColor = vdp.getBackgroundColor();
374  if (mode.getBase() == DisplayMode::GRAPHIC5) {
375  // border in SCREEN6 has separate color for even and odd pixels.
376  // TODO odd/even swapped?
377  return {palBg[(bgColor & 0x0C) >> 2],
378  palBg[(bgColor & 0x03) >> 0]};
379  }
380  Pixel col = [&] { // other modes only have a single border color
381  if (mode.getByte() == DisplayMode::GRAPHIC7) {
382  return PALETTE256[bgColor];
383  } else {
384  if (!bgColor && vdp.isSuperimposing()) {
385  return screen.getKeyColor<Pixel>();
386  } else {
387  return palBg[bgColor];
388  }
389  }
390  }();
391  return {col, col};
392 }
393 
394 template<typename Pixel>
396  int fromX, int fromY, int limitX, int limitY)
397 {
398  auto [border0, border1] = getBorderColors();
399 
400  int startY = std::max(fromY - lineRenderTop, 0);
401  int endY = std::min(limitY - lineRenderTop, 240);
402  if ((fromX == 0) && (limitX == VDP::TICKS_PER_LINE) &&
403  (border0 == border1)) {
404  // complete lines, non striped
405  for (auto y : xrange(startY, endY)) {
406  workFrame->setBlank(y, border0);
407  // setBlank() implies this line is not suitable
408  // for left/right border optimization in a later
409  // frame.
410  }
411  } else {
412  unsigned lineWidth = vdp.getDisplayMode().getLineWidth();
413  unsigned x = translateX(fromX, (lineWidth == 512));
414  unsigned num = translateX(limitX, (lineWidth == 512)) - x;
415  unsigned width = (lineWidth == 512) ? 640 : 320;
417  for (auto y : xrange(startY, endY)) {
418  memset(workFrame->getLinePtrDirect<Pixel>(y) + x,
419  num, border0, border1);
420  if (limitX == VDP::TICKS_PER_LINE) {
421  // Only set line width at the end (right
422  // border) of the line. This ensures we can
423  // keep testing the width of the previous
424  // version of this line for all (partial)
425  // updates of this line.
426  workFrame->setLineWidth(y, width);
427  }
428  }
429  }
430 }
431 
432 template<typename Pixel>
434  int /*fromX*/, int fromY,
435  int displayX, int displayY,
436  int displayWidth, int displayHeight)
437 {
438  // Note: we don't call workFrame->setLineWidth() because that's done in
439  // drawBorder() (for the right border). And the value we set there is
440  // anyway the same as the one we would set here.
441  DisplayMode mode = vdp.getDisplayMode();
442  int lineWidth = mode.getLineWidth();
443  if (lineWidth == 256) {
444  int endX = displayX + displayWidth;
445  displayX /= 2;
446  displayWidth = endX / 2 - displayX;
447  }
448 
449  // Clip to screen area.
450  int screenLimitY = std::min(
451  fromY + displayHeight - lineRenderTop,
452  240);
453  int screenY = fromY - lineRenderTop;
454  if (screenY < 0) {
455  displayY -= screenY;
456  fromY = lineRenderTop;
457  screenY = 0;
458  }
459  displayHeight = screenLimitY - screenY;
460  if (displayHeight <= 0) return;
461 
462  int leftBackground =
463  translateX(vdp.getLeftBackground(), lineWidth == 512);
464  // TODO: Find out why this causes 1-pixel jitter:
465  //dest.x = translateX(fromX);
466  int hScroll =
467  mode.isTextMode()
468  ? 0
469  : 8 * (lineWidth / 256) * (vdp.getHorizontalScrollHigh() & 0x1F);
470 
471  // Page border is display X coordinate where to stop drawing current page.
472  // This is either the multi page split point, or the right edge of the
473  // rectangle to draw, whichever comes first.
474  // Note that it is possible for pageBorder to be to the left of displayX,
475  // in that case only the second page should be drawn.
476  int pageBorder = displayX + displayWidth;
477  auto [scrollPage1, scrollPage2] = [&]() -> std::pair<int, int> {
478  if (vdp.isMultiPageScrolling()) {
479  int p1 = vdp.getHorizontalScrollHigh() >> 5;
480  int p2 = p1 ^ 1;
481  return {p1, p2};
482  } else {
483  return {0, 0};
484  }
485  }();
486  // Because SDL blits do not wrap, unlike GL textures, the pageBorder is
487  // also used if multi page is disabled.
488  int pageSplit = lineWidth - hScroll;
489  if (pageSplit < pageBorder) {
490  pageBorder = pageSplit;
491  }
492 
493  if (mode.isBitmapMode()) {
494  for (auto y : xrange(screenY, screenLimitY)) {
495  // Which bits in the name mask determine the page?
496  // TODO optimize this?
497  // Calculating pageMaskOdd/Even is a non-trivial amount
498  // of work. We used to do this per frame (more or less)
499  // but now do it per line. Per-line is actually only
500  // needed when vdp.isFastBlinkEnabled() is true.
501  // Idea: can be cheaply calculated incrementally.
502  int pageMaskOdd = (mode.isPlanar() ? 0x000 : 0x200) |
503  vdp.getEvenOddMask(y);
504  int pageMaskEven = vdp.isMultiPageScrolling()
505  ? (pageMaskOdd & ~0x100)
506  : pageMaskOdd;
507  const int vramLine[2] = {
508  (vram.nameTable.getMask() >> 7) & (pageMaskEven | displayY),
509  (vram.nameTable.getMask() >> 7) & (pageMaskOdd | displayY)
510  };
511 
512  Pixel buf[512];
513  int lineInBuf = -1; // buffer data not valid
514  Pixel* dst = workFrame->getLinePtrDirect<Pixel>(y)
515  + leftBackground + displayX;
516  int firstPageWidth = pageBorder - displayX;
517  if (firstPageWidth > 0) {
518  if (((displayX + hScroll) == 0) &&
519  (firstPageWidth == lineWidth)) {
520  // fast-path, directly render to destination
521  renderBitmapLine(dst, vramLine[scrollPage1]);
522  } else {
523  lineInBuf = vramLine[scrollPage1];
524  renderBitmapLine(buf, vramLine[scrollPage1]);
525  const Pixel* src = buf + displayX + hScroll;
526  memcpy(dst, src, firstPageWidth * sizeof(Pixel));
527  }
528  } else {
529  firstPageWidth = 0;
530  }
531  if (firstPageWidth < displayWidth) {
532  if (lineInBuf != vramLine[scrollPage2]) {
533  renderBitmapLine(buf, vramLine[scrollPage2]);
534  }
535  unsigned x = displayX < pageBorder
536  ? 0 : displayX + hScroll - lineWidth;
537  memcpy(dst + firstPageWidth,
538  buf + x,
539  (displayWidth - firstPageWidth) * sizeof(Pixel));
540  }
541 
542  displayY = (displayY + 1) & 255;
543  }
544  } else {
545  // horizontal scroll (high) is implemented in CharacterConverter
546  for (auto y : xrange(screenY, screenLimitY)) {
547  assert(!vdp.isMSX1VDP() || displayY < 192);
548 
549  Pixel* dst = workFrame->getLinePtrDirect<Pixel>(y)
550  + leftBackground + displayX;
551  if ((displayX == 0) && (displayWidth == lineWidth)){
552  characterConverter.convertLine(dst, displayY);
553  } else {
554  Pixel buf[512];
555  characterConverter.convertLine(buf, displayY);
556  const Pixel* src = buf + displayX;
557  memcpy(dst, src, displayWidth * sizeof(Pixel));
558  }
559 
560  displayY = (displayY + 1) & 255;
561  }
562  }
563 }
564 
565 template<typename Pixel>
567  int /*fromX*/, int fromY,
568  int displayX, int displayY,
569  int displayWidth, int displayHeight)
570 {
571  // Clip to screen area.
572  // TODO: Code duplicated from drawDisplay.
573  int screenLimitY = std::min(
574  fromY + displayHeight - lineRenderTop,
575  240);
576  int screenY = fromY - lineRenderTop;
577  if (screenY < 0) {
578  displayY -= screenY;
579  fromY = lineRenderTop;
580  screenY = 0;
581  }
582  displayHeight = screenLimitY - screenY;
583  if (displayHeight <= 0) return;
584 
585  // Render sprites.
586  // TODO: Call different SpriteConverter methods depending on narrow/wide
587  // pixels in this display mode?
588  int spriteMode = vdp.getDisplayMode().getSpriteMode(vdp.isMSX1VDP());
589  int displayLimitX = displayX + displayWidth;
590  int limitY = fromY + displayHeight;
591  int screenX = translateX(
592  vdp.getLeftSprites(),
593  vdp.getDisplayMode().getLineWidth() == 512);
594  if (spriteMode == 1) {
595  for (int y = fromY; y < limitY; y++, screenY++) {
596  Pixel* pixelPtr = workFrame->getLinePtrDirect<Pixel>(screenY) + screenX;
597  spriteConverter.drawMode1(y, displayX, displayLimitX, pixelPtr);
598  }
599  } else {
600  byte mode = vdp.getDisplayMode().getByte();
601  if (mode == DisplayMode::GRAPHIC5) {
602  for (int y = fromY; y < limitY; y++, screenY++) {
603  Pixel* pixelPtr = workFrame->getLinePtrDirect<Pixel>(screenY) + screenX;
604  spriteConverter.template drawMode2<DisplayMode::GRAPHIC5>(
605  y, displayX, displayLimitX, pixelPtr);
606  }
607  } else if (mode == DisplayMode::GRAPHIC6) {
608  for (int y = fromY; y < limitY; y++, screenY++) {
609  Pixel* pixelPtr = workFrame->getLinePtrDirect<Pixel>(screenY) + screenX;
610  spriteConverter.template drawMode2<DisplayMode::GRAPHIC6>(
611  y, displayX, displayLimitX, pixelPtr);
612  }
613  } else {
614  for (int y = fromY; y < limitY; y++, screenY++) {
615  Pixel* pixelPtr = workFrame->getLinePtrDirect<Pixel>(screenY) + screenX;
616  spriteConverter.template drawMode2<DisplayMode::GRAPHIC4>(
617  y, displayX, displayLimitX, pixelPtr);
618  }
619  }
620  }
621 }
622 
623 template<typename Pixel>
625 {
626  return postProcessor->isRecording();
627 }
628 
629 template<typename Pixel>
630 void SDLRasterizer<Pixel>::update(const Setting& setting) noexcept
631 {
632  if (&setting == one_of(&renderSettings.getGammaSetting(),
633  &renderSettings.getBrightnessSetting(),
634  &renderSettings.getContrastSetting(),
635  &renderSettings.getColorMatrixSetting())) {
636  precalcPalette();
637  resetPalette();
638  }
639 }
640 
641 
642 // Force template instantiation.
643 #if HAVE_16BPP
644 template class SDLRasterizer<uint16_t>;
645 #endif
646 #if HAVE_32BPP || COMPONENT_GL
647 template class SDLRasterizer<uint32_t>;
648 #endif
649 
650 } // namespace openmsx
int g
Definition: one_of.hh:7
Represents a VDP display mode.
Definition: DisplayMode.hh:16
constexpr bool isPlanar() const
Is VRAM "planar" in the current display mode? Graphic 6 and 7 spread their bytes over two VRAM ICs,...
Definition: DisplayMode.hh:148
constexpr unsigned getLineWidth() const
Get number of pixels on a display line in this mode.
Definition: DisplayMode.hh:188
constexpr bool isBitmapMode() const
Is the current mode a bitmap mode? Graphic4 and higher are bitmap modes.
Definition: DisplayMode.hh:138
constexpr bool isTextMode() const
Is the current mode a text mode? Text1 and Text2 are text modes.
Definition: DisplayMode.hh:130
constexpr byte getByte() const
Get the dispay mode as a byte: YAE YJK M5..M1 combined.
Definition: DisplayMode.hh:101
Represents the output window/screen of openMSX.
Definition: Display.hh:33
@ FIELD_NONINTERLACED
Interlacing is off for this frame.
Definition: FrameSource.hh:22
@ FIELD_EVEN
Interlacing is on and this is an even frame.
Definition: FrameSource.hh:25
@ FIELD_ODD
Interlacing is on and this is an odd frame.
Definition: FrameSource.hh:28
A frame buffer where pixels can be written to.
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:14
StringSetting & getColorMatrixSetting()
Color matrix setting.
FloatSetting & getGammaSetting()
The amount of gamma correction.
FloatSetting & getBrightnessSetting()
Brightness video setting.
FloatSetting & getContrastSetting()
Contrast video setting.
static constexpr uint16_t GRAPHIC7_SPRITE_PALETTE[16]
Sprite palette in Graphic 7 mode.
Definition: Renderer.hh:185
Rasterizer using a frame buffer approach: it writes pixels to a single rectangular pixel buffer.
void setHorizontalScrollLow(byte scroll) override
void setDisplayMode(DisplayMode mode) override
Precalc several values that depend on the display mode.
void setTransparency(bool enabled) override
void setPalette(int index, int grb) override
Change an entry in the palette.
void setHorizontalAdjust(int adjust) override
void setBackgroundColor(int index) override
Changes the background color.
bool isRecording() const override
Is video recording active?
void drawDisplay(int fromX, int fromY, int displayX, int displayY, int displayWidth, int displayHeight) override
Render a rectangle of display pixels on the host screen.
void reset() override
Resynchronize with VDP: all cached states are flushed.
void drawBorder(int fromX, int fromY, int limitX, int limitY) override
Render a rectangle of border pixels on the host screen.
void setSuperimposeVideoFrame(const RawFrame *videoSource) override
void frameEnd() override
Indicates the end of the current frame.
void frameStart(EmuTime::param time) override
Indicates the start of a new frame.
void setBorderMask(bool masked) override
bool isActive() override
Will the output of this Rasterizer be displayed? There is no point in producing a frame that will not...
void drawSprites(int fromX, int fromY, int displayX, int displayY, int displayWidth, int displayHeight) override
Render a rectangle of sprite pixels on the host screen.
PostProcessor * getPostProcessor() const override
See VDP::getPostProcessor().
void attach(Observer< T > &observer)
Definition: Subject.hh:50
Unified implementation of MSX Video Display Processors (VDPs).
Definition: VDP.hh:63
static constexpr int TICKS_PER_LINE
Number of VDP clock ticks per line.
Definition: VDP.hh:72
bool isMSX1VDP() const
Is this an MSX1 VDP?
Definition: VDP.hh:93
constexpr auto enumerate(Iterable &&iterable)
Heavily inspired by Nathan Reed's blog post: Python-Like enumerate() In C++17 http://reedbeta....
Definition: enumerate.hh:28
Definition: gl_mat.hh:23
vecN< 3, float > vec3
Definition: gl_vec.hh:140
constexpr vecN< N, T > min(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:269
vecN< 3, int > ivec3
Definition: gl_vec.hh:143
constexpr vecN< N, T > max(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:287
This file implemented 3 utility functions:
Definition: Autofire.cc:5
uint32_t Pixel
constexpr int TICKS_LEFT_BORDER
VDP ticks between start of line and start of left border.
constexpr int TICKS_VISIBLE_MIDDLE
The middle of the visible (display + borders) part of a line, expressed in VDP ticks since the start ...
constexpr KeyMatrixPosition x
Keyboard bindings.
Definition: Keyboard.cc:124
constexpr auto xrange(T e)
Definition: xrange.hh:155