• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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