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