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 "MSXMotherBoard.hh"
6 #include "Display.hh"
7 #include "Renderer.hh"
8 #include "RenderSettings.hh"
9 #include "PostProcessor.hh"
10 #include "FloatSetting.hh"
11 #include "StringSetting.hh"
12 #include "MemoryOps.hh"
13 #include "VisibleSurface.hh"
14 #include "memory.hh"
15 #include "build-info.hh"
16 #include "components.hh"
17 #include <algorithm>
18 #include <cassert>
19 #include <cstdint>
20 
21 using namespace gl;
22 
23 namespace openmsx {
24 
27 static const int TICKS_LEFT_BORDER = 100 + 102;
28 
33 static const int TICKS_VISIBLE_MIDDLE =
34  TICKS_LEFT_BORDER + (VDP::TICKS_PER_LINE - TICKS_LEFT_BORDER - 27) / 2;
35 
42 static inline 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 <class Pixel>
58 inline void SDLRasterizer<Pixel>::renderBitmapLine(Pixel* buf, unsigned vramLine)
59 {
60  if (vdp.getDisplayMode().isPlanar()) {
61  const byte* vramPtr0;
62  const byte* vramPtr1;
63  vram.bitmapCacheWindow.getReadAreaPlanar(
64  vramLine * 256, 256, vramPtr0, vramPtr1);
65  bitmapConverter.convertLinePlanar(buf, vramPtr0, vramPtr1);
66  } else {
67  const byte* vramPtr =
68  vram.bitmapCacheWindow.getReadArea(vramLine * 128, 128);
69  bitmapConverter.convertLine(buf, vramPtr);
70  }
71 }
72 
73 template <class Pixel>
75  VDP& vdp_, Display& display, VisibleSurface& screen_,
76  std::unique_ptr<PostProcessor> postProcessor_)
77  : vdp(vdp_), vram(vdp.getVRAM())
78  , screen(screen_)
79  , postProcessor(std::move(postProcessor_))
80  , workFrame(make_unique<RawFrame>(screen.getSDLFormat(), 640, 240))
81  , renderSettings(display.getRenderSettings())
82  , characterConverter(vdp, palFg, palBg)
83  , bitmapConverter(palFg, PALETTE256, V9958_COLORS)
84  , spriteConverter(vdp.getSpriteChecker())
85 {
86  // Init the palette.
87  precalcPalette();
88 
89  // Initialize palette (avoid UMR)
90  if (!vdp.isMSX1VDP()) {
91  for (int i = 0; i < 16; ++i) {
92  palFg[i] = palFg[i + 16] = palBg[i] =
93  V9938_COLORS[0][0][0];
94  }
95  }
96 
97  renderSettings.getGammaSetting() .attach(*this);
98  renderSettings.getBrightnessSetting() .attach(*this);
99  renderSettings.getContrastSetting() .attach(*this);
100  renderSettings.getColorMatrixSetting().attach(*this);
101 }
102 
103 template <class Pixel>
105 {
106  renderSettings.getColorMatrixSetting().detach(*this);
107  renderSettings.getGammaSetting() .detach(*this);
108  renderSettings.getBrightnessSetting() .detach(*this);
109  renderSettings.getContrastSetting() .detach(*this);
110 }
111 
112 template <class Pixel>
114 {
115  return postProcessor.get();
116 }
117 
118 template <class Pixel>
120 {
121  return postProcessor->needRender() &&
122  vdp.getMotherBoard().isActive() &&
124 }
125 
126 template <class Pixel>
128 {
129  // Init renderer state.
131  spriteConverter.setTransparency(vdp.getTransparency());
132 
133  resetPalette();
134 }
135 
136 template <class Pixel>
138 {
139  if (!vdp.isMSX1VDP()) {
140  // Reset the palette.
141  for (int i = 0; i < 16; i++) {
142  setPalette(i, vdp.getPalette(i));
143  }
144  }
145 }
146 
147 template<class Pixel>
149 {
150  postProcessor->setSuperimposeVideoFrame(videoSource);
151  precalcColorIndex0(vdp.getDisplayMode(), vdp.getTransparency(),
152  videoSource, vdp.getBackgroundColor());
153 }
154 
155 template <class Pixel>
157 {
158  workFrame = postProcessor->rotateFrames(std::move(workFrame), time);
159  workFrame->init(
163 
164  // Calculate line to render at top of screen.
165  // Make sure the display area is centered.
166  // 240 - 212 = 28 lines available for top/bottom border; 14 each.
167  // NTSC: display at [32..244),
168  // PAL: display at [59..271).
169  lineRenderTop = vdp.isPalTiming() ? 59 - 14 : 32 - 14;
170 
171 
172  // We haven't drawn any left/right borders yet this frame, thus so far
173  // all is still consistent (same settings for all left/right borders).
174  mixedLeftRightBorders = false;
175 
176  auto& borderInfo = workFrame->getBorderInfo();
177  Pixel color0, color1;
178  getBorderColors(color0, color1);
179  canSkipLeftRightBorders =
180  (borderInfo.mode == vdp.getDisplayMode().getByte()) &&
181  (borderInfo.color0 == color0) &&
182  (borderInfo.color1 == color1) &&
183  (borderInfo.adjust == vdp.getHorizontalAdjust()) &&
184  (borderInfo.scroll == vdp.getHorizontalScrollLow()) &&
185  (borderInfo.masked == vdp.isBorderMasked());
186 }
187 
188 template <class Pixel>
190 {
191  auto& borderInfo = workFrame->getBorderInfo();
192  if (mixedLeftRightBorders) {
193  // This frame contains left/right borders drawn with different
194  // settings. So don't use it as a starting point for future
195  // border drawing optimizations.
196  borderInfo.mode = 0xff; // invalid mode, other fields don't matter
197  } else {
198  // All left/right borders in this frame are uniform (drawn with
199  // the same settings). If in a later frame the border-related
200  // settings are still the same, we can skip drawing borders.
201  Pixel color0, color1;
202  getBorderColors(color0, color1);
203  borderInfo.mode = vdp.getDisplayMode().getByte();
204  borderInfo.color0 = color0;
205  borderInfo.color1 = color1;
206  borderInfo.adjust = vdp.getHorizontalAdjust();
207  borderInfo.scroll = vdp.getHorizontalScrollLow();
208  borderInfo.masked = vdp.isBorderMasked();
209  }
210 }
211 
212 template <class Pixel>
214 {
215  // Can no longer use the skip-border drawing optimization this frame.
216  canSkipLeftRightBorders = false;
217 
218  // Cannot use this frame as a starting point for future skip-border
219  // optimizations.
220  mixedLeftRightBorders = true;
221 }
222 
223 template <class Pixel>
225 {
226  if (mode.isBitmapMode()) {
227  bitmapConverter.setDisplayMode(mode);
228  } else {
229  characterConverter.setDisplayMode(mode);
230  }
231  precalcColorIndex0(mode, vdp.getTransparency(),
232  vdp.isSuperimposing(), vdp.getBackgroundColor());
233  spriteConverter.setDisplayMode(mode);
234  spriteConverter.setPalette(mode.getByte() == DisplayMode::GRAPHIC7
235  ? palGraphic7Sprites : palBg);
236 
237  borderSettingChanged();
238 }
239 
240 template <class Pixel>
241 void SDLRasterizer<Pixel>::setPalette(int index, int grb)
242 {
243  // Update SDL colors in palette.
244  Pixel newColor = V9938_COLORS[(grb >> 4) & 7][grb >> 8][grb & 7];
245  palFg[index ] = newColor;
246  palFg[index + 16] = newColor;
247  palBg[index ] = newColor;
248  bitmapConverter.palette16Changed();
249 
250  precalcColorIndex0(vdp.getDisplayMode(), vdp.getTransparency(),
251  vdp.isSuperimposing(), vdp.getBackgroundColor());
252  borderSettingChanged();
253 }
254 
255 template <class Pixel>
257 {
259  precalcColorIndex0(vdp.getDisplayMode(), vdp.getTransparency(),
260  vdp.isSuperimposing(), index);
261  }
262  borderSettingChanged();
263 }
264 
265 template <class Pixel>
267 {
268  borderSettingChanged();
269 }
270 
271 template <class Pixel>
273 {
274  borderSettingChanged();
275 }
276 
277 template <class Pixel>
279 {
280  borderSettingChanged();
281 }
282 
283 template <class Pixel>
285 {
286  spriteConverter.setTransparency(enabled);
287  precalcColorIndex0(vdp.getDisplayMode(), enabled,
288  vdp.isSuperimposing(), vdp.getBackgroundColor());
289 }
290 
291 template <class Pixel>
293 {
294  if (vdp.isMSX1VDP()) {
295  // Fixed palette.
296  const auto palette = vdp.getMSX1Palette();
297  for (int i = 0; i < 16; ++i) {
298  const auto rgb = palette[i];
299  palFg[i] = palFg[i + 16] = palBg[i] =
300  screen.mapKeyedRGB<Pixel>(
301  renderSettings.transformRGB(
302  vec3(rgb[0], rgb[1], rgb[2]) / 255.0f));
303  }
304  } else {
305  if (vdp.hasYJK()) {
306  // Precalculate palette for V9958 colors.
307  if (renderSettings.isColorMatrixIdentity()) {
308  // Most users use the "normal" monitor type; making this a
309  // special case speeds up palette precalculation a lot.
310  int intensity[32];
311  for (int i = 0; i < 32; ++i) {
312  intensity[i] =
313  int(255 * renderSettings.transformComponent(i / 31.0));
314  }
315  for (int rgb = 0; rgb < (1 << 15); ++rgb) {
316  V9958_COLORS[rgb] = screen.mapKeyedRGB255<Pixel>(ivec3(
317  intensity[(rgb >> 10) & 31],
318  intensity[(rgb >> 5) & 31],
319  intensity[(rgb >> 0) & 31]));
320  }
321  } else {
322  for (int r = 0; r < 32; ++r) {
323  for (int g = 0; g < 32; ++g) {
324  for (int b = 0; b < 32; ++b) {
325  V9958_COLORS[(r << 10) + (g << 5) + b] =
326  screen.mapKeyedRGB<Pixel>(
327  renderSettings.transformRGB(
328  vec3(r, g, b) / 31.0f));
329  }
330  }
331  }
332  }
333  // Precalculate palette for V9938 colors.
334  // Based on comparing red and green gradients, using palette and
335  // YJK, in SCREEN11 on a real turbo R.
336  for (int r3 = 0; r3 < 8; ++r3) {
337  int r5 = (r3 << 2) | (r3 >> 1);
338  for (int g3 = 0; g3 < 8; ++g3) {
339  int g5 = (g3 << 2) | (g3 >> 1);
340  for (int b3 = 0; b3 < 8; ++b3) {
341  int b5 = (b3 << 2) | (b3 >> 1);
342  V9938_COLORS[r3][g3][b3] =
343  V9958_COLORS[(r5 << 10) + (g5 << 5) + b5];
344  }
345  }
346  }
347  } else {
348  // Precalculate palette for V9938 colors.
349  if (renderSettings.isColorMatrixIdentity()) {
350  int intensity[8];
351  for (int i = 0; i < 8; ++i) {
352  intensity[i] =
353  int(255 * renderSettings.transformComponent(i / 7.0f));
354  }
355  for (int r = 0; r < 8; ++r) {
356  for (int g = 0; g < 8; ++g) {
357  for (int b = 0; b < 8; ++b) {
358  V9938_COLORS[r][g][b] =
359  screen.mapKeyedRGB255<Pixel>(ivec3(
360  intensity[r],
361  intensity[g],
362  intensity[b]));
363  }
364  }
365  }
366  } else {
367  for (int r = 0; r < 8; ++r) {
368  for (int g = 0; g < 8; ++g) {
369  for (int b = 0; b < 8; ++b) {
370  V9938_COLORS[r][g][b] =
371  screen.mapKeyedRGB<Pixel>(
372  renderSettings.transformRGB(
373  vec3(r, g, b) / 7.0f));;
374  }
375  }
376  }
377  }
378  }
379  // Precalculate Graphic 7 bitmap palette.
380  for (int i = 0; i < 256; ++i) {
381  PALETTE256[i] = V9938_COLORS
382  [(i & 0x1C) >> 2]
383  [(i & 0xE0) >> 5]
384  [(i & 0x03) == 3 ? 7 : (i & 0x03) * 2];
385  }
386  // Precalculate Graphic 7 sprite palette.
387  for (int i = 0; i < 16; ++i) {
388  uint16_t grb = Renderer::GRAPHIC7_SPRITE_PALETTE[i];
389  palGraphic7Sprites[i] =
390  V9938_COLORS[(grb >> 4) & 7][grb >> 8][grb & 7];
391  }
392  }
393 }
394 
395 template <class Pixel>
397  bool transparency, const RawFrame* superimposing, byte bgcolorIndex)
398 {
399  // Graphic7 mode doesn't use transparency.
400  if (mode.getByte() == DisplayMode::GRAPHIC7) {
401  transparency = false;
402  }
403 
404  int tpIndex = transparency ? bgcolorIndex : 0;
405  if (mode.getBase() != DisplayMode::GRAPHIC5) {
406  Pixel c = (superimposing && (bgcolorIndex == 0))
407  ? screen.getKeyColor<Pixel>()
408  : palBg[tpIndex];
409 
410  if (palFg[0] != c) {
411  palFg[0] = c;
412  bitmapConverter.palette16Changed();
413  }
414  } else {
415  // TODO: superimposing
416  if ((palFg[ 0] != palBg[tpIndex >> 2]) ||
417  (palFg[16] != palBg[tpIndex & 3])) {
418  palFg[ 0] = palBg[tpIndex >> 2];
419  palFg[16] = palBg[tpIndex & 3];
420  bitmapConverter.palette16Changed();
421  }
422  }
423 }
424 
425 template <class Pixel>
426 void SDLRasterizer<Pixel>::getBorderColors(Pixel& border0, Pixel& border1)
427 {
428  DisplayMode mode = vdp.getDisplayMode();
429  int bgColor = vdp.getBackgroundColor();
430  if (mode.getBase() == DisplayMode::GRAPHIC5) {
431  // border in SCREEN6 has separate color for even and odd pixels.
432  // TODO odd/even swapped?
433  border0 = palBg[(bgColor & 0x0C) >> 2];
434  border1 = palBg[(bgColor & 0x03) >> 0];
435  } else if (mode.getByte() == DisplayMode::GRAPHIC7) {
436  border0 = border1 = PALETTE256[bgColor];
437  } else {
438  if (!bgColor && vdp.isSuperimposing()) {
439  border0 = border1 = screen.getKeyColor<Pixel>();
440  } else {
441  border0 = border1 = palBg[bgColor];
442  }
443  }
444 }
445 
446 template <class Pixel>
448  int fromX, int fromY, int limitX, int limitY)
449 {
450  Pixel border0, border1;
451  getBorderColors(border0, border1);
452 
453  int startY = std::max(fromY - lineRenderTop, 0);
454  int endY = std::min(limitY - lineRenderTop, 240);
455  if ((fromX == 0) && (limitX == VDP::TICKS_PER_LINE) &&
456  (border0 == border1)) {
457  // complete lines, non striped
458  for (int y = startY; y < endY; y++) {
459  workFrame->setBlank(y, border0);
460  // setBlank() implies this line is not suitable
461  // for left/right border optimization in a later
462  // frame.
463  }
464  } else {
465  unsigned lineWidth = vdp.getDisplayMode().getLineWidth();
466  unsigned x = translateX(fromX, (lineWidth == 512));
467  unsigned num = translateX(limitX, (lineWidth == 512)) - x;
468  unsigned width = (lineWidth == 512) ? 640 : 320;
470  for (int y = startY; y < endY; ++y) {
471  // workFrame->linewidth != 1 means the line has
472  // left/right borders.
473  if (canSkipLeftRightBorders &&
474  (workFrame->getLineWidthDirect(y) != 1)) continue;
475  memset(workFrame->getLinePtrDirect<Pixel>(y) + x,
476  num, border0, border1);
477  if (limitX == VDP::TICKS_PER_LINE) {
478  // Only set line width at the end (right
479  // border) of the line. This ensures we can
480  // keep testing the width of the previous
481  // version of this line for all (partial)
482  // updates of this line.
483  workFrame->setLineWidth(y, width);
484  }
485  }
486  }
487 }
488 
489 template <class Pixel>
491  int /*fromX*/, int fromY,
492  int displayX, int displayY,
493  int displayWidth, int displayHeight)
494 {
495  // Note: we don't call workFrame->setLineWidth() because that's done in
496  // drawBorder() (for the right border). And the value we set there is
497  // anyway the same as the one we would set here.
498  DisplayMode mode = vdp.getDisplayMode();
499  unsigned lineWidth = mode.getLineWidth();
500  if (lineWidth == 256) {
501  int endX = displayX + displayWidth;
502  displayX /= 2;
503  displayWidth = endX / 2 - displayX;
504  }
505 
506  // Clip to screen area.
507  int screenLimitY = std::min(
508  fromY + displayHeight - lineRenderTop,
509  240);
510  int screenY = fromY - lineRenderTop;
511  if (screenY < 0) {
512  displayY -= screenY;
513  fromY = lineRenderTop;
514  screenY = 0;
515  }
516  displayHeight = screenLimitY - screenY;
517  if (displayHeight <= 0) return;
518 
519  int leftBackground =
520  translateX(vdp.getLeftBackground(), lineWidth == 512);
521  // TODO: Find out why this causes 1-pixel jitter:
522  //dest.x = translateX(fromX);
523  int hScroll =
524  mode.isTextMode()
525  ? 0
526  : 8 * (lineWidth / 256) * (vdp.getHorizontalScrollHigh() & 0x1F);
527 
528  // Page border is display X coordinate where to stop drawing current page.
529  // This is either the multi page split point, or the right edge of the
530  // rectangle to draw, whichever comes first.
531  // Note that it is possible for pageBorder to be to the left of displayX,
532  // in that case only the second page should be drawn.
533  int pageBorder = displayX + displayWidth;
534  int scrollPage1, scrollPage2;
535  if (vdp.isMultiPageScrolling()) {
536  scrollPage1 = vdp.getHorizontalScrollHigh() >> 5;
537  scrollPage2 = scrollPage1 ^ 1;
538  } else {
539  scrollPage1 = 0;
540  scrollPage2 = 0;
541  }
542  // Because SDL blits do not wrap, unlike GL textures, the pageBorder is
543  // also used if multi page is disabled.
544  int pageSplit = lineWidth - hScroll;
545  if (pageSplit < pageBorder) {
546  pageBorder = pageSplit;
547  }
548 
549  if (mode.isBitmapMode()) {
550  // Which bits in the name mask determine the page?
551  int pageMaskOdd = (mode.isPlanar() ? 0x000 : 0x200) |
552  vdp.getEvenOddMask();
553  int pageMaskEven = vdp.isMultiPageScrolling()
554  ? (pageMaskOdd & ~0x100)
555  : pageMaskOdd;
556 
557  for (int y = screenY; y < screenLimitY; y++) {
558  const int vramLine[2] = {
559  (vram.nameTable.getMask() >> 7) & (pageMaskEven | displayY),
560  (vram.nameTable.getMask() >> 7) & (pageMaskOdd | displayY)
561  };
562 
563  Pixel buf[512];
564  int lineInBuf = -1; // buffer data not valid
565  Pixel* dst = workFrame->getLinePtrDirect<Pixel>(y)
566  + leftBackground + displayX;
567  int firstPageWidth = pageBorder - displayX;
568  if (firstPageWidth > 0) {
569  if ((displayX + hScroll) == 0) {
570  renderBitmapLine(dst, vramLine[scrollPage1]);
571  } else {
572  lineInBuf = vramLine[scrollPage1];
573  renderBitmapLine(buf, vramLine[scrollPage1]);
574  const Pixel* src = buf + displayX + hScroll;
575  memcpy(dst, src, firstPageWidth * sizeof(Pixel));
576  }
577  } else {
578  firstPageWidth = 0;
579  }
580  if (firstPageWidth < displayWidth) {
581  if (lineInBuf != vramLine[scrollPage2]) {
582  renderBitmapLine(buf, vramLine[scrollPage2]);
583  }
584  unsigned x = displayX < pageBorder
585  ? 0 : displayX + hScroll - lineWidth;
586  memcpy(dst + firstPageWidth,
587  buf + x,
588  (displayWidth - firstPageWidth) * sizeof(Pixel));
589  }
590 
591  displayY = (displayY + 1) & 255;
592  }
593  } else {
594  // horizontal scroll (high) is implemented in CharacterConverter
595  for (int y = screenY; y < screenLimitY; y++) {
596  assert(!vdp.isMSX1VDP() || displayY < 192);
597 
598  Pixel* dst = workFrame->getLinePtrDirect<Pixel>(y)
599  + leftBackground + displayX;
600  if (displayX == 0) {
601  characterConverter.convertLine(dst, displayY);
602  } else {
603  Pixel buf[512];
604  characterConverter.convertLine(buf, displayY);
605  const Pixel* src = buf + displayX;
606  memcpy(dst, src, displayWidth * sizeof(Pixel));
607  }
608 
609  displayY = (displayY + 1) & 255;
610  }
611  }
612 }
613 
614 template <class Pixel>
616  int /*fromX*/, int fromY,
617  int displayX, int displayY,
618  int displayWidth, int displayHeight)
619 {
620  // Clip to screen area.
621  // TODO: Code duplicated from drawDisplay.
622  int screenLimitY = std::min(
623  fromY + displayHeight - lineRenderTop,
624  240);
625  int screenY = fromY - lineRenderTop;
626  if (screenY < 0) {
627  displayY -= screenY;
628  fromY = lineRenderTop;
629  screenY = 0;
630  }
631  displayHeight = screenLimitY - screenY;
632  if (displayHeight <= 0) return;
633 
634  // Render sprites.
635  // TODO: Call different SpriteConverter methods depending on narrow/wide
636  // pixels in this display mode?
637  int spriteMode = vdp.getDisplayMode().getSpriteMode(vdp.isMSX1VDP());
638  int displayLimitX = displayX + displayWidth;
639  int limitY = fromY + displayHeight;
640  int screenX = translateX(
641  vdp.getLeftSprites(),
642  vdp.getDisplayMode().getLineWidth() == 512);
643  if (spriteMode == 1) {
644  for (int y = fromY; y < limitY; y++, screenY++) {
645  Pixel* pixelPtr = workFrame->getLinePtrDirect<Pixel>(screenY) + screenX;
646  spriteConverter.drawMode1(y, displayX, displayLimitX, pixelPtr);
647  }
648  } else {
649  byte mode = vdp.getDisplayMode().getByte();
650  if (mode == DisplayMode::GRAPHIC5) {
651  for (int y = fromY; y < limitY; y++, screenY++) {
652  Pixel* pixelPtr = workFrame->getLinePtrDirect<Pixel>(screenY) + screenX;
653  spriteConverter.template drawMode2<DisplayMode::GRAPHIC5>(
654  y, displayX, displayLimitX, pixelPtr);
655  }
656  } else if (mode == DisplayMode::GRAPHIC6) {
657  for (int y = fromY; y < limitY; y++, screenY++) {
658  Pixel* pixelPtr = workFrame->getLinePtrDirect<Pixel>(screenY) + screenX;
659  spriteConverter.template drawMode2<DisplayMode::GRAPHIC6>(
660  y, displayX, displayLimitX, pixelPtr);
661  }
662  } else {
663  for (int y = fromY; y < limitY; y++, screenY++) {
664  Pixel* pixelPtr = workFrame->getLinePtrDirect<Pixel>(screenY) + screenX;
665  spriteConverter.template drawMode2<DisplayMode::GRAPHIC4>(
666  y, displayX, displayLimitX, pixelPtr);
667  }
668  }
669  }
670 }
671 
672 template <class Pixel>
674 {
675  return postProcessor->isRecording();
676 }
677 
678 template <class Pixel>
679 void SDLRasterizer<Pixel>::update(const Setting& setting)
680 {
681  if ((&setting == &renderSettings.getGammaSetting()) ||
682  (&setting == &renderSettings.getBrightnessSetting()) ||
683  (&setting == &renderSettings.getContrastSetting()) ||
684  (&setting == &renderSettings.getColorMatrixSetting())) {
685  precalcPalette();
686  resetPalette();
687  }
688 }
689 
690 
691 // Force template instantiation.
692 #if HAVE_16BPP
693 template class SDLRasterizer<uint16_t>;
694 #endif
695 #if HAVE_32BPP || COMPONENT_GL
696 template class SDLRasterizer<uint32_t>;
697 #endif
698 
699 } // namespace openmsx
FloatSetting & getBrightnessSetting()
Brightness video setting.
bool isBorderMasked() const
Gets the current border mask setting.
Definition: VDP.hh:296
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:159
Pixel mapKeyedRGB255(gl::ivec3 rgb)
Returns the pixel value for the given RGB color.
void setPalette(int index, int grb) override
Change an entry in the palette.
Pixel mapKeyedRGB(gl::vec3 rgb)
Returns the pixel value for the given RGB color.
Represents the output window/screen of openMSX.
Definition: Display.hh:31
int getHorizontalAdjust() const
This is a combination of the (horizontal) set adjust register and the YJK-mode bit.
Definition: VDP.hh:428
static const int TICKS_PER_LINE
Number of VDP clock ticks per line.
Definition: VDP.hh:72
void setBackgroundColor(int index) override
Changes the background color.
Interlacing is on and this is an odd frame.
Definition: FrameSource.hh:28
bool isMultiPageScrolling() const
Is multi page scrolling enabled? It is considered enabled if both the multi page scrolling flag is en...
Definition: VDP.hh:306
vecN< N, T > min(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:257
bool isBitmapMode() const
Is the current mode a bitmap mode? Graphic4 and higher are bitmap modes.
Definition: DisplayMode.hh:149
FloatSetting & getGammaSetting()
The amount of gamma correction.
void reset() override
Resynchronize with VDP: all cached states are flushed.
DisplayMode getDisplayMode() const
Get the display mode the VDP is in.
Definition: VDP.hh:141
Rasterizer using a frame buffer approach: it writes pixels to a single rectangular pixel buffer...
uint8_t byte
8 bit unsigned integer
Definition: openmsx.hh:26
int getSpriteMode(bool isMSX1) const
Get the sprite mode of this display mode.
Definition: DisplayMode.hh:177
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.
int getLeftSprites() const
Gets the number of VDP clockticks between start of line and the start of the sprite plane...
Definition: VDP.hh:439
STL namespace.
Represents a VDP display mode.
Definition: DisplayMode.hh:14
VRAMWindow nameTable
Definition: VDPVRAM.hh:657
byte getHorizontalScrollHigh() const
Gets the current horizontal scroll higher bits.
Definition: VDP.hh:287
uint32_t Pixel
bool isActive() override
Will the output of this Rasterizer be displayed? There is no point in producing a frame that will not...
vecN< N, T > max(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:266
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:467
const RawFrame * isSuperimposing() const
Are we currently superimposing? In case of superimpose, returns a pointer to the to-be-superimposed f...
Definition: VDP.hh:155
FloatSetting & getContrastSetting()
Contrast video setting.
Pixel getKeyColor() const
Returns the color key for this output surface.
void attach(Observer< T > &observer)
Definition: Subject.hh:52
vecN< 3, int > ivec3
Definition: gl_vec.hh:131
int getEvenOddMask() const
Expresses the state of even/odd page interchange in a mask on the line number.
Definition: VDP.hh:369
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.
StringSetting & getColorMatrixSetting()
Color matrix setting.
bool isInterlaced() const
Get interlace status.
Definition: VDP.hh:333
A video frame as output by the VDP scanline conversion unit, before any postprocessing filters are ap...
Definition: RawFrame.hh:25
bool isRecording() const override
Is video recording active?
int getMask() const
Gets the mask for this window.
Definition: VDPVRAM.hh:146
bool isTextMode() const
Is the current mode a text mode? Text1 and Text2 are text modes.
Definition: DisplayMode.hh:138
MSXMotherBoard & getMotherBoard() const
Get the mother board this device belongs to.
Definition: MSXDevice.cc:78
bool getTransparency() const
Gets the current transparency setting.
Definition: VDP.hh:174
void drawBorder(int fromX, int fromY, int limitX, int limitY) override
Render a rectangle of border pixels on the host screen.
gl::vec3 transformRGB(gl::vec3 rgb) const
Apply brightness, contrast and gamma transformation on the input color.
void setHorizontalScrollLow(byte scroll) override
bool isMSX1VDP() const
Is this an MSX1 VDP?
Definition: VDP.hh:93
bool isColorMatrixIdentity()
Returns true iff the current color matrix is the identity matrix.
An OutputSurface which is visible to the user, such as a window or a full screen display.
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
void setTransparency(bool enabled) override
Interlacing is on and this is an even frame.
Definition: FrameSource.hh:25
void setHorizontalAdjust(int adjust) override
byte getByte() const
Get the dispay mode as a byte: YAE YJK M5..M1 combined.
Definition: DisplayMode.hh:109
bool getEvenOdd() const
Is the even or odd field being displayed?
Definition: VDP.hh:355
bool isFastForwarding() const
void setDisplayMode(DisplayMode mode) override
Precalc several values that depend on the display mode.
Unified implementation of MSX Video Display Processors (VDPs).
Definition: VDP.hh:61
Interlacing is off for this frame.
Definition: FrameSource.hh:22
Abstract base class for post processors.
byte getHorizontalScrollLow() const
Gets the current horizontal scroll lower bits.
Definition: VDP.hh:278
const std::array< std::array< uint8_t, 3 >, 16 > getMSX1Palette() const
Get the (fixed) palette for this MSX1 VDP.
Definition: VDP.cc:1452
vecN< 3, float > vec3
Definition: gl_vec.hh:128
bool isPalTiming() const
Is PAL timing active? This setting is fixed at start of frame.
Definition: VDP.hh:322
bool hasYJK() const
Does this VDP support YJK display?
Definition: VDP.hh:128
static const uint16_t GRAPHIC7_SPRITE_PALETTE[16]
Sprite palette in Graphic 7 mode.
Definition: Renderer.hh:184
void detach(Observer< T > &observer)
Definition: Subject.hh:58
byte getBase() const
Get the base dispay mode as an integer: M5..M1 combined.
Definition: DisplayMode.hh:123
float transformComponent(float c) const
Apply brightness, contrast and gamma transformation on the input color component. ...
unsigned getLineWidth() const
Get number of pixels on a display line in this mode.
Definition: DisplayMode.hh:199
word getPalette(int index) const
Gets a palette entry.
Definition: VDP.hh:228
Definition: gl_mat.hh:23
std::unique_ptr< T > make_unique()
Definition: memory.hh:27
void setBorderMask(bool masked) override
void frameStart(EmuTime::param time) override
Indicates the start of a new frame.
void frameEnd() override
Indicates the end of the current frame.
void setSuperimposeVideoFrame(const RawFrame *videoSource) override
PostProcessor * getPostProcessor() const override
See VDP::getPostProcessor().
int getBackgroundColor() const
Gets the current background color.
Definition: VDP.hh:193