|
|
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.6 root 7: //
8: // レンダラ
9: //
10:
1.1.1.4 root 11: #include "renderer.h"
1.1.1.9 ! root 12: #include "planevram.h"
1.1.1.8 root 13: #include "syncer.h"
1.1.1.6 root 14: #include "uimessage.h"
1.1.1.9 ! root 15: #include "videoctlr.h"
1.1 root 16:
17: // コンストラクタ
18: Renderer::Renderer()
1.1.1.8 root 19: : inherited(OBJ_RENDERER)
1.1 root 20: {
1.1.1.9 ! root 21: #if defined(HAVE_AVX2)
! 22: enable_avx2 = gMainApp.enable_avx2;
! 23: #endif
! 24:
1.1.1.6 root 25: monitor.func = ToMonitorCallback(&X68030Renderer::MonitorUpdate);
26: monitor.SetSize(68, 33);
27: monitor.Regist(ID_MONITOR_RENDERER);
1.1 root 28: }
29:
30: // デストラクタ
31: Renderer::~Renderer()
32: {
1.1.1.6 root 33: TerminateThread();
1.1.1.8 root 34: }
35:
36: // 初期化
37: bool
38: Renderer::Init()
39: {
40: if (inherited::Init() == false) {
41: return false;
42: }
43:
44: syncer = GetSyncer();
45:
46: return true;
1.1 root 47: }
48:
1.1.1.6 root 49: // リセット
50: void
51: Renderer::ResetHard(bool poweron)
1.1 root 52: {
1.1.1.8 root 53: next_refresh_rtime = syncer->GetRealTime();
1.1 root 54:
1.1.1.6 root 55: // 統計情報をクリア
56: render_time.Reset();
57: render_exec = 0;
58: last_mod_blocks = 0;
59: total_mod_blocks = 0;
60: total_invalidate2 = 0;
1.1 root 61: }
62:
1.1.1.6 root 63: // 電源オフ
64: void
1.1 root 65: Renderer::PowerOff()
66: {
1.1.1.6 root 67: if (enable) {
1.1 root 68: // レンダリングスレッドに指示
69: std::unique_lock<std::mutex> lock(mtx);
70: request |= REQ_REND_POWEROFF;
71: cv.notify_one();
72: }
73: }
74:
1.1.1.6 root 75: // 合成処理イネーブル
76: // 一度だけ呼び出すことができる
1.1 root 77: void
1.1.1.6 root 78: Renderer::Enable()
1.1 root 79: {
1.1.1.6 root 80: assert(enable == false);
1.1 root 81:
1.1.1.6 root 82: enable = true;
83: bitmap.Create(width, height);
84: // 初期値灰色にしておく
85: bitmap.Fill(Color(0x70, 0x70, 0x70));
1.1 root 86: }
87:
1.1.1.6 root 88: // 画面合成処理 (VM スレッドで CRTC/CRTC2 から呼ばれる)。
1.1 root 89: // 今は一画面単位で合成を行なっている。ラスター云々は未対応。
90: void
91: Renderer::Render()
92: {
93: // CLI 版なら何もしない。
1.1.1.6 root 94: if (enable == false) {
1.1 root 95: return;
96: }
97:
1.1.1.6 root 98: // 更新されていればレンダラに引き渡す
1.1.1.8 root 99: ModifyInfo mod = planevram->GetModify();
1.1.1.6 root 100: if (__predict_false(invalidate2 == true)) {
101: mod.invalidate2 = true;
102: }
103:
104: if (mod.IsDirty() || mod.invalidate2) {
105: if (modq.Enqueue(mod)) {
106: // 更新情報を引き取ったのでクリアする
1.1.1.8 root 107: planevram->ClearDirty();
1.1.1.6 root 108: invalidate2 = false;
109: } else {
110: // VM スレッドが速すぎるため次回に持ち越し
111: }
112: }
113:
1.1 root 114: // スケジューラ都合による間引きとかがあればここらへんで評価?
115: // XXX どっちのスレッドでやるか
116:
117: // レンダリングスレッドに指示
118: std::unique_lock<std::mutex> lock(mtx);
119: request |= REQ_REND_NORMAL;
120: cv.notify_one();
121: }
122:
1.1.1.6 root 123: // 全画面更新の指示 (パレット変更やスクロールなど VRAM の変更を伴わないもの)。
1.1.1.4 root 124: // ここでは無効化だけ受け付けておいて、実際の処理はレンダリングの際に行う。
125: void
1.1.1.6 root 126: Renderer::Invalidate2()
1.1.1.4 root 127: {
1.1.1.6 root 128: invalidate2 = true;
1.1 root 129: }
130:
131: // レンダリングスレッド
132: void
133: Renderer::ThreadRun()
134: {
135: for (;;) {
136: uint32 req;
137:
138: // 何か起きるまで待つ
139: {
140: std::unique_lock<std::mutex> lock(mtx);
141: cv.wait(lock, [&] { return (request != 0); });
142: req = request;
143: request = 0;
144: }
145:
146: if ((req & REQ_TERMINATE)) {
147: // 終了するので、他のフラグは無視
148: break;
1.1.1.4 root 149: }
150: if ((req & REQ_REND_POWEROFF)) {
1.1 root 151: // 電源オフ時の描画 (通常描画フラグは無視)
152:
153: // 電源オフされると画面を灰色にする。
154: // 黒でもいいけど、電源オンで黒いままなのと区別したい。
1.1.1.6 root 155: bitmap.Fill(Color(0x70, 0x70, 0x70));
156: // UI に通知
157: UIMessage::Post(UIMessage::RENDER);
1.1.1.4 root 158: continue;
159: }
160: if ((req & REQ_REND_NORMAL)) {
1.1 root 161: // 通常描画
1.1.1.6 root 162: if (modq.Dequeue(&modify)) {
163: // 更新ブロック数を数える (統計用)
164: last_mod_blocks = modify.n_dirty;
165: total_mod_blocks += last_mod_blocks;
166: if (__predict_false(modify.invalidate2)) {
167: total_invalidate2++;
168: }
1.1 root 169:
1.1.1.6 root 170: // レンダラを駆動する。
171: // out_dirty は前回 UI に通知した後一度でも更新があれば true。
172: render_time.Start();
173: out_dirty |= RenderMain();
174: render_time.Stop();
175: render_exec++;
176: }
177:
178: if (out_dirty) {
1.1.1.8 root 179: uint64 rtime = syncer->GetRealTime();
1.1.1.6 root 180: if (rtime >= next_refresh_rtime) {
181: UIMessage::Post(UIMessage::RENDER);
182: next_refresh_rtime = rtime + refresh_interval;
183: out_dirty = false;
184: }
1.1 root 185: }
186: }
187: }
188: }
189:
1.1.1.6 root 190: // スレッドの終了を指示
1.1.1.2 root 191: void
192: Renderer::Terminate()
193: {
194: std::unique_lock<std::mutex> lock(mtx);
195: request |= REQ_TERMINATE;
196: cv.notify_one();
197: }
198:
1.1.1.6 root 199: // 描画更新(通知)間隔を設定
200: void
201: Renderer::SetRefreshInterval(uint64 t)
202: {
203: refresh_interval = t;
204: }
205:
206: // モニタ更新
207: void
208: Renderer::MonitorUpdate(Monitor *, TextScreen& screen)
209: {
210: int x;
211: int y;
212:
213: screen.Clear();
214:
215: // modify
216: screen.Print(0, 0, "Last Update Region");
1.1.1.8 root 217: const uint8 *m = &modify.bits[0];
218: for (int i = 0; i < 32; i++) {
219: char buf[33];
220: uint8 c;
221: for (int j = 0; j < 32; j++) {
222: if (__predict_false(*m++ != 0)) {
1.1.1.6 root 223: c = '*';
224: } else {
225: c = '.';
226: }
227: buf[j] = c;
228: }
229:
1.1.1.8 root 230: buf[32] = '\0';
231: screen.Print(0, 1 + i, "%4d:%s", i * 32, buf);
1.1.1.6 root 232: }
1.1.1.8 root 233: screen.Puts(0, 1, "Y=");
1.1.1.6 root 234:
235: x = 43;
236: y = 0;
237: uint64 nsec = render_time.Elapsed();
238: screen.Print(x, y++, "RenderTime %3d.%06d sec",
239: (int)(nsec / 1000 / 1000 / 1000),
240: (int)(nsec / 1000) % (1000 * 1000));
241:
242: screen.Print(x, y++, "RenderExec %9" PRIu64, render_exec);
243:
244: y++;
245: screen.Print(x, y++, "Last Mod Blks %9d", last_mod_blocks);
246: screen.Print(x, y++, "Total Mod Blks %9" PRIu64, total_mod_blocks);
247: screen.Print(x, y++, "Total Invalid2 %9" PRIu64, total_invalidate2);
248: }
249:
1.1.1.9 ! root 250: // RGBX から RGB への変換。
! 251: void
! 252: Renderer::RGBXtoRGB(BitmapRGB& dst, const BitmapRGBX& src)
! 253: {
! 254: assert(dst.GetWidth() == src.GetWidth());
! 255: assert(dst.GetHeight() == src.GetHeight());
! 256: assert(src.GetWidth() % 4 == 0);
! 257:
! 258: #if defined(HAVE_AVX2)
! 259: if (__predict_true(enable_avx2)) {
! 260: RGBXtoRGB_avx2(dst, src);
! 261: } else
! 262: #endif
! 263: {
! 264: RGBXtoRGB_gen(dst, src);
! 265: }
! 266: }
! 267:
! 268: // RGBX から RGB への変換。(C++ 版)
! 269: /*static*/ void
! 270: Renderer::RGBXtoRGB_gen(BitmapRGB& dst, const BitmapRGBX& src)
! 271: {
! 272: for (int y = 0, yend = src.GetHeight(); y < yend; y++) {
! 273: const uint32 *s = (const uint32 *)src.GetRowPtr(y);
! 274: uint32 *d = (uint32 *)dst.GetRowPtr(y);
! 275:
! 276: const uint32 *send = s + src.GetWidth();
! 277: for (; s < send; ) {
! 278: // 4ピクセルずつ処理する
! 279:
! 280: uint32 c0 = htole32(*s++);
! 281: uint32 c1 = htole32(*s++);
! 282: uint32 c2 = htole32(*s++);
! 283: uint32 c3 = htole32(*s++);
! 284:
! 285: // c0 = $x0B0G0R0
! 286: // c1 = $x1B1G1R1
! 287: // c2 = $x2B2G2R2
! 288: // c3 = $x3B3G3R3
! 289: //
! 290: // d[0] = $00B0G0R0 | $R1000000 = $R1B0G0R0
! 291: // d[1] = $0000B1G1 | $G2R20000 = $G2R2B1G1
! 292: // d[2] = $000000B2 | $B3G3R300 = $B3G3R3B2
! 293:
! 294: *d++ = le32toh((c0 ) | (c1 << 24));
! 295: *d++ = le32toh((c1 >> 8) | (c2 << 16));
! 296: *d++ = le32toh((c2 >> 16) | (c3 << 8));
! 297: }
! 298: }
! 299: }
! 300:
1.1.1.6 root 301:
1.1 root 302: //
303: // X68030 レンダラ
304: //
305:
306: // コンストラクタ
307: X68030Renderer::X68030Renderer()
308: {
309: // XXX とりあえず
310: width = 768;
311: height = 512;
1.1.1.9 ! root 312:
! 313: bitmap32.Create(width, height);
1.1 root 314: }
315:
316: // デストラクタ
317: X68030Renderer::~X68030Renderer()
318: {
319: }
320:
1.1.1.9 ! root 321: // 初期化
! 322: bool
! 323: X68030Renderer::Init()
! 324: {
! 325: if (inherited::Init() == false) {
! 326: return false;
! 327: }
! 328:
! 329: planevram = GetPlaneVRAMDevice();
! 330: videoctlr = GetVideoCtlrDevice();
! 331:
! 332: return true;
! 333: }
! 334:
1.1 root 335: // 画面合成
336: bool
337: X68030Renderer::RenderMain()
338: {
1.1.1.9 ! root 339: bool updated = videoctlr->Render(bitmap32, modify);
! 340: if (updated) {
! 341: RGBXtoRGB(bitmap, bitmap32);
! 342: }
! 343: return updated;
1.1 root 344: }
345:
1.1.1.6 root 346:
1.1 root 347: //
348: // LUNA レンダラ
349: //
350:
351: // コンストラクタ
352: LunaRenderer::LunaRenderer()
353: {
354: width = 1280;
355: height = 1024;
1.1.1.9 ! root 356:
! 357: textbmp.Create(width, height);
1.1 root 358: }
359:
360: // デストラクタ
361: LunaRenderer::~LunaRenderer()
362: {
363: }
364:
1.1.1.9 ! root 365: // 初期化
! 366: bool
! 367: LunaRenderer::Init()
! 368: {
! 369: if (inherited::Init() == false) {
! 370: return false;
! 371: }
! 372:
! 373: planevram = GetPlaneVRAMDevice();
! 374:
! 375: return true;
! 376: }
! 377:
1.1 root 378: // 画面合成
379: bool
380: LunaRenderer::RenderMain()
381: {
1.1.1.9 ! root 382: // 型変換だけ必要
! 383: bool updated = planevram->Render(textbmp, modify);
! 384: if (updated) {
! 385: RGBXtoRGB(bitmap, textbmp);
! 386: }
! 387: return updated;
1.1.1.8 root 388: }
389:
390:
391: //
1.1.1.9 ! root 392: // 何もしないレンダラ
1.1.1.8 root 393: //
394:
395: // コンストラクタ
1.1.1.9 ! root 396: NopRenderer::NopRenderer()
1.1.1.8 root 397: {
398: // XXX サポートしてない
399: width = 640;
400: height = 480;
401: }
402:
403: // デストラクタ
1.1.1.9 ! root 404: NopRenderer::~NopRenderer()
1.1.1.8 root 405: {
406: }
407:
408: // 画面合成
409: bool
1.1.1.9 ! root 410: NopRenderer::RenderMain()
1.1.1.8 root 411: {
412: return false;
1.1.1.6 root 413: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.