/* * Copyright 2019 Google LLC * SPDX-License-Identifier: MIT * * based in part on anv and radv which are: * Copyright © 2015 Intel Corporation * Copyright © 2016 Red Hat. * Copyright © 2016 Bas Nieuwenhuizen */ #include "vn_physical_device.h" #include #include "git_sha1.h" #include "util/mesa-sha1.h" #include "venus-protocol/vn_protocol_driver_device.h" #include "vk_android.h" #include "vn_android.h" #include "vn_instance.h" #define IMAGE_FORMAT_CACHE_MAX_ENTRIES 100 #define VN_EXTENSION_TABLE_INDEX(tbl, ext) \ ((const bool *)((const void *)(&(tbl)) + \ offsetof(__typeof__(tbl), ext)) - \ (tbl).extensions) /** Add `elem` to the pNext chain of `head`. */ #define VN_ADD_PNEXT(head, s_type, elem) \ do { \ (elem).sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_##s_type; \ (elem).pNext = (head).pNext; \ (head).pNext = &(elem); \ } while (0) /** * If the renderer supports the extension, add `elem` to the pNext chain of * `head`. */ #define VN_ADD_PNEXT_EXT(head, s_type, elem, ext_cond) \ do { \ if (ext_cond) \ VN_ADD_PNEXT((head), s_type, (elem)); \ } while (0) /** * Set member in core feature/property struct to value. (This provides visual * parity with VN_SET_CORE_FIELD). */ #define VN_SET_CORE_VALUE(core_struct, member, val) \ do { \ (core_struct)->member = (val); \ } while (0) /** Copy member into core feature/property struct from extension struct. */ #define VN_SET_CORE_FIELD(core_struct, member, ext_struct) \ VN_SET_CORE_VALUE((core_struct), member, (ext_struct).member) /** * Copy array member into core feature/property struct from extension struct. */ #define VN_SET_CORE_ARRAY(core_struct, member, ext_struct) \ do { \ memcpy((core_struct)->member, (ext_struct).member, \ sizeof((core_struct)->member)); \ } while (0) /** * Copy vk struct members to common vk properties. */ #define VN_SET_VK_PROPS(vk_props, vk_struct) \ do { \ vk_set_physical_device_properties_struct( \ (vk_props), (const VkBaseInStructure *)(vk_struct)); \ } while (0) /** * Copy vk struct members to common vk properties if extension is supported. */ #define VN_SET_VK_PROPS_EXT(vk_props, vk_struct, ext_cond) \ do { \ if (ext_cond) \ VN_SET_VK_PROPS(vk_props, vk_struct); \ } while (0) static void vn_physical_device_init_features(struct vn_physical_device *physical_dev) { const uint32_t renderer_version = physical_dev->renderer_version; const struct vk_device_extension_table *exts = &physical_dev->renderer_extensions; struct vn_ring *ring = physical_dev->instance->ring.ring; VkPhysicalDeviceFeatures2 feats2 = { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, }; struct { VkPhysicalDeviceFeatures vulkan_1_0; VkPhysicalDeviceVulkan11Features vulkan_1_1; VkPhysicalDeviceVulkan12Features vulkan_1_2; VkPhysicalDeviceVulkan13Features vulkan_1_3; /* Vulkan 1.1 */ VkPhysicalDevice16BitStorageFeatures _16bit_storage; VkPhysicalDeviceMultiviewFeatures multiview; VkPhysicalDeviceVariablePointersFeatures variable_pointers; VkPhysicalDeviceProtectedMemoryFeatures protected_memory; VkPhysicalDeviceSamplerYcbcrConversionFeatures sampler_ycbcr_conversion; VkPhysicalDeviceShaderDrawParametersFeatures shader_draw_parameters; /* Vulkan 1.2 */ VkPhysicalDevice8BitStorageFeatures _8bit_storage; VkPhysicalDeviceShaderAtomicInt64Features shader_atomic_int64; VkPhysicalDeviceShaderFloat16Int8Features shader_float16_int8; VkPhysicalDeviceDescriptorIndexingFeatures descriptor_indexing; VkPhysicalDeviceScalarBlockLayoutFeatures scalar_block_layout; VkPhysicalDeviceImagelessFramebufferFeatures imageless_framebuffer; VkPhysicalDeviceUniformBufferStandardLayoutFeatures uniform_buffer_standard_layout; VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures shader_subgroup_extended_types; VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures separate_depth_stencil_layouts; VkPhysicalDeviceHostQueryResetFeatures host_query_reset; VkPhysicalDeviceTimelineSemaphoreFeatures timeline_semaphore; VkPhysicalDeviceBufferDeviceAddressFeatures buffer_device_address; VkPhysicalDeviceVulkanMemoryModelFeatures vulkan_memory_model; /* Vulkan 1.3 */ VkPhysicalDeviceDynamicRenderingFeatures dynamic_rendering; VkPhysicalDeviceImageRobustnessFeatures image_robustness; VkPhysicalDeviceInlineUniformBlockFeatures inline_uniform_block; VkPhysicalDeviceMaintenance4Features maintenance4; VkPhysicalDevicePipelineCreationCacheControlFeatures pipeline_creation_cache_control; VkPhysicalDevicePrivateDataFeatures private_data; VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures shader_demote_to_helper_invocation; VkPhysicalDeviceShaderIntegerDotProductFeatures shader_integer_dot_product; VkPhysicalDeviceShaderTerminateInvocationFeatures shader_terminate_invocation; VkPhysicalDeviceSynchronization2Features synchronization2; VkPhysicalDeviceSubgroupSizeControlFeatures subgroup_size_control; VkPhysicalDeviceTextureCompressionASTCHDRFeatures texture_compression_astc_hdr; VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeatures zero_initialize_workgroup_memory; /* Vulkan 1.3: The extensions for the below structs were promoted, but * some struct members were omitted from * VkPhysicalDeviceVulkan13Features. */ VkPhysicalDevice4444FormatsFeaturesEXT _4444_formats; VkPhysicalDeviceExtendedDynamicStateFeaturesEXT extended_dynamic_state; VkPhysicalDeviceExtendedDynamicState2FeaturesEXT extended_dynamic_state_2; VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT texel_buffer_alignment; VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT ycbcr_2plane_444_formats; /* KHR */ VkPhysicalDeviceFragmentShadingRateFeaturesKHR fragment_shading_rate; VkPhysicalDeviceMaintenance5FeaturesKHR maintenance5; VkPhysicalDeviceShaderClockFeaturesKHR shader_clock; VkPhysicalDeviceShaderExpectAssumeFeaturesKHR expect_assume; /* EXT */ VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT attachment_feedback_loop_layout; VkPhysicalDeviceBorderColorSwizzleFeaturesEXT border_color_swizzle; VkPhysicalDeviceColorWriteEnableFeaturesEXT color_write_enable; VkPhysicalDeviceConditionalRenderingFeaturesEXT conditional_rendering; VkPhysicalDeviceCustomBorderColorFeaturesEXT custom_border_color; VkPhysicalDeviceDepthClipControlFeaturesEXT depth_clip_control; VkPhysicalDeviceDepthClipEnableFeaturesEXT depth_clip_enable; VkPhysicalDeviceDynamicRenderingUnusedAttachmentsFeaturesEXT dynamic_rendering_unused_attachments; VkPhysicalDeviceExtendedDynamicState3FeaturesEXT extended_dynamic_state_3; VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT fragment_shader_interlock; VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT graphics_pipeline_library; VkPhysicalDeviceImage2DViewOf3DFeaturesEXT image_2d_view_of_3d; VkPhysicalDeviceImageViewMinLodFeaturesEXT image_view_min_lod; VkPhysicalDeviceIndexTypeUint8FeaturesEXT index_type_uint8; VkPhysicalDeviceLineRasterizationFeaturesEXT line_rasterization; VkPhysicalDeviceMultiDrawFeaturesEXT multi_draw; VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT mutable_descriptor_type; VkPhysicalDeviceNonSeamlessCubeMapFeaturesEXT non_seamless_cube_map; VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT primitive_topology_list_restart; VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT primitives_generated_query; VkPhysicalDeviceProvokingVertexFeaturesEXT provoking_vertex; VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT rasterization_order_attachment_access; VkPhysicalDeviceRobustness2FeaturesEXT robustness_2; VkPhysicalDeviceTransformFeedbackFeaturesEXT transform_feedback; VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT vertex_attribute_divisor; VkPhysicalDeviceVertexInputDynamicStateFeaturesEXT vertex_input_dynamic_state; } local_feats; /* Clear the struct so that all unqueried features will be VK_FALSE. */ memset(&local_feats, 0, sizeof(local_feats)); assert(renderer_version >= VK_API_VERSION_1_1); /* clang-format off */ if (renderer_version >= VK_API_VERSION_1_2) { VN_ADD_PNEXT(feats2, VULKAN_1_1_FEATURES, local_feats.vulkan_1_1); VN_ADD_PNEXT(feats2, VULKAN_1_2_FEATURES, local_feats.vulkan_1_2); } else { /* Vulkan 1.1 */ VN_ADD_PNEXT(feats2, 16BIT_STORAGE_FEATURES, local_feats._16bit_storage); VN_ADD_PNEXT(feats2, MULTIVIEW_FEATURES, local_feats.multiview); VN_ADD_PNEXT(feats2, PROTECTED_MEMORY_FEATURES, local_feats.protected_memory); VN_ADD_PNEXT(feats2, SAMPLER_YCBCR_CONVERSION_FEATURES, local_feats.sampler_ycbcr_conversion); VN_ADD_PNEXT(feats2, SHADER_DRAW_PARAMETERS_FEATURES, local_feats.shader_draw_parameters); VN_ADD_PNEXT(feats2, VARIABLE_POINTERS_FEATURES, local_feats.variable_pointers); /* Vulkan 1.2 */ VN_ADD_PNEXT_EXT(feats2, 8BIT_STORAGE_FEATURES, local_feats._8bit_storage, exts->KHR_8bit_storage); VN_ADD_PNEXT_EXT(feats2, BUFFER_DEVICE_ADDRESS_FEATURES, local_feats.buffer_device_address, exts->KHR_buffer_device_address); VN_ADD_PNEXT_EXT(feats2, DESCRIPTOR_INDEXING_FEATURES, local_feats.descriptor_indexing, exts->EXT_descriptor_indexing); VN_ADD_PNEXT_EXT(feats2, HOST_QUERY_RESET_FEATURES, local_feats.host_query_reset, exts->EXT_host_query_reset); VN_ADD_PNEXT_EXT(feats2, IMAGELESS_FRAMEBUFFER_FEATURES, local_feats.imageless_framebuffer, exts->KHR_imageless_framebuffer); VN_ADD_PNEXT_EXT(feats2, SCALAR_BLOCK_LAYOUT_FEATURES, local_feats.scalar_block_layout, exts->EXT_scalar_block_layout); VN_ADD_PNEXT_EXT(feats2, SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES, local_feats.separate_depth_stencil_layouts, exts->KHR_separate_depth_stencil_layouts); VN_ADD_PNEXT_EXT(feats2, SHADER_ATOMIC_INT64_FEATURES, local_feats.shader_atomic_int64, exts->KHR_shader_atomic_int64); VN_ADD_PNEXT_EXT(feats2, SHADER_FLOAT16_INT8_FEATURES, local_feats.shader_float16_int8, exts->KHR_shader_float16_int8); VN_ADD_PNEXT_EXT(feats2, SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES, local_feats.shader_subgroup_extended_types, exts->KHR_shader_subgroup_extended_types); VN_ADD_PNEXT_EXT(feats2, TIMELINE_SEMAPHORE_FEATURES, local_feats.timeline_semaphore, exts->KHR_timeline_semaphore); VN_ADD_PNEXT_EXT(feats2, UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES, local_feats.uniform_buffer_standard_layout, exts->KHR_uniform_buffer_standard_layout); VN_ADD_PNEXT_EXT(feats2, VULKAN_MEMORY_MODEL_FEATURES, local_feats.vulkan_memory_model, exts->KHR_vulkan_memory_model); } if (renderer_version >= VK_API_VERSION_1_3) { VN_ADD_PNEXT(feats2, VULKAN_1_3_FEATURES, local_feats.vulkan_1_3); } else { VN_ADD_PNEXT_EXT(feats2, DYNAMIC_RENDERING_FEATURES, local_feats.dynamic_rendering, exts->KHR_dynamic_rendering); VN_ADD_PNEXT_EXT(feats2, IMAGE_ROBUSTNESS_FEATURES, local_feats.image_robustness, exts->EXT_image_robustness); VN_ADD_PNEXT_EXT(feats2, INLINE_UNIFORM_BLOCK_FEATURES, local_feats.inline_uniform_block, exts->EXT_inline_uniform_block); VN_ADD_PNEXT_EXT(feats2, MAINTENANCE_4_FEATURES, local_feats.maintenance4, exts->KHR_maintenance4); VN_ADD_PNEXT_EXT(feats2, PIPELINE_CREATION_CACHE_CONTROL_FEATURES, local_feats.pipeline_creation_cache_control, exts->EXT_pipeline_creation_cache_control); VN_ADD_PNEXT_EXT(feats2, PRIVATE_DATA_FEATURES, local_feats.private_data, exts->EXT_private_data); VN_ADD_PNEXT_EXT(feats2, SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES, local_feats.shader_demote_to_helper_invocation, exts->EXT_shader_demote_to_helper_invocation); VN_ADD_PNEXT_EXT(feats2, SHADER_INTEGER_DOT_PRODUCT_FEATURES, local_feats.shader_integer_dot_product, exts->KHR_shader_integer_dot_product); VN_ADD_PNEXT_EXT(feats2, SHADER_TERMINATE_INVOCATION_FEATURES, local_feats.shader_terminate_invocation, exts->KHR_shader_terminate_invocation); VN_ADD_PNEXT_EXT(feats2, SUBGROUP_SIZE_CONTROL_FEATURES, local_feats.subgroup_size_control, exts->EXT_subgroup_size_control); VN_ADD_PNEXT_EXT(feats2, SYNCHRONIZATION_2_FEATURES, local_feats.synchronization2, exts->KHR_synchronization2); VN_ADD_PNEXT_EXT(feats2, TEXTURE_COMPRESSION_ASTC_HDR_FEATURES, local_feats.texture_compression_astc_hdr, exts->EXT_texture_compression_astc_hdr); VN_ADD_PNEXT_EXT(feats2, ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES, local_feats.zero_initialize_workgroup_memory, exts->KHR_zero_initialize_workgroup_memory); } /* Vulkan 1.3: The extensions for the below structs were promoted, but some * struct members were omitted from VkPhysicalDeviceVulkan13Features. */ VN_ADD_PNEXT_EXT(feats2, 4444_FORMATS_FEATURES_EXT, local_feats._4444_formats, exts->EXT_4444_formats); VN_ADD_PNEXT_EXT(feats2, EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT, local_feats.extended_dynamic_state_2, exts->EXT_extended_dynamic_state2); VN_ADD_PNEXT_EXT(feats2, EXTENDED_DYNAMIC_STATE_FEATURES_EXT, local_feats.extended_dynamic_state, exts->EXT_extended_dynamic_state); VN_ADD_PNEXT_EXT(feats2, TEXEL_BUFFER_ALIGNMENT_FEATURES_EXT, local_feats.texel_buffer_alignment, exts->EXT_texel_buffer_alignment); VN_ADD_PNEXT_EXT(feats2, YCBCR_2_PLANE_444_FORMATS_FEATURES_EXT, local_feats.ycbcr_2plane_444_formats, exts->EXT_ycbcr_2plane_444_formats); /* KHR */ VN_ADD_PNEXT_EXT(feats2, FRAGMENT_SHADING_RATE_FEATURES_KHR, local_feats.fragment_shading_rate, exts->KHR_fragment_shading_rate); VN_ADD_PNEXT_EXT(feats2, SHADER_CLOCK_FEATURES_KHR, local_feats.shader_clock, exts->KHR_shader_clock); VN_ADD_PNEXT_EXT(feats2, SHADER_EXPECT_ASSUME_FEATURES_KHR, local_feats.expect_assume, exts->KHR_shader_expect_assume); VN_ADD_PNEXT_EXT(feats2, MAINTENANCE_5_FEATURES_KHR, local_feats.maintenance5, exts->KHR_maintenance5); /* EXT */ VN_ADD_PNEXT_EXT(feats2, ATTACHMENT_FEEDBACK_LOOP_LAYOUT_FEATURES_EXT, local_feats.attachment_feedback_loop_layout, exts->EXT_attachment_feedback_loop_layout); VN_ADD_PNEXT_EXT(feats2, BORDER_COLOR_SWIZZLE_FEATURES_EXT, local_feats.border_color_swizzle, exts->EXT_border_color_swizzle); VN_ADD_PNEXT_EXT(feats2, COLOR_WRITE_ENABLE_FEATURES_EXT, local_feats.color_write_enable, exts->EXT_color_write_enable); VN_ADD_PNEXT_EXT(feats2, CONDITIONAL_RENDERING_FEATURES_EXT, local_feats.conditional_rendering, exts->EXT_conditional_rendering); VN_ADD_PNEXT_EXT(feats2, CUSTOM_BORDER_COLOR_FEATURES_EXT, local_feats.custom_border_color, exts->EXT_custom_border_color); VN_ADD_PNEXT_EXT(feats2, DEPTH_CLIP_CONTROL_FEATURES_EXT, local_feats.depth_clip_control, exts->EXT_depth_clip_control); VN_ADD_PNEXT_EXT(feats2, DEPTH_CLIP_ENABLE_FEATURES_EXT, local_feats.depth_clip_enable, exts->EXT_depth_clip_enable); VN_ADD_PNEXT_EXT(feats2, DYNAMIC_RENDERING_UNUSED_ATTACHMENTS_FEATURES_EXT, local_feats.dynamic_rendering_unused_attachments, exts->EXT_dynamic_rendering_unused_attachments); VN_ADD_PNEXT_EXT(feats2, EXTENDED_DYNAMIC_STATE_3_FEATURES_EXT, local_feats.extended_dynamic_state_3, exts->EXT_extended_dynamic_state3); VN_ADD_PNEXT_EXT(feats2, FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT, local_feats.fragment_shader_interlock, exts->EXT_fragment_shader_interlock); VN_ADD_PNEXT_EXT(feats2, GRAPHICS_PIPELINE_LIBRARY_FEATURES_EXT, local_feats.graphics_pipeline_library, exts->EXT_graphics_pipeline_library); VN_ADD_PNEXT_EXT(feats2, IMAGE_2D_VIEW_OF_3D_FEATURES_EXT, local_feats.image_2d_view_of_3d, exts->EXT_image_2d_view_of_3d); VN_ADD_PNEXT_EXT(feats2, IMAGE_VIEW_MIN_LOD_FEATURES_EXT, local_feats.image_view_min_lod, exts->EXT_image_view_min_lod); VN_ADD_PNEXT_EXT(feats2, INDEX_TYPE_UINT8_FEATURES_EXT, local_feats.index_type_uint8, exts->EXT_index_type_uint8); VN_ADD_PNEXT_EXT(feats2, LINE_RASTERIZATION_FEATURES_EXT, local_feats.line_rasterization, exts->EXT_line_rasterization); VN_ADD_PNEXT_EXT(feats2, MULTI_DRAW_FEATURES_EXT, local_feats.multi_draw, exts->EXT_multi_draw); VN_ADD_PNEXT_EXT(feats2, MUTABLE_DESCRIPTOR_TYPE_FEATURES_EXT, local_feats.mutable_descriptor_type, exts->EXT_mutable_descriptor_type || exts->VALVE_mutable_descriptor_type); VN_ADD_PNEXT_EXT(feats2, NON_SEAMLESS_CUBE_MAP_FEATURES_EXT, local_feats.non_seamless_cube_map, exts->EXT_non_seamless_cube_map); VN_ADD_PNEXT_EXT(feats2, PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT, local_feats.primitive_topology_list_restart, exts->EXT_primitive_topology_list_restart); VN_ADD_PNEXT_EXT(feats2, PRIMITIVES_GENERATED_QUERY_FEATURES_EXT, local_feats.primitives_generated_query, exts->EXT_primitives_generated_query); VN_ADD_PNEXT_EXT(feats2, PROVOKING_VERTEX_FEATURES_EXT, local_feats.provoking_vertex, exts->EXT_provoking_vertex); VN_ADD_PNEXT_EXT(feats2, RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_EXT, local_feats.rasterization_order_attachment_access, exts->EXT_rasterization_order_attachment_access); VN_ADD_PNEXT_EXT(feats2, ROBUSTNESS_2_FEATURES_EXT, local_feats.robustness_2, exts->EXT_robustness2); VN_ADD_PNEXT_EXT(feats2, TRANSFORM_FEEDBACK_FEATURES_EXT, local_feats.transform_feedback, exts->EXT_transform_feedback); VN_ADD_PNEXT_EXT(feats2, VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT, local_feats.vertex_attribute_divisor, exts->EXT_vertex_attribute_divisor); VN_ADD_PNEXT_EXT(feats2, VERTEX_INPUT_DYNAMIC_STATE_FEATURES_EXT, local_feats.vertex_input_dynamic_state, exts->EXT_vertex_input_dynamic_state); /* clang-format on */ vn_call_vkGetPhysicalDeviceFeatures2( ring, vn_physical_device_to_handle(physical_dev), &feats2); struct vk_features *feats = &physical_dev->base.base.supported_features; vk_set_physical_device_features(feats, &feats2); /* Enable features for extensions natively implemented in Venus driver. * See vn_physical_device_get_native_extensions. */ VN_SET_CORE_VALUE(feats, deviceMemoryReport, true); /* Disable unsupported ExtendedDynamicState3Features */ if (exts->EXT_extended_dynamic_state3) { /* TODO: Add support for VK_EXT_sample_locations */ VN_SET_CORE_VALUE(feats, extendedDynamicState3SampleLocationsEnable, false); /* TODO: Add support for VK_EXT_blend_operation_advanced */ VN_SET_CORE_VALUE(feats, extendedDynamicState3ColorBlendAdvanced, false); /* VK_NV_* extensions required */ VN_SET_CORE_VALUE(feats, extendedDynamicState3ViewportWScalingEnable, false); VN_SET_CORE_VALUE(feats, extendedDynamicState3ViewportSwizzle, false); VN_SET_CORE_VALUE(feats, extendedDynamicState3CoverageToColorEnable, false); VN_SET_CORE_VALUE(feats, extendedDynamicState3CoverageToColorLocation, false); VN_SET_CORE_VALUE(feats, extendedDynamicState3CoverageModulationMode, false); VN_SET_CORE_VALUE( feats, extendedDynamicState3CoverageModulationTableEnable, false); VN_SET_CORE_VALUE(feats, extendedDynamicState3CoverageModulationTable, false); VN_SET_CORE_VALUE(feats, extendedDynamicState3CoverageReductionMode, false); VN_SET_CORE_VALUE( feats, extendedDynamicState3RepresentativeFragmentTestEnable, false); VN_SET_CORE_VALUE(feats, extendedDynamicState3ShadingRateImageEnable, false); } } static void vn_physical_device_init_uuids(struct vn_physical_device *physical_dev) { struct vk_properties *props = &physical_dev->base.base.properties; struct mesa_sha1 sha1_ctx; uint8_t sha1[SHA1_DIGEST_LENGTH]; static_assert(VK_UUID_SIZE <= SHA1_DIGEST_LENGTH, ""); _mesa_sha1_init(&sha1_ctx); _mesa_sha1_update(&sha1_ctx, &props->pipelineCacheUUID, sizeof(props->pipelineCacheUUID)); _mesa_sha1_final(&sha1_ctx, sha1); memcpy(props->pipelineCacheUUID, sha1, VK_UUID_SIZE); _mesa_sha1_init(&sha1_ctx); _mesa_sha1_update(&sha1_ctx, &props->vendorID, sizeof(props->vendorID)); _mesa_sha1_update(&sha1_ctx, &props->deviceID, sizeof(props->deviceID)); _mesa_sha1_final(&sha1_ctx, sha1); memcpy(props->deviceUUID, sha1, VK_UUID_SIZE); _mesa_sha1_init(&sha1_ctx); _mesa_sha1_update(&sha1_ctx, props->driverName, strlen(props->driverName)); _mesa_sha1_update(&sha1_ctx, props->driverInfo, strlen(props->driverInfo)); _mesa_sha1_final(&sha1_ctx, sha1); memcpy(props->driverUUID, sha1, VK_UUID_SIZE); memset(props->deviceLUID, 0, VK_LUID_SIZE); props->deviceNodeMask = 0; props->deviceLUIDValid = false; } static void vn_physical_device_sanitize_properties(struct vn_physical_device *physical_dev) { struct vn_instance *instance = physical_dev->instance; const struct vk_device_extension_table *exts = &physical_dev->renderer_extensions; struct vk_properties *props = &physical_dev->base.base.properties; const uint32_t version_override = vk_get_version_override(); if (version_override) { props->apiVersion = version_override; } else { /* cap the advertised api version */ uint32_t ver = MIN3(props->apiVersion, VN_MAX_API_VERSION, instance->renderer->info.vk_xml_version); if (VK_VERSION_PATCH(ver) > VK_VERSION_PATCH(props->apiVersion)) { ver = ver - VK_VERSION_PATCH(ver) + VK_VERSION_PATCH(props->apiVersion); } /* Clamp to 1.2 if we disabled VK_KHR_synchronization2 since it * is required for 1.3. * See vn_physical_device_get_passthrough_extensions() */ if (!physical_dev->base.base.supported_extensions.KHR_synchronization2) ver = MIN2(VK_API_VERSION_1_2, ver); props->apiVersion = ver; } /* ANGLE relies on ARM proprietary driver version for workarounds */ const char *engine_name = instance->base.base.app_info.engine_name; const bool forward_driver_version = props->driverID == VK_DRIVER_ID_ARM_PROPRIETARY && engine_name && strcmp(engine_name, "ANGLE") == 0; if (!forward_driver_version) props->driverVersion = vk_get_driver_version(); physical_dev->wa_min_fb_align = strstr(props->deviceName, "JSL") ? 128 : 1; char device_name[VK_MAX_PHYSICAL_DEVICE_NAME_SIZE]; int device_name_len = snprintf(device_name, sizeof(device_name), "Virtio-GPU Venus (%s)", props->deviceName); if (device_name_len >= VK_MAX_PHYSICAL_DEVICE_NAME_SIZE) { memcpy(device_name + VK_MAX_PHYSICAL_DEVICE_NAME_SIZE - 5, "...)", 4); device_name_len = VK_MAX_PHYSICAL_DEVICE_NAME_SIZE - 1; } memcpy(props->deviceName, device_name, device_name_len + 1); /* store renderer VkDriverId for implementation specific workarounds */ physical_dev->renderer_driver_id = props->driverID; VN_SET_CORE_VALUE(props, driverID, VK_DRIVER_ID_MESA_VENUS); snprintf(props->driverName, sizeof(props->driverName), "venus"); snprintf(props->driverInfo, sizeof(props->driverInfo), "Mesa " PACKAGE_VERSION MESA_GIT_SHA1); VN_SET_CORE_VALUE(props, conformanceVersion.major, 1); VN_SET_CORE_VALUE(props, conformanceVersion.minor, 3); VN_SET_CORE_VALUE(props, conformanceVersion.subminor, 0); VN_SET_CORE_VALUE(props, conformanceVersion.patch, 0); vn_physical_device_init_uuids(physical_dev); /* Disable unsupported VkPhysicalDeviceFragmentShadingRatePropertiesKHR */ if (exts->KHR_fragment_shading_rate) { /* TODO: Add support for VK_EXT_sample_locations */ VN_SET_CORE_VALUE(props, fragmentShadingRateWithCustomSampleLocations, false); } } static void vn_physical_device_init_properties(struct vn_physical_device *physical_dev) { const uint32_t renderer_version = physical_dev->renderer_version; struct vn_instance *instance = physical_dev->instance; const struct vn_renderer_info *renderer_info = &instance->renderer->info; struct vk_properties *props = &physical_dev->base.base.properties; const struct vk_device_extension_table *exts = &physical_dev->renderer_extensions; VkPhysicalDeviceProperties2 props2 = { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, }; struct { /* Vulkan 1.1 */ VkPhysicalDeviceVulkan11Properties vulkan_1_1; VkPhysicalDeviceIDProperties id; VkPhysicalDeviceSubgroupProperties subgroup; VkPhysicalDevicePointClippingProperties point_clipping; VkPhysicalDeviceMultiviewProperties multiview; VkPhysicalDeviceProtectedMemoryProperties protected_memory; VkPhysicalDeviceMaintenance3Properties maintenance_3; /* Vulkan 1.2 */ VkPhysicalDeviceVulkan12Properties vulkan_1_2; VkPhysicalDeviceDriverProperties driver; VkPhysicalDeviceFloatControlsProperties float_controls; VkPhysicalDeviceDescriptorIndexingProperties descriptor_indexing; VkPhysicalDeviceDepthStencilResolveProperties depth_stencil_resolve; VkPhysicalDeviceSamplerFilterMinmaxProperties sampler_filter_minmax; VkPhysicalDeviceTimelineSemaphoreProperties timeline_semaphore; /* Vulkan 1.3 */ VkPhysicalDeviceVulkan13Properties vulkan_1_3; VkPhysicalDeviceInlineUniformBlockProperties inline_uniform_block; VkPhysicalDeviceMaintenance4Properties maintenance4; VkPhysicalDeviceShaderIntegerDotProductProperties shader_integer_dot_product; VkPhysicalDeviceSubgroupSizeControlProperties subgroup_size_control; VkPhysicalDeviceTexelBufferAlignmentProperties texel_buffer_alignment; /* KHR */ VkPhysicalDevicePushDescriptorPropertiesKHR push_descriptor; VkPhysicalDeviceFragmentShadingRatePropertiesKHR fragment_shading_rate; /* EXT */ VkPhysicalDeviceConservativeRasterizationPropertiesEXT conservative_rasterization; VkPhysicalDeviceCustomBorderColorPropertiesEXT custom_border_color; VkPhysicalDeviceExtendedDynamicState3PropertiesEXT extended_dynamic_state_3; VkPhysicalDeviceGraphicsPipelineLibraryPropertiesEXT graphics_pipeline_library; VkPhysicalDeviceLineRasterizationPropertiesEXT line_rasterization; VkPhysicalDeviceMultiDrawPropertiesEXT multi_draw; VkPhysicalDevicePCIBusInfoPropertiesEXT pci_bus_info; VkPhysicalDeviceProvokingVertexPropertiesEXT provoking_vertex; VkPhysicalDeviceRobustness2PropertiesEXT robustness_2; VkPhysicalDeviceTransformFeedbackPropertiesEXT transform_feedback; VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT vertex_attribute_divisor; } local_props; /* Clear the structs so all unqueried properties will be well-defined. */ memset(props, 0, sizeof(*props)); memset(&local_props, 0, sizeof(local_props)); assert(renderer_version >= VK_API_VERSION_1_1); /* clang-format off */ if (renderer_version >= VK_API_VERSION_1_2) { VN_ADD_PNEXT(props2, VULKAN_1_1_PROPERTIES, local_props.vulkan_1_1); VN_ADD_PNEXT(props2, VULKAN_1_2_PROPERTIES, local_props.vulkan_1_2); } else { /* Vulkan 1.1 */ VN_ADD_PNEXT(props2, ID_PROPERTIES, local_props.id); VN_ADD_PNEXT(props2, MAINTENANCE_3_PROPERTIES, local_props.maintenance_3); VN_ADD_PNEXT(props2, MULTIVIEW_PROPERTIES, local_props.multiview); VN_ADD_PNEXT(props2, POINT_CLIPPING_PROPERTIES, local_props.point_clipping); VN_ADD_PNEXT(props2, PROTECTED_MEMORY_PROPERTIES, local_props.protected_memory); VN_ADD_PNEXT(props2, SUBGROUP_PROPERTIES, local_props.subgroup); /* Vulkan 1.2 */ VN_ADD_PNEXT_EXT(props2, DEPTH_STENCIL_RESOLVE_PROPERTIES, local_props.depth_stencil_resolve, exts->KHR_depth_stencil_resolve); VN_ADD_PNEXT_EXT(props2, DESCRIPTOR_INDEXING_PROPERTIES, local_props.descriptor_indexing, exts->EXT_descriptor_indexing); VN_ADD_PNEXT_EXT(props2, DRIVER_PROPERTIES, local_props.driver, exts->KHR_driver_properties); VN_ADD_PNEXT_EXT(props2, FLOAT_CONTROLS_PROPERTIES, local_props.float_controls, exts->KHR_shader_float_controls); VN_ADD_PNEXT_EXT(props2, SAMPLER_FILTER_MINMAX_PROPERTIES, local_props.sampler_filter_minmax, exts->EXT_sampler_filter_minmax); VN_ADD_PNEXT_EXT(props2, TIMELINE_SEMAPHORE_PROPERTIES, local_props.timeline_semaphore, exts->KHR_timeline_semaphore); } if (renderer_version >= VK_API_VERSION_1_3) { VN_ADD_PNEXT(props2, VULKAN_1_3_PROPERTIES, local_props.vulkan_1_3); } else { VN_ADD_PNEXT_EXT(props2, INLINE_UNIFORM_BLOCK_PROPERTIES, local_props.inline_uniform_block, exts->EXT_inline_uniform_block); VN_ADD_PNEXT_EXT(props2, MAINTENANCE_4_PROPERTIES, local_props.maintenance4, exts->KHR_maintenance4); VN_ADD_PNEXT_EXT(props2, SHADER_INTEGER_DOT_PRODUCT_PROPERTIES, local_props.shader_integer_dot_product, exts->KHR_shader_integer_dot_product); VN_ADD_PNEXT_EXT(props2, SUBGROUP_SIZE_CONTROL_PROPERTIES, local_props.subgroup_size_control, exts->EXT_subgroup_size_control); VN_ADD_PNEXT_EXT(props2, TEXEL_BUFFER_ALIGNMENT_PROPERTIES, local_props.texel_buffer_alignment, exts->EXT_texel_buffer_alignment); } /* KHR */ VN_ADD_PNEXT_EXT(props2, FRAGMENT_SHADING_RATE_PROPERTIES_KHR, local_props.fragment_shading_rate, exts->KHR_fragment_shading_rate); VN_ADD_PNEXT_EXT(props2, PUSH_DESCRIPTOR_PROPERTIES_KHR, local_props.push_descriptor, exts->KHR_push_descriptor); /* EXT */ VN_ADD_PNEXT_EXT(props2, CONSERVATIVE_RASTERIZATION_PROPERTIES_EXT, local_props.conservative_rasterization, exts->EXT_conservative_rasterization); VN_ADD_PNEXT_EXT(props2, CUSTOM_BORDER_COLOR_PROPERTIES_EXT, local_props.custom_border_color, exts->EXT_custom_border_color); VN_ADD_PNEXT_EXT(props2, EXTENDED_DYNAMIC_STATE_3_PROPERTIES_EXT, local_props.extended_dynamic_state_3, exts->EXT_extended_dynamic_state3); VN_ADD_PNEXT_EXT(props2, GRAPHICS_PIPELINE_LIBRARY_PROPERTIES_EXT, local_props.graphics_pipeline_library, exts->EXT_graphics_pipeline_library); VN_ADD_PNEXT_EXT(props2, LINE_RASTERIZATION_PROPERTIES_EXT, local_props.line_rasterization, exts->EXT_line_rasterization); VN_ADD_PNEXT_EXT(props2, MULTI_DRAW_PROPERTIES_EXT, local_props.multi_draw, exts->EXT_multi_draw); VN_ADD_PNEXT_EXT(props2, PCI_BUS_INFO_PROPERTIES_EXT, local_props.pci_bus_info, exts->EXT_pci_bus_info); VN_ADD_PNEXT_EXT(props2, PROVOKING_VERTEX_PROPERTIES_EXT, local_props.provoking_vertex, exts->EXT_provoking_vertex); VN_ADD_PNEXT_EXT(props2, ROBUSTNESS_2_PROPERTIES_EXT, local_props.robustness_2, exts->EXT_robustness2); VN_ADD_PNEXT_EXT(props2, TRANSFORM_FEEDBACK_PROPERTIES_EXT, local_props.transform_feedback, exts->EXT_transform_feedback); VN_ADD_PNEXT_EXT(props2, VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT, local_props.vertex_attribute_divisor, exts->EXT_vertex_attribute_divisor); /* clang-format on */ vn_call_vkGetPhysicalDeviceProperties2( instance->ring.ring, vn_physical_device_to_handle(physical_dev), &props2); /* clang-format off */ /* Vulkan 1.0 */ VN_SET_VK_PROPS(props, &props2); /* Vulkan 1.1 and 1.2 */ if (renderer_version >= VK_API_VERSION_1_2) { VN_SET_VK_PROPS(props, &local_props.vulkan_1_1); VN_SET_VK_PROPS(props, &local_props.vulkan_1_2); } else { /* Vulkan 1.1 */ VN_SET_VK_PROPS(props, &local_props.id); VN_SET_VK_PROPS(props, &local_props.subgroup); VN_SET_VK_PROPS(props, &local_props.point_clipping); VN_SET_VK_PROPS(props, &local_props.multiview); VN_SET_VK_PROPS(props, &local_props.protected_memory); VN_SET_VK_PROPS(props, &local_props.maintenance_3); /* Vulkan 1.2 */ VN_SET_VK_PROPS_EXT(props, &local_props.driver, exts->KHR_driver_properties); VN_SET_VK_PROPS_EXT(props, &local_props.float_controls, exts->KHR_shader_float_controls); VN_SET_VK_PROPS_EXT(props, &local_props.descriptor_indexing, exts->EXT_descriptor_indexing); VN_SET_VK_PROPS_EXT(props, &local_props.depth_stencil_resolve, exts->KHR_depth_stencil_resolve); VN_SET_VK_PROPS_EXT(props, &local_props.sampler_filter_minmax, exts->EXT_sampler_filter_minmax); VN_SET_VK_PROPS_EXT(props, &local_props.timeline_semaphore, exts->KHR_timeline_semaphore); } /* Vulkan 1.3 */ if (renderer_version >= VK_API_VERSION_1_3) { VN_SET_VK_PROPS(props, &local_props.vulkan_1_3); } else { VN_SET_VK_PROPS_EXT(props, &local_props.subgroup_size_control, exts->EXT_subgroup_size_control); VN_SET_VK_PROPS_EXT(props, &local_props.inline_uniform_block, exts->EXT_inline_uniform_block); VN_SET_VK_PROPS_EXT(props, &local_props.shader_integer_dot_product, exts->KHR_shader_integer_dot_product); VN_SET_VK_PROPS_EXT(props, &local_props.texel_buffer_alignment, exts->EXT_texel_buffer_alignment); VN_SET_VK_PROPS_EXT(props, &local_props.maintenance4, exts->KHR_maintenance4); } /* KHR */ VN_SET_VK_PROPS_EXT(props, &local_props.fragment_shading_rate, exts->KHR_fragment_shading_rate); VN_SET_VK_PROPS_EXT(props, &local_props.push_descriptor, exts->KHR_push_descriptor); /* EXT */ VN_SET_VK_PROPS_EXT(props, &local_props.conservative_rasterization, exts->EXT_conservative_rasterization); VN_SET_VK_PROPS_EXT(props, &local_props.custom_border_color, exts->EXT_custom_border_color); VN_SET_VK_PROPS_EXT(props, &local_props.extended_dynamic_state_3, exts->EXT_extended_dynamic_state3); VN_SET_VK_PROPS_EXT(props, &local_props.graphics_pipeline_library, exts->EXT_graphics_pipeline_library); VN_SET_VK_PROPS_EXT(props, &local_props.line_rasterization, exts->EXT_line_rasterization); VN_SET_VK_PROPS_EXT(props, &local_props.multi_draw, exts->EXT_multi_draw); VN_SET_VK_PROPS_EXT(props, &local_props.pci_bus_info, exts->EXT_pci_bus_info); VN_SET_VK_PROPS_EXT(props, &local_props.provoking_vertex, exts->EXT_provoking_vertex); VN_SET_VK_PROPS_EXT(props, &local_props.robustness_2, exts->EXT_robustness2); VN_SET_VK_PROPS_EXT(props, &local_props.transform_feedback, exts->EXT_transform_feedback); VN_SET_VK_PROPS_EXT(props, &local_props.vertex_attribute_divisor, exts->EXT_vertex_attribute_divisor); /* clang-format on */ /* initialize native properties */ /* VK_EXT_physical_device_drm */ VN_SET_VK_PROPS(props, &renderer_info->drm.props); /* VK_EXT_pci_bus_info */ if (renderer_info->pci.has_bus_info) VN_SET_VK_PROPS(props, &renderer_info->pci.props); #if DETECT_OS_ANDROID /* VK_ANDROID_native_buffer */ if (vn_android_gralloc_get_shared_present_usage()) props->sharedImage = true; #endif /* TODO: Fix sparse binding on lavapipe. */ if (props->driverID == VK_DRIVER_ID_MESA_LLVMPIPE) physical_dev->sparse_binding_disabled = true; vn_physical_device_sanitize_properties(physical_dev); } static VkResult vn_physical_device_init_queue_family_properties( struct vn_physical_device *physical_dev) { struct vn_instance *instance = physical_dev->instance; struct vn_ring *ring = instance->ring.ring; const VkAllocationCallbacks *alloc = &instance->base.base.alloc; uint32_t count; vn_call_vkGetPhysicalDeviceQueueFamilyProperties2( ring, vn_physical_device_to_handle(physical_dev), &count, NULL); VkQueueFamilyProperties2 *props = vk_alloc(alloc, sizeof(*props) * count, VN_DEFAULT_ALIGN, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); if (!props) return VK_ERROR_OUT_OF_HOST_MEMORY; for (uint32_t i = 0; i < count; i++) { props[i].sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2; props[i].pNext = NULL; } vn_call_vkGetPhysicalDeviceQueueFamilyProperties2( ring, vn_physical_device_to_handle(physical_dev), &count, props); /* Filter out queue families that exclusively support sparse binding as * we need additional support for submitting feedback commands */ uint32_t sparse_count = 0; uint32_t non_sparse_only_count = 0; for (uint32_t i = 0; i < count; i++) { if (props[i].queueFamilyProperties.queueFlags & ~VK_QUEUE_SPARSE_BINDING_BIT) { props[non_sparse_only_count++].queueFamilyProperties = props[i].queueFamilyProperties; } if (props[i].queueFamilyProperties.queueFlags & VK_QUEUE_SPARSE_BINDING_BIT) { sparse_count++; } } if (VN_DEBUG(NO_SPARSE) || (sparse_count && non_sparse_only_count + sparse_count == count)) physical_dev->sparse_binding_disabled = true; physical_dev->queue_family_properties = props; physical_dev->queue_family_count = non_sparse_only_count; return VK_SUCCESS; } static void vn_physical_device_init_memory_properties( struct vn_physical_device *physical_dev) { struct vn_instance *instance = physical_dev->instance; struct vn_ring *ring = instance->ring.ring; VkPhysicalDeviceMemoryProperties2 props2 = { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2, }; vn_call_vkGetPhysicalDeviceMemoryProperties2( ring, vn_physical_device_to_handle(physical_dev), &props2); physical_dev->memory_properties = props2.memoryProperties; /* Kernel makes every mapping coherent. If a memory type is truly * incoherent, it's better to remove the host-visible flag than silently * making it coherent. However, for app compatibility purpose, when * coherent-cached memory type is unavailable, we append the cached bit to * the first coherent memory type. */ bool has_coherent_cached = false; uint32_t first_coherent = VK_MAX_MEMORY_TYPES; VkPhysicalDeviceMemoryProperties *props = &physical_dev->memory_properties; for (uint32_t i = 0; i < props->memoryTypeCount; i++) { VkMemoryPropertyFlags *flags = &props->memoryTypes[i].propertyFlags; const bool coherent = *flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; const bool cached = *flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT; if (coherent) { if (first_coherent == VK_MAX_MEMORY_TYPES) first_coherent = i; if (cached) has_coherent_cached = true; } else if (cached) { *flags &= ~(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT); } } if (!has_coherent_cached) { props->memoryTypes[first_coherent].propertyFlags |= VK_MEMORY_PROPERTY_HOST_CACHED_BIT; } } static void vn_physical_device_init_external_memory( struct vn_physical_device *physical_dev) { /* When a renderer VkDeviceMemory is exportable, we can create a * vn_renderer_bo from it. The vn_renderer_bo can be freely exported as an * opaque fd or a dma-buf. * * When an external memory can be imported as a vn_renderer_bo, that bo * might be imported as a renderer side VkDeviceMemory. * * However, to know if a rendender VkDeviceMemory is exportable or if a bo * can be imported as a renderer VkDeviceMemory. We have to start from * physical device external image and external buffer properties queries, * which requires to know the renderer supported external handle types. For * such info, we can reliably retrieve from the external memory extensions * advertised by the renderer. * * We require VK_EXT_external_memory_dma_buf to expose driver side external * memory support for a renderer running on Linux. As a comparison, when * the renderer runs on Windows, VK_KHR_external_memory_win32 might be * required for the same. * * For vtest, the protocol does not support external memory import. So we * only mask out the importable bit so that wsi over vtest can be supported. */ if (physical_dev->renderer_extensions.EXT_external_memory_dma_buf) { physical_dev->external_memory.renderer_handle_type = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; #if DETECT_OS_ANDROID physical_dev->external_memory.supported_handle_types |= VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID; #else /* DETECT_OS_ANDROID */ physical_dev->external_memory.supported_handle_types = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT | VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; #endif /* DETECT_OS_ANDROID */ } } static void vn_physical_device_init_external_fence_handles( struct vn_physical_device *physical_dev) { /* The current code manipulates the host-side VkFence directly. * vkWaitForFences is translated to repeated vkGetFenceStatus. * * External fence is not possible currently. Instead, we cheat by * translating vkGetFenceFdKHR to an empty renderer submission for the * out fence, along with a venus protocol command to fix renderer side * fence payload. * * We would like to create a vn_renderer_sync from a host-side VkFence, * similar to how a vn_renderer_bo is created from a host-side * VkDeviceMemory. That would require kernel support and tons of works on * the host side. If we had that, and we kept both the vn_renderer_sync * and the host-side VkFence in sync, we would have the freedom to use * either of them depending on the occasions, and support external fences * and idle waiting. */ if (physical_dev->renderer_extensions.KHR_external_fence_fd) { struct vn_ring *ring = physical_dev->instance->ring.ring; const VkPhysicalDeviceExternalFenceInfo info = { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO, .handleType = VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT, }; VkExternalFenceProperties props = { .sType = VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES, }; vn_call_vkGetPhysicalDeviceExternalFenceProperties( ring, vn_physical_device_to_handle(physical_dev), &info, &props); physical_dev->renderer_sync_fd.fence_exportable = props.externalFenceFeatures & VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT; } physical_dev->external_fence_handles = 0; if (physical_dev->instance->renderer->info.has_external_sync) { physical_dev->external_fence_handles = VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT; } } static void vn_physical_device_init_external_semaphore_handles( struct vn_physical_device *physical_dev) { /* The current code manipulates the host-side VkSemaphore directly. It * works very well for binary semaphores because there is no CPU operation. * But for timeline semaphores, the situation is similar to that of fences. * vkWaitSemaphores is translated to repeated vkGetSemaphoreCounterValue. * * External semaphore is not possible currently. Instead, we cheat when * the semaphore is binary and the handle type is sync file. We do an empty * renderer submission for the out fence, along with a venus protocol * command to fix renderer side semaphore payload. * * We would like to create a vn_renderer_sync from a host-side VkSemaphore, * similar to how a vn_renderer_bo is created from a host-side * VkDeviceMemory. The reasoning is the same as that for fences. * Additionally, we would like the sync file exported from the * vn_renderer_sync to carry the necessary information to identify the * host-side VkSemaphore. That would allow the consumers to wait on the * host side rather than the guest side. */ if (physical_dev->renderer_extensions.KHR_external_semaphore_fd) { struct vn_ring *ring = physical_dev->instance->ring.ring; const VkPhysicalDeviceExternalSemaphoreInfo info = { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO, .handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT, }; VkExternalSemaphoreProperties props = { .sType = VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES, }; vn_call_vkGetPhysicalDeviceExternalSemaphoreProperties( ring, vn_physical_device_to_handle(physical_dev), &info, &props); physical_dev->renderer_sync_fd.semaphore_exportable = props.externalSemaphoreFeatures & VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT; physical_dev->renderer_sync_fd.semaphore_importable = props.externalSemaphoreFeatures & VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT; } physical_dev->external_binary_semaphore_handles = 0; physical_dev->external_timeline_semaphore_handles = 0; if (physical_dev->instance->renderer->info.has_external_sync) { physical_dev->external_binary_semaphore_handles = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT; } } static inline bool vn_physical_device_get_external_memory_support( const struct vn_physical_device *physical_dev) { if (!physical_dev->external_memory.renderer_handle_type) return false; /* see vn_physical_device_init_external_memory */ if (physical_dev->external_memory.renderer_handle_type == VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT) { const struct vk_device_extension_table *renderer_exts = &physical_dev->renderer_extensions; return renderer_exts->EXT_image_drm_format_modifier && renderer_exts->EXT_queue_family_foreign; } /* expand support once the renderer can run on non-Linux platforms */ return false; } static void vn_physical_device_get_native_extensions( const struct vn_physical_device *physical_dev, struct vk_device_extension_table *exts) { memset(exts, 0, sizeof(*exts)); if (physical_dev->instance->renderer->info.has_external_sync && physical_dev->renderer_sync_fd.fence_exportable) exts->KHR_external_fence_fd = true; if (physical_dev->instance->renderer->info.has_external_sync && physical_dev->renderer_sync_fd.semaphore_importable && physical_dev->renderer_sync_fd.semaphore_exportable) exts->KHR_external_semaphore_fd = true; const bool can_external_mem = vn_physical_device_get_external_memory_support(physical_dev); if (can_external_mem) { #if DETECT_OS_ANDROID exts->ANDROID_external_memory_android_hardware_buffer = true; /* For wsi, we require renderer: * - semaphore sync fd import for queue submission to skip scrubbing the * wsi wait semaphores. * - fence sync fd export for QueueSignalReleaseImageANDROID to export a * sync fd. * * TODO: relax these requirements by: * - properly scrubbing wsi wait semaphores * - not creating external fence but exporting sync fd directly */ if (physical_dev->renderer_sync_fd.semaphore_importable && physical_dev->renderer_sync_fd.fence_exportable) exts->ANDROID_native_buffer = true; #else /* DETECT_OS_ANDROID */ exts->KHR_external_memory_fd = true; exts->EXT_external_memory_dma_buf = true; #endif /* DETECT_OS_ANDROID */ } #ifdef VN_USE_WSI_PLATFORM if (can_external_mem && physical_dev->renderer_sync_fd.semaphore_importable) { exts->KHR_incremental_present = true; exts->KHR_swapchain = true; exts->KHR_swapchain_mutable_format = true; } /* VK_EXT_pci_bus_info is required by common wsi to decide whether native * image or prime blit is used. Meanwhile, venus must stay on native image * path for proper fencing. * - For virtgpu, VK_EXT_pci_bus_info is natively supported. * - For vtest, pci bus info must be queried from the renderer side physical * device to be compared against the render node opened by common wsi. */ exts->EXT_pci_bus_info = physical_dev->instance->renderer->info.pci.has_bus_info || physical_dev->renderer_extensions.EXT_pci_bus_info; #endif exts->EXT_physical_device_drm = true; /* use common implementation */ exts->EXT_tooling_info = true; exts->EXT_device_memory_report = true; } static void vn_physical_device_get_passthrough_extensions( const struct vn_physical_device *physical_dev, struct vk_device_extension_table *exts) { *exts = (struct vk_device_extension_table){ /* promoted to VK_VERSION_1_1 */ .KHR_16bit_storage = true, .KHR_bind_memory2 = true, .KHR_dedicated_allocation = true, .KHR_descriptor_update_template = true, .KHR_device_group = true, .KHR_external_fence = true, .KHR_external_memory = true, .KHR_external_semaphore = true, .KHR_get_memory_requirements2 = true, .KHR_maintenance1 = true, .KHR_maintenance2 = true, .KHR_maintenance3 = true, .KHR_multiview = true, .KHR_relaxed_block_layout = true, .KHR_sampler_ycbcr_conversion = true, .KHR_shader_draw_parameters = true, .KHR_storage_buffer_storage_class = true, .KHR_variable_pointers = true, /* promoted to VK_VERSION_1_2 */ .KHR_8bit_storage = true, .KHR_buffer_device_address = true, .KHR_create_renderpass2 = true, .KHR_depth_stencil_resolve = true, .KHR_draw_indirect_count = true, .KHR_driver_properties = true, .KHR_image_format_list = true, .KHR_imageless_framebuffer = true, .KHR_sampler_mirror_clamp_to_edge = true, .KHR_separate_depth_stencil_layouts = true, .KHR_shader_atomic_int64 = true, .KHR_shader_float16_int8 = true, .KHR_shader_float_controls = true, .KHR_shader_subgroup_extended_types = true, .KHR_spirv_1_4 = true, .KHR_timeline_semaphore = true, .KHR_uniform_buffer_standard_layout = true, .KHR_vulkan_memory_model = true, .EXT_descriptor_indexing = true, .EXT_host_query_reset = true, .EXT_sampler_filter_minmax = true, .EXT_scalar_block_layout = true, .EXT_separate_stencil_usage = true, .EXT_shader_viewport_index_layer = true, /* promoted to VK_VERSION_1_3 */ .KHR_copy_commands2 = true, .KHR_dynamic_rendering = true, .KHR_format_feature_flags2 = true, .KHR_maintenance4 = true, .KHR_shader_integer_dot_product = true, .KHR_shader_non_semantic_info = true, .KHR_shader_terminate_invocation = true, /* Our implementation requires semaphore sync fd import * for VK_KHR_synchronization2. */ .KHR_synchronization2 = physical_dev->renderer_sync_fd.semaphore_importable, .KHR_zero_initialize_workgroup_memory = true, .EXT_4444_formats = true, .EXT_extended_dynamic_state = true, .EXT_extended_dynamic_state2 = true, .EXT_image_robustness = true, .EXT_inline_uniform_block = true, .EXT_pipeline_creation_cache_control = true, /* hide behind renderer support to allow structs passing through */ .EXT_pipeline_creation_feedback = true, .EXT_shader_demote_to_helper_invocation = true, .EXT_subgroup_size_control = true, .EXT_texel_buffer_alignment = true, .EXT_texture_compression_astc_hdr = true, .EXT_ycbcr_2plane_444_formats = true, /* KHR */ .KHR_fragment_shading_rate = true, .KHR_maintenance5 = true, .KHR_pipeline_library = true, .KHR_push_descriptor = true, .KHR_shader_clock = true, .KHR_shader_expect_assume = true, /* EXT */ .EXT_attachment_feedback_loop_layout = true, .EXT_border_color_swizzle = true, .EXT_calibrated_timestamps = true, .EXT_color_write_enable = true, .EXT_conditional_rendering = true, .EXT_conservative_rasterization = true, .EXT_custom_border_color = true, .EXT_depth_clip_control = true, .EXT_depth_clip_enable = true, .EXT_extended_dynamic_state3 = true, .EXT_dynamic_rendering_unused_attachments = true, .EXT_external_memory_acquire_unmodified = true, .EXT_fragment_shader_interlock = true, .EXT_graphics_pipeline_library = !VN_DEBUG(NO_GPL), .EXT_image_2d_view_of_3d = true, .EXT_image_drm_format_modifier = true, .EXT_image_view_min_lod = true, .EXT_index_type_uint8 = true, .EXT_line_rasterization = true, .EXT_load_store_op_none = true, /* TODO: re-enable after generic app compat issues are resolved */ .EXT_memory_budget = false, .EXT_multi_draw = true, .EXT_mutable_descriptor_type = true, .EXT_non_seamless_cube_map = true, .EXT_primitive_topology_list_restart = true, .EXT_primitives_generated_query = true, /* hide behind renderer support to allow structs passing through */ .EXT_private_data = true, .EXT_provoking_vertex = true, .EXT_queue_family_foreign = true, .EXT_rasterization_order_attachment_access = true, .EXT_robustness2 = true, .EXT_shader_stencil_export = true, .EXT_shader_subgroup_ballot = true, .EXT_transform_feedback = true, .EXT_vertex_attribute_divisor = true, .EXT_vertex_input_dynamic_state = true, /* vendor */ .VALVE_mutable_descriptor_type = true, }; } static void vn_physical_device_init_supported_extensions( struct vn_physical_device *physical_dev) { struct vk_device_extension_table native; struct vk_device_extension_table passthrough; vn_physical_device_get_native_extensions(physical_dev, &native); vn_physical_device_get_passthrough_extensions(physical_dev, &passthrough); for (uint32_t i = 0; i < VK_DEVICE_EXTENSION_COUNT; i++) { const VkExtensionProperties *props = &vk_device_extensions[i]; #ifdef ANDROID_STRICT if (!vk_android_allowed_device_extensions.extensions[i]) continue; #endif if (native.extensions[i]) { physical_dev->base.base.supported_extensions.extensions[i] = true; physical_dev->extension_spec_versions[i] = props->specVersion; } else if (passthrough.extensions[i] && physical_dev->renderer_extensions.extensions[i]) { physical_dev->base.base.supported_extensions.extensions[i] = true; physical_dev->extension_spec_versions[i] = MIN2( physical_dev->extension_spec_versions[i], props->specVersion); } } } static VkResult vn_physical_device_init_renderer_extensions( struct vn_physical_device *physical_dev) { struct vn_instance *instance = physical_dev->instance; struct vn_ring *ring = instance->ring.ring; const VkAllocationCallbacks *alloc = &instance->base.base.alloc; /* get renderer extensions */ uint32_t count; VkResult result = vn_call_vkEnumerateDeviceExtensionProperties( ring, vn_physical_device_to_handle(physical_dev), NULL, &count, NULL); if (result != VK_SUCCESS) return result; VkExtensionProperties *exts = NULL; if (count) { exts = vk_alloc(alloc, sizeof(*exts) * count, VN_DEFAULT_ALIGN, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); if (!exts) return VK_ERROR_OUT_OF_HOST_MEMORY; result = vn_call_vkEnumerateDeviceExtensionProperties( ring, vn_physical_device_to_handle(physical_dev), NULL, &count, exts); if (result < VK_SUCCESS) { vk_free(alloc, exts); return result; } } physical_dev->extension_spec_versions = vk_zalloc(alloc, sizeof(*physical_dev->extension_spec_versions) * VK_DEVICE_EXTENSION_COUNT, VN_DEFAULT_ALIGN, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); if (!physical_dev->extension_spec_versions) { vk_free(alloc, exts); return VK_ERROR_OUT_OF_HOST_MEMORY; } for (uint32_t i = 0; i < VK_DEVICE_EXTENSION_COUNT; i++) { const VkExtensionProperties *props = &vk_device_extensions[i]; for (uint32_t j = 0; j < count; j++) { if (strcmp(props->extensionName, exts[j].extensionName)) continue; /* check encoder support */ const uint32_t enc_ext_spec_version = vn_extension_get_spec_version(props->extensionName); if (!enc_ext_spec_version) continue; physical_dev->renderer_extensions.extensions[i] = true; physical_dev->extension_spec_versions[i] = MIN2(exts[j].specVersion, enc_ext_spec_version); break; } } vk_free(alloc, exts); return VK_SUCCESS; } static VkResult vn_physical_device_init_renderer_version( struct vn_physical_device *physical_dev) { struct vn_instance *instance = physical_dev->instance; struct vn_ring *ring = instance->ring.ring; /* * We either check and enable VK_KHR_get_physical_device_properties2, or we * must use vkGetPhysicalDeviceProperties to get the device-level version. */ VkPhysicalDeviceProperties props; vn_call_vkGetPhysicalDeviceProperties( ring, vn_physical_device_to_handle(physical_dev), &props); if (props.apiVersion < VN_MIN_RENDERER_VERSION) { if (VN_DEBUG(INIT)) { vn_log(instance, "%s has unsupported renderer device version %d.%d", props.deviceName, VK_VERSION_MAJOR(props.apiVersion), VK_VERSION_MINOR(props.apiVersion)); } return VK_ERROR_INITIALIZATION_FAILED; } /* device version for internal use is capped */ physical_dev->renderer_version = MIN3(props.apiVersion, instance->renderer_api_version, instance->renderer->info.vk_xml_version); return VK_SUCCESS; } static void vn_image_format_cache_debug_dump( struct vn_image_format_properties_cache *cache) { vn_log(NULL, " hit %u\n", cache->debug.cache_hit_count); vn_log(NULL, " miss %u\n", cache->debug.cache_miss_count); vn_log(NULL, " skip %u\n", cache->debug.cache_skip_count); } static void vn_image_format_cache_init(struct vn_physical_device *physical_dev) { struct vn_image_format_properties_cache *cache = &physical_dev->image_format_cache; if (VN_PERF(NO_ASYNC_IMAGE_FORMAT)) return; cache->ht = _mesa_hash_table_create(NULL, vn_cache_key_hash_function, vn_cache_key_equal_function); if (!cache->ht) return; simple_mtx_init(&cache->mutex, mtx_plain); list_inithead(&cache->lru); } static void vn_image_format_cache_fini(struct vn_physical_device *physical_dev) { const VkAllocationCallbacks *alloc = &physical_dev->base.base.instance->alloc; struct vn_image_format_properties_cache *cache = &physical_dev->image_format_cache; if (!cache->ht) return; hash_table_foreach(cache->ht, hash_entry) { struct vn_image_format_cache_entry *cache_entry = hash_entry->data; list_del(&cache_entry->head); vk_free(alloc, cache_entry); } assert(list_is_empty(&cache->lru)); _mesa_hash_table_destroy(cache->ht, NULL); simple_mtx_destroy(&cache->mutex); if (VN_DEBUG(CACHE)) vn_image_format_cache_debug_dump(cache); } static void vn_physical_device_disable_sparse_binding( struct vn_physical_device *physical_dev) { /* To support sparse binding with feedback, we require sparse binding queue * families to also support submiting feedback commands. Any queue * families that exclusively support sparse binding are filtered out. If a * device only supports sparse binding with exclusive queue families that * get filtered out then disable the feature. */ struct vk_features *feats = &physical_dev->base.base.supported_features; VN_SET_CORE_VALUE(feats, sparseBinding, false); VN_SET_CORE_VALUE(feats, sparseResidencyBuffer, false); VN_SET_CORE_VALUE(feats, sparseResidencyImage2D, false); VN_SET_CORE_VALUE(feats, sparseResidencyImage3D, false); VN_SET_CORE_VALUE(feats, sparseResidency2Samples, false); VN_SET_CORE_VALUE(feats, sparseResidency4Samples, false); VN_SET_CORE_VALUE(feats, sparseResidency8Samples, false); VN_SET_CORE_VALUE(feats, sparseResidency16Samples, false); VN_SET_CORE_VALUE(feats, sparseResidencyAliased, false); struct vk_properties *props = &physical_dev->base.base.properties; VN_SET_CORE_VALUE(props, sparseAddressSpaceSize, 0); VN_SET_CORE_VALUE(props, sparseResidencyStandard2DBlockShape, 0); VN_SET_CORE_VALUE(props, sparseResidencyStandard2DMultisampleBlockShape, 0); VN_SET_CORE_VALUE(props, sparseResidencyStandard3DBlockShape, 0); VN_SET_CORE_VALUE(props, sparseResidencyAlignedMipSize, 0); VN_SET_CORE_VALUE(props, sparseResidencyNonResidentStrict, 0); } static VkResult vn_physical_device_init(struct vn_physical_device *physical_dev) { struct vn_instance *instance = physical_dev->instance; const VkAllocationCallbacks *alloc = &instance->base.base.alloc; VkResult result; result = vn_physical_device_init_renderer_extensions(physical_dev); if (result != VK_SUCCESS) return result; vn_physical_device_init_external_memory(physical_dev); vn_physical_device_init_external_fence_handles(physical_dev); vn_physical_device_init_external_semaphore_handles(physical_dev); vn_physical_device_init_supported_extensions(physical_dev); result = vn_physical_device_init_queue_family_properties(physical_dev); if (result != VK_SUCCESS) goto fail; /* TODO query all caps with minimal round trips */ vn_physical_device_init_features(physical_dev); vn_physical_device_init_properties(physical_dev); if (physical_dev->sparse_binding_disabled) vn_physical_device_disable_sparse_binding(physical_dev); vn_physical_device_init_memory_properties(physical_dev); result = vn_wsi_init(physical_dev); if (result != VK_SUCCESS) goto fail; simple_mtx_init(&physical_dev->format_update_mutex, mtx_plain); util_sparse_array_init(&physical_dev->format_properties, sizeof(struct vn_format_properties_entry), 64); vn_image_format_cache_init(physical_dev); return VK_SUCCESS; fail: vk_free(alloc, physical_dev->extension_spec_versions); vk_free(alloc, physical_dev->queue_family_properties); return result; } void vn_physical_device_fini(struct vn_physical_device *physical_dev) { struct vn_instance *instance = physical_dev->instance; const VkAllocationCallbacks *alloc = &instance->base.base.alloc; vn_image_format_cache_fini(physical_dev); simple_mtx_destroy(&physical_dev->format_update_mutex); util_sparse_array_finish(&physical_dev->format_properties); vn_wsi_fini(physical_dev); vk_free(alloc, physical_dev->extension_spec_versions); vk_free(alloc, physical_dev->queue_family_properties); vn_physical_device_base_fini(&physical_dev->base); } static struct vn_physical_device * find_physical_device(struct vn_physical_device *physical_devs, uint32_t count, vn_object_id id) { for (uint32_t i = 0; i < count; i++) { if (physical_devs[i].base.id == id) return &physical_devs[i]; } return NULL; } static VkResult vn_instance_enumerate_physical_device_groups_locked( struct vn_instance *instance, struct vn_physical_device *physical_devs, uint32_t physical_dev_count) { VkInstance instance_handle = vn_instance_to_handle(instance); struct vn_ring *ring = instance->ring.ring; const VkAllocationCallbacks *alloc = &instance->base.base.alloc; VkResult result; uint32_t count; result = vn_call_vkEnumeratePhysicalDeviceGroups(ring, instance_handle, &count, NULL); if (result != VK_SUCCESS) return result; VkPhysicalDeviceGroupProperties *groups = vk_alloc(alloc, sizeof(*groups) * count, VN_DEFAULT_ALIGN, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); if (!groups) return VK_ERROR_OUT_OF_HOST_MEMORY; /* VkPhysicalDeviceGroupProperties::physicalDevices is treated as an input * by the encoder. Each VkPhysicalDevice must point to a valid object. * Each object must have id 0 as well, which is interpreted as a query by * the renderer. */ struct vn_physical_device_base *temp_objs = vk_zalloc(alloc, sizeof(*temp_objs) * VK_MAX_DEVICE_GROUP_SIZE * count, VN_DEFAULT_ALIGN, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); if (!temp_objs) { vk_free(alloc, groups); return VK_ERROR_OUT_OF_HOST_MEMORY; } for (uint32_t i = 0; i < count; i++) { VkPhysicalDeviceGroupProperties *group = &groups[i]; group->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES; group->pNext = NULL; for (uint32_t j = 0; j < VK_MAX_DEVICE_GROUP_SIZE; j++) { struct vn_physical_device_base *temp_obj = &temp_objs[VK_MAX_DEVICE_GROUP_SIZE * i + j]; temp_obj->base.base.type = VK_OBJECT_TYPE_PHYSICAL_DEVICE; group->physicalDevices[j] = (VkPhysicalDevice)temp_obj; } } result = vn_call_vkEnumeratePhysicalDeviceGroups(ring, instance_handle, &count, groups); if (result != VK_SUCCESS) { vk_free(alloc, groups); vk_free(alloc, temp_objs); return result; } /* fix VkPhysicalDeviceGroupProperties::physicalDevices to point to * physical_devs and discard unsupported ones */ uint32_t supported_count = 0; for (uint32_t i = 0; i < count; i++) { VkPhysicalDeviceGroupProperties *group = &groups[i]; uint32_t group_physical_dev_count = 0; for (uint32_t j = 0; j < group->physicalDeviceCount; j++) { struct vn_physical_device_base *temp_obj = (struct vn_physical_device_base *)group->physicalDevices[j]; struct vn_physical_device *physical_dev = find_physical_device( physical_devs, physical_dev_count, temp_obj->id); if (!physical_dev) continue; group->physicalDevices[group_physical_dev_count++] = vn_physical_device_to_handle(physical_dev); } group->physicalDeviceCount = group_physical_dev_count; if (!group->physicalDeviceCount) continue; if (supported_count < i) groups[supported_count] = *group; supported_count++; } count = supported_count; assert(count); vk_free(alloc, temp_objs); instance->physical_device.groups = groups; instance->physical_device.group_count = count; return VK_SUCCESS; } static VkResult enumerate_physical_devices(struct vn_instance *instance, struct vn_physical_device **out_physical_devs, uint32_t *out_count) { const VkAllocationCallbacks *alloc = &instance->base.base.alloc; struct vn_ring *ring = instance->ring.ring; struct vn_physical_device *physical_devs = NULL; VkResult result; uint32_t count = 0; result = vn_call_vkEnumeratePhysicalDevices( ring, vn_instance_to_handle(instance), &count, NULL); if (result != VK_SUCCESS || !count) return result; physical_devs = vk_zalloc(alloc, sizeof(*physical_devs) * count, VN_DEFAULT_ALIGN, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); if (!physical_devs) return VK_ERROR_OUT_OF_HOST_MEMORY; STACK_ARRAY(VkPhysicalDevice, handles, count); for (uint32_t i = 0; i < count; i++) { struct vn_physical_device *physical_dev = &physical_devs[i]; struct vk_physical_device_dispatch_table dispatch_table; vk_physical_device_dispatch_table_from_entrypoints( &dispatch_table, &vn_physical_device_entrypoints, true); vk_physical_device_dispatch_table_from_entrypoints( &dispatch_table, &wsi_physical_device_entrypoints, false); result = vn_physical_device_base_init( &physical_dev->base, &instance->base, NULL, &dispatch_table); if (result != VK_SUCCESS) { count = i; goto fail; } physical_dev->instance = instance; handles[i] = vn_physical_device_to_handle(physical_dev); } result = vn_call_vkEnumeratePhysicalDevices( ring, vn_instance_to_handle(instance), &count, handles); if (result != VK_SUCCESS) goto fail; STACK_ARRAY_FINISH(handles); *out_physical_devs = physical_devs; *out_count = count; return VK_SUCCESS; fail: for (uint32_t i = 0; i < count; i++) vn_physical_device_base_fini(&physical_devs[i].base); vk_free(alloc, physical_devs); STACK_ARRAY_FINISH(handles); return result; } static uint32_t filter_physical_devices(struct vn_physical_device *physical_devs, uint32_t count) { uint32_t supported_count = 0; for (uint32_t i = 0; i < count; i++) { struct vn_physical_device *physical_dev = &physical_devs[i]; /* init renderer version and discard unsupported devices */ VkResult result = vn_physical_device_init_renderer_version(physical_dev); if (result != VK_SUCCESS) { vn_physical_device_base_fini(&physical_dev->base); continue; } if (supported_count < i) physical_devs[supported_count] = *physical_dev; supported_count++; } return supported_count; } static VkResult vn_instance_enumerate_physical_devices_and_groups(struct vn_instance *instance) { const VkAllocationCallbacks *alloc = &instance->base.base.alloc; struct vn_physical_device *physical_devs = NULL; uint32_t count = 0; VkResult result = VK_SUCCESS; mtx_lock(&instance->physical_device.mutex); if (instance->physical_device.initialized) goto unlock; instance->physical_device.initialized = true; result = enumerate_physical_devices(instance, &physical_devs, &count); if (result != VK_SUCCESS) goto unlock; count = filter_physical_devices(physical_devs, count); if (!count) { vk_free(alloc, physical_devs); goto unlock; } /* fully initialize physical devices */ for (uint32_t i = 0; i < count; i++) { struct vn_physical_device *physical_dev = &physical_devs[i]; result = vn_physical_device_init(physical_dev); if (result != VK_SUCCESS) { for (uint32_t j = 0; j < i; j++) vn_physical_device_fini(&physical_devs[j]); for (uint32_t j = i; j < count; j++) vn_physical_device_base_fini(&physical_devs[j].base); vk_free(alloc, physical_devs); goto unlock; } } result = vn_instance_enumerate_physical_device_groups_locked( instance, physical_devs, count); if (result != VK_SUCCESS) { for (uint32_t i = 0; i < count; i++) vn_physical_device_fini(&physical_devs[i]); vk_free(alloc, physical_devs); goto unlock; } instance->physical_device.devices = physical_devs; instance->physical_device.device_count = count; unlock: mtx_unlock(&instance->physical_device.mutex); return result; } /* physical device commands */ VkResult vn_EnumeratePhysicalDevices(VkInstance _instance, uint32_t *pPhysicalDeviceCount, VkPhysicalDevice *pPhysicalDevices) { struct vn_instance *instance = vn_instance_from_handle(_instance); VkResult result = vn_instance_enumerate_physical_devices_and_groups(instance); if (result != VK_SUCCESS) return vn_error(instance, result); VK_OUTARRAY_MAKE_TYPED(VkPhysicalDevice, out, pPhysicalDevices, pPhysicalDeviceCount); for (uint32_t i = 0; i < instance->physical_device.device_count; i++) { vk_outarray_append_typed(VkPhysicalDevice, &out, physical_dev) { *physical_dev = vn_physical_device_to_handle( &instance->physical_device.devices[i]); } } return vk_outarray_status(&out); } VkResult vn_EnumeratePhysicalDeviceGroups( VkInstance _instance, uint32_t *pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties *pPhysicalDeviceGroupProperties) { struct vn_instance *instance = vn_instance_from_handle(_instance); VkResult result = vn_instance_enumerate_physical_devices_and_groups(instance); if (result != VK_SUCCESS) return vn_error(instance, result); VK_OUTARRAY_MAKE_TYPED(VkPhysicalDeviceGroupProperties, out, pPhysicalDeviceGroupProperties, pPhysicalDeviceGroupCount); for (uint32_t i = 0; i < instance->physical_device.group_count; i++) { vk_outarray_append_typed(VkPhysicalDeviceGroupProperties, &out, props) { *props = instance->physical_device.groups[i]; } } return vk_outarray_status(&out); } VkResult vn_EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, const char *pLayerName, uint32_t *pPropertyCount, VkExtensionProperties *pProperties) { struct vn_physical_device *physical_dev = vn_physical_device_from_handle(physicalDevice); if (pLayerName) return vn_error(physical_dev->instance, VK_ERROR_LAYER_NOT_PRESENT); VK_OUTARRAY_MAKE_TYPED(VkExtensionProperties, out, pProperties, pPropertyCount); for (uint32_t i = 0; i < VK_DEVICE_EXTENSION_COUNT; i++) { if (physical_dev->base.base.supported_extensions.extensions[i]) { vk_outarray_append_typed(VkExtensionProperties, &out, prop) { *prop = vk_device_extensions[i]; prop->specVersion = physical_dev->extension_spec_versions[i]; } } } return vk_outarray_status(&out); } VkResult vn_EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount, VkLayerProperties *pProperties) { *pPropertyCount = 0; return VK_SUCCESS; } static struct vn_format_properties_entry * vn_physical_device_get_format_properties( struct vn_physical_device *physical_dev, VkFormat format) { return util_sparse_array_get(&physical_dev->format_properties, format); } static void vn_physical_device_add_format_properties( struct vn_physical_device *physical_dev, struct vn_format_properties_entry *entry, const VkFormatProperties *props, const VkFormatProperties3 *props3) { simple_mtx_lock(&physical_dev->format_update_mutex); if (!entry->valid) { entry->properties = *props; entry->valid = true; } if (props3 && !entry->props3_valid) { entry->properties3 = *props3; entry->props3_valid = true; } simple_mtx_unlock(&physical_dev->format_update_mutex); } void vn_GetPhysicalDeviceQueueFamilyProperties2( VkPhysicalDevice physicalDevice, uint32_t *pQueueFamilyPropertyCount, VkQueueFamilyProperties2 *pQueueFamilyProperties) { struct vn_physical_device *physical_dev = vn_physical_device_from_handle(physicalDevice); VK_OUTARRAY_MAKE_TYPED(VkQueueFamilyProperties2, out, pQueueFamilyProperties, pQueueFamilyPropertyCount); for (uint32_t i = 0; i < physical_dev->queue_family_count; i++) { vk_outarray_append_typed(VkQueueFamilyProperties2, &out, props) { *props = physical_dev->queue_family_properties[i]; } } } void vn_GetPhysicalDeviceMemoryProperties2( VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2 *pMemoryProperties) { struct vn_physical_device *physical_dev = vn_physical_device_from_handle(physicalDevice); struct vn_ring *ring = physical_dev->instance->ring.ring; VkPhysicalDeviceMemoryBudgetPropertiesEXT *memory_budget = NULL; /* Don't waste time searching for unsupported structs. */ if (physical_dev->base.base.supported_extensions.EXT_memory_budget) { memory_budget = vk_find_struct(pMemoryProperties->pNext, PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT); } /* When the app queries invariant memory properties, we return a cached * copy. For dynamic properties, we must query the server. */ if (memory_budget) { vn_call_vkGetPhysicalDeviceMemoryProperties2(ring, physicalDevice, pMemoryProperties); } /* Even when we query the server for memory properties, we must still * overwrite the invariant memory properties returned from the server with * our cached version. Our cached version may differ from the server's * version due to workarounds. */ pMemoryProperties->memoryProperties = physical_dev->memory_properties; } void vn_GetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2 *pFormatProperties) { struct vn_physical_device *physical_dev = vn_physical_device_from_handle(physicalDevice); struct vn_ring *ring = physical_dev->instance->ring.ring; /* VkFormatProperties3 is cached if its the only struct in pNext */ VkFormatProperties3 *props3 = NULL; if (pFormatProperties->pNext) { const VkBaseOutStructure *base = pFormatProperties->pNext; if (base->sType == VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_3 && base->pNext == NULL) { props3 = (VkFormatProperties3 *)base; } } struct vn_format_properties_entry *entry = NULL; if (!pFormatProperties->pNext || props3) { entry = vn_physical_device_get_format_properties(physical_dev, format); if (entry->valid) { const bool has_valid_props3 = props3 && entry->props3_valid; if (has_valid_props3) *props3 = entry->properties3; /* Make the host call if our cache doesn't have props3 but the app * now requests it. */ if (!props3 || has_valid_props3) { pFormatProperties->formatProperties = entry->properties; pFormatProperties->pNext = props3; return; } } } vn_call_vkGetPhysicalDeviceFormatProperties2(ring, physicalDevice, format, pFormatProperties); if (entry) { vn_physical_device_add_format_properties( physical_dev, entry, &pFormatProperties->formatProperties, props3); } } struct vn_physical_device_image_format_info { VkPhysicalDeviceImageFormatInfo2 format; VkPhysicalDeviceExternalImageFormatInfo external; VkImageFormatListCreateInfo list; VkImageStencilUsageCreateInfo stencil_usage; VkPhysicalDeviceImageDrmFormatModifierInfoEXT modifier; }; static const VkPhysicalDeviceImageFormatInfo2 * vn_physical_device_fix_image_format_info( const VkPhysicalDeviceImageFormatInfo2 *info, const VkExternalMemoryHandleTypeFlagBits renderer_handle_type, struct vn_physical_device_image_format_info *local_info) { local_info->format = *info; VkBaseOutStructure *dst = (void *)&local_info->format; bool is_ahb = false; bool has_format_list = false; /* we should generate deep copy functions... */ vk_foreach_struct_const(src, info->pNext) { void *pnext = NULL; switch (src->sType) { case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO: memcpy(&local_info->external, src, sizeof(local_info->external)); is_ahb = local_info->external.handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID; local_info->external.handleType = renderer_handle_type; pnext = &local_info->external; break; case VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO: has_format_list = true; memcpy(&local_info->list, src, sizeof(local_info->list)); pnext = &local_info->list; break; case VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO: memcpy(&local_info->stencil_usage, src, sizeof(local_info->stencil_usage)); pnext = &local_info->stencil_usage; break; case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT: memcpy(&local_info->modifier, src, sizeof(local_info->modifier)); pnext = &local_info->modifier; break; default: break; } if (pnext) { dst->pNext = pnext; dst = pnext; } } if (is_ahb) { assert(local_info->format.tiling != VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT); local_info->format.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT; if (!vn_android_get_drm_format_modifier_info(&local_info->format, &local_info->modifier)) return NULL; dst->pNext = (void *)&local_info->modifier; dst = dst->pNext; if ((info->flags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT) && (!has_format_list || !local_info->list.viewFormatCount)) { /* 12.3. Images * * If tiling is VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT and flags * contains VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT, then the pNext chain * must include a VkImageFormatListCreateInfo structure with non-zero * viewFormatCount. */ VkImageFormatListCreateInfo *list = &local_info->list; uint32_t vcount = 0; const VkFormat *vformats = vn_android_format_to_view_formats(info->format, &vcount); if (!vformats) { /* local_info persists through the image format query call */ vformats = &local_info->format.format; vcount = 1; } list->sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO; list->viewFormatCount = vcount; list->pViewFormats = vformats; if (!has_format_list) { dst->pNext = (void *)list; dst = dst->pNext; } } } dst->pNext = NULL; return &local_info->format; } static uint32_t vn_modifier_plane_count(struct vn_physical_device *physical_dev, VkFormat format, uint64_t modifier) { VkPhysicalDevice physical_dev_handle = vn_physical_device_to_handle(physical_dev); VkDrmFormatModifierPropertiesListEXT modifier_list = { .sType = VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT, .pDrmFormatModifierProperties = NULL, }; VkFormatProperties2 format_props = { .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2, .pNext = &modifier_list, }; vn_GetPhysicalDeviceFormatProperties2(physical_dev_handle, format, &format_props); STACK_ARRAY(VkDrmFormatModifierPropertiesEXT, modifier_props, modifier_list.drmFormatModifierCount); if (!modifier_props) return 0; modifier_list.pDrmFormatModifierProperties = modifier_props; vn_GetPhysicalDeviceFormatProperties2(physical_dev_handle, format, &format_props); uint32_t plane_count = 0; for (uint32_t i = 0; i < modifier_list.drmFormatModifierCount; i++) { const struct VkDrmFormatModifierPropertiesEXT *props = &modifier_list.pDrmFormatModifierProperties[i]; if (modifier == props->drmFormatModifier) { plane_count = props->drmFormatModifierPlaneCount; break; } } STACK_ARRAY_FINISH(modifier_props); return plane_count; } static bool vn_image_get_image_format_key( struct vn_physical_device *physical_dev, const VkPhysicalDeviceImageFormatInfo2 *format_info, const VkImageFormatProperties2 *format_props, uint8_t *key) { struct mesa_sha1 sha1_ctx; if (!physical_dev->image_format_cache.ht) return false; _mesa_sha1_init(&sha1_ctx); /* VUID-VkPhysicalDeviceImageFormatInfo2-pNext-pNext * Each pNext member of any structure (including this one) in the pNext * chain must be either NULL or a pointer to a valid instance of * VkImageCompressionControlEXT, VkImageFormatListCreateInfo, * VkImageStencilUsageCreateInfo, VkOpticalFlowImageFormatInfoNV, * VkPhysicalDeviceExternalImageFormatInfo, * VkPhysicalDeviceImageDrmFormatModifierInfoEXT, * VkPhysicalDeviceImageViewImageFormatInfoEXT, or VkVideoProfileListInfoKHR * * Exclude VkOpticalFlowImageFormatInfoNV and VkVideoProfileListInfoKHR */ if (format_info->pNext) { vk_foreach_struct_const(src, format_info->pNext) { switch (src->sType) { case VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT: { struct VkImageCompressionControlEXT *compression_control = (struct VkImageCompressionControlEXT *)src; _mesa_sha1_update(&sha1_ctx, &compression_control->flags, sizeof(VkImageCompressionFlagsEXT)); _mesa_sha1_update( &sha1_ctx, compression_control->pFixedRateFlags, sizeof(uint32_t) * compression_control->compressionControlPlaneCount); break; } case VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO: { struct VkImageFormatListCreateInfo *format_list = (struct VkImageFormatListCreateInfo *)src; _mesa_sha1_update( &sha1_ctx, format_list->pViewFormats, sizeof(VkFormat) * format_list->viewFormatCount); break; } case VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO: { struct VkImageStencilUsageCreateInfo *stencil_usage = (struct VkImageStencilUsageCreateInfo *)src; _mesa_sha1_update(&sha1_ctx, &stencil_usage->stencilUsage, sizeof(VkImageUsageFlags)); break; } case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO: { struct VkPhysicalDeviceExternalImageFormatInfo *ext_image = (struct VkPhysicalDeviceExternalImageFormatInfo *)src; _mesa_sha1_update(&sha1_ctx, &ext_image->handleType, sizeof(VkExternalMemoryHandleTypeFlagBits)); break; } case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT: { struct VkPhysicalDeviceImageDrmFormatModifierInfoEXT *modifier_info = (struct VkPhysicalDeviceImageDrmFormatModifierInfoEXT *)src; _mesa_sha1_update(&sha1_ctx, &modifier_info->drmFormatModifier, sizeof(uint64_t)); if (modifier_info->sharingMode == VK_SHARING_MODE_CONCURRENT) { _mesa_sha1_update( &sha1_ctx, modifier_info->pQueueFamilyIndices, sizeof(uint32_t) * modifier_info->queueFamilyIndexCount); } break; } case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_IMAGE_FORMAT_INFO_EXT: { struct VkPhysicalDeviceImageViewImageFormatInfoEXT *view_image = (struct VkPhysicalDeviceImageViewImageFormatInfoEXT *)src; _mesa_sha1_update(&sha1_ctx, &view_image->imageViewType, sizeof(VkImageViewType)); break; } default: physical_dev->image_format_cache.debug.cache_skip_count++; return false; } } } /* Hash pImageFormatProperties pNext as well since some of them are * optional in that they can be attached without a corresponding pNext * in pImageFormatInfo. * * VUID-VkImageFormatProperties2-pNext-pNext * Each pNext member of any structure (including this one) in the pNext * chain must be either NULL or a pointer to a valid instance of * VkAndroidHardwareBufferUsageANDROID, VkExternalImageFormatProperties, * VkFilterCubicImageViewImageFormatPropertiesEXT, * VkHostImageCopyDevicePerformanceQueryEXT, * VkImageCompressionPropertiesEXT, * VkSamplerYcbcrConversionImageFormatProperties, or * VkTextureLODGatherFormatPropertiesAMD * * VkAndroidHardwareBufferUsageANDROID is handled outside of the cache. * VkFilterCubicImageViewImageFormatPropertiesEXT, * VkHostImageCopyDevicePerformanceQueryEXT, * VkHostImageCopyDevicePerformanceQueryEXT, * VkTextureLODGatherFormatPropertiesAMD are not supported */ if (format_props->pNext) { vk_foreach_struct_const(src, format_props->pNext) { switch (src->sType) { case VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES: case VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_PROPERTIES_EXT: case VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES: _mesa_sha1_update(&sha1_ctx, &src->sType, sizeof(VkStructureType)); break; default: physical_dev->image_format_cache.debug.cache_skip_count++; return false; } } } static const size_t format_info_2_hash_block_size = sizeof(VkFormat) + sizeof(VkImageType) + sizeof(VkImageTiling) + sizeof(VkImageUsageFlags) + sizeof(VkImageCreateFlags); _mesa_sha1_update(&sha1_ctx, &format_info->format, format_info_2_hash_block_size); _mesa_sha1_final(&sha1_ctx, key); return true; } static bool vn_image_init_format_from_cache( struct vn_physical_device *physical_dev, struct VkImageFormatProperties2 *pImageFormatProperties, VkResult *cached_result, uint8_t *key) { struct vn_image_format_properties_cache *cache = &physical_dev->image_format_cache; assert(cache->ht); simple_mtx_lock(&cache->mutex); struct hash_entry *hash_entry = _mesa_hash_table_search(cache->ht, key); if (hash_entry) { struct vn_image_format_cache_entry *cache_entry = hash_entry->data; /* Copy the properties even if the cached_result is not supported. * Per spec 1.3.275 "If the combination of parameters to * vkGetPhysicalDeviceImageFormatProperties2 is not supported by the * implementation for use in vkCreateImage, then all members of * imageFormatProperties will be filled with zero." */ pImageFormatProperties->imageFormatProperties = cache_entry->properties.format.imageFormatProperties; *cached_result = cache_entry->properties.cached_result; if (pImageFormatProperties->pNext) { vk_foreach_struct_const(src, pImageFormatProperties->pNext) { switch (src->sType) { case VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES: { struct VkExternalImageFormatProperties *ext_image = (struct VkExternalImageFormatProperties *)src; ext_image->externalMemoryProperties = cache_entry->properties.ext_image.externalMemoryProperties; break; } case VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_PROPERTIES_EXT: { struct VkImageCompressionPropertiesEXT *compression = (struct VkImageCompressionPropertiesEXT *)src; compression->imageCompressionFlags = cache_entry->properties.compression.imageCompressionFlags; compression->imageCompressionFixedRateFlags = cache_entry->properties.compression .imageCompressionFixedRateFlags; break; } case VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES: { struct VkSamplerYcbcrConversionImageFormatProperties *ycbcr_conversion = (struct VkSamplerYcbcrConversionImageFormatProperties *) src; ycbcr_conversion->combinedImageSamplerDescriptorCount = cache_entry->properties.ycbcr_conversion .combinedImageSamplerDescriptorCount; break; } default: unreachable("unexpected format props pNext"); } } } list_move_to(&cache_entry->head, &cache->lru); p_atomic_inc(&cache->debug.cache_hit_count); } else { p_atomic_inc(&cache->debug.cache_miss_count); } simple_mtx_unlock(&cache->mutex); return !!hash_entry; } static void vn_image_store_format_in_cache( struct vn_physical_device *physical_dev, uint8_t *key, struct VkImageFormatProperties2 *pImageFormatProperties, VkResult cached_result) { const VkAllocationCallbacks *alloc = &physical_dev->base.base.instance->alloc; struct vn_image_format_properties_cache *cache = &physical_dev->image_format_cache; struct vn_image_format_cache_entry *cache_entry = NULL; assert(cache->ht); simple_mtx_lock(&cache->mutex); /* Check if entry was added before lock */ if (_mesa_hash_table_search(cache->ht, key)) { simple_mtx_unlock(&cache->mutex); return; } if (_mesa_hash_table_num_entries(cache->ht) == IMAGE_FORMAT_CACHE_MAX_ENTRIES) { /* Evict/use the last entry in the lru list for this new entry */ cache_entry = list_last_entry(&cache->lru, struct vn_image_format_cache_entry, head); _mesa_hash_table_remove_key(cache->ht, cache_entry->key); list_del(&cache_entry->head); } else { cache_entry = vk_zalloc(alloc, sizeof(*cache_entry), VN_DEFAULT_ALIGN, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); if (!cache_entry) { simple_mtx_unlock(&cache->mutex); return; } } if (pImageFormatProperties->pNext) { vk_foreach_struct_const(src, pImageFormatProperties->pNext) { switch (src->sType) { case VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES: { cache_entry->properties.ext_image = *((struct VkExternalImageFormatProperties *)src); break; } case VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_PROPERTIES_EXT: { cache_entry->properties.compression = *((struct VkImageCompressionPropertiesEXT *)src); break; } case VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES: { cache_entry->properties.ycbcr_conversion = *((struct VkSamplerYcbcrConversionImageFormatProperties *)src); break; } default: unreachable("unexpected format props pNext"); } } } cache_entry->properties.format = *pImageFormatProperties; cache_entry->properties.cached_result = cached_result; memcpy(cache_entry->key, key, SHA1_DIGEST_LENGTH); _mesa_hash_table_insert(cache->ht, cache_entry->key, cache_entry); list_add(&cache_entry->head, &cache->lru); simple_mtx_unlock(&cache->mutex); } VkResult vn_GetPhysicalDeviceImageFormatProperties2( VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo, VkImageFormatProperties2 *pImageFormatProperties) { struct vn_physical_device *physical_dev = vn_physical_device_from_handle(physicalDevice); struct vn_ring *ring = physical_dev->instance->ring.ring; const VkExternalMemoryHandleTypeFlagBits renderer_handle_type = physical_dev->external_memory.renderer_handle_type; const VkExternalMemoryHandleTypeFlags supported_handle_types = physical_dev->external_memory.supported_handle_types; const struct wsi_image_create_info *wsi_info = vk_find_struct_const( pImageFormatInfo->pNext, WSI_IMAGE_CREATE_INFO_MESA); const VkPhysicalDeviceImageDrmFormatModifierInfoEXT *modifier_info = vk_find_struct_const( pImageFormatInfo->pNext, PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT); /* force common wsi into choosing DRM_FORMAT_MOD_LINEAR or else fall back * to the legacy path, for which Venus also forces LINEAR for wsi images. */ if (VN_PERF(NO_TILED_WSI_IMAGE)) { if (wsi_info && modifier_info && modifier_info->drmFormatModifier != DRM_FORMAT_MOD_LINEAR) { if (VN_DEBUG(WSI)) { vn_log(physical_dev->instance, "rejecting non-linear wsi image format modifier %" PRIu64, modifier_info->drmFormatModifier); } return vn_error(physical_dev->instance, VK_ERROR_FORMAT_NOT_SUPPORTED); } } /* Integration with Xwayland (using virgl-backed gbm) may only use * modifiers for which `memory_plane_count == format_plane_count` with the * distinction defined in the spec for VkDrmFormatModifierPropertiesEXT. * * The spec also states that: * If an image is non-linear, then the partition of the image’s memory * into memory planes is implementation-specific and may be unrelated to * the partition of the image’s content into format planes. * * A modifier like I915_FORMAT_MOD_Y_TILED_CCS with an extra CCS * metadata-only _memory_ plane is not supported by virgl. In general, * since the partition of format planes into memory planes (even when their * counts match) cannot be guarantably known, the safest option is to limit * both plane counts to 1 while virgl may be involved. */ if (wsi_info && modifier_info && !physical_dev->instance->enable_wsi_multi_plane_modifiers && modifier_info->drmFormatModifier != DRM_FORMAT_MOD_LINEAR) { const uint32_t plane_count = vn_modifier_plane_count(physical_dev, pImageFormatInfo->format, modifier_info->drmFormatModifier); if (plane_count != 1) { if (VN_DEBUG(WSI)) { vn_log(physical_dev->instance, "rejecting multi-plane (%u) modifier %" PRIu64 " for wsi image with format %u", plane_count, modifier_info->drmFormatModifier, pImageFormatInfo->format); } return vn_error(physical_dev->instance, VK_ERROR_FORMAT_NOT_SUPPORTED); } } const VkPhysicalDeviceExternalImageFormatInfo *external_info = vk_find_struct_const(pImageFormatInfo->pNext, PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO); if (external_info && !external_info->handleType) external_info = NULL; struct vn_physical_device_image_format_info local_info; if (external_info) { if (!(external_info->handleType & supported_handle_types)) { return vn_error(physical_dev->instance, VK_ERROR_FORMAT_NOT_SUPPORTED); } /* Check the image tiling against the renderer handle type: * - No need to check for AHB since the tiling will either be forwarded * or overwritten based on the renderer external memory type. * - For opaque fd and dma_buf fd handle types, passthrough tiling when * the renderer external memory is dma_buf. Then we can avoid * reconstructing the structs to support drm format modifier tiling * like how we support AHB. */ if (external_info->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID) { if (renderer_handle_type == VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT && pImageFormatInfo->tiling != VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) { return vn_error(physical_dev->instance, VK_ERROR_FORMAT_NOT_SUPPORTED); } } if (external_info->handleType != renderer_handle_type) { pImageFormatInfo = vn_physical_device_fix_image_format_info( pImageFormatInfo, renderer_handle_type, &local_info); if (!pImageFormatInfo) { return vn_error(physical_dev->instance, VK_ERROR_FORMAT_NOT_SUPPORTED); } } } /* Since venus-protocol doesn't pass the wsi_image_create_info struct, we * must remove the ALIAS_BIT here and in vn_wsi_create_image(). * ANV rejects the bit for external+nonlinear images that don't have WSI * info chained. */ if (wsi_info && physical_dev->renderer_driver_id == VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA) { if (pImageFormatInfo != &local_info.format) { local_info.format = *pImageFormatInfo; pImageFormatInfo = &local_info.format; } local_info.format.flags &= ~VK_IMAGE_CREATE_ALIAS_BIT; } /* Check if image format props is in the cache. */ uint8_t key[SHA1_DIGEST_LENGTH] = { 0 }; const bool cacheable = vn_image_get_image_format_key( physical_dev, pImageFormatInfo, pImageFormatProperties, key); VkResult result = VK_SUCCESS; if (!(cacheable && vn_image_init_format_from_cache(physical_dev, pImageFormatProperties, &result, key))) { result = vn_call_vkGetPhysicalDeviceImageFormatProperties2( ring, physicalDevice, pImageFormatInfo, pImageFormatProperties); /* If cacheable, cache successful and unsupported results. */ if (cacheable && (result == VK_SUCCESS || result == VK_ERROR_FORMAT_NOT_SUPPORTED || result == VK_ERROR_IMAGE_USAGE_NOT_SUPPORTED_KHR)) { vn_image_store_format_in_cache(physical_dev, key, pImageFormatProperties, result); } } if (result != VK_SUCCESS || !external_info) return vn_result(physical_dev->instance, result); if (external_info->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID) { VkAndroidHardwareBufferUsageANDROID *ahb_usage = vk_find_struct(pImageFormatProperties->pNext, ANDROID_HARDWARE_BUFFER_USAGE_ANDROID); if (ahb_usage) { ahb_usage->androidHardwareBufferUsage = vk_image_usage_to_ahb_usage( pImageFormatInfo->flags, pImageFormatInfo->usage); } /* AHBs with mipmap usage will ignore this property */ pImageFormatProperties->imageFormatProperties.maxMipLevels = 1; } VkExternalImageFormatProperties *img_props = vk_find_struct( pImageFormatProperties->pNext, EXTERNAL_IMAGE_FORMAT_PROPERTIES); if (!img_props) return VK_SUCCESS; VkExternalMemoryProperties *mem_props = &img_props->externalMemoryProperties; if (renderer_handle_type == VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT && !physical_dev->instance->renderer->info.has_dma_buf_import) { mem_props->externalMemoryFeatures &= ~VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT; } if (external_info->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID) { /* AHB backed image requires renderer to support import bit */ if (!(mem_props->externalMemoryFeatures & VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT)) return vn_error(physical_dev->instance, VK_ERROR_FORMAT_NOT_SUPPORTED); mem_props->externalMemoryFeatures = VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT | VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT | VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT; mem_props->exportFromImportedHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID; mem_props->compatibleHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID; } else { mem_props->compatibleHandleTypes = supported_handle_types; mem_props->exportFromImportedHandleTypes = (mem_props->exportFromImportedHandleTypes & renderer_handle_type) ? supported_handle_types : 0; } return VK_SUCCESS; } void vn_GetPhysicalDeviceSparseImageFormatProperties2( VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2 *pFormatInfo, uint32_t *pPropertyCount, VkSparseImageFormatProperties2 *pProperties) { struct vn_physical_device *physical_dev = vn_physical_device_from_handle(physicalDevice); struct vn_ring *ring = physical_dev->instance->ring.ring; /* If VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT is not supported for the given * arguments, pPropertyCount will be set to zero upon return, and no data * will be written to pProperties. */ if (physical_dev->sparse_binding_disabled) { *pPropertyCount = 0; return; } /* TODO per-device cache */ vn_call_vkGetPhysicalDeviceSparseImageFormatProperties2( ring, physicalDevice, pFormatInfo, pPropertyCount, pProperties); } void vn_GetPhysicalDeviceExternalBufferProperties( VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo *pExternalBufferInfo, VkExternalBufferProperties *pExternalBufferProperties) { struct vn_physical_device *physical_dev = vn_physical_device_from_handle(physicalDevice); struct vn_ring *ring = physical_dev->instance->ring.ring; const VkExternalMemoryHandleTypeFlagBits renderer_handle_type = physical_dev->external_memory.renderer_handle_type; const VkExternalMemoryHandleTypeFlags supported_handle_types = physical_dev->external_memory.supported_handle_types; const bool is_ahb = pExternalBufferInfo->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID; VkExternalMemoryProperties *props = &pExternalBufferProperties->externalMemoryProperties; if (!(pExternalBufferInfo->handleType & supported_handle_types)) { props->compatibleHandleTypes = pExternalBufferInfo->handleType; props->exportFromImportedHandleTypes = 0; props->externalMemoryFeatures = 0; return; } VkPhysicalDeviceExternalBufferInfo local_info; if (pExternalBufferInfo->handleType != renderer_handle_type) { local_info = *pExternalBufferInfo; local_info.handleType = renderer_handle_type; pExternalBufferInfo = &local_info; } /* TODO per-device cache */ vn_call_vkGetPhysicalDeviceExternalBufferProperties( ring, physicalDevice, pExternalBufferInfo, pExternalBufferProperties); if (renderer_handle_type == VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT && !physical_dev->instance->renderer->info.has_dma_buf_import) { props->externalMemoryFeatures &= ~VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT; } if (is_ahb) { props->compatibleHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID; /* AHB backed buffer requires renderer to support import bit while it * also requires the renderer to must not advertise dedicated only bit */ if (!(props->externalMemoryFeatures & VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT) || (props->externalMemoryFeatures & VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT)) { props->externalMemoryFeatures = 0; props->exportFromImportedHandleTypes = 0; return; } props->externalMemoryFeatures = VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT | VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT; props->exportFromImportedHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID; } else { props->compatibleHandleTypes = supported_handle_types; props->exportFromImportedHandleTypes = (props->exportFromImportedHandleTypes & renderer_handle_type) ? supported_handle_types : 0; } } void vn_GetPhysicalDeviceExternalFenceProperties( VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo *pExternalFenceInfo, VkExternalFenceProperties *pExternalFenceProperties) { struct vn_physical_device *physical_dev = vn_physical_device_from_handle(physicalDevice); if (pExternalFenceInfo->handleType & physical_dev->external_fence_handles) { pExternalFenceProperties->compatibleHandleTypes = physical_dev->external_fence_handles; pExternalFenceProperties->exportFromImportedHandleTypes = physical_dev->external_fence_handles; pExternalFenceProperties->externalFenceFeatures = VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT | VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT; } else { pExternalFenceProperties->compatibleHandleTypes = 0; pExternalFenceProperties->exportFromImportedHandleTypes = 0; pExternalFenceProperties->externalFenceFeatures = 0; } } void vn_GetPhysicalDeviceExternalSemaphoreProperties( VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo *pExternalSemaphoreInfo, VkExternalSemaphoreProperties *pExternalSemaphoreProperties) { struct vn_physical_device *physical_dev = vn_physical_device_from_handle(physicalDevice); const VkSemaphoreTypeCreateInfo *type_info = vk_find_struct_const( pExternalSemaphoreInfo->pNext, SEMAPHORE_TYPE_CREATE_INFO); const VkSemaphoreType sem_type = type_info ? type_info->semaphoreType : VK_SEMAPHORE_TYPE_BINARY; const VkExternalSemaphoreHandleTypeFlags valid_handles = sem_type == VK_SEMAPHORE_TYPE_BINARY ? physical_dev->external_binary_semaphore_handles : physical_dev->external_timeline_semaphore_handles; if (pExternalSemaphoreInfo->handleType & valid_handles) { pExternalSemaphoreProperties->compatibleHandleTypes = valid_handles; pExternalSemaphoreProperties->exportFromImportedHandleTypes = valid_handles; pExternalSemaphoreProperties->externalSemaphoreFeatures = VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT | VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT; } else { pExternalSemaphoreProperties->compatibleHandleTypes = 0; pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0; pExternalSemaphoreProperties->externalSemaphoreFeatures = 0; } } VkResult vn_GetPhysicalDeviceCalibrateableTimeDomainsEXT( VkPhysicalDevice physicalDevice, uint32_t *pTimeDomainCount, VkTimeDomainEXT *pTimeDomains) { struct vn_physical_device *physical_dev = vn_physical_device_from_handle(physicalDevice); struct vn_ring *ring = physical_dev->instance->ring.ring; return vn_call_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT( ring, physicalDevice, pTimeDomainCount, pTimeDomains); } VkResult vn_GetPhysicalDeviceFragmentShadingRatesKHR( VkPhysicalDevice physicalDevice, uint32_t *pFragmentShadingRateCount, VkPhysicalDeviceFragmentShadingRateKHR *pFragmentShadingRates) { struct vn_physical_device *physical_dev = vn_physical_device_from_handle(physicalDevice); struct vn_ring *ring = physical_dev->instance->ring.ring; return vn_call_vkGetPhysicalDeviceFragmentShadingRatesKHR( ring, physicalDevice, pFragmentShadingRateCount, pFragmentShadingRates); }