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

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.5   root       12: #include "lunafb.h"
1.1.1.6 ! root       13: #include "sync.h"
        !            14: #include "uimessage.h"
1.1       root       15: 
1.1.1.6 ! root       16: // グローバル参照用
        !            17: Renderer *gRenderer;
1.1       root       18: 
                     19: // コンストラクタ
                     20: Renderer::Renderer()
1.1.1.5   root       21:        : inherited("Renderer")
1.1       root       22: {
1.1.1.6 ! root       23:        monitor.func = ToMonitorCallback(&X68030Renderer::MonitorUpdate);
        !            24:        monitor.SetSize(68, 33);
        !            25:        monitor.Regist(ID_MONITOR_RENDERER);
1.1       root       26: }
                     27: 
                     28: // デストラクタ
                     29: Renderer::~Renderer()
                     30: {
1.1.1.6 ! root       31:        TerminateThread();
        !            32:        gRenderer = NULL;
1.1       root       33: }
                     34: 
1.1.1.6 ! root       35: // リセット
        !            36: void
        !            37: Renderer::ResetHard(bool poweron)
1.1       root       38: {
1.1.1.6 ! root       39:        next_refresh_rtime = gSync->GetRealTime();
1.1       root       40: 
1.1.1.6 ! root       41:        // 統計情報をクリア
        !            42:        render_time.Reset();
        !            43:        render_exec = 0;
        !            44:        last_mod_blocks = 0;
        !            45:        total_mod_blocks = 0;
        !            46:        total_invalidate2 = 0;
1.1       root       47: }
                     48: 
1.1.1.6 ! root       49: // 電源オフ
        !            50: void
1.1       root       51: Renderer::PowerOff()
                     52: {
1.1.1.6 ! root       53:        if (enable) {
1.1       root       54:                // レンダリングスレッドに指示
                     55:                std::unique_lock<std::mutex> lock(mtx);
                     56:                request |= REQ_REND_POWEROFF;
                     57:                cv.notify_one();
                     58:        }
                     59: }
                     60: 
1.1.1.6 ! root       61: // 合成処理イネーブル
        !            62: // 一度だけ呼び出すことができる
1.1       root       63: void
1.1.1.6 ! root       64: Renderer::Enable()
1.1       root       65: {
1.1.1.6 ! root       66:        assert(enable == false);
1.1       root       67: 
1.1.1.6 ! root       68:        enable = true;
        !            69:        bitmap.Create(width, height);
        !            70:        // 初期値灰色にしておく
        !            71:        bitmap.Fill(Color(0x70, 0x70, 0x70));
1.1       root       72: }
                     73: 
1.1.1.6 ! root       74: // 画面合成処理 (VM スレッドで CRTC/CRTC2 から呼ばれる)。
1.1       root       75: // 今は一画面単位で合成を行なっている。ラスター云々は未対応。
                     76: void
                     77: Renderer::Render()
                     78: {
                     79:        // CLI 版なら何もしない。
1.1.1.6 ! root       80:        if (enable == false) {
1.1       root       81:                return;
                     82:        }
                     83: 
1.1.1.6 ! root       84:        // 更新されていればレンダラに引き渡す
        !            85:        ModifyInfo mod = gPlaneVRAM->GetModify();
        !            86:        if (__predict_false(invalidate2 == true)) {
        !            87:                mod.invalidate2 = true;
        !            88:        }
        !            89: 
        !            90:        if (mod.IsDirty() || mod.invalidate2) {
        !            91:                if (modq.Enqueue(mod)) {
        !            92:                        // 更新情報を引き取ったのでクリアする
        !            93:                        gPlaneVRAM->ClearDirty();
        !            94:                        invalidate2 = false;
        !            95:                } else {
        !            96:                        // VM スレッドが速すぎるため次回に持ち越し
        !            97:                }
        !            98:        }
        !            99: 
1.1       root      100:        // スケジューラ都合による間引きとかがあればここらへんで評価?
                    101:        // XXX どっちのスレッドでやるか
                    102: 
                    103:        // レンダリングスレッドに指示
                    104:        std::unique_lock<std::mutex> lock(mtx);
                    105:        request |= REQ_REND_NORMAL;
                    106:        cv.notify_one();
                    107: }
                    108: 
1.1.1.6 ! root      109: // 全画面更新の指示 (パレット変更やスクロールなど VRAM の変更を伴わないもの)。
1.1.1.4   root      110: // ここでは無効化だけ受け付けておいて、実際の処理はレンダリングの際に行う。
                    111: void
1.1.1.6 ! root      112: Renderer::Invalidate2()
1.1.1.4   root      113: {
1.1.1.6 ! root      114:        invalidate2 = true;
1.1       root      115: }
                    116: 
                    117: // レンダリングスレッド
                    118: void
                    119: Renderer::ThreadRun()
                    120: {
                    121:        for (;;) {
                    122:                uint32 req;
                    123: 
                    124:                // 何か起きるまで待つ
                    125:                {
                    126:                        std::unique_lock<std::mutex> lock(mtx);
                    127:                        cv.wait(lock, [&] { return (request != 0); });
                    128:                        req = request;
                    129:                        request = 0;
                    130:                }
                    131: 
                    132:                if ((req & REQ_TERMINATE)) {
                    133:                        // 終了するので、他のフラグは無視
                    134:                        break;
1.1.1.4   root      135:                }
                    136:                if ((req & REQ_REND_POWEROFF)) {
1.1       root      137:                        // 電源オフ時の描画 (通常描画フラグは無視)
                    138: 
                    139:                        // 電源オフされると画面を灰色にする。
                    140:                        // 黒でもいいけど、電源オンで黒いままなのと区別したい。
1.1.1.6 ! root      141:                        bitmap.Fill(Color(0x70, 0x70, 0x70));
        !           142:                        // UI に通知
        !           143:                        UIMessage::Post(UIMessage::RENDER);
1.1.1.4   root      144:                        continue;
                    145:                }
                    146:                if ((req & REQ_REND_NORMAL)) {
1.1       root      147:                        // 通常描画
1.1.1.6 ! root      148:                        if (modq.Dequeue(&modify)) {
        !           149:                                // 更新ブロック数を数える (統計用)
        !           150:                                last_mod_blocks = modify.n_dirty;
        !           151:                                total_mod_blocks += last_mod_blocks;
        !           152:                                if (__predict_false(modify.invalidate2)) {
        !           153:                                        total_invalidate2++;
        !           154:                                }
1.1       root      155: 
1.1.1.6 ! root      156: #if defined(PERF_HIT)
        !           157:                                // ブロックのヒット効率
        !           158:                                int update_word = 0;
        !           159:                                for (auto v : modify.dirty_word) {
        !           160:                                        if (v) {
        !           161:                                                update_word++;
        !           162:                                        }
        !           163:                                }
        !           164:                                int update_block = last_mod_blocks * BLKY * (BLKX / 32);
        !           165:                                hitrate_total_word += update_word;
        !           166:                                hitrate_total_block += update_block;
        !           167:                                hitrate_ma.EnqueueForce((double)update_word / update_block);
        !           168: #endif
        !           169: 
        !           170:                                // レンダラを駆動する。
        !           171:                                // out_dirty は前回 UI に通知した後一度でも更新があれば true。
        !           172:                                render_time.Start();
        !           173:                                out_dirty |= RenderMain();
        !           174:                                render_time.Stop();
        !           175:                                render_exec++;
        !           176:                        }
        !           177: 
        !           178:                        if (out_dirty) {
        !           179:                                uint64 rtime = gSync->GetRealTime();
        !           180:                                if (rtime >= next_refresh_rtime) {
        !           181:                                        UIMessage::Post(UIMessage::RENDER);
        !           182:                                        next_refresh_rtime = rtime + refresh_interval;
        !           183:                                        out_dirty = false;
        !           184:                                }
1.1       root      185:                        }
                    186:                }
                    187:        }
                    188: }
                    189: 
1.1.1.6 ! root      190: // スレッドの終了を指示
1.1.1.2   root      191: void
                    192: Renderer::Terminate()
                    193: {
                    194:        std::unique_lock<std::mutex> lock(mtx);
                    195:        request |= REQ_TERMINATE;
                    196:        cv.notify_one();
                    197: }
                    198: 
1.1.1.6 ! root      199: // 描画更新(通知)間隔を設定
        !           200: void
        !           201: Renderer::SetRefreshInterval(uint64 t)
        !           202: {
        !           203:        refresh_interval = t;
        !           204: }
        !           205: 
        !           206: // モニタ更新
        !           207: void
        !           208: Renderer::MonitorUpdate(Monitor *, TextScreen& screen)
        !           209: {
        !           210:        int x;
        !           211:        int y;
        !           212: 
        !           213:        screen.Clear();
        !           214: 
        !           215:        // modify
        !           216:        screen.Print(0, 0, "Last Update Region");
        !           217:        for (int i = 0, end = modify.bits.size(); i < end; i++) {
        !           218:                char buf[17];
        !           219: 
        !           220:                uint16 m = modify.bits[i];
        !           221:                int j;
        !           222:                for (j = 0; j < 16; j++, m <<= 1) {
        !           223:                        uint8 c;
        !           224:                        if (__predict_false((int16)m < 0)) {
        !           225:                                c = '*';
        !           226:                        } else {
        !           227:                                c = '.';
        !           228:                        }
        !           229:                        buf[j] = c;
        !           230:                }
        !           231:                buf[j] = '\0';
        !           232: 
        !           233:                screen.Print((i / 32) * 21, 1 + (i % 32), "%2d:%s", i, buf);
        !           234:        }
        !           235: 
        !           236:        x = 43;
        !           237:        y = 0;
        !           238:        uint64 nsec = render_time.Elapsed();
        !           239:        screen.Print(x, y++, "RenderTime %3d.%06d sec",
        !           240:                (int)(nsec / 1000 / 1000 / 1000),
        !           241:                (int)(nsec / 1000) % (1000 * 1000));
        !           242: 
        !           243:        screen.Print(x, y++, "RenderExec      %9" PRIu64, render_exec);
        !           244: 
        !           245:        y++;
        !           246:        screen.Print(x, y++, "Last Mod Blks   %9d", last_mod_blocks);
        !           247:        screen.Print(x, y++, "Total Mod Blks  %9" PRIu64, total_mod_blocks);
        !           248:        screen.Print(x, y++, "Total Invalid2  %9" PRIu64, total_invalidate2);
        !           249: 
        !           250: #if defined(PERF_HIT)
        !           251:        y++;
        !           252:        // ヒット効率(?)、移動平均
        !           253:        double rate = 0.0;
        !           254:        int len = hitrate_ma.Length();
        !           255:        for (int i = 0; i < len; i++) {
        !           256:                rate += hitrate_ma.Peek(i);
        !           257:        }
        !           258:        if (__predict_true(len != 0)) {
        !           259:                rate = rate / len * 100;
        !           260:        }
        !           261:        screen.Print(x, y++, "Hit Rate(MA)       %5.1f%%", rate);
        !           262:        screen.Print(x, y++, " (total avg)       %5.1f%%",
        !           263:                (double)hitrate_total_word / hitrate_total_block * 100);
        !           264: #endif
        !           265: }
        !           266: 
        !           267: 
1.1       root      268: //
                    269: // X68030 レンダラ
                    270: //
                    271: 
                    272: // コンストラクタ
                    273: X68030Renderer::X68030Renderer()
                    274: {
                    275:        // XXX とりあえず
                    276:        width = 768;
                    277:        height = 512;
                    278: }
                    279: 
                    280: // デストラクタ
                    281: X68030Renderer::~X68030Renderer()
                    282: {
                    283: }
                    284: 
                    285: // 画面合成
                    286: bool
                    287: X68030Renderer::RenderMain()
                    288: {
                    289:        // 今はテキスト画面のみを合成バッファに直接描いている
1.1.1.6 ! root      290:        return gPlaneVRAM->Render(bitmap, modify);
1.1       root      291: }
                    292: 
1.1.1.6 ! root      293: 
1.1       root      294: //
                    295: // LUNA レンダラ
                    296: //
                    297: 
                    298: // コンストラクタ
                    299: LunaRenderer::LunaRenderer()
                    300: {
                    301:        width = 1280;
                    302:        height = 1024;
                    303: }
                    304: 
                    305: // デストラクタ
                    306: LunaRenderer::~LunaRenderer()
                    307: {
                    308: }
                    309: 
                    310: // 画面合成
                    311: bool
                    312: LunaRenderer::RenderMain()
                    313: {
1.1.1.6 ! root      314:        return gPlaneVRAM->Render(bitmap, modify);
        !           315: }
1.1       root      316: 
1.1.1.6 ! root      317: const BitmapI8&
        !           318: LunaRenderer::GetComposite() const
        !           319: {
        !           320:        return gLunafb->GetComposite();
1.1       root      321: }

unix.superglobalmegacorp.com

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