cl3/
gl.rs

1// Copyright (c) 2021-2024 Via Technology Ltd.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//    http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! `OpenCL` `OpenGL` Interoperability API.
16
17#![allow(unused_unsafe)]
18#![allow(non_camel_case_types, deprecated)]
19#![allow(clippy::not_unsafe_ptr_arg_deref, clippy::missing_safety_doc)]
20
21pub use opencl_sys::{
22    cl_GLenum, cl_GLint, cl_GLsync, cl_GLuint, cl_command_queue, cl_context, cl_context_properties,
23    cl_event, cl_gl_context_info, cl_gl_object_type, cl_gl_platform_info, cl_gl_texture_info,
24    cl_int, cl_mem, cl_mem_flags, cl_uint, CL_CGL_SHAREGROUP_KHR,
25    CL_COMMAND_GL_FENCE_SYNC_OBJECT_KHR, CL_CURRENT_DEVICE_FOR_GL_CONTEXT_KHR,
26    CL_DEVICES_FOR_GL_CONTEXT_KHR, CL_EGL_DISPLAY_KHR, CL_GLX_DISPLAY_KHR, CL_GL_CONTEXT_KHR,
27    CL_GL_MIPMAP_LEVEL, CL_GL_NUM_SAMPLES, CL_GL_OBJECT_BUFFER, CL_GL_OBJECT_RENDERBUFFER,
28    CL_GL_OBJECT_TEXTURE1D, CL_GL_OBJECT_TEXTURE1D_ARRAY, CL_GL_OBJECT_TEXTURE2D,
29    CL_GL_OBJECT_TEXTURE2D_ARRAY, CL_GL_OBJECT_TEXTURE3D, CL_GL_OBJECT_TEXTURE_BUFFER,
30    CL_GL_TEXTURE_TARGET, CL_INVALID_VALUE, CL_KHR_GL_SHARING, CL_SUCCESS, CL_WGL_HDC_KHR,
31};
32
33use super::info_type::InfoType;
34use super::{api_info_size, api_info_value, api_info_vector};
35#[allow(unused_imports)]
36use libc::{c_void, intptr_t, size_t};
37use std::mem;
38use std::ptr;
39
40/// Create an `OpenCL` buffer object for a context from an OpenGL buffer.
41/// Calls clCreateFromGLBuffer to create an `OpenCL` buffer object.
42///
43/// * `context` - a valid `OpenCL` context created from an OpenGL context.
44/// * `flags` - a bit-field used to specify allocation and usage information
45///   about the image memory object being created, see:
46///   [Memory Flags](https://www.khronos.org/registry/OpenCL/specs/3.0-unified/html/OpenCL_API.html#memory-flags-table).
47/// * `bufobj` - the OpenGL buffer.
48///
49/// returns a Result containing the new `OpenCL` buffer object
50/// or the error code from the `OpenCL` C API function.
51#[inline]
52pub unsafe fn create_from_gl_buffer(
53    context: cl_context,
54    flags: cl_mem_flags,
55    bufobj: cl_GLuint,
56) -> Result<cl_mem, cl_int> {
57    let mut status: cl_int = CL_INVALID_VALUE;
58    let mem = cl_call!(clCreateFromGLBuffer(context, flags, bufobj, &mut status));
59    if CL_SUCCESS == status {
60        Ok(mem)
61    } else {
62        Err(status)
63    }
64}
65
66/// Create an `OpenCL` image object, image array object, or image buffer object.
67///
68/// For a context from an OpenGL texture object, texture array object,
69/// texture buffer object, or a single face of an OpenGL cubemap texture object.
70/// Calls clCreateFromGLTexture to create an `OpenCL` memory object.
71///
72/// * `context` - a valid `OpenCL` context created from an OpenGL context.
73/// * `flags` - a bit-field used to specify allocation and usage information
74///   about the image memory object being created, see:
75///   [Memory Flags](https://www.khronos.org/registry/OpenCL/specs/3.0-unified/html/OpenCL_API.html#memory-flags-table).
76/// * `texture_target` - used to define the image type of texture.
77/// * `miplevel ` - used to define the mipmap level.
78/// * `texture  ` - the name of a GL buffer texture object.
79///
80/// returns a Result containing the new `OpenCL` image object
81/// or the error code from the `OpenCL` C API function.
82#[inline]
83pub unsafe fn create_from_gl_texture(
84    context: cl_context,
85    flags: cl_mem_flags,
86    texture_target: cl_GLenum,
87    miplevel: cl_GLint,
88    texture: cl_GLuint,
89) -> Result<cl_mem, cl_int> {
90    let mut status: cl_int = CL_INVALID_VALUE;
91    let mem = cl_call!(clCreateFromGLTexture(
92        context,
93        flags,
94        texture_target,
95        miplevel,
96        texture,
97        &mut status,
98    ));
99    if CL_SUCCESS == status {
100        Ok(mem)
101    } else {
102        Err(status)
103    }
104}
105
106/// Create an `OpenCL` 2D image object from an OpenGL renderbuffer object.
107///
108/// Calls clCreateFromGLRenderbuffer to create an `OpenCL` buffer object.
109///
110/// * `context` - a valid `OpenCL` context created from an OpenGL context.
111/// * `flags` - a bit-field used to specify allocation and usage information
112///   about the image memory object being created, see:
113///   [Memory Flags](https://www.khronos.org/registry/OpenCL/specs/3.0-unified/html/OpenCL_API.html#memory-flags-table).
114/// * `renderbuffer`  - a GL renderbuffer object.
115///
116/// returns a Result containing the new `OpenCL` image object
117/// or the error code from the `OpenCL` C API function.
118#[inline]
119pub unsafe fn create_from_gl_render_buffer(
120    context: cl_context,
121    flags: cl_mem_flags,
122    renderbuffer: cl_GLuint,
123) -> Result<cl_mem, cl_int> {
124    let mut status: cl_int = CL_INVALID_VALUE;
125    let mem = cl_call!(clCreateFromGLRenderbuffer(
126        context,
127        flags,
128        renderbuffer,
129        &mut status
130    ));
131    if CL_SUCCESS == status {
132        Ok(mem)
133    } else {
134        Err(status)
135    }
136}
137
138/// Query an OpenGL object used to create an `OpenCL` memory object.
139///
140/// Calls clGetGLObjectInfo to get the object type and name.
141///
142/// * `memobj` - a valid `OpenCL` memory object handle.
143///
144/// returns a Result containing the OpenGL object type and name
145/// or the error code from the `OpenCL` C API function.
146#[inline]
147pub fn get_gl_object_info(memobj: cl_mem) -> Result<(cl_GLuint, cl_GLuint), cl_int> {
148    let mut object_type: cl_uint = CL_GL_OBJECT_BUFFER;
149    let mut object_name: cl_uint = 0;
150    let status = unsafe {
151        cl_call!(clGetGLObjectInfo(
152            memobj,
153            &mut object_type,
154            &mut object_name
155        ))
156    };
157    if CL_SUCCESS == status {
158        Ok((object_type, object_name))
159    } else {
160        Err(status)
161    }
162}
163
164/// Get data about an OpenGL texture object.
165///
166/// Calls clGetGLTextureInfo to get the desired data about the texture object.
167pub fn get_gl_texture_data(
168    memobj: cl_mem,
169    param_name: cl_gl_texture_info,
170) -> Result<Vec<u8>, cl_int> {
171    api_info_size!(get_size, clGetGLTextureInfo);
172    let size = get_size(memobj, param_name)?;
173    api_info_vector!(get_vector, u8, clGetGLTextureInfo);
174    get_vector(memobj, param_name, size)
175}
176
177/// Get information about the GL texture object associated with a memory object.
178///
179/// Calls clGetGLTextureInfo to get the desired information.
180///
181/// * `memobj` - the `OpenCL` memory object.
182/// * `param_name` - the type of memory object information being queried, see:
183///   [Texture Info](https://www.khronos.org/registry/OpenCL//sdk/2.2/docs/man/html/clGetGLTextureInfo.html).
184///
185/// returns a Result containing the desired information in an `InfoType` enum
186/// or the error code from the `OpenCL` C API function.
187pub fn get_gl_texture_info(
188    memobj: cl_mem,
189    param_name: cl_gl_texture_info,
190) -> Result<InfoType, cl_int> {
191    match param_name {
192        CL_GL_TEXTURE_TARGET => {
193            api_info_value!(get_value, cl_GLenum, clGetGLTextureInfo);
194            Ok(InfoType::Uint(get_value(memobj, param_name)?))
195        }
196
197        CL_GL_MIPMAP_LEVEL | CL_GL_NUM_SAMPLES => {
198            api_info_value!(get_value, cl_GLint, clGetGLTextureInfo);
199            Ok(InfoType::Int(get_value(memobj, param_name)?))
200        }
201
202        _ => Ok(InfoType::VecUchar(get_gl_texture_data(memobj, param_name)?)),
203    }
204}
205
206/// Acquire `OpenCL` memory objects that have been created from `OpenGL` objects.
207/// Calls `clEnqueueAcquireGLObjects`.
208///
209/// * `command_queue` - a valid `OpenCL` `command_queue`.
210/// * `num_objects` - the number of memory objects to acquire.
211/// * `mem_objects` - the memory objects to acquire.
212/// * `num_events_in_wait_list` - the number of events in the wait list.
213/// * `event_wait_list` - the wait list events.
214///
215/// returns a Result containing the new `OpenCL` event
216/// or the error code from the `OpenCL` C API function.
217#[inline]
218pub unsafe fn enqueue_acquire_gl_objects(
219    command_queue: cl_command_queue,
220    num_objects: cl_uint,
221    mem_objects: *const cl_mem,
222    num_events_in_wait_list: cl_uint,
223    event_wait_list: *const cl_event,
224) -> Result<cl_event, cl_int> {
225    let mut event: cl_event = ptr::null_mut();
226    let status: cl_int = cl_call!(clEnqueueAcquireGLObjects(
227        command_queue,
228        num_objects,
229        mem_objects,
230        num_events_in_wait_list,
231        event_wait_list,
232        &mut event,
233    ));
234    if CL_SUCCESS == status {
235        Ok(event)
236    } else {
237        Err(status)
238    }
239}
240
241/// Release `OpenCL` memory objects that have been created from `OpenGL` objects.
242/// Calls `clEnqueueReleaseGLObjects`.
243///
244/// * `command_queue` - a valid `OpenCL` `command_queue`.
245/// * `num_objects` - the number of memory objects to acquire.
246/// * `mem_objects` - the memory objects to acquire.
247/// * `num_events_in_wait_list` - the number of events in the wait list.
248/// * `event_wait_list` - the wait list events.
249///
250/// returns a Result containing the new `OpenCL` event
251/// or the error code from the `OpenCL` C API function.
252#[inline]
253pub unsafe fn enqueue_release_gl_objects(
254    command_queue: cl_command_queue,
255    num_objects: cl_uint,
256    mem_objects: *const cl_mem,
257    num_events_in_wait_list: cl_uint,
258    event_wait_list: *const cl_event,
259) -> Result<cl_event, cl_int> {
260    let mut event: cl_event = ptr::null_mut();
261    let status: cl_int = cl_call!(clEnqueueReleaseGLObjects(
262        command_queue,
263        num_objects,
264        mem_objects,
265        num_events_in_wait_list,
266        event_wait_list,
267        &mut event,
268    ));
269    if CL_SUCCESS == status {
270        Ok(event)
271    } else {
272        Err(status)
273    }
274}
275
276/// Create an `OpenCL` 2D image object from an `OpenGL` 2D texture object,
277/// or a single face of an OpenGL cubemap texture object.
278///
279/// Calls clCreateFromGLTexture2D to create an `OpenCL` memory object.
280/// Deprecated in `CL_VERSION_1_2`, use `create_from_gl_texture`.
281///
282/// * `context` - a valid `OpenCL` context created from an OpenGL context.
283/// * `flags` - a bit-field used to specify allocation and usage information
284///   about the image memory object being created, see:
285///   [Memory Flags](https://www.khronos.org/registry/OpenCL/specs/3.0-unified/html/OpenCL_API.html#memory-flags-table).
286/// * `texture_target` - used to define the image type of texture.
287/// * `miplevel ` - used to define the mipmap level.
288/// * `texture  ` - the name of a GL 2D, cubemap or rectangle texture object.
289///
290/// returns a Result containing the new `OpenCL` image object
291/// or the error code from the `OpenCL` C API function.
292#[cfg_attr(
293    any(
294        feature = "CL_VERSION_1_2",
295        feature = "CL_VERSION_2_0",
296        feature = "CL_VERSION_2_1",
297        feature = "CL_VERSION_2_2",
298        feature = "CL_VERSION_3_0"
299    ),
300    deprecated(
301        since = "0.1.0",
302        note = "From CL_VERSION_1_2 use create_from_gl_texture"
303    )
304)]
305#[inline]
306pub unsafe fn create_from_gl_texture_2d(
307    context: cl_context,
308    flags: cl_mem_flags,
309    texture_target: cl_GLenum,
310    miplevel: cl_GLint,
311    texture: cl_GLuint,
312) -> Result<cl_mem, cl_int> {
313    let mut status: cl_int = CL_INVALID_VALUE;
314    let mem = cl_call!(clCreateFromGLTexture2D(
315        context,
316        flags,
317        texture_target,
318        miplevel,
319        texture,
320        &mut status,
321    ));
322    if CL_SUCCESS == status {
323        Ok(mem)
324    } else {
325        Err(status)
326    }
327}
328
329/// Create an `OpenCL` 3D image object from an OpenGL 3D texture object.
330///
331/// Calls `clCreateFromGLTexture3D` to create an `OpenCL` memory object.
332/// Deprecated in `CL_VERSION_1_2`, use `create_from_gl_texture`.
333///
334/// * `context` - a valid `OpenCL` context created from an OpenGL context.
335/// * `flags` - a bit-field used to specify allocation and usage information
336///   about the image memory object being created, see:
337///   [Memory Flags](https://www.khronos.org/registry/OpenCL/specs/3.0-unified/html/OpenCL_API.html#memory-flags-table).
338/// * `texture_target` - used to define the image type of texture.
339/// * `miplevel ` - used to define the mipmap level.
340/// * `texture  ` - the name of a GL 2D, cubemap or rectangle texture object.
341///
342/// returns a Result containing the new `OpenCL` image object
343/// or the error code from the `OpenCL` C API function.
344#[cfg_attr(
345    any(
346        feature = "CL_VERSION_1_2",
347        feature = "CL_VERSION_2_0",
348        feature = "CL_VERSION_2_1",
349        feature = "CL_VERSION_2_2",
350        feature = "CL_VERSION_3_0"
351    ),
352    deprecated(
353        since = "0.1.0",
354        note = "From CL_VERSION_1_2 use create_from_gl_texture"
355    )
356)]
357#[inline]
358pub unsafe fn create_from_gl_texture_3d(
359    context: cl_context,
360    flags: cl_mem_flags,
361    texture_target: cl_GLenum,
362    miplevel: cl_GLint,
363    texture: cl_GLuint,
364) -> Result<cl_mem, cl_int> {
365    let mut status: cl_int = CL_INVALID_VALUE;
366    let mem = cl_call!(clCreateFromGLTexture3D(
367        context,
368        flags,
369        texture_target,
370        miplevel,
371        texture,
372        &mut status,
373    ));
374    if CL_SUCCESS == status {
375        Ok(mem)
376    } else {
377        Err(status)
378    }
379}
380
381/// Get OpenGL context information.
382/// Calls `clGetGLContextInfoKHR` to get the desired information.
383///
384/// * `properties` - the `OpenCL` context properties.
385/// * `param_name` - the type of memory object information being queried, see:
386///   [Context Info](https://www.khronos.org/registry/OpenCL//sdk/2.2/docs/man/html/clGetGLContextInfoKHR.html).
387///
388/// returns a Result containing the desired information in an `InfoType` enum
389/// or the error code from the `OpenCL` C API function.
390#[cfg(any(feature = "cl_khr_gl_sharing", feature = "dynamic"))]
391pub fn get_gl_context_info_khr(
392    properties: *mut cl_context_properties,
393    param_name: cl_gl_context_info,
394) -> Result<InfoType, cl_int> {
395    match param_name {
396        CL_CURRENT_DEVICE_FOR_GL_CONTEXT_KHR => {
397            let mut data: intptr_t = 0;
398            let data_ptr: *mut intptr_t = &mut data;
399            let status = unsafe {
400                cl_call!(clGetGLContextInfoKHR(
401                    properties,
402                    param_name,
403                    mem::size_of::<intptr_t>(),
404                    data_ptr.cast::<c_void>(),
405                    ptr::null_mut(),
406                ))
407            };
408            if CL_SUCCESS == status {
409                Ok(InfoType::Ptr(data))
410            } else {
411                Err(status)
412            }
413        }
414
415        CL_DEVICES_FOR_GL_CONTEXT_KHR => {
416            // Get the size
417            let mut size: size_t = 0;
418            let status = unsafe {
419                cl_call!(clGetGLContextInfoKHR(
420                    properties,
421                    param_name,
422                    0,
423                    ptr::null_mut(),
424                    &mut size
425                ))
426            };
427            if CL_SUCCESS != status {
428                Err(status)
429            } else if 0 < size {
430                // Get the data
431                let count = size / mem::size_of::<intptr_t>();
432                let mut data: Vec<intptr_t> = Vec::with_capacity(count);
433                let status = unsafe {
434                    cl_call!(clGetGLContextInfoKHR(
435                        properties,
436                        param_name,
437                        size,
438                        data.as_mut_ptr().cast::<c_void>(),
439                        ptr::null_mut(),
440                    ))
441                };
442                if CL_SUCCESS == status {
443                    Ok(InfoType::VecIntPtr(data))
444                } else {
445                    Err(status)
446                }
447            } else {
448                Ok(InfoType::VecIntPtr(Vec::default()))
449            }
450        }
451
452        _ => {
453            // Get the size
454            let mut size: size_t = 0;
455            let status = unsafe {
456                cl_call!(clGetGLContextInfoKHR(
457                    properties,
458                    param_name,
459                    0,
460                    ptr::null_mut(),
461                    &mut size
462                ))
463            };
464            if CL_SUCCESS != status {
465                Err(status)
466            } else if 0 < size {
467                // Get the data
468                let mut data: Vec<u8> = Vec::with_capacity(size);
469                let status = unsafe {
470                    cl_call!(clGetGLContextInfoKHR(
471                        properties,
472                        param_name,
473                        size,
474                        data.as_mut_ptr().cast::<c_void>(),
475                        ptr::null_mut(),
476                    ))
477                };
478                if CL_SUCCESS == status {
479                    Ok(InfoType::VecUchar(data))
480                } else {
481                    Err(status)
482                }
483            } else {
484                Ok(InfoType::VecUchar(Vec::default()))
485            }
486        }
487    }
488}
489
490/// Create an event object linked to an OpenGL sync object.
491/// Requires the `cl_khr_gl_event` extension
492/// Calls `clCreateEventFromGLsyncKHR`.
493///
494/// * `context` - a valid `OpenCL` context.
495/// * `sync` - the sync object in the GL share group associated with context.
496///
497/// returns a Result containing the new `OpenCL` event
498/// or the error code from the `OpenCL` C API function.
499#[cfg(any(feature = "cl_khr_gl_event", feature = "dynamic"))]
500#[inline]
501pub fn create_event_from_gl_sync_khr(
502    context: cl_context,
503    sync: cl_GLsync,
504) -> Result<cl_event, cl_int> {
505    let mut status: cl_int = CL_INVALID_VALUE;
506    let event: cl_event =
507        unsafe { cl_call!(clCreateEventFromGLsyncKHR(context, sync, &mut status)) };
508    if CL_SUCCESS == status {
509        Ok(event)
510    } else {
511        Err(status)
512    }
513}