|
|
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.11 root 12: #include "console.h"
13: #include "monitor.h"
1.1.1.9 root 14: #include "planevram.h"
1.1.1.10 root 15: #include "scheduler.h"
1.1.1.8 root 16: #include "syncer.h"
1.1.1.6 root 17: #include "uimessage.h"
1.1.1.9 root 18: #include "videoctlr.h"
1.1 root 19:
1.1.1.10 root 20: #if 0
21: #define PERFREND
22: #include "stopwatch.h"
23: static Stopwatch sw_notify;
24: static uint64 notify_time;
25: static uint notify_count;
26: static uint64 render_time;
27: static uint64 stretch_time;
28: static uint64 convert_time;
29: static uint convert_count;
30: #endif
31:
32: // 電源オフ時の画面色 (電源オンで黒なのとは区別したいのであえて灰色)
33: static const Color ScreenOffColor(0x70, 0x70, 0x70);
34:
1.1 root 35: // コンストラクタ
36: Renderer::Renderer()
1.1.1.8 root 37: : inherited(OBJ_RENDERER)
1.1 root 38: {
1.1.1.11 root 39: monitor = gMonitorManager->Regist(ID_MONITOR_RENDERER, this);
40: monitor->func = ToMonitorCallback(&Renderer::MonitorUpdate);
41: monitor->SetSize(42, 10);
1.1 root 42: }
43:
44: // デストラクタ
45: Renderer::~Renderer()
46: {
1.1.1.6 root 47: TerminateThread();
1.1.1.8 root 48: }
49:
50: // 初期化
51: bool
52: Renderer::Init()
53: {
1.1.1.10 root 54: scheduler = GetScheduler();
1.1.1.8 root 55: syncer = GetSyncer();
56:
1.1.1.10 root 57: // GUI ならレンダラ有効。
58: if (gMainApp.IsGUI()) {
59: enable = true;
60: bitmap.Create(width, height);
61: // 初期値 (どこでやる?)
62: bitmap.Fill(ScreenOffColor);
63: }
64:
1.1.1.8 root 65: return true;
1.1 root 66: }
67:
1.1.1.6 root 68: // リセット
69: void
70: Renderer::ResetHard(bool poweron)
1.1 root 71: {
1.1.1.8 root 72: next_refresh_rtime = syncer->GetRealTime();
1.1 root 73:
1.1.1.6 root 74: // 統計情報をクリア
1.1.1.10 root 75: uint64 now = scheduler->GetVirtTime();
76: stat_input_count = 0;
77: last_input_time = now;
78: ma_input_span.Clear();
79: stat_render_count = 0;
80: stat_noupdate_count = 0;
81: stat_nobitmap_count = 0;
82: stat_output_count = 0;
83: last_output_time = now;
84: ma_output_span.Clear();
1.1 root 85: }
86:
1.1.1.6 root 87: // 電源オフ
88: void
1.1 root 89: Renderer::PowerOff()
90: {
1.1.1.6 root 91: if (enable) {
1.1.1.11 root 92: #if defined(PERFREND)
93: sw_notify.Restart();
94: #endif
1.1 root 95: // レンダリングスレッドに指示
96: std::unique_lock<std::mutex> lock(mtx);
1.1.1.10 root 97: request |= REQ_SCREENOFF;
1.1 root 98: cv.notify_one();
99: }
100: }
101:
1.1.1.11 root 102: // 画面合成処理 (VM スレッドで呼ばれる)。
1.1 root 103: // 今は一画面単位で合成を行なっている。ラスター云々は未対応。
104: void
1.1.1.10 root 105: Renderer::NotifyRender()
1.1 root 106: {
107: // CLI 版なら何もしない。
1.1.1.6 root 108: if (enable == false) {
1.1 root 109: return;
110: }
111:
1.1.1.10 root 112: // 統計情報
113: stat_input_count++;
114: uint64 now = scheduler->GetVirtTime();
115: ma_input_span.EnqueueForce(now - last_input_time);
116: last_input_time = now;
117:
118: #if defined(PERFREND)
1.1.1.11 root 119: sw_notify.Restart();
1.1.1.10 root 120: #endif
1.1.1.6 root 121:
1.1.1.11 root 122: // レンダラスレッドに描画指示を出すだけ。
123: {
124: std::unique_lock<std::mutex> lock(mtx);
125: request |= REQ_RENDER;
126: cv.notify_one();
1.1.1.6 root 127: }
1.1 root 128: }
129:
130: // レンダリングスレッド
131: void
132: Renderer::ThreadRun()
133: {
1.1.1.10 root 134: if (enable) {
135: SetThreadAffinityHint(AffinityClass::Heavy);
136: }
137:
138: int64 delay = 0;
1.1 root 139: for (;;) {
140: uint32 req;
141:
142: // 何か起きるまで待つ
143: {
144: std::unique_lock<std::mutex> lock(mtx);
1.1.1.10 root 145: if (delay == 0) {
146: cv.wait(lock, [&] { return (request != 0); });
147: } else {
148: cv.wait_for(lock, std::chrono::nanoseconds(delay),
149: [&] { return (request != 0); });
150: if (request == 0) {
151: request = REQ_POST;
152: }
153: }
1.1 root 154: req = request;
155: request = 0;
156: }
157:
158: if ((req & REQ_TERMINATE)) {
159: // 終了するので、他のフラグは無視
160: break;
1.1.1.4 root 161: }
1.1 root 162:
1.1.1.10 root 163: // req に基づいて処理。
164: int64 t = DoRender(req);
165: if (t == 0 || (req & REQ_POST)) {
166: // UI に即通知。
167:
168: // 統計情報
169: stat_output_count++;
170: uint64 now = syncer->GetRealTime();
171: ma_output_span.EnqueueForce(now - last_output_time);
172: last_output_time = now;
173:
1.1.1.6 root 174: UIMessage::Post(UIMessage::RENDER);
1.1.1.10 root 175: delay = 0;
176: } else if (t > 0) {
177: // 指定時間後に UI に通知。
178: delay = t;
1.1.1.4 root 179: }
1.1.1.10 root 180: }
181: }
1.1 root 182:
1.1.1.10 root 183: // req に基づいて描画する。
184: // UI への描画通知を遅延させる時間を返す (即通知する場合は 0)。
185: // UI に通知しない場合は -1 を返す。
186: int64
187: Renderer::DoRender(uint32 req)
188: {
189: // 1. REND_NORMAL なら電源オン時の通常描画指示、
190: // REND_POWEROFF なら電源オン→オフ遷移時の描画指示。
191: // 2. REND_RESIZE なら valid = false にして、表示ビットマップをリサイズ。
192: // 3. 必要なら bitmap を拡大縮小。
193: // 4. bitmap24 に描画して valid = true;
1.1.1.6 root 194:
1.1.1.10 root 195: #if defined(PERFREND)
196: Stopwatch sw;
197: #endif
198: bool updated = false;
199:
200: if ((req & REQ_RENDER)) {
201: // 通常描画
202:
203: #if defined(PERFREND)
204: sw_notify.Stop();
205: notify_time += sw_notify.Elapsed();
206: notify_count++;
207:
1.1.1.11 root 208: sw.Restart();
1.1.1.10 root 209: #endif
1.1.1.11 root 210: // レンダラを駆動する。
211: updated = RenderMD();
1.1.1.10 root 212: #if defined(PERFREND)
1.1.1.11 root 213: sw.Stop();
214: render_time += sw.Elapsed();
1.1.1.10 root 215: #endif
1.1.1.11 root 216: stat_render_count++;
1.1 root 217: }
1.1.1.10 root 218: if ((req & REQ_SCREENOFF)) {
219: // 電源オン→オフ時の描画
220: bitmap.Fill(ScreenOffColor);
221: updated = true;
222: }
223:
224: if ((req & REQ_RESIZE)) {
225: // 表示ビットマップのリサイズ要求
226:
227: bitmap24_valid = false;
228: bitmap24.reset(new BitmapRGB(new_viewwidth, new_viewheight));
229: if ((bool)bitmap24 == false) {
230: putlog(0, "Could not allocate BitmapRGB(%u, %u)",
231: new_viewwidth, new_viewheight);
232: return -1;
233: }
234: viewrect = Rect(0, 0, new_viewwidth, new_viewheight);
235: updated = true;
236: }
237:
238: // 更新箇所がなければここで終わり。
239: if (updated == false) {
240: stat_noupdate_count++;
241: return -1;
242: }
243:
244: // 出力ビットマップが用意できてなければここで終わり。
245: if (__predict_false((bool)bitmap24 == false)) {
246: stat_nobitmap_count++;
247: return -1;
248: }
249:
250: // 等倍表示でなければ拡大縮小。
251: #if defined(PERFREND)
252: sw.Restart();
253: #endif
254: BitmapRGBX scaled_bitmap;
255: BitmapRGBX *src_bitmap;
256: if (bitmap.GetWidth() == bitmap24->GetWidth() &&
257: bitmap.GetHeight() == bitmap24->GetHeight())
258: {
259: src_bitmap = &bitmap;
260: } else {
261: scaled_bitmap.Create(viewrect.w, viewrect.h);
262: scaled_bitmap.DrawBitmapStretch(viewrect, bitmap);
263: src_bitmap = &scaled_bitmap;
264: }
265: #if defined(PERFREND)
266: sw.Stop();
267: stretch_time += sw.Elapsed();
268: #endif
269:
270: // wxWidgets 用の RGBX→RGB 変換。
271: #if defined(PERFREND)
272: sw.Restart();
273: #endif
274: src_bitmap->ConvertToRGB(*bitmap24);
275: bitmap24_valid = true;
276: #if defined(PERFREND)
277: sw.Stop();
278: convert_time += sw.Elapsed();
279: #endif
280:
281: #if defined(PERFREND)
282: if (++convert_count % 100 == 0) {
1.1.1.11 root 283: printf("Notify %u, Render %u, Stretch %u, Convert %u [usec]\n",
1.1.1.10 root 284: (uint)(notify_time / notify_count / 1000U),
285: (uint)(render_time / stat_render_count / 1000U),
286: (uint)(stretch_time / convert_count / 1000U),
287: (uint)(convert_time / convert_count / 1000U));
288: }
289: #endif
290:
291: if ((req & (REQ_SCREENOFF | REQ_RESIZE))) {
292: // 電源オン→オフ遷移かリサイズ要求時は即通知。
293: return 0;
294: }
295:
296: // 通常描画のみならここで通知を律速する。
297: uint64 rtime = syncer->GetRealTime();
298: if (rtime < next_refresh_rtime) {
299: return next_refresh_rtime - rtime;
300: }
301: next_refresh_rtime = rtime + refresh_interval;
302: return 0;
1.1 root 303: }
304:
1.1.1.6 root 305: // スレッドの終了を指示
1.1.1.2 root 306: void
307: Renderer::Terminate()
308: {
309: std::unique_lock<std::mutex> lock(mtx);
310: request |= REQ_TERMINATE;
311: cv.notify_one();
312: }
313:
1.1.1.10 root 314: // リサイズ指示
315: void
316: Renderer::ResizeView(uint width_, uint height_)
317: {
318: assert(enable);
319:
320: new_viewwidth = width_;
321: new_viewheight = height_;
322:
323: std::unique_lock<std::mutex> lock(mtx);
324: request |= REQ_RESIZE;
325: cv.notify_one();
326: }
327:
1.1.1.6 root 328: // 描画更新(通知)間隔を設定
329: void
330: Renderer::SetRefreshInterval(uint64 t)
331: {
332: refresh_interval = t;
333: }
334:
335: // モニタ更新
336: void
337: Renderer::MonitorUpdate(Monitor *, TextScreen& screen)
338: {
339: int x;
340: int y;
341:
342: screen.Clear();
343:
1.1.1.10 root 344: x = 16;
1.1.1.6 root 345: y = 0;
346:
1.1.1.10 root 347: screen.Puts(0, y++, "<Statistics>");
1.1.1.6 root 348:
1.1.1.10 root 349: screen.Puts(0, y, "Input Count");
350: screen.Print(x, y++, "%26s", format_number(stat_input_count).c_str());
351: uint count = ma_input_span.Length();
352: uint64 ma = 0;
353: for (uint i = 0; i < count; i++) {
354: ma += ma_input_span.Peek(i);
355: }
356: if (count != 0) {
357: ma /= count;
358: }
359: screen.Puts(0, y, "Input Frequency(VT)");
360: screen.Print(x + 18, y, "%5.1f Hz",
361: ma == 0 ? 0.0 : (double)1000'000'000 / ma);
1.1.1.6 root 362: y++;
363:
1.1.1.10 root 364: y++;
365: screen.Puts(0, y, "RenderMD Count");
366: screen.Print(x, y++, "%26s", format_number(stat_render_count).c_str());
367: screen.Puts(0, y, "NoUpdate Count");
368: screen.Print(x, y++, "%26s", format_number(stat_noupdate_count).c_str());
369: screen.Puts(0, y, "NoBitmap Count");
370: screen.Print(x, y++, "%26s", format_number(stat_nobitmap_count).c_str());
1.1.1.9 root 371:
1.1.1.10 root 372: y++;
373: screen.Puts(0, y, "Output Count");
374: screen.Print(x, y++, "%26s", format_number(stat_output_count).c_str());
375: count = ma_output_span.Length();
376: ma = 0;
377: for (uint i = 0; i < count; i++) {
378: ma += ma_output_span.Peek(i);
379: }
380: if (count != 0) {
381: ma /= count;
382: }
383: screen.Puts(0, y, "Output Frequency(RT)");
384: screen.Print(x + 18, y, "%5.1f Hz",
385: ma == 0 ? 0.0 : (double)1000'000'000 / ma);
386: y++;
1.1.1.9 root 387: }
388:
1.1.1.6 root 389:
1.1 root 390: //
391: // X68030 レンダラ
392: //
393:
394: // コンストラクタ
395: X68030Renderer::X68030Renderer()
396: {
397: // XXX とりあえず
398: width = 768;
399: height = 512;
1.1.1.9 root 400:
1.1.1.10 root 401: bitmap.Create(width, height);
1.1 root 402: }
403:
404: // デストラクタ
405: X68030Renderer::~X68030Renderer()
406: {
407: }
408:
1.1.1.9 root 409: // 初期化
410: bool
411: X68030Renderer::Init()
412: {
413: if (inherited::Init() == false) {
414: return false;
415: }
416:
417: videoctlr = GetVideoCtlrDevice();
418:
419: return true;
420: }
421:
1.1 root 422: // 画面合成
423: bool
1.1.1.10 root 424: X68030Renderer::RenderMD()
1.1 root 425: {
1.1.1.11 root 426: bool updated = videoctlr->Render(bitmap);
1.1.1.9 root 427: return updated;
1.1 root 428: }
429:
1.1.1.6 root 430:
1.1 root 431: //
432: // LUNA レンダラ
433: //
434:
435: // コンストラクタ
436: LunaRenderer::LunaRenderer()
437: {
438: width = 1280;
439: height = 1024;
1.1.1.9 root 440:
1.1.1.10 root 441: bitmap.Create(width, height);
1.1 root 442: }
443:
444: // デストラクタ
445: LunaRenderer::~LunaRenderer()
446: {
447: }
448:
1.1.1.9 root 449: // 初期化
450: bool
451: LunaRenderer::Init()
452: {
453: if (inherited::Init() == false) {
454: return false;
455: }
456:
457: planevram = GetPlaneVRAMDevice();
458:
459: return true;
460: }
461:
1.1 root 462: // 画面合成
463: bool
1.1.1.10 root 464: LunaRenderer::RenderMD()
1.1 root 465: {
1.1.1.11 root 466: bool updated = planevram->Render(bitmap);
1.1.1.9 root 467: return updated;
1.1.1.8 root 468: }
469:
470:
471: //
1.1.1.11 root 472: // コンソールレンダラ
1.1.1.8 root 473: //
474:
475: // コンストラクタ
1.1.1.11 root 476: ConsoleRenderer::ConsoleRenderer()
1.1.1.8 root 477: {
1.1.1.11 root 478: // 視認性のためフチを追加。
479: width = 640 + Padding * 2;
480: height = 480 + Padding * 2;
481:
482: bitmap.Create(width, height);
1.1.1.8 root 483: }
484:
485: // デストラクタ
1.1.1.11 root 486: ConsoleRenderer::~ConsoleRenderer()
1.1.1.8 root 487: {
488: }
489:
1.1.1.11 root 490: // 初期化
1.1.1.10 root 491: bool
1.1.1.11 root 492: ConsoleRenderer::Init()
1.1.1.10 root 493: {
1.1.1.11 root 494: if (inherited::Init() == false) {
495: return false;
496: }
1.1.1.10 root 497:
1.1.1.11 root 498: console = GetConsoleDevice();
499:
500: return true;
1.1.1.10 root 501: }
502:
1.1.1.8 root 503: // 画面合成
504: bool
1.1.1.11 root 505: ConsoleRenderer::RenderMD()
1.1.1.8 root 506: {
1.1.1.11 root 507: bool updated = console->Render(bitmap);
508: return updated;
1.1.1.6 root 509: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.