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

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2022 nono project
                      4: // Licensed under nono-license.txt
                      5: //
                      6: 
                      7: //
                      8: // プレーン VRAM (垂直 VRAM)
                      9: // Lunafb と X68k TVRAM の共通部分
                     10: //
                     11: 
                     12: #include "planevram.h"
                     13: #include "mybswap.h"
1.1.1.5 ! root       14: #include <algorithm>
        !            15: #include <array>
        !            16: 
        !            17: // v[] がいずれかでも true なら true を返す。
        !            18: static bool
        !            19: AnyOf(const std::vector<bool>& v)
        !            20: {
        !            21:        return std::any_of(v.begin(), v.end(), [](bool x) { return x; });
        !            22: }
1.1       root       23: 
                     24: // コンストラクタ
1.1.1.2   root       25: PlaneVRAMDevice::PlaneVRAMDevice(int width_, int height_)
                     26:        : inherited(OBJ_PLANEVRAM)
1.1       root       27: {
1.1.1.2   root       28:        // ポカ避け。継承クラス側が設定する。
1.1       root       29:        nplane = -1;
                     30: 
                     31:        composite.Create(width_, height_);
                     32: 
1.1.1.5 ! root       33:        dirty.line.resize(height_);
        !            34:        pending.line.resize(height_);
1.1       root       35: 
                     36:        // レンダリング時に使うテーブルを事前に計算。
                     37:        InitDeptable();
                     38: }
                     39: 
                     40: // デストラクタ
                     41: PlaneVRAMDevice::~PlaneVRAMDevice()
                     42: {
                     43: }
                     44: 
                     45: // リセット
                     46: void
                     47: PlaneVRAMDevice::ResetHard(bool poweron)
                     48: {
                     49:        // XXX ここ?
                     50:        Invalidate();
                     51: }
                     52: 
                     53: // レンダリング時に使うテーブルを事前に計算。
                     54: void
                     55: PlaneVRAMDevice::InitDeptable()
                     56: {
                     57:        deptable.reset(new uint64[256]);
                     58: 
                     59:        // %abcdefgh の8ビットを
                     60:        // リトルエンディアンホストでは
                     61:        // %0000000h'0000000g'0000000f'0000000e'0000000d'0000000c'0000000b'0000000a
                     62:        // ビッグエンディアンホストでは
                     63:        // %0000000a'0000000b'0000000c'0000000d'0000000e'0000000f'0000000g'0000000h
                     64:        // の64ビットに伸張する。
                     65:        // (8ビットを各バイトの最下位ビットに対応させる)
1.1.1.4   root       66:        for (uint i = 0; i < 256; i++) {
1.1       root       67:                uint64 res = 0;
                     68:                for (int bit = 0; bit < 8; bit++) {
                     69:                        int n = bit * 8;
                     70: #if BYTE_ORDER == LITTLE_ENDIAN
                     71:                        n = 56 - n;
                     72: #endif
                     73:                        res |= (uint64)((i >> bit) & 1) << n;
                     74:                }
                     75:                deptable[i] = res;
                     76:        }
                     77: }
                     78: 
                     79: // 全画面の更新フラグを立てる
                     80: void
                     81: PlaneVRAMDevice::Invalidate()
                     82: {
1.1.1.5 ! root       83:        std::fill(dirty.line.begin(), dirty.line.end(), 1);
1.1       root       84: }
                     85: 
1.1.1.5 ! root       86: // VRAM には更新がないが再レンダリングが必要。
        !            87: // パレット変更、スクロール等。VM スレッドから呼ばれる。
1.1       root       88: void
1.1.1.5 ! root       89: PlaneVRAMDevice::Invalidate2()
1.1       root       90: {
1.1.1.5 ! root       91:        dirty.invalidate2 = true;
1.1       root       92: }
                     93: 
1.1.1.5 ! root       94: // 画面更新する必要があるか。
        !            95: // dirty から pending を更新してみて、更新が一つでもあれば true を返す。
        !            96: // VM スレッドで呼ばれる。
1.1.1.4   root       97: bool
1.1.1.5 ! root       98: PlaneVRAMDevice::Snap()
1.1       root       99: {
1.1.1.5 ! root      100:        const uint height = composite.GetHeight();
        !           101:        bool update_needed;
1.1.1.4   root      102: 
1.1.1.5 ! root      103:        // 更新 (dirty) があれば pending に重ねる。
        !           104:        {
        !           105:                std::unique_lock<std::mutex> lock(mtx);
        !           106:                for (int y = 0; y < height; y++) {
        !           107:                        // std::vector<bool> には operator|=() がない。
        !           108:                        if (__predict_false(dirty.line[y])) {
        !           109:                                pending.line[y] = true;
        !           110:                                dirty.line[y] = false;
        !           111:                        }
1.1       root      112:                }
1.1.1.5 ! root      113: 
        !           114:                if (__predict_false(dirty.invalidate2)) {
        !           115:                        pending.invalidate2 = true;
        !           116:                        dirty.invalidate2 = false;
        !           117:                }
        !           118: 
        !           119:                update_needed = AnyOf(pending.line) || pending.invalidate2;
1.1       root      120:        }
1.1.1.5 ! root      121: 
        !           122:        return update_needed;
1.1       root      123: }
                    124: 
                    125: // 画面合成。
                    126: // レンダラスレッドから呼ばれる。
1.1.1.5 ! root      127: // dst を更新すれば true を返す。
1.1       root      128: bool
1.1.1.5 ! root      129: PlaneVRAMDevice::Render(BitmapRGBX& dst)
1.1       root      130: {
                    131:        bool updated = false;
                    132: 
1.1.1.5 ! root      133:        // ローカルにコピー。
        !           134:        ModifyInfo modified;
        !           135:        {
        !           136:                std::unique_lock<std::mutex> lock(mtx);
        !           137:                modified.line = pending.line;
        !           138:                std::fill(pending.line.begin(), pending.line.end(), false);
        !           139:                modified.invalidate2 = pending.invalidate2;
        !           140:                pending.invalidate2 = false;
        !           141:        }
        !           142: 
        !           143:        // VRAM に更新があれば composite を更新。
        !           144:        if (AnyOf(modified.line)) {
        !           145:                RenderVRAMToComposite(modified.line);
1.1       root      146:                updated = true;
                    147:        }
                    148: 
1.1.1.5 ! root      149:        // composite に更新があるか(updated)、
        !           150:        // 無条件に更新するか(modified.invalidate2) なら dst を更新。
        !           151:        if (updated || modified.invalidate2) {
        !           152:                RenderCompositeToRGBX(dst, modified);
1.1       root      153:                updated = true;
                    154:        }
                    155: 
                    156:        return updated;
                    157: }
                    158: 
                    159: // VRAM から composite 画面を合成する。
                    160: // レンダラスレッドから呼ばれる。
                    161: void
1.1.1.5 ! root      162: PlaneVRAMDevice::RenderVRAMToComposite(const std::vector<bool>& modified)
1.1       root      163: {
1.1.1.4   root      164:        const uint width  = composite.GetWidth();
                    165:        const uint height = composite.GetHeight();
                    166:        const uint planesz = (width / 8) * height;
1.1       root      167: 
1.1.1.2   root      168:        // 1bpp はパレット的にはほぼ 4bpp と同じ扱いになる。
                    169:        const int nplane4 = (nplane == 1) ? 4 : nplane;
                    170: 
1.1       root      171:        // テキスト合成画面を描く
1.1.1.4   root      172:        for (uint y = 0; y < height; y++) {
1.1.1.5 ! root      173:                bool mod = modified[y];
        !           174:                if (mod == false) {
1.1.1.2   root      175:                        continue;
                    176:                }
                    177: 
                    178:                const uint32 *src = (const uint32 *)&mem[0];
                    179:                src += y * width / 32;
1.1.1.3   root      180:                uint64 *dst = (uint64 *)composite.GetRowPtr(y);
1.1.1.2   root      181: 
1.1.1.4   root      182:                for (uint x = 0; x < width / 32; x++) {
1.1.1.2   root      183:                        std::array<uint32, 8> data;
                    184: 
                    185:                        // VRAM はホストエンディアンに関係なく 32bit で読み込んだ
                    186:                        // 時の MSB が左端ピクセル。
                    187:                        // ここでは左側から 8ピクセル(8ビット)ずつ 4回処理する
                    188:                        // のを最下位バイトから順に右シフトで行いたいので、
                    189:                        // (バイト内のビット順は維持したまま) バイトスワップする。
                    190:                        //
                    191:                        //          31     24  23     16  15      8   7      0
                    192:                        //        +----------+----------+----------+----------+
                    193:                        // VRAM   |+00 .. +07|+08 .. +15|+16 .. +23|+24 .. +31|
                    194:                        //        +----------+----------+----------+----------+
                    195:                        //  ↓
                    196:                        //        +----------+----------+----------+----------+
                    197:                        // data[] |+24 .. +31|+16 .. +23|+08 .. +15|+00 .. +07|
                    198:                        //        +----------+----------+----------+----------+
                    199:                        if (__predict_false(nplane == 1)) {
                    200:                                // LUNA 1bpp の場合残りの3プレーンは ff で埋める。
                    201:                                // 実際にも存在しないプレーンは ff が読み出せて
                    202:                                // カラーインデックスは $e か $f の二択になるので。
                    203:                                data[0] = bswap32(src[0]);
                    204:                                data[1] = 0xffffffff;
                    205:                                data[2] = 0xffffffff;
                    206:                                data[3] = 0xffffffff;
                    207:                        } else {
1.1.1.4   root      208:                                uint offset = planesz / sizeof(uint32);
1.1.1.2   root      209:                                for (int plane = 0; plane < nplane; plane++) {
                    210:                                        data[plane] = bswap32(src[plane * offset]);
                    211:                                }
1.1       root      212:                        }
1.1.1.2   root      213:                        src++;
1.1       root      214: 
1.1.1.2   root      215:                        // data[] の下位 8bit ずつを取り出して deptable[] で変換。
                    216:                        // p0..p3 は1バイト x 8個。
                    217:                        //
                    218:                        // data[] = %xxxxxxxx'xxxxxxxx'xxxxxxxx'ABCDEFGH
                    219:                        // ↓
                    220:                        // (リトルエンディアンホストの場合)
                    221:                        // p.H = %0000000H'0000000G'0000000F'0000000E
                    222:                        // p.L = %0000000D'0000000C'0000000B'0000000A
                    223:                        for (int b = 0; b < 4; b++) {
                    224:                                uint64 cc = 0;
                    225: 
                    226:                                for (int plane = 0; plane < nplane4; plane++) {
                    227:                                        uint64 p;
                    228:                                        p = deptable[data[plane] & 0xff];
                    229:                                        p <<= plane;
                    230:                                        cc |= p;
                    231:                                        data[plane] >>= 8;
1.1       root      232:                                }
1.1.1.2   root      233: 
                    234:                                // cc (64bit = 8バイト) は各バイトが各ピクセルの
                    235:                                // カラーインデックスになっているので
                    236:                                // BitmapI8 に 8バイト一気に書き込める。
                    237:                                // (エンディアンの影響は deptable[] で処理してある)
                    238:                                *dst++ = cc;
1.1       root      239:                        }
                    240:                }
                    241:        }
                    242: }
                    243: 
1.1.1.3   root      244: // composite 画面とパレット情報から RGBX 画面を合成する。
1.1.1.5 ! root      245: // modified は composite 上での変更箇所を示している。
1.1       root      246: // レンダラスレッドから呼ばれる。
                    247: void
1.1.1.3   root      248: PlaneVRAMDevice::RenderCompositeToRGBX(BitmapRGBX& dst,
1.1.1.5 ! root      249:        const ModifyInfo& modified)
1.1       root      250: {
1.1.1.4   root      251:        const uint width  = dst.GetWidth();
                    252:        const uint height = dst.GetHeight();
1.1       root      253: 
1.1.1.2   root      254:        // view_mod は表示領域 view における更新ラスタ
1.1       root      255:        BitmapI8 view(width, height);
1.1.1.2   root      256:        std::vector<uint8> view_mod(height);
1.1       root      257: 
                    258:        // この view に対する modify を計算する
1.1.1.5 ! root      259:        if (__predict_false(modified.invalidate2)) {
1.1.1.2   root      260:                std::fill(view_mod.begin(), view_mod.end(), 1);
1.1       root      261:        } else {
                    262:                // Y scroll 方向の modify 計算
1.1.1.2   root      263:                int sy = yscroll;
                    264:                for (int y = 0; y < height; y++, sy++) {
                    265:                        if (sy >= composite.GetHeight()) {
                    266:                                sy -= composite.GetHeight();
1.1       root      267:                        }
1.1.1.5 ! root      268:                        view_mod[y] = modified.line[sy];
1.1       root      269:                }
                    270: 
1.1.1.2   root      271:                // 右がはみ出す場合は、はみ出した先のラスタも加味する。
                    272:                if (xscroll + view.GetWidth() > composite.GetWidth()) {
                    273:                        sy = yscroll;
                    274:                        for (int y = 0; y < height; y++, sy++) {
                    275:                                if (sy >= composite.GetHeight()) {
                    276:                                        sy -= composite.GetHeight();
                    277:                                }
                    278:                                int sy2 = GetWrapY(sy);
1.1.1.5 ! root      279:                                view_mod[y] |= modified.line[sy2];
1.1       root      280:                        }
                    281:                }
                    282:        }
                    283: 
                    284:        // composite からスクロールを加味した表示領域 view を作る
1.1.1.2   root      285:        int sy = yscroll;
                    286:        for (int y = 0; y < height; y++, sy++) {
                    287:                if (sy >= composite.GetHeight()) {
                    288:                        sy -= composite.GetHeight();
                    289:                }
                    290:                if (view_mod[y] == 0) {
                    291:                        continue;
                    292:                }
1.1       root      293: 
1.1.1.3   root      294:                uint8 *v = view.GetRowPtr(y);
1.1.1.2   root      295:                uint8 *c = composite.GetPtr(xscroll, sy);
                    296:                if (xscroll + view.GetWidth() <= composite.GetWidth()) {
                    297:                        memcpy(v, c, view.GetWidth());
                    298:                } else {
                    299:                        // はみ出しの折り返し
                    300:                        int len1 = composite.GetWidth() - xscroll;
                    301:                        memcpy(v, c, len1);
                    302:                        v += len1;
                    303:                        int sy2 = GetWrapY(sy);
1.1.1.3   root      304:                        c = composite.GetRowPtr(sy2);
1.1.1.2   root      305:                        int len2 = view.GetWidth() - len1;
                    306:                        memcpy(v, c, len2);
1.1       root      307:                }
                    308:        }
                    309: 
1.1.1.3   root      310:        // view (I8) を Bitmap (RGBX) に展開する
1.1.1.4   root      311:        dst.DrawBitmapI8Raster(view, palette, &view_mod[0]);
1.1       root      312: }

unix.superglobalmegacorp.com

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