use {
crate::{
Vertex,
buffer::{
self, Buffer, Filter, Read, ReadFailed, Sampler, Texture, Texture2d, Write, WriteFailed,
},
compute,
instance::{Row, RowValue},
layer::{Config, Layer},
mesh::{self, Mesh},
render,
set::{self, Data, GroupHandler, UniqueSet, Visit},
shader::{ComputeShader, RenderShader, Shader},
sl,
state::{Scheduler, State},
storage::{Storage, Uniform},
usage::u,
value::{StorageValue, UniformValue},
workload::Workload,
},
dunge_shade::group::Group,
std::{error, fmt, pin::Pin, sync::Arc},
};
pub fn context() -> Builder {
Builder(wgpu::Features::empty())
}
pub struct Builder(wgpu::Features);
impl Builder {
#[cfg(not(target_family = "wasm"))]
pub fn enable_polygon_mode_line(self) -> Self {
Self(self.0 | wgpu::Features::POLYGON_MODE_LINE)
}
#[cfg(not(target_family = "wasm"))]
pub fn enable_polygon_mode_point(self) -> Self {
Self(self.0 | wgpu::Features::POLYGON_MODE_POINT)
}
}
impl IntoFuture for Builder {
type Output = Result<Context, FailedMakeContext>;
type IntoFuture = Pin<Box<dyn Future<Output = Self::Output>>>;
fn into_future(self) -> Self::IntoFuture {
Box::pin(async move {
let state = State::new(self.0).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<M, A, K>(&self, module: M) -> Shader<M::Input, M::Set>
where
M: sl::IntoModule<A, K>,
{
Shader::new(&self.0, module)
}
pub fn make_set<K, S, D>(&self, shader: &Shader<K, S>, set: D) -> UniqueSet<S>
where
D: Data<Set = S>,
{
UniqueSet::new(&self.0, shader.data(), set)
}
pub fn make_uniform<V>(&self, val: &V) -> Uniform<V>
where
V: UniformValue,
{
Uniform::new(self, val)
}
pub fn make_storage<V>(&self, val: &V) -> Storage<V>
where
V: StorageValue + ?Sized,
{
Storage::new(self, val)
}
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_workload<S>(&self, shader: &ComputeShader<S>) -> Workload<compute::Input<S>> {
Workload::new(&self.0, shader.data())
}
pub fn make_mesh<V>(&self, data: &mesh::MeshData<'_, V>) -> Mesh<V>
where
V: Vertex,
{
Mesh::new(&self.0, data)
}
pub fn make_row<V>(&self, data: &[V]) -> Row<V>
where
V: RowValue,
{
Row::new(&self.0, data)
}
pub fn make_texture<U>(&self, data: buffer::TextureData<'_, U>) -> Texture2d<U>
where
U: u::TextureUsages,
{
Texture::new(&self.0, data)
}
pub fn make_sampler(&self, filter: Filter) -> Sampler {
Sampler::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>(
&self,
set: &mut UniqueSet<S>,
handler: &GroupHandler<S, G::Projection>,
group: G,
) where
G: Visit + Group,
{
set::update(&self.0, set, handler, group);
}
}
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),
}
}
}