「 OpenGL 」一覧

OpenGLでMSAA


以前にDirectX11でMSAAというタイトルでテクスチャに対するMSAAをやってみましたが今回はそれのOpenGL版をやってみたいと思います。結果はこんな感じです。画像を切った貼ったしたので、ねつ造と言われてしまうかも・・・。

ogl-msaa-result

必要になるGL拡張

最近のOpenGL対応ボードならば問題ないと思いますが、OpenGL 2.1対応とか言われているボードでは下記の拡張が存在するか確認が必要です。

  • GL_EXT_framebuffer_blit
  • GL_EXT_framebuffer_multisample

これが NVの拡張であってもとりあえず使えるには使えると思います。

手順

まず、FBOが2つ必要になります。内訳としては次のような感じです。

  • MSAA描画するFramebufferObject(fbo)を作成する.
  • MSAA処理されたテクスチャを得るためのfboを作成する

描画時の流れはこんな感じです。

  1. MSAAのFBOをバインドして描画を行う
  2. MSAAのFBOから通常FBOへBlitFramebuffer
  3. 通常FBOの中にアタッチされているテクスチャを使用

このBlitFramebufferという処理がDirectXでいうところの Resolve関数になるかなと思います。
この処理によって通常のテクスチャとしてMSAAがかかった描画結果を使用することができます。
DirectX時はテクスチャに対して Resolve 出来ましたが GLではそれが直テクスチャ指定できないので一度FBOを作る必要があるようです。

プログラムコード

まずMSAAのFBOを作るところです。
MSAAの場合はテクスチャをアタッチするのではなくレンダーバッファをMSAA用のものを作成し、それを使用するようにします。

Resolve先のFBOを作成します。

描画の時の Resolve関連はこんな感じになります。

注意点など

glBlitFramebufferのバッファフラグは OR 結合で複数指定は出来ないようなので注意しましょう。
MSAAの動作確認時には、小さいテクスチャに対して描画してそれを拡大して貼るのがおすすめです。また、元々は水平垂直のポリゴンを回転させて斜めになるようにして描画したものを使用するとMSAAのかかり具合の確認がしやすいです。

確認の際にはテクスチャフィルタをポイントサンプルとなるようにしておくことや、ドットバイドットの表示をしておくことも忘れがち&やっちゃいがちなので注意しましょう。
(現にDX11のときにはうまくできたのに、GL版実装中で自分が↑をやっちゃいました)


XPERIA Z1 Compact (4.3)で GL Extension


XPERIA Z1 Compact (Android 4.3) にて GL Extension のリストを取得してみました。

OpenGL ES 3.0 V@53.0 AU@04.03.00.146.083 (CL@)
Qualcomm Adreno (TM) 330

GL_AMD_compressed_ATC_texture
GL_AMD_performance_monitor
GL_AMD_program_binary_Z400
GL_EXT_debug_label
GL_EXT_debug_marker
GL_EXT_discard_framebuffer
GL_EXT_robustness
GL_EXT_texture_format_BGRA8888
GL_EXT_texture_type_2_10_10_10_REV
GL_NV_fence
GL_OES_compressed_ETC1_RGB8_texture
GL_OES_depth_texture
GL_OES_depth24
GL_OES_EGL_image
GL_OES_EGL_image_external
GL_OES_element_index_uint
GL_OES_fbo_render_mipmap
GL_OES_fragment_precision_high
GL_OES_get_program_binary
GL_OES_packed_depth_stencil
GL_OES_depth_texture_cube_map
GL_OES_rgb8_rgba8
GL_OES_standard_derivatives
GL_OES_texture_3D
GL_OES_texture_float
GL_OES_texture_half_float
GL_OES_texture_half_float_linear
GL_OES_texture_npot
GL_OES_vertex_half_float
GL_OES_vertex_type_10_10_10_2
GL_OES_vertex_array_object
GL_QCOM_alpha_test
GL_QCOM_binning_control
GL_QCOM_driver_control
GL_QCOM_perfmon_global_mode
GL_QCOM_extended_get
GL_QCOM_extended_get2
GL_QCOM_tiled_rendering
GL_QCOM_writeonly_rendering
GL_EXT_sRGB
GL_EXT_texture_filter_anisotropic
GL_EXT_color_buffer_float
GL_EXT_color_buffer_half_float
GL_EXT_disjoint_timer_query

微妙にですが S4 のものと比べて extension の個数が減っています・・・。


GalaxyS4 Kitkat (4.4) で GL extension


GalaxyS4 について kitkatに更新してからGL Extensionのリストを取得してみました。

OpenGL ES 3.0 V@45.0 AU@  (CL@3869936)
Qualcomm  Adreno (TM) 320

GL_AMD_compressed_ATC_texture
GL_AMD_performance_monitor
GL_AMD_program_binary_Z400
GL_EXT_debug_label
GL_EXT_debug_marker
GL_EXT_discard_framebuffer
GL_EXT_robustness
GL_EXT_texture_format_BGRA8888
GL_EXT_texture_type_2_10_10_10_REV
GL_NV_fence
GL_OES_compressed_ETC1_RGB8_texture
GL_OES_depth_texture
GL_OES_depth24
GL_OES_EGL_image
GL_OES_EGL_image_external
GL_OES_element_index_uint
GL_OES_fbo_render_mipmap
GL_OES_fragment_precision_high
GL_OES_get_program_binary
GL_OES_packed_depth_stencil
GL_OES_depth_texture_cube_map
GL_OES_rgb8_rgba8
GL_OES_standard_derivatives
GL_OES_texture_3D
GL_OES_texture_float
GL_OES_texture_half_float
GL_OES_texture_half_float_linear
GL_OES_texture_npot
GL_OES_vertex_half_float
GL_OES_vertex_type_10_10_10_2
GL_OES_vertex_array_object
GL_QCOM_alpha_test
GL_QCOM_binning_control
GL_QCOM_driver_control
GL_QCOM_perfmon_global_mode
GL_QCOM_extended_get
GL_QCOM_extended_get2
GL_QCOM_tiled_rendering
GL_QCOM_writeonly_rendering
GL_EXT_sRGB
GL_EXT_sRGB_write_control
GL_EXT_texture_sRGB_decode
GL_EXT_texture_filter_anisotropic
GL_EXT_multisampled_render_to_texture
GL_EXT_color_buffer_float
GL_EXT_color_buffer_half_float
GL_EXT_disjoint_timer_query

Ubuntuで EGL使えるか?


先日NVIDIAのドライバをインストールした Ubuntu ですが、なんとEGLやGLES2についてのライブラリをもっているようでした。(331.20ではダメだった・・・)

これは X 上で EGL & GLES2が使えるんじゃないかと思い試してみることにしました。

続きを読む


OpenGL の ComputeShader


今回はようやくOpenGLでのComputeShaderを扱ってみます。意外とOpenGLでのComputeShaderって話題になっていないようで、ワクワクしています。

手順

VertexShader, FragmentShader などを生成するように、ComputeShader を生成します。ComputeShaderもまたGLSLで記述するので、今までのシェーダーを生成するような感じでプログラムを記述します。ひとつ違うのは出力する箇所でしょうか、今まではピクセルに出力する感じで out 変数に入れていましたが、ComputeShader では imageXXX というサンプラーっぽい型のuniform変数に値を書き込んでいく感じになります。

C++側のコードは以下のような感じになります。通常のシェーダーと同じようにGLSLをコンパイルして ShaderProgram を作成します。

ComputeShaderからの結果を格納するためのテクスチャを用意しておきます。
このときいつも通りにテクスチャを用意した後、下記のAPIにて設定しておきます。これが Shader Image load store 拡張のAPIになります。これによりテクスチャをUAV化というか書き込み先として利用できるようになります。

通常のメインループにおいては、以下のような感じでコンピュートシェーダーを実行し、結果をテクスチャとして利用して貼り付けています。コンピュートシェーダーの実行は glDispatchCompute で行います。

GL_computeshader

今回は gl_GlobalInvocationID を使って処理しているだけですが、各処理ブロックを識別するのに使える変数がもっとたくさんあります。これらの意味を理解して適切に使っていかないと折角の演算力を生かし切ることができません。
CUDAやDirectComputeのほうでもこれらのパラメータに相当するものがあるようなので、またそれらを試してみたときにどういう対応なのか、どの部分を指し示すのかをまとめてみたいと思います。


OpenGLでComputeShaderを使う前に


OpenGLでComputeShader を使う前に実は知っておくべきことが意外とある、ということで今回はその内容についてです。

ComputeShader は演算のためのシェーダーです。その演算内容をどこかに書き出さなければなりません。OpenGLでは、2種類ほどあるようでそれが以下の物に該当するようです。

  • Shader Image load store
  • Shader Storage buffer object (ssbo)

前者はOpenGL 4.2で取り入れられたもので、後者は 4.3 ではいったもののようです。

Shader Image load storeは、フォーマットが決められた出力先へ記録することができるようです。たとえば float4つの値を2次元テクスチャに記録するとか、そんな感じです。DirectXのほうはよくわかっていませんが RWTexture2D とかそういう系列のものに近いんじゃないかと思います。

Shader Storage buffer object (SSBOと略するらしい) は、フォーマットは比較的自由でGLのシェーダーの中からは Read/WriteできるUniform Buffer Object(UBO)のようなものとしてアクセスができる物のようです。DirectX11のほうでいえば、RWStructuredBuffer に相当するといったところでしょうか。

一方DirectXのRWByteAddressBuffer に相当する物はちょっとわかりませんでした。あまり一般的に使われる物ではない、という位置づけでOpenGLでは入っていないのでしょうか。知っている人がいたら教えて下さい。

言い忘れていましたが、これらUAV相当ということでひとまとめにしてもいいのかもしれません。


GLSLのシェーダーリフレクション (2)


OpenGL (GLSL) のユニフォームブロックでのシェーダーリフレクションを試してみました。
ここで使った vertexShader, fragment shaderは以下のようなものです。

これらのシェーダーについて情報を出してみるとこのような感じになりました。
まずはシェーダーユニフォームの一覧.

ユニフォームブロックの中身のメンバには、ロケーションIDは振られていないことが確認できます。ユニフォームのインデックスは振られており、情報はこちら軽油で取得できるようです。
そして、ユニフォームブロックに関して情報を取得してみます。

ユニフォームブロック内でのシェーダー定数のオフセットが取得できました。
ユニフォームブロック内に構造体を配置しても、従来のシェーダー定数の場合と変わらないような名前でオフセットやデータ型を取得できることがわかります。

std140 とかレイアウト指定をしない場合、シェーダーによって(環境によって?)定数の位置が変わりそうです。
そのため、UBOを複数のシェーダーで使い回すのは難しそうです。この場合結局定数毎に書き込む位置を見てバッファ内のデータ更新という手続きをとるので、あまりUBOによる描画効率化に繋がらないように感じます。

ユニフォームブロック内の定数であっても GL_ACTIVE_UNIFORMS にて有効なユニフォーム変数としてカウントされていることに少々驚きました。ただしユニフォームブロック内の変数名からは有効なロケーションが取得できません。ユニフォームブロック内の変数についてはロケーション=-1となっているようです。


GLSLのシェーダーリフレクション


GLSLいじりの過程で、シェーダーリフレクションっぽいことをやってみたのでその調査結果です。

OpenGLでは別に他のライブラリに依存することなく、シェーダーリフレクションの機能を持っています。普段ではuniform変数のロケーション情報を名前から取得しているかと思いますが、その延長上でいろいろな情報をとれるようになっています。

そこで次のようなシェーダープログラム(抜粋)で、どのように情報がとれてくるか試してみました。

結果はこんな感じでした。ドライバの状態によっては別の結果を返してきそうな気配も・・・。AMDやIntelで試してみたいところです。

NVIDIA 331.65 のドライバの結果。

ここからわかることは、次のような感じかと。

  • 配列の場合には [0] とか付加されて返ってくる. (NVIDIAの場合限定かも?)
  • サイズとして配列のサイズ(長さ)が返ってくる
  • 構造体メンバの場合は、構造体変数名が間に挟まっている
  • 構造体だからといって、1つのuniform location に集約されるわけではない

GLSLは構造体使えるから、お?とおもっていたのですが、実際のところは内部のメンバに対して1つずつロケーションが与えられているようです。

次回には、Uniform Blockでのリフレクションのチェックをしてみたいと思います。


最近のGLSLでは色々廃止になってる…


最近のGLSLでは結構廃止になっている部分が多い。ちょっと踏んだところをメモとして残しておきます。

varying, attribute 廃止

これは割と定番ですが、最近のGLSLでは廃止になってます。
代わりに in/out を使用して、シェーダーに対する入力、出力を記述していきます。

その割に、頂点入力としては glGetAttribLocation 使用して、頂点シェーダーの in で書かれた変数を取得するなど、APIとしてはアンバランスに感じます。

textureCUBEの廃止

キューブマップからのテクセルのサンプルで textureCUBEを使用していた部分が最近のものではコンパイルエラーとなるようです。自分の環境では以下のエラーが出力されました。

ではキューブマップからのフェッチはどうするのかというと、以下のような感じで良さそうです。

どうやらtextureCubeだけが廃止扱いではないようです。続く。

texture1D廃止

texture1D, texture1DProj, texture1DLod, texture1DProjLod が廃止になっています。代わりに texture 関数を使えとのことです。

texture2D廃止

texture2D, texture2DProj, texure2DLod, texture2DProjLod が廃止になっています。代わりに texture 関数を使えとのことです。

texture3D廃止

texture3D, texture3DProj, texture3DLod, texture3DProjLod が廃止になっています。代わりに texture 関数を使えとのことです。

shadow系の廃止

shadow1D, shadow2D, shadow1DProj, shadow2DProj, shadow1DLod, shadow2DLod, shadow1DProjLod, shadow2DProjLod が廃止になっています。

デフォルトのグローバルで使えた各変数

これらのものが廃止扱いになっています。あまり使うことはなかったかもしれませんが、たまに使われているケースがあってこのことを知らないと悩みます。
gl_FragColor もまた廃止なので注意が必要です。


Texture Buffer Object (TBO)について


どうやらこれはTextureBuffer-Objectではなく、Texture-BufferObject という意味であるとのことです。そしてこれは、VBO(Vertex buffer object)のバッファデータをテクスチャとして利用するための仕組みであるとのことです。

テクスチャのデータは glTexImage系の関数で準備をしますが、TBOについてはあくまでバッファオブジェクトなので glBufferData などでデータを転送します。そして転送後はこのバッファをテクスチャデータの供給元とすべく、テクスチャのIDとの関連付けを行います。これらの作業をコードで示すと以下のような感じになります。

注意点としては、関連付けるテクスチャを GL_TEXTURE_2Dではなく GL_TEXTURE_BUFFER にバインドする点でしょうか。

TBOの特徴

サンプラ不要でデータにアクセスすることが可能となる点が挙げられます。
通常の2Dテクスチャと違って samplerBuffer を使用することや texelFetch でインデックス指定でアクセスすることも違っています。TBOは1次元配列のように使うという感じでしょうか。

個人的に思うのはこれはジオメトリシェーダーからのストリームアウト(Transform feedback)での結果はVBOに書かれます。これをテクスチャとして使いたいケースでもあるのかなと思いました。
あるいは、バッファオブジェクトを作成して何らかのデータを格納しておきたいケースがあるとか。このデータをテクスチャとして参照することで、リードオンリーではあるものの割と大きなテーブルとして利用可能である、とか。