diff --git a/src/IndexBuffer.zig b/src/IndexBuffer.zig new file mode 100644 index 0000000..216ca16 --- /dev/null +++ b/src/IndexBuffer.zig @@ -0,0 +1,49 @@ +const zgpu = @import("zgpu"); + +const main = @import("main.zig"); + +index_buffer_handle: zgpu.BufferHandle, + +pub fn init(index_count: usize) @This() { + // NOTE For some reason, the method function call syntax doesn't compile + const index_buffer_handle = zgpu.GraphicsContext.createBuffer(main.gctx, .{ + .usage = .{ .copy_dst = true, .index = true }, + .size = index_count * @sizeOf(u16), + }); + + return .{ + .index_buffer_handle = index_buffer_handle, + }; +} + +pub fn deinit(self: *@This()) void { + main.gctx.releaseResource(self.index_buffer_handle); + self.* = undefined; +} + +pub fn indexCount(self: @This()) usize { + return @divExact(self.info().size, @sizeOf(u16)); +} + +pub fn write(self: @This(), offset: usize, data: []const u16) void { + main.gctx.queue.writeBuffer(self.obj(), offset, u16, data); +} + +pub fn ensureCapacityDiscard(self: *@This(), desired_index_count: usize) void { + if (self.indexCount() < desired_index_count) { + main.gctx.releaseResource(self.index_buffer_handle); + // NOTE For some reason, the method function call syntax doesn't compile + self.index_buffer_handle = zgpu.GraphicsContext.createBuffer(main.gctx, .{ + .usage = .{ .copy_dst = true, .index = true }, + .size = desired_index_count * @sizeOf(u16), + }); + } +} + +pub fn info(self: @This()) zgpu.BufferInfo { + return main.gctx.lookupResourceInfo(self.index_buffer_handle).?; +} + +pub fn obj(self: @This()) zgpu.wgpu.Buffer { + return main.gctx.lookupResource(self.index_buffer_handle).?; +} diff --git a/src/Samplers.zig b/src/Samplers.zig new file mode 100644 index 0000000..18ee15a --- /dev/null +++ b/src/Samplers.zig @@ -0,0 +1,47 @@ +const std = @import("std"); + +const zgpu = @import("zgpu"); + +const main = @import("main.zig"); + +pub var sampler_cache: std.AutoHashMapUnmanaged(Descriptor, zgpu.SamplerHandle) = .{}; + +pub const Descriptor = struct { + address_mode_u: zgpu.wgpu.AddressMode = .repeat, + address_mode_v: zgpu.wgpu.AddressMode = .repeat, + address_mode_w: zgpu.wgpu.AddressMode = .repeat, + mag_filter: zgpu.wgpu.FilterMode = .linear, + min_filter: zgpu.wgpu.FilterMode = .linear, + mipmap_filter: zgpu.wgpu.MipmapFilterMode = .linear, +}; + +pub fn getOrCreateSampler(descriptor: Descriptor) !zgpu.SamplerHandle { + const entry = try sampler_cache.getOrPut(main.allocator, descriptor); + + if (entry.found_existing) { + return entry.value_ptr.*; + } else { + const sampler_handle = main.gctx.createSampler(.{ + .address_mode_u = descriptor.address_mode_u, + .address_mode_v = descriptor.address_mode_v, + .address_mode_w = descriptor.address_mode_w, + .mag_filter = descriptor.mag_filter, + .min_filter = descriptor.min_filter, + .mipmap_filter = descriptor.mipmap_filter, + }); + + entry.key_ptr.* = descriptor; + entry.value_ptr.* = sampler_handle; + + return sampler_handle; + } +} + +pub fn deinit() void { + var sampler_cache_it = sampler_cache.valueIterator(); + while (sampler_cache_it.next()) |sampler_handle| { + main.gctx.releaseResource(sampler_handle.*); + } + + sampler_cache.deinit(main.allocator); +} diff --git a/src/Texture.zig b/src/Texture.zig new file mode 100644 index 0000000..cc4df3f --- /dev/null +++ b/src/Texture.zig @@ -0,0 +1,82 @@ +const zgpu = @import("zgpu"); + +const main = @import("main.zig"); + +texture_handle: zgpu.TextureHandle, +texture_view_handle: zgpu.TextureViewHandle, + +pub fn init2DSingleChannel(width: u32, height: u32) @This() { + const texture_handle = main.gctx.createTexture(.{ + .usage = .{ .texture_binding = true, .copy_dst = true }, + .size = .{ .width = width, .height = height }, + .format = .r8_unorm, + }); + + const texture_view_handle = main.gctx.createTextureView(texture_handle, .{ + .format = .r8_unorm, + .dimension = .tvdim_2d, + }); + + return .{ + .texture_handle = texture_handle, + .texture_view_handle = texture_view_handle, + }; +} + +pub fn init2D(width: u32, height: u32) @This() { + const texture_handle = main.gctx.createTexture(.{ + .usage = .{ .texture_binding = true, .copy_dst = true }, + .size = .{ .width = width, .height = height }, + .format = .rgba8_unorm, + }); + + const texture_view_handle = main.gctx.createTextureView(texture_handle, .{ + .format = .rgba8_unorm, + .dimension = .tvdim_2d, + }); + + return .{ + .texture_handle = texture_handle, + .texture_view_handle = texture_view_handle, + }; +} + +pub fn init2DArray(width: u32, height: u32, layers: u32) @This() { + const texture_handle = main.gctx.createTexture(.{ + .usage = .{ .texture_binding = true, .copy_dst = true }, + .size = .{ .width = width, .height = height, .depth_or_array_layers = layers }, + .format = .rgba8_unorm, + }); + + const texture_view_handle = main.gctx.createTextureView(texture_handle, .{ + .format = .rgba8_unorm, + .dimension = .tvdim_2d_array, + }); + + return .{ + .texture_handle = texture_handle, + .texture_view_handle = texture_view_handle, + }; +} + +pub fn deinit(self: *@This()) void { + main.gctx.releaseResource(self.texture_view_handle); + main.gctx.releaseResource(self.texture_handle); + self.* = undefined; +} + +pub fn texInfo(self: @This()) zgpu.TextureInfo { + return main.gctx.lookupResourceInfo(self.texture_handle).?; +} + +pub fn texObj(self: @This()) zgpu.wgpu.Texture { + return main.gctx.lookupResource(self.texture_handle).?; +} + +pub fn tvInfo(self: @This()) zgpu.TextureViewInfo { + return main.gctx.lookupResourceInfo(self.texture_view_handle).?; +} + +pub fn tvObj(self: @This()) zgpu.wgpu.TextureView { + return main.gctx.lookupResource(self.texture_view_handle).?; +} diff --git a/src/VertexBuffer.zig b/src/VertexBuffer.zig new file mode 100644 index 0000000..b16accf --- /dev/null +++ b/src/VertexBuffer.zig @@ -0,0 +1,53 @@ +const zgpu = @import("zgpu"); + +const main = @import("main.zig"); + +pub fn VertexBuffer(comptime T: type) type { + return struct { + vertex_buffer_handle: zgpu.BufferHandle, + + pub fn init(vertex_count: usize) @This() { + // NOTE For some reason, the method function call syntax doesn't compile + const vertex_buffer_handle = zgpu.GraphicsContext.createBuffer(main.gctx, .{ + .usage = .{ .copy_dst = true, .vertex = true }, + .size = vertex_count * @sizeOf(T), + }); + + return .{ + .vertex_buffer_handle = vertex_buffer_handle, + }; + } + + pub fn deinit(self: *@This()) void { + main.gctx.releaseResource(self.vertex_buffer_handle); + self.* = undefined; + } + + pub fn vertexCount(self: @This()) usize { + return @divExact(self.info().size, @sizeOf(T)); + } + + pub fn write(self: @This(), offset: usize, data: []const T) void { + main.gctx.queue.writeBuffer(self.obj(), offset, T, data); + } + + pub fn ensureCapacityDiscard(self: *@This(), desired_vertex_count: usize) void { + if (self.vertexCount() < desired_vertex_count) { + main.gctx.releaseResource(self.vertex_buffer_handle); + // NOTE For some reason, the method function call syntax doesn't compile + self.vertex_buffer_handle = zgpu.GraphicsContext.createBuffer(main.gctx, .{ + .usage = .{ .copy_dst = true, .vertex = true }, + .size = desired_vertex_count * @sizeOf(T), + }); + } + } + + pub fn info(self: @This()) zgpu.BufferInfo { + return main.gctx.lookupResourceInfo(self.vertex_buffer_handle).?; + } + + pub fn obj(self: @This()) zgpu.wgpu.Buffer { + return main.gctx.lookupResource(self.vertex_buffer_handle).?; + } + }; +}