use {
crate::{
buffer::{
self, Buffer, Filter, Read, ReadFailed, TextureBuffer, TextureSampler, Write,
WriteFailed,
},
layer::{Config, Layer},
mesh::{self, Mesh},
render,
set::{self, Group, GroupHandler, Groups, Nth, UniqueSet},
shader::{RenderShader, Shader},
state::{Scheduler, State},
store::{self, Row, Storage, StorageValue, Uniform},
usage::u,
},
dunge_shade::{bytes::Bytes, irc::Value, link::Render},
std::{error, fmt, sync::Arc},
};
pub async fn context() -> Result<Context, FailedMakeContext> {
let state = State::new().await?;
Ok(Context(Arc::new(state)))
}
#[derive(Clone)]
pub struct Context(Arc<State>);
impl Context {
pub(crate) fn state(&self) -> &State {
&self.0
}
pub fn make_shader<I, S>(&self, render: Render<I, S>) -> Shader<I, S> {
Shader::new(&self.0, render)
}
pub fn make_set<I, G, const N: usize>(
&self,
shader: &Shader<I, G::Inner>,
set: G,
) -> UniqueSet<G::Inner>
where
G: Groups<N>,
{
UniqueSet::new(&self.0, shader.data(), set)
}
pub fn make_uniform<V>(&self, value: &V) -> Uniform<V>
where
V: Value + Bytes,
{
const { assert!(size_of::<V>() > 0, "value cannot be zero sized") }
store::uniform(value, self)
}
pub fn make_storage<V>(&self, value: &V) -> Option<Storage<V>>
where
V: StorageValue + ?Sized,
{
store::storage(value, self)
}
pub fn make_layer<V, I, S, C>(
&self,
shader: &RenderShader<S, V, I>,
conf: C,
) -> Layer<render::Input<V, I, S>>
where
C: Into<Config>,
{
let conf = conf.into();
Layer::new(&self.0, shader.data(), conf)
}
pub fn make_mesh<V>(&self, data: &mesh::MeshData<'_, V>) -> Mesh<V>
where
V: Bytes,
{
Mesh::new(&self.0, data)
}
pub fn make_row<V>(&self, value: &[V]) -> Option<Row<V>>
where
V: Value + Bytes,
{
store::row(value, self)
}
pub fn make_texture<U>(&self, data: buffer::TextureData<'_, U>) -> TextureBuffer<2, U>
where
U: u::TextureUsages,
{
TextureBuffer::new(&self.0, data)
}
pub fn make_sampler(&self, filter: Filter) -> TextureSampler {
TextureSampler::new(&self.0, filter)
}
pub fn make_buffer<U>(&self, data: buffer::BufferData<'_, U>) -> Buffer<U>
where
U: u::BufferUsages,
{
Buffer::new(&self.0, data)
}
#[inline]
pub async fn read<'buf, U>(&self, buf: &'buf mut Buffer<U>) -> Result<Read<'buf>, ReadFailed>
where
U: u::Read,
{
buf.read(&self.0).await
}
#[inline]
pub async fn write<'buf, U>(&self, buf: &'buf mut Buffer<U>) -> Result<Write<'buf>, WriteFailed>
where
U: u::Write,
{
buf.write(&self.0).await
}
#[inline]
pub async fn shed<F>(&self, f: F)
where
F: FnOnce(&mut Scheduler),
{
self.0.run(f).await;
}
pub fn update_group<S, G, const N: usize>(
&self,
set: &mut UniqueSet<S>,
handler: &GroupHandler<G::Inner, N>,
group: G,
) where
S: Nth<N, Output = G::Inner>,
G: Group,
{
set::update(&self.0, set, handler, group);
}
pub fn wgpu_info(&self) -> wgpu::AdapterInfo {
self.0.wgpu_info()
}
}
impl fmt::Debug for Context {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("Context").field(&"..").finish()
}
}
#[derive(Debug)]
pub enum FailedMakeContext {
BackendSelection(wgpu::RequestAdapterError),
RequestDevice(wgpu::RequestDeviceError),
}
impl fmt::Display for FailedMakeContext {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::BackendSelection(e) => write!(f, "failed to select backend: {e}"),
Self::RequestDevice(e) => write!(f, "failed to get device: {e}"),
}
}
}
impl error::Error for FailedMakeContext {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match self {
Self::BackendSelection(e) => Some(e),
Self::RequestDevice(e) => Some(e),
}
}
}