|
|
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.