|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.