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  auto [vramPtr0, vramPtr1] =
60  vram.bitmapCacheWindow.getReadAreaPlanar(vramLine * 256, 256);
61  bitmapConverter.convertLinePlanar(buf, vramPtr0, vramPtr1);
62  } else {
63  const byte* vramPtr =
64  vram.bitmapCacheWindow.getReadArea(vramLine * 128, 128);
65  bitmapConverter.convertLine(buf, vramPtr);
66  }
67 }
68 
69 template <class Pixel>
71  VDP& vdp_, Display& display, OutputSurface& screen_,
72  std::unique_ptr<PostProcessor> postProcessor_)
73  : vdp(vdp_), vram(vdp.getVRAM())
74  , screen(screen_)
75  , postProcessor(std::move(postProcessor_))
76  , workFrame(std::make_unique<RawFrame>(screen.getPixelFormat(), 640, 240))
77  , renderSettings(display.getRenderSettings())
78  , characterConverter(vdp, palFg, palBg)
79  , bitmapConverter(palFg, PALETTE256, V9958_COLORS)
80  , spriteConverter(vdp.getSpriteChecker())
81 {
82  // Init the palette.
83  precalcPalette();
84 
85  // Initialize palette (avoid UMR)
86  if (!vdp.isMSX1VDP()) {
87  for (int i = 0; i < 16; ++i) {
88  palFg[i] = palFg[i + 16] = palBg[i] =
89  V9938_COLORS[0][0][0];
90  }
91  }
92 
93  renderSettings.getGammaSetting() .attach(*this);
94  renderSettings.getBrightnessSetting() .attach(*this);
95  renderSettings.getContrastSetting() .attach(*this);
96  renderSettings.getColorMatrixSetting().attach(*this);
97 }
98 
99 template <class Pixel>
101 {
102  renderSettings.getColorMatrixSetting().detach(*this);
103  renderSettings.getGammaSetting() .detach(*this);
104  renderSettings.getBrightnessSetting() .detach(*this);
105  renderSettings.getContrastSetting() .detach(*this);
106 }
107 
108 template <class Pixel>
110 {
111  return postProcessor.get();
112 }
113 
114 template <class Pixel>
116 {
117  return postProcessor->needRender() &&
118  vdp.getMotherBoard().isActive() &&
119  !vdp.getMotherBoard().isFastForwarding();
120 }
121 
122 template <class Pixel>
124 {
125  // Init renderer state.
126  setDisplayMode(vdp.getDisplayMode());
127  spriteConverter.setTransparency(vdp.getTransparency());
128 
129  resetPalette();
130 }
131 
132 template <class Pixel>
134 {
135  if (!vdp.isMSX1VDP()) {
136  // Reset the palette.
137  for (int i = 0; i < 16; i++) {
138  setPalette(i, vdp.getPalette(i));
139  }
140  }
141 }
142 
143 template<class Pixel>
145 {
146  postProcessor->setSuperimposeVideoFrame(videoSource);
147  precalcColorIndex0(vdp.getDisplayMode(), vdp.getTransparency(),
148  videoSource, vdp.getBackgroundColor());
149 }
150 
151 template <class Pixel>
152 void SDLRasterizer<Pixel>::frameStart(EmuTime::param time)
153 {
154  workFrame = postProcessor->rotateFrames(std::move(workFrame), time);
155  workFrame->init(
156  vdp.isInterlaced() ? (vdp.getEvenOdd() ? FrameSource::FIELD_ODD
159 
160  // Calculate line to render at top of screen.
161  // Make sure the display area is centered.
162  // 240 - 212 = 28 lines available for top/bottom border; 14 each.
163  // NTSC: display at [32..244),
164  // PAL: display at [59..271).
165  lineRenderTop = vdp.isPalTiming() ? 59 - 14 : 32 - 14;
166 
167 
168  // We haven't drawn any left/right borders yet this frame, thus so far
169  // all is still consistent (same settings for all left/right borders).
170  mixedLeftRightBorders = false;
171 
172  auto& borderInfo = workFrame->getBorderInfo();
173  Pixel color0, color1;
174  getBorderColors(color0, color1);
175  canSkipLeftRightBorders =
176  (borderInfo.mode == vdp.getDisplayMode().getByte()) &&
177  (borderInfo.color0 == color0) &&
178  (borderInfo.color1 == color1) &&
179  (borderInfo.adjust == vdp.getHorizontalAdjust()) &&
180  (borderInfo.scroll == vdp.getHorizontalScrollLow()) &&
181  (borderInfo.masked == vdp.isBorderMasked());
182 }
183 
184 template <class Pixel>
186 {
187  auto& borderInfo = workFrame->getBorderInfo();
188  if (mixedLeftRightBorders) {
189  // This frame contains left/right borders drawn with different
190  // settings. So don't use it as a starting point for future
191  // border drawing optimizations.
192  borderInfo.mode = 0xff; // invalid mode, other fields don't matter
193  } else {
194  // All left/right borders in this frame are uniform (drawn with
195  // the same settings). If in a later frame the border-related
196  // settings are still the same, we can skip drawing borders.
197  Pixel color0, color1;
198  getBorderColors(color0, color1);
199  borderInfo.mode = vdp.getDisplayMode().getByte();
200  borderInfo.color0 = color0;
201  borderInfo.color1 = color1;
202  borderInfo.adjust = vdp.getHorizontalAdjust();
203  borderInfo.scroll = vdp.getHorizontalScrollLow();
204  borderInfo.masked = vdp.isBorderMasked();
205  }
206 }
207 
208 template <class Pixel>
210 {
211  // Can no longer use the skip-border drawing optimization this frame.
212  canSkipLeftRightBorders = false;
213 
214  // Cannot use this frame as a starting point for future skip-border
215  // optimizations.
216  mixedLeftRightBorders = true;
217 }
218 
219 template <class Pixel>
221 {
222  if (mode.isBitmapMode()) {
223  bitmapConverter.setDisplayMode(mode);
224  } else {
225  characterConverter.setDisplayMode(mode);
226  }
227  precalcColorIndex0(mode, vdp.getTransparency(),
228  vdp.isSuperimposing(), vdp.getBackgroundColor());
229  spriteConverter.setDisplayMode(mode);
230  spriteConverter.setPalette(mode.getByte() == DisplayMode::GRAPHIC7
231  ? palGraphic7Sprites : palBg);
232 
233  borderSettingChanged();
234 }
235 
236 template <class Pixel>
237 void SDLRasterizer<Pixel>::setPalette(int index, int grb)
238 {
239  // Update SDL colors in palette.
240  Pixel newColor = V9938_COLORS[(grb >> 4) & 7][grb >> 8][grb & 7];
241  palFg[index ] = newColor;
242  palFg[index + 16] = newColor;
243  palBg[index ] = newColor;
244  bitmapConverter.palette16Changed();
245 
246  precalcColorIndex0(vdp.getDisplayMode(), vdp.getTransparency(),
247  vdp.isSuperimposing(), vdp.getBackgroundColor());
248  borderSettingChanged();
249 }
250 
251 template <class Pixel>
253 {
254  if (vdp.getDisplayMode().getByte() != DisplayMode::GRAPHIC7) {
255  precalcColorIndex0(vdp.getDisplayMode(), vdp.getTransparency(),
256  vdp.isSuperimposing(), index);
257  }
258  borderSettingChanged();
259 }
260 
261 template <class Pixel>
263 {
264  borderSettingChanged();
265 }
266 
267 template <class Pixel>
269 {
270  borderSettingChanged();
271 }
272 
273 template <class Pixel>
275 {
276  borderSettingChanged();
277 }
278 
279 template <class Pixel>
281 {
282  spriteConverter.setTransparency(enabled);
283  precalcColorIndex0(vdp.getDisplayMode(), enabled,
284  vdp.isSuperimposing(), vdp.getBackgroundColor());
285 }
286 
287 template <class Pixel>
289 {
290  if (vdp.isMSX1VDP()) {
291  // Fixed palette.
292  const auto palette = vdp.getMSX1Palette();
293  for (int i = 0; i < 16; ++i) {
294  const auto rgb = palette[i];
295  palFg[i] = palFg[i + 16] = palBg[i] =
296  screen.mapKeyedRGB<Pixel>(
297  renderSettings.transformRGB(
298  vec3(rgb[0], rgb[1], rgb[2]) / 255.0f));
299  }
300  } else {
301  if (vdp.hasYJK()) {
302  // Precalculate palette for V9958 colors.
303  if (renderSettings.isColorMatrixIdentity()) {
304  // Most users use the "normal" monitor type; making this a
305  // special case speeds up palette precalculation a lot.
306  int intensity[32];
307  for (int i = 0; i < 32; ++i) {
308  intensity[i] =
309  int(255 * renderSettings.transformComponent(i / 31.0));
310  }
311  for (int rgb = 0; rgb < (1 << 15); ++rgb) {
312  V9958_COLORS[rgb] = screen.mapKeyedRGB255<Pixel>(ivec3(
313  intensity[(rgb >> 10) & 31],
314  intensity[(rgb >> 5) & 31],
315  intensity[(rgb >> 0) & 31]));
316  }
317  } else {
318  for (int r = 0; r < 32; ++r) {
319  for (int g = 0; g < 32; ++g) {
320  for (int b = 0; b < 32; ++b) {
321  V9958_COLORS[(r << 10) + (g << 5) + b] =
322  screen.mapKeyedRGB<Pixel>(
323  renderSettings.transformRGB(
324  vec3(r, g, b) / 31.0f));
325  }
326  }
327  }
328  }
329  // Precalculate palette for V9938 colors.
330  // Based on comparing red and green gradients, using palette and
331  // YJK, in SCREEN11 on a real turbo R.
332  for (int r3 = 0; r3 < 8; ++r3) {
333  int r5 = (r3 << 2) | (r3 >> 1);
334  for (int g3 = 0; g3 < 8; ++g3) {
335  int g5 = (g3 << 2) | (g3 >> 1);
336  for (int b3 = 0; b3 < 8; ++b3) {
337  int b5 = (b3 << 2) | (b3 >> 1);
338  V9938_COLORS[r3][g3][b3] =
339  V9958_COLORS[(r5 << 10) + (g5 << 5) + b5];
340  }
341  }
342  }
343  } else {
344  // Precalculate palette for V9938 colors.
345  if (renderSettings.isColorMatrixIdentity()) {
346  int intensity[8];
347  for (int i = 0; i < 8; ++i) {
348  intensity[i] =
349  int(255 * renderSettings.transformComponent(i / 7.0f));
350  }
351  for (int r = 0; r < 8; ++r) {
352  for (int g = 0; g < 8; ++g) {
353  for (int b = 0; b < 8; ++b) {
354  V9938_COLORS[r][g][b] =
355  screen.mapKeyedRGB255<Pixel>(ivec3(
356  intensity[r],
357  intensity[g],
358  intensity[b]));
359  }
360  }
361  }
362  } else {
363  for (int r = 0; r < 8; ++r) {
364  for (int g = 0; g < 8; ++g) {
365  for (int b = 0; b < 8; ++b) {
366  V9938_COLORS[r][g][b] =
367  screen.mapKeyedRGB<Pixel>(
368  renderSettings.transformRGB(
369  vec3(r, g, b) / 7.0f));;
370  }
371  }
372  }
373  }
374  }
375  // Precalculate Graphic 7 bitmap palette.
376  for (int i = 0; i < 256; ++i) {
377  PALETTE256[i] = V9938_COLORS
378  [(i & 0x1C) >> 2]
379  [(i & 0xE0) >> 5]
380  [(i & 0x03) == 3 ? 7 : (i & 0x03) * 2];
381  }
382  // Precalculate Graphic 7 sprite palette.
383  for (int i = 0; i < 16; ++i) {
384  uint16_t grb = Renderer::GRAPHIC7_SPRITE_PALETTE[i];
385  palGraphic7Sprites[i] =
386  V9938_COLORS[(grb >> 4) & 7][grb >> 8][grb & 7];
387  }
388  }
389 }
390 
391 template <class Pixel>
392 void SDLRasterizer<Pixel>::precalcColorIndex0(DisplayMode mode,
393  bool transparency, const RawFrame* superimposing, byte bgcolorIndex)
394 {
395  // Graphic7 mode doesn't use transparency.
396  if (mode.getByte() == DisplayMode::GRAPHIC7) {
397  transparency = false;
398  }
399 
400  int tpIndex = transparency ? bgcolorIndex : 0;
401  if (mode.getBase() != DisplayMode::GRAPHIC5) {
402  Pixel c = (superimposing && (bgcolorIndex == 0))
403  ? screen.getKeyColor<Pixel>()
404  : palBg[tpIndex];
405 
406  if (palFg[0] != c) {
407  palFg[0] = c;
408  bitmapConverter.palette16Changed();
409  }
410  } else {
411  // TODO: superimposing
412  if ((palFg[ 0] != palBg[tpIndex >> 2]) ||
413  (palFg[16] != palBg[tpIndex & 3])) {
414  palFg[ 0] = palBg[tpIndex >> 2];
415  palFg[16] = palBg[tpIndex & 3];
416  bitmapConverter.palette16Changed();
417  }
418  }
419 }
420 
421 template <class Pixel>
422 void SDLRasterizer<Pixel>::getBorderColors(Pixel& border0, Pixel& border1)
423 {
424  DisplayMode mode = vdp.getDisplayMode();
425  int bgColor = vdp.getBackgroundColor();
426  if (mode.getBase() == DisplayMode::GRAPHIC5) {
427  // border in SCREEN6 has separate color for even and odd pixels.
428  // TODO odd/even swapped?
429  border0 = palBg[(bgColor & 0x0C) >> 2];
430  border1 = palBg[(bgColor & 0x03) >> 0];
431  } else if (mode.getByte() == DisplayMode::GRAPHIC7) {
432  border0 = border1 = PALETTE256[bgColor];
433  } else {
434  if (!bgColor && vdp.isSuperimposing()) {
435  border0 = border1 = screen.getKeyColor<Pixel>();
436  } else {
437  border0 = border1 = palBg[bgColor];
438  }
439  }
440 }
441 
442 template <class Pixel>
444  int fromX, int fromY, int limitX, int limitY)
445 {
446  Pixel border0, border1;
447  getBorderColors(border0, border1);
448 
449  int startY = std::max(fromY - lineRenderTop, 0);
450  int endY = std::min(limitY - lineRenderTop, 240);
451  if ((fromX == 0) && (limitX == VDP::TICKS_PER_LINE) &&
452  (border0 == border1)) {
453  // complete lines, non striped
454  for (int y = startY; y < endY; y++) {
455  workFrame->setBlank(y, border0);
456  // setBlank() implies this line is not suitable
457  // for left/right border optimization in a later
458  // frame.
459  }
460  } else {
461  unsigned lineWidth = vdp.getDisplayMode().getLineWidth();
462  unsigned x = translateX(fromX, (lineWidth == 512));
463  unsigned num = translateX(limitX, (lineWidth == 512)) - x;
464  unsigned width = (lineWidth == 512) ? 640 : 320;
466  for (int y = startY; y < endY; ++y) {
467  // workFrame->linewidth != 1 means the line has
468  // left/right borders.
469  if (canSkipLeftRightBorders &&
470  (workFrame->getLineWidthDirect(y) != 1)) continue;
471  memset(workFrame->getLinePtrDirect<Pixel>(y) + x,
472  num, border0, border1);
473  if (limitX == VDP::TICKS_PER_LINE) {
474  // Only set line width at the end (right
475  // border) of the line. This ensures we can
476  // keep testing the width of the previous
477  // version of this line for all (partial)
478  // updates of this line.
479  workFrame->setLineWidth(y, width);
480  }
481  }
482  }
483 }
484 
485 template <class Pixel>
487  int /*fromX*/, int fromY,
488  int displayX, int displayY,
489  int displayWidth, int displayHeight)
490 {
491  // Note: we don't call workFrame->setLineWidth() because that's done in
492  // drawBorder() (for the right border). And the value we set there is
493  // anyway the same as the one we would set here.
494  DisplayMode mode = vdp.getDisplayMode();
495  int lineWidth = mode.getLineWidth();
496  if (lineWidth == 256) {
497  int endX = displayX + displayWidth;
498  displayX /= 2;
499  displayWidth = endX / 2 - displayX;
500  }
501 
502  // Clip to screen area.
503  int screenLimitY = std::min(
504  fromY + displayHeight - lineRenderTop,
505  240);
506  int screenY = fromY - lineRenderTop;
507  if (screenY < 0) {
508  displayY -= screenY;
509  fromY = lineRenderTop;
510  screenY = 0;
511  }
512  displayHeight = screenLimitY - screenY;
513  if (displayHeight <= 0) return;
514 
515  int leftBackground =
516  translateX(vdp.getLeftBackground(), lineWidth == 512);
517  // TODO: Find out why this causes 1-pixel jitter:
518  //dest.x = translateX(fromX);
519  int hScroll =
520  mode.isTextMode()
521  ? 0
522  : 8 * (lineWidth / 256) * (vdp.getHorizontalScrollHigh() & 0x1F);
523 
524  // Page border is display X coordinate where to stop drawing current page.
525  // This is either the multi page split point, or the right edge of the
526  // rectangle to draw, whichever comes first.
527  // Note that it is possible for pageBorder to be to the left of displayX,
528  // in that case only the second page should be drawn.
529  int pageBorder = displayX + displayWidth;
530  auto [scrollPage1, scrollPage2] = [&]() -> std::pair<int, int> {
531  if (vdp.isMultiPageScrolling()) {
532  int p1 = vdp.getHorizontalScrollHigh() >> 5;
533  int p2 = p1 ^ 1;
534  return {p1, p2};
535  } else {
536  return {0, 0};
537  }
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 == one_of(&renderSettings.getGammaSetting(),
686  &renderSettings.getBrightnessSetting(),
687  &renderSettings.getContrastSetting(),
688  &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
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:144
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:220
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:152
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:115
VDP.hh
openmsx::SDLRasterizer::setHorizontalAdjust
void setHorizontalAdjust(int adjust) override
Definition: SDLRasterizer.cc:262
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:443
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:677
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:486
openmsx::SDLRasterizer::~SDLRasterizer
~SDLRasterizer() override
Definition: SDLRasterizer.cc:100
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:109
openmsx::SDLRasterizer::setBorderMask
void setBorderMask(bool masked) override
Definition: SDLRasterizer.cc:274
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:123
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:1416
openmsx::SDLRasterizer::setTransparency
void setTransparency(bool enabled) override
Definition: SDLRasterizer.cc:280
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:185
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:268
openmsx::SDLRasterizer::setBackgroundColor
void setBackgroundColor(int index) override
Changes the background color.
Definition: SDLRasterizer.cc:252
openmsx::SDLRasterizer::setPalette
void setPalette(int index, int grb) override
Change an entry in the palette.
Definition: SDLRasterizer.cc:237
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:619
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