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.assertTrue; 20 import static org.junit.Assert.fail; 21 import static org.junit.Assume.assumeTrue; 22 23 import android.platform.test.annotations.RequiresDevice; 24 import com.android.compatibility.common.util.ApiLevelUtil; 25 import com.android.compatibility.common.util.PropertyUtil; 26 import com.android.compatibility.common.util.VsrTest; 27 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; 28 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; 29 import org.json.JSONArray; 30 import org.json.JSONObject; 31 import org.junit.Before; 32 import org.junit.Test; 33 import org.junit.runner.RunWith; 34 35 /* 36 * VTS test for Vulkan requirements. 37 */ 38 @RequiresDevice 39 @RunWith(DeviceJUnit4ClassRunner.class) 40 public class VulkanTest extends BaseHostJUnit4Test { 41 private static final int VK_PHYSICAL_DEVICE_TYPE_CPU = 4; 42 private static final int VULKAN_1_1_API_VERSION = 0x401000; 43 private static final int VULKAN_1_3_API_VERSION = 0x403000; 44 45 // Feature version corresponding to dEQP level for 2023-03-01. 46 public static final int DEQP_LEVEL_FOR_U = 0x7E70301; 47 48 // Feature version corresponding to dEQP level for 2022-03-01. 49 public static final int DEQP_LEVEL_FOR_T = 0x7E60301; 50 51 // Feature version corresponding to dEQP level for 2021-03-01. 52 public static final int DEQP_LEVEL_FOR_S = 0x7E50301; 53 54 // Feature version corresponding to dEQP level for 2020-03-01. 55 public static final int DEQP_LEVEL_FOR_R = 0x7E40301; 56 57 private static final String VK_EXT_DEVICE_MEMORY_REPORT_EXTENSION_NAME = 58 "VK_EXT_device_memory_report"; 59 private static final int VK_EXT_DEVICE_MEMORY_REPORT_SPEC_VERSION = 1; 60 61 private JSONObject[] mVulkanDevices; 62 63 /** 64 * Test specific setup 65 */ 66 @Before setUp()67 public void setUp() throws Exception { 68 final String output = getDevice().executeShellCommand("cmd gpu vkjson"); 69 final JSONArray vkjson; 70 // vkjson output in Android N is JSONArray. 71 if (ApiLevelUtil.isBefore(getDevice(), Build.OC)) { 72 vkjson = (new JSONArray(output)); 73 } else { 74 vkjson = (new JSONObject(output)).getJSONArray("devices"); 75 } 76 mVulkanDevices = new JSONObject[vkjson.length()]; 77 for (int i = 0; i < vkjson.length(); i++) { 78 mVulkanDevices[i] = vkjson.getJSONObject(i); 79 } 80 } 81 82 /** 83 * 64-bits devices released with Q must support Vulkan 1.1. 84 */ 85 @VsrTest(requirements = {"VSR-3.2.1-001.001"}) 86 @Test checkVulkan1_1Requirements()87 public void checkVulkan1_1Requirements() throws Exception { 88 // Only test for new 64-bits devices that is Q and above. 89 assumeTrue("Test does not apply for devices released before Q", 90 PropertyUtil.getVendorApiLevel(getDevice()) >= Build.QT); 91 assumeTrue("Test does not apply for 32-bits devices", 92 getDevice().getProperty("ro.product.cpu.abi").contains("64")); 93 94 assertTrue(mVulkanDevices.length > 0); 95 96 int bestApiVersion = 0; 97 for (JSONObject device : mVulkanDevices) { 98 final int apiVersion = device.getJSONObject("properties").getInt("apiVersion"); 99 if (bestApiVersion < apiVersion) { 100 bestApiVersion = apiVersion; 101 } 102 } 103 assertTrue("Supported Vulkan version must be at least 1.1", 104 bestApiVersion >= VULKAN_1_1_API_VERSION); 105 } 106 107 /** 108 * 64-bits devices released with U must support Vulkan 1.3. 109 */ 110 @VsrTest(requirements = {"VSR-3.2.1-001.003"}) 111 @Test checkVulkan1_3Requirements()112 public void checkVulkan1_3Requirements() throws Exception { 113 // Only test for new 64-bits devices that is Q and above. 114 assumeTrue("Test does not apply for devices released before U", 115 PropertyUtil.getVendorApiLevel(getDevice()) >= Build.UDC); 116 assumeTrue("Test does not apply for 32-bits devices", 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.3", 129 bestApiVersion >= VULKAN_1_3_API_VERSION); 130 } 131 132 /** 133 * Devices with only CPU Vulkan must properly set "ro.cpuvulkan.version" property. 134 */ 135 @VsrTest(requirements = {"VSR-3.2.1-002"}) 136 @Test checkCpuVulkanRequirements()137 public void checkCpuVulkanRequirements() throws Exception { 138 // Only test for new devices that is Q and above. 139 assumeTrue("Test does not apply for devices released before Q", 140 PropertyUtil.getVendorApiLevel(getDevice()) >= Build.QT); 141 142 if (mVulkanDevices.length == 0) { 143 return; 144 } 145 146 boolean hasOnlyCpuDevice = true; 147 int bestApiVersion = 0; 148 for (JSONObject device : mVulkanDevices) { 149 if (device.getJSONObject("properties").getInt("deviceType") 150 != VK_PHYSICAL_DEVICE_TYPE_CPU) { 151 hasOnlyCpuDevice = false; 152 } else { 153 final int apiVersion = device.getJSONObject("properties").getInt("apiVersion"); 154 if (bestApiVersion < apiVersion) { 155 bestApiVersion = apiVersion; 156 } 157 } 158 } 159 160 if (!hasOnlyCpuDevice) { 161 return; 162 } 163 164 final int advertisedApiVersion = 165 Integer.parseInt(getDevice().getProperty("ro.cpuvulkan.version")); 166 assertEquals("Advertised CPU Vulkan api version " + advertisedApiVersion 167 + " doesn't match the best physical device api version " + bestApiVersion, 168 bestApiVersion, advertisedApiVersion); 169 } 170 171 /** 172 * Verify that FEATURE_VULKAN_DEQP_LEVEL (feature:android.software.vulkan.deqp.level) has a 173 * sufficiently high version in relation to the vendor and first product API level. 174 */ 175 @VsrTest(requirements = 176 {"VSR-3.2.2-001/VSR-3.2.2-002/VSR-3.2.2-003/VSR-3.2.2-004/VSR-3.2.2-005"}) 177 @Test 178 public void checkVulkanDeqpLevelIsHighEnough()179 checkVulkanDeqpLevelIsHighEnough() throws Exception { 180 final int apiLevel = Util.getVendorApiLevelOrFirstProductApiLevel(getDevice()); 181 182 assumeTrue("Test does not apply for API level lower than R", apiLevel >= Build.RVC); 183 assumeTrue("Test does not apply for devices without Vulkan", mVulkanDevices.length > 0); 184 185 // Map from API level to required dEQP level. 186 final int requiredVulkanDeqpLevel; 187 switch (apiLevel) { 188 case Build.RVC: 189 requiredVulkanDeqpLevel = DEQP_LEVEL_FOR_R; 190 break; 191 case Build.SC: 192 case Build.SC_V2: 193 requiredVulkanDeqpLevel = DEQP_LEVEL_FOR_S; 194 break; 195 case Build.TM: 196 requiredVulkanDeqpLevel = DEQP_LEVEL_FOR_T; 197 break; 198 case Build.UDC: 199 requiredVulkanDeqpLevel = DEQP_LEVEL_FOR_U; 200 break; 201 default: 202 fail("Test should only run for API levels: R, S, Sv2, TM, UDC, ..."); 203 return; 204 } 205 206 // Check that the feature flag is present and its value is at least the required dEQP level. 207 final String output = getDevice().executeShellCommand(String.format( 208 "pm has-feature android.software.vulkan.deqp.level %d", requiredVulkanDeqpLevel)); 209 210 if (!output.trim().equals("true")) { 211 final String message = String.format( 212 "Advertised Vulkan dEQP level feature is too low or does not exist.\n" 213 + "Expected:\nfeature:android.software.vulkan.deqp.level>=%d\n" 214 + "Actual:\n%s", 215 requiredVulkanDeqpLevel, 216 getDevice().executeShellCommand("pm list features | grep deqp")); 217 218 fail(message); 219 } 220 } 221 222 /** 223 * For devices launching with Android 12 or higher, if the device supports Vulkan 1.1 or higher, 224 * VK_EXT_device_memory_report extension must be supported. 225 */ 226 @VsrTest(requirements = {"VSR-3.2.1-006"}) 227 @Test checkVulkanDeviceMemoryReportSupport()228 public void checkVulkanDeviceMemoryReportSupport() throws Exception { 229 final int apiLevel = Util.getVendorApiLevelOrFirstProductApiLevel(getDevice()); 230 231 assumeTrue("Test does not apply for API level lower than S", apiLevel >= Build.SC); 232 233 assumeTrue("Test does not apply for devices without Vulkan support", 234 mVulkanDevices.length > 0); 235 236 for (int i = 0; i < mVulkanDevices.length; ++i) { 237 final JSONObject device = mVulkanDevices[i]; 238 // Skip extension check if Vulkan device's API version is < 1.1. 239 if (device.getJSONObject("properties").getInt("apiVersion") < VULKAN_1_1_API_VERSION) { 240 continue; 241 } 242 243 final boolean isSupported = 244 hasExtension(device, VK_EXT_DEVICE_MEMORY_REPORT_EXTENSION_NAME, 245 VK_EXT_DEVICE_MEMORY_REPORT_SPEC_VERSION); 246 247 if (!isSupported) { 248 final String message = 249 String.format("Vulkan devices with API version >= 1.1 must support %s " 250 + "but the device at index %d does not. " 251 + "Check 'adb shell cmd gpu vkjson'.", 252 VK_EXT_DEVICE_MEMORY_REPORT_EXTENSION_NAME, i); 253 254 fail(message); 255 } 256 } 257 } 258 hasExtension(JSONObject device, String name, int minVersion)259 private boolean hasExtension(JSONObject device, String name, int minVersion) throws Exception { 260 JSONArray extensions = device.getJSONArray("extensions"); 261 for (int i = 0; i < extensions.length(); i++) { 262 JSONObject ext = extensions.getJSONObject(i); 263 if (ext.getString("extensionName").equals(name) 264 && ext.getInt("specVersion") >= minVersion) 265 return true; 266 } 267 return false; 268 } 269 } 270