--- nono/vm/renderer.cpp 2026/04/29 17:04:28 1.1.1.1 +++ nono/vm/renderer.cpp 2026/04/29 17:04:55 1.1.1.5 @@ -1,23 +1,25 @@ // // nono -// Copyright (C) 2018 isaki@NetBSD.org +// Copyright (C) 2020 nono project +// Licensed under nono-license.txt // -#include "object.h" -#include "bitmap.h" -#include "bt454.h" #include "renderer.h" +#include "bt454.h" +#include "lunafb.h" +#include "mythread.h" #include "tvram.h" -Renderer *gRenderer; +std::unique_ptr gRenderer; static void *renderer_run(void *); // コンストラクタ Renderer::Renderer() + : inherited("Renderer") { - logname = "renderer"; - devname = "Render"; + // 初回は必ず描画する? (電源オン直後かな?) + invalidate = true; } // デストラクタ @@ -25,18 +27,18 @@ Renderer::~Renderer() { // imagebuf の所有権は持っていないので解放不要。 - // スレッド終了を指示 - std::unique_lock lock(mtx); - request |= REQ_TERMINATE; - cv.notify_one(); + if (thread_created) { + Terminate(); + pthread_join(thread, NULL); + } } bool Renderer::Init() { // レンダリングスレッド起動 - pthread_t th; - pthread_create(&th, NULL, renderer_run, NULL); + pthread_create(&thread, NULL, renderer_run, NULL); + thread_created = true; return true; } @@ -88,12 +90,21 @@ Renderer::Render() cv.notify_one(); } +// 全画面無効化の指示 (パレット変更で呼ばれる)。 +// ここでは無効化だけ受け付けておいて、実際の処理はレンダリングの際に行う。 +void +Renderer::Invalidate() +{ + std::unique_lock lock(mtx); + request |= REQ_INVALIDATE; + cv.notify_one(); +} + // レンダリングスレッドのエントリポイント void * renderer_run(void *dummy) { - pthread_setname_np("Renderer"); - pthread_detach(pthread_self()); + PTHREAD_SETNAME("Renderer"); gRenderer->ThreadRun(); return NULL; @@ -117,8 +128,8 @@ Renderer::ThreadRun() if ((req & REQ_TERMINATE)) { // 終了するので、他のフラグは無視 break; - - } else if ((req & REQ_REND_POWEROFF)) { + } + if ((req & REQ_REND_POWEROFF)) { // 電源オフ時の描画 (通常描画フラグは無視) // 電源オフされると画面を灰色にする。 @@ -126,8 +137,16 @@ Renderer::ThreadRun() memset(imagebuf, 0x70, width * height * BPP); // ウィンドウに通知 refresh_callback(); - - } else if ((req & REQ_REND_NORMAL)) { + continue; + } + if ((req & REQ_INVALIDATE)) { + // 全画面無効化の指示。ここではフラグを立てるだけ。 + // パレットは普段はまず変更されないが、変更する時には連続して + // 全パレットが変更されがちなので、ここでフラグを蓄積する。 + // このフラグは同じスレッドの RenderMain() 内で回収する。 + invalidate = true; + } + if ((req & REQ_REND_NORMAL)) { // 通常描画 // レンダラを駆動して @@ -139,6 +158,17 @@ Renderer::ThreadRun() } } +// スレッドの終了を指示 (スレッドは動いていること) +void +Renderer::Terminate() +{ + assert(thread_created); + + std::unique_lock lock(mtx); + request |= REQ_TERMINATE; + cv.notify_one(); +} + // // X68030 レンダラ // @@ -182,11 +212,23 @@ LunaRenderer::~LunaRenderer() { } +bool +LunaRenderer::Init() +{ + if (inherited::Init() == false) { + return false; + } + + // ホストパレット配列を取得。 + pal = gBT454->GetHostPalette(); + return true; +} + + // 画面合成 bool LunaRenderer::RenderMain() { - const uint8 *pal; const uint32 *plane0; std::atomic *dirty; int hscroll; @@ -197,13 +239,10 @@ LunaRenderer::RenderMain() assert(imagebuf); dst0 = imagebuf; - // パレット取得 - pal = gBT454->GetHostPalette(); - // ビットマップ - gBitmap->GetRFCNT(&hscroll, &vscroll); - const uint8 *mem = gBitmap->GetBuf(); - dirty = gBitmap->GetDirty(); + gLunafb->GetRFCNT(&hscroll, &vscroll); + const uint8 *mem = gLunafb->GetBuf(); + dirty = gLunafb->GetDirty(); updated = false; @@ -212,11 +251,20 @@ LunaRenderer::RenderMain() // レンダリング終了時に dirty が 2 なら 0 に戻す。 // これによりレンダリング中に VRAM への書き込みがあれば次回描画される。 + // 全域を無効化して画面全体を描画し直す。 + // XXX この処理中に VRAM 書き込み等があっても整合するんだっけこれ + if (invalidate) { + for (int y = 0; y < height; y++) { + dirty[y] = 1; + } + invalidate = false; + } + // sy はメモリ上の Y 座標 // dy はレンダラ画面の Y 座標 (RFCNT のラスタカウンタを考慮) // XXX とりあえず1プレーン - plane0 = (uint32 *)mem; + plane0 = (const uint32 *)mem; int sy = vscroll; for (int dy = 0; dy < height; dst0 += width * BPP, dy++, sy++) { sy &= 0x3ff;