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"
|
"crates/game"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[profile.debug-release]
|
||||||
|
inherits = "release"
|
||||||
|
opt-level = 2
|
||||||
|
debug = true
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
anyhow = "1.0.89"
|
anyhow = "1.0.89"
|
||||||
ash = "0.38.0"
|
ash = "0.38.0"
|
||||||
|
|
|
@ -26,6 +26,17 @@ pub struct BufferDesc {
|
||||||
pub alloc_flags: vk_mem::AllocationCreateFlags,
|
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 {
|
impl std::fmt::Debug for BufferDesc {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
f.debug_struct("BufferDesc")
|
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 {
|
impl Default for BufferDesc {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|
|
@ -64,6 +64,7 @@ impl SingleUseCommandPool {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get the underlying pool, bypassing the mutex
|
/// get the underlying pool, bypassing the mutex
|
||||||
|
#[allow(dead_code)]
|
||||||
pub unsafe fn pool(&self) -> vk::CommandPool {
|
pub unsafe fn pool(&self) -> vk::CommandPool {
|
||||||
self.pool.data_ptr().read()
|
self.pool.data_ptr().read()
|
||||||
}
|
}
|
||||||
|
@ -129,6 +130,8 @@ pub enum CommandBufferState {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
struct CommandBufferState2(AtomicU8);
|
struct CommandBufferState2(AtomicU8);
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
impl CommandBufferState2 {
|
impl CommandBufferState2 {
|
||||||
fn initial() -> Self {
|
fn initial() -> Self {
|
||||||
Self(AtomicU8::new(CommandBufferState::Initial as u8))
|
Self(AtomicU8::new(CommandBufferState::Initial as u8))
|
||||||
|
@ -188,11 +191,13 @@ impl !Sync for SingleUseCommand {}
|
||||||
impl SingleUseCommand {
|
impl SingleUseCommand {
|
||||||
pub fn new(device: Device, pool: Arc<SingleUseCommandPool>) -> VkResult<Self> {
|
pub fn new(device: Device, pool: Arc<SingleUseCommandPool>) -> VkResult<Self> {
|
||||||
let buffer = unsafe {
|
let buffer = unsafe {
|
||||||
let alloc_info = vk::CommandBufferAllocateInfo::default()
|
let buffer = pool.pool.with_locked(|pool| {
|
||||||
.command_buffer_count(1)
|
let alloc_info = vk::CommandBufferAllocateInfo::default()
|
||||||
.command_pool(pool.pool())
|
.command_buffer_count(1)
|
||||||
.level(vk::CommandBufferLevel::PRIMARY);
|
.command_pool(*pool)
|
||||||
let buffer = device.dev().allocate_command_buffers(&alloc_info)?[0];
|
.level(vk::CommandBufferLevel::PRIMARY);
|
||||||
|
Ok(device.dev().allocate_command_buffers(&alloc_info)?[0])
|
||||||
|
})?;
|
||||||
|
|
||||||
device.dev().begin_command_buffer(
|
device.dev().begin_command_buffer(
|
||||||
buffer,
|
buffer,
|
||||||
|
|
|
@ -184,7 +184,7 @@ pub fn egui_pre_pass(
|
||||||
rg.import_image(
|
rg.import_image(
|
||||||
img,
|
img,
|
||||||
Access {
|
Access {
|
||||||
layout: Some(vk::ImageLayout::GENERAL),
|
layout: vk::ImageLayout::GENERAL,
|
||||||
..Access::undefined()
|
..Access::undefined()
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -229,12 +229,12 @@ pub fn egui_pre_pass(
|
||||||
Access {
|
Access {
|
||||||
stage: vk::PipelineStageFlags2::NONE,
|
stage: vk::PipelineStageFlags2::NONE,
|
||||||
mask: vk::AccessFlags2::empty(),
|
mask: vk::AccessFlags2::empty(),
|
||||||
layout: Some(vk::ImageLayout::UNDEFINED),
|
layout: vk::ImageLayout::UNDEFINED,
|
||||||
},
|
},
|
||||||
Access {
|
Access {
|
||||||
stage: vk::PipelineStageFlags2::TRANSFER,
|
stage: vk::PipelineStageFlags2::TRANSFER,
|
||||||
mask: vk::AccessFlags2::TRANSFER_WRITE,
|
mask: vk::AccessFlags2::TRANSFER_WRITE,
|
||||||
layout: Some(vk::ImageLayout::TRANSFER_DST_OPTIMAL),
|
layout: vk::ImageLayout::TRANSFER_DST_OPTIMAL,
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
|
@ -270,12 +270,12 @@ pub fn egui_pre_pass(
|
||||||
Access {
|
Access {
|
||||||
stage: vk::PipelineStageFlags2::TRANSFER,
|
stage: vk::PipelineStageFlags2::TRANSFER,
|
||||||
mask: vk::AccessFlags2::TRANSFER_WRITE,
|
mask: vk::AccessFlags2::TRANSFER_WRITE,
|
||||||
layout: Some(vk::ImageLayout::TRANSFER_DST_OPTIMAL),
|
layout: vk::ImageLayout::TRANSFER_DST_OPTIMAL,
|
||||||
},
|
},
|
||||||
Access {
|
Access {
|
||||||
stage: vk::PipelineStageFlags2::TRANSFER,
|
stage: vk::PipelineStageFlags2::TRANSFER,
|
||||||
mask: vk::AccessFlags2::TRANSFER_READ,
|
mask: vk::AccessFlags2::TRANSFER_READ,
|
||||||
layout: Some(vk::ImageLayout::TRANSFER_SRC_OPTIMAL),
|
layout: vk::ImageLayout::TRANSFER_SRC_OPTIMAL,
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
@ -285,12 +285,12 @@ pub fn egui_pre_pass(
|
||||||
Access {
|
Access {
|
||||||
stage: vk::PipelineStageFlags2::NONE,
|
stage: vk::PipelineStageFlags2::NONE,
|
||||||
mask: vk::AccessFlags2::empty(),
|
mask: vk::AccessFlags2::empty(),
|
||||||
layout: Some(vk::ImageLayout::GENERAL),
|
layout: vk::ImageLayout::GENERAL,
|
||||||
},
|
},
|
||||||
Access {
|
Access {
|
||||||
stage: vk::PipelineStageFlags2::TRANSFER,
|
stage: vk::PipelineStageFlags2::TRANSFER,
|
||||||
mask: vk::AccessFlags2::TRANSFER_WRITE,
|
mask: vk::AccessFlags2::TRANSFER_WRITE,
|
||||||
layout: Some(vk::ImageLayout::TRANSFER_DST_OPTIMAL),
|
layout: vk::ImageLayout::TRANSFER_DST_OPTIMAL,
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
@ -334,12 +334,12 @@ pub fn egui_pre_pass(
|
||||||
Access {
|
Access {
|
||||||
stage: vk::PipelineStageFlags2::TRANSFER,
|
stage: vk::PipelineStageFlags2::TRANSFER,
|
||||||
mask: vk::AccessFlags2::TRANSFER_WRITE,
|
mask: vk::AccessFlags2::TRANSFER_WRITE,
|
||||||
layout: Some(vk::ImageLayout::TRANSFER_DST_OPTIMAL),
|
layout: vk::ImageLayout::TRANSFER_DST_OPTIMAL,
|
||||||
},
|
},
|
||||||
Access {
|
Access {
|
||||||
stage: vk::PipelineStageFlags2::ALL_COMMANDS,
|
stage: vk::PipelineStageFlags2::ALL_COMMANDS,
|
||||||
mask: vk::AccessFlags2::empty(),
|
mask: vk::AccessFlags2::empty(),
|
||||||
layout: Some(vk::ImageLayout::GENERAL),
|
layout: vk::ImageLayout::GENERAL,
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
|
@ -374,13 +374,13 @@ pub fn egui_pre_pass(
|
||||||
(
|
(
|
||||||
*id,
|
*id,
|
||||||
Access {
|
Access {
|
||||||
layout: Some(vk::ImageLayout::GENERAL),
|
layout: vk::ImageLayout::GENERAL,
|
||||||
..Access::undefined()
|
..Access::undefined()
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
record,
|
record: Some(record),
|
||||||
});
|
});
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -730,7 +730,7 @@ pub fn egui_pass(
|
||||||
rg.add_pass(PassDesc {
|
rg.add_pass(PassDesc {
|
||||||
reads,
|
reads,
|
||||||
writes,
|
writes,
|
||||||
record,
|
record: Some(record),
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(to_remove_tex_ids)
|
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::{
|
use crate::{
|
||||||
define_device_owned_handle,
|
define_device_owned_handle,
|
||||||
|
@ -33,7 +37,6 @@ pub struct ImageDesc {
|
||||||
impl std::hash::Hash for ImageDesc {
|
impl std::hash::Hash for ImageDesc {
|
||||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
self.flags.hash(state);
|
self.flags.hash(state);
|
||||||
self.name.hash(state);
|
|
||||||
self.format.hash(state);
|
self.format.hash(state);
|
||||||
self.kind.hash(state);
|
self.kind.hash(state);
|
||||||
self.mip_levels.hash(state);
|
self.mip_levels.hash(state);
|
||||||
|
@ -128,8 +131,8 @@ define_device_owned_handle! {
|
||||||
format: vk::Format,
|
format: vk::Format,
|
||||||
views: Mutex<HashMap<ImageViewDesc, vk::ImageView>>,
|
views: Mutex<HashMap<ImageViewDesc, vk::ImageView>>,
|
||||||
aliases: Mutex<HashMap<ImageDesc, Arc<Image>>>,
|
aliases: Mutex<HashMap<ImageDesc, Arc<Image>>>,
|
||||||
parent: Option<Arc<Image>>,
|
parent: Option<Weak<Image>>,
|
||||||
is_swapchain_image:bool,
|
is_swapchain_image: bool,
|
||||||
} => |this| if !this.is_swapchain_image {
|
} => |this| if !this.is_swapchain_image {
|
||||||
unsafe {
|
unsafe {
|
||||||
for &view in this.views.lock().values() {
|
for &view in this.views.lock().values() {
|
||||||
|
@ -266,20 +269,19 @@ impl Image {
|
||||||
self.size.depth
|
self.size.depth
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_parent(self: &Arc<Self>) -> Arc<Image> {
|
fn get_parent_or_self(self: &Arc<Self>) -> Arc<Image> {
|
||||||
self.parent.clone().unwrap_or_else(|| self.clone())
|
self.parent
|
||||||
}
|
|
||||||
|
|
||||||
fn get_alloc(&self) -> Option<&vk_mem::Allocation> {
|
|
||||||
self.alloc
|
|
||||||
.as_ref()
|
.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>> {
|
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>> {
|
unsafe fn get_alias_inner(self: Arc<Self>, desc: ImageDesc) -> VkResult<Arc<Image>> {
|
||||||
use std::collections::hash_map::Entry::*;
|
use std::collections::hash_map::Entry::*;
|
||||||
match self.aliases.lock().entry(desc.clone()) {
|
match self.aliases.lock().entry(desc.clone()) {
|
||||||
|
@ -327,7 +329,8 @@ impl Image {
|
||||||
.mip_levels(mip_levels);
|
.mip_levels(mip_levels);
|
||||||
|
|
||||||
let alloc = self
|
let alloc = self
|
||||||
.get_alloc()
|
.alloc
|
||||||
|
.as_ref()
|
||||||
.expect("no alloc associated with image. is this the framebuffer?");
|
.expect("no alloc associated with image. is this the framebuffer?");
|
||||||
|
|
||||||
let image = unsafe {
|
let image = unsafe {
|
||||||
|
@ -342,7 +345,6 @@ impl Image {
|
||||||
image
|
image
|
||||||
};
|
};
|
||||||
|
|
||||||
let parent = self.parent.clone().unwrap_or(self.clone());
|
|
||||||
let alias = Self::construct(
|
let alias = Self::construct(
|
||||||
self.device().clone(),
|
self.device().clone(),
|
||||||
image,
|
image,
|
||||||
|
@ -352,8 +354,8 @@ impl Image {
|
||||||
format,
|
format,
|
||||||
Mutex::new(HashMap::new()),
|
Mutex::new(HashMap::new()),
|
||||||
Mutex::new(HashMap::new()),
|
Mutex::new(HashMap::new()),
|
||||||
Some(parent.clone()),
|
Some(Arc::downgrade(&self)),
|
||||||
parent.is_swapchain_image,
|
self.is_swapchain_image,
|
||||||
)?;
|
)?;
|
||||||
Ok(vacant.insert(Arc::new(alias)).clone())
|
Ok(vacant.insert(Arc::new(alias)).clone())
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,7 @@ mod egui_pass;
|
||||||
mod images;
|
mod images;
|
||||||
mod pipeline;
|
mod pipeline;
|
||||||
mod render_graph;
|
mod render_graph;
|
||||||
|
mod rendering;
|
||||||
mod sync;
|
mod sync;
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
|
@ -441,6 +442,7 @@ impl PhysicalDeviceProperties {
|
||||||
pub struct PhysicalDevice {
|
pub struct PhysicalDevice {
|
||||||
pdev: vk::PhysicalDevice,
|
pdev: vk::PhysicalDevice,
|
||||||
queue_families: DeviceQueueFamilies,
|
queue_families: DeviceQueueFamilies,
|
||||||
|
#[allow(dead_code)]
|
||||||
properties: PhysicalDeviceProperties,
|
properties: PhysicalDeviceProperties,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -729,7 +731,7 @@ impl Swapchain {
|
||||||
format,
|
format,
|
||||||
)
|
)
|
||||||
.inspect(|img| {
|
.inspect(|img| {
|
||||||
img.get_view(images::ImageViewDesc {
|
_ = img.get_view(images::ImageViewDesc {
|
||||||
name: Some(format!("swapchain-{swapchain:?}-image-{i}-view").into()),
|
name: Some(format!("swapchain-{swapchain:?}-image-{i}-view").into()),
|
||||||
kind: vk::ImageViewType::TYPE_2D,
|
kind: vk::ImageViewType::TYPE_2D,
|
||||||
format,
|
format,
|
||||||
|
@ -2534,7 +2536,6 @@ impl<W> Renderer<W> {
|
||||||
let mut rg = render_graph::RenderGraph::new();
|
let mut rg = render_graph::RenderGraph::new();
|
||||||
let (textures_to_remove, cmds) = util::timed("record command buffer", || {
|
let (textures_to_remove, cmds) = util::timed("record command buffer", || {
|
||||||
let framebuffer = rg.import_image(frame.image.clone(), Access::undefined());
|
let framebuffer = rg.import_image(frame.image.clone(), Access::undefined());
|
||||||
rg.mark_as_output(framebuffer);
|
|
||||||
|
|
||||||
render_graph::clear_pass(&mut rg, clear_color, framebuffer);
|
render_graph::clear_pass(&mut rg, clear_color, framebuffer);
|
||||||
egui_pass::egui_pre_pass(
|
egui_pass::egui_pre_pass(
|
||||||
|
@ -2555,7 +2556,8 @@ impl<W> Renderer<W> {
|
||||||
output,
|
output,
|
||||||
framebuffer,
|
framebuffer,
|
||||||
)?;
|
)?;
|
||||||
render_graph::present_pass(&mut rg, framebuffer);
|
|
||||||
|
rg.mark_as_output(framebuffer, Access::present());
|
||||||
|
|
||||||
Result::Ok((textures_to_remove, rg.resolve(dev.clone())?))
|
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
|
&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