2

私が変換しているゲームは8ビットのパレットテクスチャで動作しており、レンダリングのためにそのテクスチャの一部をOpenGLテクスチャに更新する必要があるほぼすべてのフレームです。次のようになります。

unsigned short RGB565PaletteLookupTable[256];   // Lookup table

unsigned char* Src;                             // Source data
unsigned short* Dst;                            // Destination buffer
int SrcPitch;                                   // Source data row length
int OriginX, OriginY, Width, Height;            // Subrectangle to copy

assert( Width % 4 == 0 );

int SrcOffset = SrcPitch-Width;
Src += OriginY*SrcPitch+OriginX;

int x, y;

for( y = OriginY; y < OriginY+Height; ++y, Src += SrcOffset )
{
    for( x = OriginX; x < OriginX+Width; x += 4 )
    {
        *Dst++ = RGB565PaletteLookupTable[*Src++];
        *Dst++ = RGB565PaletteLookupTable[*Src++];
        *Dst++ = RGB565PaletteLookupTable[*Src++];
        *Dst++ = RGB565PaletteLookupTable[*Src++];
    }
}

このコードはゲーム中にメインスレッド時間の17%を要するので、私はそれをスピードアップする方法を探しています。データは直接glTexSubImage2D()に送られるため、宛先バッファーでは何も変更できません。それは古くて文書化されていないゲームのコードから来ており、それがどのように機能するかはもう誰にもわからないので、私もそれをあまり混乱させることはできません。ルックアップテーブルはこの古代のコードによっても提供され、ゲーム中に変更される可能性があります。

Accelerateフレームワーク/アセンブリ命令/その他の手段を使用してこのコードを高速化することは可能でしょうか?RGB888からRGB565への直接変換の例を読みましたが、これらはルックアップテーブルを使用する必要はありませんでした。それを最適にスピードアップする方法を学ぶためにどこを見ればよいですか?

更新:OriginXも4整列であり、次のようにコードを改良できたことがわかりました。

unsigned long RGB565PaletteLookupTable[256];   // Lookup table

unsigned char* Src;                             // Source data
unsigned long* Dst;                            // Destination buffer
int SrcPitch;                                   // Source data row length
int OriginX, OriginY, Width, Height;            // Subrectangle to copy

assert( Width % 4 == 0 );

int SrcOffset = SrcPitch-Width;
Src += OriginY*SrcPitch+OriginX;
SrcOffset >>= 2;

int x, y;

unsigned long* LSrc = (unsigned long*)Src;

for( y = OriginY; y < OriginY+Height; ++y, LSrc += SrcOffset )
{
    for( x = OriginX; x < OriginX+Width; x += 4 )
    {
        unsigned long Indexes = *LSrc++;
        unsigned long Result = RGB565PaletteLookupTable[ Indexes & 0xFF ];
        Indexes >>= 8;
        Result |= ( RGB565PaletteLookupTable[ Indexes & 0xFF ] << 16 );
        *Dst++ = Result;
        Indexes >>= 8;
        Result = RGB565PaletteLookupTable[ Indexes & 0xFF ];
        Indexes >>= 8;
        Result |= ( RGB565PaletteLookupTable[ Indexes & 0xFF ] << 16 );
        *Dst++ = Result;
    }
}

このコードは、私が知る限りではありません。アラインされていないメモリアクセスを使用します。パフォーマンスが少し向上しました。つまり、メインスレッド時間の15.5%が必要になります。でももっとスピードアップしたいと思っていました。

理論的には、ルックアップテーブルの操作はそれぞれ、前の操作と後続の操作から独立しているため(それぞれが同じルックアップテーブルから読み取るという事実は別として)、SIMD命令、またはおそらくアセンブリ命令があると予想していました。これにより、多くのピクセルを並行して検索できます。何かのようなもの

_mm_movemask_ps( _mm_cmpneq_ps( _mm_loadu_ps( cmp1 ), _mm_loadu_ps( cmp2 ) ) ) )

Macではmemcmp(cmp1、cmp2、16)と同じことをしますが、8倍速くなります。

私は今それを探し続けます。

更新:NEON命令セットを使用してテーブルルックアップを高速化する方法はないようだと判断しました。テーブルは512バイトの大きさである必要があり、ARMレジスタに完全に収める方法はありません。VTBXNEON命令は一度に最大32バイトを処理でき、ルックアップ結果のサイズは次のサイズと等しくなければならないことも前提としています。インデックス。http://forums.arm.com/index.php?/topic/15521-8bit-look-up-table-by-neon-code/で説明されている同様の問題の解決策として解決できる可能性のあるものがありますが、それは勝ちました私には合いません。したがって、すべてのオペランドの配置が正しいことを確認することが、この問題に対する最善の答えのようです。

4

2 に答える 2

3

問題はキャッシュにあります。Srcから多くの読み取りを行い、それが4つ整列されていない場合(OriginXは任意である可能性が高いため、これが当てはまる可能性があります)、(* Src ++)は整列されていない読み取りのサイクルを浪費します。

(OriginX%4 == 0)を適用し、残りの(OriginX%4)ピクセルをメインループの外側にコピーしてみてください。

"* Dst ++ ="と同じです-Dstが整列されていないので、不良です。RGB565ペア(2つの連続した* Dst書き込み)を1つの32ビットコピーに結合してみてください。ループを単純にするためにさらにいくつかのピクセルを上書きしてから、境界ピクセルを処理することもできます。

あなたがアイデアを得ることを願っています。

2番目の方法:GPUへの変換をオフロードします。

RGB565PaletteLookupTableの1Dテクスチャを作成し、(Src + RGB565PaletteLookupTable)を取得してDstを出力する単純なフラグメントシェーダーを記述します(glTexImage2Dは、現在のようにDstではなくSrcテクスチャを更新します)

于 2012-06-26T21:17:23.330 に答える
0

RGB565PaletteLookupTableからにコピーしているだけなのでDst、を使用することを検討してmemcpyください。これは、プラットフォーム上のバッファを実際にコピーするための最速の方法を利用する可能性があります。これにより、コードアセンブリを渡さなくても、サイクルごとにより多くのバイトをコピーする命令を使用できるという利点が得られます。

于 2012-06-26T21:04:51.663 に答える