Bug 1878375 - Synchronize vendored Rust libraries with mozilla-central. r=darktrojan
mozilla-central: eeada934b615e943700b2b09e517fd419d9abcb8 comm-central: d6335c2b9e6a517c8103e37a0ffec4b69b25c54d Differential Revision: https://phabricator.services.mozilla.com/D213382 --HG-- extra : amend_source : 2ece21a2ca08b1a10253d50c65798043e1ed20ed
This commit is contained in:
Родитель
649cc90219
Коммит
1deed10da7
|
@ -1494,9 +1494,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "etagere"
|
||||
version = "0.2.7"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6301151a318f367f392c31395beb1cfba5ccd9abc44d1db0db3a4b27b9601c89"
|
||||
checksum = "4460bc8c5caa3360e4221a5a2930c654a141dd3fe067a00c5355c488e711ae79"
|
||||
dependencies = [
|
||||
"euclid",
|
||||
"serde",
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"mc_workspace_toml": "50c105726dd9f7aa5c90114fb6f907234844ce7750dec4e18c3b245b33ae6ba8a44936e692a2ac11271a5cfc1ae8f1f1235482ddb4e72693a9513479d611bc4d", "mc_gkrust_toml": "ec12ac730b7f709bd839c1fc9c65f36ae6f82b481902e72769b3d32cfc0a66a6cbf3246a9ab933eca3b3ca06f4f27fe9e88f4706142732460399344681da9e9e", "mc_cargo_lock": "b39abccbd6f59569ba9b3ff5e994ff336d83a7b0db2cca46c5221592511abc98001feb1a9f374d20b23aa19bb9de33e7388d77a1ac222705fb1c27bb2776598d"}
|
||||
{"mc_workspace_toml": "50c105726dd9f7aa5c90114fb6f907234844ce7750dec4e18c3b245b33ae6ba8a44936e692a2ac11271a5cfc1ae8f1f1235482ddb4e72693a9513479d611bc4d", "mc_gkrust_toml": "ec12ac730b7f709bd839c1fc9c65f36ae6f82b481902e72769b3d32cfc0a66a6cbf3246a9ab933eca3b3ca06f4f27fe9e88f4706142732460399344681da9e9e", "mc_cargo_lock": "782edd552ef699c5ae86e947024314838be3e334bb327cc61afd42f8338edbb13a8201397b4f145a1e67559b3aa43a05e9361f248b604f8062ceaa3959cd0f3c"}
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"131c1c4b73450c0109caa889c666ffd912d19e8cbb9249f3c71ef8f19ae5f909","LICENSE":"739e55c73735c9733d8be0e3ab1c3bdb2240df594602c18eefbf8c851a83a734","README.md":"e983d46af6c7fc18592ad9644d340bf3c5be9117490606b04aff9ac91c8c0495","src/allocator.rs":"7eea45f5cacb8b1822697638e7cf63d10c4a2047b6405123e3e401beae391510","src/bucketed.rs":"caad4039803df2eaf0b326c900b608f5707dda9066a72c87f95c98de87f96e0c","src/lib.rs":"ca8c534dcbccfc8c694b40622dbcecb45062bf79b36e1f5e000b680851059cb1"},"package":"6301151a318f367f392c31395beb1cfba5ccd9abc44d1db0db3a4b27b9601c89"}
|
||||
{"files":{"Cargo.toml":"62163c32b26a2035c22f8d99a9ac5eb6077bacb751b8582171df6cacf480d5f8","LICENSE-APACHE":"2d56a37f3d1e461f6b1539ab94e0e6bcc55443e376098aee85ac3b2890860290","LICENSE-MIT":"9cfc9c9a4608501b5da3746948d2be2dd709ad51f6bcb0c1c685760ee3dde31f","README.md":"e983d46af6c7fc18592ad9644d340bf3c5be9117490606b04aff9ac91c8c0495","src/allocator.rs":"d84d62a3eb8dda52064f31d6b135ca08bc8c6b04937b34a61accf875740314ff","src/bucketed.rs":"ebd8e560f0e4b839b4ea887789be5e03767839cc245bd52567ad66bec224053f","src/lib.rs":"6dbb3c623cc4a1bc641dd314e0a8482788945eb6fb7c11c9fd9d6ddad6a630e1"},"package":"4460bc8c5caa3360e4221a5a2930c654a141dd3fe067a00c5355c488e711ae79"}
|
|
@ -12,16 +12,19 @@
|
|||
[package]
|
||||
edition = "2018"
|
||||
name = "etagere"
|
||||
version = "0.2.7"
|
||||
version = "0.2.11"
|
||||
authors = ["Nicolas Silva <nical@fastmail.com>"]
|
||||
exclude = [".backup*"]
|
||||
description = "Dynamic 2D texture atlas allocation using the shelf packing algorithm."
|
||||
documentation = "https://docs.rs/etagere/"
|
||||
readme = "README.md"
|
||||
keywords = ["2d"]
|
||||
license = "MIT/Apache-2.0"
|
||||
repository = "https://github.com/nical/etagere"
|
||||
|
||||
[profile.release]
|
||||
debug = true
|
||||
debug = 2
|
||||
|
||||
[dependencies.euclid]
|
||||
version = "0.22"
|
||||
|
||||
|
@ -34,4 +37,7 @@ version = "0.4"
|
|||
|
||||
[features]
|
||||
checks = []
|
||||
serialization = ["serde", "euclid/serde"]
|
||||
serialization = [
|
||||
"serde",
|
||||
"euclid/serde",
|
||||
]
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2020 Nicolas Silva
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -0,0 +1,13 @@
|
|||
Copyright 2020 Nicolas Silva
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -0,0 +1,20 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2020 Nicolas Silva
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -42,6 +42,7 @@ struct Shelf {
|
|||
prev: ShelfIndex,
|
||||
next: ShelfIndex,
|
||||
first_item: ItemIndex,
|
||||
first_unallocated: ItemIndex,
|
||||
is_empty: bool,
|
||||
}
|
||||
|
||||
|
@ -52,6 +53,8 @@ struct Item {
|
|||
width: u16,
|
||||
prev: ItemIndex,
|
||||
next: ItemIndex,
|
||||
prev_unallocated: ItemIndex,
|
||||
next_unallocated: ItemIndex,
|
||||
shelf: ShelfIndex,
|
||||
allocated: bool,
|
||||
generation: u16,
|
||||
|
@ -148,6 +151,7 @@ impl AtlasAllocator {
|
|||
next,
|
||||
is_empty: true,
|
||||
first_item,
|
||||
first_unallocated: first_item,
|
||||
});
|
||||
|
||||
self.items.push(Item {
|
||||
|
@ -155,6 +159,8 @@ impl AtlasAllocator {
|
|||
width: self.shelf_width,
|
||||
prev: ItemIndex::NONE,
|
||||
next: ItemIndex::NONE,
|
||||
prev_unallocated: ItemIndex::NONE,
|
||||
next_unallocated: ItemIndex::NONE,
|
||||
shelf: current,
|
||||
allocated: false,
|
||||
generation: 1,
|
||||
|
@ -213,14 +219,14 @@ impl AtlasAllocator {
|
|||
continue;
|
||||
}
|
||||
|
||||
let mut item_idx = shelf.first_item;
|
||||
let mut item_idx = shelf.first_unallocated;
|
||||
while item_idx.is_some() {
|
||||
let item = &self.items[item_idx.index()];
|
||||
if !item.allocated && item.width >= width {
|
||||
break;
|
||||
}
|
||||
|
||||
item_idx = item.next;
|
||||
item_idx = item.next_unallocated;
|
||||
}
|
||||
|
||||
if item_idx.is_some() {
|
||||
|
@ -257,6 +263,7 @@ impl AtlasAllocator {
|
|||
prev: selected_shelf,
|
||||
next: shelf.next,
|
||||
first_item: ItemIndex::NONE,
|
||||
first_unallocated: ItemIndex::NONE,
|
||||
is_empty: true,
|
||||
});
|
||||
|
||||
|
@ -265,12 +272,15 @@ impl AtlasAllocator {
|
|||
width: self.shelf_width,
|
||||
prev: ItemIndex::NONE,
|
||||
next: ItemIndex::NONE,
|
||||
prev_unallocated: ItemIndex::NONE,
|
||||
next_unallocated: ItemIndex::NONE,
|
||||
shelf: new_shelf_idx,
|
||||
allocated: false,
|
||||
generation: 1,
|
||||
});
|
||||
|
||||
self.shelves[new_shelf_idx.index()].first_item = new_item_idx;
|
||||
self.shelves[new_shelf_idx.index()].first_unallocated = new_item_idx;
|
||||
|
||||
let next = self.shelves[selected_shelf.index()].next;
|
||||
self.shelves[selected_shelf.index()].height = height;
|
||||
|
@ -292,6 +302,8 @@ impl AtlasAllocator {
|
|||
width: item.width - width,
|
||||
prev: selected_item,
|
||||
next: item.next,
|
||||
prev_unallocated: item.prev_unallocated,
|
||||
next_unallocated: item.next_unallocated,
|
||||
shelf: item.shelf,
|
||||
allocated: false,
|
||||
generation: 1,
|
||||
|
@ -303,7 +315,31 @@ impl AtlasAllocator {
|
|||
if item.next.is_some() {
|
||||
self.items[item.next.index()].prev = new_item_idx;
|
||||
}
|
||||
|
||||
// Replace the item in the "unallocated" list.
|
||||
let shelf = &mut self.shelves[selected_shelf.index()];
|
||||
if shelf.first_unallocated == selected_item {
|
||||
shelf.first_unallocated = new_item_idx;
|
||||
}
|
||||
if item.prev_unallocated.is_some() {
|
||||
self.items[item.prev_unallocated.index()].next_unallocated = new_item_idx;
|
||||
}
|
||||
if item.next_unallocated.is_some() {
|
||||
self.items[item.next_unallocated.index()].prev_unallocated = new_item_idx;
|
||||
}
|
||||
} else {
|
||||
// Remove the item from the "unallocated" list.
|
||||
let shelf = &mut self.shelves[selected_shelf.index()];
|
||||
if shelf.first_unallocated == selected_item {
|
||||
shelf.first_unallocated = item.next_unallocated;
|
||||
}
|
||||
if item.prev_unallocated.is_some() {
|
||||
self.items[item.prev_unallocated.index()].next_unallocated = item.next_unallocated;
|
||||
}
|
||||
if item.next_unallocated.is_some() {
|
||||
self.items[item.next_unallocated.index()].prev_unallocated = item.prev_unallocated;
|
||||
}
|
||||
|
||||
width = item.width;
|
||||
}
|
||||
|
||||
|
@ -337,7 +373,6 @@ impl AtlasAllocator {
|
|||
pub fn deallocate(&mut self, id: AllocId) {
|
||||
let item_idx = ItemIndex(id.index());
|
||||
|
||||
//let item = self.items[item_idx.index()].clone();
|
||||
let Item { mut prev, mut next, mut width, allocated, shelf, generation, .. } = self.items[item_idx.index()];
|
||||
assert!(allocated);
|
||||
assert_eq!(generation, id.generation(), "Invalid AllocId");
|
||||
|
@ -350,6 +385,18 @@ impl AtlasAllocator {
|
|||
|
||||
let next_next = self.items[next.index()].next;
|
||||
let next_width = self.items[next.index()].width;
|
||||
// Remove next from the "unallocated" list.
|
||||
let next_unallocated = self.items[next.index()].next_unallocated;
|
||||
let prev_unallocated = self.items[next.index()].prev_unallocated;
|
||||
if self.shelves[shelf.index()].first_unallocated == next {
|
||||
self.shelves[shelf.index()].first_unallocated = next_unallocated;
|
||||
}
|
||||
if prev_unallocated.is_some() {
|
||||
self.items[prev_unallocated.index()].next_unallocated = next_unallocated;
|
||||
}
|
||||
if next_unallocated.is_some() {
|
||||
self.items[next_unallocated.index()].prev_unallocated = prev_unallocated;
|
||||
}
|
||||
|
||||
self.items[item_idx.index()].next = next_next;
|
||||
self.items[item_idx.index()].width += next_width;
|
||||
|
@ -367,6 +414,8 @@ impl AtlasAllocator {
|
|||
|
||||
if prev.is_some() && !self.items[prev.index()].allocated {
|
||||
// Merge the item into the previous one.
|
||||
// No need to add the item_idx to the "unallocated" list since it
|
||||
// is getting merged into an already unallocated item.
|
||||
|
||||
self.items[prev.index()].next = next;
|
||||
self.items[prev.index()].width += width;
|
||||
|
@ -379,6 +428,15 @@ impl AtlasAllocator {
|
|||
self.remove_item(item_idx);
|
||||
|
||||
prev = self.items[prev.index()].prev;
|
||||
} else {
|
||||
// Insert item_idx in the "unallocated" list.
|
||||
let first = self.shelves[shelf.index()].first_unallocated;
|
||||
if first.is_some() {
|
||||
self.items[first.index()].prev_unallocated = item_idx;
|
||||
}
|
||||
self.items[item_idx.index()].next_unallocated = first;
|
||||
self.items[item_idx.index()].prev_unallocated = ItemIndex::NONE;
|
||||
self.shelves[shelf.index()].first_unallocated = item_idx;
|
||||
}
|
||||
|
||||
if prev.is_none() && next.is_none() {
|
||||
|
@ -536,12 +594,16 @@ impl AtlasAllocator {
|
|||
prev_empty = shelf.is_empty;
|
||||
|
||||
let mut accum_w = 0;
|
||||
let mut accum_unallocated_w = 0;
|
||||
let mut prev_allocated = true;
|
||||
let mut item_idx = shelf.first_item;
|
||||
let mut prev_item_idx = ItemIndex::NONE;
|
||||
while item_idx.is_some() {
|
||||
let item = &self.items[item_idx.index()];
|
||||
accum_w += item.width;
|
||||
if !item.allocated {
|
||||
accum_unallocated_w += item.width;
|
||||
}
|
||||
|
||||
assert_eq!(item.prev, prev_item_idx);
|
||||
|
||||
|
@ -556,6 +618,24 @@ impl AtlasAllocator {
|
|||
|
||||
assert_eq!(accum_w, self.shelf_width);
|
||||
|
||||
// Traverse the shelf's unallocated list, validate it and check that it matches
|
||||
// the amount of unallocated space we found from traversing the whole shelf.
|
||||
accum_w = 0;
|
||||
let mut item_idx = shelf.first_unallocated;
|
||||
let mut prev_unallocated_idx = ItemIndex::NONE;
|
||||
while item_idx.is_some() {
|
||||
let item = &self.items[item_idx.index()];
|
||||
assert!(!item.allocated);
|
||||
|
||||
assert_eq!(item.prev_unallocated, prev_unallocated_idx);
|
||||
accum_w += item.width;
|
||||
|
||||
prev_unallocated_idx = item_idx;
|
||||
item_idx = item.next_unallocated;
|
||||
}
|
||||
|
||||
assert_eq!(accum_w, accum_unallocated_w, "items missing from the unallocated list?");
|
||||
|
||||
shelf_idx = shelf.next;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -135,6 +135,69 @@ impl BucketedAtlasAllocator {
|
|||
size2(w as i32, h as i32)
|
||||
}
|
||||
|
||||
pub fn grow(&mut self, new_size: Size) {
|
||||
assert!(new_size.width < u16::MAX as i32);
|
||||
assert!(new_size.height < u16::MAX as i32);
|
||||
|
||||
let (new_width, new_height) = if self.flip_xy {
|
||||
(new_size.height as u16, new_size.width as u16)
|
||||
} else {
|
||||
(new_size.width as u16, new_size.height as u16)
|
||||
};
|
||||
|
||||
assert!(new_width >= self.width);
|
||||
assert!(new_height >= self.height);
|
||||
|
||||
self.available_height += new_height - self.height;
|
||||
self.width = new_width;
|
||||
self.height = new_height;
|
||||
|
||||
if self.num_columns == 1 {
|
||||
// Add as many new buckets as possible to the existing shelves.
|
||||
let additional_width = self.width - self.column_width;
|
||||
|
||||
let len = self.shelves.len();
|
||||
|
||||
for shelf_index in 0..len {
|
||||
let shelf = &self.shelves[shelf_index];
|
||||
let mut x = self.column_width;
|
||||
let bucket_width = shelf.bucket_width;
|
||||
|
||||
let max_new_buckets = (MAX_BIN_COUNT - self.buckets.len()) as u16;
|
||||
let mut num_buckets_to_add = additional_width / bucket_width;
|
||||
num_buckets_to_add = num_buckets_to_add.min(max_new_buckets);
|
||||
|
||||
let mut bucket_next = shelf.first_bucket;
|
||||
|
||||
for _ in 0..num_buckets_to_add {
|
||||
let bucket = Bucket {
|
||||
next: bucket_next,
|
||||
x,
|
||||
free_space: bucket_width,
|
||||
refcount: 0,
|
||||
shelf: shelf_index as u16,
|
||||
generation: Wrapping(0),
|
||||
item_count: 0,
|
||||
};
|
||||
|
||||
x += bucket_width;
|
||||
|
||||
let bucket_index = self.add_bucket(bucket);
|
||||
|
||||
bucket_next = bucket_index;
|
||||
}
|
||||
|
||||
self.shelves[shelf_index].first_bucket = bucket_next;
|
||||
}
|
||||
|
||||
// Resize the existing column.
|
||||
self.column_width = self.width;
|
||||
} else {
|
||||
// Add as many new columns as possible.
|
||||
self.num_columns = self.width / self.column_width;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.shelves.is_empty()
|
||||
}
|
||||
|
@ -235,7 +298,7 @@ impl BucketedAtlasAllocator {
|
|||
|
||||
/// How much space is available for future allocations.
|
||||
pub fn free_space(&self) -> i32 {
|
||||
(self.width * self.height) as i32 - self.allocated_space
|
||||
(self.width as i32 * self.height as i32) - self.allocated_space
|
||||
}
|
||||
|
||||
fn alloc_from_bucket(&mut self, shelf_index: usize, bucket_index: BucketIndex, width: u16) -> Option<Allocation> {
|
||||
|
@ -274,6 +337,22 @@ impl BucketedAtlasAllocator {
|
|||
Some(Allocation { id, rectangle })
|
||||
}
|
||||
|
||||
fn add_bucket(&mut self, mut bucket: Bucket) -> BucketIndex {
|
||||
let mut bucket_index = self.first_unallocated_bucket;
|
||||
|
||||
if bucket_index == BucketIndex::INVALID {
|
||||
bucket_index = BucketIndex(self.buckets.len() as u16);
|
||||
self.buckets.push(bucket);
|
||||
} else {
|
||||
let idx = bucket_index.to_usize();
|
||||
bucket.generation = self.buckets[idx].generation + Wrapping(1);
|
||||
self.first_unallocated_bucket = self.buckets[idx].next;
|
||||
self.buckets[idx] = bucket;
|
||||
}
|
||||
|
||||
bucket_index
|
||||
}
|
||||
|
||||
fn add_shelf(&mut self, width: u16, height: u16) -> usize {
|
||||
|
||||
let can_add_column = self.current_column + 1 < self.num_columns;
|
||||
|
@ -304,7 +383,7 @@ impl BucketedAtlasAllocator {
|
|||
let mut x = self.current_column * self.column_width;
|
||||
let mut bucket_next = BucketIndex::INVALID;
|
||||
for _ in 0..num_buckets {
|
||||
let mut bucket = Bucket {
|
||||
let bucket = Bucket {
|
||||
next: bucket_next,
|
||||
x,
|
||||
free_space: bucket_width,
|
||||
|
@ -314,19 +393,9 @@ impl BucketedAtlasAllocator {
|
|||
item_count: 0,
|
||||
};
|
||||
|
||||
let mut bucket_index = self.first_unallocated_bucket;
|
||||
x += bucket_width;
|
||||
|
||||
if bucket_index == BucketIndex::INVALID {
|
||||
bucket_index = BucketIndex(self.buckets.len() as u16);
|
||||
self.buckets.push(bucket);
|
||||
} else {
|
||||
let idx = bucket_index.to_usize();
|
||||
bucket.generation = self.buckets[idx].generation + Wrapping(1);
|
||||
self.first_unallocated_bucket = self.buckets[idx].next;
|
||||
|
||||
self.buckets[idx] = bucket;
|
||||
}
|
||||
let bucket_index = self.add_bucket(bucket);
|
||||
|
||||
bucket_next = bucket_index;
|
||||
}
|
||||
|
@ -724,6 +793,94 @@ fn test_coalesce_shelves() {
|
|||
assert_eq!(atlas.allocated_space(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn grow_vertically() {
|
||||
let mut atlas = BucketedAtlasAllocator::new(size2(256, 256));
|
||||
|
||||
// Allocate 7 shelves (leaving 32px of remaining space on top).
|
||||
let mut ids = Vec::new();
|
||||
for _ in 0..7 {
|
||||
for _ in 0..8 {
|
||||
ids.push(atlas.allocate(size2(32, 32)).unwrap().id)
|
||||
}
|
||||
}
|
||||
|
||||
// Free the first shelf.
|
||||
for i in 0..8 {
|
||||
atlas.deallocate(ids[i]);
|
||||
}
|
||||
|
||||
// Free the 3rd and 4th shelf.
|
||||
for i in 16..32 {
|
||||
atlas.deallocate(ids[i]);
|
||||
}
|
||||
|
||||
// Not enough space left in existing shelves and above.
|
||||
// even coalescing is not sufficient.
|
||||
assert!(atlas.allocate(size2(70, 70)).is_none());
|
||||
|
||||
// Grow just enough vertically to fit the previous region
|
||||
atlas.grow(size2(256, 256 + 70 - 32));
|
||||
|
||||
// Allocation should succeed now
|
||||
assert!(atlas.allocate(size2(70, 70)).is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn grow_horizontally() {
|
||||
let mut atlas = BucketedAtlasAllocator::new(size2(256, 256));
|
||||
|
||||
// Allocate 7 shelves (leaving 32px of remaining space on top).
|
||||
let mut ids = Vec::new();
|
||||
for _ in 0..7 {
|
||||
for _ in 0..8 {
|
||||
ids.push(atlas.allocate(size2(32, 32)).unwrap().id)
|
||||
}
|
||||
}
|
||||
|
||||
// Free the first shelf.
|
||||
for i in 0..8 {
|
||||
atlas.deallocate(ids[i]);
|
||||
}
|
||||
|
||||
// Free the 3rd and 4th shelf.
|
||||
for i in 16..32 {
|
||||
atlas.deallocate(ids[i]);
|
||||
}
|
||||
|
||||
// Not enough space left in existing shelves and above.
|
||||
// even coalescing is not sufficient.
|
||||
assert!(atlas.allocate(size2(512, 32)).is_none());
|
||||
|
||||
// Grow just enough horizontally to add more buckets
|
||||
atlas.grow(size2(256 * 2, 256));
|
||||
|
||||
// Allocation should succeed now
|
||||
assert!(atlas.allocate(size2(512, 32)).is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn grow_to_fit_allocation() {
|
||||
let mut atlas = BucketedAtlasAllocator::new(size2(32, 32));
|
||||
|
||||
// Allocate a shelve to make sure we have a non-empty atlas to test the update.
|
||||
atlas.allocate(size2(32, 32)).unwrap();
|
||||
|
||||
// Try to make a big allocation that doesn't fit.
|
||||
let big_allocation = size2(256, 256);
|
||||
|
||||
assert!(atlas.allocate(big_allocation).is_none());
|
||||
|
||||
// Grow to make enough space for the wanted allocation plus the original shelf.
|
||||
atlas.grow(size2(256, 32 + 256));
|
||||
|
||||
// Adding to the original shelf should succeed.
|
||||
assert!(atlas.allocate(size2(32, 32)).is_some());
|
||||
|
||||
// Big allocation should also succeed now.
|
||||
assert!(atlas.allocate(big_allocation).is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn columns() {
|
||||
let mut atlas = BucketedAtlasAllocator::with_options(size2(64, 64), &AllocatorOptions {
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
//! This crate provides two implementations of the shelf packing algorithm for *dynamic*
|
||||
//! texture atlas allocation (dynamic here means supporting both allocation and deallocation).
|
||||
//!
|
||||
//! [A thousand ways to pack the bin](http://pds25.egloos.com/pds/201504/21/98/RectangleBinPack.pdf)
|
||||
//! [A thousand ways to pack the bin](https://github.com/juj/RectangleBinPack/blob/master/RectangleBinPack.pdf)
|
||||
//! is a good resource to learn about rectangle packing algorithms, although it does not not cover
|
||||
//! deallocation which complicates the problem space a fair bit.
|
||||
//!
|
||||
|
|
Загрузка…
Ссылка в новой задаче