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

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

unix.superglobalmegacorp.com

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