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