1

我正在向 OpenCL 编码迈出第一步。我有一个框架,我知道它至少可以从 CPU 中获取一个数组,在 OpenCL 中进行操作,然后读回该数组(给出正确答案)。我目前正在尝试通过添加在此 OpenCL 示例中找到的位移网格来改进这一点(幻灯片 18-23;唯一显着的改进是我将 VBO 更改为 float3 而不是 float4)。

我已经按照前面那些幻灯片和这个资源中的内容设置了一个共享上下文。我用 CPU 输入数据测试了 VBO(所以我知道它绘制正确)。另外,我在 VBO 之前创建了上下文(受此线程的启发)。最后,我尝试将内核改造成以下[已编辑]:

__kernel void sine_wave(__global float3* pos, int width, int height, float time) {
    uint x = get_global_id(0); uint y = get_global_id(1);
    pos[y*width+x] = (float3)(1.0f,1.0f,1.0f);
}

然而,无论我做什么,我都无法让 OpenCL 程序更新任何内容。没有错误,什么都没有,但 VBO 与输入数据保持一致。如果我不指定输入数据,则所有点都呈现在 (0,0,0)。我不知道是什么原因造成的。

想法?谢谢,
伊恩

PS #1:当前系统是 NVIDIA GTX 580M,在 Windows 7 x64 上,尽管编写的代码是为了便于移植。

PS #2:如果没有人有任何线索,我可以提供代码。. .

4

1 回答 1

1

嗯,我想通了。经过数小时的搜索,我下载了 NVIDIA 的 GPU 计算工具包,这似乎是链接演示的来源。然后,我将他们的代码大大减少到以下约 220 行源代码(可能对你们未来的编码人员有所帮助):

#pragma comment(lib,"Opengl32.lib")
#pragma comment(lib,"glu32.lib")
#pragma comment(lib,"OpenCL.lib")
#pragma comment(lib,"glew32.lib")
#pragma comment(lib,"glut32.lib")

// OpenGL Graphics Includes
#include <GL/glew.h>
#if defined (__APPLE__) || defined(MACOSX)
    #include <OpenGL/OpenGL.h>
    #include <GLUT/glut.h>
#else
    #include <GL/glut.h>
    #ifdef UNIX
        #include <GL/glx.h>
    #endif
#endif

#include <CL/opencl.h>

// Rendering window vars
const unsigned int window_width = 512;
const unsigned int window_height = 512;
const unsigned int mesh_width = 256;
const unsigned int mesh_height = 256;

// OpenCL vars
cl_context cxGPUContext;
cl_device_id* cdDevices;
cl_command_queue cqCommandQueue;
cl_kernel ckKernel;
cl_mem vbo_cl;
cl_program cpProgram;
size_t szGlobalWorkSize[] = {mesh_width, mesh_height};

// vbo variables
GLuint vbo;

int mouse_old_x, mouse_old_y;
int mouse_buttons = 0;
float rotate_x = 0.0, rotate_y = 0.0;
float translate_z = -3.0;
void mouse(int button, int state, int x, int y) {
    if (state == GLUT_DOWN) {
        mouse_buttons |= 1<<button;
    } else if (state == GLUT_UP) {
        mouse_buttons = 0;
    }

    mouse_old_x = x;
    mouse_old_y = y;
}
void motion(int x, int y) {
    float dx, dy;
    dx = (float)(x - mouse_old_x);
    dy = (float)(y - mouse_old_y);

    if (mouse_buttons & 1) {
        rotate_x += dy * 0.2f;
        rotate_y += dx * 0.2f;
    } else if (mouse_buttons & 4) {
        translate_z += dy * 0.01f;
    }

    mouse_old_x = x;
    mouse_old_y = y;
}

void DisplayGL(void) {
    static float anim = 0.0f;

    // run OpenCL kernel to generate vertex positions
    glFinish();
    clEnqueueAcquireGLObjects(cqCommandQueue, 1, &vbo_cl, 0,0,0);

    clSetKernelArg(ckKernel, 3, sizeof(float), &anim);
    clEnqueueNDRangeKernel(cqCommandQueue, ckKernel, 2, NULL, szGlobalWorkSize, NULL, 0,0,0 );

    clEnqueueReleaseGLObjects(cqCommandQueue, 1, &vbo_cl, 0,0,0);
    clFinish(cqCommandQueue);

    // set view matrix
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
    glTranslatef(0.0, 0.0, translate_z);
    glRotatef(rotate_x, 1.0, 0.0, 0.0);
    glRotatef(rotate_y, 0.0, 1.0, 0.0);

    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glVertexPointer(4, GL_FLOAT, 0, 0);
    glEnableClientState(GL_VERTEX_ARRAY);
    glColor3f(1.0, 0.0, 0.0);
    glDrawArrays(GL_POINTS, 0, mesh_width * mesh_height);
    glDisableClientState(GL_VERTEX_ARRAY);

    // flip backbuffer to screen
    glutSwapBuffers();

    anim += 0.01f;
}

void timerEvent(int value) {
    glutPostRedisplay();
    glutTimerFunc(10, timerEvent,0);
}

int main(int argc, char** argv) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
    glutInitWindowPosition (glutGet(GLUT_SCREEN_WIDTH)/2 - window_width/2,  glutGet(GLUT_SCREEN_HEIGHT)/2 - window_height/2);
    glutInitWindowSize(window_width, window_height);
    glutCreateWindow("OpenCL/GL Interop (VBO)");

    glutDisplayFunc(DisplayGL);
    glutMouseFunc(mouse);
    glutMotionFunc(motion);
    glutTimerFunc(10, timerEvent,0);

    glewInit();

    glClearColor(0.0, 0.0, 0.0, 1.0);
    glDisable(GL_DEPTH_TEST);

    glViewport(0, 0, window_width, window_height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(60.0, (GLfloat)window_width / (GLfloat) window_height, 0.1, 10.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    //Get the NVIDIA platform
    cl_platform_id cpPlatform;
    clGetPlatformIDs(1,&cpPlatform,NULL);

    // Get the number of GPU devices available to the platform
    cl_uint uiDevCount;
    clGetDeviceIDs(cpPlatform, CL_DEVICE_TYPE_GPU, 0, NULL, &uiDevCount);

    // Create the device list
    cdDevices = new cl_device_id [uiDevCount];
    clGetDeviceIDs(cpPlatform, CL_DEVICE_TYPE_GPU, uiDevCount, cdDevices, NULL);
    // Define OS-specific context properties and create the OpenCL context
#if defined (__APPLE__)
    CGLContextObj kCGLContext = CGLGetCurrentContext();
    CGLShareGroupObj kCGLShareGroup = CGLGetShareGroup(kCGLContext);
    cl_context_properties props[] = 
    {
        CL_CONTEXT_PROPERTY_USE_CGL_SHAREGROUP_APPLE, (cl_context_properties)kCGLShareGroup, 
        0 
    };
    cxGPUContext = clCreateContext(props, 0,0, NULL, NULL, &ciErrNum);
#else
#ifdef UNIX
    cl_context_properties props[] = 
    {
        CL_GL_CONTEXT_KHR, (cl_context_properties)glXGetCurrentContext(), 
        CL_GLX_DISPLAY_KHR, (cl_context_properties)glXGetCurrentDisplay(), 
        CL_CONTEXT_PLATFORM, (cl_context_properties)cpPlatform, 
        0
    };
    cxGPUContext = clCreateContext(props, 1, &cdDevices[uiDeviceUsed], NULL, NULL, &ciErrNum);
#else // Win32
    cl_context_properties props[] = 
    {
        CL_GL_CONTEXT_KHR, (cl_context_properties)wglGetCurrentContext(), 
        CL_WGL_HDC_KHR, (cl_context_properties)wglGetCurrentDC(), 
        CL_CONTEXT_PLATFORM, (cl_context_properties)cpPlatform, 
        0
    };
    cxGPUContext = clCreateContext(props, 1, &cdDevices[0], NULL, NULL, NULL);
#endif
#endif

    // create a command-queue
    cqCommandQueue = clCreateCommandQueue(cxGPUContext, cdDevices[0], 0, NULL);

    const char* cSourceCL = "__kernel void sine_wave(__global float4* pos, unsigned int width, unsigned int height, float time)\n"
    "{\n"
    "   unsigned int x = get_global_id(0);\n"
    "   unsigned int y = get_global_id(1);\n"
    "\n"
    "   // calculate uv coordinates\n"
    "   float u = x / (float) width;\n"
    "   float v = y / (float) height;\n"
    "   u = u*2.0f - 1.0f;\n"
    "   v = v*2.0f - 1.0f;\n"
    "\n"
    "   // calculate simple sine wave pattern\n"
    "   float freq = 4.0f;\n"
    "   float w = sin(u*freq + time) * cos(v*freq + time) * 0.5f;\n"
    "\n"
    "   // write output vertex\n"
    "   pos[y*width+x] = (float4)(u, w, v, 1.0f);\n"
    "}\n";
    cpProgram = clCreateProgramWithSource(cxGPUContext, 1, (const char **) &cSourceCL, NULL, NULL);

    clBuildProgram(cpProgram, 0, NULL, "-cl-fast-relaxed-math", NULL, NULL);

    // create the kernel
    ckKernel = clCreateKernel(cpProgram, "sine_wave", NULL);

    // create VBO (if using standard GL or CL-GL interop), otherwise create Cl buffer
    unsigned int size = mesh_width * mesh_height * 4 * sizeof(float);

    glGenBuffers(1,&vbo);
    glBindBuffer(GL_ARRAY_BUFFER,vbo);
    // initialize buffer object
    glBufferData(GL_ARRAY_BUFFER, size, 0, GL_DYNAMIC_DRAW);

    // create OpenCL buffer from GL VBO
    vbo_cl = clCreateFromGLBuffer(cxGPUContext, CL_MEM_WRITE_ONLY, vbo, NULL);

    // set the args values 
    clSetKernelArg(ckKernel, 0, sizeof(cl_mem), (void *) &vbo_cl);
    clSetKernelArg(ckKernel, 1, sizeof(unsigned int), &mesh_width);
    clSetKernelArg(ckKernel, 2, sizeof(unsigned int), &mesh_height);

    glutMainLoop();
}

在与我的原始代码比较之后,我(最终)发现了关键区别。

对:

clEnqueueNDRangeKernel(context->command_queue, kernel->kernel, 2, NULL, global,NULL, 0,0,0 );

错误的:

clEnqueueNDRangeKernel(context->command_queue, kernel->kernel, 2, NULL, global,local, 0,0,0 );

事实证明,我使用的网格大小为 10x10,比我在其他地方看到的示例要小,这告诉我使用 16x16 表示“本地”。因为“global”是网格大小,所以“global”小于“local”。

出于某种原因,这并没有导致任何错误,尽管在这一点上老实说我不能说我完全理解这些变量的目的。

伊恩

于 2012-06-10T07:48:00.693 回答