28static constexpr int TICKS_LEFT_BORDER = 100 + 102;
29static constexpr int TICKS_RIGHT_BORDER = 100 + 102 + 56 + 1024 + 59;
35static constexpr int TICKS_VISIBLE_MIDDLE =
44static constexpr int translateX(
int absoluteX,
bool narrow)
46 int maxX =
narrow ? 640 : 320;
67 if (absoluteX < TICKS_LEFT_BORDER)
return 0;
68 if (absoluteX > TICKS_RIGHT_BORDER)
return maxX;
72 const int ROUND_MASK =
narrow ? ~1 : ~3;
73 return ((absoluteX - (TICKS_VISIBLE_MIDDLE & ROUND_MASK))
78inline void SDLRasterizer::renderBitmapLine(std::span<Pixel> buf,
unsigned vramLine)
81 auto [vramPtr0, vramPtr1] =
93 std::unique_ptr<PostProcessor> postProcessor_)
94 : vdp(vdp_), vram(vdp.getVRAM())
96 , postProcessor(
std::move(postProcessor_))
98 , renderSettings(display.getRenderSettings())
99 , characterConverter(vdp,
subspan<16>(palFg), palBg)
100 , bitmapConverter(palFg, PALETTE256, V9958_COLORS)
101 , spriteConverter(vdp.getSpriteChecker(), palBg)
108 for (
auto i :
xrange(16)) {
109 palFg[i] = palFg[i + 16] = palBg[i] =
110 V9938_COLORS[0][0][0];
130 return postProcessor.get();
135 return postProcessor->needRender() &&
149void SDLRasterizer::resetPalette()
153 for (
auto i :
xrange(16)) {
161 postProcessor->setSuperimposeVideoFrame(videoSource);
168 workFrame = postProcessor->rotateFrames(std::move(workFrame), time);
179 lineRenderTop = vdp.
isPalTiming() ? 59 - 14 : 32 - 14;
197 ? palGraphic7Sprites : palBg);
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;
241void SDLRasterizer::precalcPalette()
246 for (
auto i :
xrange(16)) {
247 const auto rgb = palette[i];
248 palFg[i] = palFg[i + 16] = palBg[i] =
251 vec3(rgb[0], rgb[1], rgb[2]) * (1.0f / 255.0f)));
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)));
263 for (
auto [rgb, col] :
enumerate(V9958_COLORS)) {
265 intensity[(rgb >> 10) & 31],
266 intensity[(rgb >> 5) & 31],
267 intensity[(rgb >> 0) & 31]));
270 for (
auto r :
xrange(32)) {
272 for (
auto b :
xrange(32)) {
273 vec3 rgb{narrow<float>(r),
276 V9958_COLORS[(r << 10) + (
g << 5) + b] =
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];
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)));
304 for (
auto r :
xrange(8)) {
306 for (
auto b :
xrange(8)) {
307 V9938_COLORS[r][
g][b] =
316 for (
auto r :
xrange(8)) {
318 for (
auto b :
xrange(8)) {
319 vec3 rgb{narrow<float>(r),
322 V9938_COLORS[r][
g][b] =
331 for (
auto i :
xrange(256)) {
332 PALETTE256[i] = V9938_COLORS
335 [(i & 0x03) == 3 ? 7 : (i & 0x03) * 2];
338 for (
auto i :
xrange(16)) {
340 palGraphic7Sprites[i] =
341 V9938_COLORS[(grb >> 4) & 7][grb >> 8][grb & 7];
346void SDLRasterizer::precalcColorIndex0(DisplayMode mode,
347 bool transparency,
const RawFrame* superimposing,
byte bgColorIndex)
351 transparency =
false;
354 int tpIndex = transparency ? bgColorIndex : 0;
356 Pixel c = (superimposing && (bgColorIndex == 0))
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];
375std::pair<Pixel, Pixel> SDLRasterizer::getBorderColors()
382 return {palBg[(bgColor & 0x0C) >> 2],
383 palBg[(bgColor & 0x03) >> 0]};
387 return PALETTE256[bgColor];
392 return palBg[bgColor];
400 int fromX,
int fromY,
int limitX,
int limitY)
402 auto [border0, border1] = getBorderColors();
404 int startY = std::max(fromY - lineRenderTop, 0);
405 int endY = std::min(limitY - lineRenderTop, 240);
407 (border0 == border1)) {
409 for (
auto y :
xrange(startY, endY)) {
410 workFrame->setBlank(y, border0);
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),
430 workFrame->setLineWidth(y, width);
438 int displayX,
int displayY,
439 int displayWidth,
int displayHeight)
446 if (lineWidth == 256) {
447 int endX = displayX + displayWidth;
449 displayWidth = endX / 2 - displayX;
453 int screenLimitY = std::min(
454 fromY + displayHeight - lineRenderTop,
456 int screenY = fromY - lineRenderTop;
462 displayHeight = screenLimitY - screenY;
463 if (displayHeight <= 0)
return;
479 int pageBorder = displayX + displayWidth;
480 auto [scrollPage1, scrollPage2] = [&]() -> std::pair<int, int> {
491 if (
int pageSplit = narrow<int>(lineWidth - hScroll);
492 pageSplit < pageBorder) {
493 pageBorder = pageSplit;
497 for (
auto y :
xrange(screenY, screenLimitY)) {
505 unsigned pageMaskOdd = (mode.
isPlanar() ? 0x000 : 0x200) |
508 ? (pageMaskOdd & ~0x100)
510 const std::array<unsigned, 2> vramLine = {
515 std::array<Pixel, 512> buf;
516 auto lineInBuf = unsigned(-1);
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))) {
523 renderBitmapLine(dst, vramLine[scrollPage1]);
525 lineInBuf = vramLine[scrollPage1];
526 renderBitmapLine(buf, vramLine[scrollPage1]);
527 auto src =
subspan(buf, displayX + hScroll, firstPageWidth);
533 if (firstPageWidth < displayWidth) {
534 if (lineInBuf != vramLine[scrollPage2]) {
535 renderBitmapLine(buf, vramLine[scrollPage2]);
537 unsigned x = displayX < pageBorder
538 ? 0 : displayX + hScroll - lineWidth;
543 displayY = (displayY + 1) & 255;
547 for (
auto y :
xrange(screenY, screenLimitY)) {
548 assert(!vdp.
isMSX1VDP() || displayY < 192);
550 auto dst = workFrame->getLineDirect(y).subspan(leftBackground + displayX);
551 if ((displayX == 0) && (displayWidth == narrow<int>(lineWidth))){
554 std::array<Pixel, 512> buf;
556 auto src =
subspan(buf, displayX, displayWidth);
560 displayY = (displayY + 1) & 255;
568 int displayWidth,
int displayHeight)
572 int screenLimitY = std::min(
573 fromY + displayHeight - lineRenderTop,
575 int screenY = fromY - lineRenderTop;
577 fromY = lineRenderTop;
580 displayHeight = screenLimitY - screenY;
581 if (displayHeight <= 0)
return;
587 int displayLimitX = displayX + displayWidth;
588 int limitY = fromY + displayHeight;
589 int screenX = translateX(
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);
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);
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);
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);
623 return postProcessor->isRecording();
629 &renderSettings.getBrightnessSetting(),
630 &renderSettings.getContrastSetting(),
631 &renderSettings.getColorMatrixSetting())) {
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.
@ 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.
bool isFastForwarding() const
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...
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.
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.
~SDLRasterizer() override
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)
void attach(Observer< T > &observer)
VRAMWindow bitmapCacheWindow
Unified implementation of MSX Video Display Processors (VDPs).
bool getEvenOdd() const
Is the even or odd field being displayed?
unsigned getEvenOddMask() const
Expresses the state of even/odd page interchange in a mask on the line number.
int getLeftBackground() const
Gets the number of VDP clock ticks between start of line and the time when the background pixel with ...
std::array< std::array< uint8_t, 3 >, 16 > getMSX1Palette() const
Get the (fixed) palette for this MSX1 VDP.
const RawFrame * isSuperimposing() const
Are we currently superimposing? In case of superimpose, returns a pointer to the to-be-superimposed f...
static constexpr int TICKS_PER_LINE
Number of VDP clock ticks per line.
uint16_t getPalette(unsigned index) const
Gets a palette entry.
byte getHorizontalScrollHigh() const
Gets the current horizontal scroll higher bits.
DisplayMode getDisplayMode() const
Get the display mode the VDP is in.
bool isMSX1VDP() const
Is this an MSX1 VDP?
byte getBackgroundColor() const
Gets the current background color.
bool hasYJK() const
Does this VDP support YJK display?
bool isMultiPageScrolling() const
Is multi page scrolling enabled? It is considered enabled if both the multi page scrolling flag is en...
bool isPalTiming() const
Is PAL timing active? This setting is fixed at start of frame.
bool isInterlaced() const
Get interlace status.
bool getTransparency() const
Gets the current transparency setting.
int getLeftSprites() const
Gets the number of VDP clock ticks between start of line and the start of the sprite plane.
unsigned getMask() const
Gets the mask for this window.
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.
std::span< const byte, size > getReadArea(unsigned index) const
Gets a span of a contiguous part of the VRAM.
constexpr auto enumerate(Iterable &&iterable)
Heavily inspired by Nathan Reed's blog post: Python-Like enumerate() In C++17 http://reedbeta....
This file implemented 3 utility functions:
CharacterConverter::Pixel Pixel
constexpr auto copy(InputRange &&range, OutputIter out)
constexpr To narrow(From from) noexcept
constexpr auto subspan(Range &&range, size_t offset, size_t count=std::dynamic_extent)
constexpr auto xrange(T e)