mirror of
https://github.com/italicsjenga/vello.git
synced 2025-01-10 20:51:29 +11:00
Migrate to BufferUsage
Adopt the BufferUsage concept from WebGPU, and replace MemFlags, which is inadequate.
This commit is contained in:
parent
34d8fa358b
commit
e9a8b4643b
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -849,6 +849,7 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ash",
|
"ash",
|
||||||
"ash-window",
|
"ash-window",
|
||||||
|
"bitflags",
|
||||||
"raw-window-handle",
|
"raw-window-handle",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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(
|
||||||
|
|
Loading…
Reference in a new issue