More cleaning, small issue with copy by value sprites and textures. CL is spitting out erros that it isn't supposed to be able to spit out

This commit is contained in:
MitchellHansen
2017-04-04 02:21:45 -07:00
parent 3670d6509e
commit 941754d4f0
3 changed files with 191 additions and 189 deletions

View File

@@ -32,7 +32,7 @@ class OpenCL {
public: public:
OpenCL(sf::Vector2i resolution); OpenCL();
~OpenCL(); ~OpenCL();
// command queues are associated with a device and context, so for multi-gpu applications you would need // command queues are associated with a device and context, so for multi-gpu applications you would need
@@ -45,15 +45,28 @@ public:
// kernels on one or more devices specified in the context. // kernels on one or more devices specified in the context.
// - Contexts cannot be created using more than one platform! // - Contexts cannot be created using more than one platform!
bool init();
bool compile_kernel(std::string kernel_path, std::string kernel_name);
bool init(sf::Vector4f *range); // Create an image buffer from an SF texture. Access Type is the read/write specifier required by OpenCL
bool create_image_buffer(std::string buffer_name, sf::Texture* texture, cl_int access_type);
void run_kernel(std::string kernel_name); // Have CL create and manage the texture for the image buffer. Access Type is the read/write specifier required by OpenCL
bool create_image_buffer(std::string buffer_name, sf::Vector2i size, cl_int access_type);
// Create a buffer with CL_MEM_READ_ONLY and CL_MEM_COPY_HOST_PTR
int create_buffer(std::string buffer_name, cl_uint size, void* data);
// Create a buffer with user defined data access flags
int create_buffer(std::string buffer_name, cl_uint size, void* data, cl_mem_flags flags);
int set_kernel_arg(std::string kernel_name, int index, std::string buffer_name);
void run_kernel(std::string kernel_name, sf::Vector2i work_size);
void draw(sf::RenderWindow *window); void draw(sf::RenderWindow *window);
class device { class device {
public: public:
@@ -72,7 +85,8 @@ public:
#pragma pack(pop) #pragma pack(pop)
device(cl_device_id device_id, cl_platform_id platform_id); device(cl_device_id device_id, cl_platform_id platform_id);
void print(std::ostream& stream); device(const device& d);
void print(std::ostream& stream) const;
void print_packed_data(std::ostream& stream); void print_packed_data(std::ostream& stream);
cl_device_id getDeviceId() const { return device_id; }; cl_device_id getDeviceId() const { return device_id; };
@@ -92,21 +106,9 @@ public:
private: private:
bool load_config();
void save_config();
std::vector<device> device_list;
std::vector<std::pair<cl_platform_id, std::vector<cl_device_id>>> platforms_and_devices;
int error = 0; int error = 0;
// Sprite and texture that is shared between CL and GL
sf::Sprite viewport_sprite;
sf::Texture viewport_texture;
sf::Vector2i viewport_resolution;
// The device which we have selected according to certain criteria // The device which we have selected according to certain criteria
cl_platform_id platform_id; cl_platform_id platform_id;
@@ -119,41 +121,27 @@ private:
// Maps which contain a mapping from "name" to the host side CL memory object // Maps which contain a mapping from "name" to the host side CL memory object
std::unordered_map<std::string, cl_kernel> kernel_map; std::unordered_map<std::string, cl_kernel> kernel_map;
std::unordered_map<std::string, cl_mem> buffer_map; std::unordered_map<std::string, cl_mem> buffer_map;
std::unordered_map<std::string, std::pair<sf::Sprite, sf::Texture>> image_map;
std::vector<device> device_list;
// Query the hardware on this machine and select the best device and the platform on which it resides // Query the hardware on this machine and store the devices
void aquire_hardware(); bool aquire_hardware();
// After aquiring hardware, create a shared context using platform specific CL commands // After aquiring hardware, create a shared context using platform specific CL commands
void create_shared_context(); bool create_shared_context();
// Command queues must be created with a valid context // Command queues must be created with a valid context
void create_command_queue(); bool create_command_queue();
// Compile the kernel and store it in the kernel map with the name as the key
bool compile_kernel(std::string kernel_path, std::string kernel_name);
// Buffer operations
// All of these functions create and store a buffer in a map with the key representing their name
// Create an image buffer from an SF texture. Access Type is the read/write specifier required by OpenCL
int create_image_buffer(std::string buffer_name, cl_uint size, sf::Texture* texture, cl_int access_type);
// Create a buffer with CL_MEM_READ_ONLY and CL_MEM_COPY_HOST_PTR
int create_buffer(std::string buffer_name, cl_uint size, void* data);
// Create a buffer with user defined data access flags
int create_buffer(std::string buffer_name, cl_uint size, void* data, cl_mem_flags flags);
// Store a cl_mem object in the buffer map <string:name, cl_mem:buffer> // Store a cl_mem object in the buffer map <string:name, cl_mem:buffer>
int store_buffer(cl_mem buffer, std::string buffer_name); bool store_buffer(cl_mem buffer, std::string buffer_name);
// Using CL release the memory object and remove the KVP associated with the buffer name // Using CL release the memory object and remove the KVP associated with the buffer name
int release_buffer(std::string buffer_name); bool release_buffer(std::string buffer_name);
void assign_kernel_args(); bool load_config();
int set_kernel_arg(std::string kernel_name, int index, std::string buffer_name); void save_config();
static bool vr_assert(int error_code, std::string function_name); static bool vr_assert(int error_code, std::string function_name);

View File

@@ -1,10 +1,15 @@
#include <OpenCL.h> #include <OpenCL.h>
#include "util.hpp" #include "util.hpp"
OpenCL::OpenCL() {
}
void OpenCL::run_kernel(std::string kernel_name) { OpenCL::~OpenCL() {
}
size_t global_work_size[2] = { static_cast<size_t>(viewport_resolution.x), static_cast<size_t>(viewport_resolution.y) }; void OpenCL::run_kernel(std::string kernel_name, sf::Vector2i work_size) {
size_t global_work_size[2] = { static_cast<size_t>(work_size.x), static_cast<size_t>(work_size.y) };
cl_kernel kernel = kernel_map.at(kernel_name); cl_kernel kernel = kernel_map.at(kernel_name);
@@ -32,49 +37,60 @@ void OpenCL::run_kernel(std::string kernel_name) {
void OpenCL::draw(sf::RenderWindow *window) { void OpenCL::draw(sf::RenderWindow *window) {
window->draw(viewport_sprite); for (auto i: image_map) {
window->draw(i.second.first);
}
} }
void OpenCL::aquire_hardware() { bool OpenCL::aquire_hardware()
{
// Get the number of platforms // Get the number of platforms
cl_uint plt_cnt = 0; cl_uint platform_count = 0;
clGetPlatformIDs(0, nullptr, &plt_cnt); clGetPlatformIDs(0, nullptr, &platform_count);
if (platform_count == 0) {
std::cout << "There appears to be no OpenCL platforms on this machine" << std::endl;
return false;
}
// Get the ID's for those platforms // Get the ID's for those platforms
std::vector<cl_platform_id> plt_buf(plt_cnt); std::vector<cl_platform_id> plt_buf(platform_count);
clGetPlatformIDs(plt_cnt, plt_buf.data(), nullptr);
// Populate the storage vector with the platform id's clGetPlatformIDs(platform_count, plt_buf.data(), nullptr);
for (auto id : plt_buf) { if (vr_assert(error, "clGetPlatformIDs"))
platforms_and_devices.push_back(std::make_pair(id, std::vector<cl_device_id>())); return false;
}
int device_position = 0; // Cycle through the platform ID's
for (unsigned int i = 0; i < plt_cnt; i++) { for (unsigned int i = 0; i < platform_count; i++) {
// And get their device count
cl_uint deviceIdCount = 0; cl_uint deviceIdCount = 0;
error = clGetDeviceIDs(plt_buf[i], CL_DEVICE_TYPE_ALL, 0, nullptr, &deviceIdCount); error = clGetDeviceIDs(plt_buf[i], CL_DEVICE_TYPE_ALL, 0, nullptr, &deviceIdCount);
if (vr_assert(error, "clGetDeviceIDs"))
return false;
// Check to see if we even have OpenCL on this machine
if (deviceIdCount == 0) { if (deviceIdCount == 0) {
std::cout << "There appears to be no devices, or none at least supporting OpenCL" << std::endl; std::cout << "There appears to be no devices associated with this platform" << std::endl;
return;
}
// Get the device ids } else {
// Get the device ids and place them in the device list
std::vector<cl_device_id> deviceIds(deviceIdCount); std::vector<cl_device_id> deviceIds(deviceIdCount);
error = clGetDeviceIDs(plt_buf[i], CL_DEVICE_TYPE_ALL, deviceIdCount, deviceIds.data(), NULL); error = clGetDeviceIDs(plt_buf[i], CL_DEVICE_TYPE_ALL, deviceIdCount, deviceIds.data(), NULL);
if (vr_assert(error, "clGetDeviceIDs"))
return false;
for (int d = 0; d < deviceIds.size(); d++) { for (int d = 0; d < deviceIds.size(); d++) {
device_list.emplace_back(device(deviceIds[d], plt_buf.at(i))); device_list.emplace_back(device(deviceIds[d], plt_buf.at(i)));
} }
} }
} }
void OpenCL::create_shared_context() { }
bool OpenCL::create_shared_context() {
// Hurray for standards! // Hurray for standards!
// Setup the context properties to grab the current GL context // Setup the context properties to grab the current GL context
@@ -110,6 +126,11 @@ void OpenCL::create_shared_context() {
0 0
}; };
#elif
std::cout << "Target machine not supported for cl_khr_gl_sharing" << std::endl;
return false;
#endif #endif
// Create our shared context // Create our shared context
@@ -122,26 +143,29 @@ void OpenCL::create_shared_context() {
); );
if (vr_assert(error, "clCreateContext")) if (vr_assert(error, "clCreateContext"))
return; return false;
return true;
} }
void OpenCL::create_command_queue() { bool OpenCL::create_command_queue() {
// If context and device_id have initialized // Command queue requires a context and device id. It can also be a device ID list
// as long as the devices reside on the same platform
if (context && device_id) { if (context && device_id) {
command_queue = clCreateCommandQueue(context, device_id, 0, &error); command_queue = clCreateCommandQueue(context, device_id, 0, &error);
if (vr_assert(error, "clCreateCommandQueue")) if (vr_assert(error, "clCreateCommandQueue"))
return; return false;
return; } else {
}
else { std::cout << "Failed creating the command queue. Context or device_id not initialized" << std::endl;
std::cout << "Failed creating the command queue. Context or device_id not initialized"; return false;
return;
} }
return true;
} }
bool OpenCL::compile_kernel(std::string kernel_path, std::string kernel_name) { bool OpenCL::compile_kernel(std::string kernel_path, std::string kernel_name) {
@@ -200,23 +224,56 @@ bool OpenCL::compile_kernel(std::string kernel_path, std::string kernel_name) {
return true; return true;
} }
int OpenCL::create_image_buffer(std::string buffer_name, cl_uint size, sf::Texture* texture, cl_int access_type) { bool OpenCL::create_image_buffer(std::string buffer_name, sf::Texture* texture, cl_int access_type) {
if (buffer_map.count(buffer_name) > 0) { if (buffer_map.count(buffer_name) > 0) {
release_buffer(buffer_name); release_buffer(buffer_name);
// Need to check to see if we are taking care of the texture as well
if (image_map.count(buffer_name) > 0)
image_map.erase(buffer_name);
} }
int error;
cl_mem buff = clCreateFromGLTexture( cl_mem buff = clCreateFromGLTexture(
context, access_type, GL_TEXTURE_2D, context, access_type, GL_TEXTURE_2D,
0, texture->getNativeHandle(), &error); 0, texture->getNativeHandle(), &error);
if (vr_assert(error, "clCreateFromGLTexture")) if (vr_assert(error, "clCreateFromGLTexture"))
return 1; return false;
store_buffer(buff, buffer_name); store_buffer(buff, buffer_name);
return 1; return true;
}
bool OpenCL::create_image_buffer(std::string buffer_name, sf::Vector2i size, cl_int access_type) {
if (buffer_map.count(buffer_name) > 0) {
release_buffer(buffer_name);
// Need to check to see if we are taking care of the texture as well
if (image_map.count(buffer_name) > 0)
image_map.erase(buffer_name);
}
sf::Texture texture;
texture.create(size.x, size.y);
sf::Sprite sprite(texture);
image_map[buffer_name] = std::make_pair(sprite, texture);
cl_mem buff = clCreateFromGLTexture(
context, access_type, GL_TEXTURE_2D,
0, texture.getNativeHandle(), &error);
if (vr_assert(error, "clCreateFromGLTexture"))
return false;
store_buffer(buff, buffer_name);
return true;
} }
int OpenCL::create_buffer(std::string buffer_name, cl_uint size, void* data) { int OpenCL::create_buffer(std::string buffer_name, cl_uint size, void* data) {
@@ -258,45 +315,47 @@ int OpenCL::create_buffer(std::string buffer_name, cl_uint size, void* data, cl_
} }
int OpenCL::store_buffer(cl_mem buffer, std::string buffer_name) { bool OpenCL::store_buffer(cl_mem buffer, std::string buffer_name) {
if (buffer_map.count(buffer_name)) { if (buffer_map.count(buffer_name) > 0) {
clReleaseMemObject(buffer_map[buffer_name]);
error = clReleaseMemObject(buffer_map.at(buffer_name));
if (vr_assert(error, "clReleaseMemObject")) {
std::cout << "Error releasing overlapping buffer : " << buffer_name;
std::cout << "Buffer not added";
return false;
}
} }
buffer_map[buffer_name] = buffer; buffer_map[buffer_name] = buffer;
return 1; return true;
} }
int OpenCL::release_buffer(std::string buffer_name) { bool OpenCL::release_buffer(std::string buffer_name) {
if (buffer_map.count(buffer_name) > 0) { if (buffer_map.count(buffer_name) > 0) {
int error = clReleaseMemObject(buffer_map.at(buffer_name)); error = clReleaseMemObject(buffer_map.at(buffer_name));
if (vr_assert(error, "clReleaseMemObject")) { if (vr_assert(error, "clReleaseMemObject")) {
std::cout << "Error releasing buffer : " << buffer_name; std::cout << "Error releasing buffer : " << buffer_name;
std::cout << "Buffer not removed"; std::cout << "Buffer not removed";
return -1; return false;
} }
else {
buffer_map.erase(buffer_name); buffer_map.erase(buffer_name);
}
} } else {
else {
std::cout << "Error releasing buffer : " << buffer_name; std::cout << "Error releasing buffer : " << buffer_name;
std::cout << "Buffer not found"; std::cout << "Buffer not found";
return -1; return false;
} }
return 1; return true;
}
void OpenCL::assign_kernel_args() {
} }
int OpenCL::set_kernel_arg(std::string kernel_name, int index, std::string buffer_name) { int OpenCL::set_kernel_arg(std::string kernel_name, int index, std::string buffer_name) {
@@ -315,19 +374,6 @@ int OpenCL::set_kernel_arg(std::string kernel_name, int index, std::string buffe
return 1; return 1;
} }
OpenCL::OpenCL(sf::Vector2i resolution) : viewport_resolution(resolution){
viewport_texture.create(viewport_resolution.x, viewport_resolution.y);
viewport_sprite.setTexture(viewport_texture);
}
OpenCL::~OpenCL() {
}
bool OpenCL::load_config() { bool OpenCL::load_config() {
std::ifstream input_file("device_config.bin", std::ios::binary | std::ios::in); std::ifstream input_file("device_config.bin", std::ios::binary | std::ios::in);
@@ -368,11 +414,10 @@ void OpenCL::save_config() {
output_file.close(); output_file.close();
} }
bool OpenCL::init(sf::Vector4f *range) bool OpenCL::init() {
{
// Initialize opencl up to the point where we start assigning buffers if (!aquire_hardware())
aquire_hardware(); return false;
if (!load_config()) { if (!load_config()) {
@@ -399,25 +444,14 @@ bool OpenCL::init(sf::Vector4f *range)
platform_id = device_list.at(selection).getPlatformId(); platform_id = device_list.at(selection).getPlatformId();
save_config(); save_config();
} }
create_shared_context(); if (!create_shared_context())
return false;
create_command_queue(); if (!create_command_queue())
return false;
while (!compile_kernel("../kernels/mandlebrot.cl", "mandlebrot")) {
std::cin.get();
}
create_image_buffer("viewport_image", viewport_texture.getSize().x * viewport_texture.getSize().x * 4 * sizeof(float), &viewport_texture, CL_MEM_WRITE_ONLY);
create_buffer("image_res", sizeof(sf::Vector2i), &viewport_resolution);
create_buffer("range", sizeof(sf::Vector4f), range, CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR);
set_kernel_arg("mandlebrot", 0, "image_res");
set_kernel_arg("mandlebrot", 1, "viewport_image");
set_kernel_arg("mandlebrot", 2, "range");
return true; return true;
} }
@@ -648,7 +682,20 @@ OpenCL::device::device(cl_device_id device_id, cl_platform_id platform_id) {
} }
void OpenCL::device::print(std::ostream& stream) { OpenCL::device::device(const device& d) {
// member values, copy individually
device_id = d.device_id;
platform_id = d.platform_id;
is_little_endian = d.is_little_endian;
cl_gl_sharing = d.cl_gl_sharing;
// struct so it copies by value
data = d.data;
}
void OpenCL::device::print(std::ostream& stream) const {
stream << "\n\tDevice ID : " << device_id << std::endl; stream << "\n\tDevice ID : " << device_id << std::endl;
stream << "\tDevice Name : " << data.device_name << std::endl; stream << "\tDevice Name : " << data.device_name << std::endl;

View File

@@ -24,64 +24,39 @@ float elap_time() {
const int WINDOW_X = 1920; const int WINDOW_X = 1920;
const int WINDOW_Y = 1080; const int WINDOW_Y = 1080;
float scale(float valueIn, float origMin, float origMax, float scaledMin, float scaledMax) {
return ((scaledMax - scaledMin) * (valueIn - origMin) / (origMax - origMin)) + scaledMin;
}
void func(int id, int count, sf::Uint8* pixels) {
for (int pixel_x = 0; pixel_x < WINDOW_X; pixel_x++) {
for (int pixel_y = (WINDOW_Y * ((float)id / count)); pixel_y < (WINDOW_Y * ((float)(id + 1) / count)); pixel_y++) {
float y0 = scale(pixel_y, 0, WINDOW_Y, -1.0f, 1.0f);
float x0 = scale(pixel_x, 0, WINDOW_X, -2.0f, 1.0f);
float x = 0.0;
float y = 0.0;
int iteration_count = 0;
int interation_threshold = 1000;
while (x*x + y*y < 4 && iteration_count < interation_threshold) {
float x_temp = x*x - y*y + x0;
y = 2 * x * y + y0;
x = x_temp;
iteration_count++;
}
sf::Color c(0, 0, scale(iteration_count, 0, 1000, 0, 255), 255);
int val = scale(iteration_count, 0, 1000, 0, 16777216);
pixels[(pixel_y * WINDOW_X + pixel_x) * 4 + 0] = val & 0xff;
pixels[(pixel_y * WINDOW_X + pixel_x) * 4 + 1] = (val >> 8) & 0xff;
pixels[(pixel_y * WINDOW_X + pixel_x) * 4 + 2] = (val >> 16) & 0xff;
pixels[(pixel_y * WINDOW_X + pixel_x) * 4 + 3] = 200;
}
}
}
enum Mouse_State {PRESSED, DEPRESSED}; enum Mouse_State {PRESSED, DEPRESSED};
int main() { int main() {
std::mt19937 rng(time(NULL));
std::uniform_int_distribution<int> rgen(100, 400);
sf::RenderWindow window(sf::VideoMode(WINDOW_X, WINDOW_Y), "quick-sfml-template"); sf::RenderWindow window(sf::VideoMode(WINDOW_X, WINDOW_Y), "quick-sfml-template");
window.setFramerateLimit(60); window.setFramerateLimit(60);
float physic_step = 0.166f; float physic_step = 0.166f;
float physic_time = 0.0f; float physic_time = 0.0f;
double frame_time = 0.0, elapsed_time = 0.0, delta_time = 0.0, accumulator_time = 0.0, current_time = 0.0; double frame_time = 0.0, elapsed_time = 0.0, delta_time = 0.0, accumulator_time = 0.0, current_time = 0.0;
fps_counter fps;
OpenCL cl(sf::Vector2i(WINDOW_X, WINDOW_Y)); OpenCL cl;
sf::Vector4f range(-1.0f, 1.0f, -1.0f, 1.0f); sf::Vector4f range(-1.0f, 1.0f, -1.0f, 1.0f);
cl.init(&range); sf::Vector2i window_dimensions(WINDOW_X, WINDOW_Y);
cl.init();
while (!cl.compile_kernel("../kernels/mandlebrot.cl", "mandlebrot")) {
std::cin.get();
}
sf::Texture t;
t.create(WINDOW_X, WINDOW_Y);
sf::Sprite window_sprite(t);
cl.create_image_buffer("viewport_image", &t, CL_MEM_WRITE_ONLY);
cl.create_buffer("image_res", sizeof(sf::Vector2i), &window_dimensions);
cl.create_buffer("range", sizeof(sf::Vector4f), (void*)&range, CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR);
cl.set_kernel_arg("mandlebrot", 0, "image_res");
cl.set_kernel_arg("mandlebrot", 1, "viewport_image");
cl.set_kernel_arg("mandlebrot", 2, "range");
while (window.isOpen()) while (window.isOpen())
{ {
@@ -130,23 +105,15 @@ int main() {
accumulator_time += delta_time; accumulator_time += delta_time;
while (accumulator_time >= physic_step) { // While the frame has sim time, update while (accumulator_time >= physic_step) { // While the frame has sim time, update
accumulator_time -= physic_step; accumulator_time -= physic_step;
physic_time += physic_step; physic_time += physic_step;
// Do physics at 60fps
} }
cl.run_kernel("mandlebrot");
window.clear(sf::Color::White); window.clear(sf::Color::White);
cl.run_kernel("mandlebrot", window_dimensions);
cl.draw(&window); cl.draw(&window);
window.draw(window_sprite);
//window.draw(viewport_sprite);
fps.draw(&window);
fps.frame(delta_time);
window.display(); window.display();