zgpu

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

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 }