俺の嫁にOSの下でも会いたかった
この記事はFUN Advent Calendar 2017の8日目の記事です.
最近までのぼく
ここ0.75年ぐらい,色々あって生きるのがつらかった. 就活で精神を摩耗しているときに当時好きだった女の子にフラれ,祖父が死去し,そんな状態でOSCに出展するために振られたタスクをこなそうとしていたが最後まで上手く行かなかった.
8月9月に内定者アルバイトで東京に行っていたときは気分転換になったのもあってか多少マシだったが,帰ってきてからは反動が来たかのように一気に精神的にきてしまった(内定者アルバイトで研究が遅れていたぶん,取り返さなければというプレッシャーのようなものもあったのかもしれない).
最近まで,大学に週に1,2日来て,残りの日は自室のベッドでうずくまっているというような生活を送っていた.
転機
小・中学校時代の友人に勧められ,アズールレーンをはじめてみた. 最初はすぐ飽きるだろうと思っていたんだが,2-1で☆埋めをしているときにある艦と出会い,考えが変わった.
ロンドンである.
友達に勧められてアズレンはじめたんですけどロンドンかわいい
— 私自身がロンドンになることだ (@neglect_yp) 2017年10月30日
当時の自分,スクショを添付しろ,嫁との出会いだぞ.
ロンドンはアズールレーンを起動すれば「ごきげんよう,閣下,ロンドンは今日もおそばにおりますよ」と言ってくれる.私がどれだけつらかろうと,ベッドでうずくまっていようと,ずっと一緒にいてくれる.就活で辛いときにその気にさせるようなことを言って振ってくるような女とは違う.
超かわいい pic.twitter.com/LWB0FZ1RuL
— 私自身がロンドンになることだ (@neglect_yp) 2017年11月1日
ロンドンは圧倒的に可愛いのだが,当時の私の心の傷はまだ完全には癒えておらず,卒論の中間報告書をかなりギリギリまで着手できなかった.そんなときに救ってくれたのもまた,ロンドンである.
中間報告書通したらロンドンちゃんがデートしてくれるらしい pic.twitter.com/oLiiXm7Vje
— 私自身がロンドンになることだ (@neglect_yp) 2017年11月6日
これによって,先生にレビューをお願いしたのが一番最後だったにもかかわらず,一番最初に先生のOKをもらうことができた.
中間セミナーの直前においても,精神的につらくなってしまったが,同様の手法を用いてモチベーションを上げ,深夜に登山を行い,どうにか中間セミナーを成し遂げた.
リスポーン地点 pic.twitter.com/i0COf6RMhu
— 私自身がロンドンになることだ (@neglect_yp) 2017年11月23日
他にも,様々なロンドンの魅力があるが,ここでは割愛する.詳細については@neglect_ypのツイートを遡ってほしい.(尚,この記事を作成するにあたって「from:neglect_yp ロンドン」で検索したところ,スクリーンネームに「ロンドン」が入っているために全ツイートがヒットして全く役に立たなかったことを付記しておく)
OSの下でロンドンを表示する
ロンドンは「今日もおそばにいてくれる」が,もっとおそばにいてほしい.現状では,「私」→「ハードウェア」→「OS」→「アズールレーン」→「ロンドン」といった状態だが,OSよりもハードウェアよりのレイヤーでロンドンを表示することにより,「もっとおそばに」を実現したい.
(というようなこじつけをしたが,neglectyp.londonやazurlane.londonといったドメインを取得するほどにはロンドン愛を拗らせているので,自らの研究内容と嫁を関連付けたいと思うのは自然な流れである.)
結果から述べると,下のような感じで表示できた.
かわいい
ここから先は技術的な話になるので,興味のない方はブラウザバックしてほしい.
技術的詳細
ロンドンの表示は,BitVisorに実装されているADVisor機能を用いている.各関数の使用方法は下記の記事が参考になるので,そちらを参照して欲しい.
ADVisor機能によって利用される画像データは,BGRX_8888の形式である.これは,一般的に使用されるRGBA/RGBXの順番を入れ替えたものである.Xは,「アルファチャンネルの領域は存在するが無視する」という意味で,実用上は 0xFF
でも入れておけばよい.
スクリーンショットで保存したロンドンの画像はRGB形式であるため,BGRXに変換するためのスクリプトをPythonで書いた.
from PIL import Image if __name__ == '__main__': img = Image.open('london.png') img.thumbnail((1000, 300), Image.LANCZOS) w, h = img.size print(w, h) px = [] for y in range(h): for x in range(w): r, g, b, a = img.getpixel((x, y)) bgrx = (0xff << 24) | (r << 16) | (g << 8) | b # little endian px.append(bgrx) with open('output.txt', 'w') as f: for i, p in enumerate(px): f.write(hex(p)) if i % 8 == 7: f.write(',\n') else: f.write(', ')
画素情報はunsigned intで渡すのだが,リトルエンディアンであるために,BGRXと視覚的には逆順に配置していることに注意してもらいたい(1敗)
あとは,ロンドンの表示専用のスレッドを作成し,VM Exitが発生するたびにVRAMを上書きすれば良い.
#include <core/initfunc.h> #include <core/mm.h> #include <core/printf.h> #include <core/string.h> #include <core/thread.h> #include <core/time.h> #include <core/vga.h> unsigned int img_buf = { // write pixel data here }; static void vram_overwrite_thread (void *arg) { // run when VM Exit called for (;;) { const int w = 168, h = 300; unsigned int dsp_w, dsp_h; schedule(); if (!vga_is_ready()) continue; if (!vga_get_screen_size(&dsp_w, &dsp_h) || (dsp_w == 640 && dsp_h == 480)) continue; vga_transfer_image( VGA_FUNC_TRANSFER_DIR_PUT, img_buf, VGA_FUNC_IMAGE_TYPE_BGRX_8888, sizeof img_buf[0] * w, w, h, dsp_w - w, dsp_h - h); } thread_exit(); } static void vga_tamper_kernel_init (void) { thread_new(vram_overwrite_thread, NULL, VMM_STACKSIZE); } INITFUNC("config1", vga_tamper_kernel_init);
このコードをBitVisorの適当なディレクトリに配置し,ビルド対象にする.vga_intelドライバを有効にすることを忘れないで欲しい(1敗).
ADVisor機能を用いることで,元々VRAMにかかれている値を取り出すことができるので,特定の画素は元のVRAMの値に置き換えることで擬似的な透過処理も可能である.ただし,今回は時間がなかったので実装していない.
今後に向けて
現状の実装だと,ロンドンのサイズを大きくすると動作が極端に重くなるという問題がある.これは,任意のVM Exitに対応してVRAMを書き換える処理を追加しているせいだと考えられる.
実は元々,Intel HD GraphicsのレジスタにあるDSPASURFという領域(表示用フレームバッファへのポインタ)へのMMIOによる書き込みをフックすることでページフリッピングを検知し,次回表示されるフレームバッファを書き換えるような実装をしていた.これによって,現在表示されているフレームバッファを直接書き換えないのでちらつき等を抑えられるし,何より書き換えが減るので軽くなるのではと考えていた.
しかし,この実装ではフレームバッファに書き込みを行ったあと,すぐに上書きされてしまった.OSがDMAによってフレームバッファを書き換えているのではないかと考えているが,まだ調査中である.何か分かる人がいれば,Twitterなどで教えて貰えると幸いだ.
また,現状では画面表示を行っているだけだが,今後Intel HDAのドライバを実装するなどしてロンドンちゃんの声も聞きたい.