1 /*
2  * Copyright (C) 2024 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 android.mediapc.cts;
17 
18 import android.mediapc.cts.common.PerformanceClassEvaluator;
19 import android.mediapc.cts.common.Requirements;
20 import android.mediapc.cts.common.Requirements.VulkanRequirement;
21 import android.util.Log;
22 
23 import androidx.test.ext.junit.runners.AndroidJUnit4;
24 
25 import com.android.compatibility.common.util.CddTest;
26 
27 import com.google.common.collect.ImmutableList;
28 
29 import org.json.JSONArray;
30 import org.json.JSONException;
31 import org.json.JSONObject;
32 import org.junit.Before;
33 import org.junit.Rule;
34 import org.junit.Test;
35 import org.junit.rules.TestName;
36 import org.junit.runner.RunWith;
37 
38 /**
39  * Verify Vulkan MPC requirements.
40  */
41 @RunWith(AndroidJUnit4.class)
42 public class VulkanTest {
43 
44     private static final String LOG_TAG = VulkanTest.class.getSimpleName();
45     private static final int VK_PHYSICAL_DEVICE_TYPE_CPU = 4;
46 
47 
48     private static final String VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME = "VK_EXT_global_priority";
49     private static final int VK_EXT_GLOBAL_PRIORITY_SPEC_VERSION = 1;
50 
51     private ImmutableList<JSONObject> mVulkanDevices;
nativeGetVkJSON()52     private static native String nativeGetVkJSON();
53 
54     @Rule
55     public final TestName mTestName = new TestName();
56 
57     static {
58         System.loadLibrary("ctsmediapc_vulkan_jni");
59     }
60 
61     /**
62      * Test specific setup
63      */
64     @Before
setUp()65     public void setUp() throws Exception {
66         JSONObject instance = new JSONObject(nativeGetVkJSON());
67         final JSONArray vkjson = instance.getJSONArray("devices");
68         var builder = ImmutableList.<JSONObject>builder();
69         for (int i = 0; i < vkjson.length(); i++) {
70             builder.add(vkjson.getJSONObject(i));
71         }
72         mVulkanDevices = builder.build();
73     }
74 
75     /**
76      * <b>7.1.4.1/H-1-3</b> MUST support
77      * {@code VkPhysicalDeviceProtectedMemoryFeatures.protectedMemory} and
78      * {@code VK_EXT_global_priority}.
79      */
80     @CddTest(requirements = {"7.1.4.1/H-1-3"})
81     @Test
checkVulkanProtectedMemoryAndGlobalPrioritySupport()82     public void checkVulkanProtectedMemoryAndGlobalPrioritySupport() throws Exception {
83 
84         PerformanceClassEvaluator pce = new PerformanceClassEvaluator(this.mTestName);
85         VulkanRequirement req = Requirements.addR7_1_4_1__H_1_3(pce);
86 
87         var filteredDevices = mVulkanDevices.stream().filter(this::notCpuDevice).toList();
88         final boolean extGlobalPriority = filteredDevices.stream().allMatch(
89                 device -> hasExtension(device, VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME,
90                         VK_EXT_GLOBAL_PRIORITY_SPEC_VERSION));
91         final boolean hasProtectedMemory = filteredDevices.stream().allMatch(
92                 this::hasProtectedMemory);
93 
94         req.setVkNonCpuDeviceCount(filteredDevices.size());
95         req.setVkPhysicalDeviceProtectedMemory(hasProtectedMemory);
96         req.setVkExtGlobalPriority(extGlobalPriority);
97 
98         pce.submitAndCheck();
99     }
100 
notCpuDevice(JSONObject device)101     private boolean notCpuDevice(JSONObject device) {
102         try {
103             return device.getJSONObject("properties").getInt("deviceType")
104                     != VK_PHYSICAL_DEVICE_TYPE_CPU;
105         } catch (JSONException e) {
106             Log.e(LOG_TAG, "Failed to get device type of %s".formatted(device), e);
107             return false;
108         }
109     }
110 
hasExtension(JSONObject device, String name, int minVersion)111     private static boolean hasExtension(JSONObject device, String name, int minVersion) {
112         try {
113             JSONArray extensions = device.getJSONArray("extensions");
114             for (int i = 0; i < extensions.length(); i++) {
115                 JSONObject ext = extensions.getJSONObject(i);
116                 if (ext.getString("extensionName").equals(name)
117                         && ext.getInt("specVersion")
118                         >= minVersion) {
119                     return true;
120                 }
121             }
122         } catch (Exception e) {
123             Log.e(LOG_TAG,
124                     "Failed to get extension %s v%s from %s".formatted(name, minVersion, device),
125                     e);
126         }
127         return false;
128     }
129 
hasProtectedMemory(JSONObject device)130     private boolean hasProtectedMemory(JSONObject device) {
131         try {
132             return device.getJSONObject("protectedMemoryFeatures")
133                     .getInt("protectedMemory") == 1;
134         } catch (Exception e) {
135             Log.e(LOG_TAG, "Failed to test for protect memory of  %s".formatted(device), e);
136         }
137         return false;
138     }
139 }
140