mirror of
https://github.com/usatiuk/cardboy.git
synced 2025-10-28 23:27:49 +01:00
fps counter
This commit is contained in:
@@ -40,6 +40,7 @@ public:
|
|||||||
void onStart() override {
|
void onStart() override {
|
||||||
prevInput = {};
|
prevInput = {};
|
||||||
statusMessage.clear();
|
statusMessage.clear();
|
||||||
|
resetFpsStats();
|
||||||
ensureFilesystemReady();
|
ensureFilesystemReady();
|
||||||
refreshRomList();
|
refreshRomList();
|
||||||
mode = Mode::Browse;
|
mode = Mode::Browse;
|
||||||
@@ -63,6 +64,7 @@ public:
|
|||||||
browserDirty = true;
|
browserDirty = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
DispTools::draw_to_display_async_wait();
|
||||||
gb_run_frame(&gb);
|
gb_run_frame(&gb);
|
||||||
renderGameFrame();
|
renderGameFrame();
|
||||||
break;
|
break;
|
||||||
@@ -94,14 +96,16 @@ private:
|
|||||||
InputState prevInput{};
|
InputState prevInput{};
|
||||||
|
|
||||||
// Emulator state
|
// Emulator state
|
||||||
struct gb_s gb{};
|
struct gb_s gb{};
|
||||||
bool gbReady = false;
|
bool gbReady = false;
|
||||||
std::vector<uint8_t> romData;
|
std::vector<uint8_t> romData;
|
||||||
std::vector<uint8_t> cartRam;
|
std::vector<uint8_t> cartRam;
|
||||||
std::array<uint8_t, LCD_WIDTH * LCD_HEIGHT> frameBuffer{};
|
bool frameDirty = false;
|
||||||
bool frameDirty = false;
|
uint32_t fpsLastSampleMs = 0;
|
||||||
std::string activeRomName;
|
uint32_t fpsFrameCounter = 0;
|
||||||
std::string activeRomSavePath;
|
uint32_t fpsCurrent = 0;
|
||||||
|
std::string activeRomName;
|
||||||
|
std::string activeRomSavePath;
|
||||||
|
|
||||||
bool ensureFilesystemReady() {
|
bool ensureFilesystemReady() {
|
||||||
esp_err_t err = FsHelper::get().mount();
|
esp_err_t err = FsHelper::get().mount();
|
||||||
@@ -233,7 +237,6 @@ private:
|
|||||||
browserDirty = false;
|
browserDirty = false;
|
||||||
|
|
||||||
DispTools::draw_to_display_async_wait();
|
DispTools::draw_to_display_async_wait();
|
||||||
framebuffer.clear(false);
|
|
||||||
|
|
||||||
const std::string_view title = "GAME BOY";
|
const std::string_view title = "GAME BOY";
|
||||||
const int titleWidth = font16x8::measureText(title, 2, 1);
|
const int titleWidth = font16x8::measureText(title, 2, 1);
|
||||||
@@ -334,6 +337,9 @@ private:
|
|||||||
activeRomSavePath = buildSavePath(rom.fullPath);
|
activeRomSavePath = buildSavePath(rom.fullPath);
|
||||||
loadSaveFile();
|
loadSaveFile();
|
||||||
|
|
||||||
|
resetFpsStats();
|
||||||
|
fpsLastSampleMs = context.clock.millis();
|
||||||
|
|
||||||
gbReady = true;
|
gbReady = true;
|
||||||
mode = Mode::Running;
|
mode = Mode::Running;
|
||||||
frameDirty = true;
|
frameDirty = true;
|
||||||
@@ -345,6 +351,7 @@ private:
|
|||||||
|
|
||||||
void unloadRom() {
|
void unloadRom() {
|
||||||
if (!gbReady) {
|
if (!gbReady) {
|
||||||
|
resetFpsStats();
|
||||||
romData.clear();
|
romData.clear();
|
||||||
cartRam.clear();
|
cartRam.clear();
|
||||||
activeRomName.clear();
|
activeRomName.clear();
|
||||||
@@ -353,6 +360,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
maybeSaveRam();
|
maybeSaveRam();
|
||||||
|
resetFpsStats();
|
||||||
|
|
||||||
gbReady = false;
|
gbReady = false;
|
||||||
romData.clear();
|
romData.clear();
|
||||||
@@ -401,27 +409,27 @@ private:
|
|||||||
return;
|
return;
|
||||||
frameDirty = false;
|
frameDirty = false;
|
||||||
|
|
||||||
DispTools::draw_to_display_async_wait();
|
++fpsFrameCounter;
|
||||||
framebuffer.clear(false);
|
const uint32_t nowMs = context.clock.millis();
|
||||||
|
if (fpsLastSampleMs == 0)
|
||||||
const int offsetX = (framebuffer.width() - LCD_WIDTH) / 2;
|
fpsLastSampleMs = nowMs;
|
||||||
const int offsetY = (framebuffer.height() - LCD_HEIGHT) / 2;
|
const uint32_t elapsed = nowMs - fpsLastSampleMs;
|
||||||
|
if (elapsed >= 1000U) {
|
||||||
for (int y = 0; y < LCD_HEIGHT; ++y) {
|
const uint64_t scaledFrames = static_cast<uint64_t>(fpsFrameCounter) * 1000ULL;
|
||||||
const int dstY = offsetY + y;
|
fpsCurrent = static_cast<uint32_t>(scaledFrames / elapsed);
|
||||||
if (dstY < 0 || dstY >= framebuffer.height())
|
fpsFrameCounter = 0;
|
||||||
continue;
|
fpsLastSampleMs = nowMs;
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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())
|
if (!activeRomName.empty())
|
||||||
font16x8::drawText(framebuffer, 16, 16, activeRomName, 1, true, 1);
|
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);
|
font16x8::drawText(framebuffer, 16, framebuffer.height() - 24, "START+SELECT BACK", 1, true, 1);
|
||||||
|
|
||||||
DispTools::draw_to_display_async_start();
|
DispTools::draw_to_display_async_start();
|
||||||
@@ -464,6 +472,12 @@ private:
|
|||||||
browserDirty = true;
|
browserDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void resetFpsStats() {
|
||||||
|
fpsLastSampleMs = 0;
|
||||||
|
fpsFrameCounter = 0;
|
||||||
|
fpsCurrent = 0;
|
||||||
|
}
|
||||||
|
|
||||||
static std::string buildSavePath(const std::string& romPath) {
|
static std::string buildSavePath(const std::string& romPath) {
|
||||||
std::string result = romPath;
|
std::string result = romPath;
|
||||||
const auto dot = result.find_last_of('.');
|
const auto dot = result.find_last_of('.');
|
||||||
@@ -516,11 +530,20 @@ private:
|
|||||||
if (!self || line >= LCD_HEIGHT)
|
if (!self || line >= LCD_HEIGHT)
|
||||||
return;
|
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) {
|
for (int x = 0; x < LCD_WIDTH; ++x) {
|
||||||
// Collapse 2-bit colour into monochrome.
|
// Collapse 2-bit colour into monochrome.
|
||||||
const uint8_t shade = pixels[x] & 0x03u;
|
const uint8_t shade = pixels[x] & 0x03u;
|
||||||
self->frameBuffer[offset + static_cast<std::size_t>(x)] = (shade >= 2) ? 1 : 0;
|
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;
|
self->frameDirty = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,13 +102,13 @@ void SMD::async_draw_start() {
|
|||||||
_tx.tx_buffer = dma_buf;
|
_tx.tx_buffer = dma_buf;
|
||||||
_tx.length = SMD::kLineDataBytes * 8;
|
_tx.length = SMD::kLineDataBytes * 8;
|
||||||
dma_buf[0] = 0b10000000 | (_vcom << 6);
|
dma_buf[0] = 0b10000000 | (_vcom << 6);
|
||||||
_inFlight = true;
|
_inFlight = true;
|
||||||
ESP_ERROR_CHECK(spi_device_queue_trans(_spi, &_tx, 0));
|
ESP_ERROR_CHECK(spi_device_queue_trans(_spi, &_tx, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMD::async_draw_wait() {
|
void SMD::async_draw_wait() {
|
||||||
if (uxSemaphoreGetCount(s_clearSem) || !_inFlight) {
|
if (!_inFlight || uxSemaphoreGetCount(s_clearSem)) {
|
||||||
assert((uxSemaphoreGetCount(s_clearSem) == 0) == _inFlight);
|
// assert((uxSemaphoreGetCount(s_clearSem) == 0) == _inFlight);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!xSemaphoreTake(s_clearSem, portMAX_DELAY))
|
if (!xSemaphoreTake(s_clearSem, portMAX_DELAY))
|
||||||
|
|||||||
Reference in New Issue
Block a user