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 "VisibleSurface.hh"
11 #include "build-info.hh"
12 #include "components.hh"
13 #include <algorithm>
14 #include <cassert>
15 #include <cstdint>
16 #include <memory>
17 
18 using namespace gl;
19 
20 namespace openmsx {
21 
24 constexpr int TICKS_LEFT_BORDER = 100 + 102;
25 
30 constexpr int TICKS_VISIBLE_MIDDLE =
31  TICKS_LEFT_BORDER + (VDP::TICKS_PER_LINE - TICKS_LEFT_BORDER - 27) / 2;
32 
39 static inline int translateX(int absoluteX, bool narrow)
40 {
41  int maxX = narrow ? 640 : 320;
42  if (absoluteX == VDP::TICKS_PER_LINE) return maxX;
43 
44  // Note: The ROUND_MASK forces the ticks to a pixel (2-tick) boundary.
45  // If this is not done, rounding errors will occur.
46  const int ROUND_MASK = narrow ? ~1 : ~3;
47  int screenX =
48  ((absoluteX - (TICKS_VISIBLE_MIDDLE & ROUND_MASK))
49  >> (narrow ? 1 : 2))
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(std::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>
153 void SDLRasterizer<Pixel>::frameStart(EmuTime::param time)
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  int 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  for (int y = screenY; y < screenLimitY; y++) {
548  // Which bits in the name mask determine the page?
549  // TODO optimize this?
550  // Calculating pageMaskOdd/Even is a non-trivial amount
551  // of work. We used to do this per frame (more or less)
552  // but now do it per line. Per-line is actually only
553  // needed when vdp.isFastBlinkEnabled() is true.
554  // Idea: can be cheaply calculated incrementally.
555  int pageMaskOdd = (mode.isPlanar() ? 0x000 : 0x200) |
556  vdp.getEvenOddMask(y);
557  int pageMaskEven = vdp.isMultiPageScrolling()
558  ? (pageMaskOdd & ~0x100)
559  : pageMaskOdd;
560  const int vramLine[2] = {
561  (vram.nameTable.getMask() >> 7) & (pageMaskEven | displayY),
562  (vram.nameTable.getMask() >> 7) & (pageMaskOdd | displayY)
563  };
564 
565  Pixel buf[512];
566  int lineInBuf = -1; // buffer data not valid
567  Pixel* dst = workFrame->getLinePtrDirect<Pixel>(y)
568  + leftBackground + displayX;
569  int firstPageWidth = pageBorder - displayX;
570  if (firstPageWidth > 0) {
571  if (((displayX + hScroll) == 0) &&
572  (firstPageWidth == lineWidth)) {
573  // fast-path, directly render to destination
574  renderBitmapLine(dst, vramLine[scrollPage1]);
575  } else {
576  lineInBuf = vramLine[scrollPage1];
577  renderBitmapLine(buf, vramLine[scrollPage1]);
578  const Pixel* src = buf + displayX + hScroll;
579  memcpy(dst, src, firstPageWidth * sizeof(Pixel));
580  }
581  } else {
582  firstPageWidth = 0;
583  }
584  if (firstPageWidth < displayWidth) {
585  if (lineInBuf != vramLine[scrollPage2]) {
586  renderBitmapLine(buf, vramLine[scrollPage2]);
587  }
588  unsigned x = displayX < pageBorder
589  ? 0 : displayX + hScroll - lineWidth;
590  memcpy(dst + firstPageWidth,
591  buf + x,
592  (displayWidth - firstPageWidth) * sizeof(Pixel));
593  }
594 
595  displayY = (displayY + 1) & 255;
596  }
597  } else {
598  // horizontal scroll (high) is implemented in CharacterConverter
599  for (int y = screenY; y < screenLimitY; y++) {
600  assert(!vdp.isMSX1VDP() || displayY < 192);
601 
602  Pixel* dst = workFrame->getLinePtrDirect<Pixel>(y)
603  + leftBackground + displayX;
604  if ((displayX == 0) && (displayWidth == lineWidth)){
605  characterConverter.convertLine(dst, displayY);
606  } else {
607  Pixel buf[512];
608  characterConverter.convertLine(buf, displayY);
609  const Pixel* src = buf + displayX;
610  memcpy(dst, src, displayWidth * sizeof(Pixel));
611  }
612 
613  displayY = (displayY + 1) & 255;
614  }
615  }
616 }
617 
618 template <class Pixel>
620  int /*fromX*/, int fromY,
621  int displayX, int displayY,
622  int displayWidth, int displayHeight)
623 {
624  // Clip to screen area.
625  // TODO: Code duplicated from drawDisplay.
626  int screenLimitY = std::min(
627  fromY + displayHeight - lineRenderTop,
628  240);
629  int screenY = fromY - lineRenderTop;
630  if (screenY < 0) {
631  displayY -= screenY;
632  fromY = lineRenderTop;
633  screenY = 0;
634  }
635  displayHeight = screenLimitY - screenY;
636  if (displayHeight <= 0) return;
637 
638  // Render sprites.
639  // TODO: Call different SpriteConverter methods depending on narrow/wide
640  // pixels in this display mode?
641  int spriteMode = vdp.getDisplayMode().getSpriteMode(vdp.isMSX1VDP());
642  int displayLimitX = displayX + displayWidth;
643  int limitY = fromY + displayHeight;
644  int screenX = translateX(
645  vdp.getLeftSprites(),
646  vdp.getDisplayMode().getLineWidth() == 512);
647  if (spriteMode == 1) {
648  for (int y = fromY; y < limitY; y++, screenY++) {
649  Pixel* pixelPtr = workFrame->getLinePtrDirect<Pixel>(screenY) + screenX;
650  spriteConverter.drawMode1(y, displayX, displayLimitX, pixelPtr);
651  }
652  } else {
653  byte mode = vdp.getDisplayMode().getByte();
654  if (mode == DisplayMode::GRAPHIC5) {
655  for (int y = fromY; y < limitY; y++, screenY++) {
656  Pixel* pixelPtr = workFrame->getLinePtrDirect<Pixel>(screenY) + screenX;
657  spriteConverter.template drawMode2<DisplayMode::GRAPHIC5>(
658  y, displayX, displayLimitX, pixelPtr);
659  }
660  } else if (mode == DisplayMode::GRAPHIC6) {
661  for (int y = fromY; y < limitY; y++, screenY++) {
662  Pixel* pixelPtr = workFrame->getLinePtrDirect<Pixel>(screenY) + screenX;
663  spriteConverter.template drawMode2<DisplayMode::GRAPHIC6>(
664  y, displayX, displayLimitX, pixelPtr);
665  }
666  } else {
667  for (int y = fromY; y < limitY; y++, screenY++) {
668  Pixel* pixelPtr = workFrame->getLinePtrDirect<Pixel>(screenY) + screenX;
669  spriteConverter.template drawMode2<DisplayMode::GRAPHIC4>(
670  y, displayX, displayLimitX, pixelPtr);
671  }
672  }
673  }
674 }
675 
676 template <class Pixel>
678 {
679  return postProcessor->isRecording();
680 }
681 
682 template <class Pixel>
683 void SDLRasterizer<Pixel>::update(const Setting& setting)
684 {
685  if ((&setting == &renderSettings.getGammaSetting()) ||
686  (&setting == &renderSettings.getBrightnessSetting()) ||
687  (&setting == &renderSettings.getContrastSetting()) ||
688  (&setting == &renderSettings.getColorMatrixSetting())) {
689  precalcPalette();
690  resetPalette();
691  }
692 }
693 
694 
695 // Force template instantiation.
696 #if HAVE_16BPP
697 template class SDLRasterizer<uint16_t>;
698 #endif
699 #if HAVE_32BPP || COMPONENT_GL
700 template class SDLRasterizer<uint32_t>;
701 #endif
702 
703 } // 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
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:370
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
constexpr int TICKS_VISIBLE_MIDDLE
The middle of the visible (display + borders) part of a line, expressed in VDP ticks since the start ...
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:269
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:385
byte getHorizontalScrollLow() const
Gets the current horizontal scroll lower bits.
Definition: VDP.hh:278
constexpr bool isTextMode() const
Is the current mode a text mode? Text1 and Text2 are text modes.
Definition: DisplayMode.hh:129
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:507
VRAMWindow nameTable
Definition: VDPVRAM.hh:666
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:287
bool hasYJK() const
Does this VDP support YJK display?
Definition: VDP.hh:128
FloatSetting & getContrastSetting()
Contrast video setting.
constexpr int TICKS_LEFT_BORDER
VDP ticks between start of line and start of left border.
static constexpr int TICKS_PER_LINE
Number of VDP clock ticks per line.
Definition: VDP.hh:72
constexpr int getSpriteMode(bool isMSX1) const
Get the sprite mode of this display mode.
Definition: DisplayMode.hh:168
int getBackgroundColor() const
Gets the current background color.
Definition: VDP.hh:193
void attach(Observer< T > &observer)
Definition: Subject.hh:50
vecN< 3, int > ivec3
Definition: gl_vec.hh:143
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:546
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?
void drawBorder(int fromX, int fromY, int limitX, int limitY) override
Render a rectangle of border pixels on the host screen.
constexpr bool isBitmapMode() const
Is the current mode a bitmap mode? Graphic4 and higher are bitmap modes.
Definition: DisplayMode.hh:140
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:518
bool getTransparency() const
Gets the current transparency setting.
Definition: VDP.hh:174
constexpr byte getByte() const
Get the dispay mode as a byte: YAE YJK M5..M1 combined.
Definition: DisplayMode.hh:100
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:73
void setHorizontalAdjust(int adjust) override
constexpr unsigned getLineWidth() const
Get number of pixels on a display line in this mode.
Definition: DisplayMode.hh:190
int g
void setDisplayMode(DisplayMode mode) override
Precalc several values that depend on the display mode.
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:150
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. ...
constexpr byte getBase() const
Get the base dispay mode as an integer: M5..M1 combined.
Definition: DisplayMode.hh:114
vecN< 3, float > vec3
Definition: gl_vec.hh:140
gl::vec3 transformRGB(gl::vec3 rgb) const
Apply brightness, contrast and gamma transformation on the input color.
std::array< std::array< uint8_t, 3 >, 16 > getMSX1Palette() const
Get the (fixed) palette for this MSX1 VDP.
Definition: VDP.cc:1482
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:56
constexpr KeyMatrixPosition x
Keyboard bindings.
Definition: Keyboard.cc:1377
bool isInterlaced() const
Get interlace status.
Definition: VDP.hh:333
Definition: gl_mat.hh:24
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().