Compare commits
15 commits
fdfc74c668
...
dbc4294c09
Author | SHA1 | Date | |
---|---|---|---|
|
dbc4294c09 | ||
|
9242d44755 | ||
|
2cad8adb55 | ||
|
6274b6e5a8 | ||
|
3332e59453 | ||
|
107c43ee77 | ||
|
efd73fce43 | ||
|
131887b633 | ||
|
146ffa654f | ||
|
3deca28391 | ||
|
5a1ed9340e | ||
|
30269f7bd2 | ||
|
003d507573 | ||
|
0f96689079 | ||
|
260275d694 |
3
.cargo/config.toml
Normal file
3
.cargo/config.toml
Normal file
|
@ -0,0 +1,3 @@
|
|||
[target.x86_64-unknown-linux-gnu]
|
||||
linker = "clang"
|
||||
rustflags = ["-C", "link-arg=-fuse-ld=/usr/bin/mold"]
|
|
@ -7,6 +7,11 @@ members = [
|
|||
"crates/game"
|
||||
]
|
||||
|
||||
[profile.debug-release]
|
||||
inherits = "release"
|
||||
opt-level = 2
|
||||
debug = true
|
||||
|
||||
[workspace.dependencies]
|
||||
anyhow = "1.0.89"
|
||||
ash = "0.38.0"
|
||||
|
|
|
@ -26,6 +26,17 @@ pub struct BufferDesc {
|
|||
pub alloc_flags: vk_mem::AllocationCreateFlags,
|
||||
}
|
||||
|
||||
impl std::hash::Hash for BufferDesc {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.flags.hash(state);
|
||||
self.size.hash(state);
|
||||
self.usage.hash(state);
|
||||
self.queue_families.hash(state);
|
||||
self.mem_usage.hash(state);
|
||||
self.alloc_flags.bits().hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for BufferDesc {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("BufferDesc")
|
||||
|
@ -49,6 +60,20 @@ impl std::fmt::Debug for BufferDesc {
|
|||
}
|
||||
}
|
||||
|
||||
impl Eq for BufferDesc {}
|
||||
impl PartialEq for BufferDesc {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.flags == other.flags
|
||||
// for hashmaps, `Eq` may be more strict than `Hash`
|
||||
&& self.name == other.name
|
||||
&& self.size == other.size
|
||||
&& self.usage == other.usage
|
||||
&& self.queue_families == other.queue_families
|
||||
&& self.mem_usage == other.mem_usage
|
||||
&& self.alloc_flags.bits() == other.alloc_flags.bits()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for BufferDesc {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
|
|
|
@ -64,6 +64,7 @@ impl SingleUseCommandPool {
|
|||
}
|
||||
|
||||
/// get the underlying pool, bypassing the mutex
|
||||
#[allow(dead_code)]
|
||||
pub unsafe fn pool(&self) -> vk::CommandPool {
|
||||
self.pool.data_ptr().read()
|
||||
}
|
||||
|
@ -129,6 +130,8 @@ pub enum CommandBufferState {
|
|||
#[derive(Debug)]
|
||||
#[repr(transparent)]
|
||||
struct CommandBufferState2(AtomicU8);
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl CommandBufferState2 {
|
||||
fn initial() -> Self {
|
||||
Self(AtomicU8::new(CommandBufferState::Initial as u8))
|
||||
|
@ -188,11 +191,13 @@ impl !Sync for SingleUseCommand {}
|
|||
impl SingleUseCommand {
|
||||
pub fn new(device: Device, pool: Arc<SingleUseCommandPool>) -> VkResult<Self> {
|
||||
let buffer = unsafe {
|
||||
let buffer = pool.pool.with_locked(|pool| {
|
||||
let alloc_info = vk::CommandBufferAllocateInfo::default()
|
||||
.command_buffer_count(1)
|
||||
.command_pool(pool.pool())
|
||||
.command_pool(*pool)
|
||||
.level(vk::CommandBufferLevel::PRIMARY);
|
||||
let buffer = device.dev().allocate_command_buffers(&alloc_info)?[0];
|
||||
Ok(device.dev().allocate_command_buffers(&alloc_info)?[0])
|
||||
})?;
|
||||
|
||||
device.dev().begin_command_buffer(
|
||||
buffer,
|
||||
|
|
|
@ -184,7 +184,7 @@ pub fn egui_pre_pass(
|
|||
rg.import_image(
|
||||
img,
|
||||
Access {
|
||||
layout: Some(vk::ImageLayout::GENERAL),
|
||||
layout: vk::ImageLayout::GENERAL,
|
||||
..Access::undefined()
|
||||
},
|
||||
),
|
||||
|
@ -229,12 +229,12 @@ pub fn egui_pre_pass(
|
|||
Access {
|
||||
stage: vk::PipelineStageFlags2::NONE,
|
||||
mask: vk::AccessFlags2::empty(),
|
||||
layout: Some(vk::ImageLayout::UNDEFINED),
|
||||
layout: vk::ImageLayout::UNDEFINED,
|
||||
},
|
||||
Access {
|
||||
stage: vk::PipelineStageFlags2::TRANSFER,
|
||||
mask: vk::AccessFlags2::TRANSFER_WRITE,
|
||||
layout: Some(vk::ImageLayout::TRANSFER_DST_OPTIMAL),
|
||||
layout: vk::ImageLayout::TRANSFER_DST_OPTIMAL,
|
||||
},
|
||||
None,
|
||||
)
|
||||
|
@ -270,12 +270,12 @@ pub fn egui_pre_pass(
|
|||
Access {
|
||||
stage: vk::PipelineStageFlags2::TRANSFER,
|
||||
mask: vk::AccessFlags2::TRANSFER_WRITE,
|
||||
layout: Some(vk::ImageLayout::TRANSFER_DST_OPTIMAL),
|
||||
layout: vk::ImageLayout::TRANSFER_DST_OPTIMAL,
|
||||
},
|
||||
Access {
|
||||
stage: vk::PipelineStageFlags2::TRANSFER,
|
||||
mask: vk::AccessFlags2::TRANSFER_READ,
|
||||
layout: Some(vk::ImageLayout::TRANSFER_SRC_OPTIMAL),
|
||||
layout: vk::ImageLayout::TRANSFER_SRC_OPTIMAL,
|
||||
},
|
||||
None,
|
||||
);
|
||||
|
@ -285,12 +285,12 @@ pub fn egui_pre_pass(
|
|||
Access {
|
||||
stage: vk::PipelineStageFlags2::NONE,
|
||||
mask: vk::AccessFlags2::empty(),
|
||||
layout: Some(vk::ImageLayout::GENERAL),
|
||||
layout: vk::ImageLayout::GENERAL,
|
||||
},
|
||||
Access {
|
||||
stage: vk::PipelineStageFlags2::TRANSFER,
|
||||
mask: vk::AccessFlags2::TRANSFER_WRITE,
|
||||
layout: Some(vk::ImageLayout::TRANSFER_DST_OPTIMAL),
|
||||
layout: vk::ImageLayout::TRANSFER_DST_OPTIMAL,
|
||||
},
|
||||
None,
|
||||
);
|
||||
|
@ -334,12 +334,12 @@ pub fn egui_pre_pass(
|
|||
Access {
|
||||
stage: vk::PipelineStageFlags2::TRANSFER,
|
||||
mask: vk::AccessFlags2::TRANSFER_WRITE,
|
||||
layout: Some(vk::ImageLayout::TRANSFER_DST_OPTIMAL),
|
||||
layout: vk::ImageLayout::TRANSFER_DST_OPTIMAL,
|
||||
},
|
||||
Access {
|
||||
stage: vk::PipelineStageFlags2::ALL_COMMANDS,
|
||||
mask: vk::AccessFlags2::empty(),
|
||||
layout: Some(vk::ImageLayout::GENERAL),
|
||||
layout: vk::ImageLayout::GENERAL,
|
||||
},
|
||||
None,
|
||||
)
|
||||
|
@ -374,13 +374,13 @@ pub fn egui_pre_pass(
|
|||
(
|
||||
*id,
|
||||
Access {
|
||||
layout: Some(vk::ImageLayout::GENERAL),
|
||||
layout: vk::ImageLayout::GENERAL,
|
||||
..Access::undefined()
|
||||
},
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
record,
|
||||
record: Some(record),
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
@ -730,7 +730,7 @@ pub fn egui_pass(
|
|||
rg.add_pass(PassDesc {
|
||||
reads,
|
||||
writes,
|
||||
record,
|
||||
record: Some(record),
|
||||
});
|
||||
|
||||
Ok(to_remove_tex_ids)
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
use std::{borrow::Cow, collections::HashMap, sync::Arc};
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
collections::HashMap,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
define_device_owned_handle,
|
||||
|
@ -33,7 +37,6 @@ pub struct ImageDesc {
|
|||
impl std::hash::Hash for ImageDesc {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.flags.hash(state);
|
||||
self.name.hash(state);
|
||||
self.format.hash(state);
|
||||
self.kind.hash(state);
|
||||
self.mip_levels.hash(state);
|
||||
|
@ -128,7 +131,7 @@ define_device_owned_handle! {
|
|||
format: vk::Format,
|
||||
views: Mutex<HashMap<ImageViewDesc, vk::ImageView>>,
|
||||
aliases: Mutex<HashMap<ImageDesc, Arc<Image>>>,
|
||||
parent: Option<Arc<Image>>,
|
||||
parent: Option<Weak<Image>>,
|
||||
is_swapchain_image: bool,
|
||||
} => |this| if !this.is_swapchain_image {
|
||||
unsafe {
|
||||
|
@ -266,20 +269,19 @@ impl Image {
|
|||
self.size.depth
|
||||
}
|
||||
|
||||
fn get_parent(self: &Arc<Self>) -> Arc<Image> {
|
||||
self.parent.clone().unwrap_or_else(|| self.clone())
|
||||
}
|
||||
|
||||
fn get_alloc(&self) -> Option<&vk_mem::Allocation> {
|
||||
self.alloc
|
||||
fn get_parent_or_self(self: &Arc<Self>) -> Arc<Image> {
|
||||
self.parent
|
||||
.as_ref()
|
||||
.or(self.parent.as_ref().and_then(|image| image.get_alloc()))
|
||||
.map(|weak| weak.upgrade().unwrap())
|
||||
.unwrap_or_else(|| self.clone())
|
||||
}
|
||||
|
||||
pub unsafe fn get_alias(self: &Arc<Self>, desc: ImageDesc) -> VkResult<Arc<Self>> {
|
||||
self.get_parent().get_alias_inner(desc)
|
||||
self.get_parent_or_self().get_alias_inner(desc)
|
||||
}
|
||||
|
||||
/// must only be called on the primogenitor of an image.
|
||||
/// get the primogenitor with [`Self::get_parent_or_self()`]
|
||||
unsafe fn get_alias_inner(self: Arc<Self>, desc: ImageDesc) -> VkResult<Arc<Image>> {
|
||||
use std::collections::hash_map::Entry::*;
|
||||
match self.aliases.lock().entry(desc.clone()) {
|
||||
|
@ -327,7 +329,8 @@ impl Image {
|
|||
.mip_levels(mip_levels);
|
||||
|
||||
let alloc = self
|
||||
.get_alloc()
|
||||
.alloc
|
||||
.as_ref()
|
||||
.expect("no alloc associated with image. is this the framebuffer?");
|
||||
|
||||
let image = unsafe {
|
||||
|
@ -342,7 +345,6 @@ impl Image {
|
|||
image
|
||||
};
|
||||
|
||||
let parent = self.parent.clone().unwrap_or(self.clone());
|
||||
let alias = Self::construct(
|
||||
self.device().clone(),
|
||||
image,
|
||||
|
@ -352,8 +354,8 @@ impl Image {
|
|||
format,
|
||||
Mutex::new(HashMap::new()),
|
||||
Mutex::new(HashMap::new()),
|
||||
Some(parent.clone()),
|
||||
parent.is_swapchain_image,
|
||||
Some(Arc::downgrade(&self)),
|
||||
self.is_swapchain_image,
|
||||
)?;
|
||||
Ok(vacant.insert(Arc::new(alias)).clone())
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ mod egui_pass;
|
|||
mod images;
|
||||
mod pipeline;
|
||||
mod render_graph;
|
||||
mod rendering;
|
||||
mod sync;
|
||||
mod util;
|
||||
|
||||
|
@ -441,6 +442,7 @@ impl PhysicalDeviceProperties {
|
|||
pub struct PhysicalDevice {
|
||||
pdev: vk::PhysicalDevice,
|
||||
queue_families: DeviceQueueFamilies,
|
||||
#[allow(dead_code)]
|
||||
properties: PhysicalDeviceProperties,
|
||||
}
|
||||
|
||||
|
@ -729,7 +731,7 @@ impl Swapchain {
|
|||
format,
|
||||
)
|
||||
.inspect(|img| {
|
||||
img.get_view(images::ImageViewDesc {
|
||||
_ = img.get_view(images::ImageViewDesc {
|
||||
name: Some(format!("swapchain-{swapchain:?}-image-{i}-view").into()),
|
||||
kind: vk::ImageViewType::TYPE_2D,
|
||||
format,
|
||||
|
@ -2534,7 +2536,6 @@ impl<W> Renderer<W> {
|
|||
let mut rg = render_graph::RenderGraph::new();
|
||||
let (textures_to_remove, cmds) = util::timed("record command buffer", || {
|
||||
let framebuffer = rg.import_image(frame.image.clone(), Access::undefined());
|
||||
rg.mark_as_output(framebuffer);
|
||||
|
||||
render_graph::clear_pass(&mut rg, clear_color, framebuffer);
|
||||
egui_pass::egui_pre_pass(
|
||||
|
@ -2555,7 +2556,8 @@ impl<W> Renderer<W> {
|
|||
output,
|
||||
framebuffer,
|
||||
)?;
|
||||
render_graph::present_pass(&mut rg, framebuffer);
|
||||
|
||||
rg.mark_as_output(framebuffer, Access::present());
|
||||
|
||||
Result::Ok((textures_to_remove, rg.resolve(dev.clone())?))
|
||||
})?;
|
||||
|
|
File diff suppressed because it is too large
Load diff
1
crates/renderer/src/rendering/mod.rs
Normal file
1
crates/renderer/src/rendering/mod.rs
Normal file
|
@ -0,0 +1 @@
|
|||
|
|
@ -414,3 +414,100 @@ impl<'a, T: 'a> DerefMut for WithLifetime<'a, T> {
|
|||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
bitflags::bitflags! {
|
||||
pub struct PipelineAccess: u32 {
|
||||
const TRANSFER = 1 << 0;
|
||||
const VERTEX_ATTRIBUTE_INPUT = 1 << 1;
|
||||
const DRAW_INDIRECT = 1 << 2;
|
||||
const VERTEX_INPUT = 1 << 3;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BitIter<'a> {
|
||||
bits: &'a [u64],
|
||||
num_bits: usize,
|
||||
bit_offset: usize,
|
||||
bit_index: usize,
|
||||
}
|
||||
|
||||
impl<'a> std::fmt::Display for BitIter<'a> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("BitIter")
|
||||
.field_with("bits", |f| {
|
||||
write!(f, "[")?;
|
||||
for bit in self.clone() {
|
||||
write!(f, "{bit}, ")?;
|
||||
}
|
||||
write!(f, " ]")
|
||||
})
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> BitIter<'a> {
|
||||
pub fn new(bits: &'a [u64], num_bits: usize) -> Self {
|
||||
Self {
|
||||
bits,
|
||||
num_bits,
|
||||
bit_index: 0,
|
||||
bit_offset: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn chunks(self, chunk_size: usize) -> ChunkedBitIter<'a> {
|
||||
ChunkedBitIter {
|
||||
inner: self,
|
||||
chunk_size,
|
||||
pos: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Iterator for BitIter<'_> {
|
||||
type Item = usize;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
loop {
|
||||
if self.bit_index >= self.num_bits {
|
||||
return None;
|
||||
}
|
||||
|
||||
let bit_index = self.bit_index + self.bit_offset;
|
||||
let byte_idx = bit_index / 64;
|
||||
let byte_offset = bit_index % 64;
|
||||
self.bit_index += 1;
|
||||
|
||||
if (self.bits[byte_idx] >> byte_offset) & 1 == 1 {
|
||||
return Some(self.bit_index - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ChunkedBitIter<'a> {
|
||||
inner: BitIter<'a>,
|
||||
chunk_size: usize,
|
||||
pos: usize,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for ChunkedBitIter<'a> {
|
||||
type Item = BitIter<'a>;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.pos >= self.inner.num_bits {
|
||||
return None;
|
||||
}
|
||||
let bits = (self.inner.num_bits - self.pos).min(self.chunk_size);
|
||||
|
||||
let iter = BitIter {
|
||||
bits: &self.inner.bits[self.pos / 64..],
|
||||
bit_offset: self.pos % 64,
|
||||
bit_index: 0,
|
||||
num_bits: bits,
|
||||
};
|
||||
self.pos += bits;
|
||||
|
||||
Some(iter)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue