diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/api/egl/mod.rs | 222 |
1 files changed, 139 insertions, 83 deletions
diff --git a/src/api/egl/mod.rs b/src/api/egl/mod.rs index 5e80068..582e376 100644 --- a/src/api/egl/mod.rs +++ b/src/api/egl/mod.rs @@ -9,6 +9,7 @@ use GlContext; use GlRequest; use PixelFormat; use PixelFormatRequirements; +use ReleaseBehavior; use Robustness; use Api; @@ -247,8 +248,9 @@ impl Context { } }; - let configs = unsafe { try!(enumerate_configs(&egl, display, &egl_version, api, version)) }; - let (config_id, pixel_format) = try!(pf_reqs.choose_pixel_format(configs.into_iter())); + let (config_id, pixel_format) = unsafe { + try!(choose_fbconfig(&egl, display, &egl_version, api, version, pf_reqs)) + }; Ok(ContextPrototype { opengl: opengl, @@ -451,108 +453,162 @@ impl<'a> ContextPrototype<'a> { } } -unsafe fn enumerate_configs(egl: &ffi::egl::Egl, display: ffi::egl::types::EGLDisplay, - egl_version: &(ffi::egl::types::EGLint, ffi::egl::types::EGLint), - api: Api, version: Option<(u8, u8)>) - -> Result<Vec<(ffi::egl::types::EGLConfig, PixelFormat)>, CreationError> +unsafe fn choose_fbconfig(egl: &ffi::egl::Egl, display: ffi::egl::types::EGLDisplay, + egl_version: &(ffi::egl::types::EGLint, ffi::egl::types::EGLint), + api: Api, version: Option<(u8, u8)>, reqs: &PixelFormatRequirements) + -> Result<(ffi::egl::types::EGLConfig, PixelFormat), CreationError> { - let mut num_configs = mem::uninitialized(); - if egl.GetConfigs(display, ptr::null_mut(), 0, &mut num_configs) == 0 { - return Err(CreationError::OsError(format!("eglGetConfigs failed"))); - } + let descriptor = { + let mut out: Vec<c_int> = Vec::with_capacity(37); - let mut configs_ids = Vec::with_capacity(num_configs as usize); - if egl.GetConfigs(display, configs_ids.as_mut_ptr(), - configs_ids.capacity() as ffi::egl::types::EGLint, - &mut num_configs) == 0 - { - return Err(CreationError::OsError(format!("eglGetConfigs failed"))); - } - configs_ids.set_len(num_configs as usize); + if egl_version >= &(1, 2) { + out.push(ffi::egl::COLOR_BUFFER_TYPE as c_int); + out.push(ffi::egl::RGB_BUFFER as c_int); + } - // analyzing each config - let mut result = Vec::with_capacity(num_configs as usize); - for config_id in configs_ids { - macro_rules! attrib { - ($egl:expr, $display:expr, $config:expr, $attr:expr) => ( - { - let mut value = mem::uninitialized(); - let res = $egl.GetConfigAttrib($display, $config, - $attr as ffi::egl::types::EGLint, &mut value); - if res == 0 { - return Err(CreationError::OsError(format!("eglGetConfigAttrib failed"))); - } - value + if egl_version >= &(1, 3) { + out.push(ffi::egl::SURFACE_TYPE as c_int); + out.push((ffi::egl::WINDOW_BIT | ffi::egl::PBUFFER_BIT) as c_int); + } + + match (api, version) { + (Api::OpenGlEs, Some((3, _))) => { + if egl_version < &(1, 3) { return Err(CreationError::NoAvailablePixelFormat); } + out.push(ffi::egl::RENDERABLE_TYPE as c_int); + out.push(ffi::egl::OPENGL_ES3_BIT as c_int); + out.push(ffi::egl::CONFORMANT as c_int); + out.push(ffi::egl::OPENGL_ES3_BIT as c_int); + }, + (Api::OpenGlEs, Some((2, _))) => { + if egl_version < &(1, 3) { return Err(CreationError::NoAvailablePixelFormat); } + out.push(ffi::egl::RENDERABLE_TYPE as c_int); + out.push(ffi::egl::OPENGL_ES2_BIT as c_int); + out.push(ffi::egl::CONFORMANT as c_int); + out.push(ffi::egl::OPENGL_ES2_BIT as c_int); + }, + (Api::OpenGlEs, Some((1, _))) => { + if egl_version >= &(1, 3) { + out.push(ffi::egl::RENDERABLE_TYPE as c_int); + out.push(ffi::egl::OPENGL_ES_BIT as c_int); + out.push(ffi::egl::CONFORMANT as c_int); + out.push(ffi::egl::OPENGL_ES_BIT as c_int); } - ) + }, + (Api::OpenGlEs, _) => unimplemented!(), + (Api::OpenGl, Some((1, _))) => { + if egl_version < &(1, 3) { return Err(CreationError::NoAvailablePixelFormat); } + out.push(ffi::egl::RENDERABLE_TYPE as c_int); + out.push(ffi::egl::OPENGL_BIT as c_int); + out.push(ffi::egl::CONFORMANT as c_int); + out.push(ffi::egl::OPENGL_BIT as c_int); + }, + (_, _) => unimplemented!(), }; - let renderable = attrib!(egl, display, config_id, ffi::egl::RENDERABLE_TYPE) as u32; - let conformant = attrib!(egl, display, config_id, ffi::egl::CONFORMANT) as u32; + if let Some(hardware_accelerated) = reqs.hardware_accelerated { + out.push(ffi::egl::CONFIG_CAVEAT as c_int); + out.push(if hardware_accelerated { + ffi::egl::NONE as c_int + } else { + ffi::egl::SLOW_CONFIG as c_int + }); + } - if api == Api::OpenGlEs { - if let Some(version) = version { - if version.0 == 3 && (renderable & ffi::egl::OPENGL_ES3_BIT == 0 || - conformant & ffi::egl::OPENGL_ES3_BIT == 0) - { - continue; - } + if let Some(color) = reqs.color_bits { + out.push(ffi::egl::RED_SIZE as c_int); + out.push((color / 3) as c_int); + out.push(ffi::egl::GREEN_SIZE as c_int); + out.push((color / 3 + if color % 3 != 0 { 1 } else { 0 }) as c_int); + out.push(ffi::egl::BLUE_SIZE as c_int); + out.push((color / 3 + if color % 3 == 2 { 1 } else { 0 }) as c_int); + } - if version.0 == 2 && (renderable & ffi::egl::OPENGL_ES2_BIT == 0 || - conformant & ffi::egl::OPENGL_ES2_BIT == 0) - { - continue; - } + if let Some(alpha) = reqs.alpha_bits { + out.push(ffi::egl::ALPHA_SIZE as c_int); + out.push(alpha as c_int); + } - if version.0 == 1 && (renderable & ffi::egl::OPENGL_ES_BIT == 0 || - conformant & ffi::egl::OPENGL_ES_BIT == 0) - { - continue; - } - } + if let Some(depth) = reqs.depth_bits { + out.push(ffi::egl::DEPTH_SIZE as c_int); + out.push(depth as c_int); + } - } else if api == Api::OpenGl { - if renderable & ffi::egl::OPENGL_BIT == 0 || - conformant & ffi::egl::OPENGL_BIT == 0 - { - continue; - } + if let Some(stencil) = reqs.stencil_bits { + out.push(ffi::egl::STENCIL_SIZE as c_int); + out.push(stencil as c_int); } - if attrib!(egl, display, config_id, ffi::egl::SURFACE_TYPE) & - (ffi::egl::WINDOW_BIT | ffi::egl::PBUFFER_BIT) as i32 == 0 - { - continue; + if let Some(true) = reqs.double_buffer { + return Err(CreationError::NoAvailablePixelFormat); } - if attrib!(egl, display, config_id, ffi::egl::TRANSPARENT_TYPE) != ffi::egl::NONE as i32 { - continue; + if let Some(multisampling) = reqs.multisampling { + out.push(ffi::egl::SAMPLES as c_int); + out.push(multisampling as c_int); } - if attrib!(egl, display, config_id, ffi::egl::COLOR_BUFFER_TYPE) != ffi::egl::RGB_BUFFER as i32 { - continue; + if reqs.stereoscopy { + return Err(CreationError::NoAvailablePixelFormat); } - result.push((config_id, PixelFormat { - hardware_accelerated: attrib!(egl, display, config_id, ffi::egl::CONFIG_CAVEAT) - != ffi::egl::SLOW_CONFIG as i32, - color_bits: attrib!(egl, display, config_id, ffi::egl::RED_SIZE) as u8 + - attrib!(egl, display, config_id, ffi::egl::BLUE_SIZE) as u8 + - attrib!(egl, display, config_id, ffi::egl::GREEN_SIZE) as u8, - alpha_bits: attrib!(egl, display, config_id, ffi::egl::ALPHA_SIZE) as u8, - depth_bits: attrib!(egl, display, config_id, ffi::egl::DEPTH_SIZE) as u8, - stencil_bits: attrib!(egl, display, config_id, ffi::egl::STENCIL_SIZE) as u8, - stereoscopy: false, - double_buffer: true, - multisampling: match attrib!(egl, display, config_id, ffi::egl::SAMPLES) { - 0 | 1 => None, - a => Some(a as u16), + // FIXME: srgb is not taken into account + + match reqs.release_behavior { + ReleaseBehavior::Flush => (), + ReleaseBehavior::None => { + // TODO: with EGL you need to manually set the behavior + unimplemented!() }, - srgb: false, // TODO: use EGL_KHR_gl_colorspace to know that - })); + } + + out.push(0); + out + }; + + // calling `eglChooseConfig` + let mut config_id = mem::uninitialized(); + let mut num_configs = mem::uninitialized(); + if egl.ChooseConfig(display, descriptor.as_ptr(), &mut config_id, 1, &mut num_configs) == 0 { + return Err(CreationError::OsError(format!("eglChooseConfig failed"))); + } + if num_configs == 0 { + return Err(CreationError::NoAvailablePixelFormat); } - Ok(result) + // analyzing each config + macro_rules! attrib { + ($egl:expr, $display:expr, $config:expr, $attr:expr) => ( + { + let mut value = mem::uninitialized(); + let res = $egl.GetConfigAttrib($display, $config, + $attr as ffi::egl::types::EGLint, &mut value); + if res == 0 { + return Err(CreationError::OsError(format!("eglGetConfigAttrib failed"))); + } + value + } + ) + }; + + let desc = PixelFormat { + hardware_accelerated: attrib!(egl, display, config_id, ffi::egl::CONFIG_CAVEAT) + != ffi::egl::SLOW_CONFIG as i32, + color_bits: attrib!(egl, display, config_id, ffi::egl::RED_SIZE) as u8 + + attrib!(egl, display, config_id, ffi::egl::BLUE_SIZE) as u8 + + attrib!(egl, display, config_id, ffi::egl::GREEN_SIZE) as u8, + alpha_bits: attrib!(egl, display, config_id, ffi::egl::ALPHA_SIZE) as u8, + depth_bits: attrib!(egl, display, config_id, ffi::egl::DEPTH_SIZE) as u8, + stencil_bits: attrib!(egl, display, config_id, ffi::egl::STENCIL_SIZE) as u8, + stereoscopy: false, + double_buffer: true, + multisampling: match attrib!(egl, display, config_id, ffi::egl::SAMPLES) { + 0 | 1 => None, + a => Some(a as u16), + }, + srgb: false, // TODO: use EGL_KHR_gl_colorspace to know that + }; + + Ok((config_id, desc)) } unsafe fn create_context(egl: &ffi::egl::Egl, display: ffi::egl::types::EGLDisplay, |