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