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