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