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(),
65 testParams.pipelineConstructionType);
66 }
67
initPrograms(SourceCollections & programCollection,TestParams testParams)68 void initPrograms(SourceCollections &programCollection, TestParams testParams)
69 {
70 DE_UNREF(testParams.usePipelineCache);
71
72 programCollection.glslSources.add("color_vert")
73 << glu::VertexSource("#version 450\n"
74 "vec2 vertices[3];\n"
75 "\n"
76 "void main()\n"
77 "{\n"
78 " vertices[0] = vec2(-1.0, -1.0);\n"
79 " vertices[1] = vec2( 1.0, -1.0);\n"
80 " vertices[2] = vec2( 0.0, 1.0);\n"
81 " gl_Position = vec4(vertices[gl_VertexIndex % 3], 0.0, 1.0);\n"
82 "}\n");
83
84 programCollection.glslSources.add("color_frag") << glu::FragmentSource("#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 ¶ms, 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(
101 ShaderWrapper(vk, vkDevice, context.getBinaryCollection().get("color_vert"), 0));
102
103 const Unique<VkCommandPool> cmdPool(createCommandPool(
104 vk, vkDevice, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
105 context.getUniversalQueueFamilyIndex()));
106 const Unique<VkCommandBuffer> cmdBuffer(
107 allocateCommandBuffer(vk, vkDevice, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
108
109 const VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
110 VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
111 DE_NULL, // const void* pNext;
112 0u, // VkPipelineLayoutCreateFlags flags;
113 0u, // uint32_t setLayoutCount;
114 DE_NULL, // const VkDescriptorSetLayout* pSetLayouts;
115 0u, // uint32_t pushConstantRangeCount;
116 DE_NULL // const VkPushConstantRange* pPushConstantRanges;
117 };
118
119 // Multiple passes for destroy layout in order to increase the chance of crashing if some resource/state gets carried over from previous iterations.
120 int numTests = destroyLayout ? 3 : 1;
121 for (int i = 0; i < numTests; ++i)
122 {
123 PipelineLayoutWrapper pipelineLayout(params.pipelineConstructionType, vk, vkDevice, &pipelineLayoutCreateInfo,
124 DE_NULL);
125 RenderPassWrapper renderPass(params.pipelineConstructionType, vk, vkDevice, VK_FORMAT_R8G8B8A8_UNORM);
126 const VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = {
127 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
128 DE_NULL, // const void* pNext;
129 0u, // VkPipelineVertexInputStateCreateFlags flags;
130 0u, // uint32_t vertexBindingDescriptionCount;
131 DE_NULL, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
132 0u, // uint32_t vertexAttributeDescriptionCount;
133 DE_NULL // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
134 };
135 const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo = {
136 VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType;
137 DE_NULL, // const void* pNext;
138 0u, // VkPipelineInputAssemblyStateCreateFlags flags;
139 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, // VkPrimitiveTopology topology;
140 VK_FALSE // VkBool32 primitiveRestartEnable;
141 };
142 const VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo = {
143 VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
144 DE_NULL, // const void* pNext;
145 0u, // VkPipelineRasterizationStateCreateFlags flags;
146 VK_FALSE, // VkBool32 depthClampEnable;
147 VK_TRUE, // VkBool32 rasterizerDiscardEnable;
148 VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode;
149 VK_CULL_MODE_BACK_BIT, // VkCullModeFlags cullMode;
150 VK_FRONT_FACE_CLOCKWISE, // VkFrontFace frontFace;
151 VK_FALSE, // VkBool32 depthBiasEnable;
152 0.0f, // float depthBiasConstantFactor;
153 0.0f, // float depthBiasClamp;
154 0.0f, // float depthBiasSlopeFactor;
155 1.0f // float lineWidth;
156 };
157 const VkPipelineColorBlendAttachmentState colorBlendAttachmentState = {
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 VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
169 DE_NULL, // const void* pNext;
170 0u, // VkPipelineColorBlendStateCreateFlags flags;
171 VK_FALSE, // VkBool32 logicOpEnable;
172 VK_LOGIC_OP_CLEAR, // VkLogicOp logicOp;
173 1u, // uint32_t attachmentCount;
174 &colorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments;
175 {0.0f, 0.0f, 0.0f, 0.0f} // float blendConstants[4];
176 };
177 const VkPipelineCacheCreateInfo pipelineCacheCreateInfo = {
178 VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, // VkStructureType sType;
179 DE_NULL, // const void* pNext;
180 #ifndef CTS_USES_VULKANSC
181 (VkPipelineCacheCreateFlags)0u, // VkPipelineCacheCreateFlags flags;
182 0u, // size_t initialDataSize;
183 DE_NULL // const void* pInitialData;
184 #else
185 VK_PIPELINE_CACHE_CREATE_READ_ONLY_BIT |
186 VK_PIPELINE_CACHE_CREATE_USE_APPLICATION_STORAGE_BIT, // VkPipelineCacheCreateFlags flags;
187 context.getResourceInterface()->getCacheDataSize(), // uintptr_t initialDataSize;
188 context.getResourceInterface()->getCacheData() // const void* pInitialData;
189 #endif // CTS_USES_VULKANSC
190 };
191 const Unique<VkPipelineCache> pipelineCache(createPipelineCache(vk, vkDevice, &pipelineCacheCreateInfo));
192
193 const std::vector<VkViewport> viewports{};
194 const std::vector<VkRect2D> scissors{};
195 GraphicsPipelineWrapper graphicsPipeline(vki, vk, physicalDevice, vkDevice, context.getDeviceExtensions(),
196 params.pipelineConstructionType,
197 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, scissors, pipelineLayout, *renderPass, 0u, vertexShaderModule,
209 &rasterizationStateCreateInfo)
210 // Uninitialized so the pipeline wrapper does not add fragment stage.
211 // This avoids running into VUID-VkGraphicsPipelineCreateInfo-pStages-06894 due to enabled rasterizerDiscard
212 .setupFragmentShaderState(pipelineLayout, *renderPass, 0u, vk::ShaderWrapper())
213 .setupFragmentOutputState(*renderPass, 0u, &colorBlendStateCreateInfo)
214 .setMonolithicPipelineLayout(pipelineLayout)
215 .buildPipeline(params.usePipelineCache ? *pipelineCache : DE_NULL);
216
217 const uint32_t framebufferWidth = 32;
218 const uint32_t framebufferHeight = 32;
219 if (destroyLayout)
220 {
221 // This will destroy the pipelineLayout when going out of enclosing scope
222 pipelineLayout.destroy();
223 }
224 const VkCommandBufferBeginInfo cmdBufferBeginInfo = {
225 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType;
226 DE_NULL, // const void* pNext;
227 0u, // VkCommandBufferUsageFlags flags;
228 (const VkCommandBufferInheritanceInfo *)DE_NULL // const VkCommandBufferInheritanceInfo* pInheritanceInfo;
229 };
230 if (!destroyLayout)
231 {
232 VK_CHECK(vk.beginCommandBuffer(*cmdBuffer, &cmdBufferBeginInfo));
233 VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
234 }
235 else
236 {
237 auto &allocator = context.getDefaultAllocator();
238 const auto queue = context.getUniversalQueue();
239 const VkFormat attachmentFormat = VK_FORMAT_R8G8B8A8_UNORM;
240 const tcu::TextureFormat textureFormat = mapVkFormat(attachmentFormat);
241 const VkDeviceSize imageSize = framebufferWidth * framebufferHeight * textureFormat.getPixelSize();
242 const VkImageCreateInfo imageCreateInfo = {
243 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
244 DE_NULL, // const void* pNext;
245 (VkImageCreateFlags)0, // VkImageCreateFlags flags;
246 VK_IMAGE_TYPE_2D, // VkImageType imageType;
247 attachmentFormat, // VkFormat format;
248 {framebufferWidth, framebufferHeight, 1u}, // VkExtent3D extent;
249 1u, // uint32_t mipLevels;
250 1u, // uint32_t arrayLayers;
251 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
252 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
253 VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
254 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, // VkImageUsageFlags usage;
255 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
256 0u, // uint32_t queueFamilyIndexCount;
257 DE_NULL, // const uint32_t* pQueueFamilyIndices;
258 VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout initialLayout;
259 };
260 const ImageWithMemory attachmentImage(vk, vkDevice, context.getDefaultAllocator(), imageCreateInfo,
261 MemoryRequirement::Any);
262 const VkImageSubresourceRange colorSubresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u};
263 const Unique<VkImageView> attachmentImageView(vk::makeImageView(
264 vk, vkDevice, *attachmentImage, VK_IMAGE_VIEW_TYPE_2D, attachmentFormat, colorSubresourceRange));
265 const VkBufferCreateInfo imageBufferCreateInfo =
266 vk::makeBufferCreateInfo(imageSize, vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT);
267 const BufferWithMemory imageBuffer(vk, vkDevice, allocator, imageBufferCreateInfo,
268 vk::MemoryRequirement::HostVisible);
269 renderPass.createFramebuffer(vk, vkDevice, *attachmentImage, *attachmentImageView, framebufferWidth,
270 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 {{clearColor.x(), clearColor.y(), clearColor.z(), clearColor.w()}} // float float32[4];
276 };
277 VkClearAttachment attachment = {
278 VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask;
279 0u, // uint32_t colorAttachment;
280 clearValue // VkClearValue clearValue;
281 };
282 const VkRect2D renderArea = {{0, 0}, {framebufferWidth, framebufferHeight}};
283 const VkClearRect rect = {
284 renderArea, // VkRect2D rect
285 0u, // uint32_t baseArrayLayer
286 1u // uint32_t layerCount
287 };
288 renderPass.begin(vk, *cmdBuffer, renderArea, clearValue);
289 vk.cmdClearAttachments(*cmdBuffer, 1, &attachment, 1, &rect);
290 renderPass.end(vk, *cmdBuffer);
291 vk::copyImageToBuffer(vk, *cmdBuffer, *attachmentImage, *imageBuffer,
292 tcu::IVec2(framebufferWidth, framebufferHeight));
293 VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
294
295 vk::submitCommandsAndWait(vk, vkDevice, queue, *cmdBuffer);
296 VK_CHECK(vk.resetCommandBuffer(*cmdBuffer, VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT));
297 const auto &imageBufferAlloc = imageBuffer.getAllocation();
298 vk::invalidateAlloc(vk, vkDevice, imageBufferAlloc);
299
300 const auto imageBufferPtr =
301 reinterpret_cast<const char *>(imageBufferAlloc.getHostPtr()) + imageBufferAlloc.getOffset();
302 const tcu::ConstPixelBufferAccess imagePixels(textureFormat, framebufferWidth, framebufferHeight, 1u,
303 imageBufferPtr);
304
305 #ifdef CTS_USES_VULKANSC
306 if (context.getTestContext().getCommandLine().isSubProcess())
307 #endif // CTS_USES_VULKANSC
308 {
309 for (int z = 0; z < imagePixels.getDepth(); ++z)
310 for (int y = 0; y < imagePixels.getHeight(); ++y)
311 for (int x = 0; x < imagePixels.getWidth(); ++x)
312 {
313 const auto pixel = imagePixels.getPixel(x, y, z);
314 if (pixel != clearColor)
315 {
316 std::ostringstream msg;
317 msg << "Pixel value mismatch after framebuffer clear."
318 << " diff: " << pixel << " vs " << clearColor;
319
320 return tcu::TestStatus::fail(
321 msg.str() /*"Pixel value mismatch after framebuffer clear."*/);
322 }
323 }
324 }
325 }
326 }
327 // Passes as long as no crash occurred.
328 return tcu::TestStatus::pass("Pass");
329 }
330
testEarlyDestroyKeepLayout(Context & context,TestParams params)331 tcu::TestStatus testEarlyDestroyKeepLayout(Context &context, TestParams params)
332 {
333 return testEarlyDestroy(context, params, false);
334 }
335
testEarlyDestroyDestroyLayout(Context & context,TestParams params)336 tcu::TestStatus testEarlyDestroyDestroyLayout(Context &context, TestParams params)
337 {
338 return testEarlyDestroy(context, params, true);
339 }
340
addEarlyDestroyTestCasesWithFunctions(tcu::TestCaseGroup * group,PipelineConstructionType pipelineConstructionType)341 void addEarlyDestroyTestCasesWithFunctions(tcu::TestCaseGroup *group, PipelineConstructionType pipelineConstructionType)
342 {
343 TestParams params{
344 pipelineConstructionType,
345 true,
346 false,
347 };
348
349 addFunctionCaseWithPrograms(group, "cache", checkSupport, initPrograms, testEarlyDestroyKeepLayout, params);
350 params.usePipelineCache = false;
351 addFunctionCaseWithPrograms(group, "no_cache", checkSupport, initPrograms, testEarlyDestroyKeepLayout, params);
352 params.usePipelineCache = true;
353 addFunctionCaseWithPrograms(group, "cache_destroy_layout", checkSupport, initPrograms,
354 testEarlyDestroyDestroyLayout, params);
355 params.usePipelineCache = false;
356 addFunctionCaseWithPrograms(group, "no_cache_destroy_layout", checkSupport, initPrograms,
357 testEarlyDestroyDestroyLayout, params);
358 params.useMaintenance5 = true;
359 addFunctionCaseWithPrograms(group, "no_cache_destroy_layout_maintenance5", checkSupport, initPrograms,
360 testEarlyDestroyDestroyLayout, params);
361 }
362
363 } // namespace
364
createEarlyDestroyTests(tcu::TestContext & testCtx,PipelineConstructionType pipelineConstructionType)365 tcu::TestCaseGroup *createEarlyDestroyTests(tcu::TestContext &testCtx,
366 PipelineConstructionType pipelineConstructionType)
367 {
368 return createTestGroup(testCtx, "early_destroy", addEarlyDestroyTestCasesWithFunctions, pipelineConstructionType);
369 }
370
371 } // namespace pipeline
372 } // namespace vkt
373