GDIとDirectX

激しく今さら感がするけど、以前ID3DX10Fontの代わりにDrawText()してたやつについて。
RGB値が反転してるっぽい感触がしていたっぽい件について情報が整理できたのでまとめ。

まずWindowsの色を扱うAPIは色の表現としてCOLORREF型とRGBQUAD型の2種類のどちらかを使うみたい。この時点でもう意味不明なんだけど、RGBQUADを使いそうなのはWindows GDIのヘルプで「RGBQUAD」を見ると

  • CreateDIBitmap
  • CreateDIBSection
  • GetDIBits
  • SetDIBits
  • SetDIBitsToDevice
  • StretchDIBits

が「See Also」にあがっているのでこの辺の関数が該当する模様。

で、他はCOLORREFを使うっぽい。2つの型は微妙にビット位置がアレでプログラムを作って調べたらこんな感じだった。

COLORREF型 RGBQUAD型
物理 RGB0 BGR0
論理 0BGR 0RGB

物理ってのがメモリに配置された状態でのバイト並びで論理ってのがプログラムで変数として見たときの並びね。
結論としては2つの型でRGBが逆転してる。
しかも両方とも最上位バイトは予約。αチャネルではなくて予約。0x00以外を入れてAPIを呼び出すと処理してくれない…orz
おまけに書き込み操作を行うAPIを呼ぶとご丁寧に最上位バイトを0x00で埋める。この動作はDirectX側でαチャネルを見てると面倒なことになる。
こんな感じなので2つの型で相互変換するときには単純なエンディアン変換ではダメ。エンディアン変換して8ビット右シフトしたら大丈夫だけど。


それで、じゃぁ気になるあいつは何型なの?って話なんだけど、これもプログラムで確かめてみた。

項目 物理 合致する型
DXGI_FORMAT_R8G8B8A8_UNORMのテクスチャ RGBA COLORREF型
CreateDIBSection()でもらったポインタ BGR0 RGBQUAD型
GetPixel()で取得した値 RGB0 COLORREF型

と、まぁこんな感じでR8G8B8A8_UNORMはCOLORREFで取り扱えば良いらしい。
試した感じだと、ID3D11DeviceContext::UpdateSubresource()とかID3D11DeviceContext::Map()とかで直接データを取り扱うときはRGBAの並びになってるっぽい感じ。シェーダからfloat4で書き込むと(x, y, z, w)の値がそれぞれ(R, G, B, A)になるみたい。

それでさっきRGBQUADのSee AlsoにあがっていたCreateDIBSection()は、CreateDIBSection()したDIBのポインタ領域にHDC経由でいろいろ書きこむとBGR0になっちゃってよろしくない感じ。仕方がないので色の指定をするときにCOLORREF指定のAPIでもRGBQUADを無理やりわたすしかなさそう。
HDC経由じゃなくてDIBのポインタ経由で直接書き込む場合はCOLORREFとして書き込んであげればOK。Map()してそのままポインタの先をmemcpy()でも良いと思うし、UpdateSubresource()で転送しても良いと思う。

ちなみに少し気になってGetPixel()してみたら表の通りCOLORREFに自動変換してくれてびっくりした。少なくともAPI同士ではおかしくならないように考慮されているっぽいから、直接メモリにアクセスする場合だけ問題になるみたいだね。


このあたりの背景があって、

  • DXGI_FORMAT_B8G8R8A8_UNORM
  • D3D11_RESOURCE_MISC_GDI_COMPATIBLE
  • IDXGISurface1::GetDC()

あたりが用意されているのかと。
この辺を指定したテクスチャなら直接HDCで書き込んでもCreateDIBSection()のRGBQUADデータをUpdateSubresource()しても大丈夫なんじゃないかと思う。以前なぜかうまくいかなかったので今もう一度試す気にはならないけど。

ところで、B8G8R8A8なテクスチャをシェーダにわたすとどう見えるんだろうね。私気になります。
ID3D11DeviceContext::CopyResource()については元先のFORMAT(幅・高さなども)が一致してないとコピーできないらしいのでダメだろうけど。



あと、最後にOpenGLについてはこちらが非常によくまとまっていて参考になると思います。
http://d.hatena.ne.jp/keim_at_Si/20050128/p1
※:「COLORREF RGBQUAD」でググって見つかったサイト。