|
|
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:
1.1.1.2 ! root 12: std::unique_ptr<Renderer> gRenderer;
1.1 root 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:
1.1.1.2 ! root 28: if (thread_created) {
! 29: Terminate();
! 30: pthread_join(thread, NULL);
! 31: }
1.1 root 32: }
33:
34: bool
35: Renderer::Init()
36: {
37: // レンダリングスレッド起動
1.1.1.2 ! root 38: pthread_create(&thread, NULL, renderer_run, NULL);
! 39: thread_created = true;
1.1 root 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:
97: gRenderer->ThreadRun();
98: return NULL;
99: }
100:
101: // レンダリングスレッド
102: void
103: Renderer::ThreadRun()
104: {
105: for (;;) {
106: uint32 req;
107:
108: // 何か起きるまで待つ
109: {
110: std::unique_lock<std::mutex> lock(mtx);
111: cv.wait(lock, [&] { return (request != 0); });
112: req = request;
113: request = 0;
114: }
115:
116: if ((req & REQ_TERMINATE)) {
117: // 終了するので、他のフラグは無視
118: break;
119:
120: } else if ((req & REQ_REND_POWEROFF)) {
121: // 電源オフ時の描画 (通常描画フラグは無視)
122:
123: // 電源オフされると画面を灰色にする。
124: // 黒でもいいけど、電源オンで黒いままなのと区別したい。
125: memset(imagebuf, 0x70, width * height * BPP);
126: // ウィンドウに通知
127: refresh_callback();
128:
129: } else if ((req & REQ_REND_NORMAL)) {
130: // 通常描画
131:
132: // レンダラを駆動して
133: if (RenderMain()) {
134: // 更新があればウィンドウに通知
135: refresh_callback();
136: }
137: }
138: }
139: }
140:
1.1.1.2 ! root 141: // スレッドの終了を指示 (スレッドは動いていること)
! 142: void
! 143: Renderer::Terminate()
! 144: {
! 145: assert(thread_created);
! 146:
! 147: std::unique_lock<std::mutex> lock(mtx);
! 148: request |= REQ_TERMINATE;
! 149: cv.notify_one();
! 150: }
! 151:
1.1 root 152: //
153: // X68030 レンダラ
154: //
155:
156: // コンストラクタ
157: X68030Renderer::X68030Renderer()
158: {
159: // XXX とりあえず
160: width = 768;
161: height = 512;
162: }
163:
164: // デストラクタ
165: X68030Renderer::~X68030Renderer()
166: {
167: }
168:
169: // 画面合成
170: bool
171: X68030Renderer::RenderMain()
172: {
173: assert(imagebuf);
174:
175: // 今はテキスト画面のみを合成バッファに直接描いている
176: return gTVRAM->Render(imagebuf);
177: }
178:
179: //
180: // LUNA レンダラ
181: //
182:
183: // コンストラクタ
184: LunaRenderer::LunaRenderer()
185: {
186: width = 1280;
187: height = 1024;
188: }
189:
190: // デストラクタ
191: LunaRenderer::~LunaRenderer()
192: {
193: }
194:
195: // 画面合成
196: bool
197: LunaRenderer::RenderMain()
198: {
199: const uint8 *pal;
200: const uint32 *plane0;
201: std::atomic<uint8> *dirty;
202: int hscroll;
203: int vscroll;
204: uint8 *dst0;
205: bool updated;
206:
207: assert(imagebuf);
208: dst0 = imagebuf;
209:
210: // パレット取得
211: pal = gBT454->GetHostPalette();
212:
213: // ビットマップ
214: gBitmap->GetRFCNT(&hscroll, &vscroll);
215: const uint8 *mem = gBitmap->GetBuf();
216: dirty = gBitmap->GetDirty();
217:
218: updated = false;
219:
220: // dirty は VRAM への書き込みがあれば常に 1 にする。
221: // レンダリング時に dirty が 1 なら 2 にしてレンダリング。
222: // レンダリング終了時に dirty が 2 なら 0 に戻す。
223: // これによりレンダリング中に VRAM への書き込みがあれば次回描画される。
224:
225: // sy はメモリ上の Y 座標
226: // dy はレンダラ画面の Y 座標 (RFCNT のラスタカウンタを考慮)
227:
228: // XXX とりあえず1プレーン
229: plane0 = (uint32 *)mem;
230: int sy = vscroll;
231: for (int dy = 0; dy < height; dst0 += width * BPP, dy++, sy++) {
232: sy &= 0x3ff;
233:
234: if (atomic_cas_8(&dirty[sy], 1, 2) == 1) {
235: uint8 *dst = dst0;
236: // sx はメモリ上の X オフセット (ロングワード単位)
237: // dx はレンダラ画面の X オフセット (ロングワード単位)
238: // XXX 水平オフセットが仕様以上の時の挙動は未実装
239:
240: int sx = (sy * 2048 + hscroll) / 32;
241: int shift = (hscroll & 31);
242: for (int dx = 0; dx < width / 32; dx++, sx++) {
243: uint32 p0 = plane0[sx];
244: if (shift) {
245: p0 = (p0 << shift) | (plane0[sx + 1] >> (32 - shift));
246: }
247:
248: // 1ロングワードの横 32bit が横 32dot に相当
249: for (int j = 0; j < 32; j++) {
250: // 1bpp の時 P1,P2,P3 分はプルアップされて %1 に
251: // なっているっぽいので、実質 #14 か #15 ということ。
252: uint c = 14;
253: // カラーコード(パレット番号)を作成
254: if ((p0 & 0x80000000U)) c |= 1;
255: p0 <<= 1;
256:
257: *dst++ = pal[c * 4 + 0];
258: *dst++ = pal[c * 4 + 1];
259: *dst++ = pal[c * 4 + 2];
260: }
261: }
262:
263: // 2の時だけ0に戻す
264: atomic_cas_8(&dirty[sy], 2, 0);
265: updated = true;
266: }
267: }
268:
269: return updated;
270: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.