如何在OpenCL中从设备发送/读取数据?

如何在OpenCL中从设备发送/读取数据?,opencl,Opencl,如何在设备上创建一些数据,然后在主机上发送/读取 我试着跟随,但似乎不起作用 #include <stdio.h> #include <stdlib.h> #include "vectors.h" #include "sphere.h" #include "shading.h" #include "ray.h" #include "stdbool.h" #include <CL/cl.h> #if defined __APPLE__ #include &l

如何在设备上创建一些数据,然后在主机上发送/读取

我试着跟随,但似乎不起作用

#include <stdio.h>
#include <stdlib.h>

#include "vectors.h"
#include "sphere.h"
#include "shading.h"
#include "ray.h"
#include "stdbool.h"
#include <CL/cl.h>

#if defined __APPLE__
#include <OpenGL/gl.h>
#include <OpenGL/glu.h>
#include <GLUT/glut.h>
#elif defined (WIN32)
#include <GL/freeglut.h>
#else
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/freeglut_std.h>
#endif

#include <time.h>

VECTOR3D light;
SPHERE sphere[NSPHERES];
static PIXEL pixel;
VIEWPORT viewport;
VECTOR3D view_point;
VEC_BASIS camera_frame;
cl_double focal_distance;


double color;
//double kd_red, kd_green, kd_blue;
//double ks_red, ks_green, ks_blue;
double red, green, blue;
double light_intensity, ambi_light_intensity;
double theta, reflected_theta;

int bShadow = 0;

int direction[NSPHERES];

int intersection_object = -1; // none
double current_lambda = 0x7fefffffffffffff; // maximum positive double
double current_reflected_lambda = 0x7fefffffffffffff; // maximum positive double

// window identifier:
static int win;

void Timer (int obsolete) {
    glutPostRedisplay();
    glutTimerFunc(10, Timer, 0);
}

// opencl stuff
typedef struct cl_struct {
    cl_platform_id platform_id;
    cl_device_id device_id;
    cl_context context;
    cl_command_queue queue;
} cl_struct;

#define MAX_SOURCE_SIZE (0x100000)

void disp2(void) {

    int i,j;
    PIXEL* pCurrentPixel;
    PIXEL* pPixels;

    int VPWIDTH = viewport.xvmax - viewport.xvmin;
    int VPHEIGHT = viewport.yvmax - viewport.yvmin;

    pPixels = (PIXEL*)(viewport.pPixels);

    //clear all pixels:
    glClear(GL_COLOR_BUFFER_BIT);

    // For all pixels:
    for (i=0; i<VPWIDTH; i++) {
        for (j=0; j<VPHEIGHT; j++) {

            pCurrentPixel = (PIXEL*)(pPixels + VPWIDTH*i + j);

            //set color for the current pixel:
            glColor3f(pCurrentPixel->rgb[0] , pCurrentPixel->rgb[1], pCurrentPixel->rgb[2]);

            // draw pixel
            glBegin(GL_POINTS);
            glVertex2i(i, j);
            glEnd();
        } // j
    } //i

    //glFlush();
    glutSwapBuffers();
}

void init(void) {

    direction[0] = 1;
    direction[1] = 0;
    direction[2] = 1;

    pixel.i = 0;
    pixel.j = 0;

    // set scene:
    // 1. define viewport
    viewport.xvmin = -VIEWPLANE;
    viewport.yvmin = -VIEWPLANE;
    viewport.xvmax = VIEWPLANE;
    viewport.yvmax = VIEWPLANE;

    // 2. allocate enough space for pixels in viewport
    viewport.pPixels = (PIXEL *) malloc(sizeof(PIXEL) * (viewport.xvmax - viewport.xvmin) * (viewport.yvmax- viewport.yvmin));

    // 3. set camera:
    camera_frame.u.x = 1.0;
    camera_frame.u.y = 0.0;
    camera_frame.u.z = 0.0;

    camera_frame.v.x = 0.0;
    camera_frame.v.y = 1.0;
    camera_frame.v.z = 0.0;

    camera_frame.n.x = 0.0;
    camera_frame.n.y = 0.0;
    camera_frame.n.z = 1.0;

    view_point.x = (viewport.xvmax - viewport.xvmin) / 2.0 ;
    view_point.y = (viewport.yvmax - viewport.yvmin) / 2.0 ;
    view_point.z = 0.0;

    // 4. set light:
    light.x = view_point.x - 1300;
    light.y = view_point.y + 1300 ;
    light.z = view_point.z - 300;


    ambi_light_intensity = 1.0;
    light_intensity = 1.0;

    focal_distance = FOCALDIST;

    // 5. put spheres behind the viewport:
    sphere[0].radius = RADIUS/1.5;
    sphere[0].center.x  = view_point.x - (RADIUS+30);
    sphere[0].center.y  = view_point.y ;
    sphere[0].center.z  = view_point.z - focal_distance - (2*RADIUS+20);
    // the first sphere is blue:
    set_rgb_array(sphere[0].kd_rgb, 0.0, 0.0, 0.8);
    set_rgb_array(sphere[0].ks_rgb, 1.0, 1.0, 1.0);
    set_rgb_array(sphere[0].ka_rgb, 0.0, 0.0, 0.2);
    sphere[0].shininess = 100.0;
    sphere[0].mirror = false;

    sphere[1].radius = RADIUS/1.2;
    sphere[1].center.x  = view_point.x + 0;
    sphere[1].center.y  = view_point.y + 50;
    sphere[1].center.z  = view_point.z - focal_distance - (3*RADIUS+20);
    // the second sphere is green:
    set_rgb_array(sphere[1].kd_rgb, 0.0, 0.5, 0.0);
    set_rgb_array(sphere[1].ks_rgb, 1.0, 1.0, 1.0);
    set_rgb_array(sphere[1].ka_rgb, 0.0, 0.2, 0.0);
    sphere[1].shininess = 10.0;
    sphere[1].mirror = false;


    sphere[2].radius = RADIUS;
    sphere[2].center.x  = view_point.x + (2*RADIUS+30);
    sphere[2].center.y  = view_point.y + 100;
    sphere[2].center.z  = view_point.z - focal_distance - (4*RADIUS+20);
    // the third sphere is red:
    set_rgb_array(sphere[2].kd_rgb, 1.0, 0.0, 0.0);
    set_rgb_array(sphere[2].ks_rgb, 1.0, 1.0, 1.0);
    set_rgb_array(sphere[2].ka_rgb, 0.2, 0.0, 0.0);
    sphere[2].shininess = 100.0;
    sphere[2].mirror = false;


    sphere[3].radius = 1*RADIUS;
    sphere[3].center.x  = view_point.x ;
    sphere[3].center.y  = view_point.y - 100*RADIUS-130;
    sphere[3].center.z  = view_point.z - focal_distance - (4*RADIUS+20);
    // the third sphere is red:
    set_rgb_array(sphere[3].kd_rgb, 0.5, 0.5, 0.5);
    set_rgb_array(sphere[3].ks_rgb, 1.0, 1.0, 1.0);
    set_rgb_array(sphere[3].ka_rgb, 0.5, 0.5, 0.5);
    sphere[3].shininess = 100.0;
    sphere[3].mirror = false;

    // set clearing (background) color to white:
    glClearColor(0.0, 0.0, 0.0, 0.0);
    // specify that ortgogonal 2D projection is to be used to
    // map context of 2D world coordinats to the screen. We use the
    // world-coordinate rectangle of the same aspect ratio as the display window
    // so ther is no distortion:
    glMatrixMode(GL_PROJECTION);
    gluOrtho2D(0.0, WINDOW, 0.0, WINDOW);
}

int main(int argc, const char * argv[]) {
    clock_t startCPU, endCPU, startGPU, endGPU;

    // init glut:
    glutInit (&argc, argv);
    // specify the display mode to be RGB and single buffering:
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
    // specify the initial window position:
    glutInitWindowPosition(100, 100);
    // specify the initial window size:
    glutInitWindowSize(WINDOW,WINDOW);
    // create the window and set title:
    win = glutCreateWindow("Basic Ray Tracer by Pa3cio, UL FRI");

    init();

    // Create the two input vectors
    int i, j, k, l;

    int VPWIDTH = viewport.xvmax - viewport.xvmin;
    int VPHEIGHT = viewport.yvmax - viewport.yvmin;

    // PIXEL* pixels = (PIXEL*) malloc(sizeof(PIXEL) * VPWIDTH * VPHEIGHT);
    PIXEL* pPixelsFromGPU = (PIXEL*) malloc(sizeof(PIXEL) * VPWIDTH * VPHEIGHT);

    PIXEL* pCurrentPixel;
    PIXEL* pPixels;
    RAY ray, shadow_ray;

    SPHERE_INTERSECTION intersection, current_intersection, shadow_ray_intersection;

    // Load the kernel source code into the array source_str
    FILE *fp;
    char *source_str;
    size_t source_size;

    fp = fopen("/home/rokj/sula/vpsa/seminarska/kernel.cl", "r");
    if (!fp) {
        fprintf(stderr, "Failed to load kernel.\n");
        exit(1);
    }
    source_str = (char*)malloc(MAX_SOURCE_SIZE);
    source_size = fread( source_str, 1, MAX_SOURCE_SIZE, fp);
    fclose( fp );

    // Get platform and device information
    cl_platform_id platform_id = NULL;
    cl_device_id device_id = NULL;
    cl_uint ret_num_devices;
    cl_uint ret_num_platforms;
    cl_int ret = clGetPlatformIDs(1, &platform_id, &ret_num_platforms);
    ret = clGetDeviceIDs( platform_id, CL_DEVICE_TYPE_CPU, 1,
                          &device_id, &ret_num_devices);

    // Create an OpenCL context
    cl_context context = clCreateContext( NULL, 1, &device_id, NULL, NULL, &ret);

    // Create a command queue
    cl_command_queue command_queue = clCreateCommandQueue(context, device_id, 0, &ret);

    // Create memory buffers on the device for each vector
    cl_mem output = clCreateBuffer(context, CL_MEM_WRITE_ONLY|CL_MEM_ALLOC_HOST_PTR,
                                      VPWIDTH * VPHEIGHT * sizeof(PIXEL), NULL, &ret);

    // Create a program from the kernel source
    cl_program program = clCreateProgramWithSource(context, 1,
                                                   (const char **)&source_str, (const size_t *)&source_size, &ret);

    // Build the program
    ret = clBuildProgram(program, 1, &device_id, NULL, NULL, NULL);

    // Create the OpenCL kernel
    cl_kernel kernel = clCreateKernel(program, "compute_ray", &ret);

    // Set the arguments of the kernel
    ret = clSetKernelArg(kernel, 0, sizeof(cl_mem), (void *)&output);
    if (ret != CL_SUCCESS) {
        fputs("error setting CL kernel arg 1\n", stderr);
        exit(1);
    }

    ret = clSetKernelArg(kernel, 1, sizeof(VECTOR3D), &view_point);
    if (ret != CL_SUCCESS) {
        fputs("error setting CL kernel arg 2\n", stderr);
        exit(1);
    }

    ret = clSetKernelArg(kernel, 2, sizeof(VECTOR3D), &camera_frame.n);
    if (ret != CL_SUCCESS) {
        fputs("error setting CL kernel arg 3\n", stderr);
        exit(1);
    }

    ret = clSetKernelArg(kernel, 3, sizeof(VECTOR3D), &camera_frame.u);
    if (ret != CL_SUCCESS) {
        fputs("error setting CL kernel arg 4\n", stderr);
        exit(1);
    }

    ret = clSetKernelArg(kernel, 4, sizeof(VECTOR3D), &camera_frame.v);
    if (ret != CL_SUCCESS) {
        fputs("error setting CL kernel arg 5\n", stderr);
        exit(1);
    }

    ret = clSetKernelArg(kernel, 5, sizeof(cl_int), &viewport.xvmin);
    if (ret != CL_SUCCESS) {
        fputs("error setting CL kernel arg 6\n", stderr);
        exit(1);
    }

    ret = clSetKernelArg(kernel, 6, sizeof(cl_int), &viewport.yvmin);
    if (ret != CL_SUCCESS) {
        fputs("error setting CL kernel arg 7\n", stderr);
        exit(1);
    }

    ret = clSetKernelArg(kernel, 7, sizeof(cl_double), &focal_distance);
    if (ret != CL_SUCCESS) {
        fputs("error setting CL kernel arg 7\n", stderr);
        exit(1);
    }

    ret = clSetKernelArg(kernel, 8, sizeof(cl_int), &VPWIDTH);
    if (ret != CL_SUCCESS) {
        fputs("error setting CL kernel arg 9\n", stderr);
        exit(1);
    }

    ret = clSetKernelArg(kernel, 9, sizeof(cl_int), &VPHEIGHT);
    if (ret != CL_SUCCESS) {
        fputs("error setting CL kernel arg 10\n", stderr);
        exit(1);
    }

    ret = clFinish(command_queue);

    // Execute the OpenCL kernel on the list
    size_t global_item_size = VPWIDTH * VPHEIGHT; // Process the entire lists
    size_t local_item_size = 1024; // Divide work items into groups of 64

    ret = clEnqueueNDRangeKernel(command_queue, kernel, 1, NULL,
                                 &global_item_size, &local_item_size, 0, NULL, NULL);

    // Read the memory buffer C on the device to the local variable C
    ret = clEnqueueReadBuffer(command_queue, output, CL_TRUE, 0,
                              VPWIDTH * VPHEIGHT * sizeof(PIXEL), pPixelsFromGPU, 0, NULL, NULL);

    // Display the result to the screen
    //for(i = 0; i < LIST_SIZE; i++)
    //    printf("%d + %d = %d\n", A[i], B[i], C[i]);

    // Clean up
//    ret = clFlush(command_queue);
//    ret = clFinish(command_queue);
//    ret = clReleaseKernel(kernel);
//    ret = clReleaseProgram(program);
//    ret = clReleaseMemObject(b_mem_obj);
//    ret = clReleaseCommandQueue(command_queue);
//    ret = clReleaseContext(context);


    pPixels = (PIXEL*) (pPixelsFromGPU);

    // For all pixels:
    for (i=0; i<VPWIDTH; i++) {
        for (j=0; j<VPHEIGHT; j++) {    
            //pCurrentPixel = (PIXEL*)(pPixels + VPWIDTH*i + j);
            // here I try to get pixel set on GPU, but it does not work
            pCurrentPixel = &pPixels[i*VPWIDTH+j];

        } //j
    } //i

    viewport.pPixels = (PIXEL*) (pPixelsFromGPU);

    // register callback function to display graphics:
    glutDisplayFunc(disp2);
    // call Timer():
    Timer(0);
    // enter tha main loop and process events:
    glutMainLoop();

    free(pPixelsFromGPU);

    return 0;
}
我故意将I、j、原点和方向结构设置为固定数字,以便查看是否设置了数字

然后我试着在GPU上设置像素

pCurrentPixel=&pPixels[i*VPWIDTH+j]

但是pCurrentPixel->i例如是0而不是33

代码使用以下命令编译:

gcc -c main.c -o main.o
gcc -c shading.c -o shading.o
gcc -c sphere.c -o sphere.o
gcc -c ray.c -o ray.o
gcc -c vectors.c -o vectors.o
gcc -I/usr/include -L/usr/lib/x86_64-linux-gnu main.o shading.o sphere.o ray.o vectors.o -lGL -lglut -lGLU -lX11 -lm -lrt -lOpenCL -o main

除了设置正确的VPWIDTH和VPHEIGHT
输出[i*w*j]=像素必须更改为
输出[i*w+j]=像素在C代码中。

如果它是您编写的结构数组,则可能是未定义的行为。例如,像素的大小可能与主机中的设备大小不同,可能需要不同的对齐方式。您需要提供正确的对齐方式。在您提供的代码中,不清楚
output[i*w*j]
的含义。
i
w
j
是索引吗?这些值是如何导出的?如何计算像素?最重要的是,您在代码中的什么地方为内核指定了
output
?此处提供的信息不足,无法诊断您的问题。已添加其他信息。我们仍需要更多信息。首先,重点应该放在习语的完整和可验证的部分上。我知道项目本身可能非常庞大,但仅仅在代码段之间放置
,就非常不清楚组件之间是如何连接的。分配参数的部分与提交参数的部分是同一个函数的一部分,还是分为不同的函数?如果是,这些函数是如何调用的?您可能会在提供足够的代码方面犯错误,这样我们就可以在正确配置的环境中自行编译。添加了几乎完整的代码。
typedef struct Vector3D {
    double x;
    double y;
    double z;
    double dummy1;
} VECTOR3D;

typedef struct ray {
    VECTOR3D origin;
    VECTOR3D direction;
} RAY;

typedef struct pixel {
    RAY ray;
    double rgb[4];
    int i;
    int j;
    int dummy1;
    int dummy2;
    int dummy3;
    int dummy4;
    int dummy5;
    int dummy6;
} PIXEL;

void vec_sub(VECTOR3D *v1, VECTOR3D *v2, VECTOR3D *v3) {
    v1->x = v2->x - v3->x;
    v1->y = v2->y - v3->y;
    v1->z = v2->z - v3->z;
}

void vec_add(VECTOR3D *v1, VECTOR3D *v2, VECTOR3D *v3) {
    v1->x = v2->x + v3->x;
    v1->y = v2->y + v3->y;
    v1->z = v2->z + v3->z;
}


void vec_scale(double scale, VECTOR3D *v1, VECTOR3D *v2) {
    v1->x = scale * v2->x;
    v1->y = scale * v2->y;
    v1->z = scale * v2->z;
}

double dotproduct(VECTOR3D *v1, VECTOR3D *v2) {

    return v1->x * v2->x + v1->y * v2->y + v1->z * v2->z;
}

void normalize_vector(VECTOR3D *v) {

    double magnitude;

    // 1. calculate the magnitude (length):
    magnitude = sqrt( dotproduct(v, v) );

    // 2. normalize the vector:
    v->x = v->x / magnitude;
    v->y = v->y / magnitude;
    v->z = v->z / magnitude;
}


__kernel void compute_ray(
        write_only global PIXEL *output,
        VECTOR3D view_point,
        VECTOR3D camera_frame_n,
        VECTOR3D camera_frame_u,
        VECTOR3D camera_frame_v,
        const int viewport_xvmin,
        const int viewport_yvmin,
        const double distance,
        const int w, const int h
)
{
    float u, v;
    VECTOR3D v1, v2, v3, v4, dir;
    RAY ray;
    PIXEL pixel;

    int gi = get_global_id(0);
    int i = gi / w;
    int j = gi % w;

    u = (float)(viewport_xvmin) + (float)(i) + 0.5f;
    v = (float)(viewport_yvmin) + (float)(j) + 0.5f;

    vec_scale(-distance, &v1, &camera_frame_n);
    vec_scale(u, &v2, &camera_frame_u);
    vec_scale(v, &v3, &camera_frame_v);

    ray.origin.x = 22;
    ray.origin.y = 22;
    ray.origin.z = 22;

    vec_add(&v4, &v1, &v2);
    vec_add(&dir, &v4, &v3);
    normalize_vector(&dir);

    ray.direction.x = 11;
    ray.direction.y = 11;
    ray.direction.z = 11;

    pixel.ray = ray;
    pixel.i = 33;
    pixel.j = 33;

    output[i*w*j] = pixel;
}
gcc -c main.c -o main.o
gcc -c shading.c -o shading.o
gcc -c sphere.c -o sphere.o
gcc -c ray.c -o ray.o
gcc -c vectors.c -o vectors.o
gcc -I/usr/include -L/usr/lib/x86_64-linux-gnu main.o shading.o sphere.o ray.o vectors.o -lGL -lglut -lGLU -lX11 -lm -lrt -lOpenCL -o main