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

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

unix.superglobalmegacorp.com

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