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;
421 for (auto y : xrange(startY, endY)) {
422 memset(workFrame->getLineDirect(y).subspan(x, num),
423 border0, border1);
424 if (limitX == VDP::TICKS_PER_LINE) {
425 // Only set line width at the end (right
426 // border) of the line. This ensures we can
427 // keep testing the width of the previous
428 // version of this line for all (partial)
429 // updates of this line.
430 workFrame->setLineWidth(y, width);
431 }
432 }
433 }
434}
435
437 int /*fromX*/, int fromY,
438 int displayX, int displayY,
439 int displayWidth, int displayHeight)
440{
441 // Note: we don't call workFrame->setLineWidth() because that's done in
442 // drawBorder() (for the right border). And the value we set there is
443 // anyway the same as the one we would set here.
444 DisplayMode mode = vdp.getDisplayMode();
445 unsigned lineWidth = mode.getLineWidth();
446 if (lineWidth == 256) {
447 int endX = displayX + displayWidth;
448 displayX /= 2;
449 displayWidth = endX / 2 - displayX;
450 }
451
452 // Clip to screen area.
453 int screenLimitY = std::min(
454 fromY + displayHeight - lineRenderTop,
455 240);
456 int screenY = fromY - lineRenderTop;
457 if (screenY < 0) {
458 displayY -= screenY;
459 //fromY = lineRenderTop;
460 screenY = 0;
461 }
462 displayHeight = screenLimitY - screenY;
463 if (displayHeight <= 0) return;
464
465 int leftBackground =
466 translateX(vdp.getLeftBackground(), lineWidth == 512);
467 // TODO: Find out why this causes 1-pixel jitter:
468 //dest.x = translateX(fromX);
469 unsigned hScroll =
470 mode.isTextMode()
471 ? 0
472 : 8 * (lineWidth / 256) * (vdp.getHorizontalScrollHigh() & 0x1F);
473
474 // Page border is display X coordinate where to stop drawing current page.
475 // This is either the multi page split point, or the right edge of the
476 // rectangle to draw, whichever comes first.
477 // Note that it is possible for pageBorder to be to the left of displayX,
478 // in that case only the second page should be drawn.
479 int pageBorder = displayX + displayWidth;
480 auto [scrollPage1, scrollPage2] = [&]() -> std::pair<int, int> {
481 if (vdp.isMultiPageScrolling()) {
482 int p1 = vdp.getHorizontalScrollHigh() >> 5;
483 int p2 = p1 ^ 1;
484 return {p1, p2};
485 } else {
486 return {0, 0};
487 }
488 }();
489 // Because SDL blits do not wrap, unlike GL textures, the pageBorder is
490 // also used if multi page is disabled.
491 if (int pageSplit = narrow<int>(lineWidth - hScroll);
492 pageSplit < pageBorder) {
493 pageBorder = pageSplit;
494 }
495
496 if (mode.isBitmapMode()) {
497 for (auto y : xrange(screenY, screenLimitY)) {
498 // Which bits in the name mask determine the page?
499 // TODO optimize this?
500 // Calculating pageMaskOdd/Even is a non-trivial amount
501 // of work. We used to do this per frame (more or less)
502 // but now do it per line. Per-line is actually only
503 // needed when vdp.isFastBlinkEnabled() is true.
504 // Idea: can be cheaply calculated incrementally.
505 unsigned pageMaskOdd = (mode.isPlanar() ? 0x000 : 0x200) |
506 vdp.getEvenOddMask(y);
507 unsigned pageMaskEven = vdp.isMultiPageScrolling()
508 ? (pageMaskOdd & ~0x100)
509 : pageMaskOdd;
510 const std::array<unsigned, 2> vramLine = {
511 (vram.nameTable.getMask() >> 7) & (pageMaskEven | displayY),
512 (vram.nameTable.getMask() >> 7) & (pageMaskOdd | displayY)
513 };
514
515 std::array<Pixel, 512> buf;
516 auto lineInBuf = unsigned(-1); // buffer data not valid
517 auto dst = workFrame->getLineDirect(y).subspan(leftBackground + displayX);
518 int firstPageWidth = pageBorder - displayX;
519 if (firstPageWidth > 0) {
520 if (((displayX + hScroll) == 0) &&
521 (firstPageWidth == narrow<int>(lineWidth))) {
522 // fast-path, directly render to destination
523 renderBitmapLine(dst, vramLine[scrollPage1]);
524 } else {
525 lineInBuf = vramLine[scrollPage1];
526 renderBitmapLine(buf, vramLine[scrollPage1]);
527 auto src = subspan(buf, displayX + hScroll, firstPageWidth);
528 ranges::copy(src, dst);
529 }
530 } else {
531 firstPageWidth = 0;
532 }
533 if (firstPageWidth < displayWidth) {
534 if (lineInBuf != vramLine[scrollPage2]) {
535 renderBitmapLine(buf, vramLine[scrollPage2]);
536 }
537 unsigned x = displayX < pageBorder
538 ? 0 : displayX + hScroll - lineWidth;
539 ranges::copy(subspan(buf, x, displayWidth - firstPageWidth),
540 subspan(dst, firstPageWidth));
541 }
542
543 displayY = (displayY + 1) & 255;
544 }
545 } else {
546 // horizontal scroll (high) is implemented in CharacterConverter
547 for (auto y : xrange(screenY, screenLimitY)) {
548 assert(!vdp.isMSX1VDP() || displayY < 192);
549
550 auto dst = workFrame->getLineDirect(y).subspan(leftBackground + displayX);
551 if ((displayX == 0) && (displayWidth == narrow<int>(lineWidth))){
552 characterConverter.convertLine(dst, displayY);
553 } else {
554 std::array<Pixel, 512> buf;
555 characterConverter.convertLine(buf, displayY);
556 auto src = subspan(buf, displayX, displayWidth);
557 ranges::copy(src, dst);
558 }
559
560 displayY = (displayY + 1) & 255;
561 }
562 }
563}
564
566 int /*fromX*/, int fromY,
567 int displayX, int /*displayY*/,
568 int displayWidth, int displayHeight)
569{
570 // Clip to screen area.
571 // TODO: Code duplicated from drawDisplay.
572 int screenLimitY = std::min(
573 fromY + displayHeight - lineRenderTop,
574 240);
575 int screenY = fromY - lineRenderTop;
576 if (screenY < 0) {
577 fromY = lineRenderTop;
578 screenY = 0;
579 }
580 displayHeight = screenLimitY - screenY;
581 if (displayHeight <= 0) return;
582
583 // Render sprites.
584 // TODO: Call different SpriteConverter methods depending on narrow/wide
585 // pixels in this display mode?
586 int spriteMode = vdp.getDisplayMode().getSpriteMode(vdp.isMSX1VDP());
587 int displayLimitX = displayX + displayWidth;
588 int limitY = fromY + displayHeight;
589 int screenX = translateX(
590 vdp.getLeftSprites(),
591 vdp.getDisplayMode().getLineWidth() == 512);
592 if (spriteMode == 1) {
593 for (int y = fromY; y < limitY; y++, screenY++) {
594 auto dst = workFrame->getLineDirect(screenY).subspan(screenX);
595 spriteConverter.drawMode1(y, displayX, displayLimitX, dst);
596 }
597 } else {
598 byte mode = vdp.getDisplayMode().getByte();
599 if (mode == DisplayMode::GRAPHIC5) {
600 for (int y = fromY; y < limitY; y++, screenY++) {
601 auto dst = workFrame->getLineDirect(screenY).subspan(screenX);
602 spriteConverter.template drawMode2<DisplayMode::GRAPHIC5>(
603 y, displayX, displayLimitX, dst);
604 }
605 } else if (mode == DisplayMode::GRAPHIC6) {
606 for (int y = fromY; y < limitY; y++, screenY++) {
607 auto dst = workFrame->getLineDirect(screenY).subspan(screenX);
608 spriteConverter.template drawMode2<DisplayMode::GRAPHIC6>(
609 y, displayX, displayLimitX, dst);
610 }
611 } else {
612 for (int y = fromY; y < limitY; y++, screenY++) {
613 auto dst = workFrame->getLineDirect(screenY).subspan(screenX);
614 spriteConverter.template drawMode2<DisplayMode::GRAPHIC4>(
615 y, displayX, displayLimitX, dst);
616 }
617 }
618 }
619}
620
622{
623 return postProcessor->isRecording();
624}
625
626void SDLRasterizer::update(const Setting& setting) noexcept
627{
628 if (&setting == one_of(&renderSettings.getGammaSetting(),
629 &renderSettings.getBrightnessSetting(),
630 &renderSettings.getContrastSetting(),
631 &renderSettings.getColorMatrixSetting())) {
632 precalcPalette();
633 resetPalette();
634 }
635}
636
637} // 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:1543
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:182
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