This repository has been archived on 2024-12-30. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.
2024CG-project-render/include/GpuApplication.h
2024-11-15 14:50:01 +01:00

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