「 OpenGL 」一覧

OpenGL @NVIDIAでのメモリ調査


NVIDIA Geforce で OpenGL を使った場合のシステムメモリの消費について調べてみましたが、サイズ可変でどのくらい消費量が変わるのか、というものでした。また API 実行の各タイミングで計測したのみで、時間経過を考慮していませんでした。

今回はサイズは固定し、 100 フレームに 1 回頂点バッファを確保して描画するという方法を試してみました。また描画に使用されない場合は処理をされないという可能性を除外するため、次フレーム以降は確保したバッファを用いての描画を行うようにしています。

確保のタイミングで、以前の確保時のデータとどのくらいメモリ使用量が変動するかをグラフ化したものが以下となります。
nvidia_opengl_temporary

結果

NVIDIA の場合、 OpenGL の作業用のメモリとして多めのメモリを使用する傾向にあるようです。しかしフレームの経過とともにその作業メモリを解放も行っているようです(そうでないと差分デルタが減った説明ができない)
多くの場合は、 VRAM 側に確保したメモリサイズと同じ程度のメモリを消費すると考えて良さそうです。


OpenGLでOut of memory とメモリの関係


細かな単位で OpenGL の頂点バッファをたくさん確保していたらこんなエラーに出会いました。ちなみにプログラムの実行タイミング次第では OpenGL で OUT_OF_MEMORY のエラー状態がちゃんと返りました。エラー返す前に異常系に落ちたという感じでしょうか。
nvidia_driver_oom

この症状が出るまでの様子を、使用システムメモリ、使用VRAM量、使用中の共有ビデオメモリ量、との値をグラフにしてみたものが以下となります。

nvidia_ogl_outofmemory_log

実験プログラムについて

Windows 7 x64 (16GB) の環境で、 Geforce GTX750 Ti (2GB) を装着しています。
300 描画フレーム間隔で、 128MB の単位で頂点バッファを確保するプログラムを動作させています。また、確保後は次のフレーム以降、バッファ先頭だけ使ってではありますが描画処理も行っています。

このようにしている背景としては、描画されないデータは処理されないのでは?という点と SwapBuffers が呼ばれない場合、作業メモリが解放されないのではという疑惑があるためです。そのために、描画ループを回しつつ、定期間隔で確保実験するに至りました。

この結果について

実際の搭載 VRAM 量までは順調に VRAM 側にリソースが確保されるようです。それがいっぱいになると共有メモリを使うようになっていくのが見えます。このとき、ドライバのなかでデータの整理が行われるのか、一時的に逆転送など行い共有メモリ量が増加&VRAM側をパージしている様子がうかがえました。
また VRAM に確保されようが、システム全体の使用メモリは増加していくのがわかります(黒線のグラフ)。使用した VRAM リソースの合計は約3GBでした。

実験その後

VRAM の断片化とかあるかなと考えて、バッファのサイズを 32MB に減らして再実験しました。このときアプリケーションもまた 32bit ですが、 LargeAddressAware をオンにして 4GB までのアドレス空間使えるようにしてみました。
 しかしながら、4GB まで使えるようになったというような結果を予想していましたが、3GB付近でエラーとなってしまいました。アプリケーションのアドレス空間の問題ではないようです。エラーが出た際のプロセスの状況を探ってみると、 1.3GB 程度のメモリ使用量となっており、このときプライベートヒープで割としめられていました。そのブロック単位も 32MB ほどなっており、どうやら VRAM リソースとして確保した何かのコピー(もしくは実体の待避?)かと思われます。これらの情報は VMMap を見れば詳細にわかります。

このような状況になってもちゃんと動き続ける今の Windows や NVIDIA のドライバはすごいなぁと関心もした次第です。


OpenGL API とメモリの消費について NVIDIA特別編


どうにも NVIDIA のメモリ消費について、メモリ消費しすぎな感じがあったので追加調査してみることにしました。

32MB VBOの場合(前回の結果)

状態 メモリ(MB) Dedicate(MB) 共有メモリ(MB)
初期化終了後 999.8 36 13
元データ準備 1031.7 36 13
glBufferData実行後 1114.7 68 32
元データ破棄 1082.7 68 32
初回描画後 1082.9 70 32

そこで今回はサイズを変化させた VBO 2つでどのように変化するか、しないかを見ていきたいと思います。

4MB VBO x2

状態 メモリ(MB) Dedicate(MB) 共有メモリ(MB)
初期化終了後 1023.0 36 14
元データ準備(4MB x2) 1037.9 36 14
glBufferData (1)実行後 1050.8 40 16
glBufferData (2)実行後 1054.8 44 24
元データ破棄 1043.4 44 24
初回描画後 1043.4 45 25

BufferData2回分の内部データとして 16.9MB を消費、定常的には 20.6 MB の消費という結果になりました。VRAM のリソースとしては 4MB x2 = 8MB = 44-36 と想定に合うサイズが使用されています

16MB VBO x2

状態 メモリ(MB) Dedicate(MB) 共有メモリ(MB)
初期化終了後 1019.1 36 14
元データ準備(16MB x2) 1048.2 36 14
glBufferData (1)実行後 52 32
glBufferData (2)実行後 1133.2 68 36
元データ破棄 1101.2 68 36
初回描画後 1101.4 70 37

BufferData2回分の内部データとして 85MB を消費、定常的には 82.2 MB ほどメモリを使用する結果になりました。 VRAM リソースとしては 70-36 = 34 MB となりおおよそ想定の範囲の結果に。

64MB VBO x2

状態 メモリ(MB) Dedicate(MB) 共有メモリ(MB)
初期化終了後 1023.9 36 14
元データ準備(64MB x2) 1156.0 36 14
glBufferData (1)実行後 1302.1 100 32
glBufferData (2)実行後 1433.2 164 36
元データ破棄 1304.9 164 36
初回描画後 1309.3 165 37

BufferData 2回分の内部データとして 277.2MB, 定常状態として 285MB の消費となっています。

まとめ

サイズを変更させて実験してみましたが、元データサイズの倍以上は消費されると考えて良さそうです。
これらの内容をグラフ化すると以下のようになります。なかなか作業メモリ(というかバッキングストア)分がひどいことに。

nvidia_ogl_working_memory_usage

追加

別視点から実験してみました。OpenGL @NVIDIAでのメモリ調査


OpenGL API とメモリの消費について AMD限定編


前回は NVIDIA, AMD と両者での差異を見るために同じコードで実験しました。今回は AMD ならではの OpenGL 拡張を用いてどう変化が起こるかを見てみたいと思います。

AMD_pinned_memory

拡張に AMD_pinned_memory というものがあります。これは GPU から物理メモリへのアクセスをさせるという拡張です。
こちらを用いると、以前実験したように中身を書き換えても再送コマンドの実行が必要なかったりします。

実験

pinned_memory の機能を用いて前回と同じように、頂点バッファ (VBO) を作成してみます。この際に使用メモリと使用 VRAM がどのように変化するかを観測します。
確保する頂点バッファは 32MB とし、今回もまたプロセスヒープの影響がないように、それと、アライメント調節の手間を減らすため OS からの直接ページのアロケートを使っています。

実験結果

実験は RADEON 5450, 7750 で行っていますが、傾向が異なることはなかったので、 5450 のほうを記載しています。また pinned memory の場合は元データ解放処理ができないのでその項目は除外しています.

状態 メモリ(MB) Dedicate(MB) 共有メモリ(MB)
初期化終了後 1193.7 44 19
元データ準備 1226.2 44 19
glBufferData実行後 1226.2 44 19
初回描画後 1220.1 47 52

32MB の VBO は Shared Memory の扱いとして処理されたようです。おおよそ 32.5 MB 消費されています。
注目すべきは glBufferData の内部で追加のメモリが要求されていないことです。前回 NVIDIA, AMD 双方で標準的な方法で glBufferData を実行の際にはこの部分で内部で勝手に追加のメモリを消費されていました。また初回の描画で初めてリソースが確保されるようです。

まとめ

pinned memory 拡張は暗黙のメモリ確保がないという点でよさそうに感じました。前回の時もそうでしたが、 AMD の場合には定常状態においては、元データサイズ分程度のシャドウコピーがどこかに存在するようです。 NVIDIA の場合と違い、バッファサイズ分を見積もっておけば良さそうなのでまだ制御がしやすそうです。


OpenGL API とメモリの消費について


使用中 VRAM の計測ができるようになったので、 OpenGL API を使ったときにどのようにメモリが使われていくのかを調べてみました。特に OpenGL の場合にはブラックボックス化された何かという印象が強く、暗黙に消費部分が多いのでは?と感じているためです。この記事エントリ読んでいる方も、そんな風に感じていたりするかもしれません。

環境

プログラム開発PCと調査対象PCを分離して、なるべく影響しないようにして計測しました。また折角なので NVIDIA Geforce, AMD Radeon のそれぞれで調べてみました。Intel HD Graphics はターゲット環境として用意できなかったので未計測です。
使用した OS は Windows 7 64bit で、各ボードでの最新ドライバを使用しました。

  • Geforce 9800 340.52
  • RADEON HD 5450/7750 Omega 14.12

ボードがちょっと古いですが、傾向はつかめるかなと思います。

免責事項

本調査結果の無断転載を禁止します。本調査はあくまで個人の趣味&好奇心から調べたものであり、結果および考察内容への責任は負いかねます。

実験内容

OpenGL を用いて頂点バッファ(VBO)を作成して、描画。このときに各フェーズでメインメモリと VRAM においてどのように消費されていくかを記録しました。基本的にはOpenGL 2.1世代で標準と思える機能のみを使用して、最近の OpenGL 4.4 系の拡張は未使用です。この状態で、バッファタイプは GL_STATIC_DRAW を設定して、データは VRAM へ配置されることを期待したプログラムを作成しました。
また頂点バッファのサイズは 32MB としました。そして転送元データはOSからの直接アロケートを使用し、プロセスのヒープによる影響を受けないよう工夫しています。

NVIDIA Geforce の場合

NVIDIA の場合には、メモリ使用量の変動幅が大きく、複数回の平均をとっています。

状態 メモリ(MB) Dedicate(MB) 共有メモリ(MB)
初期化終了後 999.8 36 13
元データ準備 1031.7 36 13
glBufferData実行後 1114.7 68 32
元データ破棄 1082.7 68 32
初回描画後 1082.9 70 32

上記のような結果になり、データを転送する際には元データ32MBに加えて glBufferData 内部でさらに追加の作業メモリを使用しているようです。それも単に元データのシャドウコピー 32MB という単位ではなく、約 83MB と2倍ちょっと使用しています。

AMD RADEON の場合

AMD の場合にはメモリ変動幅が NVIDIA に比べて低めでした。

状態 メモリ(MB) Dedicate(MB) 共有メモリ(MB)
初期化終了後 1195.7 44 19
元データ準備 1228.0 44 19
glBufferData実行後 1292.2 44 19
元データ破棄 1260.2 44 19
初回描画後 1229.9 79 20

上記のような結果になった. glBufferData 内部でのメモリ消費量は 64.2 MB となり、元データの倍ほどの作業メモリがあるようです。初回描画後は転送に使った作業メモリなどが解放されているためか、初期化終了後からバッファ分程度のメモリ増加にとどまっています。(1229.9-1195.7 = 34.2 MB)
また glBufferData 実行では VRAM が消費されていないことがわかりました。実際に処理されるのは初回描画される直前、もしくは、コマンドに積まれてGPUが実行するときまで遅延されるということでしょうか。

まとめ

NVIDIA にしろ AMD にしろ、 glBufferData で作業メモリを消費します。ここまではすでに予測している人も多かったと思います。しかし元データのコピー分だろうと見積もっていたはずです。今回の計測によりそれはハズレであることがわかりました。
少なくとも、元データ以上のサイズが消費され、今回の場合では2倍以上必要になるケースがあることがわかりました。
そして定常状態になった時、 AMD のほうは元データ分だけが消費されているのに対し、NVIDIA は glBufferData 実行直後からおおよそ変動しません。今回のケースでは 32MB の頂点バッファなのに、約 83MB もの領域を消費してしまっています。

メモリがシビアになるケースでは、このことを考慮してプログラムを作成した方がよいかもしれません。


OpenGL 4.5 が発表されました


Siggraph2014開催期間中にOpenGL 4.5が発表されました。
そしてNVIDIAのドライバは既に公開が始まっているということで、早速インストールしてエクステンションリストの確認をしてみました。
リストは後述しますが、手元のボードが 650Ti ということもあり無事に拡張が使えるようです。

OpenGL 4.5のスライドはこれ OPENGL 4.5 UPDATE FOR NVIDIA GPUSがわかりやすいと思います。

DSA(DirectStateAccess)がコア機能に入っただとかロバスト関連がコアに入ったとかは順当な格上げとして、
個人的に驚いたのはDX11エミュレーション機能が(いまさら)含まれてきた点です。
特に、ビューポートの原点が左下だったのが左上に指定できる機能やZの範囲を0,1にできるようになった点はとても驚きです。
これは近いうちに実コードで試してみたいと思います。おそらくこれでFBOテクスチャの上下反転問題も気にしなくてよくなりそうな予感です。
なおこれららの拡張は GL_ARB_clip_control というものなので、実は4.5まで待たずとも既にドライバで対応済みの可能性があるようです(4.3付近でエクステンションに並んでいたとか噂です)。

あとスライドでようやく記載として乗りましたが、Linux (X11)でのEGLサポートだそうです。

さてお待ちかねのエクステンションリストです。

GL_AMD_multi_draw_indirect
GL_AMD_seamless_cubemap_per_texture
GL_ARB_arrays_of_arrays
GL_ARB_base_instance
GL_ARB_bindless_texture
GL_ARB_blend_func_extended
GL_ARB_buffer_storage
GL_ARB_clear_buffer_object
GL_ARB_clear_texture
GL_ARB_clip_control
GL_ARB_color_buffer_float
GL_ARB_compatibility
GL_ARB_compressed_texture_pixel_storage
GL_ARB_conservative_depth
GL_ARB_compute_shader
GL_ARB_compute_variable_group_size
GL_ARB_conditional_render_inverted
GL_ARB_context_flush_control
GL_ARB_copy_buffer
GL_ARB_copy_image
GL_ARB_cull_distance
GL_ARB_debug_output
GL_ARB_depth_buffer_float
GL_ARB_depth_clamp
GL_ARB_depth_texture
GL_ARB_derivative_control
GL_ARB_direct_state_access
GL_ARB_draw_buffers
GL_ARB_draw_buffers_blend
GL_ARB_draw_indirect
GL_ARB_draw_elements_base_vertex
GL_ARB_draw_instanced
GL_ARB_enhanced_layouts
GL_ARB_ES2_compatibility
GL_ARB_ES3_compatibility
GL_ARB_ES3_1_compatibility
GL_ARB_explicit_attrib_location
GL_ARB_explicit_uniform_location
GL_ARB_fragment_coord_conventions
GL_ARB_fragment_layer_viewport
GL_ARB_fragment_program
GL_ARB_fragment_program_shadow
GL_ARB_fragment_shader
GL_ARB_framebuffer_no_attachments
GL_ARB_framebuffer_object
GL_ARB_framebuffer_sRGB
GL_ARB_geometry_shader4
GL_ARB_get_program_binary
GL_ARB_get_texture_sub_image
GL_ARB_gpu_shader5
GL_ARB_gpu_shader_fp64
GL_ARB_half_float_pixel
GL_ARB_half_float_vertex
GL_ARB_imaging
GL_ARB_indirect_parameters
GL_ARB_instanced_arrays
GL_ARB_internalformat_query
GL_ARB_internalformat_query2
GL_ARB_invalidate_subdata
GL_ARB_map_buffer_alignment
GL_ARB_map_buffer_range
GL_ARB_multi_bind
GL_ARB_multi_draw_indirect
GL_ARB_multisample
GL_ARB_multitexture
GL_ARB_occlusion_query
GL_ARB_occlusion_query2
GL_ARB_pipeline_statistics_query
GL_ARB_pixel_buffer_object
GL_ARB_point_parameters
GL_ARB_point_sprite
GL_ARB_program_interface_query
GL_ARB_provoking_vertex
GL_ARB_robust_buffer_access_behavior
GL_ARB_robustness
GL_ARB_sample_shading
GL_ARB_sampler_objects
GL_ARB_seamless_cube_map
GL_ARB_seamless_cubemap_per_texture
GL_ARB_separate_shader_objects
GL_ARB_shader_atomic_counters
GL_ARB_shader_bit_encoding
GL_ARB_shader_draw_parameters
GL_ARB_shader_group_vote
GL_ARB_shader_image_load_store
GL_ARB_shader_image_size
GL_ARB_shader_objects
GL_ARB_shader_precision
GL_ARB_query_buffer_object
GL_ARB_shader_storage_buffer_object
GL_ARB_shader_subroutine
GL_ARB_shader_texture_image_samples
GL_ARB_shader_texture_lod
GL_ARB_shading_language_100
GL_ARB_shading_language_420pack
GL_ARB_shading_language_include
GL_ARB_shading_language_packing
GL_ARB_shadow
GL_ARB_sparse_buffer
GL_ARB_sparse_texture
GL_ARB_stencil_texturing
GL_ARB_sync
GL_ARB_tessellation_shader
GL_ARB_texture_barrier
GL_ARB_texture_border_clamp
GL_ARB_texture_buffer_object
GL_ARB_texture_buffer_object_rgb32
GL_ARB_texture_buffer_range
GL_ARB_texture_compression
GL_ARB_texture_compression_bptc
GL_ARB_texture_compression_rgtc
GL_ARB_texture_cube_map
GL_ARB_texture_cube_map_array
GL_ARB_texture_env_add
GL_ARB_texture_env_combine
GL_ARB_texture_env_crossbar
GL_ARB_texture_env_dot3
GL_ARB_texture_float
GL_ARB_texture_gather
GL_ARB_texture_mirror_clamp_to_edge
GL_ARB_texture_mirrored_repeat
GL_ARB_texture_multisample
GL_ARB_texture_non_power_of_two
GL_ARB_texture_query_levels
GL_ARB_texture_query_lod
GL_ARB_texture_rectangle
GL_ARB_texture_rg
GL_ARB_texture_rgb10_a2ui
GL_ARB_texture_stencil8
GL_ARB_texture_storage
GL_ARB_texture_storage_multisample
GL_ARB_texture_swizzle
GL_ARB_texture_view
GL_ARB_timer_query
GL_ARB_transform_feedback2
GL_ARB_transform_feedback3
GL_ARB_transform_feedback_instanced
GL_ARB_transform_feedback_overflow_query
GL_ARB_transpose_matrix
GL_ARB_uniform_buffer_object
GL_ARB_vertex_array_bgra
GL_ARB_vertex_array_object
GL_ARB_vertex_attrib_64bit
GL_ARB_vertex_attrib_binding
GL_ARB_vertex_buffer_object
GL_ARB_vertex_program
GL_ARB_vertex_shader
GL_ARB_vertex_type_10f_11f_11f_rev
GL_ARB_vertex_type_2_10_10_10_rev
GL_ARB_viewport_array
GL_ARB_window_pos
GL_ATI_draw_buffers
GL_ATI_texture_float
GL_ATI_texture_mirror_once
GL_S3_s3tc
GL_EXT_texture_env_add
GL_EXT_abgr
GL_EXT_bgra
GL_EXT_bindable_uniform
GL_EXT_blend_color
GL_EXT_blend_equation_separate
GL_EXT_blend_func_separate
GL_EXT_blend_minmax
GL_EXT_blend_subtract
GL_EXT_compiled_vertex_array
GL_EXT_Cg_shader
GL_EXT_depth_bounds_test
GL_EXT_direct_state_access
GL_EXT_draw_buffers2
GL_EXT_draw_instanced
GL_EXT_draw_range_elements
GL_EXT_fog_coord
GL_EXT_framebuffer_blit
GL_EXT_framebuffer_multisample
GL_EXTX_framebuffer_mixed_formats
GL_EXT_framebuffer_multisample_blit_scaled
GL_EXT_framebuffer_object
GL_EXT_framebuffer_sRGB
GL_EXT_geometry_shader4
GL_EXT_gpu_program_parameters
GL_EXT_gpu_shader4
GL_EXT_multi_draw_arrays
GL_EXT_packed_depth_stencil
GL_EXT_packed_float
GL_EXT_packed_pixels
GL_EXT_pixel_buffer_object
GL_EXT_point_parameters
GL_EXT_provoking_vertex
GL_EXT_rescale_normal
GL_EXT_secondary_color
GL_EXT_separate_shader_objects
GL_EXT_separate_specular_color
GL_EXT_shader_image_load_store
GL_EXT_shader_integer_mix
GL_EXT_shadow_funcs
GL_EXT_stencil_two_side
GL_EXT_stencil_wrap
GL_EXT_texture3D
GL_EXT_texture_array
GL_EXT_texture_buffer_object
GL_EXT_texture_compression_dxt1
GL_EXT_texture_compression_latc
GL_EXT_texture_compression_rgtc
GL_EXT_texture_compression_s3tc
GL_EXT_texture_cube_map
GL_EXT_texture_edge_clamp
GL_EXT_texture_env_combine
GL_EXT_texture_env_dot3
GL_EXT_texture_filter_anisotropic
GL_EXT_texture_integer
GL_EXT_texture_lod
GL_EXT_texture_lod_bias
GL_EXT_texture_mirror_clamp
GL_EXT_texture_object
GL_EXT_texture_shared_exponent
GL_EXT_texture_sRGB
GL_EXT_texture_sRGB_decode
GL_EXT_texture_storage
GL_EXT_texture_swizzle
GL_EXT_timer_query
GL_EXT_transform_feedback2
GL_EXT_vertex_array
GL_EXT_vertex_array_bgra
GL_EXT_vertex_attrib_64bit
GL_EXT_import_sync_object
GL_IBM_rasterpos_clip
GL_IBM_texture_mirrored_repeat
GL_KHR_debug
GL_KHR_robust_buffer_access_behavior
GL_KHR_robustness
GL_KTX_buffer_region
GL_NV_bindless_multi_draw_indirect
GL_NV_bindless_multi_draw_indirect_count
GL_NV_bindless_texture
GL_NV_blend_equation_advanced
GL_NV_blend_square
GL_NV_compute_program5
GL_NV_conditional_render
GL_NV_copy_depth_to_color
GL_NV_copy_image
GL_NV_depth_buffer_float
GL_NV_depth_clamp
GL_NV_draw_texture
GL_NV_ES1_1_compatibility
GL_NV_ES3_1_compatibility
GL_NV_explicit_multisample
GL_NV_fence
GL_NV_float_buffer
GL_NV_fog_distance
GL_NV_fragment_program
GL_NV_fragment_program_option
GL_NV_fragment_program2
GL_NV_framebuffer_multisample_coverage
GL_NV_geometry_shader4
GL_NV_gpu_program4
GL_NV_gpu_program4_1
GL_NV_gpu_program5
GL_NV_gpu_program5_mem_extended
GL_NV_gpu_program_fp64
GL_NV_gpu_shader5
GL_NV_half_float
GL_NV_light_max_exponent
GL_NV_multisample_coverage
GL_NV_multisample_filter_hint
GL_NV_occlusion_query
GL_NV_packed_depth_stencil
GL_NV_parameter_buffer_object
GL_NV_parameter_buffer_object2
GL_NV_path_rendering
GL_NV_pixel_data_range
GL_NV_point_sprite
GL_NV_primitive_restart
GL_NV_register_combiners
GL_NV_register_combiners2
GL_NV_shader_atomic_counters
GL_NV_shader_atomic_float
GL_NV_shader_buffer_load
GL_NV_shader_storage_buffer_object
GL_NV_texgen_reflection
GL_NV_texture_barrier
GL_NV_texture_compression_vtc
GL_NV_texture_env_combine4
GL_NV_texture_expand_normal
GL_NV_texture_multisample
GL_NV_texture_rectangle
GL_NV_texture_shader
GL_NV_texture_shader2
GL_NV_texture_shader3
GL_NV_transform_feedback
GL_NV_transform_feedback2
GL_NV_vertex_array_range
GL_NV_vertex_array_range2
GL_NV_vertex_attrib_integer_64bit
GL_NV_vertex_buffer_unified_memory
GL_NV_vertex_program
GL_NV_vertex_program1_1
GL_NV_vertex_program2
GL_NV_vertex_program2_option
GL_NV_vertex_program3
GL_NVX_conditional_render
GL_NVX_gpu_memory_info
GL_NVX_nvenc_interop
GL_NV_shader_thread_group
GL_NV_shader_thread_shuffle
GL_KHR_blend_equation_advanced
GL_SGIS_generate_mipmap
GL_SGIS_texture_lod
GL_SGIX_depth_texture
GL_SGIX_shadow
GL_SUN_slice_accum
GL_WIN_swap_hint
WGL_EXT_swap_control

GALAXY Tab S 8.4を開発者目線で調べてみた


先日8月頭に発売された GALAXY Tab S 8.4(SM-T700 すなわちWiFiモデル) を調べてみました。基本的なことは各所のサイトで紹介されていると思いますので、ここではプログラマ目線で個人的に気になることを調べてみました。

初期状態でのOSは Android 4.4.2 です。
搭載しているプロセッサは、Samsung Exynos 5420 (Cortex-A7 x4 1.3GHz + A15 x4 1.9GHz) オクタコアです。
またこの中に入っている GPU は Mali-T628 となっています。
注意すべき点は、LTEモデルだとこのあたりが変わっていて、Snapdragon 800, Adreno330 となります。
画面解像度は、 2560×1600 WQXGA となっています。

個人的に、Snapdragon 800(Adreno330)は割と主流の流れなので、ここでは貴重なMali 6xx搭載の Wifiモデルを選ぶのがよさそうに思います。というか、GPUが他と違い珍しいので惹かれます。

さて、開発者として個人的に気にしている点が、このブログでも何度か登場しているNDKで開発してのネイティブデバッグができるか(ndk-gdbが使用可能であるか?)と、OpenGL ESの拡張はどのくらい、どんなものを備えているか、です。

ndk-gdb

サンプルのhello-jniでndk-gdbを起動させてみました。
結果はうまく動いていました。このあたりはさすがGalaxyシリーズと言ったところでしょうか。
この時点で開発用途には、現役で使えそうです。

OpenGL(ES)のExtension

この環境でエクステンションを取得してみました。GPUとOSからOpenGL ES 3.0だと思いますので期待できそうです。

GL Vendor = ARM
GL Renderer = Mali-T628

GL_EXT_debug_marker
GL_ARM_rgba8
GL_ARM_mali_shader_binary
GL_OES_depth24
GL_OES_depth_texture
GL_OES_depth_texture_cube_map
GL_OES_packed_depth_stencil
GL_OES_rgb8_rgba8
GL_EXT_read_format_bgra
GL_OES_compressed_paletted_texture
GL_OES_compressed_ETC1_RGB8_texture
GL_OES_standard_derivatives
GL_OES_EGL_image
GL_OES_EGL_image_external
GL_OES_EGL_sync
GL_OES_texture_npot
GL_OES_vertex_half_float
GL_OES_required_internalformat
GL_OES_vertex_array_object
GL_OES_mapbuffer
GL_EXT_texture_format_BGRA8888
GL_EXT_texture_rg
GL_EXT_texture_type_2_10_10_10_REV
GL_OES_fbo_render_mipmap
GL_OES_element_index_uint
GL_EXT_shadow_samplers
GL_KHR_texture_compression_astc_ldr
GL_KHR_debug
GL_EXT_occlusion_query_boolean
GL_EXT_blend_minmax
GL_EXT_discard_framebuffer
GL_OES_get_program_binary
GL_OES_texture_3D
GL_EXT_texture_storage
GL_EXT_multisampled_render_to_texture
GL_OES_surfaceless_context
GL_ARM_mali_program_binary

このような結果になりました。良くも悪くもARMのGPUといったところでしょうか。テクスチャ圧縮のASTCがサポートされています。残念なのは、float texture に関するサポートがないようにみえるところです。 GL_OES_texture_float などが全く見当たりません。
また、3.0からはマルチレンダーターゲットがサポートされ、ディファードシェーディングもできる!と巷で話がありますが、これではfloat値をレンダーターゲットにできず、そのテクニックが使用不可能です。そもそも OpenGL ES 3.0 で FBO に float テクスチャをセットできるかは “GL_EXT_color_buffer_float” という別の拡張をサポートしているかがキーですが。

こういった特徴から、素のOpenGL ES 3.0 に近いGPUであるといえそうです。どのくらい標準的に普及するかは謎なところですが、テスト機の1台としてはなかなかそさそうには感じています。


フルスペックOpenGLとGLES 3.0 とで比較してみた


EGL使ったものと通常のGLX(OpenGL)とで性能差を感じたので、実験してみたいと思います。
JetsonTK1でEGL使用した場合には、OpenGLES 3.0のコンテキストが使用されます。通常の初期化をGLX経由でした場合には OpenGL 4.4のコンテキストとなります。

これらで同じようにパフォーマンス有利に働くように、頂点バッファ(バッファオブジェクト)、頂点配列オブジェクト(VAO)らを用いて、トーラスを描画するプログラムを作成してみました。
これで平均のフレームレートを計測してみようと思います。

OpenGL 4.4 (GLX) の場合

GL_VERSION = 4.4.0 NVIDIA 19.3
GL_RENDERER = GK20A/AXI
36075 frames in 30.0 seconds = 1202.478 FPS
30672 frames in 30.0 seconds = 1022.298 FPS
31040 frames in 30.0 seconds = 1034.529 FPS
30626 frames in 30.0 seconds = 1020.849 FPS
31759 frames in 30.0 seconds = 1058.631 FPS

OpenGLES 3.0 (EGL) の場合

R:8, G:8, B:8, A:8, Depth:24
GL_VERSION = OpenGL ES 3.0 19.3
GL_RENDERER = GK20A/AXI
7293 frames in 30.0 seconds = 243.029 FPS
5748 frames in 30.0 seconds = 191.589 FPS
5741 frames in 30.0 seconds = 191.364 FPS
6332 frames in 30.0 seconds = 211.061 FPS
5015 frames in 30.0 seconds = 167.141 FPS
6324 frames in 30.0 seconds = 210.780 FPS
5463 frames in 30.0 seconds = 182.089 FPS

まとめ

通常GLのほうが、およそ5倍のFPSとなっていました。
あまりCPUで処理をしていないので、描画系に何か違いがありそうです。
EGLのほうではダブルバッファのフラグが見当たらなかったこともあって、設定など特にしていませんがこれが影響しているかも。
 またフレームレートが安定しないボードだったので、可変フレームレートで描画するようにしてみました。見かけの速度が一定となると、多少変動したところで見栄えが悪くなることはないのできれいに見えます。処理が遅くて安定しない環境では、可変フレームレートで描画するようなプログラムもいいなと感じました。

ubuntu-screenshot-torus


Jetson TK1でGLXでOpenGLを使ってみる


前回はEGLで組んでみましたが、折角普通のLinux,OpenGLが使えるボードということで、X11とGLXで前回同様のアプリケーションを作成してみようと思います。

NVIDIAでLinux OpenGL といえば、関数エントリが共有ライブラリに準備されていることで有名です。この組み込み用ではどうであるか確認してみます。

$ nm -Do /usr/lib/arm-linux-gnueabihf/tegra/libGL.so.1

## 一部抜粋  ###

/usr/lib/arm-linux-gnueabihf/tegra/libGL.so.1:00067478 T glActiveStencilFaceEXT
/usr/lib/arm-linux-gnueabihf/tegra/libGL.so.1:0005ec80 T glActiveTexture
/usr/lib/arm-linux-gnueabihf/tegra/libGL.so.1:00064688 T glActiveTextureARB
/usr/lib/arm-linux-gnueabihf/tegra/libGL.so.1:0006b58c T glActiveVaryingNV
/usr/lib/arm-linux-gnueabihf/tegra/libGL.so.1:0005d82c T glAlphaFunc
/usr/lib/arm-linux-gnueabihf/tegra/libGL.so.1:0006ed38 T glAlphaFuncx
/usr/lib/arm-linux-gnueabihf/tegra/libGL.so.1:000656d4 T glAreProgramsResidentNV
/usr/lib/arm-linux-gnueabihf/tegra/libGL.so.1:0005e4d8 T glAreTexturesResident
/usr/lib/arm-linux-gnueabihf/tegra/libGL.so.1:00064568 T glAreTexturesResidentEXT
/usr/lib/arm-linux-gnueabihf/tegra/libGL.so.1:0005e19c T glArrayElement
/usr/lib/arm-linux-gnueabihf/tegra/libGL.so.1:0006440c T glArrayElementEXT
/usr/lib/arm-linux-gnueabihf/tegra/libGL.so.1:0006aa24 T glAttachObjectARB
/usr/lib/arm-linux-gnueabihf/tegra/libGL.so.1:000603f8 T glAttachShader
/usr/lib/arm-linux-gnueabihf/tegra/libGL.so.1:0005b800 T glBegin
/usr/lib/arm-linux-gnueabihf/tegra/libGL.so.1:00061498 T glBeginConditionalRender
/usr/lib/arm-linux-gnueabihf/tegra/libGL.so.1:0006b154 T glBeginConditionalRenderNV
/usr/lib/arm-linux-gnueabihf/tegra/libGL.so.1:0006b10c T glBeginConditionalRenderNVX
/usr/lib/arm-linux-gnueabihf/tegra/libGL.so.1:00066d08 T glBeginOcclusionQueryNV

今回のボードでも前例通り各関数の実体が含まれるようです。
そこで、GLヘッダを読み込む前に、 GL_GLEXT_PROTOTYPES (1) を定義して extern宣言させた状態にしておきます。

早速プログラムを示します。

このプログラムを実行してみたのがこんな感じです。
Ubuntu-screenshot-glx

GL_RENDERER: GK20A/AXI
GL_VENDOR: NVIDIA Corporation
GL_VERSION: 4.4.0 NVIDIA 19.3
FPS: 1294.80
FPS: 1151.00
FPS: 1046.20
FPS: 1073.00
FPS: 1049.40
FPS: 1051.40
FPS: 987.60
FPS: 995.60
FPS: 1008.20
FPS: 1582.60

平均するとおよそ1000ちょいのFPSといったところでしょうか。前回のEGLに比べると多少パフォーマンスがよい傾向にありそうです。
VSyncをオフにしてみようと思ったのですが、 glXSwapIntervalEXT がこの環境では使用できず試してみることは出来ませんでした。コンテキストは予想通り最新の 4.4 が取得されました。

プログラムコードがglVertexAttribPointerでクライアント配列を渡している部分があったり、毎描画フレームで無駄な処理をしているところが多いので、もしかするとCPU側でバラツキの要因を持っているのかもしれません。


Jetson TK1のOpenGL Extensionリスト


NVIDIA GTC Japan 2014 に参加してきました。そしてJETSON TK1を触ることが出来たので、Tegra K1 の OpenGL Extension リストを取得してみました。噂通り標準のOpenGLサポートしていることがうかがえます。たくさんの拡張名が出てきました。
ついでに、NVIDIA拡張も色々と入っているようで…。

GL_AMD_multi_draw_indirect
GL_AMD_seamless_cubemap_per_texture
GL_ARB_arrays_of_arrays
GL_ARB_base_instance
GL_ARB_bindless_texture
GL_ARB_blend_func_extended
GL_ARB_buffer_storage
GL_ARB_clear_buffer_object
GL_ARB_clear_texture
GL_ARB_color_buffer_float
GL_ARB_compatibility
GL_ARB_compressed_texture_pixel_storage
GL_ARB_conservative_depth
GL_ARB_compute_shader
GL_ARB_compute_variable_group_size
GL_ARB_copy_buffer
GL_ARB_copy_image
GL_ARB_debug_output
GL_ARB_depth_buffer_float
GL_ARB_depth_clamp
GL_ARB_depth_texture
GL_ARB_draw_buffers
GL_ARB_draw_buffers_blend
GL_ARB_draw_indirect
GL_ARB_draw_elements_base_vertex
GL_ARB_draw_instanced
GL_ARB_enhanced_layouts
GL_ARB_ES2_compatibility
GL_ARB_ES3_compatibility
GL_ARB_explicit_attrib_location
GL_ARB_explicit_uniform_location
GL_ARB_fragment_coord_conventions
GL_ARB_fragment_layer_viewport
GL_ARB_fragment_program
GL_ARB_fragment_program_shadow
GL_ARB_fragment_shader
GL_ARB_framebuffer_no_attachments
GL_ARB_framebuffer_object
GL_ARB_framebuffer_sRGB
GL_ARB_geometry_shader4
GL_ARB_get_program_binary
GL_ARB_gpu_shader5
GL_ARB_gpu_shader_fp64
GL_ARB_half_float_pixel
GL_ARB_half_float_vertex
GL_ARB_imaging
GL_ARB_indirect_parameters
GL_ARB_instanced_arrays
GL_ARB_internalformat_query
GL_ARB_internalformat_query2
GL_ARB_invalidate_subdata
GL_ARB_map_buffer_alignment
GL_ARB_map_buffer_range
GL_ARB_multi_bind
GL_ARB_multi_draw_indirect
GL_ARB_multisample
GL_ARB_multitexture
GL_ARB_occlusion_query
GL_ARB_occlusion_query2
GL_ARB_pixel_buffer_object
GL_ARB_point_parameters
GL_ARB_point_sprite
GL_ARB_program_interface_query
GL_ARB_provoking_vertex
GL_ARB_robust_buffer_access_behavior
GL_ARB_robustness
GL_ARB_sample_shading
GL_ARB_sampler_objects
GL_ARB_seamless_cube_map
GL_ARB_seamless_cubemap_per_texture
GL_ARB_separate_shader_objects
GL_ARB_shader_atomic_counters
GL_ARB_shader_bit_encoding
GL_ARB_shader_draw_parameters
GL_ARB_shader_group_vote
GL_ARB_shader_image_load_store
GL_ARB_shader_image_size
GL_ARB_shader_objects
GL_ARB_shader_precision
GL_ARB_query_buffer_object
GL_ARB_shader_storage_buffer_object
GL_ARB_shader_subroutine
GL_ARB_shader_texture_lod
GL_ARB_shading_language_100
GL_ARB_shading_language_420pack
GL_ARB_shading_language_include
GL_ARB_shading_language_packing
GL_ARB_shadow
GL_ARB_stencil_texturing
GL_ARB_sync
GL_ARB_tessellation_shader
GL_ARB_texture_border_clamp
GL_ARB_texture_buffer_object
GL_ARB_texture_buffer_object_rgb32
GL_ARB_texture_buffer_range
GL_ARB_texture_compression
GL_ARB_texture_compression_bptc
GL_ARB_texture_compression_rgtc
GL_ARB_texture_cube_map
GL_ARB_texture_cube_map_array
GL_ARB_texture_env_add
GL_ARB_texture_env_combine
GL_ARB_texture_env_crossbar
GL_ARB_texture_env_dot3
GL_ARB_texture_float
GL_ARB_texture_gather
GL_ARB_texture_mirror_clamp_to_edge
GL_ARB_texture_mirrored_repeat
GL_ARB_texture_multisample
GL_ARB_texture_non_power_of_two
GL_ARB_texture_query_levels
GL_ARB_texture_query_lod
GL_ARB_texture_rectangle
GL_ARB_texture_rg
GL_ARB_texture_rgb10_a2ui
GL_ARB_texture_stencil8
GL_ARB_texture_storage
GL_ARB_texture_storage_multisample
GL_ARB_texture_swizzle
GL_ARB_texture_view
GL_ARB_timer_query
GL_ARB_transform_feedback2
GL_ARB_transform_feedback3
GL_ARB_transform_feedback_instanced
GL_ARB_transpose_matrix
GL_ARB_uniform_buffer_object
GL_ARB_vertex_array_bgra
GL_ARB_vertex_array_object
GL_ARB_vertex_attrib_64bit
GL_ARB_vertex_attrib_binding
GL_ARB_vertex_buffer_object
GL_ARB_vertex_program
GL_ARB_vertex_shader
GL_ARB_vertex_type_10f_11f_11f_rev
GL_ARB_vertex_type_2_10_10_10_rev
GL_ARB_viewport_array
GL_ARB_window_pos
GL_ATI_draw_buffers
GL_ATI_texture_float
GL_ATI_texture_mirror_once
GL_S3_s3tc
GL_EXT_texture_env_add
GL_EXT_abgr
GL_EXT_bgra
GL_EXT_bindable_uniform
GL_EXT_blend_color
GL_EXT_blend_equation_separate
GL_EXT_blend_func_separate
GL_EXT_blend_minmax
GL_EXT_blend_subtract
GL_EXT_compiled_vertex_array
GL_EXT_Cg_shader
GL_EXT_depth_bounds_test
GL_EXT_direct_state_access
GL_EXT_draw_buffers2
GL_EXT_draw_instanced
GL_EXT_draw_range_elements
GL_EXT_fog_coord
GL_EXT_framebuffer_blit
GL_EXT_framebuffer_multisample
GL_EXTX_framebuffer_mixed_formats
GL_EXT_framebuffer_multisample_blit_scaled
GL_EXT_framebuffer_object
GL_EXT_framebuffer_sRGB
GL_EXT_geometry_shader4
GL_EXT_gpu_program_parameters
GL_EXT_gpu_shader4
GL_EXT_multi_draw_arrays
GL_EXT_packed_depth_stencil
GL_EXT_packed_float
GL_EXT_packed_pixels
GL_EXT_pixel_buffer_object
GL_EXT_point_parameters
GL_EXT_provoking_vertex
GL_EXT_rescale_normal
GL_EXT_secondary_color
GL_EXT_separate_shader_objects
GL_EXT_separate_specular_color
GL_EXT_shader_image_load_store
GL_EXT_shader_integer_mix
GL_EXT_shadow_funcs
GL_EXT_stencil_two_side
GL_EXT_stencil_wrap
GL_EXT_texture3D
GL_EXT_texture_array
GL_EXT_texture_buffer_object
GL_EXT_texture_compression_dxt1
GL_EXT_texture_compression_latc
GL_EXT_texture_compression_rgtc
GL_EXT_texture_compression_s3tc
GL_EXT_texture_cube_map
GL_EXT_texture_edge_clamp
GL_EXT_texture_env_combine
GL_EXT_texture_env_dot3
GL_EXT_texture_filter_anisotropic
GL_EXT_texture_integer
GL_EXT_texture_lod
GL_EXT_texture_lod_bias
GL_EXT_texture_mirror_clamp
GL_EXT_texture_object
GL_EXT_texture_shared_exponent
GL_EXT_texture_sRGB
GL_EXT_texture_sRGB_decode
GL_EXT_texture_storage
GL_EXT_texture_swizzle
GL_EXT_timer_query
GL_EXT_transform_feedback2
GL_EXT_vertex_array
GL_EXT_vertex_array_bgra
GL_EXT_vertex_attrib_64bit
GL_EXT_x11_sync_object
GL_EXT_import_sync_object
GL_IBM_rasterpos_clip
GL_IBM_texture_mirrored_repeat
GL_KHR_debug
GL_KHR_texture_compression_astc_ldr
GL_KTX_buffer_region
GL_NV_bindless_multi_draw_indirect
GL_NV_bindless_texture
GL_NV_blend_equation_advanced
GL_NV_blend_equation_advanced_coherent
GL_NV_blend_square
GL_NV_compute_program5
GL_NV_conditional_render
GL_NV_copy_depth_to_color
GL_NV_copy_image
GL_NV_depth_buffer_float
GL_NV_depth_clamp
GL_NV_draw_texture
GL_NV_ES1_1_compatibility
GL_NV_explicit_multisample
GL_NV_fence
GL_NV_float_buffer
GL_NV_fog_distance
GL_NV_fragment_program
GL_NV_fragment_program_option
GL_NV_fragment_program2
GL_NV_framebuffer_multisample_coverage
GL_NV_geometry_shader4
GL_NV_gpu_program4
GL_NV_gpu_program4_1
GL_NV_gpu_program5
GL_NV_gpu_program5_mem_extended
GL_NV_gpu_program_fp64
GL_NV_gpu_shader5
GL_NV_half_float
GL_NV_light_max_exponent
GL_NV_multisample_coverage
GL_NV_multisample_filter_hint
GL_NV_occlusion_query
GL_NV_packed_depth_stencil
GL_NV_parameter_buffer_object
GL_NV_parameter_buffer_object2
GL_NV_path_rendering
GL_NV_pixel_data_range
GL_NV_point_sprite
GL_NV_primitive_restart
GL_NV_register_combiners
GL_NV_register_combiners2
GL_NV_shader_atomic_counters
GL_NV_shader_atomic_float
GL_NV_shader_buffer_load
GL_NV_shader_storage_buffer_object
GL_NV_texgen_reflection
GL_NV_texture_barrier
GL_NV_texture_compression_vtc
GL_NV_texture_env_combine4
GL_NV_texture_expand_normal
GL_NV_texture_multisample
GL_NV_texture_rectangle
GL_NV_texture_shader
GL_NV_texture_shader2
GL_NV_texture_shader3
GL_NV_transform_feedback
GL_NV_transform_feedback2
GL_NV_vdpau_interop
GL_NV_vertex_array_range
GL_NV_vertex_array_range2
GL_NV_vertex_attrib_integer_64bit
GL_NV_vertex_buffer_unified_memory
GL_NV_vertex_program
GL_NV_vertex_program1_1
GL_NV_vertex_program2
GL_NV_vertex_program2_option
GL_NV_vertex_program3
GL_NVX_conditional_render
GL_NVX_nvenc_interop
GL_NVX_shader_thread_group
GL_NVX_shader_thread_shuffle
GL_SGIS_generate_mipmap
GL_SGIS_texture_lod
GL_SGIX_depth_texture
GL_SGIX_shadow
GL_SUN_slice_accum

標準のOpenGLが動くためか、EGLのライブラリは v2 までのものしか含まれていない様子。
スペック上は GLES 3.0 サポートだったような気がしますが、これはまぁフルスペックの GL 4.4 内の GL_ARB_ES3_compatibility があるからこちらで対応よろしくってことでしょうか。