Ejemplo n.º 1
0
    def _create_physical_device(self):
        '''Create Vulkan physical device

        The best physical device is selected through criteria.
        '''

        physical_devices = vk.vkEnumeratePhysicalDevices(self.instance)

        if not physical_devices:
            msg = "No physical device found"
            logger.critical(msg)
            raise VulkError(msg)

        features = [
            vk.vkGetPhysicalDeviceFeatures(p) for p in physical_devices
        ]
        properties = [
            vk.vkGetPhysicalDeviceProperties(p) for p in physical_devices
        ]

        logger.debug("Available physical devices: %s",
                     [p.deviceName for p in properties])

        # Select best physical device based on properties ans features
        selected_index = 0
        best_score = 0
        for i, d in enumerate(physical_devices):
            score = 0

            # Discrete GPU is better
            if properties[i].deviceType == \
               vk.VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
                score += 1000

            score += properties[i].limits.maxImageDimension2D

            # Device must contain graphic and present queue family
            if not VulkContext._get_queue_families(
                    d, self.surface,
                    self.pfn['vkGetPhysicalDeviceSurfaceSupportKHR']):
                score = 0

            if score > best_score:
                best_score = score
                selected_index = i

        # No available physical device
        if best_score == 0:
            msg = "No available physical device"
            logger.critical(msg)
            raise VulkError(msg)

        # The best device is now selected_index
        self.physical_device = physical_devices[selected_index]
        self.physical_device_properties = properties[selected_index]
        self.physical_device_features = features[selected_index]

        logger.debug("%s device selected",
                     self.physical_device_properties.deviceName)
Ejemplo n.º 2
0
    def _get_instance_extensions(window, configuration):
        '''Get extensions which depend on the window and configuration

        *Parameters:*

        - `window`: The `VulkWindow`
        - `configuration`: Configuration from App

        *Returns:*

        Extension list
        '''

        # Get available extensions
        available_extensions = [
            e.extensionName
            for e in vk.vkEnumerateInstanceExtensionProperties(None)
        ]
        logger.debug("Available instance extensions: %s", available_extensions)

        # Compute needed extensions
        extension_mapping = {
            sdl2.SDL_SYSWM_X11: vk.VK_KHR_XLIB_SURFACE_EXTENSION_NAME,
            sdl2.SDL_SYSWM_WINDOWS: vk.VK_KHR_WIN32_SURFACE_EXTENSION_NAME,
            sdl2.SDL_SYSWM_WAYLAND: vk.VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME,
            sdl2.SDL_SYSWM_MIR: vk.VK_KHR_MIR_SURFACE_EXTENSION_NAME
        }
        sdl_subsystem = window.info.subsystem

        if sdl_subsystem not in extension_mapping:
            msg = "Vulkan not supported on this plateform: %s" % sdl_subsystem
            logger.critical(msg)
            raise VulkError(msg)

        # Select extension
        enabled_extensions = []
        enabled_extensions.append(vk.VK_KHR_SURFACE_EXTENSION_NAME)
        enabled_extensions.append(extension_mapping[sdl_subsystem])

        if configuration.debug:
            if vk.VK_EXT_DEBUG_REPORT_EXTENSION_NAME in available_extensions:
                enabled_extensions.append(
                    vk.VK_EXT_DEBUG_REPORT_EXTENSION_NAME)
            else:
                configuration.debug = False
                logger.warning("Vulkan debug extension not present and debug"
                               "mode asked, disabling debug mode")

        # Check extensions availability
        if not all(e in available_extensions for e in enabled_extensions):
            msg = "Vulkan extensions are not all available"
            logger.critical(msg)
            raise VulkError(msg)

        return enabled_extensions
Ejemplo n.º 3
0
    def _get_instance_extensions(self):
        """Get extensions which depend on the window

        Returns:
            Extensions list (list[str])
        """

        # Get available extensions
        available_extensions = [
            e.extensionName
            for e in vk.vkEnumerateInstanceExtensionProperties(None)
        ]
        logger.debug("Available instance extensions: %s", available_extensions)

        # Compute needed extensions
        extension_mapping = {
            sdl2.SDL_SYSWM_X11: vk.VK_KHR_XLIB_SURFACE_EXTENSION_NAME,
            sdl2.SDL_SYSWM_WINDOWS: vk.VK_KHR_WIN32_SURFACE_EXTENSION_NAME,
            sdl2.SDL_SYSWM_WAYLAND: vk.VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME,
            sdl2.SDL_SYSWM_MIR: vk.VK_KHR_MIR_SURFACE_EXTENSION_NAME
        }
        sdl_subsystem = self.window.info.subsystem

        if sdl_subsystem not in extension_mapping:
            msg = "Vulkan not supported on this plateform: %s" % sdl_subsystem
            logger.critical(msg)
            raise VulkError(msg)

        # Select extension
        enabled_extensions = []
        enabled_extensions.append(vk.VK_KHR_SURFACE_EXTENSION_NAME)
        enabled_extensions.append(extension_mapping[sdl_subsystem])

        if self.debug_enabled:
            if vk.VK_EXT_DEBUG_REPORT_EXTENSION_NAME in available_extensions:
                enabled_extensions.append(
                    vk.VK_EXT_DEBUG_REPORT_EXTENSION_NAME)
            else:
                self.debug_enabled = False
                logger.warning("Vulkan debug extension not present and debug"
                               "mode asked, disabling Vulkan debug mode")

        # Check extensions availability
        if not all(e in available_extensions for e in enabled_extensions):
            msg = "Vulkan extensions are not all available"
            logger.critical(msg)
            raise VulkError(msg)

        return enabled_extensions
Ejemplo n.º 4
0
 def add_pfn(name):
     try:
         self.pfn[name] = vk.vkGetInstanceProcAddr(self.instance, name)
     except ImportError:
         msg = "Can't get address of %s extension function" % name
         logger.critical(msg)
         raise VulkError(msg)
Ejemplo n.º 5
0
    def _get_device_extensions(physical_device):
        '''Get device extensions

        *Parameters:*

        - `physical_device`: The VkPhysicalDevice to check

        *Returns:*

        Extension list
        '''

        # Get available extensions
        available_extensions = [
            e.extensionName for e in vk.vkEnumerateDeviceExtensionProperties(
                physical_device, None)
        ]
        logger.debug("Available device extensions: %s", available_extensions)

        # Select extensions
        enabled_extensions = []
        enabled_extensions.append(vk.VK_KHR_SWAPCHAIN_EXTENSION_NAME)

        # Check extensions availability
        if not all(e in available_extensions for e in enabled_extensions):
            msg = "Vulkan extensions are not all available"
            logger.critical(msg)
            raise VulkError(msg)

        return enabled_extensions
Ejemplo n.º 6
0
    def _get_pfn(self, configuration):
        '''Get extension function pointers

        Get only functions used in `VulkContext`, vulkan instance must exist

        *Parameters:*

        - `configuration`: Configuration from Application
        '''

        if not self.instance:
            msg = "_create_instance must be called before _get_pfn"
            logger.critical(msg)
            raise VulkError(msg)

        def add_pfn(name):
            try:
                self.pfn[name] = vk.vkGetInstanceProcAddr(self.instance, name)
            except ImportError:
                msg = "Can't get address of %s extension function" % name
                logger.critical(msg)
                raise VulkError(msg)

        extension_functions = {
            'vkDestroySurfaceKHR', 'vkGetPhysicalDeviceSurfaceSupportKHR',
            'vkGetPhysicalDeviceSurfaceCapabilitiesKHR',
            'vkGetPhysicalDeviceSurfaceFormatsKHR',
            'vkGetPhysicalDeviceSurfacePresentModesKHR',
            'vkCreateSwapchainKHR', 'vkGetSwapchainImagesKHR',
            'vkAcquireNextImageKHR', 'vkQueuePresentKHR'
        }

        debug_extension_functions = {
            'vkCreateDebugReportCallbackEXT',
            'vkDestroyDebugReportCallbackEXT',
        }

        if configuration.debug:
            extension_functions.update(debug_extension_functions)

        for name in extension_functions:
            add_pfn(name)
Ejemplo n.º 7
0
    def _create_swapchain(self, configuration):
        '''Create Vulkan swapchain

        *Parameters:*

        - `configuration`: Configuration from Application
        '''
        surface_capabilities = self.pfn[
            'vkGetPhysicalDeviceSurfaceCapabilitiesKHR'](self.physical_device,
                                                         self.surface)  # noqa
        surface_formats = self.pfn['vkGetPhysicalDeviceSurfaceFormatsKHR'](
            self.physical_device, self.surface)  # noqa
        surface_present_modes = self.pfn[
            'vkGetPhysicalDeviceSurfacePresentModesKHR'](self.physical_device,
                                                         self.surface)  # noqa

        if not surface_formats or not surface_present_modes:
            msg = "No available swapchain"
            logger.critical(msg)
            raise VulkError(msg)

        def get_format(formats):
            for f in formats:
                if f.format == vk.VK_FORMAT_UNDEFINED:
                    return f
                if f.format == vk.VK_FORMAT_B8G8R8A8_UNORM and \
                   f.colorSpace == vk.VK_COLOR_SPACE_SRGB_NONLINEAR_KHR:
                    return f
            return formats[0]

        def get_present_mode(present_modes):
            for p in present_modes:
                if p == vk.VK_PRESENT_MODE_MAILBOX_KHR:
                    return p
            return vk.VK_PRESENT_MODE_FIFO_KHR

        def get_swap_extent(capabilities):
            uint32_max = 4294967295

            if capabilities.currentExtent.width != uint32_max:
                return capabilities.currentExtent

            width = max(
                capabilities.minImageExtent.width,
                min(capabilities.maxImageExtent.width, configuration.width))

            height = max(
                capabilities.minImageExtent.height,
                min(capabilities.maxImageExtent.height, configuration.height))

            return vk.VkExtent2D(width=width, height=height)

        surface_format = get_format(surface_formats)
        present_mode = get_present_mode(surface_present_modes)
        extent = get_swap_extent(surface_capabilities)

        # Try to create triple buffering
        image_count = surface_capabilities.minImageCount + 1
        if surface_capabilities.maxImageCount > 0 and \
           image_count > surface_capabilities.maxImageCount:
            image_count = surface_capabilities.maxImageCount

        sharing_mode = vk.VK_SHARING_MODE_EXCLUSIVE
        queue_family_indices = []
        if self.queue_family_indices['graphic'] != \
           self.queue_family_indices['present']:
            sharing_mode = vk.VK_SHARING_MODE_CONCURRENT
            queue_family_indices = [
                v for v in self.queue_family_indices.values()
            ]

        # Finally create swapchain
        swapchain_create = vk.VkSwapchainCreateInfoKHR(
            sType=vk.VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
            flags=0,
            surface=self.surface,
            minImageCount=image_count,
            imageFormat=surface_format.format,
            imageColorSpace=surface_format.colorSpace,
            imageExtent=extent,
            imageArrayLayers=1,
            imageUsage=vk.VK_IMAGE_USAGE_TRANSFER_DST_BIT,
            imageSharingMode=sharing_mode,
            queueFamilyIndexCount=len(queue_family_indices),
            pQueueFamilyIndices=queue_family_indices,
            compositeAlpha=vk.VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
            presentMode=present_mode,
            clipped=vk.VK_TRUE,
            oldSwapchain=None,
            preTransform=surface_capabilities.currentTransform)

        self.swapchain = self.pfn['vkCreateSwapchainKHR'](self.device,
                                                          swapchain_create)
        self.width = extent.width
        self.height = extent.height
        self.swapchain_format = surface_format.format

        swapchain_raw_images = self.pfn['vkGetSwapchainImagesKHR'](
            self.device, self.swapchain)

        self.swapchain_images = []
        for raw_image in swapchain_raw_images:
            # Put swapchain image in Image
            # It's a bad practice but for this specific use case, it's good
            img = vo.Image.__new__(vo.Image)
            img.image = raw_image
            img.format = surface_format.format
            img.width = self.width
            img.height = self.height
            img.depth = 1
            self.swapchain_images.append(img)

        # Update layout of all swapchain images to present khr
        for image in self.swapchain_images:
            with vo.immediate_buffer(self) as cmd:
                image.update_layout(cmd, vc.ImageLayout.UNDEFINED,
                                    vc.ImageLayout.PRESENT_SRC_KHR,
                                    vc.PipelineStage.TOP_OF_PIPE,
                                    vc.PipelineStage.TOP_OF_PIPE,
                                    vc.Access.NONE, vc.Access.MEMORY_READ)

        logger.debug("Swapchain created with %s images",
                     len(self.swapchain_images))
Ejemplo n.º 8
0
 def android():
     # TODO
     raise VulkError("Android not supported for now")