/* This Source Code Form is subject to the terms of the Mozilla Public *License,v.2.0.IfacopyoftheMPLwasnotdistributedwiththis
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize};
//TODO: gather real-world statistics on the bin usage in order to assist the decision // on where to place the size thresholds.
const NUM_BINS: usize = 3; /// The minimum number of pixels on each side that we require for rects to be classified as /// particular bin of freelists. const MIN_RECT_AXIS_SIZES: [i32; NUM_BINS] = [1, 16, 32];
#[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] struct Bin { // Store sizes with fewer bits per item and in a separate array to speed up // the search.
sizes: Vec<FreeRectSize>,
rects: Vec<FreeRect>,
}
/// A texture allocator using the guillotine algorithm. /// /// See sections 2.2 and 2.2.5 in "A Thousand Ways to Pack the Bin - A Practical Approach to Two- /// Dimensional Rectangle Bin Packing": /// /// http://clb.demon.fi/files/RectangleBinPack.pdf /// /// This approach was chosen because of its simplicity and good performance. /// /// Note: the allocations are spread across multiple textures, and also are binned /// orthogonally in order to speed up the search. #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pubstruct GuillotineAllocator {
bins: [Bin; NUM_BINS],
}
fn push(&mutself, slice: FreeRectSlice, rect: DeviceIntRect) { let id = FreeListBin::for_size(&rect.size()).0as usize; self.bins[id].rects.push(FreeRect {
slice,
rect,
}); self.bins[id].sizes.push(FreeRectSize {
width: rect.width() as i16,
height: rect.height() as i16,
});
}
/// Find a suitable rect in the free list. We choose the first fit. fn find_index_of_best_rect(
&self,
requested_dimensions: &DeviceIntSize,
) -> Option<(FreeListBin, FreeListIndex)> {
let start_bin = FreeListBin::for_size(&requested_dimensions);
let w = requested_dimensions.width as i16; let h = requested_dimensions.height as i16;
(start_bin.0 .. NUM_BINS as u8)
.find_map(|id| { self.bins[id as usize].sizes
.iter()
.position(|candidate| w <= candidate.width && h <= candidate.height)
.map(|index| (FreeListBin(id), FreeListIndex(index)))
})
}
// Split that results in the single largest area (Min Area Split Rule, MINAS). fn split_guillotine(&mutself, chosen: &FreeRect, requested_dimensions: &DeviceIntSize) { let candidate_free_rect_to_right = DeviceIntRect::from_origin_and_size(
DeviceIntPoint::new(
chosen.rect.min.x + requested_dimensions.width,
chosen.rect.min.y,
),
DeviceIntSize::new(
chosen.rect.width() - requested_dimensions.width,
requested_dimensions.height,
),
); let candidate_free_rect_to_bottom = DeviceIntRect::from_origin_and_size(
DeviceIntPoint::new(
chosen.rect.min.x,
chosen.rect.min.y + requested_dimensions.height,
),
DeviceIntSize::new(
requested_dimensions.width,
chosen.rect.height() - requested_dimensions.height,
),
);
// Add the guillotined rects back to the free list. if !new_free_rect_to_right.is_empty() { self.push(chosen.slice, new_free_rect_to_right);
} if !new_free_rect_to_bottom.is_empty() { self.push(chosen.slice, new_free_rect_to_bottom);
}
}
pubfn allocate(
&mutself, requested_dimensions: &DeviceIntSize
) -> Option<(FreeRectSlice, DeviceIntPoint)> { letmut requested_dimensions = *requested_dimensions; // Round up the size to a multiple of 8. This reduces the fragmentation // of the atlas.
requested_dimensions.width = (requested_dimensions.width + 7) & !7;
requested_dimensions.height = (requested_dimensions.height + 7) & !7;
let (bin, index) = self.find_index_of_best_rect(&requested_dimensions)?;
// Remove the rect from the free list and decide how to guillotine it. let chosen = self.bins[bin.0as usize].rects.swap_remove(index.0); self.bins[bin.0as usize].sizes.swap_remove(index.0); self.split_guillotine(&chosen, &requested_dimensions);
// Return the result.
Some((chosen.slice, chosen.rect.min))
}
/// Add a new slice to the allocator, and immediately allocate a rect from it. pubfn extend(
&mutself,
slice: FreeRectSlice,
total_size: DeviceIntSize,
requested_dimensions: DeviceIntSize,
) { self.split_guillotine(
&FreeRect { slice, rect: total_size.into() },
&requested_dimensions
);
}
}
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.14Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-08-26)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.