--- nono/vm/renderer.cpp 2026/04/29 17:05:41 1.1.1.13 +++ nono/vm/renderer.cpp 2026/04/29 17:05:59 1.1.1.16 @@ -5,7 +5,7 @@ // // -// レンダラ +// ビデオレンダラ // #include "renderer.h" @@ -21,11 +21,12 @@ #define PERFREND #include "stopwatch.h" static Stopwatch sw_notify; -static uint64 notify_time; +static uint64 last_report_rtime; +static uint64 notify_nsec; static uint notify_count; -static uint64 render_time; -static uint64 stretch_time; -static uint64 convert_time; +static uint64 render_nsec; +static uint64 stretch_nsec; +static uint64 convert_nsec; static uint convert_count; #endif @@ -33,26 +34,28 @@ static uint convert_count; static const Color ScreenOffColor(0x70, 0x70, 0x70); // コンストラクタ -Renderer::Renderer() - : inherited(OBJ_RENDERER) +VideoRenderer::VideoRenderer() + : inherited(OBJ_VIDEO_RENDERER) { + AddAlias("Renderer"); + monitor = gMonitorManager->Regist(ID_MONITOR_RENDERER, this); - monitor->func = ToMonitorCallback(&Renderer::MonitorUpdate); + monitor->SetCallback(&VideoRenderer::MonitorScreen); monitor->SetSize(42, 10); } // デストラクタ -Renderer::~Renderer() +VideoRenderer::~VideoRenderer() { TerminateThread(); } // 初期化 bool -Renderer::Init() +VideoRenderer::Init() { - scheduler = GetScheduler(); syncer = GetSyncer(); + uimessage = gMainApp.GetUIMessage(); // GUI ならレンダラ有効。 if (gMainApp.IsGUI()) { @@ -67,7 +70,7 @@ Renderer::Init() // リセット void -Renderer::ResetHard(bool poweron) +VideoRenderer::ResetHard(bool poweron) { next_refresh_rtime = syncer->GetRealTime(); @@ -82,18 +85,21 @@ Renderer::ResetHard(bool poweron) stat_output_count = 0; last_output_time = now; ma_output_span.Clear(); +#if defined(PERFREND) + last_report_rtime = syncer->GetRealTime(); +#endif } // 電源オフ void -Renderer::PowerOff() +VideoRenderer::PowerOff() { if (enable) { #if defined(PERFREND) sw_notify.Restart(); #endif // レンダリングスレッドに指示 - std::unique_lock lock(mtx); + std::lock_guard lock(mtx); request |= REQ_SCREENOFF; cv.notify_one(); } @@ -102,7 +108,7 @@ Renderer::PowerOff() // 画面合成処理 (VM スレッドで呼ばれる)。 // 今は一画面単位で合成を行なっている。ラスター云々は未対応。 void -Renderer::NotifyRender() +VideoRenderer::NotifyRender() { // CLI 版なら何もしない。 if (enable == false) { @@ -121,7 +127,7 @@ Renderer::NotifyRender() // レンダラスレッドに描画指示を出すだけ。 { - std::unique_lock lock(mtx); + std::lock_guard lock(mtx); request |= REQ_RENDER; cv.notify_one(); } @@ -129,7 +135,7 @@ Renderer::NotifyRender() // レンダリングスレッド void -Renderer::ThreadRun() +VideoRenderer::ThreadRun() { if (enable) { SetThreadAffinityHint(AffinityClass::Heavy); @@ -162,6 +168,9 @@ Renderer::ThreadRun() // req に基づいて処理。 int64 t = DoRender(req); +#if defined(PERFREND) + PrintPerf(); +#endif if (t == 0 || (req & REQ_POST)) { // UI に即通知。 @@ -171,7 +180,7 @@ Renderer::ThreadRun() ma_output_span.EnqueueForce(now - last_output_time); last_output_time = now; - UIMessage::Post(UIMessage::RENDER); + uimessage->Post(UIMessage::RENDER); delay = 0; } else if (t > 0) { // 指定時間後に UI に通知。 @@ -184,7 +193,7 @@ Renderer::ThreadRun() // UI への描画通知を遅延させる時間を返す (即通知する場合は 0)。 // UI に通知しない場合は -1 を返す。 int64 -Renderer::DoRender(uint32 req) +VideoRenderer::DoRender(uint32 req) { // 1. REND_NORMAL なら電源オン時の通常描画指示、 // REND_POWEROFF なら電源オン→オフ遷移時の描画指示。 @@ -202,7 +211,7 @@ Renderer::DoRender(uint32 req) #if defined(PERFREND) sw_notify.Stop(); - notify_time += sw_notify.Elapsed(); + notify_nsec += sw_notify.Elapsed_nsec(); notify_count++; sw.Restart(); @@ -211,7 +220,7 @@ Renderer::DoRender(uint32 req) updated = RenderMD(); #if defined(PERFREND) sw.Stop(); - render_time += sw.Elapsed(); + render_nsec += sw.Elapsed_nsec(); #endif stat_render_count++; } @@ -267,7 +276,7 @@ Renderer::DoRender(uint32 req) } #if defined(PERFREND) sw.Stop(); - stretch_time += sw.Elapsed(); + stretch_nsec += sw.Elapsed_nsec(); #endif // wxWidgets 用の RGBX→RGB 変換。 @@ -278,17 +287,8 @@ Renderer::DoRender(uint32 req) bitmap24_valid = true; #if defined(PERFREND) sw.Stop(); - convert_time += sw.Elapsed(); -#endif - -#if defined(PERFREND) - if (++convert_count % 100 == 0) { - printf("Notify %u, Render %u, Stretch %u, Convert %u [usec]\n", - (uint)(notify_time / notify_count / 1000U), - (uint)(render_time / stat_render_count / 1000U), - (uint)(stretch_time / convert_count / 1000U), - (uint)(convert_time / convert_count / 1000U)); - } + convert_nsec += sw.Elapsed_nsec(); + convert_count++; #endif if ((req & (REQ_SCREENOFF | REQ_RESIZE))) { @@ -305,42 +305,81 @@ Renderer::DoRender(uint32 req) return 0; } +#if defined(PERFREND) +void +VideoRenderer::PrintPerf() +{ + uint64 now = syncer->GetRealTime(); + if (now - last_report_rtime < 5_sec) { + return; + } + + double rate = 0; + uint nt_usec = 0; + uint rt_usec = 0; + uint st_usec = 0; + uint ct_usec = 0; + if (notify_count != 0) { + rate = (double)notify_count * 1_sec / (now - last_report_rtime); + nt_usec = nsec_to_usec(notify_nsec) / notify_count; + rt_usec = nsec_to_usec(render_nsec) / notify_count; + } + if (convert_count != 0) { + st_usec = nsec_to_usec(stretch_nsec) / convert_count; + ct_usec = nsec_to_usec(convert_nsec) / convert_count; + } + + printf( + "%5.1f calls/s: Notify %u us, Render %u us, Stretch %u us, Convert %u us\n", + rate, nt_usec, rt_usec, st_usec, ct_usec); + + notify_nsec = 0; + render_nsec = 0; + stretch_nsec = 0; + convert_nsec = 0; + notify_count = 0; + convert_count = 0; + last_report_rtime = now; +} +#endif // PERFREND + // スレッドの終了を指示 void -Renderer::Terminate() +VideoRenderer::Terminate() { - std::unique_lock lock(mtx); + std::lock_guard lock(mtx); request |= REQ_TERMINATE; cv.notify_one(); } // リサイズ指示 void -Renderer::ResizeView(uint width_, uint height_) +VideoRenderer::ResizeView(uint width_, uint height_) { assert(enable); new_viewwidth = width_; new_viewheight = height_; - std::unique_lock lock(mtx); + std::lock_guard lock(mtx); request |= REQ_RESIZE; cv.notify_one(); } -// 描画更新(通知)間隔を設定 +// 描画更新(通知)間隔を設定。[msec] で指定。 void -Renderer::SetRefreshInterval(uint64 t) +VideoRenderer::SetRefreshInterval(uint64 msec) { - refresh_interval = t; + refresh_interval = msec_to_tsec(msec); } // モニタ更新 void -Renderer::MonitorUpdate(Monitor *, TextScreen& screen) +VideoRenderer::MonitorScreen(Monitor *, TextScreen& screen) { int x; int y; + uint64 ma; screen.Clear(); @@ -351,15 +390,8 @@ Renderer::MonitorUpdate(Monitor *, TextS screen.Puts(0, y, "Input Count"); screen.Print(x, y++, "%26s", format_number(stat_input_count).c_str()); - uint count = ma_input_span.Length(); - uint64 ma = 0; - for (uint i = 0; i < count; i++) { - ma += ma_input_span.Peek(i); - } - if (count != 0) { - ma /= count; - } screen.Puts(0, y, "Input Frequency(VT)"); + ma = ma_input_span.GetMovingAverage(); screen.Print(x + 18, y, "%5.1f Hz", ma == 0 ? 0.0 : (double)1000'000'000 / ma); y++; @@ -375,15 +407,8 @@ Renderer::MonitorUpdate(Monitor *, TextS y++; screen.Puts(0, y, "Output Count"); screen.Print(x, y++, "%26s", format_number(stat_output_count).c_str()); - count = ma_output_span.Length(); - ma = 0; - for (uint i = 0; i < count; i++) { - ma += ma_output_span.Peek(i); - } - if (count != 0) { - ma /= count; - } screen.Puts(0, y, "Output Frequency(RT)"); + ma = ma_output_span.GetMovingAverage(); screen.Print(x + 18, y, "%5.1f Hz", ma == 0 ? 0.0 : (double)1000'000'000 / ma); y++; @@ -395,7 +420,7 @@ Renderer::MonitorUpdate(Monitor *, TextS // // コンストラクタ -X68030Renderer::X68030Renderer() +X68030VideoRenderer::X68030VideoRenderer() { // XXX とりあえず width = 768; @@ -405,13 +430,13 @@ X68030Renderer::X68030Renderer() } // デストラクタ -X68030Renderer::~X68030Renderer() +X68030VideoRenderer::~X68030VideoRenderer() { } // 初期化 bool -X68030Renderer::Init() +X68030VideoRenderer::Init() { if (inherited::Init() == false) { return false; @@ -424,7 +449,7 @@ X68030Renderer::Init() // 画面合成 bool -X68030Renderer::RenderMD() +X68030VideoRenderer::RenderMD() { bool updated = videoctlr->Render(bitmap); return updated; @@ -436,7 +461,7 @@ X68030Renderer::RenderMD() // // コンストラクタ -LunaRenderer::LunaRenderer() +LunaVideoRenderer::LunaVideoRenderer() { width = 1280; height = 1024; @@ -445,13 +470,13 @@ LunaRenderer::LunaRenderer() } // デストラクタ -LunaRenderer::~LunaRenderer() +LunaVideoRenderer::~LunaVideoRenderer() { } // 初期化 bool -LunaRenderer::Init() +LunaVideoRenderer::Init() { if (inherited::Init() == false) { return false; @@ -464,7 +489,7 @@ LunaRenderer::Init() // 画面合成 bool -LunaRenderer::RenderMD() +LunaVideoRenderer::RenderMD() { bool updated = planevram->Render(bitmap); return updated; @@ -479,8 +504,8 @@ LunaRenderer::RenderMD() ConsoleRenderer::ConsoleRenderer() { // 視認性のためフチを追加。 - width = 640 + Padding * 2; - height = 480 + Padding * 2; + width = (80 * 8) + Padding * 2; + height = (24 * 16) + Padding * 2; bitmap.Create(width, height); }