#ifndef GPU_APPLICATION_H #define GPU_APPLICATION_H #include #include // needs to be after glad.h #include #include #include #include #include "shader.h" #include "CL_Helpers.h" // Interface class GPUApplication { public: virtual bool InitGL() = 0; virtual void Run() = 0; virtual void Cleanup() = 0; std::string kernelFile; protected: cl::Platform platform; cl::Device device; cl::Context context; cl::CommandQueue queue; cl::Program program; public: bool InitCL() { // Find a combination of a cl::Platform and cl::Device to run OpenCL // ----------------------------------------------------------------- { std::vector> foundPlatformDeviceCombinations; bool found = false; std::stringstream setupOutput; std::vector allPlatforms; cl::Platform::get(&allPlatforms); std::vector deviceTypes; #if !defined(__APPLE__) && !defined(__MACOSX) deviceTypes.push_back(CL_DEVICE_TYPE_ACCELERATOR); deviceTypes.push_back(CL_DEVICE_TYPE_CPU); #endif deviceTypes.push_back(CL_DEVICE_TYPE_GPU); setupOutput << "Found the following platforms and devices:" << std::endl; for (auto& p : allPlatforms) { std::string pname = p.getInfo(); if (pname.find("Clover") == std::string::npos) { std::string platver = p.getInfo(); setupOutput << " - Platform name: " << pname << std::endl; setupOutput << " Platform version: " << platver << std::endl; for (auto& devType : deviceTypes) { std::vector devices; p.getDevices(devType, &devices); if (devices.size()) { setupOutput << " Device name: " << devices[0].getInfo< CL_DEVICE_NAME>() << std::endl; foundPlatformDeviceCombinations.push_back(std::pair(p, devices[0])); } } } } if (foundPlatformDeviceCombinations.size() == 0) { std::cout << "Error: no OpenCL platform-device combination found.\n"; return false; } std::cout << setupOutput.str(); // Choose here which combination you would like to use // --------------------------------------------------- int idxOfPlatformAndDevice = 0; platform = foundPlatformDeviceCombinations[idxOfPlatformAndDevice].first; device = foundPlatformDeviceCombinations[idxOfPlatformAndDevice].second; if ((cl::Platform::setDefault(platform) != platform) || (cl::Device::setDefault(device) != device)) { std::cout << "Error: could not set the default platform/devide" << std::endl; return false; } std::cout << "Picked combination " << idxOfPlatformAndDevice << ", i.e. " << platform.getInfo() << ", " << platform.getInfo() << ", " << device.getInfo< CL_DEVICE_NAME>() << std::endl; } // Setup cl::Context and cl::CommandQueue // -------------------------------------- //cl::Context context; // necessary to manage objects such as CommandQueues, memory, program, kernel objects and for executing kernels on 1/more devices specified in the Context //cl::CommandQueue queue; // necessary to push command onto the device { cl_int err = CL_SUCCESS; context = cl::Context(device, NULL, NULL, NULL, &err); if ((context() == 0) || (err != CL_SUCCESS)) { std::cout << "Error: failed to create the context. Bad installation?" << std::endl; if (err != CL_SUCCESS) std::cout << " " << ClErrorToString(err) << std::endl; return false; } queue = cl::CommandQueue(context, device, 0, &err); if ((queue() == 0) || (err != CL_SUCCESS)) { std::cout << "Error: failed to create the queue. Bad installation?" << std::endl; if (err != CL_SUCCESS) std::cout << " " << ClErrorToString(err) << std::endl; return false; } if ((cl::Context::setDefault(context) != context) || (cl::CommandQueue::setDefault(queue) != queue)) { std::cout << "Error: could not set the default context/commandqueue" << std::endl; return false; } } // Compile and build the kernel // -------------------------------------- std::ifstream ifs(kernelFile.c_str()); const std::string kernel_code((std::istreambuf_iterator(ifs)), (std::istreambuf_iterator())); if (kernel_code.size() == 0) { std::cout << "Error: failed to read file " << kernelFile << std::endl; return false; } cl::Program::Sources sources; sources.push_back({ kernel_code.c_str(),kernel_code.length() }); // Program links source code to context program = cl::Program(context, sources); // build source code if (program.build() != CL_SUCCESS) { std::cout << " Error building: " << program.getBuildInfo(device) << "\n"; return false; } return true; } }; // Child classes class GpuSimpleAdd : public GPUApplication { public: GpuSimpleAdd(std::string kernelFile); bool InitGL() override; void Run() override; void Cleanup() override; }; class GpuPerlinNoise : public GPUApplication { public: GpuPerlinNoise(std::string kernelFile); bool InitGL() override; void Run() override; void Cleanup() override; protected: bool HandleUserInput(); GLFWwindow* window = NULL; Shader shader; GLuint VAO; GLuint texture; float elevation = 0; float azimuth = 0; }; class GpuParticleSystem : public GPUApplication { public: GpuParticleSystem(std::string kernelFile); bool InitGL() override; void Run() override; void Cleanup() override; protected: void InitPosVel(); bool HandleUserInput(); GLFWwindow* window = NULL; Shader shader; GLuint VAO = 0; GLuint VBOs[2] = { 0 , 0 }; int nrParticles = 2000; std::vector positions; std::vector velocities; bool reset = false; float cursorX = 0; float cursorY = 0; }; #endif