Migrate to BufferUsage

Adopt the BufferUsage concept from WebGPU, and replace MemFlags, which
is inadequate.
This commit is contained in:
Raph Levien 2021-05-21 19:31:37 -07:00
parent 34d8fa358b
commit e9a8b4643b
8 changed files with 71 additions and 41 deletions

1
Cargo.lock generated
View file

@ -849,6 +849,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"ash", "ash",
"ash-window", "ash-window",
"bitflags",
"raw-window-handle", "raw-window-handle",
] ]

View file

@ -10,3 +10,4 @@ edition = "2018"
ash = "0.31" ash = "0.31"
ash-window = "0.5" ash-window = "0.5"
raw-window-handle = "0.3" raw-window-handle = "0.3"
bitflags = "1.2.1"

View file

@ -1,16 +1,16 @@
use piet_gpu_hal::hub; use piet_gpu_hal::hub;
use piet_gpu_hal::vulkan::VkInstance; use piet_gpu_hal::vulkan::VkInstance;
use piet_gpu_hal::{CmdBuf, MemFlags}; use piet_gpu_hal::{BufferUsage, CmdBuf};
fn main() { fn main() {
let (instance, _) = VkInstance::new(None).unwrap(); let (instance, _) = VkInstance::new(None).unwrap();
unsafe { unsafe {
let device = instance.device(None).unwrap(); let device = instance.device(None).unwrap();
let session = hub::Session::new(device); let session = hub::Session::new(device);
let mem_flags = MemFlags::host_coherent(); let usage = BufferUsage::MAP_READ | BufferUsage::MAP_WRITE | BufferUsage::STORAGE;
let src = (0..256).map(|x| x + 1).collect::<Vec<u32>>(); let src = (0..256).map(|x| x + 1).collect::<Vec<u32>>();
let mut buffer = session let mut buffer = session
.create_buffer(std::mem::size_of_val(&src[..]) as u64, mem_flags) .create_buffer(std::mem::size_of_val(&src[..]) as u64, usage)
.unwrap(); .unwrap();
buffer.write(&src).unwrap(); buffer.write(&src).unwrap();
let code = include_bytes!("./shader/collatz.spv"); let code = include_bytes!("./shader/collatz.spv");

View file

@ -10,9 +10,8 @@ use std::sync::{Arc, Mutex, Weak};
use crate::vulkan; use crate::vulkan;
use crate::DescriptorSetBuilder as DescriptorSetBuilderTrait; use crate::DescriptorSetBuilder as DescriptorSetBuilderTrait;
use crate::PipelineBuilder as PipelineBuilderTrait; use crate::PipelineBuilder as PipelineBuilderTrait;
use crate::{Device, Error, GpuInfo, SamplerParams}; use crate::{BufferUsage, Device, Error, GpuInfo, SamplerParams};
pub type MemFlags = <vulkan::VkDevice as Device>::MemFlags;
pub type Semaphore = <vulkan::VkDevice as Device>::Semaphore; pub type Semaphore = <vulkan::VkDevice as Device>::Semaphore;
pub type Pipeline = <vulkan::VkDevice as Device>::Pipeline; pub type Pipeline = <vulkan::VkDevice as Device>::Pipeline;
pub type DescriptorSet = <vulkan::VkDevice as Device>::DescriptorSet; pub type DescriptorSet = <vulkan::VkDevice as Device>::DescriptorSet;
@ -143,8 +142,8 @@ impl Session {
)) ))
} }
pub fn create_buffer(&self, size: u64, mem_flags: MemFlags) -> Result<Buffer, Error> { pub fn create_buffer(&self, size: u64, usage: BufferUsage) -> Result<Buffer, Error> {
let buffer = self.0.device.create_buffer(size, mem_flags)?; let buffer = self.0.device.create_buffer(size, usage)?;
Ok(Buffer(Arc::new(BufferInner { Ok(Buffer(Arc::new(BufferInner {
buffer, buffer,
session: Arc::downgrade(&self.0), session: Arc::downgrade(&self.0),
@ -155,9 +154,8 @@ impl Session {
&self, &self,
width: u32, width: u32,
height: u32, height: u32,
mem_flags: MemFlags,
) -> Result<Image, Error> { ) -> Result<Image, Error> {
let image = self.0.device.create_image2d(width, height, mem_flags)?; let image = self.0.device.create_image2d(width, height)?;
Ok(Image(Arc::new(ImageInner { Ok(Image(Arc::new(ImageInner {
image, image,
session: Arc::downgrade(&self.0), session: Arc::downgrade(&self.0),

View file

@ -2,6 +2,9 @@
/// ///
/// This abstraction is inspired by gfx-hal, but is specialized to the needs of piet-gpu. /// This abstraction is inspired by gfx-hal, but is specialized to the needs of piet-gpu.
/// In time, it may go away and be replaced by either gfx-hal or wgpu. /// In time, it may go away and be replaced by either gfx-hal or wgpu.
use bitflags::bitflags;
pub mod hub; pub mod hub;
pub mod vulkan; pub mod vulkan;
@ -29,6 +32,25 @@ pub enum SamplerParams {
Linear, Linear,
} }
bitflags! {
/// The intended usage for this buffer.
pub struct BufferUsage: u32 {
/// The buffer can be mapped for reading CPU-side.
const MAP_READ = 0x1;
/// The buffer can be mapped for writing CPU-side.
const MAP_WRITE = 0x2;
/// The buffer can be copied from.
const COPY_SRC = 0x4;
/// The buffer can be copied to.
const COPY_DST = 0x8;
/// The buffer can be bound to a compute shader.
const STORAGE = 0x80;
/// The buffer can be used to store the results of queries.
const QUERY_RESOLVE = 0x200;
// May add other types.
}
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
/// Information about the GPU. /// Information about the GPU.
pub struct GpuInfo { pub struct GpuInfo {
@ -55,7 +77,6 @@ pub struct SubgroupSize {
pub trait Device: Sized { pub trait Device: Sized {
type Buffer: 'static; type Buffer: 'static;
type Image; type Image;
type MemFlags: MemFlags;
type Pipeline; type Pipeline;
type DescriptorSet; type DescriptorSet;
type QueryPool; type QueryPool;
@ -72,7 +93,7 @@ pub trait Device: Sized {
/// the info. /// the info.
fn query_gpu_info(&self) -> GpuInfo; fn query_gpu_info(&self) -> GpuInfo;
fn create_buffer(&self, size: u64, mem_flags: Self::MemFlags) -> Result<Self::Buffer, Error>; fn create_buffer(&self, size: u64, usage: BufferUsage) -> Result<Self::Buffer, Error>;
/// Destroy a buffer. /// Destroy a buffer.
/// ///
@ -86,7 +107,6 @@ pub trait Device: Sized {
&self, &self,
width: u32, width: u32,
height: u32, height: u32,
mem_flags: Self::MemFlags,
) -> Result<Self::Image, Error>; ) -> Result<Self::Image, Error>;
/// Destroy an image. /// Destroy an image.

View file

@ -9,7 +9,7 @@ use ash::extensions::{ext::DebugUtils, khr};
use ash::version::{DeviceV1_0, EntryV1_0, InstanceV1_0, InstanceV1_1}; use ash::version::{DeviceV1_0, EntryV1_0, InstanceV1_0, InstanceV1_1};
use ash::{vk, Device, Entry, Instance}; use ash::{vk, Device, Entry, Instance};
use crate::{Device as DeviceTrait, Error, GpuInfo, ImageLayout, SamplerParams, SubgroupSize}; use crate::{BufferUsage, Device as DeviceTrait, Error, GpuInfo, ImageLayout, SamplerParams, SubgroupSize};
pub struct VkInstance { pub struct VkInstance {
/// Retain the dynamic lib. /// Retain the dynamic lib.
@ -447,7 +447,6 @@ impl crate::Device for VkDevice {
type DescriptorSet = DescriptorSet; type DescriptorSet = DescriptorSet;
type Pipeline = Pipeline; type Pipeline = Pipeline;
type QueryPool = QueryPool; type QueryPool = QueryPool;
type MemFlags = MemFlags;
type Fence = vk::Fence; type Fence = vk::Fence;
type Semaphore = vk::Semaphore; type Semaphore = vk::Semaphore;
type PipelineBuilder = PipelineBuilder; type PipelineBuilder = PipelineBuilder;
@ -458,9 +457,19 @@ impl crate::Device for VkDevice {
self.gpu_info.clone() self.gpu_info.clone()
} }
fn create_buffer(&self, size: u64, mem_flags: MemFlags) -> Result<Buffer, Error> { fn create_buffer(&self, size: u64, usage: BufferUsage) -> Result<Buffer, Error> {
unsafe { unsafe {
let device = &self.device.device; let device = &self.device.device;
let mut vk_usage = vk::BufferUsageFlags::empty();
if usage.contains(BufferUsage::STORAGE) {
vk_usage |= vk::BufferUsageFlags::STORAGE_BUFFER;
}
if usage.contains(BufferUsage::COPY_SRC) {
vk_usage |= vk::BufferUsageFlags::TRANSFER_SRC;
}
if usage.contains(BufferUsage::COPY_DST) {
vk_usage |= vk::BufferUsageFlags::TRANSFER_DST;
}
let buffer = device.create_buffer( let buffer = device.create_buffer(
&vk::BufferCreateInfo::builder() &vk::BufferCreateInfo::builder()
.size(size) .size(size)
@ -473,9 +482,10 @@ impl crate::Device for VkDevice {
None, None,
)?; )?;
let mem_requirements = device.get_buffer_memory_requirements(buffer); let mem_requirements = device.get_buffer_memory_requirements(buffer);
let mem_flags = memory_property_flags_for_usage(usage);
let mem_type = find_memory_type( let mem_type = find_memory_type(
mem_requirements.memory_type_bits, mem_requirements.memory_type_bits,
mem_flags.0, mem_flags,
&self.device_mem_props, &self.device_mem_props,
) )
.unwrap(); // TODO: proper error .unwrap(); // TODO: proper error
@ -505,7 +515,6 @@ impl crate::Device for VkDevice {
&self, &self,
width: u32, width: u32,
height: u32, height: u32,
mem_flags: Self::MemFlags,
) -> Result<Self::Image, Error> { ) -> Result<Self::Image, Error> {
let device = &self.device.device; let device = &self.device.device;
let extent = vk::Extent3D { let extent = vk::Extent3D {
@ -533,9 +542,10 @@ impl crate::Device for VkDevice {
None, None,
)?; )?;
let mem_requirements = device.get_image_memory_requirements(image); let mem_requirements = device.get_image_memory_requirements(image);
let mem_flags = vk::MemoryPropertyFlags::DEVICE_LOCAL;
let mem_type = find_memory_type( let mem_type = find_memory_type(
mem_requirements.memory_type_bits, mem_requirements.memory_type_bits,
mem_flags.0, mem_flags,
&self.device_mem_props, &self.device_mem_props,
) )
.unwrap(); // TODO: proper error .unwrap(); // TODO: proper error
@ -1002,16 +1012,6 @@ impl crate::CmdBuf<VkDevice> for CmdBuf {
} }
} }
impl crate::MemFlags for MemFlags {
fn device_local() -> Self {
MemFlags(vk::MemoryPropertyFlags::DEVICE_LOCAL)
}
fn host_coherent() -> Self {
MemFlags(vk::MemoryPropertyFlags::HOST_VISIBLE | vk::MemoryPropertyFlags::HOST_COHERENT)
}
}
impl crate::PipelineBuilder<VkDevice> for PipelineBuilder { impl crate::PipelineBuilder<VkDevice> for PipelineBuilder {
fn add_buffers(&mut self, n_buffers: u32) { fn add_buffers(&mut self, n_buffers: u32) {
let start = self.bindings.len() as u32; let start = self.bindings.len() as u32;
@ -1368,6 +1368,16 @@ unsafe fn choose_compute_device(
None None
} }
fn memory_property_flags_for_usage(usage: BufferUsage) -> vk::MemoryPropertyFlags {
if usage.intersects(BufferUsage::MAP_READ | BufferUsage::MAP_WRITE) {
vk::MemoryPropertyFlags::HOST_VISIBLE | vk::MemoryPropertyFlags::HOST_COHERENT
} else {
vk::MemoryPropertyFlags::DEVICE_LOCAL
}
}
// This could get more sophisticated about asking for CACHED when appropriate, but is
// probably going to get replaced by a gpu-alloc solution anyway.
fn find_memory_type( fn find_memory_type(
memory_type_bits: u32, memory_type_bits: u32,
property_flags: vk::MemoryPropertyFlags, property_flags: vk::MemoryPropertyFlags,

View file

@ -6,7 +6,7 @@ use clap::{App, Arg};
use piet_gpu_hal::hub; use piet_gpu_hal::hub;
use piet_gpu_hal::vulkan::VkInstance; use piet_gpu_hal::vulkan::VkInstance;
use piet_gpu_hal::{CmdBuf, Error, MemFlags}; use piet_gpu_hal::{BufferUsage, CmdBuf, Error};
use piet_gpu::{render_scene, render_svg, PietGpuRenderContext, Renderer, HEIGHT, WIDTH}; use piet_gpu::{render_scene, render_svg, PietGpuRenderContext, Renderer, HEIGHT, WIDTH};
@ -253,8 +253,9 @@ fn main() -> Result<(), Error> {
//dump_scene(&scene); //dump_scene(&scene);
let renderer = Renderer::new(&session, scene, n_paths, n_pathseg, n_trans)?; let renderer = Renderer::new(&session, scene, n_paths, n_pathseg, n_trans)?;
let image_usage = BufferUsage::MAP_READ | BufferUsage::COPY_DST;
let image_buf = let image_buf =
session.create_buffer((WIDTH * HEIGHT * 4) as u64, MemFlags::host_coherent())?; session.create_buffer((WIDTH * HEIGHT * 4) as u64, image_usage)?;
cmd_buf.begin(); cmd_buf.begin();
renderer.record(&mut cmd_buf, &query_pool); renderer.record(&mut cmd_buf, &query_pool);

View file

@ -13,7 +13,7 @@ use piet::{Color, ImageFormat, RenderContext};
use piet_gpu_types::encoder::Encode; use piet_gpu_types::encoder::Encode;
use piet_gpu_hal::hub; use piet_gpu_hal::hub;
use piet_gpu_hal::{CmdBuf, Error, ImageLayout, MemFlags}; use piet_gpu_hal::{BufferUsage, CmdBuf, Error, ImageLayout};
use pico_svg::PicoSvg; use pico_svg::PicoSvg;
@ -237,8 +237,8 @@ impl Renderer {
n_pathseg: usize, n_pathseg: usize,
n_trans: usize, n_trans: usize,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
let host = MemFlags::host_coherent(); let dev = BufferUsage::STORAGE | BufferUsage::COPY_DST;
let dev = MemFlags::device_local(); let host_upload = BufferUsage::MAP_WRITE | BufferUsage::COPY_SRC;
let n_elements = scene.len() / piet_gpu_types::scene::Element::fixed_size(); let n_elements = scene.len() / piet_gpu_types::scene::Element::fixed_size();
println!( println!(
@ -247,7 +247,7 @@ impl Renderer {
); );
let mut scene_buf_host = session let mut scene_buf_host = session
.create_buffer(std::mem::size_of_val(&scene[..]) as u64, host) .create_buffer(std::mem::size_of_val(&scene[..]) as u64, host_upload)
.unwrap(); .unwrap();
let scene_buf_dev = session let scene_buf_dev = session
.create_buffer(std::mem::size_of_val(&scene[..]) as u64, dev) .create_buffer(std::mem::size_of_val(&scene[..]) as u64, dev)
@ -255,10 +255,10 @@ impl Renderer {
scene_buf_host.write(&scene)?; scene_buf_host.write(&scene)?;
let state_buf = session.create_buffer(1 * 1024 * 1024, dev)?; let state_buf = session.create_buffer(1 * 1024 * 1024, dev)?;
let image_dev = session.create_image2d(WIDTH as u32, HEIGHT as u32, dev)?; let image_dev = session.create_image2d(WIDTH as u32, HEIGHT as u32)?;
const CONFIG_SIZE: u64 = 10 * 4; // Size of Config in setup.h. const CONFIG_SIZE: u64 = 10 * 4; // Size of Config in setup.h.
let mut config_buf_host = session.create_buffer(CONFIG_SIZE, host)?; let mut config_buf_host = session.create_buffer(CONFIG_SIZE, host_upload)?;
let config_buf_dev = session.create_buffer(CONFIG_SIZE, dev)?; let config_buf_dev = session.create_buffer(CONFIG_SIZE, dev)?;
// TODO: constants // TODO: constants
@ -293,7 +293,7 @@ impl Renderer {
trans_base as u32, trans_base as u32,
])?; ])?;
let mut memory_buf_host = session.create_buffer(2 * 4, host)?; let mut memory_buf_host = session.create_buffer(2 * 4, host_upload)?;
let memory_buf_dev = session.create_buffer(128 * 1024 * 1024, dev)?; let memory_buf_dev = session.create_buffer(128 * 1024 * 1024, dev)?;
memory_buf_host.write(&[alloc as u32, 0 /* Overflow flag */])?; memory_buf_host.write(&[alloc as u32, 0 /* Overflow flag */])?;
@ -485,12 +485,11 @@ impl Renderer {
if format != ImageFormat::RgbaPremul { if format != ImageFormat::RgbaPremul {
return Err("unsupported image format".into()); return Err("unsupported image format".into());
} }
let host_mem_flags = MemFlags::host_coherent(); let host_upload = BufferUsage::MAP_WRITE | BufferUsage::COPY_SRC;
let dev_mem_flags = MemFlags::device_local(); let mut buffer = session.create_buffer(buf.len() as u64, host_upload)?;
let mut buffer = session.create_buffer(buf.len() as u64, host_mem_flags)?;
buffer.write(buf)?; buffer.write(buf)?;
let image = let image =
session.create_image2d(width.try_into()?, height.try_into()?, dev_mem_flags)?; session.create_image2d(width.try_into()?, height.try_into()?)?;
let mut cmd_buf = session.cmd_buf()?; let mut cmd_buf = session.cmd_buf()?;
cmd_buf.begin(); cmd_buf.begin();
cmd_buf.image_barrier( cmd_buf.image_barrier(