fps counter

This commit is contained in:
2025-10-08 22:39:48 +02:00
parent 429d704c8c
commit 4c0fd5243f
2 changed files with 55 additions and 32 deletions

View File

@@ -40,6 +40,7 @@ public:
void onStart() override {
prevInput = {};
statusMessage.clear();
resetFpsStats();
ensureFilesystemReady();
refreshRomList();
mode = Mode::Browse;
@@ -63,6 +64,7 @@ public:
browserDirty = true;
break;
}
DispTools::draw_to_display_async_wait();
gb_run_frame(&gb);
renderGameFrame();
break;
@@ -94,14 +96,16 @@ private:
InputState prevInput{};
// Emulator state
struct gb_s gb{};
bool gbReady = false;
std::vector<uint8_t> romData;
std::vector<uint8_t> cartRam;
std::array<uint8_t, LCD_WIDTH * LCD_HEIGHT> frameBuffer{};
bool frameDirty = false;
std::string activeRomName;
std::string activeRomSavePath;
struct gb_s gb{};
bool gbReady = false;
std::vector<uint8_t> romData;
std::vector<uint8_t> cartRam;
bool frameDirty = false;
uint32_t fpsLastSampleMs = 0;
uint32_t fpsFrameCounter = 0;
uint32_t fpsCurrent = 0;
std::string activeRomName;
std::string activeRomSavePath;
bool ensureFilesystemReady() {
esp_err_t err = FsHelper::get().mount();
@@ -233,7 +237,6 @@ private:
browserDirty = false;
DispTools::draw_to_display_async_wait();
framebuffer.clear(false);
const std::string_view title = "GAME BOY";
const int titleWidth = font16x8::measureText(title, 2, 1);
@@ -334,6 +337,9 @@ private:
activeRomSavePath = buildSavePath(rom.fullPath);
loadSaveFile();
resetFpsStats();
fpsLastSampleMs = context.clock.millis();
gbReady = true;
mode = Mode::Running;
frameDirty = true;
@@ -345,6 +351,7 @@ private:
void unloadRom() {
if (!gbReady) {
resetFpsStats();
romData.clear();
cartRam.clear();
activeRomName.clear();
@@ -353,6 +360,7 @@ private:
}
maybeSaveRam();
resetFpsStats();
gbReady = false;
romData.clear();
@@ -401,27 +409,27 @@ private:
return;
frameDirty = false;
DispTools::draw_to_display_async_wait();
framebuffer.clear(false);
const int offsetX = (framebuffer.width() - LCD_WIDTH) / 2;
const int offsetY = (framebuffer.height() - LCD_HEIGHT) / 2;
for (int y = 0; y < LCD_HEIGHT; ++y) {
const int dstY = offsetY + y;
if (dstY < 0 || dstY >= framebuffer.height())
continue;
for (int x = 0; x < LCD_WIDTH; ++x) {
const int dstX = offsetX + x;
if (dstX < 0 || dstX >= framebuffer.width())
continue;
const bool on = frameBuffer[static_cast<std::size_t>(y) * LCD_WIDTH + x] != 0;
framebuffer.drawPixel(dstX, dstY, on);
}
++fpsFrameCounter;
const uint32_t nowMs = context.clock.millis();
if (fpsLastSampleMs == 0)
fpsLastSampleMs = nowMs;
const uint32_t elapsed = nowMs - fpsLastSampleMs;
if (elapsed >= 1000U) {
const uint64_t scaledFrames = static_cast<uint64_t>(fpsFrameCounter) * 1000ULL;
fpsCurrent = static_cast<uint32_t>(scaledFrames / elapsed);
fpsFrameCounter = 0;
fpsLastSampleMs = nowMs;
}
char fpsBuf[16];
std::snprintf(fpsBuf, sizeof(fpsBuf), "%u FPS", static_cast<unsigned>(fpsCurrent));
const std::string fpsText(fpsBuf);
const int fpsWidth = font16x8::measureText(fpsText, 1, 1);
const int fpsX = std::max(16, framebuffer.width() - fpsWidth - 16);
if (!activeRomName.empty())
font16x8::drawText(framebuffer, 16, 16, activeRomName, 1, true, 1);
font16x8::drawText(framebuffer, fpsX, 16, fpsText, 1, true, 1);
font16x8::drawText(framebuffer, 16, framebuffer.height() - 24, "START+SELECT BACK", 1, true, 1);
DispTools::draw_to_display_async_start();
@@ -464,6 +472,12 @@ private:
browserDirty = true;
}
void resetFpsStats() {
fpsLastSampleMs = 0;
fpsFrameCounter = 0;
fpsCurrent = 0;
}
static std::string buildSavePath(const std::string& romPath) {
std::string result = romPath;
const auto dot = result.find_last_of('.');
@@ -516,11 +530,20 @@ private:
if (!self || line >= LCD_HEIGHT)
return;
const std::size_t offset = static_cast<std::size_t>(line) * LCD_WIDTH;
const int offsetX = (self->framebuffer.width() - LCD_WIDTH) / 2;
const int offsetY = (self->framebuffer.height() - LCD_HEIGHT) / 2;
const int dstY = offsetY + static_cast<int>(line);
if (dstY < 0 || dstY >= self->framebuffer.height())
return;
for (int x = 0; x < LCD_WIDTH; ++x) {
// Collapse 2-bit colour into monochrome.
const uint8_t shade = pixels[x] & 0x03u;
self->frameBuffer[offset + static_cast<std::size_t>(x)] = (shade >= 2) ? 1 : 0;
const uint8_t shade = pixels[x] & 0x03u;
const bool on = (shade >= 2);
const int dstX = offsetX + x;
if (dstX < 0 || dstX >= self->framebuffer.width())
continue;
self->framebuffer.drawPixel(dstX, dstY, on);
}
self->frameDirty = true;
}

View File

@@ -102,13 +102,13 @@ void SMD::async_draw_start() {
_tx.tx_buffer = dma_buf;
_tx.length = SMD::kLineDataBytes * 8;
dma_buf[0] = 0b10000000 | (_vcom << 6);
_inFlight = true;
_inFlight = true;
ESP_ERROR_CHECK(spi_device_queue_trans(_spi, &_tx, 0));
}
void SMD::async_draw_wait() {
if (uxSemaphoreGetCount(s_clearSem) || !_inFlight) {
assert((uxSemaphoreGetCount(s_clearSem) == 0) == _inFlight);
if (!_inFlight || uxSemaphoreGetCount(s_clearSem)) {
// assert((uxSemaphoreGetCount(s_clearSem) == 0) == _inFlight);
return;
}
if (!xSemaphoreTake(s_clearSem, portMAX_DELAY))