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

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: 
                      7: #include "object.h"
                      8: #include "bitmap.h"
                      9: #include "bt454.h"
1.1.1.3 ! root       10: #include "mythread.h"
1.1       root       11: #include "renderer.h"
                     12: #include "tvram.h"
                     13: 
1.1.1.2   root       14: std::unique_ptr<Renderer> gRenderer;
1.1       root       15: 
                     16: static void *renderer_run(void *);
                     17: 
                     18: // コンストラクタ
                     19: Renderer::Renderer()
                     20: {
                     21:        logname = "renderer";
                     22:        devname = "Render";
                     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: 
                     93: // レンダリングスレッドのエントリポイント
                     94: void *
                     95: renderer_run(void *dummy)
                     96: {
1.1.1.3 ! root       97:        PTHREAD_SETNAME("Renderer");
1.1       root       98: 
                     99:        gRenderer->ThreadRun();
                    100:        return NULL;
                    101: }
                    102: 
                    103: // レンダリングスレッド
                    104: void
                    105: Renderer::ThreadRun()
                    106: {
                    107:        for (;;) {
                    108:                uint32 req;
                    109: 
                    110:                // 何か起きるまで待つ
                    111:                {
                    112:                        std::unique_lock<std::mutex> lock(mtx);
                    113:                        cv.wait(lock, [&] { return (request != 0); });
                    114:                        req = request;
                    115:                        request = 0;
                    116:                }
                    117: 
                    118:                if ((req & REQ_TERMINATE)) {
                    119:                        // 終了するので、他のフラグは無視
                    120:                        break;
                    121: 
                    122:                } else if ((req & REQ_REND_POWEROFF)) {
                    123:                        // 電源オフ時の描画 (通常描画フラグは無視)
                    124: 
                    125:                        // 電源オフされると画面を灰色にする。
                    126:                        // 黒でもいいけど、電源オンで黒いままなのと区別したい。
                    127:                        memset(imagebuf, 0x70, width * height * BPP);
                    128:                        // ウィンドウに通知
                    129:                        refresh_callback();
                    130: 
                    131:                } else if ((req & REQ_REND_NORMAL)) {
                    132:                        // 通常描画
                    133: 
                    134:                        // レンダラを駆動して
                    135:                        if (RenderMain()) {
                    136:                                // 更新があればウィンドウに通知
                    137:                                refresh_callback();
                    138:                        }
                    139:                }
                    140:        }
                    141: }
                    142: 
1.1.1.2   root      143: // スレッドの終了を指示 (スレッドは動いていること)
                    144: void
                    145: Renderer::Terminate()
                    146: {
                    147:        assert(thread_created);
                    148: 
                    149:        std::unique_lock<std::mutex> lock(mtx);
                    150:        request |= REQ_TERMINATE;
                    151:        cv.notify_one();
                    152: }
                    153: 
1.1       root      154: //
                    155: // X68030 レンダラ
                    156: //
                    157: 
                    158: // コンストラクタ
                    159: X68030Renderer::X68030Renderer()
                    160: {
                    161:        // XXX とりあえず
                    162:        width = 768;
                    163:        height = 512;
                    164: }
                    165: 
                    166: // デストラクタ
                    167: X68030Renderer::~X68030Renderer()
                    168: {
                    169: }
                    170: 
                    171: // 画面合成
                    172: bool
                    173: X68030Renderer::RenderMain()
                    174: {
                    175:        assert(imagebuf);
                    176: 
                    177:        // 今はテキスト画面のみを合成バッファに直接描いている
                    178:        return gTVRAM->Render(imagebuf);
                    179: }
                    180: 
                    181: //
                    182: // LUNA レンダラ
                    183: //
                    184: 
                    185: // コンストラクタ
                    186: LunaRenderer::LunaRenderer()
                    187: {
                    188:        width = 1280;
                    189:        height = 1024;
                    190: }
                    191: 
                    192: // デストラクタ
                    193: LunaRenderer::~LunaRenderer()
                    194: {
                    195: }
                    196: 
                    197: // 画面合成
                    198: bool
                    199: LunaRenderer::RenderMain()
                    200: {
                    201:        const uint8 *pal;
                    202:        const uint32 *plane0;
                    203:        std::atomic<uint8> *dirty;
                    204:        int hscroll;
                    205:        int vscroll;
                    206:        uint8 *dst0;
                    207:        bool updated;
                    208: 
                    209:        assert(imagebuf);
                    210:        dst0 = imagebuf;
                    211: 
                    212:        // パレット取得
                    213:        pal = gBT454->GetHostPalette();
                    214: 
                    215:        // ビットマップ
                    216:        gBitmap->GetRFCNT(&hscroll, &vscroll);
                    217:        const uint8 *mem = gBitmap->GetBuf();
                    218:        dirty = gBitmap->GetDirty();
                    219: 
                    220:        updated = false;
                    221: 
                    222:        // dirty は VRAM への書き込みがあれば常に 1 にする。
                    223:        // レンダリング時に dirty が 1 なら 2 にしてレンダリング。
                    224:        // レンダリング終了時に dirty が 2 なら 0 に戻す。
                    225:        // これによりレンダリング中に VRAM への書き込みがあれば次回描画される。
                    226: 
                    227:        // sy はメモリ上の Y 座標
                    228:        // dy はレンダラ画面の Y 座標 (RFCNT のラスタカウンタを考慮)
                    229: 
                    230:        // XXX とりあえず1プレーン
1.1.1.3 ! root      231:        plane0 = (const uint32 *)mem;
1.1       root      232:        int sy = vscroll;
                    233:        for (int dy = 0; dy < height; dst0 += width * BPP, dy++, sy++) {
                    234:                sy &= 0x3ff;
                    235: 
                    236:                if (atomic_cas_8(&dirty[sy], 1, 2) == 1) {
                    237:                        uint8 *dst = dst0;
                    238:                        // sx はメモリ上の X オフセット (ロングワード単位)
                    239:                        // dx はレンダラ画面の X オフセット (ロングワード単位)
                    240:                        // XXX 水平オフセットが仕様以上の時の挙動は未実装
                    241: 
                    242:                        int sx = (sy * 2048 + hscroll) / 32;
                    243:                        int shift = (hscroll & 31);
                    244:                        for (int dx = 0; dx < width / 32; dx++, sx++) {
                    245:                                uint32 p0 = plane0[sx];
                    246:                                if (shift) {
                    247:                                        p0 = (p0 << shift) | (plane0[sx + 1] >> (32 - shift));
                    248:                                }
                    249: 
                    250:                                // 1ロングワードの横 32bit が横 32dot に相当
                    251:                                for (int j = 0; j < 32; j++) {
                    252:                                        // 1bpp の時 P1,P2,P3 分はプルアップされて %1 に
                    253:                                        // なっているっぽいので、実質 #14 か #15 ということ。
                    254:                                        uint c = 14;
                    255:                                        // カラーコード(パレット番号)を作成
                    256:                                        if ((p0 & 0x80000000U)) c |= 1;
                    257:                                        p0 <<= 1;
                    258: 
                    259:                                        *dst++ = pal[c * 4 + 0];
                    260:                                        *dst++ = pal[c * 4 + 1];
                    261:                                        *dst++ = pal[c * 4 + 2];
                    262:                                }
                    263:                        }
                    264: 
                    265:                        // 2の時だけ0に戻す
                    266:                        atomic_cas_8(&dirty[sy], 2, 0);
                    267:                        updated = true;
                    268:                }
                    269:        }
                    270: 
                    271:        return updated;
                    272: }

unix.superglobalmegacorp.com

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