/* * Copyright 2025 Google LLC * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef skgpu_VulkanPreferredFeatures_DEFINED #define skgpu_VulkanPreferredFeatures_DEFINED #include "include/private/base/SkAPI.h" #include "include/private/gpu/vk/SkiaVulkan.h" #include #include #include namespace skgpu { class SK_API VulkanPreferredFeatures { public: ~VulkanPreferredFeatures(); /* * VulkanPreferredFeatures is used by Skia to add extensions and features on top of what the app * wants to enable. The flow of Vulkan initialization for an app that wants to use Skia would * be: * * ``` * // Query the loader for instance information, decide on API version to use * * // Prepare for Skia-enabled extensions and features * skgpu::VulkanPreferredFeatures skiaFeatures; * skiaFeatures.init(apiVersion); * * // Decide on instance extensions to use in the app. * * // Allow Skia to add to the instance extension list. * skiaFeatures.addToInstanceExtensions(...); * * // Create the instance, choose physical device, query available extensions, decide on * // device features to query * * // Allow Skia to add to the feature query list. * skiaFeatures.addFeaturesToQuery(...); * * // Query features, decide on extensions and features to enable. * * // Allow Skia to add to the device extension and feature list. * skiaFeatures.addFeaturesToEnable(...); * * // Create the Vulkan device. * ``` * * Parameters: * * * appAPIVersion: The API version the app has specified in VkApplicationInfo::apiVersion (and * will later provide in VulkanBackendContext::fMaxAPIVersion). The minimum supported version * is VK_API_VERSION_1_1, maximum is VK_API_VERSION_1_4. */ void init(uint32_t appAPIVersion); /* * Before creating a Vulkan instance, call addToInstanceExtensions to give Skia a chance to add * instance extensions it may take advantage of. Extensions are only added to appExtensions if * caller hasn't already included them to be enabled. * * Parameters: * * * instanceExtensions, instanceExtensionCount: The list of available instance extensions as * queried from the loader. * * appExtensions: The list of extensions to be enabled on the instance; more extensions may be * added to this list by this call. */ void addToInstanceExtensions(const VkExtensionProperties* instanceExtensions, size_t instanceExtensionCount, std::vector& appExtensions); /* * Before querying Vulkan device features, call addFeaturesToQuery to give Skia a chance to add * device extension features it may take advantage of to the query. Features are only added to * appFeatures if caller hasn't already included them in the query. * * Beware that the structs that get chained to appFeatures are member variables of this class, * so this object must not leave scope until feature query and device creation is complete. * * Parameters: * * * deviceExtensions, deviceExtensionCount: The list of available device extensions as queried * from the physical device. * * appFeatures: The features to be queried from the physical device; more features may be * added to the pNext chain by this call. */ void addFeaturesToQuery(const VkExtensionProperties* deviceExtensions, size_t deviceExtensionCount, VkPhysicalDeviceFeatures2& appFeatures); /* * Before creating the Vulkan device, call addFeaturesToEnable to give Skia a chance to add * device extensions and features it may take advantage of. Extensions and features are only * added to appExtensions and appFeatures respectively if caller hasn't already included them to * be enabled. This function may replace chained features with VkPhysicalDeviceVulkanNNFeatures * structs instead in order to add features. Features that are already enabled by the * application are retained in that case in the new struct. * * Parameters: * * * appExtensions: The list of extensions to be enabled on the device; more extensions may be * added to this list by this call. * * appFeatures: The features to be enabled on the device; more features may be * added to the pNext chain by this call. */ void addFeaturesToEnable(std::vector& appExtensions, VkPhysicalDeviceFeatures2& appFeatures); private: uint32_t fAPIVersion = 0; // Track what the application did, so warnings can be generated if the class is not // fully/correctly used. bool fHasAddedToInstanceExtensions = false; bool fHasAddedFeaturesToQuery = false; bool fHasAddedFeaturesToEnable = false; // The list of device features Skia is interested in. If any are included in // VkPhysicalDeviceFeatures2::pNext by the app, it is not included again by Skia. However, to // take best advantage of the Vulkan API, the app should not intentionally include these feature // structs only to forcefully disable the feature - this blocks Skia from leveraging it. // // When ambiguous, the extension name is included to determine which extension a feature struct // has come from. This is usually needed when addFeaturesToQuery has included a feature struct // that is present in multiple extensions (e.g. due to extension promotion). It is later used by // addFeaturesToEnable to know which extension to enable. // Available since Vulkan 1.2 VkPhysicalDeviceVulkan11Features fVulkan11 = {}; // Available since Vulkan 1.2 VkPhysicalDeviceVulkan12Features fVulkan12 = {}; // Available since Vulkan 1.3 VkPhysicalDeviceVulkan13Features fVulkan13 = {}; // Available since Vulkan 1.4 VkPhysicalDeviceVulkan14Features fVulkan14 = {}; // Feature of VK_EXT_rasterization_order_attachment_access or // VK_ARM_rasterization_order_attachment_access. VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT fRasterizationOrderAttachmentAccess = {}; const char* fRasterizationOrderAttachmentAccessExtension = nullptr; // Feature of VK_EXT_blend_operation_advanced VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT fBlendOperationAdvanced = {}; // Feature of VK_EXT_extended_dynamic_state VkPhysicalDeviceExtendedDynamicStateFeaturesEXT fExtendedDynamicState = {}; // Feature of VK_EXT_extended_dynamic_state2 VkPhysicalDeviceExtendedDynamicState2FeaturesEXT fExtendedDynamicState2 = {}; // Feature of VK_EXT_vertex_input_dynamic_state VkPhysicalDeviceVertexInputDynamicStateFeaturesEXT fVertexInputDynamicState = {}; // Feature of VK_EXT_graphics_pipeline_library VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT fGraphicsPipelineLibrary = {}; // Feature of VK_KHR_sampler_ycbcr_conversion or Vulkan 1.1 VkPhysicalDeviceSamplerYcbcrConversionFeatures fSamplerYcbcrConversion = {}; // Feature of VK_EXT_rgba10x6_formats VkPhysicalDeviceRGBA10X6FormatsFeaturesEXT fRGBA10x6Formats = {}; // Feature of VK_KHR_synchronization2 or Vulkan 1.3 VkPhysicalDeviceDynamicRenderingFeatures fSynchronization2 = {}; // Feature of VK_KHR_dynamic_rendering or Vulkan 1.3 VkPhysicalDeviceDynamicRenderingFeatures fDynamicRendering = {}; // Feature of VK_KHR_dynamic_rendering_local_read or Vulkan 1.4 VkPhysicalDeviceDynamicRenderingLocalReadFeatures fDynamicRenderingLocalRead = {}; // Feature of VK_EXT_multisampled_render_to_single_sampled VkPhysicalDeviceMultisampledRenderToSingleSampledFeaturesEXT fMultisampledRenderToSingleSampled = {}; // Feature of VK_EXT_host_image_copy or Vulkan 1.4 VkPhysicalDeviceHostImageCopyFeatures fHostImageCopy = {}; // Feature of VK_EXT_pipeline_creation_cache_control or Vulkan 1.3 VkPhysicalDevicePipelineCreationCacheControlFeatures fPipelineCreationCacheControl = {}; // Feature of VK_EXT_frame_boundary VkPhysicalDeviceFrameBoundaryFeaturesEXT fFrameBoundary = {}; // Extensions that don't have a feature: // VK_KHR_driver_properties or Vulkan 1.2 const char* fDriverPropertiesExtension = nullptr; // VK_KHR_create_renderpass2 or Vulkan 1.2 const char* fCreateRenderpass2Extension = nullptr; // VK_EXT_load_store_op_none, VK_KHR_load_store_op_none or Vulkan 1.4 const char* fLoadStoreOpNoneExtension = nullptr; // VK_EXT_conservative_rasterization const char* fConservativeRasterizationExtension = nullptr; #if defined(SK_BUILD_FOR_ANDROID) // VK_ANDROID_external_memory_android_hardware_buffer const char* fExternalMemoryAHardwareBufferExtension = nullptr; #endif // Extensions that the other extensions above depend on: // Dependency of VK_EXT_graphics_pipeline_library: VK_KHR_pipeline_library const char* fPipelineLibraryExtension = nullptr; // Dependencies of VK_EXT_host_image_copy: VK_KHR_copy_commands2, VK_KHR_format_feature_flags2 const char* fCopyCommands2Extension = nullptr; const char* fFormatFeatureFlags2Extension = nullptr; // Dependency of VK_EXT_multisampled_render_to_single_sampled: VK_KHR_depth_stencil_resolve const char* fDepthStencilResolveExtension = nullptr; #if defined(SK_BUILD_FOR_ANDROID) // Dependency of VK_ANDROID_external_memory_android_hardware_buffer: VK_EXT_queue_family_foreign const char* fQueueFamilyForeignExtension = nullptr; #endif }; } // namespace skgpu #endif // skgpu_VulkanPreferredFeatures_DEFINED