30 VDP& vdp_, std::span<const Pixel, 16> palFg_, std::span<const Pixel, 16> palBg_)
31 : vdp(vdp_), vram(vdp.getVRAM()), palFg(palFg_), palBg(palBg_)
38 assert(modeBase < 0x0C);
46 renderGraphic1(subspan<256>(buf), line);
49 renderText1(subspan<256>(buf), line);
52 renderMulti(subspan<256>(buf), line);
55 renderGraphic2(subspan<256>(buf), line);
58 renderGraphic2(subspan<256>(buf), line);
61 renderText2(subspan<512>(buf), line);
65 renderText1Q(subspan<256>(buf), line);
67 renderBlank (subspan<256>(buf));
72 renderMultiQ(subspan<256>(buf), line);
74 renderBlank (subspan<256>(buf));
79 renderBogus(subspan<256>(buf));
81 renderBlank(subspan<256>(buf));
88static inline __m128i select(__m128i a0, __m128i a1, __m128i mask)
90 return _mm_xor_si128(_mm_and_si128(_mm_xor_si128(a0, a1), mask), a0);
94static inline void draw6(
97 pixelPtr[0] = (pattern & 0x80) ? fg : bg;
98 pixelPtr[1] = (pattern & 0x40) ? fg : bg;
99 pixelPtr[2] = (pattern & 0x20) ? fg : bg;
100 pixelPtr[3] = (pattern & 0x10) ? fg : bg;
101 pixelPtr[4] = (pattern & 0x08) ? fg : bg;
102 pixelPtr[5] = (pattern & 0x04) ? fg : bg;
106static inline void draw8(
111 const __m128i m74 = _mm_set_epi32(0x10, 0x20, 0x40, 0x80);
112 const __m128i m30 = _mm_set_epi32(0x01, 0x02, 0x04, 0x08);
113 const __m128i zero = _mm_setzero_si128();
115 __m128i fg4 = _mm_set1_epi32(fg);
116 __m128i bg4 = _mm_set1_epi32(bg);
117 __m128i pat = _mm_set1_epi32(pattern);
119 __m128i b74 = _mm_cmpeq_epi32(_mm_and_si128(pat, m74), zero);
120 __m128i b30 = _mm_cmpeq_epi32(_mm_and_si128(pat, m30), zero);
122 auto* out = std::bit_cast<__m128i*>(pixelPtr);
123 _mm_storeu_si128(out + 0, select(fg4, bg4, b74));
124 _mm_storeu_si128(out + 1, select(fg4, bg4, b30));
130 pixelPtr[0] = (pattern & 0x80) ? fg : bg;
131 pixelPtr[1] = (pattern & 0x40) ? fg : bg;
132 pixelPtr[2] = (pattern & 0x20) ? fg : bg;
133 pixelPtr[3] = (pattern & 0x10) ? fg : bg;
134 pixelPtr[4] = (pattern & 0x08) ? fg : bg;
135 pixelPtr[5] = (pattern & 0x04) ? fg : bg;
136 pixelPtr[6] = (pattern & 0x02) ? fg : bg;
137 pixelPtr[7] = (pattern & 0x01) ? fg : bg;
141void CharacterConverter::renderText1(std::span<Pixel, 256> buf,
int line)
const
153 unsigned nameStart = (line / 8) * 40;
154 unsigned nameEnd = nameStart + 40;
155 Pixel* __restrict pixelPtr = buf.data();
156 for (
auto name :
xrange(nameStart, nameEnd)) {
157 unsigned charCode = vram.
nameTable.
readNP((name + 0xC00) | (~0u << 12));
158 auto pattern = patternArea[l + charCode * 8];
159 draw6(pixelPtr, fg, bg, pattern);
163void CharacterConverter::renderText1Q(std::span<Pixel, 256> buf,
int line)
const
173 unsigned nameStart = (line / 8) * 40;
174 unsigned nameEnd = nameStart + 40;
175 unsigned patternQuarter = (line & 0xC0) << 2;
176 Pixel* __restrict pixelPtr = buf.data();
177 for (
auto name :
xrange(nameStart, nameEnd)) {
178 unsigned charCode = vram.
nameTable.
readNP((name + 0xC00) | (~0u << 12));
179 unsigned patternNr = patternQuarter | charCode;
181 patternBaseLine | (patternNr * 8));
182 draw6(pixelPtr, fg, bg, pattern);
186void CharacterConverter::renderText2(std::span<Pixel, 512> buf,
int line)
const
190 Pixel blinkFg, blinkBg;
204 unsigned colorStart = (line / 8) * (80 / 8);
205 unsigned nameStart = (line / 8) * 80;
206 Pixel* __restrict pixelPtr = buf.data();
207 for (
auto i :
xrange(80 / 8)) {
209 (colorStart + i) | (~0u << 9));
211 (nameStart + 8 * i) | (~0u << 12));
213 (colorPattern & 0x80) ? blinkFg : plainFg,
214 (colorPattern & 0x80) ? blinkBg : plainBg,
215 patternArea[l + nameArea[0] * 8]);
217 (colorPattern & 0x40) ? blinkFg : plainFg,
218 (colorPattern & 0x40) ? blinkBg : plainBg,
219 patternArea[l + nameArea[1] * 8]);
221 (colorPattern & 0x20) ? blinkFg : plainFg,
222 (colorPattern & 0x20) ? blinkBg : plainBg,
223 patternArea[l + nameArea[2] * 8]);
225 (colorPattern & 0x10) ? blinkFg : plainFg,
226 (colorPattern & 0x10) ? blinkBg : plainBg,
227 patternArea[l + nameArea[3] * 8]);
229 (colorPattern & 0x08) ? blinkFg : plainFg,
230 (colorPattern & 0x08) ? blinkBg : plainBg,
231 patternArea[l + nameArea[4] * 8]);
233 (colorPattern & 0x04) ? blinkFg : plainFg,
234 (colorPattern & 0x04) ? blinkBg : plainBg,
235 patternArea[l + nameArea[5] * 8]);
237 (colorPattern & 0x02) ? blinkFg : plainFg,
238 (colorPattern & 0x02) ? blinkBg : plainBg,
239 patternArea[l + nameArea[6] * 8]);
241 (colorPattern & 0x01) ? blinkFg : plainFg,
242 (colorPattern & 0x01) ? blinkBg : plainBg,
243 patternArea[l + nameArea[7] * 8]);
247std::span<const byte, 32> CharacterConverter::getNamePtr(
int line,
int scroll)
const
252 ((line / 8) * 32) | ((scroll & 0x20) ? 0x8000 : 0));
254void CharacterConverter::renderGraphic1(std::span<Pixel, 256> buf,
int line)
const
261 auto namePtr = getNamePtr(line, scroll);
262 Pixel* __restrict pixelPtr = buf.data();
264 auto charCode = namePtr[scroll & 0x1F];
265 auto pattern = patternArea[l + charCode * 8];
266 auto color = colorArea[charCode / 8];
267 Pixel fg = palFg[color >> 4];
268 Pixel bg = palFg[color & 0x0F];
269 draw8(pixelPtr, fg, bg, pattern);
270 if (!(++scroll & 0x1F)) namePtr = getNamePtr(line, scroll);
274void CharacterConverter::renderGraphic2(std::span<Pixel, 256> buf,
int line)
const
276 int quarter8 = (((line / 8) * 32) & ~0xFF) * 8;
277 int line7 = line & 7;
279 auto namePtr = getNamePtr(line, scroll);
281 Pixel* __restrict pixelPtr = buf.data();
284 ((scroll & 0x1f) == 0)) {
290 for (
auto n :
xrange(32)) {
291 auto charCode8 = namePtr[n] * 8;
292 auto pattern = patternArea[line7 + charCode8];
293 auto color = colorArea [line7 + charCode8];
294 Pixel fg = palFg[color >> 4];
295 Pixel bg = palFg[color & 0x0F];
296 draw8(pixelPtr, fg, bg, pattern);
303 unsigned baseLine = (~0u << 13) | quarter8 | line7;
305 unsigned charCode8 = namePtr[scroll & 0x1F] * 8;
306 unsigned index = charCode8 | baseLine;
309 Pixel fg = palFg[color >> 4];
310 Pixel bg = palFg[color & 0x0F];
311 draw8(pixelPtr, fg, bg, pattern);
312 if (!(++scroll & 0x1F)) namePtr = getNamePtr(line, scroll);
317void CharacterConverter::renderMultiHelper(
318 Pixel* __restrict pixelPtr,
int line,
319 unsigned mask,
unsigned patternQuarter)
const
321 unsigned baseLine = mask | ((line / 4) & 7);
323 auto namePtr = getNamePtr(line, scroll);
325 unsigned patternNr = patternQuarter | namePtr[scroll & 0x1F];
327 Pixel cl = palFg[color >> 4];
328 Pixel cr = palFg[color & 0x0F];
329 pixelPtr[0] = cl; pixelPtr[1] = cl;
330 pixelPtr[2] = cl; pixelPtr[3] = cl;
331 pixelPtr[4] = cr; pixelPtr[5] = cr;
332 pixelPtr[6] = cr; pixelPtr[7] = cr;
334 if (!(++scroll & 0x1F)) namePtr = getNamePtr(line, scroll);
337void CharacterConverter::renderMulti(std::span<Pixel, 256> buf,
int line)
const
339 unsigned mask = (~0u << 11);
340 renderMultiHelper(buf.data(), line, mask, 0);
343void CharacterConverter::renderMultiQ(
344 std::span<Pixel, 256> buf,
int line)
const
346 unsigned mask = (~0u << 13);
347 unsigned patternQuarter = (line * 4) & ~0xFF;
348 renderMultiHelper(buf.data(), line, mask, patternQuarter);
351void CharacterConverter::renderBogus(std::span<Pixel, 256> buf)
const
353 Pixel* __restrict pixelPtr = buf.data();
356 auto draw = [&](
int n,
Pixel col) {
357 pixelPtr = std::fill_n(pixelPtr, n, col);
367void CharacterConverter::renderBlank(std::span<Pixel, 256> buf)
const
void setDisplayMode(DisplayMode mode)
Select the display mode to use for scanline conversion.
CharacterConverter(VDP &vdp, std::span< const Pixel, 16 > palFg, std::span< const Pixel, 16 > palBg)
Create a new bitmap scanline converter.
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 byte getBase() const
Get the base display mode as an integer: M5..M1 combined.
static constexpr uint8_t GRAPHIC3
static constexpr uint8_t MULTIQ
static constexpr uint8_t MULTICOLOR
static constexpr uint8_t TEXT1Q
static constexpr uint8_t GRAPHIC1
static constexpr uint8_t TEXT2
static constexpr uint8_t GRAPHIC2
static constexpr uint8_t TEXT1
Unified implementation of MSX Video Display Processors (VDPs).
int getForegroundColor() const
Gets the current foreground color.
int getBlinkBackgroundColor() const
Gets the current blinking color for blinking text.
byte getHorizontalScrollHigh() const
Gets the current horizontal scroll higher bits.
bool getBlinkState() const
Gets the current blink state.
int getBlinkForegroundColor() const
Gets the current blinking color for blinking text.
bool isMSX1VDP() const
Is this an MSX1 VDP?
byte getBackgroundColor() const
Gets the current background color.
byte getVerticalScroll() const
Gets the current vertical scroll (line displayed at Y=0).
bool isContinuous(unsigned index, unsigned size) const
Is the given index range continuous in VRAM (iow there's no mirroring) Only if the range is continuou...
byte readNP(unsigned index) const
Reads a byte from VRAM in its current state.
std::span< const byte, size > getReadArea(unsigned index) const
Gets a span of a contiguous part of the VRAM.
This file implemented 3 utility functions:
CharacterConverter::Pixel Pixel
constexpr void fill(ForwardRange &&range, const T &value)
constexpr void repeat(T n, Op op)
Repeat the given operation 'op' 'n' times.
constexpr auto xrange(T e)