2017-05-15 1 views
0

Je fais mes premiers pas bancaux avec OpenCL (l'API C++) et j'ai rencontré un problème où je suis à bout de nerfs et je n'ai aucune idée de quoi peut-être tort. Lors de la définition de l'argument du noyau image2d_t (voir le code distillé ci-dessous), l'appel se déclenche et renvoie le code d'erreur -50 (= CL_INVALID_ARG_VALUE) et je n'ai aucune idée de la raison. J'utilise la plateforme Intel OpenCL et mon CPU (OpenCL 2.0) et j'ai pu compiler et exécuter d'autres exemples de code sans aucun problème.C++ OpenCL kernel retourne CL_INVALID_ARG_VALUE pour __read_only image2d_t

#include "stdafx.h" 

#include <vector> 
#include <string> 
#include <iostream> 

#define CL_HPP_ENABLE_EXCEPTIONS 
#define CL_HPP_TARGET_OPENCL_VERSION 200 

#include <CL/cl2.hpp> 

std::string my_kernel = R"(
__constant sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE; 

__kernel void simple_copy( __read_only image2d_t input_image 
         , __write_only image2d_t output_image 
         ) 
{ 
    int2 coords; 
    coords.x = get_global_id(0); 
    coords.y = get_global_id(1); 

    float4 value = read_imagef(input_image, sampler, coords); 
    write_imagef(output_image, coords, value); 
})"; 

int main() 
{ 
    try 
    { 
     //define source and destination image data 
     constexpr unsigned channels = 4, width = 2, height = 2; 
     std::array<std::uint8_t, channels*width*height> source = { 0,0,0,255, 255,0,0,255, 0,255,0,255, 0,0,255,255 }; 
     std::array<std::uint8_t, channels*width*height> destination{}; //value initialization 

     //initialize OpenCL 
     std::vector<cl::Platform> platforms; 
     cl::Platform::get(&platforms); 
     auto platform = platforms.front(); 
     std::vector<cl::Device> devices; 
     platform.getDevices(CL_DEVICE_TYPE_ALL, &devices); 
     auto device = devices.front(); 
     auto context = cl::Context(device); 
     auto queue = cl::CommandQueue(context, device); 

     //create OpenCL image buffers 
     auto image_format = cl::ImageFormat(CL_RGBA, CL_UNSIGNED_INT8); 
     auto input_image = cl::Image2D(context, CL_MEM_READ_ONLY, image_format, width, height); 
     auto output_image = cl::Image2D(context, CL_MEM_WRITE_ONLY, image_format, width, height); 

     //transfer source image data to device 
     auto origin = cl::array<cl::size_type, 3U>{0, 0, 0}; 
     auto region = cl::array<cl::size_type, 3U>{width, height, 1}; 
     queue.enqueueWriteImage(input_image, CL_TRUE, origin, region, 0, 0, &source[0]); 

     //compile device code, retrieve kernel, set kernel arguments 
     auto program = cl::Program(my_kernel, CL_TRUE); 
     auto kernel = cl::Kernel(program, "simple_copy"); 
     kernel.setArg(0, input_image); //ERROR: throws -50 (= CL_INVALID_ARG_VALUE) ... why?! 
     kernel.setArg(1, output_image); 

     //enqueue copy kernel 
     queue.enqueueNDRangeKernel(kernel, cl::NullRange, cl::NDRange(width, height), cl::NullRange); 

     //read result back to host 
     queue.enqueueReadImage(output_image, CL_TRUE, origin, region, 0, 0, &destination[0]); 

     //output result 
     for (auto const & val : destination) 
     { 
      std::cout << val << " "; 
     } 
     std::cout << std::endl; 
    } 
    catch (cl::Error & e) 
    { 
     std::cout << "caught OpenCL exception - what: " << e.what() << " err: " << e.err() << std::endl; 
    } 
    std::string str; 
    std::getline(std::cin, str); 
    return 0; 
} 

Répondre

0

Créer votre programme avec un contexte, comme suit:

auto program = cl::Program(context, my_kernel, CL_TRUE); 
+0

merci, ce fut en effet la source de problème! Savez-vous par hasard pourquoi l'appel sans contexte ou périphérique est même autorisé? (Je suppose qu'il est supposé utiliser le contexte/périphérique par défaut si j'en avais défini un? Cependant, je ne vois pas pourquoi il ne lance pas s'il n'y a pas de défaut ...?) –

+0

Il utilisera le contexte par défaut et créera un si l'un n'existe pas. Je suis d'accord que c'est un peu déroutant quand faire ce que je veux dire ne fait pas ce que vous pensiez. –