2024-03-08 12:15:16 +11:00
|
|
|
use crate::error;
|
2023-02-07 18:12:47 +11:00
|
|
|
use crate::error::{assume_d3d11_init, FilterChainError};
|
2022-11-29 17:57:04 +11:00
|
|
|
use crate::util::d3d11_get_closest_format;
|
2023-02-10 13:03:55 +11:00
|
|
|
use librashader_common::{ImageFormat, Size};
|
2022-11-30 17:38:05 +11:00
|
|
|
use librashader_presets::Scale2D;
|
2023-02-08 14:02:08 +11:00
|
|
|
use librashader_runtime::scaling::{MipmapSize, ScaleFramebuffer, ViewportSize};
|
2023-04-23 15:13:31 +10:00
|
|
|
use windows::core::ComInterface;
|
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,
|
2024-02-27 11:04:40 +11:00
|
|
|
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,
|
2023-02-10 13:03:55 +11:00
|
|
|
D3D11_TEX2D_SRV, D3D11_TEXTURE2D_DESC, D3D11_USAGE_DEFAULT,
|
2022-12-22 13:39:31 +11:00
|
|
|
};
|
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
|
|
|
|
2023-02-09 16:42:46 +11:00
|
|
|
static CLEAR: &[f32; 4] = &[0.0f32, 0.0, 0.0, 0.0];
|
|
|
|
|
2022-11-27 18:21:36 +11:00
|
|
|
#[derive(Debug, Clone)]
|
2023-02-11 16:20:35 +11:00
|
|
|
pub(crate) struct OwnedImage {
|
2023-01-30 11:04:34 +11:00
|
|
|
render: ID3D11Texture2D,
|
|
|
|
pub(crate) size: Size<u32>,
|
|
|
|
format: DXGI_FORMAT,
|
2022-11-29 17:57:04 +11:00
|
|
|
device: ID3D11Device,
|
2023-01-30 11:04:34 +11:00
|
|
|
max_mipmap: u32,
|
2022-11-27 18:21:36 +11:00
|
|
|
}
|
|
|
|
|
2023-02-11 16:20:35 +11:00
|
|
|
impl OwnedImage {
|
2022-11-30 17:38:05 +11:00
|
|
|
pub fn new(
|
|
|
|
device: &ID3D11Device,
|
|
|
|
size: Size<u32>,
|
|
|
|
format: ImageFormat,
|
2023-01-30 11:04:34 +11:00
|
|
|
mipmap: bool,
|
2023-02-11 16:20:35 +11:00
|
|
|
) -> error::Result<OwnedImage> {
|
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,
|
|
|
|
);
|
2022-12-01 16:11:41 +11:00
|
|
|
let desc = default_desc(size, format, 1);
|
2023-01-30 11:04:34 +11:00
|
|
|
let mut render = None;
|
|
|
|
device.CreateTexture2D(&desc, None, Some(&mut render))?;
|
|
|
|
assume_d3d11_init!(render, "CreateTexture2D");
|
2022-11-29 17:57:04 +11:00
|
|
|
|
2023-02-11 16:20:35 +11:00
|
|
|
Ok(OwnedImage {
|
2023-01-30 11:04:34 +11:00
|
|
|
render,
|
2022-11-29 17:57:04 +11:00
|
|
|
size,
|
|
|
|
format,
|
|
|
|
device: device.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>,
|
2023-01-30 13:26:11 +11:00
|
|
|
source_size: &Size<u32>,
|
2024-02-12 17:02:46 +11:00
|
|
|
original_size: &Size<u32>,
|
2023-01-30 11:04:34 +11:00
|
|
|
should_mipmap: bool,
|
2022-12-01 11:05:12 +11:00
|
|
|
) -> error::Result<Size<u32>> {
|
2024-02-12 17:02:46 +11:00
|
|
|
let size = source_size.scale_viewport(scaling, *viewport_size, *original_size);
|
2022-11-29 17:57:04 +11:00
|
|
|
|
2023-01-30 11:04:34 +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;
|
2023-01-30 11:04:34 +11:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2023-02-11 10:08:11 +11:00
|
|
|
pub fn clear(&mut self, ctx: &ID3D11DeviceContext) -> error::Result<()> {
|
2023-02-09 16:42:46 +11:00
|
|
|
let rtv = self.create_render_target_view()?;
|
|
|
|
unsafe {
|
2024-02-27 11:04:40 +11:00
|
|
|
ctx.ClearRenderTargetView(&rtv, CLEAR);
|
2023-02-09 16:42:46 +11:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2023-01-30 11:04:34 +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");
|
2023-01-30 11:04:34 +11:00
|
|
|
std::mem::swap(&mut self.render, &mut texture);
|
2022-11-29 17:57:04 +11:00
|
|
|
drop(texture)
|
|
|
|
}
|
|
|
|
self.format = format;
|
2022-11-30 17:52:08 +11:00
|
|
|
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(
|
2023-01-30 11:04:34 +11:00
|
|
|
&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(
|
2023-01-30 11:04:34 +11:00
|
|
|
&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
|
|
|
}
|
|
|
|
|
2023-02-11 10:08:11 +11:00
|
|
|
pub fn copy_from(
|
|
|
|
&mut self,
|
|
|
|
ctx: &ID3D11DeviceContext,
|
2024-03-08 12:15:16 +11:00
|
|
|
image: &ID3D11ShaderResourceView,
|
2023-02-11 10:08:11 +11:00
|
|
|
) -> error::Result<()> {
|
2022-12-10 17:50:54 +11:00
|
|
|
let original_resource: ID3D11Texture2D = unsafe {
|
2024-03-08 12:15:16 +11:00
|
|
|
let resource = image.GetResource()?;
|
2022-12-01 09:59:55 +11:00
|
|
|
resource.cast()?
|
2022-11-30 17:52:08 +11:00
|
|
|
};
|
|
|
|
|
2024-03-08 12:15:16 +11:00
|
|
|
let (format, image_size) = unsafe {
|
2022-11-30 17:52:08 +11:00
|
|
|
let mut desc = Default::default();
|
2022-12-10 17:50:54 +11:00
|
|
|
original_resource.GetDesc(&mut desc);
|
2024-03-08 12:15:16 +11:00
|
|
|
(desc.Format, Size::new(desc.Width, desc.Height))
|
2022-11-30 17:52:08 +11:00
|
|
|
};
|
|
|
|
|
2024-03-08 12:15:16 +11:00
|
|
|
if self.size != image_size || format != self.format {
|
2023-01-13 16:07:18 +11:00
|
|
|
// eprintln!("[history] resizing");
|
2024-03-08 12:15:16 +11:00
|
|
|
self.init(image_size, ImageFormat::from(format))?;
|
2022-11-30 17:35:20 +11:00
|
|
|
}
|
2022-11-30 17:52:08 +11:00
|
|
|
|
2022-12-01 16:24:24 +11:00
|
|
|
unsafe {
|
2023-02-11 10:08:11 +11:00
|
|
|
ctx.CopySubresourceRegion(
|
2023-01-30 11:04:34 +11:00
|
|
|
&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 {
|
2023-02-11 10:08:11 +11:00
|
|
|
ctx.GenerateMips(&srvs);
|
2022-12-10 17:50:54 +11:00
|
|
|
}
|
2022-11-30 17:35:20 +11:00
|
|
|
Ok(())
|
|
|
|
}
|
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,
|
2024-02-27 11:04:40 +11:00
|
|
|
BindFlags: (D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET).0 as u32,
|
|
|
|
CPUAccessFlags: 0,
|
|
|
|
MiscFlags: D3D11_RESOURCE_MISC_GENERATE_MIPS.0 as u32,
|
2022-11-29 17:57:04 +11:00
|
|
|
}
|
|
|
|
}
|
2023-02-07 18:12:47 +11:00
|
|
|
|
2023-02-11 16:20:35 +11:00
|
|
|
impl ScaleFramebuffer for OwnedImage {
|
2023-02-07 18:12:47 +11:00
|
|
|
type Error = FilterChainError;
|
|
|
|
type Context = ();
|
|
|
|
|
|
|
|
fn scale(
|
|
|
|
&mut self,
|
|
|
|
scaling: Scale2D,
|
|
|
|
format: ImageFormat,
|
|
|
|
viewport_size: &Size<u32>,
|
|
|
|
source_size: &Size<u32>,
|
2024-02-12 17:02:46 +11:00
|
|
|
original_size: &Size<u32>,
|
2023-02-07 18:12:47 +11:00
|
|
|
should_mipmap: bool,
|
2023-02-08 14:02:08 +11:00
|
|
|
_context: &Self::Context,
|
2023-02-07 18:12:47 +11:00
|
|
|
) -> Result<Size<u32>, Self::Error> {
|
2024-02-12 17:02:46 +11:00
|
|
|
self.scale(
|
|
|
|
scaling,
|
|
|
|
format,
|
|
|
|
viewport_size,
|
|
|
|
source_size,
|
|
|
|
original_size,
|
|
|
|
should_mipmap,
|
|
|
|
)
|
2023-02-07 18:12:47 +11:00
|
|
|
}
|
|
|
|
}
|