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 ©Region);
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