GPU ベースのコンウェイのライフ ゲーム プログラムの作成に取り組んできました。よくわからない場合は、ウィキペディアのページをご覧ください。0 が死んだセルを表し、1 が生きているセルを表す値の配列を保持することで機能する 1 つのバージョンを作成しました。次にカーネルは、セル データに基づいて画像を描画するために画像バッファー データ配列に書き込み、次にレンダリングする次の実行のためにセル配列を更新するために各セルの隣接をチェックします。
ただし、より高速な方法では、セルの値が死んでいる場合は負の数、生きている場合は正の数で表されます。そのセルの数は、隣接セルの数に 1 を加えた値を表します (0 と -0 を区別できないため、0 は不可能な値になります)。ただし、これは、セルをスポーンまたはキルするときに、それに応じて 8 つの隣接セルの値を更新する必要があることを意味します。したがって、隣接するメモリスロットから読み取るだけでよい作業手順とは異なり、この手順ではそれらのスロットに書き込む必要があります。これを行うと一貫性がなくなり、出力された配列が無効になります。たとえば、セルには 14 などの数字が含まれており、これは 13 個の隣人を示しますが、これはありえない値です。CPUで同じ手順を書いたので、コードは正しく、期待どおりに動作します。テスト後、タスクが同時にメモリに書き込もうとすると、何らかの書き込みエラーにつながる遅延があると思います。たとえば、配列データの読み取りと設定の間に遅延があり、その時点でデータが変更され、別のタスクの手順が正しくない可能性があります。私はセマフォとバリアを使用してみましたが、OpenCL と並列処理を学習したばかりで、まだ完全には把握していません。カーネルは次のとおりです。
int wrap(int val, int limit){
int response = val;
if(response<0){response+=limit;}
if(response>=limit){response-=limit;}
return response;
}
__kernel void optimizedModel(
__global uint *output,
int sizeX, int sizeY,
__global uint *colorMap,
__global uint *newCellMap,
__global uint *historyBuffer
)
{
// the x and y coordinates that currently being computed
unsigned int x = get_global_id(0);
unsigned int y = get_global_id(1);
int cellValue = historyBuffer[sizeX*y+x];
int neighborCount = abs(cellValue)-1;
output[y*sizeX+x] = colorMap[cellValue > 0 ? 1 : 0];
if(cellValue > 0){// if alive
if(neighborCount < 2 || neighborCount > 3){
// kill
for(int i=-1; i<2; i++){
for(int j=-1; j<2; j++){
if(i!=0 || j!=0){
int wxc = wrap(x+i, sizeX);
int wyc = wrap(y+j, sizeY);
newCellMap[sizeX*wyc+wxc] -= newCellMap[sizeX*wyc+wxc] > 0 ? 1 : -1;
}
}
}
newCellMap[sizeX*y+x] *= -1;
// end kill
}
}else{
if(neighborCount==3){
// spawn
for(int i=-1; i<2; i++){
for(int j=-1; j<2; j++){
if(i!=0 || j!=0){
int wxc = wrap(x+i, sizeX);
int wyc = wrap(y+j, sizeY);
newCellMap[sizeX*wyc+wxc] += newCellMap[sizeX*wyc+wxc] > 0 ? 1 : -1;
}
}
}
newCellMap[sizeX*y+x] *= -1;
// end spawn
}
}
}
- 配列出力は、カーネルの計算をレンダリングするために使用されるイメージ バッファー データです。
- sizeX定数とsizeY定数は、それぞれ画像バッファーの幅と高さです。
- colorMap配列には、イメージ バッファの値を適切に変更して色をレンダリングするために使用される、それぞれ黒と白の rgb 整数値が含まれています。
- newCellMap配列は、レンダリングが決定されると計算される更新されたセル マップです。
- historyBufferは、カーネル呼び出しの開始時のセルの古い状態です。カーネルが実行されるたびに、この配列は newCellMap 配列に更新されます。
さらに、ラップ機能は空間をトロイダルにします。期待どおりに動作するようにこのコードを修正するにはどうすればよいですか。また、タスクによる変更のたびにグローバル メモリが更新されないのはなぜでしょうか。共有メモリではないでしょうか?