librashader/librashader-runtime-d3d11/src/framebuffer.rs

271 lines
8.6 KiB
Rust
Raw Normal View History

2022-12-01 11:05:12 +11:00
use crate::error;
use crate::error::{assume_d3d11_init, FilterChainError};
2023-02-06 08:17:23 +11:00
use crate::texture::D3D11InputView;
2022-11-29 17:57:04 +11:00
use crate::util::d3d11_get_closest_format;
2022-11-30 17:38:05 +11:00
use librashader_common::{ImageFormat, Size};
use librashader_presets::Scale2D;
use librashader_runtime::scaling::{MipmapSize, ScaleableFramebuffer, ViewportSize};
2022-12-01 11:05:12 +11:00
use windows::core::Interface;
2022-11-30 17:38:05 +11:00
use windows::Win32::Graphics::Direct3D::D3D_SRV_DIMENSION_TEXTURE2D;
2022-12-22 13:39:31 +11:00
use windows::Win32::Graphics::Direct3D11::{
ID3D11Device, ID3D11DeviceContext, ID3D11RenderTargetView, ID3D11ShaderResourceView,
ID3D11Texture2D, D3D11_BIND_RENDER_TARGET, D3D11_BIND_SHADER_RESOURCE, D3D11_BOX,
D3D11_CPU_ACCESS_FLAG, D3D11_FORMAT_SUPPORT_RENDER_TARGET, D3D11_FORMAT_SUPPORT_SHADER_SAMPLE,
2022-12-22 13:39:31 +11:00
D3D11_FORMAT_SUPPORT_TEXTURE2D, D3D11_RENDER_TARGET_VIEW_DESC, D3D11_RENDER_TARGET_VIEW_DESC_0,
D3D11_RESOURCE_MISC_GENERATE_MIPS, D3D11_RTV_DIMENSION_TEXTURE2D,
D3D11_SHADER_RESOURCE_VIEW_DESC, D3D11_SHADER_RESOURCE_VIEW_DESC_0, D3D11_TEX2D_RTV,
D3D11_TEX2D_SRV, D3D11_TEXTURE2D_DESC, D3D11_USAGE_DEFAULT, D3D11_VIEWPORT,
};
2022-11-30 17:38:05 +11:00
use windows::Win32::Graphics::Dxgi::Common::{DXGI_FORMAT, DXGI_SAMPLE_DESC};
2022-11-29 17:57:04 +11:00
2022-11-27 18:21:36 +11:00
#[derive(Debug, Clone)]
2022-12-01 11:05:12 +11:00
pub(crate) struct OwnedFramebuffer {
render: ID3D11Texture2D,
pub(crate) size: Size<u32>,
format: DXGI_FORMAT,
2022-11-29 17:57:04 +11:00
device: ID3D11Device,
context: ID3D11DeviceContext,
max_mipmap: u32,
2022-11-27 18:21:36 +11:00
}
2022-11-29 17:57:04 +11:00
impl OwnedFramebuffer {
2022-11-30 17:38:05 +11:00
pub fn new(
device: &ID3D11Device,
context: &ID3D11DeviceContext,
2022-11-30 17:38:05 +11:00
size: Size<u32>,
format: ImageFormat,
mipmap: bool,
2022-12-01 11:05:12 +11:00
) -> error::Result<OwnedFramebuffer> {
2022-11-29 17:57:04 +11:00
unsafe {
2022-11-30 17:38:05 +11:00
let format = d3d11_get_closest_format(
device,
DXGI_FORMAT::from(format),
D3D11_FORMAT_SUPPORT_TEXTURE2D.0
| D3D11_FORMAT_SUPPORT_SHADER_SAMPLE.0
| D3D11_FORMAT_SUPPORT_RENDER_TARGET.0,
);
let desc = default_desc(size, format, 1);
let mut render = None;
device.CreateTexture2D(&desc, None, Some(&mut render))?;
assume_d3d11_init!(render, "CreateTexture2D");
2022-11-29 17:57:04 +11:00
Ok(OwnedFramebuffer {
render,
2022-11-29 17:57:04 +11:00
size,
format,
device: device.clone(),
context: context.clone(),
2023-01-30 13:26:34 +11:00
max_mipmap: if mipmap {
size.calculate_miplevels()
} else {
1
},
2022-11-29 17:57:04 +11:00
})
}
}
pub(crate) fn scale(
&mut self,
scaling: Scale2D,
format: ImageFormat,
viewport_size: &Size<u32>,
source_size: &Size<u32>,
should_mipmap: bool,
2022-12-01 11:05:12 +11:00
) -> error::Result<Size<u32>> {
let size = source_size.scale_viewport(scaling, *viewport_size);
2022-11-29 17:57:04 +11:00
if self.size != size
|| (should_mipmap && self.max_mipmap == 1)
|| (!should_mipmap && self.max_mipmap != 1)
{
2022-11-29 17:57:04 +11:00
self.size = size;
self.max_mipmap = if should_mipmap {
size.calculate_miplevels()
} else {
1
};
2022-11-27 18:21:36 +11:00
2022-11-29 17:57:04 +11:00
self.init(
size,
if format == ImageFormat::Unknown {
ImageFormat::R8G8B8A8Unorm
} else {
format
},
)?;
}
Ok(size)
}
2022-12-01 11:05:12 +11:00
pub fn init(&mut self, size: Size<u32>, format: ImageFormat) -> error::Result<()> {
2022-11-30 17:38:05 +11:00
let format = d3d11_get_closest_format(
&self.device,
DXGI_FORMAT::from(format),
D3D11_FORMAT_SUPPORT_TEXTURE2D.0
| D3D11_FORMAT_SUPPORT_SHADER_SAMPLE.0
| D3D11_FORMAT_SUPPORT_RENDER_TARGET.0,
);
2022-11-30 11:36:42 +11:00
let desc = default_desc(size, format, self.max_mipmap);
2022-11-29 17:57:04 +11:00
unsafe {
2023-01-17 10:45:02 +11:00
let mut texture = None;
self.device
.CreateTexture2D(&desc, None, Some(&mut texture))?;
assume_d3d11_init!(mut texture, "CreateTexture2D");
std::mem::swap(&mut self.render, &mut texture);
2022-11-29 17:57:04 +11:00
drop(texture)
}
self.format = format;
self.size = size;
2022-11-29 17:57:04 +11:00
Ok(())
}
2022-12-01 11:05:12 +11:00
pub fn create_shader_resource_view(&self) -> error::Result<ID3D11ShaderResourceView> {
2023-01-17 10:45:02 +11:00
let mut srv = None;
2022-11-29 17:57:04 +11:00
unsafe {
2023-01-17 10:45:02 +11:00
self.device.CreateShaderResourceView(
&self.render,
2022-11-30 17:38:05 +11:00
Some(&D3D11_SHADER_RESOURCE_VIEW_DESC {
Format: self.format,
ViewDimension: D3D_SRV_DIMENSION_TEXTURE2D,
Anonymous: D3D11_SHADER_RESOURCE_VIEW_DESC_0 {
Texture2D: D3D11_TEX2D_SRV {
MostDetailedMip: 0,
MipLevels: u32::MAX,
},
},
}),
2023-01-17 10:45:02 +11:00
Some(&mut srv),
)?;
2022-11-29 17:57:04 +11:00
}
2023-01-17 10:45:02 +11:00
assume_d3d11_init!(srv, "CreateShaderResourceView");
Ok(srv)
2022-11-29 17:57:04 +11:00
}
2022-12-01 11:05:12 +11:00
pub fn create_render_target_view(&self) -> error::Result<ID3D11RenderTargetView> {
2023-01-17 10:45:02 +11:00
let mut rtv = None;
2022-11-29 17:57:04 +11:00
unsafe {
2023-01-17 10:45:02 +11:00
self.device.CreateRenderTargetView(
&self.render,
2022-11-30 17:38:05 +11:00
Some(&D3D11_RENDER_TARGET_VIEW_DESC {
Format: self.format,
ViewDimension: D3D11_RTV_DIMENSION_TEXTURE2D,
Anonymous: D3D11_RENDER_TARGET_VIEW_DESC_0 {
Texture2D: D3D11_TEX2D_RTV { MipSlice: 0 },
},
}),
2023-01-17 10:45:02 +11:00
Some(&mut rtv),
)?
2022-11-29 17:57:04 +11:00
}
2023-01-17 10:45:02 +11:00
assume_d3d11_init!(rtv, "CreateRenderTargetView");
Ok(rtv)
2022-11-29 17:57:04 +11:00
}
2022-12-01 11:05:12 +11:00
pub fn as_output_framebuffer(&self) -> error::Result<OutputFramebuffer> {
2022-11-29 17:57:04 +11:00
Ok(OutputFramebuffer {
rtv: self.create_render_target_view()?,
size: self.size,
2022-11-30 17:38:05 +11:00
viewport: default_viewport(self.size),
2022-11-29 17:57:04 +11:00
})
}
2022-11-30 17:35:20 +11:00
2023-01-13 18:54:16 +11:00
pub fn copy_from(&mut self, image: &D3D11InputView) -> error::Result<()> {
2022-12-10 17:50:54 +11:00
let original_resource: ID3D11Texture2D = unsafe {
2023-01-17 10:45:02 +11:00
let resource = image.handle.GetResource()?;
2022-12-01 09:59:55 +11:00
resource.cast()?
};
let format = unsafe {
let mut desc = Default::default();
2022-12-10 17:50:54 +11:00
original_resource.GetDesc(&mut desc);
desc.Format
};
if self.size != image.size || format != self.format {
2023-01-13 16:07:18 +11:00
// eprintln!("[history] resizing");
self.init(image.size, ImageFormat::from(format))?;
2022-11-30 17:35:20 +11:00
}
2022-12-01 16:24:24 +11:00
// todo: improve mipmap generation?
// will need a staging texture + full so might not be worth it.
unsafe {
self.context.CopySubresourceRegion(
&self.render,
2022-12-01 16:24:24 +11:00
0,
0,
0,
0,
2022-12-10 17:50:54 +11:00
&original_resource,
2022-12-01 16:24:24 +11:00
0,
Some(&D3D11_BOX {
left: 0,
top: 0,
front: 0,
right: self.size.width,
bottom: self.size.height,
back: 1,
}),
)
}
2022-12-10 17:50:54 +11:00
let srvs = self.create_shader_resource_view()?;
unsafe {
self.context.GenerateMips(&srvs);
}
2022-11-30 17:35:20 +11:00
Ok(())
}
2022-11-29 17:57:04 +11:00
}
#[derive(Debug, Clone)]
2022-12-01 11:05:12 +11:00
pub(crate) struct OutputFramebuffer {
2022-11-27 18:21:36 +11:00
pub rtv: ID3D11RenderTargetView,
pub size: Size<u32>,
2022-11-30 17:38:05 +11:00
pub viewport: D3D11_VIEWPORT,
2022-11-29 17:57:04 +11:00
}
2022-12-01 14:50:57 +11:00
fn default_desc(size: Size<u32>, format: DXGI_FORMAT, mip_levels: u32) -> D3D11_TEXTURE2D_DESC {
2022-11-29 17:57:04 +11:00
D3D11_TEXTURE2D_DESC {
Width: size.width,
Height: size.height,
2022-12-01 14:50:57 +11:00
MipLevels: mip_levels,
2022-11-29 17:57:04 +11:00
ArraySize: 1,
Format: format,
SampleDesc: DXGI_SAMPLE_DESC {
Count: 1,
Quality: 0,
},
Usage: D3D11_USAGE_DEFAULT,
BindFlags: D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET,
2023-02-07 15:34:32 +11:00
CPUAccessFlags: D3D11_CPU_ACCESS_FLAG(0),
2022-12-22 13:39:31 +11:00
MiscFlags: D3D11_RESOURCE_MISC_GENERATE_MIPS,
2022-11-29 17:57:04 +11:00
}
}
pub const fn default_viewport(size: Size<u32>) -> D3D11_VIEWPORT {
D3D11_VIEWPORT {
TopLeftX: 0.0,
TopLeftY: 0.0,
Width: size.width as f32,
Height: size.height as f32,
MinDepth: 0.0,
MaxDepth: 1.0,
}
2022-11-30 17:38:05 +11:00
}
impl<T> ScaleableFramebuffer<T> for OwnedFramebuffer {
type Error = FilterChainError;
type Context = ();
fn scale(
&mut self,
scaling: Scale2D,
format: ImageFormat,
viewport_size: &Size<u32>,
source_size: &Size<u32>,
should_mipmap: bool,
_context: Self::Context,
) -> Result<Size<u32>, Self::Error> {
self.scale(scaling, format, viewport_size, source_size, should_mipmap)
}
}