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 = [
"ash",
"ash-window",
"bitflags",
"raw-window-handle",
]

View file

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

View file

@ -1,16 +1,16 @@
use piet_gpu_hal::hub;
use piet_gpu_hal::vulkan::VkInstance;
use piet_gpu_hal::{CmdBuf, MemFlags};
use piet_gpu_hal::{BufferUsage, CmdBuf};
fn main() {
let (instance, _) = VkInstance::new(None).unwrap();
unsafe {
let device = instance.device(None).unwrap();
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 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();
buffer.write(&src).unwrap();
let code = include_bytes!("./shader/collatz.spv");

View file

@ -10,9 +10,8 @@ use std::sync::{Arc, Mutex, Weak};
use crate::vulkan;
use crate::DescriptorSetBuilder as DescriptorSetBuilderTrait;
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 Pipeline = <vulkan::VkDevice as Device>::Pipeline;
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> {
let buffer = self.0.device.create_buffer(size, mem_flags)?;
pub fn create_buffer(&self, size: u64, usage: BufferUsage) -> Result<Buffer, Error> {
let buffer = self.0.device.create_buffer(size, usage)?;
Ok(Buffer(Arc::new(BufferInner {
buffer,
session: Arc::downgrade(&self.0),
@ -155,9 +154,8 @@ impl Session {
&self,
width: u32,
height: u32,
mem_flags: MemFlags,
) -> 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 {
image,
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.
/// In time, it may go away and be replaced by either gfx-hal or wgpu.
use bitflags::bitflags;
pub mod hub;
pub mod vulkan;
@ -29,6 +32,25 @@ pub enum SamplerParams {
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)]
/// Information about the GPU.
pub struct GpuInfo {
@ -55,7 +77,6 @@ pub struct SubgroupSize {
pub trait Device: Sized {
type Buffer: 'static;
type Image;
type MemFlags: MemFlags;
type Pipeline;
type DescriptorSet;
type QueryPool;
@ -72,7 +93,7 @@ pub trait Device: Sized {
/// the info.
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.
///
@ -86,7 +107,6 @@ pub trait Device: Sized {
&self,
width: u32,
height: u32,
mem_flags: Self::MemFlags,
) -> Result<Self::Image, Error>;
/// 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::{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 {
/// Retain the dynamic lib.
@ -447,7 +447,6 @@ impl crate::Device for VkDevice {
type DescriptorSet = DescriptorSet;
type Pipeline = Pipeline;
type QueryPool = QueryPool;
type MemFlags = MemFlags;
type Fence = vk::Fence;
type Semaphore = vk::Semaphore;
type PipelineBuilder = PipelineBuilder;
@ -458,9 +457,19 @@ impl crate::Device for VkDevice {
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 {
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(
&vk::BufferCreateInfo::builder()
.size(size)
@ -473,9 +482,10 @@ impl crate::Device for VkDevice {
None,
)?;
let mem_requirements = device.get_buffer_memory_requirements(buffer);
let mem_flags = memory_property_flags_for_usage(usage);
let mem_type = find_memory_type(
mem_requirements.memory_type_bits,
mem_flags.0,
mem_flags,
&self.device_mem_props,
)
.unwrap(); // TODO: proper error
@ -505,7 +515,6 @@ impl crate::Device for VkDevice {
&self,
width: u32,
height: u32,
mem_flags: Self::MemFlags,
) -> Result<Self::Image, Error> {
let device = &self.device.device;
let extent = vk::Extent3D {
@ -533,9 +542,10 @@ impl crate::Device for VkDevice {
None,
)?;
let mem_requirements = device.get_image_memory_requirements(image);
let mem_flags = vk::MemoryPropertyFlags::DEVICE_LOCAL;
let mem_type = find_memory_type(
mem_requirements.memory_type_bits,
mem_flags.0,
mem_flags,
&self.device_mem_props,
)
.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 {
fn add_buffers(&mut self, n_buffers: u32) {
let start = self.bindings.len() as u32;
@ -1368,6 +1368,16 @@ unsafe fn choose_compute_device(
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(
memory_type_bits: u32,
property_flags: vk::MemoryPropertyFlags,

View file

@ -6,7 +6,7 @@ use clap::{App, Arg};
use piet_gpu_hal::hub;
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};
@ -253,8 +253,9 @@ fn main() -> Result<(), Error> {
//dump_scene(&scene);
let renderer = Renderer::new(&session, scene, n_paths, n_pathseg, n_trans)?;
let image_usage = BufferUsage::MAP_READ | BufferUsage::COPY_DST;
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();
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_hal::hub;
use piet_gpu_hal::{CmdBuf, Error, ImageLayout, MemFlags};
use piet_gpu_hal::{BufferUsage, CmdBuf, Error, ImageLayout};
use pico_svg::PicoSvg;
@ -237,8 +237,8 @@ impl Renderer {
n_pathseg: usize,
n_trans: usize,
) -> Result<Self, Error> {
let host = MemFlags::host_coherent();
let dev = MemFlags::device_local();
let dev = BufferUsage::STORAGE | BufferUsage::COPY_DST;
let host_upload = BufferUsage::MAP_WRITE | BufferUsage::COPY_SRC;
let n_elements = scene.len() / piet_gpu_types::scene::Element::fixed_size();
println!(
@ -247,7 +247,7 @@ impl Renderer {
);
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();
let scene_buf_dev = session
.create_buffer(std::mem::size_of_val(&scene[..]) as u64, dev)
@ -255,10 +255,10 @@ impl Renderer {
scene_buf_host.write(&scene)?;
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.
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)?;
// TODO: constants
@ -293,7 +293,7 @@ impl Renderer {
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)?;
memory_buf_host.write(&[alloc as u32, 0 /* Overflow flag */])?;
@ -485,12 +485,11 @@ impl Renderer {
if format != ImageFormat::RgbaPremul {
return Err("unsupported image format".into());
}
let host_mem_flags = MemFlags::host_coherent();
let dev_mem_flags = MemFlags::device_local();
let mut buffer = session.create_buffer(buf.len() as u64, host_mem_flags)?;
let host_upload = BufferUsage::MAP_WRITE | BufferUsage::COPY_SRC;
let mut buffer = session.create_buffer(buf.len() as u64, host_upload)?;
buffer.write(buf)?;
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()?;
cmd_buf.begin();
cmd_buf.image_barrier(