fast wide scale

This commit is contained in:
2025-10-12 00:20:22 +02:00
parent b55feb68f8
commit fc9e85aea0

View File

@@ -245,7 +245,7 @@ public:
private:
enum class Mode { Browse, Running };
enum class ScaleMode { Original, FullHeight };
enum class ScaleMode { Original, FullHeight, FullHeightWide };
struct PerfTracker {
enum class CallbackKind { RomRead, CartRamRead, CartRamWrite, LcdDraw, Error };
@@ -492,10 +492,16 @@ private:
(((LCD_WIDTH * cardboy::sdk::kDisplayHeight + LCD_HEIGHT / 2) / LCD_HEIGHT) + 7) & ~7;
static constexpr int kFullHeightOffsetX = (((cardboy::sdk::kDisplayWidth - kFullHeightScaledWidth) / 2) / 8) * 8;
static constexpr int kFullHeightWideWidth = LCD_WIDTH * 2;
static constexpr int kFullHeightWideOffsetX = (((cardboy::sdk::kDisplayWidth - kFullHeightWideWidth) / 2) / 8) * 8;
static_assert(kFullHeightScaledWidth % 8 == 0);
static_assert(kFullHeightOffsetX % 8 == 0);
static_assert(kOriginalOffsetX % 8 == 0);
static_assert(kFullHeightOffsetX + kFullHeightScaledWidth <= cardboy::sdk::kDisplayWidth);
static_assert(kFullHeightWideWidth % 8 == 0);
static_assert(kFullHeightWideOffsetX % 8 == 0);
static_assert(kFullHeightWideOffsetX + kFullHeightWideWidth <= cardboy::sdk::kDisplayWidth);
inline static constexpr std::array<int, LCD_WIDTH + 1> kFullHeightColumnBounds = []() constexpr {
std::array<int, LCD_WIDTH + 1> bounds{};
@@ -704,12 +710,21 @@ private:
}
void toggleScaleMode() {
if (scaleMode == ScaleMode::Original)
switch (scaleMode) {
case ScaleMode::Original:
scaleMode = ScaleMode::FullHeight;
else
setStatus("Scale: Full height");
break;
case ScaleMode::FullHeight:
scaleMode = ScaleMode::FullHeightWide;
setStatus("Scale: Full height 2x");
break;
case ScaleMode::FullHeightWide:
scaleMode = ScaleMode::Original;
setStatus("Scale: Original");
break;
}
frameDirty = true;
setStatus(scaleMode == ScaleMode::FullHeight ? "Scale: Full height" : "Scale: Original");
}
void handleBrowserInput(const InputState& input) {
@@ -982,9 +997,21 @@ private:
const std::string fpsValue(fpsValueBuf);
const std::string fpsLabel = "FPS";
const std::string fpsText = fpsValue + " FPS";
const std::string scaleHint = (scaleMode == ScaleMode::FullHeight) ? "START+B NORMAL" : "START+B SCALE";
if (scaleMode == ScaleMode::FullHeight) {
std::string scaleHint;
switch (scaleMode) {
case ScaleMode::Original:
scaleHint = "START+B FULL";
break;
case ScaleMode::FullHeight:
scaleHint = "START+B WIDE";
break;
case ScaleMode::FullHeightWide:
scaleHint = "START+B NORMAL";
break;
}
if (scaleMode == ScaleMode::FullHeight || scaleMode == ScaleMode::FullHeightWide) {
const int textScale = 1;
const int screenHeight = framebuffer.height();
const int screenWidth = framebuffer.width();
@@ -1241,6 +1268,40 @@ private:
}
}
static void drawLineFullHeightWide(GameboyApp& self, const uint8_t pixels[160], int srcLine) {
Framebuffer& fb = self.framebuffer;
const int yStart = kFullHeightRowBounds[static_cast<std::size_t>(srcLine)];
const int yEnd = kFullHeightRowBounds[static_cast<std::size_t>(srcLine) + 1];
CARDBOY_CHECK(yEnd > yStart);
CARDBOY_CHECK((kFullHeightWideOffsetX % 8) == 0);
for (int dstY = yStart; dstY < yEnd; ++dstY) {
const int yParity = dstY & 1;
int dstX = kFullHeightWideOffsetX;
for (int srcX = 0; srcX < LCD_WIDTH; srcX += 4) {
const uint8_t p0 = pixels[srcX + 0];
const uint8_t p1 = pixels[srcX + 1];
const uint8_t p2 = pixels[srcX + 2];
const uint8_t p3 = pixels[srcX + 3];
const uint8_t p4a = static_cast<uint8_t>(p0 | (p0 << 2) | (p1 << 4) | (p1 << 6));
const uint8_t p4b = static_cast<uint8_t>(p2 | (p2 << 2) | (p3 << 4) | (p3 << 6));
const int xParity = dstX & 1;
const uint8_t n0 = kNibbleLUT[yParity][xParity][p4a];
const uint8_t n1 = kNibbleLUT[yParity][xParity][p4b];
const uint8_t pack = static_cast<uint8_t>((n0 << 4) | (n1 & 0x0F));
fb.drawBits8(dstX, dstY, pack);
dstX += 8;
}
CARDBOY_CHECK(dstX == kFullHeightWideOffsetX + kFullHeightWideWidth);
}
}
public:
static uint8_t romRead(struct gb_s* gb, const uint_fast32_t addr) {
@@ -1297,10 +1358,18 @@ private:
Framebuffer& fb = self->framebuffer;
fb.frameReady();
if (self->scaleMode == ScaleMode::FullHeight)
switch (self->scaleMode) {
case ScaleMode::FullHeight:
drawLineFullHeight(*self, pixels, static_cast<int>(line));
else
break;
case ScaleMode::FullHeightWide:
drawLineFullHeightWide(*self, pixels, static_cast<int>(line));
break;
case ScaleMode::Original:
default:
drawLineOriginal(*self, pixels, static_cast<int>(line));
break;
}
}
static const char* initErrorToString(enum gb_init_error_e err) {