1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2021 The Khronos Group Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Vulkan SC pipeline cache tests
22 *//*--------------------------------------------------------------------*/
23
24 #include "vktPipelineCacheSCTests.hpp"
25
26 #include <set>
27 #include <vector>
28 #include <string>
29
30 #include "vktTestCaseUtil.hpp"
31 #include "vktCustomInstancesDevices.hpp"
32 #include "vkDefs.hpp"
33 #include "vkDeviceUtil.hpp"
34 #include "vkQueryUtil.hpp"
35 #include "vkRefUtil.hpp"
36 #include "vkSafetyCriticalUtil.hpp"
37 #include "tcuTestLog.hpp"
38
39 namespace vkt
40 {
41 namespace sc
42 {
43
44 using namespace vk;
45
46 namespace
47 {
48
49 enum PipelineCacheTestType
50 {
51 PCTT_UNUSED = 0,
52 PCTT_WRONG_VENDOR_ID,
53 PCTT_WRONG_DEVICE_ID
54 };
55
56 struct TestParams
57 {
58 PipelineCacheTestType type;
59 };
60
createShaders(SourceCollections & dst,TestParams params)61 void createShaders (SourceCollections& dst, TestParams params)
62 {
63 DE_UNREF(params);
64
65 {
66 std::ostringstream name, code;
67 name << "vertex";
68 code <<
69 "#version 450\n"
70 "\n"
71 "void main (void)\n"
72 "{\n"
73 " gl_Position = vec4( 1.0 );\n"
74 "}\n";
75 dst.glslSources.add(name.str()) << glu::VertexSource(code.str());
76 }
77
78 {
79 std::ostringstream name, code;
80 name << "fragment";
81 code <<
82 "#version 450\n"
83 "\n"
84 "layout(location=0) out vec4 x;\n"
85 "void main (void)\n"
86 "{\n"
87 " x = vec4( 1.0 );\n"
88 "}\n";
89 dst.glslSources.add(name.str()) << glu::FragmentSource(code.str());
90 }
91
92 {
93 std::ostringstream name, code;
94 name << "compute";
95 code <<
96 "#version 450\n"
97 "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
98 "void main (void)\n"
99 "{\n"
100 " uvec4 x = uvec4( 1 );\n"
101 "}\n";
102 dst.glslSources.add(name.str()) << glu::ComputeSource(code.str());
103 }
104 }
105
createPipelineCacheTest(Context & context,TestParams testParams)106 tcu::TestStatus createPipelineCacheTest (Context& context, TestParams testParams)
107 {
108 const vk::PlatformInterface& vkp = context.getPlatformInterface();
109 const CustomInstance instance (createCustomInstanceFromContext(context));
110 const InstanceDriver& instanceDriver (instance.getDriver());
111 const VkPhysicalDevice physicalDevice = chooseDevice(instanceDriver, instance, context.getTestContext().getCommandLine());
112
113 std::string graphicsPID = "PCST_GRAPHICS";
114 std::string computePID = "PCST_COMPUTE";
115
116 // In main process : prepare one graphics pipeline and one compute pipeline
117 // Actually these pipelines are here only to ensure that pipeline cache is not empty. We don't use them in subprocess
118 if (!context.getTestContext().getCommandLine().isSubProcess())
119 {
120 const DeviceInterface& vk = context.getDeviceInterface();
121 const VkDevice device = context.getDevice();
122
123 // graphics pipeline
124 {
125 Move<VkShaderModule> vertexShader = createShaderModule(vk, device, context.getBinaryCollection().get("vertex"), 0);
126 Move<VkShaderModule> fragmentShader = createShaderModule(vk, device, context.getBinaryCollection().get("fragment"), 0);
127
128 std::vector<VkPipelineShaderStageCreateInfo> shaderStageCreateInfos;
129 shaderStageCreateInfos.push_back
130 (
131 {
132 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
133 DE_NULL, // const void* pNext;
134 (VkPipelineShaderStageCreateFlags)0, // VkPipelineShaderStageCreateFlags flags;
135 VK_SHADER_STAGE_VERTEX_BIT, // VkShaderStageFlagBits stage;
136 *vertexShader, // VkShaderModule shader;
137 "main", // const char* pName;
138 DE_NULL, // const VkSpecializationInfo* pSpecializationInfo;
139 }
140 );
141 shaderStageCreateInfos.push_back
142 (
143 {
144 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
145 DE_NULL, // const void* pNext;
146 (VkPipelineShaderStageCreateFlags)0, // VkPipelineShaderStageCreateFlags flags;
147 VK_SHADER_STAGE_FRAGMENT_BIT, // VkShaderStageFlagBits stage;
148 *fragmentShader, // VkShaderModule shader;
149 "main", // const char* pName;
150 DE_NULL, // const VkSpecializationInfo* pSpecializationInfo;
151 }
152 );
153
154 VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo;
155 VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo;
156 VkPipelineViewportStateCreateInfo viewPortStateCreateInfo;
157 VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo;
158 VkPipelineMultisampleStateCreateInfo multisampleStateCreateInfo;
159 VkPipelineColorBlendAttachmentState colorBlendAttachmentState;
160 VkPipelineColorBlendStateCreateInfo colorBlendStateCreateInfo;
161 VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo;
162 std::vector<VkDynamicState> dynamicStates{ VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
163
164 const VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo =
165 {
166 VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
167 DE_NULL, // const void* pNext;
168 (VkPipelineLayoutCreateFlags)0u, // VkPipelineLayoutCreateFlags flags;
169 0u, // deUint32 setLayoutCount;
170 DE_NULL, // const VkDescriptorSetLayout* pSetLayouts;
171 0u, // deUint32 pushConstantRangeCount;
172 DE_NULL // const VkPushConstantRange* pPushConstantRanges;
173 };
174 Move<VkPipelineLayout> pipelineLayout = createPipelineLayout(vk, device, &pipelineLayoutCreateInfo);
175
176 const VkFormat format = getRenderTargetFormat(instanceDriver, physicalDevice);
177
178 VkAttachmentDescription attachmentDescription;
179 VkAttachmentReference attachmentReference;
180 VkSubpassDescription subpassDescription;
181 VkRenderPassCreateInfo renderPassCreateInfo = prepareSimpleRenderPassCI(format, attachmentDescription, attachmentReference, subpassDescription);
182 Move<VkRenderPass> renderPass = createRenderPass(vk, device, &renderPassCreateInfo);
183
184 VkGraphicsPipelineCreateInfo graphicsPipelineCreateInfo = prepareSimpleGraphicsPipelineCI(vertexInputStateCreateInfo, shaderStageCreateInfos, inputAssemblyStateCreateInfo, viewPortStateCreateInfo,
185 rasterizationStateCreateInfo, multisampleStateCreateInfo, colorBlendAttachmentState, colorBlendStateCreateInfo, dynamicStateCreateInfo, dynamicStates, *pipelineLayout, *renderPass);
186
187 // connect pipeline identifier
188 VkPipelineOfflineCreateInfo pipelineID = resetPipelineOfflineCreateInfo();
189 applyPipelineIdentifier(pipelineID, graphicsPID);
190 pipelineID.pNext = graphicsPipelineCreateInfo.pNext;
191 graphicsPipelineCreateInfo.pNext = &pipelineID;
192
193 // creation of a pipeline in main process registers it in pipeline cache
194 Move<VkPipeline> graphicsPipeline = createGraphicsPipeline(vk, device, DE_NULL, &graphicsPipelineCreateInfo);
195 }
196
197 // compute pipeline
198 {
199 Move<VkShaderModule> computeShader = createShaderModule(vk, device, context.getBinaryCollection().get("compute"), 0);
200 VkPipelineShaderStageCreateInfo shaderStageCreateInfo =
201 {
202 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
203 DE_NULL, // const void* pNext;
204 (VkPipelineShaderStageCreateFlags)0, // VkPipelineShaderStageCreateFlags flags;
205 VK_SHADER_STAGE_COMPUTE_BIT, // VkShaderStageFlagBits stage;
206 *computeShader, // VkShaderModule shader;
207 "main", // const char* pName;
208 DE_NULL, // const VkSpecializationInfo* pSpecializationInfo;
209 };
210
211 const VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo =
212 {
213 VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
214 DE_NULL, // const void* pNext;
215 (VkPipelineLayoutCreateFlags)0u, // VkPipelineLayoutCreateFlags flags;
216 0u, // deUint32 setLayoutCount;
217 DE_NULL, // const VkDescriptorSetLayout* pSetLayouts;
218 0u, // deUint32 pushConstantRangeCount;
219 DE_NULL // const VkPushConstantRange* pPushConstantRanges;
220 };
221 Move<VkPipelineLayout> pipelineLayout = createPipelineLayout(vk, device, &pipelineLayoutCreateInfo);
222
223 VkComputePipelineCreateInfo computePipelineCreateInfo = prepareSimpleComputePipelineCI(shaderStageCreateInfo, *pipelineLayout);
224
225 // connect pipeline identifier
226 VkPipelineOfflineCreateInfo pipelineID = resetPipelineOfflineCreateInfo();
227 applyPipelineIdentifier(pipelineID, computePID);
228 pipelineID.pNext = computePipelineCreateInfo.pNext;
229 computePipelineCreateInfo.pNext = &pipelineID;
230
231 // creation of a pipeline in main process registers it in pipeline cache
232 Move<VkPipeline> computePipeline = createComputePipeline(vk, device, DE_NULL, &computePipelineCreateInfo);
233 }
234 return tcu::TestStatus::pass("Pass");
235 }
236
237 // Subprocess : prepare pipeline cache data according to test type
238 // Copy data from ResourceInterface
239 std::vector<deUint8> customCacheData (context.getResourceInterface()->getCacheDataSize());
240 deMemcpy(customCacheData.data(), context.getResourceInterface()->getCacheData(), context.getResourceInterface()->getCacheDataSize());
241 deUintptr initialDataSize = customCacheData.size();
242 VkPipelineCacheHeaderVersionSafetyCriticalOne* pcHeader = (VkPipelineCacheHeaderVersionSafetyCriticalOne*)customCacheData.data();
243
244 switch (testParams.type)
245 {
246 case PCTT_WRONG_VENDOR_ID:
247 {
248 pcHeader->headerVersionOne.vendorID = deUint32(VK_VENDOR_ID_MAX_ENUM);
249 break;
250 }
251 case PCTT_WRONG_DEVICE_ID:
252 {
253 pcHeader->headerVersionOne.deviceID = 0xFFFFFFFF;
254 break;
255 }
256 default:
257 TCU_THROW(InternalError, "Unrecognized test type");
258 }
259
260 // Now, create custom device
261 const float queuePriority = 1.0f;
262
263 const VkDeviceQueueCreateInfo deviceQueueCI =
264 {
265 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType
266 DE_NULL, // pNext
267 (VkDeviceQueueCreateFlags)0u, // flags
268 0, //queueFamilyIndex;
269 1, //queueCount;
270 &queuePriority, //pQueuePriorities;
271 };
272
273 VkDeviceCreateInfo deviceCreateInfo =
274 {
275 VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, // sType;
276 DE_NULL, // pNext;
277 (VkDeviceCreateFlags)0u, // flags
278 1, // queueRecordCount;
279 &deviceQueueCI, // pRequestedQueues;
280 0, // layerCount;
281 DE_NULL, // ppEnabledLayerNames;
282 0, // extensionCount;
283 DE_NULL, // ppEnabledExtensionNames;
284 DE_NULL, // pEnabledFeatures;
285 };
286
287 VkDeviceObjectReservationCreateInfo objectInfo = resetDeviceObjectReservationCreateInfo();
288 objectInfo.pNext = DE_NULL;
289 objectInfo.pipelineLayoutRequestCount = 2u;
290 objectInfo.renderPassRequestCount = 1u;
291 objectInfo.subpassDescriptionRequestCount = 1u;
292 objectInfo.attachmentDescriptionRequestCount = 1u;
293 objectInfo.graphicsPipelineRequestCount = 1u;
294 objectInfo.computePipelineRequestCount = 1u;
295 objectInfo.pipelineCacheRequestCount = 2u;
296
297 VkPipelineCacheCreateInfo pipelineCacheCreateInfo =
298 {
299 VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, // VkStructureType sType;
300 DE_NULL, // const void* pNext;
301 VK_PIPELINE_CACHE_CREATE_READ_ONLY_BIT |
302 VK_PIPELINE_CACHE_CREATE_USE_APPLICATION_STORAGE_BIT, // VkPipelineCacheCreateFlags flags;
303 initialDataSize, // deUintptr initialDataSize;
304 customCacheData.data() // const void* pInitialData;
305 };
306 objectInfo.pipelineCacheCreateInfoCount = 1u;
307 objectInfo.pPipelineCacheCreateInfos = &pipelineCacheCreateInfo;
308
309 std::vector<VkPipelinePoolSize> poolSizes = context.getResourceInterface()->getPipelinePoolSizes();
310 if (!poolSizes.empty())
311 {
312 objectInfo.pipelinePoolSizeCount = deUint32(poolSizes.size());
313 objectInfo.pPipelinePoolSizes = poolSizes.data();
314 }
315 void* pNext = &objectInfo;
316
317 VkPhysicalDeviceVulkanSC10Features sc10Features = createDefaultSC10Features();
318 sc10Features.pNext = pNext;
319 pNext = &sc10Features;
320
321 deviceCreateInfo.pNext = pNext;
322
323 tcu::TestStatus testStatus = tcu::TestStatus::pass("Pass");
324 Move<VkDevice> device;
325 {
326 std::vector<const char*> enabledLayers;
327
328 if (deviceCreateInfo.enabledLayerCount == 0u && context.getTestContext().getCommandLine().isValidationEnabled())
329 {
330 enabledLayers = getValidationLayers(instanceDriver, physicalDevice);
331 deviceCreateInfo.enabledLayerCount = static_cast<deUint32>(enabledLayers.size());
332 deviceCreateInfo.ppEnabledLayerNames = (enabledLayers.empty() ? DE_NULL : enabledLayers.data());
333 }
334 VkDevice object = 0;
335 VkResult result = instanceDriver.createDevice(physicalDevice, &deviceCreateInfo, DE_NULL, &object);
336 switch (testParams.type)
337 {
338 case PCTT_WRONG_VENDOR_ID:
339 case PCTT_WRONG_DEVICE_ID:
340 if (result != VK_ERROR_INVALID_PIPELINE_CACHE_DATA)
341 testStatus = tcu::TestStatus::fail("Fail");
342 break;
343 default:
344 TCU_THROW(InternalError, "Unrecognized test type");
345 }
346 if (result != VK_SUCCESS)
347 return testStatus;
348 device = Move<VkDevice>(check<VkDevice>(object), Deleter<VkDevice>(vkp, instance, object, DE_NULL));
349 }
350
351 // create our own pipeline cache in subprocess. Use VK functions directly
352 GetDeviceProcAddrFunc getDeviceProcAddrFunc = (GetDeviceProcAddrFunc)vkp.getInstanceProcAddr(instance, "vkGetDeviceProcAddr");
353 CreatePipelineCacheFunc createPipelineCacheFunc = (CreatePipelineCacheFunc)getDeviceProcAddrFunc(*device, "vkCreatePipelineCache");
354 DestroyPipelineCacheFunc destroyPipelineCacheFunc = (DestroyPipelineCacheFunc)getDeviceProcAddrFunc(*device, "vkDestroyPipelineCache");
355
356 VkPipelineCache pipelineCache;
357 VkResult result = createPipelineCacheFunc(*device, &pipelineCacheCreateInfo, DE_NULL, &pipelineCache);
358
359 switch (testParams.type)
360 {
361 case PCTT_WRONG_VENDOR_ID:
362 case PCTT_WRONG_DEVICE_ID:
363 if (result != VK_ERROR_INVALID_PIPELINE_CACHE_DATA)
364 testStatus = tcu::TestStatus::fail("Fail");
365 break;
366 default:
367 TCU_THROW(InternalError, "Unrecognized test type");
368 }
369
370 if (result == VK_SUCCESS)
371 destroyPipelineCacheFunc(*device, pipelineCache, DE_NULL);
372
373 return testStatus;
374 }
375
376 } // anonymous
377
createPipelineCacheTests(tcu::TestContext & testCtx)378 tcu::TestCaseGroup* createPipelineCacheTests (tcu::TestContext& testCtx)
379 {
380 de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "pipeline_cache", "Tests verifying Vulkan SC pipeline cache"));
381
382 const struct
383 {
384 PipelineCacheTestType testType;
385 const char* name;
386 } tests[] =
387 {
388 { PCTT_WRONG_VENDOR_ID, "incorrect_vendor_id" },
389 { PCTT_WRONG_DEVICE_ID, "incorrect_device_id" },
390 };
391
392 for (int testIdx = 0; testIdx < DE_LENGTH_OF_ARRAY(tests); ++testIdx)
393 {
394 TestParams params{ tests[testIdx].testType };
395 addFunctionCaseWithPrograms(group.get(), tests[testIdx].name, "", createShaders, createPipelineCacheTest, params);
396 }
397
398 return group.release();
399 }
400
401 } // sc
402
403 } // vkt
404