vk: write uniforms directly to host-visible mapped memory
This commit is contained in:
parent
fceda0e99d
commit
e947271f9a
|
@ -1,6 +1,7 @@
|
|||
use crate::error;
|
||||
use crate::vulkan_primitives::VulkanBuffer;
|
||||
use ash::vk;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[rustfmt::skip]
|
||||
pub(crate) static VBO_DEFAULT_FINAL: &[f32; 16] = &[
|
||||
|
@ -13,12 +14,12 @@ pub(crate) static VBO_DEFAULT_FINAL: &[f32; 16] = &[
|
|||
|
||||
pub struct DrawQuad {
|
||||
buffer: VulkanBuffer,
|
||||
device: ash::Device,
|
||||
device: Arc<ash::Device>,
|
||||
}
|
||||
|
||||
impl DrawQuad {
|
||||
pub fn new(
|
||||
device: &ash::Device,
|
||||
device: &Arc<ash::Device>,
|
||||
mem_props: &vk::PhysicalDeviceMemoryProperties,
|
||||
) -> error::Result<DrawQuad> {
|
||||
let mut buffer = VulkanBuffer::new(
|
||||
|
|
|
@ -8,7 +8,8 @@ use crate::queue_selection::get_graphics_queue;
|
|||
use crate::render_target::{RenderTarget, DEFAULT_MVP};
|
||||
use crate::samplers::SamplerSet;
|
||||
use crate::texture::{InputImage, OwnedImage, OwnedImageLayout, VulkanImage};
|
||||
use crate::ubo_ring::VkUboRing;
|
||||
// use crate::ubo_ring::VkUboRing;
|
||||
use crate::vulkan_primitives::RawVulkanBuffer;
|
||||
use crate::vulkan_state::VulkanGraphicsPipeline;
|
||||
use crate::{error, util};
|
||||
use ash::vk;
|
||||
|
@ -352,8 +353,13 @@ impl FilterChainVulkan {
|
|||
.as_ref()
|
||||
.map(|ubo| ubo.size as usize)
|
||||
.unwrap_or(0);
|
||||
let uniform_storage = UniformStorage::new(
|
||||
ubo_size,
|
||||
let uniform_storage = UniformStorage::new_with_storage(
|
||||
RawVulkanBuffer::new(
|
||||
&vulkan.device,
|
||||
&vulkan.memory_properties,
|
||||
vk::BufferUsageFlags::UNIFORM_BUFFER,
|
||||
ubo_size,
|
||||
)?,
|
||||
reflection
|
||||
.push_constant
|
||||
.as_ref()
|
||||
|
@ -383,13 +389,12 @@ impl FilterChainVulkan {
|
|||
frames_in_flight,
|
||||
)?;
|
||||
|
||||
let ubo_ring = VkUboRing::new(
|
||||
&vulkan.device,
|
||||
&vulkan.memory_properties,
|
||||
frames_in_flight as usize,
|
||||
ubo_size,
|
||||
)?;
|
||||
// shader_vulkan: 2026
|
||||
// let ubo_ring = VkUboRing::new(
|
||||
// &vulkan.device,
|
||||
// &vulkan.memory_properties,
|
||||
// frames_in_flight as usize,
|
||||
// ubo_size,
|
||||
// )?;
|
||||
filters.push(FilterPass {
|
||||
device: vulkan.device.clone(),
|
||||
reflection,
|
||||
|
@ -399,7 +404,7 @@ impl FilterChainVulkan {
|
|||
source,
|
||||
config,
|
||||
graphics_pipeline,
|
||||
ubo_ring,
|
||||
// ubo_ring,
|
||||
frames_in_flight,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::filter_chain::FilterCommon;
|
|||
use crate::render_target::RenderTarget;
|
||||
use crate::samplers::SamplerSet;
|
||||
use crate::texture::InputImage;
|
||||
use crate::ubo_ring::VkUboRing;
|
||||
use crate::vulkan_primitives::RawVulkanBuffer;
|
||||
use crate::vulkan_state::VulkanGraphicsPipeline;
|
||||
use crate::{error, VulkanImage};
|
||||
use ash::vk;
|
||||
|
@ -14,7 +14,7 @@ use librashader_reflect::reflect::semantics::{
|
|||
};
|
||||
use librashader_reflect::reflect::ShaderReflection;
|
||||
use librashader_runtime::binding::{BindSemantics, TextureInput};
|
||||
use librashader_runtime::uniforms::{UniformStorage, UniformStorageAccess};
|
||||
use librashader_runtime::uniforms::{NoUniformBinder, UniformStorage, UniformStorageAccess};
|
||||
use rustc_hash::FxHashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
|
@ -22,12 +22,12 @@ pub struct FilterPass {
|
|||
pub device: Arc<ash::Device>,
|
||||
pub reflection: ShaderReflection,
|
||||
// pub(crate) compiled: ShaderCompilerOutput<Vec<u32>>,
|
||||
pub(crate) uniform_storage: UniformStorage,
|
||||
pub(crate) uniform_storage: UniformStorage<NoUniformBinder, Option<()>, RawVulkanBuffer>,
|
||||
pub uniform_bindings: FxHashMap<UniformBinding, MemberOffset>,
|
||||
pub source: ShaderSource,
|
||||
pub config: ShaderPassConfig,
|
||||
pub graphics_pipeline: VulkanGraphicsPipeline,
|
||||
pub ubo_ring: VkUboRing,
|
||||
// pub ubo_ring: VkUboRing,
|
||||
pub frames_in_flight: u32,
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,7 @@ impl TextureInput for InputImage {
|
|||
}
|
||||
}
|
||||
|
||||
impl BindSemantics for FilterPass {
|
||||
impl BindSemantics<NoUniformBinder, Option<()>, RawVulkanBuffer> for FilterPass {
|
||||
type InputTexture = InputImage;
|
||||
type SamplerSet = SamplerSet;
|
||||
type DescriptorSet<'a> = vk::DescriptorSet;
|
||||
|
@ -113,10 +113,21 @@ impl FilterPass {
|
|||
);
|
||||
|
||||
if let Some(ubo) = &self.reflection.ubo {
|
||||
// shader_vulkan: 2554 (ra uses uses one big buffer)
|
||||
// itll be simpler for us if we just use a RingBuffer<vk::Buffer> tbh.
|
||||
self.ubo_ring
|
||||
.bind_to_descriptor_set(descriptor, ubo.binding, &self.uniform_storage)?;
|
||||
// RetroArch uses uses one big buffer for this and handles alignment themselves.
|
||||
// It's simpler here if we just use a buffer for each pass but not ideal.
|
||||
//
|
||||
// May want to switch to something like VMA in the future.
|
||||
|
||||
// VkUboRing is no longer used, we just write directly to the storage now.
|
||||
|
||||
// self.ubo_ring
|
||||
// .bind_to_descriptor_set(descriptor, ubo.binding, &self.uniform_storage)?;
|
||||
|
||||
self.uniform_storage.inner_ubo().bind_to_descriptor_set(
|
||||
descriptor,
|
||||
ubo.binding,
|
||||
&self.uniform_storage,
|
||||
)?;
|
||||
}
|
||||
|
||||
output.output.begin_pass(cmd);
|
||||
|
|
|
@ -12,6 +12,8 @@ use std::mem::align_of;
|
|||
const ENTRY_POINT: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(b"main\0") };
|
||||
|
||||
#[derive(Default, Clone, Debug, Copy)]
|
||||
#[repr(C)]
|
||||
#[allow(dead_code)]
|
||||
struct Vertex {
|
||||
pos: [f32; 4],
|
||||
color: [f32; 4],
|
||||
|
|
|
@ -14,7 +14,6 @@ mod queue_selection;
|
|||
mod render_target;
|
||||
mod samplers;
|
||||
mod texture;
|
||||
mod ubo_ring;
|
||||
mod util;
|
||||
mod vulkan_primitives;
|
||||
mod vulkan_state;
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
use crate::{error, util};
|
||||
use ash::vk;
|
||||
use librashader_runtime::uniforms::UniformStorageAccess;
|
||||
use std::ffi::c_void;
|
||||
use std::mem::ManuallyDrop;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::ptr::NonNull;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub struct VulkanImageMemory {
|
||||
|
@ -36,9 +40,9 @@ impl Drop for VulkanImageMemory {
|
|||
|
||||
pub struct VulkanBuffer {
|
||||
pub handle: vk::Buffer,
|
||||
device: ash::Device,
|
||||
pub memory: vk::DeviceMemory,
|
||||
pub size: vk::DeviceSize,
|
||||
device: Arc<ash::Device>,
|
||||
memory: vk::DeviceMemory,
|
||||
size: vk::DeviceSize,
|
||||
}
|
||||
|
||||
pub struct VulkanBufferMapHandle<'a> {
|
||||
|
@ -48,7 +52,7 @@ pub struct VulkanBufferMapHandle<'a> {
|
|||
|
||||
impl VulkanBuffer {
|
||||
pub fn new(
|
||||
device: &ash::Device,
|
||||
device: &Arc<ash::Device>,
|
||||
mem_props: &vk::PhysicalDeviceMemoryProperties,
|
||||
usage: vk::BufferUsageFlags,
|
||||
size: usize,
|
||||
|
@ -112,13 +116,15 @@ impl Drop for VulkanBuffer {
|
|||
|
||||
impl<'a> VulkanBufferMapHandle<'a> {
|
||||
pub unsafe fn copy_from(&mut self, offset: usize, src: &[u8]) {
|
||||
std::ptr::copy_nonoverlapping(
|
||||
src.as_ptr(),
|
||||
let mut align = ash::util::Align::new(
|
||||
self.ptr
|
||||
.map_addr(|original| original.wrapping_add(offset))
|
||||
.cast(),
|
||||
src.len(),
|
||||
std::mem::align_of::<u8>() as u64,
|
||||
self.buffer.size,
|
||||
);
|
||||
|
||||
align.copy_from_slice(src);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -127,3 +133,87 @@ impl<'a> Drop for VulkanBufferMapHandle<'a> {
|
|||
unsafe { self.buffer.device.unmap_memory(self.buffer.memory) }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RawVulkanBuffer {
|
||||
buffer: ManuallyDrop<VulkanBuffer>,
|
||||
ptr: NonNull<c_void>,
|
||||
}
|
||||
|
||||
impl RawVulkanBuffer {
|
||||
pub fn new(
|
||||
device: &Arc<ash::Device>,
|
||||
mem_props: &vk::PhysicalDeviceMemoryProperties,
|
||||
usage: vk::BufferUsageFlags,
|
||||
size: usize,
|
||||
) -> error::Result<Self> {
|
||||
let buffer = ManuallyDrop::new(VulkanBuffer::new(device, mem_props, usage, size)?);
|
||||
let ptr = unsafe {
|
||||
NonNull::new_unchecked(device.map_memory(
|
||||
buffer.memory,
|
||||
0,
|
||||
buffer.size,
|
||||
vk::MemoryMapFlags::empty(),
|
||||
)?)
|
||||
};
|
||||
|
||||
Ok(RawVulkanBuffer { buffer, ptr })
|
||||
}
|
||||
|
||||
pub fn bind_to_descriptor_set(
|
||||
&self,
|
||||
descriptor_set: vk::DescriptorSet,
|
||||
binding: u32,
|
||||
storage: &impl UniformStorageAccess,
|
||||
) -> error::Result<()> {
|
||||
unsafe {
|
||||
let buffer_info = [vk::DescriptorBufferInfo::builder()
|
||||
.buffer(self.buffer.handle)
|
||||
.offset(0)
|
||||
.range(storage.ubo_slice().len() as vk::DeviceSize)
|
||||
.build()];
|
||||
|
||||
let write_info = [vk::WriteDescriptorSet::builder()
|
||||
.descriptor_type(vk::DescriptorType::UNIFORM_BUFFER)
|
||||
.dst_set(descriptor_set)
|
||||
.dst_binding(binding)
|
||||
.dst_array_element(0)
|
||||
.buffer_info(&buffer_info)
|
||||
.build()];
|
||||
|
||||
self.buffer.device.update_descriptor_sets(&write_info, &[])
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for RawVulkanBuffer {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
self.buffer.device.unmap_memory(self.buffer.memory);
|
||||
self.ptr = NonNull::dangling();
|
||||
if self.buffer.memory != vk::DeviceMemory::null() {
|
||||
self.buffer.device.free_memory(self.buffer.memory, None);
|
||||
}
|
||||
|
||||
if self.buffer.handle != vk::Buffer::null() {
|
||||
self.buffer.device.destroy_buffer(self.buffer.handle, None);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for RawVulkanBuffer {
|
||||
type Target = [u8];
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
unsafe { std::slice::from_raw_parts(self.ptr.as_ptr().cast(), self.buffer.size as usize) }
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for RawVulkanBuffer {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
unsafe {
|
||||
std::slice::from_raw_parts_mut(self.ptr.as_ptr().cast(), self.buffer.size as usize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -183,7 +183,6 @@ impl VulkanGraphicsPipeline {
|
|||
reflection: &ShaderReflection,
|
||||
replicas: u32,
|
||||
) -> error::Result<VulkanGraphicsPipeline> {
|
||||
// shader_vulkan 1927 (init_pipeline_layout)
|
||||
let pipeline_layout = PipelineLayoutObjects::new(reflection, replicas, device)?;
|
||||
|
||||
let input_assembly = vk::PipelineInputAssemblyStateCreateInfo::builder()
|
||||
|
|
|
@ -6,6 +6,7 @@ use librashader_reflect::reflect::semantics::{
|
|||
};
|
||||
use std::collections::HashMap;
|
||||
use std::hash::BuildHasher;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
/// Trait for input textures used during uniform binding,
|
||||
pub trait TextureInput {
|
||||
|
@ -47,8 +48,9 @@ where
|
|||
}
|
||||
|
||||
/// Trait that abstracts binding of semantics to shader uniforms.
|
||||
pub trait BindSemantics<H = NoUniformBinder, C = Option<()>>
|
||||
pub trait BindSemantics<H = NoUniformBinder, C = Option<()>, S = Box<[u8]>>
|
||||
where
|
||||
S: Deref<Target = [u8]> + DerefMut,
|
||||
H: BindUniform<C, f32>,
|
||||
H: BindUniform<C, u32>,
|
||||
H: BindUniform<C, i32>,
|
||||
|
@ -84,7 +86,7 @@ where
|
|||
fn bind_semantics<'a>(
|
||||
device: &Self::DeviceContext,
|
||||
sampler_set: &Self::SamplerSet,
|
||||
uniform_storage: &mut UniformStorage<H, C>,
|
||||
uniform_storage: &mut UniformStorage<H, C, S>,
|
||||
descriptor_set: &mut Self::DescriptorSet<'a>,
|
||||
mvp: &[f32; 16],
|
||||
frame_count: u32,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use librashader_reflect::reflect::semantics::MemberOffset;
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
/// A scalar value that is valid as a uniform member
|
||||
pub trait UniformScalar: Copy + bytemuck::Pod {}
|
||||
|
@ -36,7 +37,10 @@ pub trait UniformStorageAccess {
|
|||
fn push_slice(&self) -> &[u8];
|
||||
}
|
||||
|
||||
impl<T, H> UniformStorageAccess for UniformStorage<T, H> {
|
||||
impl<T, H, S> UniformStorageAccess for UniformStorage<T, H, S>
|
||||
where
|
||||
S: Deref<Target = [u8]> + DerefMut,
|
||||
{
|
||||
fn ubo_pointer(&self) -> *const u8 {
|
||||
self.ubo.as_ptr()
|
||||
}
|
||||
|
@ -64,24 +68,29 @@ impl<T> BindUniform<Option<()>, T> for NoUniformBinder {
|
|||
}
|
||||
|
||||
/// A helper to bind uniform variables to UBO or Push Constant Buffers.
|
||||
pub struct UniformStorage<H = NoUniformBinder, C = Option<()>> {
|
||||
ubo: Box<[u8]>,
|
||||
pub struct UniformStorage<H = NoUniformBinder, C = Option<()>, S = Box<[u8]>>
|
||||
where
|
||||
S: Deref<Target = [u8]> + DerefMut,
|
||||
{
|
||||
ubo: S,
|
||||
push: Box<[u8]>,
|
||||
_h: PhantomData<H>,
|
||||
_c: PhantomData<C>,
|
||||
}
|
||||
|
||||
impl<H, C> UniformStorage<H, C> {
|
||||
/// Create a new `UniformStorage` with the given size for UBO and Push Constant Buffer sizes.
|
||||
pub fn new(ubo_size: usize, push_size: usize) -> Self {
|
||||
UniformStorage {
|
||||
ubo: vec![0u8; ubo_size].into_boxed_slice(),
|
||||
push: vec![0u8; push_size].into_boxed_slice(),
|
||||
_h: Default::default(),
|
||||
_c: Default::default(),
|
||||
}
|
||||
impl<H, C, S> UniformStorage<H, C, S>
|
||||
where
|
||||
S: Deref<Target = [u8]> + DerefMut,
|
||||
{
|
||||
pub fn inner_ubo(&self) -> &S {
|
||||
&self.ubo
|
||||
}
|
||||
}
|
||||
|
||||
impl<H, C, S> UniformStorage<H, C, S>
|
||||
where
|
||||
S: Deref<Target = [u8]> + DerefMut,
|
||||
{
|
||||
#[inline(always)]
|
||||
fn write_scalar_inner<T: UniformScalar>(buffer: &mut [u8], value: T, ctx: C)
|
||||
where
|
||||
|
@ -100,8 +109,8 @@ impl<H, C> UniformStorage<H, C> {
|
|||
H: BindUniform<C, T>,
|
||||
{
|
||||
let (buffer, offset) = match offset {
|
||||
MemberOffset::Ubo(offset) => (&mut self.ubo, offset),
|
||||
MemberOffset::PushConstant(offset) => (&mut self.push, offset),
|
||||
MemberOffset::Ubo(offset) => (self.ubo.deref_mut(), offset),
|
||||
MemberOffset::PushConstant(offset) => (self.push.deref_mut(), offset),
|
||||
};
|
||||
|
||||
Self::write_scalar_inner(
|
||||
|
@ -110,10 +119,33 @@ impl<H, C> UniformStorage<H, C> {
|
|||
ctx,
|
||||
)
|
||||
}
|
||||
|
||||
/// Create a new `UniformStorage` with the given backing storage
|
||||
pub fn new_with_storage(storage: S, push_size: usize) -> UniformStorage<H, C, S> {
|
||||
UniformStorage {
|
||||
ubo: storage,
|
||||
push: vec![0u8; push_size].into_boxed_slice(),
|
||||
_h: Default::default(),
|
||||
_c: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<H, C> UniformStorage<H, C>
|
||||
impl<H, C> UniformStorage<H, C, Box<[u8]>> {
|
||||
/// Create a new `UniformStorage` with the given size for UBO and Push Constant Buffer sizes.
|
||||
pub fn new(ubo_size: usize, push_size: usize) -> UniformStorage<H, C, Box<[u8]>> {
|
||||
UniformStorage {
|
||||
ubo: vec![0u8; ubo_size].into_boxed_slice(),
|
||||
push: vec![0u8; push_size].into_boxed_slice(),
|
||||
_h: Default::default(),
|
||||
_c: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<H, C, S> UniformStorage<H, C, S>
|
||||
where
|
||||
S: Deref<Target = [u8]> + DerefMut,
|
||||
H: for<'a> BindUniform<C, &'a [f32; 4]>,
|
||||
{
|
||||
#[inline(always)]
|
||||
|
@ -128,8 +160,8 @@ where
|
|||
#[inline(always)]
|
||||
pub fn bind_vec4(&mut self, offset: MemberOffset, value: impl Into<[f32; 4]>, ctx: C) {
|
||||
let (buffer, offset) = match offset {
|
||||
MemberOffset::Ubo(offset) => (&mut self.ubo, offset),
|
||||
MemberOffset::PushConstant(offset) => (&mut self.push, offset),
|
||||
MemberOffset::Ubo(offset) => (self.ubo.deref_mut(), offset),
|
||||
MemberOffset::PushConstant(offset) => (self.push.deref_mut(), offset),
|
||||
};
|
||||
|
||||
Self::write_vec4_inner(
|
||||
|
@ -140,8 +172,9 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<H, C> UniformStorage<H, C>
|
||||
impl<H, C, S> UniformStorage<H, C, S>
|
||||
where
|
||||
S: Deref<Target = [u8]> + DerefMut,
|
||||
H: for<'a> BindUniform<C, &'a [f32; 16]>,
|
||||
{
|
||||
#[inline(always)]
|
||||
|
@ -156,8 +189,8 @@ where
|
|||
#[inline(always)]
|
||||
pub fn bind_mat4(&mut self, offset: MemberOffset, value: &[f32; 16], ctx: C) {
|
||||
let (buffer, offset) = match offset {
|
||||
MemberOffset::Ubo(offset) => (&mut self.ubo, offset),
|
||||
MemberOffset::PushConstant(offset) => (&mut self.push, offset),
|
||||
MemberOffset::Ubo(offset) => (self.ubo.deref_mut(), offset),
|
||||
MemberOffset::PushConstant(offset) => (self.push.deref_mut(), offset),
|
||||
};
|
||||
Self::write_mat4_inner(
|
||||
&mut buffer[offset..][..16 * std::mem::size_of::<f32>()],
|
||||
|
|
Loading…
Reference in a new issue