mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 08:46:08 +03:00
avoid an alloc and buffer copy in the common case on font loading
This commit is contained in:
@ -93,6 +93,11 @@ pub fn reserve(self: *Atlas, alloc: Allocator, width: u32, height: u32) !Region
|
|||||||
// x, y are populated within :best_idx below
|
// x, y are populated within :best_idx below
|
||||||
var region: Region = .{ .x = 0, .y = 0, .width = width, .height = height };
|
var region: Region = .{ .x = 0, .y = 0, .width = width, .height = height };
|
||||||
|
|
||||||
|
// If our width/height are 0, then we return the region as-is. This
|
||||||
|
// may seem like an error case but it simplifies downstream callers who
|
||||||
|
// might be trying to write empty data.
|
||||||
|
if (width == 0 and height == 0) return region;
|
||||||
|
|
||||||
// Find the location in our nodes list to insert the new node for this region.
|
// Find the location in our nodes list to insert the new node for this region.
|
||||||
var best_idx: usize = best_idx: {
|
var best_idx: usize = best_idx: {
|
||||||
var best_height: u32 = std.math.maxInt(u32);
|
var best_height: u32 = std.math.maxInt(u32);
|
||||||
|
@ -88,6 +88,7 @@ pub fn loadGlyph(self: Face, alloc: Allocator, atlas: *Atlas, cp: u32) !Glyph {
|
|||||||
|
|
||||||
const glyph = self.ft_face.*.glyph;
|
const glyph = self.ft_face.*.glyph;
|
||||||
const bitmap = glyph.*.bitmap;
|
const bitmap = glyph.*.bitmap;
|
||||||
|
assert(bitmap.pixel_mode == ftc.FT_PIXEL_MODE_GRAY);
|
||||||
|
|
||||||
const src_w = bitmap.width;
|
const src_w = bitmap.width;
|
||||||
const src_h = bitmap.rows;
|
const src_h = bitmap.rows;
|
||||||
@ -96,25 +97,33 @@ pub fn loadGlyph(self: Face, alloc: Allocator, atlas: *Atlas, cp: u32) !Glyph {
|
|||||||
|
|
||||||
const region = try atlas.reserve(alloc, tgt_w, tgt_h);
|
const region = try atlas.reserve(alloc, tgt_w, tgt_h);
|
||||||
|
|
||||||
// Build our buffer
|
// If we have data, copy it into the atlas
|
||||||
//
|
if (region.width > 0 and region.height > 0) {
|
||||||
// TODO(perf): we can avoid a buffer copy here in some cases where
|
// We can avoid a buffer copy if our atlas width and bitmap
|
||||||
// tgt_w == bitmap.width and bitmap.width == bitmap.pitch
|
// width match and the bitmap pitch is just the width (meaning
|
||||||
const buffer = try alloc.alloc(u8, tgt_w * tgt_h);
|
// the data is tightly packed).
|
||||||
defer alloc.free(buffer);
|
const needs_copy = !(tgt_w == bitmap.width and bitmap.width == bitmap.pitch);
|
||||||
var dst_ptr = buffer;
|
|
||||||
var src_ptr = bitmap.buffer;
|
|
||||||
var i: usize = 0;
|
|
||||||
while (i < src_h) : (i += 1) {
|
|
||||||
std.mem.copy(u8, dst_ptr, src_ptr[0..bitmap.width]);
|
|
||||||
dst_ptr = dst_ptr[tgt_w..];
|
|
||||||
src_ptr += @intCast(usize, bitmap.pitch);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write the glyph information into the atlas
|
// If we need to copy the data, we copy it into a temporary buffer.
|
||||||
assert(region.width == tgt_w);
|
const buffer = if (needs_copy) buffer: {
|
||||||
assert(region.height == tgt_h);
|
var temp = try alloc.alloc(u8, tgt_w * tgt_h);
|
||||||
atlas.set(region, buffer);
|
var dst_ptr = temp;
|
||||||
|
var src_ptr = bitmap.buffer;
|
||||||
|
var i: usize = 0;
|
||||||
|
while (i < src_h) : (i += 1) {
|
||||||
|
std.mem.copy(u8, dst_ptr, src_ptr[0..bitmap.width]);
|
||||||
|
dst_ptr = dst_ptr[tgt_w..];
|
||||||
|
src_ptr += @intCast(usize, bitmap.pitch);
|
||||||
|
}
|
||||||
|
break :buffer temp;
|
||||||
|
} else bitmap.buffer[0..(tgt_w * tgt_h)];
|
||||||
|
defer if (buffer.ptr != bitmap.buffer) alloc.free(buffer);
|
||||||
|
|
||||||
|
// Write the glyph information into the atlas
|
||||||
|
assert(region.width == tgt_w);
|
||||||
|
assert(region.height == tgt_h);
|
||||||
|
atlas.set(region, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
// Store glyph metadata
|
// Store glyph metadata
|
||||||
return Glyph{
|
return Glyph{
|
||||||
|
Reference in New Issue
Block a user