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

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

unix.superglobalmegacorp.com

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