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