浮動小数点数計算(2)
ピクセルごとに少ない計算量だとあまり速くならないが、
ピクセルごとにループを回すと速くなる。
前回の問題を、
を計算するように変える。
コードはほとんど変わらない。
シェーダープログラムのほうを次のようにする。
//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;
}