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

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

unix.superglobalmegacorp.com

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