1 /* 2 * Copyright (C) 2023 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 package com.android.gpu.vts; 17 18 import static org.junit.Assert.assertEquals; 19 import static org.junit.Assert.assertNotNull; 20 import static org.junit.Assert.assertTrue; 21 import static org.junit.Assert.fail; 22 import static org.junit.Assume.assumeFalse; 23 import static org.junit.Assume.assumeTrue; 24 25 import android.platform.test.annotations.RequiresDevice; 26 import com.android.compatibility.common.util.ApiLevelUtil; 27 import com.android.compatibility.common.util.FeatureUtil; 28 import com.android.compatibility.common.util.PropertyUtil; 29 import com.android.compatibility.common.util.VsrTest; 30 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; 31 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; 32 import org.json.JSONArray; 33 import org.json.JSONObject; 34 import org.junit.Before; 35 import org.junit.Test; 36 import org.junit.runner.RunWith; 37 38 /* 39 * VTS test for Vulkan requirements. 40 */ 41 @RequiresDevice 42 @RunWith(DeviceJUnit4ClassRunner.class) 43 public class VulkanTest extends BaseHostJUnit4Test { 44 private static final int VK_PHYSICAL_DEVICE_TYPE_CPU = 4; 45 private static final int VULKAN_1_1_API_VERSION = 0x401000; 46 private static final int VULKAN_1_3_API_VERSION = 0x403000; 47 48 // Feature version corresponding to dEQP level for 2025-03-01. 49 public static final int DEQP_LEVEL_FOR_VENDOR_26Q2 = 0x7E90301; 50 51 // Feature version corresponding to dEQP level for 2025-03-01. 52 public static final int DEQP_LEVEL_FOR_VENDOR_25Q2 = 0x7E90301; 53 54 // Feature version corresponding to dEQP level for 2024-03-01. 55 public static final int DEQP_LEVEL_FOR_VENDOR_24Q2 = 0x7E80301; 56 57 // Feature version corresponding to dEQP level for 2023-03-01. 58 public static final int DEQP_LEVEL_FOR_U = 0x7E70301; 59 60 // Feature version corresponding to dEQP level for 2022-03-01. 61 public static final int DEQP_LEVEL_FOR_T = 0x7E60301; 62 63 // Feature version corresponding to dEQP level for 2021-03-01. 64 public static final int DEQP_LEVEL_FOR_S = 0x7E50301; 65 66 // Feature version corresponding to dEQP level for 2020-03-01. 67 public static final int DEQP_LEVEL_FOR_R = 0x7E40301; 68 69 private static final String VK_EXT_DEVICE_MEMORY_REPORT_EXTENSION_NAME = 70 "VK_EXT_device_memory_report"; 71 private static final int VK_EXT_DEVICE_MEMORY_REPORT_SPEC_VERSION = 1; 72 73 private static final String VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME = "VK_EXT_global_priority"; 74 private static final int VK_EXT_GLOBAL_PRIORITY_SPEC_VERSION = 1; 75 private static final String VK_KHR_GLOBAL_PRIORITY_EXTENSION_NAME = "VK_KHR_global_priority"; 76 private static final int VK_KHR_GLOBAL_PRIORITY_SPEC_VERSION = 1; 77 78 // the string to parse to confirm that Skia is using vulkan 79 private static final String SKIA_PIPELINE = "Pipeline=Skia"; 80 private static final String SKIA_VULKAN_PIPELINE = "Pipeline=Skia (Vulkan)"; 81 82 private JSONObject[] mVulkanDevices; 83 private JSONObject mVulkanProfiles; 84 85 /** 86 * Test specific setup 87 */ 88 @Before setUp()89 public void setUp() throws Exception { 90 final String output = getDevice().executeShellCommand("cmd gpu vkjson"); 91 final JSONArray vkjson; 92 // vkjson output in Android N is JSONArray. 93 if (ApiLevelUtil.isBefore(getDevice(), Build.OC)) { 94 vkjson = (new JSONArray(output)); 95 } else { 96 vkjson = (new JSONObject(output)).getJSONArray("devices"); 97 } 98 mVulkanDevices = new JSONObject[vkjson.length()]; 99 for (int i = 0; i < vkjson.length(); i++) { 100 mVulkanDevices[i] = vkjson.getJSONObject(i); 101 } 102 103 final String profiles = getDevice().executeShellCommand("cmd gpu vkprofiles"); 104 mVulkanProfiles = new JSONObject(profiles); 105 } 106 107 /** 108 * 64-bit SoCs released with Q must support Vulkan 1.1. 109 */ 110 @VsrTest(requirements = {"VSR-3.2.1-001.001"}) 111 @Test checkVulkan1_1Requirements()112 public void checkVulkan1_1Requirements() throws Exception { 113 // Only test for new 64-bit SoCs that are Q and above. 114 assumeTrue("Test does not apply for SoCs released before Q", 115 PropertyUtil.getVsrApiLevel(getDevice()) >= Build.QT); 116 assumeTrue("Test does not apply for 32-bit SoCs", 117 getDevice().getProperty("ro.product.cpu.abi").contains("64")); 118 119 assertTrue(mVulkanDevices.length > 0); 120 121 int bestApiVersion = 0; 122 for (JSONObject device : mVulkanDevices) { 123 final int apiVersion = device.getJSONObject("properties").getInt("apiVersion"); 124 if (bestApiVersion < apiVersion) { 125 bestApiVersion = apiVersion; 126 } 127 } 128 assertTrue("Supported Vulkan version must be at least 1.1", 129 bestApiVersion >= VULKAN_1_1_API_VERSION); 130 } 131 132 /** 133 * 64-bit SoCs released with U must support Vulkan 1.3. 134 * All SoCs released with V must support Vulkan 1.3. 135 */ 136 @VsrTest(requirements = {"VSR-3.2.1-001.003", "VSR-3.2.1-007"}) 137 @Test checkVulkan1_3Requirements()138 public void checkVulkan1_3Requirements() throws Exception { 139 assumeTrue("Test does not apply for SoCs released before U", 140 PropertyUtil.getVsrApiLevel(getDevice()) >= Build.UDC); 141 assumeTrue("Test does not apply for automotive devices released before V", 142 !FeatureUtil.isAutomotive(getDevice()) 143 || PropertyUtil.getVsrApiLevel(getDevice()) > Build.UDC); 144 145 // Don't test if an SoC released during U is 32 bit 146 // If an SoC is released with V then both 32 and 64 bit are to be tested 147 if (PropertyUtil.getVsrApiLevel(getDevice()) == Build.UDC) { 148 assumeTrue("Test does not apply for 32-bit SoCs released with Android U", 149 getDevice().getProperty("ro.product.cpu.abi").contains("64")); 150 } 151 152 assertTrue(mVulkanDevices.length > 0); 153 154 int bestApiVersion = 0; 155 for (JSONObject device : mVulkanDevices) { 156 final int apiVersion = device.getJSONObject("properties").getInt("apiVersion"); 157 if (bestApiVersion < apiVersion) { 158 bestApiVersion = apiVersion; 159 } 160 } 161 assertTrue("Supported Vulkan version must be at least 1.3", 162 bestApiVersion >= VULKAN_1_3_API_VERSION); 163 } 164 165 /** 166 * SoCs with only CPU Vulkan must properly set "ro.cpuvulkan.version" property. 167 */ 168 @VsrTest(requirements = {"VSR-3.2.1-002"}) 169 @Test checkCpuVulkanRequirements()170 public void checkCpuVulkanRequirements() throws Exception { 171 // Only test for new SoCs that are Q and above. 172 assumeTrue("Test does not apply for SoCs released before Q", 173 PropertyUtil.getVsrApiLevel(getDevice()) >= Build.QT); 174 175 if (mVulkanDevices.length == 0) { 176 return; 177 } 178 179 boolean hasOnlyCpuDevice = true; 180 int bestApiVersion = 0; 181 for (JSONObject device : mVulkanDevices) { 182 if (device.getJSONObject("properties").getInt("deviceType") 183 != VK_PHYSICAL_DEVICE_TYPE_CPU) { 184 hasOnlyCpuDevice = false; 185 } else { 186 final int apiVersion = device.getJSONObject("properties").getInt("apiVersion"); 187 if (bestApiVersion < apiVersion) { 188 bestApiVersion = apiVersion; 189 } 190 } 191 } 192 193 if (!hasOnlyCpuDevice) { 194 return; 195 } 196 197 final int advertisedApiVersion = 198 Integer.parseInt(getDevice().getProperty("ro.cpuvulkan.version")); 199 assertEquals("Advertised CPU Vulkan api version " + advertisedApiVersion 200 + " doesn't match the best physical device api version " + bestApiVersion, 201 bestApiVersion, advertisedApiVersion); 202 } 203 204 /** 205 * Verify that FEATURE_VULKAN_DEQP_LEVEL (feature:android.software.vulkan.deqp.level) has a 206 * sufficiently high version in relation to the vendor and first product API level. 207 */ 208 @VsrTest(requirements = {"VSR-3.2.2-001", "VSR-3.2.2-002", "VSR-3.2.2-003", "VSR-3.2.2-004", 209 "VSR-3.2.2-005", "VSR-3.2.2-006"}) 210 @Test 211 public void checkVulkanDeqpLevelIsHighEnough()212 checkVulkanDeqpLevelIsHighEnough() throws Exception { 213 final int apiLevel = Util.getVendorApiLevelOrFirstProductApiLevel(getDevice()); 214 215 assumeTrue("Test does not apply for API level lower than R", apiLevel >= Build.RVC); 216 assumeTrue("Test does not apply for SoCs without Vulkan", mVulkanDevices.length > 0); 217 218 // Map from API level to required dEQP level. 219 final int requiredVulkanDeqpLevel; 220 switch (apiLevel) { 221 case Build.RVC: 222 requiredVulkanDeqpLevel = DEQP_LEVEL_FOR_R; 223 break; 224 case Build.SC: 225 case Build.SC_V2: 226 requiredVulkanDeqpLevel = DEQP_LEVEL_FOR_S; 227 break; 228 case Build.TM: 229 requiredVulkanDeqpLevel = DEQP_LEVEL_FOR_T; 230 break; 231 case Build.UDC: 232 requiredVulkanDeqpLevel = DEQP_LEVEL_FOR_U; 233 break; 234 case Build.VENDOR_24Q2: 235 requiredVulkanDeqpLevel = DEQP_LEVEL_FOR_VENDOR_24Q2; 236 break; 237 case Build.VENDOR_25Q2: 238 requiredVulkanDeqpLevel = DEQP_LEVEL_FOR_VENDOR_25Q2; 239 break; 240 case Build.VENDOR_26Q2: 241 requiredVulkanDeqpLevel = DEQP_LEVEL_FOR_VENDOR_26Q2; 242 break; 243 default: 244 fail("Test should only run for API levels: R, S, Sv2, TM, UDC, 202404, 202504, " 245 + "202606..."); 246 return; 247 } 248 249 // Check that the feature flag is present and its value is at least the required dEQP level. 250 final String output = getDevice().executeShellCommand(String.format( 251 "pm has-feature android.software.vulkan.deqp.level %d", requiredVulkanDeqpLevel)); 252 253 if (!output.trim().equals("true")) { 254 final String message = String.format( 255 "Advertised Vulkan dEQP level feature is too low or does not exist.\n" 256 + "Expected:\nfeature:android.software.vulkan.deqp.level>=%d\n" 257 + "Actual:\n%s", 258 requiredVulkanDeqpLevel, 259 getDevice().executeShellCommand("pm list features | grep deqp")); 260 261 fail(message); 262 } 263 } 264 265 /** 266 * For SoCs launching with Android 12 or higher, if the SoC supports Vulkan 1.1 or higher, 267 * VK_EXT_device_memory_report extension must be supported. 268 */ 269 @VsrTest(requirements = {"VSR-3.2.1-006"}) 270 @Test checkVulkanDeviceMemoryReportSupport()271 public void checkVulkanDeviceMemoryReportSupport() throws Exception { 272 final int apiLevel = Util.getVendorApiLevelOrFirstProductApiLevel(getDevice()); 273 274 assumeTrue("Test does not apply for API level lower than S", apiLevel >= Build.SC); 275 276 assumeTrue( 277 "Test does not apply for SoCs without Vulkan support", mVulkanDevices.length > 0); 278 279 for (int i = 0; i < mVulkanDevices.length; ++i) { 280 final JSONObject device = mVulkanDevices[i]; 281 // Skip extension check if Vulkan device's API version is < 1.1. 282 if (device.getJSONObject("properties").getInt("apiVersion") < VULKAN_1_1_API_VERSION) { 283 continue; 284 } 285 286 final boolean isSupported = 287 hasExtension(device, VK_EXT_DEVICE_MEMORY_REPORT_EXTENSION_NAME, 288 VK_EXT_DEVICE_MEMORY_REPORT_SPEC_VERSION); 289 290 if (!isSupported) { 291 final String message = 292 String.format("Vulkan devices with API version >= 1.1 must support %s " 293 + "but the device at index %d does not. " 294 + "Check 'adb shell cmd gpu vkjson'.", 295 VK_EXT_DEVICE_MEMORY_REPORT_EXTENSION_NAME, i); 296 297 fail(message); 298 } 299 } 300 } 301 mustChipsetMeetA15Requirement()302 private boolean mustChipsetMeetA15Requirement() throws Exception { 303 final long boardApiLevel = getDevice().getIntProperty("ro.board.api_level", Build.VENDOR_24Q2); 304 return boardApiLevel >= Build.VENDOR_24Q2; 305 } 306 mustChipsetMeetA16Requirement()307 private boolean mustChipsetMeetA16Requirement() throws Exception { 308 // All SoCs starting or restarting GRF with A16, or not in GRF 309 final long boardFirstApiLevel = getDevice().getIntProperty("ro.board.first_api_level", Build.VENDOR_25Q2); 310 final long boardApiLevel = getDevice().getIntProperty("ro.board.api_level", Build.VENDOR_25Q2); 311 312 return boardApiLevel >= Build.VENDOR_25Q2 || // Chipsets at A16 level 313 (boardFirstApiLevel <= 32 && boardApiLevel < 34); // Old chipsets that would need to reenter at A16 314 } 315 316 /** 317 * All SoCs released with V must support Skia Vulkan with HWUI 318 */ 319 @VsrTest(requirements = {"VSR-3.2.1-009"}) 320 @Test checkSkiaVulkanSupport()321 public void checkSkiaVulkanSupport() throws Exception { 322 323 assumeTrue(mustChipsetMeetA15Requirement()); 324 325 final String gfxinfo = getDevice().executeShellCommand("dumpsys gfxinfo"); 326 assertNotNull(gfxinfo); 327 assertTrue(gfxinfo.length() > 0); 328 329 int skiaDataIndex = gfxinfo.indexOf(SKIA_PIPELINE); 330 assertTrue("The SoCs adb shell dumpsys gfxinfo must contain a Skia pipeline", 331 skiaDataIndex >= 0); 332 333 String tmpinfo = gfxinfo; 334 while (skiaDataIndex != -1) { 335 // Remove string before next Skia pipeline 336 tmpinfo = tmpinfo.substring(skiaDataIndex); 337 338 // Get the pipeline descriptor line 339 final int newlinecharacter = tmpinfo.indexOf(System.getProperty("line.separator")); 340 String line = tmpinfo.substring(0, newlinecharacter); 341 342 // Confirm that the pipeline uses Vulkan 343 assertTrue("All Skia pipelines must use Vulkan", line.equals(SKIA_VULKAN_PIPELINE)); 344 345 // Remove line and find next pipeline 346 tmpinfo = tmpinfo.substring(newlinecharacter + 1); 347 skiaDataIndex = tmpinfo.indexOf(SKIA_PIPELINE); 348 } 349 } 350 351 /** 352 * All SoCs released with V must support ABP 2022 353 */ 354 @VsrTest(requirements = {"VSR-3.2.1-008"}) 355 @Test checkAndroidBaselineProfile2022Support()356 public void checkAndroidBaselineProfile2022Support() throws Exception { 357 assumeTrue(mustChipsetMeetA15Requirement()); 358 assumeFalse("Exclude new graphics requirements for TV", FeatureUtil.isTV(getDevice())); 359 360 boolean hasOnlyCpuDevice = true; 361 for (JSONObject device : mVulkanDevices) { 362 if (device.getJSONObject("properties").getInt("deviceType") 363 != VK_PHYSICAL_DEVICE_TYPE_CPU) { 364 hasOnlyCpuDevice = false; 365 } 366 } 367 368 if (hasOnlyCpuDevice) { 369 return; 370 } 371 372 String supported = mVulkanProfiles.getString("VP_ANDROID_baseline_2022"); 373 assertEquals("This SoC must support VP_ANDROID_baseline_2022.", "SUPPORTED", supported); 374 } 375 376 /** 377 * All SoCs released with V must support VPA15 378 */ 379 @VsrTest(requirements = {"VSR-3.2.1-008"}) 380 @Test checkVpAndroid15MinimumsSupport()381 public void checkVpAndroid15MinimumsSupport() throws Exception { 382 assumeTrue(mustChipsetMeetA15Requirement()); 383 assumeFalse("Exclude new graphics requirements for TV", FeatureUtil.isTV(getDevice())); 384 385 boolean hasOnlyCpuDevice = true; 386 for (JSONObject device : mVulkanDevices) { 387 if (device.getJSONObject("properties").getInt("deviceType") 388 != VK_PHYSICAL_DEVICE_TYPE_CPU) { 389 hasOnlyCpuDevice = false; 390 } 391 } 392 393 if (hasOnlyCpuDevice) { 394 return; 395 } 396 397 String supported = mVulkanProfiles.getString("VP_ANDROID_15_minimums"); 398 assertEquals("This SoC must support VP_ANDROID_15_minimums.", "SUPPORTED", supported); 399 } 400 401 /** 402 * All SoCs starting or restarting GRF with A16 must support VPA16 403 */ 404 @VsrTest(requirements = {"VSR-3.2.1-009"}) 405 @Test checkVpAndroid16MinimumsSupport()406 public void checkVpAndroid16MinimumsSupport() throws Exception { 407 assumeTrue(mustChipsetMeetA16Requirement()); 408 assumeFalse("Exclude new graphics requirements for TV", FeatureUtil.isTV(getDevice())); 409 410 boolean hasOnlyCpuDevice = true; 411 for (JSONObject device : mVulkanDevices) { 412 if (device.getJSONObject("properties").getInt("deviceType") 413 != VK_PHYSICAL_DEVICE_TYPE_CPU) { 414 hasOnlyCpuDevice = false; 415 } 416 } 417 418 if (hasOnlyCpuDevice) { 419 return; 420 } 421 422 String supported = mVulkanProfiles.getString("VP_ANDROID_16_minimums"); 423 assertEquals("This SoC must support VP_ANDROID_16_minimums.", "SUPPORTED", supported); 424 } 425 426 /** 427 * All SoCs starting or restarting GRF with A17 must support protectedMemory. 428 * For A15/A16 produce assumption failure if this requirement is not met instead of failing. 429 * Swiftshader and other CPU-based implementations are exempt due to meaningful implementations 430 * of protected memory being infeasible for them. 431 */ 432 @VsrTest(requirements = {"VSR-3.2.1-011"}) 433 @Test checkProtectedMemorySupport()434 public void checkProtectedMemorySupport() throws Exception { 435 final int apiLevel = PropertyUtil.getVendorApiLevel(getDevice()); 436 437 final boolean allowSoftFailure = apiLevel <= Build.VENDOR_25Q2; 438 assumeFalse("Exclude new graphics requirements for TV", FeatureUtil.isTV(getDevice())); 439 440 assertTrue(mVulkanDevices.length > 0); 441 442 for (JSONObject device : mVulkanDevices) { 443 // Skip CPU implementations entirely 444 if (device.getJSONObject("properties").getInt("deviceType") 445 == VK_PHYSICAL_DEVICE_TYPE_CPU) { 446 continue; 447 } 448 449 final int protectedMemory = 450 device.getJSONObject("protectedMemoryFeatures").getInt("protectedMemory"); 451 if (allowSoftFailure) 452 assumeTrue("Chipsets entering GRF before A17 should support protectedMemory", 453 protectedMemory == 1); 454 else 455 assertTrue("Chipsets starting or restarting GRF with A17 must support protectedMemory", 456 protectedMemory == 1); 457 } 458 } 459 460 /** 461 * All SoCs starting or restarting GRF with A17 must support VK_EXT_global_priority (or VK_KHR_global_priority). 462 * For A15/A16 produce assumption failure if this requirement is not met instead of failing. 463 * Swiftshader and other CPU-based implementations are exempt. 464 */ 465 @VsrTest(requirements = {"VSR-3.2.1-011"}) 466 @Test checkGlobalPrioritySupport()467 public void checkGlobalPrioritySupport() throws Exception { 468 final int apiLevel = PropertyUtil.getVendorApiLevel(getDevice()); 469 470 final boolean allowSoftFailure = apiLevel <= Build.VENDOR_25Q2; 471 assumeFalse("Exclude new graphics requirements for TV", FeatureUtil.isTV(getDevice())); 472 473 assertTrue(mVulkanDevices.length > 0); 474 475 for (JSONObject device : mVulkanDevices) { 476 // Skip CPU implementations entirely 477 if (device.getJSONObject("properties").getInt("deviceType") 478 == VK_PHYSICAL_DEVICE_TYPE_CPU) { 479 continue; 480 } 481 482 final boolean extGlobalPriority = hasExtension(device, 483 VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME, VK_EXT_GLOBAL_PRIORITY_SPEC_VERSION); 484 final boolean khrGlobalPriority = hasExtension(device, 485 VK_KHR_GLOBAL_PRIORITY_EXTENSION_NAME, VK_KHR_GLOBAL_PRIORITY_SPEC_VERSION); 486 if (allowSoftFailure) 487 assumeTrue("Chipsets entering GRF before A17 should support global_priority", 488 extGlobalPriority || khrGlobalPriority); 489 else 490 assertTrue("Chipsets starting or restarting GRF with A17 must support global_priority", 491 extGlobalPriority || khrGlobalPriority); 492 } 493 } 494 hasExtension(JSONObject device, String name, int minVersion)495 private boolean hasExtension(JSONObject device, String name, int minVersion) throws Exception { 496 JSONArray extensions = device.getJSONArray("extensions"); 497 for (int i = 0; i < extensions.length(); i++) { 498 JSONObject ext = extensions.getJSONObject(i); 499 if (ext.getString("extensionName").equals(name) 500 && ext.getInt("specVersion") >= minVersion) 501 return true; 502 } 503 return false; 504 } 505 } 506