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.
This commit is contained in:
chyyran 2023-02-08 21:21:40 -05:00
parent 771a0896d7
commit 5e99ddf73c
18 changed files with 334 additions and 163 deletions

View file

@ -63,17 +63,17 @@ typedef void D3D12_CPU_DESCRIPTOR_HANDLE;
/// Error codes for librashader error types. /// Error codes for librashader error types.
enum LIBRA_ERRNO enum LIBRA_ERRNO
#ifdef __cplusplus #ifdef __cplusplus
: int32_t : int32_t
#endif // __cplusplus #endif // __cplusplus
{ {
LIBRA_ERRNO_UNKNOWN_ERROR = 0, LIBRA_ERRNO_UNKNOWN_ERROR = 0,
LIBRA_ERRNO_INVALID_PARAMETER = 1, LIBRA_ERRNO_INVALID_PARAMETER = 1,
LIBRA_ERRNO_INVALID_STRING = 2, LIBRA_ERRNO_INVALID_STRING = 2,
LIBRA_ERRNO_PRESET_ERROR = 3, LIBRA_ERRNO_PRESET_ERROR = 3,
LIBRA_ERRNO_PREPROCESS_ERROR = 4, LIBRA_ERRNO_PREPROCESS_ERROR = 4,
LIBRA_ERRNO_SHADER_PARAMETER_ERROR = 5, LIBRA_ERRNO_SHADER_PARAMETER_ERROR = 5,
LIBRA_ERRNO_REFLECT_ERROR = 6, LIBRA_ERRNO_REFLECT_ERROR = 6,
LIBRA_ERRNO_RUNTIME_ERROR = 7, LIBRA_ERRNO_RUNTIME_ERROR = 7,
}; };
#ifndef __cplusplus #ifndef __cplusplus
typedef int32_t LIBRA_ERRNO; typedef int32_t LIBRA_ERRNO;
@ -108,29 +108,29 @@ typedef struct _shader_preset *libra_shader_preset_t;
/// A preset parameter. /// A preset parameter.
typedef struct libra_preset_param_t { typedef struct libra_preset_param_t {
/// The name of the parameter /// The name of the parameter
const char *name; const char *name;
/// The description of the parameter. /// The description of the parameter.
const char *description; const char *description;
/// The initial value the parameter is set to. /// The initial value the parameter is set to.
float initial; float initial;
/// The minimum value that the parameter can be set to. /// The minimum value that the parameter can be set to.
float minimum; float minimum;
/// The maximum value that the parameter can be set to. /// The maximum value that the parameter can be set to.
float maximum; float maximum;
/// The step by which this parameter can be incremented or decremented. /// The step by which this parameter can be incremented or decremented.
float step; float step;
} libra_preset_param_t; } libra_preset_param_t;
/// A list of preset parameters. /// A list of preset parameters.
typedef struct libra_preset_param_list_t { typedef struct libra_preset_param_list_t {
/// A pointer to the parameter /// A pointer to the parameter
const struct libra_preset_param_t *parameters; const struct libra_preset_param_t *parameters;
/// The number of parameters in the list. /// The number of parameters in the list.
uint64_t length; uint64_t length;
/// For internal use only. /// For internal use only.
/// Changing this causes immediate undefined behaviour on freeing this parameter list. /// Changing this causes immediate undefined behaviour on freeing this parameter list.
uint64_t _internal_alloc; uint64_t _internal_alloc;
} libra_preset_param_list_t; } libra_preset_param_list_t;
#if defined(LIBRA_RUNTIME_OPENGL) #if defined(LIBRA_RUNTIME_OPENGL)
@ -140,12 +140,12 @@ typedef const void *(*libra_gl_loader_t)(const char*);
/// Options for filter chain creation. /// Options for filter chain creation.
typedef struct filter_chain_gl_opt_t { typedef struct filter_chain_gl_opt_t {
/// The GLSL version. Should be at least `330`. /// The GLSL version. Should be at least `330`.
uint16_t gl_version; uint16_t gl_version;
/// Whether or not to use the Direct State Access APIs. Only available on OpenGL 4.5+. /// Whether or not to use the Direct State Access APIs. Only available on OpenGL 4.5+.
bool use_dsa; bool use_dsa;
/// Whether or not to explicitly disable mipmap generation regardless of shader preset settings. /// Whether or not to explicitly disable mipmap generation regardless of shader preset settings.
bool force_no_mipmaps; bool force_no_mipmaps;
} filter_chain_gl_opt_t; } filter_chain_gl_opt_t;
#if defined(LIBRA_RUNTIME_OPENGL) #if defined(LIBRA_RUNTIME_OPENGL)
@ -169,35 +169,35 @@ typedef struct libra_source_image_gl_t {
/// Defines the output viewport for a rendered frame. /// Defines the output viewport for a rendered frame.
typedef struct libra_viewport_t { typedef struct libra_viewport_t {
/// The x offset in the viewport framebuffer to begin rendering from. /// The x offset in the viewport framebuffer to begin rendering from.
float x; float x;
/// The y offset in the viewport framebuffer to begin rendering from. /// The y offset in the viewport framebuffer to begin rendering from.
float y; float y;
/// The width of the viewport framebuffer. /// The width of the viewport framebuffer.
uint32_t width; uint32_t width;
/// The height of the viewport framebuffer. /// The height of the viewport framebuffer.
uint32_t height; uint32_t height;
} libra_viewport_t; } libra_viewport_t;
#if defined(LIBRA_RUNTIME_OPENGL) #if defined(LIBRA_RUNTIME_OPENGL)
/// OpenGL parameters for the output framebuffer. /// 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. /// A framebuffer GLuint to the output framebuffer.
uint32_t handle; uint32_t handle;
/// A texture GLuint to the logical buffer of the output framebuffer. /// A texture GLuint to the logical buffer of the output framebuffer.
uint32_t texture; uint32_t texture;
/// The format of the output framebuffer. /// The format of the output framebuffer.
uint32_t format; uint32_t format;
} libra_draw_framebuffer_gl_t; } libra_output_framebuffer_gl_t;
#endif #endif
/// Options for each OpenGL shader frame. /// Options for each OpenGL shader frame.
typedef struct frame_gl_opt_t { typedef struct frame_gl_opt_t {
/// Whether or not to clear the history buffers. /// Whether or not to clear the history buffers.
bool clear_history; bool clear_history;
/// The direction of rendering. /// The direction of rendering.
/// -1 indicates that the frames are played in reverse order. /// -1 indicates that the frames are played in reverse order.
int32_t frame_direction; int32_t frame_direction;
} frame_gl_opt_t; } frame_gl_opt_t;
#if defined(LIBRA_RUNTIME_VULKAN) #if defined(LIBRA_RUNTIME_VULKAN)
@ -219,13 +219,13 @@ typedef struct libra_device_vk_t {
/// Options for filter chain creation. /// Options for filter chain creation.
typedef struct filter_chain_vk_opt_t { typedef struct filter_chain_vk_opt_t {
/// The number of frames in flight to keep. If zero, defaults to three. /// The number of frames in flight to keep. If zero, defaults to three.
uint32_t frames_in_flight; uint32_t frames_in_flight;
/// Whether or not to explicitly disable mipmap generation regardless of shader preset settings. /// Whether or not to explicitly disable mipmap generation regardless of shader preset settings.
bool force_no_mipmaps; bool force_no_mipmaps;
/// Use explicit render pass objects It is recommended if possible to use dynamic rendering, /// Use explicit render pass objects It is recommended if possible to use dynamic rendering,
/// because render-pass mode will create new framebuffers per pass. /// because render-pass mode will create new framebuffers per pass.
bool use_render_pass; bool use_render_pass;
} filter_chain_vk_opt_t; } filter_chain_vk_opt_t;
#if defined(LIBRA_RUNTIME_VULKAN) #if defined(LIBRA_RUNTIME_VULKAN)
@ -235,7 +235,7 @@ typedef struct _filter_chain_vk *libra_vk_filter_chain_t;
#if defined(LIBRA_RUNTIME_VULKAN) #if defined(LIBRA_RUNTIME_VULKAN)
/// Vulkan parameters for the source image. /// 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. /// A raw `VkImage` handle to the source image.
VkImage handle; VkImage handle;
/// The `VkFormat` of the source image. /// The `VkFormat` of the source image.
@ -244,28 +244,38 @@ typedef struct libra_image_vk_t {
uint32_t width; uint32_t width;
/// The height of the source image. /// The height of the source image.
uint32_t height; 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 #endif
/// Options for each Vulkan shader frame. /// Options for each Vulkan shader frame.
typedef struct frame_vk_opt_t { typedef struct frame_vk_opt_t {
/// Whether or not to clear the history buffers. /// Whether or not to clear the history buffers.
bool clear_history; bool clear_history;
/// The direction of rendering. /// The direction of rendering.
/// -1 indicates that the frames are played in reverse order. /// -1 indicates that the frames are played in reverse order.
int32_t frame_direction; int32_t frame_direction;
} frame_vk_opt_t; } frame_vk_opt_t;
/// Options for Direct3D11 filter chain creation. /// Options for Direct3D11 filter chain creation.
typedef struct filter_chain_d3d11_opt_t { typedef struct filter_chain_d3d11_opt_t {
/// Use a deferred context to record shader rendering state. /// Use a deferred context to record shader rendering state.
/// ///
/// The deferred context will be executed on the immediate context /// The deferred context will be executed on the immediate context
/// with `RenderContextState = true`. /// with `RenderContextState = true`.
bool use_deferred_context; bool use_deferred_context;
/// Whether or not to explicitly disable mipmap /// Whether or not to explicitly disable mipmap
/// generation regardless of shader preset settings. /// generation regardless of shader preset settings.
bool force_no_mipmaps; bool force_no_mipmaps;
} filter_chain_d3d11_opt_t; } filter_chain_d3d11_opt_t;
#if defined(LIBRA_RUNTIME_D3D11) #if defined(LIBRA_RUNTIME_D3D11)
@ -287,21 +297,21 @@ typedef struct libra_source_image_d3d11_t {
/// Options for each Direct3D11 shader frame. /// Options for each Direct3D11 shader frame.
typedef struct frame_d3d11_opt_t { typedef struct frame_d3d11_opt_t {
/// Whether or not to clear the history buffers. /// Whether or not to clear the history buffers.
bool clear_history; bool clear_history;
/// The direction of rendering. /// The direction of rendering.
/// -1 indicates that the frames are played in reverse order. /// -1 indicates that the frames are played in reverse order.
int32_t frame_direction; int32_t frame_direction;
} frame_d3d11_opt_t; } frame_d3d11_opt_t;
/// Options for Direct3D11 filter chain creation. /// Options for Direct3D11 filter chain creation.
typedef struct filter_chain_d3d12_opt_t { typedef struct filter_chain_d3d12_opt_t {
/// Force the HLSL shader pipeline. This may reduce shader compatibility. /// Force the HLSL shader pipeline. This may reduce shader compatibility.
bool force_hlsl_pipeline; bool force_hlsl_pipeline;
/// Whether or not to explicitly disable mipmap /// Whether or not to explicitly disable mipmap
/// generation for intermediate passes regardless /// generation for intermediate passes regardless
/// of shader preset settings. /// of shader preset settings.
bool force_no_mipmaps; bool force_no_mipmaps;
} filter_chain_d3d12_opt_t; } filter_chain_d3d12_opt_t;
#if defined(LIBRA_RUNTIME_D3D12) #if defined(LIBRA_RUNTIME_D3D12)
@ -310,7 +320,7 @@ typedef struct _filter_chain_d3d12 *libra_d3d12_filter_chain_t;
#endif #endif
#if defined(LIBRA_RUNTIME_D3D12) #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 { typedef struct libra_source_image_d3d12_t {
/// The resource containing the image. /// The resource containing the image.
const ID3D12Resource * resource; const ID3D12Resource * resource;
@ -325,13 +335,23 @@ typedef struct libra_source_image_d3d12_t {
} libra_source_image_d3d12_t; } libra_source_image_d3d12_t;
#endif #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. /// Options for each Direct3D11 shader frame.
typedef struct frame_d3d12_opt_t { typedef struct frame_d3d12_opt_t {
/// Whether or not to clear the history buffers. /// Whether or not to clear the history buffers.
bool clear_history; bool clear_history;
/// The direction of rendering. /// The direction of rendering.
/// -1 indicates that the frames are played in reverse order. /// -1 indicates that the frames are played in reverse order.
int32_t frame_direction; int32_t frame_direction;
} frame_d3d12_opt_t; } frame_d3d12_opt_t;
/// Function pointer definition for /// 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, size_t frame_count,
struct libra_source_image_gl_t image, struct libra_source_image_gl_t image,
struct libra_viewport_t viewport, struct libra_viewport_t viewport,
struct libra_draw_framebuffer_gl_t out, struct libra_output_framebuffer_gl_t out,
const float *mvp, const float *mvp,
const struct frame_gl_opt_t *opt); const struct frame_gl_opt_t *opt);
#endif #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, typedef libra_error_t (*PFN_libra_vk_filter_chain_frame)(libra_vk_filter_chain_t *chain,
VkCommandBuffer command_buffer, VkCommandBuffer command_buffer,
size_t frame_count, size_t frame_count,
struct libra_image_vk_t image, struct libra_source_image_vk_t image,
struct libra_viewport_t viewport, struct libra_viewport_t viewport,
struct libra_image_vk_t out, struct libra_output_image_vk_t out,
const float *mvp, const float *mvp,
const struct frame_vk_opt_t *opt); const struct frame_vk_opt_t *opt);
#endif #endif
@ -576,7 +596,7 @@ typedef libra_error_t (*PFN_libra_d3d12_filter_chain_frame)(libra_d3d12_filter_c
size_t frame_count, size_t frame_count,
struct libra_source_image_d3d12_t image, struct libra_source_image_d3d12_t image,
struct libra_viewport_t viewport, struct libra_viewport_t viewport,
D3D12_CPU_DESCRIPTOR_HANDLE out, struct libra_output_image_d3d12_t out,
const float *mvp, const float *mvp,
const struct frame_d3d12_opt_t *opt); const struct frame_d3d12_opt_t *opt);
#endif #endif
@ -777,7 +797,7 @@ libra_error_t libra_gl_filter_chain_frame(libra_gl_filter_chain_t *chain,
size_t frame_count, size_t frame_count,
struct libra_source_image_gl_t image, struct libra_source_image_gl_t image,
struct libra_viewport_t viewport, struct libra_viewport_t viewport,
struct libra_draw_framebuffer_gl_t out, struct libra_output_framebuffer_gl_t out,
const float *mvp, const float *mvp,
const struct frame_gl_opt_t *opt); const struct frame_gl_opt_t *opt);
#endif #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, libra_error_t libra_vk_filter_chain_frame(libra_vk_filter_chain_t *chain,
VkCommandBuffer command_buffer, VkCommandBuffer command_buffer,
size_t frame_count, size_t frame_count,
struct libra_image_vk_t image, struct libra_source_image_vk_t image,
struct libra_viewport_t viewport, struct libra_viewport_t viewport,
struct libra_image_vk_t out, struct libra_output_image_vk_t out,
const float *mvp, const float *mvp,
const struct frame_vk_opt_t *opt); const struct frame_vk_opt_t *opt);
#endif #endif
@ -1053,7 +1073,7 @@ libra_error_t libra_d3d12_filter_chain_frame(libra_d3d12_filter_chain_t *chain,
size_t frame_count, size_t frame_count,
struct libra_source_image_d3d12_t image, struct libra_source_image_d3d12_t image,
struct libra_viewport_t viewport, struct libra_viewport_t viewport,
D3D12_CPU_DESCRIPTOR_HANDLE out, struct libra_output_image_d3d12_t out,
const float *mvp, const float *mvp,
const struct frame_d3d12_opt_t *opt); const struct frame_d3d12_opt_t *opt);
#endif #endif

View file

@ -120,7 +120,7 @@ libra_error_t __librashader__noop_gl_filter_chain_create(
libra_error_t __librashader__noop_gl_filter_chain_frame( libra_error_t __librashader__noop_gl_filter_chain_frame(
libra_gl_filter_chain_t *chain, size_t frame_count, libra_gl_filter_chain_t *chain, size_t frame_count,
struct libra_source_image_gl_t image, struct libra_viewport_t viewport, 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) { const struct frame_gl_opt_t *opt) {
return NULL; 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_error_t __librashader__noop_vk_filter_chain_frame(
libra_vk_filter_chain_t *chain, VkCommandBuffer command_buffer, libra_vk_filter_chain_t *chain, VkCommandBuffer command_buffer,
size_t frame_count, struct libra_image_vk_t image, size_t frame_count, struct libra_source_image_vk_t image,
struct libra_viewport_t viewport, struct libra_image_vk_t out, struct libra_viewport_t viewport, struct libra_output_image_vk_t out,
const float *mvp, const struct frame_vk_opt_t *opt) { const float *mvp, const struct frame_vk_opt_t *opt) {
return NULL; return NULL;
} }
@ -247,7 +247,7 @@ libra_error_t __librashader__noop_d3d12_filter_chain_frame(
libra_d3d12_filter_chain_t *chain, libra_d3d12_filter_chain_t *chain,
const ID3D12GraphicsCommandList *command_list, size_t frame_count, const ID3D12GraphicsCommandList *command_list, size_t frame_count,
struct libra_source_image_d3d12_t image, struct libra_viewport_t viewport, 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) { const struct frame_d3d12_opt_t *opt) {
return NULL; return NULL;
} }

View file

@ -17,7 +17,7 @@ pub use librashader::runtime::d3d12::capi::options::FrameOptionsD3D12;
use librashader::runtime::d3d12::{D3D12InputImage, D3D12OutputView}; use librashader::runtime::d3d12::{D3D12InputImage, D3D12OutputView};
use librashader::runtime::{FilterChainParameters, Size, Viewport}; use librashader::runtime::{FilterChainParameters, Size, Viewport};
/// Direct3D 11 parameters for the source image. /// Direct3D 12 parameters for the source image.
#[repr(C)] #[repr(C)]
pub struct libra_source_image_d3d12_t { pub struct libra_source_image_d3d12_t {
/// The resource containing the image. /// The resource containing the image.
@ -32,6 +32,15 @@ pub struct libra_source_image_d3d12_t {
pub height: u32, 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<libra_source_image_d3d12_t> for D3D12InputImage { impl TryFrom<libra_source_image_d3d12_t> for D3D12InputImage {
type Error = LibrashaderError; type Error = LibrashaderError;
@ -111,7 +120,7 @@ extern_fn! {
frame_count: usize, frame_count: usize,
image: libra_source_image_d3d12_t, image: libra_source_image_d3d12_t,
viewport: libra_viewport_t, viewport: libra_viewport_t,
out: D3D12_CPU_DESCRIPTOR_HANDLE, out: libra_output_image_d3d12_t,
mvp: *const f32, mvp: *const f32,
opt: *const FrameOptionsD3D12 opt: *const FrameOptionsD3D12
) mut |chain| { ) mut |chain| {
@ -132,7 +141,7 @@ extern_fn! {
let viewport = Viewport { let viewport = Viewport {
x: viewport.x, x: viewport.x,
y: viewport.y, 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, mvp,
}; };

View file

@ -31,7 +31,7 @@ pub struct libra_source_image_gl_t {
/// OpenGL parameters for the output framebuffer. /// OpenGL parameters for the output framebuffer.
#[repr(C)] #[repr(C)]
pub struct libra_draw_framebuffer_gl_t { pub struct libra_output_framebuffer_gl_t {
/// A framebuffer GLuint to the output framebuffer. /// A framebuffer GLuint to the output framebuffer.
pub handle: u32, pub handle: u32,
/// A texture GLuint to the logical buffer of the output framebuffer. /// A texture GLuint to the logical buffer of the output framebuffer.
@ -125,7 +125,7 @@ extern_fn! {
frame_count: usize, frame_count: usize,
image: libra_source_image_gl_t, image: libra_source_image_gl_t,
viewport: libra_viewport_t, viewport: libra_viewport_t,
out: libra_draw_framebuffer_gl_t, out: libra_output_framebuffer_gl_t,
mvp: *const f32, mvp: *const f32,
opt: *const FrameOptionsGL opt: *const FrameOptionsGL
) mut |chain| { ) mut |chain| {

View file

@ -23,7 +23,7 @@ pub type libra_PFN_vkGetInstanceProcAddr =
/// Vulkan parameters for the source image. /// Vulkan parameters for the source image.
#[repr(C)] #[repr(C)]
pub struct libra_image_vk_t { pub struct libra_source_image_vk_t {
/// A raw `VkImage` handle to the source image. /// A raw `VkImage` handle to the source image.
pub handle: vk::Image, pub handle: vk::Image,
/// The `VkFormat` of the source image. /// The `VkFormat` of the source image.
@ -34,6 +34,15 @@ pub struct libra_image_vk_t {
pub height: u32, 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 /// Handles required to instantiate vulkan
#[repr(C)] #[repr(C)]
pub struct libra_device_vk_t { pub struct libra_device_vk_t {
@ -50,8 +59,8 @@ pub struct libra_device_vk_t {
pub entry: vk::PFN_vkGetInstanceProcAddr, pub entry: vk::PFN_vkGetInstanceProcAddr,
} }
impl From<libra_image_vk_t> for VulkanImage { impl From<libra_source_image_vk_t> for VulkanImage {
fn from(value: libra_image_vk_t) -> Self { fn from(value: libra_source_image_vk_t) -> Self {
VulkanImage { VulkanImage {
size: Size::new(value.width, value.height), size: Size::new(value.width, value.height),
image: value.handle, image: value.handle,
@ -134,15 +143,19 @@ extern_fn! {
chain: *mut libra_vk_filter_chain_t, chain: *mut libra_vk_filter_chain_t,
command_buffer: vk::CommandBuffer, command_buffer: vk::CommandBuffer,
frame_count: usize, frame_count: usize,
image: libra_image_vk_t, image: libra_source_image_vk_t,
viewport: libra_viewport_t, viewport: libra_viewport_t,
out: libra_image_vk_t, out: libra_output_image_vk_t,
mvp: *const f32, mvp: *const f32,
opt: *const FrameOptionsVulkan opt: *const FrameOptionsVulkan
) mut |chain| { ) mut |chain| {
assert_some_ptr!(mut chain); assert_some_ptr!(mut chain);
let image: VulkanImage = image.into(); 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() { let mvp = if mvp.is_null() {
None None
} else { } else {

View file

@ -407,7 +407,7 @@ impl FilterChainD3D12 {
validator, validator,
&dxil, &dxil,
root_signature, root_signature,
render_format, render_format
) { ) {
(dxil_reflection, graphics_pipeline) (dxil_reflection, graphics_pipeline)
} else { } else {
@ -688,6 +688,15 @@ impl FilterChainD3D12 {
// try to hint the optimizer // try to hint the optimizer
assert_eq!(last.len(), 1); assert_eq!(last.len(), 1);
if let Some(pass) = last.iter_mut().next() { 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.filter = pass.config.filter;
source.wrap_mode = pass.config.wrap_mode; source.wrap_mode = pass.config.wrap_mode;

View file

@ -281,7 +281,11 @@ impl OwnedImage {
); );
} }
Ok(D3D12OutputView::new(descriptor, self.size)) Ok(D3D12OutputView::new(
descriptor,
self.size,
self.format.into(),
))
} }
pub fn scale( pub fn scale(

View file

@ -7,7 +7,9 @@ use librashader_reflect::back::dxil::DxilObject;
use librashader_reflect::back::ShaderCompilerOutput; use librashader_reflect::back::ShaderCompilerOutput;
use librashader_reflect::reflect::semantics::BindingStage; use librashader_reflect::reflect::semantics::BindingStage;
use windows::Win32::Foundation::BOOL; 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::{ use windows::Win32::Graphics::Direct3D12::{
D3D12SerializeVersionedRootSignature, ID3D12Device, ID3D12PipelineState, ID3D12RootSignature, D3D12SerializeVersionedRootSignature, ID3D12Device, ID3D12PipelineState, ID3D12RootSignature,
D3D12_BLEND_DESC, D3D12_BLEND_INV_SRC_ALPHA, D3D12_BLEND_OP_ADD, D3D12_BLEND_SRC_ALPHA, 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 struct D3D12GraphicsPipeline {
pub(crate) handle: ID3D12PipelineState, pub(crate) handle: ID3D12PipelineState,
pub(crate) format: DXGI_FORMAT,
vertex: Vec<u8>,
fragment: Vec<u8>,
} }
const D3D12_SLANG_ROOT_PARAMETERS: &[D3D12_ROOT_PARAMETER1; 4] = &[ const D3D12_SLANG_ROOT_PARAMETERS: &[D3D12_ROOT_PARAMETER1; 4] = &[
@ -218,9 +223,49 @@ impl D3D12GraphicsPipeline {
device.CreateGraphicsPipelineState(&pipeline_desc)? device.CreateGraphicsPipelineState(&pipeline_desc)?
}; };
Ok(D3D12GraphicsPipeline { unsafe {
handle: pipeline_state, 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( pub fn new_from_dxil(

View file

@ -636,6 +636,7 @@ pub mod d3d12_hello_triangle {
resources.viewport.Width as u32, resources.viewport.Width as u32,
resources.viewport.Height as u32, resources.viewport.Height as u32,
), ),
DXGI_FORMAT_R8G8B8A8_UNORM,
), ),
}, },
frame_count, frame_count,

View file

@ -33,7 +33,7 @@ mod tests {
fn triangle_d3d12() { fn triangle_d3d12() {
let sample = hello_triangle::d3d12_hello_triangle::Sample::new( let sample = hello_triangle::d3d12_hello_triangle::Sample::new(
// "../test/slang-shaders/crt/crt-lottes.slangp", // "../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/crt/crt-royale.slangp",
// "../test/slang-shaders/vhs/VHSPro.slangp", // "../test/slang-shaders/vhs/VHSPro.slangp",
&SampleCommandLine { &SampleCommandLine {

View file

@ -49,24 +49,35 @@ impl AsRef<D3D12_CPU_DESCRIPTOR_HANDLE> for OutputDescriptor {
pub struct D3D12OutputView { pub struct D3D12OutputView {
pub(crate) descriptor: OutputDescriptor, pub(crate) descriptor: OutputDescriptor,
pub(crate) size: Size<u32>, pub(crate) size: Size<u32>,
pub(crate) format: DXGI_FORMAT,
} }
impl D3D12OutputView { impl D3D12OutputView {
pub(crate) fn new( pub(crate) fn new(
handle: D3D12DescriptorHeapSlot<RenderTargetHeap>, handle: D3D12DescriptorHeapSlot<RenderTargetHeap>,
size: Size<u32>, size: Size<u32>,
format: DXGI_FORMAT,
) -> D3D12OutputView { ) -> D3D12OutputView {
let descriptor = OutputDescriptor::Owned(handle); let descriptor = OutputDescriptor::Owned(handle);
D3D12OutputView { descriptor, size } D3D12OutputView {
descriptor,
size,
format,
}
} }
// unsafe since the lifetime of the handle has to survive // unsafe since the lifetime of the handle has to survive
pub unsafe fn new_from_raw( pub unsafe fn new_from_raw(
handle: D3D12_CPU_DESCRIPTOR_HANDLE, handle: D3D12_CPU_DESCRIPTOR_HANDLE,
size: Size<u32>, size: Size<u32>,
format: DXGI_FORMAT,
) -> D3D12OutputView { ) -> D3D12OutputView {
let descriptor = OutputDescriptor::Raw(handle); let descriptor = OutputDescriptor::Raw(handle);
D3D12OutputView { descriptor, size } D3D12OutputView {
descriptor,
size,
format,
}
} }
} }

View file

@ -2,13 +2,13 @@ use crate::draw_quad::DrawQuad;
use crate::error::FilterChainError; use crate::error::FilterChainError;
use crate::filter_pass::FilterPass; use crate::filter_pass::FilterPass;
use crate::framebuffer::OutputImage; use crate::framebuffer::OutputImage;
use crate::graphics_pipeline::VulkanGraphicsPipeline;
use crate::luts::LutTexture; use crate::luts::LutTexture;
use crate::options::{FilterChainOptionsVulkan, FrameOptionsVulkan}; use crate::options::{FilterChainOptionsVulkan, FrameOptionsVulkan};
use crate::queue_selection::get_graphics_queue; use crate::queue_selection::get_graphics_queue;
use crate::samplers::SamplerSet; use crate::samplers::SamplerSet;
use crate::texture::{InputImage, OwnedImage, OwnedImageLayout, VulkanImage}; use crate::texture::{InputImage, OwnedImage, OwnedImageLayout, VulkanImage};
use crate::vulkan_primitives::RawVulkanBuffer; use crate::vulkan_primitives::RawVulkanBuffer;
use crate::vulkan_state::VulkanGraphicsPipeline;
use crate::{error, util}; use crate::{error, util};
use ash::vk; use ash::vk;
use librashader_common::{ImageFormat, Size, Viewport}; use librashader_common::{ImageFormat, Size, Viewport};
@ -682,6 +682,12 @@ impl FilterChainVulkan {
// try to hint the optimizer // try to hint the optimizer
assert_eq!(last.len(), 1); assert_eq!(last.len(), 1);
if let Some(pass) = last.iter_mut().next() { 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.filter_mode = pass.config.filter;
source.wrap_mode = pass.config.wrap_mode; source.wrap_mode = pass.config.wrap_mode;
source.mip_filter = pass.config.filter; source.mip_filter = pass.config.filter;

View file

@ -1,9 +1,9 @@
use crate::filter_chain::FilterCommon; use crate::filter_chain::FilterCommon;
use crate::framebuffer::OutputImage; use crate::framebuffer::OutputImage;
use crate::graphics_pipeline::VulkanGraphicsPipeline;
use crate::samplers::SamplerSet; use crate::samplers::SamplerSet;
use crate::texture::InputImage; use crate::texture::InputImage;
use crate::vulkan_primitives::RawVulkanBuffer; use crate::vulkan_primitives::RawVulkanBuffer;
use crate::vulkan_state::VulkanGraphicsPipeline;
use crate::{error, VulkanImage}; use crate::{error, VulkanImage};
use ash::vk; use ash::vk;
use librashader_common::{ImageFormat, Size, Viewport}; use librashader_common::{ImageFormat, Size, Viewport};

View file

@ -8,6 +8,7 @@ use librashader_reflect::reflect::semantics::{TextureBinding, UboReflection};
use librashader_reflect::reflect::ShaderReflection; use librashader_reflect::reflect::ShaderReflection;
use librashader_runtime::render_target::RenderTarget; use librashader_runtime::render_target::RenderTarget;
use std::ffi::CStr; use std::ffi::CStr;
use std::sync::Arc;
const ENTRY_POINT: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(b"main\0") }; 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 layout: PipelineLayoutObjects,
pub pipeline: vk::Pipeline, pub pipeline: vk::Pipeline,
pub render_pass: Option<VulkanRenderPass>, pub render_pass: Option<VulkanRenderPass>,
device: Arc<ash::Device>,
vertex: VulkanShaderModule,
fragment: VulkanShaderModule,
cache: vk::PipelineCache,
} }
impl VulkanGraphicsPipeline { impl VulkanGraphicsPipeline {
pub fn new( fn create_pipeline(
device: &ash::Device, device: &ash::Device,
cache: &vk::PipelineCache, cache: &vk::PipelineCache,
shader_assembly: &ShaderCompilerOutput<Vec<u32>>, pipeline_layout: &PipelineLayoutObjects,
reflection: &ShaderReflection, vertex_module: &VulkanShaderModule,
replicas: u32, fragment_module: &VulkanShaderModule,
render_pass_format: vk::Format, render_pass: Option<&VulkanRenderPass>,
) -> error::Result<VulkanGraphicsPipeline> { ) -> error::Result<vk::Pipeline> {
let pipeline_layout = PipelineLayoutObjects::new(reflection, replicas, device)?;
let input_assembly = vk::PipelineInputAssemblyStateCreateInfo::builder() let input_assembly = vk::PipelineInputAssemblyStateCreateInfo::builder()
.topology(vk::PrimitiveTopology::TRIANGLE_STRIP) .topology(vk::PrimitiveTopology::TRIANGLE_STRIP)
.build(); .build();
@ -262,16 +265,6 @@ impl VulkanGraphicsPipeline {
.dynamic_states(&states) .dynamic_states(&states)
.build(); .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 = [ let shader_stages = [
vk::PipelineShaderStageCreateInfo::builder() vk::PipelineShaderStageCreateInfo::builder()
.stage(vk::ShaderStageFlags::VERTEX) .stage(vk::ShaderStageFlags::VERTEX)
@ -297,32 +290,93 @@ impl VulkanGraphicsPipeline {
.dynamic_state(&dynamic_state) .dynamic_state(&dynamic_state)
.layout(pipeline_layout.layout); .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<ash::Device>,
cache: &vk::PipelineCache,
shader_assembly: &ShaderCompilerOutput<Vec<u32>>,
reflection: &ShaderReflection,
replicas: u32,
render_pass_format: vk::Format,
) -> error::Result<VulkanGraphicsPipeline> {
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; let mut render_pass = None;
if render_pass_format != vk::Format::UNDEFINED { if render_pass_format != vk::Format::UNDEFINED {
render_pass = Some(VulkanRenderPass::create_render_pass( render_pass = Some(VulkanRenderPass::create_render_pass(
device, device,
render_pass_format, render_pass_format,
)?); )?);
pipeline_info = pipeline_info.render_pass(render_pass.as_ref().unwrap().handle)
} }
let pipeline_info = pipeline_info.build(); let pipeline = Self::create_pipeline(
&device,
let pipeline = unsafe { &cache,
// panic_safety: if this is successful this should return 1 pipelines. &pipeline_layout,
device &vertex_module,
.create_graphics_pipelines(*cache, &[pipeline_info], None) &fragment_module,
.map_err(|e| e.1) render_pass.as_ref(),
.unwrap()[0] )?;
};
Ok(VulkanGraphicsPipeline { Ok(VulkanGraphicsPipeline {
device: Arc::clone(device),
layout: pipeline_layout, layout: pipeline_layout,
pipeline, pipeline,
render_pass, 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)] #[inline(always)]
pub(crate) fn begin_rendering( pub(crate) fn begin_rendering(
&self, &self,

View file

@ -11,6 +11,7 @@ mod draw_quad;
mod filter_chain; mod filter_chain;
mod filter_pass; mod filter_pass;
mod framebuffer; mod framebuffer;
mod graphics_pipeline;
#[cfg(test)] #[cfg(test)]
mod hello_triangle; mod hello_triangle;
mod luts; mod luts;
@ -20,7 +21,6 @@ mod samplers;
mod texture; mod texture;
mod util; mod util;
mod vulkan_primitives; mod vulkan_primitives;
mod vulkan_state;
pub use filter_chain::FilterChainVulkan; pub use filter_chain::FilterChainVulkan;
pub use filter_chain::VulkanInstance; pub use filter_chain::VulkanInstance;
@ -41,7 +41,6 @@ mod tests {
fn triangle_vk() { fn triangle_vk() {
let entry = unsafe { ash::Entry::load().unwrap() }; let entry = unsafe { ash::Entry::load().unwrap() };
let base = VulkanBase::new(entry).unwrap(); let base = VulkanBase::new(entry).unwrap();
dbg!("finished");
let filter = FilterChainVulkan::load_from_path( let filter = FilterChainVulkan::load_from_path(
&base, &base,
// "../test/slang-shaders/crt/crt-royale.slangp", // "../test/slang-shaders/crt/crt-royale.slangp",
@ -50,7 +49,7 @@ mod tests {
Some(&FilterChainOptionsVulkan { Some(&FilterChainOptionsVulkan {
frames_in_flight: 3, frames_in_flight: 3,
force_no_mipmaps: false, force_no_mipmaps: false,
use_render_pass: false, use_render_pass: true,
}), }),
) )
.unwrap(); .unwrap();

View file

@ -3,6 +3,11 @@
#include <iostream> #include <iostream>
#include <filesystem> #include <filesystem>
#define LIBRA_RUNTIME_VULKAN
#define LIBRA_RUNTIME_OPENGL
#define LIBRA_RUNTIME_D3D11
#define LIBRA_RUNTIME_D3D12
#include "../../../../include/librashader_ld.h" #include "../../../../include/librashader_ld.h"
int main() int main()
@ -16,11 +21,11 @@ int main()
"gameboy-player-crt-royale.slangp", "gameboy-player-crt-royale.slangp",
&preset); &preset);
libra_shader_preset_t preset2; /* libra_shader_preset_t preset2;
libra_preset_create( libra_preset_create(
"../../../slang-shaders/border/gameboy-player/" "../../../slang-shaders/border/gameboy-player/"
"gameboy-player-crt-royale.slangp", "gameboy-player-crt-royale.slangp",
&preset2); &preset2);*/
instance.preset_print(&preset); instance.preset_print(&preset);
std::cout << "printed\n"; std::cout << "printed\n";

View file

@ -108,7 +108,7 @@
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
<TreatAngleIncludeAsExternal>false</TreatAngleIncludeAsExternal> <TreatAngleIncludeAsExternal>false</TreatAngleIncludeAsExternal>
<LanguageStandard>stdcpplatest</LanguageStandard> <LanguageStandard>stdcpp20</LanguageStandard>
<LanguageStandard_C>stdc17</LanguageStandard_C> <LanguageStandard_C>stdc17</LanguageStandard_C>
<AdditionalIncludeDirectories>D:\Runtime\Vulkan\1.3.224.1\Include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>D:\Runtime\Vulkan\1.3.224.1\Include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile> </ClCompile>
@ -128,6 +128,7 @@
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>D:\Runtime\Vulkan\1.3.224.1\Include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>D:\Runtime\Vulkan\1.3.224.1\Include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
@ -145,9 +146,6 @@
<ClInclude Include="..\..\..\..\include\librashader.h" /> <ClInclude Include="..\..\..\..\include\librashader.h" />
<ClInclude Include="..\..\..\..\include\librashader_ld.h" /> <ClInclude Include="..\..\..\..\include\librashader_ld.h" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Library Include="..\..\..\..\target\debug\librashader.lib" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">
</ImportGroup> </ImportGroup>

View file

@ -27,7 +27,4 @@
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Library Include="..\..\..\..\target\debug\librashader.lib" />
</ItemGroup>
</Project> </Project>