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