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

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

unix.superglobalmegacorp.com

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