//! ---------------------------------------------------- //! Shared Handles and Configs across every backend //! ---------------------------------------------------- const gtl = @import("gtl"); const Gfx = @import("../gfx.zig"); const Handle = gtl.Handle; /// ---------------------------------------------------- /// ---------------------------------------------------- pub const Window = union(enum) { win32: struct { hwnd: *anyopaque, hinstance: *anyopaque, }, xcb: struct { connection: *anyopaque, window: u32, }, xlib: struct { display: *anyopaque, window: c_ulong, }, wayland: struct { display: *anyopaque, surface: *anyopaque, }, }; /// ---------------------------------------------------- /// ---------------------------------------------------- pub const GPUType = enum { any, discrete, integrated, software, }; /// ---------------------------------------------------- /// ---------------------------------------------------- pub const AdapterConfig = struct { /// Preferred class of GPU /// `.any` disables filtering by class gpu_type: GPUType = .discrete, /// Select the adapter at a specific enumeration index /// `null` picks the first suitable one index: ?u32 = null, }; /// ---------------------------------------------------- /// ---------------------------------------------------- pub const DeviceConfig = struct { adapter: Handle(Adapter), surface: Handle(Surface), }; /// ---------------------------------------------------- /// ---------------------------------------------------- pub const Format = enum { int, float, vec2, vec3, vec4, }; /// ---------------------------------------------------- /// ---------------------------------------------------- pub const VertexBinding = struct { binding: u32 = 0, stride: u32, input_rate: enum { vertex, instance, } = .vertex, }; /// ---------------------------------------------------- /// ---------------------------------------------------- pub const VertexAttribute = struct { location: u32, binding: u32 = 0, offset: u32, format: Format, }; /// ---------------------------------------------------- /// ---------------------------------------------------- pub const UniformDesc = struct { name: []const u8, size: u32, }; /// ---------------------------------------------------- /// ---------------------------------------------------- pub const CompareOp = enum { never, less, equal, less_equal, greater, not_equal, greater_equal, always, }; /// ---------------------------------------------------- /// ---------------------------------------------------- pub const DepthFormat = enum { d16_unorm, d24_unorm_s8, d32_sfloat, }; /// ---------------------------------------------------- /// ---------------------------------------------------- pub const PipelineConfig = struct { vert_shader: Handle(Shader), frag_shader: Handle(Shader), swapchain: Handle(Swapchain), device: Handle(Device), vertex_binding: ?VertexBinding = null, vertex_attributes: []const VertexAttribute = &.{}, uniforms: []const UniformDesc = &.{}, textures: []const Handle(Texture) = &.{}, topology: enum { triangle_list, line_list, } = .triangle_list, cull_mode: enum { front_and_back, front, back, none, } = .back, front_face: enum { ccw, cw, } = .ccw, blend_mode: enum { none, alpha, } = .none, depth_format: ?DepthFormat = null, depth_test: bool = true, depth_write: bool = true, depth_compare: CompareOp = .less, }; /// ---------------------------------------------------- /// ---------------------------------------------------- pub const Pass = struct { swapchain: Handle(Swapchain), gfx: *Gfx, /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn end(self: *const Pass) void { switch (self.gfx.ctx) { .vulkan => |*v| v.endPass(self.swapchain), } } /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn draw(self: *const Pass, vertex_count: u32, instance_count: u32, first_vertex: u32, first_instance: u32) void { switch (self.gfx.ctx) { .vulkan => |*v| v.draw(vertex_count, instance_count, first_vertex, first_instance), } } /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn drawIndexed(self: *const Pass, index_count: u32, instance_count: u32, first_index: u32, vertex_offset: i32, first_instance: u32) void { switch (self.gfx.ctx) { .vulkan => |*v| v.drawIndexed(index_count, instance_count, first_index, vertex_offset, first_instance), } } }; /// ---------------------------------------------------- /// ---------------------------------------------------- pub const LoadOp = enum { clear, load, dont_care, }; /// ---------------------------------------------------- /// ---------------------------------------------------- pub const StoreOp = enum { store, dont_care, }; /// ---------------------------------------------------- /// ---------------------------------------------------- pub const RenderPassConfig = struct { clear_color: [4]f32 = .{ 0.0, 0.0, 0.0, 1.0 }, depth_enabled: bool = false, depth_format: DepthFormat = .d32_sfloat, depth_load_op: LoadOp = .clear, depth_store_op: StoreOp = .dont_care, clear_depth: f32 = 1.0, clear_stencil: u8 = 0, load_op: LoadOp = .clear, store_op: StoreOp = .store, width: ?u32 = null, height: ?u32 = null, }; /// ---------------------------------------------------- /// ---------------------------------------------------- pub const BufferUsage = enum { vertex, index, image, }; /// ---------------------------------------------------- /// ---------------------------------------------------- pub const BufferSharingMode = enum { exclusive, }; /// ---------------------------------------------------- /// ---------------------------------------------------- /// ---------------------------------------------------- /// ---------------------------------------------------- pub const PixelFormat = enum { rgba8_unorm, rgba8_srgb, bgra8_unorm, bgra8_srgb, }; /// ---------------------------------------------------- /// ---------------------------------------------------- pub const Filter = enum { nearest, linear, }; /// ---------------------------------------------------- /// ---------------------------------------------------- pub const MipmapMode = enum { nearest, linear, }; /// ---------------------------------------------------- /// ---------------------------------------------------- pub const AddressMode = enum { repeat, mirrored_repeat, clamp_to_edge, clamp_to_border, }; /// ---------------------------------------------------- /// ---------------------------------------------------- pub const ImageUsage = enum { texture, render_target, depth, }; /// ---------------------------------------------------- /// ---------------------------------------------------- pub const ImageConfig = struct { /// Read a file from disk with `stb_image` path: ?[]const u8 = null, /// Raw pixel bytes (overrides `path`) data: ?[]const u8 = null, /// Required for `.data`. `null` = use source dimensions size: ?[2]u32 = null, vertical_flip: bool = false, format: PixelFormat = .rgba8_srgb, usage: ImageUsage = .texture, mip_levels: u32 = 1, }; /// ---------------------------------------------------- /// ---------------------------------------------------- pub const SamplerConfig = struct { min_filter: Filter = .linear, mag_filter: Filter = .linear, mipmap_mode: MipmapMode = .linear, address_u: AddressMode = .repeat, address_v: AddressMode = .repeat, address_w: AddressMode = .repeat, max_anisotropy: f32 = 1.0, max_lod: f32 = 0, }; /// ---------------------------------------------------- /// ---------------------------------------------------- pub const TextureConfig = struct { image: ImageConfig = .{}, sampler: SamplerConfig = .{}, }; // // HANDLE TYPES // pub const Adapter = struct {}; pub const Device = struct {}; pub const Surface = struct {}; pub const Swapchain = struct {}; pub const Buffer = struct { handle: Handle(Buffer), device: Handle(Device), gfx: *Gfx, pub fn set(self: *const Buffer, value: anytype) !void { switch (self.gfx.ctx) { .vulkan => |*v| { const raw = v.resource.buffers.get(self.handle) orelse return error.BufferNotFound; try raw.set(value, @sizeOf(@TypeOf(value))); }, } } pub fn bind(self: *const Buffer) !void { switch (self.gfx.ctx) { .vulkan => |*v| try v.bindBuffer(self.handle), } } }; pub const Image = struct {}; pub const ImageView = struct {}; pub const Sampler = struct {}; pub const Texture = struct {}; pub const Shader = struct {}; pub const PipelineLayout = struct {}; pub const Pipeline = struct { handle: Handle(Pipeline), device: Handle(Device), gfx: *Gfx, pub fn bind(self: *const Pipeline) !void { try switch (self.gfx.ctx) { .vulkan => |*v| v.bindPipeline(self.handle), }; } pub fn setUniform(self: *const Pipeline, name: []const u8, value: anytype) !void { try switch (self.gfx.ctx) { .vulkan => |*v| v.setUniform(self.handle, name, value), }; } };