月別アーカイブ: 2015年7月

Direct3D12 ROV を試してみる (3) 半透明ソートと Intel HD Graphics

DirectX12 / DirectX11.3 の ROV のテストです。
前回はこちら→ 「Direct3D12 ROV を試してみる (2) Depth Test と半透明ソート

やっと Intel HD Graphics でも動くようになりました。

dx12_rov_suzanne01.png

↑Celeron N3150 Braswell Intel HD Graphics (Gen8) 使用

Intel HD Graphcis で問題だったのは PipelineState 生成時にエラーになることです。いろいろ試した結果 Shader に原因があることが判明。理由はよくわかっていませんが if 文中の代入を無くし、同等の加算に置き換えることで回避出来ました。GeForce では元のままで問題ありませんでした。

zstack_x= pz;
stack_x= color_enc;

↓ Intel HD Graphics

zstack_x*= 1e-32f;
zstack_x+= pz;
stack_x*= 0;
stack_x+= color_enc;

あとは Typed UAV を使わずに展開しています。シェーダーは下記の通り。

// hlsl
struct PS_OUT   {
    float4  Color   :   SV_Target;
};

RasterizerOrderedTexture2D    UColor  : register( u0 );
RasterizerOrderedTexture2D   UDepth  : register( u1 );
RasterizerOrderedTexture2D    UStack  : register( u2 );
RasterizerOrderedTexture2D   UZStack : register( u3 );

PS_OUT  pmain( VS_OUT pin, float4 pos : SV_Position )
{
    PS_OUT  pout;
    float3  Light= normalize( float3( 0.0f, -0.5f, -1.0f ) );
    float3  normal= normalize( pin.Normal );

    float3  cp= normalize( float3(0.0f, 0.0f, -120.0f) - pin.WPos.xyz );
    float3  hv= normalize( cp.xyz + Light.xyz );
    float3  specular= pow( saturate( dot( hv, normal ) ), 82.0f ) * saturate( Color.xyz + float3(0.6f, 0.6f, 0.6f) );
    float   diffuse= saturate( max( dot( normal, Light ), 0.0f ) + 0.2f );

    float4  color;
    color.xyz= Color.xyz * diffuse + specular;
    color.w= Color.w;
    pout.Color= color;

    float   pz= pos.z;
    uint2   addr2x= uint2( pos.xy );
    addr2x.x*= 4;
    uint2   addr2y= uint2( addr2x.x + 1, addr2x.y );
    uint2   addr2z= uint2( addr2x.x + 2, addr2x.y );
    uint2   addr2w= uint2( addr2x.x + 3, addr2x.y );

    uint    color_enc= EncodeColor( color );
    uint    stack_x= UStack[addr2x];
    uint    stack_y= UStack[addr2y];
    uint    stack_z= UStack[addr2z];
    uint    stack_w= UStack[addr2w];
    float   zstack_x= UZStack[addr2x];
    float   zstack_y= UZStack[addr2y];
    float   zstack_z= UZStack[addr2z];
    float   zstack_w= UZStack[addr2w];
    if( pz < zstack_w ){
        zstack_w*= 1e-32f;
        zstack_w+= pz;
        stack_w*= 0;
        stack_w+= color_enc;
    }
    if( pz < zstack_z ){
        zstack_w= zstack_z;
        stack_w= stack_z;
        zstack_z*= 1e-32f;
        zstack_z+= pz;
        stack_z*= 0;
        stack_z+= color_enc;
    }
    if( pz < zstack_y ){
        zstack_z= zstack_y;
        stack_z= stack_y;
        zstack_y*= 1e-32f;
        zstack_y+= pz;
        stack_y*= 0;
        stack_y+= color_enc;
    }
    if( pz < zstack_x ){
        zstack_y= zstack_x;
        stack_y= stack_x;
        zstack_x*= 1e-32f;
        zstack_x+= pz;
        stack_x*= 0;
        stack_x+= color_enc;
    }
    UStack[addr2x]= stack_x;
    UStack[addr2y]= stack_y;
    UStack[addr2z]= stack_z;
    UStack[addr2w]= stack_w;
    UZStack[addr2x]= zstack_x;
    UZStack[addr2y]= zstack_y;
    UZStack[addr2z]= zstack_z;
    UZStack[addr2w]= zstack_w;

    return  pout;
}

関連エントリ
Direct3D12 ROV を試してみる (2) Depth Test と半透明ソート
Direct3D12 ROV (Rasterizer Order View) を試してみる
3D 低レベル API の違い Direct3D 12/Metal
Direct3D 12 GeForce GTX970 は FeatureLevel 12_1 対応、Resource Bind/Heap Tier は低い
3D 低レベル API の現状 Direct3D 12/Metal

Direct3D12 ROV を試してみる (2) Depth Test と半透明ソート

DirectX12 / DirectX11.3 の ROV のテスト続きです。
前回はこちら→ 「Direct3D12 ROV (Rasterizer Order View) を試してみる

ROV は自分で Depth Test できます。
R32_FLOAT の UAV を 1枚追加しています。

RasterizerOrderedTexture2D UBuffer0 : register( u0 ); // R8G8B8A8
RasterizerOrderedTexture2D  UBuffer1 : register( u1 ); // R32F

PS_OUT pmain( VS_OUT pin, float4 pos : SV_Position )
{
	float	diffuse= max( dot( pin.Normal, Light ), 0.0f ) + 0.2f;
    float4  color= Color * diffuse;
	uint2	addr= uint2( pos.xy );

	float	depth= UBuffer1[addr];
	if( pos.z <= depth ){
		UBuffer0[addr]= color;    // color書き込み
		UBuffer1[addr]= pos.z;    // depth書き込み
	}

    PS_OUT  pout;
    pout.Color= color;
    return  pout;
}

下記は UAV (UBuffer0) の結果です。(Geforce GTX960)

↓ROV 無し, Depth Test 無し
dx12_rov_teapot_01.png

↓ROV あり, Depth Test 無し
dx12_rov_teapot_02.png

↓ROV 無し, Depth Test あり
dx12_rov_teapot_03.png

↓ROV あり, Depth Test あり
dx12_rov_teapot_04.png

ROV の目的とも言える半透明ソートも試してみました。

dx12_rov_teapot_05.png

力技ですがバッファ固定で 4レイヤーまで。一旦 UAV にカラーを保存して 2 pass 目で Blend しています。fp32 Blend を使った方法と違い手前の 4枚を選択できるので破綻が少なくなっています。

関連エントリ
Direct3D12 ROV (Rasterizer Order View) を試してみる
3D 低レベル API の違い Direct3D 12/Metal
Direct3D 12 GeForce GTX970 は FeatureLevel 12_1 対応、Resource Bind/Heap Tier は低い
3D 低レベル API の現状 Direct3D 12/Metal

Direct3D12 ROV (Rasterizer Order View) を試してみる

DirectX12 / DirectX11.3 の新機能である ROV (Rasterizer Order View) を試してみました。対応している GPU は下記の通り。新 Maxwell (GTX900) と HD Graphics 系です。ただし Intel HD Graphics は Typed UAV がありません。両方対応しているのは Maxwell 2 だけとなっています。

                          ROV   TypedUAV
----------------------------------------------------
GeForce  Maxwell 2         Y       Y      (GTX900)
GeForce  Maxwell 1         N       Y      (GTX750)
GeForce  Kepler            N       N
RADEON GCN 1.1             N       Y
RADEON GCN 1.0             N       Y
Intel HD Graphics Gen8     Y       N      (Broadwell)
Intel HD Graphics Gen7.5   Y       N      (Haswell)

より詳しい機能表は下記のページに掲載しています。

Direct3D 12 (DirectX 12) Windows 詳細

Shader は複数の Unit で同時に走るので、実行順番は保証されずバッファアクセスは競合します。しかしながら Pixel の出力自体は順序が保証されており結果は一定です。Blend や Depth/Stencil Test では同一の Draw Call で重ね書きしても正しい値で評価されます。
シェーダー内で任意に読み書きできる UAV はこのルールが適用されませんでした。ROV を使うと UAV の読み書きの整合性が取れるようになります。

(1) が通常の RenderTarget への描画です。
(2) は RenderTarget への書き込みと全く同じものを UAV にも書き込んでいます。擬似 MRT

// (1) hlsl
Texture2D       ColorMap0   : register( t0 );
SamplerState    Sampler0    : register( s0 );

struct PS_OUT {
    float4  Color   : SV_Target;
};

PS_OUT pmain( VS_OUT pin )
{
    PS_OUT  pout;
    float4  color_map= ColorMap0.Sample( Sampler0, pin.Texcoord );
    pout.Color= color_map;
    return  pout;
}
// (2) hlsl
Texture2D           ColorMap0   : register( t0 );
SamplerState        Sampler0    : register( s0 );
RWTexture2D UAVBuffer0  : register( u0 );

PS_OUT pmain( VS_OUT pin, float4 pos : SV_Position )
{
    PS_OUT  pout;
    float4  color_map= ColorMap0.Sample( Sampler0, pin.Texcoord );
    pout.Color= color_map;

    UAVBuffer0[ uint2(pos.xy) ]= color_map;
    return  pout;
}

dx12_rov_01.png

↑(2) の結果を 2つ並べて表示したのがこちらです。左が RTV (RenderTarget), 右が UAV です。使用したのは GeForce GTX960 (Maxwell2)。

↑右の UAV では重ね合わせに問題が生じています。並列度が上がるためプリミティブが小さい方が発生しやすいです。
これを ROV に変更したのが (3) です。

// (3) hlsl
Texture2D           ColorMap0   : register( t0 );
SamplerState        Sampler0    : register( s0 );
RasterizerOrderedTexture2D    UAVBuffer0  : register( u0 );

PS_OUT pmain( VS_OUT pin, float4 pos : SV_Position )
{
    PS_OUT  pout;
    float4  color_map= ColorMap0.Sample( Sampler0, pin.Texcoord );
    pout.Color= color_map;

    UAVBuffer0[ uint2(pos.xy) ]= color_map;
    return  pout;
}

dx12_rov_02.png

↑ (3) の結果です。左が RTV (RenderTarget), 右が ROV。
ROV では重ね合わせが正しく行われ RTV と見た目が同一になりました。

さらに ROV では、RenderTarget と違って値をシェーダーで読むことができます。
(4) は Shader 内で Blend したもの。

// (4) hlsl
Texture2D           ColorMap0   : register( t0 );
SamplerState        Sampler0    : register( s0 );
RasterizerOrderedTexture2D   UAVBuffer0  : register( u0 );

PS_OUT pmain( VS_OUT pin, float4 pos : SV_Position )
{
    PS_OUT  pout;
    float4  color_map= ColorMap0.Sample( Sampler0, pin.Texcoord );
    pout.Color= color_map;

    float4  prev_color= UAVBuffer0[uint2(pos.xy)];
    UAVBuffer0[uint2(pos.xy)]= prev_color * 0.7f + map * 0.7f;
    return  pout;
}

dx12_rov_03.png

↑(4) の結果。左が RTV, 右が ROV の半透明合成

ROV はかなり自由度が高く MRT の制限がほぼ無くなったような印象です。パフォーマンス等は調べてませんがかなり応用が効きそうです。

なお Intel HD Graphics では Typed UAV が使えないので、今まで使用してきた下記のコードが動きません。

RWTexture2D UAVBuffer0  : register( u0 );
RasterizerOrderedTexture2D    UAVBuffer0  : register( u0 );

一応対応してみました。UAV を R32_UINT として読み込みます。

// cpp HD Graphics
#define USE_TYPED_UAV 0
    D3D12_RESOURCE_DESC res_desc;
    flatlib::memory::MemClear( res_desc );
    res_desc.Dimension= D3D12_RESOURCE_DIMENSION_TEXTURE2D;
    res_desc.Alignment= 0;
    res_desc.Width= width;
    res_desc.Height= height;
    res_desc.DepthOrArraySize= 1;
    res_desc.MipLevels= 1;
#if USE_TYPED_UAV
    res_desc.Format= DXGI_FORMAT_R8G8B8A8_UNORM;
#else
    res_desc.Format= DXGI_FORMAT_R8G8B8A8_TYPELESS;
#endif
    res_desc.SampleDesc.Count= 1;
    res_desc.Layout= D3D12_TEXTURE_LAYOUT_UNKNOWN;
    res_desc.Flags= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS|D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;

    D3D12_HEAP_PROPERTIES   heap;
    flatlib::memory::MemClear( heap );
    heap.Type= D3D12_HEAP_TYPE_DEFAULT;
    heap.CPUPageProperty= D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
    heap.MemoryPoolPreference= D3D12_MEMORY_POOL_UNKNOWN;

    D3D12_CLEAR_VALUE   clear_value;
    flatlib::memory::MemClear( clear_value );
    clear_value.Format= DXGI_FORMAT_R8G8B8A8_UNORM;

    iD3DDevice->CreateCommittedResource(
            &heap,
            D3D12_HEAP_FLAG_NONE,
            &res_desc,
            D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
            &clear_value, IID_PPV_ARGS(&iUAVTexture0) );

    D3D12_UNORDERED_ACCESS_VIEW_DESC    uav_desc;
    flatlib::memory::MemClear( uav_desc );
#if USE_TYPED_UAV
    uav_desc.Format= DXGI_FORMAT_R8G8B8A8_UNORM;
#else
    uav_desc.Format= DXGI_FORMAT_R32_UINT;
#endif
    uav_desc.ViewDimension= D3D12_UAV_DIMENSION_TEXTURE2D;

    UINT    uav_descriptor_size= iD3DDevice->GetDescriptorHandleIncrementSize( D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV );
    D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle= iHeapUAV->GetCPUDescriptorHandleForHeapStart();
    cpu_handle.ptr+= uav_descriptor_size * (UAV_DYNAMIC_COUNT);
    iD3DDevice->CreateUnorderedAccessView( iUAVTexture0, nullptr, &uav_desc, cpu_handle );

シェーダーは下記の通り。

// hlsl (HD Graphics)
//RWTexture2D    UAVBuffer0    : register( u0 );
RasterizerOrderedTexture2D   UAVBuffer0  : register( u0 );

PS_OUT  pmain( VS_OUT pin, float4 pos : SV_Position )
{
    PS_OUT  pout;
    float4  color_map= TextureMap0.Sample( Sampler0, pin.Texcoord );
    pout.Color= color_map;

    uint    fetch= UAVBuffer0[ uint2(pos.xy) ];
    float4  prev_color;
    prev_color.x= ((fetch>> 0) & 255) * (1.0f/255.0f);
    prev_color.y= ((fetch>> 8) & 255) * (1.0f/255.0f);
    prev_color.z= ((fetch>>16) & 255) * (1.0f/255.0f);
    prev_color.w= ((fetch>>24) & 255) * (1.0f/255.0f);
    float4  color= saturate( prev_color * 0.7f + color_map * 0.7f );
    UAVBuffer0[ uint2(pos.xy) ]= ((uint)(color.x * 255.0f) << 0)
                                |((uint)(color.y * 255.0f) << 8)
                                |((uint)(color.z * 255.0f) <<16)
                                |((uint)(color.w * 255.0f) <<24);
    return  pout;
}

これで Intel HD Graphics でも同等の結果になりました。
RADEON は残念ながら ROV 非対応です。下記は RADEON GCN 1.1 (UAV) の結果で、こちらも GeForce 同様ブロック状のノイズが生じています。

dx12_rov_04rad.png

関連エントリ
3D 低レベル API の違い Direct3D 12/Metal
Direct3D 12 GeForce GTX970 は FeatureLevel 12_1 対応、Resource Bind/Heap Tier は低い
3D 低レベル API の現状 Direct3D 12/Metal
Direct3D 12 (DirectX12) GPU と API の対応表
DirectX 12 (Direct3D 12) と GPU の対応

3D 低レベル API の違い Direct3D 12/Metal

前回はこちら→ 「3D 低レベル API の現状 Direct3D 12/Metal

新しい API はあらゆる面で負荷の低減が行われています。

・バッファの無駄なコピーの排除
・Command など動的な変換をできるだけ避ける
・GPU との同期も暗黙に行わずアプリケーションに委ねる

自動化されていると便利ですが、アプリケーションによっては内部の仕組みが見えづらく、最適化の妨げになる場合があります。API の低レベル化は、オーバーヘッドを減らすと同時に用途に合わせて最適化が出来る範囲が広がりました。
具体的にどのあたりがこれまでと異なっているのか、いくつかまとめてみます。

● CommandBuffer と CommandQueue (D3D12/Metal)

従来の API では Context に暗黙の CommandBuffer が含まれていました。必要に応じてその都度 Command 生成 (Compile) やバッファ構築が行われており、実行や GPU との同期も表面上見えません。

新しい API では明示的に CommandBuffer (CommandList) を作成します。CommandBuffer はいくつでも生成可能でスレッド化も容易です。実行も直接 Command Queue に登録することで行います。API によっては再利用可能な事前コンパイルされた Buffer を作っておくことも可能です。CommandBuffer の完了は自分で判定する必要があります。

● PipelineState (D3D12/Metal)

以前の API では Context が State を所有していました。State は常に変更される可能性があるため Draw の直前まで内容を確定できません。Draw 命令のタイミングで必要な State を集めて Command 化が行われるため Draw Call API の負担が大きくなります。

新しい API では描画に必要な State の大半を Pipeline State に集約しています。この Object は事前に生成できるので、Command Compile や Error 判定など負荷のかかる処理を予め済ませておくことが可能。Draw Call の負担を大きく減らすことに繋がります。

● Resource Binding Table (D3D12)

Shader に割り当てるリソースのテーブルもこれまでは Context が所有していました。CBV 14個、SRV 128個、Sampler 16個 など API 毎に決められた数のスロットがあります。描画のたびに上書きされるため、Draw 毎に CommandBuffer へのコピーが必要でした。

新しい API では Resource Binding Table (Descriptor Table) もユーザーサイドで用意します。Table のサイズに制限はなくなり API 上の上限は撤廃。任意の部分を Register に割り当てるなどマッピングの自由度も高くなっています。また必要な Table を事前に生成しておけるため動的なコピーも減らせます。

● Resource 同期 (D3D12/Metal)

直前に書き込んだ Buffer を次の描画で Texture 参照する場合など、リソースの依存が発生する場合があります。ShaderUnit の実行は並列化されるので、複数の描画命令が部分的にオーバラップする可能性があるからです。従来の API では依存が発生した場合の完了待ちやキャッシュの同期はドライバの役割でした。

D3D12 ではリソースに State を設けており、読み書きのアクセスタイプが切り替わる場合 Barrier 命令を挿入する必要があります。

Metal では同期よりも PowerVR の Tile を最適化する目的で State (Action) が設けられています。RenderTarget を Texture 参照する場合は Store で、逆に Rendering 前に Tile に書き戻す場合は Load が必要です。本来の目的は違いますが他の GPU では Barrier に相当する役割を担っていると思われます。

● Buffer Renaming (D3D12/Metal)

従来の API では CPU 側から見て簡単に扱えるよう Buffer は複雑な構造を持っていました。同じバッファを部分的に書き換えて何度も描画に用いることができます。これを実現するには内部的にバッファをコピーしたり、描画のたびに異なるバッファを割り当てる Renaming が必要です。

新しい API では GPU/CPU から見える Buffer は常に同一なので、描画アクセス中のバッファ書き換えは結果に影響を与えます。Map() が返すアドレスは常に同じもので Renaming しません (Unmap が必須ではない)。動的に書き換える場合は多重化が必要です。CommandBuffer, Descriptor Table なども同様です。

従来の API でも usage パラメータとしてヒントがありましたが、内部動作の違いはわかりにくいものでした。低レベル API ではこれらの区別を自分で実装することになるため、どこで無駄が生じるのか明快です。個人的にはとてもわかりやすくなったと思っています。

関連エントリ
3D 低レベル API の現状 Direct3D 12/Metal

iPod touch 6 の浮動小数点演算速度は Core 2 Duo ライン超え

新しい iPod touch 6 は iPhone 4S 相当から 2世代飛んで一気に iPhone 6 世代へ移行しています。最も安価な iOS Device の底上げが行われました。

CPU SoC iPhone iPod iPad iPad mini
Cortex-A9 A5 iPhone 4S iPod touch 5 iPad2/iPad3 mini
Swift A6 iPhone 5/5c iPad4
Cyclone A7 iPhone 5s iPad Air mini2/mini3
Cyclone2 A8 iPhone 6/6p iPod touch 6 iPad Air2

GPU も一番新しい PowerVR Series 6XT の世代へ。

GPU PVR iPhone iPod iPad iPad mini
SGX543/554 5XT iPhone 4S/5/5c iPod touch 5 iPad2/iPad3/iPad4 mini
G6430 6 iPhone 5s iPad Air mini2/mini3
GX6450/6850 6XT iPhone 6/6p iPod touch 6 iPad Air2

RAM 容量も一段上がっています。

RAM iPhone iPod iPad iPad mini
512MB iPhone 4S iPod touch 5 iPad2 mini
1GB iPhone 5/5c/5s/6/6p iPod touch 6 iPad3/iPad4/Air mini2/mini3
2GB iPad Air2

歴代 iOS Device との速度比較は下記の通りです。(vfpbenchmark)

Device SoC CPU Clock S-SP S-DP M-SP M-DP
iPad Air 2 A8X Cyclone2 x3 1.5GHz 23.568 11.751 68.591 33.968
iPhone 5s A7 Cyclone x2 1.3GHz 20.621 10.313 40.871 20.480
iPad mini 2 A7 Cyclone x2 1.3GHz 20.373 10.223 40.616 20.238
iPod touch 6 A8 Cyclone2 x2 1.1GHz 17.964 8.899 35.530 17.775
Mac mini 2009 Core 2 Duo x2 2.0GHz 15.916 6.365 31.662 12.724
iPad 4 A6X Swift x2 1.4GHz 10.855 1.818 21.502 3.573
iPhone 5 A6 Swift x2 1.3GHz 10.094 1.710 20.029 3.398
iPad 2 A5 Cortex-A9 x2 1.0GHz 3.960 0.989 7.830 1.961
iPad mini A5 Cortex-A9 x2 1.0GHz 3.846 0.983 7.800 1.941
iPad 3 A5X Cortex-A9 x2 1.0GHz 3.394 0.983 7.752 1.954
iPod touch 5 A5 Cortex-A9 x2 0.8GHz 3.161 0.790 6.203 1.565
iPod touch 4 A4 Cortex-A8 x1 0.8GHz 3.139 0.112 3.139 0.112

S-SP = Single Thread 単精度  (GFLOPS) いずれも数値が大きいほうが高速
S-DP = Single Thread 倍精度  (GFLOPS)
M-SP = Multi Thread 単精度  (GFLOPS)
M-DP = Multi Thread 倍精度  (GFLOPS)

浮動小数点演算のピーク値だけの比較なので実際のアプリケーションの速度とは異なります。ですが、浮動小数点演算の速度だけでも Apple の公称値である「CPU 速度で 6倍」に近い数値を得ることが出来ました。

M-SP: 35.5 (iPod touch 6) / 6.2 (iPod touch 5) = 5.7倍

また 32bit 世代 (A4~A6) と 64bit 世代 (A7/A8) の間に入る調度良い比較対象だったので Mac mini Early 2009 の結果も載せてみました。もちろん最新の Core i5/i7 には敵いません。Android や Desktop PC 含めた結果を下記に載せています。

VFP Benchmark Log

GPU は ASTC 対応で PowerVR Series6XT (iOS GPUFamily2) を確認。

GL_VERSION: OpenGL ES 3.0 Apple A8 GPU - 53.13
GL_RENDERER: Apple A8 GPU
GL_VENDOR: Apple Inc.
GL_SHADING_LANGUAGE_VERSION: OpenGL ES GLSL ES 3.00

Extension:
GL_OES_standard_derivatives
GL_KHR_texture_compression_astc_ldr
GL_EXT_color_buffer_half_float
GL_EXT_debug_label
GL_EXT_debug_marker
GL_EXT_pvrtc_sRGB
GL_EXT_read_format_bgra
GL_EXT_separate_shader_objects
GL_EXT_shader_framebuffer_fetch
GL_EXT_shader_texture_lod
GL_EXT_shadow_samplers
GL_EXT_texture_filter_anisotropic
GL_APPLE_clip_distance
GL_APPLE_color_buffer_packed_float
GL_APPLE_copy_texture_levels
GL_APPLE_rgb_422
GL_APPLE_texture_format_BGRA8888
GL_IMG_read_format
GL_IMG_texture_compression_pvrtc

RAM は 1GB でした。

HW INFO: Machine = iPod7,1
HW INFO: Model = N102AP
HW INFO: Arch = N102AP
HW INFO: ByteOrder = 1234
HW INFO: NCPU = 2
HW INFO: MemSize = 1039306752
HW INFO: UserMem = 862314496
HW INFO: PageSize = 16384
HW INFO: VectorUnit = 0
HW INFO: Float = 0

関連エントリ
iPad Air 2 (Apple A8X) の浮動小数点演算能力
Android x86 Binary Translator を試してみる
iPhone 5s A7 CPU の浮動小数点演算速度 (2) (arm64/AArch64/64bit)
VFP Benchmark 関連