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

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.4   root        7: #include "renderer.h"
1.1       root        8: #include "bt454.h"
1.1.1.5 ! root        9: #include "lunafb.h"
1.1.1.3   root       10: #include "mythread.h"
1.1       root       11: #include "tvram.h"
                     12: 
1.1.1.2   root       13: std::unique_ptr<Renderer> gRenderer;
1.1       root       14: 
                     15: static void *renderer_run(void *);
                     16: 
                     17: // コンストラクタ
                     18: Renderer::Renderer()
1.1.1.5 ! root       19:        : inherited("Renderer")
1.1       root       20: {
1.1.1.4   root       21:        // 初回は必ず描画する? (電源オン直後かな?)
                     22:        invalidate = true;
1.1       root       23: }
                     24: 
                     25: // デストラクタ
                     26: Renderer::~Renderer()
                     27: {
                     28:        // imagebuf の所有権は持っていないので解放不要。
                     29: 
1.1.1.2   root       30:        if (thread_created) {
                     31:                Terminate();
                     32:                pthread_join(thread, NULL);
                     33:        }
1.1       root       34: }
                     35: 
                     36: bool
                     37: Renderer::Init()
                     38: {
                     39:        // レンダリングスレッド起動
1.1.1.2   root       40:        pthread_create(&thread, NULL, renderer_run, NULL);
                     41:        thread_created = true;
1.1       root       42: 
                     43:        return true;
                     44: }
                     45: 
                     46: bool
                     47: Renderer::PowerOff()
                     48: {
                     49:        if (imagebuf) {
                     50:                // レンダリングスレッドに指示
                     51:                std::unique_lock<std::mutex> lock(mtx);
                     52:                request |= REQ_REND_POWEROFF;
                     53:                cv.notify_one();
                     54:        }
                     55: 
                     56:        return true;
                     57: }
                     58: 
                     59: // バッファとコールバックを指定する。
                     60: // 引数 buf と callback はどちらも NULL であってはならない。
                     61: // これは画面を必要とする wx 側から呼ばれる。CLI では呼ばれない。
                     62: void
                     63: Renderer::SetBuf(uint8 *buf, void (*callback)(void))
                     64: {
                     65:        assert(buf);
                     66:        assert(callback);
                     67: 
                     68:        imagebuf = buf;
                     69:        refresh_callback = callback;
                     70: }
                     71: 
                     72: // 画面合成処理 (CRTC とかから呼ばれる部分)
                     73: // 今は一画面単位で合成を行なっている。ラスター云々は未対応。
                     74: // 画面合成を行うかどうかとか、レンダリングスレッドに指示を出すかとか
                     75: // どこら辺までを呼び出し元とこっちが分担するかは未定。
                     76: void
                     77: Renderer::Render()
                     78: {
                     79:        // CLI 版なら何もしない。
                     80:        if (imagebuf == NULL) {
                     81:                return;
                     82:        }
                     83: 
                     84:        // スケジューラ都合による間引きとかがあればここらへんで評価?
                     85:        // XXX どっちのスレッドでやるか
                     86: 
                     87:        // レンダリングスレッドに指示
                     88:        std::unique_lock<std::mutex> lock(mtx);
                     89:        request |= REQ_REND_NORMAL;
                     90:        cv.notify_one();
                     91: }
                     92: 
1.1.1.4   root       93: // 全画面無効化の指示 (パレット変更で呼ばれる)。
                     94: // ここでは無効化だけ受け付けておいて、実際の処理はレンダリングの際に行う。
                     95: void
                     96: Renderer::Invalidate()
                     97: {
                     98:        std::unique_lock<std::mutex> lock(mtx);
                     99:        request |= REQ_INVALIDATE;
                    100:        cv.notify_one();
                    101: }
                    102: 
1.1       root      103: // レンダリングスレッドのエントリポイント
                    104: void *
                    105: renderer_run(void *dummy)
                    106: {
1.1.1.3   root      107:        PTHREAD_SETNAME("Renderer");
1.1       root      108: 
                    109:        gRenderer->ThreadRun();
                    110:        return NULL;
                    111: }
                    112: 
                    113: // レンダリングスレッド
                    114: void
                    115: Renderer::ThreadRun()
                    116: {
                    117:        for (;;) {
                    118:                uint32 req;
                    119: 
                    120:                // 何か起きるまで待つ
                    121:                {
                    122:                        std::unique_lock<std::mutex> lock(mtx);
                    123:                        cv.wait(lock, [&] { return (request != 0); });
                    124:                        req = request;
                    125:                        request = 0;
                    126:                }
                    127: 
                    128:                if ((req & REQ_TERMINATE)) {
                    129:                        // 終了するので、他のフラグは無視
                    130:                        break;
1.1.1.4   root      131:                }
                    132:                if ((req & REQ_REND_POWEROFF)) {
1.1       root      133:                        // 電源オフ時の描画 (通常描画フラグは無視)
                    134: 
                    135:                        // 電源オフされると画面を灰色にする。
                    136:                        // 黒でもいいけど、電源オンで黒いままなのと区別したい。
                    137:                        memset(imagebuf, 0x70, width * height * BPP);
                    138:                        // ウィンドウに通知
                    139:                        refresh_callback();
1.1.1.4   root      140:                        continue;
                    141:                }
                    142:                if ((req & REQ_INVALIDATE)) {
                    143:                        // 全画面無効化の指示。ここではフラグを立てるだけ。
                    144:                        // パレットは普段はまず変更されないが、変更する時には連続して
                    145:                        // 全パレットが変更されがちなので、ここでフラグを蓄積する。
                    146:                        // このフラグは同じスレッドの RenderMain() 内で回収する。
                    147:                        invalidate = true;
                    148:                }
                    149:                if ((req & REQ_REND_NORMAL)) {
1.1       root      150:                        // 通常描画
                    151: 
                    152:                        // レンダラを駆動して
                    153:                        if (RenderMain()) {
                    154:                                // 更新があればウィンドウに通知
                    155:                                refresh_callback();
                    156:                        }
                    157:                }
                    158:        }
                    159: }
                    160: 
1.1.1.2   root      161: // スレッドの終了を指示 (スレッドは動いていること)
                    162: void
                    163: Renderer::Terminate()
                    164: {
                    165:        assert(thread_created);
                    166: 
                    167:        std::unique_lock<std::mutex> lock(mtx);
                    168:        request |= REQ_TERMINATE;
                    169:        cv.notify_one();
                    170: }
                    171: 
1.1       root      172: //
                    173: // X68030 レンダラ
                    174: //
                    175: 
                    176: // コンストラクタ
                    177: X68030Renderer::X68030Renderer()
                    178: {
                    179:        // XXX とりあえず
                    180:        width = 768;
                    181:        height = 512;
                    182: }
                    183: 
                    184: // デストラクタ
                    185: X68030Renderer::~X68030Renderer()
                    186: {
                    187: }
                    188: 
                    189: // 画面合成
                    190: bool
                    191: X68030Renderer::RenderMain()
                    192: {
                    193:        assert(imagebuf);
                    194: 
                    195:        // 今はテキスト画面のみを合成バッファに直接描いている
                    196:        return gTVRAM->Render(imagebuf);
                    197: }
                    198: 
                    199: //
                    200: // LUNA レンダラ
                    201: //
                    202: 
                    203: // コンストラクタ
                    204: LunaRenderer::LunaRenderer()
                    205: {
                    206:        width = 1280;
                    207:        height = 1024;
                    208: }
                    209: 
                    210: // デストラクタ
                    211: LunaRenderer::~LunaRenderer()
                    212: {
                    213: }
                    214: 
1.1.1.4   root      215: bool
                    216: LunaRenderer::Init()
                    217: {
                    218:        if (inherited::Init() == false) {
                    219:                return false;
                    220:        }
                    221: 
                    222:        // ホストパレット配列を取得。
                    223:        pal = gBT454->GetHostPalette();
                    224:        return true;
                    225: }
                    226: 
                    227: 
1.1       root      228: // 画面合成
                    229: bool
                    230: LunaRenderer::RenderMain()
                    231: {
                    232:        const uint32 *plane0;
                    233:        std::atomic<uint8> *dirty;
                    234:        int hscroll;
                    235:        int vscroll;
                    236:        uint8 *dst0;
                    237:        bool updated;
                    238: 
                    239:        assert(imagebuf);
                    240:        dst0 = imagebuf;
                    241: 
                    242:        // ビットマップ
1.1.1.5 ! root      243:        gLunafb->GetRFCNT(&hscroll, &vscroll);
        !           244:        const uint8 *mem = gLunafb->GetBuf();
        !           245:        dirty = gLunafb->GetDirty();
1.1       root      246: 
                    247:        updated = false;
                    248: 
                    249:        // dirty は VRAM への書き込みがあれば常に 1 にする。
                    250:        // レンダリング時に dirty が 1 なら 2 にしてレンダリング。
                    251:        // レンダリング終了時に dirty が 2 なら 0 に戻す。
                    252:        // これによりレンダリング中に VRAM への書き込みがあれば次回描画される。
                    253: 
1.1.1.4   root      254:        // 全域を無効化して画面全体を描画し直す。
                    255:        // XXX この処理中に VRAM 書き込み等があっても整合するんだっけこれ
                    256:        if (invalidate) {
                    257:                for (int y = 0; y < height; y++) {
                    258:                        dirty[y] = 1;
                    259:                }
                    260:                invalidate = false;
                    261:        }
                    262: 
1.1       root      263:        // sy はメモリ上の Y 座標
                    264:        // dy はレンダラ画面の Y 座標 (RFCNT のラスタカウンタを考慮)
                    265: 
                    266:        // XXX とりあえず1プレーン
1.1.1.3   root      267:        plane0 = (const uint32 *)mem;
1.1       root      268:        int sy = vscroll;
                    269:        for (int dy = 0; dy < height; dst0 += width * BPP, dy++, sy++) {
                    270:                sy &= 0x3ff;
                    271: 
                    272:                if (atomic_cas_8(&dirty[sy], 1, 2) == 1) {
                    273:                        uint8 *dst = dst0;
                    274:                        // sx はメモリ上の X オフセット (ロングワード単位)
                    275:                        // dx はレンダラ画面の X オフセット (ロングワード単位)
                    276:                        // XXX 水平オフセットが仕様以上の時の挙動は未実装
                    277: 
                    278:                        int sx = (sy * 2048 + hscroll) / 32;
                    279:                        int shift = (hscroll & 31);
                    280:                        for (int dx = 0; dx < width / 32; dx++, sx++) {
                    281:                                uint32 p0 = plane0[sx];
                    282:                                if (shift) {
                    283:                                        p0 = (p0 << shift) | (plane0[sx + 1] >> (32 - shift));
                    284:                                }
                    285: 
                    286:                                // 1ロングワードの横 32bit が横 32dot に相当
                    287:                                for (int j = 0; j < 32; j++) {
                    288:                                        // 1bpp の時 P1,P2,P3 分はプルアップされて %1 に
                    289:                                        // なっているっぽいので、実質 #14 か #15 ということ。
                    290:                                        uint c = 14;
                    291:                                        // カラーコード(パレット番号)を作成
                    292:                                        if ((p0 & 0x80000000U)) c |= 1;
                    293:                                        p0 <<= 1;
                    294: 
                    295:                                        *dst++ = pal[c * 4 + 0];
                    296:                                        *dst++ = pal[c * 4 + 1];
                    297:                                        *dst++ = pal[c * 4 + 2];
                    298:                                }
                    299:                        }
                    300: 
                    301:                        // 2の時だけ0に戻す
                    302:                        atomic_cas_8(&dirty[sy], 2, 0);
                    303:                        updated = true;
                    304:                }
                    305:        }
                    306: 
                    307:        return updated;
                    308: }

unix.superglobalmegacorp.com

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