From 5e99ddf73cc78db62e63c67ee049c513919ad9ee Mon Sep 17 00:00:00 2001 From: chyyran Date: Wed, 8 Feb 2023 21:21:40 -0500 Subject: [PATCH] vk/d3d12: recompile pipelines on incompatible output format. This also involves changes to the C API, since we're breaking API anyways might as well unify some type names. No breakages for D3D11. --- include/librashader.h | 214 ++++++++++-------- include/librashader_ld.h | 8 +- .../src/runtime/d3d12/filter_chain.rs | 15 +- .../src/runtime/gl/filter_chain.rs | 4 +- .../src/runtime/vk/filter_chain.rs | 25 +- librashader-runtime-d3d12/src/filter_chain.rs | 11 +- librashader-runtime-d3d12/src/framebuffer.rs | 6 +- .../src/graphics_pipeline.rs | 53 ++++- .../src/hello_triangle.rs | 1 + librashader-runtime-d3d12/src/lib.rs | 2 +- librashader-runtime-d3d12/src/texture.rs | 15 +- librashader-runtime-vk/src/filter_chain.rs | 8 +- librashader-runtime-vk/src/filter_pass.rs | 2 +- .../{vulkan_state.rs => graphics_pipeline.rs} | 110 ++++++--- librashader-runtime-vk/src/lib.rs | 5 +- .../librashader-capi-tests.cpp | 9 +- .../librashader-capi-tests.vcxproj | 6 +- .../librashader-capi-tests.vcxproj.filters | 3 - 18 files changed, 334 insertions(+), 163 deletions(-) rename librashader-runtime-vk/src/{vulkan_state.rs => graphics_pipeline.rs} (88%) diff --git a/include/librashader.h b/include/librashader.h index da05007..ba34336 100644 --- a/include/librashader.h +++ b/include/librashader.h @@ -63,17 +63,17 @@ typedef void D3D12_CPU_DESCRIPTOR_HANDLE; /// Error codes for librashader error types. enum LIBRA_ERRNO #ifdef __cplusplus - : int32_t + : int32_t #endif // __cplusplus -{ - LIBRA_ERRNO_UNKNOWN_ERROR = 0, - LIBRA_ERRNO_INVALID_PARAMETER = 1, - LIBRA_ERRNO_INVALID_STRING = 2, - LIBRA_ERRNO_PRESET_ERROR = 3, - LIBRA_ERRNO_PREPROCESS_ERROR = 4, - LIBRA_ERRNO_SHADER_PARAMETER_ERROR = 5, - LIBRA_ERRNO_REFLECT_ERROR = 6, - LIBRA_ERRNO_RUNTIME_ERROR = 7, + { + LIBRA_ERRNO_UNKNOWN_ERROR = 0, + LIBRA_ERRNO_INVALID_PARAMETER = 1, + LIBRA_ERRNO_INVALID_STRING = 2, + LIBRA_ERRNO_PRESET_ERROR = 3, + LIBRA_ERRNO_PREPROCESS_ERROR = 4, + LIBRA_ERRNO_SHADER_PARAMETER_ERROR = 5, + LIBRA_ERRNO_REFLECT_ERROR = 6, + LIBRA_ERRNO_RUNTIME_ERROR = 7, }; #ifndef __cplusplus typedef int32_t LIBRA_ERRNO; @@ -108,29 +108,29 @@ typedef struct _shader_preset *libra_shader_preset_t; /// A preset parameter. typedef struct libra_preset_param_t { - /// The name of the parameter - const char *name; - /// The description of the parameter. - const char *description; - /// The initial value the parameter is set to. - float initial; - /// The minimum value that the parameter can be set to. - float minimum; - /// The maximum value that the parameter can be set to. - float maximum; - /// The step by which this parameter can be incremented or decremented. - float step; + /// The name of the parameter + const char *name; + /// The description of the parameter. + const char *description; + /// The initial value the parameter is set to. + float initial; + /// The minimum value that the parameter can be set to. + float minimum; + /// The maximum value that the parameter can be set to. + float maximum; + /// The step by which this parameter can be incremented or decremented. + float step; } libra_preset_param_t; /// A list of preset parameters. typedef struct libra_preset_param_list_t { - /// A pointer to the parameter - const struct libra_preset_param_t *parameters; - /// The number of parameters in the list. - uint64_t length; - /// For internal use only. - /// Changing this causes immediate undefined behaviour on freeing this parameter list. - uint64_t _internal_alloc; + /// A pointer to the parameter + const struct libra_preset_param_t *parameters; + /// The number of parameters in the list. + uint64_t length; + /// For internal use only. + /// Changing this causes immediate undefined behaviour on freeing this parameter list. + uint64_t _internal_alloc; } libra_preset_param_list_t; #if defined(LIBRA_RUNTIME_OPENGL) @@ -140,12 +140,12 @@ typedef const void *(*libra_gl_loader_t)(const char*); /// Options for filter chain creation. typedef struct filter_chain_gl_opt_t { - /// The GLSL version. Should be at least `330`. - uint16_t gl_version; - /// Whether or not to use the Direct State Access APIs. Only available on OpenGL 4.5+. - bool use_dsa; - /// Whether or not to explicitly disable mipmap generation regardless of shader preset settings. - bool force_no_mipmaps; + /// The GLSL version. Should be at least `330`. + uint16_t gl_version; + /// Whether or not to use the Direct State Access APIs. Only available on OpenGL 4.5+. + bool use_dsa; + /// Whether or not to explicitly disable mipmap generation regardless of shader preset settings. + bool force_no_mipmaps; } filter_chain_gl_opt_t; #if defined(LIBRA_RUNTIME_OPENGL) @@ -169,35 +169,35 @@ typedef struct libra_source_image_gl_t { /// Defines the output viewport for a rendered frame. typedef struct libra_viewport_t { - /// The x offset in the viewport framebuffer to begin rendering from. - float x; - /// The y offset in the viewport framebuffer to begin rendering from. - float y; - /// The width of the viewport framebuffer. - uint32_t width; - /// The height of the viewport framebuffer. - uint32_t height; + /// The x offset in the viewport framebuffer to begin rendering from. + float x; + /// The y offset in the viewport framebuffer to begin rendering from. + float y; + /// The width of the viewport framebuffer. + uint32_t width; + /// The height of the viewport framebuffer. + uint32_t height; } libra_viewport_t; #if defined(LIBRA_RUNTIME_OPENGL) /// OpenGL parameters for the output framebuffer. -typedef struct libra_draw_framebuffer_gl_t { +typedef struct libra_output_framebuffer_gl_t { /// A framebuffer GLuint to the output framebuffer. uint32_t handle; /// A texture GLuint to the logical buffer of the output framebuffer. uint32_t texture; /// The format of the output framebuffer. uint32_t format; -} libra_draw_framebuffer_gl_t; +} libra_output_framebuffer_gl_t; #endif /// Options for each OpenGL shader frame. typedef struct frame_gl_opt_t { - /// Whether or not to clear the history buffers. - bool clear_history; - /// The direction of rendering. - /// -1 indicates that the frames are played in reverse order. - int32_t frame_direction; + /// Whether or not to clear the history buffers. + bool clear_history; + /// The direction of rendering. + /// -1 indicates that the frames are played in reverse order. + int32_t frame_direction; } frame_gl_opt_t; #if defined(LIBRA_RUNTIME_VULKAN) @@ -219,13 +219,13 @@ typedef struct libra_device_vk_t { /// Options for filter chain creation. typedef struct filter_chain_vk_opt_t { - /// The number of frames in flight to keep. If zero, defaults to three. - uint32_t frames_in_flight; - /// Whether or not to explicitly disable mipmap generation regardless of shader preset settings. - bool force_no_mipmaps; - /// Use explicit render pass objects It is recommended if possible to use dynamic rendering, - /// because render-pass mode will create new framebuffers per pass. - bool use_render_pass; + /// The number of frames in flight to keep. If zero, defaults to three. + uint32_t frames_in_flight; + /// Whether or not to explicitly disable mipmap generation regardless of shader preset settings. + bool force_no_mipmaps; + /// Use explicit render pass objects It is recommended if possible to use dynamic rendering, + /// because render-pass mode will create new framebuffers per pass. + bool use_render_pass; } filter_chain_vk_opt_t; #if defined(LIBRA_RUNTIME_VULKAN) @@ -235,7 +235,7 @@ typedef struct _filter_chain_vk *libra_vk_filter_chain_t; #if defined(LIBRA_RUNTIME_VULKAN) /// Vulkan parameters for the source image. -typedef struct libra_image_vk_t { +typedef struct libra_source_image_vk_t { /// A raw `VkImage` handle to the source image. VkImage handle; /// The `VkFormat` of the source image. @@ -244,28 +244,38 @@ typedef struct libra_image_vk_t { uint32_t width; /// The height of the source image. uint32_t height; -} libra_image_vk_t; +} libra_source_image_vk_t; +#endif + +#if defined(LIBRA_RUNTIME_VULKAN) +/// Vulkan parameters for the output image. +typedef struct libra_output_image_vk_t { + /// A raw `VkImage` handle to the output image. + VkImage handle; + /// The `VkFormat` of the output image. + VkFormat format; +} libra_output_image_vk_t; #endif /// Options for each Vulkan shader frame. typedef struct frame_vk_opt_t { - /// Whether or not to clear the history buffers. - bool clear_history; - /// The direction of rendering. - /// -1 indicates that the frames are played in reverse order. - int32_t frame_direction; + /// Whether or not to clear the history buffers. + bool clear_history; + /// The direction of rendering. + /// -1 indicates that the frames are played in reverse order. + int32_t frame_direction; } frame_vk_opt_t; /// Options for Direct3D11 filter chain creation. typedef struct filter_chain_d3d11_opt_t { - /// 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; + /// 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; } filter_chain_d3d11_opt_t; #if defined(LIBRA_RUNTIME_D3D11) @@ -287,21 +297,21 @@ typedef struct libra_source_image_d3d11_t { /// Options for each Direct3D11 shader frame. typedef struct frame_d3d11_opt_t { - /// Whether or not to clear the history buffers. - bool clear_history; - /// The direction of rendering. - /// -1 indicates that the frames are played in reverse order. - int32_t frame_direction; + /// Whether or not to clear the history buffers. + bool clear_history; + /// The direction of rendering. + /// -1 indicates that the frames are played in reverse order. + int32_t frame_direction; } frame_d3d11_opt_t; /// Options for Direct3D11 filter chain creation. typedef struct filter_chain_d3d12_opt_t { - /// Force the HLSL shader pipeline. This may reduce shader compatibility. - bool force_hlsl_pipeline; - /// Whether or not to explicitly disable mipmap - /// generation for intermediate passes regardless - /// of shader preset settings. - bool force_no_mipmaps; + /// Force the HLSL shader pipeline. This may reduce shader compatibility. + bool force_hlsl_pipeline; + /// Whether or not to explicitly disable mipmap + /// generation for intermediate passes regardless + /// of shader preset settings. + bool force_no_mipmaps; } filter_chain_d3d12_opt_t; #if defined(LIBRA_RUNTIME_D3D12) @@ -310,7 +320,7 @@ typedef struct _filter_chain_d3d12 *libra_d3d12_filter_chain_t; #endif #if defined(LIBRA_RUNTIME_D3D12) -/// Direct3D 11 parameters for the source image. +/// Direct3D 12 parameters for the source image. typedef struct libra_source_image_d3d12_t { /// The resource containing the image. const ID3D12Resource * resource; @@ -325,13 +335,23 @@ typedef struct libra_source_image_d3d12_t { } libra_source_image_d3d12_t; #endif +#if defined(LIBRA_RUNTIME_D3D12) +/// Direct3D 12 parameters for the output image. +typedef struct libra_output_image_d3d12_t { + /// A CPU descriptor handle to a shader resource view of the image. + D3D12_CPU_DESCRIPTOR_HANDLE descriptor; + /// The format of the image. + DXGI_FORMAT format; +} libra_output_image_d3d12_t; +#endif + /// Options for each Direct3D11 shader frame. typedef struct frame_d3d12_opt_t { - /// Whether or not to clear the history buffers. - bool clear_history; - /// The direction of rendering. - /// -1 indicates that the frames are played in reverse order. - int32_t frame_direction; + /// Whether or not to clear the history buffers. + bool clear_history; + /// The direction of rendering. + /// -1 indicates that the frames are played in reverse order. + int32_t frame_direction; } frame_d3d12_opt_t; /// Function pointer definition for @@ -403,7 +423,7 @@ typedef libra_error_t (*PFN_libra_gl_filter_chain_frame)(libra_gl_filter_chain_t size_t frame_count, struct libra_source_image_gl_t image, struct libra_viewport_t viewport, - struct libra_draw_framebuffer_gl_t out, + struct libra_output_framebuffer_gl_t out, const float *mvp, const struct frame_gl_opt_t *opt); #endif @@ -459,9 +479,9 @@ typedef libra_error_t (*PFN_libra_vk_filter_chain_create)(struct libra_device_vk typedef libra_error_t (*PFN_libra_vk_filter_chain_frame)(libra_vk_filter_chain_t *chain, VkCommandBuffer command_buffer, size_t frame_count, - struct libra_image_vk_t image, + struct libra_source_image_vk_t image, struct libra_viewport_t viewport, - struct libra_image_vk_t out, + struct libra_output_image_vk_t out, const float *mvp, const struct frame_vk_opt_t *opt); #endif @@ -576,7 +596,7 @@ typedef libra_error_t (*PFN_libra_d3d12_filter_chain_frame)(libra_d3d12_filter_c size_t frame_count, struct libra_source_image_d3d12_t image, struct libra_viewport_t viewport, - D3D12_CPU_DESCRIPTOR_HANDLE out, + struct libra_output_image_d3d12_t out, const float *mvp, const struct frame_d3d12_opt_t *opt); #endif @@ -777,7 +797,7 @@ libra_error_t libra_gl_filter_chain_frame(libra_gl_filter_chain_t *chain, size_t frame_count, struct libra_source_image_gl_t image, struct libra_viewport_t viewport, - struct libra_draw_framebuffer_gl_t out, + struct libra_output_framebuffer_gl_t out, const float *mvp, const struct frame_gl_opt_t *opt); #endif @@ -870,9 +890,9 @@ libra_error_t libra_vk_filter_chain_create(struct libra_device_vk_t vulkan, libra_error_t libra_vk_filter_chain_frame(libra_vk_filter_chain_t *chain, VkCommandBuffer command_buffer, size_t frame_count, - struct libra_image_vk_t image, + struct libra_source_image_vk_t image, struct libra_viewport_t viewport, - struct libra_image_vk_t out, + struct libra_output_image_vk_t out, const float *mvp, const struct frame_vk_opt_t *opt); #endif @@ -1053,7 +1073,7 @@ libra_error_t libra_d3d12_filter_chain_frame(libra_d3d12_filter_chain_t *chain, size_t frame_count, struct libra_source_image_d3d12_t image, struct libra_viewport_t viewport, - D3D12_CPU_DESCRIPTOR_HANDLE out, + struct libra_output_image_d3d12_t out, const float *mvp, const struct frame_d3d12_opt_t *opt); #endif diff --git a/include/librashader_ld.h b/include/librashader_ld.h index c3ea955..a045cac 100644 --- a/include/librashader_ld.h +++ b/include/librashader_ld.h @@ -120,7 +120,7 @@ libra_error_t __librashader__noop_gl_filter_chain_create( libra_error_t __librashader__noop_gl_filter_chain_frame( libra_gl_filter_chain_t *chain, size_t frame_count, struct libra_source_image_gl_t image, struct libra_viewport_t viewport, - struct libra_draw_framebuffer_gl_t out, const float *mvp, + struct libra_output_framebuffer_gl_t out, const float *mvp, const struct frame_gl_opt_t *opt) { return NULL; } @@ -160,8 +160,8 @@ libra_error_t __librashader__noop_vk_filter_chain_create( libra_error_t __librashader__noop_vk_filter_chain_frame( libra_vk_filter_chain_t *chain, VkCommandBuffer command_buffer, - size_t frame_count, struct libra_image_vk_t image, - struct libra_viewport_t viewport, struct libra_image_vk_t out, + size_t frame_count, struct libra_source_image_vk_t image, + struct libra_viewport_t viewport, struct libra_output_image_vk_t out, const float *mvp, const struct frame_vk_opt_t *opt) { return NULL; } @@ -247,7 +247,7 @@ libra_error_t __librashader__noop_d3d12_filter_chain_frame( libra_d3d12_filter_chain_t *chain, const ID3D12GraphicsCommandList *command_list, size_t frame_count, struct libra_source_image_d3d12_t image, struct libra_viewport_t viewport, - D3D12_CPU_DESCRIPTOR_HANDLE out, const float *mvp, + struct libra_output_image_d3d12_t out, const float *mvp, const struct frame_d3d12_opt_t *opt) { return NULL; } diff --git a/librashader-capi/src/runtime/d3d12/filter_chain.rs b/librashader-capi/src/runtime/d3d12/filter_chain.rs index 861d779..325aadd 100644 --- a/librashader-capi/src/runtime/d3d12/filter_chain.rs +++ b/librashader-capi/src/runtime/d3d12/filter_chain.rs @@ -17,7 +17,7 @@ pub use librashader::runtime::d3d12::capi::options::FrameOptionsD3D12; use librashader::runtime::d3d12::{D3D12InputImage, D3D12OutputView}; use librashader::runtime::{FilterChainParameters, Size, Viewport}; -/// Direct3D 11 parameters for the source image. +/// Direct3D 12 parameters for the source image. #[repr(C)] pub struct libra_source_image_d3d12_t { /// The resource containing the image. @@ -32,6 +32,15 @@ pub struct libra_source_image_d3d12_t { pub height: u32, } +/// Direct3D 12 parameters for the output image. +#[repr(C)] +pub struct libra_output_image_d3d12_t { + /// A CPU descriptor handle to a shader resource view of the image. + pub descriptor: D3D12_CPU_DESCRIPTOR_HANDLE, + /// The format of the image. + pub format: DXGI_FORMAT, +} + impl TryFrom for D3D12InputImage { type Error = LibrashaderError; @@ -111,7 +120,7 @@ extern_fn! { frame_count: usize, image: libra_source_image_d3d12_t, viewport: libra_viewport_t, - out: D3D12_CPU_DESCRIPTOR_HANDLE, + out: libra_output_image_d3d12_t, mvp: *const f32, opt: *const FrameOptionsD3D12 ) mut |chain| { @@ -132,7 +141,7 @@ extern_fn! { let viewport = Viewport { x: viewport.x, y: viewport.y, - output: unsafe { D3D12OutputView::new_from_raw(out, Size::new(viewport.width, viewport.height)) }, + output: unsafe { D3D12OutputView::new_from_raw(out.descriptor, Size::new(viewport.width, viewport.height), out.format) }, mvp, }; diff --git a/librashader-capi/src/runtime/gl/filter_chain.rs b/librashader-capi/src/runtime/gl/filter_chain.rs index a6e1897..595f48e 100644 --- a/librashader-capi/src/runtime/gl/filter_chain.rs +++ b/librashader-capi/src/runtime/gl/filter_chain.rs @@ -31,7 +31,7 @@ pub struct libra_source_image_gl_t { /// OpenGL parameters for the output framebuffer. #[repr(C)] -pub struct libra_draw_framebuffer_gl_t { +pub struct libra_output_framebuffer_gl_t { /// A framebuffer GLuint to the output framebuffer. pub handle: u32, /// A texture GLuint to the logical buffer of the output framebuffer. @@ -125,7 +125,7 @@ extern_fn! { frame_count: usize, image: libra_source_image_gl_t, viewport: libra_viewport_t, - out: libra_draw_framebuffer_gl_t, + out: libra_output_framebuffer_gl_t, mvp: *const f32, opt: *const FrameOptionsGL ) mut |chain| { diff --git a/librashader-capi/src/runtime/vk/filter_chain.rs b/librashader-capi/src/runtime/vk/filter_chain.rs index 5d79026..9616739 100644 --- a/librashader-capi/src/runtime/vk/filter_chain.rs +++ b/librashader-capi/src/runtime/vk/filter_chain.rs @@ -23,7 +23,7 @@ pub type libra_PFN_vkGetInstanceProcAddr = /// Vulkan parameters for the source image. #[repr(C)] -pub struct libra_image_vk_t { +pub struct libra_source_image_vk_t { /// A raw `VkImage` handle to the source image. pub handle: vk::Image, /// The `VkFormat` of the source image. @@ -34,6 +34,15 @@ pub struct libra_image_vk_t { pub height: u32, } +/// Vulkan parameters for the output image. +#[repr(C)] +pub struct libra_output_image_vk_t { + /// A raw `VkImage` handle to the output image. + pub handle: vk::Image, + /// The `VkFormat` of the output image. + pub format: vk::Format, +} + /// Handles required to instantiate vulkan #[repr(C)] pub struct libra_device_vk_t { @@ -50,8 +59,8 @@ pub struct libra_device_vk_t { pub entry: vk::PFN_vkGetInstanceProcAddr, } -impl From for VulkanImage { - fn from(value: libra_image_vk_t) -> Self { +impl From for VulkanImage { + fn from(value: libra_source_image_vk_t) -> Self { VulkanImage { size: Size::new(value.width, value.height), image: value.handle, @@ -134,15 +143,19 @@ extern_fn! { chain: *mut libra_vk_filter_chain_t, command_buffer: vk::CommandBuffer, frame_count: usize, - image: libra_image_vk_t, + image: libra_source_image_vk_t, viewport: libra_viewport_t, - out: libra_image_vk_t, + out: libra_output_image_vk_t, mvp: *const f32, opt: *const FrameOptionsVulkan ) mut |chain| { assert_some_ptr!(mut chain); let image: VulkanImage = image.into(); - let output = out.into(); + let output = VulkanImage { + image: out.handle, + size: Size::new(viewport.width, viewport.height), + format: out.format + }; let mvp = if mvp.is_null() { None } else { diff --git a/librashader-runtime-d3d12/src/filter_chain.rs b/librashader-runtime-d3d12/src/filter_chain.rs index 9af47b7..8744701 100644 --- a/librashader-runtime-d3d12/src/filter_chain.rs +++ b/librashader-runtime-d3d12/src/filter_chain.rs @@ -407,7 +407,7 @@ impl FilterChainD3D12 { validator, &dxil, root_signature, - render_format, + render_format ) { (dxil_reflection, graphics_pipeline) } else { @@ -688,6 +688,15 @@ impl FilterChainD3D12 { // try to hint the optimizer assert_eq!(last.len(), 1); if let Some(pass) = last.iter_mut().next() { + if pass.pipeline.format != viewport.output.format { + // eprintln!("recompiling final pipeline"); + pass.pipeline.recompile( + viewport.output.format, + &self.common.root_signature, + &self.common.d3d12, + )?; + } + source.filter = pass.config.filter; source.wrap_mode = pass.config.wrap_mode; diff --git a/librashader-runtime-d3d12/src/framebuffer.rs b/librashader-runtime-d3d12/src/framebuffer.rs index d46bb34..251ea27 100644 --- a/librashader-runtime-d3d12/src/framebuffer.rs +++ b/librashader-runtime-d3d12/src/framebuffer.rs @@ -281,7 +281,11 @@ impl OwnedImage { ); } - Ok(D3D12OutputView::new(descriptor, self.size)) + Ok(D3D12OutputView::new( + descriptor, + self.size, + self.format.into(), + )) } pub fn scale( diff --git a/librashader-runtime-d3d12/src/graphics_pipeline.rs b/librashader-runtime-d3d12/src/graphics_pipeline.rs index 195c1f4..582dfbb 100644 --- a/librashader-runtime-d3d12/src/graphics_pipeline.rs +++ b/librashader-runtime-d3d12/src/graphics_pipeline.rs @@ -7,7 +7,9 @@ use librashader_reflect::back::dxil::DxilObject; use librashader_reflect::back::ShaderCompilerOutput; use librashader_reflect::reflect::semantics::BindingStage; use windows::Win32::Foundation::BOOL; -use windows::Win32::Graphics::Direct3D::Dxc::{IDxcBlob, IDxcCompiler, IDxcUtils, IDxcValidator}; +use windows::Win32::Graphics::Direct3D::Dxc::{ + CLSID_DxcLibrary, DxcCreateInstance, IDxcBlob, IDxcCompiler, IDxcUtils, IDxcValidator, DXC_CP, +}; use windows::Win32::Graphics::Direct3D12::{ D3D12SerializeVersionedRootSignature, ID3D12Device, ID3D12PipelineState, ID3D12RootSignature, D3D12_BLEND_DESC, D3D12_BLEND_INV_SRC_ALPHA, D3D12_BLEND_OP_ADD, D3D12_BLEND_SRC_ALPHA, @@ -29,6 +31,9 @@ use windows::Win32::Graphics::Dxgi::Common::{DXGI_FORMAT, DXGI_FORMAT_UNKNOWN, D pub struct D3D12GraphicsPipeline { pub(crate) handle: ID3D12PipelineState, + pub(crate) format: DXGI_FORMAT, + vertex: Vec, + fragment: Vec, } const D3D12_SLANG_ROOT_PARAMETERS: &[D3D12_ROOT_PARAMETER1; 4] = &[ @@ -218,9 +223,49 @@ impl D3D12GraphicsPipeline { device.CreateGraphicsPipelineState(&pipeline_desc)? }; - Ok(D3D12GraphicsPipeline { - handle: pipeline_state, - }) + unsafe { + let vertex = Vec::from(std::slice::from_raw_parts( + vertex_dxil.GetBufferPointer().cast(), + vertex_dxil.GetBufferSize(), + )); + let fragment = Vec::from(std::slice::from_raw_parts( + fragment_dxil.GetBufferPointer().cast(), + fragment_dxil.GetBufferSize(), + )); + Ok(D3D12GraphicsPipeline { + handle: pipeline_state, + format: render_format, + vertex, + fragment, + }) + } + } + + pub fn recompile( + &mut self, + format: DXGI_FORMAT, + root_sig: &D3D12RootSignature, + device: &ID3D12Device, + ) -> error::Result<()> { + let (vertex, fragment) = unsafe { + let library: IDxcUtils = DxcCreateInstance(&CLSID_DxcLibrary)?; + let vertex = library.CreateBlobFromPinned( + self.vertex.as_ptr().cast(), + self.vertex.len() as u32, + DXC_CP(0), + )?; + let fragment = library.CreateBlobFromPinned( + self.fragment.as_ptr().cast(), + self.fragment.len() as u32, + DXC_CP(0), + )?; + (vertex, fragment) + }; + let mut new_pipeline = + Self::new_from_blobs(device, vertex.into(), fragment.into(), root_sig, format)?; + + std::mem::swap(self, &mut new_pipeline); + Ok(()) } pub fn new_from_dxil( diff --git a/librashader-runtime-d3d12/src/hello_triangle.rs b/librashader-runtime-d3d12/src/hello_triangle.rs index 5dc8bce..28823b9 100644 --- a/librashader-runtime-d3d12/src/hello_triangle.rs +++ b/librashader-runtime-d3d12/src/hello_triangle.rs @@ -636,6 +636,7 @@ pub mod d3d12_hello_triangle { resources.viewport.Width as u32, resources.viewport.Height as u32, ), + DXGI_FORMAT_R8G8B8A8_UNORM, ), }, frame_count, diff --git a/librashader-runtime-d3d12/src/lib.rs b/librashader-runtime-d3d12/src/lib.rs index 817334a..b629607 100644 --- a/librashader-runtime-d3d12/src/lib.rs +++ b/librashader-runtime-d3d12/src/lib.rs @@ -33,7 +33,7 @@ mod tests { fn triangle_d3d12() { let sample = hello_triangle::d3d12_hello_triangle::Sample::new( // "../test/slang-shaders/crt/crt-lottes.slangp", - "../test/slang-shaders/bezel/Mega_Bezel/Presets/Variations/Megatron/ADV/crt-sony-megatron-aeg-CTV-4800-VT-sdr.slangp", + "../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV-GLASS.slangp", // "../test/slang-shaders/crt/crt-royale.slangp", // "../test/slang-shaders/vhs/VHSPro.slangp", &SampleCommandLine { diff --git a/librashader-runtime-d3d12/src/texture.rs b/librashader-runtime-d3d12/src/texture.rs index 3f15bf4..6e8e072 100644 --- a/librashader-runtime-d3d12/src/texture.rs +++ b/librashader-runtime-d3d12/src/texture.rs @@ -49,24 +49,35 @@ impl AsRef for OutputDescriptor { pub struct D3D12OutputView { pub(crate) descriptor: OutputDescriptor, pub(crate) size: Size, + pub(crate) format: DXGI_FORMAT, } impl D3D12OutputView { pub(crate) fn new( handle: D3D12DescriptorHeapSlot, size: Size, + format: DXGI_FORMAT, ) -> D3D12OutputView { let descriptor = OutputDescriptor::Owned(handle); - D3D12OutputView { descriptor, size } + D3D12OutputView { + descriptor, + size, + format, + } } // unsafe since the lifetime of the handle has to survive pub unsafe fn new_from_raw( handle: D3D12_CPU_DESCRIPTOR_HANDLE, size: Size, + format: DXGI_FORMAT, ) -> D3D12OutputView { let descriptor = OutputDescriptor::Raw(handle); - D3D12OutputView { descriptor, size } + D3D12OutputView { + descriptor, + size, + format, + } } } diff --git a/librashader-runtime-vk/src/filter_chain.rs b/librashader-runtime-vk/src/filter_chain.rs index afe8afe..fd8df63 100644 --- a/librashader-runtime-vk/src/filter_chain.rs +++ b/librashader-runtime-vk/src/filter_chain.rs @@ -2,13 +2,13 @@ use crate::draw_quad::DrawQuad; use crate::error::FilterChainError; use crate::filter_pass::FilterPass; use crate::framebuffer::OutputImage; +use crate::graphics_pipeline::VulkanGraphicsPipeline; use crate::luts::LutTexture; use crate::options::{FilterChainOptionsVulkan, FrameOptionsVulkan}; use crate::queue_selection::get_graphics_queue; use crate::samplers::SamplerSet; use crate::texture::{InputImage, OwnedImage, OwnedImageLayout, VulkanImage}; use crate::vulkan_primitives::RawVulkanBuffer; -use crate::vulkan_state::VulkanGraphicsPipeline; use crate::{error, util}; use ash::vk; use librashader_common::{ImageFormat, Size, Viewport}; @@ -682,6 +682,12 @@ impl FilterChainVulkan { // try to hint the optimizer assert_eq!(last.len(), 1); if let Some(pass) = last.iter_mut().next() { + if let Some(format) = pass.graphics_pipeline.render_pass.as_ref().map(|r| r.format) + && format != viewport.output.format { + // need to recompile + pass.graphics_pipeline.recompile(viewport.output.format)?; + } + source.filter_mode = pass.config.filter; source.wrap_mode = pass.config.wrap_mode; source.mip_filter = pass.config.filter; diff --git a/librashader-runtime-vk/src/filter_pass.rs b/librashader-runtime-vk/src/filter_pass.rs index 0ad75cf..a17a275 100644 --- a/librashader-runtime-vk/src/filter_pass.rs +++ b/librashader-runtime-vk/src/filter_pass.rs @@ -1,9 +1,9 @@ use crate::filter_chain::FilterCommon; use crate::framebuffer::OutputImage; +use crate::graphics_pipeline::VulkanGraphicsPipeline; use crate::samplers::SamplerSet; use crate::texture::InputImage; use crate::vulkan_primitives::RawVulkanBuffer; -use crate::vulkan_state::VulkanGraphicsPipeline; use crate::{error, VulkanImage}; use ash::vk; use librashader_common::{ImageFormat, Size, Viewport}; diff --git a/librashader-runtime-vk/src/vulkan_state.rs b/librashader-runtime-vk/src/graphics_pipeline.rs similarity index 88% rename from librashader-runtime-vk/src/vulkan_state.rs rename to librashader-runtime-vk/src/graphics_pipeline.rs index 5cbb261..ce23e2a 100644 --- a/librashader-runtime-vk/src/vulkan_state.rs +++ b/librashader-runtime-vk/src/graphics_pipeline.rs @@ -8,6 +8,7 @@ use librashader_reflect::reflect::semantics::{TextureBinding, UboReflection}; use librashader_reflect::reflect::ShaderReflection; use librashader_runtime::render_target::RenderTarget; use std::ffi::CStr; +use std::sync::Arc; const ENTRY_POINT: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(b"main\0") }; @@ -177,19 +178,21 @@ pub struct VulkanGraphicsPipeline { pub layout: PipelineLayoutObjects, pub pipeline: vk::Pipeline, pub render_pass: Option, + device: Arc, + vertex: VulkanShaderModule, + fragment: VulkanShaderModule, + cache: vk::PipelineCache, } impl VulkanGraphicsPipeline { - pub fn new( + fn create_pipeline( device: &ash::Device, cache: &vk::PipelineCache, - shader_assembly: &ShaderCompilerOutput>, - reflection: &ShaderReflection, - replicas: u32, - render_pass_format: vk::Format, - ) -> error::Result { - let pipeline_layout = PipelineLayoutObjects::new(reflection, replicas, device)?; - + pipeline_layout: &PipelineLayoutObjects, + vertex_module: &VulkanShaderModule, + fragment_module: &VulkanShaderModule, + render_pass: Option<&VulkanRenderPass>, + ) -> error::Result { let input_assembly = vk::PipelineInputAssemblyStateCreateInfo::builder() .topology(vk::PrimitiveTopology::TRIANGLE_STRIP) .build(); @@ -262,16 +265,6 @@ impl VulkanGraphicsPipeline { .dynamic_states(&states) .build(); - let vertex_info = vk::ShaderModuleCreateInfo::builder() - .code(shader_assembly.vertex.as_ref()) - .build(); - let fragment_info = vk::ShaderModuleCreateInfo::builder() - .code(shader_assembly.fragment.as_ref()) - .build(); - - let vertex_module = VulkanShaderModule::new(device, &vertex_info)?; - let fragment_module = VulkanShaderModule::new(device, &fragment_info)?; - let shader_stages = [ vk::PipelineShaderStageCreateInfo::builder() .stage(vk::ShaderStageFlags::VERTEX) @@ -297,32 +290,93 @@ impl VulkanGraphicsPipeline { .dynamic_state(&dynamic_state) .layout(pipeline_layout.layout); + if let Some(render_pass) = render_pass { + pipeline_info = pipeline_info.render_pass(render_pass.handle) + } + + let pipeline_info = [pipeline_info.build()]; + + let pipeline = unsafe { + // panic_safety: if this is successful this should return 1 pipelines. + device + .create_graphics_pipelines(*cache, &pipeline_info, None) + .map_err(|e| e.1) + .unwrap()[0] + }; + + Ok(pipeline) + } + + pub fn new( + device: &Arc, + cache: &vk::PipelineCache, + shader_assembly: &ShaderCompilerOutput>, + reflection: &ShaderReflection, + replicas: u32, + render_pass_format: vk::Format, + ) -> error::Result { + let pipeline_layout = PipelineLayoutObjects::new(reflection, replicas, device)?; + + let vertex_info = vk::ShaderModuleCreateInfo::builder() + .code(shader_assembly.vertex.as_ref()) + .build(); + let fragment_info = vk::ShaderModuleCreateInfo::builder() + .code(shader_assembly.fragment.as_ref()) + .build(); + + let vertex_module = VulkanShaderModule::new(device, &vertex_info)?; + let fragment_module = VulkanShaderModule::new(device, &fragment_info)?; + let mut render_pass = None; if render_pass_format != vk::Format::UNDEFINED { render_pass = Some(VulkanRenderPass::create_render_pass( device, render_pass_format, )?); - pipeline_info = pipeline_info.render_pass(render_pass.as_ref().unwrap().handle) } - let pipeline_info = pipeline_info.build(); - - let pipeline = unsafe { - // panic_safety: if this is successful this should return 1 pipelines. - device - .create_graphics_pipelines(*cache, &[pipeline_info], None) - .map_err(|e| e.1) - .unwrap()[0] - }; + let pipeline = Self::create_pipeline( + &device, + &cache, + &pipeline_layout, + &vertex_module, + &fragment_module, + render_pass.as_ref(), + )?; Ok(VulkanGraphicsPipeline { + device: Arc::clone(device), layout: pipeline_layout, pipeline, render_pass, + vertex: vertex_module, + fragment: fragment_module, + cache: *cache, }) } + pub(crate) fn recompile(&mut self, format: vk::Format) -> error::Result<()> { + let mut new_renderpass = if self.render_pass.is_some() { + Some(VulkanRenderPass::create_render_pass(&self.device, format)?) + } else { + None + }; + + let mut new_pipeline = Self::create_pipeline( + &self.device, + &self.cache, + &self.layout, + &self.vertex, + &self.fragment, + new_renderpass.as_ref(), + )?; + + std::mem::swap(&mut self.render_pass, &mut new_renderpass); + std::mem::swap(&mut self.pipeline, &mut new_pipeline); + + unsafe { self.device.destroy_pipeline(new_pipeline, None) } + Ok(()) + } #[inline(always)] pub(crate) fn begin_rendering( &self, diff --git a/librashader-runtime-vk/src/lib.rs b/librashader-runtime-vk/src/lib.rs index c5284ac..c93ce27 100644 --- a/librashader-runtime-vk/src/lib.rs +++ b/librashader-runtime-vk/src/lib.rs @@ -11,6 +11,7 @@ mod draw_quad; mod filter_chain; mod filter_pass; mod framebuffer; +mod graphics_pipeline; #[cfg(test)] mod hello_triangle; mod luts; @@ -20,7 +21,6 @@ mod samplers; mod texture; mod util; mod vulkan_primitives; -mod vulkan_state; pub use filter_chain::FilterChainVulkan; pub use filter_chain::VulkanInstance; @@ -41,7 +41,6 @@ mod tests { fn triangle_vk() { let entry = unsafe { ash::Entry::load().unwrap() }; let base = VulkanBase::new(entry).unwrap(); - dbg!("finished"); let filter = FilterChainVulkan::load_from_path( &base, // "../test/slang-shaders/crt/crt-royale.slangp", @@ -50,7 +49,7 @@ mod tests { Some(&FilterChainOptionsVulkan { frames_in_flight: 3, force_no_mipmaps: false, - use_render_pass: false, + use_render_pass: true, }), ) .unwrap(); diff --git a/test/capi-tests/librashader-capi-tests/librashader-capi-tests/librashader-capi-tests.cpp b/test/capi-tests/librashader-capi-tests/librashader-capi-tests/librashader-capi-tests.cpp index f7ad773..b02decd 100644 --- a/test/capi-tests/librashader-capi-tests/librashader-capi-tests/librashader-capi-tests.cpp +++ b/test/capi-tests/librashader-capi-tests/librashader-capi-tests/librashader-capi-tests.cpp @@ -3,6 +3,11 @@ #include #include +#define LIBRA_RUNTIME_VULKAN +#define LIBRA_RUNTIME_OPENGL +#define LIBRA_RUNTIME_D3D11 +#define LIBRA_RUNTIME_D3D12 + #include "../../../../include/librashader_ld.h" int main() @@ -16,11 +21,11 @@ int main() "gameboy-player-crt-royale.slangp", &preset); - libra_shader_preset_t preset2; + /* libra_shader_preset_t preset2; libra_preset_create( "../../../slang-shaders/border/gameboy-player/" "gameboy-player-crt-royale.slangp", - &preset2); + &preset2);*/ instance.preset_print(&preset); std::cout << "printed\n"; diff --git a/test/capi-tests/librashader-capi-tests/librashader-capi-tests/librashader-capi-tests.vcxproj b/test/capi-tests/librashader-capi-tests/librashader-capi-tests/librashader-capi-tests.vcxproj index b7d35c4..6f0a6eb 100644 --- a/test/capi-tests/librashader-capi-tests/librashader-capi-tests/librashader-capi-tests.vcxproj +++ b/test/capi-tests/librashader-capi-tests/librashader-capi-tests/librashader-capi-tests.vcxproj @@ -108,7 +108,7 @@ _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true false - stdcpplatest + stdcpp20 stdc17 D:\Runtime\Vulkan\1.3.224.1\Include\;%(AdditionalIncludeDirectories) @@ -128,6 +128,7 @@ NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true D:\Runtime\Vulkan\1.3.224.1\Include\;%(AdditionalIncludeDirectories) + stdcpp20 Console @@ -145,9 +146,6 @@ - - - diff --git a/test/capi-tests/librashader-capi-tests/librashader-capi-tests/librashader-capi-tests.vcxproj.filters b/test/capi-tests/librashader-capi-tests/librashader-capi-tests/librashader-capi-tests.vcxproj.filters index c1a2512..31e8e6f 100644 --- a/test/capi-tests/librashader-capi-tests/librashader-capi-tests/librashader-capi-tests.vcxproj.filters +++ b/test/capi-tests/librashader-capi-tests/librashader-capi-tests/librashader-capi-tests.vcxproj.filters @@ -27,7 +27,4 @@ Header Files - - - \ No newline at end of file