1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2018 The Khronos Group Inc.
6 * Copyright (c) 2018 Google Inc.
7 * Copyright (c) 2023 LunarG, Inc.
8 * Copyright (c) 2023 Nintendo
9 *
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
13 *
14 * http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
21 *
22 *//*!
23 * \file
24 * \brief Early pipeline destroying tests
25 *//*--------------------------------------------------------------------*/
26
27 #include "vktPipelineEarlyDestroyTests.hpp"
28 #include "vktTestCase.hpp"
29 #include "vktTestCaseUtil.hpp"
30 #include "vktTestGroupUtil.hpp"
31 #include "vkMemUtil.hpp"
32 #include "vkPrograms.hpp"
33 #include "vkRefUtil.hpp"
34 #include "vkObjUtil.hpp"
35 #include "deUniquePtr.hpp"
36 #include "tcuTexture.hpp"
37 #include "vkImageUtil.hpp"
38 #include "vkImageWithMemory.hpp"
39 #include "vkBufferWithMemory.hpp"
40 #include "vkCmdUtil.hpp"
41
42 namespace vkt
43 {
44 namespace pipeline
45 {
46
47 using namespace vk;
48
49 namespace
50 {
51
52 struct TestParams
53 {
54 PipelineConstructionType pipelineConstructionType;
55 bool usePipelineCache;
56 bool useMaintenance5;
57 };
58
checkSupport(Context& context, TestParams testParams)59 void checkSupport(Context& context, TestParams testParams)
60 {
61 if (testParams.useMaintenance5)
62 context.requireDeviceFunctionality("VK_KHR_maintenance5");
63
64 checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(), testParams.pipelineConstructionType);
65 }
66
initPrograms(SourceCollections& programCollection, TestParams testParams)67 void initPrograms (SourceCollections& programCollection, TestParams testParams)
68 {
69 DE_UNREF(testParams.usePipelineCache);
70
71 programCollection.glslSources.add("color_vert") << glu::VertexSource(
72 "#version 450\n"
73 "vec2 vertices[3];\n"
74 "\n"
75 "void main()\n"
76 "{\n"
77 " vertices[0] = vec2(-1.0, -1.0);\n"
78 " vertices[1] = vec2( 1.0, -1.0);\n"
79 " vertices[2] = vec2( 0.0, 1.0);\n"
80 " gl_Position = vec4(vertices[gl_VertexIndex % 3], 0.0, 1.0);\n"
81 "}\n");
82
83 programCollection.glslSources.add("color_frag") << glu::FragmentSource(
84 "#version 450\n"
85 "\n"
86 "layout(location = 0) out vec4 uFragColor;\n"
87 "\n"
88 "void main()\n"
89 "{\n"
90 " uFragColor = vec4(0,1,0,1);\n"
91 "}\n");
92 }
93
testEarlyDestroy(Context& context, const TestParams& params, bool destroyLayout)94 tcu::TestStatus testEarlyDestroy (Context& context, const TestParams& params, bool destroyLayout)
95 {
96 const InstanceInterface& vki = context.getInstanceInterface();
97 const DeviceInterface& vk = context.getDeviceInterface();
98 const VkPhysicalDevice physicalDevice = context.getPhysicalDevice();
99 const VkDevice vkDevice = context.getDevice();
100 const ShaderWrapper vertexShaderModule (ShaderWrapper(vk, vkDevice, context.getBinaryCollection().get("color_vert"), 0));
101
102 const Unique<VkCommandPool> cmdPool (createCommandPool(vk, vkDevice, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, context.getUniversalQueueFamilyIndex()));
103 const Unique<VkCommandBuffer> cmdBuffer (allocateCommandBuffer(vk, vkDevice, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
104
105 const VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo =
106 {
107 VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
108 DE_NULL, // const void* pNext;
109 0u, // VkPipelineLayoutCreateFlags flags;
110 0u, // deUint32 setLayoutCount;
111 DE_NULL, // const VkDescriptorSetLayout* pSetLayouts;
112 0u, // deUint32 pushConstantRangeCount;
113 DE_NULL // const VkPushConstantRange* pPushConstantRanges;
114 };
115
116 // Multiple passes for destroy layout in order to increase the chance of crashing if some resource/state gets carried over from previous iterations.
117 int numTests = destroyLayout ? 3 : 1;
118 for(int i = 0; i < numTests; ++i)
119 {
120 PipelineLayoutWrapper pipelineLayout (params.pipelineConstructionType, vk, vkDevice, &pipelineLayoutCreateInfo, DE_NULL);
121 RenderPassWrapper renderPass (params.pipelineConstructionType, vk, vkDevice, VK_FORMAT_R8G8B8A8_UNORM);
122 const VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo =
123 {
124 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
125 DE_NULL, // const void* pNext;
126 0u, // VkPipelineVertexInputStateCreateFlags flags;
127 0u, // deUint32 vertexBindingDescriptionCount;
128 DE_NULL, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
129 0u, // deUint32 vertexAttributeDescriptionCount;
130 DE_NULL // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
131 };
132 const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo =
133 {
134 VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType;
135 DE_NULL, // const void* pNext;
136 0u, // VkPipelineInputAssemblyStateCreateFlags flags;
137 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, // VkPrimitiveTopology topology;
138 VK_FALSE // VkBool32 primitiveRestartEnable;
139 };
140 const VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo =
141 {
142 VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
143 DE_NULL, // const void* pNext;
144 0u, // VkPipelineRasterizationStateCreateFlags flags;
145 VK_FALSE, // VkBool32 depthClampEnable;
146 VK_TRUE, // VkBool32 rasterizerDiscardEnable;
147 VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode;
148 VK_CULL_MODE_BACK_BIT, // VkCullModeFlags cullMode;
149 VK_FRONT_FACE_CLOCKWISE, // VkFrontFace frontFace;
150 VK_FALSE, // VkBool32 depthBiasEnable;
151 0.0f, // float depthBiasConstantFactor;
152 0.0f, // float depthBiasClamp;
153 0.0f, // float depthBiasSlopeFactor;
154 1.0f // float lineWidth;
155 };
156 const VkPipelineColorBlendAttachmentState colorBlendAttachmentState =
157 {
158 VK_FALSE, // VkBool32 blendEnable;
159 VK_BLEND_FACTOR_ZERO, // VkBlendFactor srcColorBlendFactor;
160 VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstColorBlendFactor;
161 VK_BLEND_OP_ADD, // VkBlendOp colorBlendOp;
162 VK_BLEND_FACTOR_ZERO, // VkBlendFactor srcAlphaBlendFactor;
163 VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstAlphaBlendFactor;
164 VK_BLEND_OP_ADD, // VkBlendOp alphaBlendOp;
165 0xf // VkColorComponentFlags colorWriteMask;
166 };
167 const VkPipelineColorBlendStateCreateInfo colorBlendStateCreateInfo =
168 {
169 VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
170 DE_NULL, // const void* pNext;
171 0u, // VkPipelineColorBlendStateCreateFlags flags;
172 VK_FALSE, // VkBool32 logicOpEnable;
173 VK_LOGIC_OP_CLEAR, // VkLogicOp logicOp;
174 1u, // deUint32 attachmentCount;
175 &colorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments;
176 { 0.0f, 0.0f, 0.0f, 0.0f } // float blendConstants[4];
177 };
178 const VkPipelineCacheCreateInfo pipelineCacheCreateInfo =
179 {
180 VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, // VkStructureType sType;
181 DE_NULL, // const void* pNext;
182 #ifndef CTS_USES_VULKANSC
183 (VkPipelineCacheCreateFlags)0u, // VkPipelineCacheCreateFlags flags;
184 0u, // size_t initialDataSize;
185 DE_NULL // const void* pInitialData;
186 #else
187 VK_PIPELINE_CACHE_CREATE_READ_ONLY_BIT |
188 VK_PIPELINE_CACHE_CREATE_USE_APPLICATION_STORAGE_BIT, // VkPipelineCacheCreateFlags flags;
189 context.getResourceInterface()->getCacheDataSize(), // deUintptr initialDataSize;
190 context.getResourceInterface()->getCacheData() // const void* pInitialData;
191 #endif // CTS_USES_VULKANSC
192 };
193 const Unique<VkPipelineCache> pipelineCache (createPipelineCache(vk, vkDevice, &pipelineCacheCreateInfo));
194
195 const std::vector<VkViewport> viewports {};
196 const std::vector<VkRect2D> scissors {};
197 GraphicsPipelineWrapper graphicsPipeline (vki, vk, physicalDevice, vkDevice, context.getDeviceExtensions(), params.pipelineConstructionType, VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT);
198
199 #ifndef CTS_USES_VULKANSC
200 if (params.useMaintenance5)
201 graphicsPipeline.setPipelineCreateFlags2(VK_PIPELINE_CREATE_2_DISABLE_OPTIMIZATION_BIT_KHR);
202 #endif // CTS_USES_VULKANSC
203
204 graphicsPipeline.disableViewportState()
205 .setDefaultMultisampleState()
206 .setDefaultDepthStencilState()
207 .setupVertexInputState(&vertexInputStateCreateInfo, &inputAssemblyStateCreateInfo)
208 .setupPreRasterizationShaderState(viewports,
209 scissors,
210 pipelineLayout,
211 *renderPass,
212 0u,
213 vertexShaderModule,
214 &rasterizationStateCreateInfo)
215 // Uninitialized so the pipeline wrapper does not add fragment stage.
216 // This avoids running into VUID-VkGraphicsPipelineCreateInfo-pStages-06894 due to enabled rasterizerDiscard
217 .setupFragmentShaderState(pipelineLayout, *renderPass, 0u, vk::ShaderWrapper())
218 .setupFragmentOutputState(*renderPass, 0u, &colorBlendStateCreateInfo)
219 .setMonolithicPipelineLayout(pipelineLayout)
220 .buildPipeline(params.usePipelineCache ? *pipelineCache : DE_NULL);
221
222 const deUint32 framebufferWidth = 32;
223 const deUint32 framebufferHeight = 32;
224 if (destroyLayout)
225 {
226 // This will destroy the pipelineLayout when going out of enclosing scope
227 pipelineLayout.destroy();
228 }
229 const VkCommandBufferBeginInfo cmdBufferBeginInfo =
230 {
231 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType;
232 DE_NULL, // const void* pNext;
233 0u, // VkCommandBufferUsageFlags flags;
234 (const VkCommandBufferInheritanceInfo*)DE_NULL // const VkCommandBufferInheritanceInfo* pInheritanceInfo;
235 };
236 if (!destroyLayout) {
237 VK_CHECK(vk.beginCommandBuffer(*cmdBuffer, &cmdBufferBeginInfo));
238 VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
239 } else {
240 auto& allocator = context.getDefaultAllocator();
241 const auto queue = context.getUniversalQueue();
242 const VkFormat attachmentFormat = VK_FORMAT_R8G8B8A8_UNORM;
243 const tcu::TextureFormat textureFormat = mapVkFormat(attachmentFormat);
244 const VkDeviceSize imageSize = framebufferWidth * framebufferHeight * textureFormat.getPixelSize();
245 const VkImageCreateInfo imageCreateInfo =
246 {
247 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
248 DE_NULL, // const void* pNext;
249 (VkImageCreateFlags)0, // VkImageCreateFlags flags;
250 VK_IMAGE_TYPE_2D, // VkImageType imageType;
251 attachmentFormat, // VkFormat format;
252 { framebufferWidth, framebufferHeight, 1u }, // VkExtent3D extent;
253 1u, // deUint32 mipLevels;
254 1u, // deUint32 arrayLayers;
255 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
256 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
257 VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
258 VK_IMAGE_USAGE_TRANSFER_DST_BIT |
259 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, // VkImageUsageFlags usage;
260 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
261 0u, // deUint32 queueFamilyIndexCount;
262 DE_NULL, // const deUint32* pQueueFamilyIndices;
263 VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout initialLayout;
264 };
265 const ImageWithMemory attachmentImage (vk, vkDevice, context.getDefaultAllocator(), imageCreateInfo, MemoryRequirement::Any);
266 const VkImageSubresourceRange colorSubresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u };
267 const Unique<VkImageView> attachmentImageView (vk::makeImageView(vk, vkDevice, *attachmentImage, VK_IMAGE_VIEW_TYPE_2D, attachmentFormat, colorSubresourceRange));
268 const VkBufferCreateInfo imageBufferCreateInfo = vk::makeBufferCreateInfo(imageSize, vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT);
269 const BufferWithMemory imageBuffer (vk, vkDevice, allocator, imageBufferCreateInfo, vk::MemoryRequirement::HostVisible);
270 renderPass.createFramebuffer(vk, vkDevice, *attachmentImage, *attachmentImageView, framebufferWidth, framebufferHeight, 1u);
271
272 VK_CHECK(vk.beginCommandBuffer(*cmdBuffer, &cmdBufferBeginInfo));
273 const tcu::Vec4 clearColor = { 0.2f, 0.6f, 0.8f, 1.0f };
274 VkClearValue clearValue =
275 {
276 { { clearColor.x(), clearColor.y(),
277 clearColor.z(), clearColor.w() } } // float float32[4];
278 };
279 VkClearAttachment attachment =
280 {
281 VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask;
282 0u, // deUint32 colorAttachment;
283 clearValue // VkClearValue clearValue;
284 };
285 const VkRect2D renderArea = { { 0, 0 }, { framebufferWidth, framebufferHeight } };
286 const VkClearRect rect =
287 {
288 renderArea, // VkRect2D rect
289 0u, // uint32_t baseArrayLayer
290 1u // uint32_t layerCount
291 };
292 renderPass.begin(vk, *cmdBuffer, renderArea, clearValue);
293 vk.cmdClearAttachments(*cmdBuffer, 1, &attachment, 1, &rect);
294 renderPass.end(vk, *cmdBuffer);
295 vk::copyImageToBuffer(vk, *cmdBuffer, *attachmentImage, *imageBuffer, tcu::IVec2(framebufferWidth, framebufferHeight));
296 VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
297
298 vk::submitCommandsAndWait(vk, vkDevice, queue, *cmdBuffer);
299 VK_CHECK(vk.resetCommandBuffer(*cmdBuffer, VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT));
300 const auto& imageBufferAlloc = imageBuffer.getAllocation();
301 vk::invalidateAlloc(vk, vkDevice, imageBufferAlloc);
302
303 const auto imageBufferPtr = reinterpret_cast<const char*>(imageBufferAlloc.getHostPtr()) + imageBufferAlloc.getOffset();
304 const tcu::ConstPixelBufferAccess imagePixels (textureFormat, framebufferWidth, framebufferHeight, 1u, imageBufferPtr);
305
306 #ifdef CTS_USES_VULKANSC
307 if (context.getTestContext().getCommandLine().isSubProcess())
308 #endif // CTS_USES_VULKANSC
309 {
310 for (int z = 0; z < imagePixels.getDepth(); ++z)
311 for (int y = 0; y < imagePixels.getHeight(); ++y)
312 for (int x = 0; x < imagePixels.getWidth(); ++x)
313 {
314 const auto pixel = imagePixels.getPixel(x, y, z);
315 if (pixel != clearColor) {
316 std::ostringstream msg; msg << "Pixel value mismatch after framebuffer clear." << " diff: " << pixel << " vs " << clearColor;
317
318 return tcu::TestStatus::fail(msg.str()/*"Pixel value mismatch after framebuffer clear."*/);
319 }
320 }
321 }
322 }
323 }
324 // Passes as long as no crash occurred.
325 return tcu::TestStatus::pass("Pass");
326 }
327
testEarlyDestroyKeepLayout(Context& context, TestParams params)328 tcu::TestStatus testEarlyDestroyKeepLayout (Context& context, TestParams params)
329 {
330 return testEarlyDestroy (context, params, false);
331 }
332
testEarlyDestroyDestroyLayout(Context& context, TestParams params)333 tcu::TestStatus testEarlyDestroyDestroyLayout (Context& context, TestParams params)
334 {
335 return testEarlyDestroy (context, params, true);
336 }
337
addEarlyDestroyTestCasesWithFunctions(tcu::TestCaseGroup* group, PipelineConstructionType pipelineConstructionType)338 void addEarlyDestroyTestCasesWithFunctions (tcu::TestCaseGroup* group, PipelineConstructionType pipelineConstructionType)
339 {
340 TestParams params
341 {
342 pipelineConstructionType,
343 true,
344 false,
345 };
346
347 addFunctionCaseWithPrograms(group, "cache", checkSupport, initPrograms, testEarlyDestroyKeepLayout, params);
348 params.usePipelineCache = false;
349 addFunctionCaseWithPrograms(group, "no_cache", checkSupport, initPrograms, testEarlyDestroyKeepLayout, params);
350 params.usePipelineCache = true;
351 addFunctionCaseWithPrograms(group, "cache_destroy_layout", checkSupport, initPrograms, testEarlyDestroyDestroyLayout, params);
352 params.usePipelineCache = false;
353 addFunctionCaseWithPrograms(group, "no_cache_destroy_layout", checkSupport, initPrograms, testEarlyDestroyDestroyLayout, params);
354 params.useMaintenance5 = true;
355 addFunctionCaseWithPrograms(group, "no_cache_destroy_layout_maintenance5", checkSupport, initPrograms, testEarlyDestroyDestroyLayout, params);
356 }
357
358 } // anonymous
359
createEarlyDestroyTests(tcu::TestContext& testCtx, PipelineConstructionType pipelineConstructionType)360 tcu::TestCaseGroup* createEarlyDestroyTests (tcu::TestContext& testCtx, PipelineConstructionType pipelineConstructionType)
361 {
362 return createTestGroup(testCtx, "early_destroy", addEarlyDestroyTestCasesWithFunctions, pipelineConstructionType);
363 }
364
365 } // pipeline
366 } // vkt
367