2012-06-10 2 views
1

Я делаю первый шаг в кодировке OpenCL. У меня есть фреймворк, который, как я знаю, может, по крайней мере, взять массив из CPU, выполнить операцию в OpenCL, а затем прочитать массив (с правильным ответом). В настоящее время я пытаюсь улучшить это, добавив смещенную сетку, как показано в this OpenCL example (слайды 18-23, только значительное улучшение - я изменил VBO на float3 вместо float4).OpenCL не обновляет OpenGL VBO

Я установил общий контекст, как ранее в этих слайдах, и this resource. Я тестировал VBO с входными данными процессора (поэтому я знаю, что он правильно рисует). Кроме того, я создаю контекст перед VBO (по мотивам this thread). Наконец, я попытался переработать ядро ​​в следующем [отредактированный]:

__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). Я не могу понять, что может вызвать это.

Идеи? Спасибо,
Ian

PS # 1: текущая система - это NVIDIA GTX 580M, в Windows 7 x64, хотя написанный код предназначен для переноски.

PS # 2: Я могу предоставить код, если у вас нет никаких подсказок. , ,

+0

Я не понимаю .. вы сказали, что только значительное улучшение вы сделали меняется от float3 к float4, но от того, что я вижу, вы полностью изменили код с горкой 20 в смутное для цикла внутри ядра – ardiyu07

+0

Этот цикл ядра содержит огромное переполнение буфера. Это также полностью серийно .... – talonmies

+0

ardiyu07: Да, я попробовал это как с оригинальным кодом, так и с моей уменьшенной версией. @talonmies: хорошо, я не понял, что такое get_global_id. Кажется, теперь я понимаю лучше. И да, серийный бит был преднамеренным; Я хотел заставить все быть таким, чтобы я мог что-то изменить. – imallett

ответ

1

Ну, я понял это. После нескольких часов поиска я загрузил набор графических процессоров NVIDIA, который, как представляется, связан с демо-версией. Затем я уменьшил свой код вниз очень к следующему ~ 220 линейного источнику (возможно, это поможет Ye будущих кодеров):

#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); 

Оказывается, что размер сетки я использую, 10х10, был меньше, чем примеры, которые я видел в других местах, которые сказали мне использовать 16x16 для "local". Поскольку «глобальный» - это размер сетки, «глобальный» был меньше, чем «местный».

По какой-то причине это не вызвало никаких ошибок, хотя на данный момент я, честно говоря, не могу сказать, что полностью понимаю цели этих переменных.

Ян

+0

Вы могли бы сэкономить огромное количество боли, если бы включили проверку ошибок в код. API-интерфейс OpenCL возвращает статус (например, [clEnqueueNDRangeKernel] (http://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/clEnqueueNDRangeKernel.HTML)). Если вы проверили это возвращаемое значение, было бы сразу очевидно, что запуск ядра был неудачным и в процессе сузили область поиска для проблемы. – talonmies

+0

По иронии судьбы, я был * тщательно * проверял ошибки в коде, который я написал, но он все еще работал не так, как ожидалось. Проблема заключалась в том, что я впоследствии попытался снова скопировать пример сетки, на этот раз более дословно из источника, который не включал проверку ошибок. Конечно, при запуске кода с проверкой ошибок вы получите CL_INVALID_WORK_GROUP_SIZE. – imallett