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