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