1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
/* SPDX-License-Identifier: LGPL-2.1-or-later OR MPL-2.0

Copyright (c) 2024 DorotaC
*/
/*! EGL extensions compatible with Khronos-egl.
 * 
 * Currently only those used by crISPy are filled in.
*/

use khronos_egl as egl;
use std::ffi::c_void;
use std::mem;

pub const CONTEXT_FLAGS_KHR: egl::Int = 0x30FC;
pub const CONTEXT_OPENGL_DEBUG_BIT_KHR: egl::Int = 0x1;
pub const PLATFORM_GBM_MESA: egl::Enum = 0x31d7;
pub const LINUX_DMA_BUF_EXT: egl::Enum = 0x3270;
pub const LINUX_DRM_FOURCC_EXT: egl::Int = 0x3271;
pub const DMA_BUF_PLANE0_FD_EXT: egl::Int = 0x3272;
pub const DMA_BUF_PLANE0_OFFSET_EXT: egl::Int = 0x3273;
pub const DMA_BUF_PLANE0_PITCH_EXT: egl::Int = 0x3274;


/// Implements the EGL_EXT_platform_base extension relevant for an egl::Instance.
/// 
/// https://registry.khronos.org/EGL/extensions/EXT/EGL_EXT_platform_base.txt
pub trait ExtPlatformBaseInstance {
    unsafe fn get_platform_display_ext(
        &self,
        platform: egl::Enum,
        native_display: egl::NativeDisplayType,
        attrib_list: &[egl::Attrib]
    ) -> Result<egl::Display, egl::Error>;
}

impl<T: egl::api::EGL1_4> ExtPlatformBaseInstance for egl::Instance<T> {
    unsafe fn get_platform_display_ext(
        &self,
        platform: egl::Enum,
        native_display: egl::NativeDisplayType,
        attrib_list: &[egl::Attrib]
    ) -> Result<egl::Display, egl::Error> {
        egl::check_attrib_list(attrib_list)?;
        // Calling this function every time because eglGetPlatformDisplayEXT is unlikely to be called in a speed critical context.
        let procedure = self.get_proc_address("eglGetPlatformDisplayEXT")
            .ok_or(egl::Error::BadParameter)?;
        let procedure
            : extern "system" fn(
                egl::Enum,
                egl::NativeDisplayType,
                *const usize,
            ) -> *mut c_void
            = unsafe { mem::transmute(procedure as *const c_void) };

        let ret = procedure(
            platform,
            native_display,
            attrib_list.as_ptr(),
        );
        if ret != egl::NO_DISPLAY {
            Ok(unsafe { egl::Display::from_ptr(ret) })
        } else {
            Err(self.get_error().unwrap())
        }
    }
}


/// Implements the EGL_KHR_image_base extension relevant for an egl::Instance.
/// 
/// https://registry.khronos.org/EGL/extensions/KHR/EGL_KHR_image_base.txt
pub trait KhrImageBaseInstance {
    unsafe fn create_image_khr(
        &self,
        display: egl::Display,
        ctx: egl::Context,
        target: egl::Enum,
        buffer: egl::ClientBuffer,
        attrib_list: &[egl::Int],
    ) -> Result<egl::Image, egl::Error>;
}

impl <T: egl::api::EGL1_2> KhrImageBaseInstance for egl::Instance<T> {
    unsafe fn create_image_khr(
        &self,
        display: egl::Display,
        ctx: egl::Context,
        target: egl::Enum,
        buffer: egl::ClientBuffer,
        attrib_list: &[egl::Int],
    ) -> Result<egl::Image, egl::Error> {
        egl::check_int_list(attrib_list)?;
        // Calling this function every time because eglGetPlatformDisplayEXT is unlikely to be called in a speed critical context.
        let procedure = self.get_proc_address("eglCreateImageKHR")
            .ok_or(egl::Error::BadParameter)?;
        let procedure
            : extern "system" fn(egl::NativeDisplayType, *mut c_void, egl::Enum, *mut c_void, *const egl::Int)
                -> *mut c_void
            = unsafe { mem::transmute(procedure as *const c_void) };

        unsafe {
            let image = procedure(
                display.as_ptr(),
                ctx.as_ptr(),
                target,
                buffer.as_ptr(),
                attrib_list.as_ptr(),
            );
            if image != egl::NO_IMAGE {
                Ok(egl::Image::from_ptr(image))
            } else {
                Err(self.get_error().unwrap())
            }
        }
    }
}



pub type ImageOES = *const c_void;

/// Implements the OES_EGL_image extension relevant for an egl::Instance.
/// 
/// https://registry.khronos.org/OpenGL/extensions/OES/OES_EGL_image.txt
pub trait OesImageInstance {
    unsafe fn image_target_texture_2d_oes(
        &self,
        target: egl::Enum,
        image: egl::Image,
    ) -> Result<(), egl::Error>;
}

impl <T: egl::api::EGL1_1> OesImageInstance for egl::Instance<T> {
    unsafe fn image_target_texture_2d_oes(
        &self,
        target: egl::Enum,
        image: egl::Image,
    ) -> Result<(), egl::Error> {
        // Calling this function every time because eglGetPlatformDisplayEXT is unlikely to be called in a speed critical context.
        let procedure = self.get_proc_address("glEGLImageTargetTexture2DOES")
            .ok_or(egl::Error::BadParameter)?;
        let procedure
            : unsafe extern "system" fn(egl::Enum, ImageOES) -> ()
            = unsafe { mem::transmute(procedure as *const c_void) };

        unsafe {procedure(target, image.as_ptr() )};
        match self.get_error() {
            Some(e) => Err(e),
            None => Ok(()),
        }
    }
}