Browse Source

got yellow framebuffer working

master
Thomas Johnson 4 months ago
commit
40ec9090c5
  1. 2
      .gitignore
  2. 12
      Cargo.toml
  3. 72
      src/hash_wrapper.rs
  4. 426
      src/main.rs
  5. 8
      src/yellow.frag

2
.gitignore

@ -0,0 +1,2 @@
/target
Cargo.lock

12
Cargo.toml

@ -0,0 +1,12 @@
[package]
name = "vulkan-dabble"
version = "0.1.0"
authors = ["thajohns <thajohns@clarkson.edu>"]
edition = "2018"
[dependencies]
winit = "0.25"
vulkano = "0.24"
vulkano-win = "0.24"
vulkano-shaders = "0.24"

72
src/hash_wrapper.rs

@ -0,0 +1,72 @@
use core::hash::{Hash, Hasher};
use core::ops::{Deref, DerefMut};
// A type for manipulating how something is hashed.
pub struct HashWrapper<T, U, F>(T, F)
where
F: Fn(&T) -> U,
U: Hash;
impl<T, U, F> HashWrapper<T, U, F>
where
F: Fn(&T) -> U,
U: Hash,
{
pub fn new(item: T, map: F) -> HashWrapper<T, U, F> {
HashWrapper(item, map)
}
pub fn into_inner(self) -> T {
self.0
}
}
impl<T, U, F> PartialEq for HashWrapper<T, U, F>
where
F: Fn(&T) -> U,
U: Hash + Eq,
{
fn eq(&self, other: &Self) -> bool {
self.1(&self.0).eq(&other.1(&other.0))
}
}
impl<T, U, F> Eq for HashWrapper<T, U, F>
where
F: Fn(&T) -> U,
U: Hash + Eq,
{
}
impl<T, U, F> Hash for HashWrapper<T, U, F>
where
F: Fn(&T) -> U,
U: Hash,
{
fn hash<H: Hasher>(&self, state: &mut H) {
self.1(&self.0).hash(state);
}
}
impl<T, U, F> Deref for HashWrapper<T, U, F>
where
F: Fn(&T) -> U,
U: Hash,
{
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
impl<T, U, F> DerefMut for HashWrapper<T, U, F>
where
F: Fn(&T) -> U,
U: Hash,
{
fn deref_mut(&mut self) -> &mut T {
&mut self.0
}
}

426
src/main.rs

@ -0,0 +1,426 @@
extern crate vulkano;
extern crate vulkano_win;
extern crate vulkano_shaders;
extern crate winit;
mod hash_wrapper;
mod shader {
vulkano_shaders::shader!{
ty: "compute",
path: "src/yellow.frag",
}
}
use std::collections::hash_set::HashSet;
use std::sync::Arc;
use vulkano::device::{Device, DeviceExtensions, Features, Queue};
use vulkano::descriptor::descriptor_set::{PersistentDescriptorSet, PersistentDescriptorSetImg, UnsafeDescriptorSetLayout};
use vulkano::format::Format;
use vulkano::image::{ImageUsage, SwapchainImage, view::ImageView};
use vulkano::instance::{
ApplicationInfo, Instance, InstanceExtensions, PhysicalDevice, Version as VkVersion,
};
use vulkano::swapchain::{
self, ColorSpace, CompositeAlpha, FullscreenExclusive, PresentMode, Surface, Swapchain,
};
use vulkano::sync::{SharingMode, GpuFuture};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, PrimaryCommandBuffer};
use vulkano::pipeline::{ComputePipeline, ComputePipelineAbstract};
use vulkano_win::VkSurfaceBuild;
use winit::{
dpi::{PhysicalPosition, PhysicalSize, Position, Size},
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::{Fullscreen, Window, WindowBuilder},
};
use hash_wrapper::HashWrapper;
const DEFAULT_DIMS: [u32; 2] = [100, 100];
struct VulkanWindow {
sfc: Arc<Surface<Window>>,
el: EventLoop<()>,
vk: VulkanData<Window>,
}
struct VulkanData<W> {
inst: Arc<Instance>,
swp_caps: swapchain::Capabilities,
device_idx: usize,
device: Arc<Device>,
compute_queue: Arc<Queue>,
present_queue: Arc<Queue>,
compute_pipeline: Arc<ComputePipeline>,
desc_set_layout: Arc<UnsafeDescriptorSetLayout>,
swapchain: Arc<Swapchain<W>>,
swapchain_images: Vec<Arc<SwapchainImage<W>>>,
desc_sets: Vec<Arc<PersistentDescriptorSet<((), PersistentDescriptorSetImg<Arc<ImageView<Arc<SwapchainImage<W>>>>>)>>>,
}
#[derive(Debug)]
struct QueueFamilies {
compute_idx: Option<usize>,
present_idx: Option<usize>,
}
impl QueueFamilies {
fn new() -> Self {
QueueFamilies {
compute_idx: None,
present_idx: None,
}
}
fn is_complete(&self) -> bool {
self.compute_idx.is_some() && self.present_idx.is_some()
}
fn populate<W>(&mut self, dev: &PhysicalDevice, surface: &Arc<Surface<W>>) {
for (i, qf) in dev.queue_families().enumerate() {
println!("queue family {}: {:?}", i, qf);
if qf.supports_compute() {
self.compute_idx = Some(i);
}
if surface.is_supported(qf).unwrap() {
self.present_idx = Some(i);
}
}
}
}
const VALIDATION_LAYERS: &[&str] = &[
// "VK_LAYER_LUNARG_core_validation",
// "VK_LAYER_KHRONOS_validation",
// "VK_LAYER_LUNARG_standard_validation",
// "VK_LAYER_LUNARG_parameter_validation",
];
const USE_VALIDATION_LAYERS: bool = true;
impl VulkanWindow {
fn init_winit(inst: &Arc<Instance>) -> (Arc<Surface<Window>>, EventLoop<()>) {
let el = EventLoop::new();
let sfc = WindowBuilder::new()
.with_title("reeee")
.with_visible(true)
.with_inner_size(Size::Physical(PhysicalSize {
width: DEFAULT_DIMS[0],
height: DEFAULT_DIMS[1],
}))
.build_vk_surface(&el, inst.clone())
.expect("could not create Vulkan surface");
(sfc, el)
}
fn init() -> Self {
let inst = Self::init_vk_instance();
let (sfc, el) = Self::init_winit(&inst);
let mut vk = VulkanData::init(inst, sfc.clone());
vk.do_frame(&sfc, DEFAULT_DIMS);
Self {
sfc,
el,
vk,
}
}
fn init_vk_instance() -> Arc<Instance> {
//let sup_ext = InstanceExtensions::supported_by_core()
// .expect("Unable to retrieve supported Vulkan extensions");
//println!("supported Vulkan extensions: {:?}", sup_ext);
let app_info = ApplicationInfo {
application_name: Some("vk-test".into()),
application_version: Some(VkVersion {
major: 0,
minor: 0,
patch: 0,
}),
engine_name: Some("No Engine".into()),
engine_version: Some(VkVersion {
major: 0,
minor: 0,
patch: 0,
}),
};
let req_ext = vulkano_win::required_extensions();
if USE_VALIDATION_LAYERS {
Instance::new(Some(&app_info), vulkano::instance::Version::V1_2, &req_ext, VALIDATION_LAYERS.iter().cloned())
.expect("Unable to create a Vulkan instance")
} else {
Instance::new(Some(&app_info), vulkano::instance::Version::V1_2, &req_ext, None)
.expect("Unable to create a Vulkan instance")
}
}
fn do_loop(mut self) {
let el = self.el;
let sfc = self.sfc;
let mut vk = self.vk;
let mut dims = DEFAULT_DIMS;
el.run(move |ev, _, elcf| {
println!("running event loop: {:?}", ev);
*elcf = ControlFlow::Wait;
match ev {
Event::MainEventsCleared { .. } => {
sfc.window().request_redraw();
}
Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
} => {
println!("closing window");
*elcf = ControlFlow::Exit;
}
Event::WindowEvent {
event: WindowEvent::Resized(size),
..
} => {
println!("resizing to {}x{}", size.width, size.height);
dims[0] = size.width;
dims[1] = size.height;
vk.rebuild_swapchain(&sfc, dims);
}
Event::RedrawRequested(_) => {
println!("redrawing: {:?}", sfc.window().outer_size());
vk.do_frame(&sfc, dims);
}
_ => {}
}
});
}
}
impl<W: 'static + Sync + Send> VulkanData<W> {
fn init(inst: Arc<Instance>, sfc: Arc<Surface<W>>) -> Self {
use std::io::Write;
let device_idxs = PhysicalDevice::enumerate(&inst)
.enumerate()
.filter_map(|(i, dev)| {
if Self::check_physical_device(&dev, &sfc) {
Some((i, dev))
} else {
None
}
})
.collect::<Vec<_>>();
if device_idxs.is_empty() {
panic!("No graphics devices with Vulkan support were detected!");
}
let device_idx = if device_idxs.len() == 1 {
device_idxs[0].0
} else {
println!("Please select a device:");
device_idxs.iter().enumerate().for_each(|(i, (_j, dev))| {
println!("{}: {}", i, dev.properties().device_name.as_ref().unwrap());
});
print!("> ");
std::io::stdout().flush().unwrap_or_else(|_| {
println!("");
()
});
loop {
let mut response = String::new();
std::io::stdin().read_line(&mut response).unwrap();
let len = response.len();
if len == 0 {
panic!("Unexpected EOF while asking about which graphics device to use");
}
match (&response[0..len - 1]).parse::<usize>() {
Ok(n) => {
if n >= device_idxs.len() {
println!("That number isn't in the correct range. Please try again.");
print!("> ");
std::io::stdout().flush().unwrap();
} else {
break n;
}
}
Err(_) => {
println!("That doesn't appear to be a valid number. Please try again.");
print!("> ");
std::io::stdout().flush().unwrap();
}
}
}
};
let phy_dev = PhysicalDevice::from_index(&inst, device_idx).unwrap();
let swp_caps = sfc
.capabilities(phy_dev.clone())
.expect("unable to determine capabilities of surface with device!");
let (device, _qis, compute_queue, present_queue) = Self::create_device(&sfc, phy_dev);
let (compute_pipeline, desc_set_layout) = Self::make_pipeline(&device);
let (swapchain, swapchain_images, desc_sets) =
Self::make_swapchain_and_desc_sets(&device, &sfc, &swp_caps, &compute_queue, &present_queue, &desc_set_layout, DEFAULT_DIMS);
Self {
inst,
swp_caps,
device_idx,
device,
compute_queue,
present_queue,
compute_pipeline,
desc_set_layout,
swapchain,
swapchain_images,
desc_sets,
}
}
fn required_device_extensions() -> DeviceExtensions {
DeviceExtensions {
khr_swapchain: true,
..DeviceExtensions::none()
}
}
fn check_physical_device(device: &PhysicalDevice, surface: &Arc<Surface<W>>) -> bool {
let mut qfs = QueueFamilies::new();
qfs.populate(device, surface);
let sup_ext = DeviceExtensions::supported_by_device(*device);
qfs.is_complete()
&& Self::required_device_extensions().difference(&sup_ext) == DeviceExtensions::none()
}
fn make_pipeline(
device: &Arc<Device>,
) -> (Arc<ComputePipeline>, Arc<UnsafeDescriptorSetLayout>) {
let shader_module = shader::Shader::load(device.clone()).expect("could not create shader!");
let compute_pipeline = Arc::new(ComputePipeline::new(device.clone(), &shader_module.main_entry_point(), &(), None)
.expect("could not create compute pipeline"));
let desc_set_layout = compute_pipeline.layout().descriptor_set_layout(0).expect("could not get the descriptor set layout of the pipeline!").clone();
(compute_pipeline, desc_set_layout)
}
fn make_swapchain_and_desc_sets(
device: &Arc<Device>,
surface: &Arc<Surface<W>>,
swp_cap: &swapchain::Capabilities,
gfxq: &Arc<Queue>,
pstq: &Arc<Queue>,
desc_set_layout: &Arc<UnsafeDescriptorSetLayout>,
dims: [u32; 2],
) -> (Arc<Swapchain<W>>, Vec<Arc<SwapchainImage<W>>>, Vec<Arc<PersistentDescriptorSet<((), PersistentDescriptorSetImg<Arc<ImageView<Arc<SwapchainImage<W>>>>>)>>>) {
let sharing = {
let mut set = HashSet::new();
let cl = |c: &&Arc<Queue>| &***c as *const Queue;
set.insert(HashWrapper::new(gfxq, cl));
set.insert(HashWrapper::new(pstq, cl));
if set.len() == 1 {
SharingMode::from(set.into_iter().next().unwrap().into_inner())
} else {
SharingMode::from(
set.into_iter()
.map(|x: HashWrapper<_, _, _>| x.into_inner())
.collect::<Vec<_>>()
.as_slice(),
)
}
};
let calpha = {
let supported = swp_cap.supported_composite_alpha;
if supported.supports(CompositeAlpha::PostMultiplied) {
CompositeAlpha::PostMultiplied
} else if supported.supports(CompositeAlpha::Opaque) {
CompositeAlpha::Opaque
} else {
panic!("no valid modes of alpha compositing are supported");
}
};
let usage = ImageUsage {
storage: true,
color_attachment: true,
.. ImageUsage::none()
};
let dims = swp_cap.current_extent.unwrap_or(dims);
let (swapchain, swapchain_images) = Swapchain::start(
device.clone(),
surface.clone()
)
.num_images(u32::max(2, swp_cap.min_image_count))
.dimensions(dims)
.transform(swp_cap.current_transform)
.composite_alpha(calpha)
.usage(usage)
.sharing_mode(sharing)
.build()
.expect("unable to create swapchain!");
let desc_sets = (0..swapchain_images.len()).map(|i|
Arc::new(PersistentDescriptorSet::start(desc_set_layout.clone()).add_image(ImageView::new(swapchain_images[i].clone()).unwrap()).unwrap().build().expect("could not build descriptor set!"))
).collect::<Vec<_>>();
(swapchain, swapchain_images, desc_sets)
}
fn create_device(
sfc: &Arc<Surface<W>>,
phy_dev: PhysicalDevice,
) -> (Arc<Device>, QueueFamilies, Arc<Queue>, Arc<Queue>) {
let mut qis = QueueFamilies::new();
qis.populate(&phy_dev, &sfc);
let qfs = vec![qis.compute_idx.unwrap(), qis.present_idx.unwrap()]
.into_iter()
.collect::<HashSet<usize>>()
.into_iter()
.map(|i| (phy_dev.queue_families().nth(i).unwrap(), 1.0f32));
let (device, mut queue_iter) = Device::new(
phy_dev,
&Features::none(),
&Self::required_device_extensions(),
qfs,
)
.expect("could not create graphics device");
let compute_queue = queue_iter.next().unwrap();
let present_queue = queue_iter.next().unwrap_or_else(|| compute_queue.clone());
(device, qis, compute_queue, present_queue)
}
fn rebuild_swapchain(&mut self, sfc: &Arc<Surface<W>>, dims: [u32; 2]) {
let (swapchain, swapchain_images) = self.swapchain.recreate().dimensions(dims).build().expect("could not rebuild swapchain!");
let desc_sets = (0..swapchain_images.len()).map(|i|
Arc::new(PersistentDescriptorSet::start(self.desc_set_layout.clone()).add_image(ImageView::new(swapchain_images[i].clone()).unwrap()).unwrap().build().expect("could not build descriptor set!"))
).collect::<Vec<_>>();
self.swapchain = swapchain;
self.swapchain_images = swapchain_images;
self.desc_sets = desc_sets;
}
fn do_frame(&mut self, sfc: &Arc<Surface<W>>, dims: [u32; 2]) {
let (image_idx, suboptimal, acquire_future) = swapchain::acquire_next_image(self.swapchain.clone(), None).expect("could not acquire swapchain image!");
let mut command_buffer_builder = AutoCommandBufferBuilder::primary(
self.device.clone(),
self.compute_queue.family(),
CommandBufferUsage::OneTimeSubmit,
).expect("could not make command buffer builder!");
command_buffer_builder
.dispatch(
[dims[0], dims[1], 1],
self.compute_pipeline.clone(),
self.desc_sets[image_idx].clone(),
(),
None,
).expect("could not dispatch compute operation!");
let command_buffer = command_buffer_builder.build().expect("could not build command buffer!");
acquire_future
.then_execute(self.compute_queue.clone(), command_buffer).expect("could not queue execution of command buffer!")
.then_signal_semaphore()
.then_swapchain_present(self.present_queue.clone(), self.swapchain.clone(), image_idx)
.flush().expect("could not flush gpu queue!");
if (suboptimal) { self.rebuild_swapchain(sfc, dims); }
}
}
fn main() {
//println!(
// "layers: {:?}",
// vulkano::instance::layers_list()
// .expect("Unable to enumerate available Vulkan layers")
// .map(|ly| (ly.name().to_string(), ly.description().to_string()))
// .collect::<Vec<_>>()
//);
let vw = VulkanWindow::init();
vw.do_loop();
}

8
src/yellow.frag

@ -0,0 +1,8 @@
#version 450
layout(set = 0, binding = 0, rgba8) uniform writeonly image2D img;
void main() {
vec4 color = vec4(1.0, 1.0, 0.0, 1.0);
imageStore(img, ivec2(gl_GlobalInvocationID.xy), color);
}
Loading…
Cancel
Save