「 2012年11月 」一覧

Releaseビルドでの挙動違い


C++の話になりますが、VisualStudioを使っていて、Releaseビルドしているのに挙動が変わる、ということに何度か出遭ったことがあります。
その挙動が変わるというのが、デバッガ接続している状態でReleaseビルド実行体を実行しているときには正常に動くのに、実行体を単体で実行させたときには不正アクセス等で異常終了する、という感じです。Releaseビルドではデバッグ版のようにメモリを初期値で塗りつぶしたりという余計な操作を行わないことは知られています。あくまでこれはビルドでの挙動なので、今回のようなデバッガの有無では挙動が変わりません。となると、今回のこの挙動の差はいったいどこから来ているのだろうかと、ちょっと考え込んでしまいました。

調べてみると、デバッガの有無で変わるポイントとして、使用するヒープの性質が異なることがわかりました。デバッガが接続されていると、Low-Fragmentation Heap,(通称LFHというもの)が有効にならない、とあります。
参考: http://support.microsoft.com/kb/929136

妙な翻訳ですが、デバッグ時でもLFHを使いたい場合には、_NO_DEBUG_HEAPを有効にすればよいようです。そもそもLFHが使えない原因が他のヒープに関するデバッグフラグが設定されることのようで・・・。

さて、このような訳でデバッガの有無で使用されるヒープの種類が異なるということがわかりました。このヒープの差がおそらくReleaseビルドのアプリケーションの動作の差異となって現れたのではないかと考えます。ただし、たまたま使用されるメモリの中身が何かしらの残骸値であったために不正終了を引き起こしたという単純なケースもあると思います。

結局のところは、メモリの未初期化が影響してこのような差異に繋がっていることが可能性として高いので、この場合には1度そのようなクラスメンバの未初期化が残っていないか確認してみた方が良さそうです。


VisualStudio2012で古い関数を使う(SDLチェック)


VisualStudio 2012を使っていて、従来でも警告はされていた古い関数群を使用すると、デフォルト設定ではエラーとなることに気付きました。例えば次のような関数です。

  • strcat
  • strcpy
  • fopen

C関数の古くからある物で、Microsoftが末尾 _s が付く関数が用意されているものがその対象となっているように見えます。

これは、プロジェクト設定の”SDLチェック“という部分で変更が可能となっていました。デフォルトでは有効なのですが、無効にすることで従来と同じ挙動(警告メッセージが出る)に切り替わることが確認できました。

安全なコードを書く、という意味においては有効なままプログラムを作りたいと思いますが、移植性を考えると _s付きの関数が全てで用意されているわけではないので、難しいところだなと思います。


QNAPのNASでHDD交換


QNAPのNASでHDD交換しようとしてとても焦ったのでメモとして残しておきます。

出遭った現象としては、新規にHDDを挿入しても認識はするもののリビルドが走らない、というものです。
そのときのログメッセージとしては、”Add drive 1 to the volume failed” と記録されていました。

そもそも新規に購入してきたディスクではないのでディスクそのものの故障を疑ったりもしましたが、別PCでチェックしても問題なく、WindowsPCでフォーマットを行って挿入してもうまくいかず、とても悩みました。

いろいろと調べたり、実験したりして、ようやくたどり着いたのが、
ディスクにパーティションが存在してはいけない、という結論です。
WindowsPCでフォーマットしてある状態というのは、既にパーティションが存在してしまうので、NGということです。
ここで、フォーマットを行った後、パーティションの削除を行ってから、QNAP NASに挿入することでようやくRAIDアレイのリビルドが開始されました。

買ってきた直後のディスクでならうまくいくのには、こんな部分が絡んでいたようです。


GL_INTEL_map_texture 拡張


久々にIntelがOpenGL拡張を出していました。
それは、GL_INTEL_map_texture というもので、内容を読むと
GPUが読んでいるメモリ領域を直接CPUからアクセス可能にする拡張のようです。

確かに最近のIntel CPUはGPU統合してしまっており、グラフィックスメモリはすなわちメインメモリなわけで、CPUから直接扱うことが出来るようになっても自然です。
VRAMのように振る舞って一度メインメモリにコピーとか無駄なことをしなくてすむわけです。

増える関数はこんな感じです。

おおよそ通常のglMapBuffer/UnmapBufferと同じようですが、CPU/GPUでメモリ同期を取るためのSync関数も用意があるみたいです。

仕様: http://www.opengl.org/registry/specs/INTEL/map_texture.txt


NVIDIA GeForce GTX 650 TiのOpenGL 4.3


Geforce GTX650Tiを装着して現行のドライバを入れて発覚したのですが、公式ドライバ 306.97では OpenGL 4.3 はまだ使えないようです!
glGetString( GL_VERSION ) で取得してバージョン表示では、 4.2 となっていました。

カタログ上は以下のように OpenGL 4.3 へ対応をうたっているのですが、もうしばらくかかるのかもしれません。(これはNVIDIAのページからコピーした物です。)

追記

まだベータドライバですが、310.33というバージョンのものが配布されています。こちらで試してみたところ、glGetString( GL_VERSION )では 4.3 が返ってくるようになりました。この状態だと、OpenGL ES 3.0のこともあるので、かなりのGL extensionsが増えていました。

以下、拡張取得リストです。


透明ウィンドウ(半透明ウィンドウ)の話 その3


透明なウィンドウということで、このシリーズも第3回。今回が最後となりそうです。
ようやく Windows7,Windows8両方ともで動かせるやり方が発見できました。
なお、Windows7のAeroGlassOFF状態でも動くので、注意して実装すればWindowsXPでもこの方法でいけるのではないかと思います。

その方法は、レイヤードウィンドウを使う方法です。
これを使っての半透明ウィンドウはWindows7,Windows8ともに正常に動作することが手元では確認できました。
ただし、レイヤードウィンドウの簡単なサンプルによくあるSetLayeredWindowAttributes関数を使ってしまうと、ウィンドウ全体での半透明設定や、カラーキーによる抜き色指定になってしまうため、背景とうまく溶け込ませた半透明の処理があまりうまく出来ないため、使用しないでおきます。

半透明もうまく処理するレイヤードウィンドウの作り方としては、DIBとUpdateLayeredWindowとを使って実現します。
DIBで半透明用のメモリ上のフレームバッファを用意して、その中にデータを書き込み、その結果をUpdateLayeredWindow関数で転送して、画面に表示します。この部分はGDIに関係する処理となります。
この手順の中で、「その中にデータを書き込み」の部分ですが、レイヤードウィンドウの各ピクセルの条件において、乗算済みアルファであることを要求されるので、その点に注意しながら実装を行います。

さて、ピクセル列にまでなったデータを表示する方法はこれでわかりました。あとはこれをどう用意するかですが、これにはDirectXであれOpenGLであれ、一度書いたデータをメインメモリ上に読み直す、取得し直すことが必要になってきます。いくつかの方法はあるでしょうが、環境に合わせてパフォーマンスと相談しながら実装を検討することになるかと思います。手頃で簡単なものは、DirectXであればバックバッファをロックできるようにフラグを立ててしまうか、OpenGLならglReadPixelsの関数で読み出してしまうとか。
ただ、ラスタライズした結果を読み戻す処理になるのでそれなりに負荷がかかるのは仕方のないことでしょう。
(ただ、今はPCI-Express接続になっているし、昔のAGP接続に比べて転送がネックになることが少なくなってきている、との話もあるので実際に計測してみないことには何とも。)

結果

手元で実装したものの結果を貼っておきます。まずはWindows7で動かした物です。
背景にコードが若干見えると思いますが、これはOpenGLで実装しているものです。

一方で、これをWindows8で実行したものです。こちらはスマホのカメラで撮ったのでちょっと画質がイマイチです。

でも、どちらの場合でも描画した結果をデスクトップ上に半透明も有効にして重ねて描画できていることが確認できるかとおもいます。

 

追記

この透明ウィンドウ関連の話をされている、こちらhttp://umezawa.dyndns.info/wordpress/?p=3455 のページでもレイヤードウィンドウを使ってWindows8で期待通りに動いてくれる、とあります。 Windows8ではやはりこの方法できまり、という感じですかね。


Windows8でG41ドライバがない?


G41のWindows8用ドライバがない

実験機にWindows8をインストールしたのですが、OpenGL動くかな?と思って試してみたところ、GDI Generic状態になっていました。これはまともに動いていない!ということで、デバイスはG41だったのでそれにあわせてWindows7用のドライバを入れようとしました。しかしながら、これが失敗。最低条件を満たしていないという意のメッセージが出てきました。

Windows7用を使おうとしたのは、IntelのページでWindows8用が見つからなかったためです。

このような状態ではやりたいことのチェックが出来なかったので、RADEON HD 5450を追加して、Catalyst 12.10をインストールしてOpenGLが使えるのか?というチェックをしてみたいと思います。

(しかしこのままだとG41でWindows8はちょっと使えないかも。DirectXのみのサポートという感じになるのだろうか・・・。)
サポート範囲なら早く対応ドライバが出て欲しいところです。
→ どうやら旧チップはWindows同梱版でのみの対応となり、メーカーでは出さないようです。これによりOpenGL対応は絶望的。CPU内蔵のグラフィックスであればIntelさんが個別に出していくとのことです。

ソース: http://communities.intel.com/docs/DOC-19646

RADEON 5450にて

ドライバインストールして、とりあえず使えるのかどうかを見るために、OpenGLの初期化および各情報を取得してみました。
以下その中身。

デスクトップモードでアプリ動かしてみての結果ですが、使えそうです。


Windows8のブートローダー


Windows8を既に複数のOSが入ったディスクにインストールしてみたら、ブートローダーがさらに変わってた!

以前のようなコンソールの味気ない物に比べると、かなり見栄えがよくなったように思います。
ちなみにこの写真は、自分の動作検証用PCに入れてみたときのものです。検証用なのでいくつものOSを入れてます。

Windows7以降のVHDブートは便利ですね。できればVistaから対応して欲しかった・・・。


VisualStudio2012を入れての不具合?


VisualStudio を過去のバージョンをいくつかインストールしている人は自分だけでは無いと思います。
今回VisualStudio 2012をインストールした後で、過去のVisualStudioがエラーを吐くような状態になってしまい、ちょっと困っていた&解決策を見つけたので、メモがてら書いてみようと思います。

その今回困ったという現象が、VisualStudio 2012をインストールした後でVisualStudio 2010でのビルドがことごとく失敗するという物です。エラーメッセージとしては次のような物が出てきます。
LINK : fatal error LNK1123: COFF への変換中に障害が発生しました: ファイルが無効であるか、または壊れています。

そのときの画面の状態は以下のような感じです。

この現象が出てしまっている人はそれなりに居るようで、ほとんどの場合は次のような対処で問題を回避しているようです。

  • 埋め込みマニフェストをオフにする。
    (プロジェクトのプロパティで、マニフェストツール/入出力カテゴリで、埋め込みマニフェスト を”いいえ”にする)
  • あるいは、インクリメンタルリンクをオフにする
  • さらには、.rcのリソースファイルを削除(可能ならば)

でもこの問題の起こる原因は、VisualStudio 2010 にあり、VisualStudio 2012 の問題ではないということでした。問題解決のためには、VisualStudio 2010 の ServicePack (SP1)をインストールすることが必要でした。ここでSP1をインストールして再度同じプロジェクトをビルドしてみたところ、問題は起こらないようです。

問題が起こっている人は、VS10sp1-KB983509.exe (VisualStudio 2010 SP1)をインストールしてみてください。ちなみにVS2012を入れた後にインストールしても問題は起こらないようですよ。

まとめると、VisualStudioは複数インストールしてもいいが、その際に過去のバージョンのServicePackは事前に当てておきましょう、ということになるでしょうか。


透明ウィンドウの話 その2.1


昨日からわかったことが1つ。
どうやら HBITMAPに直接OpenGLから描画する方法は目的からずれることになりそう。

というのも、メモリDCのHBITMAPを対象とした描画だと OpenGLがソフトウェアエミュレーション状態になっているようでした。これじゃシェーダーを使ったものが扱えない。
おおよそ OpenGL 1.2とかその辺のレベルしか機能使えないんじゃないだろうか。

やはり一度描画してフレームバッファからメインメモリ上にピクセルを読み出して、LayeredWindowで描画する方法が一番現実的か。