//! ---------------------------------------------------- //! Shared Handles and Configs across every backend //! ---------------------------------------------------- const vk = @import("vulkan"); const gtl = @import("gtl"); const Gfx = @import("../gfx.zig"); const Handle = gtl.Handle; pub const Backend = enum { vulkan }; pub const VKAPIVersion = enum { v1_0, v1_1, v1_2, v1_3, v1_4, }; pub const VK11Features = struct { shader_draw_parameters: bool = true, }; pub const VK13Features = struct { dynamic_rendering: bool = true, synchronization2: bool = true, }; pub const VK14Features = struct { dynamic_rendering_local_read: bool = true, }; pub const DeviceType = enum { discrete, integrated, software, }; pub const VKInstanceConfig = struct { api_version: VKAPIVersion = .v1_3, vk_11_features: VK11Features = .{}, vk_13_features: VK13Features = .{}, vk_14_features: VK14Features = .{}, }; pub const InstanceConfig = union(Backend) { vulkan: VKInstanceConfig, }; // // RAW // pub const RawInstance = union(Backend) { vulkan: *vk.VkInstance_T, }; pub const RawFrame = union(Backend) { vulkan: struct { cmd_buf: *vk.VkCommandBuffer_T, image_index: u32 = 0, image_available: *vk.VkSemaphore_T, fence: *vk.VkFence_T, }, }; pub const RawAdapter = union(Backend) { vulkan: *vk.VkPhysicalDevice_T, }; pub const RawDevice = union(Backend) { vulkan: struct { device: *vk.VkDevice_T, graphics_queue: *vk.VkQueue_T, present_queue: *vk.VkQueue_T, }, }; pub const RawBuffer = union(Backend) { vulkan: *vk.VkBuffer_T, }; pub const RawShader = union(Backend) { vulkan: *vk.VkShaderModule_T, }; pub const RawPipeline = union(Backend) { vulkan: struct { pipeline: *vk.VkPipeline_T, descriptor_pool: *vk.VkDescriptorPool_T, }, }; // // INFOS // /// ---------------------------------------------------- /// ---------------------------------------------------- pub const AdapterInfo = struct { name: [256]u8, gpu_type: DeviceType, device_id: u32, vendor_id: u32, }; /// ---------------------------------------------------- /// ---------------------------------------------------- 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 AdapterConfig = struct { device_type: DeviceType = .discrete, 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, }; /// ---------------------------------------------------- /// TODO: Mabe mabe use this for slang shader /// ---------------------------------------------------- pub const ShaderDescriptor = struct { shaders: []const Handle(Shader), vert_entry_point_name: ?[]const u8 = null, frag_entry_point_name: ?[]const u8 = null, }; /// ---------------------------------------------------- /// ---------------------------------------------------- pub const PipelineConfig = struct { vert_shader: Handle(Shader), frag_shader: Handle(Shader), vert_entry_point_name: ?[]const u8 = null, frag_entry_point_name: ?[]const u8 = null, 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.getBackend() catch return).*) { .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.getBackend() catch return).*) { .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.getBackend() catch return).*) { .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 }, /// Optional texture to render into instead of the swapchain image render_target: ?Handle(Texture) = null, 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 Instance = struct {}; 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 ((try self.gfx.getBackend()).*) { .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 ((try self.gfx.getBackend()).*) { .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 ((try self.gfx.getBackend()).*) { .vulkan => |*v| v.bindPipeline(self.handle), }; } pub fn setUniform(self: *const Pipeline, name: []const u8, value: anytype) !void { try switch ((try self.gfx.getBackend()).*) { .vulkan => |*v| v.setUniform(self.handle, name, value), }; } };