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

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

unix.superglobalmegacorp.com

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