Vulkan Window window Surface

Hello everyone, the next will introduce Vulkan Window Surface  .

VulkanIs a free platform features associated with the APIcollection. It can not interact directly with the window system. In order to render the results are presented to the screen, you need to establish Vulkana connection between the window system, we need to use WSI(a form of system integration) extension. In this section, we will discuss first, that VK_KHR_surface . It exposes VkSurfaceKHR , it represents surfacea type of abstract, to present the rendered image to use. We want to use in the program to surfacebe introduced by our already GLFWextended its associated open form of support. In simple terms surface is connected to form a bridge Vulkan system.

VK_KHR_surface extension is an instance-level extension, so far we've had it enabled, it is included in glfwGetRequiredInstanceExtensions returned list. The list also includes a number of other WSI extension will use in the next few panels.

You need to instancecreate a form immediately after creation surface, because it will affect the choice of a physical device. The reason why this section will surfacecreate logic included in the discussions, is because the form surfacefor rendering, presentation is a relatively big problem, if premature creating a physical device to join this part, will confuse the basic physical device settings work. In addition the form surfaceitself to Vulkanalso not compulsory. VulkanAllowed to do so, it does not need the same OpenGLas is necessary to create a form surface.

First, create a Window Surface

Now set out to create a form surface, a class member debugCallbackto join members of the variables under Surface .

VkSurfaceKHR surface;

Although VkSurfaceKHR object and its use is not associated with the platform, but the details need to rely on the creation of a specific form of the system. For example, in the Windowsplatform, it takes WIndowson the HWND and HMODULE handle. Thus providing the appropriate extension for a particular platform, in Windowsthe as VK_KHR_win32_surface , it is automatically included in glfwGetRequiredInstanceExtensions list.

We will demonstrate how to use the platform-specific extensions to create Windowson the surfacebridge, but does not actually use it in the tutorial. The use of such libraries GLFW avoid writing no sense of cross-platform-dependent code. GLFWIn fact by glfwCreateWindowSurface a good deal of difference platform. Of course, the ideal is to rely on them to help us before the completion of specific work, look behind the realization is helpful.

Because a form surfaceis a Vulkansubject that needs filling VkWin32SurfaceCreateInfoKHR structure, there are two important parameters: HWND and hInstance . If you are familiar windowsunder development you should know that these are the window handle and process.

VkWin32SurfaceCreateInfoKHR createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
createInfo.hwnd = glfwGetWin32Window(window);
createInfo.hinstance = GetModuleHandle(nullptr);

glfwGetWin32Window function is used to obtain the original form object from GLFW the HWND . GetModuleHandle function returns the current process HINSTANCE handle.

After completion of the filling structure, you can use vkCreateWin32SurfaceKHR create surface bridge, and before obtaining create, destroy DebugReportCallEXT , as here, the same need to instancecreate get surfacein function. Here are the parameters involved instancesurfaceinformation created, custom allocator and ultimately save surfacehandle variables.

auto CreateWin32SurfaceKHR = (PFN_vkCreateWin32SurfaceKHR) vkGetInstanceProcAddr(instance, "vkCreateWin32SurfaceKHR");

if (!CreateWin32SurfaceKHR || CreateWin32SurfaceKHR(instance, &createInfo, nullptr, &surface) != VK_SUCCESS) {
    throw std::runtime_error("failed to create window surface!");
}

This process is similar to the other platforms, for example Linux, using the X11 interface window system, by vkCreateXcbSurfaceKHR establish a connection function.

glfwCreateWindowSurface function according to the difference of different platforms, on the implementation details will be different. We will now integrate them into our program. From initVulkan add a function CreateSurface , arranged in createInstnace and setupDebugCallback after the function.

void initVulkan() {
    createInstance();
    setupDebugCallback();
    createSurface();
    pickPhysicalDevice();
    createLogicalDevice();
}

void createSurface() {

}

GLFWDo not use the structure, but chose a very direct parameters passed to the calling function.

void createSurface() {
    if (glfwCreateWindowSurface(instance, window, nullptr, &surface) != VK_SUCCESS) {
        throw std::runtime_error("failed to create window surface!");
    }
}

Parameter is VkInstance , GLFWthe form of the pointer, and a dispenser for storing custom VkSurfaceKHR variable pointer. Unified platform for different return VkResult . GLFWIt does not provide a dedicated function to destroy surface, but simply by Vulkanthe original APIcompletion:

void cleanup() {
        ...
        vkDestroySurfaceKHR(instance, surface, nullptr);
        vkDestroyInstance(instance, nullptr);
        ...
    }

Finally, make sure to clean surface is completed before the instance is destroyed.

Second, the inquiry demonstrate support

Although the Vulkanimplementation of integrated functionality to support the form, but that does not mean each physical device in the system supports it. Therefore, we need to expand isDeviceSuitable function, ensure that the device can be rendered to the image we have created surface. Because presentationis a characteristic feature of the queue, so the solution to the problem is to find the support presentationof a cluster queue, queue finally get to meet the surfaceneed to create.

The reality is that support graphicscommand queue and cluster support presentationcommand queue cluster may not be the same cluster. Therefore, we need to modify QueueFamilyIndices structure to support the differentiation of storage.

struct QueueFamilyIndices {
    int graphicsFamily = -1;
    int presentFamily = -1;

    bool isComplete() {
        return graphicsFamily >= 0 && presentFamily >= 0;
    }
};

Next, we modify findQueueFamilies function to find with presentationqueues cluster functions. Core code is used to check the function vkGetPhysicalDeviceSurfaceSupportKHR , it physical device, a queue and cluster index surfaceas parameters. In VK_QUEUE_GRAPHICS_BIT add a call to a function in the same loop:

VkBool32 presentSupport = false;
vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport);

Then the need to check a Boolean value and stored in presentationa queue clustered indexes:

if (queueFamily.queueCount > 0 && presentSupport) {
    indices.presentFamily = i;
}

Note that, in order to support graphicsand presentationfunctionality, our actual environment may be obtained in the same queue cluster, it may be different, for in our program structure and data selection logic will follow are from different clusters are processing queue , so that we can deal with the unified both cases. In addition, for performance reasons, we can also add logic to explicitly specify the physical equipment used graphicsand presentationfunctions from the same cluster queue.

Third, create a presentation queue

The remaining thing is to modify the logical device creation process is to create presentationthe queue and get VkQueue handle. Add save queue handle member variables:

VkQueue presentQueue;

Next, we need more VkDeviceQueueCreateInfo structures to create queues with different functions. An elegant way is to create a set collection to ensure the uniqueness of the queue for the queue clusters of clusters of different functions:

#include <set>

...

QueueFamilyIndices indices = findQueueFamilies(physicalDevice);

std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
std::set<int> uniqueQueueFamilies = {indices.graphicsFamily, indices.presentFamily};

float queuePriority = 1.0f;
for (int queueFamily : uniqueQueueFamilies) {
    VkDeviceQueueCreateInfo queueCreateInfo = {};
    queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
    queueCreateInfo.queueFamilyIndex = queueFamily;
    queueCreateInfo.queueCount = 1;
    queueCreateInfo.pQueuePriorities = &queuePriority;
    queueCreateInfos.push_back(queueCreateInfo);
}

But also modify VkDeviceCreateInfo point set of queues:

createInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());
createInfo.pQueueCreateInfos = queueCreateInfos.data();

If the queue is the same cluster, then we need to pass the time index. Finally, add a call to retrieve the queue handle:

vkGetDeviceQueue(device, indices.presentFamily, 0, &presentQueue);

In this example, the queue is the same cluster, the two handles may have the same value.

 

 

 

 

Published 53 original articles · won praise 62 · views 20000 +

Guess you like

Origin blog.csdn.net/u010281924/article/details/105369161