main.zig (7931B)
1 const builtin = @import("builtin"); 2 const std = @import("std"); 3 4 const glfw = @import("glfw"); 5 const wgpu = @import("wgpu"); 6 const math = @import("math"); 7 8 const Callback1 = wgpu.Callback1; 9 const DeviceCallback = wgpu.DeviceCallback; 10 const CommandBuffer = wgpu.CommandBuffer; 11 const Device = wgpu.Device; 12 const Instance = wgpu.Instance; 13 const StringView = wgpu.StringView; 14 15 const PerspectiveCamera = @import("camera.zig").PerspectiveCamera; 16 const RenderPipeline = @import("render_pipeline.zig").RenderPipeline; 17 const TriangleRenderPipeline = @import("render_pipeline.zig").TriangleRenderPipeline; 18 19 fn zgpu_log_callback(level: wgpu.LogLevel, message: []const u8) void { 20 switch (level) { 21 .@"error" => { 22 std.log.err("[wgpu] {s}", .{message}); 23 }, 24 .warn => { 25 std.log.warn("[wgpu] {s}", .{message}); 26 }, 27 .info => { 28 std.log.debug("[wgpu] {s}", .{message}); 29 }, 30 .debug, .trace => { 31 std.log.debug("[wgpu] {s}", .{message}); 32 }, 33 .off => unreachable, 34 } 35 } 36 37 fn zgpu_error_callback( 38 error_type: wgpu.ErrorType, 39 message: []const u8, 40 ) void { 41 std.log.err("[wgpu - {}] {s}", .{ error_type, message }); 42 } 43 44 fn zgpu_device_lost_callback( 45 reason: wgpu.DeviceLostReason, 46 message: []const u8, 47 ) void { 48 std.log.err("[wgpu - {}] {s}", .{ reason, message }); 49 } 50 51 pub fn main() !void { 52 try glfw.init(); 53 defer glfw.terminate(); 54 55 glfw.windowHint(.client_api, glfw.ClientApi.no_api); 56 const window = try glfw.Window.create(640, 480, "Example", null, null); 57 defer window.destroy(); 58 59 wgpu.setLogCallback(Callback1(zgpu_log_callback)); 60 wgpu.setLogLevel(.warn); 61 62 const desc = Instance.Descriptor{ 63 .next = .{ 64 .extras = &.{ 65 .backends = .primary, 66 .flags = .validation, 67 .dx12_compiler = .undefined, 68 .gles3_minor_version = .automatic, 69 .gl_fence_behavior = .normal, 70 .dxil_path = null, 71 .dxc_path = null, 72 .dxc_max_shader_model = .dxc_max_shader_model_v6_0, 73 }, 74 }, 75 .features = .{ 76 .timed_wait_any_enable = false, 77 .timed_wait_any_max_count = 0, 78 }, 79 }; 80 81 const instance = Instance.create(&desc) orelse { 82 std.log.err("failed to create GPU instance", .{}); 83 std.process.exit(1); 84 }; 85 defer instance.release(); 86 87 const surface = switch (builtin.target.os.tag) { 88 .linux => instance.createSurface(&.{ 89 .next = .{ 90 .from_xlib_window = &.{ 91 .window = try glfw.native.getX11Window(window)(), 92 .display = try glfw.native.getX11Display(), 93 }, 94 }, 95 .label = StringView.fromSlice("Example Surface"), 96 }), 97 .macos => instance.createSurface(&.{ 98 .next = .{ 99 .from_metal_layer = &.{ 100 .layer = glfw.native.getMetalLayer(window), 101 }, 102 }, 103 .label = StringView.fromSlice("Example Surface"), 104 }), 105 else => @compileError("Unsupported OS"), 106 } orelse { 107 std.log.err("failed to create GPU surface", .{}); 108 std.process.exit(1); 109 }; 110 defer surface.release(); 111 112 const adapter = switch (builtin.target.os.tag) { 113 .linux => try instance.requestAdapter(&.{ 114 .feature_level = .core, 115 .power_preference = .high_performance, 116 .backend_type = .vulkan, 117 .force_fallback_adapter = false, 118 .compatible_surface = surface, 119 }), 120 .macos => try instance.requestAdapter(&.{ 121 .feature_level = .core, 122 .power_preference = .high_performance, 123 .backend_type = .metal, 124 .force_fallback_adapter = false, 125 // the adapter seems to be compatible, but when I request that it 126 // is it can't find one 127 .compatible_surface = null, 128 }), 129 else => @compileError("Unsupported OS"), 130 }; 131 defer adapter.release(); 132 133 const device = try adapter.requestDevice(&.{ 134 .label = StringView.fromSlice("Example Device"), 135 .required_feature_count = 0, 136 .required_features = null, 137 .required_limits = null, 138 .default_queue = .{ 139 .label = StringView.fromSlice("Example Default Queue"), 140 }, 141 .device_lost_callback_info = .{ 142 .callback = DeviceCallback(zgpu_device_lost_callback), 143 .mode = .allow_spontaneous, 144 .userdata1 = null, 145 .userdata2 = null, 146 }, 147 .uncaptured_error_callback_info = .{ 148 .callback = DeviceCallback(zgpu_error_callback), 149 .userdata1 = null, 150 .userdata2 = null, 151 }, 152 }); 153 defer device.release(); 154 155 const queue = device.getQueue(); 156 defer queue.release(); 157 158 surface.configure(&.{ 159 .device = device, 160 .format = .bgra8_unorm, 161 .usage = .{ .render_attachment = true }, 162 .width = 640, 163 .height = 480, 164 .view_format_count = 0, 165 .view_formats = null, 166 .alpha_mode = .auto, 167 .present_mode = .fifo, 168 }); 169 170 171 var triangle_rp = try TriangleRenderPipeline.init(device); 172 173 const camera = PerspectiveCamera{ 174 .yaw = 100.0, 175 .pitch = -10.0, 176 }; 177 const uniform_data = TriangleRenderPipeline.UniformData{ 178 .view_matrix = camera.view(), 179 .proj_matrix = camera.proj(), 180 }; 181 triangle_rp.setUniform(queue, &uniform_data); 182 183 const pipelines = [_]RenderPipeline{ 184 triangle_rp.renderPipeline(), 185 }; 186 187 while (!window.shouldClose()) { 188 glfw.pollEvents(); 189 const current_texture = surface.getCurrentTexture(); 190 const texture = current_texture.texture; 191 defer texture.release(); 192 const view = texture.createView(&.{ 193 .label = StringView.fromSlice("Example View"), 194 .format = .bgra8_unorm, 195 .dimension = .@"2d", 196 .base_mip_level = 0, 197 .mip_level_count = 1, 198 .base_array_layer = 0, 199 .array_layer_count = 1, 200 .aspect = .all, 201 .usage = .{ .render_attachment = true }, 202 }).?; 203 defer view.release(); 204 { 205 const encoder = device.createCommandEncoder(&.{ 206 .label = StringView.fromSlice("Example Encoder"), 207 }).?; 208 defer encoder.release(); 209 { 210 const pass = encoder.beginRenderPass(&.{ 211 .label = StringView.fromSlice("Example Render Pass"), 212 .color_attachment_count = 1, 213 .color_attachments = &.{ 214 .{ 215 .view = view, 216 .resolve_target = null, 217 .load_op = .clear, 218 .store_op = .store, 219 .clear_value = .{ .r = 1, .g = 1, .b = 1, .a = 1 }, 220 }, 221 }, 222 .depth_stencil_attachment = null, 223 .occlusion_query_set = null, 224 .timestamp_writes = null, 225 }); 226 227 for (pipelines) |pipeline| { 228 pipeline.frame(pass); 229 } 230 231 defer pass.release(); 232 defer pass.end(); 233 } 234 { 235 var command = encoder.finish(&.{ 236 .label = StringView.fromSlice("Example Command Buffer"), 237 }).?; 238 defer command.release(); 239 queue.submit(&[_]*CommandBuffer{command}); 240 } 241 } 242 switch (surface.present()) { 243 .success => {}, 244 .@"error" => std.log.err("surface presentation failed", .{}), 245 } 246 } 247 }