use crate::dx12::{
RafxDeviceContextDx12, RafxFenceDx12, RafxQueueDx12, RafxRawImageDx12, RafxSemaphoreDx12,
RafxTextureDx12,
};
use crate::{
RafxExtents3D, RafxFormat, RafxResourceType, RafxResult, RafxSampleCount,
RafxSwapchainColorSpace, RafxSwapchainDef, RafxSwapchainImage, RafxTexture, RafxTextureDef,
RafxTextureDimensions,
};
use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle, RawWindowHandle};
use windows::core::Interface;
use windows::Win32::Graphics::Dxgi::IDXGISwapChain3;
use super::dxgi;
const SWAPCHAIN_IMAGE_COUNT: u32 = 3;
pub struct RafxSwapchainDx12 {
device_context: RafxDeviceContextDx12,
swapchain_def: RafxSwapchainDef,
format: RafxFormat,
color_space: RafxSwapchainColorSpace,
swapchain_images: Vec<RafxSwapchainImage>,
swapchain: dxgi::IDXGISwapChain3,
swapchain_flags: dxgi::DXGI_SWAP_CHAIN_FLAG,
present_queue: RafxQueueDx12,
}
unsafe impl Send for RafxSwapchainDx12 {}
unsafe impl Sync for RafxSwapchainDx12 {}
impl RafxSwapchainDx12 {
pub fn swapchain_def(&self) -> &RafxSwapchainDef {
&self.swapchain_def
}
pub fn image_count(&self) -> usize {
SWAPCHAIN_IMAGE_COUNT as usize
}
pub fn format(&self) -> RafxFormat {
self.format
}
pub fn color_space(&self) -> RafxSwapchainColorSpace {
self.color_space
}
pub fn dx12_swapchain(&self) -> &dxgi::IDXGISwapChain3 {
&self.swapchain
}
pub fn swapchain_flags(&self) -> dxgi::DXGI_SWAP_CHAIN_FLAG {
self.swapchain_flags
}
pub fn new(
device_context: &RafxDeviceContextDx12,
_raw_display_handle: &dyn HasRawDisplayHandle,
raw_window_handle: &dyn HasRawWindowHandle,
swapchain_def: &RafxSwapchainDef,
present_queue: &RafxQueueDx12,
) -> RafxResult<RafxSwapchainDx12> {
let preferred_color_space = RafxSwapchainColorSpace::Srgb;
let pixel_format = dxgi::Common::DXGI_FORMAT_B8G8R8A8_UNORM;
let swapchain_format = RafxFormat::B8G8R8A8_SRGB;
let hwnd = match raw_window_handle.raw_window_handle() {
RawWindowHandle::Win32(hwnd) => {
println!("HWND: {:?}", hwnd);
windows::Win32::Foundation::HWND(hwnd.hwnd as isize)
}
_ => return Err("Cannot create RafxSurfaceDx12 on this operating system".into()),
};
let sample_desc = super::dxgi::Common::DXGI_SAMPLE_DESC {
Count: 1,
Quality: 0,
};
let desc = dxgi::DXGI_SWAP_CHAIN_DESC1 {
Width: swapchain_def.width,
Height: swapchain_def.height,
Format: pixel_format,
Stereo: windows::Win32::Foundation::FALSE,
SampleDesc: sample_desc,
BufferUsage: dxgi::DXGI_USAGE_RENDER_TARGET_OUTPUT,
BufferCount: SWAPCHAIN_IMAGE_COUNT,
Scaling: dxgi::DXGI_SCALING_STRETCH,
SwapEffect: dxgi::DXGI_SWAP_EFFECT_FLIP_DISCARD,
AlphaMode: dxgi::Common::DXGI_ALPHA_MODE_UNSPECIFIED,
Flags: 0,
};
let swapchain = unsafe {
let swapchain: IDXGISwapChain3 = device_context
.dxgi_factory()
.CreateSwapChainForHwnd(present_queue.dx12_queue(), hwnd, &desc, None, None)?
.cast()?;
device_context
.dxgi_factory()
.MakeWindowAssociation(hwnd, dxgi::DXGI_MWA_NO_ALT_ENTER)?;
swapchain
};
let swapchain_images = Self::create_swapchain_images(
device_context,
&swapchain_def,
swapchain_format,
&swapchain,
)?;
let swapchain_def = swapchain_def.clone();
Ok(RafxSwapchainDx12 {
device_context: device_context.clone(),
swapchain_def,
format: swapchain_format,
color_space: preferred_color_space,
swapchain_images,
swapchain,
swapchain_flags: dxgi::DXGI_SWAP_CHAIN_FLAG(0),
present_queue: present_queue.clone(),
})
}
fn create_swapchain_images(
device_context: &RafxDeviceContextDx12,
swapchain_def: &&RafxSwapchainDef,
swapchain_format: RafxFormat,
swapchain: &IDXGISwapChain3,
) -> RafxResult<Vec<RafxSwapchainImage>> {
let mut swapchain_images = Vec::with_capacity(SWAPCHAIN_IMAGE_COUNT as usize);
for i in 0..SWAPCHAIN_IMAGE_COUNT {
let raw_image = RafxRawImageDx12 {
image: unsafe { swapchain.GetBuffer(i)? },
allocation: None,
};
let format = swapchain_format;
let resource_type = RafxResourceType::TEXTURE | RafxResourceType::RENDER_TARGET_COLOR;
let swapchain_image = RafxTextureDx12::from_existing(
device_context,
Some(raw_image),
&RafxTextureDef {
extents: RafxExtents3D {
width: swapchain_def.width,
height: swapchain_def.height,
depth: 1,
},
array_length: 1,
mip_count: 1,
format,
resource_type,
sample_count: RafxSampleCount::SampleCount1,
dimensions: RafxTextureDimensions::Dim2D,
},
)?;
swapchain_images.push(RafxSwapchainImage {
texture: RafxTexture::Dx12(swapchain_image),
swapchain_image_index: i,
});
}
Ok(swapchain_images)
}
pub fn rebuild(
&mut self,
swapchain_def: &RafxSwapchainDef,
) -> RafxResult<()> {
self.present_queue.wait_for_queue_idle()?;
self.swapchain_images.clear();
let pixel_format = dxgi::Common::DXGI_FORMAT_B8G8R8A8_UNORM;
let swapchain_format = RafxFormat::B8G8R8A8_SRGB;
unsafe {
self.swapchain.ResizeBuffers(
SWAPCHAIN_IMAGE_COUNT,
swapchain_def.width,
swapchain_def.height,
pixel_format,
0,
)?;
}
let swapchain_images = Self::create_swapchain_images(
&self.device_context,
&swapchain_def,
swapchain_format,
&self.swapchain,
)?;
self.swapchain_images = swapchain_images;
self.swapchain_def = swapchain_def.clone();
Ok(())
}
pub fn acquire_next_image_fence(
&mut self,
_fence: &RafxFenceDx12,
) -> RafxResult<RafxSwapchainImage> {
self.acquire_next_image()
}
pub fn acquire_next_image_semaphore(
&mut self,
_semaphore: &RafxSemaphoreDx12,
) -> RafxResult<RafxSwapchainImage> {
self.acquire_next_image()
}
pub fn acquire_next_image(&mut self) -> RafxResult<RafxSwapchainImage> {
let swapchain_image_index = unsafe { self.swapchain.GetCurrentBackBufferIndex() };
Ok(self.swapchain_images[swapchain_image_index as usize].clone())
}
}