zgpu

git clone git://git.electrosoup.com/zgpu
Log | Files | Refs | Submodules | README

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 }