main.zig (10560B)
1 const builtin = @import("builtin"); 2 const std = @import("std"); 3 4 const glfw = @import("glfw"); 5 const wgpu = @import("wgpu"); 6 7 const Callback1 = wgpu.Callback1; 8 const DeviceCallback = wgpu.DeviceCallback; 9 const CommandBuffer = wgpu.CommandBuffer; 10 const Device = wgpu.Device; 11 const Instance = wgpu.Instance; 12 const StringView = wgpu.StringView; 13 14 fn zgpu_log_callback(level: wgpu.LogLevel, message: []const u8) void { 15 switch (level) { 16 .@"error" => { 17 std.log.err("[wgpu] {s}", .{message}); 18 }, 19 .warn => { 20 std.log.warn("[wgpu] {s}", .{message}); 21 }, 22 .info => { 23 std.log.debug("[wgpu] {s}", .{message}); 24 }, 25 .debug, .trace => { 26 std.log.debug("[wgpu] {s}", .{message}); 27 }, 28 .off => unreachable, 29 } 30 } 31 32 fn zgpu_error_callback( 33 error_type: wgpu.ErrorType, 34 message: []const u8, 35 ) void { 36 std.log.err("[wgpu - {}] {s}", .{ error_type, message }); 37 } 38 39 fn zgpu_device_lost_callback( 40 reason: wgpu.DeviceLostReason, 41 message: []const u8, 42 ) void { 43 std.log.err("[wgpu - {}] {s}", .{ reason, message }); 44 } 45 46 pub fn main() !void { 47 try glfw.init(); 48 defer glfw.terminate(); 49 50 glfw.windowHint(.client_api, glfw.ClientApi.no_api); 51 const window = try glfw.Window.create(640, 480, "Example", null, null); 52 defer window.destroy(); 53 54 wgpu.setLogCallback(Callback1(zgpu_log_callback)); 55 wgpu.setLogLevel(.warn); 56 57 const desc = Instance.Descriptor{ 58 .next = .{ 59 .extras = &.{ 60 .backends = .primary, 61 .flags = .validation, 62 .dx12_compiler = .undefined, 63 .gles3_minor_version = .automatic, 64 .gl_fence_behavior = .normal, 65 .dxil_path = null, 66 .dxc_path = null, 67 .dxc_max_shader_model = .dxc_max_shader_model_v6_0, 68 }, 69 }, 70 .features = .{ 71 .timed_wait_any_enable = false, 72 .timed_wait_any_max_count = 0, 73 }, 74 }; 75 76 const instance = Instance.create(&desc) orelse { 77 std.log.err("failed to create GPU instance", .{}); 78 std.process.exit(1); 79 }; 80 defer instance.release(); 81 82 const surface = switch (builtin.target.os.tag) { 83 .linux => instance.createSurface(&.{ 84 .next = .{ 85 .from_xlib_window = &.{ 86 .window = try glfw.native.getX11Window(window)(), 87 .display = try glfw.native.getX11Display(), 88 }, 89 }, 90 .label = StringView.fromSlice("Example Surface"), 91 }), 92 .macos => instance.createSurface(&.{ 93 .next = .{ 94 .from_metal_layer = &.{ 95 .layer = glfw.native.getMetalLayer(window), 96 }, 97 }, 98 .label = StringView.fromSlice("Example Surface"), 99 }), 100 else => @compileError("Unsupported OS"), 101 } orelse { 102 std.log.err("failed to create GPU surface", .{}); 103 std.process.exit(1); 104 }; 105 defer surface.release(); 106 107 108 const adapter = switch (builtin.target.os.tag) { 109 .linux => try instance.requestAdapter(&.{ 110 .feature_level = .core, 111 .power_preference = .high_performance, 112 .backend_type = .vulkan, 113 .force_fallback_adapter = false, 114 .compatible_surface = surface, 115 }), 116 .macos => try instance.requestAdapter(&.{ 117 .feature_level = .core, 118 .power_preference = .high_performance, 119 .backend_type = .metal, 120 .force_fallback_adapter = false, 121 // the adapter seems to be compatible, but when I request that it 122 // is it can't find one 123 .compatible_surface = null, 124 }), 125 else => @compileError("Unsupported OS"), 126 }; 127 defer adapter.release(); 128 129 const device = try adapter.requestDevice(&.{ 130 .label = StringView.fromSlice("Example Device"), 131 .required_feature_count = 0, 132 .required_features = null, 133 .required_limits = null, 134 .default_queue = .{ 135 .label = StringView.fromSlice("Example Default Queue"), 136 }, 137 .device_lost_callback_info = .{ 138 .callback = DeviceCallback(zgpu_device_lost_callback), 139 .mode = .allow_spontaneous, 140 .userdata1 = null, 141 .userdata2 = null, 142 }, 143 .uncaptured_error_callback_info = .{ 144 .callback = DeviceCallback(zgpu_error_callback), 145 .userdata1 = null, 146 .userdata2 = null, 147 }, 148 }); 149 defer device.release(); 150 151 const queue = device.getQueue(); 152 defer queue.release(); 153 154 surface.configure(&.{ 155 .device = device, 156 .format = .bgra8_unorm, 157 .usage = .{ .render_attachment = true }, 158 .width = 640, 159 .height = 480, 160 .view_format_count = 0, 161 .view_formats = null, 162 .alpha_mode = .auto, 163 .present_mode = .fifo, 164 }); 165 166 const vs = 167 \\ @vertex fn main( 168 \\ @builtin(vertex_index) vtx_idx : u32 169 \\ ) -> @builtin(position) vec4<f32> { 170 \\ let x = f32(i32(vtx_idx) - 1); 171 \\ let y = f32(i32(vtx_idx & 1u) * 2 - 1); 172 \\ return vec4<f32>(x, y, 0.0, 1.0); 173 \\ } 174 ; 175 const vs_module = device.createShaderModule(&.{ 176 .next = .{ .wgsl = &.{ .code = StringView.fromSlice(vs) } }, 177 .label = StringView.fromSlice("Example Vertex Shader"), 178 }) orelse { 179 std.log.err("failed to compile vertex shader", .{}); 180 std.process.exit(1); 181 }; 182 defer vs_module.release(); 183 184 const fs = 185 \\ @fragment fn main() -> @location(0) vec4<f32> { 186 \\ return vec4<f32>(1.0, 0.0, 0.0, 1.0); 187 \\ } 188 ; 189 const fs_module = device.createShaderModule(&.{ 190 .next = .{ .wgsl = &.{ .code = StringView.fromSlice(fs) } }, 191 .label = StringView.fromSlice("Example Fragment Shader"), 192 }) orelse { 193 std.log.err("failed to compile fragment shader", .{}); 194 std.process.exit(1); 195 }; 196 defer fs_module.release(); 197 198 const pipeline_layout = device.createPipelineLayout(&.{ 199 .label = StringView.fromSlice("Example Pipeline Layout"), 200 .bind_group_layout_count = 0, 201 .bind_group_layouts = null, 202 }).?; 203 defer pipeline_layout.release(); 204 205 const pipeline = device.createRenderPipeline(&.{ 206 .label = StringView.fromSlice("Example Render Pipeline"), 207 .layout = pipeline_layout, 208 .vertex = .{ 209 .module = vs_module, 210 .entry_point = StringView.fromSlice("main"), 211 .constant_count = 0, 212 .constants = null, 213 .buffer_count = 0, 214 .buffers = null, 215 }, 216 .primitive = .{ 217 .topology = .triangle_list, 218 .strip_index_format = .undefined, 219 .front_face = .ccw, 220 .cull_mode = .none, 221 .unclipped_depth = false, 222 }, 223 .depth_stencil = null, 224 .multisample = .{ 225 .count = 1, 226 .mask = 0xFFFFFFFF, 227 .alpha_to_coverage_enabled = false, 228 }, 229 .fragment_state = &.{ 230 .module = fs_module, 231 .entry_point = StringView.fromSlice("main"), 232 .constant_count = 0, 233 .constants = null, 234 .target_count = 1, 235 .targets = &.{ 236 .{ 237 .format = .bgra8_unorm, 238 .blend = &.{ 239 .color = .{ 240 .operation = .add, 241 .src_factor = .one, 242 .dst_factor = .zero, 243 }, 244 .alpha = .{ 245 .operation = .add, 246 .src_factor = .one, 247 .dst_factor = .zero, 248 }, 249 }, 250 .write_mask = .{ 251 .red = true, 252 .green = true, 253 .blue = true, 254 .alpha = true, 255 }, 256 }, 257 }, 258 }, 259 }) orelse { 260 std.log.err("failed to create render pipeline", .{}); 261 std.process.exit(1); 262 }; 263 defer pipeline.release(); 264 265 while (!window.shouldClose()) { 266 glfw.pollEvents(); 267 const current_texture = surface.getCurrentTexture(); 268 const texture = current_texture.texture; 269 defer texture.release(); 270 const view = texture.createView(&.{ 271 .label = StringView.fromSlice("Example View"), 272 .format = .bgra8_unorm, 273 .dimension = .@"2d", 274 .base_mip_level = 0, 275 .mip_level_count = 1, 276 .base_array_layer = 0, 277 .array_layer_count = 1, 278 .aspect = .all, 279 .usage = .{ .render_attachment = true }, 280 }).?; 281 defer view.release(); 282 { 283 const encoder = device.createCommandEncoder(&.{ 284 .label = StringView.fromSlice("Example Encoder"), 285 }).?; 286 defer encoder.release(); 287 { 288 const pass = encoder.beginRenderPass(&.{ 289 .label = StringView.fromSlice("Example Render Pass"), 290 .color_attachment_count = 1, 291 .color_attachments = &.{ 292 .{ 293 .view = view, 294 .resolve_target = null, 295 .load_op = .clear, 296 .store_op = .store, 297 .clear_value = .{ .r = 1, .g = 1, .b = 1, .a = 1 }, 298 }, 299 }, 300 .depth_stencil_attachment = null, 301 .occlusion_query_set = null, 302 .timestamp_writes = null, 303 }); 304 305 pass.setPipeline(pipeline); 306 pass.draw(3, 1, 0, 0); 307 308 defer pass.release(); 309 defer pass.end(); 310 } 311 { 312 var command = encoder.finish(&.{ 313 .label = StringView.fromSlice("Example Command Buffer"), 314 }).?; 315 defer command.release(); 316 queue.submit(&[_]*CommandBuffer{command}); 317 } 318 } 319 switch (surface.present()) { 320 .success => {}, 321 .@"error" => std.log.err("surface presentation failed", .{}), 322 } 323 } 324 }