use super::device::Device;
use super::surface::Surface;
use crate::device::Device as DeviceInterface;
use crate::{ContextAttributes, ContextID, Error, SurfaceInfo};
use std::os::raw::c_void;
pub enum Context<Def, Alt>
where
Def: DeviceInterface,
Alt: DeviceInterface,
{
Default(Def::Context),
Alternate(Alt::Context),
}
#[derive(Clone)]
pub enum ContextDescriptor<Def, Alt>
where
Def: DeviceInterface,
Alt: DeviceInterface,
{
Default(Def::ContextDescriptor),
Alternate(Alt::ContextDescriptor),
}
pub enum NativeContext<Def, Alt>
where
Def: DeviceInterface,
Alt: DeviceInterface,
{
Default(Def::NativeContext),
Alternate(Alt::NativeContext),
}
impl<Def, Alt> Device<Def, Alt>
where
Def: DeviceInterface,
Alt: DeviceInterface,
{
pub fn create_context_descriptor(
&self,
attributes: &ContextAttributes,
) -> Result<ContextDescriptor<Def, Alt>, Error> {
match *self {
Device::Default(ref device) => device
.create_context_descriptor(attributes)
.map(ContextDescriptor::Default),
Device::Alternate(ref device) => device
.create_context_descriptor(attributes)
.map(ContextDescriptor::Alternate),
}
}
pub fn create_context(
&self,
descriptor: &ContextDescriptor<Def, Alt>,
share_with: Option<&Context<Def, Alt>>,
) -> Result<Context<Def, Alt>, Error> {
match (self, descriptor) {
(&Device::Default(ref device), ContextDescriptor::Default(descriptor)) => {
let shared = match share_with {
Some(Context::Default(other)) => Some(other),
Some(_) => {
return Err(Error::IncompatibleSharedContext);
}
None => None,
};
device
.create_context(descriptor, shared)
.map(Context::Default)
}
(&Device::Alternate(ref device), ContextDescriptor::Alternate(descriptor)) => {
let shared = match share_with {
Some(Context::Alternate(other)) => Some(other),
Some(_) => {
return Err(Error::IncompatibleSharedContext);
}
None => None,
};
device
.create_context(descriptor, shared)
.map(Context::Alternate)
}
_ => Err(Error::IncompatibleContextDescriptor),
}
}
pub unsafe fn create_context_from_native_context(
&self,
native_context: NativeContext<Def, Alt>,
) -> Result<Context<Def, Alt>, Error> {
match self {
Device::Default(device) => match native_context {
NativeContext::Default(native_context) => device
.create_context_from_native_context(native_context)
.map(Context::Default),
_ => Err(Error::IncompatibleNativeContext),
},
Device::Alternate(device) => match native_context {
NativeContext::Alternate(native_context) => device
.create_context_from_native_context(native_context)
.map(Context::Alternate),
_ => Err(Error::IncompatibleNativeContext),
},
}
}
pub fn destroy_context(&self, context: &mut Context<Def, Alt>) -> Result<(), Error> {
match (self, &mut *context) {
(Device::Default(device), &mut Context::Default(ref mut context)) => {
device.destroy_context(context)
}
(Device::Alternate(device), &mut Context::Alternate(ref mut context)) => {
device.destroy_context(context)
}
_ => Err(Error::IncompatibleContext),
}
}
pub fn native_context(&self, context: &Context<Def, Alt>) -> NativeContext<Def, Alt> {
match (self, context) {
(Device::Default(device), Context::Default(context)) => {
NativeContext::Default(device.native_context(context))
}
(Device::Alternate(device), Context::Alternate(context)) => {
NativeContext::Alternate(device.native_context(context))
}
_ => panic!("Incompatible context!"),
}
}
pub fn context_descriptor(&self, context: &Context<Def, Alt>) -> ContextDescriptor<Def, Alt> {
match (self, context) {
(Device::Default(device), Context::Default(context)) => {
ContextDescriptor::Default(device.context_descriptor(context))
}
(Device::Alternate(device), Context::Alternate(context)) => {
ContextDescriptor::Alternate(device.context_descriptor(context))
}
_ => panic!("Incompatible context!"),
}
}
pub fn make_context_current(&self, context: &Context<Def, Alt>) -> Result<(), Error> {
match (self, context) {
(Device::Default(device), Context::Default(context)) => {
device.make_context_current(context)
}
(Device::Alternate(device), Context::Alternate(context)) => {
device.make_context_current(context)
}
_ => Err(Error::IncompatibleContext),
}
}
pub fn make_no_context_current(&self) -> Result<(), Error> {
match self {
Device::Default(device) => device.make_no_context_current(),
Device::Alternate(device) => device.make_no_context_current(),
}
}
pub fn bind_surface_to_context(
&self,
context: &mut Context<Def, Alt>,
surface: Surface<Def, Alt>,
) -> Result<(), (Error, Surface<Def, Alt>)> {
match (self, &mut *context) {
(Device::Default(device), &mut Context::Default(ref mut context)) => match surface {
Surface::Default(surface) => device
.bind_surface_to_context(context, surface)
.map_err(|(err, surface)| (err, Surface::Default(surface))),
_ => Err((Error::IncompatibleSurface, surface)),
},
(Device::Alternate(device), &mut Context::Alternate(ref mut context)) => {
match surface {
Surface::Alternate(surface) => device
.bind_surface_to_context(context, surface)
.map_err(|(err, surface)| (err, Surface::Alternate(surface))),
_ => Err((Error::IncompatibleSurface, surface)),
}
}
_ => Err((Error::IncompatibleContext, surface)),
}
}
pub fn unbind_surface_from_context(
&self,
context: &mut Context<Def, Alt>,
) -> Result<Option<Surface<Def, Alt>>, Error> {
match (self, &mut *context) {
(Device::Default(device), &mut Context::Default(ref mut context)) => device
.unbind_surface_from_context(context)
.map(|surface| surface.map(Surface::Default)),
(Device::Alternate(device), &mut Context::Alternate(ref mut context)) => device
.unbind_surface_from_context(context)
.map(|surface| surface.map(Surface::Alternate)),
_ => Err(Error::IncompatibleContext),
}
}
pub fn context_descriptor_attributes(
&self,
context_descriptor: &ContextDescriptor<Def, Alt>,
) -> ContextAttributes {
match (self, context_descriptor) {
(Device::Default(device), ContextDescriptor::Default(context_descriptor)) => {
device.context_descriptor_attributes(context_descriptor)
}
(Device::Alternate(device), ContextDescriptor::Alternate(context_descriptor)) => {
device.context_descriptor_attributes(context_descriptor)
}
_ => panic!("Incompatible context!"),
}
}
pub fn get_proc_address(
&self,
context: &Context<Def, Alt>,
symbol_name: &str,
) -> *const c_void {
match (self, context) {
(Device::Default(device), Context::Default(context)) => {
device.get_proc_address(context, symbol_name)
}
(Device::Alternate(device), Context::Alternate(context)) => {
device.get_proc_address(context, symbol_name)
}
_ => panic!("Incompatible context!"),
}
}
pub fn context_id(&self, context: &Context<Def, Alt>) -> ContextID {
match (self, context) {
(Device::Default(device), Context::Default(context)) => device.context_id(context),
(Device::Alternate(device), Context::Alternate(context)) => device.context_id(context),
_ => panic!("Incompatible context!"),
}
}
pub fn context_surface_info(
&self,
context: &Context<Def, Alt>,
) -> Result<Option<SurfaceInfo>, Error> {
match (self, context) {
(Device::Default(device), Context::Default(context)) => {
device.context_surface_info(context)
}
(Device::Alternate(device), Context::Alternate(context)) => {
device.context_surface_info(context)
}
_ => Err(Error::IncompatibleContext),
}
}
}