• 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.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