--- nono/vm/renderer.cpp 2026/04/29 17:05:13 1.1.1.7 +++ nono/vm/renderer.cpp 2026/04/29 17:05:24 1.1.1.9 @@ -9,17 +9,19 @@ // #include "renderer.h" -#include "lunafb.h" -#include "sync.h" +#include "planevram.h" +#include "syncer.h" #include "uimessage.h" - -// グローバル参照用 -Renderer *gRenderer; +#include "videoctlr.h" // コンストラクタ Renderer::Renderer() - : inherited("Renderer") + : inherited(OBJ_RENDERER) { +#if defined(HAVE_AVX2) + enable_avx2 = gMainApp.enable_avx2; +#endif + monitor.func = ToMonitorCallback(&X68030Renderer::MonitorUpdate); monitor.SetSize(68, 33); monitor.Regist(ID_MONITOR_RENDERER); @@ -29,14 +31,26 @@ Renderer::Renderer() Renderer::~Renderer() { TerminateThread(); - gRenderer = NULL; +} + +// 初期化 +bool +Renderer::Init() +{ + if (inherited::Init() == false) { + return false; + } + + syncer = GetSyncer(); + + return true; } // リセット void Renderer::ResetHard(bool poweron) { - next_refresh_rtime = gSync->GetRealTime(); + next_refresh_rtime = syncer->GetRealTime(); // 統計情報をクリア render_time.Reset(); @@ -82,7 +96,7 @@ Renderer::Render() } // 更新されていればレンダラに引き渡す - ModifyInfo mod = gPlaneVRAM->GetModify(); + ModifyInfo mod = planevram->GetModify(); if (__predict_false(invalidate2 == true)) { mod.invalidate2 = true; } @@ -90,7 +104,7 @@ Renderer::Render() if (mod.IsDirty() || mod.invalidate2) { if (modq.Enqueue(mod)) { // 更新情報を引き取ったのでクリアする - gPlaneVRAM->ClearDirty(); + planevram->ClearDirty(); invalidate2 = false; } else { // VM スレッドが速すぎるため次回に持ち越し @@ -153,20 +167,6 @@ Renderer::ThreadRun() total_invalidate2++; } -#if defined(PERF_HIT) - // ブロックのヒット効率 - int update_word = 0; - for (auto v : modify.dirty_word) { - if (v) { - update_word++; - } - } - int update_block = last_mod_blocks * BLKY * (BLKX / 32); - hitrate_total_word += update_word; - hitrate_total_block += update_block; - hitrate_ma.EnqueueForce((double)update_word / update_block); -#endif - // レンダラを駆動する。 // out_dirty は前回 UI に通知した後一度でも更新があれば true。 render_time.Start(); @@ -176,7 +176,7 @@ Renderer::ThreadRun() } if (out_dirty) { - uint64 rtime = gSync->GetRealTime(); + uint64 rtime = syncer->GetRealTime(); if (rtime >= next_refresh_rtime) { UIMessage::Post(UIMessage::RENDER); next_refresh_rtime = rtime + refresh_interval; @@ -214,24 +214,23 @@ Renderer::MonitorUpdate(Monitor *, TextS // modify screen.Print(0, 0, "Last Update Region"); - for (int i = 0, end = modify.bits.size(); i < end; i++) { - char buf[17]; - - uint16 m = modify.bits[i]; - int j; - for (j = 0; j < 16; j++, m <<= 1) { - uint8 c; - if (__predict_false((int16)m < 0)) { + const uint8 *m = &modify.bits[0]; + for (int i = 0; i < 32; i++) { + char buf[33]; + uint8 c; + for (int j = 0; j < 32; j++) { + if (__predict_false(*m++ != 0)) { c = '*'; } else { c = '.'; } buf[j] = c; } - buf[j] = '\0'; - screen.Print((i / 32) * 21, 1 + (i % 32), "%2d:%s", i, buf); + buf[32] = '\0'; + screen.Print(0, 1 + i, "%4d:%s", i * 32, buf); } + screen.Puts(0, 1, "Y="); x = 43; y = 0; @@ -246,22 +245,57 @@ Renderer::MonitorUpdate(Monitor *, TextS screen.Print(x, y++, "Last Mod Blks %9d", last_mod_blocks); screen.Print(x, y++, "Total Mod Blks %9" PRIu64, total_mod_blocks); screen.Print(x, y++, "Total Invalid2 %9" PRIu64, total_invalidate2); +} -#if defined(PERF_HIT) - y++; - // ヒット効率(?)、移動平均 - double rate = 0.0; - int len = hitrate_ma.Length(); - for (int i = 0; i < len; i++) { - rate += hitrate_ma.Peek(i); - } - if (__predict_true(len != 0)) { - rate = rate / len * 100; - } - screen.Print(x, y++, "Hit Rate(MA) %5.1f%%", rate); - screen.Print(x, y++, " (total avg) %5.1f%%", - (double)hitrate_total_word / hitrate_total_block * 100); +// RGBX から RGB への変換。 +void +Renderer::RGBXtoRGB(BitmapRGB& dst, const BitmapRGBX& src) +{ + assert(dst.GetWidth() == src.GetWidth()); + assert(dst.GetHeight() == src.GetHeight()); + assert(src.GetWidth() % 4 == 0); + +#if defined(HAVE_AVX2) + if (__predict_true(enable_avx2)) { + RGBXtoRGB_avx2(dst, src); + } else #endif + { + RGBXtoRGB_gen(dst, src); + } +} + +// RGBX から RGB への変換。(C++ 版) +/*static*/ void +Renderer::RGBXtoRGB_gen(BitmapRGB& dst, const BitmapRGBX& src) +{ + for (int y = 0, yend = src.GetHeight(); y < yend; y++) { + const uint32 *s = (const uint32 *)src.GetRowPtr(y); + uint32 *d = (uint32 *)dst.GetRowPtr(y); + + const uint32 *send = s + src.GetWidth(); + for (; s < send; ) { + // 4ピクセルずつ処理する + + uint32 c0 = htole32(*s++); + uint32 c1 = htole32(*s++); + uint32 c2 = htole32(*s++); + uint32 c3 = htole32(*s++); + + // c0 = $x0B0G0R0 + // c1 = $x1B1G1R1 + // c2 = $x2B2G2R2 + // c3 = $x3B3G3R3 + // + // d[0] = $00B0G0R0 | $R1000000 = $R1B0G0R0 + // d[1] = $0000B1G1 | $G2R20000 = $G2R2B1G1 + // d[2] = $000000B2 | $B3G3R300 = $B3G3R3B2 + + *d++ = le32toh((c0 ) | (c1 << 24)); + *d++ = le32toh((c1 >> 8) | (c2 << 16)); + *d++ = le32toh((c2 >> 16) | (c3 << 8)); + } + } } @@ -275,6 +309,8 @@ X68030Renderer::X68030Renderer() // XXX とりあえず width = 768; height = 512; + + bitmap32.Create(width, height); } // デストラクタ @@ -282,12 +318,29 @@ X68030Renderer::~X68030Renderer() { } +// 初期化 +bool +X68030Renderer::Init() +{ + if (inherited::Init() == false) { + return false; + } + + planevram = GetPlaneVRAMDevice(); + videoctlr = GetVideoCtlrDevice(); + + return true; +} + // 画面合成 bool X68030Renderer::RenderMain() { - // 今はテキスト画面のみを合成バッファに直接描いている - return gPlaneVRAM->Render(bitmap, modify); + bool updated = videoctlr->Render(bitmap32, modify); + if (updated) { + RGBXtoRGB(bitmap, bitmap32); + } + return updated; } @@ -300,6 +353,8 @@ LunaRenderer::LunaRenderer() { width = 1280; height = 1024; + + textbmp.Create(width, height); } // デストラクタ @@ -307,9 +362,52 @@ LunaRenderer::~LunaRenderer() { } +// 初期化 +bool +LunaRenderer::Init() +{ + if (inherited::Init() == false) { + return false; + } + + planevram = GetPlaneVRAMDevice(); + + return true; +} + // 画面合成 bool LunaRenderer::RenderMain() { - return gPlaneVRAM->Render(bitmap, modify); + // 型変換だけ必要 + bool updated = planevram->Render(textbmp, modify); + if (updated) { + RGBXtoRGB(bitmap, textbmp); + } + return updated; +} + + +// +// 何もしないレンダラ +// + +// コンストラクタ +NopRenderer::NopRenderer() +{ + // XXX サポートしてない + width = 640; + height = 480; +} + +// デストラクタ +NopRenderer::~NopRenderer() +{ +} + +// 画面合成 +bool +NopRenderer::RenderMain() +{ + return false; }