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

master
MitchellHansen 8 years ago
parent 3670d6509e
commit 941754d4f0

@ -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,14 +45,27 @@ 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);
void draw(sf::RenderWindow *window); // 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);
class device { class device {
@ -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,42 +121,28 @@ 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);
}; };

@ -1,10 +1,15 @@
#include <OpenCL.h> #include <OpenCL.h>
#include "util.hpp" #include "util.hpp"
OpenCL::OpenCL() {
}
OpenCL::~OpenCL() {
}
void OpenCL::run_kernel(std::string kernel_name) { void OpenCL::run_kernel(std::string kernel_name, sf::Vector2i work_size) {
size_t global_work_size[2] = { static_cast<size_t>(viewport_resolution.x), static_cast<size_t>(viewport_resolution.y) }; 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;
} } else {
// Get the device ids
std::vector<cl_device_id> deviceIds(deviceIdCount);
error = clGetDeviceIDs(plt_buf[i], CL_DEVICE_TYPE_ALL, deviceIdCount, deviceIds.data(), NULL);
for (int d = 0; d < deviceIds.size(); d++) {
device_list.emplace_back(device(deviceIds[d], plt_buf.at(i))); // Get the device ids and place them in the device list
std::vector<cl_device_id> deviceIds(deviceIdCount);
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++) {
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();
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); if (!create_command_queue())
create_buffer("image_res", sizeof(sf::Vector2i), &viewport_resolution); return false;
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;

@ -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();

Loading…
Cancel
Save