--- nono/vm/planevram.cpp 2026/04/29 17:05:29 1.1.1.4 +++ nono/vm/planevram.cpp 2026/04/29 17:05:33 1.1.1.5 @@ -11,6 +11,15 @@ #include "planevram.h" #include "mybswap.h" +#include +#include + +// v[] がいずれかでも true なら true を返す。 +static bool +AnyOf(const std::vector& v) +{ + return std::any_of(v.begin(), v.end(), [](bool x) { return x; }); +} // コンストラクタ PlaneVRAMDevice::PlaneVRAMDevice(int width_, int height_) @@ -21,7 +30,8 @@ PlaneVRAMDevice::PlaneVRAMDevice(int wid composite.Create(width_, height_); - dirty.resize(height_); + dirty.line.resize(height_); + pending.line.resize(height_); // レンダリング時に使うテーブルを事前に計算。 InitDeptable(); @@ -70,52 +80,76 @@ PlaneVRAMDevice::InitDeptable() void PlaneVRAMDevice::Invalidate() { - std::fill(dirty.begin(), dirty.end(), 1); + std::fill(dirty.line.begin(), dirty.line.end(), 1); } -// 全画面の更新フラグを下ろす -// VM スレッドから呼ばれる。 +// VRAM には更新がないが再レンダリングが必要。 +// パレット変更、スクロール等。VM スレッドから呼ばれる。 void -PlaneVRAMDevice::ClearDirty() +PlaneVRAMDevice::Invalidate2() { - std::fill(dirty.begin(), dirty.end(), 0); + dirty.invalidate2 = true; } -// 更新情報を取得。更新がなければ false を返す。 -// VM スレッドから呼ばれる。 +// 画面更新する必要があるか。 +// dirty から pending を更新してみて、更新が一つでもあれば true を返す。 +// VM スレッドで呼ばれる。 bool -PlaneVRAMDevice::GetModify(ModifyInfo *mod) const +PlaneVRAMDevice::Snap() { - memcpy(&mod->bits[0], &dirty[0], mod->bits.size()); + const uint height = composite.GetHeight(); + bool update_needed; - // 一つでも更新があれば dirty。 - mod->dirty = false; - for (int i = 0; i < dirty.size(); i++) { - if (dirty[i]) { - mod->dirty = true; - break; + // 更新 (dirty) があれば pending に重ねる。 + { + std::unique_lock lock(mtx); + for (int y = 0; y < height; y++) { + // std::vector には operator|=() がない。 + if (__predict_false(dirty.line[y])) { + pending.line[y] = true; + dirty.line[y] = false; + } } + + if (__predict_false(dirty.invalidate2)) { + pending.invalidate2 = true; + dirty.invalidate2 = false; + } + + update_needed = AnyOf(pending.line) || pending.invalidate2; } - return mod->dirty; + + return update_needed; } // 画面合成。 // レンダラスレッドから呼ばれる。 +// dst を更新すれば true を返す。 bool -PlaneVRAMDevice::Render(BitmapRGBX& dst, const ModifyInfo& modify) +PlaneVRAMDevice::Render(BitmapRGBX& dst) { bool updated = false; - // VRAM に更新があれば composite を更新 - if (modify.IsDirty()) { - RenderVRAMToComposite(modify); + // ローカルにコピー。 + ModifyInfo modified; + { + std::unique_lock lock(mtx); + modified.line = pending.line; + std::fill(pending.line.begin(), pending.line.end(), false); + modified.invalidate2 = pending.invalidate2; + pending.invalidate2 = false; + } + + // VRAM に更新があれば composite を更新。 + if (AnyOf(modified.line)) { + RenderVRAMToComposite(modified.line); updated = true; } - // composite に更新があるか(update)、 - // 無条件に更新するか(invalidate2) なら dst を更新。 - if (updated || modify.invalidate2) { - RenderCompositeToRGBX(dst, modify); + // composite に更新があるか(updated)、 + // 無条件に更新するか(modified.invalidate2) なら dst を更新。 + if (updated || modified.invalidate2) { + RenderCompositeToRGBX(dst, modified); updated = true; } @@ -125,7 +159,7 @@ PlaneVRAMDevice::Render(BitmapRGBX& dst, // VRAM から composite 画面を合成する。 // レンダラスレッドから呼ばれる。 void -PlaneVRAMDevice::RenderVRAMToComposite(const ModifyInfo& modify) +PlaneVRAMDevice::RenderVRAMToComposite(const std::vector& modified) { const uint width = composite.GetWidth(); const uint height = composite.GetHeight(); @@ -136,8 +170,8 @@ PlaneVRAMDevice::RenderVRAMToComposite(c // テキスト合成画面を描く for (uint y = 0; y < height; y++) { - uint8 mod = modify.bits[y]; - if (mod == 0) { + bool mod = modified[y]; + if (mod == false) { continue; } @@ -208,11 +242,11 @@ PlaneVRAMDevice::RenderVRAMToComposite(c } // composite 画面とパレット情報から RGBX 画面を合成する。 -// modify は composite 上での変更箇所を示している。 +// modified は composite 上での変更箇所を示している。 // レンダラスレッドから呼ばれる。 void PlaneVRAMDevice::RenderCompositeToRGBX(BitmapRGBX& dst, - const ModifyInfo& modify) + const ModifyInfo& modified) { const uint width = dst.GetWidth(); const uint height = dst.GetHeight(); @@ -222,7 +256,7 @@ PlaneVRAMDevice::RenderCompositeToRGBX(B std::vector view_mod(height); // この view に対する modify を計算する - if (__predict_false(modify.invalidate2)) { + if (__predict_false(modified.invalidate2)) { std::fill(view_mod.begin(), view_mod.end(), 1); } else { // Y scroll 方向の modify 計算 @@ -231,7 +265,7 @@ PlaneVRAMDevice::RenderCompositeToRGBX(B if (sy >= composite.GetHeight()) { sy -= composite.GetHeight(); } - view_mod[y] = modify.bits[sy]; + view_mod[y] = modified.line[sy]; } // 右がはみ出す場合は、はみ出した先のラスタも加味する。 @@ -242,7 +276,7 @@ PlaneVRAMDevice::RenderCompositeToRGBX(B sy -= composite.GetHeight(); } int sy2 = GetWrapY(sy); - view_mod[y] |= modify.bits[sy2]; + view_mod[y] |= modified.line[sy2]; } } }