1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2023 The Khronos Group Inc.
6  * Copyright (c) 2023 Google LLC.
7  * Copyright (c) 2023 LunarG, Inc.
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  *//*!
22  * \file
23  * \brief Test robustness with pipeline cache
24  *//*--------------------------------------------------------------------*/
25 
26 #include "vktPipelineRobustnessCacheTests.hpp"
27 
28 #include "vktTestCase.hpp"
29 #include "vktTestGroupUtil.hpp"
30 
31 #include "vkBufferWithMemory.hpp"
32 #include "vkObjUtil.hpp"
33 #include "vkBuilderUtil.hpp"
34 #include "vkTypeUtil.hpp"
35 #include "vkPipelineConstructionUtil.hpp"
36 #include "vkCmdUtil.hpp"
37 #include "vkImageUtil.hpp"
38 
39 namespace vkt
40 {
41 namespace pipeline
42 {
43 
44 enum RobustnessBehaviour
45 {
46     ROBUSTNESS   = 0,
47     ROBUSTNESS_2 = 1,
48 };
49 
50 enum RobustnessType
51 {
52     STORAGE = 0,
53     UNIFORM,
54     VERTEX_INPUT,
55     IMAGE,
56 };
57 
58 namespace
59 {
60 
makeBufferForImage(const vk::DeviceInterface & vk,const vk::VkDevice device,vk::Allocator & allocator,vk::VkFormat imageFormat,vk::VkExtent2D imageExtent)61 std::unique_ptr<vk::BufferWithMemory> makeBufferForImage(const vk::DeviceInterface &vk, const vk::VkDevice device,
62                                                          vk::Allocator &allocator, vk::VkFormat imageFormat,
63                                                          vk::VkExtent2D imageExtent)
64 {
65     const auto tcuFormat      = mapVkFormat(imageFormat);
66     const auto outBufferSize  = static_cast<vk::VkDeviceSize>(static_cast<uint32_t>(tcu::getPixelSize(tcuFormat)) *
67                                                              imageExtent.width * imageExtent.height);
68     const auto outBufferUsage = vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT;
69     const auto outBufferInfo  = vk::makeBufferCreateInfo(outBufferSize, outBufferUsage);
70 
71     auto outBuffer = std::unique_ptr<vk::BufferWithMemory>(
72         new vk::BufferWithMemory(vk, device, allocator, outBufferInfo, vk::MemoryRequirement::HostVisible));
73 
74     return outBuffer;
75 }
76 
makeImageCreateInfo(vk::VkFormat format,vk::VkExtent3D extent,vk::VkImageUsageFlags usage)77 vk::VkImageCreateInfo makeImageCreateInfo(vk::VkFormat format, vk::VkExtent3D extent, vk::VkImageUsageFlags usage)
78 {
79     const vk::VkImageCreateInfo imageCreateInfo = {
80         vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
81         nullptr,                                 // const void* pNext;
82         (vk::VkImageCreateFlags)0u,              // VkImageCreateFlags flags;
83         vk::VK_IMAGE_TYPE_2D,                    // VkImageType imageType;
84         format,                                  // VkFormat format;
85         extent,                                  // VkExtent3D extent;
86         1u,                                      // uint32_t mipLevels;
87         1u,                                      // uint32_t arrayLayers;
88         vk::VK_SAMPLE_COUNT_1_BIT,               // VkSampleCountFlagBits samples;
89         vk::VK_IMAGE_TILING_OPTIMAL,             // VkImageTiling tiling;
90         usage,                                   // VkImageUsageFlags usage;
91         vk::VK_SHARING_MODE_EXCLUSIVE,           // VkSharingMode sharingMode;
92         0u,                                      // uint32_t queueFamilyIndexCount;
93         nullptr,                                 // const uint32_t* pQueueFamilyIndices;
94         vk::VK_IMAGE_LAYOUT_UNDEFINED,           // VkImageLayout initialLayout;
95     };
96 
97     return imageCreateInfo;
98 }
99 
makeSampler(const vk::DeviceInterface & vk,const vk::VkDevice device)100 vk::Move<vk::VkSampler> makeSampler(const vk::DeviceInterface &vk, const vk::VkDevice device)
101 {
102     const vk::VkSamplerCreateInfo samplerInfo = {
103         vk::VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,   // sType
104         DE_NULL,                                     // pNext
105         0u,                                          // flags
106         vk::VK_FILTER_NEAREST,                       // magFilter
107         vk::VK_FILTER_NEAREST,                       // minFilter
108         vk::VK_SAMPLER_MIPMAP_MODE_NEAREST,          // mipmapMode
109         vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,   // addressModeU
110         vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,   // addressModeV
111         vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,   // addressModeW
112         0.0f,                                        // mipLodBias
113         VK_FALSE,                                    // anisotropyEnable
114         1.0f,                                        // maxAnisotropy
115         false,                                       // compareEnable
116         vk::VK_COMPARE_OP_ALWAYS,                    // compareOp
117         0.0f,                                        // minLod
118         1.0f,                                        // maxLod
119         vk::VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, // borderColor
120         VK_FALSE,                                    // unnormalizedCoords
121     };
122 
123     return createSampler(vk, device, &samplerInfo);
124 }
125 
126 class PipelineCacheTestInstance : public vkt::TestInstance
127 {
128 public:
PipelineCacheTestInstance(vkt::Context & context,vk::PipelineConstructionType pipelineConstructionType,RobustnessBehaviour robustnessBufferBehaviour,RobustnessType type)129     PipelineCacheTestInstance(vkt::Context &context, vk::PipelineConstructionType pipelineConstructionType,
130                               RobustnessBehaviour robustnessBufferBehaviour, RobustnessType type)
131         : vkt::TestInstance(context)
132         , m_pipelineConstructionType(pipelineConstructionType)
133         , m_robustnessBufferBehaviour(robustnessBufferBehaviour)
134         , m_type(type)
135         , m_extent()
136     {
137     }
138 
139 private:
140     void draw(const vk::GraphicsPipelineWrapper &pipeline);
141     bool verifyImage(tcu::Vec4 value, bool oob);
142     tcu::TestStatus iterate(void);
143 
144     const vk::PipelineConstructionType m_pipelineConstructionType;
145     const RobustnessBehaviour m_robustnessBufferBehaviour;
146     const RobustnessType m_type;
147 
148     vk::VkExtent2D m_extent;
149     vk::Move<vk::VkCommandPool> m_cmdPool;
150     vk::Move<vk::VkCommandBuffer> m_cmdBuffer;
151     de::MovePtr<vk::BufferWithMemory> m_buffer;
152     vk::RenderPassWrapper m_renderPass;
153     vk::PipelineLayoutWrapper m_pipelineLayout;
154     vk::Move<vk::VkDescriptorPool> m_descriptorPool;
155     vk::Move<vk::VkDescriptorSet> m_descriptorSet;
156     de::MovePtr<vk::ImageWithMemory> m_colorAttachment;
157     std::unique_ptr<vk::BufferWithMemory> m_outBuffer;
158 };
159 
draw(const vk::GraphicsPipelineWrapper & pipeline)160 void PipelineCacheTestInstance::draw(const vk::GraphicsPipelineWrapper &pipeline)
161 {
162     const vk::DeviceInterface &vk = m_context.getDeviceInterface();
163     const vk::VkDevice device     = m_context.getDevice();
164     const vk::VkQueue queue       = m_context.getUniversalQueue();
165 
166     const tcu::Vec4 clearColor(0.0f, 0.0f, 0.0f, 1.0f);
167 
168     vk::beginCommandBuffer(vk, *m_cmdBuffer);
169     if (m_type == VERTEX_INPUT)
170     {
171         vk::VkDeviceSize offset = 0u;
172         vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &**m_buffer, &offset);
173     }
174     m_renderPass.begin(vk, *m_cmdBuffer, makeRect2D(m_extent), clearColor);
175     vk.cmdBindDescriptorSets(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelineLayout, 0, 1,
176                              &*m_descriptorSet, 0, DE_NULL);
177     pipeline.bind(*m_cmdBuffer);
178     vk.cmdDraw(*m_cmdBuffer, 4, 1, 0, 0);
179     m_renderPass.end(vk, *m_cmdBuffer);
180     vk::endCommandBuffer(vk, *m_cmdBuffer);
181 
182     vk::submitCommandsAndWait(vk, device, queue, *m_cmdBuffer);
183 
184     vk::beginCommandBuffer(vk, *m_cmdBuffer);
185     vk::copyImageToBuffer(vk, *m_cmdBuffer, m_colorAttachment->get(), (*m_outBuffer).get(),
186                           tcu::IVec2(m_extent.width, m_extent.height));
187     vk::endCommandBuffer(vk, *m_cmdBuffer);
188     vk::submitCommandsAndWait(vk, device, queue, *m_cmdBuffer);
189 }
190 
verifyImage(tcu::Vec4 value,bool oob)191 bool PipelineCacheTestInstance::verifyImage(tcu::Vec4 value, bool oob)
192 {
193     const vk::DeviceInterface &vk = m_context.getDeviceInterface();
194     const vk::VkDevice device     = m_context.getDevice();
195 
196     auto &outBufferAlloc = m_outBuffer->getAllocation();
197 
198     invalidateAlloc(vk, device, outBufferAlloc);
199     const tcu::ConstPixelBufferAccess result(vk::mapVkFormat(vk::VK_FORMAT_R32G32B32A32_SFLOAT),
200                                              tcu::IVec3(m_extent.width, m_extent.height, 1),
201                                              (const char *)outBufferAlloc.getHostPtr());
202 
203     const uint32_t h = result.getHeight();
204     const uint32_t w = result.getWidth();
205     for (uint32_t y = 0; y < h; y++)
206     {
207         for (uint32_t x = 0; x < w; x++)
208         {
209             tcu::Vec4 pix = result.getPixel(x, y);
210 
211             if (oob && m_type == IMAGE)
212             {
213                 for (uint32_t i = 0; i < 4; ++i)
214                     if (pix[i] != 0.0f && pix[i] != 1.0f)
215                         return false;
216             }
217             else if (pix != value)
218                 return false;
219         }
220     }
221     return true;
222 }
223 
iterate(void)224 tcu::TestStatus PipelineCacheTestInstance::iterate(void)
225 {
226     const vk::InstanceInterface &vki          = m_context.getInstanceInterface();
227     const vk::DeviceInterface &vk             = m_context.getDeviceInterface();
228     const vk::VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice();
229     const vk::VkDevice device                 = m_context.getDevice();
230     const uint32_t queueFamilyIndex           = m_context.getUniversalQueueFamilyIndex();
231     const vk::VkQueue queue                   = m_context.getUniversalQueue();
232     auto &alloc                               = m_context.getDefaultAllocator();
233     const auto &deviceExtensions              = m_context.getDeviceExtensions();
234 
235     m_extent                       = {32, 32};
236     const uint32_t bufferSize      = sizeof(float) * 4u;
237     const uint32_t indexBufferSize = sizeof(uint32_t);
238 
239     const auto subresourceRange = vk::makeImageSubresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
240 
241     m_cmdPool   = createCommandPool(vk, device, vk::VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
242     m_cmdBuffer = (allocateCommandBuffer(vk, device, *m_cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
243 
244     m_buffer = de::MovePtr<vk::BufferWithMemory>(new vk::BufferWithMemory(
245         vk, device, alloc,
246         vk::makeBufferCreateInfo(bufferSize,
247                                  vk::VK_BUFFER_USAGE_TRANSFER_SRC_BIT | vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT |
248                                      vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | vk::VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT |
249                                      vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT),
250         vk::MemoryRequirement::HostVisible));
251 
252     de::MovePtr<vk::BufferWithMemory> indexBuffer = de::MovePtr<vk::BufferWithMemory>(
253         new vk::BufferWithMemory(vk, device, alloc,
254                                  vk::makeBufferCreateInfo(indexBufferSize, vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT |
255                                                                                vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT),
256                                  vk::MemoryRequirement::HostVisible));
257     de::MovePtr<vk::ImageWithMemory> image = de::MovePtr<vk::ImageWithMemory>(new vk::ImageWithMemory(
258         vk, device, alloc,
259         makeImageCreateInfo(vk::VK_FORMAT_R32G32B32A32_SFLOAT, {1, 1, 1},
260                             vk::VK_IMAGE_USAGE_STORAGE_BIT | vk::VK_IMAGE_USAGE_TRANSFER_DST_BIT),
261         vk::MemoryRequirement::Any));
262     const auto imageView                   = makeImageView(vk, device, image->get(), vk::VK_IMAGE_VIEW_TYPE_2D,
263                                                            vk::VK_FORMAT_R32G32B32A32_SFLOAT, subresourceRange);
264     const auto sampler                     = makeSampler(vk, device);
265 
266     auto &bufferAlloc      = m_buffer->getAllocation();
267     auto &indexBufferAlloc = indexBuffer->getAllocation();
268     const float values[4]  = {0.5f, 0.5f, 0.5f, 0.5f};
269     deMemcpy(bufferAlloc.getHostPtr(), values, sizeof(float) * 4);
270     flushAlloc(vk, device, bufferAlloc);
271     const uint32_t index = 0u;
272     deMemcpy(indexBufferAlloc.getHostPtr(), &index, sizeof(uint32_t));
273     flushAlloc(vk, device, indexBufferAlloc);
274 
275     const vk::VkDescriptorBufferInfo descriptorBufferInfo(makeDescriptorBufferInfo(m_buffer->get(), 0, bufferSize));
276     const vk::VkDescriptorImageInfo descriptorImageInfo(
277         makeDescriptorImageInfo(sampler.get(), imageView.get(), vk::VK_IMAGE_LAYOUT_GENERAL));
278     const vk::VkDescriptorBufferInfo indexBufferInfo(makeDescriptorBufferInfo(indexBuffer->get(), 0, indexBufferSize));
279 
280     const std::vector<vk::VkViewport> viewports{makeViewport(m_extent)};
281     const std::vector<vk::VkRect2D> scissors{makeRect2D(m_extent)};
282 
283     vk::ShaderWrapper vert = vk::ShaderWrapper(vk, device, m_context.getBinaryCollection().get("vert"));
284     vk::ShaderWrapper frag = vk::ShaderWrapper(vk, device, m_context.getBinaryCollection().get("frag"));
285 
286     vk::VkDescriptorType descriptorType = vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
287     if (m_type == STORAGE)
288     {
289         descriptorType = vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
290     }
291     else if (m_type == UNIFORM)
292     {
293         descriptorType = vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
294     }
295     else if (m_type == IMAGE)
296     {
297         descriptorType = vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
298     }
299 
300     const auto descriptorSetLayout(
301         vk::DescriptorSetLayoutBuilder()
302             .addSingleBinding(descriptorType, vk::VK_SHADER_STAGE_FRAGMENT_BIT)
303             .addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
304                               vk::VK_SHADER_STAGE_VERTEX_BIT | vk::VK_SHADER_STAGE_FRAGMENT_BIT)
305             .build(vk, device));
306 
307     m_pipelineLayout = vk::PipelineLayoutWrapper(m_pipelineConstructionType, vk, device, *descriptorSetLayout);
308 
309     m_descriptorPool = (vk::DescriptorPoolBuilder()
310                             .addType(descriptorType)
311                             .addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
312                             .build(vk, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1));
313     m_descriptorSet  = makeDescriptorSet(vk, device, *m_descriptorPool, *descriptorSetLayout);
314     vk::DescriptorSetUpdateBuilder builder;
315     if (m_type == STORAGE || m_type == UNIFORM)
316         builder.writeSingle(*m_descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), descriptorType,
317                             &descriptorBufferInfo);
318     if (m_type == IMAGE)
319         builder.writeSingle(*m_descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), descriptorType,
320                             &descriptorImageInfo);
321     builder.writeSingle(*m_descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u),
322                         vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &indexBufferInfo);
323     builder.update(vk, device);
324     ;
325 
326     //buffer to read the output image
327     m_outBuffer = makeBufferForImage(vk, device, alloc, vk::VK_FORMAT_R32G32B32A32_SFLOAT, m_extent);
328 
329     const auto vertModule = vk::createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"));
330     const auto fragModule = vk::createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"));
331 
332     // Color attachment.
333     const vk::VkImageCreateInfo imageCreateInfo = {
334         vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,                                       // VkStructureType sType;
335         nullptr,                                                                       // const void* pNext;
336         0u,                                                                            // VkImageCreateFlags flags;
337         vk::VK_IMAGE_TYPE_2D,                                                          // VkImageType imageType;
338         vk::VK_FORMAT_R32G32B32A32_SFLOAT,                                             // VkFormat format;
339         {m_extent.width, m_extent.height, 1},                                          // VkExtent3D extent;
340         1u,                                                                            // uint32_t mipLevels;
341         1u,                                                                            // uint32_t arrayLayers;
342         vk::VK_SAMPLE_COUNT_1_BIT,                                                     // VkSampleCountFlagBits samples;
343         vk::VK_IMAGE_TILING_OPTIMAL,                                                   // VkImageTiling tiling;
344         vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT, // VkImageUsageFlags usage;
345         vk::VK_SHARING_MODE_EXCLUSIVE,                                                 // VkSharingMode sharingMode;
346         0u,                            // uint32_t queueFamilyIndexCount;
347         DE_NULL,                       // const uint32_t* pQueueFamilyIndices;
348         vk::VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
349     };
350 
351     m_colorAttachment = de::MovePtr<vk::ImageWithMemory>(
352         new vk::ImageWithMemory(vk, device, alloc, imageCreateInfo, vk::MemoryRequirement::Any));
353     const auto colorAttachmentView = makeImageView(vk, device, m_colorAttachment->get(), vk::VK_IMAGE_VIEW_TYPE_2D,
354                                                    vk::VK_FORMAT_R32G32B32A32_SFLOAT, subresourceRange);
355 
356     m_renderPass = vk::RenderPassWrapper(m_pipelineConstructionType, vk, device, vk::VK_FORMAT_R32G32B32A32_SFLOAT);
357     m_renderPass.createFramebuffer(vk, device, **m_colorAttachment, *colorAttachmentView, 32, 32);
358 
359     vk::VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = {
360         vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
361         nullptr,                                                       // const void* pNext;
362         0u,                                                            // VkPipelineVertexInputStateCreateFlags flags;
363         0u,                                                            // uint32_t vertexBindingDescriptionCount;
364         DE_NULL, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
365         0u,      // uint32_t vertexAttributeDescriptionCount;
366         DE_NULL, // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
367     };
368 
369     vk::VkVertexInputBindingDescription bindingDescription;
370     bindingDescription.binding   = 0;
371     bindingDescription.stride    = sizeof(float);
372     bindingDescription.inputRate = vk::VK_VERTEX_INPUT_RATE_INSTANCE;
373 
374     std::vector<vk::VkVertexInputAttributeDescription> attributeDescriptions(16);
375     for (uint32_t i = 0; i < (uint32_t)attributeDescriptions.size(); ++i)
376     {
377         attributeDescriptions[i].location = i;
378         attributeDescriptions[i].binding  = 0;
379         attributeDescriptions[i].format   = vk::VK_FORMAT_R32G32B32A32_SFLOAT;
380         attributeDescriptions[i].offset   = (uint32_t)(sizeof(float) * i);
381     }
382 
383     if (m_type == VERTEX_INPUT)
384     {
385         vertexInputStateCreateInfo.vertexBindingDescriptionCount   = 1u;
386         vertexInputStateCreateInfo.pVertexBindingDescriptions      = &bindingDescription;
387         vertexInputStateCreateInfo.vertexAttributeDescriptionCount = (uint32_t)attributeDescriptions.size();
388         vertexInputStateCreateInfo.pVertexAttributeDescriptions    = attributeDescriptions.data();
389     }
390 
391     // Input assembly.
392     const vk::VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo = {
393         vk::VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType;
394         nullptr,                                                         // const void* pNext;
395         0u,                                       // VkPipelineInputAssemblyStateCreateFlags flags;
396         vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, // VkPrimitiveTopology topology;
397         false,                                    // VkBool32 primitiveRestartEnable;
398     };
399 
400     const vk::VkPipelineCacheCreateInfo pipelineCacheCreateInfo = {
401         vk::VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, // VkStructureType sType;
402         DE_NULL,                                          // const void* pNext;
403         0u,                                               // VkPipelineCacheCreateFlags flags;
404         0u,                                               // uintptr_t initialDataSize;
405         DE_NULL,                                          // const void* pInitialData;
406     };
407 
408     vk::Move<vk::VkPipelineCache> pipelineCache = createPipelineCache(vk, device, &pipelineCacheCreateInfo);
409 
410     vk::GraphicsPipelineWrapper graphicsPipeline(vki, vk, physicalDevice, device, deviceExtensions,
411                                                  m_pipelineConstructionType);
412     graphicsPipeline.setDefaultTopology(vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP)
413         .setDefaultRasterizationState()
414         .setDefaultMultisampleState()
415         .setDefaultDepthStencilState()
416         .setDefaultColorBlendState()
417         .setupVertexInputState(&vertexInputStateCreateInfo, &inputAssemblyStateCreateInfo)
418         .setupPreRasterizationShaderState(viewports, scissors, m_pipelineLayout, *m_renderPass, 0u, vert)
419         .setupFragmentShaderState(m_pipelineLayout, *m_renderPass, 0u, frag)
420         .setupFragmentOutputState(*m_renderPass)
421         .setMonolithicPipelineLayout(m_pipelineLayout)
422         .buildPipeline(*pipelineCache);
423 
424     vk::VkPipelineRobustnessCreateInfoEXT pipelineRobustnessInfo = vk::initVulkanStructure();
425     vk::PipelineRobustnessCreateInfoWrapper pipelineRobustnessWrapper(&pipelineRobustnessInfo);
426 
427     if (m_robustnessBufferBehaviour == ROBUSTNESS)
428     {
429         if (m_type == STORAGE)
430             pipelineRobustnessInfo.storageBuffers = vk::VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_EXT;
431         else if (m_type == UNIFORM)
432             pipelineRobustnessInfo.uniformBuffers = vk::VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_EXT;
433         else if (m_type == VERTEX_INPUT)
434             pipelineRobustnessInfo.vertexInputs = vk::VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_EXT;
435         else if (m_type == IMAGE)
436             pipelineRobustnessInfo.images = vk::VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_ROBUST_IMAGE_ACCESS_EXT;
437     }
438     else
439     {
440         if (m_type == STORAGE)
441             pipelineRobustnessInfo.storageBuffers =
442                 vk::VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_2_EXT;
443         else if (m_type == UNIFORM)
444             pipelineRobustnessInfo.uniformBuffers =
445                 vk::VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_2_EXT;
446         else if (m_type == VERTEX_INPUT)
447             pipelineRobustnessInfo.vertexInputs = vk::VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_2_EXT;
448         else if (m_type == IMAGE)
449             pipelineRobustnessInfo.images = vk::VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_ROBUST_IMAGE_ACCESS_2_EXT;
450     }
451 
452     vk::GraphicsPipelineWrapper robustPipeline(vki, vk, physicalDevice, device, deviceExtensions,
453                                                m_pipelineConstructionType);
454     robustPipeline.setDefaultTopology(vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP)
455         .setDefaultRasterizationState()
456         .setDefaultMultisampleState()
457         .setDefaultDepthStencilState()
458         .setDefaultColorBlendState()
459         .setPipelineRobustnessState(pipelineRobustnessWrapper)
460         .setupVertexInputState(&vertexInputStateCreateInfo, &inputAssemblyStateCreateInfo)
461         .setupPreRasterizationShaderState(viewports, scissors, m_pipelineLayout, *m_renderPass, 0u, vert)
462         .setupFragmentShaderState(m_pipelineLayout, *m_renderPass, 0u, frag)
463         .setupFragmentOutputState(*m_renderPass)
464         .setMonolithicPipelineLayout(m_pipelineLayout)
465         .buildPipeline(*pipelineCache, 0, 0, vk::PipelineCreationFeedbackCreateInfoWrapper());
466 
467     if (m_type == IMAGE)
468     {
469         // Initialize image
470         const vk::VkImageMemoryBarrier preImageBarrier = {
471             vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
472             DE_NULL,                                    // const void* pNext;
473             0u,                                         // VkAccessFlags srcAccessMask;
474             vk::VK_ACCESS_TRANSFER_WRITE_BIT,           // VkAccessFlags dstAccessMask;
475             vk::VK_IMAGE_LAYOUT_UNDEFINED,              // VkImageLayout oldLayout;
476             vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,   // VkImageLayout newLayout;
477             VK_QUEUE_FAMILY_IGNORED,                    // uint32_t srcQueueFamilyIndex;
478             VK_QUEUE_FAMILY_IGNORED,                    // uint32_t dstQueueFamilyIndex;
479             **image,                                    // VkImage image;
480             {
481                 // VkImageSubresourceRange subresourceRange;
482                 vk::VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspect;
483                 0u,                            // uint32_t baseMipLevel;
484                 1u,                            // uint32_t mipLevels;
485                 0u,                            // uint32_t baseArraySlice;
486                 1u,                            // uint32_t arraySize;
487             }};
488 
489         const vk::VkImageMemoryBarrier postImageBarrier = {
490             vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
491             DE_NULL,                                    // const void* pNext;
492             vk::VK_ACCESS_TRANSFER_WRITE_BIT,           // VkAccessFlags srcAccessMask;
493             vk::VK_ACCESS_SHADER_READ_BIT,              // VkAccessFlags dstAccessMask;
494             vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,   // VkImageLayout oldLayout;
495             vk::VK_IMAGE_LAYOUT_GENERAL,                // VkImageLayout newLayout;
496             VK_QUEUE_FAMILY_IGNORED,                    // uint32_t srcQueueFamilyIndex;
497             VK_QUEUE_FAMILY_IGNORED,                    // uint32_t dstQueueFamilyIndex;
498             **image,                                    // VkImage image;
499             {
500                 // VkImageSubresourceRange subresourceRange;
501                 vk::VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspect;
502                 0u,                            // uint32_t baseMipLevel;
503                 1u,                            // uint32_t mipLevels;
504                 0u,                            // uint32_t baseArraySlice;
505                 1u,                            // uint32_t arraySize;
506             }};
507 
508         const vk::VkBufferImageCopy copyRegion = {
509             0u, // VkDeviceSize bufferOffset;
510             0u, // uint32_t bufferRowLength;
511             0u, // uint32_t bufferImageHeight;
512             {
513                 vk::VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspect;
514                 0u,                            // uint32_t mipLevel;
515                 0u,                            // uint32_t baseArrayLayer;
516                 1u,                            // uint32_t layerCount;
517             },                                 // VkImageSubresourceLayers imageSubresource;
518             {0, 0, 0},                         // VkOffset3D imageOffset;
519             {1, 1, 1},                         // VkExtent3D imageExtent;
520         };
521 
522         vk::beginCommandBuffer(vk, *m_cmdBuffer);
523         vk.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT,
524                               (vk::VkDependencyFlags)0, 0, (const vk::VkMemoryBarrier *)DE_NULL, 0u, DE_NULL, 1u,
525                               &preImageBarrier);
526         vk.cmdCopyBufferToImage(*m_cmdBuffer, **m_buffer, **image, vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u,
527                                 &copyRegion);
528         vk.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_TRANSFER_BIT,
529                               vk::VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, (vk::VkDependencyFlags)0, 0,
530                               (const vk::VkMemoryBarrier *)DE_NULL, 0, (const vk::VkBufferMemoryBarrier *)DE_NULL, 1,
531                               &postImageBarrier);
532         vk::endCommandBuffer(vk, *m_cmdBuffer);
533         vk::submitCommandsAndWait(vk, device, queue, *m_cmdBuffer);
534     }
535 
536     draw(graphicsPipeline);
537 
538     if (!verifyImage(tcu::Vec4(values[0]), false))
539         return tcu::TestStatus::fail("Fail");
540 
541     uint32_t invalidIndex = m_type == VERTEX_INPUT ? 15u : 999u;
542     deMemcpy(indexBufferAlloc.getHostPtr(), &invalidIndex, sizeof(uint32_t));
543     flushAlloc(vk, device, indexBufferAlloc);
544 
545     draw(robustPipeline);
546 
547     if (m_robustnessBufferBehaviour == ROBUSTNESS_2)
548     {
549         if (!verifyImage(tcu::Vec4(0.0f), true))
550             return tcu::TestStatus::fail("Fail");
551     }
552 
553     return tcu::TestStatus::pass("Pass");
554 }
555 
556 class PipelineCacheTestCase : public vkt::TestCase
557 {
558 public:
PipelineCacheTestCase(tcu::TestContext & context,const char * name,vk::PipelineConstructionType pipelineConstructionType,RobustnessBehaviour robustnessBufferBehaviour,RobustnessType type)559     PipelineCacheTestCase(tcu::TestContext &context, const char *name,
560                           vk::PipelineConstructionType pipelineConstructionType,
561                           RobustnessBehaviour robustnessBufferBehaviour, RobustnessType type)
562         : TestCase(context, name)
563         , m_pipelineConstructionType(pipelineConstructionType)
564         , m_robustnessBufferBehaviour(robustnessBufferBehaviour)
565         , m_type(type)
566     {
567     }
568 
569 private:
570     void checkSupport(vkt::Context &context) const;
571     void initPrograms(vk::SourceCollections &programCollection) const;
createInstance(vkt::Context & context) const572     vkt::TestInstance *createInstance(vkt::Context &context) const
573     {
574         return new PipelineCacheTestInstance(context, m_pipelineConstructionType, m_robustnessBufferBehaviour, m_type);
575     }
576 
577     const vk::PipelineConstructionType m_pipelineConstructionType;
578     const RobustnessBehaviour m_robustnessBufferBehaviour;
579     const RobustnessType m_type;
580 };
581 
checkSupport(vkt::Context & context) const582 void PipelineCacheTestCase::checkSupport(vkt::Context &context) const
583 {
584     context.requireDeviceFunctionality("VK_EXT_pipeline_robustness");
585     if (m_robustnessBufferBehaviour == ROBUSTNESS_2)
586         context.requireDeviceFunctionality("VK_EXT_robustness2");
587 
588     vk::VkPhysicalDevicePipelineRobustnessFeaturesEXT pipelineRobustnessFeatures = vk::initVulkanStructure();
589     vk::VkPhysicalDeviceRobustness2FeaturesEXT robustness2Features =
590         vk::initVulkanStructure(&pipelineRobustnessFeatures);
591     vk::VkPhysicalDeviceFeatures2 features2;
592 
593     features2.sType = vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
594     features2.pNext = &robustness2Features;
595 
596     context.getInstanceInterface().getPhysicalDeviceFeatures2(context.getPhysicalDevice(), &features2);
597 
598     if (pipelineRobustnessFeatures.pipelineRobustness == false)
599         TCU_THROW(NotSupportedError,
600                   "VkPhysicalDevicePipelineRobustnessFeaturesEXT::pipelineRobustness feature not supported");
601 
602     if (m_robustnessBufferBehaviour == ROBUSTNESS_2)
603     {
604         if (m_type == IMAGE)
605         {
606             if (robustness2Features.robustImageAccess2 == false)
607                 TCU_THROW(NotSupportedError,
608                           "VkPhysicalDeviceRobustness2FeaturesEXT::robustImageAccess2 feature not supported");
609         }
610         else
611         {
612             if (robustness2Features.robustBufferAccess2 == false)
613                 TCU_THROW(NotSupportedError,
614                           "VkPhysicalDeviceRobustness2FeaturesEXT::robustBufferAccess2 feature not supported");
615         }
616     }
617 
618     vk::checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(),
619                                               m_pipelineConstructionType);
620 }
621 
initPrograms(vk::SourceCollections & programCollection) const622 void PipelineCacheTestCase::initPrograms(vk::SourceCollections &programCollection) const
623 {
624     if (m_type == VERTEX_INPUT)
625     {
626         {
627             std::ostringstream vert;
628             vert << "#version 450\n"
629                  << "layout(location = 0) in float in_values[16];\n"
630                  << "layout(location = 0) out float out_value;\n"
631                  << "layout (set=0, binding=1) restrict readonly buffer IndexBuffer {\n"
632                  << "    uint index;\n"
633                  << "};\n"
634                  << "void main()\n"
635                  << "{\n"
636                  << "    vec2 vertex = vec2(gl_VertexIndex & 1u, (gl_VertexIndex >> 1u) & 1u);\n"
637                  << "    gl_Position = vec4(vertex * 2.0f - 1.0f, 0.0f, 1.0f);\n"
638                  << "    out_value = in_values[index];\n"
639                  << "}\n";
640 
641             programCollection.glslSources.add("vert") << glu::VertexSource(vert.str());
642         }
643         {
644             std::ostringstream frag;
645             frag << "#version 450\n"
646                  << "layout (location=0) in float in_value;\n"
647                  << "layout (location=0) out vec4 out_color;\n"
648                  << "void main()\n"
649                  << "{\n"
650                  << "    out_color = vec4(in_value);\n"
651                  << "}\n";
652 
653             programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
654         }
655     }
656     else
657     {
658         {
659             std::ostringstream vert;
660             vert << "#version 450\n"
661                  << "void main()\n"
662                  << "{\n"
663                  << "    vec2 vertex = vec2(gl_VertexIndex & 1u, (gl_VertexIndex >> 1u) & 1u);\n"
664                  << "    gl_Position = vec4(vertex * 2.0f - 1.0f, 0.0f, 1.0f);\n"
665                  << "}\n";
666 
667             programCollection.glslSources.add("vert") << glu::VertexSource(vert.str());
668         }
669         {
670             std::string descriptor = {};
671             std::string write      = {};
672             if (m_type == STORAGE)
673             {
674                 descriptor = "layout (set=0, binding=0) restrict readonly buffer StorageBuffer {\n"
675                              "    float values[];\n"
676                              "};\n";
677                 write      = "    out_color = vec4(values[index]);\n";
678             }
679             else if (m_type == UNIFORM)
680             {
681                 descriptor = "layout (std140, set=0, binding=0) restrict uniform UniformBuffer {\n"
682                              "    float values[1000];\n"
683                              "};\n";
684                 write      = "    out_color = vec4(values[index]);\n";
685             }
686             else if (m_type == IMAGE)
687             {
688                 descriptor = "layout (set=0, binding=0, rgba32f) uniform image2D tex;\n";
689                 write      = "    out_color = imageLoad(tex, ivec2(index, 0));\n";
690             }
691 
692             std::ostringstream frag;
693             frag << "#version 450\n"
694                  << "layout (location=0) out vec4 out_color;\n"
695                  << descriptor << "layout (set=0, binding=1) restrict readonly buffer IndexBuffer {\n"
696                  << "    uint index;\n"
697                  << "};\n"
698                  << "void main()\n"
699                  << "{\n"
700                  << write << "}\n";
701 
702             programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
703         }
704     }
705 }
706 
707 } // namespace
708 
createPipelineRobustnessCacheTests(tcu::TestContext & testCtx,vk::PipelineConstructionType pipelineConstructionType)709 tcu::TestCaseGroup *createPipelineRobustnessCacheTests(tcu::TestContext &testCtx,
710                                                        vk::PipelineConstructionType pipelineConstructionType)
711 {
712     // Test pipeline cache with different robustness enabled
713     de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "pipeline_cache"));
714 
715     const struct
716     {
717         RobustnessBehaviour robustnessBehaviour;
718         const char *name;
719     } robustnessTests[] = {
720         {ROBUSTNESS, "robustness"},
721         {ROBUSTNESS_2, "robustness2"},
722     };
723 
724     const struct
725     {
726         RobustnessType type;
727         const char *name;
728     } typeTests[] = {
729         {STORAGE, "storage"},
730         {UNIFORM, "uniform"},
731         {VERTEX_INPUT, "vertex_input"},
732         {IMAGE, "image"},
733     };
734 
735     for (const auto &robustnessTest : robustnessTests)
736     {
737         de::MovePtr<tcu::TestCaseGroup> robustnessGroup(new tcu::TestCaseGroup(testCtx, robustnessTest.name));
738         for (const auto &typeTest : typeTests)
739         {
740             robustnessGroup->addChild(new PipelineCacheTestCase(testCtx, typeTest.name, pipelineConstructionType,
741                                                                 robustnessTest.robustnessBehaviour, typeTest.type));
742         }
743         testGroup->addChild(robustnessGroup.release());
744     }
745 
746     return testGroup.release();
747 }
748 
749 } // namespace pipeline
750 } // namespace vkt
751