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