Add a target for the GLFW surface helper.

This CL moves the GLFWUtils.cpp into a dawn/glfw/utils.cpp and
GLFWUtils.h into include/webgpu/webgpu_glfw.h. A build target
(`webgpu_glfw` alias to `dawn_glfw`) is added in order to allow
using that target in downstream projects without having to re-implement.

Change-Id: I93e85d5af3f486b3c754f2f854aafbda51901d6d
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/98700
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Dan Sinclair <dsinclair@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
dan sinclair 2022-08-14 15:59:25 +00:00 committed by Dawn LUCI CQ
parent fe835738c5
commit 52cc4f5d1c
18 changed files with 158 additions and 191 deletions

View File

@ -1,4 +1,4 @@
// Copyright 2020 The Dawn Authors
// Copyright 2022 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,27 +12,47 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SRC_DAWN_UTILS_GLFWUTILS_H_
#define SRC_DAWN_UTILS_GLFWUTILS_H_
#ifndef INCLUDE_WEBGPU_WEBGPU_GLFW_H_
#define INCLUDE_WEBGPU_WEBGPU_GLFW_H_
#include <memory>
#include "dawn/webgpu_cpp.h"
#include "webgpu/webgpu_cpp.h"
#if defined(WGPU_GLFW_SHARED_LIBRARY)
#if defined(_WIN32)
#if defined(WGPU_GLFW_IMPLEMENTATION)
#define WGPU_GLFW_EXPORT __declspec(dllexport)
#else
#define WGPU_GLFW_EXPORT __declspec(dllimport)
#endif
#else // defined(_WIN32)
#if defined(WGPU_GLFW_IMPLEMENTATION)
#define WGPU_GLFW_EXPORT __attribute__((visibility("default")))
#else
#define WGPU_GLFW_EXPORT
#endif
#endif // defined(_WIN32)
#else // defined(WGPU_GLFW_SHARED_LIBRARY)
#define WGPU_GLFW_EXPORT
#endif // defined(WGPU_GLFW_SHARED_LIBRARY)
struct GLFWwindow;
namespace utils {
namespace wgpu::glfw {
// Does the necessary setup on the GLFWwindow to allow creating a wgpu::Surface with it and
// calls `instance.CreateSurface` with the correct descriptor for this window.
// Returns a null wgpu::Surface on failure.
wgpu::Surface CreateSurfaceForWindow(const wgpu::Instance& instance, GLFWwindow* window);
WGPU_GLFW_EXPORT wgpu::Surface CreateSurfaceForWindow(const wgpu::Instance& instance,
GLFWwindow* window);
// Use for testing only. Does everything that CreateSurfaceForWindow does except the call to
// CreateSurface. Useful to be able to modify the descriptor for testing, or when trying to
// avoid using the global proc table.
std::unique_ptr<wgpu::ChainedStruct> SetupWindowAndGetSurfaceDescriptor(GLFWwindow* window);
WGPU_GLFW_EXPORT std::unique_ptr<wgpu::ChainedStruct> SetupWindowAndGetSurfaceDescriptor(
GLFWwindow* window);
} // namespace utils
} // namespace wgpu::glfw
#endif // SRC_DAWN_UTILS_GLFWUTILS_H_
#endif // INCLUDE_WEBGPU_WEBGPU_GLFW_H_

View File

@ -22,6 +22,7 @@ add_subdirectory(native)
add_subdirectory(wire)
# TODO(dawn:269): Remove once the implementation-based swapchains are removed.
add_subdirectory(utils)
add_subdirectory(glfw)
if (DAWN_BUILD_SAMPLES)
#TODO(dawn:269): Add this once implementation-based swapchains are removed.

51
src/dawn/glfw/BUILD.gn Normal file
View File

@ -0,0 +1,51 @@
# Copyright 2022 The Dawn Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import("../../../scripts/dawn_overrides_with_defaults.gni")
import("${dawn_root}/scripts/dawn_component.gni")
import("${dawn_root}/scripts/dawn_features.gni")
###############################################################################
# GLFW utils
###############################################################################
if (dawn_supports_glfw_for_windowing) {
static_library("glfw") {
defines = [ "WGPU_GLFW_IMPLEMENTATION" ]
sources = [ "utils.cpp" ]
deps = [
"${dawn_root}/src/dawn:cpp",
"${dawn_root}/src/dawn:proc",
"${dawn_root}/src/dawn/common",
]
if (dawn_enable_metal) {
sources += [ "utils_metal.mm" ]
frameworks = [
"Metal.framework",
"QuartzCore.framework",
]
}
public_deps = [
"${dawn_root}/include/dawn:cpp_headers",
"${dawn_root}/third_party/gn/glfw",
]
}
} else {
group("glfw") {
}
}

View File

@ -0,0 +1,45 @@
# Copyright 2022 The Dawn Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
if(DAWN_SUPPORTS_GLFW_FOR_WINDOWING)
add_library(dawn_glfw STATIC ${DAWN_PLACEHOLDER_FILE})
common_compile_options(dawn_glfw)
target_sources(dawn_glfw PRIVATE
"utils.cpp"
)
target_link_libraries(dawn_glfw
PUBLIC
glfw
dawncpp_headers
dawn_common
PRIVATE
dawn_internal_config
)
target_compile_definitions(dawn_glfw PRIVATE "WGPU_IMPLEMENTATION")
if(BUILD_SHARED_LIBS)
target_compile_definitions(dawn_glfw PRIVATE "WGPU_SHARED_LIBRARY")
endif()
if (DAWN_ENABLE_METAL)
target_link_libraries(dawn_glfw PRIVATE "-framework Metal")
target_sources(dawn_glfw PRIVATE
"utils_metal.mm"
)
endif()
add_library(webgpu_glfw ALIAS dawn_glfw)
endif()

5
src/dawn/glfw/README.md Normal file
View File

@ -0,0 +1,5 @@
In order to use Dawn WebGPU implementation with GLFW there is some
boilerplate code needed in order to create the WebGPU surface. This repo
contains an implementation of that boilerplate which can be used by
downstream applications. It can also serve as an example of how to
integrate Dawn and GLFW if there is desire to not use this helper.

View File

@ -13,11 +13,12 @@
// limitations under the License.
#include <cstdlib>
#include <memory>
#include <utility>
#include "GLFW/glfw3.h"
#include "dawn/common/Platform.h"
#include "dawn/utils/GLFWUtils.h"
#include "webgpu/webgpu_glfw.h"
#if DAWN_PLATFORM_IS(WINDOWS)
#define GLFW_EXPOSE_NATIVE_WIN32
@ -30,7 +31,7 @@
#endif
#include "GLFW/glfw3native.h"
namespace utils {
namespace wgpu::glfw {
wgpu::Surface CreateSurfaceForWindow(const wgpu::Instance& instance, GLFWwindow* window) {
std::unique_ptr<wgpu::ChainedStruct> chainedDescriptor =
@ -81,4 +82,4 @@ std::unique_ptr<wgpu::ChainedStruct> SetupWindowAndGetSurfaceDescriptor(GLFWwind
#endif
}
} // namespace utils
} // namespace wgpu::glfw

View File

@ -13,10 +13,10 @@
// limitations under the License.
#if !defined(DAWN_ENABLE_BACKEND_METAL)
#error "GLFWUtils_metal.mm requires the Metal backend to be enabled."
#error "utils_metal.mm requires the Metal backend to be enabled."
#endif // !defined(DAWN_ENABLE_BACKEND_METAL)
#include "dawn/utils/GLFWUtils.h"
#include "webgpu/webgpu_glfw.h"
#import <QuartzCore/CAMetalLayer.h>
#include "GLFW/glfw3.h"
@ -26,7 +26,7 @@
#define GLFW_EXPOSE_NATIVE_COCOA
#include "GLFW/glfw3native.h"
namespace utils {
namespace wgpu::glfw {
std::unique_ptr<wgpu::ChainedStruct> SetupWindowAndGetSurfaceDescriptorCocoa(GLFWwindow* window) {
NSWindow* nsWindow = glfwGetCocoaWindow(window);
@ -46,4 +46,4 @@ std::unique_ptr<wgpu::ChainedStruct> SetupWindowAndGetSurfaceDescriptorCocoa(GLF
return std::move(desc);
}
} // namespace utils
} // namespace wgpu::glfw

View File

@ -36,10 +36,10 @@ static_library("utils") {
"${dawn_root}/src/dawn:cpp",
"${dawn_root}/src/dawn:proc_shared",
"${dawn_root}/src/dawn/common",
"${dawn_root}/src/dawn/glfw",
"${dawn_root}/src/dawn/native",
"${dawn_root}/src/dawn/utils",
"${dawn_root}/src/dawn/utils:bindings",
"${dawn_root}/src/dawn/utils:glfw",
"${dawn_root}/src/dawn/wire",
]
public_configs = [ "${dawn_root}/src/dawn/common:internal_config" ]

View File

@ -23,6 +23,7 @@ target_link_libraries(dawn_sample_utils PUBLIC
dawncpp
dawn_proc
dawn_common
dawn_glfw
dawn_native
dawn_wire
dawn_utils

View File

@ -63,10 +63,10 @@
#include "dawn/dawn_proc.h"
#include "dawn/native/DawnNative.h"
#include "dawn/utils/ComboRenderPipelineDescriptor.h"
#include "dawn/utils/GLFWUtils.h"
#include "dawn/utils/ScopedAutoreleasePool.h"
#include "dawn/utils/WGPUHelpers.h"
#include "dawn/webgpu_cpp.h"
#include "webgpu/webgpu_glfw.h"
struct WindowData {
GLFWwindow* window = nullptr;
@ -123,7 +123,7 @@ void AddWindow() {
std::unique_ptr<WindowData> data = std::make_unique<WindowData>();
data->window = window;
data->serial = windowSerial++;
data->surface = utils::CreateSurfaceForWindow(instance->Get(), window);
data->surface = wgpu::glfw::CreateSurfaceForWindow(instance->Get(), window);
data->currentDesc = descriptor;
data->targetDesc = descriptor;
SyncFromWindow(data.get());

View File

@ -28,10 +28,10 @@
#include "dawn/dawn_proc.h"
#include "dawn/dawn_wsi.h"
#include "dawn/native/DawnNative.h"
#include "dawn/utils/GLFWUtils.h"
#include "dawn/utils/TerribleCommandBuffer.h"
#include "dawn/wire/WireClient.h"
#include "dawn/wire/WireServer.h"
#include "webgpu/webgpu_glfw.h"
void PrintDeviceError(WGPUErrorType errorType, const char* message, void*) {
const char* errorTypeName = "";
@ -132,7 +132,7 @@ wgpu::Device CreateCppDawnDevice() {
DawnProcTable backendProcs = dawn::native::GetProcs();
// Create the swapchain
auto surfaceChainedDesc = utils::SetupWindowAndGetSurfaceDescriptor(window);
auto surfaceChainedDesc = wgpu::glfw::SetupWindowAndGetSurfaceDescriptor(window);
WGPUSurfaceDescriptor surfaceDesc;
surfaceDesc.nextInChain = reinterpret_cast<WGPUChainedStruct*>(surfaceChainedDesc.get());
WGPUSurface surface = backendProcs.instanceCreateSurface(instance->Get(), &surfaceDesc);

View File

@ -371,7 +371,7 @@ source_set("test_infra_sources") {
if (dawn_supports_glfw_for_windowing || dawn_enable_opengl) {
assert(dawn_supports_glfw_for_windowing)
public_deps += [ "${dawn_root}/src/dawn/utils:glfw" ]
public_deps += [ "${dawn_root}/src/dawn/glfw" ]
}
sources = [

View File

@ -16,8 +16,8 @@
#include "dawn/common/Constants.h"
#include "dawn/common/Log.h"
#include "dawn/utils/GLFWUtils.h"
#include "dawn/utils/WGPUHelpers.h"
#include "webgpu/webgpu_glfw.h"
#include "GLFW/glfw3.h"
@ -45,7 +45,7 @@ class SwapChainTests : public DawnTest {
int height;
glfwGetFramebufferSize(window, &width, &height);
surface = utils::CreateSurfaceForWindow(GetInstance(), window);
surface = wgpu::glfw::CreateSurfaceForWindow(GetInstance(), window);
ASSERT_NE(surface, nullptr);
baseDescriptor.width = width;

View File

@ -17,8 +17,8 @@
#include "dawn/common/Constants.h"
#include "dawn/common/Log.h"
#include "dawn/utils/ComboRenderPipelineDescriptor.h"
#include "dawn/utils/GLFWUtils.h"
#include "dawn/utils/WGPUHelpers.h"
#include "webgpu/webgpu_glfw.h"
#include "GLFW/glfw3.h"
@ -38,7 +38,7 @@ class SwapChainValidationTests : public DawnTest {
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
window = glfwCreateWindow(400, 400, "SwapChainValidationTests window", nullptr, nullptr);
surface = utils::CreateSurfaceForWindow(GetInstance(), window);
surface = wgpu::glfw::CreateSurfaceForWindow(GetInstance(), window);
ASSERT_NE(surface, nullptr);
goodDescriptor.width = 1;

View File

@ -20,8 +20,8 @@
#include "dawn/dawn_proc.h"
#include "dawn/native/DawnNative.h"
#include "dawn/tests/DawnTest.h"
#include "dawn/utils/GLFWUtils.h"
#include "gtest/gtest.h"
#include "webgpu/webgpu_glfw.h"
// Include windows.h before GLFW so GLFW's APIENTRY macro doesn't conflict with windows.h's.
#if DAWN_PLATFORM_IS(WINDOWS)
@ -84,7 +84,7 @@ class WindowSurfaceInstanceTests : public testing::Test {
TEST_F(WindowSurfaceInstanceTests, ControlCase) {
GLFWwindow* window = CreateWindow();
std::unique_ptr<wgpu::ChainedStruct> chainedDescriptor =
utils::SetupWindowAndGetSurfaceDescriptor(window);
wgpu::glfw::SetupWindowAndGetSurfaceDescriptor(window);
wgpu::SurfaceDescriptor descriptor;
descriptor.nextInChain = chainedDescriptor.get();
@ -126,9 +126,9 @@ TEST_F(WindowSurfaceInstanceTests, HTMLCanvasDescriptor) {
TEST_F(WindowSurfaceInstanceTests, TwoChainedDescriptors) {
GLFWwindow* window = CreateWindow();
std::unique_ptr<wgpu::ChainedStruct> chainedDescriptor1 =
utils::SetupWindowAndGetSurfaceDescriptor(window);
wgpu::glfw::SetupWindowAndGetSurfaceDescriptor(window);
std::unique_ptr<wgpu::ChainedStruct> chainedDescriptor2 =
utils::SetupWindowAndGetSurfaceDescriptor(window);
wgpu::glfw::SetupWindowAndGetSurfaceDescriptor(window);
wgpu::SurfaceDescriptor descriptor;
descriptor.nextInChain = chainedDescriptor1.get();
@ -143,7 +143,7 @@ TEST_F(WindowSurfaceInstanceTests, TwoChainedDescriptors) {
TEST_F(WindowSurfaceInstanceTests, CorrectSTypeHWND) {
GLFWwindow* window = CreateWindow();
std::unique_ptr<wgpu::ChainedStruct> chainedDescriptor =
utils::SetupWindowAndGetSurfaceDescriptor(window);
wgpu::glfw::SetupWindowAndGetSurfaceDescriptor(window);
ASSERT_EQ(chainedDescriptor->sType, wgpu::SType::SurfaceDescriptorFromWindowsHWND);
}
@ -179,7 +179,7 @@ TEST_F(WindowSurfaceInstanceTests, HWNDSurfacesAreInvalid) {
TEST_F(WindowSurfaceInstanceTests, CorrectSTypeXlib) {
GLFWwindow* window = CreateWindow();
std::unique_ptr<wgpu::ChainedStruct> chainedDescriptor =
utils::SetupWindowAndGetSurfaceDescriptor(window);
wgpu::glfw::SetupWindowAndGetSurfaceDescriptor(window);
ASSERT_EQ(chainedDescriptor->sType, wgpu::SType::SurfaceDescriptorFromXlibWindow);
}
@ -219,7 +219,7 @@ TEST_F(WindowSurfaceInstanceTests, XlibSurfacesAreInvalid) {
TEST_F(WindowSurfaceInstanceTests, CorrectSTypeMetal) {
GLFWwindow* window = CreateWindow();
std::unique_ptr<wgpu::ChainedStruct> chainedDescriptor =
utils::SetupWindowAndGetSurfaceDescriptor(window);
wgpu::glfw::SetupWindowAndGetSurfaceDescriptor(window);
ASSERT_EQ(chainedDescriptor->sType, wgpu::SType::SurfaceDescriptorFromMetalLayer);
}

View File

@ -16,48 +16,6 @@ import("../../../scripts/dawn_overrides_with_defaults.gni")
import("${dawn_root}/scripts/dawn_features.gni")
###############################################################################
# GLFW wrapping target
###############################################################################
# GLFW does not support ChromeOS, Android or Fuchsia, so provide a small mock
# library that can be linked into the Dawn tests on these platforms. Otherwise,
# use the real library from third_party/.
if (dawn_supports_glfw_for_windowing) {
group("glfw") {
public_deps = [ "${dawn_root}/third_party/gn/glfw" ]
}
} else if (is_fuchsia) {
# The mock implementation of GLFW on Fuchsia
config("glfw_public_config") {
# Allow inclusion of <GLFW/glfw3.h>
include_dirs = [ "${dawn_glfw_dir}/include" ]
# The GLFW/glfw3.h header includes <GL/gl.h> by default, but the latter
# does not exist on Fuchsia. Defining GLFW_INCLUDE_NONE helps work around
# the issue, but it needs to be defined for any file that includes the
# header.
defines = [
"GLFW_INCLUDE_NONE",
"GLFW_INCLUDE_VULKAN",
]
}
static_library("glfw") {
sources = [
# NOTE: The header below is required to pass "gn check".
"${dawn_glfw_dir}/include/GLFW/glfw3.h",
"Glfw3Fuchsia.cpp",
]
public_configs = [ ":glfw_public_config" ]
deps = [ "${dawn_root}/src/dawn/common" ]
}
} else {
# Just skip GLFW on other systems
group("glfw") {
}
}
###############################################################################
# Utils for tests and samples
###############################################################################
@ -121,19 +79,6 @@ static_library("utils") {
sources += [ "ScopedAutoreleasePool.cpp" ]
}
if (dawn_supports_glfw_for_windowing) {
sources += [
"GLFWUtils.cpp",
"GLFWUtils.h",
]
deps += [ ":glfw" ]
if (dawn_enable_metal) {
sources += [ "GLFWUtils_metal.mm" ]
frameworks += [ "Metal.framework" ]
}
}
public_deps = [ "${dawn_root}/include/dawn:cpp_headers" ]
}
@ -154,8 +99,8 @@ if (dawn_standalone) {
public_deps = [ "${dawn_root}/include/dawn:headers" ]
deps = [
":glfw",
"${dawn_root}/src/dawn/common",
"${dawn_root}/src/dawn/glfw",
"${dawn_root}/src/dawn/native",
]
libs = []

View File

@ -73,8 +73,6 @@ if(DAWN_SUPPORTS_GLFW_FOR_WINDOWING)
target_sources(dawn_utils PRIVATE
"BackendBinding.cpp"
"BackendBinding.h"
"GLFWUtils.cpp"
"GLFWUtils.h"
)
target_link_libraries(dawn_utils PRIVATE glfw)
@ -84,7 +82,6 @@ if(DAWN_SUPPORTS_GLFW_FOR_WINDOWING)
if (DAWN_ENABLE_METAL)
target_sources(dawn_utils PRIVATE
"GLFWUtils_metal.mm"
"MetalBinding.mm"
)
endif()

View File

@ -1,99 +0,0 @@
// Copyright 2019 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// A mock GLFW implementation that supports Fuchsia, but only implements
// the functions called from Dawn.
#include <dlfcn.h>
// NOTE: This must be included before GLFW/glfw3.h because the latter will
// include <vulkan/vulkan.h> and "common/vulkan_platform.h" wants to be
// the first header to do so for validity reasons (e.g. undefining weird
// macros on Windows and Linux).
// clang-format off
#include "dawn/common/vulkan_platform.h"
#include "dawn/common/Assert.h"
#include "GLFW/glfw3.h"
// clang-format on
int glfwInit(void) {
return GLFW_TRUE;
}
void glfwDefaultWindowHints(void) {}
void glfwWindowHint(int hint, int value) {
DAWN_UNUSED(hint);
DAWN_UNUSED(value);
}
struct GLFWwindow {
PFN_vkGetInstanceProcAddr GetInstanceProcAddress = nullptr;
void* vulkan_loader = nullptr;
GLFWwindow() {
vulkan_loader = ::dlopen("libvulkan.so", RTLD_NOW);
ASSERT(vulkan_loader != nullptr);
GetInstanceProcAddress = reinterpret_cast<PFN_vkGetInstanceProcAddr>(
dlsym(vulkan_loader, "vkGetInstanceProcAddr"));
ASSERT(GetInstanceProcAddress != nullptr);
}
~GLFWwindow() {
if (vulkan_loader) {
::dlclose(vulkan_loader);
}
vulkan_loader = nullptr;
}
};
GLFWwindow* glfwCreateWindow(int width,
int height,
const char* title,
GLFWmonitor* monitor,
GLFWwindow* share) {
ASSERT(monitor == nullptr);
ASSERT(share == nullptr);
DAWN_UNUSED(width);
DAWN_UNUSED(height);
DAWN_UNUSED(title);
return new GLFWwindow();
}
VkResult glfwCreateWindowSurface(VkInstance instance,
GLFWwindow* window,
const VkAllocationCallbacks* allocator,
VkSurfaceKHR* surface) {
// IMPORTANT: This assumes that the VkInstance was created with a Fuchsia
// swapchain layer enabled, as well as the corresponding extension that
// is queried here to perform the surface creation. Dawn should do all
// required steps in VulkanInfo.cpp, VulkanFunctions.cpp and BackendVk.cpp.
auto vkCreateImagePipeSurfaceFUCHSIA = reinterpret_cast<PFN_vkCreateImagePipeSurfaceFUCHSIA>(
window->GetInstanceProcAddress(instance, "vkCreateImagePipeSurfaceFUCHSIA"));
ASSERT(vkCreateImagePipeSurfaceFUCHSIA != nullptr);
if (!vkCreateImagePipeSurfaceFUCHSIA) {
*surface = VK_NULL_HANDLE;
return VK_ERROR_FEATURE_NOT_PRESENT;
}
const struct VkImagePipeSurfaceCreateInfoFUCHSIA create_info = {
VK_STRUCTURE_TYPE_IMAGEPIPE_SURFACE_CREATE_INFO_FUCHSIA,
nullptr, // pNext
0, // flags, ignored for now
ZX_HANDLE_INVALID, // imagePipeHandle, a null handle matches the framebuffer.
};
return vkCreateImagePipeSurfaceFUCHSIA(instance, &create_info, nullptr, surface);
}