hoj-senna / ashen-aetna Goto Github PK
View Code? Open in Web Editor NEWAshen Aetna — Rustily stumbling around on an ash-covered volcano (A tutorial on/in/about/with 3D graphics, Rust, Vulkan, ash)
Ashen Aetna — Rustily stumbling around on an ash-covered volcano (A tutorial on/in/about/with 3D graphics, Rust, Vulkan, ash)
Hello hoj-senna and thank you for this amazing tutorial (:
I had a question about this part:
What is the logic for this 'handle_to_index' variable? If it wants to keep a history about which handle is for which index in an order like this : 'handle -> index' (Red outline number 1 where handle is the key and index is the value) then why did we use index as the key in the second outlined part? (Number 2). I know they are both of type usize, but should'nt we write it in this way? :
self.handle_to_index.insert(handle2, index1);
self.handle_to_index.insert(handle1, index2);
Hello,
thanks for this awesome tutorial! It was a great help getting into Vulkan/Ask.
I just have one question. Normally when working with OpenGL, one has to convert the colors to gamma space at the end of the shader to make the color brightness look more real: pow(radiance.xyz, vec3(1.0/2.2));
.
But you didn't apply the gamma correction. Also, when rendering all brightness levels, it seems to look correct. Applying gamma just makes it way too bright. So it seems like the image is already gamma-corrected.
So I found out, that we create the framebuffer with the format from surfaces.get_formats(physical_device)
, which in my case returns the following:
[src\renderer\swapchain.rs:36] surfaces.get_formats(physical_device)? = [
SurfaceFormatKHR {
format: B8G8R8A8_UNORM,
color_space: SRGB_NONLINEAR,
},
SurfaceFormatKHR {
format: B8G8R8A8_SRGB,
color_space: SRGB_NONLINEAR,
},
SurfaceFormatKHR {
format: A2B10G10R10_UNORM_PACK32,
color_space: SRGB_NONLINEAR,
},
]
And there we only select the first one. Why is that? Is the order always guaranteed to be the same? Then why just don't we specify VK::Format::B8G8R8A8_UNORM
directly?
Also, I was under the impression, that only B8G8R8A8_SRGB
applies the gamma correction automatically? But I can't find any other part of the application, which might influence the SRGB/linear/gamma space behaviour. In fact when specifying the B8G8R8A8_SRGB format instead of the UNORM one, the picture still looks exactly the same?
Thanks,
Michael
I'm learning Vulkan from doc and your doc ,first thanks for you.
when I first display a triangle on screen. it's fine so far..But when i close the window ,it will crash.
In the drop function. unless comment many line.
the Layer could show Error information swapchian and semaphore is invalid..I think maybe the winit loop still call draw, when close.
(It is equivalent to the end of Chapter 11)
how do I solve this problem?
I can't understand why appear this.
this my program
could you give me some help ?
In case you ever decide to rewrite/update your articles in the future I thought I'd mention that vk-mem is effectively unmaintained. They haven't released 0.2.3 to fix the issues with newer Rust, and it seems newer versions of ash don't work with it either. Additionally, it's broken on Windows and the month-old pull request to fix it has gone unnoticed by the maintainer. Community consensus seems to be to use gpu-allocator instead. I've gotten to the chapter where vk-mem is introduced and am adapting it to use gpu-allocator instead since as a Windows user I can't use vk-mem unless that pull request is ever merged.
P.S. Thanks for writing these articles. They are a great help for getting started with Vulkan using Rust and even inspired me to start writing a similar guide to Vulkan and Rust.
Hi,
The section of code where you create the swap chain was causing the program to crash on my system:
let queuefamilies = [qfamindices.0];
let swapchain_create_info = vk::SwapchainCreateInfoKHR::builder()
.surface(surface)
.min_image_count(
3.max(surface_capabilities.min_image_count)
.min(surface_capabilities.max_image_count),
)
.image_format(surface_formats.first().unwrap().format)
.image_color_space(surface_formats.first().unwrap().color_space)
.image_extent(surface_capabilities.current_extent)
.image_array_layers(1)
.image_usage(vk::ImageUsageFlags::COLOR_ATTACHMENT)
.image_sharing_mode(vk::SharingMode::EXCLUSIVE)
.queue_family_indices(&queuefamilies)
.pre_transform(surface_capabilities.current_transform)
.composite_alpha(vk::CompositeAlphaFlagsKHR::OPAQUE)
.present_mode(vk::PresentModeKHR::FIFO);
let swapchain_loader = ash::extensions::khr::Swapchain::new(&instance, &logical_device);
let swapchain = unsafe { swapchain_loader.create_swapchain(&swapchain_create_info, None)? };
This was due to the GPU on my system returning 0 for max_image_count
which meant the code would try to create a swap chain with zero images. In the spec a zero for max_image_count
means there is no maximum so the code to select the number of images should account for this.
As well as the current_extent
can be set to 0xffffffff
to show that the surface size is determined by the parameter passed in which needs to be handled differently as well. This is probably due to using Wayland instead of Xlib since the window is not created until you start drawing to it.
My modified version of this section of the code:
let mut min_image_count = 3.max(surface_capabilities.min_image_count);
if surface_capabilities.max_image_count != 0 {
min_image_count = min_image_count.max(surface_capabilities.max_image_count);
}
let image_extent = if surface_capabilities.current_extent.width == u32::MAX
&& surface_capabilities.current_extent.height == u32::MAX
{
vk::Extent2D {
width: 800,
height: 600,
}
} else {
surface_capabilities.current_extent
};
let queue_families = [queue_index];
let swapchain_create_info = vk::SwapchainCreateInfoKHR::builder()
.surface(surface.surface)
.min_image_count(min_image_count)
.image_format(surface_format.format)
.image_color_space(surface_format.color_space)
.image_extent(image_extent)
.image_array_layers(1)
.image_usage(vk::ImageUsageFlags::COLOR_ATTACHMENT)
.image_sharing_mode(vk::SharingMode::EXCLUSIVE)
.queue_family_indices(&queue_families)
.pre_transform(surface_capabilities.current_transform)
.composite_alpha(vk::CompositeAlphaFlagsKHR::OPAQUE)
.present_mode(vk::PresentModeKHR::FIFO);
Hey,
just wanted to let you know of some of the improvements I would make. Might be of interest to everyone, that used your guide as starting point and wants to improve it a little bit further.
We can make the code platform independent by using ash_window, like so:
let surface = unsafe { ash_window::create_surface(entry, instance, window, None).unwrap() };
let surface_loader = khr::Surface::new(entry, instance);
Also add ash-window = "0.5.0"
to your cargo.toml
.
Also makes the code a little bit shorter.
As long as vk-mem version 0.2.3. is not released (gwihlidal/vk-mem-rs#46), use vk-mem = { git = "https://github.com/gwihlidal/vk-mem-rs", version = "0.2.3" }
in cargo.toml
.
Current version is not working, see gwihlidal/vk-mem-rs#47;
We should pick a device more carefully. Prefer discrete GPUs, but maybe rank by other metrics. See https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Physical_devices_and_queue_families.
See https://vulkan-tutorial.com/Drawing_a_triangle/Presentation/Window_surface, chapter "Querying for presentation support" and following.
Because it's possible that the queue supporting the drawing command won't support presentation. So we should create a separate presentation queue, and use it for presentation. We already have a separate transfer queue, but it seems like it's never used.
EDIT: On the other hand, it's very rare (not sure if such a device does even exist), where there is not a queue that supports presentation and drawing. So maybe just use that one queue and panic otherwise. Because using two different queues might have some implications later, where transfers occur.
The Mailbox presentation mode should be preferred.
Example:
pub fn choose_present_mode(
&self,
physical_device: vk::PhysicalDevice,
) -> Result<vk::PresentModeKHR, vk::Result> {
let present_modes = self.get_present_modes(physical_device)?;
Ok(if present_modes.contains(&vk::PresentModeKHR::MAILBOX) {
vk::PresentModeKHR::MAILBOX
} else {
vk::PresentModeKHR::FIFO
})
}
Similarly, we should choose a presentation format. Right now, we just select the first entry (*surface.get_formats(physical_device)?.first().unwrap();
, remember? See #4).
E.g.:
pub fn choose_format(
&self,
physical_device: vk::PhysicalDevice,
) -> Result<vk::SurfaceFormatKHR, vk::Result> {
let formats = self.get_formats(physical_device)?;
let optimal = formats.iter().find(|x| {
x.format == vk::Format::B8G8R8A8_UNORM
&& x.color_space == vk::ColorSpaceKHR::SRGB_NONLINEAR
});
Ok(if let Some(optimal) = optimal {
*optimal
} else {
formats[0]
})
}
Also consider using vk::Format::B8G8R8A8_SRGB
to apply gamma correction automatically (currently is no gamma correction applied). But then also the shader inputs have to be in SRGB space.
In chapter 37/38 we display textures. But when using the Mailbox presentation mode, the texture will flicker. This is because we have to create a WriteDescriptorSet for every texture descriptor set (of every swapchain image), like so:
let texture_id = renderer.new_texture_from_file("./assets/images/rust.png")?;
if let Some(texture) = renderer.texture_storage.get(texture_id) {
for dss in &renderer.descriptor_sets_texture {
let imageinfo = vk::DescriptorImageInfo {
image_layout: vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL,
image_view: texture.imageview,
sampler: texture.sampler,
..Default::default()
};
let descriptorwrite_image = vk::WriteDescriptorSet {
dst_set: *dss,
dst_binding: 0,
dst_array_element: 0,
descriptor_type: vk::DescriptorType::COMBINED_IMAGE_SAMPLER,
descriptor_count: 1,
p_image_info: [imageinfo].as_ptr(),
..Default::default()
};
unsafe {
renderer
.device
.update_descriptor_sets(&[descriptorwrite_image], &[]);
}
}
}
Oh and lastly it would be nice, if all the code would be available in this repository, too instead of just in the markdown files.
I might extend this list in the future, as I finish your tutorial.
I was wondering if you had any recommendation as to where to go after reaching the last chapter, since I know there’s missing content, would you recommend continuing with the vulkan-tutorial, if so what chapter?
Thank you.
Hej, first of thanks for this amazing and in-depth tutorial (might be even beyond that). I implemented it while following along, with one difference, I'm using 0.31
of ash. Which produces the following panic in chapter 18:
thread 'main' panicked at 'attempted to zero-initialize type `ash::Device`, which is invalid', /home/xla/.rustup/toolchains/nightly-2020-12-13-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/mem/mod.rs:623:9
It stems from gwihlidal/vk-mem-rs#42 and should be fixed once 0.2.3
has landed.
Including my Cargo.toml
:
[package]
name = "vulkanrenderer"
version = "0.1.0"
authors = ["Alexander Simmerl <[email protected]>"]
edition = "2018"
[dependencies]
ash = "0.31"
vk-mem = "0.2"
vk-shader-macros = "0.2"
winit = "0.24"
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.