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
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
unsigned getLineWidth() const
Get number of pixels on a display line in this mode.
Definition: DisplayMode.hh:199
FloatSetting & getBrightnessSetting()
Brightness video setting.
word getPalette(int index) const
Gets a palette entry.
Definition: VDP.hh:228
bool getEvenOdd() const
Is the even or odd field being displayed?
Definition: VDP.hh:355
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:32
static const int TICKS_PER_LINE
Number of VDP clock ticks per line.
Definition: VDP.hh:72
byte getByte() const
Get the dispay mode as a byte: YAE YJK M5..M1 combined.
Definition: DisplayMode.hh:109
void setBackgroundColor(int index) override
Changes the background color.
Interlacing is on and this is an odd frame.
Definition: FrameSource.hh:28
vecN< N, T > min(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:257
FloatSetting & getGammaSetting()
The amount of gamma correction.
void reset() override
Resynchronize with VDP: all cached states are flushed.
Rasterizer using a frame buffer approach: it writes pixels to a single rectangular pixel buffer...
bool isFastForwarding() const
uint8_t byte
8 bit unsigned integer
Definition: openmsx.hh:26
DisplayMode getDisplayMode() const
Get the display mode the VDP is in.
Definition: VDP.hh:141
bool isPalTiming() const
Is PAL timing active? This setting is fixed at start of frame.
Definition: VDP.hh:322
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.
STL namespace.
int getEvenOddMask() const
Expresses the state of even/odd page interchange in a mask on the line number.
Definition: VDP.hh:369
byte getHorizontalScrollLow() const
Gets the current horizontal scroll lower bits.
Definition: VDP.hh:278
Represents a VDP display mode.
Definition: DisplayMode.hh:14
int getHorizontalAdjust() const
This is a combination of the (horizontal) set adjust register and the YJK-mode bit.
Definition: VDP.hh:428
VRAMWindow nameTable
Definition: VDPVRAM.hh:657
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
bool isTextMode() const
Is the current mode a text mode? Text1 and Text2 are text modes.
Definition: DisplayMode.hh:138
bool hasYJK() const
Does this VDP support YJK display?
Definition: VDP.hh:128
const std::array< std::array< uint8_t, 3 >, 16 > getMSX1Palette() const
Get the (fixed) palette for this MSX1 VDP.
Definition: VDP.cc:1452
FloatSetting & getContrastSetting()
Contrast video setting.
int getSpriteMode(bool isMSX1) const
Get the sprite mode of this display mode.
Definition: DisplayMode.hh:177
int getBackgroundColor() const
Gets the current background color.
Definition: VDP.hh:193
void attach(Observer< T > &observer)
Definition: Subject.hh:52
vecN< 3, int > ivec3
Definition: gl_vec.hh:131
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
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.
byte getHorizontalScrollHigh() const
Gets the current horizontal scroll higher bits.
Definition: VDP.hh:287
bool isBorderMasked() const
Gets the current border mask setting.
Definition: VDP.hh:296
StringSetting & getColorMatrixSetting()
Color matrix setting.
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?
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
void drawBorder(int fromX, int fromY, int limitX, int limitY) override
Render a rectangle of border pixels on the host screen.
void setHorizontalScrollLow(byte scroll) override
int getLeftSprites() const
Gets the number of VDP clockticks between start of line and the start of the sprite plane...
Definition: VDP.hh:439
bool getTransparency() const
Gets the current transparency setting.
Definition: VDP.hh:174
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.
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
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
MSXMotherBoard & getMotherBoard() const
Get the mother board this device belongs to.
Definition: MSXDevice.cc:78
void setHorizontalAdjust(int adjust) override
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.
float transformComponent(float c) const
Apply brightness, contrast and gamma transformation on the input color component. ...
vecN< 3, float > vec3
Definition: gl_vec.hh:128
gl::vec3 transformRGB(gl::vec3 rgb) const
Apply brightness, contrast and gamma transformation on the input color.
static const uint16_t GRAPHIC7_SPRITE_PALETTE[16]
Sprite palette in Graphic 7 mode.
Definition: Renderer.hh:184
int getMask() const
Gets the mask for this window.
Definition: VDPVRAM.hh:146
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
bool isBitmapMode() const
Is the current mode a bitmap mode? Graphic4 and higher are bitmap modes.
Definition: DisplayMode.hh:149
bool isInterlaced() const
Get interlace status.
Definition: VDP.hh:333
Definition: gl_mat.hh:23
std::unique_ptr< T > make_unique()
Definition: memory.hh:27
Pixel getKeyColor() const
Returns the color key for this output surface.
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().