282 lines
11 KiB
Zig
282 lines
11 KiB
Zig
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 <dawn/dawn_proc.h>
|
|
// #include <dawn/dawn_wsi.h>
|
|
// #include <dawn_native/DawnNative.h>
|
|
// #include <dawn_wire/WireClient.h>
|
|
// #include <dawn_wire/WireServer.h>
|
|
// #include "GLFW/glfw3.h"
|
|
|
|
// #include <algorithm>
|
|
// #include <cstring>
|
|
|
|
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<dawn_native::Instance> 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<wgpu::TextureFormat>(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;
|
|
// }
|