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

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: }

unix.superglobalmegacorp.com

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