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