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

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

unix.superglobalmegacorp.com

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