GPGPUで整数計算(3)

浮動小数点数計算(2)

ピクセルごとに少ない計算量だとあまり速くならないが、
ピクセルごとにループを回すと速くなる。


前回の問題を、

 \int_0^{\frac{\pi}{2}}{\sin{x}dx} \simeq \frac{\pi}{2nm}\sum_{k = 0}^{n-1}{\sum_{l=0}^{m-1}{\sin{\frac{\pi}{2n}(k+\frac{l}{m})}}}

を計算するように変える。
コードはほとんど変わらない。
シェーダープログラムのほうを次のようにする。


//shader_nv2.frag
uniform samplerRECT texUnit0;

uniform int nRep;
uniform float dx;

void main(void) {
vec4 color = texRECT(texUnit0, gl_FragCoord.xy);
vec4 result = vec4(0, 0, 0, 0);
for(int i = 0; i < nRep; i++) {
result += sin(color);
color += vec4(dx);
}
gl_FragColor = result;
}

colorをdxずつ大きくして、nRep回sinの計算を繰り返す。
それを足し合わせたものを返す。


unifomとなっているのは、CPUのほうから送る値で、
どのピクセルでも共通で変わらない。
これらは、次のようにCPUから送る。


const int nRep = 256;
int h_nRep = glGetUniformLocationARB(g_programObject, "nRep");
glUniform1iARB(h_nRep, nRep);
int h_dx = glGetUniformLocationARB(g_programObject, "dx");
glUniform1fARB(h_dx, M_PI / 2 / nData / nRep);

説明すべきなのは、これくらいかな?


かかった時間は、

GPU : 11.6msec
CPU : 3719.2msec

となった。



// gpgpu2.cpp
// main以外は前回と共通
int main(int argc, char **argv) {
const int nWidth = 256;
const int nHeight = 256;
const int nData = nWidth * nHeight * 4;
float *data = new float[nData];
const int nRep = 256;

glutInit( &argc, argv );
glutInitWindowSize(nWidth, nHeight);
unsigned int g_glutWindowHandle;
g_glutWindowHandle = glutCreateWindow("GpgpuHelloWorld");
glewInit();

unsigned int g_fb = -1;
glGenFramebuffersEXT(1, &g_fb);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, g_fb);

GLhandleARB g_programObject;
GLint texUnit0;
unsigned int g_nTexID[1];
CreateShader(g_programObject, texUnit0, "shader_nv2.frag");
glGenTextures(1, g_nTexID);

unsigned short TEX_OPT1 = GL_TEXTURE_RECTANGLE_NV;
unsigned short TEX_OPT2 = GL_FLOAT_RGBA32_NV;

CreateTexture(g_nTexID[0], nWidth, nHeight, TEX_OPT1, TEX_OPT2);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, nWidth, 0.0, nHeight);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glViewport(0, 0, nWidth, nHeight);

glFlush();

for(int y = 0; y < nHeight; y++) {
for(int x = 0; x < nWidth; x++) {
for(int i = 0; i < 4; i++) {
int k = (y * nWidth + x) * 4 + i;
data[k] = k * (M_PI / 2 / nData);
}
}
}

glBindTexture(TEX_OPT1, g_nTexID[0]);
glTexSubImage2D(TEX_OPT1, 0, 0, 0,
nWidth, nHeight, GL_RGBA, GL_FLOAT, data);

glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
GL_COLOR_ATTACHMENT0_EXT, TEX_OPT1, g_nTexID[0], 0);
glUseProgramObjectARB(g_programObject);

glActiveTexture(GL_TEXTURE0);
glBindTexture(TEX_OPT1, g_nTexID[0]);
glUniform1iARB(texUnit0, 0);

int h_nRep = glGetUniformLocationARB(g_programObject, "nRep");
glUniform1iARB(h_nRep, nRep);
int h_dx = glGetUniformLocationARB(g_programObject, "dx");
glUniform1fARB(h_dx, M_PI / 2 / nData / nRep);

glDrawBuffer (GL_COLOR_ATTACHMENT0_EXT);

glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0);
glVertex2f (0.0, 0.0);
glTexCoord2f(nWidth, 0.0);
glVertex2f (nWidth, 0.0);
glTexCoord2f(nWidth, nHeight);
glVertex2f (nWidth, nHeight);
glTexCoord2f(0.0, nHeight);
glVertex2f (0.0, nHeight);
glEnd();

glFlush();
glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);

glReadPixels(0,0, nWidth, nHeight, GL_RGBA, GL_FLOAT, data);
glDeleteTextures(1, g_nTexID);

double integralGPU = 0;
for(int i = 0; i < nData; i++) {
integralGPU += data[i];
}
printf("GPU : %f\n", integralGPU * (M_PI / 2 / nData / nRep));

double integralCPU = 0;
for(int i = 0; i < nData * nRep; i++) {
integralCPU += sin(i * (M_PI / 2 / nData / nRep));
}
printf("CPU : %f\n", integralCPU * (M_PI / 2 / nData / nRep));

delete [] data;
glutDestroyWindow(g_glutWindowHandle);

return 0;
}