|
|
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: //
8: // GVRAM
9: //
1.1.1.6 root 10:
1.1 root 11: // GVRAM はワード単位でホストバイトオーダ配置なので、
12: // バイトアクセス時は HB() マクロを使用のこと。
13:
1.1.1.6 root 14: #include "gvram.h"
1.1.1.11 root 15: #include "event.h"
16: #include "textscreen.h"
1.1.1.6 root 17: #include "videoctlr.h"
18:
1.1.1.8 root 19: // InsideOut p.135
1.1.1.11 root 20: /*static*/ const busdata
21: GVRAMDevice::wait = busdata::Wait(9 * 40_nsec);
1.1.1.8 root 22:
1.1.1.6 root 23: // コンストラクタ
1.1 root 24: GVRAMDevice::GVRAMDevice()
1.1.1.7 root 25: : inherited(OBJ_GVRAM)
1.1 root 26: {
1.1.1.11 root 27: composite.Create(1024, 1024);
1.1 root 28: }
29:
1.1.1.6 root 30: // デストラクタ
1.1 root 31: GVRAMDevice::~GVRAMDevice()
32: {
33: }
34:
1.1.1.10 root 35: // 初期化
36: bool
37: GVRAMDevice::Init()
38: {
1.1.1.12! root 39: size_t devlen = 0x20'0000; // XXX とりあえず
1.1.1.10 root 40: mem.reset(new(std::nothrow) uint8[devlen]);
41: if ((bool)mem == false) {
1.1.1.12! root 42: warnx("Could not allocate %zu bytes at %s", devlen, __method__);
1.1.1.10 root 43: return false;
44: }
45:
1.1.1.11 root 46: videoctlr = GetVideoCtlrDevice();
47:
48: // 加工済みグラフィックパレットを取得。
49: palette = &(videoctlr->GetHostPalette())[0];
50:
1.1.1.10 root 51: return true;
52: }
53:
1.1.1.11 root 54: void
55: GVRAMDevice::ResetHard(bool poweron)
56: {
57: // XXX ここ?
58: Invalidate();
59: }
60:
61: // 全画面の更新フラグを立てる。
62: void
63: GVRAMDevice::Invalidate()
64: {
65: dirty.line.set();
66: }
67:
1.1.1.9 root 68: inline uint32
69: GVRAMDevice::Decoder(uint32 addr) const
1.1 root 70: {
1.1.1.9 root 71: return addr - baseaddr;
1.1 root 72: }
73:
1.1.1.8 root 74: busdata
1.1.1.9 root 75: GVRAMDevice::Read(busaddr addr)
1.1 root 76: {
1.1.1.9 root 77: uint32 offset = Decoder(addr.Addr());
1.1.1.8 root 78: busdata data;
1.1.1.9 root 79:
80: data = *(uint16 *)&mem[offset & ~1U];
1.1.1.8 root 81: data |= wait;
1.1.1.9 root 82: data |= BusData::Size2;
1.1.1.8 root 83: return data;
1.1 root 84: }
85:
1.1.1.8 root 86: busdata
1.1.1.9 root 87: GVRAMDevice::Write(busaddr addr, uint32 data)
1.1 root 88: {
1.1.1.9 root 89: uint32 offset = Decoder(addr.Addr());
90: uint32 reqsize = addr.GetSize();
91: uint32 datasize = std::min(2 - (offset & 1U), reqsize);
92: data >>= (reqsize - datasize) * 8;
93:
1.1.1.11 root 94: // 現状 1024x1024 (4bit) しか対応していない。
95: if (__predict_false(datasize == 1)) {
96: if ((offset & 1) != 0) {
97: mem[HB(offset)] = data & 0x0f;
98: }
1.1.1.9 root 99: } else {
1.1.1.11 root 100: *(uint16 *)&mem[offset] = data & 0x0f;
1.1.1.9 root 101: }
1.1.1.11 root 102: SetDirty(offset);
1.1.1.9 root 103:
104: busdata r = wait;
105: r |= busdata::Size(datasize);
106: return r;
1.1 root 107: }
108:
1.1.1.8 root 109: busdata
1.1.1.9 root 110: GVRAMDevice::Peek1(uint32 addr)
1.1 root 111: {
1.1.1.9 root 112: uint32 offset = Decoder(addr);
113: return mem[HB(offset)];
1.1 root 114: }
1.1.1.11 root 115:
116: bool
117: GVRAMDevice::Poke1(uint32 addr, uint32 data)
118: {
119: if ((int32)data >= 0) {
120: uint32 offset = Decoder(addr);
121: // 現状 1024x1024 モードしか対応していないため
122: // 有効なのはワード中下位4ビット。
123: if ((offset & 1) != 0) {
124: mem[HB(offset)] = data & 0x0f;
125: // この場合も画面を更新する。
126: SetDirty(offset);
127: }
128: }
129: return true;
130: }
131:
132: // offset の位置に対応する更新フラグを立てる。
133: // offset はページ先頭からのバイトオフセット。
134: inline void
135: GVRAMDevice::SetDirty(uint32 offset)
136: {
137: // GVRAM (1024x1024 モード) は
138: // 横 1024 ドット(2048バイト) x 縦 1024 ドット。
139: //
140: // 1 0
141: // 4 3 2 1 0 f e d c b a 9 8 7 6 5 4 3 2 1 0
142: // +-------------------+---------------------+
143: // GVRAM | Y座標 (1024dot) | X座標 (1024word) |
144: // +-------------------+---------------------+
145: // : :
146: // +-------------------+
147: // | |
148: // +-------------------+
149: // 9 8 7 6 5 4 3 2 1 0
150:
151: // 更新フラグはラスタ単位
152: uint y = offset >> 11;
153: dirty.line.set(y);
154: }
155:
156: // 画面更新する必要があるか。
157: // VM スレッドで呼ばれる。
158: bool
159: GVRAMDevice::Snap()
160: {
161: bool update_needed;
162:
163: // 更新 (dirty) があれば pending に重ねる。
164: {
165: std::lock_guard<std::mutex> lock(mtx);
166: pending.line |= dirty.line;
167: dirty.line.reset();
168:
169: if (__predict_false(dirty.invalidate2)) {
170: pending.invalidate2 = true;
171: dirty.invalidate2 = false;
172: }
173:
174: update_needed = pending.line.any() || pending.invalidate2;
175: }
176:
177: return update_needed;
178: }
179:
180: // 画面合成。
181: // レンダラスレッドで VideoCtlr から呼ばれる。
182: // dst を更新すれば true を返す。
183: bool
184: GVRAMDevice::Render(BitmapRGBX& dst)
185: {
186: bool updated = false;
187:
188: // ローカルにコピー。
189: ModifyInfo modified;
190: {
191: std::lock_guard<std::mutex> lock(mtx);
192: modified.line = pending.line;
193: modified.invalidate2 = pending.invalidate2;
194: pending.line.reset();
195: pending.invalidate2 = false;
196: }
197:
198: // GVRAM に更新があれば composite を更新。
199: if (modified.line.any()) {
200: Render1024ToComposite(modified.line);
201: updated = true;
202: }
203:
204: // composite に更新があるか(updated)、
205: // 無条件に更新するか(modified.invalidate2) なら dst を更新。
206: if (updated || modified.invalidate2) {
207: RenderCompositeToRGBX(dst, modified);
208: updated = true;
209: }
210:
211: return updated;
212: }
213:
214: // GVRAM (1024x1024、16色モード) から composite 画面を合成する。
215: // レンダラスレッドから呼ばれる。
216: void
217: GVRAMDevice::Render1024ToComposite(const bitset1024& modified)
218: {
219: constexpr uint xend = 1024;
220: constexpr uint yend = 1024;
221: for (uint y = 0; y < yend; y++) {
222: if (__predict_true(modified.test(y) == false)) {
223: continue;
224: }
225:
226: const uint16 *src = (const uint16 *)&mem[0];
227: src += y * 1024;
228: uint8 *dst = (uint8 *)composite.GetRowPtr(y);
229: for (uint x = 0; x < xend; x++) {
230: *dst++ = *src++;
231: }
232: }
233: }
234:
235: void
236: GVRAMDevice::RenderCompositeToRGBX(BitmapRGBX& dst,
237: const ModifyInfo& modified)
238: {
239: dst.DrawBitmapI8(0, 0, composite, palette);
240: }
241:
242: // (x, y) 位置のピクセル情報を screen に出力。(ビットマップモニタの情報欄)
243: void
244: GVRAMDevice::UpdateInfo(TextScreen& screen, int x, int y) const
245: {
246: screen.Clear();
247:
248: // 0 1 2 3 4 5 6
249: // 012345678901234567890123456789012345678901234567890123456789012345
250: // X=1023 Y=1023: ColorCode=$d
251:
252: screen.Puts(0, 0, "X= Y=");
253: if (x >= 0) {
254: const uint16 *mem16 = (const uint16 *)&mem[0];
255: uint16 cc = mem16[y * 1024 + x];
256: screen.Print(2, 0, "%4d Y=%4d Colorcode=$%x", x, y, cc);
257: }
258: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.