vk: create vulkan state for each shader
This commit is contained in:
parent
bf840d02e4
commit
6ce7af12e1
7 changed files with 388 additions and 195 deletions
|
@ -17,7 +17,7 @@ description = "RetroArch shaders for all."
|
||||||
librashader-common = { path = "../librashader-common", features = ["vulkan"], version = "0.1.0-alpha.4" }
|
librashader-common = { path = "../librashader-common", features = ["vulkan"], version = "0.1.0-alpha.4" }
|
||||||
librashader-presets = { path = "../librashader-presets", version = "0.1.0-alpha.4" }
|
librashader-presets = { path = "../librashader-presets", version = "0.1.0-alpha.4" }
|
||||||
librashader-preprocess = { path = "../librashader-preprocess", version = "0.1.0-alpha.4" }
|
librashader-preprocess = { path = "../librashader-preprocess", version = "0.1.0-alpha.4" }
|
||||||
librashader-reflect = { path = "../librashader-reflect", version = "0.1.0-alpha.4", features = ["standalone"] }
|
librashader-reflect = { path = "../librashader-reflect", version = "0.1.0-alpha.4", features = [] }
|
||||||
librashader-runtime = { path = "../librashader-runtime" , version = "0.1.0-alpha.4" }
|
librashader-runtime = { path = "../librashader-runtime" , version = "0.1.0-alpha.4" }
|
||||||
spirv_cross = "0.23.1"
|
spirv_cross = "0.23.1"
|
||||||
rustc-hash = "1.1.0"
|
rustc-hash = "1.1.0"
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
use std::ffi::CStr;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use ash::vk;
|
use ash::vk;
|
||||||
use ash::vk::{PFN_vkGetInstanceProcAddr, PrimitiveTopology, PushConstantRange, StaticFn};
|
use ash::vk::{ColorComponentFlags, PFN_vkGetInstanceProcAddr, StaticFn};
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
|
use librashader_common::ImageFormat;
|
||||||
use librashader_preprocess::ShaderSource;
|
use librashader_preprocess::ShaderSource;
|
||||||
use librashader_presets::{ShaderPassConfig, ShaderPreset, TextureConfig};
|
use librashader_presets::{ShaderPassConfig, ShaderPreset, TextureConfig};
|
||||||
use librashader_reflect::back::{CompilerBackend, CompileShader, FromCompilation};
|
use librashader_reflect::back::{CompilerBackend, CompileShader, FromCompilation};
|
||||||
|
@ -11,9 +13,10 @@ use librashader_reflect::front::shaderc::GlslangCompilation;
|
||||||
use librashader_reflect::reflect::ReflectShader;
|
use librashader_reflect::reflect::ReflectShader;
|
||||||
use librashader_reflect::reflect::semantics::{Semantic, ShaderSemantics, TextureSemantics, UniformBinding, UniformSemantic, UniqueSemantics};
|
use librashader_reflect::reflect::semantics::{Semantic, ShaderSemantics, TextureSemantics, UniformBinding, UniformSemantic, UniqueSemantics};
|
||||||
use librashader_runtime::uniforms::UniformStorage;
|
use librashader_runtime::uniforms::UniformStorage;
|
||||||
use crate::{error, util};
|
use crate::error;
|
||||||
use crate::filter_pass::{FilterPass, PipelineDescriptors, PipelineObjects};
|
use crate::filter_pass::FilterPass;
|
||||||
use crate::framebuffer::Framebuffer;
|
use crate::framebuffer::{Framebuffer, VulkanRenderPass};
|
||||||
|
use crate::vulkan_state::{PipelineLayoutObjects, VulkanGraphicsPipeline};
|
||||||
|
|
||||||
pub struct Vulkan {
|
pub struct Vulkan {
|
||||||
physical_device: vk::PhysicalDevice,
|
physical_device: vk::PhysicalDevice,
|
||||||
|
@ -43,6 +46,17 @@ pub struct VulkanInfo<'a> {
|
||||||
get_instance_proc_addr: PFN_vkGetInstanceProcAddr
|
get_instance_proc_addr: PFN_vkGetInstanceProcAddr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<VulkanInfo<'_>> for ash::Device {
|
||||||
|
fn from(vulkan: VulkanInfo) -> Self {
|
||||||
|
unsafe {
|
||||||
|
let instance = ash::Instance::load(&StaticFn {
|
||||||
|
get_instance_proc_addr: vulkan.get_instance_proc_addr,
|
||||||
|
}, vulkan.instance.clone());
|
||||||
|
ash::Device::load(instance.fp_v1_0(), vulkan.device.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct FilterChainVulkan {
|
pub struct FilterChainVulkan {
|
||||||
pub(crate) common: FilterCommon,
|
pub(crate) common: FilterCommon,
|
||||||
pub(crate) passes: Vec<FilterPass>,
|
pub(crate) passes: Vec<FilterPass>,
|
||||||
|
@ -66,7 +80,7 @@ pub type FilterChainOptionsVulkan = ();
|
||||||
impl FilterChainVulkan {
|
impl FilterChainVulkan {
|
||||||
/// Load the shader preset at the given path into a filter chain.
|
/// Load the shader preset at the given path into a filter chain.
|
||||||
pub fn load_from_path(
|
pub fn load_from_path(
|
||||||
vulkan: VulkanInfo,
|
vulkan: impl Into<ash::Device>,
|
||||||
path: impl AsRef<Path>,
|
path: impl AsRef<Path>,
|
||||||
options: Option<&FilterChainOptionsVulkan>,
|
options: Option<&FilterChainOptionsVulkan>,
|
||||||
) -> error::Result<FilterChainVulkan> {
|
) -> error::Result<FilterChainVulkan> {
|
||||||
|
@ -76,21 +90,16 @@ impl FilterChainVulkan {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_from_preset(
|
pub fn load_from_preset(
|
||||||
vulkan: VulkanInfo,
|
vulkan: impl Into<ash::Device>,
|
||||||
preset: ShaderPreset,
|
preset: ShaderPreset,
|
||||||
options: Option<&FilterChainOptionsVulkan>,
|
options: Option<&FilterChainOptionsVulkan>,
|
||||||
) -> error::Result<FilterChainVulkan> {
|
) -> error::Result<FilterChainVulkan> {
|
||||||
let (passes, semantics) = FilterChainVulkan::load_preset(preset.shaders, &preset.textures)?;
|
let (passes, semantics) = FilterChainVulkan::load_preset(preset.shaders, &preset.textures)?;
|
||||||
|
let device = vulkan.into();
|
||||||
|
|
||||||
unsafe {
|
// initialize passes
|
||||||
let instance = ash::Instance::load(&StaticFn {
|
let filters = Self::init_passes(&device, passes, &semantics, 3)?;
|
||||||
get_instance_proc_addr: vulkan.get_instance_proc_addr,
|
eprintln!("filters initialized ok.");
|
||||||
}, vulkan.instance.clone());
|
|
||||||
|
|
||||||
let device = ash::Device::load(instance.fp_v1_0(), vulkan.device.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
todo!();
|
todo!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,14 +163,16 @@ impl FilterChainVulkan {
|
||||||
) -> error::Result<Box<[FilterPass]>> {
|
) -> error::Result<Box<[FilterPass]>> {
|
||||||
let mut filters = Vec::new();
|
let mut filters = Vec::new();
|
||||||
|
|
||||||
|
let pipeline_cache = unsafe {
|
||||||
|
device.create_pipeline_cache(&vk::PipelineCacheCreateInfo::default(),
|
||||||
|
None)?
|
||||||
|
};
|
||||||
|
|
||||||
// initialize passes
|
// initialize passes
|
||||||
for (index, (config, source, mut reflect)) in passes.into_iter().enumerate() {
|
for (index, (config, mut source, mut reflect)) in passes.into_iter().enumerate() {
|
||||||
let reflection = reflect.reflect(index, semantics)?;
|
let reflection = reflect.reflect(index, semantics)?;
|
||||||
let spirv_words = reflect.compile(None)?;
|
let spirv_words = reflect.compile(None)?;
|
||||||
|
|
||||||
// todo: make framebuffers:
|
|
||||||
// shader_vulkan: 2280
|
|
||||||
|
|
||||||
let uniform_storage = UniformStorage::new(
|
let uniform_storage = UniformStorage::new(
|
||||||
reflection
|
reflection
|
||||||
.ubo
|
.ubo
|
||||||
|
@ -189,34 +200,28 @@ impl FilterChainVulkan {
|
||||||
uniform_bindings.insert(UniformBinding::TextureSize(*semantics), param.offset);
|
uniform_bindings.insert(UniformBinding::TextureSize(*semantics), param.offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
// shader_vulkan 1927 (pipeline_layout)
|
// default to something sane
|
||||||
let pipeline_objects = PipelineObjects::new(&reflection, images, device)?;
|
if source.format == ImageFormat::Unknown {
|
||||||
|
source.format = ImageFormat::R8G8B8A8Unorm
|
||||||
|
}
|
||||||
|
|
||||||
let ia = vk::PipelineInputAssemblyStateCreateInfo::builder()
|
let graphics_pipeline = VulkanGraphicsPipeline::new(device,
|
||||||
.topology(PrimitiveTopology::TRIANGLE_STRIP);
|
&pipeline_cache,
|
||||||
let vao_attrs = [vk::VertexInputAttributeDescription {
|
&spirv_words, &reflection, source.format, images)
|
||||||
location: 0,
|
.unwrap();
|
||||||
binding: 0,
|
|
||||||
format: vk::Format::R32G32_SFLOAT,
|
|
||||||
offset: 0,
|
|
||||||
}, vk::VertexInputAttributeDescription {
|
|
||||||
location: 1,
|
|
||||||
binding: 0,
|
|
||||||
format: vk::Format::R32G32_SFLOAT,
|
|
||||||
offset: (2 * std::mem::size_of::<f32>()) as u32,
|
|
||||||
}];
|
|
||||||
|
|
||||||
// shader_vulkan: 2026
|
// shader_vulkan: 2026
|
||||||
|
|
||||||
filters.push(FilterPass {
|
filters.push(FilterPass {
|
||||||
compiled: spirv_words,
|
compiled: spirv_words,
|
||||||
uniform_storage,
|
uniform_storage,
|
||||||
uniform_bindings,
|
uniform_bindings,
|
||||||
source,
|
source,
|
||||||
config,
|
config,
|
||||||
|
graphics_pipeline
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
todo!();
|
|
||||||
|
Ok(filters.into_boxed_slice())
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,11 +2,9 @@ use rustc_hash::FxHashMap;
|
||||||
use librashader_preprocess::ShaderSource;
|
use librashader_preprocess::ShaderSource;
|
||||||
use librashader_presets::ShaderPassConfig;
|
use librashader_presets::ShaderPassConfig;
|
||||||
use librashader_reflect::back::ShaderCompilerOutput;
|
use librashader_reflect::back::ShaderCompilerOutput;
|
||||||
use librashader_reflect::reflect::semantics::{BindingStage, MemberOffset, TextureBinding, UboReflection, UniformBinding};
|
use librashader_reflect::reflect::semantics::{MemberOffset, UniformBinding};
|
||||||
use librashader_runtime::uniforms::UniformStorage;
|
use librashader_runtime::uniforms::UniformStorage;
|
||||||
use ash::vk;
|
use crate::vulkan_state::VulkanGraphicsPipeline;
|
||||||
use librashader_reflect::reflect::ShaderReflection;
|
|
||||||
use crate::{error, util};
|
|
||||||
|
|
||||||
pub struct FilterPass {
|
pub struct FilterPass {
|
||||||
pub(crate) compiled: ShaderCompilerOutput<Vec<u32>>,
|
pub(crate) compiled: ShaderCompilerOutput<Vec<u32>>,
|
||||||
|
@ -14,141 +12,5 @@ pub struct FilterPass {
|
||||||
pub uniform_bindings: FxHashMap<UniformBinding, MemberOffset>,
|
pub uniform_bindings: FxHashMap<UniformBinding, MemberOffset>,
|
||||||
pub source: ShaderSource,
|
pub source: ShaderSource,
|
||||||
pub config: ShaderPassConfig,
|
pub config: ShaderPassConfig,
|
||||||
}
|
pub graphics_pipeline: VulkanGraphicsPipeline,
|
||||||
|
|
||||||
pub struct PipelineDescriptors {
|
|
||||||
pub replicas: u32,
|
|
||||||
pub layout_bindings: Vec<vk::DescriptorSetLayoutBinding>,
|
|
||||||
pub pool_sizes: Vec<vk::DescriptorPoolSize>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PipelineDescriptors {
|
|
||||||
pub fn new(duplicates: u32) -> Self {
|
|
||||||
Self {
|
|
||||||
replicas: duplicates,
|
|
||||||
layout_bindings: vec![],
|
|
||||||
pool_sizes: vec![],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_ubo_binding(&mut self, ubo_meta: Option<&UboReflection>) {
|
|
||||||
if let Some(ubo_meta) = ubo_meta && !ubo_meta.stage_mask.is_empty() {
|
|
||||||
let mut ubo_mask = util::binding_stage_to_vulkan_stage(ubo_meta.stage_mask);
|
|
||||||
|
|
||||||
self.layout_bindings.push(vk::DescriptorSetLayoutBinding {
|
|
||||||
binding: ubo_meta.binding,
|
|
||||||
descriptor_type: vk::DescriptorType::UNIFORM_BUFFER,
|
|
||||||
descriptor_count: 1,
|
|
||||||
stage_flags: ubo_mask,
|
|
||||||
p_immutable_samplers: std::ptr::null(),
|
|
||||||
});
|
|
||||||
|
|
||||||
self.pool_sizes.push(vk::DescriptorPoolSize {
|
|
||||||
ty: vk::DescriptorType::UNIFORM_BUFFER,
|
|
||||||
descriptor_count: self.replicas,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_texture_bindings<'a>(&mut self, textures: impl Iterator<Item = &'a TextureBinding>) {
|
|
||||||
let mut texture_mask = vk::ShaderStageFlags::FRAGMENT;
|
|
||||||
for texture in textures {
|
|
||||||
self.layout_bindings.push(vk::DescriptorSetLayoutBinding {
|
|
||||||
binding: texture.binding,
|
|
||||||
descriptor_type: vk::DescriptorType::COMBINED_IMAGE_SAMPLER,
|
|
||||||
descriptor_count: 1,
|
|
||||||
stage_flags: texture_mask,
|
|
||||||
p_immutable_samplers: std::ptr::null(),
|
|
||||||
});
|
|
||||||
|
|
||||||
self.pool_sizes.push(vk::DescriptorPoolSize {
|
|
||||||
ty: vk::DescriptorType::COMBINED_IMAGE_SAMPLER,
|
|
||||||
descriptor_count: self.replicas,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn binding_count(&self) -> usize {
|
|
||||||
self.layout_bindings.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn bindings(&self) -> &[vk::DescriptorSetLayoutBinding] {
|
|
||||||
self.layout_bindings.as_ref()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_descriptor_set_layout(&self, device: &ash::Device) -> error::Result<vk::DescriptorSetLayout> {
|
|
||||||
unsafe {
|
|
||||||
let layout = device.create_descriptor_set_layout(
|
|
||||||
&vk::DescriptorSetLayoutCreateInfo::builder()
|
|
||||||
.bindings(self.bindings())
|
|
||||||
.build(),
|
|
||||||
None)?;
|
|
||||||
Ok(layout)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct PipelineObjects {
|
|
||||||
pub layout: vk::PipelineLayout,
|
|
||||||
pub pool: vk::DescriptorPool,
|
|
||||||
pub descriptor_sets: Vec<vk::DescriptorSet>,
|
|
||||||
pub descriptor_set_layout: [vk::DescriptorSetLayout;1],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PipelineObjects {
|
|
||||||
pub fn new(reflection: &ShaderReflection, replicas: u32, device: &ash::Device) -> error::Result<Self> {
|
|
||||||
let mut descriptors = PipelineDescriptors::new(replicas);
|
|
||||||
descriptors.add_ubo_binding(reflection.ubo.as_ref());
|
|
||||||
descriptors.add_texture_bindings(reflection.meta.texture_meta.values());
|
|
||||||
|
|
||||||
let mut descriptor_set_layout = [descriptors.create_descriptor_set_layout(device)?];
|
|
||||||
|
|
||||||
let mut pipeline_create_info = vk::PipelineLayoutCreateInfo::builder()
|
|
||||||
.set_layouts(&descriptor_set_layout);
|
|
||||||
|
|
||||||
let pipeline_create_info = if let Some(push_constant) = &reflection.push_constant {
|
|
||||||
let mut stage_mask = util::binding_stage_to_vulkan_stage(push_constant.stage_mask);
|
|
||||||
let push_constant_range = [
|
|
||||||
vk::PushConstantRange::builder()
|
|
||||||
.stage_flags(stage_mask)
|
|
||||||
.size(push_constant.size)
|
|
||||||
.build()
|
|
||||||
];
|
|
||||||
pipeline_create_info.push_constant_ranges(&push_constant_range).build()
|
|
||||||
} else {
|
|
||||||
pipeline_create_info.build()
|
|
||||||
};
|
|
||||||
|
|
||||||
let layout = unsafe {
|
|
||||||
device.create_pipeline_layout(&pipeline_create_info, None)?
|
|
||||||
};
|
|
||||||
|
|
||||||
let pool = unsafe {
|
|
||||||
device.create_descriptor_pool(&vk::DescriptorPoolCreateInfo::builder()
|
|
||||||
.max_sets(replicas)
|
|
||||||
.pool_sizes(&descriptors.pool_sizes)
|
|
||||||
.build(), None)?
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut descriptor_sets = Vec::new();
|
|
||||||
let alloc_info = vk::DescriptorSetAllocateInfo::builder()
|
|
||||||
.descriptor_pool(pool)
|
|
||||||
.set_layouts(&descriptor_set_layout)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
for _ in 0..replicas {
|
|
||||||
unsafe {
|
|
||||||
descriptor_sets.push(device.allocate_descriptor_sets(&alloc_info)?)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let descriptor_sets: Vec<vk::DescriptorSet> = descriptor_sets.into_iter().flatten().collect();
|
|
||||||
|
|
||||||
return Ok(PipelineObjects {
|
|
||||||
layout,
|
|
||||||
descriptor_set_layout,
|
|
||||||
descriptor_sets,
|
|
||||||
pool,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,10 +8,9 @@ use crate::util::find_vulkan_memory_type;
|
||||||
pub struct Framebuffer {
|
pub struct Framebuffer {
|
||||||
device: ash::Device,
|
device: ash::Device,
|
||||||
size: Size<u32>,
|
size: Size<u32>,
|
||||||
format: ImageFormat,
|
|
||||||
max_levels: u32,
|
max_levels: u32,
|
||||||
mem_props: vk::PhysicalDeviceMemoryProperties,
|
mem_props: vk::PhysicalDeviceMemoryProperties,
|
||||||
render_pass: vk::RenderPass,
|
render_pass: VulkanRenderPass,
|
||||||
framebuffer: Option<VulkanFramebuffer>
|
framebuffer: Option<VulkanFramebuffer>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,11 +72,21 @@ impl Drop for VulkanFramebuffer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Framebuffer {
|
pub struct VulkanRenderPass {
|
||||||
pub fn create_render_pass(device: &ash::Device, format: vk::Format) -> error::Result<vk::RenderPass> {
|
pub render_pass: vk::RenderPass,
|
||||||
|
format: ImageFormat
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VulkanRenderPass {
|
||||||
|
pub fn create_render_pass(device: &ash::Device, mut format: ImageFormat) -> error::Result<Self> {
|
||||||
|
// default to reasonable choice if unknown
|
||||||
|
if format == ImageFormat::Unknown {
|
||||||
|
format = ImageFormat::R8G8B8A8Unorm;
|
||||||
|
}
|
||||||
|
|
||||||
let attachment = vk::AttachmentDescription::builder()
|
let attachment = vk::AttachmentDescription::builder()
|
||||||
.flags(vk::AttachmentDescriptionFlags::empty())
|
.flags(vk::AttachmentDescriptionFlags::empty())
|
||||||
.format(format)
|
.format(format.into())
|
||||||
.samples(SampleCountFlags::TYPE_1)
|
.samples(SampleCountFlags::TYPE_1)
|
||||||
.load_op(AttachmentLoadOp::DONT_CARE)
|
.load_op(AttachmentLoadOp::DONT_CARE)
|
||||||
.store_op(AttachmentStoreOp::STORE)
|
.store_op(AttachmentStoreOp::STORE)
|
||||||
|
@ -104,18 +113,23 @@ impl Framebuffer {
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
Ok(device.create_render_pass(&renderpass_info, None)?)
|
let rp = device.create_render_pass(&renderpass_info, None)?;
|
||||||
|
Ok(Self {
|
||||||
|
render_pass: rp,
|
||||||
|
format
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(device: &ash::Device, size: Size<u32>, format: ImageFormat, mip_levels: u32, mem_props: vk::PhysicalDeviceMemoryProperties) -> error::Result<Self> {
|
impl Framebuffer {
|
||||||
|
pub fn new(device: &ash::Device, size: Size<u32>, render_pass: VulkanRenderPass, mip_levels: u32, mem_props: vk::PhysicalDeviceMemoryProperties) -> error::Result<Self> {
|
||||||
let mut framebuffer = Framebuffer {
|
let mut framebuffer = Framebuffer {
|
||||||
device: device.clone(),
|
device: device.clone(),
|
||||||
size,
|
size,
|
||||||
format,
|
|
||||||
max_levels: mip_levels,
|
max_levels: mip_levels,
|
||||||
mem_props,
|
mem_props,
|
||||||
render_pass: Framebuffer::create_render_pass(device, format.into())?,
|
render_pass,
|
||||||
framebuffer: None
|
framebuffer: None
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -128,7 +142,7 @@ impl Framebuffer {
|
||||||
pub fn create_vulkan_image(&mut self) -> error::Result<VulkanFramebuffer> {
|
pub fn create_vulkan_image(&mut self) -> error::Result<VulkanFramebuffer> {
|
||||||
let image_create_info = vk::ImageCreateInfo::builder()
|
let image_create_info = vk::ImageCreateInfo::builder()
|
||||||
.image_type(ImageType::TYPE_2D)
|
.image_type(ImageType::TYPE_2D)
|
||||||
.format(self.format.into())
|
.format(self.render_pass.format.into())
|
||||||
.extent(Extent3D {
|
.extent(Extent3D {
|
||||||
width: self.size.width,
|
width: self.size.width,
|
||||||
height: self.size.height,
|
height: self.size.height,
|
||||||
|
@ -171,7 +185,7 @@ impl Framebuffer {
|
||||||
|
|
||||||
let mut view_info = vk::ImageViewCreateInfo::builder()
|
let mut view_info = vk::ImageViewCreateInfo::builder()
|
||||||
.view_type(ImageViewType::TYPE_2D)
|
.view_type(ImageViewType::TYPE_2D)
|
||||||
.format(self.format.into())
|
.format(self.render_pass.format.into())
|
||||||
.image(image.clone())
|
.image(image.clone())
|
||||||
.subresource_range(image_subresource)
|
.subresource_range(image_subresource)
|
||||||
.components(swizzle_components)
|
.components(swizzle_components)
|
||||||
|
@ -188,7 +202,7 @@ impl Framebuffer {
|
||||||
|
|
||||||
let framebuffer = unsafe {
|
let framebuffer = unsafe {
|
||||||
self.device.create_framebuffer(&vk::FramebufferCreateInfo::builder()
|
self.device.create_framebuffer(&vk::FramebufferCreateInfo::builder()
|
||||||
.render_pass(self.render_pass)
|
.render_pass(self.render_pass.render_pass)
|
||||||
.attachments(&[image_view])
|
.attachments(&[image_view])
|
||||||
.width(self.size.width)
|
.width(self.size.width)
|
||||||
.height(self.size.height)
|
.height(self.size.height)
|
||||||
|
|
|
@ -8,7 +8,7 @@ use std::mem::align_of;
|
||||||
use crate::offset_of;
|
use crate::offset_of;
|
||||||
|
|
||||||
mod base;
|
mod base;
|
||||||
use base::*;
|
pub use base::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Copy)]
|
#[derive(Clone, Debug, Copy)]
|
||||||
struct Vertex {
|
struct Vertex {
|
||||||
|
@ -16,9 +16,8 @@ struct Vertex {
|
||||||
color: [f32; 4],
|
color: [f32; 4],
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn main() {
|
pub(crate) fn main(base: ExampleBase) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let base = ExampleBase::new(900, 600);
|
|
||||||
let renderpass_attachments = [
|
let renderpass_attachments = [
|
||||||
vk::AttachmentDescription {
|
vk::AttachmentDescription {
|
||||||
format: base.surface_format.format,
|
format: base.surface_format.format,
|
||||||
|
|
|
@ -7,12 +7,22 @@ mod filter_pass;
|
||||||
mod error;
|
mod error;
|
||||||
mod util;
|
mod util;
|
||||||
mod framebuffer;
|
mod framebuffer;
|
||||||
|
mod vulkan_state;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use crate::filter_chain::FilterChainVulkan;
|
||||||
use super::*;
|
use super::*;
|
||||||
#[test]
|
#[test]
|
||||||
fn triangle_vk() {
|
fn triangle_vk() {
|
||||||
hello_triangle::main();
|
let base = hello_triangle::ExampleBase::new(900, 600);
|
||||||
|
let mut filter = FilterChainVulkan::load_from_path(
|
||||||
|
base.device.clone(),
|
||||||
|
"../test/slang-shaders/border/gameboy-player/gameboy-player-crt-royale.slangp",
|
||||||
|
None
|
||||||
|
)
|
||||||
|
// FilterChain::load_from_path("../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp", None)
|
||||||
|
.unwrap();
|
||||||
|
hello_triangle::main(base);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
303
librashader-runtime-vk/src/vulkan_state.rs
Normal file
303
librashader-runtime-vk/src/vulkan_state.rs
Normal file
|
@ -0,0 +1,303 @@
|
||||||
|
use std::ffi::CStr;
|
||||||
|
use ash::vk;
|
||||||
|
use librashader_common::ImageFormat;
|
||||||
|
use librashader_reflect::back::ShaderCompilerOutput;
|
||||||
|
use librashader_reflect::reflect::semantics::{TextureBinding, UboReflection};
|
||||||
|
use librashader_reflect::reflect::ShaderReflection;
|
||||||
|
use crate::{error, util};
|
||||||
|
use crate::framebuffer::VulkanRenderPass;
|
||||||
|
|
||||||
|
pub struct PipelineDescriptors {
|
||||||
|
pub replicas: u32,
|
||||||
|
pub layout_bindings: Vec<vk::DescriptorSetLayoutBinding>,
|
||||||
|
pub pool_sizes: Vec<vk::DescriptorPoolSize>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PipelineDescriptors {
|
||||||
|
pub fn new(duplicates: u32) -> Self {
|
||||||
|
Self {
|
||||||
|
replicas: duplicates,
|
||||||
|
layout_bindings: vec![],
|
||||||
|
pool_sizes: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_ubo_binding(&mut self, ubo_meta: Option<&UboReflection>) {
|
||||||
|
if let Some(ubo_meta) = ubo_meta && !ubo_meta.stage_mask.is_empty() {
|
||||||
|
let mut ubo_mask = util::binding_stage_to_vulkan_stage(ubo_meta.stage_mask);
|
||||||
|
|
||||||
|
self.layout_bindings.push(vk::DescriptorSetLayoutBinding {
|
||||||
|
binding: ubo_meta.binding,
|
||||||
|
descriptor_type: vk::DescriptorType::UNIFORM_BUFFER,
|
||||||
|
descriptor_count: 1,
|
||||||
|
stage_flags: ubo_mask,
|
||||||
|
p_immutable_samplers: std::ptr::null(),
|
||||||
|
});
|
||||||
|
|
||||||
|
self.pool_sizes.push(vk::DescriptorPoolSize {
|
||||||
|
ty: vk::DescriptorType::UNIFORM_BUFFER,
|
||||||
|
descriptor_count: self.replicas,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_texture_bindings<'a>(&mut self, textures: impl Iterator<Item = &'a TextureBinding>) {
|
||||||
|
let mut texture_mask = vk::ShaderStageFlags::FRAGMENT;
|
||||||
|
for texture in textures {
|
||||||
|
self.layout_bindings.push(vk::DescriptorSetLayoutBinding {
|
||||||
|
binding: texture.binding,
|
||||||
|
descriptor_type: vk::DescriptorType::COMBINED_IMAGE_SAMPLER,
|
||||||
|
descriptor_count: 1,
|
||||||
|
stage_flags: texture_mask,
|
||||||
|
p_immutable_samplers: std::ptr::null(),
|
||||||
|
});
|
||||||
|
|
||||||
|
self.pool_sizes.push(vk::DescriptorPoolSize {
|
||||||
|
ty: vk::DescriptorType::COMBINED_IMAGE_SAMPLER,
|
||||||
|
descriptor_count: self.replicas,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn binding_count(&self) -> usize {
|
||||||
|
self.layout_bindings.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bindings(&self) -> &[vk::DescriptorSetLayoutBinding] {
|
||||||
|
self.layout_bindings.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_descriptor_set_layout(&self, device: &ash::Device) -> error::Result<vk::DescriptorSetLayout> {
|
||||||
|
unsafe {
|
||||||
|
let layout = device.create_descriptor_set_layout(
|
||||||
|
&vk::DescriptorSetLayoutCreateInfo::builder()
|
||||||
|
.bindings(self.bindings())
|
||||||
|
.build(),
|
||||||
|
None)?;
|
||||||
|
Ok(layout)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PipelineLayoutObjects {
|
||||||
|
pub layout: vk::PipelineLayout,
|
||||||
|
pub pool: vk::DescriptorPool,
|
||||||
|
pub descriptor_sets: Vec<vk::DescriptorSet>,
|
||||||
|
pub descriptor_set_layout: [vk::DescriptorSetLayout; 1],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PipelineLayoutObjects {
|
||||||
|
pub fn new(reflection: &ShaderReflection, replicas: u32, device: &ash::Device) -> error::Result<Self> {
|
||||||
|
let mut descriptors = PipelineDescriptors::new(replicas);
|
||||||
|
descriptors.add_ubo_binding(reflection.ubo.as_ref());
|
||||||
|
descriptors.add_texture_bindings(reflection.meta.texture_meta.values());
|
||||||
|
|
||||||
|
let mut descriptor_set_layout = [descriptors.create_descriptor_set_layout(device)?];
|
||||||
|
|
||||||
|
let mut pipeline_create_info = vk::PipelineLayoutCreateInfo::builder()
|
||||||
|
.set_layouts(&descriptor_set_layout);
|
||||||
|
|
||||||
|
let pipeline_create_info = if let Some(push_constant) = &reflection.push_constant {
|
||||||
|
let mut stage_mask = util::binding_stage_to_vulkan_stage(push_constant.stage_mask);
|
||||||
|
let push_constant_range = [
|
||||||
|
vk::PushConstantRange::builder()
|
||||||
|
.stage_flags(stage_mask)
|
||||||
|
.size(push_constant.size)
|
||||||
|
.build()
|
||||||
|
];
|
||||||
|
pipeline_create_info.push_constant_ranges(&push_constant_range).build()
|
||||||
|
} else {
|
||||||
|
pipeline_create_info.build()
|
||||||
|
};
|
||||||
|
|
||||||
|
let layout = unsafe {
|
||||||
|
device.create_pipeline_layout(&pipeline_create_info, None)?
|
||||||
|
};
|
||||||
|
|
||||||
|
let pool = unsafe {
|
||||||
|
device.create_descriptor_pool(&vk::DescriptorPoolCreateInfo::builder()
|
||||||
|
.max_sets(replicas)
|
||||||
|
.pool_sizes(&descriptors.pool_sizes)
|
||||||
|
.build(), None)?
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut descriptor_sets = Vec::new();
|
||||||
|
let alloc_info = vk::DescriptorSetAllocateInfo::builder()
|
||||||
|
.descriptor_pool(pool)
|
||||||
|
.set_layouts(&descriptor_set_layout)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
for _ in 0..replicas {
|
||||||
|
unsafe {
|
||||||
|
descriptor_sets.push(device.allocate_descriptor_sets(&alloc_info)?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let descriptor_sets: Vec<vk::DescriptorSet> = descriptor_sets.into_iter().flatten().collect();
|
||||||
|
|
||||||
|
return Ok(PipelineLayoutObjects {
|
||||||
|
layout,
|
||||||
|
descriptor_set_layout,
|
||||||
|
descriptor_sets,
|
||||||
|
pool,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct VulkanShaderModule {
|
||||||
|
shader: vk::ShaderModule,
|
||||||
|
device: ash::Device,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VulkanShaderModule {
|
||||||
|
pub fn new(device: &ash::Device, info: &vk::ShaderModuleCreateInfo) -> error::Result<VulkanShaderModule> {
|
||||||
|
Ok(VulkanShaderModule {
|
||||||
|
shader: unsafe { device.create_shader_module(info, None)? },
|
||||||
|
device: device.clone()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for VulkanShaderModule {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
self.device.destroy_shader_module(self.shader, None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct VulkanGraphicsPipeline {
|
||||||
|
layout: PipelineLayoutObjects,
|
||||||
|
render_pass: VulkanRenderPass,
|
||||||
|
pipeline: vk::Pipeline
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VulkanGraphicsPipeline {
|
||||||
|
pub fn new(device: &ash::Device, cache: &vk::PipelineCache, shader_assembly: &ShaderCompilerOutput<Vec<u32>>, reflection: &ShaderReflection, mut format: ImageFormat, replicas: u32) -> error::Result<VulkanGraphicsPipeline> {
|
||||||
|
// default to something sane
|
||||||
|
if format == ImageFormat::Unknown {
|
||||||
|
format = ImageFormat::R8G8B8A8Unorm
|
||||||
|
}
|
||||||
|
|
||||||
|
// shader_vulkan 1927 (init_pipeline_layout)
|
||||||
|
let pipeline_layout = PipelineLayoutObjects::new(&reflection, replicas, device)?;
|
||||||
|
|
||||||
|
let input_assembly = vk::PipelineInputAssemblyStateCreateInfo::builder()
|
||||||
|
.topology(vk::PrimitiveTopology::TRIANGLE_STRIP)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let vao_state = [vk::VertexInputAttributeDescription {
|
||||||
|
location: 0,
|
||||||
|
binding: 0,
|
||||||
|
format: vk::Format::R32G32_SFLOAT,
|
||||||
|
offset: 0,
|
||||||
|
}, vk::VertexInputAttributeDescription {
|
||||||
|
location: 1,
|
||||||
|
binding: 0,
|
||||||
|
format: vk::Format::R32G32_SFLOAT,
|
||||||
|
offset: (2 * std::mem::size_of::<f32>()) as u32,
|
||||||
|
}];
|
||||||
|
|
||||||
|
let input_binding = vk::VertexInputBindingDescription::builder()
|
||||||
|
.binding(0)
|
||||||
|
.stride(4 * std::mem::size_of::<f32>() as u32)
|
||||||
|
.input_rate(vk::VertexInputRate::VERTEX)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let pipeline_input_state = vk::PipelineVertexInputStateCreateInfo::builder()
|
||||||
|
.vertex_binding_descriptions(&[input_binding])
|
||||||
|
.vertex_attribute_descriptions(&vao_state)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let raster_state = vk::PipelineRasterizationStateCreateInfo::builder()
|
||||||
|
.polygon_mode(vk::PolygonMode::FILL)
|
||||||
|
.cull_mode(vk::CullModeFlags::NONE)
|
||||||
|
.front_face(vk::FrontFace::COUNTER_CLOCKWISE)
|
||||||
|
.depth_clamp_enable(false)
|
||||||
|
.rasterizer_discard_enable(false)
|
||||||
|
.depth_bias_enable(false)
|
||||||
|
.line_width(1.0)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let blend_state = vk::PipelineColorBlendStateCreateInfo::builder()
|
||||||
|
.attachments(&[vk::PipelineColorBlendAttachmentState::builder()
|
||||||
|
.blend_enable(false)
|
||||||
|
.color_write_mask(vk::ColorComponentFlags::from_raw(0xf))
|
||||||
|
.build()])
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let viewport_state = vk::PipelineViewportStateCreateInfo::builder()
|
||||||
|
.viewport_count(1)
|
||||||
|
.scissor_count(1)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let depth_stencil_state = vk::PipelineDepthStencilStateCreateInfo::builder()
|
||||||
|
.depth_test_enable(false)
|
||||||
|
.depth_write_enable(false)
|
||||||
|
.stencil_test_enable(false)
|
||||||
|
.depth_bounds_test_enable(false)
|
||||||
|
.min_depth_bounds(1.0)
|
||||||
|
.max_depth_bounds(1.0)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let multisample_state = vk::PipelineMultisampleStateCreateInfo::builder()
|
||||||
|
.rasterization_samples(vk::SampleCountFlags::TYPE_1)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let dynamic_state = vk::PipelineDynamicStateCreateInfo::builder()
|
||||||
|
.dynamic_states(&[vk::DynamicState::VIEWPORT, vk::DynamicState::SCISSOR])
|
||||||
|
.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)
|
||||||
|
.name(unsafe { CStr::from_bytes_with_nul_unchecked(b"main\0") })
|
||||||
|
.module(vertex_module.shader.clone())
|
||||||
|
.build(),
|
||||||
|
vk::PipelineShaderStageCreateInfo::builder()
|
||||||
|
.stage(vk::ShaderStageFlags::FRAGMENT)
|
||||||
|
.name(unsafe { CStr::from_bytes_with_nul_unchecked(b"main\0") })
|
||||||
|
.module(fragment_module.shader.clone())
|
||||||
|
.build(),
|
||||||
|
];
|
||||||
|
|
||||||
|
let render_pass = VulkanRenderPass::create_render_pass(device, format).unwrap();
|
||||||
|
|
||||||
|
let pipeline_info = vk::GraphicsPipelineCreateInfo::builder()
|
||||||
|
.stages(&shader_stages)
|
||||||
|
.vertex_input_state(&pipeline_input_state)
|
||||||
|
.input_assembly_state(&input_assembly)
|
||||||
|
.rasterization_state(&raster_state)
|
||||||
|
.color_blend_state(&blend_state)
|
||||||
|
.multisample_state(&multisample_state)
|
||||||
|
.viewport_state(&viewport_state)
|
||||||
|
.depth_stencil_state(&depth_stencil_state)
|
||||||
|
.dynamic_state(&dynamic_state)
|
||||||
|
.render_pass(render_pass.render_pass.clone())
|
||||||
|
.layout(pipeline_layout.layout)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let pipeline = unsafe {
|
||||||
|
// panic_safety: if this is successful this should return 1 pipelines.
|
||||||
|
device.create_graphics_pipelines(cache.clone(), &[pipeline_info], None)
|
||||||
|
.map_err(|e| e.1).unwrap()[0]
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(VulkanGraphicsPipeline {
|
||||||
|
layout: pipeline_layout,
|
||||||
|
render_pass,
|
||||||
|
pipeline
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue