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 
36 template <class Pixel>
37 inline int SDLRasterizer<Pixel>::translateX(int absoluteX, bool narrow)
38 {
39  int maxX = narrow ? 640 : 320;
40  if (absoluteX == VDP::TICKS_PER_LINE) return maxX;
41 
42  // Note: The ROUND_MASK forces the ticks to a pixel (2-tick) boundary.
43  // If this is not done, rounding errors will occur.
44  // This is especially tricky because division of a negative number
45  // is rounded towards zero instead of down.
46  const int ROUND_MASK = narrow ? ~1 : ~3;
47  int screenX =
48  ((absoluteX & ROUND_MASK) - (TICKS_VISIBLE_MIDDLE & ROUND_MASK))
49  / (narrow ? 2 : 4)
50  + maxX / 2;
51  return std::max(screenX, 0);
52 }
53 
54 template <class Pixel>
55 inline void SDLRasterizer<Pixel>::renderBitmapLine(Pixel* buf, unsigned vramLine)
56 {
57  if (vdp.getDisplayMode().isPlanar()) {
58  const byte* vramPtr0;
59  const byte* vramPtr1;
60  vram.bitmapCacheWindow.getReadAreaPlanar(
61  vramLine * 256, 256, vramPtr0, vramPtr1);
62  bitmapConverter.convertLinePlanar(buf, vramPtr0, vramPtr1);
63  } else {
64  const byte* vramPtr =
65  vram.bitmapCacheWindow.getReadArea(vramLine * 128, 128);
66  bitmapConverter.convertLine(buf, vramPtr);
67  }
68 }
69 
70 template <class Pixel>
72  VDP& vdp_, Display& display, VisibleSurface& screen_,
73  std::unique_ptr<PostProcessor> postProcessor_)
74  : vdp(vdp_), vram(vdp.getVRAM())
75  , screen(screen_)
76  , postProcessor(std::move(postProcessor_))
77  , workFrame(make_unique<RawFrame>(screen.getSDLFormat(), 640, 240))
78  , renderSettings(display.getRenderSettings())
79  , characterConverter(vdp, palFg, palBg)
80  , bitmapConverter(palFg, PALETTE256, V9958_COLORS)
81  , spriteConverter(vdp.getSpriteChecker())
82 {
83  // Init the palette.
84  precalcPalette();
85 
86  // Initialize palette (avoid UMR)
87  if (!vdp.isMSX1VDP()) {
88  for (int i = 0; i < 16; ++i) {
89  palFg[i] = palFg[i + 16] = palBg[i] =
90  V9938_COLORS[0][0][0];
91  }
92  }
93 
94  renderSettings.getGammaSetting() .attach(*this);
95  renderSettings.getBrightnessSetting() .attach(*this);
96  renderSettings.getContrastSetting() .attach(*this);
97  renderSettings.getColorMatrixSetting().attach(*this);
98 }
99 
100 template <class Pixel>
102 {
103  renderSettings.getColorMatrixSetting().detach(*this);
104  renderSettings.getGammaSetting() .detach(*this);
105  renderSettings.getBrightnessSetting() .detach(*this);
106  renderSettings.getContrastSetting() .detach(*this);
107 }
108 
109 template <class Pixel>
111 {
112  return postProcessor.get();
113 }
114 
115 template <class Pixel>
117 {
118  return postProcessor->needRender() &&
119  vdp.getMotherBoard().isActive() &&
121 }
122 
123 template <class Pixel>
125 {
126  // Init renderer state.
128  spriteConverter.setTransparency(vdp.getTransparency());
129 
130  resetPalette();
131 }
132 
133 template <class Pixel>
135 {
136  if (!vdp.isMSX1VDP()) {
137  // Reset the palette.
138  for (int i = 0; i < 16; i++) {
139  setPalette(i, vdp.getPalette(i));
140  }
141  }
142 }
143 
144 template<class Pixel>
146 {
147  postProcessor->setSuperimposeVideoFrame(videoSource);
148  precalcColorIndex0(vdp.getDisplayMode(), vdp.getTransparency(),
149  videoSource, vdp.getBackgroundColor());
150 }
151 
152 template <class Pixel>
154 {
155  workFrame = postProcessor->rotateFrames(std::move(workFrame), time);
156  workFrame->init(
160 
161  // Calculate line to render at top of screen.
162  // Make sure the display area is centered.
163  // 240 - 212 = 28 lines available for top/bottom border; 14 each.
164  // NTSC: display at [32..244),
165  // PAL: display at [59..271).
166  lineRenderTop = vdp.isPalTiming() ? 59 - 14 : 32 - 14;
167 
168 
169  // We haven't drawn any left/right borders yet this frame, thus so far
170  // all is still consistent (same settings for all left/right borders).
171  mixedLeftRightBorders = false;
172 
173  auto& borderInfo = workFrame->getBorderInfo();
174  Pixel color0, color1;
175  getBorderColors(color0, color1);
176  canSkipLeftRightBorders =
177  (borderInfo.mode == vdp.getDisplayMode().getByte()) &&
178  (borderInfo.color0 == color0) &&
179  (borderInfo.color1 == color1) &&
180  (borderInfo.adjust == vdp.getHorizontalAdjust()) &&
181  (borderInfo.scroll == vdp.getHorizontalScrollLow()) &&
182  (borderInfo.masked == vdp.isBorderMasked());
183 }
184 
185 template <class Pixel>
187 {
188  auto& borderInfo = workFrame->getBorderInfo();
189  if (mixedLeftRightBorders) {
190  // This frame contains left/right borders drawn with different
191  // settings. So don't use it as a starting point for future
192  // border drawing optimizations.
193  borderInfo.mode = 0xff; // invalid mode, other fields don't matter
194  } else {
195  // All left/right borders in this frame are uniform (drawn with
196  // the same settings). If in a later frame the border-related
197  // settings are still the same, we can skip drawing borders.
198  Pixel color0, color1;
199  getBorderColors(color0, color1);
200  borderInfo.mode = vdp.getDisplayMode().getByte();
201  borderInfo.color0 = color0;
202  borderInfo.color1 = color1;
203  borderInfo.adjust = vdp.getHorizontalAdjust();
204  borderInfo.scroll = vdp.getHorizontalScrollLow();
205  borderInfo.masked = vdp.isBorderMasked();
206  }
207 }
208 
209 template <class Pixel>
211 {
212  // Can no longer use the skip-border drawing optimization this frame.
213  canSkipLeftRightBorders = false;
214 
215  // Cannot use this frame as a starting point for future skip-border
216  // optimizations.
217  mixedLeftRightBorders = true;
218 }
219 
220 template <class Pixel>
222 {
223  if (mode.isBitmapMode()) {
224  bitmapConverter.setDisplayMode(mode);
225  } else {
226  characterConverter.setDisplayMode(mode);
227  }
228  precalcColorIndex0(mode, vdp.getTransparency(),
229  vdp.isSuperimposing(), vdp.getBackgroundColor());
230  spriteConverter.setDisplayMode(mode);
231  spriteConverter.setPalette(mode.getByte() == DisplayMode::GRAPHIC7
232  ? palGraphic7Sprites : palBg);
233 
234  borderSettingChanged();
235 }
236 
237 template <class Pixel>
238 void SDLRasterizer<Pixel>::setPalette(int index, int grb)
239 {
240  // Update SDL colors in palette.
241  Pixel newColor = V9938_COLORS[(grb >> 4) & 7][grb >> 8][grb & 7];
242  palFg[index ] = newColor;
243  palFg[index + 16] = newColor;
244  palBg[index ] = newColor;
245  bitmapConverter.palette16Changed();
246 
247  precalcColorIndex0(vdp.getDisplayMode(), vdp.getTransparency(),
248  vdp.isSuperimposing(), vdp.getBackgroundColor());
249  borderSettingChanged();
250 }
251 
252 template <class Pixel>
254 {
256  precalcColorIndex0(vdp.getDisplayMode(), vdp.getTransparency(),
257  vdp.isSuperimposing(), index);
258  }
259  borderSettingChanged();
260 }
261 
262 template <class Pixel>
264 {
265  borderSettingChanged();
266 }
267 
268 template <class Pixel>
270 {
271  borderSettingChanged();
272 }
273 
274 template <class Pixel>
276 {
277  borderSettingChanged();
278 }
279 
280 template <class Pixel>
282 {
283  spriteConverter.setTransparency(enabled);
284  precalcColorIndex0(vdp.getDisplayMode(), enabled,
285  vdp.isSuperimposing(), vdp.getBackgroundColor());
286 }
287 
288 template <class Pixel>
290 {
291  if (vdp.isMSX1VDP()) {
292  // Fixed palette.
293  const auto palette = vdp.getMSX1Palette();
294  for (int i = 0; i < 16; ++i) {
295  const auto rgb = palette[i];
296  palFg[i] = palFg[i + 16] = palBg[i] =
297  screen.mapKeyedRGB<Pixel>(
298  renderSettings.transformRGB(
299  vec3(rgb[0], rgb[1], rgb[2]) / 255.0f));
300  }
301  } else {
302  if (vdp.hasYJK()) {
303  // Precalculate palette for V9958 colors.
304  if (renderSettings.isColorMatrixIdentity()) {
305  // Most users use the "normal" monitor type; making this a
306  // special case speeds up palette precalculation a lot.
307  int intensity[32];
308  for (int i = 0; i < 32; ++i) {
309  intensity[i] =
310  int(255 * renderSettings.transformComponent(i / 31.0));
311  }
312  for (int rgb = 0; rgb < (1 << 15); ++rgb) {
313  V9958_COLORS[rgb] = screen.mapKeyedRGB255<Pixel>(ivec3(
314  intensity[(rgb >> 10) & 31],
315  intensity[(rgb >> 5) & 31],
316  intensity[(rgb >> 0) & 31]));
317  }
318  } else {
319  for (int r = 0; r < 32; ++r) {
320  for (int g = 0; g < 32; ++g) {
321  for (int b = 0; b < 32; ++b) {
322  V9958_COLORS[(r << 10) + (g << 5) + b] =
323  screen.mapKeyedRGB<Pixel>(
324  renderSettings.transformRGB(
325  vec3(r, g, b) / 31.0f));
326  }
327  }
328  }
329  }
330  // Precalculate palette for V9938 colors.
331  // Based on comparing red and green gradients, using palette and
332  // YJK, in SCREEN11 on a real turbo R.
333  for (int r3 = 0; r3 < 8; ++r3) {
334  int r5 = (r3 << 2) | (r3 >> 1);
335  for (int g3 = 0; g3 < 8; ++g3) {
336  int g5 = (g3 << 2) | (g3 >> 1);
337  for (int b3 = 0; b3 < 8; ++b3) {
338  int b5 = (b3 << 2) | (b3 >> 1);
339  V9938_COLORS[r3][g3][b3] =
340  V9958_COLORS[(r5 << 10) + (g5 << 5) + b5];
341  }
342  }
343  }
344  } else {
345  // Precalculate palette for V9938 colors.
346  if (renderSettings.isColorMatrixIdentity()) {
347  int intensity[8];
348  for (int i = 0; i < 8; ++i) {
349  intensity[i] =
350  int(255 * renderSettings.transformComponent(i / 7.0f));
351  }
352  for (int r = 0; r < 8; ++r) {
353  for (int g = 0; g < 8; ++g) {
354  for (int b = 0; b < 8; ++b) {
355  V9938_COLORS[r][g][b] =
356  screen.mapKeyedRGB255<Pixel>(ivec3(
357  intensity[r],
358  intensity[g],
359  intensity[b]));
360  }
361  }
362  }
363  } else {
364  for (int r = 0; r < 8; ++r) {
365  for (int g = 0; g < 8; ++g) {
366  for (int b = 0; b < 8; ++b) {
367  V9938_COLORS[r][g][b] =
368  screen.mapKeyedRGB<Pixel>(
369  renderSettings.transformRGB(
370  vec3(r, g, b) / 7.0f));;
371  }
372  }
373  }
374  }
375  }
376  // Precalculate Graphic 7 bitmap palette.
377  for (int i = 0; i < 256; ++i) {
378  PALETTE256[i] = V9938_COLORS
379  [(i & 0x1C) >> 2]
380  [(i & 0xE0) >> 5]
381  [(i & 0x03) == 3 ? 7 : (i & 0x03) * 2];
382  }
383  // Precalculate Graphic 7 sprite palette.
384  for (int i = 0; i < 16; ++i) {
385  uint16_t grb = Renderer::GRAPHIC7_SPRITE_PALETTE[i];
386  palGraphic7Sprites[i] =
387  V9938_COLORS[(grb >> 4) & 7][grb >> 8][grb & 7];
388  }
389  }
390 }
391 
392 template <class Pixel>
394  bool transparency, const RawFrame* superimposing, byte bgcolorIndex)
395 {
396  // Graphic7 mode doesn't use transparency.
397  if (mode.getByte() == DisplayMode::GRAPHIC7) {
398  transparency = false;
399  }
400 
401  int tpIndex = transparency ? bgcolorIndex : 0;
402  if (mode.getBase() != DisplayMode::GRAPHIC5) {
403  Pixel c = (superimposing && (bgcolorIndex == 0))
404  ? screen.getKeyColor<Pixel>()
405  : palBg[tpIndex];
406 
407  if (palFg[0] != c) {
408  palFg[0] = c;
409  bitmapConverter.palette16Changed();
410  }
411  } else {
412  // TODO: superimposing
413  if ((palFg[ 0] != palBg[tpIndex >> 2]) ||
414  (palFg[16] != palBg[tpIndex & 3])) {
415  palFg[ 0] = palBg[tpIndex >> 2];
416  palFg[16] = palBg[tpIndex & 3];
417  bitmapConverter.palette16Changed();
418  }
419  }
420 }
421 
422 template <class Pixel>
423 void SDLRasterizer<Pixel>::getBorderColors(Pixel& border0, Pixel& border1)
424 {
425  DisplayMode mode = vdp.getDisplayMode();
426  int bgColor = vdp.getBackgroundColor();
427  if (mode.getBase() == DisplayMode::GRAPHIC5) {
428  // border in SCREEN6 has separate color for even and odd pixels.
429  // TODO odd/even swapped?
430  border0 = palBg[(bgColor & 0x0C) >> 2];
431  border1 = palBg[(bgColor & 0x03) >> 0];
432  } else if (mode.getByte() == DisplayMode::GRAPHIC7) {
433  border0 = border1 = PALETTE256[bgColor];
434  } else {
435  if (!bgColor && vdp.isSuperimposing()) {
436  border0 = border1 = screen.getKeyColor<Pixel>();
437  } else {
438  border0 = border1 = palBg[bgColor];
439  }
440  }
441 }
442 
443 template <class Pixel>
445  int fromX, int fromY, int limitX, int limitY)
446 {
447  Pixel border0, border1;
448  getBorderColors(border0, border1);
449 
450  int startY = std::max(fromY - lineRenderTop, 0);
451  int endY = std::min(limitY - lineRenderTop, 240);
452  if ((fromX == 0) && (limitX == VDP::TICKS_PER_LINE) &&
453  (border0 == border1)) {
454  // complete lines, non striped
455  for (int y = startY; y < endY; y++) {
456  workFrame->setBlank(y, border0);
457  // setBlank() implies this line is not suitable
458  // for left/right border optimization in a later
459  // frame.
460  }
461  } else {
462  unsigned lineWidth = vdp.getDisplayMode().getLineWidth();
463  unsigned x = translateX(fromX, (lineWidth == 512));
464  unsigned num = translateX(limitX, (lineWidth == 512)) - x;
465  unsigned width = (lineWidth == 512) ? 640 : 320;
467  for (int y = startY; y < endY; ++y) {
468  // workFrame->linewidth != 1 means the line has
469  // left/right borders.
470  if (canSkipLeftRightBorders &&
471  (workFrame->getLineWidthDirect(y) != 1)) continue;
472  memset(workFrame->getLinePtrDirect<Pixel>(y) + x,
473  num, border0, border1);
474  if (limitX == VDP::TICKS_PER_LINE) {
475  // Only set line width at the end (right
476  // border) of the line. This ensures we can
477  // keep testing the width of the previous
478  // version of this line for all (partial)
479  // updates of this line.
480  workFrame->setLineWidth(y, width);
481  }
482  }
483  }
484 }
485 
486 template <class Pixel>
488  int /*fromX*/, int fromY,
489  int displayX, int displayY,
490  int displayWidth, int displayHeight)
491 {
492  // Note: we don't call workFrame->setLineWidth() because that's done in
493  // drawBorder() (for the right border). And the value we set there is
494  // anyway the same as the one we would set here.
495  DisplayMode mode = vdp.getDisplayMode();
496  unsigned lineWidth = mode.getLineWidth();
497  if (lineWidth == 256) {
498  int endX = displayX + displayWidth;
499  displayX /= 2;
500  displayWidth = endX / 2 - displayX;
501  }
502 
503  // Clip to screen area.
504  int screenLimitY = std::min(
505  fromY + displayHeight - lineRenderTop,
506  240);
507  int screenY = fromY - lineRenderTop;
508  if (screenY < 0) {
509  displayY -= screenY;
510  fromY = lineRenderTop;
511  screenY = 0;
512  }
513  displayHeight = screenLimitY - screenY;
514  if (displayHeight <= 0) return;
515 
516  int leftBackground =
517  translateX(vdp.getLeftBackground(), lineWidth == 512);
518  // TODO: Find out why this causes 1-pixel jitter:
519  //dest.x = translateX(fromX);
520  int hScroll =
521  mode.isTextMode()
522  ? 0
523  : 8 * (lineWidth / 256) * (vdp.getHorizontalScrollHigh() & 0x1F);
524 
525  // Page border is display X coordinate where to stop drawing current page.
526  // This is either the multi page split point, or the right edge of the
527  // rectangle to draw, whichever comes first.
528  // Note that it is possible for pageBorder to be to the left of displayX,
529  // in that case only the second page should be drawn.
530  int pageBorder = displayX + displayWidth;
531  int scrollPage1, scrollPage2;
532  if (vdp.isMultiPageScrolling()) {
533  scrollPage1 = vdp.getHorizontalScrollHigh() >> 5;
534  scrollPage2 = scrollPage1 ^ 1;
535  } else {
536  scrollPage1 = 0;
537  scrollPage2 = 0;
538  }
539  // Because SDL blits do not wrap, unlike GL textures, the pageBorder is
540  // also used if multi page is disabled.
541  int pageSplit = lineWidth - hScroll;
542  if (pageSplit < pageBorder) {
543  pageBorder = pageSplit;
544  }
545 
546  if (mode.isBitmapMode()) {
547  // Which bits in the name mask determine the page?
548  int pageMaskOdd = (mode.isPlanar() ? 0x000 : 0x200) |
549  vdp.getEvenOddMask();
550  int pageMaskEven = vdp.isMultiPageScrolling()
551  ? (pageMaskOdd & ~0x100)
552  : pageMaskOdd;
553 
554  for (int y = screenY; y < screenLimitY; y++) {
555  const int vramLine[2] = {
556  (vram.nameTable.getMask() >> 7) & (pageMaskEven | displayY),
557  (vram.nameTable.getMask() >> 7) & (pageMaskOdd | displayY)
558  };
559 
560  Pixel buf[512];
561  int lineInBuf = -1; // buffer data not valid
562  Pixel* dst = workFrame->getLinePtrDirect<Pixel>(y)
563  + leftBackground + displayX;
564  int firstPageWidth = pageBorder - displayX;
565  if (firstPageWidth > 0) {
566  if ((displayX + hScroll) == 0) {
567  renderBitmapLine(dst, vramLine[scrollPage1]);
568  } else {
569  lineInBuf = vramLine[scrollPage1];
570  renderBitmapLine(buf, vramLine[scrollPage1]);
571  const Pixel* src = buf + displayX + hScroll;
572  memcpy(dst, src, firstPageWidth * sizeof(Pixel));
573  }
574  } else {
575  firstPageWidth = 0;
576  }
577  if (firstPageWidth < displayWidth) {
578  if (lineInBuf != vramLine[scrollPage2]) {
579  renderBitmapLine(buf, vramLine[scrollPage2]);
580  }
581  unsigned x = displayX < pageBorder
582  ? 0 : displayX + hScroll - lineWidth;
583  memcpy(dst + firstPageWidth,
584  buf + x,
585  (displayWidth - firstPageWidth) * sizeof(Pixel));
586  }
587 
588  displayY = (displayY + 1) & 255;
589  }
590  } else {
591  // horizontal scroll (high) is implemented in CharacterConverter
592  for (int y = screenY; y < screenLimitY; y++) {
593  assert(!vdp.isMSX1VDP() || displayY < 192);
594 
595  Pixel* dst = workFrame->getLinePtrDirect<Pixel>(y)
596  + leftBackground + displayX;
597  if (displayX == 0) {
598  characterConverter.convertLine(dst, displayY);
599  } else {
600  Pixel buf[512];
601  characterConverter.convertLine(buf, displayY);
602  const Pixel* src = buf + displayX;
603  memcpy(dst, src, displayWidth * sizeof(Pixel));
604  }
605 
606  displayY = (displayY + 1) & 255;
607  }
608  }
609 }
610 
611 template <class Pixel>
613  int /*fromX*/, int fromY,
614  int displayX, int displayY,
615  int displayWidth, int displayHeight)
616 {
617  // Clip to screen area.
618  // TODO: Code duplicated from drawDisplay.
619  int screenLimitY = std::min(
620  fromY + displayHeight - lineRenderTop,
621  240);
622  int screenY = fromY - lineRenderTop;
623  if (screenY < 0) {
624  displayY -= screenY;
625  fromY = lineRenderTop;
626  screenY = 0;
627  }
628  displayHeight = screenLimitY - screenY;
629  if (displayHeight <= 0) return;
630 
631  // Render sprites.
632  // TODO: Call different SpriteConverter methods depending on narrow/wide
633  // pixels in this display mode?
634  int spriteMode = vdp.getDisplayMode().getSpriteMode(vdp.isMSX1VDP());
635  int displayLimitX = displayX + displayWidth;
636  int limitY = fromY + displayHeight;
637  int screenX = translateX(
638  vdp.getLeftSprites(),
639  vdp.getDisplayMode().getLineWidth() == 512);
640  if (spriteMode == 1) {
641  for (int y = fromY; y < limitY; y++, screenY++) {
642  Pixel* pixelPtr = workFrame->getLinePtrDirect<Pixel>(screenY) + screenX;
643  spriteConverter.drawMode1(y, displayX, displayLimitX, pixelPtr);
644  }
645  } else {
646  byte mode = vdp.getDisplayMode().getByte();
647  if (mode == DisplayMode::GRAPHIC5) {
648  for (int y = fromY; y < limitY; y++, screenY++) {
649  Pixel* pixelPtr = workFrame->getLinePtrDirect<Pixel>(screenY) + screenX;
650  spriteConverter.template drawMode2<DisplayMode::GRAPHIC5>(
651  y, displayX, displayLimitX, pixelPtr);
652  }
653  } else if (mode == DisplayMode::GRAPHIC6) {
654  for (int y = fromY; y < limitY; y++, screenY++) {
655  Pixel* pixelPtr = workFrame->getLinePtrDirect<Pixel>(screenY) + screenX;
656  spriteConverter.template drawMode2<DisplayMode::GRAPHIC6>(
657  y, displayX, displayLimitX, pixelPtr);
658  }
659  } else {
660  for (int y = fromY; y < limitY; y++, screenY++) {
661  Pixel* pixelPtr = workFrame->getLinePtrDirect<Pixel>(screenY) + screenX;
662  spriteConverter.template drawMode2<DisplayMode::GRAPHIC4>(
663  y, displayX, displayLimitX, pixelPtr);
664  }
665  }
666  }
667 }
668 
669 template <class Pixel>
671 {
672  return postProcessor->isRecording();
673 }
674 
675 template <class Pixel>
676 void SDLRasterizer<Pixel>::update(const Setting& setting)
677 {
678  if ((&setting == &renderSettings.getGammaSetting()) ||
679  (&setting == &renderSettings.getBrightnessSetting()) ||
680  (&setting == &renderSettings.getContrastSetting()) ||
681  (&setting == &renderSettings.getColorMatrixSetting())) {
682  precalcPalette();
683  resetPalette();
684  }
685 }
686 
687 
688 // Force template instantiation.
689 #if HAVE_16BPP
690 template class SDLRasterizer<uint16_t>;
691 #endif
692 #if HAVE_32BPP || COMPONENT_GL
693 template class SDLRasterizer<uint32_t>;
694 #endif
695 
696 } // 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:1447
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