|
|
1.1 root 1: //
2: // nono
1.1.1.3 root 3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
1.1 root 5: //
6:
1.1.1.6 ! root 7: //
! 8: // レンダラ
! 9: //
! 10:
1.1.1.4 root 11: #include "renderer.h"
1.1.1.5 root 12: #include "lunafb.h"
1.1.1.6 ! root 13: #include "sync.h"
! 14: #include "uimessage.h"
1.1 root 15:
1.1.1.6 ! root 16: // グローバル参照用
! 17: Renderer *gRenderer;
1.1 root 18:
19: // コンストラクタ
20: Renderer::Renderer()
1.1.1.5 root 21: : inherited("Renderer")
1.1 root 22: {
1.1.1.6 ! root 23: monitor.func = ToMonitorCallback(&X68030Renderer::MonitorUpdate);
! 24: monitor.SetSize(68, 33);
! 25: monitor.Regist(ID_MONITOR_RENDERER);
1.1 root 26: }
27:
28: // デストラクタ
29: Renderer::~Renderer()
30: {
1.1.1.6 ! root 31: TerminateThread();
! 32: gRenderer = NULL;
1.1 root 33: }
34:
1.1.1.6 ! root 35: // リセット
! 36: void
! 37: Renderer::ResetHard(bool poweron)
1.1 root 38: {
1.1.1.6 ! root 39: next_refresh_rtime = gSync->GetRealTime();
1.1 root 40:
1.1.1.6 ! root 41: // 統計情報をクリア
! 42: render_time.Reset();
! 43: render_exec = 0;
! 44: last_mod_blocks = 0;
! 45: total_mod_blocks = 0;
! 46: total_invalidate2 = 0;
1.1 root 47: }
48:
1.1.1.6 ! root 49: // 電源オフ
! 50: void
1.1 root 51: Renderer::PowerOff()
52: {
1.1.1.6 ! root 53: if (enable) {
1.1 root 54: // レンダリングスレッドに指示
55: std::unique_lock<std::mutex> lock(mtx);
56: request |= REQ_REND_POWEROFF;
57: cv.notify_one();
58: }
59: }
60:
1.1.1.6 ! root 61: // 合成処理イネーブル
! 62: // 一度だけ呼び出すことができる
1.1 root 63: void
1.1.1.6 ! root 64: Renderer::Enable()
1.1 root 65: {
1.1.1.6 ! root 66: assert(enable == false);
1.1 root 67:
1.1.1.6 ! root 68: enable = true;
! 69: bitmap.Create(width, height);
! 70: // 初期値灰色にしておく
! 71: bitmap.Fill(Color(0x70, 0x70, 0x70));
1.1 root 72: }
73:
1.1.1.6 ! root 74: // 画面合成処理 (VM スレッドで CRTC/CRTC2 から呼ばれる)。
1.1 root 75: // 今は一画面単位で合成を行なっている。ラスター云々は未対応。
76: void
77: Renderer::Render()
78: {
79: // CLI 版なら何もしない。
1.1.1.6 ! root 80: if (enable == false) {
1.1 root 81: return;
82: }
83:
1.1.1.6 ! root 84: // 更新されていればレンダラに引き渡す
! 85: ModifyInfo mod = gPlaneVRAM->GetModify();
! 86: if (__predict_false(invalidate2 == true)) {
! 87: mod.invalidate2 = true;
! 88: }
! 89:
! 90: if (mod.IsDirty() || mod.invalidate2) {
! 91: if (modq.Enqueue(mod)) {
! 92: // 更新情報を引き取ったのでクリアする
! 93: gPlaneVRAM->ClearDirty();
! 94: invalidate2 = false;
! 95: } else {
! 96: // VM スレッドが速すぎるため次回に持ち越し
! 97: }
! 98: }
! 99:
1.1 root 100: // スケジューラ都合による間引きとかがあればここらへんで評価?
101: // XXX どっちのスレッドでやるか
102:
103: // レンダリングスレッドに指示
104: std::unique_lock<std::mutex> lock(mtx);
105: request |= REQ_REND_NORMAL;
106: cv.notify_one();
107: }
108:
1.1.1.6 ! root 109: // 全画面更新の指示 (パレット変更やスクロールなど VRAM の変更を伴わないもの)。
1.1.1.4 root 110: // ここでは無効化だけ受け付けておいて、実際の処理はレンダリングの際に行う。
111: void
1.1.1.6 ! root 112: Renderer::Invalidate2()
1.1.1.4 root 113: {
1.1.1.6 ! root 114: invalidate2 = true;
1.1 root 115: }
116:
117: // レンダリングスレッド
118: void
119: Renderer::ThreadRun()
120: {
121: for (;;) {
122: uint32 req;
123:
124: // 何か起きるまで待つ
125: {
126: std::unique_lock<std::mutex> lock(mtx);
127: cv.wait(lock, [&] { return (request != 0); });
128: req = request;
129: request = 0;
130: }
131:
132: if ((req & REQ_TERMINATE)) {
133: // 終了するので、他のフラグは無視
134: break;
1.1.1.4 root 135: }
136: if ((req & REQ_REND_POWEROFF)) {
1.1 root 137: // 電源オフ時の描画 (通常描画フラグは無視)
138:
139: // 電源オフされると画面を灰色にする。
140: // 黒でもいいけど、電源オンで黒いままなのと区別したい。
1.1.1.6 ! root 141: bitmap.Fill(Color(0x70, 0x70, 0x70));
! 142: // UI に通知
! 143: UIMessage::Post(UIMessage::RENDER);
1.1.1.4 root 144: continue;
145: }
146: if ((req & REQ_REND_NORMAL)) {
1.1 root 147: // 通常描画
1.1.1.6 ! root 148: if (modq.Dequeue(&modify)) {
! 149: // 更新ブロック数を数える (統計用)
! 150: last_mod_blocks = modify.n_dirty;
! 151: total_mod_blocks += last_mod_blocks;
! 152: if (__predict_false(modify.invalidate2)) {
! 153: total_invalidate2++;
! 154: }
1.1 root 155:
1.1.1.6 ! root 156: #if defined(PERF_HIT)
! 157: // ブロックのヒット効率
! 158: int update_word = 0;
! 159: for (auto v : modify.dirty_word) {
! 160: if (v) {
! 161: update_word++;
! 162: }
! 163: }
! 164: int update_block = last_mod_blocks * BLKY * (BLKX / 32);
! 165: hitrate_total_word += update_word;
! 166: hitrate_total_block += update_block;
! 167: hitrate_ma.EnqueueForce((double)update_word / update_block);
! 168: #endif
! 169:
! 170: // レンダラを駆動する。
! 171: // out_dirty は前回 UI に通知した後一度でも更新があれば true。
! 172: render_time.Start();
! 173: out_dirty |= RenderMain();
! 174: render_time.Stop();
! 175: render_exec++;
! 176: }
! 177:
! 178: if (out_dirty) {
! 179: uint64 rtime = gSync->GetRealTime();
! 180: if (rtime >= next_refresh_rtime) {
! 181: UIMessage::Post(UIMessage::RENDER);
! 182: next_refresh_rtime = rtime + refresh_interval;
! 183: out_dirty = false;
! 184: }
1.1 root 185: }
186: }
187: }
188: }
189:
1.1.1.6 ! root 190: // スレッドの終了を指示
1.1.1.2 root 191: void
192: Renderer::Terminate()
193: {
194: std::unique_lock<std::mutex> lock(mtx);
195: request |= REQ_TERMINATE;
196: cv.notify_one();
197: }
198:
1.1.1.6 ! root 199: // 描画更新(通知)間隔を設定
! 200: void
! 201: Renderer::SetRefreshInterval(uint64 t)
! 202: {
! 203: refresh_interval = t;
! 204: }
! 205:
! 206: // モニタ更新
! 207: void
! 208: Renderer::MonitorUpdate(Monitor *, TextScreen& screen)
! 209: {
! 210: int x;
! 211: int y;
! 212:
! 213: screen.Clear();
! 214:
! 215: // modify
! 216: screen.Print(0, 0, "Last Update Region");
! 217: for (int i = 0, end = modify.bits.size(); i < end; i++) {
! 218: char buf[17];
! 219:
! 220: uint16 m = modify.bits[i];
! 221: int j;
! 222: for (j = 0; j < 16; j++, m <<= 1) {
! 223: uint8 c;
! 224: if (__predict_false((int16)m < 0)) {
! 225: c = '*';
! 226: } else {
! 227: c = '.';
! 228: }
! 229: buf[j] = c;
! 230: }
! 231: buf[j] = '\0';
! 232:
! 233: screen.Print((i / 32) * 21, 1 + (i % 32), "%2d:%s", i, buf);
! 234: }
! 235:
! 236: x = 43;
! 237: y = 0;
! 238: uint64 nsec = render_time.Elapsed();
! 239: screen.Print(x, y++, "RenderTime %3d.%06d sec",
! 240: (int)(nsec / 1000 / 1000 / 1000),
! 241: (int)(nsec / 1000) % (1000 * 1000));
! 242:
! 243: screen.Print(x, y++, "RenderExec %9" PRIu64, render_exec);
! 244:
! 245: y++;
! 246: screen.Print(x, y++, "Last Mod Blks %9d", last_mod_blocks);
! 247: screen.Print(x, y++, "Total Mod Blks %9" PRIu64, total_mod_blocks);
! 248: screen.Print(x, y++, "Total Invalid2 %9" PRIu64, total_invalidate2);
! 249:
! 250: #if defined(PERF_HIT)
! 251: y++;
! 252: // ヒット効率(?)、移動平均
! 253: double rate = 0.0;
! 254: int len = hitrate_ma.Length();
! 255: for (int i = 0; i < len; i++) {
! 256: rate += hitrate_ma.Peek(i);
! 257: }
! 258: if (__predict_true(len != 0)) {
! 259: rate = rate / len * 100;
! 260: }
! 261: screen.Print(x, y++, "Hit Rate(MA) %5.1f%%", rate);
! 262: screen.Print(x, y++, " (total avg) %5.1f%%",
! 263: (double)hitrate_total_word / hitrate_total_block * 100);
! 264: #endif
! 265: }
! 266:
! 267:
1.1 root 268: //
269: // X68030 レンダラ
270: //
271:
272: // コンストラクタ
273: X68030Renderer::X68030Renderer()
274: {
275: // XXX とりあえず
276: width = 768;
277: height = 512;
278: }
279:
280: // デストラクタ
281: X68030Renderer::~X68030Renderer()
282: {
283: }
284:
285: // 画面合成
286: bool
287: X68030Renderer::RenderMain()
288: {
289: // 今はテキスト画面のみを合成バッファに直接描いている
1.1.1.6 ! root 290: return gPlaneVRAM->Render(bitmap, modify);
1.1 root 291: }
292:
1.1.1.6 ! root 293:
1.1 root 294: //
295: // LUNA レンダラ
296: //
297:
298: // コンストラクタ
299: LunaRenderer::LunaRenderer()
300: {
301: width = 1280;
302: height = 1024;
303: }
304:
305: // デストラクタ
306: LunaRenderer::~LunaRenderer()
307: {
308: }
309:
310: // 画面合成
311: bool
312: LunaRenderer::RenderMain()
313: {
1.1.1.6 ! root 314: return gPlaneVRAM->Render(bitmap, modify);
! 315: }
1.1 root 316:
1.1.1.6 ! root 317: const BitmapI8&
! 318: LunaRenderer::GetComposite() const
! 319: {
! 320: return gLunafb->GetComposite();
1.1 root 321: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.