dxwr 0.4.3

Direct3D12 and DXGI wrapper library
Documentation
use super::*;
use windows::Win32::Foundation::HWND;
use windows::Win32::Graphics::Dxgi::{Common::*, *};
use windows::core::Interface;

pub struct Builder<Q = ()> {
    cmd_queue: Q,
    desc: DXGI_SWAP_CHAIN_DESC1,
}

impl Builder<()> {
    fn new() -> Self {
        Self {
            cmd_queue: (),
            desc: DXGI_SWAP_CHAIN_DESC1 {
                Scaling: DXGI_SCALING_STRETCH,
                SampleDesc: DXGI_SAMPLE_DESC {
                    Count: 1,
                    Quality: 0,
                },
                ..Default::default()
            },
        }
    }
}

impl<Q> Builder<Q> {
    #[inline]
    pub fn command_queue(
        self,
        cmd_queue: &CommandQueue<command_list_type::Direct>,
    ) -> Builder<CommandQueue<command_list_type::Direct>> {
        Builder {
            cmd_queue: cmd_queue.clone(),
            desc: DXGI_SWAP_CHAIN_DESC1 { ..self.desc },
        }
    }

    #[inline]
    pub fn width(mut self, width: u32) -> Self {
        self.desc.Width = width;
        self
    }

    #[inline]
    pub fn height(mut self, height: u32) -> Self {
        self.desc.Height = height;
        self
    }

    #[inline]
    pub fn stereo(mut self, stereo: bool) -> Self {
        self.desc.Stereo = stereo.into();
        self
    }

    #[inline]
    pub fn format(mut self, format: DXGI_FORMAT) -> Self {
        self.desc.Format = format;
        self
    }

    #[inline]
    pub fn sample_desc(mut self, desc: DXGI_SAMPLE_DESC) -> Self {
        self.desc.SampleDesc = desc;
        self
    }

    #[inline]
    pub fn buffer_usage(mut self, usage: DXGI_USAGE) -> Self {
        self.desc.BufferUsage = usage;
        self
    }

    #[inline]
    pub fn buffer_count(mut self, count: u32) -> Self {
        self.desc.BufferCount = count;
        self
    }

    #[inline]
    pub fn scaling(mut self, scaling: DXGI_SCALING) -> Self {
        self.desc.Scaling = scaling;
        self
    }

    #[inline]
    pub fn swap_effect(mut self, effect: DXGI_SWAP_EFFECT) -> Self {
        self.desc.SwapEffect = effect;
        self
    }

    #[inline]
    pub fn alpha_mode(mut self, mode: DXGI_ALPHA_MODE) -> Self {
        self.desc.AlphaMode = mode;
        self
    }

    #[inline]
    pub fn flags(mut self, flags: u32) -> Self {
        self.desc.Flags = flags;
        self
    }
}

impl Builder<CommandQueue<command_list_type::Direct>> {
    #[inline]
    pub fn build_for_composition(self) -> windows::core::Result<SwapChain> {
        let factory = dxgi_factory();
        let handle: IDXGISwapChain4 = unsafe {
            factory
                .CreateSwapChainForComposition(self.cmd_queue.handle(), &self.desc, None)?
                .cast()
                .unwrap()
        };

        Ok(SwapChain {
            handle,
            cmd_queue: self.cmd_queue,
        })
    }

    #[inline]
    pub fn build_for_hwnd(self, hwnd: *mut std::ffi::c_void) -> windows::core::Result<SwapChain> {
        let factory = dxgi_factory();
        let handle: IDXGISwapChain4 = unsafe {
            factory
                .CreateSwapChainForHwnd(
                    self.cmd_queue.handle(),
                    HWND(hwnd),
                    &self.desc,
                    None,
                    None,
                )?
                .cast()
                .unwrap()
        };
        Ok(SwapChain {
            handle,
            cmd_queue: self.cmd_queue,
        })
    }
}

#[derive(Clone, Default)]
pub struct ResizeBuffers {
    pub count: Option<u32>,
    pub width: Option<u32>,
    pub height: Option<u32>,
    pub format: Option<DXGI_FORMAT>,
    pub flags: Option<DXGI_SWAP_CHAIN_FLAG>,
}

#[derive(Clone)]
pub struct SwapChain {
    handle: IDXGISwapChain4,
    cmd_queue: CommandQueue<command_list_type::Direct>,
}

impl SwapChain {
    #[inline]
    #[allow(clippy::new_ret_no_self)]
    pub fn new() -> Builder {
        Builder::new()
    }

    #[inline]
    pub fn get_buffer(&self, index: usize) -> windows::core::Result<Resource> {
        unsafe { Ok(Resource::from_raw(self.handle.GetBuffer(index as u32)?)) }
    }

    #[inline]
    pub fn get_current_back_buffer_index(&self) -> usize {
        unsafe { self.handle.GetCurrentBackBufferIndex() as usize }
    }

    #[inline]
    pub fn get_last_present_count(&self) -> windows::core::Result<u32> {
        unsafe { self.handle.GetLastPresentCount() }
    }

    #[inline]
    pub fn get_frame_latency_waitable_object(&self) -> Handle {
        Handle::new(unsafe { self.handle.GetFrameLatencyWaitableObject() })
    }

    #[inline]
    pub fn set_maximum_frame_latency(&self, max_latency: u32) -> windows::core::Result<()> {
        unsafe { self.handle.SetMaximumFrameLatency(max_latency) }
    }

    #[inline]
    pub fn resize_buffers(&self, params: &ResizeBuffers) -> windows::core::Result<()> {
        unsafe {
            self.handle.ResizeBuffers(
                params.count.unwrap_or(0),
                params.width.unwrap_or(0),
                params.height.unwrap_or(0),
                params.format.unwrap_or(DXGI_FORMAT_UNKNOWN),
                DXGI_SWAP_CHAIN_FLAG(params.flags.map_or(0, |flag| flag.0)),
            )?;
            Ok(())
        }
    }

    #[inline]
    pub fn present(
        &self,
        fence: &Fence,
        interval: u32,
        flags: DXGI_PRESENT,
    ) -> windows::core::Result<Signal> {
        unsafe {
            self.handle.Present(interval, flags).ok()?;
        }
        self.cmd_queue.signal(fence)
    }

    #[inline]
    pub fn handle(&self) -> &IDXGISwapChain4 {
        &self.handle
    }
}