From 0cb6f6a346cd7ac11ced98d5caa711f5039c7774 Mon Sep 17 00:00:00 2001 From: chyyran Date: Fri, 10 Feb 2023 18:08:11 -0500 Subject: [PATCH] d3d11: be agnostic about deferred contexts This brings the D3D11 API more in line with the D3D12 and Vulkan runtimes. To get the old behaviour with immediate contexts, just pass a NULL context. --- include/librashader.h | 52 ++++++---- include/librashader_ld.h | 11 ++- librashader-capi/cbindgen.toml | 25 +++-- librashader-capi/src/lib.rs | 2 +- .../src/runtime/d3d11/filter_chain.rs | 31 ++++-- .../src/runtime/d3d12/filter_chain.rs | 12 ++- .../src/runtime/gl/filter_chain.rs | 2 +- .../src/runtime/vk/filter_chain.rs | 7 +- librashader-runtime-d3d11/src/draw_quad.rs | 11 +-- librashader-runtime-d3d11/src/filter_chain.rs | 95 +++++-------------- librashader-runtime-d3d11/src/filter_pass.rs | 47 +++++---- librashader-runtime-d3d11/src/framebuffer.rs | 19 ++-- .../src/hello_triangle.rs | 14 +++ librashader-runtime-d3d11/src/lib.rs | 2 - librashader-runtime-d3d11/src/options.rs | 6 -- librashader-runtime-d3d12/src/filter_chain.rs | 31 ------ .../examples/example_win32_directx11/main.cpp | 11 ++- .../dx11-example-2/code.cpp | 12 ++- .../dx11-example/main.cpp | 2 +- 19 files changed, 189 insertions(+), 203 deletions(-) diff --git a/include/librashader.h b/include/librashader.h index ebb6c87..6ffaded 100644 --- a/include/librashader.h +++ b/include/librashader.h @@ -38,6 +38,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #else typedef void ID3D11Device; +typedef void ID3D11DeviceContext; typedef void ID3D11RenderTargetView; typedef void ID3D11ShaderResourceView; #endif @@ -289,11 +290,6 @@ typedef struct frame_vk_opt_t { typedef struct filter_chain_d3d11_opt_t { /// The librashader API version. LIBRASHADER_API_VERSION version; - /// Use a deferred context to record shader rendering state. - /// - /// The deferred context will be executed on the immediate context - /// with `RenderContextState = true`. - bool use_deferred_context; /// Whether or not to explicitly disable mipmap /// generation regardless of shader preset settings. bool force_no_mipmaps; @@ -309,7 +305,7 @@ typedef struct _filter_chain_d3d11 *libra_d3d11_filter_chain_t; /// Direct3D 11 parameters for the source image. typedef struct libra_source_image_d3d11_t { /// A shader resource view into the source image - const ID3D11ShaderResourceView * handle; + ID3D11ShaderResourceView * handle; /// The width of the source image. uint32_t width; /// The height of the source image. @@ -353,7 +349,7 @@ typedef struct _filter_chain_d3d12 *libra_d3d12_filter_chain_t; /// Direct3D 12 parameters for the source image. typedef struct libra_source_image_d3d12_t { /// The resource containing the image. - const ID3D12Resource * resource; + ID3D12Resource * resource; /// A CPU descriptor handle to a shader resource view of the image. D3D12_CPU_DESCRIPTOR_HANDLE descriptor; /// The format of the image. @@ -561,7 +557,7 @@ typedef libra_error_t (*PFN_libra_vk_filter_chain_free)(libra_vk_filter_chain_t ///libra_d3d11_filter_chain_create typedef libra_error_t (*PFN_libra_d3d11_filter_chain_create)(libra_shader_preset_t *preset, const struct filter_chain_d3d11_opt_t *options, - const ID3D11Device * device, + ID3D11Device * device, libra_d3d11_filter_chain_t *out); #endif @@ -569,10 +565,11 @@ typedef libra_error_t (*PFN_libra_d3d11_filter_chain_create)(libra_shader_preset /// Function pointer definition for ///libra_d3d11_filter_chain_frame typedef libra_error_t (*PFN_libra_d3d11_filter_chain_frame)(libra_d3d11_filter_chain_t *chain, + ID3D11DeviceContext * device_context, size_t frame_count, struct libra_source_image_d3d11_t image, struct libra_viewport_t viewport, - const ID3D11RenderTargetView * out, + ID3D11RenderTargetView * out, const float *mvp, const struct frame_d3d11_opt_t *opt); #endif @@ -618,7 +615,7 @@ typedef libra_error_t (*PFN_libra_d3d11_filter_chain_free)(libra_d3d11_filter_ch ///libra_d3d12_filter_chain_create typedef libra_error_t (*PFN_libra_d3d12_filter_chain_create)(libra_shader_preset_t *preset, const struct filter_chain_d3d12_opt_t *opt, - const ID3D12Device * device, + ID3D12Device * device, libra_d3d12_filter_chain_t *out); #endif @@ -626,7 +623,7 @@ typedef libra_error_t (*PFN_libra_d3d12_filter_chain_create)(libra_shader_preset /// Function pointer definition for ///libra_d3d12_filter_chain_frame typedef libra_error_t (*PFN_libra_d3d12_filter_chain_frame)(libra_d3d12_filter_chain_t *chain, - const ID3D12GraphicsCommandList * command_list, + ID3D12GraphicsCommandList * command_list, size_t frame_count, struct libra_source_image_d3d12_t image, struct libra_viewport_t viewport, @@ -918,7 +915,12 @@ libra_error_t libra_vk_filter_chain_create(struct libra_device_vk_t vulkan, /// Records rendering commands for a frame with the given parameters for the given filter chain /// to the input command buffer. /// -/// librashader will not do any queue submissions. +/// * The input image must be in the `VK_SHADER_READ_ONLY_OPTIMAL` layout. +/// * The output image must be in `VK_COLOR_ATTACHMENT_OPTIMAL` layout. +/// +/// librashader **will not** create a pipeline barrier for the final pass. The output image will +/// remain in `VK_COLOR_ATTACHMENT_OPTIMAL` after all shader passes. The caller must transition +/// the output image to the final layout. /// /// ## Safety /// - `libra_vk_filter_chain_frame` **must not be called within a RenderPass**. @@ -1005,13 +1007,17 @@ libra_error_t libra_vk_filter_chain_free(libra_vk_filter_chain_t *chain); /// - `out` must be aligned, but may be null, invalid, or uninitialized. libra_error_t libra_d3d11_filter_chain_create(libra_shader_preset_t *preset, const struct filter_chain_d3d11_opt_t *options, - const ID3D11Device * device, + ID3D11Device * device, libra_d3d11_filter_chain_t *out); #endif #if defined(LIBRA_RUNTIME_D3D11) /// Draw a frame with the given parameters for the given filter chain. /// +/// If `device_context` is null, then commands are recorded onto the immediate context. Otherwise, +/// it will record commands onto the provided context. If the context is deferred, librashader +/// will not finalize command lists. The context must otherwise be associated with the `ID3D11Device` +/// /// ## Safety /// - `chain` may be null, invalid, but not uninitialized. If `chain` is null or invalid, this /// function will return an error. @@ -1021,13 +1027,17 @@ libra_error_t libra_d3d11_filter_chain_create(libra_shader_preset_t *preset, /// struct. /// - `out` must not be null. /// - `image.handle` must not be null. +/// - If `device_context` is null, commands will be recorded onto the immediate context of the `ID3D11Device` +/// this filter chain was created with. The context must otherwise be associated with the `ID3D11Device` +/// the filter chain was created with. /// - You must ensure that only one thread has access to `chain` before you call this function. Only one /// thread at a time may call this function. libra_error_t libra_d3d11_filter_chain_frame(libra_d3d11_filter_chain_t *chain, + ID3D11DeviceContext * device_context, size_t frame_count, struct libra_source_image_d3d11_t image, struct libra_viewport_t viewport, - const ID3D11RenderTargetView * out, + ID3D11RenderTargetView * out, const float *mvp, const struct frame_d3d11_opt_t *opt); #endif @@ -1096,7 +1106,7 @@ libra_error_t libra_d3d11_filter_chain_free(libra_d3d11_filter_chain_t *chain); /// - `out` must be aligned, but may be null, invalid, or uninitialized. libra_error_t libra_d3d12_filter_chain_create(libra_shader_preset_t *preset, const struct filter_chain_d3d12_opt_t *opt, - const ID3D12Device * device, + ID3D12Device * device, libra_d3d12_filter_chain_t *out); #endif @@ -1104,6 +1114,13 @@ libra_error_t libra_d3d12_filter_chain_create(libra_shader_preset_t *preset, /// Records rendering commands for a frame with the given parameters for the given filter chain /// to the input command list. /// +/// * The input image must be in the `D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE` resource state. +/// * The output image must be in `D3D12_RESOURCE_STATE_RENDER_TARGET` resource state. +/// +/// librashader **will not** create a resource barrier for the final pass. The output image will +/// remain in `D3D12_RESOURCE_STATE_RENDER_TARGET` after all shader passes. The caller must transition +/// the output image to the final resource state. +/// /// ## Safety /// - `chain` may be null, invalid, but not uninitialized. If `chain` is null or invalid, this /// function will return an error. @@ -1113,11 +1130,12 @@ libra_error_t libra_d3d12_filter_chain_create(libra_shader_preset_t *preset, /// struct. /// - `out` must be a descriptor handle to a render target view. /// - `image.resource` must not be null. -/// - `command_list` must not be null. +/// - `command_list` must be a non-null pointer to a `ID3D12GraphicsCommandList` that is open, +/// and must be associated with the `ID3D12Device` this filter chain was created with. /// - You must ensure that only one thread has access to `chain` before you call this function. Only one /// thread at a time may call this function. libra_error_t libra_d3d12_filter_chain_frame(libra_d3d12_filter_chain_t *chain, - const ID3D12GraphicsCommandList * command_list, + ID3D12GraphicsCommandList * command_list, size_t frame_count, struct libra_source_image_d3d12_t image, struct libra_viewport_t viewport, diff --git a/include/librashader_ld.h b/include/librashader_ld.h index a045cac..5c7cf61 100644 --- a/include/librashader_ld.h +++ b/include/librashader_ld.h @@ -195,15 +195,16 @@ libra_error_t __librashader__noop_vk_filter_chain_get_active_pass_count( #if defined(LIBRA_RUNTIME_D3D11) libra_error_t __librashader__noop_d3d11_filter_chain_create( libra_shader_preset_t *preset, - const struct filter_chain_d3d11_opt_t *options, const ID3D11Device *device, + const struct filter_chain_d3d11_opt_t *options, ID3D11Device *device, libra_d3d11_filter_chain_t *out) { return NULL; } libra_error_t __librashader__noop_d3d11_filter_chain_frame( - libra_d3d11_filter_chain_t *chain, size_t frame_count, + libra_d3d11_filter_chain_t *chain, + ID3D11DeviceContext *device_context, size_t frame_count, struct libra_source_image_d3d11_t image, struct libra_viewport_t viewport, - const ID3D11RenderTargetView *out, const float *mvp, + ID3D11RenderTargetView *out, const float *mvp, const struct frame_d3d11_opt_t *opt) { return NULL; } @@ -238,14 +239,14 @@ libra_error_t __librashader__noop_d3d11_filter_chain_get_active_pass_count( #if defined(LIBRA_RUNTIME_D3D12) libra_error_t __librashader__noop_d3d12_filter_chain_create( libra_shader_preset_t *preset, - const struct filter_chain_d3d12_opt_t *options, const ID3D12Device *device, + const struct filter_chain_d3d12_opt_t *options, ID3D12Device *device, libra_d3d12_filter_chain_t *out) { return NULL; } libra_error_t __librashader__noop_d3d12_filter_chain_frame( libra_d3d12_filter_chain_t *chain, - const ID3D12GraphicsCommandList *command_list, size_t frame_count, + ID3D12GraphicsCommandList *command_list, size_t frame_count, struct libra_source_image_d3d12_t image, struct libra_viewport_t viewport, struct libra_output_image_d3d12_t out, const float *mvp, const struct frame_d3d12_opt_t *opt) { diff --git a/librashader-capi/cbindgen.toml b/librashader-capi/cbindgen.toml index bbdba5a..6159111 100644 --- a/librashader-capi/cbindgen.toml +++ b/librashader-capi/cbindgen.toml @@ -36,6 +36,7 @@ after_includes = """ #include #else typedef void ID3D11Device; +typedef void ID3D11DeviceContext; typedef void ID3D11RenderTargetView; typedef void ID3D11ShaderResourceView; #endif @@ -64,6 +65,7 @@ typedef void D3D12_CPU_DESCRIPTOR_HANDLE; "feature = runtime-d3d11" = "LIBRA_RUNTIME_D3D11" "feature = runtime-d3d12" = "LIBRA_RUNTIME_D3D12" + [parse] parse_deps = true include = ["librashader", @@ -140,6 +142,8 @@ include = [ "PFN_libra_d3d12_filter_chain_free", ] +exclude = ["Option_ID3D11DeviceContext"] + [export.rename] "LibrashaderError" = "_libra_error" "ShaderPreset" = "_shader_preset" @@ -156,12 +160,17 @@ include = [ "Format" = "VkFormat" "Image" = "VkImage" -#hack to get proper pointer indirection for COM pointers -"ID3D11Device" = "const ID3D11Device *" -"ID3D11RenderTargetView" = "const ID3D11RenderTargetView *" -"ID3D11ShaderResourceView" = "const ID3D11ShaderResourceView *" +# hack to get proper pointer indirection for COM pointers +# we don't need one for ID3D11DeviceContext. +"ID3D11Device" = "ID3D11Device *" +"ID3D11DeviceContext" = "ID3D11DeviceContext *" +"ID3D11RenderTargetView" = "ID3D11RenderTargetView *" +"ID3D11ShaderResourceView" = "ID3D11ShaderResourceView *" -#hack to get proper pointer indirection for COM pointers -"ID3D12Device" = "const ID3D12Device *" -"ID3D12Resource" = "const ID3D12Resource *" -"ID3D12GraphicsCommandList" = "const ID3D12GraphicsCommandList *" \ No newline at end of file +# hack to force cbindgen to not generate option type for nullable ID3D11DeviceContext. +"Option_ID3D11DeviceContext" = "ID3D11DeviceContext *" + +# hack to get proper pointer indirection for COM pointers +"ID3D12Device" = "ID3D12Device *" +"ID3D12Resource" = "ID3D12Resource *" +"ID3D12GraphicsCommandList" = "ID3D12GraphicsCommandList *" \ No newline at end of file diff --git a/librashader-capi/src/lib.rs b/librashader-capi/src/lib.rs index 9ec6fcb..2eed5e0 100644 --- a/librashader-capi/src/lib.rs +++ b/librashader-capi/src/lib.rs @@ -87,4 +87,4 @@ pub type LIBRASHADER_API_VERSION = usize; pub const LIBRASHADER_CURRENT_VERSION: LIBRASHADER_API_VERSION = 0; #[allow(dead_code)] -const fn assert_thread_safe() { } +const fn assert_thread_safe() {} diff --git a/librashader-capi/src/runtime/d3d11/filter_chain.rs b/librashader-capi/src/runtime/d3d11/filter_chain.rs index 7729d0e..8e0ec28 100644 --- a/librashader-capi/src/runtime/d3d11/filter_chain.rs +++ b/librashader-capi/src/runtime/d3d11/filter_chain.rs @@ -10,14 +10,14 @@ use std::mem::{ManuallyDrop, MaybeUninit}; use std::ptr::NonNull; use std::slice; use windows::Win32::Graphics::Direct3D11::{ - ID3D11Device, ID3D11RenderTargetView, ID3D11ShaderResourceView, + ID3D11Device, ID3D11DeviceContext, ID3D11RenderTargetView, ID3D11ShaderResourceView, }; use librashader::runtime::d3d11::capi::options::FilterChainOptionsD3D11; use librashader::runtime::d3d11::capi::options::FrameOptionsD3D11; -use librashader::runtime::{FilterChainParameters, Size, Viewport}; use crate::LIBRASHADER_API_VERSION; +use librashader::runtime::{FilterChainParameters, Size, Viewport}; /// Direct3D 11 parameters for the source image. #[repr(C)] @@ -49,12 +49,6 @@ impl TryFrom for D3D11InputView { pub struct filter_chain_d3d11_opt_t { /// The librashader API version. pub version: LIBRASHADER_API_VERSION, - /// Use a deferred context to record shader rendering state. - /// - /// The deferred context will be executed on the immediate context - /// with `RenderContextState = true`. - pub use_deferred_context: bool, - /// Whether or not to explicitly disable mipmap /// generation regardless of shader preset settings. pub force_no_mipmaps: bool, @@ -62,7 +56,7 @@ pub struct filter_chain_d3d11_opt_t { config_struct! { impl FilterChainOptionsD3D11 => filter_chain_d3d11_opt_t { - 0 => [use_deferred_context, force_no_mipmaps]; + 0 => [force_no_mipmaps]; } } @@ -130,9 +124,20 @@ extern_fn! { } } +// This assert ensures that the bindings of Option> to ID3D11DeviceContext* is sound. +const _: () = assert!( + std::mem::size_of::() + == std::mem::size_of::>>() +); + extern_fn! { /// Draw a frame with the given parameters for the given filter chain. /// + /// If `device_context` is null, then commands are recorded onto the immediate context. Otherwise, + /// it will record commands onto the provided context. If the context is deferred, librashader + /// will not finalize command lists. The context must otherwise be associated with the `ID3D11Device` + // the filter chain was created with. + /// /// ## Safety /// - `chain` may be null, invalid, but not uninitialized. If `chain` is null or invalid, this /// function will return an error. @@ -142,10 +147,16 @@ extern_fn! { /// struct. /// - `out` must not be null. /// - `image.handle` must not be null. + /// - If `device_context` is null, commands will be recorded onto the immediate context of the `ID3D11Device` + /// this filter chain was created with. The context must otherwise be associated with the `ID3D11Device` + /// the filter chain was created with. /// - You must ensure that only one thread has access to `chain` before you call this function. Only one /// thread at a time may call this function. fn libra_d3d11_filter_chain_frame( chain: *mut libra_d3d11_filter_chain_t, + // cbindgen can't discover that ID3D11DeviceContext has the niche optimization + // so ManuallyDrop> doesn't generate correct bindings. + device_context: Option>, frame_count: usize, image: libra_source_image_d3d11_t, viewport: libra_viewport_t, @@ -180,7 +191,7 @@ extern_fn! { let opt = opt.map(FromUninit::from_uninit); let image = image.try_into()?; - chain.frame(image, &viewport, frame_count, opt.as_ref())?; + chain.frame(device_context.as_deref(), image, &viewport, frame_count, opt.as_ref())?; } } diff --git a/librashader-capi/src/runtime/d3d12/filter_chain.rs b/librashader-capi/src/runtime/d3d12/filter_chain.rs index c85ea66..d421664 100644 --- a/librashader-capi/src/runtime/d3d12/filter_chain.rs +++ b/librashader-capi/src/runtime/d3d12/filter_chain.rs @@ -16,9 +16,9 @@ use windows::Win32::Graphics::Dxgi::Common::DXGI_FORMAT; use librashader::runtime::d3d12::capi::options::FilterChainOptionsD3D12; use librashader::runtime::d3d12::capi::options::FrameOptionsD3D12; +use crate::LIBRASHADER_API_VERSION; use librashader::runtime::d3d12::{D3D12InputImage, D3D12OutputView}; use librashader::runtime::{FilterChainParameters, Size, Viewport}; -use crate::LIBRASHADER_API_VERSION; /// Direct3D 12 parameters for the source image. #[repr(C)] @@ -149,6 +149,13 @@ extern_fn! { /// Records rendering commands for a frame with the given parameters for the given filter chain /// to the input command list. /// + /// * The input image must be in the `D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE` resource state. + /// * The output image must be in `D3D12_RESOURCE_STATE_RENDER_TARGET` resource state. + /// + /// librashader **will not** create a resource barrier for the final pass. The output image will + /// remain in `D3D12_RESOURCE_STATE_RENDER_TARGET` after all shader passes. The caller must transition + /// the output image to the final resource state. + /// /// ## Safety /// - `chain` may be null, invalid, but not uninitialized. If `chain` is null or invalid, this /// function will return an error. @@ -158,7 +165,8 @@ extern_fn! { /// struct. /// - `out` must be a descriptor handle to a render target view. /// - `image.resource` must not be null. - /// - `command_list` must not be null. + /// - `command_list` must be a non-null pointer to a `ID3D12GraphicsCommandList` that is open, + /// and must be associated with the `ID3D12Device` this filter chain was created with. /// - You must ensure that only one thread has access to `chain` before you call this function. Only one /// thread at a time may call this function. fn libra_d3d12_filter_chain_frame( diff --git a/librashader-capi/src/runtime/gl/filter_chain.rs b/librashader-capi/src/runtime/gl/filter_chain.rs index cf3728d..2c2331f 100644 --- a/librashader-capi/src/runtime/gl/filter_chain.rs +++ b/librashader-capi/src/runtime/gl/filter_chain.rs @@ -10,11 +10,11 @@ use std::mem::MaybeUninit; use std::ptr::NonNull; use std::slice; +use crate::LIBRASHADER_API_VERSION; use librashader::runtime::gl::capi::options::FilterChainOptionsGL; use librashader::runtime::gl::capi::options::FrameOptionsGL; use librashader::runtime::FilterChainParameters; use librashader::runtime::{Size, Viewport}; -use crate::LIBRASHADER_API_VERSION; /// A GL function loader that librashader needs to be initialized with. pub type libra_gl_loader_t = unsafe extern "system" fn(*const c_char) -> *const c_void; diff --git a/librashader-capi/src/runtime/vk/filter_chain.rs b/librashader-capi/src/runtime/vk/filter_chain.rs index 5666b7c..47c836b 100644 --- a/librashader-capi/src/runtime/vk/filter_chain.rs +++ b/librashader-capi/src/runtime/vk/filter_chain.rs @@ -171,7 +171,12 @@ extern_fn! { /// Records rendering commands for a frame with the given parameters for the given filter chain /// to the input command buffer. /// - /// librashader will not do any queue submissions. + /// * The input image must be in the `VK_SHADER_READ_ONLY_OPTIMAL` layout. + /// * The output image must be in `VK_COLOR_ATTACHMENT_OPTIMAL` layout. + /// + /// librashader **will not** create a pipeline barrier for the final pass. The output image will + /// remain in `VK_COLOR_ATTACHMENT_OPTIMAL` after all shader passes. The caller must transition + /// the output image to the final layout. /// /// ## Safety /// - `libra_vk_filter_chain_frame` **must not be called within a RenderPass**. diff --git a/librashader-runtime-d3d11/src/draw_quad.rs b/librashader-runtime-d3d11/src/draw_quad.rs index 9ef5f34..71adac2 100644 --- a/librashader-runtime-d3d11/src/draw_quad.rs +++ b/librashader-runtime-d3d11/src/draw_quad.rs @@ -71,13 +71,12 @@ const FINAL_VBO_DATA: [D3D11Vertex; 4] = [ static VBO_DATA: &[D3D11Vertex; 8] = &concat_arrays!(OFFSCREEN_VBO_DATA, FINAL_VBO_DATA); pub(crate) struct DrawQuad { - context: ID3D11DeviceContext, stride: u32, vbo: ID3D11Buffer, } impl DrawQuad { - pub fn new(device: &ID3D11Device, context: &ID3D11DeviceContext) -> error::Result { + pub fn new(device: &ID3D11Device) -> error::Result { unsafe { let mut vbo = None; device.CreateBuffer( @@ -100,18 +99,16 @@ impl DrawQuad { Ok(DrawQuad { vbo, - context: context.clone(), stride: std::mem::size_of::() as u32, }) } } - pub fn bind_vbo_for_frame(&self) { + pub fn bind_vbo_for_frame(&self, context: &ID3D11DeviceContext) { unsafe { - self.context - .IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + context.IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - self.context.IASetVertexBuffers( + context.IASetVertexBuffers( 0, 1, Some(&Some(self.vbo.clone())), diff --git a/librashader-runtime-d3d11/src/filter_chain.rs b/librashader-runtime-d3d11/src/filter_chain.rs index d025148..bfaa82b 100644 --- a/librashader-runtime-d3d11/src/filter_chain.rs +++ b/librashader-runtime-d3d11/src/filter_chain.rs @@ -56,10 +56,8 @@ pub struct FilterChainD3D11 { } pub(crate) struct Direct3D11 { - pub(crate) device: ID3D11Device, - pub(crate) current_context: ID3D11DeviceContext, + pub(crate) _device: ID3D11Device, pub(crate) immediate_context: ID3D11DeviceContext, - pub context_is_deferred: bool, } pub(crate) struct FilterCommon { @@ -97,8 +95,6 @@ impl FilterChainD3D11 { FilterChainError, >(preset.shaders, &preset.textures)?; - let use_deferred_context = options.map_or(false, |f| f.use_deferred_context); - let samplers = SamplerSet::new(device)?; // initialize passes @@ -106,30 +102,10 @@ impl FilterChainD3D11 { let immediate_context = unsafe { device.GetImmediateContext()? }; - let current_context = if use_deferred_context { - // check if device supports deferred contexts - if let Err(_) = unsafe { device.CreateDeferredContext(0, None) } { - immediate_context.clone() - } else { - let mut context = None; - unsafe { device.CreateDeferredContext(0, Some(&mut context))? }; - assume_d3d11_init!(context, "CreateDeferredContext"); - context - } - } else { - immediate_context.clone() - }; - // initialize output framebuffers let mut output_framebuffers = Vec::new(); output_framebuffers.resize_with(filters.len(), || { - OwnedFramebuffer::new( - device, - ¤t_context, - Size::new(1, 1), - ImageFormat::R8G8B8A8Unorm, - false, - ) + OwnedFramebuffer::new(device, Size::new(1, 1), ImageFormat::R8G8B8A8Unorm, false) }); // resolve all results @@ -143,13 +119,7 @@ impl FilterChainD3D11 { // // initialize feedback framebuffers let mut feedback_framebuffers = Vec::new(); feedback_framebuffers.resize_with(filters.len(), || { - OwnedFramebuffer::new( - device, - ¤t_context, - Size::new(1, 1), - ImageFormat::R8G8B8A8Unorm, - false, - ) + OwnedFramebuffer::new(device, Size::new(1, 1), ImageFormat::R8G8B8A8Unorm, false) }); // resolve all results let feedback_framebuffers = feedback_framebuffers @@ -160,12 +130,12 @@ impl FilterChainD3D11 { feedback_textures.resize_with(filters.len(), || None); // load luts - let luts = FilterChainD3D11::load_luts(device, ¤t_context, &preset.textures)?; + let luts = FilterChainD3D11::load_luts(device, &immediate_context, &preset.textures)?; let (history_framebuffers, history_textures) = - FilterChainD3D11::init_history(device, ¤t_context, &filters)?; + FilterChainD3D11::init_history(device, &filters)?; - let draw_quad = DrawQuad::new(device, ¤t_context)?; + let draw_quad = DrawQuad::new(device)?; let state = D3D11State::new(device)?; Ok(FilterChainD3D11 { passes: filters, @@ -174,10 +144,8 @@ impl FilterChainD3D11 { history_framebuffers, common: FilterCommon { d3d11: Direct3D11 { - device: device.clone(), - current_context, + _device: device.clone(), immediate_context, - context_is_deferred: use_deferred_context, }, config: FilterMutable { passes_enabled: preset.shader_count as usize, @@ -317,7 +285,6 @@ impl FilterChainD3D11 { fn init_history( device: &ID3D11Device, - context: &ID3D11DeviceContext, filters: &Vec, ) -> error::Result<(VecDeque, Box<[Option]>)> { let required_images = @@ -334,13 +301,7 @@ impl FilterChainD3D11 { // eprintln!("[history] using frame history with {required_images} images"); let mut framebuffers = VecDeque::with_capacity(required_images); framebuffers.resize_with(required_images, || { - OwnedFramebuffer::new( - device, - context, - Size::new(1, 1), - ImageFormat::R8G8B8A8Unorm, - false, - ) + OwnedFramebuffer::new(device, Size::new(1, 1), ImageFormat::R8G8B8A8Unorm, false) }); let framebuffers = framebuffers @@ -353,9 +314,13 @@ impl FilterChainD3D11 { Ok((framebuffers, history_textures.into_boxed_slice())) } - fn push_history(&mut self, input: &D3D11InputView) -> error::Result<()> { + fn push_history( + &mut self, + ctx: &ID3D11DeviceContext, + input: &D3D11InputView, + ) -> error::Result<()> { if let Some(mut back) = self.history_framebuffers.pop_back() { - back.copy_from(input)?; + back.copy_from(ctx, input)?; self.history_framebuffers.push_front(back) } @@ -400,17 +365,23 @@ impl FilterChainD3D11 { /// Process a frame with the input image. pub fn frame( &mut self, + ctx: Option<&ID3D11DeviceContext>, input: D3D11InputView, viewport: &Viewport, frame_count: usize, options: Option<&FrameOptionsD3D11>, ) -> error::Result<()> { let max = std::cmp::min(self.passes.len(), self.common.config.passes_enabled); + + // Need to clone this because pushing history needs a mutable borrow. + let immediate_context = &self.common.d3d11.immediate_context.clone(); + let ctx = ctx.unwrap_or(immediate_context); + let passes = &mut self.passes[0..max]; if let Some(options) = options { if options.clear_history { for framebuffer in &mut self.history_framebuffers { - framebuffer.clear()?; + framebuffer.clear(ctx)?; } } } @@ -467,10 +438,8 @@ impl FilterChainD3D11 { let passes_len = passes.len(); let (pass, last) = passes.split_at_mut(passes_len - 1); - let state_guard = self - .state - .enter_filter_state(&self.common.d3d11.current_context); - self.common.draw_quad.bind_vbo_for_frame(); + let state_guard = self.state.enter_filter_state(ctx); + self.common.draw_quad.bind_vbo_for_frame(ctx); for (index, pass) in pass.iter_mut().enumerate() { source.filter = pass.config.filter; @@ -478,6 +447,7 @@ impl FilterChainD3D11 { let target = &self.output_framebuffers[index]; let size = target.size; pass.draw( + ctx, index, &self.common, pass.config.get_frame_count(frame_count), @@ -506,6 +476,7 @@ impl FilterChainD3D11 { source.filter = pass.config.filter; source.wrap_mode = pass.config.wrap_mode; pass.draw( + &ctx, passes_len - 1, &self.common, pass.config.get_frame_count(frame_count), @@ -524,22 +495,8 @@ impl FilterChainD3D11 { ); drop(state_guard); - self.push_history(&input)?; - if self.common.d3d11.context_is_deferred { - unsafe { - let mut command_list = None; - self.common - .d3d11 - .current_context - .FinishCommandList(false, Some(&mut command_list))?; - assume_d3d11_init!(command_list, "FinishCommandList"); - self.common - .d3d11 - .immediate_context - .ExecuteCommandList(&command_list, true); - } - } + self.push_history(ctx, &input)?; Ok(()) } diff --git a/librashader-runtime-d3d11/src/filter_pass.rs b/librashader-runtime-d3d11/src/filter_pass.rs index 5ebed8b..28659b1 100644 --- a/librashader-runtime-d3d11/src/filter_pass.rs +++ b/librashader-runtime-d3d11/src/filter_pass.rs @@ -14,7 +14,7 @@ use librashader_runtime::filter_pass::FilterPassMeta; use librashader_runtime::quad::QuadType; use librashader_runtime::render_target::RenderTarget; use windows::Win32::Graphics::Direct3D11::{ - ID3D11Buffer, ID3D11InputLayout, ID3D11PixelShader, ID3D11SamplerState, + ID3D11Buffer, ID3D11DeviceContext, ID3D11InputLayout, ID3D11PixelShader, ID3D11SamplerState, ID3D11ShaderResourceView, ID3D11VertexShader, D3D11_MAPPED_SUBRESOURCE, D3D11_MAP_WRITE_DISCARD, D3D11_VIEWPORT, }; @@ -137,6 +137,7 @@ impl FilterPass { pub(crate) fn draw( &mut self, + ctx: &ID3D11DeviceContext, pass_index: usize, parent: &FilterCommon, frame_count: u32, @@ -147,19 +148,15 @@ impl FilterPass { output: RenderTarget, vbo_type: QuadType, ) -> error::Result<()> { - let _device = &parent.d3d11.device; - let context = &parent.d3d11.current_context; - if self.config.mipmap_input && !parent.disable_mipmaps { unsafe { - context.GenerateMips(&source.view.handle); - // context.GenerateMips(&original.view.handle); + ctx.GenerateMips(&source.view.handle); } } unsafe { - context.IASetInputLayout(&self.vertex_layout); - context.VSSetShader(&self.vertex_shader, None); - context.PSSetShader(&self.pixel_shader, None); + ctx.IASetInputLayout(&self.vertex_layout); + ctx.VSSetShader(&self.vertex_shader, None); + ctx.PSSetShader(&self.pixel_shader, None); } let mut textures: [Option; 16] = std::array::from_fn(|_| None); @@ -183,20 +180,20 @@ impl FilterPass { // upload uniforms unsafe { let mut map = D3D11_MAPPED_SUBRESOURCE::default(); - context.Map(&ubo.buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, Some(&mut map))?; + ctx.Map(&ubo.buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, Some(&mut map))?; std::ptr::copy_nonoverlapping( self.uniform_storage.ubo_pointer(), map.pData.cast(), ubo.size as usize, ); - context.Unmap(&ubo.buffer, 0); + ctx.Unmap(&ubo.buffer, 0); } if ubo.stage_mask.contains(BindingStage::VERTEX) { - unsafe { context.VSSetConstantBuffers(ubo.binding, Some(&[ubo.buffer.clone()])) } + unsafe { ctx.VSSetConstantBuffers(ubo.binding, Some(&[ubo.buffer.clone()])) } } if ubo.stage_mask.contains(BindingStage::FRAGMENT) { - unsafe { context.PSSetConstantBuffers(ubo.binding, Some(&[ubo.buffer.clone()])) } + unsafe { ctx.PSSetConstantBuffers(ubo.binding, Some(&[ubo.buffer.clone()])) } } } @@ -204,26 +201,26 @@ impl FilterPass { // upload push constants unsafe { let mut map = D3D11_MAPPED_SUBRESOURCE::default(); - context.Map(&push.buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, Some(&mut map))?; + ctx.Map(&push.buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, Some(&mut map))?; std::ptr::copy_nonoverlapping( self.uniform_storage.push_pointer(), map.pData.cast(), push.size as usize, ); - context.Unmap(&push.buffer, 0); + ctx.Unmap(&push.buffer, 0); } if push.stage_mask.contains(BindingStage::VERTEX) { - unsafe { context.VSSetConstantBuffers(push.binding, Some(&[push.buffer.clone()])) } + unsafe { ctx.VSSetConstantBuffers(push.binding, Some(&[push.buffer.clone()])) } } if push.stage_mask.contains(BindingStage::FRAGMENT) { - unsafe { context.PSSetConstantBuffers(push.binding, Some(&[push.buffer.clone()])) } + unsafe { ctx.PSSetConstantBuffers(push.binding, Some(&[push.buffer.clone()])) } } } unsafe { // reset RTVs - context.OMSetRenderTargets(None, None); + ctx.OMSetRenderTargets(None, None); } unsafe { @@ -233,11 +230,11 @@ impl FilterPass { std::mem::size_of::>() == std::mem::size_of::() ); - context.PSSetShaderResources(0, Some(std::mem::transmute(textures.as_ref()))); - context.PSSetSamplers(0, Some(std::mem::transmute(samplers.as_ref()))); + ctx.PSSetShaderResources(0, Some(std::mem::transmute(textures.as_ref()))); + ctx.PSSetSamplers(0, Some(std::mem::transmute(samplers.as_ref()))); - context.OMSetRenderTargets(Some(&[output.output.handle.clone()]), None); - context.RSSetViewports(Some(&[D3D11_VIEWPORT { + ctx.OMSetRenderTargets(Some(&[output.output.handle.clone()]), None); + ctx.RSSetViewports(Some(&[D3D11_VIEWPORT { TopLeftX: output.x, TopLeftY: output.y, Width: output.output.size.width as f32, @@ -247,12 +244,12 @@ impl FilterPass { }])) } - parent.draw_quad.draw_quad(context, vbo_type); + parent.draw_quad.draw_quad(ctx, vbo_type); unsafe { // unbind resources. - context.PSSetShaderResources(0, Some(std::mem::transmute(NULL_TEXTURES.as_ref()))); - context.OMSetRenderTargets(None, None); + ctx.PSSetShaderResources(0, Some(std::mem::transmute(NULL_TEXTURES.as_ref()))); + ctx.OMSetRenderTargets(None, None); } Ok(()) } diff --git a/librashader-runtime-d3d11/src/framebuffer.rs b/librashader-runtime-d3d11/src/framebuffer.rs index cccdfba..c68dd30 100644 --- a/librashader-runtime-d3d11/src/framebuffer.rs +++ b/librashader-runtime-d3d11/src/framebuffer.rs @@ -26,14 +26,12 @@ pub(crate) struct OwnedFramebuffer { pub(crate) size: Size, format: DXGI_FORMAT, device: ID3D11Device, - context: ID3D11DeviceContext, max_mipmap: u32, } impl OwnedFramebuffer { pub fn new( device: &ID3D11Device, - context: &ID3D11DeviceContext, size: Size, format: ImageFormat, mipmap: bool, @@ -56,7 +54,6 @@ impl OwnedFramebuffer { size, format, device: device.clone(), - context: context.clone(), max_mipmap: if mipmap { size.calculate_miplevels() } else { @@ -99,10 +96,10 @@ impl OwnedFramebuffer { Ok(size) } - pub fn clear(&mut self) -> error::Result<()> { + pub fn clear(&mut self, ctx: &ID3D11DeviceContext) -> error::Result<()> { let rtv = self.create_render_target_view()?; unsafe { - self.context.ClearRenderTargetView(&rtv, CLEAR.as_ptr()); + ctx.ClearRenderTargetView(&rtv, CLEAR.as_ptr()); } Ok(()) } @@ -181,7 +178,11 @@ impl OwnedFramebuffer { }) } - pub fn copy_from(&mut self, image: &D3D11InputView) -> error::Result<()> { + pub fn copy_from( + &mut self, + ctx: &ID3D11DeviceContext, + image: &D3D11InputView, + ) -> error::Result<()> { let original_resource: ID3D11Texture2D = unsafe { let resource = image.handle.GetResource()?; resource.cast()? @@ -198,10 +199,8 @@ impl OwnedFramebuffer { self.init(image.size, ImageFormat::from(format))?; } - // todo: improve mipmap generation? - // will need a staging texture + full so might not be worth it. unsafe { - self.context.CopySubresourceRegion( + ctx.CopySubresourceRegion( &self.render, 0, 0, @@ -222,7 +221,7 @@ impl OwnedFramebuffer { let srvs = self.create_shader_resource_view()?; unsafe { - self.context.GenerateMips(&srvs); + ctx.GenerateMips(&srvs); } Ok(()) } diff --git a/librashader-runtime-d3d11/src/hello_triangle.rs b/librashader-runtime-d3d11/src/hello_triangle.rs index 9a8bae2..018ff01 100644 --- a/librashader-runtime-d3d11/src/hello_triangle.rs +++ b/librashader-runtime-d3d11/src/hello_triangle.rs @@ -280,6 +280,7 @@ pub mod d3d11_hello_triangle { pub viewport: D3D11_VIEWPORT, pub shader_output: Option, pub frame_count: usize, + pub deferred_context: ID3D11DeviceContext, } impl Sample { @@ -387,6 +388,11 @@ pub mod d3d11_hello_triangle { .CreateRenderTargetView(&renderbuffer, None, Some(&mut rtv))?; (renderbuffer, rtv.unwrap()) }; + + let mut context = None; + unsafe { self.device.CreateDeferredContext(0, Some(&mut context))? }; + let context = context.expect("Could not create deferred context"); + self.resources = Some(Resources { swapchain, backbuffer_rtv: Some(rtv), @@ -405,6 +411,7 @@ pub mod d3d11_hello_triangle { triangle_uniform_values: Default::default(), renderbuffer, renderbufffer_rtv: render_rtv, + deferred_context: context, viewport: D3D11_VIEWPORT { TopLeftX: 0.0, TopLeftY: 0.0, @@ -561,6 +568,7 @@ pub mod d3d11_hello_triangle { // eprintln!("w: {} h: {}", backbuffer_desc.Width, backbuffer_desc.Height); self.filter .frame( + Some(&resources.deferred_context), D3D11InputView { handle: srv, size: Size { @@ -585,6 +593,12 @@ pub mod d3d11_hello_triangle { ) .unwrap(); + let mut command_list = None; + resources + .deferred_context + .FinishCommandList(false, Some(&mut command_list))?; + let command_list = command_list.unwrap(); + self.context.ExecuteCommandList(&command_list, false); // self.context.CopyResource(&resources.backbuffer, &backup); } diff --git a/librashader-runtime-d3d11/src/lib.rs b/librashader-runtime-d3d11/src/lib.rs index 5f875ce..39e673f 100644 --- a/librashader-runtime-d3d11/src/lib.rs +++ b/librashader-runtime-d3d11/src/lib.rs @@ -58,7 +58,6 @@ mod tests { let sample = hello_triangle::d3d11_hello_triangle::Sample::new( filter.as_deref().unwrap_or(FILTER_PATH), Some(&FilterChainOptionsD3D11 { - use_deferred_context: false, force_no_mipmaps: false, }), // replace below with 'None' for the triangle @@ -83,7 +82,6 @@ mod tests { let sample = hello_triangle::d3d11_hello_triangle::Sample::new( FILTER_PATH, Some(&FilterChainOptionsD3D11 { - use_deferred_context: false, force_no_mipmaps: false, }), // replace below with 'None' for the triangle diff --git a/librashader-runtime-d3d11/src/options.rs b/librashader-runtime-d3d11/src/options.rs index e8cbff8..a102d4c 100644 --- a/librashader-runtime-d3d11/src/options.rs +++ b/librashader-runtime-d3d11/src/options.rs @@ -15,12 +15,6 @@ pub struct FrameOptionsD3D11 { #[repr(C)] #[derive(Default, Debug, Clone)] pub struct FilterChainOptionsD3D11 { - /// Use a deferred context to record shader rendering state. - /// - /// The deferred context will be executed on the immediate context - /// with `RenderContextState = true`. - pub use_deferred_context: bool, - /// Whether or not to explicitly disable mipmap /// generation regardless of shader preset settings. pub force_no_mipmaps: bool, diff --git a/librashader-runtime-d3d12/src/filter_chain.rs b/librashader-runtime-d3d12/src/filter_chain.rs index f40c917..fa4b885 100644 --- a/librashader-runtime-d3d12/src/filter_chain.rs +++ b/librashader-runtime-d3d12/src/filter_chain.rs @@ -492,37 +492,6 @@ impl FilterChainD3D12 { let filters: error::Result> = filters.into_iter().collect(); let filters = filters?; - // - // // Need to take care of the heaps in a single thread because [;16] is not sized..? - // let filters: Vec> = filters - // .into_iter() - // .zip(work_heaps) - // .zip(sampler_work_heaps) - // .map( - // |( - // ( - // (reflection, uniform_bindings, uniform_storage, pipeline, config, source), - // mut texture_heap, - // ), - // mut sampler_heap, - // )| { - // let texture_heap = texture_heap.alloc_range()?; - // let sampler_heap = sampler_heap.alloc_range()?; - // Ok(FilterPass { - // reflection, - // uniform_bindings, - // uniform_storage, - // pipeline, - // config, - // texture_heap, - // sampler_heap, - // source, - // }) - // }, - // ) - // .collect(); - // let filters: error::Result> = filters.into_iter().collect(); - // let filters = filters?; // Panic SAFETY: mipmap_heap is always 1024 descriptors. Ok(( diff --git a/test/capi-tests/imgui/examples/example_win32_directx11/main.cpp b/test/capi-tests/imgui/examples/example_win32_directx11/main.cpp index a8d5374..a923201 100644 --- a/test/capi-tests/imgui/examples/example_win32_directx11/main.cpp +++ b/test/capi-tests/imgui/examples/example_win32_directx11/main.cpp @@ -19,6 +19,7 @@ static ID3D11RenderTargetView* g_mainRenderTargetView = NULL; static ID3D11Texture2D* g_pBackBuffer = NULL; static ID3D11Texture2D* g_pFramebufferCopy = NULL; static ID3D11ShaderResourceView* g_framebufferCopySRV = NULL; +static ID3D11DeviceContext* g_deferredContext = NULL; // Forward declarations of helper functions bool CreateDeviceD3D(HWND hWnd); @@ -70,8 +71,7 @@ int main(int, char**) libra_d3d11_filter_chain_t filter_chain; filter_chain_d3d11_opt_t opt = { - .use_deferred_context = true, - .force_no_mipmaps = true, + .force_no_mipmaps = false, }; libra.d3d11_filter_chain_create(&preset, &opt, g_pd3dDevice, &filter_chain); @@ -187,9 +187,10 @@ int main(int, char**) .frame_direction = -1 }; - libra.d3d11_filter_chain_frame(&filter_chain, frameCount, input, vp, + libra.d3d11_filter_chain_frame(&filter_chain, NULL, frameCount, input, vp, g_mainRenderTargetView, NULL, &frame_opt); + g_pSwapChain->Present(1, 0); // Present with vsync //g_pSwapChain->Present(0, 0); // Present without vsync frameCount += 1; @@ -237,7 +238,9 @@ bool CreateDeviceD3D(HWND hWnd) res = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_WARP, NULL, createDeviceFlags, featureLevelArray, 2, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &featureLevel, &g_pd3dDeviceContext); if (res != S_OK) return false; - + res = g_pd3dDevice->CreateDeferredContext(0, &g_deferredContext); + if (res != S_OK) + return false; CreateRenderTarget(); return true; } diff --git a/test/capi-tests/librashader-capi-tests/dx11-example-2/code.cpp b/test/capi-tests/librashader-capi-tests/dx11-example-2/code.cpp index 1954b74..5522982 100644 --- a/test/capi-tests/librashader-capi-tests/dx11-example-2/code.cpp +++ b/test/capi-tests/librashader-capi-tests/dx11-example-2/code.cpp @@ -55,17 +55,19 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, baseDeviceContext->QueryInterface(__uuidof(ID3D11DeviceContext1), reinterpret_cast(&deviceContext)); + ID3D11DeviceContext* deferredContext; + baseDevice->CreateDeferredContext(0, &deferredContext); + /////////////////////////////////////////////////////////////////////////////////////////////// auto libra = librashader_load_instance(); libra_shader_preset_t preset; auto error = libra.preset_create( - "../../../slang-shaders/crt/crt-lottes.slangp", + "../../../slang-shaders/crt/crt-royale.slangp", &preset); libra_d3d11_filter_chain_t filter_chain; filter_chain_d3d11_opt_t opt = { - .use_deferred_context = true, .force_no_mipmaps = false, }; @@ -485,9 +487,13 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, frame_d3d11_opt_t frame_opt = {.clear_history = false, .frame_direction = -1}; - libra.d3d11_filter_chain_frame(&filter_chain, frameCount, input, vp, + libra.d3d11_filter_chain_frame(&filter_chain, deferredContext, frameCount, input, + vp, framebufferRTV, NULL, &frame_opt); + ID3D11CommandList* commandList; + deferredContext->FinishCommandList(false, &commandList); + deviceContext->ExecuteCommandList(commandList, true); //////////////////////////////////////////////////////////////////////// swapChain->Present(1, 0); frameCount += 1; diff --git a/test/capi-tests/librashader-capi-tests/dx11-example/main.cpp b/test/capi-tests/librashader-capi-tests/dx11-example/main.cpp index 1ba34bc..3ba2a24 100644 --- a/test/capi-tests/librashader-capi-tests/dx11-example/main.cpp +++ b/test/capi-tests/librashader-capi-tests/dx11-example/main.cpp @@ -404,7 +404,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, libra_viewport_t vp = {0, 0, viewport.Width, viewport.Height, }; - libra.d3d11_filter_chain_frame(&filter_chain, frameCount, input, vp, + libra.d3d11_filter_chain_frame(&filter_chain, NULL, frameCount, input, vp, d3d11FrameBufferView, NULL, NULL); copySrv->Release();