1 /* 2 * Copyright 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.graphics.cts; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertNotNull; 21 import static org.junit.Assert.assertNull; 22 import static org.junit.Assert.assertTrue; 23 import static org.junit.Assume.assumeTrue; 24 25 import android.content.pm.FeatureInfo; 26 import android.content.pm.PackageManager; 27 import android.util.ArrayMap; 28 import android.util.Log; 29 30 import androidx.test.InstrumentationRegistry; 31 import androidx.test.filters.SmallTest; 32 import androidx.test.runner.AndroidJUnit4; 33 34 import com.android.compatibility.common.util.CddTest; 35 import com.android.compatibility.common.util.PropertyUtil; 36 37 import org.json.JSONArray; 38 import org.json.JSONException; 39 import org.json.JSONObject; 40 import org.junit.Before; 41 import org.junit.Test; 42 import org.junit.runner.RunWith; 43 44 import java.util.Arrays; 45 import java.util.HashSet; 46 import java.util.Map; 47 import java.util.Set; 48 49 /** 50 * Test that the Vulkan loader is present, supports the required extensions, and that system 51 * features accurately indicate the capabilities of the Vulkan driver if one exists. 52 */ 53 @SmallTest 54 @RunWith(AndroidJUnit4.class) 55 public class VulkanFeaturesTest { 56 57 static { 58 System.loadLibrary("ctsgraphics_jni"); 59 } 60 61 private static final String TAG = VulkanFeaturesTest.class.getSimpleName(); 62 private static final boolean DEBUG = false; 63 64 // Require patch version 3 for Vulkan 1.0: It was the first publicly available version, 65 // and there was an important bugfix relative to 1.0.2. 66 private static final int VULKAN_1_0 = 0x00400003; // 1.0.3 67 private static final int VULKAN_1_1 = 0x00401000; // 1.1.0 68 private static final int VULKAN_1_2 = 0x00402000; // 1.2.0 69 private static final int VULKAN_1_3 = 0x00403000; // 1.3.0 70 71 private static final String VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME = 72 "VK_ANDROID_external_memory_android_hardware_buffer"; 73 private static final int VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_SPEC_VERSION = 2; 74 75 private static final String VK_KHR_SURFACE = "VK_KHR_surface"; 76 private static final int VK_KHR_SURFACE_SPEC_VERSION = 25; 77 78 private static final String VK_KHR_ANDROID_SURFACE = "VK_KHR_android_surface"; 79 private static final int VK_KHR_ANDROID_SURFACE_SPEC_VERSION = 6; 80 81 private static final String VK_KHR_SWAPCHAIN = "VK_KHR_swapchain"; 82 private static final int VK_KHR_SWAPCHAIN_SPEC_VERSION = 68; 83 84 private static final String VK_KHR_MAINTENANCE1 = "VK_KHR_maintenance1"; 85 private static final int VK_KHR_MAINTENANCE1_SPEC_VERSION = 1; 86 87 private static final String VK_KHR_INCREMENTAL_PRESENT = "VK_KHR_incremental_present"; 88 private static final int VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION = 1; 89 90 private static final int VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT = 0x8; 91 private static final int VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT = 0x10; 92 private static final int VK_PHYSICAL_DEVICE_TYPE_CPU = 4; 93 94 private static final int API_LEVEL_BEFORE_ANDROID_HARDWARE_BUFFER_REQ = 28; 95 96 private static final int DEQP_LEVEL_FOR_V = 0x7E80301; 97 private static final int DEQP_LEVEL_FOR_U = 0x7E70301; 98 private static final int DEQP_LEVEL_FOR_T = 0x7E60301; 99 private static final int DEQP_LEVEL_FOR_S = 0x7E50301; 100 private static final int DEQP_LEVEL_FOR_R = 0x7E40301; 101 private static final int DEQP_LEVEL_BEFORE_R = 0; 102 103 private static final Map<Integer, String[]> DEQP_EXTENSIONS_MAP = new ArrayMap<>(); 104 static { DEQP_EXTENSIONS_MAP.put( DEQP_LEVEL_FOR_V, new String[] { "VK_KHR_calibrated_timestamps", "VK_KHR_cooperative_matrix", "VK_KHR_index_type_uint8", "VK_KHR_line_rasterization", "VK_KHR_load_store_op_none", "VK_KHR_maintenance5", "VK_KHR_maintenance6", "VK_KHR_map_memory2", "VK_KHR_ray_tracing_position_fetch", "VK_KHR_shader_expect_assume", "VK_KHR_shader_quad_control", "VK_KHR_vertex_attribute_divisor", "VK_ANDROID_external_format_resolve", "VK_KHR_dynamic_rendering_local_read", "VK_KHR_shader_float_controls2", "VK_KHR_shader_maximal_reconvergence", "VK_KHR_shader_subgroup_rotate", "VK_KHR_video_decode_av1", "VK_KHR_video_encode_h264", "VK_KHR_video_encode_h265", "VK_KHR_video_encode_queue", "VK_KHR_video_maintenance1"})105 DEQP_EXTENSIONS_MAP.put( 106 DEQP_LEVEL_FOR_V, 107 new String[] { 108 "VK_KHR_calibrated_timestamps", 109 "VK_KHR_cooperative_matrix", 110 "VK_KHR_index_type_uint8", 111 "VK_KHR_line_rasterization", 112 "VK_KHR_load_store_op_none", 113 "VK_KHR_maintenance5", 114 "VK_KHR_maintenance6", 115 "VK_KHR_map_memory2", 116 "VK_KHR_ray_tracing_position_fetch", 117 "VK_KHR_shader_expect_assume", 118 "VK_KHR_shader_quad_control", 119 "VK_KHR_vertex_attribute_divisor", 120 "VK_ANDROID_external_format_resolve", 121 "VK_KHR_dynamic_rendering_local_read", 122 "VK_KHR_shader_float_controls2", 123 "VK_KHR_shader_maximal_reconvergence", 124 "VK_KHR_shader_subgroup_rotate", 125 "VK_KHR_video_decode_av1", 126 "VK_KHR_video_encode_h264", 127 "VK_KHR_video_encode_h265", 128 "VK_KHR_video_encode_queue", 129 "VK_KHR_video_maintenance1"}); DEQP_EXTENSIONS_MAP.put( DEQP_LEVEL_FOR_U, new String[] { "VK_KHR_fragment_shader_barycentric", "VK_KHR_ray_tracing_maintenance1", "VK_KHR_video_decode_h264", "VK_KHR_video_decode_h265", "VK_KHR_video_decode_queue", "VK_KHR_video_queue", "VK_GOOGLE_user_type"})130 DEQP_EXTENSIONS_MAP.put( 131 DEQP_LEVEL_FOR_U, 132 new String[] { 133 "VK_KHR_fragment_shader_barycentric", 134 "VK_KHR_ray_tracing_maintenance1", 135 "VK_KHR_video_decode_h264", 136 "VK_KHR_video_decode_h265", 137 "VK_KHR_video_decode_queue", 138 "VK_KHR_video_queue", 139 "VK_GOOGLE_user_type"}); DEQP_EXTENSIONS_MAP.put( DEQP_LEVEL_FOR_T, new String[] { "VK_KHR_dynamic_rendering", "VK_KHR_format_feature_flags2", "VK_KHR_global_priority", "VK_KHR_maintenance4", "VK_KHR_portability_subset", "VK_KHR_present_id", "VK_KHR_present_wait", "VK_KHR_shader_subgroup_uniform_control_flow", "VK_KHR_portability_enumeration"})140 DEQP_EXTENSIONS_MAP.put( 141 DEQP_LEVEL_FOR_T, 142 new String[] { 143 "VK_KHR_dynamic_rendering", 144 "VK_KHR_format_feature_flags2", 145 "VK_KHR_global_priority", 146 "VK_KHR_maintenance4", 147 "VK_KHR_portability_subset", 148 "VK_KHR_present_id", 149 "VK_KHR_present_wait", 150 "VK_KHR_shader_subgroup_uniform_control_flow", 151 "VK_KHR_portability_enumeration"}); DEQP_EXTENSIONS_MAP.put( DEQP_LEVEL_FOR_S, new String[] { "VK_KHR_copy_commands2", "VK_KHR_shader_terminate_invocation", "VK_KHR_ray_tracing_pipeline", "VK_KHR_ray_query", "VK_KHR_acceleration_structure", "VK_KHR_pipeline_library", "VK_KHR_deferred_host_operations", "VK_KHR_fragment_shading_rate", "VK_KHR_zero_initialize_workgroup_memory", "VK_KHR_workgroup_memory_explicit_layout", "VK_KHR_synchronization2", "VK_KHR_shader_integer_dot_product"})152 DEQP_EXTENSIONS_MAP.put( 153 DEQP_LEVEL_FOR_S, 154 new String[] { 155 "VK_KHR_copy_commands2", 156 "VK_KHR_shader_terminate_invocation", 157 "VK_KHR_ray_tracing_pipeline", 158 "VK_KHR_ray_query", 159 "VK_KHR_acceleration_structure", 160 "VK_KHR_pipeline_library", 161 "VK_KHR_deferred_host_operations", 162 "VK_KHR_fragment_shading_rate", 163 "VK_KHR_zero_initialize_workgroup_memory", 164 "VK_KHR_workgroup_memory_explicit_layout", 165 "VK_KHR_synchronization2", 166 "VK_KHR_shader_integer_dot_product"}); DEQP_EXTENSIONS_MAP.put( DEQP_LEVEL_FOR_R, new String[] { "VK_KHR_swapchain", "VK_KHR_swapchain_mutable_format", "VK_KHR_display_swapchain", "VK_KHR_sampler_mirror_clamp_to_edge", "VK_KHR_external_memory_win32", "VK_KHR_external_memory_fd", "VK_KHR_win32_keyed_mutex", "VK_KHR_external_semaphore_win32", "VK_KHR_external_semaphore_fd", "VK_KHR_push_descriptor", "VK_KHR_shader_float16_int8", "VK_KHR_incremental_present", "VK_KHR_8bit_storage", "VK_KHR_create_renderpass2", "VK_KHR_shared_presentable_image", "VK_KHR_external_fence_win32", "VK_KHR_external_fence_fd", "VK_KHR_image_format_list", "VK_KHR_driver_properties", "VK_KHR_shader_float_controls", "VK_KHR_depth_stencil_resolve", "VK_KHR_draw_indirect_count", "VK_KHR_shader_atomic_int64", "VK_KHR_vulkan_memory_model", "VK_KHR_uniform_buffer_standard_layout", "VK_KHR_imageless_framebuffer", "VK_KHR_shader_subgroup_extended_types", "VK_KHR_buffer_device_address", "VK_KHR_separate_depth_stencil_layouts", "VK_KHR_timeline_semaphore", "VK_KHR_spirv_1_4", "VK_KHR_pipeline_executable_properties", "VK_KHR_shader_clock", "VK_KHR_performance_query", "VK_KHR_shader_non_semantic_info", "VK_KHR_surface", "VK_KHR_display", "VK_KHR_xlib_surface", "VK_KHR_xcb_surface", "VK_KHR_wayland_surface", "VK_KHR_mir_surface", "VK_KHR_android_surface", "VK_KHR_win32_surface", "VK_KHR_get_surface_capabilities2", "VK_KHR_get_display_properties2", "VK_KHR_surface_protected_capabilities", "VK_GOOGLE_decorate_string", "VK_GOOGLE_hlsl_functionality1"})167 DEQP_EXTENSIONS_MAP.put( 168 DEQP_LEVEL_FOR_R, 169 new String[] { 170 "VK_KHR_swapchain", 171 "VK_KHR_swapchain_mutable_format", 172 "VK_KHR_display_swapchain", 173 "VK_KHR_sampler_mirror_clamp_to_edge", 174 "VK_KHR_external_memory_win32", 175 "VK_KHR_external_memory_fd", 176 "VK_KHR_win32_keyed_mutex", 177 "VK_KHR_external_semaphore_win32", 178 "VK_KHR_external_semaphore_fd", 179 "VK_KHR_push_descriptor", 180 "VK_KHR_shader_float16_int8", 181 "VK_KHR_incremental_present", 182 "VK_KHR_8bit_storage", 183 "VK_KHR_create_renderpass2", 184 "VK_KHR_shared_presentable_image", 185 "VK_KHR_external_fence_win32", 186 "VK_KHR_external_fence_fd", 187 "VK_KHR_image_format_list", 188 "VK_KHR_driver_properties", 189 "VK_KHR_shader_float_controls", 190 "VK_KHR_depth_stencil_resolve", 191 "VK_KHR_draw_indirect_count", 192 "VK_KHR_shader_atomic_int64", 193 "VK_KHR_vulkan_memory_model", 194 "VK_KHR_uniform_buffer_standard_layout", 195 "VK_KHR_imageless_framebuffer", 196 "VK_KHR_shader_subgroup_extended_types", 197 "VK_KHR_buffer_device_address", 198 "VK_KHR_separate_depth_stencil_layouts", 199 "VK_KHR_timeline_semaphore", 200 "VK_KHR_spirv_1_4", 201 "VK_KHR_pipeline_executable_properties", 202 "VK_KHR_shader_clock", 203 "VK_KHR_performance_query", 204 "VK_KHR_shader_non_semantic_info", 205 "VK_KHR_surface", 206 "VK_KHR_display", 207 "VK_KHR_xlib_surface", 208 "VK_KHR_xcb_surface", 209 "VK_KHR_wayland_surface", 210 "VK_KHR_mir_surface", 211 "VK_KHR_android_surface", 212 "VK_KHR_win32_surface", 213 "VK_KHR_get_surface_capabilities2", 214 "VK_KHR_get_display_properties2", 215 "VK_KHR_surface_protected_capabilities", 216 "VK_GOOGLE_decorate_string", 217 "VK_GOOGLE_hlsl_functionality1"}); DEQP_EXTENSIONS_MAP.put( DEQP_LEVEL_BEFORE_R, new String[] { "VK_KHR_multiview", "VK_KHR_device_group", "VK_KHR_shader_draw_parameters", "VK_KHR_maintenance1", "VK_KHR_external_memory", "VK_KHR_external_semaphore", "VK_KHR_16bit_storage", "VK_KHR_descriptor_update_template", "VK_KHR_external_fence", "VK_KHR_maintenance2", "VK_KHR_variable_pointers", "VK_KHR_dedicated_allocation", "VK_KHR_storage_buffer_storage_class", "VK_KHR_relaxed_block_layout", "VK_KHR_get_memory_requirements2", "VK_KHR_sampler_ycbcr_conversion", "VK_KHR_bind_memory2", "VK_KHR_maintenance3", "VK_KHR_get_physical_device_properties2", "VK_KHR_device_group_creation", "VK_KHR_external_memory_capabilities", "VK_KHR_external_semaphore_capabilities", "VK_KHR_external_fence_capabilities", "VK_ANDROID_external_memory_android_hardware_buffer", "VK_GOOGLE_display_timing"})218 DEQP_EXTENSIONS_MAP.put( 219 DEQP_LEVEL_BEFORE_R, 220 new String[] { 221 "VK_KHR_multiview", 222 "VK_KHR_device_group", 223 "VK_KHR_shader_draw_parameters", 224 "VK_KHR_maintenance1", 225 "VK_KHR_external_memory", 226 "VK_KHR_external_semaphore", 227 "VK_KHR_16bit_storage", 228 "VK_KHR_descriptor_update_template", 229 "VK_KHR_external_fence", 230 "VK_KHR_maintenance2", 231 "VK_KHR_variable_pointers", 232 "VK_KHR_dedicated_allocation", 233 "VK_KHR_storage_buffer_storage_class", 234 "VK_KHR_relaxed_block_layout", 235 "VK_KHR_get_memory_requirements2", 236 "VK_KHR_sampler_ycbcr_conversion", 237 "VK_KHR_bind_memory2", 238 "VK_KHR_maintenance3", 239 "VK_KHR_get_physical_device_properties2", 240 "VK_KHR_device_group_creation", 241 "VK_KHR_external_memory_capabilities", 242 "VK_KHR_external_semaphore_capabilities", 243 "VK_KHR_external_fence_capabilities", 244 "VK_ANDROID_external_memory_android_hardware_buffer", 245 "VK_GOOGLE_display_timing"}); 246 } 247 248 private PackageManager mPm; 249 private FeatureInfo mVulkanHardwareLevel = null; 250 private FeatureInfo mVulkanHardwareVersion = null; 251 private FeatureInfo mVulkanHardwareCompute = null; 252 private FeatureInfo mVulkanDeqpLevel = null; 253 private JSONObject mVkJSON = null; 254 private JSONObject mVulkanDevices[]; 255 private JSONObject mBestDevice = null; 256 private boolean mIsTV = false; 257 258 @Before setup()259 public void setup() throws Throwable { 260 mPm = InstrumentationRegistry.getTargetContext().getPackageManager(); 261 FeatureInfo features[] = mPm.getSystemAvailableFeatures(); 262 if (features != null) { 263 for (FeatureInfo feature : features) { 264 if (PackageManager.FEATURE_VULKAN_HARDWARE_LEVEL.equals(feature.name)) { 265 mVulkanHardwareLevel = feature; 266 if (DEBUG) { 267 Log.d(TAG, feature.name + "=" + feature.version); 268 } 269 } else if (PackageManager.FEATURE_VULKAN_HARDWARE_VERSION.equals(feature.name)) { 270 mVulkanHardwareVersion = feature; 271 if (DEBUG) { 272 Log.d(TAG, feature.name + "=0x" + Integer.toHexString(feature.version)); 273 } 274 } else if (PackageManager.FEATURE_VULKAN_HARDWARE_COMPUTE.equals(feature.name)) { 275 mVulkanHardwareCompute = feature; 276 if (DEBUG) { 277 Log.d(TAG, feature.name + "=" + feature.version); 278 } 279 } else if (PackageManager.FEATURE_VULKAN_DEQP_LEVEL.equals(feature.name)) { 280 mVulkanDeqpLevel = feature; 281 if (DEBUG) { 282 Log.d(TAG, feature.name + "=" + feature.version); 283 } 284 } else if (PackageManager.FEATURE_LEANBACK.equals(feature.name)) { 285 mIsTV = true; 286 } 287 } 288 } 289 290 mVkJSON = new JSONObject(nativeGetVkJSON()); 291 mVulkanDevices = getVulkanDevices(mVkJSON); 292 mBestDevice = getBestDevice(); 293 } 294 295 @CddTest(requirement = "7.1.4.2/C-1-1,C-2-1") 296 @Test testVulkanHardwareFeatures()297 public void testVulkanHardwareFeatures() throws JSONException { 298 if (DEBUG) { 299 Log.d(TAG, "Inspecting " + mVulkanDevices.length + " devices"); 300 } 301 if (mVulkanDevices.length == 0) { 302 assertNull("System feature " + PackageManager.FEATURE_VULKAN_HARDWARE_LEVEL + 303 " is supported, but no Vulkan physical devices are available", 304 mVulkanHardwareLevel); 305 assertNull("System feature " + PackageManager.FEATURE_VULKAN_HARDWARE_VERSION + 306 " is supported, but no Vulkan physical devices are available", 307 mVulkanHardwareLevel); 308 assertNull("System feature " + PackageManager.FEATURE_VULKAN_HARDWARE_COMPUTE + 309 " is supported, but no Vulkan physical devices are available", 310 mVulkanHardwareCompute); 311 return; 312 } 313 314 if (hasOnlyCpuDevice()) { 315 return; 316 } 317 318 assertNotNull("Vulkan physical devices are available, but system feature " + 319 PackageManager.FEATURE_VULKAN_HARDWARE_LEVEL + " is not supported", 320 mVulkanHardwareLevel); 321 assertNotNull("Vulkan physical devices are available, but system feature " + 322 PackageManager.FEATURE_VULKAN_HARDWARE_VERSION + " is not supported", 323 mVulkanHardwareVersion); 324 if (mVulkanHardwareLevel == null || mVulkanHardwareVersion == null) { 325 return; 326 } 327 328 assertTrue("System feature " + PackageManager.FEATURE_VULKAN_HARDWARE_LEVEL + 329 " version " + mVulkanHardwareLevel.version + " is not one of the defined " + 330 " versions [0..1]", 331 mVulkanHardwareLevel.version >= 0 && mVulkanHardwareLevel.version <= 1); 332 assertTrue("System feature " + PackageManager.FEATURE_VULKAN_HARDWARE_VERSION + 333 " version 0x" + Integer.toHexString(mVulkanHardwareVersion.version) + " is not" + 334 " one of the versions allowed", 335 isHardwareVersionAllowed(mVulkanHardwareVersion.version)); 336 if (mVulkanHardwareCompute != null) { 337 assertTrue("System feature " + PackageManager.FEATURE_VULKAN_HARDWARE_COMPUTE + 338 " version " + mVulkanHardwareCompute.version + 339 " is not one of the versions allowed", 340 mVulkanHardwareCompute.version == 0); 341 } 342 343 int bestDeviceLevel = determineHardwareLevel(mBestDevice); 344 int bestComputeLevel = determineHardwareCompute(mBestDevice); 345 int bestDeviceVersion = determineHardwareVersion(mBestDevice); 346 347 assertEquals("System feature " + PackageManager.FEATURE_VULKAN_HARDWARE_LEVEL + 348 " version " + mVulkanHardwareLevel.version + " doesn't match best physical device " + 349 " hardware level " + bestDeviceLevel, 350 bestDeviceLevel, mVulkanHardwareLevel.version); 351 assertTrue( 352 "System feature " + PackageManager.FEATURE_VULKAN_HARDWARE_VERSION + 353 " version 0x" + Integer.toHexString(mVulkanHardwareVersion.version) + 354 " isn't close enough (same major and minor version, less or equal patch version)" + 355 " to best physical device version 0x" + Integer.toHexString(bestDeviceVersion), 356 isVersionCompatible(bestDeviceVersion, mVulkanHardwareVersion.version)); 357 if (mVulkanHardwareCompute == null) { 358 assertEquals("System feature " + PackageManager.FEATURE_VULKAN_HARDWARE_COMPUTE + 359 " not present, but required features are supported", 360 bestComputeLevel, -1); 361 } else { 362 assertEquals("System feature " + PackageManager.FEATURE_VULKAN_HARDWARE_COMPUTE + 363 " version " + mVulkanHardwareCompute.version + 364 " doesn't match best physical device (version: " + bestComputeLevel + ")", 365 bestComputeLevel, mVulkanHardwareCompute.version); 366 } 367 } 368 369 @CddTest(requirement = "3.3.1/C-0-12") 370 @Test testVulkanApplicationBinaryInterfaceRequirements()371 public void testVulkanApplicationBinaryInterfaceRequirements() throws JSONException { 372 assumeTrue("Skipping because Vulkan is not supported", mVulkanHardwareVersion != null); 373 374 if (hasOnlyCpuDevice()) { 375 return; 376 } 377 378 assertTrue("Devices must support the core Vulkan 1.1", 379 mVulkanHardwareVersion.version >= VULKAN_1_1); 380 } 381 382 @CddTest(requirement = "7.1.4.2/C-1-3") 383 @Test testVulkanApiForEachDevice()384 public void testVulkanApiForEachDevice() throws JSONException { 385 for (JSONObject device : mVulkanDevices) { 386 assertTrue("All enumerated VPhysicalDevice must support Vulkan 1.1", 387 determineHardwareVersion(device) >= VULKAN_1_1); 388 } 389 } 390 391 @CddTest(requirement = "7.1.4.2/C-3-1") 392 @Test testVulkan1_1Requirements()393 public void testVulkan1_1Requirements() throws JSONException { 394 if (mVulkanHardwareVersion == null || mVulkanHardwareVersion.version < VULKAN_1_1 395 || !PropertyUtil.isVendorApiLevelNewerThan( 396 API_LEVEL_BEFORE_ANDROID_HARDWARE_BUFFER_REQ)) { 397 return; 398 } 399 assertTrue("Devices with Vulkan 1.1 must support sampler YCbCr conversion", 400 mBestDevice.getJSONObject("samplerYcbcrConversionFeatures") 401 .getInt("samplerYcbcrConversion") != 0); 402 403 if (hasOnlyCpuDevice()) { 404 return; 405 } 406 assertTrue("Devices with Vulkan 1.1 must support " + 407 VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME + 408 " (version >= " + VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_SPEC_VERSION + 409 ")", 410 hasDeviceExtension(mBestDevice, 411 VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME, 412 VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_SPEC_VERSION)); 413 assertTrue("Devices with Vulkan 1.1 must support SYNC_FD external semaphores", 414 hasHandleType(mBestDevice.getJSONArray("externalSemaphoreProperties"), 415 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT, 416 "externalSemaphoreFeatures", 0x3 /* importable + exportable */)); 417 assertTrue("Devices with Vulkan 1.1 must support SYNC_FD external fences", 418 hasHandleType(mBestDevice.getJSONArray("externalFenceProperties"), 419 VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT, 420 "externalFenceFeatures", 0x3 /* importable + exportable */)); 421 } 422 423 @CddTest(requirement = "7.1.4.2/C-1-7, 3.3.1/C-0-12") 424 @Test testVulkanRequiredExtensions()425 public void testVulkanRequiredExtensions() throws JSONException { 426 assumeTrue("Skipping because Vulkan is not supported", mVulkanDevices.length > 0); 427 428 assertVulkanInstanceExtension(VK_KHR_SURFACE, VK_KHR_SURFACE_SPEC_VERSION); 429 assertVulkanInstanceExtension(VK_KHR_ANDROID_SURFACE, VK_KHR_ANDROID_SURFACE_SPEC_VERSION); 430 431 assertVulkanDeviceExtension(VK_KHR_SWAPCHAIN, VK_KHR_SWAPCHAIN_SPEC_VERSION); 432 assertVulkanDeviceExtension(VK_KHR_INCREMENTAL_PRESENT, 433 VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION); 434 assertVulkanDeviceExtension(VK_KHR_MAINTENANCE1, VK_KHR_MAINTENANCE1_SPEC_VERSION); 435 } 436 437 @CddTest(requirement = "7.9.2/C-1-5") 438 @Test testVulkanVersionForVrHighPerformance()439 public void testVulkanVersionForVrHighPerformance() { 440 if (!mPm.hasSystemFeature(PackageManager.FEATURE_VR_MODE_HIGH_PERFORMANCE)) 441 return; 442 assertTrue( 443 "VR high-performance devices must support Vulkan 1.0 with Hardware Level 0, " + 444 "but this device does not.", 445 mVulkanHardwareVersion != null && mVulkanHardwareVersion.version >= VULKAN_1_0 && 446 mVulkanHardwareLevel != null && mVulkanHardwareLevel.version >= 0); 447 } 448 449 @CddTest(requirement = "7.1.4.2/C-1-11") 450 @Test testVulkanBlockedExtensions()451 public void testVulkanBlockedExtensions() throws JSONException { 452 assertNoVulkanDeviceExtension("VK_KHR_performance_query"); 453 assertNoVulkanDeviceExtension("VK_KHR_video_queue"); 454 assertNoVulkanDeviceExtension("VK_KHR_video_decode_queue"); 455 assertNoVulkanDeviceExtension("VK_KHR_video_encode_queue"); 456 } 457 458 @CddTest(requirement = "7.1.4.2") 459 @Test testVulkanVariantSupport()460 public void testVulkanVariantSupport() throws JSONException { 461 assumeTrue("Skipping because Vulkan is not supported", mVulkanHardwareVersion != null); 462 463 int expectedVariant = 0x0; 464 int actualVariant = (mVulkanHardwareVersion.version >> 29) & 0x7; 465 assertEquals(expectedVariant, actualVariant); 466 } 467 468 @CddTest(requirement = "7.1.4.2/C-1-14") 469 @Test testVulkanExposedDeviceExtensions()470 public void testVulkanExposedDeviceExtensions() throws JSONException { 471 assumeTrue("Skipping because Vulkan is not supported", mVulkanHardwareVersion != null); 472 473 if (hasOnlyCpuDevice()) { 474 return; 475 } 476 477 // Determine the set of device-side extensions that can be exposed 478 // Note this only includes VK_KHR, VK_GOOGLE, VK_ANDROID 479 final int deviceDeqpLevel = mVulkanDeqpLevel.version; 480 Set<String> allowedDeviceExtensions = new HashSet<String>(); 481 for (Integer level : DEQP_EXTENSIONS_MAP.keySet()) { 482 if (deviceDeqpLevel >= level) { 483 allowedDeviceExtensions.addAll(Arrays.asList(DEQP_EXTENSIONS_MAP.get(level))); 484 } 485 } 486 487 // Get the set of all device-side extensions exposed by the device 488 final JSONArray deviceExtensions = mBestDevice.getJSONArray("extensions"); 489 // Search for any device extensions that should not be exposed 490 Set<String> untestedExtensions = new HashSet<String>(); 491 for (int i = 0; i < deviceExtensions.length(); i++) { 492 JSONObject extension = deviceExtensions.getJSONObject(i); 493 String deviceExtension = extension.getString("extensionName"); 494 boolean vk_android = deviceExtension.startsWith("VK_ANDROID"); 495 boolean vk_google = deviceExtension.startsWith("VK_GOOGLE"); 496 boolean vk_khr = deviceExtension.startsWith("VK_KHR"); 497 if (!vk_android && !vk_google && !vk_khr) { 498 if (DEBUG) { 499 Log.d(TAG, "Device extension exposed is not KHR, GOOGLE, or ANDROID: " 500 + deviceExtension); 501 } 502 continue; 503 } 504 if (!allowedDeviceExtensions.contains(deviceExtension)) { 505 if (DEBUG) { 506 Log.d(TAG, "Device extension exposed on device not found in dEQP level " 507 + deviceDeqpLevel + ": " + deviceExtension); 508 } 509 untestedExtensions.add(deviceExtension); 510 } 511 } 512 513 assertEquals("This device exposes the extensions:\n" + untestedExtensions 514 + "\n that are not tested under its claimed dEQP level: " + deviceDeqpLevel, 515 0, untestedExtensions.size()); 516 } 517 nativeGetABPSupport()518 private static native String nativeGetABPSupport(); nativeGetABPCpuOnlySupport()519 private static native String nativeGetABPCpuOnlySupport(); 520 521 @CddTest(requirement = "7.1.4.2/C-1-13") 522 @Test testAndroidBaselineProfile2021Support()523 public void testAndroidBaselineProfile2021Support() throws JSONException { 524 assumeTrue("Skipping because Vulkan is not supported", mVulkanHardwareVersion != null); 525 assumeTrue("Skipping because ABP is not required of TV devices", !mIsTV); 526 527 if (!hasOnlyCpuDevice()) { 528 assertEquals("This device must support the ABP 2021.", "", nativeGetABPSupport()); 529 } else { 530 assertEquals("This device must support the ABP 2021.", "", 531 nativeGetABPCpuOnlySupport()); 532 } 533 } 534 getBestDevice()535 private JSONObject getBestDevice() throws JSONException { 536 JSONObject bestDevice = null; 537 int bestDeviceLevel = -1; 538 int bestComputeLevel = -1; 539 int bestDeviceVersion = -1; 540 for (JSONObject device : mVulkanDevices) { 541 int level = determineHardwareLevel(device); 542 int compute = determineHardwareCompute(device); 543 int version = determineHardwareVersion(device); 544 if (DEBUG) { 545 Log.d(TAG, device.getJSONObject("properties").getString("deviceName") + 546 ": level=" + level + " compute=" + compute + 547 " version=0x" + Integer.toHexString(version)); 548 } 549 if (level >= bestDeviceLevel && compute >= bestComputeLevel && 550 version >= bestDeviceVersion) { 551 bestDevice = device; 552 bestDeviceLevel = level; 553 bestComputeLevel = compute; 554 bestDeviceVersion = version; 555 } 556 } 557 return bestDevice; 558 } 559 hasOnlyCpuDevice()560 private boolean hasOnlyCpuDevice() throws JSONException { 561 for (JSONObject device : mVulkanDevices) { 562 if (device.getJSONObject("properties").getInt("deviceType") 563 != VK_PHYSICAL_DEVICE_TYPE_CPU) { 564 return false; 565 } 566 } 567 return true; 568 } 569 determineHardwareLevel(JSONObject device)570 private int determineHardwareLevel(JSONObject device) throws JSONException { 571 JSONObject features = device.getJSONObject("features"); 572 boolean textureCompressionETC2 = features.getInt("textureCompressionETC2") != 0; 573 boolean fullDrawIndexUint32 = features.getInt("fullDrawIndexUint32") != 0; 574 boolean imageCubeArray = features.getInt("imageCubeArray") != 0; 575 boolean independentBlend = features.getInt("independentBlend") != 0; 576 boolean geometryShader = features.getInt("geometryShader") != 0; 577 boolean tessellationShader = features.getInt("tessellationShader") != 0; 578 boolean sampleRateShading = features.getInt("sampleRateShading") != 0; 579 boolean textureCompressionASTC_LDR = features.getInt("textureCompressionASTC_LDR") != 0; 580 boolean fragmentStoresAndAtomics = features.getInt("fragmentStoresAndAtomics") != 0; 581 boolean shaderImageGatherExtended = features.getInt("shaderImageGatherExtended") != 0; 582 boolean shaderUniformBufferArrayDynamicIndexing = features.getInt("shaderUniformBufferArrayDynamicIndexing") != 0; 583 boolean shaderSampledImageArrayDynamicIndexing = features.getInt("shaderSampledImageArrayDynamicIndexing") != 0; 584 if (!textureCompressionETC2) { 585 return -1; 586 } 587 if (!fullDrawIndexUint32 || 588 !imageCubeArray || 589 !independentBlend || 590 !geometryShader || 591 !tessellationShader || 592 !sampleRateShading || 593 !textureCompressionASTC_LDR || 594 !fragmentStoresAndAtomics || 595 !shaderImageGatherExtended || 596 !shaderUniformBufferArrayDynamicIndexing || 597 !shaderSampledImageArrayDynamicIndexing) { 598 return 0; 599 } 600 return 1; 601 } 602 determineHardwareCompute(JSONObject device)603 private int determineHardwareCompute(JSONObject device) throws JSONException { 604 boolean variablePointers = false; 605 try { 606 variablePointers = device.getJSONObject("variablePointerFeatures") 607 .getInt("variablePointers") != 0; 608 } catch (JSONException exp) { 609 try { 610 variablePointers = device.getJSONObject("VK_KHR_variable_pointers") 611 .getJSONObject("variablePointerFeaturesKHR") 612 .getInt("variablePointers") != 0; 613 } catch (JSONException exp2) { 614 variablePointers = false; 615 } 616 } 617 JSONObject limits = device.getJSONObject("properties").getJSONObject("limits"); 618 int maxPerStageDescriptorStorageBuffers = limits.getInt("maxPerStageDescriptorStorageBuffers"); 619 if (DEBUG) { 620 Log.d(TAG, device.getJSONObject("properties").getString("deviceName") + 621 ": variablePointers=" + variablePointers + 622 " maxPerStageDescriptorStorageBuffers=" + maxPerStageDescriptorStorageBuffers); 623 } 624 if (!variablePointers || maxPerStageDescriptorStorageBuffers < 16) 625 return -1; 626 return 0; 627 } 628 determineHardwareVersion(JSONObject device)629 private int determineHardwareVersion(JSONObject device) throws JSONException { 630 return device.getJSONObject("properties").getInt("apiVersion"); 631 } 632 isVersionCompatible(int expected, int actual)633 private boolean isVersionCompatible(int expected, int actual) { 634 int expectedVariant = (expected >> 29) & 0x7; 635 int expectedMajor = (expected >> 22) & 0x7F; 636 int expectedMinor = (expected >> 12) & 0x3FF; 637 int expectedPatch = (expected >> 0) & 0xFFF; 638 int actualVariant = (actual >> 29) & 0x7; 639 int actualMajor = (actual >> 22) & 0x7F; 640 int actualMinor = (actual >> 12) & 0x3FF; 641 int actualPatch = (actual >> 0) & 0xFFF; 642 return (actualVariant == expectedVariant) 643 && (actualMajor == expectedMajor) 644 && (actualMinor == expectedMinor) 645 && (actualPatch <= expectedPatch); 646 } 647 isHardwareVersionAllowed(int actual)648 private boolean isHardwareVersionAllowed(int actual) { 649 // Limit which system feature hardware versions are allowed. If a new major/minor version 650 // is released, we don't want devices claiming support for it until tests for the new 651 // version are available. And only claiming support for a base patch level per major/minor 652 // pair reduces fragmentation seen by developers. Patch-level changes are supposed to be 653 // forwards and backwards compatible; if a developer *really* needs to alter behavior based 654 // on the patch version, they can do so at runtime, but must be able to handle previous 655 // patch versions. 656 final int[] ALLOWED_HARDWARE_VERSIONS = { 657 VULKAN_1_0, 658 VULKAN_1_1, 659 VULKAN_1_2, 660 VULKAN_1_3, 661 }; 662 for (int expected : ALLOWED_HARDWARE_VERSIONS) { 663 if (actual == expected) { 664 return true; 665 } 666 } 667 return false; 668 } 669 assertVulkanDeviceExtension(final String name, final int minVersion)670 private void assertVulkanDeviceExtension(final String name, final int minVersion) 671 throws JSONException { 672 assertTrue( 673 String.format( 674 "Devices with Vulkan must support device extension %s (version >= %d)", 675 name, 676 minVersion), 677 hasDeviceExtension(mBestDevice, name, minVersion)); 678 } 679 assertNoVulkanDeviceExtension(final String name)680 private void assertNoVulkanDeviceExtension(final String name) 681 throws JSONException { 682 for (JSONObject device : mVulkanDevices) { 683 assertTrue( 684 String.format("Devices must not support Vulkan device extension %s", name), 685 !hasDeviceExtension(device, name, 0)); 686 } 687 } 688 assertVulkanInstanceExtension(final String name, final int minVersion)689 private void assertVulkanInstanceExtension(final String name, final int minVersion) 690 throws JSONException { 691 assertTrue( 692 String.format( 693 "Devices with Vulkan must support instance extension %s (version >= %d)", 694 name, 695 minVersion), 696 hasInstanceExtension(name, minVersion)); 697 } 698 hasDeviceExtension( final JSONObject device, final String name, final int minVersion)699 private static boolean hasDeviceExtension( 700 final JSONObject device, 701 final String name, 702 final int minVersion) throws JSONException { 703 final JSONArray deviceExtensions = device.getJSONArray("extensions"); 704 return hasExtension(deviceExtensions, name, minVersion); 705 } 706 hasInstanceExtension( final String name, final int minVersion)707 private boolean hasInstanceExtension( 708 final String name, 709 final int minVersion) throws JSONException { 710 // Instance extensions are in the top-level vkjson object. 711 final JSONArray instanceExtensions = mVkJSON.getJSONArray("extensions"); 712 return hasExtension(instanceExtensions, name, minVersion); 713 } 714 hasExtension( final JSONArray extensions, final String name, final int minVersion)715 private static boolean hasExtension( 716 final JSONArray extensions, 717 final String name, 718 final int minVersion) throws JSONException { 719 for (int i = 0; i < extensions.length(); i++) { 720 JSONObject ext = extensions.getJSONObject(i); 721 if (ext.getString("extensionName").equals(name) && 722 ext.getInt("specVersion") >= minVersion) 723 return true; 724 } 725 return false; 726 } 727 hasHandleType(JSONArray handleTypes, int type, String featuresName, int requiredFeatures)728 private boolean hasHandleType(JSONArray handleTypes, int type, 729 String featuresName, int requiredFeatures) throws JSONException { 730 for (int i = 0; i < handleTypes.length(); i++) { 731 JSONArray typeRecord = handleTypes.getJSONArray(i); 732 if (typeRecord.getInt(0) == type) { 733 JSONObject typeInfo = typeRecord.getJSONObject(1); 734 if ((typeInfo.getInt(featuresName) & requiredFeatures) == requiredFeatures) 735 return true; 736 } 737 } 738 return false; 739 } 740 nativeGetVkJSON()741 private static native String nativeGetVkJSON(); 742 getVulkanDevices(final JSONObject vkJSON)743 private static JSONObject[] getVulkanDevices(final JSONObject vkJSON) throws JSONException { 744 JSONArray devicesArray = vkJSON.getJSONArray("devices"); 745 JSONObject[] devices = new JSONObject[devicesArray.length()]; 746 for (int i = 0; i < devicesArray.length(); i++) { 747 devices[i] = devicesArray.getJSONObject(i); 748 } 749 return devices; 750 } 751 } 752