renderer/metal: use wuffs for format conversion

This commit is contained in:
Mitchell Hashimoto
2024-09-02 20:43:55 -07:00
parent de612934a0
commit 8ffa7328a9

View File

@ -2,6 +2,7 @@ const std = @import("std");
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const assert = std.debug.assert; const assert = std.debug.assert;
const objc = @import("objc"); const objc = @import("objc");
const wuffs = @import("wuffs");
const mtl = @import("api.zig"); const mtl = @import("api.zig");
@ -301,9 +302,8 @@ pub const Image = union(enum) {
// RGB needs to be converted to RGBA because Metal textures // RGB needs to be converted to RGBA because Metal textures
// don't support RGB. // don't support RGB.
.pending_rgb => |*p| { .pending_rgb => |*p| {
// Note: this is the slowest possible way to do this...
const data = p.dataSlice(3); const data = p.dataSlice(3);
const rgba = try rgbToRgba(alloc, data); const rgba = try wuffs.swizzle.rgbToRgba(alloc, data);
alloc.free(data); alloc.free(data);
p.data = rgba.ptr; p.data = rgba.ptr;
self.* = .{ .pending_rgba = p.* }; self.* = .{ .pending_rgba = p.* };
@ -311,7 +311,7 @@ pub const Image = union(enum) {
.replace_rgb => |*r| { .replace_rgb => |*r| {
const data = r.pending.dataSlice(3); const data = r.pending.dataSlice(3);
const rgba = try rgbToRgba(alloc, data); const rgba = try wuffs.swizzle.rgbToRgba(alloc, data);
alloc.free(data); alloc.free(data);
r.pending.data = rgba.ptr; r.pending.data = rgba.ptr;
self.* = .{ .replace_rgba = r.* }; self.* = .{ .replace_rgba = r.* };
@ -320,7 +320,7 @@ pub const Image = union(enum) {
// Gray and Gray+Alpha need to be converted to RGBA, too. // Gray and Gray+Alpha need to be converted to RGBA, too.
.pending_gray => |*p| { .pending_gray => |*p| {
const data = p.dataSlice(1); const data = p.dataSlice(1);
const rgba = try grayToRgba(alloc, data); const rgba = try wuffs.swizzle.gToRgba(alloc, data);
alloc.free(data); alloc.free(data);
p.data = rgba.ptr; p.data = rgba.ptr;
self.* = .{ .pending_rgba = p.* }; self.* = .{ .pending_rgba = p.* };
@ -328,7 +328,7 @@ pub const Image = union(enum) {
.replace_gray => |*r| { .replace_gray => |*r| {
const data = r.pending.dataSlice(2); const data = r.pending.dataSlice(2);
const rgba = try grayToRgba(alloc, data); const rgba = try wuffs.swizzle.gToRgba(alloc, data);
alloc.free(data); alloc.free(data);
r.pending.data = rgba.ptr; r.pending.data = rgba.ptr;
self.* = .{ .replace_rgba = r.* }; self.* = .{ .replace_rgba = r.* };
@ -336,7 +336,7 @@ pub const Image = union(enum) {
.pending_gray_alpha => |*p| { .pending_gray_alpha => |*p| {
const data = p.dataSlice(2); const data = p.dataSlice(2);
const rgba = try gaToRgba(alloc, data); const rgba = try wuffs.swizzle.gaToRgba(alloc, data);
alloc.free(data); alloc.free(data);
p.data = rgba.ptr; p.data = rgba.ptr;
self.* = .{ .pending_rgba = p.* }; self.* = .{ .pending_rgba = p.* };
@ -344,7 +344,7 @@ pub const Image = union(enum) {
.replace_gray_alpha => |*r| { .replace_gray_alpha => |*r| {
const data = r.pending.dataSlice(2); const data = r.pending.dataSlice(2);
const rgba = try gaToRgba(alloc, data); const rgba = try wuffs.swizzle.gaToRgba(alloc, data);
alloc.free(data); alloc.free(data);
r.pending.data = rgba.ptr; r.pending.data = rgba.ptr;
self.* = .{ .replace_rgba = r.* }; self.* = .{ .replace_rgba = r.* };
@ -352,56 +352,6 @@ pub const Image = union(enum) {
} }
} }
fn grayToRgba(alloc: Allocator, data: []const u8) ![]u8 {
const pixels = data.len;
var rgba = try alloc.alloc(u8, pixels * 4);
errdefer alloc.free(rgba);
var i: usize = 0;
while (i < pixels) : (i += 1) {
const rgba_i = i * 4;
rgba[rgba_i] = data[i];
rgba[rgba_i + 1] = data[i];
rgba[rgba_i + 2] = data[i];
rgba[rgba_i + 3] = 255;
}
return rgba;
}
fn gaToRgba(alloc: Allocator, data: []const u8) ![]u8 {
const pixels = data.len / 2;
var rgba = try alloc.alloc(u8, pixels * 4);
errdefer alloc.free(rgba);
var i: usize = 0;
while (i < pixels) : (i += 1) {
const data_i = i * 2;
const rgba_i = i * 4;
rgba[rgba_i] = data[data_i];
rgba[rgba_i + 1] = data[data_i];
rgba[rgba_i + 2] = data[data_i];
rgba[rgba_i + 3] = data[data_i + 1];
}
return rgba;
}
fn rgbToRgba(alloc: Allocator, data: []const u8) ![]u8 {
const pixels = data.len / 3;
var rgba = try alloc.alloc(u8, pixels * 4);
errdefer alloc.free(rgba);
var i: usize = 0;
while (i < pixels) : (i += 1) {
const data_i = i * 3;
const rgba_i = i * 4;
rgba[rgba_i] = data[data_i];
rgba[rgba_i + 1] = data[data_i + 1];
rgba[rgba_i + 2] = data[data_i + 2];
rgba[rgba_i + 3] = 255;
}
return rgba;
}
/// Upload the pending image to the GPU and change the state of this /// Upload the pending image to the GPU and change the state of this
/// image to ready. /// image to ready.
pub fn upload( pub fn upload(