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

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.9 ! root       12: #include "planevram.h"
1.1.1.8   root       13: #include "syncer.h"
1.1.1.6   root       14: #include "uimessage.h"
1.1.1.9 ! root       15: #include "videoctlr.h"
1.1       root       16: 
                     17: // コンストラクタ
                     18: Renderer::Renderer()
1.1.1.8   root       19:        : inherited(OBJ_RENDERER)
1.1       root       20: {
1.1.1.9 ! root       21: #if defined(HAVE_AVX2)
        !            22:        enable_avx2 = gMainApp.enable_avx2;
        !            23: #endif
        !            24: 
1.1.1.6   root       25:        monitor.func = ToMonitorCallback(&X68030Renderer::MonitorUpdate);
                     26:        monitor.SetSize(68, 33);
                     27:        monitor.Regist(ID_MONITOR_RENDERER);
1.1       root       28: }
                     29: 
                     30: // デストラクタ
                     31: Renderer::~Renderer()
                     32: {
1.1.1.6   root       33:        TerminateThread();
1.1.1.8   root       34: }
                     35: 
                     36: // 初期化
                     37: bool
                     38: Renderer::Init()
                     39: {
                     40:        if (inherited::Init() == false) {
                     41:                return false;
                     42:        }
                     43: 
                     44:        syncer = GetSyncer();
                     45: 
                     46:        return true;
1.1       root       47: }
                     48: 
1.1.1.6   root       49: // リセット
                     50: void
                     51: Renderer::ResetHard(bool poweron)
1.1       root       52: {
1.1.1.8   root       53:        next_refresh_rtime = syncer->GetRealTime();
1.1       root       54: 
1.1.1.6   root       55:        // 統計情報をクリア
                     56:        render_time.Reset();
                     57:        render_exec = 0;
                     58:        last_mod_blocks = 0;
                     59:        total_mod_blocks = 0;
                     60:        total_invalidate2 = 0;
1.1       root       61: }
                     62: 
1.1.1.6   root       63: // 電源オフ
                     64: void
1.1       root       65: Renderer::PowerOff()
                     66: {
1.1.1.6   root       67:        if (enable) {
1.1       root       68:                // レンダリングスレッドに指示
                     69:                std::unique_lock<std::mutex> lock(mtx);
                     70:                request |= REQ_REND_POWEROFF;
                     71:                cv.notify_one();
                     72:        }
                     73: }
                     74: 
1.1.1.6   root       75: // 合成処理イネーブル
                     76: // 一度だけ呼び出すことができる
1.1       root       77: void
1.1.1.6   root       78: Renderer::Enable()
1.1       root       79: {
1.1.1.6   root       80:        assert(enable == false);
1.1       root       81: 
1.1.1.6   root       82:        enable = true;
                     83:        bitmap.Create(width, height);
                     84:        // 初期値灰色にしておく
                     85:        bitmap.Fill(Color(0x70, 0x70, 0x70));
1.1       root       86: }
                     87: 
1.1.1.6   root       88: // 画面合成処理 (VM スレッドで CRTC/CRTC2 から呼ばれる)。
1.1       root       89: // 今は一画面単位で合成を行なっている。ラスター云々は未対応。
                     90: void
                     91: Renderer::Render()
                     92: {
                     93:        // CLI 版なら何もしない。
1.1.1.6   root       94:        if (enable == false) {
1.1       root       95:                return;
                     96:        }
                     97: 
1.1.1.6   root       98:        // 更新されていればレンダラに引き渡す
1.1.1.8   root       99:        ModifyInfo mod = planevram->GetModify();
1.1.1.6   root      100:        if (__predict_false(invalidate2 == true)) {
                    101:                mod.invalidate2 = true;
                    102:        }
                    103: 
                    104:        if (mod.IsDirty() || mod.invalidate2) {
                    105:                if (modq.Enqueue(mod)) {
                    106:                        // 更新情報を引き取ったのでクリアする
1.1.1.8   root      107:                        planevram->ClearDirty();
1.1.1.6   root      108:                        invalidate2 = false;
                    109:                } else {
                    110:                        // VM スレッドが速すぎるため次回に持ち越し
                    111:                }
                    112:        }
                    113: 
1.1       root      114:        // スケジューラ都合による間引きとかがあればここらへんで評価?
                    115:        // XXX どっちのスレッドでやるか
                    116: 
                    117:        // レンダリングスレッドに指示
                    118:        std::unique_lock<std::mutex> lock(mtx);
                    119:        request |= REQ_REND_NORMAL;
                    120:        cv.notify_one();
                    121: }
                    122: 
1.1.1.6   root      123: // 全画面更新の指示 (パレット変更やスクロールなど VRAM の変更を伴わないもの)。
1.1.1.4   root      124: // ここでは無効化だけ受け付けておいて、実際の処理はレンダリングの際に行う。
                    125: void
1.1.1.6   root      126: Renderer::Invalidate2()
1.1.1.4   root      127: {
1.1.1.6   root      128:        invalidate2 = true;
1.1       root      129: }
                    130: 
                    131: // レンダリングスレッド
                    132: void
                    133: Renderer::ThreadRun()
                    134: {
                    135:        for (;;) {
                    136:                uint32 req;
                    137: 
                    138:                // 何か起きるまで待つ
                    139:                {
                    140:                        std::unique_lock<std::mutex> lock(mtx);
                    141:                        cv.wait(lock, [&] { return (request != 0); });
                    142:                        req = request;
                    143:                        request = 0;
                    144:                }
                    145: 
                    146:                if ((req & REQ_TERMINATE)) {
                    147:                        // 終了するので、他のフラグは無視
                    148:                        break;
1.1.1.4   root      149:                }
                    150:                if ((req & REQ_REND_POWEROFF)) {
1.1       root      151:                        // 電源オフ時の描画 (通常描画フラグは無視)
                    152: 
                    153:                        // 電源オフされると画面を灰色にする。
                    154:                        // 黒でもいいけど、電源オンで黒いままなのと区別したい。
1.1.1.6   root      155:                        bitmap.Fill(Color(0x70, 0x70, 0x70));
                    156:                        // UI に通知
                    157:                        UIMessage::Post(UIMessage::RENDER);
1.1.1.4   root      158:                        continue;
                    159:                }
                    160:                if ((req & REQ_REND_NORMAL)) {
1.1       root      161:                        // 通常描画
1.1.1.6   root      162:                        if (modq.Dequeue(&modify)) {
                    163:                                // 更新ブロック数を数える (統計用)
                    164:                                last_mod_blocks = modify.n_dirty;
                    165:                                total_mod_blocks += last_mod_blocks;
                    166:                                if (__predict_false(modify.invalidate2)) {
                    167:                                        total_invalidate2++;
                    168:                                }
1.1       root      169: 
1.1.1.6   root      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) {
1.1.1.8   root      179:                                uint64 rtime = syncer->GetRealTime();
1.1.1.6   root      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");
1.1.1.8   root      217:        const uint8 *m = &modify.bits[0];
                    218:        for (int i = 0; i < 32; i++) {
                    219:                char buf[33];
                    220:                uint8 c;
                    221:                for (int j = 0; j < 32; j++) {
                    222:                        if (__predict_false(*m++ != 0)) {
1.1.1.6   root      223:                                c = '*';
                    224:                        } else {
                    225:                                c = '.';
                    226:                        }
                    227:                        buf[j] = c;
                    228:                }
                    229: 
1.1.1.8   root      230:                buf[32] = '\0';
                    231:                screen.Print(0, 1 + i, "%4d:%s", i * 32, buf);
1.1.1.6   root      232:        }
1.1.1.8   root      233:        screen.Puts(0, 1, "Y=");
1.1.1.6   root      234: 
                    235:        x = 43;
                    236:        y = 0;
                    237:        uint64 nsec = render_time.Elapsed();
                    238:        screen.Print(x, y++, "RenderTime %3d.%06d sec",
                    239:                (int)(nsec / 1000 / 1000 / 1000),
                    240:                (int)(nsec / 1000) % (1000 * 1000));
                    241: 
                    242:        screen.Print(x, y++, "RenderExec      %9" PRIu64, render_exec);
                    243: 
                    244:        y++;
                    245:        screen.Print(x, y++, "Last Mod Blks   %9d", last_mod_blocks);
                    246:        screen.Print(x, y++, "Total Mod Blks  %9" PRIu64, total_mod_blocks);
                    247:        screen.Print(x, y++, "Total Invalid2  %9" PRIu64, total_invalidate2);
                    248: }
                    249: 
1.1.1.9 ! root      250: // RGBX から RGB への変換。
        !           251: void
        !           252: Renderer::RGBXtoRGB(BitmapRGB& dst, const BitmapRGBX& src)
        !           253: {
        !           254:        assert(dst.GetWidth() == src.GetWidth());
        !           255:        assert(dst.GetHeight() == src.GetHeight());
        !           256:        assert(src.GetWidth() % 4 == 0);
        !           257: 
        !           258: #if defined(HAVE_AVX2)
        !           259:        if (__predict_true(enable_avx2)) {
        !           260:                RGBXtoRGB_avx2(dst, src);
        !           261:        } else
        !           262: #endif
        !           263:        {
        !           264:                RGBXtoRGB_gen(dst, src);
        !           265:        }
        !           266: }
        !           267: 
        !           268: // RGBX から RGB への変換。(C++ 版)
        !           269: /*static*/ void
        !           270: Renderer::RGBXtoRGB_gen(BitmapRGB& dst, const BitmapRGBX& src)
        !           271: {
        !           272:        for (int y = 0, yend = src.GetHeight(); y < yend; y++) {
        !           273:                const uint32 *s = (const uint32 *)src.GetRowPtr(y);
        !           274:                uint32 *d = (uint32 *)dst.GetRowPtr(y);
        !           275: 
        !           276:                const uint32 *send = s + src.GetWidth();
        !           277:                for (; s < send; ) {
        !           278:                        // 4ピクセルずつ処理する
        !           279: 
        !           280:                        uint32 c0 = htole32(*s++);
        !           281:                        uint32 c1 = htole32(*s++);
        !           282:                        uint32 c2 = htole32(*s++);
        !           283:                        uint32 c3 = htole32(*s++);
        !           284: 
        !           285:                        // c0   = $x0B0G0R0
        !           286:                        // c1   = $x1B1G1R1
        !           287:                        // c2   = $x2B2G2R2
        !           288:                        // c3   = $x3B3G3R3
        !           289:                        //
        !           290:                        // d[0] = $00B0G0R0 | $R1000000 = $R1B0G0R0
        !           291:                        // d[1] = $0000B1G1 | $G2R20000 = $G2R2B1G1
        !           292:                        // d[2] = $000000B2 | $B3G3R300 = $B3G3R3B2
        !           293: 
        !           294:                        *d++ = le32toh((c0      ) | (c1 << 24));
        !           295:                        *d++ = le32toh((c1 >>  8) | (c2 << 16));
        !           296:                        *d++ = le32toh((c2 >> 16) | (c3 <<  8));
        !           297:                }
        !           298:        }
        !           299: }
        !           300: 
1.1.1.6   root      301: 
1.1       root      302: //
                    303: // X68030 レンダラ
                    304: //
                    305: 
                    306: // コンストラクタ
                    307: X68030Renderer::X68030Renderer()
                    308: {
                    309:        // XXX とりあえず
                    310:        width = 768;
                    311:        height = 512;
1.1.1.9 ! root      312: 
        !           313:        bitmap32.Create(width, height);
1.1       root      314: }
                    315: 
                    316: // デストラクタ
                    317: X68030Renderer::~X68030Renderer()
                    318: {
                    319: }
                    320: 
1.1.1.9 ! root      321: // 初期化
        !           322: bool
        !           323: X68030Renderer::Init()
        !           324: {
        !           325:        if (inherited::Init() == false) {
        !           326:                return false;
        !           327:        }
        !           328: 
        !           329:        planevram = GetPlaneVRAMDevice();
        !           330:        videoctlr = GetVideoCtlrDevice();
        !           331: 
        !           332:        return true;
        !           333: }
        !           334: 
1.1       root      335: // 画面合成
                    336: bool
                    337: X68030Renderer::RenderMain()
                    338: {
1.1.1.9 ! root      339:        bool updated = videoctlr->Render(bitmap32, modify);
        !           340:        if (updated) {
        !           341:                RGBXtoRGB(bitmap, bitmap32);
        !           342:        }
        !           343:        return updated;
1.1       root      344: }
                    345: 
1.1.1.6   root      346: 
1.1       root      347: //
                    348: // LUNA レンダラ
                    349: //
                    350: 
                    351: // コンストラクタ
                    352: LunaRenderer::LunaRenderer()
                    353: {
                    354:        width = 1280;
                    355:        height = 1024;
1.1.1.9 ! root      356: 
        !           357:        textbmp.Create(width, height);
1.1       root      358: }
                    359: 
                    360: // デストラクタ
                    361: LunaRenderer::~LunaRenderer()
                    362: {
                    363: }
                    364: 
1.1.1.9 ! root      365: // 初期化
        !           366: bool
        !           367: LunaRenderer::Init()
        !           368: {
        !           369:        if (inherited::Init() == false) {
        !           370:                return false;
        !           371:        }
        !           372: 
        !           373:        planevram = GetPlaneVRAMDevice();
        !           374: 
        !           375:        return true;
        !           376: }
        !           377: 
1.1       root      378: // 画面合成
                    379: bool
                    380: LunaRenderer::RenderMain()
                    381: {
1.1.1.9 ! root      382:        // 型変換だけ必要
        !           383:        bool updated = planevram->Render(textbmp, modify);
        !           384:        if (updated) {
        !           385:                RGBXtoRGB(bitmap, textbmp);
        !           386:        }
        !           387:        return updated;
1.1.1.8   root      388: }
                    389: 
                    390: 
                    391: //
1.1.1.9 ! root      392: // 何もしないレンダラ
1.1.1.8   root      393: //
                    394: 
                    395: // コンストラクタ
1.1.1.9 ! root      396: NopRenderer::NopRenderer()
1.1.1.8   root      397: {
                    398:        // XXX サポートしてない
                    399:        width = 640;
                    400:        height = 480;
                    401: }
                    402: 
                    403: // デストラクタ
1.1.1.9 ! root      404: NopRenderer::~NopRenderer()
1.1.1.8   root      405: {
                    406: }
                    407: 
                    408: // 画面合成
                    409: bool
1.1.1.9 ! root      410: NopRenderer::RenderMain()
1.1.1.8   root      411: {
                    412:        return false;
1.1.1.6   root      413: }

unix.superglobalmegacorp.com

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