const std = @import("std"); const assert = std.debug.assert; const glfw = @import("glfw"); const c = @import("c.zig").c; // #include "SampleUtils.h" // #include "common/Assert.h" // #include "common/Log.h" // #include "common/Platform.h" // #include "common/SystemUtils.h" // #include "utils/BackendBinding.h" // #include "utils/GLFWUtils.h" // #include "utils/TerribleCommandBuffer.h" // #include // #include // #include // #include // #include // #include "GLFW/glfw3.h" // #include // #include fn printDeviceError(error_type: c.WGPUErrorType, message: [*c]const u8, _: ?*c_void) callconv(.C) void { switch (error_type) { c.WGPUErrorType_Validation => std.debug.print("dawn: validation error: {s}\n", .{message}), c.WGPUErrorType_OutOfMemory => std.debug.print("dawn: out of memory: {s}\n", .{message}), c.WGPUErrorType_Unknown => std.debug.print("dawn: unknown error: {s}\n", .{message}), c.WGPUErrorType_DeviceLost => std.debug.print("dawn: device lost: {s}\n", .{message}), else => unreachable, } } const CmdBufType = enum { none, terrible }; // static std::unique_ptr instance; // static utils::BackendBinding* binding = nullptr; // static GLFWwindow* window = nullptr; // static dawn_wire::WireServer* wireServer = nullptr; // static dawn_wire::WireClient* wireClient = nullptr; // static utils::TerribleCommandBuffer* c2sBuf = nullptr; // static utils::TerribleCommandBuffer* s2cBuf = nullptr; const Setup = struct { device: c.WGPUDevice, binding: c.MachUtilsBackendBinding, window: glfw.Window, }; fn detectBackendType() c.WGPUBackendType { if (std.os.getenv("WGPU_BACKEND")) |backend| { if (std.ascii.eqlIgnoreCase(backend, "opengl")) return c.WGPUBackendType_OpenGL; if (std.ascii.eqlIgnoreCase(backend, "opengles")) return c.WGPUBackendType_OpenGLES; if (std.ascii.eqlIgnoreCase(backend, "d3d11")) return c.WGPUBackendType_D3D11; if (std.ascii.eqlIgnoreCase(backend, "d3d12")) return c.WGPUBackendType_D3D12; if (std.ascii.eqlIgnoreCase(backend, "metal")) return c.WGPUBackendType_Metal; if (std.ascii.eqlIgnoreCase(backend, "null")) return c.WGPUBackendType_Null; if (std.ascii.eqlIgnoreCase(backend, "vulkan")) return c.WGPUBackendType_Vulkan; @panic("unknown BACKEND type"); } const target = @import("builtin").target; if (target.isDarwin()) return c.WGPUBackendType_Metal; if (target.os.tag == .windows) return c.WGPUBackendType_D3D12; return c.WGPUBackendType_Vulkan; } fn backendTypeString(t: c.WGPUBackendType) []const u8 { return switch (t) { c.WGPUBackendType_OpenGL => "OpenGL", c.WGPUBackendType_OpenGLES => "OpenGLES", c.WGPUBackendType_D3D11 => "D3D11", c.WGPUBackendType_D3D12 => "D3D12", c.WGPUBackendType_Metal => "Metal", c.WGPUBackendType_Null => "Null", c.WGPUBackendType_Vulkan => "Vulkan", else => unreachable, }; } pub fn setup() !Setup { const backend_type = detectBackendType(); const cmd_buf_type = CmdBufType.none; try glfw.init(.{}); // Create the test window and discover adapters using it (esp. for OpenGL) var hints = glfwWindowHintsForBackend(backend_type); hints.cocoa_retina_framebuffer = false; const window = try glfw.Window.create(640, 480, "Dawn window", null, null, hints); const instance = c.machDawnNativeInstance_init(); try discoverAdapter(instance, window, backend_type); const adapters = c.machDawnNativeInstance_getAdapters(instance); var backend_adapter: ?c.MachDawnNativeAdapter = null; var i: usize = 0; while (i < c.machDawnNativeAdapters_length(adapters)) : (i += 1) { const adapter = c.machDawnNativeAdapters_index(adapters, i); const properties = c.machDawnNativeAdapter_getProperties(adapter); if (c.machDawnNativeAdapterProperties_getBackendType(properties) == backend_type) { const name = c.machDawnNativeAdapterProperties_getName(properties); const driver_description = c.machDawnNativeAdapterProperties_getDriverDescription(properties); std.debug.print("found {s} adapter: {s}, {s}\n", .{ backendTypeString(backend_type), name, driver_description }); backend_adapter = adapter; } } assert(backend_adapter != null); const backend_device = c.machDawnNativeAdapter_createDevice(backend_adapter.?, null); const backend_procs = c.machDawnNativeGetProcs(); const binding = c.machUtilsCreateBinding(backend_type, @ptrCast(*c.GLFWwindow, window.handle), backend_device); if (binding == null) { @panic("failed to create binding"); } // Choose whether to use the backend procs and devices directly, or set up the wire. var procs: ?*const c.DawnProcTable = null; var c_device: ?c.WGPUDevice = null; switch (cmd_buf_type) { CmdBufType.none => { procs = backend_procs; c_device = backend_device; }, CmdBufType.terrible => { // TODO(slimsag): @panic("not implemented"); // c2sBuf = new utils::TerribleCommandBuffer(); // s2cBuf = new utils::TerribleCommandBuffer(); // dawn_wire::WireServerDescriptor serverDesc = {}; // serverDesc.procs = &backendProcs; // serverDesc.serializer = s2cBuf; // wireServer = new dawn_wire::WireServer(serverDesc); // c2sBuf->SetHandler(wireServer); // dawn_wire::WireClientDescriptor clientDesc = {}; // clientDesc.serializer = c2sBuf; // wireClient = new dawn_wire::WireClient(clientDesc); // procs = dawn_wire::client::GetProcs(); // s2cBuf->SetHandler(wireClient); // auto deviceReservation = wireClient->ReserveDevice(); // wireServer->InjectDevice(backendDevice, deviceReservation.id, // deviceReservation.generation); // cDevice = deviceReservation.device; }, } c.dawnProcSetProcs(procs.?); procs.?.deviceSetUncapturedErrorCallback.?(c_device.?, printDeviceError, null); return Setup{ .device = c_device.?, .binding = binding, .window = window, }; } fn glfwWindowHintsForBackend(backend: c.WGPUBackendType) glfw.Window.Hints { return switch (backend) { c.WGPUBackendType_OpenGL => .{ // Ask for OpenGL 4.4 which is what the GL backend requires for compute shaders and // texture views. .context_version_major = 4, .context_version_minor = 4, .opengl_forward_compat = true, .opengl_profile = .opengl_core_profile, }, c.WGPUBackendType_OpenGLES => .{ .context_version_major = 3, .context_version_minor = 1, .client_api = .opengl_es_api, .context_creation_api = .egl_context_api, }, else => .{ // Without this GLFW will initialize a GL context on the window, which prevents using // the window with other APIs (by crashing in weird ways). .client_api = .no_api, }, }; } fn discoverAdapter(instance: c.MachDawnNativeInstance, window: glfw.Window, typ: c.WGPUBackendType) !void { if (typ == c.WGPUBackendType_OpenGL) { try glfw.makeContextCurrent(window); const adapter_options = c.MachDawnNativeAdapterDiscoveryOptions_OpenGL{ .getProc = @ptrCast(fn ([*c]const u8) callconv(.C) ?*c_void, glfw.getProcAddress), }; _ = c.machDawnNativeInstance_discoverAdapters(instance, typ, &adapter_options); } else if (typ == c.WGPUBackendType_OpenGLES) { try glfw.makeContextCurrent(window); const adapter_options = c.MachDawnNativeAdapterDiscoveryOptions_OpenGLES{ .getProc = @ptrCast(fn ([*c]const u8) callconv(.C) ?*c_void, glfw.getProcAddress), }; _ = c.machDawnNativeInstance_discoverAdapters(instance, typ, &adapter_options); } else { c.machDawnNativeInstance_discoverDefaultAdapters(instance); } } // wgpu::TextureFormat GetPreferredSwapChainTextureFormat() { // DoFlush(); // return static_cast(binding->GetPreferredSwapChainTextureFormat()); // } // wgpu::TextureView CreateDefaultDepthStencilView(const wgpu::Device& device) { // wgpu::TextureDescriptor descriptor; // descriptor.dimension = wgpu::TextureDimension::e2D; // descriptor.size.width = 640; // descriptor.size.height = 480; // descriptor.size.depthOrArrayLayers = 1; // descriptor.sampleCount = 1; // descriptor.format = wgpu::TextureFormat::Depth24PlusStencil8; // descriptor.mipLevelCount = 1; // descriptor.usage = wgpu::TextureUsage::RenderAttachment; // auto depthStencilTexture = device.CreateTexture(&descriptor); // return depthStencilTexture.CreateView(); // } // bool InitSample(int argc, const char** argv) { // for (int i = 1; i < argc; i++) { // if (std::string("-b") == argv[i] || std::string("--backend") == argv[i]) { // i++; // if (i < argc && std::string("d3d12") == argv[i]) { // backendType = wgpu::BackendType::D3D12; // continue; // } // if (i < argc && std::string("metal") == argv[i]) { // backendType = wgpu::BackendType::Metal; // continue; // } // if (i < argc && std::string("null") == argv[i]) { // backendType = wgpu::BackendType::Null; // continue; // } // if (i < argc && std::string("opengl") == argv[i]) { // backendType = wgpu::BackendType::OpenGL; // continue; // } // if (i < argc && std::string("opengles") == argv[i]) { // backendType = wgpu::BackendType::OpenGLES; // continue; // } // if (i < argc && std::string("vulkan") == argv[i]) { // backendType = wgpu::BackendType::Vulkan; // continue; // } // fprintf(stderr, // "--backend expects a backend name (opengl, opengles, metal, d3d12, null, " // "vulkan)\n"); // return false; // } // if (std::string("-c") == argv[i] || std::string("--command-buffer") == argv[i]) { // i++; // if (i < argc && std::string("none") == argv[i]) { // cmdBufType = CmdBufType::None; // continue; // } // if (i < argc && std::string("terrible") == argv[i]) { // cmdBufType = CmdBufType::Terrible; // continue; // } // fprintf(stderr, "--command-buffer expects a command buffer name (none, terrible)\n"); // return false; // } // if (std::string("-h") == argv[i] || std::string("--help") == argv[i]) { // printf("Usage: %s [-b BACKEND] [-c COMMAND_BUFFER]\n", argv[0]); // printf(" BACKEND is one of: d3d12, metal, null, opengl, opengles, vulkan\n"); // printf(" COMMAND_BUFFER is one of: none, terrible\n"); // return false; // } // } // return true; // }