-
Notifications
You must be signed in to change notification settings - Fork 58
-
Hi, I'm trying to get arrayfire and glium to cooperate; Is that currently possible with both libraries as they are? or is there some lower level work that needs to be done?
Basically trying to figure out how to do this:
let arr: Array<f32> glium::VertexBuffer::new_raw(display as &Facade, arr.device_ptr() ,bindings, arr.elements() * std::mem::size_of::<f32>()).unwrap() //or glium::buffer::Buffer::new<f32>(display as &Facade, arr.device_ptr(), BufferType::TextureBuffer, glium::buffer::BufferMode::Default)
while keeping everything on the gpu and avoiding expensive gpu->cpu->gpu operations.
Is this even possible? And if so, what steps need to be taken?
Thanks!
Beta Was this translation helpful? Give feedback.
All reactions
@nodeSpace Yes, I believe it is completely possible to do that. However, it would require some additional helper code apart from using the libraries glium and arrayfire. arrayfire/forge essentially handles the same workflow(avoids via CPU data transfers) which is ArrayFire's graphics(OpenGL based) functionality provider.
Let's say you are using CUDA backend of ArrayFire. Have a look at the functions from forge helper header: createGLBuffer, copyToGLBuffer, releaseGLBuffer for an idea on C++ code does it. You would need similar functions in rust that are written with glium as target. I think the following steps should essentially let you handle the OpenGL interop successfully.
- Create a sh...
Replies: 1 comment 5 replies
-
@nodeSpace Yes, I believe it is completely possible to do that. However, it would require some additional helper code apart from using the libraries glium and arrayfire. arrayfire/forge essentially handles the same workflow(avoids via CPU data transfers) which is ArrayFire's graphics(OpenGL based) functionality provider.
Let's say you are using CUDA backend of ArrayFire. Have a look at the functions from forge helper header: createGLBuffer, copyToGLBuffer, releaseGLBuffer for an idea on C++ code does it. You would need similar functions in rust that are written with glium as target. I think the following steps should essentially let you handle the OpenGL interop successfully.
- Create a shared resource handle
cudaGraphicsResourcein rust using vertex buffer resource id returned by glium. Note that this vertex buffer's size in bytes should match the array you want to display. Matching data type is also important - Essentially whatcreateGLBufferdoes in forge project - Copy data from CUDA device pointer to shared resource created in step (1). Note that this is also a device buffer sitting on GPU. So, you are essentially only doing a device-to-device memcopy which is many times faster than host-to-device/device-to-host copy. - Essentially what
copyToGLBufferdoes in forge project. - Release the shared resource handle during program exit or when you are done using it.
This workflow would need CUDA rust API. You can take a look at arrayfire's CUDA/OpenCL interop crates to see what we use in those projects. Any crate exposes CUDA API will do the job of creating/copying/releasing the shared CUDA-OpenGL resource.
The entire process remains the same if you use OpenCL backend with OpenCL APIs replacing their respective CUDA APIs.
Updated
My mistake, I didn't mention one additional detail regarding OpenCL, you would need to some additional modifications to your code.
Firstly, use ArrayFire's OpenCL interop crate - https://github.com/arrayfire/arrayfire-rust/tree/master/opencl-interop
You need to use some crate that enables you use OpenCL API in rust, you can use the OpenCL crate that af-opencl-interop crate uses for easy integration.
The following are the additional steps:
- create an OpenCL context using OpenGL context handle
- Now add the device on which context from step (1) is created and the context itself to ArrayFire device manager - Please look at the documentation of af_opencl_interop for relevant functions.
- Set device to this newly added device in ArrayFire and use that for computations.
With the above setup done before any devices are used by OpenCL in ArrayFire. You should be able to share the OpenCL-OpenGL context. There are some examples in af-opencl-interop crate, please have a look - they might help with figuring out the opencl context creation etc.
Beta Was this translation helpful? Give feedback.
All reactions
-
Hi, thanks for the reply!
I used opencl (because need it to run on cards that aren't nvidia) and followed the steps you outlined.
It took a while, but when I thought I finally got it to work, I got:
################################ OPENCL ERROR ###############################
Error executing function: clEnqueueCopyBuffer
Status error code: CL_INVALID_CONTEXT (-34)
So it looks like I can't transfer data from the arrayfire context to opencl context.
Am I missing something, or is there a way around this?
Thanks for the help!
Beta Was this translation helpful? Give feedback.
All reactions
-
Updated the original answer.
Beta Was this translation helpful? Give feedback.
All reactions
-
Ah thanks! ok
Alright, so Ive been trying to get the add_device_context and set_device_context working, but no matter what I did afcl::add_device_context would panic with Error message: Unsupported operation/parameter option.
I finally just pretty much straight copy pasted the first part of the interop example:
// Choose platform & device(s) to use. Create a context, queue, let platform_id = ocl_core::default_platform().unwrap(); let device_ids = ocl_core::get_device_ids(&platform_id, None, None).unwrap(); let device_id = device_ids[0]; let context_properties = ocl_core::ContextProperties::new().platform(platform_id); let context = ocl_core::create_context(Some(&context_properties), &[device_id], None, None).unwrap(); let queue = ocl_core::create_command_queue(&context, &device_id, None).unwrap(); let dims = [8, 1, 1]; // Create a `Buffer`: let mut vec = vec![0.0f32; dims[0]]; let buffer = unsafe { ocl_core::create_buffer( &context, ocl_core::MEM_READ_WRITE | ocl_core::MEM_COPY_HOST_PTR, dims[0], Some(&vec), ) .unwrap() }; ocl_core::finish(&queue).unwrap(); //sync up before switching to arrayfire // Add custom device, context and associated queue to ArrayFire afcl::add_device_context(device_id.as_raw(), context.as_ptr(), queue.as_ptr()); afcl::set_device_context(device_id.as_raw(), context.as_ptr()); af::info();
and it still threw the same error.
So at this point i'm a bit at a loss how to resolve this,
sorry for all the questions and thanks for answering them so far!
Update:
was able to fix the above issue and get the example to work by calling arrayfire::set_backend(arrayfire::Backend::OPENCL); first. Seems my computer has cuda so it was defaulting to that and the example didn't account for that.
Beta Was this translation helpful? Give feedback.
All reactions
-
Ah, I see what you mean. It wasn't setting for the right interop-backend. Sorry about that. I shall update the example. You are also welcome to send in a small PR to fix the same.
Beta Was this translation helpful? Give feedback.
All reactions
-
Was still crashing even after fixing the above issue, seems I'm running into another issue with this; see: #282 (comment)
Beta Was this translation helpful? Give feedback.