mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-05-05 05:14:40 +00:00
kitty graphics: address review comments
- move wuffs code from src/ to pkg/ - eliminate stray debug logs - make logs a warning instead of an error - remove initialization of some structs to zero
This commit is contained in:
committed by
Mitchell Hashimoto
parent
e6c3ba2cf9
commit
6edeb45e7e
30
pkg/wuffs/build.zig
Normal file
30
pkg/wuffs/build.zig
Normal file
@@ -0,0 +1,30 @@
|
||||
const std = @import("std");
|
||||
|
||||
pub fn build(b: *std.Build) void {
|
||||
const target = b.standardTargetOptions(.{});
|
||||
const optimize = b.standardOptimizeOption(.{});
|
||||
|
||||
const wuffs = b.dependency("wuffs", .{});
|
||||
|
||||
const module = b.addModule("wuffs", .{
|
||||
.root_source_file = b.path("src/main.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.link_libc = true,
|
||||
});
|
||||
|
||||
module.addIncludePath(wuffs.path("release/c"));
|
||||
module.addCSourceFile(
|
||||
.{
|
||||
.file = wuffs.path("release/c/wuffs-v0.4.c"),
|
||||
.flags = f: {
|
||||
const flags = @import("src/defs.zig").build;
|
||||
var a: [flags.len][]const u8 = undefined;
|
||||
inline for (flags, 0..) |flag, i| {
|
||||
a[i] = "-D" ++ flag ++ "=1";
|
||||
}
|
||||
break :f &a;
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
17
pkg/wuffs/build.zig.zon
Normal file
17
pkg/wuffs/build.zig.zon
Normal file
@@ -0,0 +1,17 @@
|
||||
.{
|
||||
.name = "wuffs",
|
||||
|
||||
.version = "0.0.0",
|
||||
.dependencies = .{
|
||||
.wuffs = .{
|
||||
.url = "https://github.com/google/wuffs/archive/refs/tags/v0.4.0-alpha.8.tar.gz",
|
||||
.hash = "12200984439edc817fbcbbaff564020e5104a0d04a2d0f53080700827052de700462",
|
||||
},
|
||||
},
|
||||
|
||||
.paths = .{
|
||||
"build.zig",
|
||||
"build.zig.zon",
|
||||
"src",
|
||||
},
|
||||
}
|
||||
6
pkg/wuffs/src/c.zig
Normal file
6
pkg/wuffs/src/c.zig
Normal file
@@ -0,0 +1,6 @@
|
||||
pub const c = @cImport({
|
||||
for (@import("defs.zig").cimport) |d| {
|
||||
@cDefine(d, "1");
|
||||
}
|
||||
@cInclude("wuffs-v0.4.c");
|
||||
});
|
||||
21
pkg/wuffs/src/defs.zig
Normal file
21
pkg/wuffs/src/defs.zig
Normal file
@@ -0,0 +1,21 @@
|
||||
//! Define all of the C macros that WUFFS uses to configure itself here so
|
||||
//! that the settings used to import the C "header" file stay in sync with the
|
||||
//! settings used build the C "source" file.
|
||||
|
||||
pub const cimport = [_][]const u8{
|
||||
"WUFFS_CONFIG__MODULES",
|
||||
"WUFFS_CONFIG__MODULE__AUX__BASE",
|
||||
"WUFFS_CONFIG__MODULE__AUX__IMAGE",
|
||||
"WUFFS_CONFIG__MODULE__BASE",
|
||||
"WUFFS_CONFIG__MODULE__ADLER32",
|
||||
"WUFFS_CONFIG__MODULE__CRC32",
|
||||
"WUFFS_CONFIG__MODULE__DEFLATE",
|
||||
"WUFFS_CONFIG__MODULE__JPEG",
|
||||
"WUFFS_CONFIG__MODULE__PNG",
|
||||
"WUFFS_CONFIG__MODULE__ZLIB",
|
||||
};
|
||||
|
||||
// The only difference should be that the "build" defines WUFFS_IMPLEMENTATION
|
||||
pub const build = [_][]const u8{
|
||||
"WUFFS_IMPLEMENTATION",
|
||||
} ++ cimport;
|
||||
3
pkg/wuffs/src/error.zig
Normal file
3
pkg/wuffs/src/error.zig
Normal file
@@ -0,0 +1,3 @@
|
||||
const std = @import("std");
|
||||
|
||||
pub const Error = std.mem.Allocator.Error || error{WuffsError};
|
||||
2
pkg/wuffs/src/main.zig
Normal file
2
pkg/wuffs/src/main.zig
Normal file
@@ -0,0 +1,2 @@
|
||||
pub const png = @import("png.zig");
|
||||
pub const swizzle = @import("swizzle.zig");
|
||||
138
pkg/wuffs/src/png.zig
Normal file
138
pkg/wuffs/src/png.zig
Normal file
@@ -0,0 +1,138 @@
|
||||
const std = @import("std");
|
||||
|
||||
const c = @import("c.zig").c;
|
||||
const Error = @import("error.zig").Error;
|
||||
|
||||
const log = std.log.scoped(.wuffs_png);
|
||||
|
||||
pub fn decode(alloc: std.mem.Allocator, data: []const u8) Error!struct {
|
||||
width: u32,
|
||||
height: u32,
|
||||
data: []const u8,
|
||||
} {
|
||||
// Work around some weirdness in WUFFS/Zig, there are some structs that
|
||||
// are defined as "extern" by the Zig compiler which means that Zig won't
|
||||
// allocate them on the stack at compile time. WUFFS has functions for
|
||||
// dynamically allocating these structs but they use the C malloc/free. This
|
||||
// gets around that by using the Zig allocator to allocate enough memory for
|
||||
// the struct and then casts it to the appropriate pointer.
|
||||
|
||||
const decoder_buf = try alloc.alloc(u8, c.sizeof__wuffs_png__decoder());
|
||||
defer alloc.free(decoder_buf);
|
||||
|
||||
const decoder: ?*c.wuffs_png__decoder = @constCast(@ptrCast(decoder_buf));
|
||||
{
|
||||
const status = c.wuffs_png__decoder__initialize(
|
||||
decoder,
|
||||
c.sizeof__wuffs_png__decoder(),
|
||||
c.WUFFS_VERSION,
|
||||
0,
|
||||
);
|
||||
if (!c.wuffs_base__status__is_ok(&status)) {
|
||||
const e = c.wuffs_base__status__message(&status);
|
||||
log.warn("{s}", .{e});
|
||||
return error.WuffsError;
|
||||
}
|
||||
}
|
||||
|
||||
var source_buffer: c.wuffs_base__io_buffer = undefined;
|
||||
source_buffer.data.ptr = @constCast(@ptrCast(data.ptr));
|
||||
source_buffer.data.len = data.len;
|
||||
source_buffer.meta.wi = data.len;
|
||||
source_buffer.meta.ri = 0;
|
||||
source_buffer.meta.pos = 0;
|
||||
source_buffer.meta.closed = true;
|
||||
|
||||
var image_config: c.wuffs_base__image_config = undefined;
|
||||
{
|
||||
const status = c.wuffs_png__decoder__decode_image_config(
|
||||
decoder,
|
||||
&image_config,
|
||||
&source_buffer,
|
||||
);
|
||||
if (!c.wuffs_base__status__is_ok(&status)) {
|
||||
const e = c.wuffs_base__status__message(&status);
|
||||
log.warn("{s}", .{e});
|
||||
return error.WuffsError;
|
||||
}
|
||||
}
|
||||
|
||||
const width = c.wuffs_base__pixel_config__width(&image_config.pixcfg);
|
||||
const height = c.wuffs_base__pixel_config__height(&image_config.pixcfg);
|
||||
|
||||
c.wuffs_base__pixel_config__set(
|
||||
&image_config.pixcfg,
|
||||
c.WUFFS_BASE__PIXEL_FORMAT__RGBA_PREMUL,
|
||||
c.WUFFS_BASE__PIXEL_SUBSAMPLING__NONE,
|
||||
width,
|
||||
height,
|
||||
);
|
||||
|
||||
const destination = try alloc.alloc(
|
||||
u8,
|
||||
width * height * @sizeOf(c.wuffs_base__color_u32_argb_premul),
|
||||
);
|
||||
errdefer alloc.free(destination);
|
||||
|
||||
// temporary buffer for intermediate processing of image
|
||||
const work_buffer = try alloc.alloc(
|
||||
u8,
|
||||
c.wuffs_png__decoder__workbuf_len(decoder).max_incl,
|
||||
);
|
||||
defer alloc.free(work_buffer);
|
||||
|
||||
const work_slice = c.wuffs_base__make_slice_u8(
|
||||
work_buffer.ptr,
|
||||
work_buffer.len,
|
||||
);
|
||||
|
||||
var pixel_buffer: c.wuffs_base__pixel_buffer = undefined;
|
||||
{
|
||||
const status = c.wuffs_base__pixel_buffer__set_from_slice(
|
||||
&pixel_buffer,
|
||||
&image_config.pixcfg,
|
||||
c.wuffs_base__make_slice_u8(destination.ptr, destination.len),
|
||||
);
|
||||
if (!c.wuffs_base__status__is_ok(&status)) {
|
||||
const e = c.wuffs_base__status__message(&status);
|
||||
log.warn("{s}", .{e});
|
||||
return error.WuffsError;
|
||||
}
|
||||
}
|
||||
|
||||
var frame_config: c.wuffs_base__frame_config = undefined;
|
||||
{
|
||||
const status = c.wuffs_png__decoder__decode_frame_config(
|
||||
decoder,
|
||||
&frame_config,
|
||||
&source_buffer,
|
||||
);
|
||||
if (!c.wuffs_base__status__is_ok(&status)) {
|
||||
const e = c.wuffs_base__status__message(&status);
|
||||
log.warn("{s}", .{e});
|
||||
return error.WuffsError;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const status = c.wuffs_png__decoder__decode_frame(
|
||||
decoder,
|
||||
&pixel_buffer,
|
||||
&source_buffer,
|
||||
c.WUFFS_BASE__PIXEL_BLEND__SRC_OVER,
|
||||
work_slice,
|
||||
null,
|
||||
);
|
||||
if (!c.wuffs_base__status__is_ok(&status)) {
|
||||
const e = c.wuffs_base__status__message(&status);
|
||||
log.warn("{s}", .{e});
|
||||
return error.WuffsError;
|
||||
}
|
||||
}
|
||||
|
||||
return .{
|
||||
.width = width,
|
||||
.height = height,
|
||||
.data = destination,
|
||||
};
|
||||
}
|
||||
103
pkg/wuffs/src/swizzle.zig
Normal file
103
pkg/wuffs/src/swizzle.zig
Normal file
@@ -0,0 +1,103 @@
|
||||
const std = @import("std");
|
||||
|
||||
const c = @import("c.zig").c;
|
||||
const Error = @import("error.zig").Error;
|
||||
|
||||
const log = std.log.scoped(.wuffs_swizzler);
|
||||
|
||||
pub fn gToRgba(alloc: std.mem.Allocator, src: []const u8) Error![]u8 {
|
||||
return swizzle(
|
||||
alloc,
|
||||
src,
|
||||
c.WUFFS_BASE__PIXEL_FORMAT__Y,
|
||||
c.WUFFS_BASE__PIXEL_FORMAT__RGBA_PREMUL,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn gaToRgba(alloc: std.mem.Allocator, src: []const u8) Error![]u8 {
|
||||
return swizzle(
|
||||
alloc,
|
||||
src,
|
||||
c.WUFFS_BASE__PIXEL_FORMAT__YA_PREMUL,
|
||||
c.WUFFS_BASE__PIXEL_FORMAT__RGBA_PREMUL,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn rgbToRgba(alloc: std.mem.Allocator, src: []const u8) Error![]u8 {
|
||||
return swizzle(
|
||||
alloc,
|
||||
src,
|
||||
c.WUFFS_BASE__PIXEL_FORMAT__RGB,
|
||||
c.WUFFS_BASE__PIXEL_FORMAT__RGBA_PREMUL,
|
||||
);
|
||||
}
|
||||
|
||||
fn swizzle(
|
||||
alloc: std.mem.Allocator,
|
||||
src: []const u8,
|
||||
comptime src_pixel_format: u32,
|
||||
comptime dst_pixel_format: u32,
|
||||
) Error![]u8 {
|
||||
const src_slice = c.wuffs_base__make_slice_u8(
|
||||
@constCast(src.ptr),
|
||||
src.len,
|
||||
);
|
||||
|
||||
const dst_fmt = c.wuffs_base__make_pixel_format(
|
||||
dst_pixel_format,
|
||||
);
|
||||
|
||||
std.debug.assert(c.wuffs_base__pixel_format__is_direct(&dst_fmt));
|
||||
std.debug.assert(c.wuffs_base__pixel_format__is_interleaved(&dst_fmt));
|
||||
std.debug.assert(c.wuffs_base__pixel_format__bits_per_pixel(&dst_fmt) % 8 == 0);
|
||||
|
||||
const dst_size = c.wuffs_base__pixel_format__bits_per_pixel(&dst_fmt) / 8;
|
||||
|
||||
const src_fmt = c.wuffs_base__make_pixel_format(
|
||||
src_pixel_format,
|
||||
);
|
||||
|
||||
std.debug.assert(c.wuffs_base__pixel_format__is_direct(&src_fmt));
|
||||
std.debug.assert(c.wuffs_base__pixel_format__is_interleaved(&src_fmt));
|
||||
std.debug.assert(c.wuffs_base__pixel_format__bits_per_pixel(&src_fmt) % 8 == 0);
|
||||
|
||||
const src_size = c.wuffs_base__pixel_format__bits_per_pixel(&src_fmt) / 8;
|
||||
|
||||
std.debug.assert(src.len % src_size == 0);
|
||||
|
||||
const dst = try alloc.alloc(u8, src.len * dst_size / src_size);
|
||||
errdefer alloc.free(dst);
|
||||
|
||||
const dst_slice = c.wuffs_base__make_slice_u8(
|
||||
dst.ptr,
|
||||
dst.len,
|
||||
);
|
||||
|
||||
var swizzler: c.wuffs_base__pixel_swizzler = undefined;
|
||||
|
||||
{
|
||||
const status = c.wuffs_base__pixel_swizzler__prepare(
|
||||
&swizzler,
|
||||
dst_fmt,
|
||||
c.wuffs_base__empty_slice_u8(),
|
||||
src_fmt,
|
||||
c.wuffs_base__empty_slice_u8(),
|
||||
c.WUFFS_BASE__PIXEL_BLEND__SRC_OVER,
|
||||
);
|
||||
if (!c.wuffs_base__status__is_ok(&status)) {
|
||||
const e = c.wuffs_base__status__message(&status);
|
||||
log.warn("{s}", .{e});
|
||||
return error.WuffsError;
|
||||
}
|
||||
}
|
||||
{
|
||||
_ = c.wuffs_base__pixel_swizzler__swizzle_interleaved_from_slice(
|
||||
&swizzler,
|
||||
dst_slice,
|
||||
c.wuffs_base__empty_slice_u8(),
|
||||
src_slice,
|
||||
);
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
Reference in New Issue
Block a user