almost done!
This commit is contained in:
parent
ac7e8889db
commit
60760ba67f
|
|
@ -1,9 +0,0 @@
|
||||||
[target.x86_64-unknown-linux-gnu]
|
|
||||||
linker = "clang"
|
|
||||||
rustflags = [
|
|
||||||
"-Clink-arg=-fuse-ld=mold",
|
|
||||||
|
|
||||||
# Nightly
|
|
||||||
"-Zshare-generics=y",
|
|
||||||
"-Zthreads=0",
|
|
||||||
]
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use rand::{Rng, SeedableRng};
|
use rand::{Rng, SeedableRng};
|
||||||
use renderer::{Renderer2, render_graph, swapchain::WindowSurface};
|
use renderer::{
|
||||||
|
Renderer2, render_graph,
|
||||||
|
swapchain::{Surface, SwapchainConfiguration},
|
||||||
|
};
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
use tracing_subscriber::EnvFilter;
|
use tracing_subscriber::EnvFilter;
|
||||||
use winit::{
|
use winit::{
|
||||||
|
|
@ -18,7 +21,7 @@ struct WindowState {
|
||||||
egui_platform: egui_winit_platform::Platform,
|
egui_platform: egui_winit_platform::Platform,
|
||||||
demo_app: egui_demo_lib::DemoWindows,
|
demo_app: egui_demo_lib::DemoWindows,
|
||||||
scale_factor: f64,
|
scale_factor: f64,
|
||||||
surface: WindowSurface,
|
surface: Surface,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct WinitState {
|
struct WinitState {
|
||||||
|
|
@ -53,13 +56,24 @@ impl WinitState {
|
||||||
fn handle_final_resize(&mut self, window_id: WindowId, new_size: PhysicalSize<u32>) {
|
fn handle_final_resize(&mut self, window_id: WindowId, new_size: PhysicalSize<u32>) {
|
||||||
_ = (window_id, new_size);
|
_ = (window_id, new_size);
|
||||||
info!("TODO: implement resize events");
|
info!("TODO: implement resize events");
|
||||||
if let Some(window) = self.windows.get(&window_id) {
|
if let Some(WindowState { surface, .. }) = self.windows.get(&window_id) {
|
||||||
window
|
let config = surface
|
||||||
.surface
|
.swapchain()
|
||||||
.recreate_with(Some(renderer::Extent2D {
|
.as_ref()
|
||||||
width: new_size.width,
|
.map(|swapchain| swapchain.config().clone())
|
||||||
height: new_size.height,
|
.unwrap_or(SwapchainConfiguration::default());
|
||||||
}))
|
|
||||||
|
surface
|
||||||
|
.configure(
|
||||||
|
self.renderer.device(),
|
||||||
|
SwapchainConfiguration {
|
||||||
|
extent: renderer::Extent2D {
|
||||||
|
width: new_size.width,
|
||||||
|
height: new_size.height,
|
||||||
|
},
|
||||||
|
..config
|
||||||
|
},
|
||||||
|
)
|
||||||
.expect("swapchain recreation");
|
.expect("swapchain recreation");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -91,10 +105,8 @@ impl WinitState {
|
||||||
let dev = renderer.device().clone();
|
let dev = renderer.device().clone();
|
||||||
|
|
||||||
use renderer::ash::vk::Handle;
|
use renderer::ash::vk::Handle;
|
||||||
use renderer::device::DeviceOwned;
|
|
||||||
let [r, g, b]: [f32; 3] =
|
let [r, g, b]: [f32; 3] =
|
||||||
rand::prelude::StdRng::seed_from_u64(window.surface.surface.handle().as_raw())
|
rand::prelude::StdRng::seed_from_u64(window.surface.raw().as_raw()).random();
|
||||||
.random();
|
|
||||||
render_graph::clear_pass(rg, renderer::util::Rgba([r, g, b, 1.0]), framebuffer);
|
render_graph::clear_pass(rg, renderer::util::Rgba([r, g, b, 1.0]), framebuffer);
|
||||||
egui_pre_pass(
|
egui_pre_pass(
|
||||||
&dev,
|
&dev,
|
||||||
|
|
@ -290,7 +302,7 @@ impl ApplicationHandler for WinitState {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let _ = tracing_subscriber::fmt()
|
_ = tracing_subscriber::fmt()
|
||||||
.with_env_filter(EnvFilter::from_default_env())
|
.with_env_filter(EnvFilter::from_default_env())
|
||||||
.init();
|
.init();
|
||||||
let ev = EventLoop::new().unwrap();
|
let ev = EventLoop::new().unwrap();
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,13 @@
|
||||||
#!/bin/bash
|
#! /usr/bin/env nix-shell
|
||||||
|
#! nix-shell -i bash -p shader-slang
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
SLANGC="/opt/shader-slang-bin/bin/slangc"
|
SLANGC="slangc"
|
||||||
|
|
||||||
$SLANGC egui.slang -profile glsl_450 -target spirv -o egui_vert.spv -entry vertex
|
$SLANGC egui.slang -profile glsl_450 -target spirv -o egui_vert.spv -entry vertex
|
||||||
$SLANGC egui.slang -profile glsl_450 -target spirv -o egui_frag.spv -entry fragment
|
$SLANGC egui.slang -profile glsl_450 -target spirv -o egui_frag.spv -entry fragment
|
||||||
$SLANGC egui.slang -profile glsl_450 -target spirv -entry vertex -entry fragment -o egui.spv
|
$SLANGC egui.slang -profile glsl_450 -target spirv -entry vertex -entry fragment -o egui.spv
|
||||||
$SLANGC wireframe.slang -profile glsl_450 -target spirv -entry vertex -entry fragment -o wireframe.spv
|
$SLANGC wireframe.slang -profile glsl_450 -target spirv -entry vertex -entry fragment -o wireframe.spv
|
||||||
$SLANGC font.slang -profile glsl_450 -target spirv -entry vertex -entry fragment -o font.spv
|
$SLANGC font.slang -profile glsl_450 -target spirv -entry vertex -entry fragment -o font.spv
|
||||||
$SLANGC font.slang -profile glsl_450 -target spirv -entry mesh -entry task -entry fragment_barycentric -o font_mesh.spv
|
# $SLANGC font.slang -profile glsl_450 -target spirv -entry mesh -entry task -entry fragment_barycentric -o font_mesh.spv
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,14 @@ struct Fragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct VertexIn {
|
struct VertexIn {
|
||||||
[[vk::layout(0)]] float2 pos;
|
[[vk::location(0)]] float2 pos;
|
||||||
[[vk::layout(1)]] float2 uv;
|
[[vk::location(1)]] float2 uv;
|
||||||
[[vk::layout(2)]] float4 color;
|
[[vk::location(2)]] float4 color;
|
||||||
}
|
}
|
||||||
struct VertexOut {
|
struct VertexOut {
|
||||||
[[vk::layout(0)]] float4 color;
|
[[vk::location(0)]] float4 color;
|
||||||
[[vk::layout(1)]] float2 uv;
|
[[vk::location(1)]] float2 uv;
|
||||||
[[vk::layout(2), flat]] uint draw_id;
|
nointerpolation [[vk::location(2)]] uint draw_id;
|
||||||
float4 position : SV_Position;
|
float4 position : SV_Position;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1,9 +1,9 @@
|
||||||
|
|
||||||
struct VertexIn {
|
struct VertexIn {
|
||||||
[[vk::layout(0)]] float2 pos;
|
[[vk::location(0)]] float2 pos;
|
||||||
}
|
}
|
||||||
struct VertexOut {
|
struct VertexOut {
|
||||||
[[vk::layout(0)]] float4 color;
|
[[vk::location(0)]] float4 color;
|
||||||
float4 position : SV_Position;
|
float4 position : SV_Position;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -1,9 +1,9 @@
|
||||||
struct VertexIn {
|
struct VertexIn {
|
||||||
[[vk::layout(0)]] float2 pos;
|
[[vk::location(0)]] float2 pos;
|
||||||
[[vk::layout(1)]] float4 color;
|
[[vk::location(1)]] float4 color;
|
||||||
}
|
}
|
||||||
struct VertexOut {
|
struct VertexOut {
|
||||||
[[vk::layout(0)]] float4 color;
|
[[vk::location(0)]] float4 color;
|
||||||
float4 position : SV_Position;
|
float4 position : SV_Position;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -74,7 +74,7 @@ impl Default for BufferDesc {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Buffer {
|
pub struct Buffer {
|
||||||
buffer: DeviceObject<vk::Buffer>,
|
buffer: DeviceObject<vk::Buffer>,
|
||||||
desc: BufferDesc,
|
pub desc: BufferDesc,
|
||||||
alloc: Allocation,
|
alloc: Allocation,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -106,6 +106,12 @@ impl Buffer {
|
||||||
},
|
},
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
device
|
||||||
|
.raw
|
||||||
|
.bind_buffer_memory(buffer, alloc.memory(), alloc.offset())?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
buffer: DeviceObject::new(buffer, device.clone(), desc.name.clone()),
|
buffer: DeviceObject::new(buffer, device.clone(), desc.name.clone()),
|
||||||
desc,
|
desc,
|
||||||
|
|
@ -138,7 +144,9 @@ impl Buffer {
|
||||||
|
|
||||||
pub fn map(&mut self) -> Option<&[u8]> {
|
pub fn map(&mut self) -> Option<&[u8]> {
|
||||||
if let Some(alloc) = self.alloc.allocation() {
|
if let Some(alloc) = self.alloc.allocation() {
|
||||||
alloc.mapped_slice()
|
alloc
|
||||||
|
.mapped_slice()
|
||||||
|
.map(|slice| &slice[..self.desc.size as usize])
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
@ -146,7 +154,9 @@ impl Buffer {
|
||||||
|
|
||||||
pub fn map_mut(&mut self) -> Option<&mut [u8]> {
|
pub fn map_mut(&mut self) -> Option<&mut [u8]> {
|
||||||
if let Some(alloc) = self.alloc.allocation_mut() {
|
if let Some(alloc) = self.alloc.allocation_mut() {
|
||||||
alloc.mapped_slice_mut()
|
alloc
|
||||||
|
.mapped_slice_mut()
|
||||||
|
.map(|slice| &mut slice[..self.desc.size as usize])
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -568,7 +568,7 @@ impl DeviceInner {
|
||||||
let buffer_vec: Vec<u8>;
|
let buffer_vec: Vec<u8>;
|
||||||
|
|
||||||
let name_bytes = if name.is_empty() {
|
let name_bytes = if name.is_empty() {
|
||||||
&[]
|
&[0]
|
||||||
} else if name.len() < buffer.len() {
|
} else if name.len() < buffer.len() {
|
||||||
buffer[..name.len()].copy_from_slice(name.as_bytes());
|
buffer[..name.len()].copy_from_slice(name.as_bytes());
|
||||||
&buffer[..]
|
&buffer[..]
|
||||||
|
|
@ -582,8 +582,14 @@ impl DeviceInner {
|
||||||
&buffer_vec
|
&buffer_vec
|
||||||
};
|
};
|
||||||
|
|
||||||
let name = CStr::from_bytes_with_nul(name_bytes)
|
let name = CStr::from_bytes_until_nul(name_bytes)
|
||||||
.expect("there is always a nul terminator because we added one");
|
.inspect_err(|_| {
|
||||||
|
panic!(
|
||||||
|
"debug name {:?} contains interior nul byte, which is not allowed",
|
||||||
|
name_bytes
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.expect("{name_bytes:?} there is always a nul terminator because we added one");
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
_ = self
|
_ = self
|
||||||
|
|
|
||||||
|
|
@ -373,7 +373,7 @@ pub fn egui_pre_pass(
|
||||||
extent: vk::Extent3D {
|
extent: vk::Extent3D {
|
||||||
width: size.0,
|
width: size.0,
|
||||||
height: size.1,
|
height: size.1,
|
||||||
depth: 0,
|
depth: 1,
|
||||||
},
|
},
|
||||||
}],
|
}],
|
||||||
);
|
);
|
||||||
|
|
@ -508,7 +508,8 @@ pub fn egui_pass(
|
||||||
let map = staging.map_mut().unwrap();
|
let map = staging.map_mut().unwrap();
|
||||||
|
|
||||||
let (st_vertices, rest) = map.split_at_mut(vertices_size);
|
let (st_vertices, rest) = map.split_at_mut(vertices_size);
|
||||||
let (st_indices, st_drawcalls) = rest.split_at_mut(indices_size);
|
let (st_indices, rest) = rest.split_at_mut(indices_size);
|
||||||
|
let (st_drawcalls, _rest) = rest.split_at_mut(draw_calls_size);
|
||||||
st_vertices.copy_from_slice(bytemuck::cast_slice(&vertices));
|
st_vertices.copy_from_slice(bytemuck::cast_slice(&vertices));
|
||||||
st_indices.copy_from_slice(bytemuck::cast_slice(&indices));
|
st_indices.copy_from_slice(bytemuck::cast_slice(&indices));
|
||||||
st_drawcalls.copy_from_slice(bytemuck::cast_slice(&draw_calls));
|
st_drawcalls.copy_from_slice(bytemuck::cast_slice(&draw_calls));
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::Device;
|
use super::Device;
|
||||||
use ash::vk;
|
use ash::vk::{self, Handle};
|
||||||
use gpu_allocator::vulkan::{AllocationCreateDesc, AllocationScheme};
|
use gpu_allocator::vulkan::{AllocationCreateDesc, AllocationScheme};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
|
|
||||||
|
|
@ -172,10 +172,33 @@ impl Image {
|
||||||
},
|
},
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
Self::new_with_allocation_unchecked(
|
||||||
|
device.clone(),
|
||||||
|
image,
|
||||||
|
Allocation::Owned(DeviceObject::new_without_name(alloc, device)),
|
||||||
|
desc,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_with_allocation_unchecked(
|
||||||
|
device: Device,
|
||||||
|
image: vk::Image,
|
||||||
|
allocation: Allocation,
|
||||||
|
desc: ImageDesc,
|
||||||
|
) -> crate::Result<Self> {
|
||||||
|
// bind memory
|
||||||
|
if let Some(alloc) = allocation.allocation() {
|
||||||
|
unsafe {
|
||||||
|
device
|
||||||
|
.raw
|
||||||
|
.bind_image_memory(image, alloc.memory(), alloc.offset())?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
image: ImageInner::Allocated(
|
image: ImageInner::Allocated(
|
||||||
DeviceObject::new(image, device.clone(), desc.name.clone()),
|
DeviceObject::new(image, device, desc.name.clone()),
|
||||||
Allocation::Owned(DeviceObject::new_without_name(alloc, device)),
|
allocation,
|
||||||
),
|
),
|
||||||
desc,
|
desc,
|
||||||
views: Default::default(),
|
views: Default::default(),
|
||||||
|
|
@ -213,14 +236,7 @@ impl Image {
|
||||||
return Err(crate::Error::Unspecified);
|
return Err(crate::Error::Unspecified);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Self {
|
Self::new_with_allocation_unchecked(device, image, allocation, desc)
|
||||||
image: ImageInner::Allocated(
|
|
||||||
DeviceObject::new(image, device.clone(), desc.name.clone()),
|
|
||||||
allocation,
|
|
||||||
),
|
|
||||||
desc,
|
|
||||||
views: Default::default(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_swapchain_image(image: vk::Image, swapchain: &Swapchain) -> Self {
|
pub fn from_swapchain_image(image: vk::Image, swapchain: &Swapchain) -> Self {
|
||||||
|
|
@ -252,7 +268,7 @@ impl Image {
|
||||||
device: Device,
|
device: Device,
|
||||||
desc: &ImageDesc,
|
desc: &ImageDesc,
|
||||||
) -> crate::Result<(vk::Image, vk::MemoryRequirements)> {
|
) -> crate::Result<(vk::Image, vk::MemoryRequirements)> {
|
||||||
tracing::trace!("allocate new image with desc={desc:?}");
|
tracing::trace!("new image with desc={desc:?}");
|
||||||
let ImageDesc {
|
let ImageDesc {
|
||||||
flags,
|
flags,
|
||||||
format,
|
format,
|
||||||
|
|
@ -406,7 +422,7 @@ impl Image {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if desc.mip_range.0 > self.desc.mip_levels || desc.mip_range.1 > self.desc.mip_levels {
|
if !desc.mip_range.fits_in(self.desc.mip_levels) {
|
||||||
tracing::error!(
|
tracing::error!(
|
||||||
"image view mip range {:?} exceeds image mip levels {}",
|
"image view mip range {:?} exceeds image mip levels {}",
|
||||||
desc.mip_range,
|
desc.mip_range,
|
||||||
|
|
@ -432,6 +448,11 @@ impl Image {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tracing::trace!(
|
||||||
|
"new image view with desc={desc:?} for image {:x}",
|
||||||
|
self.image().as_raw()
|
||||||
|
);
|
||||||
|
|
||||||
let create_info = vk::ImageViewCreateInfo::default()
|
let create_info = vk::ImageViewCreateInfo::default()
|
||||||
.flags(desc.flags)
|
.flags(desc.flags)
|
||||||
.image(self.image())
|
.image(self.image())
|
||||||
|
|
@ -441,9 +462,9 @@ impl Image {
|
||||||
.subresource_range(
|
.subresource_range(
|
||||||
vk::ImageSubresourceRange::default()
|
vk::ImageSubresourceRange::default()
|
||||||
.aspect_mask(desc.aspect)
|
.aspect_mask(desc.aspect)
|
||||||
.base_mip_level(desc.mip_range.0)
|
.base_mip_level(desc.mip_range.start)
|
||||||
.level_count(desc.mip_range.count())
|
.level_count(desc.mip_range.count())
|
||||||
.base_array_layer(desc.layer_range.0)
|
.base_array_layer(desc.layer_range.start)
|
||||||
.layer_count(desc.layer_range.count()),
|
.layer_count(desc.layer_range.count()),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -497,6 +518,8 @@ impl ImageViewDesc {
|
||||||
Self {
|
Self {
|
||||||
kind: vk::ImageViewType::TYPE_2D,
|
kind: vk::ImageViewType::TYPE_2D,
|
||||||
aspect: vk::ImageAspectFlags::COLOR,
|
aspect: vk::ImageAspectFlags::COLOR,
|
||||||
|
mip_range: MipRange { start: 0, end: 1 },
|
||||||
|
layer_range: MipRange { start: 0, end: 1 },
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -557,17 +580,35 @@ impl ImageViewDesc {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub struct MipRange(u32, u32);
|
pub struct MipRange {
|
||||||
|
start: u32,
|
||||||
|
end: u32,
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for MipRange {
|
impl Default for MipRange {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self(0, vk::REMAINING_ARRAY_LAYERS)
|
Self {
|
||||||
|
start: 0,
|
||||||
|
end: vk::REMAINING_ARRAY_LAYERS,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MipRange {
|
impl MipRange {
|
||||||
fn count(&self) -> u32 {
|
pub fn count(&self) -> u32 {
|
||||||
self.1
|
self.end
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fits_in(&self, total_mips: u32) -> bool {
|
||||||
|
self.start < total_mips && (self.end == vk::REMAINING_MIP_LEVELS || self.end <= total_mips)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn end(&self) -> Option<u32> {
|
||||||
|
if self.end == vk::REMAINING_ARRAY_LAYERS {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(self.end)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -584,7 +625,7 @@ impl<R: core::ops::RangeBounds<u32>> From<R> for MipRange {
|
||||||
std::ops::Bound::Unbounded => vk::REMAINING_MIP_LEVELS,
|
std::ops::Bound::Unbounded => vk::REMAINING_MIP_LEVELS,
|
||||||
};
|
};
|
||||||
|
|
||||||
Self(start, count)
|
Self { start, end: count }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use std::{
|
use std::{
|
||||||
cmp::Ordering,
|
cmp::Ordering,
|
||||||
ffi::{CStr, CString},
|
ffi::{CStr, CString},
|
||||||
|
mem::MaybeUninit,
|
||||||
ops::Deref,
|
ops::Deref,
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
@ -20,8 +21,14 @@ pub struct DebugUtilsCreateInfo {
|
||||||
pub message_type: vk::DebugUtilsMessageTypeFlagsEXT,
|
pub message_type: vk::DebugUtilsMessageTypeFlagsEXT,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) struct InstanceExtensions {
|
||||||
|
pub(crate) get_surface_capabilities2: Option<khr::get_surface_capabilities2::Instance>,
|
||||||
|
pub(crate) surface_maintenance1: Option<()>,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct InstanceInner {
|
pub struct InstanceInner {
|
||||||
pub raw: ash::Instance,
|
pub raw: ash::Instance,
|
||||||
|
pub(crate) extensions: InstanceExtensions,
|
||||||
pub entry: Entry,
|
pub entry: Entry,
|
||||||
pub(crate) _debug_utils: DebugUtils,
|
pub(crate) _debug_utils: DebugUtils,
|
||||||
}
|
}
|
||||||
|
|
@ -65,7 +72,7 @@ const DEBUG_LAYER_SETTINGS: &[vk::LayerSettingEXT] = &[];
|
||||||
const DEBUG_LAYER_SETTINGS: &[vk::LayerSettingEXT] = &[
|
const DEBUG_LAYER_SETTINGS: &[vk::LayerSettingEXT] = &[
|
||||||
vk::LayerSettingEXT {
|
vk::LayerSettingEXT {
|
||||||
p_layer_name: VALIDATION_LAYER.as_ptr(),
|
p_layer_name: VALIDATION_LAYER.as_ptr(),
|
||||||
p_setting_name: c"VK_KHRONOS_VALIDATION_VALIDATE_BEST_PRACTICES".as_ptr(),
|
p_setting_name: c"validate_best_practices".as_ptr(),
|
||||||
value_count: 1,
|
value_count: 1,
|
||||||
p_values: &[1u8; 1] as *const u8 as _,
|
p_values: &[1u8; 1] as *const u8 as _,
|
||||||
ty: vk::LayerSettingTypeEXT::BOOL32,
|
ty: vk::LayerSettingTypeEXT::BOOL32,
|
||||||
|
|
@ -73,7 +80,7 @@ const DEBUG_LAYER_SETTINGS: &[vk::LayerSettingEXT] = &[
|
||||||
},
|
},
|
||||||
vk::LayerSettingEXT {
|
vk::LayerSettingEXT {
|
||||||
p_layer_name: VALIDATION_LAYER.as_ptr(),
|
p_layer_name: VALIDATION_LAYER.as_ptr(),
|
||||||
p_setting_name: c"VK_KHRONOS_VALIDATION_VALIDATE_BEST_PRACTICES_AMD".as_ptr(),
|
p_setting_name: c"validate_best_practices_amd".as_ptr(),
|
||||||
value_count: 1,
|
value_count: 1,
|
||||||
p_values: &[1u8; 1] as *const u8 as _,
|
p_values: &[1u8; 1] as *const u8 as _,
|
||||||
ty: vk::LayerSettingTypeEXT::BOOL32,
|
ty: vk::LayerSettingTypeEXT::BOOL32,
|
||||||
|
|
@ -81,7 +88,7 @@ const DEBUG_LAYER_SETTINGS: &[vk::LayerSettingEXT] = &[
|
||||||
},
|
},
|
||||||
vk::LayerSettingEXT {
|
vk::LayerSettingEXT {
|
||||||
p_layer_name: VALIDATION_LAYER.as_ptr(),
|
p_layer_name: VALIDATION_LAYER.as_ptr(),
|
||||||
p_setting_name: c"VK_KHRONOS_VALIDATION_VALIDATE_SYNC".as_ptr(),
|
p_setting_name: c"validate_sync".as_ptr(),
|
||||||
value_count: 1,
|
value_count: 1,
|
||||||
p_values: &[1u8; 1] as *const u8 as _,
|
p_values: &[1u8; 1] as *const u8 as _,
|
||||||
ty: vk::LayerSettingTypeEXT::BOOL32,
|
ty: vk::LayerSettingTypeEXT::BOOL32,
|
||||||
|
|
@ -147,6 +154,12 @@ impl Instance {
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
requested_extensions.push(make_extension!(ext::layer_settings));
|
requested_extensions.push(make_extension!(ext::layer_settings));
|
||||||
|
|
||||||
|
// These are wanted for surface capabilities querying, but not strictly
|
||||||
|
// required, and are only supported on newer devices, especially on
|
||||||
|
// NVIDIA cards.
|
||||||
|
requested_extensions.push(make_extension!(khr::get_surface_capabilities2));
|
||||||
|
requested_extensions.push(make_extension!(ext::surface_maintenance1));
|
||||||
|
|
||||||
let (extensions, unsupported_extensions) =
|
let (extensions, unsupported_extensions) =
|
||||||
get_extensions(&entry, &layers, requested_extensions, desc.display_handle)?;
|
get_extensions(&entry, &layers, requested_extensions, desc.display_handle)?;
|
||||||
|
|
||||||
|
|
@ -161,14 +174,14 @@ impl Instance {
|
||||||
.iter()
|
.iter()
|
||||||
.map(|layer| layer.as_ptr())
|
.map(|layer| layer.as_ptr())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let extensions = extensions
|
let extension_names = extensions
|
||||||
.iter()
|
.iter()
|
||||||
.map(|ext| ext.name.as_ptr())
|
.map(|ext| ext.name.as_ptr())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let create_info = vk::InstanceCreateInfo::default()
|
let create_info = vk::InstanceCreateInfo::default()
|
||||||
.application_info(&app_info)
|
.application_info(&app_info)
|
||||||
.enabled_extension_names(&extensions)
|
.enabled_extension_names(&extension_names)
|
||||||
.enabled_layer_names(&layers)
|
.enabled_layer_names(&layers)
|
||||||
.push_next(&mut validation_info);
|
.push_next(&mut validation_info);
|
||||||
|
|
||||||
|
|
@ -201,8 +214,18 @@ impl Instance {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let extensions = InstanceExtensions {
|
||||||
|
get_surface_capabilities2: extensions
|
||||||
|
.contains(&make_extension!(khr::get_surface_capabilities2))
|
||||||
|
.then(|| khr::get_surface_capabilities2::Instance::new(&entry, &instance)),
|
||||||
|
surface_maintenance1: extensions
|
||||||
|
.contains(&make_extension!(ext::surface_maintenance1))
|
||||||
|
.then_some(()),
|
||||||
|
};
|
||||||
|
|
||||||
let instance = Arc::new(InstanceInner {
|
let instance = Arc::new(InstanceInner {
|
||||||
raw: instance,
|
raw: instance,
|
||||||
|
extensions,
|
||||||
_debug_utils: debug_utils,
|
_debug_utils: debug_utils,
|
||||||
entry,
|
entry,
|
||||||
});
|
});
|
||||||
|
|
@ -225,17 +248,19 @@ impl Instance {
|
||||||
pdevs.pop().ok_or(Error::NoAdapter)
|
pdevs.pop().ok_or(Error::NoAdapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Queries the surface capabilities of the given physical device and
|
||||||
|
/// surface, including supported formats and present modes.
|
||||||
|
/// If a present mode is provided, and the
|
||||||
|
/// `VK_KHR_get_surface_capabilities2` and `VK_EXT_surface_maintenance1`
|
||||||
|
/// extensions are available, it will also query present mode compatibility
|
||||||
|
/// information to filter the present modes based on the provided initial
|
||||||
|
/// mode.
|
||||||
pub(crate) fn get_adapter_surface_capabilities(
|
pub(crate) fn get_adapter_surface_capabilities(
|
||||||
&self,
|
&self,
|
||||||
pdev: vk::PhysicalDevice,
|
pdev: vk::PhysicalDevice,
|
||||||
surface: &Surface,
|
surface: &Surface,
|
||||||
|
present_mode: Option<vk::PresentModeKHR>,
|
||||||
) -> crate::Result<SurfaceCapabilities> {
|
) -> crate::Result<SurfaceCapabilities> {
|
||||||
let capabilities = unsafe {
|
|
||||||
surface
|
|
||||||
.functor
|
|
||||||
.get_physical_device_surface_capabilities(pdev, surface.raw)?
|
|
||||||
};
|
|
||||||
|
|
||||||
let formats = unsafe {
|
let formats = unsafe {
|
||||||
surface
|
surface
|
||||||
.functor
|
.functor
|
||||||
|
|
@ -248,8 +273,52 @@ impl Instance {
|
||||||
.get_physical_device_surface_present_modes(pdev, surface.raw)?
|
.get_physical_device_surface_present_modes(pdev, surface.raw)?
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let generic_caps = unsafe {
|
||||||
|
surface
|
||||||
|
.functor
|
||||||
|
.get_physical_device_surface_capabilities(pdev, surface.raw)?
|
||||||
|
};
|
||||||
|
|
||||||
|
let (capabilities, present_modes) = if let Some(ref functor) =
|
||||||
|
self.extensions.get_surface_capabilities2
|
||||||
|
&& self.extensions.surface_maintenance1.is_some()
|
||||||
|
{
|
||||||
|
let mut capabilities = vk::SurfaceCapabilities2KHR::default();
|
||||||
|
let mut surface_info =
|
||||||
|
vk::PhysicalDeviceSurfaceInfo2KHR::default().surface(surface.raw());
|
||||||
|
|
||||||
|
let present_mode = present_mode.unwrap_or(present_modes[0]);
|
||||||
|
let mut surface_present_mode =
|
||||||
|
vk::SurfacePresentModeEXT::default().present_mode(present_mode);
|
||||||
|
surface_info = surface_info.push_next(&mut surface_present_mode);
|
||||||
|
|
||||||
|
let mut present_modes = MaybeUninit::<[vk::PresentModeKHR; 8]>::uninit();
|
||||||
|
let mut present_mode_info = vk::SurfacePresentModeCompatibilityEXT::default()
|
||||||
|
.present_modes(unsafe { present_modes.assume_init_mut() });
|
||||||
|
capabilities = capabilities.push_next(&mut present_mode_info);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
functor.get_physical_device_surface_capabilities2(
|
||||||
|
pdev,
|
||||||
|
&surface_info,
|
||||||
|
&mut capabilities,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
(capabilities.surface_capabilities, unsafe {
|
||||||
|
let num_present_modes = present_mode_info.present_mode_count as usize;
|
||||||
|
present_modes.assume_init()[..num_present_modes].to_vec()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
(generic_caps, present_modes)
|
||||||
|
};
|
||||||
|
|
||||||
|
// surface.functor
|
||||||
|
// .get_physical_device_surface_capabilities2(pdev, surface.raw, present_mode)?;
|
||||||
|
|
||||||
Ok(SurfaceCapabilities {
|
Ok(SurfaceCapabilities {
|
||||||
capabilities,
|
capabilities,
|
||||||
|
min_image_count: generic_caps.min_image_count,
|
||||||
formats,
|
formats,
|
||||||
present_modes,
|
present_modes,
|
||||||
})
|
})
|
||||||
|
|
@ -260,7 +329,7 @@ impl Instance {
|
||||||
pdev: vk::PhysicalDevice,
|
pdev: vk::PhysicalDevice,
|
||||||
) -> crate::Result<PhysicalDeviceInfo> {
|
) -> crate::Result<PhysicalDeviceInfo> {
|
||||||
let properties = get_physical_device_properties(&self.inner, pdev)?;
|
let properties = get_physical_device_properties(&self.inner, pdev)?;
|
||||||
let features = get_physical_device_features(&self.inner, pdev, &properties)?;
|
let features = get_physical_device_features(&self.inner, pdev, &properties);
|
||||||
|
|
||||||
Ok(PhysicalDeviceInfo {
|
Ok(PhysicalDeviceInfo {
|
||||||
pdev,
|
pdev,
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
slice_partition_dedup
|
slice_partition_dedup
|
||||||
)]
|
)]
|
||||||
|
|
||||||
use std::{collections::HashMap, fmt::Debug, sync::Arc};
|
use std::{collections::HashMap, fmt::Debug, path::PathBuf, sync::Arc};
|
||||||
|
|
||||||
use raw_window_handle::{RawDisplayHandle, RawWindowHandle};
|
use raw_window_handle::{RawDisplayHandle, RawWindowHandle};
|
||||||
|
|
||||||
|
|
@ -115,6 +115,8 @@ pub enum Error {
|
||||||
view_kind: vk::ImageViewType,
|
view_kind: vk::ImageViewType,
|
||||||
image_kind: vk::ImageType,
|
image_kind: vk::ImageType,
|
||||||
},
|
},
|
||||||
|
#[error("Asset missing at path {0:?}")]
|
||||||
|
AssetMissing(PathBuf),
|
||||||
#[error("Unspecified Error")]
|
#[error("Unspecified Error")]
|
||||||
Unspecified,
|
Unspecified,
|
||||||
#[error("BEEP BOOP create an error variant for {0} BEEP BOOP")]
|
#[error("BEEP BOOP create an error variant for {0} BEEP BOOP")]
|
||||||
|
|
@ -181,6 +183,9 @@ pub struct PhysicalDeviceInfo {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SurfaceCapabilities {
|
pub struct SurfaceCapabilities {
|
||||||
pub capabilities: SurfaceCapabilitiesKHR,
|
pub capabilities: SurfaceCapabilitiesKHR,
|
||||||
|
/// The minimum number of images that must be present in the swapchain for
|
||||||
|
/// the surface for any present mode supported by the surface.
|
||||||
|
pub min_image_count: u32,
|
||||||
pub formats: Vec<vk::SurfaceFormatKHR>,
|
pub formats: Vec<vk::SurfaceFormatKHR>,
|
||||||
pub present_modes: Vec<vk::PresentModeKHR>,
|
pub present_modes: Vec<vk::PresentModeKHR>,
|
||||||
}
|
}
|
||||||
|
|
@ -558,10 +563,15 @@ fn get_physical_device_features(
|
||||||
instance: &InstanceInner,
|
instance: &InstanceInner,
|
||||||
pdev: vk::PhysicalDevice,
|
pdev: vk::PhysicalDevice,
|
||||||
properties: &PhysicalDeviceProperties,
|
properties: &PhysicalDeviceProperties,
|
||||||
) -> Result<PhysicalDeviceFeatures> {
|
) -> PhysicalDeviceFeatures {
|
||||||
let mut features = PhysicalDeviceFeatures::default();
|
let mut features = PhysicalDeviceFeatures::default();
|
||||||
let mut features2 = vk::PhysicalDeviceFeatures2::default();
|
let mut features2 = vk::PhysicalDeviceFeatures2::default();
|
||||||
|
|
||||||
|
features2 = features2
|
||||||
|
.push_next(&mut features.core11)
|
||||||
|
.push_next(&mut features.core12)
|
||||||
|
.push_next(&mut features.core13);
|
||||||
|
|
||||||
if properties.supports_extension(make_extension!(ext::mesh_shader)) {
|
if properties.supports_extension(make_extension!(ext::mesh_shader)) {
|
||||||
features2 = features2.push_next(
|
features2 = features2.push_next(
|
||||||
features
|
features
|
||||||
|
|
@ -576,7 +586,9 @@ fn get_physical_device_features(
|
||||||
.get_physical_device_features2(pdev, &mut features2);
|
.get_physical_device_features2(pdev, &mut features2);
|
||||||
}
|
}
|
||||||
|
|
||||||
todo!()
|
features.core = features2.features;
|
||||||
|
|
||||||
|
features
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_physical_device_properties(
|
fn get_physical_device_properties(
|
||||||
|
|
@ -738,7 +750,6 @@ impl EguiState {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
max_sets: 1,
|
max_sets: 1,
|
||||||
..Default::default()
|
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
let descriptor_layout = pipeline::DescriptorSetLayout::new(
|
let descriptor_layout = pipeline::DescriptorSetLayout::new(
|
||||||
|
|
@ -931,7 +942,25 @@ impl Renderer2 {
|
||||||
let device = adapter.create_logical_device(
|
let device = adapter.create_logical_device(
|
||||||
&instance,
|
&instance,
|
||||||
&[],
|
&[],
|
||||||
PhysicalDeviceFeatures::default(),
|
PhysicalDeviceFeatures {
|
||||||
|
core11: vk::PhysicalDeviceVulkan11Features {
|
||||||
|
shader_draw_parameters: vk::TRUE,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
core12: vk::PhysicalDeviceVulkan12Features {
|
||||||
|
descriptor_binding_partially_bound: vk::TRUE,
|
||||||
|
descriptor_binding_sampled_image_update_after_bind: vk::TRUE,
|
||||||
|
runtime_descriptor_array: vk::TRUE,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
core13: vk::PhysicalDeviceVulkan13Features {
|
||||||
|
synchronization2: vk::TRUE,
|
||||||
|
dynamic_rendering: vk::TRUE,
|
||||||
|
maintenance4: vk::TRUE,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
Some(display),
|
Some(display),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
|
@ -975,13 +1004,8 @@ impl Renderer2 {
|
||||||
surface.configure(
|
surface.configure(
|
||||||
&self.device,
|
&self.device,
|
||||||
swapchain::SwapchainConfiguration {
|
swapchain::SwapchainConfiguration {
|
||||||
present_mode: vk::PresentModeKHR::MAILBOX,
|
|
||||||
format: vk::Format::R8G8B8A8_UNORM,
|
|
||||||
color_space: vk::ColorSpaceKHR::SRGB_NONLINEAR,
|
|
||||||
image_count: 3,
|
|
||||||
extent,
|
extent,
|
||||||
composite_alpha_mode: vk::CompositeAlphaFlagsKHR::OPAQUE,
|
..Default::default()
|
||||||
usage: vk::ImageUsageFlags::COLOR_ATTACHMENT | vk::ImageUsageFlags::TRANSFER_DST,
|
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
Ok(surface)
|
Ok(surface)
|
||||||
|
|
|
||||||
|
|
@ -449,13 +449,14 @@ impl ShaderModule {
|
||||||
pub fn new_from_path<P: AsRef<Path>>(device: Device, path: P) -> crate::Result<Self> {
|
pub fn new_from_path<P: AsRef<Path>>(device: Device, path: P) -> crate::Result<Self> {
|
||||||
use std::io::{BufReader, Read, Seek};
|
use std::io::{BufReader, Read, Seek};
|
||||||
|
|
||||||
let mut file = std::fs::File::open(path)?;
|
let path = path.as_ref();
|
||||||
|
let mut file =
|
||||||
|
std::fs::File::open(path).map_err(|_| crate::Error::AssetMissing(path.to_owned()))?;
|
||||||
let size = file.seek(std::io::SeekFrom::End(0))? / 4;
|
let size = file.seek(std::io::SeekFrom::End(0))? / 4;
|
||||||
file.seek(std::io::SeekFrom::Start(0))?;
|
file.seek(std::io::SeekFrom::Start(0))?;
|
||||||
let mut reader = BufReader::new(file);
|
let mut reader = BufReader::new(file);
|
||||||
|
|
||||||
let mut buffer = Vec::<u32>::with_capacity(size as usize);
|
let mut buffer = vec![0; size as usize];
|
||||||
buffer.resize(size as usize, 0);
|
|
||||||
let size = reader.read(bytemuck::cast_slice_mut(buffer.as_mut_slice()))?;
|
let size = reader.read(bytemuck::cast_slice_mut(buffer.as_mut_slice()))?;
|
||||||
buffer.resize(size / 4, 0);
|
buffer.resize(size / 4, 0);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
|
num::NonZero,
|
||||||
ops::Deref,
|
ops::Deref,
|
||||||
sync::{
|
sync::{
|
||||||
Arc,
|
Arc,
|
||||||
|
|
@ -30,7 +31,6 @@ pub struct Surface {
|
||||||
#[debug(skip)]
|
#[debug(skip)]
|
||||||
pub(crate) functor: khr::surface::Instance,
|
pub(crate) functor: khr::surface::Instance,
|
||||||
pub(crate) instance: Instance,
|
pub(crate) instance: Instance,
|
||||||
pub(crate) capabilities: Mutex<HashMap<vk::PhysicalDevice, SurfaceCapabilities>>,
|
|
||||||
pub(crate) swapchain: RwLock<Option<Arc<Swapchain>>>,
|
pub(crate) swapchain: RwLock<Option<Arc<Swapchain>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -43,23 +43,6 @@ impl Drop for Surface {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Surface {
|
impl Surface {
|
||||||
pub fn get_capabilities<'a>(
|
|
||||||
&'a self,
|
|
||||||
adapter: vk::PhysicalDevice,
|
|
||||||
) -> parking_lot::MappedMutexGuard<'a, SurfaceCapabilities> {
|
|
||||||
let lock = self.capabilities.lock();
|
|
||||||
parking_lot::MutexGuard::map(
|
|
||||||
lock,
|
|
||||||
|caps: &mut HashMap<vk::PhysicalDevice, SurfaceCapabilities>| {
|
|
||||||
caps.entry(adapter).or_insert_with(|| {
|
|
||||||
self.instance
|
|
||||||
.get_adapter_surface_capabilities(adapter, self)
|
|
||||||
.expect("surface is not compatible with the adapter")
|
|
||||||
})
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn configure(&self, device: &Device, config: SwapchainConfiguration) -> Result<()> {
|
pub fn configure(&self, device: &Device, config: SwapchainConfiguration) -> Result<()> {
|
||||||
let guard = self.swapchain.read();
|
let guard = self.swapchain.read();
|
||||||
if let Some(swapchain) = guard.as_ref()
|
if let Some(swapchain) = guard.as_ref()
|
||||||
|
|
@ -80,7 +63,7 @@ impl Surface {
|
||||||
drop(guard);
|
drop(guard);
|
||||||
self.swapchain.write().replace(Arc::new(new_swapchain));
|
self.swapchain.write().replace(Arc::new(new_swapchain));
|
||||||
|
|
||||||
todo!()
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
|
@ -100,7 +83,6 @@ impl Surface {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
raw,
|
raw,
|
||||||
functor,
|
functor,
|
||||||
capabilities: Mutex::new(HashMap::new()),
|
|
||||||
swapchain: RwLock::new(None),
|
swapchain: RwLock::new(None),
|
||||||
instance: instance.clone(),
|
instance: instance.clone(),
|
||||||
})
|
})
|
||||||
|
|
@ -136,7 +118,6 @@ impl Surface {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
raw,
|
raw,
|
||||||
functor,
|
functor,
|
||||||
capabilities: Mutex::new(HashMap::new()),
|
|
||||||
swapchain: RwLock::new(None),
|
swapchain: RwLock::new(None),
|
||||||
instance: instance.clone(),
|
instance: instance.clone(),
|
||||||
})
|
})
|
||||||
|
|
@ -150,8 +131,8 @@ impl Surface {
|
||||||
instance: &Instance,
|
instance: &Instance,
|
||||||
adapter: &PhysicalDeviceInfo,
|
adapter: &PhysicalDeviceInfo,
|
||||||
config: &mut SwapchainConfiguration,
|
config: &mut SwapchainConfiguration,
|
||||||
) -> Result<()> {
|
) -> Result<SurfaceCapabilities> {
|
||||||
let surface_caps = instance.get_adapter_surface_capabilities(adapter.pdev, self)?;
|
let surface_caps = instance.get_adapter_surface_capabilities(adapter.pdev, self, None)?;
|
||||||
|
|
||||||
let max_image_dim = adapter.properties.core.limits.max_image_dimension2_d;
|
let max_image_dim = adapter.properties.core.limits.max_image_dimension2_d;
|
||||||
if config.extent.width > max_image_dim || config.extent.height > max_image_dim {
|
if config.extent.width > max_image_dim || config.extent.height > max_image_dim {
|
||||||
|
|
@ -182,10 +163,39 @@ impl Surface {
|
||||||
config.present_mode = fallback_mode;
|
config.present_mode = fallback_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We do this calculation with the original surface capabilities, which
|
||||||
|
// gives us the maximum min_image_count of all present modes, which
|
||||||
|
// allows us to switch present modes without needing to recreate the
|
||||||
|
// swapchain.
|
||||||
|
let max_image_count = NonZero::new(surface_caps.capabilities.max_image_count)
|
||||||
|
.map(|n| n.get())
|
||||||
|
.unwrap_or(u32::MAX);
|
||||||
|
let min_image_count = surface_caps.min_image_count;
|
||||||
|
|
||||||
|
// we want `config.image_count` images acquired at the same time, but we
|
||||||
|
// also need to respect the surface's minimum and maximum image count
|
||||||
|
// limits.
|
||||||
|
let image_count = (min_image_count + config.image_count).min(max_image_count);
|
||||||
|
|
||||||
|
// in case the surface's image count limits prevent us from having the
|
||||||
|
// desired number of images in flight, reduce the requested image count
|
||||||
|
// to fit within the limits.
|
||||||
|
// this value corresponds to `S-M` in the Vulkan spec.
|
||||||
|
config.image_count = image_count - min_image_count;
|
||||||
|
|
||||||
|
// different present modes have different image counts/extents: now that
|
||||||
|
// we know we have a supported present mode, re-query the surface
|
||||||
|
// capabilities to get the correct image counts.
|
||||||
|
let surface_caps = instance.get_adapter_surface_capabilities(
|
||||||
|
adapter.pdev,
|
||||||
|
self,
|
||||||
|
Some(config.present_mode),
|
||||||
|
)?;
|
||||||
|
|
||||||
if !surface_caps.formats.iter().any(|&format| {
|
if !surface_caps.formats.iter().any(|&format| {
|
||||||
format.format == config.format && format.color_space == config.color_space
|
format.format == config.format && format.color_space == config.color_space
|
||||||
}) {
|
}) {
|
||||||
// wgpu just rejects the swapchain if the format is not supported. is that smarter?
|
// (note): wgpu just rejects the swapchain if the format is not supported. is that smarter?
|
||||||
// find a fallback format
|
// find a fallback format
|
||||||
let format = surface_caps
|
let format = surface_caps
|
||||||
.formats
|
.formats
|
||||||
|
|
@ -206,16 +216,16 @@ impl Surface {
|
||||||
config.color_space = format.color_space;
|
config.color_space = format.color_space;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(surface_caps)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn get_fallback_swapchain_configuration(
|
pub fn get_fallback_swapchain_configuration(
|
||||||
&self,
|
&self,
|
||||||
instance: &Instance,
|
instance: &Instance,
|
||||||
adapter: &PhysicalDeviceInfo,
|
adapter: &PhysicalDeviceInfo,
|
||||||
) -> Result<SwapchainConfiguration> {
|
) -> Result<SwapchainConfiguration> {
|
||||||
let surface_caps = instance.get_adapter_surface_capabilities(adapter.pdev, self)?;
|
let surface_caps = instance.get_adapter_surface_capabilities(adapter.pdev, self, None)?;
|
||||||
|
|
||||||
let present_mode = surface_caps
|
let present_mode = surface_caps
|
||||||
.present_modes
|
.present_modes
|
||||||
|
|
@ -279,11 +289,15 @@ impl Surface {
|
||||||
) -> Option<impl std::future::Future<Output = crate::Result<(SwapchainImage, bool)>>> {
|
) -> Option<impl std::future::Future<Output = crate::Result<(SwapchainImage, bool)>>> {
|
||||||
// ensure lock does not block for the entire duration of the async image acquisition.
|
// ensure lock does not block for the entire duration of the async image acquisition.
|
||||||
let swapchain = self.swapchain.read().as_ref().cloned();
|
let swapchain = self.swapchain.read().as_ref().cloned();
|
||||||
if let Some(swapchain) = swapchain {
|
swapchain.map(|swapchain| swapchain.acquire_image())
|
||||||
Some(swapchain.acquire_image())
|
}
|
||||||
} else {
|
|
||||||
None
|
pub fn swapchain(&self) -> parking_lot::RwLockReadGuard<'_, Option<Arc<Swapchain>>> {
|
||||||
}
|
self.swapchain.read()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn raw(&self) -> vk::SurfaceKHR {
|
||||||
|
self.raw
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -364,10 +378,13 @@ impl Swapchain {
|
||||||
mut config: SwapchainConfiguration,
|
mut config: SwapchainConfiguration,
|
||||||
old_swapchain: Option<&Self>,
|
old_swapchain: Option<&Self>,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
surface.validate_swapchain_configuration(&device.instance, &device.adapter, &mut config)?;
|
let surface_caps = surface.validate_swapchain_configuration(
|
||||||
let surface_caps = device
|
&device.instance,
|
||||||
.instance
|
&device.adapter,
|
||||||
.get_adapter_surface_capabilities(device.adapter.pdev, surface)?;
|
&mut config,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
tracing::trace!("surface capabilities: {surface_caps:#?}");
|
||||||
|
|
||||||
let functor = device
|
let functor = device
|
||||||
.device_extensions
|
.device_extensions
|
||||||
|
|
@ -388,7 +405,7 @@ impl Swapchain {
|
||||||
.present_mode(config.present_mode)
|
.present_mode(config.present_mode)
|
||||||
.image_color_space(config.color_space)
|
.image_color_space(config.color_space)
|
||||||
.image_format(config.format)
|
.image_format(config.format)
|
||||||
.min_image_count(surface_caps.capabilities.min_image_count)
|
.min_image_count(surface_caps.min_image_count + config.image_count)
|
||||||
.image_usage(config.usage)
|
.image_usage(config.usage)
|
||||||
.image_array_layers(1)
|
.image_array_layers(1)
|
||||||
.image_extent(config.extent)
|
.image_extent(config.extent)
|
||||||
|
|
@ -463,7 +480,11 @@ impl Swapchain {
|
||||||
.collect::<VkResult<Vec<_>>>()?
|
.collect::<VkResult<Vec<_>>>()?
|
||||||
};
|
};
|
||||||
|
|
||||||
tracing::trace!("fences: {fences:?}");
|
tracing::trace!(
|
||||||
|
image_count = images.len(),
|
||||||
|
min_image_count = surface_caps.capabilities.min_image_count,
|
||||||
|
config = ?config,
|
||||||
|
"created swapchain:");
|
||||||
|
|
||||||
Ok(Swapchain {
|
Ok(Swapchain {
|
||||||
functor: device
|
functor: device
|
||||||
|
|
@ -590,6 +611,10 @@ impl Swapchain {
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn config(&self) -> &SwapchainConfiguration {
|
||||||
|
&self.config
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
@ -691,6 +716,20 @@ pub struct SwapchainConfiguration {
|
||||||
pub usage: vk::ImageUsageFlags,
|
pub usage: vk::ImageUsageFlags,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for SwapchainConfiguration {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
present_mode: vk::PresentModeKHR::MAILBOX,
|
||||||
|
format: vk::Format::R8G8B8A8_UNORM,
|
||||||
|
color_space: vk::ColorSpaceKHR::SRGB_NONLINEAR,
|
||||||
|
image_count: 3,
|
||||||
|
extent: vk::Extent2D::default().width(1).height(1),
|
||||||
|
composite_alpha_mode: vk::CompositeAlphaFlagsKHR::OPAQUE,
|
||||||
|
usage: vk::ImageUsageFlags::TRANSFER_DST | vk::ImageUsageFlags::COLOR_ATTACHMENT,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Swapchain {
|
impl Swapchain {
|
||||||
pub fn with_locked<T, F: FnOnce(&Self) -> T>(&self, f: F) -> T {
|
pub fn with_locked<T, F: FnOnce(&Self) -> T>(&self, f: F) -> T {
|
||||||
let _lock = self.guard.lock();
|
let _lock = self.guard.lock();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue