28static constexpr int TICKS_LEFT_BORDER = 100 + 102;
34static constexpr int TICKS_VISIBLE_MIDDLE =
43static constexpr int translateX(
int absoluteX,
bool narrow)
45 int maxX =
narrow ? 640 : 320;
50 const int ROUND_MASK =
narrow ? ~1 : ~3;
52 ((absoluteX - (TICKS_VISIBLE_MIDDLE & ROUND_MASK))
55 return std::max(screenX, 0);
58inline void SDLRasterizer::renderBitmapLine(std::span<Pixel> buf,
unsigned vramLine)
61 auto [vramPtr0, vramPtr1] =
73 std::unique_ptr<PostProcessor> postProcessor_)
74 : vdp(vdp_), vram(vdp.getVRAM())
76 , postProcessor(
std::move(postProcessor_))
78 , renderSettings(display.getRenderSettings())
79 , characterConverter(vdp,
subspan<16>(palFg), palBg)
80 , bitmapConverter(palFg, PALETTE256, V9958_COLORS)
81 , spriteConverter(vdp.getSpriteChecker(), palBg)
88 for (
auto i :
xrange(16)) {
89 palFg[i] = palFg[i + 16] = palBg[i] =
90 V9938_COLORS[0][0][0];
110 return postProcessor.get();
115 return postProcessor->needRender() &&
129void SDLRasterizer::resetPalette()
133 for (
auto i :
xrange(16)) {
141 postProcessor->setSuperimposeVideoFrame(videoSource);
148 workFrame = postProcessor->rotateFrames(std::move(workFrame), time);
159 lineRenderTop = vdp.
isPalTiming() ? 59 - 14 : 32 - 14;
177 ? palGraphic7Sprites : palBg);
184 Pixel newColor = V9938_COLORS[(grb >> 4) & 7][grb >> 8][grb & 7];
185 palFg[index ] = newColor;
186 palFg[index + 16] = newColor;
187 palBg[index ] = newColor;
221void SDLRasterizer::precalcPalette()
226 for (
auto i :
xrange(16)) {
227 const auto rgb = palette[i];
228 palFg[i] = palFg[i + 16] = palBg[i] =
231 vec3(rgb[0], rgb[1], rgb[2]) * (1.0f / 255.0f)));
239 std::array<int, 32> intensity;
240 for (
auto [i, r] :
enumerate(intensity)) {
241 r = narrow_cast<int>(255.0f * renderSettings.
transformComponent(narrow<float>(i) * (1.0f / 31.0f)));
243 for (
auto [rgb, col] :
enumerate(V9958_COLORS)) {
245 intensity[(rgb >> 10) & 31],
246 intensity[(rgb >> 5) & 31],
247 intensity[(rgb >> 0) & 31]));
250 for (
auto r :
xrange(32)) {
252 for (
auto b :
xrange(32)) {
253 vec3 rgb{narrow<float>(r),
256 V9958_COLORS[(r << 10) + (
g << 5) + b] =
266 for (
auto r3 :
xrange(8)) {
267 int r5 = (r3 << 2) | (r3 >> 1);
268 for (
auto g3 :
xrange(8)) {
269 int g5 = (g3 << 2) | (g3 >> 1);
270 for (
auto b3 :
xrange(8)) {
271 int b5 = (b3 << 2) | (b3 >> 1);
272 V9938_COLORS[r3][g3][b3] =
273 V9958_COLORS[(r5 << 10) + (g5 << 5) + b5];
280 std::array<int, 8> intensity;
281 for (
auto [i, r] :
enumerate(intensity)) {
282 r = narrow_cast<int>(255.0f * renderSettings.
transformComponent(narrow<float>(i) * (1.0f / 7.0f)));
284 for (
auto r :
xrange(8)) {
286 for (
auto b :
xrange(8)) {
287 V9938_COLORS[r][
g][b] =
296 for (
auto r :
xrange(8)) {
298 for (
auto b :
xrange(8)) {
299 vec3 rgb{narrow<float>(r),
302 V9938_COLORS[r][
g][b] =
311 for (
auto i :
xrange(256)) {
312 PALETTE256[i] = V9938_COLORS
315 [(i & 0x03) == 3 ? 7 : (i & 0x03) * 2];
318 for (
auto i :
xrange(16)) {
320 palGraphic7Sprites[i] =
321 V9938_COLORS[(grb >> 4) & 7][grb >> 8][grb & 7];
326void SDLRasterizer::precalcColorIndex0(DisplayMode mode,
327 bool transparency,
const RawFrame* superimposing,
byte bgColorIndex)
331 transparency =
false;
334 int tpIndex = transparency ? bgColorIndex : 0;
336 Pixel c = (superimposing && (bgColorIndex == 0))
346 if ((palFg[ 0] != palBg[tpIndex >> 2]) ||
347 (palFg[16] != palBg[tpIndex & 3])) {
348 palFg[ 0] = palBg[tpIndex >> 2];
349 palFg[16] = palBg[tpIndex & 3];
355std::pair<Pixel, Pixel> SDLRasterizer::getBorderColors()
362 return {palBg[(bgColor & 0x0C) >> 2],
363 palBg[(bgColor & 0x03) >> 0]};
367 return PALETTE256[bgColor];
372 return palBg[bgColor];
380 int fromX,
int fromY,
int limitX,
int limitY)
382 auto [border0, border1] = getBorderColors();
384 int startY = std::max(fromY - lineRenderTop, 0);
385 int endY = std::min(limitY - lineRenderTop, 240);
387 (border0 == border1)) {
389 for (
auto y :
xrange(startY, endY)) {
390 workFrame->setBlank(y, border0);
397 unsigned x = translateX(fromX, (lineWidth == 512));
398 unsigned num = translateX(limitX, (lineWidth == 512)) - x;
399 unsigned width = (lineWidth == 512) ? 640 : 320;
401 for (
auto y :
xrange(startY, endY)) {
402 memset(workFrame->getLineDirect(y).subspan(x, num),
410 workFrame->setLineWidth(y, width);
418 int displayX,
int displayY,
419 int displayWidth,
int displayHeight)
426 if (lineWidth == 256) {
427 int endX = displayX + displayWidth;
429 displayWidth = endX / 2 - displayX;
433 int screenLimitY = std::min(
434 fromY + displayHeight - lineRenderTop,
436 int screenY = fromY - lineRenderTop;
439 fromY = lineRenderTop;
442 displayHeight = screenLimitY - screenY;
443 if (displayHeight <= 0)
return;
459 int pageBorder = displayX + displayWidth;
460 auto [scrollPage1, scrollPage2] = [&]() -> std::pair<int, int> {
471 int pageSplit = narrow<int>(lineWidth - hScroll);
472 if (pageSplit < pageBorder) {
473 pageBorder = pageSplit;
477 for (
auto y :
xrange(screenY, screenLimitY)) {
485 unsigned pageMaskOdd = (mode.
isPlanar() ? 0x000 : 0x200) |
488 ? (pageMaskOdd & ~0x100)
490 const std::array<unsigned, 2> vramLine = {
495 std::array<Pixel, 512> buf;
496 auto lineInBuf = unsigned(-1);
497 auto dst = workFrame->getLineDirect(y).subspan(leftBackground + displayX);
498 int firstPageWidth = pageBorder - displayX;
499 if (firstPageWidth > 0) {
500 if (((displayX + hScroll) == 0) &&
501 (firstPageWidth == narrow<int>(lineWidth))) {
503 renderBitmapLine(dst, vramLine[scrollPage1]);
505 lineInBuf = vramLine[scrollPage1];
506 renderBitmapLine(buf, vramLine[scrollPage1]);
507 auto src =
subspan(buf, displayX + hScroll, firstPageWidth);
513 if (firstPageWidth < displayWidth) {
514 if (lineInBuf != vramLine[scrollPage2]) {
515 renderBitmapLine(buf, vramLine[scrollPage2]);
517 unsigned x = displayX < pageBorder
518 ? 0 : displayX + hScroll - lineWidth;
523 displayY = (displayY + 1) & 255;
527 for (
auto y :
xrange(screenY, screenLimitY)) {
528 assert(!vdp.
isMSX1VDP() || displayY < 192);
530 auto dst = workFrame->getLineDirect(y).subspan(leftBackground + displayX);
531 if ((displayX == 0) && (displayWidth == narrow<int>(lineWidth))){
534 std::array<Pixel, 512> buf;
536 auto src =
subspan(buf, displayX, displayWidth);
540 displayY = (displayY + 1) & 255;
548 int displayWidth,
int displayHeight)
552 int screenLimitY = std::min(
553 fromY + displayHeight - lineRenderTop,
555 int screenY = fromY - lineRenderTop;
557 fromY = lineRenderTop;
560 displayHeight = screenLimitY - screenY;
561 if (displayHeight <= 0)
return;
567 int displayLimitX = displayX + displayWidth;
568 int limitY = fromY + displayHeight;
569 int screenX = translateX(
572 if (spriteMode == 1) {
573 for (
int y = fromY; y < limitY; y++, screenY++) {
574 auto dst = workFrame->getLineDirect(screenY).subspan(screenX);
575 spriteConverter.
drawMode1(y, displayX, displayLimitX, dst);
580 for (
int y = fromY; y < limitY; y++, screenY++) {
581 auto dst = workFrame->getLineDirect(screenY).subspan(screenX);
582 spriteConverter.template drawMode2<DisplayMode::GRAPHIC5>(
583 y, displayX, displayLimitX, dst);
586 for (
int y = fromY; y < limitY; y++, screenY++) {
587 auto dst = workFrame->getLineDirect(screenY).subspan(screenX);
588 spriteConverter.template drawMode2<DisplayMode::GRAPHIC6>(
589 y, displayX, displayLimitX, dst);
592 for (
int y = fromY; y < limitY; y++, screenY++) {
593 auto dst = workFrame->getLineDirect(screenY).subspan(screenX);
594 spriteConverter.template drawMode2<DisplayMode::GRAPHIC4>(
595 y, displayX, displayLimitX, dst);
603 return postProcessor->isRecording();
609 &renderSettings.getBrightnessSetting(),
610 &renderSettings.getContrastSetting(),
611 &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)
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,...
constexpr unsigned getLineWidth() const
Get number of pixels on a display line in this mode.
constexpr bool isBitmapMode() const
Is the current mode a bitmap mode? Graphic4 and higher are bitmap modes.
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.
@ FIELD_NONINTERLACED
Interlacing is off for this frame.
@ FIELD_EVEN
Interlacing is on and this is an even frame.
@ FIELD_ODD
Interlacing is on and this is an odd 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.
SDLRasterizer(const SDLRasterizer &)=delete
void setBorderMask(bool masked) override
void frameStart(EmuTime::param time) override
Indicates the start of a new frame.
void setHorizontalAdjust(int adjust) override
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 setTransparency(bool enabled)
Update the transparency setting.
void drawMode1(int absLine, int minX, int maxX, std::span< Pixel > pixelPtr)
Draw sprites in sprite mode 1.
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
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)