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 "enumerate.hh"
12#include "one_of.hh"
13#include "xrange.hh"
14#include <algorithm>
15#include <array>
16#include <cassert>
17#include <cstdint>
18#include <memory>
19
20using namespace gl;
21
22namespace openmsx {
23
25
28static constexpr int TICKS_LEFT_BORDER = 100 + 102;
29static constexpr int TICKS_RIGHT_BORDER = 100 + 102 + 56 + 1024 + 59;
30
35static constexpr int TICKS_VISIBLE_MIDDLE =
36 TICKS_LEFT_BORDER + (VDP::TICKS_PER_LINE - TICKS_LEFT_BORDER - 27) / 2;
37
44static constexpr int translateX(int absoluteX, bool narrow)
45{
46 int maxX = narrow ? 640 : 320;
47
48 // Clip positions outside left/right VDP border to left/right "extended"
49 // border ("extended" because we map 569.5 VDP pixels to 640 host pixels).
50 // This prevents "inventing" new pixels that the real VDP would not
51 // render (e.g. by rapidly changing the border-color register). So we
52 // only extend actual VDP pixels.
53 //
54 // This was also needed to prevent a UMR:
55 // * The VDP switches to a new display mode at a specific moment in the
56 // line, for details see VDP::syncAtNextLine(). Summary: (with
57 // set-adjust=0) that is 144 cycles past the (start of the) sync
58 // signal.
59 // * Without this check, for 'absoluteX=144', this function would return
60 // a non-zero value.
61 // * Suppose we're switching from a 256 to a 512 pixel wide mode. This
62 // switch happens at cycle=144, but that meant the first few pixels
63 // are still renderer at width=256 and the rest of the line at
64 // width=512. But, without this check, that meant some pixels in the
65 // 640-pixel wide host buffer are never written, resulting in a UMR.
66 // * Clipping to TICKS_{LEFT,RIGHT}_BORDER prevents this.
67 if (absoluteX < TICKS_LEFT_BORDER) return 0;
68 if (absoluteX > TICKS_RIGHT_BORDER) return maxX;
69
70 // Note: The ROUND_MASK forces the ticks to a pixel (2-tick) boundary.
71 // If this is not done, rounding errors will occur.
72 const int ROUND_MASK = narrow ? ~1 : ~3;
73 return ((absoluteX - (TICKS_VISIBLE_MIDDLE & ROUND_MASK))
74 >> (narrow ? 1 : 2))
75 + maxX / 2;
76}
77
78inline void SDLRasterizer::renderBitmapLine(std::span<Pixel> buf, unsigned vramLine)
79{
80 if (vdp.getDisplayMode().isPlanar()) {
81 auto [vramPtr0, vramPtr1] =
82 vram.bitmapCacheWindow.getReadAreaPlanar<256>(vramLine * 256);
83 bitmapConverter.convertLinePlanar(buf, vramPtr0, vramPtr1);
84 } else {
85 auto vramPtr =
86 vram.bitmapCacheWindow.getReadArea<128>(vramLine * 128);
87 bitmapConverter.convertLine(buf, vramPtr);
88 }
89}
90
92 VDP& vdp_, Display& display, OutputSurface& screen_,
93 std::unique_ptr<PostProcessor> postProcessor_)
94 : vdp(vdp_), vram(vdp.getVRAM())
95 , screen(screen_)
96 , postProcessor(std::move(postProcessor_))
97 , workFrame(std::make_unique<RawFrame>(640, 240))
98 , renderSettings(display.getRenderSettings())
99 , characterConverter(vdp, subspan<16>(palFg), palBg)
100 , bitmapConverter(palFg, PALETTE256, V9958_COLORS)
101 , spriteConverter(vdp.getSpriteChecker(), palBg)
102{
103 // Init the palette.
104 precalcPalette();
105
106 // Initialize palette (avoid UMR)
107 if (!vdp.isMSX1VDP()) {
108 for (auto i : xrange(16)) {
109 palFg[i] = palFg[i + 16] = palBg[i] =
110 V9938_COLORS[0][0][0];
111 }
112 }
113
114 renderSettings.getGammaSetting() .attach(*this);
115 renderSettings.getBrightnessSetting() .attach(*this);
116 renderSettings.getContrastSetting() .attach(*this);
117 renderSettings.getColorMatrixSetting().attach(*this);
118}
119
121{
122 renderSettings.getColorMatrixSetting().detach(*this);
123 renderSettings.getGammaSetting() .detach(*this);
124 renderSettings.getBrightnessSetting() .detach(*this);
125 renderSettings.getContrastSetting() .detach(*this);
126}
127
129{
130 return postProcessor.get();
131}
132
134{
135 return postProcessor->needRender() &&
136 vdp.getMotherBoard().isActive() &&
138}
139
141{
142 // Init renderer state.
144 spriteConverter.setTransparency(vdp.getTransparency());
145
146 resetPalette();
147}
148
149void SDLRasterizer::resetPalette()
150{
151 if (!vdp.isMSX1VDP()) {
152 // Reset the palette.
153 for (auto i : xrange(16)) {
154 setPalette(i, vdp.getPalette(i));
155 }
156 }
157}
158
160{
161 postProcessor->setSuperimposeVideoFrame(videoSource);
162 precalcColorIndex0(vdp.getDisplayMode(), vdp.getTransparency(),
163 videoSource, vdp.getBackgroundColor());
164}
165
166void SDLRasterizer::frameStart(EmuTime::param time)
167{
168 workFrame = postProcessor->rotateFrames(std::move(workFrame), time);
169 workFrame->init(
173
174 // Calculate line to render at top of screen.
175 // Make sure the display area is centered.
176 // 240 - 212 = 28 lines available for top/bottom border; 14 each.
177 // NTSC: display at [32..244),
178 // PAL: display at [59..271).
179 lineRenderTop = vdp.isPalTiming() ? 59 - 14 : 32 - 14;
180}
181
183{
184}
185
187{
188 if (mode.isBitmapMode()) {
189 bitmapConverter.setDisplayMode(mode);
190 } else {
191 characterConverter.setDisplayMode(mode);
192 }
193 precalcColorIndex0(mode, vdp.getTransparency(),
195 spriteConverter.setDisplayMode(mode);
196 spriteConverter.setPalette(mode.getByte() == DisplayMode::GRAPHIC7
197 ? palGraphic7Sprites : palBg);
198
199}
200
201void SDLRasterizer::setPalette(unsigned index, int grb)
202{
203 // Update SDL colors in palette.
204 Pixel newColor = V9938_COLORS[(grb >> 4) & 7][grb >> 8][grb & 7];
205 palFg[index ] = newColor;
206 palFg[index + 16] = newColor;
207 palBg[index ] = newColor;
208 bitmapConverter.palette16Changed();
209
210 precalcColorIndex0(vdp.getDisplayMode(), vdp.getTransparency(),
212}
213
215{
217 precalcColorIndex0(vdp.getDisplayMode(), vdp.getTransparency(),
218 vdp.isSuperimposing(), index);
219 }
220}
221
223{
224}
225
227{
228}
229
230void SDLRasterizer::setBorderMask(bool /*masked*/)
231{
232}
233
235{
236 spriteConverter.setTransparency(enabled);
237 precalcColorIndex0(vdp.getDisplayMode(), enabled,
239}
240
241void SDLRasterizer::precalcPalette()
242{
243 if (vdp.isMSX1VDP()) {
244 // Fixed palette.
245 const auto palette = vdp.getMSX1Palette();
246 for (auto i : xrange(16)) {
247 const auto rgb = palette[i];
248 palFg[i] = palFg[i + 16] = palBg[i] =
249 screen.mapRGB(
250 renderSettings.transformRGB(
251 vec3(rgb[0], rgb[1], rgb[2]) * (1.0f / 255.0f)));
252 }
253 } else {
254 if (vdp.hasYJK()) {
255 // Precalculate palette for V9958 colors.
256 if (renderSettings.isColorMatrixIdentity()) {
257 // Most users use the "normal" monitor type; making this a
258 // special case speeds up palette precalculation a lot.
259 std::array<int, 32> intensity;
260 for (auto [i, r] : enumerate(intensity)) {
261 r = narrow_cast<int>(255.0f * renderSettings.transformComponent(narrow<float>(i) * (1.0f / 31.0f)));
262 }
263 for (auto [rgb, col] : enumerate(V9958_COLORS)) {
264 col = screen.mapRGB255(ivec3(
265 intensity[(rgb >> 10) & 31],
266 intensity[(rgb >> 5) & 31],
267 intensity[(rgb >> 0) & 31]));
268 }
269 } else {
270 for (auto r : xrange(32)) {
271 for (auto g : xrange(32)) {
272 for (auto b : xrange(32)) {
273 vec3 rgb{narrow<float>(r),
274 narrow<float>(g),
275 narrow<float>(b)};
276 V9958_COLORS[(r << 10) + (g << 5) + b] =
277 screen.mapRGB(
278 renderSettings.transformRGB(rgb * (1.0f / 31.0f)));
279 }
280 }
281 }
282 }
283 // Precalculate palette for V9938 colors.
284 // Based on comparing red and green gradients, using palette and
285 // YJK, in SCREEN11 on a real turbo R.
286 for (auto r3 : xrange(8)) {
287 int r5 = (r3 << 2) | (r3 >> 1);
288 for (auto g3 : xrange(8)) {
289 int g5 = (g3 << 2) | (g3 >> 1);
290 for (auto b3 : xrange(8)) {
291 int b5 = (b3 << 2) | (b3 >> 1);
292 V9938_COLORS[r3][g3][b3] =
293 V9958_COLORS[(r5 << 10) + (g5 << 5) + b5];
294 }
295 }
296 }
297 } else {
298 // Precalculate palette for V9938 colors.
299 if (renderSettings.isColorMatrixIdentity()) {
300 std::array<int, 8> intensity;
301 for (auto [i, r] : enumerate(intensity)) {
302 r = narrow_cast<int>(255.0f * renderSettings.transformComponent(narrow<float>(i) * (1.0f / 7.0f)));
303 }
304 for (auto r : xrange(8)) {
305 for (auto g : xrange(8)) {
306 for (auto b : xrange(8)) {
307 V9938_COLORS[r][g][b] =
308 screen.mapRGB255(ivec3(
309 intensity[r],
310 intensity[g],
311 intensity[b]));
312 }
313 }
314 }
315 } else {
316 for (auto r : xrange(8)) {
317 for (auto g : xrange(8)) {
318 for (auto b : xrange(8)) {
319 vec3 rgb{narrow<float>(r),
320 narrow<float>(g),
321 narrow<float>(b)};
322 V9938_COLORS[r][g][b] =
323 screen.mapRGB(
324 renderSettings.transformRGB(rgb * (1.0f / 7.0f)));
325 }
326 }
327 }
328 }
329 }
330 // Precalculate Graphic 7 bitmap palette.
331 for (auto i : xrange(256)) {
332 PALETTE256[i] = V9938_COLORS
333 [(i & 0x1C) >> 2]
334 [(i & 0xE0) >> 5]
335 [(i & 0x03) == 3 ? 7 : (i & 0x03) * 2];
336 }
337 // Precalculate Graphic 7 sprite palette.
338 for (auto i : xrange(16)) {
339 uint16_t grb = Renderer::GRAPHIC7_SPRITE_PALETTE[i];
340 palGraphic7Sprites[i] =
341 V9938_COLORS[(grb >> 4) & 7][grb >> 8][grb & 7];
342 }
343 }
344}
345
346void SDLRasterizer::precalcColorIndex0(DisplayMode mode,
347 bool transparency, const RawFrame* superimposing, byte bgColorIndex)
348{
349 // Graphic7 mode doesn't use transparency.
350 if (mode.getByte() == DisplayMode::GRAPHIC7) {
351 transparency = false;
352 }
353
354 int tpIndex = transparency ? bgColorIndex : 0;
355 if (mode.getBase() != DisplayMode::GRAPHIC5) {
356 Pixel c = (superimposing && (bgColorIndex == 0))
357 ? screen.getKeyColor()
358 : palBg[tpIndex];
359
360 if (palFg[0] != c) {
361 palFg[0] = c;
362 bitmapConverter.palette16Changed();
363 }
364 } else {
365 // TODO: superimposing
366 if ((palFg[ 0] != palBg[tpIndex >> 2]) ||
367 (palFg[16] != palBg[tpIndex & 3])) {
368 palFg[ 0] = palBg[tpIndex >> 2];
369 palFg[16] = palBg[tpIndex & 3];
370 bitmapConverter.palette16Changed();
371 }
372 }
373}
374
375std::pair<Pixel, Pixel> SDLRasterizer::getBorderColors()
376{
377 DisplayMode mode = vdp.getDisplayMode();
378 int bgColor = vdp.getBackgroundColor();
379 if (mode.getBase() == DisplayMode::GRAPHIC5) {
380 // border in SCREEN6 has separate color for even and odd pixels.
381 // TODO odd/even swapped?
382 return {palBg[(bgColor & 0x0C) >> 2],
383 palBg[(bgColor & 0x03) >> 0]};
384 }
385 Pixel col = [&] { // other modes only have a single border color
386 if (mode.getByte() == DisplayMode::GRAPHIC7) {
387 return PALETTE256[bgColor];
388 } else {
389 if (!bgColor && vdp.isSuperimposing()) {
390 return screen.getKeyColor();
391 } else {
392 return palBg[bgColor];
393 }
394 }
395 }();
396 return {col, col};
397}
398
400 int fromX, int fromY, int limitX, int limitY)
401{
402 auto [border0, border1] = getBorderColors();
403
404 int startY = std::max(fromY - lineRenderTop, 0);
405 int endY = std::min(limitY - lineRenderTop, 240);
406 if ((fromX == 0) && (limitX == VDP::TICKS_PER_LINE) &&
407 (border0 == border1)) {
408 // complete lines, non striped
409 for (auto y : xrange(startY, endY)) {
410 workFrame->setBlank(y, border0);
411 // setBlank() implies this line is not suitable
412 // for left/right border optimization in a later
413 // frame.
414 }
415 } else {
416 unsigned lineWidth = vdp.getDisplayMode().getLineWidth();
417 unsigned x = translateX(fromX, (lineWidth == 512));
418 unsigned num = translateX(limitX, (lineWidth == 512)) - x;
419 unsigned width = (lineWidth == 512) ? 640 : 320;
420 for (auto y : xrange(startY, endY)) {
421 MemoryOps::fill_2(workFrame->getLineDirect(y).subspan(x, num),
422 border0, border1);
423 if (limitX == VDP::TICKS_PER_LINE) {
424 // Only set line width at the end (right
425 // border) of the line. This ensures we can
426 // keep testing the width of the previous
427 // version of this line for all (partial)
428 // updates of this line.
429 workFrame->setLineWidth(y, width);
430 }
431 }
432 }
433}
434
436 int /*fromX*/, int fromY,
437 int displayX, int displayY,
438 int displayWidth, int displayHeight)
439{
440 // Note: we don't call workFrame->setLineWidth() because that's done in
441 // drawBorder() (for the right border). And the value we set there is
442 // anyway the same as the one we would set here.
443 DisplayMode mode = vdp.getDisplayMode();
444 unsigned lineWidth = mode.getLineWidth();
445 if (lineWidth == 256) {
446 int endX = displayX + displayWidth;
447 displayX /= 2;
448 displayWidth = endX / 2 - displayX;
449 }
450
451 // Clip to screen area.
452 int screenLimitY = std::min(
453 fromY + displayHeight - lineRenderTop,
454 240);
455 int screenY = fromY - lineRenderTop;
456 if (screenY < 0) {
457 displayY -= screenY;
458 //fromY = lineRenderTop;
459 screenY = 0;
460 }
461 displayHeight = screenLimitY - screenY;
462 if (displayHeight <= 0) return;
463
464 int leftBackground =
465 translateX(vdp.getLeftBackground(), lineWidth == 512);
466 // TODO: Find out why this causes 1-pixel jitter:
467 //dest.x = translateX(fromX);
468 unsigned hScroll =
469 mode.isTextMode()
470 ? 0
471 : 8 * (lineWidth / 256) * (vdp.getHorizontalScrollHigh() & 0x1F);
472
473 // Page border is display X coordinate where to stop drawing current page.
474 // This is either the multi page split point, or the right edge of the
475 // rectangle to draw, whichever comes first.
476 // Note that it is possible for pageBorder to be to the left of displayX,
477 // in that case only the second page should be drawn.
478 int pageBorder = displayX + displayWidth;
479 auto [scrollPage1, scrollPage2] = [&]() -> std::pair<int, int> {
480 if (vdp.isMultiPageScrolling()) {
481 int p1 = vdp.getHorizontalScrollHigh() >> 5;
482 int p2 = p1 ^ 1;
483 return {p1, p2};
484 } else {
485 return {0, 0};
486 }
487 }();
488 // Because SDL blits do not wrap, unlike GL textures, the pageBorder is
489 // also used if multi page is disabled.
490 if (int pageSplit = narrow<int>(lineWidth - hScroll);
491 pageSplit < pageBorder) {
492 pageBorder = pageSplit;
493 }
494
495 if (mode.isBitmapMode()) {
496 for (auto y : xrange(screenY, screenLimitY)) {
497 // Which bits in the name mask determine the page?
498 // TODO optimize this?
499 // Calculating pageMaskOdd/Even is a non-trivial amount
500 // of work. We used to do this per frame (more or less)
501 // but now do it per line. Per-line is actually only
502 // needed when vdp.isFastBlinkEnabled() is true.
503 // Idea: can be cheaply calculated incrementally.
504 unsigned pageMaskOdd = (mode.isPlanar() ? 0x000 : 0x200) |
505 vdp.getEvenOddMask(y);
506 unsigned pageMaskEven = vdp.isMultiPageScrolling()
507 ? (pageMaskOdd & ~0x100)
508 : pageMaskOdd;
509 const std::array<unsigned, 2> vramLine = {
510 (vram.nameTable.getMask() >> 7) & (pageMaskEven | displayY),
511 (vram.nameTable.getMask() >> 7) & (pageMaskOdd | displayY)
512 };
513
514 std::array<Pixel, 512> buf;
515 auto lineInBuf = unsigned(-1); // buffer data not valid
516 auto dst = workFrame->getLineDirect(y).subspan(leftBackground + displayX);
517 int firstPageWidth = pageBorder - displayX;
518 if (firstPageWidth > 0) {
519 if (((displayX + hScroll) == 0) &&
520 (firstPageWidth == narrow<int>(lineWidth))) {
521 // fast-path, directly render to destination
522 renderBitmapLine(dst, vramLine[scrollPage1]);
523 } else {
524 lineInBuf = vramLine[scrollPage1];
525 renderBitmapLine(buf, vramLine[scrollPage1]);
526 auto src = subspan(buf, displayX + hScroll, firstPageWidth);
527 ranges::copy(src, dst);
528 }
529 } else {
530 firstPageWidth = 0;
531 }
532 if (firstPageWidth < displayWidth) {
533 if (lineInBuf != vramLine[scrollPage2]) {
534 renderBitmapLine(buf, vramLine[scrollPage2]);
535 }
536 unsigned x = displayX < pageBorder
537 ? 0 : displayX + hScroll - lineWidth;
538 ranges::copy(subspan(buf, x, displayWidth - firstPageWidth),
539 subspan(dst, firstPageWidth));
540 }
541
542 displayY = (displayY + 1) & 255;
543 }
544 } else {
545 // horizontal scroll (high) is implemented in CharacterConverter
546 for (auto y : xrange(screenY, screenLimitY)) {
547 assert(!vdp.isMSX1VDP() || displayY < 192);
548
549 auto dst = workFrame->getLineDirect(y).subspan(leftBackground + displayX);
550 if ((displayX == 0) && (displayWidth == narrow<int>(lineWidth))){
551 characterConverter.convertLine(dst, displayY);
552 } else {
553 std::array<Pixel, 512> buf;
554 characterConverter.convertLine(buf, displayY);
555 auto src = subspan(buf, displayX, displayWidth);
556 ranges::copy(src, dst);
557 }
558
559 displayY = (displayY + 1) & 255;
560 }
561 }
562}
563
565 int /*fromX*/, int fromY,
566 int displayX, int /*displayY*/,
567 int displayWidth, int displayHeight)
568{
569 // Clip to screen area.
570 // TODO: Code duplicated from drawDisplay.
571 int screenLimitY = std::min(
572 fromY + displayHeight - lineRenderTop,
573 240);
574 int screenY = fromY - lineRenderTop;
575 if (screenY < 0) {
576 fromY = lineRenderTop;
577 screenY = 0;
578 }
579 displayHeight = screenLimitY - screenY;
580 if (displayHeight <= 0) return;
581
582 // Render sprites.
583 // TODO: Call different SpriteConverter methods depending on narrow/wide
584 // pixels in this display mode?
585 int spriteMode = vdp.getDisplayMode().getSpriteMode(vdp.isMSX1VDP());
586 int displayLimitX = displayX + displayWidth;
587 int limitY = fromY + displayHeight;
588 int screenX = translateX(
589 vdp.getLeftSprites(),
590 vdp.getDisplayMode().getLineWidth() == 512);
591 if (spriteMode == 1) {
592 for (int y = fromY; y < limitY; y++, screenY++) {
593 auto dst = workFrame->getLineDirect(screenY).subspan(screenX);
594 spriteConverter.drawMode1(y, displayX, displayLimitX, dst);
595 }
596 } else {
597 byte mode = vdp.getDisplayMode().getByte();
598 if (mode == DisplayMode::GRAPHIC5) {
599 for (int y = fromY; y < limitY; y++, screenY++) {
600 auto dst = workFrame->getLineDirect(screenY).subspan(screenX);
601 spriteConverter.template drawMode2<DisplayMode::GRAPHIC5>(
602 y, displayX, displayLimitX, dst);
603 }
604 } else if (mode == DisplayMode::GRAPHIC6) {
605 for (int y = fromY; y < limitY; y++, screenY++) {
606 auto dst = workFrame->getLineDirect(screenY).subspan(screenX);
607 spriteConverter.template drawMode2<DisplayMode::GRAPHIC6>(
608 y, displayX, displayLimitX, dst);
609 }
610 } else {
611 for (int y = fromY; y < limitY; y++, screenY++) {
612 auto dst = workFrame->getLineDirect(screenY).subspan(screenX);
613 spriteConverter.template drawMode2<DisplayMode::GRAPHIC4>(
614 y, displayX, displayLimitX, dst);
615 }
616 }
617 }
618}
619
621{
622 return postProcessor->isRecording();
623}
624
625void SDLRasterizer::update(const Setting& setting) noexcept
626{
627 if (&setting == one_of(&renderSettings.getGammaSetting(),
628 &renderSettings.getBrightnessSetting(),
629 &renderSettings.getContrastSetting(),
630 &renderSettings.getColorMatrixSetting())) {
631 precalcPalette();
632 resetPalette();
633 }
634}
635
636} // namespace openmsx
BaseSetting * setting
int g
void convertLinePlanar(std::span< Pixel > buf, std::span< const byte, 128 > vramPtr0, std::span< const byte, 128 > vramPtr1)
Convert a line of V9938 VRAM to 256 or 512 host pixels.
void convertLine(std::span< Pixel > buf, std::span< const byte, 128 > vramPtr)
Convert a line of V9938 VRAM to 256 or 512 host pixels.
void palette16Changed()
Inform this class about changes in the palette16 array.
void setDisplayMode(DisplayMode mode_)
Select the display mode to use for scanline conversion.
void setDisplayMode(DisplayMode mode)
Select the display mode to use for scanline conversion.
void convertLine(std::span< Pixel > buf, int line) const
Convert a line of V9938 VRAM to 256 or 512 host pixels.
Represents a VDP 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,...
static constexpr uint8_t GRAPHIC5
constexpr unsigned getLineWidth() const
Get number of pixels on a display line in this mode.
static constexpr uint8_t GRAPHIC7
constexpr bool isBitmapMode() const
Is the current mode a bitmap mode? Graphic4 and higher are bitmap modes.
static constexpr uint8_t GRAPHIC6
constexpr bool isTextMode() const
Is the current mode a text mode? Text1 and Text2 are text modes.
constexpr byte getByte() const
Get the display mode as a byte: YAE YJK M5..M1 combined.
constexpr int getSpriteMode(bool isMSX1) const
Get the sprite mode of this display mode.
Represents the output window/screen of openMSX.
Definition Display.hh:31
@ ODD
Interlacing is on and this is an odd frame.
@ EVEN
Interlacing is on and this is an even frame.
@ NONINTERLACED
Interlacing is off for this frame.
MSXMotherBoard & getMotherBoard() const
Get the mother board this device belongs to.
Definition MSXDevice.cc:70
A frame buffer where pixels can be written to.
uint32_t mapRGB255(gl::ivec3 rgb) const
Same as mapRGB, but RGB components are in range [0..255].
Pixel getKeyColor() const
Returns the color key for this output surface.
uint32_t mapRGB(gl::vec3 rgb) const
Returns the pixel value for the given RGB color.
A post processor builds the frame that is displayed from the MSX frame, while applying effects such a...
A video frame as output by the VDP scanline conversion unit, before any postprocessing filters are ap...
Definition RawFrame.hh:16
float transformComponent(float c) const
Apply brightness, contrast and gamma transformation on the input color component.
gl::vec3 transformRGB(gl::vec3 rgb) const
Apply brightness, contrast and gamma transformation on the input color.
bool isColorMatrixIdentity() const
Returns true iff the current color matrix is the identity matrix.
FloatSetting & getContrastSetting()
Contrast video setting.
FloatSetting & getBrightnessSetting()
Brightness video setting.
FloatSetting & getGammaSetting()
The amount of gamma correction.
StringSetting & getColorMatrixSetting()
Color matrix setting.
static constexpr std::array< uint16_t, 16 > GRAPHIC7_SPRITE_PALETTE
Sprite palette in Graphic 7 mode.
Definition Renderer.hh:186
PostProcessor * getPostProcessor() const override
See VDP::getPostProcessor().
bool isActive() override
Will the output of this Rasterizer be displayed? There is no point in producing a frame that will not...
void setBackgroundColor(byte index) override
Changes the background color.
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.
void setPalette(unsigned index, int grb) override
Change an entry in the palette.
void frameEnd() override
Indicates the end of the current frame.
void setBorderMask(bool masked) override
void frameStart(EmuTime::param time) override
Indicates the start of a new frame.
void setHorizontalAdjust(int adjust) override
SDLRasterizer(VDP &vdp, Display &display, OutputSurface &screen, std::unique_ptr< PostProcessor > postProcessor)
void setDisplayMode(DisplayMode mode) override
Precalc several values that depend on the display mode.
void drawBorder(int fromX, int fromY, int limitX, int limitY) override
Render a rectangle of border pixels on the host screen.
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.
void reset() override
Resynchronize with VDP: all cached states are flushed.
bool isRecording() const override
Is video recording active?
void setTransparency(bool enabled) override
void setSuperimposeVideoFrame(const RawFrame *videoSource) override
void setHorizontalScrollLow(byte scroll) override
void drawMode1(int absLine, int minX, int maxX, std::span< Pixel > pixelPtr) const
Draw sprites in sprite mode 1.
void setTransparency(bool enabled)
Update the transparency setting.
void setDisplayMode(DisplayMode newMode)
Notify SpriteConverter of a display mode change.
void setPalette(std::span< const Pixel, 16 > newPalette)
Set palette to use for converting sprites.
void detach(Observer< T > &observer)
Definition Subject.hh:60
void attach(Observer< T > &observer)
Definition Subject.hh:54
VRAMWindow bitmapCacheWindow
Definition VDPVRAM.hh:693
VRAMWindow nameTable
Definition VDPVRAM.hh:689
Unified implementation of MSX Video Display Processors (VDPs).
Definition VDP.hh:67
bool getEvenOdd() const
Is the even or odd field being displayed?
Definition VDP.hh:439
unsigned getEvenOddMask() const
Expresses the state of even/odd page interchange in a mask on the line number.
Definition VDP.hh:454
int getLeftBackground() const
Gets the number of VDP clock ticks between start of line and the time when the background pixel with ...
Definition VDP.hh:626
std::array< std::array< uint8_t, 3 >, 16 > getMSX1Palette() const
Get the (fixed) palette for this MSX1 VDP.
Definition VDP.cc:1544
const RawFrame * isSuperimposing() const
Are we currently superimposing? In case of superimpose, returns a pointer to the to-be-superimposed f...
Definition VDP.hh:170
static constexpr int TICKS_PER_LINE
Number of VDP clock ticks per line.
Definition VDP.hh:76
uint16_t getPalette(unsigned index) const
Gets a palette entry.
Definition VDP.hh:279
byte getHorizontalScrollHigh() const
Gets the current horizontal scroll higher bits.
Definition VDP.hh:349
DisplayMode getDisplayMode() const
Get the display mode the VDP is in.
Definition VDP.hh:156
bool isMSX1VDP() const
Is this an MSX1 VDP?
Definition VDP.hh:108
byte getBackgroundColor() const
Gets the current background color.
Definition VDP.hh:219
bool hasYJK() const
Does this VDP support YJK display?
Definition VDP.hh:143
bool isMultiPageScrolling() const
Is multi page scrolling enabled? It is considered enabled if both the multi page scrolling flag is en...
Definition VDP.hh:368
bool isPalTiming() const
Is PAL timing active? This setting is fixed at start of frame.
Definition VDP.hh:391
bool isInterlaced() const
Get interlace status.
Definition VDP.hh:402
bool getTransparency() const
Gets the current transparency setting.
Definition VDP.hh:189
int getLeftSprites() const
Gets the number of VDP clock ticks between start of line and the start of the sprite plane.
Definition VDP.hh:598
unsigned getMask() const
Gets the mask for this window.
Definition VDPVRAM.hh:147
std::pair< std::span< const byte, size/2 >, std::span< const byte, size/2 > > getReadAreaPlanar(unsigned index) const
Similar to getReadArea(), but now with planar addressing mode.
Definition VDPVRAM.hh:245
std::span< const byte, size > getReadArea(unsigned index) const
Gets a span of a contiguous part of the VRAM.
Definition VDPVRAM.hh:228
constexpr auto enumerate(Iterable &&iterable)
Heavily inspired by Nathan Reed's blog post: Python-Like enumerate() In C++17 http://reedbeta....
Definition enumerate.hh:28
Definition gl_mat.hh:23
vecN< 3, int > ivec3
Definition gl_vec.hh:386
void fill_2(std::span< uint32_t > out, uint32_t val0, uint32_t val1)
Definition MemoryOps.cc:16
This file implemented 3 utility functions:
Definition Autofire.cc:11
CharacterConverter::Pixel Pixel
constexpr auto copy(InputRange &&range, OutputIter out)
Definition ranges.hh:252
STL namespace.
constexpr To narrow(From from) noexcept
Definition narrow.hh:37
constexpr auto subspan(Range &&range, size_t offset, size_t count=std::dynamic_extent)
Definition ranges.hh:481
constexpr auto xrange(T e)
Definition xrange.hh:132