aboutsummaryrefslogtreecommitdiff
path: root/vcpkg/scripts/test_ports/vcpkg-ci-dawn/project
diff options
context:
space:
mode:
Diffstat (limited to 'vcpkg/scripts/test_ports/vcpkg-ci-dawn/project')
-rwxr-xr-xvcpkg/scripts/test_ports/vcpkg-ci-dawn/project/CMakeLists.txt31
-rwxr-xr-xvcpkg/scripts/test_ports/vcpkg-ci-dawn/project/main.cpp391
-rwxr-xr-xvcpkg/scripts/test_ports/vcpkg-ci-dawn/project/main.html19
-rw-r--r--vcpkg/scripts/test_ports/vcpkg-ci-dawn/project/webgpu_glfw3.cpp121
4 files changed, 562 insertions, 0 deletions
diff --git a/vcpkg/scripts/test_ports/vcpkg-ci-dawn/project/CMakeLists.txt b/vcpkg/scripts/test_ports/vcpkg-ci-dawn/project/CMakeLists.txt
new file mode 100755
index 0000000..234c04e
--- /dev/null
+++ b/vcpkg/scripts/test_ports/vcpkg-ci-dawn/project/CMakeLists.txt
@@ -0,0 +1,31 @@
+cmake_minimum_required(VERSION 3.15)
+project(vcpkg_ci_dawn)
+
+set(CMAKE_CXX_STANDARD 17)
+
+find_package(glfw3 CONFIG REQUIRED)
+
+################################################################################
+# Use cmake config #
+################################################################################
+find_package(Dawn CONFIG REQUIRED)
+add_executable(vcpkg_ci_dawn main.cpp webgpu_glfw3.cpp)
+target_link_libraries(vcpkg_ci_dawn PRIVATE glfw dawn::webgpu_dawn)
+if (EMSCRIPTEN)
+ target_link_options(vcpkg_ci_dawn PRIVATE -sASYNCIFY)
+ set(TARGET_NAME "vcpkg_ci_dawn")
+ configure_file("${CMAKE_CURRENT_LIST_DIR}/main.html" "${CMAKE_BINARY_DIR}/${TARGET_NAME}.html" @ONLY)
+endif ()
+
+################################################################################
+# Use pkg-config #
+################################################################################
+find_package(PkgConfig)
+pkg_check_modules(webgpu_dawn REQUIRED IMPORTED_TARGET unofficial_webgpu_dawn)
+add_executable(vcpkg_ci_dawn_pc main.cpp webgpu_glfw3.cpp)
+target_link_libraries(vcpkg_ci_dawn_pc PRIVATE glfw PkgConfig::webgpu_dawn)
+if (EMSCRIPTEN)
+ target_link_options(vcpkg_ci_dawn_pc PRIVATE -sASYNCIFY)
+ set(TARGET_NAME "vcpkg_ci_dawn_pc")
+ configure_file("${CMAKE_CURRENT_LIST_DIR}/main.html" "${CMAKE_BINARY_DIR}/${TARGET_NAME}.html" @ONLY)
+endif ()
diff --git a/vcpkg/scripts/test_ports/vcpkg-ci-dawn/project/main.cpp b/vcpkg/scripts/test_ports/vcpkg-ci-dawn/project/main.cpp
new file mode 100755
index 0000000..74bf086
--- /dev/null
+++ b/vcpkg/scripts/test_ports/vcpkg-ci-dawn/project/main.cpp
@@ -0,0 +1,391 @@
+//
+// Copyright (c) 2024 xiaozhuai
+//
+
+#define GLFW_INCLUDE_NONE
+
+#include <cstdio>
+#include <string>
+#include <vector>
+
+#include "GLFW/glfw3.h"
+#include "webgpu/webgpu_cpp.h"
+
+#if defined(__EMSCRIPTEN__)
+#include "emscripten/emscripten.h"
+#endif
+
+#define LOG(fmt, ...) printf(fmt "\n", ##__VA_ARGS__)
+
+#if !defined(__PRETTY_FUNCTION__) && !defined(__GNUC__)
+#define MY_PRETTY_FUNCTION __FUNCSIG__
+#else
+#define MY_PRETTY_FUNCTION __PRETTY_FUNCTION__
+#endif
+
+#define ASSERT(expr, fmt, ...) \
+ do { \
+ if (!(expr)) { \
+ LOG("Assertion failed: %s:%d, func: \"%s\", expr: \"%s\", message: " /**/ \
+ fmt, /**/ \
+ __FILE__, __LINE__, MY_PRETTY_FUNCTION, #expr, /**/ \
+ ##__VA_ARGS__); \
+ abort(); \
+ } \
+ } while (0)
+
+wgpu::Instance create_instance() {
+ wgpu::InstanceDescriptor instance_desc;
+ std::vector<wgpu::InstanceFeatureName> required_features = {
+ wgpu::InstanceFeatureName::TimedWaitAny,
+ };
+ instance_desc.requiredFeatureCount = required_features.size();
+ instance_desc.requiredFeatures = required_features.data();
+ return wgpu::CreateInstance(&instance_desc);
+}
+
+wgpu::Surface create_surface(const wgpu::Instance &instance, GLFWwindow *window);
+
+wgpu::Adapter request_adapter(const wgpu::Instance &instance, const wgpu::Surface &surface) {
+ wgpu::RequestAdapterOptions adapter_options;
+ adapter_options.compatibleSurface = surface;
+ adapter_options.powerPreference = wgpu::PowerPreference::HighPerformance;
+
+ wgpu::Adapter adapter;
+ auto adapter_future = instance.RequestAdapter(
+ &adapter_options, wgpu::CallbackMode::WaitAnyOnly,
+ [&adapter](wgpu::RequestAdapterStatus status, wgpu::Adapter adapter_ret, wgpu::StringView message) {
+ ASSERT(status == wgpu::RequestAdapterStatus::Success && adapter_ret != nullptr, "Failed to get adapter: %s",
+ message.data);
+ adapter = std::move(adapter_ret);
+ });
+ ASSERT(instance.WaitAny(adapter_future, wgpu::kLimitU64Undefined) == wgpu::WaitStatus::Success,
+ "Failed to wait for adapter request");
+
+ return adapter;
+}
+
+void device_lost_callback(const wgpu::Device &, wgpu::DeviceLostReason, wgpu::StringView message) {
+ LOG("Device lost: %s", message.data);
+}
+
+void device_uncaptured_error_callback(const wgpu::Device &, wgpu::ErrorType type, wgpu::StringView message) {
+ const char *error_type;
+ switch (type) {
+ case wgpu::ErrorType::Validation:
+ error_type = "Validation";
+ break;
+ case wgpu::ErrorType::OutOfMemory:
+ error_type = "Out of memory";
+ break;
+ case wgpu::ErrorType::Internal:
+ error_type = "Internal";
+ break;
+ case wgpu::ErrorType::Unknown:
+ error_type = "Unknown";
+ break;
+ default:
+ ASSERT(false, "Unknown ErrorType");
+ }
+ LOG("Uncaptured Error %s: %s", error_type, message.data);
+}
+
+wgpu::Device request_device(const wgpu::Instance &instance, const wgpu::Adapter &adapter) {
+ wgpu::DeviceDescriptor device_desc;
+
+ device_desc.SetDeviceLostCallback(wgpu::CallbackMode::AllowSpontaneous, device_lost_callback);
+ device_desc.SetUncapturedErrorCallback(device_uncaptured_error_callback);
+
+ wgpu::Device device;
+ auto device_future = adapter.RequestDevice(
+ &device_desc, wgpu::CallbackMode::WaitAnyOnly,
+ [&device](wgpu::RequestDeviceStatus status, wgpu::Device device_ret, wgpu::StringView message) {
+ ASSERT(status == wgpu::RequestDeviceStatus::Success && device_ret != nullptr, "Failed to get device: %s",
+ message.data);
+ device = std::move(device_ret);
+ });
+ ASSERT(instance.WaitAny(device_future, wgpu::kLimitU64Undefined) == wgpu::WaitStatus::Success,
+ "Failed to wait for device request");
+
+ return device;
+}
+
+wgpu::ShaderModule create_shader(const wgpu::Device &device, const std::string &shader_code) {
+ wgpu::ShaderSourceWGSL shader_code_desc;
+ shader_code_desc.sType = wgpu::SType::ShaderSourceWGSL;
+ shader_code_desc.code = shader_code.c_str();
+ wgpu::ShaderModuleDescriptor shader_desc;
+ shader_desc.nextInChain = &shader_code_desc;
+ return device.CreateShaderModule(&shader_desc);
+}
+
+struct alignas(16) Uniforms {
+ struct {
+ float width = 0.0f;
+ float height = 0.0f;
+ } resolution;
+ float time = 0.0f;
+};
+
+void glfw_error_callback(int error, const char *description) { LOG("GLFW error, %d, %s", error, description); }
+
+struct AppState {
+ wgpu::Instance instance;
+ wgpu::Surface surface;
+ wgpu::Adapter adapter;
+ wgpu::Device device;
+ wgpu::Queue queue;
+ wgpu::SurfaceConfiguration surface_config;
+ int surface_width = 0;
+ int surface_height = 0;
+};
+
+int main() {
+ glfwSetErrorCallback(glfw_error_callback);
+ ASSERT(glfwInit(), "GLFW init failed");
+ glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
+ auto *window = glfwCreateWindow(1024, 1024, "vcpkg-ci-dawn", nullptr, nullptr);
+
+ AppState state;
+ state.instance = create_instance();
+ state.surface = create_surface(state.instance, window);
+ state.adapter = request_adapter(state.instance, state.surface);
+ state.device = request_device(state.instance, state.adapter);
+ state.queue = state.device.GetQueue();
+
+ wgpu::SurfaceCapabilities surface_capabilities;
+ state.surface.GetCapabilities(state.adapter, &surface_capabilities);
+ glfwGetFramebufferSize(window, &state.surface_width, &state.surface_height);
+
+ state.surface_config.device = state.device;
+ state.surface_config.usage = wgpu::TextureUsage::RenderAttachment;
+ state.surface_config.format = surface_capabilities.formats[0];
+ state.surface_config.presentMode = surface_capabilities.presentModes[0];
+ state.surface_config.alphaMode = surface_capabilities.alphaModes[0];
+ state.surface_config.width = state.surface_width;
+ state.surface_config.height = state.surface_height;
+ state.surface.Configure(&state.surface_config);
+
+ glfwSetWindowUserPointer(window, &state);
+
+ glfwSetKeyCallback(window, [](GLFWwindow *window, int key, int scancode, int action, int mods) {
+ if (key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE) {
+ glfwSetWindowShouldClose(window, GLFW_TRUE);
+ }
+ });
+ glfwSetFramebufferSizeCallback(window, [](GLFWwindow *window, int width, int height) {
+ auto &state = *static_cast<AppState *>(glfwGetWindowUserPointer(window));
+ state.surface_width = width;
+ state.surface_height = height;
+ state.surface_config.width = width;
+ state.surface_config.height = height;
+ state.surface.Configure(&state.surface_config);
+ });
+
+ std::string shader_source = R"(
+struct Uniforms {
+ resolution: vec2f,
+ time: f32,
+};
+
+@group(0)
+@binding(0)
+var<uniform> uniforms: Uniforms;
+
+struct VertexInput {
+ @location(0)
+ pos: vec2f,
+};
+
+struct VertexOutput {
+ @builtin(position)
+ pos: vec4f,
+};
+
+@vertex
+fn vs_main(input: VertexInput) -> VertexOutput {
+ var output: VertexOutput;
+ output.pos = vec4f(input.pos, 0.0, 1.0);
+ return output;
+}
+
+struct FragmentInput {
+ @builtin(position)
+ coord: vec4f,
+};
+
+struct FragmentOutput {
+ @location(0)
+ color: vec4f,
+};
+
+fn palette(t: f32) -> vec3f{
+ let a = vec3f(0.5, 0.5, 0.5);
+ let b = vec3f(0.5, 0.5, 0.5);
+ let c = vec3f(1.0, 1.0, 1.0);
+ let d = vec3f(0.263, 0.416, 0.557);
+ return a + b * cos(6.28318 * (c * t + d));
+}
+
+@fragment
+fn fs_main(input: FragmentInput) -> FragmentOutput {
+ var uv = (input.coord.xy * 2.0 - uniforms.resolution) / min(uniforms.resolution.x, uniforms.resolution.y);
+ let uv0 = uv;
+ var color = vec3f(0.0);
+ for (var i: f32 = 0.0; i < 4.0; i += 1.0) {
+ uv = fract(uv * 1.5) - 0.5;
+ var d = length(uv) * exp(-length(uv0));
+ let col = palette(length(uv0) + i * 0.4 + uniforms.time * 0.4);
+ d = sin(d * 8.0 + uniforms.time) / 8.0;
+ d = abs(d);
+ d = pow(0.01 / d, 1.2);
+ color += col * d;
+ }
+ var output: FragmentOutput;
+ output.color = vec4f(color, 1.0);
+ return output;
+}
+)";
+ auto shader_module = create_shader(state.device, shader_source);
+
+ constexpr float vertices[12] = {-1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0};
+ constexpr int vertex_count = std::size(vertices) / 2;
+ wgpu::BufferDescriptor vertex_buffer_desc;
+ vertex_buffer_desc.size = sizeof(vertices);
+ vertex_buffer_desc.usage = wgpu::BufferUsage::Vertex | wgpu::BufferUsage::CopyDst;
+ wgpu::Buffer vertex_buffer = state.device.CreateBuffer(&vertex_buffer_desc);
+ state.queue.WriteBuffer(vertex_buffer, 0, vertices, sizeof(vertices));
+
+ Uniforms uniforms;
+ wgpu::BufferDescriptor uniform_buffer_desc;
+ uniform_buffer_desc.size = sizeof(uniforms);
+ uniform_buffer_desc.usage = wgpu::BufferUsage::Uniform | wgpu::BufferUsage::CopyDst;
+ wgpu::Buffer uniform_buffer = state.device.CreateBuffer(&uniform_buffer_desc);
+ state.queue.WriteBuffer(uniform_buffer, 0, &uniforms, sizeof(uniforms));
+
+ wgpu::RenderPipelineDescriptor pipeline_desc;
+
+ std::vector<wgpu::VertexAttribute> vertex_attributes(1);
+ vertex_attributes[0].format = wgpu::VertexFormat::Float32x2;
+ vertex_attributes[0].offset = 0;
+ vertex_attributes[0].shaderLocation = 0;
+ std::vector<wgpu::VertexBufferLayout> vertex_layouts(1);
+ vertex_layouts[0].arrayStride = 2 * sizeof(float);
+ vertex_layouts[0].attributeCount = vertex_attributes.size();
+ vertex_layouts[0].attributes = vertex_attributes.data();
+ vertex_layouts[0].stepMode = wgpu::VertexStepMode::Vertex;
+
+ pipeline_desc.vertex.bufferCount = vertex_layouts.size();
+ pipeline_desc.vertex.buffers = vertex_layouts.data();
+
+ pipeline_desc.vertex.module = shader_module;
+ pipeline_desc.vertex.entryPoint = "vs_main";
+ pipeline_desc.vertex.constantCount = 0;
+ pipeline_desc.vertex.constants = nullptr;
+
+ pipeline_desc.primitive.topology = wgpu::PrimitiveTopology::TriangleList;
+ pipeline_desc.primitive.stripIndexFormat = wgpu::IndexFormat::Undefined;
+ pipeline_desc.primitive.frontFace = wgpu::FrontFace::CCW;
+ pipeline_desc.primitive.cullMode = wgpu::CullMode::None;
+
+ wgpu::FragmentState fragment_state;
+ fragment_state.module = shader_module;
+ fragment_state.entryPoint = "fs_main";
+ fragment_state.constantCount = 0;
+ fragment_state.constants = nullptr;
+
+ wgpu::BlendState blend_state;
+ blend_state.color.srcFactor = wgpu::BlendFactor::SrcAlpha;
+ blend_state.color.dstFactor = wgpu::BlendFactor::OneMinusSrcAlpha;
+ blend_state.color.operation = wgpu::BlendOperation::Add;
+ blend_state.alpha.srcFactor = wgpu::BlendFactor::Zero;
+ blend_state.alpha.dstFactor = wgpu::BlendFactor::One;
+ blend_state.alpha.operation = wgpu::BlendOperation::Add;
+
+ wgpu::ColorTargetState color_target;
+ color_target.format = state.surface_config.format;
+ color_target.blend = &blend_state;
+ color_target.writeMask = wgpu::ColorWriteMask::All;
+
+ fragment_state.targetCount = 1;
+ fragment_state.targets = &color_target;
+ pipeline_desc.fragment = &fragment_state;
+
+ pipeline_desc.depthStencil = nullptr;
+ pipeline_desc.multisample.count = 1;
+ pipeline_desc.multisample.mask = ~0u;
+
+ pipeline_desc.multisample.alphaToCoverageEnabled = false;
+ pipeline_desc.layout = nullptr;
+
+ wgpu::RenderPipeline pipeline = state.device.CreateRenderPipeline(&pipeline_desc);
+
+ std::vector<wgpu::BindGroupEntry> bind_group_entries(1);
+ bind_group_entries[0].binding = 0;
+ bind_group_entries[0].buffer = uniform_buffer;
+ bind_group_entries[0].size = uniform_buffer.GetSize();
+
+ wgpu::BindGroupDescriptor bind_group_desc;
+ bind_group_desc.layout = pipeline.GetBindGroupLayout(0);
+ bind_group_desc.entryCount = bind_group_entries.size();
+ bind_group_desc.entries = bind_group_entries.data();
+ wgpu::BindGroup bind_group = state.device.CreateBindGroup(&bind_group_desc);
+
+ const double start_time = glfwGetTime();
+ while (!glfwWindowShouldClose(window)) {
+ glfwPollEvents();
+#if defined(__EMSCRIPTEN__)
+ emscripten_sleep(0);
+#endif
+
+ const double time = glfwGetTime() - start_time;
+
+ wgpu::SurfaceTexture surface_texture;
+ state.surface.GetCurrentTexture(&surface_texture);
+ ASSERT(surface_texture.status == wgpu::SurfaceGetCurrentTextureStatus::SuccessOptimal ||
+ surface_texture.status == wgpu::SurfaceGetCurrentTextureStatus::SuccessSuboptimal,
+ "Failed to get current texture");
+ if (surface_texture.status == wgpu::SurfaceGetCurrentTextureStatus::SuccessSuboptimal) {
+ LOG("Surface texture is suboptimal");
+ }
+
+ wgpu::Texture texture = surface_texture.texture;
+ wgpu::TextureView frame = texture.CreateView();
+
+ uniforms.resolution.width = static_cast<float>(texture.GetWidth());
+ uniforms.resolution.height = static_cast<float>(texture.GetHeight());
+ uniforms.time = static_cast<float>(time);
+ state.queue.WriteBuffer(uniform_buffer, 0, &uniforms, sizeof(uniforms));
+
+ auto encoder = state.device.CreateCommandEncoder();
+
+ wgpu::RenderPassColorAttachment color_attachment;
+ color_attachment.view = frame;
+ color_attachment.loadOp = wgpu::LoadOp::Clear;
+ color_attachment.storeOp = wgpu::StoreOp::Store;
+ color_attachment.clearValue = {0.1f, 0.2f, 0.3f, 1.0f};
+ wgpu::RenderPassDescriptor pass_desc;
+ pass_desc.colorAttachmentCount = 1;
+ pass_desc.colorAttachments = &color_attachment;
+ pass_desc.depthStencilAttachment = nullptr;
+
+ auto pass = encoder.BeginRenderPass(&pass_desc);
+ pass.SetPipeline(pipeline);
+ pass.SetVertexBuffer(0, vertex_buffer, 0, vertex_buffer.GetSize());
+ pass.SetBindGroup(0, bind_group, 0, nullptr);
+ pass.Draw(vertex_count);
+ pass.End();
+
+ wgpu::CommandBuffer command_buffer = encoder.Finish();
+ state.queue.Submit(1, &command_buffer);
+
+#if !defined(__EMSCRIPTEN__)
+ ASSERT(state.surface.Present(), "Failed to present the surface");
+ state.device.Tick();
+#endif
+ }
+
+ glfwDestroyWindow(window);
+ glfwTerminate();
+ return 0;
+}
diff --git a/vcpkg/scripts/test_ports/vcpkg-ci-dawn/project/main.html b/vcpkg/scripts/test_ports/vcpkg-ci-dawn/project/main.html
new file mode 100755
index 0000000..37f8b9e
--- /dev/null
+++ b/vcpkg/scripts/test_ports/vcpkg-ci-dawn/project/main.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <title>@TARGET_NAME@</title>
+ <style>
+ html, body { margin: 0; padding: 0; width: 100%; height: 100%; }
+ .canvas-container { width: 100%; height: 100%; display: flex; justify-content: center; align-items: center; }
+ #canvas { max-width: 100%; max-height: 100%; }
+ </style>
+</head>
+<body>
+<div class="canvas-container">
+ <canvas id="canvas" width="1024" height="1024"></canvas>
+</div>
+</body>
+<script type="text/javascript">var Module = {canvas: document.getElementById('canvas')};</script>
+<script type="text/javascript" src="@TARGET_NAME@.js"></script>
+</html>
diff --git a/vcpkg/scripts/test_ports/vcpkg-ci-dawn/project/webgpu_glfw3.cpp b/vcpkg/scripts/test_ports/vcpkg-ci-dawn/project/webgpu_glfw3.cpp
new file mode 100644
index 0000000..269ea1f
--- /dev/null
+++ b/vcpkg/scripts/test_ports/vcpkg-ci-dawn/project/webgpu_glfw3.cpp
@@ -0,0 +1,121 @@
+//
+// Copyright (c) 2025 xiaozhuai
+//
+
+#define GLFW_INCLUDE_NONE
+
+#include <memory>
+
+#include "GLFW/glfw3.h"
+#include "webgpu/webgpu_cpp.h"
+
+#if defined(_WIN32)
+#define GLFW_EXPOSE_NATIVE_WIN32
+#endif
+
+#if defined(__APPLE__)
+#define GLFW_EXPOSE_NATIVE_COCOA
+#endif
+
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__)
+#define DAWN_USE_X11
+#endif
+
+#if defined(DAWN_USE_X11)
+#define GLFW_EXPOSE_NATIVE_X11
+#endif
+
+#if defined(DAWN_USE_WAYLAND)
+#define GLFW_EXPOSE_NATIVE_WAYLAND
+#endif
+
+#if defined(__EMSCRIPTEN__)
+#include "emscripten/emscripten.h"
+#else
+#include "GLFW/glfw3native.h"
+#endif
+
+#if defined(__APPLE__)
+#include <objc/message.h>
+#include <objc/objc.h>
+#include <objc/runtime.h>
+template <typename T, typename... Args>
+T objc_call(id obj, const char *sel, Args... args) {
+ using FuncPtr = T (*)(id, SEL, Args...);
+ return reinterpret_cast<FuncPtr>(objc_msgSend)(obj, sel_registerName(sel), args...);
+}
+template <typename T, typename... Args>
+T objc_call(const char *clazz, const char *sel, Args... args) {
+ return objc_call<T>(reinterpret_cast<id>(objc_getClass(clazz)), sel, args...);
+}
+#endif
+
+std::unique_ptr<wgpu::ChainedStruct> setup_window_and_get_surface_descriptor(GLFWwindow *window) {
+ if (glfwGetWindowAttrib(window, GLFW_CLIENT_API) != GLFW_NO_API) {
+ return nullptr;
+ }
+
+#if defined(__EMSCRIPTEN__)
+ auto desc = std::make_unique<wgpu::EmscriptenSurfaceSourceCanvasHTMLSelector>();
+ desc->selector = "#canvas";
+ return desc;
+#elif defined(_WIN32)
+ auto desc = std::make_unique<wgpu::SurfaceSourceWindowsHWND>();
+ desc->hwnd = glfwGetWin32Window(window);
+ desc->hinstance = GetModuleHandle(nullptr);
+ return desc;
+#elif defined(__APPLE__)
+ // NSWindow *ns_window = glfwGetCocoaWindow(window);
+ // NSView *view = [ns_window contentView];
+ // [view setWantsLayer:YES];
+ // CAMetalLayer *layer = [CAMetalLayer layer];
+ // CGFloat scale_factor = [ns_window backingScaleFactor];
+ // [layer setContentsScale:scale_factor];
+ // [view setLayer:layer];
+ auto ns_window = glfwGetCocoaWindow(window);
+ CFRetain(ns_window);
+ auto view = objc_call<id>(ns_window, "contentView");
+ CFRetain(view);
+ objc_call<void, BOOL>(view, "setWantsLayer:", YES);
+ auto layer = objc_call<id>("CAMetalLayer", "layer");
+ auto scale_factor = objc_call<CGFloat>(ns_window, "backingScaleFactor");
+ objc_call<void, CGFloat>(layer, "setContentsScale:", scale_factor);
+ objc_call<void, id>(view, "setLayer:", layer);
+ auto desc = std::make_unique<wgpu::SurfaceSourceMetalLayer>();
+ desc->layer = layer;
+ CFRelease(view);
+ CFRelease(ns_window);
+ return desc;
+#elif defined(DAWN_USE_WAYLAND) || defined(DAWN_USE_X11)
+#if defined(GLFW_PLATFORM_WAYLAND) && defined(DAWN_USE_WAYLAND)
+ if (glfwGetPlatform() == GLFW_PLATFORM_WAYLAND) {
+ auto desc = std::make_unique<wgpu::SurfaceSourceWaylandSurface>();
+ desc->display = glfwGetWaylandDisplay();
+ desc->surface = glfwGetWaylandWindow(window);
+ return desc;
+ } else // NOLINT(readability/braces)
+#endif
+#if defined(DAWN_USE_X11)
+ {
+ auto desc = std::make_unique<wgpu::SurfaceSourceXlibWindow>();
+ desc->display = glfwGetX11Display();
+ desc->window = glfwGetX11Window(window);
+ return desc;
+ }
+#else
+ {
+ return nullptr;
+ }
+#endif
+#else
+ return nullptr;
+#endif
+}
+
+wgpu::Surface create_surface(const wgpu::Instance &instance, GLFWwindow *window) {
+ auto chainedDescriptor = setup_window_and_get_surface_descriptor(window);
+ wgpu::SurfaceDescriptor descriptor;
+ descriptor.nextInChain = chainedDescriptor.get();
+ wgpu::Surface surface = instance.CreateSurface(&descriptor);
+ return surface;
+}