Creating a Surface#

The next step is to create the infrastructure that allows images to be presented to the display.

In Vulkan terms, a surface is an abstraction of the native surface or window that the user actually sees. It is defined in the VK_KHR_surface extension that was initialised when creating the instance.

The surface object must be created in one of several different ways depending on which platform the application deploys to. This is because the surface holds a connection to a platform-specific native window object. For example, an application running on Android needs to use the vkCreateAndroidSurfaceWindow() method. These functions are are part of Vulkan extensions which must initialised when the instance is created.

As an example, the initSurface() method uses a variety of pre-processor directives to select the correct code path. View in context.

void VulkanHelloAPI::initSurface()
{
    // For Win32.
#ifdef VK_USE_PLATFORM_WIN32_KHR

    // Declare and populate the Win32 surface creation info struct with Win32 window instance and window handles.
    VkWin32SurfaceCreateInfoKHR surfaceInfo = {};
    surfaceInfo.flags = 0;
    surfaceInfo.pNext = nullptr;
    surfaceInfo.hinstance = surfaceData.connection;
    surfaceInfo.hwnd = surfaceData.window;
    surfaceInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;

    // Create the surface that will be rendered on using the creation info defined above.
    debugAssertFunctionResult(vk::CreateWin32SurfaceKHR(appManager.instance, &surfaceInfo, nullptr, &appManager.surface), "Windows Surface Creation");
#endif

    // For Xlib.
#ifdef VK_USE_PLATFORM_XLIB_KHR
    // Declare and populate the Xlib surface creation info struct, passing the Xlib display and window handles.
    VkXlibSurfaceCreateInfoKHR surfaceInfo = {};
    surfaceInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
    surfaceInfo.flags = 0;
    surfaceInfo.pNext = nullptr;
    surfaceInfo.dpy = surfaceData.display;
    surfaceInfo.window = surfaceData.window;

    // Create the xlib surface that will be presented on using the creation info defined above.
    debugAssertFunctionResult(vk::CreateXlibSurfaceKHR(appManager.instance, &surfaceInfo, nullptr, &appManager.surface), "XLIB Surface Creation");
#endif

    // For Xcb.
#ifdef VK_USE_PLATFORM_XCB_KHR

    // Declare and populate the Xlib surface creation info struct, passing the Xcb display and window handles.
    VkXcbSurfaceCreateInfoKHR surfaceInfo = {};
    surfaceInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
    surfaceInfo.connection = surfaceData.connection;
    surfaceInfo.window = surfaceData.window;

    // Create the xcb surface that will be presented on.
    debugAssertFunctionResult(vk::CreateXcbSurfaceKHR(appManager.instance, &surfaceInfo, nullptr, &appManager.surface), "XCB Surface Creation");
#endif

    // For Android.
#ifdef VK_USE_PLATFORM_ANDROID_KHR

    // Declare and populate the Android surface creation info struct, passing the Android window handle.
    VkAndroidSurfaceCreateInfoKHR surfaceInfo = {};
    surfaceInfo.flags = 0;
    surfaceInfo.pNext = 0;
    surfaceInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
    surfaceInfo.window = surfaceData.window;

    // Create the Android surface that will be presented on using the creation info defined above.
    debugAssertFunctionResult(vk::CreateAndroidSurfaceKHR(appManager.instance, &surfaceInfo, nullptr, &appManager.surface), "Android Surface Creation");
#endif

    // For Wayland.
#ifdef VK_USE_PLATFORM_WAYLAND_KHR

    // Declare and populate the Wayland surface creation info struct, passing the Wayland display and surface handles.
    VkWaylandSurfaceCreateInfoKHR surfaceInfo = {};
    surfaceInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
    surfaceInfo.display = surfaceData.display;
    surfaceInfo.surface = surfaceData.surface;

    // Create the Wayland surface that will be presented on using the creation info defined above.
    debugAssertFunctionResult(vk::CreateWaylandSurfaceKHR(appManager.instance, &surfaceInfo, NULL, &appManager.surface), "Wayland Surface Creation");
#endif

    // For MoltenVK
#ifdef VK_USE_PLATFORM_MACOS_MVK

    // Create the macos surface info, passing the NSView handle
    VkMacOSSurfaceCreateInfoMVK surfaceInfo = {};
    surfaceInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK;
    surfaceInfo.pNext = 0;
    surfaceInfo.flags = 0;
    // pView must be a valid NSView and must be backed by a CALayer instance of type CAMetalLayer.
    surfaceInfo.pView = surfaceData.view;

    // Create the macos surface that will be presented on.
    debugAssertFunctionResult(vk::CreateMacOSSurfaceMVK(appManager.instance, &surfaceInfo, NULL, &appManager.surface), "MacOS Surface Creation");
#endif

    // For NullWS
#ifdef USE_PLATFORM_NULLWS

    VkDisplayPropertiesKHR properties;
    uint32_t propertiesCount = 1;
    if (vk::GetPhysicalDeviceDisplayPropertiesKHR) { lastRes = vk::GetPhysicalDeviceDisplayPropertiesKHR(appManager.physicalDevice, &propertiesCount, &properties); }

    std::string supportedTransforms;
    if (properties.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) { supportedTransforms.append("none "); }
    if (properties.supportedTransforms & VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR) { supportedTransforms.append("rot90 "); }
    if (properties.supportedTransforms & VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR) { supportedTransforms.append("rot180 "); }
    if (properties.supportedTransforms & VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR) { supportedTransforms.append("rot270 "); }
    if (properties.supportedTransforms & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR) { supportedTransforms.append("h_mirror "); }
    if (properties.supportedTransforms & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR) { supportedTransforms.append("h_mirror+rot90 "); }
    if (properties.supportedTransforms & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR) { supportedTransforms.append("hmirror+rot180 "); }
    if (properties.supportedTransforms & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR) { supportedTransforms.append("hmirror+rot270 "); }
    if (properties.supportedTransforms & VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR) { supportedTransforms.append("inherit "); }

    VkDisplayKHR nativeDisplay = properties.display;

    uint32_t modeCount = 0;
    vk::GetDisplayModePropertiesKHR(appManager.physicalDevice, nativeDisplay, &modeCount, NULL);
    std::vector<VkDisplayModePropertiesKHR> modeProperties;
    modeProperties.resize(modeCount);
    vk::GetDisplayModePropertiesKHR(appManager.physicalDevice, nativeDisplay, &modeCount, modeProperties.data());

    VkDisplaySurfaceCreateInfoKHR surfaceInfo = {};

    surfaceInfo.sType = VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR;
    surfaceInfo.pNext = NULL;

    surfaceInfo.displayMode = modeProperties[0].displayMode;
    surfaceInfo.planeIndex = 0;
    surfaceInfo.planeStackIndex = 0;
    surfaceInfo.transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
    surfaceInfo.globalAlpha = 0.0f;
    surfaceInfo.alphaMode = VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR;
    surfaceInfo.imageExtent = modeProperties[0].parameters.visibleRegion;

    debugAssertFunctionResult(vk::CreateDisplayPlaneSurfaceKHR(appManager.instance, &surfaceInfo, nullptr, &appManager.surface), "Surface Creation");
#endif
    }