Annotation of nono/vm/renderer.cpp, revision 1.1.1.14

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;
1.1.1.14! root       24: static uint64 last_report_rtime;
1.1.1.10  root       25: static uint64 notify_time;
                     26: static uint notify_count;
                     27: static uint64 render_time;
                     28: static uint64 stretch_time;
                     29: static uint64 convert_time;
                     30: static uint convert_count;
                     31: #endif
                     32: 
                     33: // 電源オフ時の画面色 (電源オンで黒なのとは区別したいのであえて灰色)
                     34: static const Color ScreenOffColor(0x70, 0x70, 0x70);
                     35: 
1.1       root       36: // コンストラクタ
                     37: Renderer::Renderer()
1.1.1.8   root       38:        : inherited(OBJ_RENDERER)
1.1       root       39: {
1.1.1.11  root       40:        monitor = gMonitorManager->Regist(ID_MONITOR_RENDERER, this);
                     41:        monitor->func = ToMonitorCallback(&Renderer::MonitorUpdate);
                     42:        monitor->SetSize(42, 10);
1.1       root       43: }
                     44: 
                     45: // デストラクタ
                     46: Renderer::~Renderer()
                     47: {
1.1.1.6   root       48:        TerminateThread();
1.1.1.8   root       49: }
                     50: 
                     51: // 初期化
                     52: bool
                     53: Renderer::Init()
                     54: {
                     55:        syncer = GetSyncer();
1.1.1.14! root       56:        uimessage = gMainApp.GetUIMessage();
1.1.1.8   root       57: 
1.1.1.10  root       58:        // GUI ならレンダラ有効。
                     59:        if (gMainApp.IsGUI()) {
                     60:                enable = true;
                     61:                bitmap.Create(width, height);
                     62:                // 初期値 (どこでやる?)
                     63:                bitmap.Fill(ScreenOffColor);
                     64:        }
                     65: 
1.1.1.8   root       66:        return true;
1.1       root       67: }
                     68: 
1.1.1.6   root       69: // リセット
                     70: void
                     71: Renderer::ResetHard(bool poweron)
1.1       root       72: {
1.1.1.8   root       73:        next_refresh_rtime = syncer->GetRealTime();
1.1       root       74: 
1.1.1.6   root       75:        // 統計情報をクリア
1.1.1.10  root       76:        uint64 now = scheduler->GetVirtTime();
                     77:        stat_input_count = 0;
                     78:        last_input_time = now;
                     79:        ma_input_span.Clear();
                     80:        stat_render_count = 0;
                     81:        stat_noupdate_count = 0;
                     82:        stat_nobitmap_count = 0;
                     83:        stat_output_count = 0;
                     84:        last_output_time = now;
                     85:        ma_output_span.Clear();
1.1.1.14! root       86: #if defined(PERFREND)
        !            87:        last_report_rtime = syncer->GetRealTime();
        !            88: #endif
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:                // レンダリングスレッドに指示
1.1.1.14! root      100:                std::lock_guard<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:        {
1.1.1.14! root      128:                std::lock_guard<std::mutex> lock(mtx);
1.1.1.11  root      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);
1.1.1.14! root      169: #if defined(PERFREND)
        !           170:                PrintPerf();
        !           171: #endif
1.1.1.10  root      172:                if (t == 0 || (req & REQ_POST)) {
                    173:                        // UI に即通知。
                    174: 
                    175:                        // 統計情報
                    176:                        stat_output_count++;
                    177:                        uint64 now = syncer->GetRealTime();
                    178:                        ma_output_span.EnqueueForce(now - last_output_time);
                    179:                        last_output_time = now;
                    180: 
1.1.1.14! root      181:                        uimessage->Post(UIMessage::RENDER);
1.1.1.10  root      182:                        delay = 0;
                    183:                } else if (t > 0) {
                    184:                        // 指定時間後に UI に通知。
                    185:                        delay = t;
1.1.1.4   root      186:                }
1.1.1.10  root      187:        }
                    188: }
1.1       root      189: 
1.1.1.10  root      190: // req に基づいて描画する。
                    191: // UI への描画通知を遅延させる時間を返す (即通知する場合は 0)。
                    192: // UI に通知しない場合は -1 を返す。
                    193: int64
                    194: Renderer::DoRender(uint32 req)
                    195: {
                    196:        // 1. REND_NORMAL なら電源オン時の通常描画指示、
                    197:        //    REND_POWEROFF なら電源オン→オフ遷移時の描画指示。
                    198:        // 2. REND_RESIZE なら valid = false にして、表示ビットマップをリサイズ。
                    199:        // 3. 必要なら bitmap を拡大縮小。
                    200:        // 4. bitmap24 に描画して valid = true;
1.1.1.6   root      201: 
1.1.1.10  root      202: #if defined(PERFREND)
                    203:        Stopwatch sw;
                    204: #endif
                    205:        bool updated = false;
                    206: 
                    207:        if ((req & REQ_RENDER)) {
                    208:                // 通常描画
                    209: 
                    210: #if defined(PERFREND)
                    211:                sw_notify.Stop();
                    212:                notify_time += sw_notify.Elapsed();
                    213:                notify_count++;
                    214: 
1.1.1.11  root      215:                sw.Restart();
1.1.1.10  root      216: #endif
1.1.1.11  root      217:                // レンダラを駆動する。
                    218:                updated = RenderMD();
1.1.1.10  root      219: #if defined(PERFREND)
1.1.1.11  root      220:                sw.Stop();
                    221:                render_time += sw.Elapsed();
1.1.1.10  root      222: #endif
1.1.1.11  root      223:                stat_render_count++;
1.1       root      224:        }
1.1.1.10  root      225:        if ((req & REQ_SCREENOFF)) {
                    226:                // 電源オン→オフ時の描画
                    227:                bitmap.Fill(ScreenOffColor);
                    228:                updated = true;
                    229:        }
                    230: 
                    231:        if ((req & REQ_RESIZE)) {
                    232:                // 表示ビットマップのリサイズ要求
                    233: 
                    234:                bitmap24_valid = false;
1.1.1.13  root      235:                bitmap24.reset();
                    236:                try {
                    237:                        bitmap24.reset(new BitmapRGB(new_viewwidth, new_viewheight));
                    238:                } catch (...) { }
1.1.1.10  root      239:                if ((bool)bitmap24 == false) {
                    240:                        putlog(0, "Could not allocate BitmapRGB(%u, %u)",
                    241:                                new_viewwidth, new_viewheight);
                    242:                        return -1;
                    243:                }
                    244:                viewrect = Rect(0, 0, new_viewwidth, new_viewheight);
                    245:                updated = true;
                    246:        }
                    247: 
                    248:        // 更新箇所がなければここで終わり。
                    249:        if (updated == false) {
                    250:                stat_noupdate_count++;
                    251:                return -1;
                    252:        }
                    253: 
                    254:        // 出力ビットマップが用意できてなければここで終わり。
                    255:        if (__predict_false((bool)bitmap24 == false)) {
                    256:                stat_nobitmap_count++;
                    257:                return -1;
                    258:        }
                    259: 
                    260:        // 等倍表示でなければ拡大縮小。
                    261: #if defined(PERFREND)
                    262:        sw.Restart();
                    263: #endif
                    264:        BitmapRGBX scaled_bitmap;
                    265:        BitmapRGBX *src_bitmap;
                    266:        if (bitmap.GetWidth() == bitmap24->GetWidth() &&
                    267:                bitmap.GetHeight() == bitmap24->GetHeight())
                    268:        {
                    269:                src_bitmap = &bitmap;
                    270:        } else {
                    271:                scaled_bitmap.Create(viewrect.w, viewrect.h);
                    272:                scaled_bitmap.DrawBitmapStretch(viewrect, bitmap);
                    273:                src_bitmap = &scaled_bitmap;
                    274:        }
                    275: #if defined(PERFREND)
                    276:        sw.Stop();
                    277:        stretch_time += sw.Elapsed();
                    278: #endif
                    279: 
                    280:        // wxWidgets 用の RGBX→RGB 変換。
                    281: #if defined(PERFREND)
                    282:        sw.Restart();
                    283: #endif
                    284:        src_bitmap->ConvertToRGB(*bitmap24);
                    285:        bitmap24_valid = true;
                    286: #if defined(PERFREND)
                    287:        sw.Stop();
                    288:        convert_time += sw.Elapsed();
1.1.1.14! root      289:        convert_count++;
1.1.1.10  root      290: #endif
                    291: 
                    292:        if ((req & (REQ_SCREENOFF | REQ_RESIZE))) {
                    293:                // 電源オン→オフ遷移かリサイズ要求時は即通知。
                    294:                return 0;
                    295:        }
                    296: 
                    297:        // 通常描画のみならここで通知を律速する。
                    298:        uint64 rtime = syncer->GetRealTime();
                    299:        if (rtime < next_refresh_rtime) {
                    300:                return next_refresh_rtime - rtime;
                    301:        }
                    302:        next_refresh_rtime = rtime + refresh_interval;
                    303:        return 0;
1.1       root      304: }
                    305: 
1.1.1.14! root      306: #if defined(PERFREND)
        !           307: void
        !           308: Renderer::PrintPerf()
        !           309: {
        !           310:        uint64 now = syncer->GetRealTime();
        !           311:        if (now - last_report_rtime < 5_sec) {
        !           312:                return;
        !           313:        }
        !           314: 
        !           315:        double rate = 0;
        !           316:        uint nt = 0;
        !           317:        uint rt = 0;
        !           318:        uint st = 0;
        !           319:        uint ct = 0;
        !           320:        if (notify_count != 0) {
        !           321:                rate = (double)notify_count * 1_sec / (now - last_report_rtime);
        !           322:                nt = notify_time / notify_count / 1000U;
        !           323:                rt = render_time / notify_count / 1000U;
        !           324:        }
        !           325:        if (convert_count != 0) {
        !           326:                st = stretch_time / convert_count / 1000U;
        !           327:                ct = convert_time / convert_count / 1000U;
        !           328:        }
        !           329: 
        !           330:        printf(
        !           331:        "%5.1f calls/s: Notify %u us, Render %u us, Stretch %u us, Convert %u us\n",
        !           332:                rate, nt, rt, st, ct);
        !           333: 
        !           334:        notify_time = 0;
        !           335:        render_time = 0;
        !           336:        stretch_time = 0;
        !           337:        convert_time = 0;
        !           338:        notify_count = 0;
        !           339:        convert_count = 0;
        !           340:        last_report_rtime = now;
        !           341: }
        !           342: #endif // PERFREND
        !           343: 
1.1.1.6   root      344: // スレッドの終了を指示
1.1.1.2   root      345: void
                    346: Renderer::Terminate()
                    347: {
1.1.1.14! root      348:        std::lock_guard<std::mutex> lock(mtx);
1.1.1.2   root      349:        request |= REQ_TERMINATE;
                    350:        cv.notify_one();
                    351: }
                    352: 
1.1.1.10  root      353: // リサイズ指示
                    354: void
                    355: Renderer::ResizeView(uint width_, uint height_)
                    356: {
                    357:        assert(enable);
                    358: 
                    359:        new_viewwidth = width_;
                    360:        new_viewheight = height_;
                    361: 
1.1.1.14! root      362:        std::lock_guard<std::mutex> lock(mtx);
1.1.1.10  root      363:        request |= REQ_RESIZE;
                    364:        cv.notify_one();
                    365: }
                    366: 
1.1.1.6   root      367: // 描画更新(通知)間隔を設定
                    368: void
                    369: Renderer::SetRefreshInterval(uint64 t)
                    370: {
                    371:        refresh_interval = t;
                    372: }
                    373: 
                    374: // モニタ更新
                    375: void
                    376: Renderer::MonitorUpdate(Monitor *, TextScreen& screen)
                    377: {
                    378:        int x;
                    379:        int y;
1.1.1.14! root      380:        uint64 ma;
1.1.1.6   root      381: 
                    382:        screen.Clear();
                    383: 
1.1.1.10  root      384:        x = 16;
1.1.1.6   root      385:        y = 0;
                    386: 
1.1.1.10  root      387:        screen.Puts(0, y++, "<Statistics>");
1.1.1.6   root      388: 
1.1.1.10  root      389:        screen.Puts(0, y, "Input Count");
                    390:        screen.Print(x, y++, "%26s", format_number(stat_input_count).c_str());
                    391:        screen.Puts(0, y, "Input Frequency(VT)");
1.1.1.14! root      392:        ma = ma_input_span.GetMovingAverage();
1.1.1.10  root      393:        screen.Print(x + 18, y, "%5.1f Hz",
                    394:                ma == 0 ? 0.0 : (double)1000'000'000 / ma);
1.1.1.6   root      395:        y++;
                    396: 
1.1.1.10  root      397:        y++;
                    398:        screen.Puts(0, y, "RenderMD Count");
                    399:        screen.Print(x, y++, "%26s", format_number(stat_render_count).c_str());
                    400:        screen.Puts(0, y, "NoUpdate Count");
                    401:        screen.Print(x, y++, "%26s", format_number(stat_noupdate_count).c_str());
                    402:        screen.Puts(0, y, "NoBitmap Count");
                    403:        screen.Print(x, y++, "%26s", format_number(stat_nobitmap_count).c_str());
1.1.1.9   root      404: 
1.1.1.10  root      405:        y++;
                    406:        screen.Puts(0, y, "Output Count");
                    407:        screen.Print(x, y++, "%26s", format_number(stat_output_count).c_str());
                    408:        screen.Puts(0, y, "Output Frequency(RT)");
1.1.1.14! root      409:        ma = ma_output_span.GetMovingAverage();
1.1.1.10  root      410:        screen.Print(x + 18, y, "%5.1f Hz",
                    411:                ma == 0 ? 0.0 : (double)1000'000'000 / ma);
                    412:        y++;
1.1.1.9   root      413: }
                    414: 
1.1.1.6   root      415: 
1.1       root      416: //
                    417: // X68030 レンダラ
                    418: //
                    419: 
                    420: // コンストラクタ
                    421: X68030Renderer::X68030Renderer()
                    422: {
                    423:        // XXX とりあえず
                    424:        width = 768;
                    425:        height = 512;
1.1.1.9   root      426: 
1.1.1.10  root      427:        bitmap.Create(width, height);
1.1       root      428: }
                    429: 
                    430: // デストラクタ
                    431: X68030Renderer::~X68030Renderer()
                    432: {
                    433: }
                    434: 
1.1.1.9   root      435: // 初期化
                    436: bool
                    437: X68030Renderer::Init()
                    438: {
                    439:        if (inherited::Init() == false) {
                    440:                return false;
                    441:        }
                    442: 
                    443:        videoctlr = GetVideoCtlrDevice();
                    444: 
                    445:        return true;
                    446: }
                    447: 
1.1       root      448: // 画面合成
                    449: bool
1.1.1.10  root      450: X68030Renderer::RenderMD()
1.1       root      451: {
1.1.1.11  root      452:        bool updated = videoctlr->Render(bitmap);
1.1.1.9   root      453:        return updated;
1.1       root      454: }
                    455: 
1.1.1.6   root      456: 
1.1       root      457: //
                    458: // LUNA レンダラ
                    459: //
                    460: 
                    461: // コンストラクタ
                    462: LunaRenderer::LunaRenderer()
                    463: {
                    464:        width = 1280;
                    465:        height = 1024;
1.1.1.9   root      466: 
1.1.1.10  root      467:        bitmap.Create(width, height);
1.1       root      468: }
                    469: 
                    470: // デストラクタ
                    471: LunaRenderer::~LunaRenderer()
                    472: {
                    473: }
                    474: 
1.1.1.9   root      475: // 初期化
                    476: bool
                    477: LunaRenderer::Init()
                    478: {
                    479:        if (inherited::Init() == false) {
                    480:                return false;
                    481:        }
                    482: 
                    483:        planevram = GetPlaneVRAMDevice();
                    484: 
                    485:        return true;
                    486: }
                    487: 
1.1       root      488: // 画面合成
                    489: bool
1.1.1.10  root      490: LunaRenderer::RenderMD()
1.1       root      491: {
1.1.1.11  root      492:        bool updated = planevram->Render(bitmap);
1.1.1.9   root      493:        return updated;
1.1.1.8   root      494: }
                    495: 
                    496: 
                    497: //
1.1.1.11  root      498: // コンソールレンダラ
1.1.1.8   root      499: //
                    500: 
                    501: // コンストラクタ
1.1.1.11  root      502: ConsoleRenderer::ConsoleRenderer()
1.1.1.8   root      503: {
1.1.1.11  root      504:        // 視認性のためフチを追加。
                    505:        width = 640 + Padding * 2;
                    506:        height = 480 + Padding * 2;
                    507: 
                    508:        bitmap.Create(width, height);
1.1.1.8   root      509: }
                    510: 
                    511: // デストラクタ
1.1.1.11  root      512: ConsoleRenderer::~ConsoleRenderer()
1.1.1.8   root      513: {
                    514: }
                    515: 
1.1.1.11  root      516: // 初期化
1.1.1.10  root      517: bool
1.1.1.11  root      518: ConsoleRenderer::Init()
1.1.1.10  root      519: {
1.1.1.11  root      520:        if (inherited::Init() == false) {
                    521:                return false;
                    522:        }
1.1.1.10  root      523: 
1.1.1.11  root      524:        console = GetConsoleDevice();
                    525: 
                    526:        return true;
1.1.1.10  root      527: }
                    528: 
1.1.1.8   root      529: // 画面合成
                    530: bool
1.1.1.11  root      531: ConsoleRenderer::RenderMD()
1.1.1.8   root      532: {
1.1.1.11  root      533:        bool updated = console->Render(bitmap);
                    534:        return updated;
1.1.1.6   root      535: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.