|
|
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;
1.1.1.13! root 228: bitmap24.reset();
! 229: try {
! 230: bitmap24.reset(new BitmapRGB(new_viewwidth, new_viewheight));
! 231: } catch (...) { }
1.1.1.10 root 232: if ((bool)bitmap24 == false) {
233: putlog(0, "Could not allocate BitmapRGB(%u, %u)",
234: new_viewwidth, new_viewheight);
235: return -1;
236: }
237: viewrect = Rect(0, 0, new_viewwidth, new_viewheight);
238: updated = true;
239: }
240:
241: // 更新箇所がなければここで終わり。
242: if (updated == false) {
243: stat_noupdate_count++;
244: return -1;
245: }
246:
247: // 出力ビットマップが用意できてなければここで終わり。
248: if (__predict_false((bool)bitmap24 == false)) {
249: stat_nobitmap_count++;
250: return -1;
251: }
252:
253: // 等倍表示でなければ拡大縮小。
254: #if defined(PERFREND)
255: sw.Restart();
256: #endif
257: BitmapRGBX scaled_bitmap;
258: BitmapRGBX *src_bitmap;
259: if (bitmap.GetWidth() == bitmap24->GetWidth() &&
260: bitmap.GetHeight() == bitmap24->GetHeight())
261: {
262: src_bitmap = &bitmap;
263: } else {
264: scaled_bitmap.Create(viewrect.w, viewrect.h);
265: scaled_bitmap.DrawBitmapStretch(viewrect, bitmap);
266: src_bitmap = &scaled_bitmap;
267: }
268: #if defined(PERFREND)
269: sw.Stop();
270: stretch_time += sw.Elapsed();
271: #endif
272:
273: // wxWidgets 用の RGBX→RGB 変換。
274: #if defined(PERFREND)
275: sw.Restart();
276: #endif
277: src_bitmap->ConvertToRGB(*bitmap24);
278: bitmap24_valid = true;
279: #if defined(PERFREND)
280: sw.Stop();
281: convert_time += sw.Elapsed();
282: #endif
283:
284: #if defined(PERFREND)
285: if (++convert_count % 100 == 0) {
1.1.1.11 root 286: printf("Notify %u, Render %u, Stretch %u, Convert %u [usec]\n",
1.1.1.10 root 287: (uint)(notify_time / notify_count / 1000U),
288: (uint)(render_time / stat_render_count / 1000U),
289: (uint)(stretch_time / convert_count / 1000U),
290: (uint)(convert_time / convert_count / 1000U));
291: }
292: #endif
293:
294: if ((req & (REQ_SCREENOFF | REQ_RESIZE))) {
295: // 電源オン→オフ遷移かリサイズ要求時は即通知。
296: return 0;
297: }
298:
299: // 通常描画のみならここで通知を律速する。
300: uint64 rtime = syncer->GetRealTime();
301: if (rtime < next_refresh_rtime) {
302: return next_refresh_rtime - rtime;
303: }
304: next_refresh_rtime = rtime + refresh_interval;
305: return 0;
1.1 root 306: }
307:
1.1.1.6 root 308: // スレッドの終了を指示
1.1.1.2 root 309: void
310: Renderer::Terminate()
311: {
312: std::unique_lock<std::mutex> lock(mtx);
313: request |= REQ_TERMINATE;
314: cv.notify_one();
315: }
316:
1.1.1.10 root 317: // リサイズ指示
318: void
319: Renderer::ResizeView(uint width_, uint height_)
320: {
321: assert(enable);
322:
323: new_viewwidth = width_;
324: new_viewheight = height_;
325:
326: std::unique_lock<std::mutex> lock(mtx);
327: request |= REQ_RESIZE;
328: cv.notify_one();
329: }
330:
1.1.1.6 root 331: // 描画更新(通知)間隔を設定
332: void
333: Renderer::SetRefreshInterval(uint64 t)
334: {
335: refresh_interval = t;
336: }
337:
338: // モニタ更新
339: void
340: Renderer::MonitorUpdate(Monitor *, TextScreen& screen)
341: {
342: int x;
343: int y;
344:
345: screen.Clear();
346:
1.1.1.10 root 347: x = 16;
1.1.1.6 root 348: y = 0;
349:
1.1.1.10 root 350: screen.Puts(0, y++, "<Statistics>");
1.1.1.6 root 351:
1.1.1.10 root 352: screen.Puts(0, y, "Input Count");
353: screen.Print(x, y++, "%26s", format_number(stat_input_count).c_str());
354: uint count = ma_input_span.Length();
355: uint64 ma = 0;
356: for (uint i = 0; i < count; i++) {
357: ma += ma_input_span.Peek(i);
358: }
359: if (count != 0) {
360: ma /= count;
361: }
362: screen.Puts(0, y, "Input Frequency(VT)");
363: screen.Print(x + 18, y, "%5.1f Hz",
364: ma == 0 ? 0.0 : (double)1000'000'000 / ma);
1.1.1.6 root 365: y++;
366:
1.1.1.10 root 367: y++;
368: screen.Puts(0, y, "RenderMD Count");
369: screen.Print(x, y++, "%26s", format_number(stat_render_count).c_str());
370: screen.Puts(0, y, "NoUpdate Count");
371: screen.Print(x, y++, "%26s", format_number(stat_noupdate_count).c_str());
372: screen.Puts(0, y, "NoBitmap Count");
373: screen.Print(x, y++, "%26s", format_number(stat_nobitmap_count).c_str());
1.1.1.9 root 374:
1.1.1.10 root 375: y++;
376: screen.Puts(0, y, "Output Count");
377: screen.Print(x, y++, "%26s", format_number(stat_output_count).c_str());
378: count = ma_output_span.Length();
379: ma = 0;
380: for (uint i = 0; i < count; i++) {
381: ma += ma_output_span.Peek(i);
382: }
383: if (count != 0) {
384: ma /= count;
385: }
386: screen.Puts(0, y, "Output Frequency(RT)");
387: screen.Print(x + 18, y, "%5.1f Hz",
388: ma == 0 ? 0.0 : (double)1000'000'000 / ma);
389: y++;
1.1.1.9 root 390: }
391:
1.1.1.6 root 392:
1.1 root 393: //
394: // X68030 レンダラ
395: //
396:
397: // コンストラクタ
398: X68030Renderer::X68030Renderer()
399: {
400: // XXX とりあえず
401: width = 768;
402: height = 512;
1.1.1.9 root 403:
1.1.1.10 root 404: bitmap.Create(width, height);
1.1 root 405: }
406:
407: // デストラクタ
408: X68030Renderer::~X68030Renderer()
409: {
410: }
411:
1.1.1.9 root 412: // 初期化
413: bool
414: X68030Renderer::Init()
415: {
416: if (inherited::Init() == false) {
417: return false;
418: }
419:
420: videoctlr = GetVideoCtlrDevice();
421:
422: return true;
423: }
424:
1.1 root 425: // 画面合成
426: bool
1.1.1.10 root 427: X68030Renderer::RenderMD()
1.1 root 428: {
1.1.1.11 root 429: bool updated = videoctlr->Render(bitmap);
1.1.1.9 root 430: return updated;
1.1 root 431: }
432:
1.1.1.6 root 433:
1.1 root 434: //
435: // LUNA レンダラ
436: //
437:
438: // コンストラクタ
439: LunaRenderer::LunaRenderer()
440: {
441: width = 1280;
442: height = 1024;
1.1.1.9 root 443:
1.1.1.10 root 444: bitmap.Create(width, height);
1.1 root 445: }
446:
447: // デストラクタ
448: LunaRenderer::~LunaRenderer()
449: {
450: }
451:
1.1.1.9 root 452: // 初期化
453: bool
454: LunaRenderer::Init()
455: {
456: if (inherited::Init() == false) {
457: return false;
458: }
459:
460: planevram = GetPlaneVRAMDevice();
461:
462: return true;
463: }
464:
1.1 root 465: // 画面合成
466: bool
1.1.1.10 root 467: LunaRenderer::RenderMD()
1.1 root 468: {
1.1.1.11 root 469: bool updated = planevram->Render(bitmap);
1.1.1.9 root 470: return updated;
1.1.1.8 root 471: }
472:
473:
474: //
1.1.1.11 root 475: // コンソールレンダラ
1.1.1.8 root 476: //
477:
478: // コンストラクタ
1.1.1.11 root 479: ConsoleRenderer::ConsoleRenderer()
1.1.1.8 root 480: {
1.1.1.11 root 481: // 視認性のためフチを追加。
482: width = 640 + Padding * 2;
483: height = 480 + Padding * 2;
484:
485: bitmap.Create(width, height);
1.1.1.8 root 486: }
487:
488: // デストラクタ
1.1.1.11 root 489: ConsoleRenderer::~ConsoleRenderer()
1.1.1.8 root 490: {
491: }
492:
1.1.1.11 root 493: // 初期化
1.1.1.10 root 494: bool
1.1.1.11 root 495: ConsoleRenderer::Init()
1.1.1.10 root 496: {
1.1.1.11 root 497: if (inherited::Init() == false) {
498: return false;
499: }
1.1.1.10 root 500:
1.1.1.11 root 501: console = GetConsoleDevice();
502:
503: return true;
1.1.1.10 root 504: }
505:
1.1.1.8 root 506: // 画面合成
507: bool
1.1.1.11 root 508: ConsoleRenderer::RenderMD()
1.1.1.8 root 509: {
1.1.1.11 root 510: bool updated = console->Render(bitmap);
511: return updated;
1.1.1.6 root 512: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.