192 lines
5.7 KiB
C++
192 lines
5.7 KiB
C++
#ifndef GPU_APPLICATION_H
|
|
#define GPU_APPLICATION_H
|
|
|
|
#include <glad/glad.h>
|
|
#include <GLFW/glfw3.h> // needs to be after glad.h
|
|
#include <iostream>
|
|
#include <string>
|
|
#include <stdio.h>
|
|
#include <chrono>
|
|
#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<std::pair<cl::Platform, cl::Device>> foundPlatformDeviceCombinations;
|
|
bool found = false;
|
|
std::stringstream setupOutput;
|
|
std::vector<cl::Platform> allPlatforms;
|
|
cl::Platform::get(&allPlatforms);
|
|
std::vector<cl_device_type> 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<CL_PLATFORM_NAME>();
|
|
if (pname.find("Clover") == std::string::npos)
|
|
{
|
|
std::string platver = p.getInfo<CL_PLATFORM_VERSION>();
|
|
setupOutput << " - Platform name: " << pname << std::endl;
|
|
setupOutput << " Platform version: " << platver << std::endl;
|
|
|
|
for (auto& devType : deviceTypes)
|
|
{
|
|
std::vector<cl::Device> devices;
|
|
p.getDevices(devType, &devices);
|
|
if (devices.size())
|
|
{
|
|
setupOutput << " Device name: " << devices[0].getInfo< CL_DEVICE_NAME>() << std::endl;
|
|
foundPlatformDeviceCombinations.push_back(std::pair<cl::Platform, cl::Device>(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<CL_PLATFORM_NAME>() << ", "
|
|
<< platform.getInfo<CL_PLATFORM_VERSION>() << ", "
|
|
<< 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<char>(ifs)), (std::istreambuf_iterator<char>()));
|
|
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<CL_PROGRAM_BUILD_LOG>(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<float> positions;
|
|
std::vector<float> velocities;
|
|
bool reset = false;
|
|
float cursorX = 0;
|
|
float cursorY = 0;
|
|
};
|
|
|
|
|
|
#endif
|