1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-23 03:32:32 +00:00

Switch to Duff's device.

This commit is contained in:
Thomas Harte 2023-03-02 22:16:18 -05:00
parent 4c1973adc8
commit 3381e6b5aa

View File

@ -435,24 +435,6 @@ void Base<personality>::draw_sms(int start, int end, uint32_t cram_dot) {
// MARK: - Yamaha // MARK: - Yamaha
template <int start> struct YamahaPlotter {
static void draw_4bpp(LineBuffer &buffer, int column, uint32_t *target, const std::array<uint32_t, 16> &palette) {
switch(start) {
case 0: target[0] = palette[buffer.bitmap[column] >> 4]; [[fallthrough]];
case 1: target[1] = palette[buffer.bitmap[column] & 0xf]; [[fallthrough]];
}
}
static void draw_2bpp(LineBuffer &buffer, int column, uint32_t *target, const std::array<uint32_t, 16> &palette) {
switch(start) {
case 0: target[0] = palette[buffer.bitmap[column] >> 6]; [[fallthrough]];
case 1: target[1] = palette[(buffer.bitmap[column] >> 4) & 3]; [[fallthrough]];
case 2: target[2] = palette[(buffer.bitmap[column] >> 2) & 3]; [[fallthrough]];
case 3: target[3] = palette[buffer.bitmap[column] & 3]; [[fallthrough]];
}
}
};
template <Personality personality> template <Personality personality>
template <ScreenMode mode> template <ScreenMode mode>
void Base<personality>::draw_yamaha(LineBuffer &buffer, int start, int end) { void Base<personality>::draw_yamaha(LineBuffer &buffer, int start, int end) {
@ -460,17 +442,27 @@ void Base<personality>::draw_yamaha(LineBuffer &buffer, int start, int end) {
const int sprite_start = start >> 2; const int sprite_start = start >> 2;
const int sprite_end = end >> 2; const int sprite_end = end >> 2;
// Observation justifying Duff's device below: it's acceptable to paint too many pixels — to paint
// beyond `end` — provided that the overpainting is within normal bitmap bounds, because any
// mispainted pixels will be replaced before becoming visible to the user.
if constexpr (mode == ScreenMode::YamahaGraphics4 || mode == ScreenMode::YamahaGraphics6) { if constexpr (mode == ScreenMode::YamahaGraphics4 || mode == ScreenMode::YamahaGraphics6) {
start >>= (mode == ScreenMode::YamahaGraphics4) ? 2 : 1; start >>= (mode == ScreenMode::YamahaGraphics4) ? 2 : 1;
end >>= (mode == ScreenMode::YamahaGraphics4) ? 2 : 1; end >>= (mode == ScreenMode::YamahaGraphics4) ? 2 : 1;
switch(start & 1) { int column = start & ~1;
default: break; const int offset = start & 1;
case 1: YamahaPlotter<1>::draw_4bpp(buffer, start >> 1, &pixel_target_[start], active_palette); ++start; break; start >>= 1;
} end = (end + 1) >> 1;
while(start < end) {
YamahaPlotter<0>::draw_4bpp(buffer, start >> 1, &pixel_target_[start], active_palette); switch(offset) {
start += 2; case 0:
do {
pixel_target_[column+0] = active_palette[buffer.bitmap[start] >> 4];
case 1: pixel_target_[column+1] = active_palette[buffer.bitmap[start] & 0xf];
++start;
column += 2;
} while(start < end);
} }
} }
@ -478,15 +470,21 @@ void Base<personality>::draw_yamaha(LineBuffer &buffer, int start, int end) {
start >>= 1; start >>= 1;
end >>= 1; end >>= 1;
switch(start & 3) { int column = start & ~3;
default: break; const int offset = start & 3;
case 1: YamahaPlotter<1>::draw_2bpp(buffer, start >> 2, &pixel_target_[start], active_palette); start += 3; break; start >>= 2;
case 2: YamahaPlotter<2>::draw_2bpp(buffer, start >> 2, &pixel_target_[start], active_palette); start += 2; break; end = (end + 3) >> 2;
case 3: YamahaPlotter<3>::draw_2bpp(buffer, start >> 2, &pixel_target_[start], active_palette); start += 1; break;
} switch(offset) {
while(start < end) { case 0:
YamahaPlotter<0>::draw_2bpp(buffer, start >> 2, &pixel_target_[start], active_palette); do {
start += 4; pixel_target_[column+0] = active_palette[buffer.bitmap[start] >> 6];
case 1: pixel_target_[column+1] = active_palette[(buffer.bitmap[start] >> 4) & 3];
case 2: pixel_target_[column+2] = active_palette[(buffer.bitmap[start] >> 2) & 3];
case 3: pixel_target_[column+3] = active_palette[buffer.bitmap[start] & 3];
++start;
column += 4;
} while(start < end);
} }
} }