1#[cfg(test)]
2extern crate std;
3
4use alloc::vec;
5use alloc::vec::Vec;
6use crate::{Rectangle, Size};
7use euclid::{vec2, point2, size2};
8
9use core::num::Wrapping;
10
11const LARGE_BUCKET: usize = 2;
12const MEDIUM_BUCKET: usize = 1;
13const SMALL_BUCKET: usize = 0;
14const NUM_BUCKETS: usize = 3;
15
16fn free_list_for_size(small_threshold: i32, large_threshold: i32, size: &Size) -> usize {
17 if size.width >= large_threshold || size.height >= large_threshold {
18 LARGE_BUCKET
19 } else if size.width >= small_threshold || size.height >= small_threshold {
20 MEDIUM_BUCKET
21 } else {
22 SMALL_BUCKET
23 }
24}
25
26#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
27#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
28struct AllocIndex(u32);
29impl AllocIndex {
30 const NONE: AllocIndex = AllocIndex(u32::MAX);
31
32 fn index(self) -> usize {
33 self.0 as usize
34 }
35
36 fn is_none(self) -> bool {
37 self == AllocIndex::NONE
38 }
39
40 fn is_some(self) -> bool {
41 self != AllocIndex::NONE
42 }
43}
44
45#[repr(C)]
47#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
48#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
49pub struct AllocId(pub(crate) u32);
50
51impl AllocId {
52 pub fn serialize(&self) -> u32 {
53 self.0
54 }
55
56 pub fn deserialize(bytes: u32) -> Self {
57 AllocId(bytes)
58 }
59}
60
61const GEN_MASK: u32 = 0xFF000000;
62const IDX_MASK: u32 = 0x00FFFFFF;
63
64#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
65#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
66enum Orientation {
67 Vertical,
68 Horizontal,
69}
70
71impl Orientation {
72 fn flipped(self) -> Self {
73 match self {
74 Orientation::Vertical => Orientation::Horizontal,
75 Orientation::Horizontal => Orientation::Vertical,
76 }
77 }
78}
79
80#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
81#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
82pub enum NodeKind {
83 Container,
84 Alloc,
85 Free,
86 Unused,
87}
88
89#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
90#[derive(Clone, Debug)]
91struct Node {
92 parent: AllocIndex,
93 next_sibling: AllocIndex,
94 prev_sibling: AllocIndex,
95 kind: NodeKind,
96 orientation: Orientation,
97 rect: Rectangle,
98}
99
100#[repr(C)]
102#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
103#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
104pub struct AllocatorOptions {
105 pub alignment: Size,
111
112 pub small_size_threshold: i32,
119
120 pub large_size_threshold: i32,
127}
128
129pub const DEFAULT_OPTIONS: AllocatorOptions = AllocatorOptions {
130 alignment: size2(1, 1),
131 large_size_threshold: 256,
132 small_size_threshold: 32,
133};
134
135impl Default for AllocatorOptions {
136 fn default() -> Self {
137 DEFAULT_OPTIONS
138 }
139}
140
141#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
324#[derive(Clone)]
325pub struct AtlasAllocator {
326 nodes: Vec<Node>,
327 free_lists: [Vec<AllocIndex>; NUM_BUCKETS],
329
330 unused_nodes: AllocIndex,
333
334 generations: Vec<Wrapping<u8>>,
337
338 alignment: Size,
340
341 small_size_threshold: i32,
343
344 large_size_threshold: i32,
346
347 size: Size,
349
350 root_node: AllocIndex,
352}
353
354impl AtlasAllocator {
401 pub fn new(size: Size) -> Self {
403 AtlasAllocator::with_options(size, &DEFAULT_OPTIONS)
404 }
405
406 pub fn with_options(size: Size, options: &AllocatorOptions) -> Self {
408 assert!(options.alignment.width > 0);
409 assert!(options.alignment.height > 0);
410 assert!(size.width > 0);
411 assert!(size.height > 0);
412 assert!(options.large_size_threshold >= options.small_size_threshold);
413
414 let mut free_lists = [Vec::new(), Vec::new(), Vec::new()];
415 let bucket = free_list_for_size(
416 options.small_size_threshold,
417 options.large_size_threshold,
418 &size,
419 );
420 free_lists[bucket].push(AllocIndex(0));
421
422 AtlasAllocator {
423 nodes: vec![Node {
424 parent: AllocIndex::NONE,
425 next_sibling: AllocIndex::NONE,
426 prev_sibling: AllocIndex::NONE,
427 rect: size.into(),
428 kind: NodeKind::Free,
429 orientation: Orientation::Vertical,
430 }],
431 free_lists,
432 generations: vec![Wrapping(0)],
433 unused_nodes: AllocIndex::NONE,
434 alignment: options.alignment,
435 small_size_threshold: options.small_size_threshold,
436 large_size_threshold: options.large_size_threshold,
437 size,
438 root_node: AllocIndex(0),
439 }
440 }
441
442 pub fn size(&self) -> Size {
444 self.size
445 }
446
447 pub fn allocate(&mut self, mut requested_size: Size) -> Option<Allocation> {
449 if requested_size.is_empty() {
450 return None;
451 }
452
453 adjust_size(self.alignment.width, &mut requested_size.width);
454 adjust_size(self.alignment.height, &mut requested_size.height);
455
456 let chosen_id = self.find_suitable_rect(&requested_size);
458
459 if chosen_id.is_none() {
460 return None;
462 }
463
464 let chosen_node = self.nodes[chosen_id.index()].clone();
465 let chosen_rect = chosen_node.rect;
466 let allocated_rect = Rectangle {
467 min: chosen_rect.min,
468 max: chosen_rect.min + requested_size.to_vector(),
469 };
470 let current_orientation = chosen_node.orientation;
471 assert_eq!(chosen_node.kind, NodeKind::Free);
472
473 let (split_rect, leftover_rect, orientation) =
474 guillotine_rect(&chosen_node.rect, requested_size, current_orientation);
475
476 let allocated_id;
479 let split_id;
480 let leftover_id;
481
482 if orientation == current_orientation {
483 if !split_rect.is_empty() {
484 let next_sibling = chosen_node.next_sibling;
485
486 split_id = self.new_node();
487 self.nodes[split_id.index()] = Node {
488 parent: chosen_node.parent,
489 next_sibling,
490 prev_sibling: chosen_id,
491 rect: split_rect,
492 kind: NodeKind::Free,
493 orientation: current_orientation,
494 };
495
496 self.nodes[chosen_id.index()].next_sibling = split_id;
497 if next_sibling.is_some() {
498 self.nodes[next_sibling.index()].prev_sibling = split_id;
499 }
500 } else {
501 split_id = AllocIndex::NONE;
502 }
503
504 if !leftover_rect.is_empty() {
505 self.nodes[chosen_id.index()].kind = NodeKind::Container;
506
507 allocated_id = self.new_node();
508 leftover_id = self.new_node();
509
510 self.nodes[allocated_id.index()] = Node {
511 parent: chosen_id,
512 next_sibling: leftover_id,
513 prev_sibling: AllocIndex::NONE,
514 rect: allocated_rect,
515 kind: NodeKind::Alloc,
516 orientation: current_orientation.flipped(),
517 };
518
519 self.nodes[leftover_id.index()] = Node {
520 parent: chosen_id,
521 next_sibling: AllocIndex::NONE,
522 prev_sibling: allocated_id,
523 rect: leftover_rect,
524 kind: NodeKind::Free,
525 orientation: current_orientation.flipped(),
526 };
527 } else {
528 allocated_id = chosen_id;
530 let node = &mut self.nodes[chosen_id.index()];
531 node.kind = NodeKind::Alloc;
532 node.rect = allocated_rect;
533
534 leftover_id = AllocIndex::NONE
535 }
536 } else {
537 self.nodes[chosen_id.index()].kind = NodeKind::Container;
538
539 if !split_rect.is_empty() {
540 split_id = self.new_node();
541 self.nodes[split_id.index()] = Node {
542 parent: chosen_id,
543 next_sibling: AllocIndex::NONE,
544 prev_sibling: AllocIndex::NONE,
545 rect: split_rect,
546 kind: NodeKind::Free,
547 orientation: current_orientation.flipped(),
548 };
549 } else {
550 split_id = AllocIndex::NONE;
551 }
552
553 if !leftover_rect.is_empty() {
554 let container_id = self.new_node();
555 self.nodes[container_id.index()] = Node {
556 parent: chosen_id,
557 next_sibling: split_id,
558 prev_sibling: AllocIndex::NONE,
559 rect: Rectangle::zero(),
560 kind: NodeKind::Container,
561 orientation: current_orientation.flipped(),
562 };
563
564 self.nodes[split_id.index()].prev_sibling = container_id;
565
566 allocated_id = self.new_node();
567 leftover_id = self.new_node();
568
569 self.nodes[allocated_id.index()] = Node {
570 parent: container_id,
571 next_sibling: leftover_id,
572 prev_sibling: AllocIndex::NONE,
573 rect: allocated_rect,
574 kind: NodeKind::Alloc,
575 orientation: current_orientation,
576 };
577
578 self.nodes[leftover_id.index()] = Node {
579 parent: container_id,
580 next_sibling: AllocIndex::NONE,
581 prev_sibling: allocated_id,
582 rect: leftover_rect,
583 kind: NodeKind::Free,
584 orientation: current_orientation,
585 };
586 } else {
587 allocated_id = self.new_node();
588 self.nodes[allocated_id.index()] = Node {
589 parent: chosen_id,
590 next_sibling: split_id,
591 prev_sibling: AllocIndex::NONE,
592 rect: allocated_rect,
593 kind: NodeKind::Alloc,
594 orientation: current_orientation.flipped(),
595 };
596
597 self.nodes[split_id.index()].prev_sibling = allocated_id;
598
599 leftover_id = AllocIndex::NONE;
600 }
601 }
602
603 assert_eq!(self.nodes[allocated_id.index()].kind, NodeKind::Alloc);
604
605 if split_id.is_some() {
606 self.add_free_rect(split_id, &split_rect.size());
607 }
608
609 if leftover_id.is_some() {
610 self.add_free_rect(leftover_id, &leftover_rect.size());
611 }
612
613 #[cfg(feature = "checks")]
614 self.check_tree();
615
616 Some(Allocation {
617 id: self.alloc_id(allocated_id),
618 rectangle: allocated_rect,
619 })
620 }
621
622 pub fn deallocate(&mut self, node_id: AllocId) {
624 let mut node_id = self.get_index(node_id);
625
626 assert!(node_id.index() < self.nodes.len());
627 assert_eq!(self.nodes[node_id.index()].kind, NodeKind::Alloc);
628
629 self.nodes[node_id.index()].kind = NodeKind::Free;
630
631 loop {
632 let orientation = self.nodes[node_id.index()].orientation;
633
634 let next = self.nodes[node_id.index()].next_sibling;
635 let prev = self.nodes[node_id.index()].prev_sibling;
636
637 if next.is_some() && self.nodes[next.index()].kind == NodeKind::Free {
639 self.merge_siblings(node_id, next, orientation);
640 }
641
642 if prev.is_some() && self.nodes[prev.index()].kind == NodeKind::Free {
644 self.merge_siblings(prev, node_id, orientation);
645 node_id = prev;
646 }
647
648 let parent = self.nodes[node_id.index()].parent;
651 if self.nodes[node_id.index()].prev_sibling.is_none()
652 && self.nodes[node_id.index()].next_sibling.is_none()
653 && parent.is_some()
654 {
655 debug_assert_eq!(self.nodes[parent.index()].kind, NodeKind::Container);
656
657 self.nodes[parent.index()].rect = self.nodes[node_id.index()].rect;
659 self.nodes[parent.index()].kind = NodeKind::Free;
660 self.mark_node_unused(node_id);
661
662 node_id = parent;
664 } else {
665 let size = self.nodes[node_id.index()].rect.size();
666 self.add_free_rect(node_id, &size);
667 break;
668 }
669 }
670
671 #[cfg(feature = "checks")]
672 self.check_tree();
673 }
674
675 pub fn is_empty(&self) -> bool {
676 let root = &self.nodes[self.root_node.index()];
677
678 root.kind == NodeKind::Free && root.next_sibling.is_none()
679 }
680
681 pub fn clear(&mut self) {
683 self.nodes.clear();
684 self.nodes.push(Node {
685 parent: AllocIndex::NONE,
686 next_sibling: AllocIndex::NONE,
687 prev_sibling: AllocIndex::NONE,
688 rect: self.size.into(),
689 kind: NodeKind::Free,
690 orientation: Orientation::Vertical,
691 });
692
693 self.root_node = AllocIndex(0);
694
695 self.generations.clear();
696 self.generations.push(Wrapping(0));
697
698 self.unused_nodes = AllocIndex::NONE;
699
700 let bucket = free_list_for_size(
701 self.small_size_threshold,
702 self.large_size_threshold,
703 &self.size,
704 );
705 for i in 0..NUM_BUCKETS {
706 self.free_lists[i].clear();
707 }
708 self.free_lists[bucket].push(AllocIndex(0));
709 }
710
711 pub fn reset(&mut self, size: Size, options: &AllocatorOptions) {
713 self.alignment = options.alignment;
714 self.small_size_threshold = options.small_size_threshold;
715 self.large_size_threshold = options.large_size_threshold;
716 self.size = size;
717
718 self.clear();
719 }
720
721 pub fn rearrange(&mut self) -> ChangeList {
727 let size = self.size;
728 self.resize_and_rearrange(size)
729 }
730
731 pub fn resize_and_rearrange(&mut self, new_size: Size) -> ChangeList {
733 let mut allocs = Vec::with_capacity(self.nodes.len());
734 for (i, node) in self.nodes.iter().enumerate() {
735 if node.kind != NodeKind::Alloc {
736 continue;
737 }
738 let id = self.alloc_id(AllocIndex(i as u32));
739 allocs.push(Allocation {
740 id,
741 rectangle: node.rect,
742 });
743 }
744
745 allocs.sort_by_key(|alloc| safe_area(&alloc.rectangle));
746 allocs.reverse();
747
748 self.size = new_size;
749 self.clear();
750
751 let mut changes = Vec::new();
752 let mut failures = Vec::new();
753
754 for old in allocs {
755 let size = old.rectangle.size();
756 if let Some(new) = self.allocate(size) {
757 changes.push(Change { old, new });
758 } else {
759 failures.push(old);
760 }
761 }
762
763 ChangeList { changes, failures }
764 }
765
766 pub fn grow(&mut self, new_size: Size) {
770 assert!(new_size.width >= self.size.width);
771 assert!(new_size.height >= self.size.height);
772
773 let old_size = self.size;
774 self.size = new_size;
775
776 let dx = new_size.width - old_size.width;
777 let dy = new_size.height - old_size.height;
778
779 let root = &mut self.nodes[self.root_node.index()];
781 if root.kind == NodeKind::Free && root.rect.size() == old_size {
782 root.rect.max = root.rect.min + new_size.to_vector();
783 self.update_free_list_bucket(self.root_node);
785 return;
786 }
787
788 let root_orientation = root.orientation;
789 let grows_in_root_orientation = match root_orientation {
790 Orientation::Horizontal => dx > 0,
791 Orientation::Vertical => dy > 0,
792 };
793
794 if grows_in_root_orientation {
797 let mut sibling = self.root_node;
798 while self.nodes[sibling.index()].next_sibling != AllocIndex::NONE {
799 sibling = self.nodes[sibling.index()].next_sibling;
800 }
801 let node = &mut self.nodes[sibling.index()];
802 if node.kind == NodeKind::Free {
803 node.rect.max += match root_orientation {
804 Orientation::Horizontal => vec2(dx, 0),
805 Orientation::Vertical => vec2(0, dy),
806 };
807 self.update_free_list_bucket(sibling);
809 } else {
810 let rect = match root_orientation {
811 Orientation::Horizontal => {
812 let min = point2(node.rect.max.x, node.rect.min.y);
813 let max = min + vec2(dx, node.rect.height());
814 Rectangle { min, max }
815 }
816 Orientation::Vertical => {
817 let min = point2(node.rect.min.x, node.rect.max.y);
818 let max = min + vec2(node.rect.width(), dy);
819 Rectangle { min, max }
820 }
821 };
822
823 let next = self.new_node();
824 self.nodes[sibling.index()].next_sibling = next;
825 self.nodes[next.index()] = Node {
826 kind: NodeKind::Free,
827 rect,
828 prev_sibling: sibling,
829 next_sibling: AllocIndex::NONE,
830 parent: AllocIndex::NONE,
831 orientation: root_orientation,
832 };
833
834 self.add_free_rect(next, &rect.size());
835 }
836 }
837
838 let grows_in_opposite_orientation = match root_orientation {
839 Orientation::Horizontal => dy > 0,
840 Orientation::Vertical => dx > 0,
841 };
842
843 if grows_in_opposite_orientation {
844 let free_node = self.new_node();
845 let new_root = self.new_node();
846
847 let old_root = self.root_node;
848 self.root_node = new_root;
849
850 let new_root_orientation = root_orientation.flipped();
851
852 let min = match new_root_orientation {
853 Orientation::Horizontal => point2(old_size.width, 0),
854 Orientation::Vertical => point2(0, old_size.height),
855 };
856 let max = point2(new_size.width, new_size.height);
857 let rect = Rectangle { min, max };
858
859 self.nodes[free_node.index()] = Node {
860 parent: AllocIndex::NONE,
861 prev_sibling: new_root,
862 next_sibling: AllocIndex::NONE,
863 kind: NodeKind::Free,
864 rect,
865 orientation: new_root_orientation,
866 };
867
868 self.nodes[new_root.index()] = Node {
869 parent: AllocIndex::NONE,
870 prev_sibling: AllocIndex::NONE,
871 next_sibling: free_node,
872 kind: NodeKind::Container,
873 rect: Rectangle::zero(),
874 orientation: new_root_orientation,
875 };
876
877 self.add_free_rect(free_node, &rect.size());
878
879 let mut iter = old_root;
882 while iter != AllocIndex::NONE {
883 self.nodes[iter.index()].parent = new_root;
884 iter = self.nodes[iter.index()].next_sibling;
885 }
886
887 let mut iter = self.nodes[old_root.index()].next_sibling;
890 while iter != AllocIndex::NONE {
891 self.nodes[iter.index()].parent = new_root;
892 iter = self.nodes[iter.index()].prev_sibling;
893 }
894 }
895
896 #[cfg(feature = "checks")]
897 self.check_tree();
898 }
899
900 pub fn for_each_free_rectangle<F>(&self, mut callback: F)
902 where
903 F: FnMut(&Rectangle),
904 {
905 for node in &self.nodes {
906 if node.kind == NodeKind::Free {
907 callback(&node.rect);
908 }
909 }
910 }
911
912 pub fn for_each_allocated_rectangle<F>(&self, mut callback: F)
914 where
915 F: FnMut(AllocId, &Rectangle),
916 {
917 for (i, node) in self.nodes.iter().enumerate() {
918 if node.kind != NodeKind::Alloc {
919 continue;
920 }
921
922 let id = self.alloc_id(AllocIndex(i as u32));
923
924 callback(id, &node.rect);
925 }
926 }
927
928 fn find_suitable_rect(&mut self, requested_size: &Size) -> AllocIndex {
929 let ideal_bucket = free_list_for_size(
930 self.small_size_threshold,
931 self.large_size_threshold,
932 requested_size,
933 );
934
935 let use_worst_fit = ideal_bucket == LARGE_BUCKET;
936 for bucket in ideal_bucket..NUM_BUCKETS {
937 let mut candidate_score = if use_worst_fit { 0 } else { i32::MAX };
938 let mut candidate = None;
939
940 let mut freelist_idx = 0;
941 while freelist_idx < self.free_lists[bucket].len() {
942 let id = self.free_lists[bucket][freelist_idx];
943
944 if self.nodes[id.index()].kind != NodeKind::Free {
949 self.free_lists[bucket].swap_remove(freelist_idx);
951 continue;
952 }
953
954 let size = self.nodes[id.index()].rect.size();
955 let dx = size.width - requested_size.width;
956 let dy = size.height - requested_size.height;
957
958 if dx >= 0 && dy >= 0 {
959 if dx == 0 || dy == 0 {
960 candidate = Some((id, freelist_idx));
962 break;
963 }
964
965 let score = i32::min(dx, dy);
968 if (use_worst_fit && score > candidate_score)
969 || (!use_worst_fit && score < candidate_score)
970 {
971 candidate_score = score;
972 candidate = Some((id, freelist_idx));
973 }
974 }
975
976 freelist_idx += 1;
977 }
978
979 if let Some((id, freelist_idx)) = candidate {
980 self.free_lists[bucket].swap_remove(freelist_idx);
981 return id;
982 }
983 }
984
985 AllocIndex::NONE
986 }
987
988 fn new_node(&mut self) -> AllocIndex {
989 let idx = self.unused_nodes;
990 if idx.index() < self.nodes.len() {
991 self.unused_nodes = self.nodes[idx.index()].next_sibling;
992 self.generations[idx.index()] += Wrapping(1);
993 debug_assert_eq!(self.nodes[idx.index()].kind, NodeKind::Unused);
994 return idx;
995 }
996
997 self.nodes.push(Node {
998 parent: AllocIndex::NONE,
999 next_sibling: AllocIndex::NONE,
1000 prev_sibling: AllocIndex::NONE,
1001 rect: Rectangle::zero(),
1002 kind: NodeKind::Unused,
1003 orientation: Orientation::Horizontal,
1004 });
1005
1006 self.generations.push(Wrapping(0));
1007
1008 AllocIndex(self.nodes.len() as u32 - 1)
1009 }
1010
1011 fn mark_node_unused(&mut self, id: AllocIndex) {
1012 debug_assert!(self.nodes[id.index()].kind != NodeKind::Unused);
1013 self.nodes[id.index()].kind = NodeKind::Unused;
1014 self.nodes[id.index()].next_sibling = self.unused_nodes;
1015 self.unused_nodes = id;
1016 }
1017
1018 #[cfg(feature = "checks")]
1019 fn check_siblings(&self, id: AllocIndex, next: AllocIndex, orientation: Orientation) {
1020 if next.is_none() {
1021 return;
1022 }
1023
1024 if self.nodes[next.index()].prev_sibling != id {
1025 panic!("error: #{:?}'s next sibling #{:?} has prev sibling #{:?}", id, next, self.nodes[next.index()].prev_sibling);
1026 }
1027 assert_eq!(self.nodes[next.index()].prev_sibling, id);
1028
1029 match self.nodes[id.index()].kind {
1030 NodeKind::Container | NodeKind::Unused => {
1031 return;
1032 }
1033 _ => {}
1034 }
1035 match self.nodes[next.index()].kind {
1036 NodeKind::Container | NodeKind::Unused => {
1037 return;
1038 }
1039 _ => {}
1040 }
1041
1042 let r1 = self.nodes[id.index()].rect;
1043 let r2 = self.nodes[next.index()].rect;
1044 match orientation {
1045 Orientation::Horizontal => {
1046 assert_eq!(r1.min.y, r2.min.y);
1047 assert_eq!(r1.max.y, r2.max.y);
1048 }
1049 Orientation::Vertical => {
1050 assert_eq!(r1.min.x, r2.min.x);
1051 assert_eq!(r1.max.x, r2.max.x);
1052 }
1053 }
1054 }
1055
1056 #[cfg(feature = "checks")]
1057 fn check_tree(&self) {
1058 for node_idx in 0..self.nodes.len() {
1059 let node = &self.nodes[node_idx];
1060
1061 if node.kind == NodeKind::Unused {
1062 if node.next_sibling.is_some() {
1063 assert_eq!(self.nodes[node.next_sibling.index()].kind, NodeKind::Unused);
1064 }
1065 continue;
1066 }
1067
1068 let mut iter = node.next_sibling;
1069 while iter.is_some() {
1070 assert_eq!(self.nodes[iter.index()].orientation, node.orientation);
1071 assert_eq!(self.nodes[iter.index()].parent, node.parent);
1072 assert!(self.nodes[iter.index()].kind != NodeKind::Unused);
1073 let next = self.nodes[iter.index()].next_sibling;
1074
1075 #[cfg(feature = "checks")]
1076 self.check_siblings(iter, next, node.orientation);
1077
1078 iter = next;
1079 }
1080
1081 if node.parent.is_some() {
1082 if self.nodes[node.parent.index()].kind != NodeKind::Container {
1083 panic!("error: child: {:?} parent: {:?}", node_idx, node.parent);
1084 }
1085 assert_eq!(
1086 self.nodes[node.parent.index()].orientation,
1087 node.orientation.flipped()
1088 );
1089 assert_eq!(self.nodes[node.parent.index()].kind, NodeKind::Container);
1090 }
1091 }
1092 }
1093
1094 fn add_free_rect(&mut self, id: AllocIndex, size: &Size) {
1095 debug_assert_eq!(self.nodes[id.index()].kind, NodeKind::Free);
1096 let bucket = free_list_for_size(self.small_size_threshold, self.large_size_threshold, size);
1097 self.free_lists[bucket].push(id);
1098 }
1099
1100 fn update_free_list_bucket(&mut self, id: AllocIndex) {
1103 debug_assert_eq!(self.nodes[id.index()].kind, NodeKind::Free);
1104
1105 for bucket in 0..NUM_BUCKETS {
1107 if let Some(pos) = self.free_lists[bucket].iter().position(|&i| i == id) {
1108 self.free_lists[bucket].swap_remove(pos);
1109 break;
1110 }
1111 }
1112
1113 let size = self.nodes[id.index()].rect.size();
1114 self.add_free_rect(id, &size);
1115 }
1116
1117 fn merge_siblings(&mut self, node: AllocIndex, next: AllocIndex, orientation: Orientation) {
1119 debug_assert_eq!(self.nodes[node.index()].kind, NodeKind::Free);
1120 debug_assert_eq!(self.nodes[next.index()].kind, NodeKind::Free);
1121 let r1 = self.nodes[node.index()].rect;
1122 let r2 = self.nodes[next.index()].rect;
1123 let merge_size = self.nodes[next.index()].rect.size();
1124 match orientation {
1125 Orientation::Horizontal => {
1126 debug_assert_eq!(r1.min.y, r2.min.y);
1127 debug_assert_eq!(r1.max.y, r2.max.y);
1128 self.nodes[node.index()].rect.max.x += merge_size.width;
1129 }
1130 Orientation::Vertical => {
1131 debug_assert_eq!(r1.min.x, r2.min.x);
1132 debug_assert_eq!(r1.max.x, r2.max.x);
1133 self.nodes[node.index()].rect.max.y += merge_size.height;
1134 }
1135 }
1136
1137 let next_next = self.nodes[next.index()].next_sibling;
1139 self.nodes[node.index()].next_sibling = next_next;
1140 if next_next.is_some() {
1141 self.nodes[next_next.index()].prev_sibling = node;
1142 }
1143
1144 self.mark_node_unused(next);
1146 }
1147
1148 fn alloc_id(&self, index: AllocIndex) -> AllocId {
1149 let generation = self.generations[index.index()].0 as u32;
1150 debug_assert!(index.0 & IDX_MASK == index.0);
1151 AllocId(index.0 + (generation << 24))
1152 }
1153
1154 fn get_index(&self, id: AllocId) -> AllocIndex {
1155 let idx = id.0 & IDX_MASK;
1156 let expected_generation = (self.generations[idx as usize].0 as u32) << 24;
1157 assert_eq!(id.0 & GEN_MASK, expected_generation);
1158 AllocIndex(idx)
1159 }
1160}
1161
1162impl core::ops::Index<AllocId> for AtlasAllocator {
1163 type Output = Rectangle;
1164 fn index(&self, index: AllocId) -> &Rectangle {
1165 let idx = self.get_index(index);
1166
1167 &self.nodes[idx.index()].rect
1168 }
1169}
1170
1171pub struct SimpleAtlasAllocator {
1173 free_rects: [Vec<Rectangle>; 3],
1174 alignment: Size,
1175 small_size_threshold: i32,
1176 large_size_threshold: i32,
1177 size: Size,
1178}
1179
1180impl SimpleAtlasAllocator {
1181 pub fn new(size: Size) -> Self {
1183 Self::with_options(size, &DEFAULT_OPTIONS)
1184 }
1185
1186 pub fn with_options(size: Size, options: &AllocatorOptions) -> Self {
1188 let bucket = free_list_for_size(
1189 options.small_size_threshold,
1190 options.large_size_threshold,
1191 &size,
1192 );
1193
1194 let mut free_rects = [Vec::new(), Vec::new(), Vec::new()];
1195 free_rects[bucket].push(size.into());
1196
1197 SimpleAtlasAllocator {
1198 free_rects,
1199 alignment: options.alignment,
1200 small_size_threshold: options.small_size_threshold,
1201 large_size_threshold: options.large_size_threshold,
1202 size,
1203 }
1204 }
1205
1206 pub fn clear(&mut self) {
1208
1209 for i in 0..NUM_BUCKETS {
1210 self.free_rects[i].clear();
1211 }
1212
1213 let bucket = free_list_for_size(
1214 self.small_size_threshold,
1215 self.large_size_threshold,
1216 &self.size,
1217 );
1218
1219 self.free_rects[bucket].push(self.size.into());
1220 }
1221
1222 pub fn reset(&mut self, size: Size, options: &AllocatorOptions) {
1224 self.alignment = options.alignment;
1225 self.small_size_threshold = options.small_size_threshold;
1226 self.large_size_threshold = options.large_size_threshold;
1227 self.size = size;
1228
1229 self.clear();
1230 }
1231
1232 pub fn is_empty(&self) -> bool {
1233 for b in 0..NUM_BUCKETS {
1234 for rect in &self.free_rects[b] {
1235 return rect.size() == self.size;
1236 }
1237 }
1238
1239 return false;
1241 }
1242
1243 pub fn size(&self) -> Size {
1245 self.size
1246 }
1247
1248 pub fn allocate(&mut self, mut requested_size: Size) -> Option<Rectangle> {
1250 if requested_size.is_empty() {
1251 return None;
1252 }
1253
1254 adjust_size(self.alignment.width, &mut requested_size.width);
1255 adjust_size(self.alignment.height, &mut requested_size.height);
1256
1257 let ideal_bucket = free_list_for_size(
1258 self.small_size_threshold,
1259 self.large_size_threshold,
1260 &requested_size,
1261 );
1262
1263 let use_worst_fit = ideal_bucket == LARGE_BUCKET;
1264
1265 let mut chosen_rect = None;
1266 for bucket in ideal_bucket..NUM_BUCKETS {
1267 let mut candidate_score = if use_worst_fit { 0 } else { i32::MAX };
1268 let mut candidate = None;
1269
1270 for (index, rect) in self.free_rects[bucket].iter().enumerate() {
1271 let dx = rect.width() - requested_size.width;
1272 let dy = rect.height() - requested_size.height;
1273
1274 if dx >= 0 && dy >= 0 {
1275 if dx == 0 || dy == 0 {
1276 candidate = Some(index);
1278 break;
1279 }
1280
1281 let score = i32::min(dx, dy);
1282 if (use_worst_fit && score > candidate_score)
1283 || (!use_worst_fit && score < candidate_score)
1284 {
1285 candidate_score = score;
1286 candidate = Some(index);
1287 }
1288 }
1289 }
1290
1291 if let Some(index) = candidate {
1292 let rect = self.free_rects[bucket].remove(index);
1293 chosen_rect = Some(rect);
1294 break;
1295 }
1296 }
1297
1298 if let Some(rect) = chosen_rect {
1299 let (split_rect, leftover_rect, _) =
1300 guillotine_rect(&rect, requested_size, Orientation::Vertical);
1301 self.add_free_rect(&split_rect);
1302 self.add_free_rect(&leftover_rect);
1303
1304 return Some(Rectangle {
1305 min: rect.min,
1306 max: rect.min + requested_size.to_vector(),
1307 });
1308 }
1309
1310 None
1311 }
1312
1313 pub fn grow(&mut self, new_size: Size) {
1317 assert!(new_size.width >= self.size.width);
1318 assert!(new_size.height >= self.size.height);
1319
1320 let (split_rect, leftover_rect, _) =
1321 guillotine_rect(&new_size.into(), self.size, Orientation::Vertical);
1322
1323 self.size = new_size;
1324
1325 self.add_free_rect(&split_rect);
1326 self.add_free_rect(&leftover_rect);
1327 }
1328
1329 pub fn init_from_allocator(&mut self, src: &AtlasAllocator) {
1331 self.size = src.size;
1332 self.alignment = src.alignment;
1333 self.small_size_threshold = src.small_size_threshold;
1334 self.large_size_threshold = src.large_size_threshold;
1335
1336 for bucket in 0..NUM_BUCKETS {
1337 self.free_rects[bucket].clear();
1338
1339 for id in src.free_lists[bucket].iter() {
1340 if src.nodes[id.index()].kind != NodeKind::Free {
1345 continue;
1346 }
1347
1348 self.free_rects[bucket].push(src.nodes[id.index()].rect);
1349 }
1350 }
1351 }
1352
1353 fn add_free_rect(&mut self, rect: &Rectangle) {
1354 if rect.width() < self.alignment.width || rect.height() < self.alignment.height {
1355 return;
1356 }
1357
1358 let bucket = free_list_for_size(
1359 self.small_size_threshold,
1360 self.large_size_threshold,
1361 &rect.size(),
1362 );
1363
1364 self.free_rects[bucket].push(*rect);
1365 }
1366}
1367
1368fn adjust_size(alignment: i32, size: &mut i32) {
1369 let rem = *size % alignment;
1370 if rem > 0 {
1371 *size += alignment - rem;
1372 }
1373}
1374
1375fn safe_area(rect: &Rectangle) -> i32 {
1377 rect.width().checked_mul(rect.height()).unwrap_or(i32::MAX)
1378}
1379
1380fn guillotine_rect(
1381 chosen_rect: &Rectangle,
1382 requested_size: Size,
1383 default_orientation: Orientation,
1384) -> (Rectangle, Rectangle, Orientation) {
1385 let candidate_leftover_rect_to_right = Rectangle {
1425 min: chosen_rect.min + vec2(requested_size.width, 0),
1426 max: point2(chosen_rect.max.x, chosen_rect.min.y + requested_size.height),
1427 };
1428 let candidate_leftover_rect_to_bottom = Rectangle {
1429 min: chosen_rect.min + vec2(0, requested_size.height),
1430 max: point2(chosen_rect.min.x + requested_size.width, chosen_rect.max.y),
1431 };
1432
1433 let split_rect;
1434 let leftover_rect;
1435 let orientation;
1436 if requested_size == chosen_rect.size() {
1437 orientation = default_orientation;
1439 split_rect = Rectangle::zero();
1440 leftover_rect = Rectangle::zero();
1441 } else if safe_area(&candidate_leftover_rect_to_right) > safe_area(&candidate_leftover_rect_to_bottom) {
1442 leftover_rect = candidate_leftover_rect_to_bottom;
1443 split_rect = Rectangle {
1444 min: candidate_leftover_rect_to_right.min,
1445 max: point2(candidate_leftover_rect_to_right.max.x, chosen_rect.max.y),
1446 };
1447 orientation = Orientation::Horizontal;
1448 } else {
1449 leftover_rect = candidate_leftover_rect_to_right;
1450 split_rect = Rectangle {
1451 min: candidate_leftover_rect_to_bottom.min,
1452 max: point2(chosen_rect.max.x, candidate_leftover_rect_to_bottom.max.y),
1453 };
1454 orientation = Orientation::Vertical;
1455 }
1456
1457 (split_rect, leftover_rect, orientation)
1458}
1459
1460#[repr(C)]
1461#[derive(Copy, Clone, Debug, PartialEq)]
1462pub struct Allocation {
1463 pub id: AllocId,
1464 pub rectangle: Rectangle,
1465}
1466
1467#[repr(C)]
1468#[derive(Copy, Clone, Debug, PartialEq)]
1469pub struct Change {
1470 pub old: Allocation,
1471 pub new: Allocation,
1472}
1473
1474#[derive(Clone, Debug, PartialEq)]
1475pub struct ChangeList {
1476 pub changes: Vec<Change>,
1477 pub failures: Vec<Allocation>,
1478}
1479
1480impl ChangeList {
1481 pub fn empty() -> Self {
1482 ChangeList {
1483 changes: Vec::new(),
1484 failures: Vec::new(),
1485 }
1486 }
1487}
1488
1489#[cfg(feature = "std")]
1491pub fn dump_svg(atlas: &AtlasAllocator, output: &mut dyn std::io::Write) -> std::io::Result<()> {
1492 use svg_fmt::*;
1493
1494 writeln!(
1495 output,
1496 "{}",
1497 BeginSvg {
1498 w: atlas.size.width as f32,
1499 h: atlas.size.height as f32
1500 }
1501 )?;
1502
1503 dump_into_svg(atlas, None, output)?;
1504
1505 writeln!(output, "{}", EndSvg)
1506}
1507
1508#[cfg(feature = "std")]
1513pub fn dump_into_svg(atlas: &AtlasAllocator, rect: Option<&Rectangle>, output: &mut dyn std::io::Write) -> std::io::Result<()> {
1514 use svg_fmt::*;
1515
1516 let (sx, sy, tx, ty) = if let Some(rect) = rect {
1517 (
1518 rect.width() as f32 / atlas.size.width as f32,
1519 rect.height() as f32 / atlas.size.height as f32,
1520 rect.min.x as f32,
1521 rect.min.y as f32,
1522 )
1523 } else {
1524 (1.0, 1.0, 0.0, 0.0)
1525 };
1526
1527 for node in &atlas.nodes {
1528 let color = match node.kind {
1529 NodeKind::Free => rgb(50, 50, 50),
1530 NodeKind::Alloc => rgb(70, 70, 180),
1531 _ => {
1532 continue;
1533 }
1534 };
1535
1536 let (x, y) = node.rect.min.to_f32().to_tuple();
1537 let (w, h) = node.rect.size().to_f32().to_tuple();
1538
1539 writeln!(
1540 output,
1541 r#" {}"#,
1542 rectangle(tx + x * sx, ty + y * sy, w * sx, h * sy)
1543 .fill(color)
1544 .stroke(Stroke::Color(black(), 1.0))
1545 )?;
1546 }
1547
1548 Ok(())
1549}
1550
1551#[test]
1552fn atlas_basic() {
1553 let mut atlas = AtlasAllocator::new(size2(1000, 1000));
1554
1555 let full = atlas.allocate(size2(1000, 1000)).unwrap().id;
1556 assert!(atlas.allocate(size2(1, 1)).is_none());
1557
1558 atlas.deallocate(full);
1559
1560 let a = atlas.allocate(size2(100, 1000)).unwrap().id;
1561 let b = atlas.allocate(size2(900, 200)).unwrap().id;
1562 let c = atlas.allocate(size2(300, 200)).unwrap().id;
1563 let d = atlas.allocate(size2(200, 300)).unwrap().id;
1564 let e = atlas.allocate(size2(100, 300)).unwrap().id;
1565 let f = atlas.allocate(size2(100, 300)).unwrap().id;
1566 let g = atlas.allocate(size2(100, 300)).unwrap().id;
1567
1568 atlas.deallocate(b);
1569 atlas.deallocate(f);
1570 atlas.deallocate(c);
1571 atlas.deallocate(e);
1572 let h = atlas.allocate(size2(500, 200)).unwrap().id;
1573 atlas.deallocate(a);
1574 let i = atlas.allocate(size2(500, 200)).unwrap().id;
1575 atlas.deallocate(g);
1576 atlas.deallocate(h);
1577 atlas.deallocate(d);
1578 atlas.deallocate(i);
1579
1580 let full = atlas.allocate(size2(1000, 1000)).unwrap().id;
1581 assert!(atlas.allocate(size2(1, 1)).is_none());
1582 atlas.deallocate(full);
1583}
1584
1585#[test]
1586fn atlas_random_test() {
1587 let mut atlas = AtlasAllocator::with_options(
1588 size2(1000, 1000),
1589 &AllocatorOptions {
1590 alignment: size2(5, 2),
1591 ..DEFAULT_OPTIONS
1592 },
1593 );
1594
1595 let a = 1103515245;
1596 let c = 12345;
1597 let m = usize::pow(2, 31);
1598 let mut seed: usize = 37;
1599
1600 let mut rand = || {
1601 seed = (a * seed + c) % m;
1602 seed
1603 };
1604
1605 let mut n: usize = 0;
1606 let mut misses: usize = 0;
1607
1608 let mut allocated = Vec::new();
1609 for _ in 0..500000 {
1610 if rand() % 5 > 2 && !allocated.is_empty() {
1611 let nth = rand() % allocated.len();
1613 let id = allocated[nth];
1614 allocated.remove(nth);
1615
1616 atlas.deallocate(id);
1617 } else {
1618 let size = size2((rand() % 300) as i32 + 5, (rand() % 300) as i32 + 5);
1620
1621 if let Some(alloc) = atlas.allocate(size) {
1622 allocated.push(alloc.id);
1623 n += 1;
1624 } else {
1625 misses += 1;
1626 }
1627 }
1628 }
1629
1630 while let Some(id) = allocated.pop() {
1631 atlas.deallocate(id);
1632 }
1633
1634 std::println!("added/removed {} rectangles, {} misses", n, misses);
1635 std::println!(
1636 "nodes.cap: {}, free_list.cap: {}/{}/{}",
1637 atlas.nodes.capacity(),
1638 atlas.free_lists[LARGE_BUCKET].capacity(),
1639 atlas.free_lists[MEDIUM_BUCKET].capacity(),
1640 atlas.free_lists[SMALL_BUCKET].capacity(),
1641 );
1642
1643 let full = atlas.allocate(size2(1000, 1000)).unwrap().id;
1644 assert!(atlas.allocate(size2(1, 1)).is_none());
1645 atlas.deallocate(full);
1646}
1647
1648#[test]
1649fn test_grow() {
1650 let mut atlas = AtlasAllocator::new(size2(1000, 1000));
1651
1652 atlas.grow(size2(2000, 2000));
1653
1654 let full = atlas.allocate(size2(2000, 2000)).unwrap().id;
1655 assert!(atlas.allocate(size2(1, 1)).is_none());
1656 atlas.deallocate(full);
1657
1658 let a = atlas.allocate(size2(100, 100)).unwrap().id;
1659
1660 atlas.grow(size2(3000, 3000));
1661
1662 let b = atlas.allocate(size2(1000, 2900)).unwrap().id;
1663
1664 atlas.grow(size2(4000, 4000));
1665
1666 atlas.deallocate(b);
1667 atlas.deallocate(a);
1668
1669 let full = atlas.allocate(size2(4000, 4000)).unwrap().id;
1670 assert!(atlas.allocate(size2(1, 1)).is_none());
1671 atlas.deallocate(full);
1672}
1673
1674#[test]
1675fn clear_empty() {
1676 let mut atlas = AtlasAllocator::new(size2(1000, 1000));
1677
1678 assert!(atlas.is_empty());
1679
1680 assert!(atlas.allocate(size2(10, 10)).is_some());
1681 assert!(!atlas.is_empty());
1682
1683 atlas.clear();
1684 assert!(atlas.is_empty());
1685
1686 let a = atlas.allocate(size2(10, 10)).unwrap().id;
1687 let b = atlas.allocate(size2(20, 20)).unwrap().id;
1688 assert!(!atlas.is_empty());
1689
1690 atlas.deallocate(b);
1691 atlas.deallocate(a);
1692 assert!(atlas.is_empty());
1693
1694 atlas.clear();
1695 assert!(atlas.is_empty());
1696
1697 atlas.clear();
1698 assert!(atlas.is_empty());
1699}
1700
1701#[test]
1702fn simple_atlas() {
1703 let mut atlas = SimpleAtlasAllocator::new(size2(1000, 1000));
1704
1705 assert!(atlas.allocate(size2(1, 1001)).is_none());
1706 assert!(atlas.allocate(size2(1001, 1)).is_none());
1707
1708 let mut rectangles = Vec::new();
1709 rectangles.push(atlas.allocate(size2(100, 1000)).unwrap());
1710 rectangles.push(atlas.allocate(size2(900, 200)).unwrap());
1711 rectangles.push(atlas.allocate(size2(300, 200)).unwrap());
1712 rectangles.push(atlas.allocate(size2(200, 300)).unwrap());
1713 rectangles.push(atlas.allocate(size2(100, 300)).unwrap());
1714 rectangles.push(atlas.allocate(size2(100, 300)).unwrap());
1715 rectangles.push(atlas.allocate(size2(100, 300)).unwrap());
1716 assert!(atlas.allocate(size2(800, 800)).is_none());
1717
1718 for i in 0..rectangles.len() {
1719 for j in 0..rectangles.len() {
1720 if i == j {
1721 continue;
1722 }
1723
1724 assert!(!rectangles[i].intersects(&rectangles[j]));
1725 }
1726 }
1727}
1728
1729#[test]
1730fn allocate_zero() {
1731 let mut atlas = SimpleAtlasAllocator::new(size2(1000, 1000));
1732
1733 assert!(atlas.allocate(size2(0, 0)).is_none());
1734}
1735
1736#[test]
1737fn allocate_negative() {
1738 let mut atlas = SimpleAtlasAllocator::new(size2(1000, 1000));
1739
1740 assert!(atlas.allocate(size2(-1, 1)).is_none());
1741 assert!(atlas.allocate(size2(1, -1)).is_none());
1742 assert!(atlas.allocate(size2(-1, -1)).is_none());
1743
1744 assert!(atlas.allocate(size2(-167114179, -718142)).is_none());
1745}
1746
1747#[test]
1748fn issue_25() {
1749 let mut allocator = AtlasAllocator::new(Size::new(65536, 65536));
1750 allocator.allocate(Size::new(2,2));
1751 allocator.allocate(Size::new(65500,2));
1752 allocator.allocate(Size::new(2, 65500));
1753}
1754
1755#[test]
1756fn grow_free_list_bucket() {
1757 let mut atlas = AtlasAllocator::with_options(
1761 size2(100, 100),
1762 &AllocatorOptions {
1763 small_size_threshold: 32,
1764 large_size_threshold: 256,
1765 ..DEFAULT_OPTIONS
1766 },
1767 );
1768
1769 let a = atlas.allocate(size2(100, 90)).unwrap().id;
1773
1774 atlas.grow(size2(100, 1100));
1779
1780 assert!(
1784 atlas.allocate(size2(100, 500)).is_some(),
1785 "Should find the grown free strip in the correct bucket"
1786 );
1787
1788 atlas.deallocate(a);
1789
1790 let mut atlas2 = AtlasAllocator::with_options(
1792 size2(20, 20),
1793 &AllocatorOptions {
1794 small_size_threshold: 32,
1795 large_size_threshold: 256,
1796 ..DEFAULT_OPTIONS
1797 },
1798 );
1799 atlas2.grow(size2(512, 512));
1802
1803 assert!(
1805 atlas2.allocate(size2(500, 500)).is_some(),
1806 "Single-root grow should update the free list bucket"
1807 );
1808}