Iterative texture loading

This commit is contained in:
duck
2025-08-31 04:12:10 +05:00
parent 3f1c0aa2f8
commit 6f933449a1
3 changed files with 117 additions and 80 deletions

View File

@@ -11,17 +11,88 @@ sampler: *sdl.GPUSampler,
pub fn load(path: []const u8, alloc: std.mem.Allocator) Assets.LoadError!@This() {
_ = alloc;
var file = Assets.load(.file, path);
defer Assets.free(file);
const data = (try file.getSync()).bytes;
const data = (file.getSync() catch return error.DependencyError).bytes;
var width: u32 = undefined;
var height: u32 = undefined;
var channels: u32 = undefined;
const image = c.stbi_load_from_memory(
@ptrCast(data),
@intCast(data.len),
@ptrCast(&width),
@ptrCast(&height),
@ptrCast(&channels),
4,
);
Assets.free(file);
if (image == null) return error.ParsingError;
defer c.stbi_image_free(image);
const image_slice = image[0..@intCast(width * height * channels)];
if (width > 8192 or height > 8192) return error.FileTooBig;
const target_format = sdl.GPU_TEXTUREFORMAT_R8G8B8A8_UNORM;
const bytes_per_pixel = 4;
const texture = Graphics.createTexture(
width,
height,
target_format,
sdl.GPU_TEXTUREUSAGE_SAMPLER | sdl.GPU_TEXTUREUSAGE_COLOR_TARGET,
Graphics.MIP_LEVEL,
);
errdefer Graphics.freeTexture(texture);
const transfer_buffer_capacity = Graphics.TRANSFER_BUFFER_DEFAULT_CAPACITY;
const transfer_buffer = sdl.CreateGPUTransferBuffer(Graphics.device, &.{
.size = transfer_buffer_capacity,
.usage = sdl.GPU_TRANSFERBUFFERUSAGE_UPLOAD,
}) orelse return error.SdlError;
defer sdl.ReleaseGPUTransferBuffer(Graphics.device, transfer_buffer);
var rows_uploaded: u32 = 0;
while (rows_uploaded < height) {
const rows_to_upload = @min(height - rows_uploaded, transfer_buffer_capacity / width / bytes_per_pixel);
if (rows_to_upload == 0) return error.FileTooBig;
const command_buffer = sdl.AcquireGPUCommandBuffer(Graphics.device) orelse return error.SdlError;
{
errdefer _ = sdl.CancelGPUCommandBuffer(command_buffer);
const copy_pass = sdl.BeginGPUCopyPass(command_buffer) orelse return error.SdlError;
defer sdl.EndGPUCopyPass(copy_pass);
const map: [*]u8 = @ptrCast(sdl.MapGPUTransferBuffer(Graphics.device, transfer_buffer, false) orelse err.sdl());
@memcpy(map, image_slice[(rows_uploaded * width * bytes_per_pixel)..((rows_uploaded + rows_to_upload) * width * bytes_per_pixel)]);
sdl.UnmapGPUTransferBuffer(Graphics.device, transfer_buffer);
sdl.UploadToGPUTexture(copy_pass, &sdl.GPUTextureTransferInfo{
.offset = 0,
.pixels_per_row = width,
.rows_per_layer = rows_to_upload,
.transfer_buffer = transfer_buffer,
}, &sdl.GPUTextureRegion{
.texture = texture,
.mip_level = 0,
.layer = 0,
.x = 0,
.y = rows_uploaded,
.z = 0,
.w = width,
.h = rows_to_upload,
.d = 1,
}, false);
}
rows_uploaded += rows_to_upload;
if (rows_to_upload == height) {
sdl.GenerateMipmapsForGPUTexture(command_buffer, texture);
}
const fence = sdl.SubmitGPUCommandBufferAndAcquireFence(command_buffer) orelse return error.SdlError;
defer sdl.ReleaseGPUFence(Graphics.device, fence);
if (!sdl.WaitForGPUFences(Graphics.device, true, &fence, 1)) return error.SdlError;
}
const sampler = Graphics.createSampler();
var x: i32 = undefined;
var y: i32 = undefined;
var z: i32 = undefined;
const image = c.stbi_load_from_memory(@ptrCast(data), @intCast(data.len), &x, &y, &z, 4);
if (image == null) err.stbi();
const image_slice = image[0..@intCast(x * y * z)];
const texture, const sampler = Graphics.loadTexture(@intCast(x), @intCast(y), image_slice);
c.stbi_image_free(image);
return .{
.texture = texture,
.sampler = sampler,
@@ -30,5 +101,6 @@ pub fn load(path: []const u8, alloc: std.mem.Allocator) Assets.LoadError!@This()
pub fn unload(self: @This(), alloc: std.mem.Allocator) void {
_ = alloc;
Graphics.unloadTexture(self.texture, self.sampler);
Graphics.freeTexture(self.texture);
Graphics.freeSampler(self.sampler);
}