2023-02-06 08:17:23 +11:00
|
|
|
use crate::descriptor_heap::{CpuStagingHeap, D3D12DescriptorHeap, RenderTargetHeap};
|
2023-01-31 17:25:45 +11:00
|
|
|
use crate::error::assume_d3d12_init;
|
2023-02-01 16:16:06 +11:00
|
|
|
use crate::texture::{InputTexture, OutputTexture};
|
2023-01-31 17:25:45 +11:00
|
|
|
use crate::util::d3d12_get_closest_format;
|
2023-02-06 10:03:38 +11:00
|
|
|
use crate::{error, util};
|
2023-02-06 08:17:23 +11:00
|
|
|
use librashader_common::{FilterMode, ImageFormat, Size, WrapMode};
|
|
|
|
use librashader_presets::Scale2D;
|
|
|
|
use librashader_runtime::scaling::{MipmapSize, ViewportSize};
|
|
|
|
use std::ops::Deref;
|
|
|
|
use windows::Win32::Graphics::Direct3D12::{
|
2023-02-06 10:03:38 +11:00
|
|
|
ID3D12Device, ID3D12GraphicsCommandList, ID3D12Resource, D3D12_BOX,
|
|
|
|
D3D12_CPU_PAGE_PROPERTY_UNKNOWN, D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING,
|
|
|
|
D3D12_FEATURE_DATA_FORMAT_SUPPORT, D3D12_FORMAT_SUPPORT1_MIP,
|
|
|
|
D3D12_FORMAT_SUPPORT1_RENDER_TARGET, D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE,
|
|
|
|
D3D12_FORMAT_SUPPORT1_TEXTURE2D, D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE, D3D12_HEAP_FLAG_NONE,
|
|
|
|
D3D12_HEAP_PROPERTIES, D3D12_HEAP_TYPE_DEFAULT, D3D12_MEMORY_POOL_UNKNOWN,
|
|
|
|
D3D12_RENDER_TARGET_VIEW_DESC, D3D12_RENDER_TARGET_VIEW_DESC_0, D3D12_RESOURCE_DESC,
|
|
|
|
D3D12_RESOURCE_DIMENSION_TEXTURE2D, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET,
|
|
|
|
D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_DEST,
|
|
|
|
D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
|
|
|
|
D3D12_RTV_DIMENSION_TEXTURE2D, D3D12_SHADER_RESOURCE_VIEW_DESC,
|
|
|
|
D3D12_SHADER_RESOURCE_VIEW_DESC_0, D3D12_SRV_DIMENSION_TEXTURE2D, D3D12_TEX2D_RTV,
|
|
|
|
D3D12_TEX2D_SRV, D3D12_TEXTURE_COPY_LOCATION, D3D12_TEXTURE_COPY_LOCATION_0,
|
|
|
|
D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX,
|
2023-02-06 08:17:23 +11:00
|
|
|
};
|
|
|
|
use windows::Win32::Graphics::Dxgi::Common::DXGI_SAMPLE_DESC;
|
2023-01-31 17:25:45 +11:00
|
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub(crate) struct OwnedImage {
|
2023-02-06 08:17:23 +11:00
|
|
|
pub(crate) handle: ID3D12Resource,
|
2023-01-31 17:25:45 +11:00
|
|
|
pub(crate) size: Size<u32>,
|
2023-02-06 10:03:38 +11:00
|
|
|
pub(crate) format: ImageFormat,
|
2023-01-31 17:25:45 +11:00
|
|
|
device: ID3D12Device,
|
|
|
|
max_mipmap: u16,
|
|
|
|
}
|
|
|
|
|
2023-02-01 09:50:47 +11:00
|
|
|
impl OwnedImage {
|
|
|
|
pub fn new(
|
|
|
|
device: &ID3D12Device,
|
|
|
|
size: Size<u32>,
|
|
|
|
format: ImageFormat,
|
|
|
|
mipmap: bool,
|
|
|
|
) -> error::Result<OwnedImage> {
|
|
|
|
unsafe {
|
2023-02-06 08:17:23 +11:00
|
|
|
let miplevels = if mipmap {
|
|
|
|
size.calculate_miplevels()
|
|
|
|
} else {
|
|
|
|
1
|
|
|
|
};
|
2023-02-01 09:50:47 +11:00
|
|
|
let mut desc = D3D12_RESOURCE_DESC {
|
|
|
|
Dimension: D3D12_RESOURCE_DIMENSION_TEXTURE2D,
|
|
|
|
Alignment: 0,
|
|
|
|
Width: size.width as u64,
|
|
|
|
Height: size.height,
|
|
|
|
DepthOrArraySize: 1,
|
2023-02-01 17:25:39 +11:00
|
|
|
MipLevels: miplevels as u16,
|
2023-02-01 09:50:47 +11:00
|
|
|
Format: format.into(),
|
|
|
|
SampleDesc: DXGI_SAMPLE_DESC {
|
|
|
|
Count: 1,
|
|
|
|
Quality: 0,
|
|
|
|
},
|
|
|
|
Layout: Default::default(),
|
2023-02-01 17:57:31 +11:00
|
|
|
Flags: D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET,
|
2023-02-01 09:50:47 +11:00
|
|
|
};
|
|
|
|
|
|
|
|
let mut format_support = D3D12_FEATURE_DATA_FORMAT_SUPPORT {
|
|
|
|
Format: desc.Format,
|
|
|
|
Support1: D3D12_FORMAT_SUPPORT1_TEXTURE2D
|
|
|
|
| D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE
|
|
|
|
| D3D12_FORMAT_SUPPORT1_RENDER_TARGET,
|
|
|
|
..Default::default()
|
|
|
|
};
|
|
|
|
|
|
|
|
if mipmap {
|
|
|
|
desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
|
|
|
|
format_support.Support1 |= D3D12_FORMAT_SUPPORT1_MIP;
|
|
|
|
}
|
|
|
|
|
|
|
|
desc.Format = d3d12_get_closest_format(device, desc.Format, format_support);
|
|
|
|
let mut resource: Option<ID3D12Resource> = None;
|
|
|
|
unsafe {
|
|
|
|
device.CreateCommittedResource(
|
|
|
|
&D3D12_HEAP_PROPERTIES {
|
|
|
|
Type: D3D12_HEAP_TYPE_DEFAULT,
|
|
|
|
CPUPageProperty: D3D12_CPU_PAGE_PROPERTY_UNKNOWN,
|
|
|
|
MemoryPoolPreference: D3D12_MEMORY_POOL_UNKNOWN,
|
|
|
|
CreationNodeMask: 1,
|
|
|
|
VisibleNodeMask: 1,
|
|
|
|
},
|
|
|
|
D3D12_HEAP_FLAG_NONE,
|
|
|
|
&desc,
|
|
|
|
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
|
|
|
|
None,
|
|
|
|
&mut resource,
|
|
|
|
)?;
|
|
|
|
}
|
|
|
|
assume_d3d12_init!(resource, "CreateCommittedResource");
|
|
|
|
|
|
|
|
Ok(OwnedImage {
|
|
|
|
handle: resource,
|
|
|
|
size,
|
|
|
|
format,
|
|
|
|
device: device.clone(),
|
2023-02-01 17:25:39 +11:00
|
|
|
max_mipmap: miplevels as u16,
|
2023-02-01 09:50:47 +11:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-06 10:03:38 +11:00
|
|
|
/// SAFETY: self must fit the source image
|
|
|
|
/// source must be in D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE
|
|
|
|
pub unsafe fn copy_from(
|
|
|
|
&self,
|
|
|
|
cmd: &ID3D12GraphicsCommandList,
|
|
|
|
input: &InputTexture,
|
|
|
|
) -> error::Result<()> {
|
|
|
|
util::d3d12_resource_transition(
|
|
|
|
cmd,
|
|
|
|
&input.resource,
|
|
|
|
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
|
|
|
|
D3D12_RESOURCE_STATE_COPY_SOURCE,
|
|
|
|
);
|
|
|
|
|
|
|
|
util::d3d12_resource_transition(
|
|
|
|
cmd,
|
|
|
|
&self.handle,
|
|
|
|
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
|
|
|
|
D3D12_RESOURCE_STATE_COPY_DEST,
|
|
|
|
);
|
|
|
|
unsafe {
|
|
|
|
cmd.CopyTextureRegion(
|
|
|
|
&D3D12_TEXTURE_COPY_LOCATION {
|
|
|
|
pResource: windows::core::ManuallyDrop::new(&self.handle),
|
|
|
|
Type: D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX,
|
|
|
|
Anonymous: D3D12_TEXTURE_COPY_LOCATION_0 {
|
|
|
|
SubresourceIndex: 0,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
&D3D12_TEXTURE_COPY_LOCATION {
|
|
|
|
pResource: windows::core::ManuallyDrop::new(&input.resource),
|
|
|
|
Type: D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX,
|
|
|
|
Anonymous: D3D12_TEXTURE_COPY_LOCATION_0 {
|
|
|
|
SubresourceIndex: 0,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Some(&D3D12_BOX {
|
|
|
|
left: 0,
|
|
|
|
top: 0,
|
|
|
|
front: 0,
|
|
|
|
right: input.size.width,
|
|
|
|
bottom: input.size.height,
|
|
|
|
back: 1,
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
util::d3d12_resource_transition(
|
|
|
|
cmd,
|
|
|
|
&input.resource,
|
|
|
|
D3D12_RESOURCE_STATE_COPY_SOURCE,
|
|
|
|
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
|
|
|
|
);
|
|
|
|
util::d3d12_resource_transition(
|
|
|
|
cmd,
|
|
|
|
&self.handle,
|
|
|
|
D3D12_RESOURCE_STATE_COPY_DEST,
|
|
|
|
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
|
|
|
|
);
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2023-02-06 08:17:23 +11:00
|
|
|
pub(crate) fn create_shader_resource_view(
|
|
|
|
&self,
|
|
|
|
heap: &mut D3D12DescriptorHeap<CpuStagingHeap>,
|
|
|
|
filter: FilterMode,
|
|
|
|
wrap_mode: WrapMode,
|
|
|
|
) -> error::Result<InputTexture> {
|
2023-02-01 09:50:47 +11:00
|
|
|
let descriptor = heap.alloc_slot()?;
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
let srv_desc = D3D12_SHADER_RESOURCE_VIEW_DESC {
|
|
|
|
Format: self.format.into(),
|
|
|
|
ViewDimension: D3D12_SRV_DIMENSION_TEXTURE2D,
|
|
|
|
Shader4ComponentMapping: D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING,
|
|
|
|
Anonymous: D3D12_SHADER_RESOURCE_VIEW_DESC_0 {
|
|
|
|
Texture2D: D3D12_TEX2D_SRV {
|
2023-02-01 17:25:39 +11:00
|
|
|
MipLevels: u32::MAX,
|
2023-02-01 09:50:47 +11:00
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2023-02-06 08:17:23 +11:00
|
|
|
self.device.CreateShaderResourceView(
|
|
|
|
&self.handle,
|
|
|
|
Some(&srv_desc),
|
|
|
|
*descriptor.deref().as_ref(),
|
|
|
|
);
|
2023-01-31 17:25:45 +11:00
|
|
|
}
|
|
|
|
|
2023-02-06 08:17:23 +11:00
|
|
|
Ok(InputTexture::new(
|
2023-02-06 10:03:38 +11:00
|
|
|
self.handle.clone(),
|
2023-02-06 08:17:23 +11:00
|
|
|
descriptor,
|
|
|
|
self.size,
|
|
|
|
self.format,
|
|
|
|
wrap_mode,
|
|
|
|
filter,
|
|
|
|
))
|
2023-02-01 09:50:47 +11:00
|
|
|
}
|
|
|
|
|
2023-02-06 08:17:23 +11:00
|
|
|
pub(crate) fn create_render_target_view(
|
|
|
|
&self,
|
|
|
|
heap: &mut D3D12DescriptorHeap<RenderTargetHeap>,
|
2023-02-01 16:16:06 +11:00
|
|
|
) -> error::Result<OutputTexture> {
|
2023-02-01 09:50:47 +11:00
|
|
|
let descriptor = heap.alloc_slot()?;
|
2023-01-31 17:25:45 +11:00
|
|
|
|
|
|
|
unsafe {
|
2023-02-01 09:50:47 +11:00
|
|
|
let rtv_desc = D3D12_RENDER_TARGET_VIEW_DESC {
|
|
|
|
Format: self.format.into(),
|
|
|
|
ViewDimension: D3D12_RTV_DIMENSION_TEXTURE2D,
|
|
|
|
Anonymous: D3D12_RENDER_TARGET_VIEW_DESC_0 {
|
|
|
|
Texture2D: D3D12_TEX2D_RTV {
|
|
|
|
MipSlice: 0,
|
|
|
|
..Default::default()
|
|
|
|
},
|
2023-01-31 17:25:45 +11:00
|
|
|
},
|
2023-02-01 09:50:47 +11:00
|
|
|
};
|
|
|
|
|
2023-02-06 08:17:23 +11:00
|
|
|
self.device.CreateRenderTargetView(
|
|
|
|
&self.handle,
|
|
|
|
Some(&rtv_desc),
|
|
|
|
*descriptor.deref().as_ref(),
|
|
|
|
);
|
2023-01-31 17:25:45 +11:00
|
|
|
}
|
2023-02-01 09:50:47 +11:00
|
|
|
|
2023-02-01 16:16:06 +11:00
|
|
|
Ok(OutputTexture::new(descriptor, self.size))
|
2023-01-31 17:25:45 +11:00
|
|
|
}
|
2023-02-01 17:25:39 +11:00
|
|
|
|
2023-02-06 08:17:23 +11:00
|
|
|
pub fn scale(
|
|
|
|
&mut self,
|
|
|
|
scaling: Scale2D,
|
|
|
|
format: ImageFormat,
|
|
|
|
viewport_size: &Size<u32>,
|
|
|
|
source_size: &Size<u32>,
|
|
|
|
mipmap: bool,
|
|
|
|
) -> error::Result<Size<u32>> {
|
2023-02-01 17:25:39 +11:00
|
|
|
let size = source_size.scale_viewport(scaling, *viewport_size);
|
|
|
|
if self.size != size
|
|
|
|
|| (mipmap && self.max_mipmap == 1)
|
|
|
|
|| (!mipmap && self.max_mipmap != 1)
|
|
|
|
|| format != self.format
|
|
|
|
{
|
2023-02-06 08:17:23 +11:00
|
|
|
let mut new = OwnedImage::new(&self.device, size, format, mipmap)?;
|
2023-02-01 17:25:39 +11:00
|
|
|
|
2023-02-06 08:17:23 +11:00
|
|
|
std::mem::swap(self, &mut new);
|
2023-02-01 17:25:39 +11:00
|
|
|
}
|
|
|
|
Ok(size)
|
|
|
|
}
|
2023-02-06 08:17:23 +11:00
|
|
|
}
|