1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2021 The Khronos Group Inc.
6  * Copyright (c) 2021 Google Inc.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file
22  * \brief Transient attachment tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktFragmentOperationsTransientAttachmentTests.hpp"
26 #include "vktTestCaseUtil.hpp"
27 #include "vktTestGroupUtil.hpp"
28 
29 #include "vkDefs.hpp"
30 #include "vkBuilderUtil.hpp"
31 #include "vkCmdUtil.hpp"
32 #include "vkImageUtil.hpp"
33 #include "vkMemUtil.hpp"
34 #include "vkObjUtil.hpp"
35 #include "vkQueryUtil.hpp"
36 #include "vkTypeUtil.hpp"
37 #include "vkBarrierUtil.hpp"
38 
39 #include "tcuImageCompare.hpp"
40 #include "tcuTestLog.hpp"
41 #include "tcuTextureUtil.hpp"
42 #include "tcuVector.hpp"
43 
44 #include "deUniquePtr.hpp"
45 
46 namespace vkt
47 {
48 namespace FragmentOperations
49 {
50 using namespace vk;
51 using de::UniquePtr;
52 
53 namespace
54 {
55 
56 enum class TestMode
57 {
58     MODE_INVALID = 1u << 0,
59     MODE_COLOR   = 1u << 1,
60     MODE_DEPTH   = 1u << 2,
61     MODE_STENCIL = 1u << 3
62 };
63 
memoryPropertyFlagBitToString(VkMemoryPropertyFlags flagBit)64 const char *memoryPropertyFlagBitToString(VkMemoryPropertyFlags flagBit)
65 {
66     switch (flagBit)
67     {
68     case VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT:
69         return "VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT";
70 
71     case VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT:
72         return "VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT";
73 
74     case VK_MEMORY_PROPERTY_HOST_COHERENT_BIT:
75         return "VK_MEMORY_PROPERTY_HOST_COHERENT_BIT";
76 
77     case VK_MEMORY_PROPERTY_HOST_CACHED_BIT:
78         return "VK_MEMORY_PROPERTY_HOST_CACHED_BIT";
79 
80     case VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT:
81         return "VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT";
82 
83     case VK_MEMORY_PROPERTY_PROTECTED_BIT:
84         return "VK_MEMORY_PROPERTY_PROTECTED_BIT";
85 
86 #ifndef CTS_USES_VULKANSC
87     case VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD:
88         return "VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD";
89 
90     case VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD:
91         return "VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD";
92 
93     case VK_MEMORY_PROPERTY_RDMA_CAPABLE_BIT_NV:
94         return "VK_MEMORY_PROPERTY_RDMA_CAPABLE_BIT_NV";
95 #endif // CTS_USES_VULKANSC
96 
97     default:
98         TCU_THROW(InternalError, "Unknown memory property flag bit");
99     }
100 };
101 
getSupportedStencilFormat(const VkPhysicalDevice physDevice,const InstanceInterface & instanceInterface)102 VkFormat getSupportedStencilFormat(const VkPhysicalDevice physDevice, const InstanceInterface &instanceInterface)
103 {
104     static const VkFormat stencilFormats[] = {
105         VK_FORMAT_D16_UNORM_S8_UINT,
106         VK_FORMAT_D24_UNORM_S8_UINT,
107         VK_FORMAT_D32_SFLOAT_S8_UINT,
108     };
109 
110     for (const auto &sFormat : stencilFormats)
111     {
112         VkFormatProperties formatProps;
113         instanceInterface.getPhysicalDeviceFormatProperties(physDevice, sFormat, &formatProps);
114 
115         if ((formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0)
116         {
117             return sFormat;
118         };
119     }
120 
121     return VK_FORMAT_UNDEFINED;
122 }
123 
getMemoryTypeIndices(VkMemoryPropertyFlags propertyFlag,const VkPhysicalDeviceMemoryProperties & pMemoryProperties)124 std::vector<uint32_t> getMemoryTypeIndices(VkMemoryPropertyFlags propertyFlag,
125                                            const VkPhysicalDeviceMemoryProperties &pMemoryProperties)
126 {
127     std::vector<uint32_t> indices;
128     for (uint32_t typeIndex = 0u; typeIndex < pMemoryProperties.memoryTypeCount; ++typeIndex)
129     {
130         if ((pMemoryProperties.memoryTypes[typeIndex].propertyFlags & propertyFlag) == propertyFlag)
131             indices.push_back(typeIndex);
132     }
133     return indices;
134 }
135 
makeImageCreateInfo(const VkFormat format,const tcu::IVec2 & size,VkImageUsageFlags usage)136 VkImageCreateInfo makeImageCreateInfo(const VkFormat format, const tcu::IVec2 &size, VkImageUsageFlags usage)
137 {
138     const VkImageCreateInfo imageParams = {
139         VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
140         DE_NULL,                             // const void* pNext;
141         (VkImageCreateFlags)0,               // VkImageCreateFlags flags;
142         VK_IMAGE_TYPE_2D,                    // VkImageType imageType;
143         format,                              // VkFormat format;
144         makeExtent3D(size.x(), size.y(), 1), // VkExtent3D extent;
145         1u,                                  // uint32_t mipLevels;
146         1u,                                  // uint32_t arrayLayers;
147         VK_SAMPLE_COUNT_1_BIT,               // VkSampleCountFlagBits samples;
148         VK_IMAGE_TILING_OPTIMAL,             // VkImageTiling tiling;
149         usage,                               // VkImageUsageFlags usage;
150         VK_SHARING_MODE_EXCLUSIVE,           // VkSharingMode sharingMode;
151         0u,                                  // uint32_t queueFamilyIndexCount;
152         DE_NULL,                             // const uint32_t* pQueueFamilyIndices;
153         VK_IMAGE_LAYOUT_UNDEFINED,           // VkImageLayout initialLayout;
154     };
155     return imageParams;
156 }
157 
makeAttachment(const VkFormat format,const VkAttachmentLoadOp loadOp,const VkAttachmentStoreOp storeOp,const VkImageLayout initialLayout,const VkImageLayout finalLayout)158 VkAttachmentDescription makeAttachment(const VkFormat format, const VkAttachmentLoadOp loadOp,
159                                        const VkAttachmentStoreOp storeOp, const VkImageLayout initialLayout,
160                                        const VkImageLayout finalLayout)
161 {
162     const tcu::TextureFormat tcuFormat = mapVkFormat(format);
163     const bool hasStencil = (tcuFormat.order == tcu::TextureFormat::DS || tcuFormat.order == tcu::TextureFormat::S);
164 
165     const VkAttachmentDescription attachmentDesc = {
166         VkAttachmentDescriptionFlags(0),                         // VkAttachmentDescriptionFlags flags;
167         format,                                                  // VkFormat format;
168         VK_SAMPLE_COUNT_1_BIT,                                   // VkSampleCountFlagBits samples;
169         loadOp,                                                  // VkAttachmentLoadOp loadOp;
170         storeOp,                                                 // VkAttachmentStoreOp storeOp;
171         hasStencil ? loadOp : VK_ATTACHMENT_LOAD_OP_DONT_CARE,   // VkAttachmentLoadOp stencilLoadOp;
172         hasStencil ? storeOp : VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
173         initialLayout,                                           // VkImageLayout initialLayout;
174         finalLayout                                              // VkImageLayout finalLayout;
175     };
176 
177     return attachmentDesc;
178 }
179 
makeRenderPass(const DeviceInterface & vk,const VkDevice device,const std::vector<VkAttachmentDescription> attachmentDescriptions,const bool hasInputAttachment)180 Move<VkRenderPass> makeRenderPass(const DeviceInterface &vk, const VkDevice device,
181                                   const std::vector<VkAttachmentDescription> attachmentDescriptions,
182                                   const bool hasInputAttachment)
183 {
184     const tcu::TextureFormat tcuFormat = mapVkFormat(attachmentDescriptions[0].format);
185     const bool hasDepthStencil         = (tcuFormat.order == tcu::TextureFormat::DS ||
186                                   tcuFormat.order == tcu::TextureFormat::S || tcuFormat.order == tcu::TextureFormat::D);
187 
188     std::vector<VkAttachmentReference> testReferences;
189     const uint32_t maxAttachmentIndex = uint32_t(attachmentDescriptions.size()) - 1u;
190 
191     for (uint32_t ref = 0; ref < attachmentDescriptions.size(); ref++)
192     {
193         testReferences.push_back({ref, attachmentDescriptions[ref].finalLayout});
194     }
195 
196     const VkSubpassDescription subpassDescription = {
197         (VkSubpassDescriptionFlags)0,                      // VkSubpassDescriptionFlags        flags
198         VK_PIPELINE_BIND_POINT_GRAPHICS,                   // VkPipelineBindPoint                pipelineBindPoint
199         hasInputAttachment ? 1u : 0u,                      // uint32_t                            inputAttachmentCount
200         hasInputAttachment ? &testReferences[0] : DE_NULL, // const VkAttachmentReference*        pInputAttachments
201         !hasDepthStencil || hasInputAttachment ? 1u : 0u,  // uint32_t                            colorAttachmentCount
202         !hasDepthStencil || hasInputAttachment ? &testReferences[maxAttachmentIndex] :
203                                                  DE_NULL, // const VkAttachmentReference*        pColorAttachments
204         DE_NULL,                                          // const VkAttachmentReference*        pResolveAttachments
205         hasDepthStencil && !hasInputAttachment ? &testReferences[0] :
206                                                  DE_NULL, // const VkAttachmentReference*        pDepthStencilAttachment
207         0u,                                               // uint32_t                            preserveAttachmentCount
208         DE_NULL                                           // const uint32_t*                    pPreserveAttachments
209     };
210 
211     const VkRenderPassCreateInfo renderPassInfo = {
212         VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType                    sType
213         DE_NULL,                                   // const void*                        pNext
214         (VkRenderPassCreateFlags)0,                // VkRenderPassCreateFlags            flags
215         uint32_t(attachmentDescriptions.size()),   // uint32_t                            attachmentCount
216         attachmentDescriptions.data(),             // const VkAttachmentDescription*    pAttachments
217         1u,                                        // uint32_t                            subpassCount
218         &subpassDescription,                       // const VkSubpassDescription*        pSubpasses
219         0u,                                        // uint32_t                            dependencyCount
220         DE_NULL                                    // const VkSubpassDependency*        pDependencies
221     };
222 
223     return createRenderPass(vk, device, &renderPassInfo, DE_NULL);
224 }
225 
226 class TransientAttachmentTest : public TestCase
227 {
228 public:
229     TransientAttachmentTest(tcu::TestContext &testCtx, const std::string name, const TestMode testMode,
230                             const VkMemoryPropertyFlags flags, const tcu::IVec2 renderSize);
231 
232     void initPrograms(SourceCollections &programCollection) const;
233     TestInstance *createInstance(Context &context) const;
234     virtual void checkSupport(Context &context) const;
235 
236 private:
237     const TestMode m_testMode;
238     const VkMemoryPropertyFlags m_flags;
239     const tcu::IVec2 m_renderSize;
240 };
241 
TransientAttachmentTest(tcu::TestContext & testCtx,const std::string name,const TestMode testMode,const VkMemoryPropertyFlags flags,const tcu::IVec2 renderSize)242 TransientAttachmentTest::TransientAttachmentTest(tcu::TestContext &testCtx, const std::string name,
243                                                  const TestMode testMode, const VkMemoryPropertyFlags flags,
244                                                  const tcu::IVec2 renderSize)
245     : TestCase(testCtx, name)
246     , m_testMode(testMode)
247     , m_flags(flags)
248     , m_renderSize(renderSize)
249 {
250 }
251 
initPrograms(SourceCollections & programCollection) const252 void TransientAttachmentTest::initPrograms(SourceCollections &programCollection) const
253 {
254     // Vertex shader
255     {
256         std::ostringstream src;
257 
258         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
259             << "\n"
260             << "layout(location = 0) in vec4 position;\n"
261             << "\n"
262             << "out gl_PerVertex\n"
263             << "{\n"
264             << "   vec4 gl_Position;\n"
265             << "};\n"
266             << "\n"
267             << "void main (void)\n"
268             << "{\n"
269             << "    gl_Position = position;\n"
270             << "}\n";
271 
272         programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
273     }
274 
275     // Fragment shader
276     {
277         std::ostringstream src;
278 
279         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
280             << "\n"
281             << "layout(input_attachment_index = 0, binding = 0) uniform "
282             << (m_testMode == TestMode::MODE_STENCIL ? "usubpassInput " : "subpassInput ") << "inputValue;\n"
283             << "\n"
284             << "layout(location = 0) out vec4 fragColor;\n"
285             << "\n"
286             << "void main (void)\n"
287             << "{\n"
288             << "    fragColor = "
289             << (m_testMode == TestMode::MODE_COLOR ? "subpassLoad(inputValue);\n" :
290                 m_testMode == TestMode::MODE_DEPTH ? "vec4(subpassLoad(inputValue).r, 0.0, 0.0, 1.0);\n" :
291                                                      /*            TestMode::MODE_STENCIL    */
292                                                      "vec4(0.0, 0.0, float(subpassLoad(inputValue).r) / 256.0, 1.0);\n")
293             << "}\n";
294 
295         programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
296     }
297 }
298 
checkSupport(Context & context) const299 void TransientAttachmentTest::checkSupport(Context &context) const
300 {
301     const InstanceInterface &vki          = context.getInstanceInterface();
302     const VkPhysicalDevice physicalDevice = context.getPhysicalDevice();
303     VkImageFormatProperties formatProperties;
304     const VkPhysicalDeviceMemoryProperties pMemoryProperties = getPhysicalDeviceMemoryProperties(vki, physicalDevice);
305     const std::vector<uint32_t> memoryTypeIndices            = getMemoryTypeIndices(m_flags, pMemoryProperties);
306 
307     const VkFormat testFormat =
308         m_testMode == TestMode::MODE_DEPTH ?
309             VK_FORMAT_D16_UNORM :
310         m_testMode == TestMode::MODE_STENCIL ?
311             getSupportedStencilFormat(context.getPhysicalDevice(), context.getInstanceInterface()) :
312             VK_FORMAT_R8G8B8A8_UNORM;
313 
314     if (memoryTypeIndices.empty())
315     {
316         TCU_THROW(NotSupportedError,
317                   std::string(memoryPropertyFlagBitToString(m_flags)) + " is not supported by any memory type");
318     }
319 
320     vki.getPhysicalDeviceImageFormatProperties(
321         physicalDevice, testFormat, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL,
322         (m_testMode == TestMode::MODE_DEPTH || m_testMode == TestMode::MODE_STENCIL) ?
323             VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT :
324             VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT,
325         0u, &formatProperties);
326 
327     if (formatProperties.sampleCounts == 0 || testFormat == VK_FORMAT_UNDEFINED)
328         TCU_THROW(NotSupportedError, de::toString(testFormat) + " not supported");
329 }
330 
331 class TransientAttachmentTestInstance : public TestInstance
332 {
333 public:
334     TransientAttachmentTestInstance(Context &context, const TestMode testMode, const VkMemoryPropertyFlags flags,
335                                     const tcu::IVec2 renderSize);
336 
337     tcu::TestStatus iterate(void);
338 
339 private:
340     const TestMode m_testMode;
341     const tcu::IVec2 m_renderSize;
342     const VkImageAspectFlags m_aspectFlags;
343     const VkImageUsageFlags m_usageFlags;
344     const VkFormat m_testFormat;
345     const vk::MemoryRequirement m_memReq;
346 };
347 
TransientAttachmentTestInstance(Context & context,const TestMode testMode,const VkMemoryPropertyFlags flags,const tcu::IVec2 renderSize)348 TransientAttachmentTestInstance::TransientAttachmentTestInstance(Context &context, const TestMode testMode,
349                                                                  const VkMemoryPropertyFlags flags,
350                                                                  const tcu::IVec2 renderSize)
351     : TestInstance(context)
352     , m_testMode(testMode)
353     , m_renderSize(renderSize)
354     , m_aspectFlags(testMode == TestMode::MODE_DEPTH   ? VkImageAspectFlagBits::VK_IMAGE_ASPECT_DEPTH_BIT :
355                     testMode == TestMode::MODE_STENCIL ? VkImageAspectFlagBits::VK_IMAGE_ASPECT_STENCIL_BIT :
356                                                          VkImageAspectFlagBits::VK_IMAGE_ASPECT_COLOR_BIT)
357     , m_usageFlags(testMode == TestMode::MODE_COLOR ?
358                        VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT |
359                            VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT :
360                        VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT |
361                            VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT)
362     , m_testFormat(testMode == TestMode::MODE_DEPTH   ? VK_FORMAT_D16_UNORM :
363                    testMode == TestMode::MODE_STENCIL ? getSupportedStencilFormat(m_context.getPhysicalDevice(),
364                                                                                   m_context.getInstanceInterface()) :
365                                                         VK_FORMAT_R8G8B8A8_UNORM)
366     , m_memReq(flags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT ? MemoryRequirement::LazilyAllocated :
367                                                                  MemoryRequirement::Local)
368 {
369     DE_ASSERT(m_testMode != TestMode::MODE_INVALID);
370 }
371 
iterate(void)372 tcu::TestStatus TransientAttachmentTestInstance::iterate(void)
373 {
374     const DeviceInterface &vk                          = m_context.getDeviceInterface();
375     const VkDevice device                              = m_context.getDevice();
376     const VkQueue queue                                = m_context.getUniversalQueue();
377     const uint32_t queueFamilyIndex                    = m_context.getUniversalQueueFamilyIndex();
378     Allocator &allocator                               = m_context.getDefaultAllocator();
379     const VkImageSubresourceRange testSubresourceRange = makeImageSubresourceRange(m_aspectFlags, 0u, 1u, 0u, 1u);
380     const VkFormat outputFormat                        = VK_FORMAT_R8G8B8A8_UNORM;
381     const VkImageAspectFlags outputAspectFlags         = VkImageAspectFlagBits::VK_IMAGE_ASPECT_COLOR_BIT;
382     const VkImageUsageFlags outputUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
383 
384     // Test attachment
385     const Unique<VkImage> inputImage(
386         makeImage(vk, device, makeImageCreateInfo(m_testFormat, m_renderSize, m_usageFlags)));
387     const UniquePtr<Allocation> inputImageAllocator(bindImage(vk, device, allocator, *inputImage, m_memReq));
388     const Unique<VkImageView> inputImageView(
389         makeImageView(vk, device, *inputImage, VK_IMAGE_VIEW_TYPE_2D, m_testFormat, testSubresourceRange));
390     const VkImageView firstAttachmentImages[] = {*inputImageView};
391 
392     const VkImageSubresourceRange outputSubresourceRange = makeImageSubresourceRange(outputAspectFlags, 0u, 1u, 0u, 1u);
393     const Unique<VkImage> outputImage(
394         makeImage(vk, device, makeImageCreateInfo(outputFormat, m_renderSize, outputUsageFlags)));
395     const UniquePtr<Allocation> outputImageAllocator(
396         bindImage(vk, device, allocator, *outputImage, MemoryRequirement::Local));
397     const Unique<VkImageView> outputImageView(
398         makeImageView(vk, device, *outputImage, VK_IMAGE_VIEW_TYPE_2D, outputFormat, outputSubresourceRange));
399     const VkImageView secondAttachmentImages[] = {*inputImageView, *outputImageView};
400 
401     const VkDeviceSize resultBufferSizeBytes =
402         tcu::getPixelSize(mapVkFormat(outputFormat)) * m_renderSize.x() * m_renderSize.y();
403     const Unique<VkBuffer> resultBuffer(
404         makeBuffer(vk, device, resultBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
405     const UniquePtr<Allocation> resultBufferAlloc(
406         bindBuffer(vk, device, allocator, *resultBuffer, MemoryRequirement::HostVisible));
407 
408     // Main vertex buffer
409     const uint32_t numVertices               = 6;
410     const VkDeviceSize vertexBufferSizeBytes = 256;
411     const Unique<VkBuffer> vertexBuffer(
412         makeBuffer(vk, device, vertexBufferSizeBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
413     const UniquePtr<Allocation> vertexBufferAlloc(
414         bindBuffer(vk, device, allocator, *vertexBuffer, MemoryRequirement::HostVisible));
415 
416     {
417         tcu::Vec4 *const pVertices = reinterpret_cast<tcu::Vec4 *>(vertexBufferAlloc->getHostPtr());
418 
419         pVertices[0] = tcu::Vec4(1.0f, -1.0f, 0.0f, 1.0f);
420         pVertices[1] = tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f);
421         pVertices[2] = tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f);
422         pVertices[3] = tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f);
423         pVertices[4] = tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f);
424         pVertices[5] = tcu::Vec4(1.0f, -1.0f, 1.0f, 1.0f);
425 
426         flushAlloc(vk, device, *vertexBufferAlloc);
427     }
428 
429     // Shader modules
430     const Unique<VkShaderModule> vertexModule(
431         createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
432     const Unique<VkShaderModule> fragmentModule(
433         createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0u));
434 
435     // Descriptor pool and descriptor set
436     DescriptorPoolBuilder poolBuilder;
437     {
438         poolBuilder.addType(VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1u);
439     }
440 
441     const auto descriptorPool = poolBuilder.build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
442 
443     DescriptorSetLayoutBuilder layoutBuilderAttachments;
444     {
445         layoutBuilderAttachments.addSingleBinding(VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, VK_SHADER_STAGE_FRAGMENT_BIT);
446     }
447 
448     const auto inputAttachmentsSetLayout = layoutBuilderAttachments.build(vk, device);
449     const auto descriptorSetAttachments =
450         makeDescriptorSet(vk, device, descriptorPool.get(), inputAttachmentsSetLayout.get());
451     const std::vector<VkDescriptorSet> descriptorSets = {descriptorSetAttachments.get()};
452 
453     const VkDescriptorImageInfo imageInfo = {
454         DE_NULL,                                 // VkSampler sampler;
455         *inputImageView,                         // VkImageView imageView;
456         VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL // VkImageLayout imageLayout;
457     };
458 
459     DescriptorSetUpdateBuilder updater;
460     {
461         updater.writeSingle(descriptorSetAttachments.get(),
462                             DescriptorSetUpdateBuilder::Location::binding(static_cast<uint32_t>(0)),
463                             VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, &imageInfo);
464         updater.update(vk, device);
465     }
466 
467     const bool isDepthStencil = isDepthStencilFormat(m_testFormat);
468     VkImageLayout inputLayout =
469         isDepthStencil ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
470 
471     // Renderpasses
472     VkAttachmentDescription clearPassAttachment =
473         makeAttachment(m_testFormat, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE,
474                        VK_IMAGE_LAYOUT_UNDEFINED, inputLayout);
475     VkAttachmentDescription inputPassAttachment =
476         makeAttachment(m_testFormat, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, inputLayout,
477                        VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
478     VkAttachmentDescription outputPassAttachment =
479         makeAttachment(outputFormat, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_STORE,
480                        VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
481 
482     const Unique<VkRenderPass> renderPassOne(makeRenderPass(vk, device, {clearPassAttachment}, false));
483     const Unique<VkRenderPass> renderPassTwo(
484         makeRenderPass(vk, device, {inputPassAttachment, outputPassAttachment}, true));
485 
486     const Unique<VkFramebuffer> framebufferOne(
487         makeFramebuffer(vk, device, *renderPassOne, 1, firstAttachmentImages, m_renderSize.x(), m_renderSize.y()));
488     const Unique<VkFramebuffer> framebufferTwo(
489         makeFramebuffer(vk, device, *renderPassTwo, 2, secondAttachmentImages, m_renderSize.x(), m_renderSize.y()));
490 
491     // Pipeline
492     const std::vector<VkViewport> viewports(1, makeViewport(m_renderSize));
493     const std::vector<VkRect2D> scissors(1, makeRect2D(m_renderSize));
494     const Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout(vk, device, *inputAttachmentsSetLayout));
495     const Unique<VkPipeline> pipeline(vk::makeGraphicsPipeline(
496         vk,                                  // const DeviceInterface&                        vk
497         device,                              // const VkDevice                                device
498         *pipelineLayout,                     // const VkPipelineLayout                        pipelineLayout
499         *vertexModule,                       // const VkShaderModule                            vertexShaderModule
500         DE_NULL,                             // const VkShaderModule                            essellationControlModule
501         DE_NULL,                             // const VkShaderModule                            tessellationEvalModule
502         DE_NULL,                             // const VkShaderModule                            geometryShaderModule
503         *fragmentModule,                     // const VkShaderModule                            fragmentShaderModule
504         *renderPassTwo,                      // const VkRenderPass                            renderPass
505         viewports,                           // const std::vector<VkViewport>&                viewports
506         scissors,                            // const std::vector<VkRect2D>&                    scissors
507         VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // const VkPrimitiveTopology                    topology
508         0u,                                  // const uint32_t                                subpass
509         0u)); // const VkPipelineDepthStencilStateCreateInfo*    depthStencilStateCreateInfo
510 
511     // Command buffer
512     const Unique<VkCommandPool> cmdPool(
513         createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
514     const Unique<VkCommandBuffer> cmdBuffer(
515         allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
516 
517     {
518         const VkDeviceSize vertexBufferOffset = 0ull;
519         VkClearValue clearValue;
520 
521         if (m_testMode == TestMode::MODE_COLOR)
522             clearValue.color = {{1.0f, 1.0f, 0.0f, 1.0f}};
523         else if (m_testMode == TestMode::MODE_DEPTH)
524             clearValue.depthStencil.depth = 0.5f;
525         else if (m_testMode == TestMode::MODE_STENCIL)
526             clearValue.depthStencil = {0.0f, 128u};
527 
528         const VkRect2D renderArea = {
529             makeOffset2D(0, 0),
530             makeExtent2D(m_renderSize.x(), m_renderSize.y()),
531         };
532 
533         beginCommandBuffer(vk, *cmdBuffer);
534 
535         // Clear attachment
536         beginRenderPass(vk, *cmdBuffer, *renderPassOne, *framebufferOne, renderArea, clearValue);
537         endRenderPass(vk, *cmdBuffer);
538 
539         // Synchronize clear and read operations.
540         {
541             const auto srcAccess =
542                 isDepthStencil ? VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT : VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
543             const auto dstAccess = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
544             const auto srcStage =
545                 isDepthStencil ?
546                     (VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT) :
547                     VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
548             const auto dstStage    = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
549             const auto clearToLoad = makeMemoryBarrier(srcAccess, dstAccess);
550             cmdPipelineMemoryBarrier(vk, *cmdBuffer, srcStage, dstStage, &clearToLoad);
551         }
552 
553         // Draw with input attachment
554         beginRenderPass(vk, *cmdBuffer, *renderPassTwo, *framebufferTwo, renderArea);
555         vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
556         vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
557         vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout.get(), 0u,
558                                  static_cast<uint32_t>(descriptorSets.size()), descriptorSets.data(), 0u, nullptr);
559         vk.cmdDraw(*cmdBuffer, numVertices, 1u, 0u, 0u);
560         endRenderPass(vk, *cmdBuffer);
561 
562         copyImageToBuffer(vk, *cmdBuffer, *outputImage, *resultBuffer, m_renderSize,
563                           VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, outputPassAttachment.finalLayout, 1u, outputAspectFlags,
564                           outputAspectFlags);
565 
566         endCommandBuffer(vk, *cmdBuffer);
567         submitCommandsAndWait(vk, device, queue, *cmdBuffer);
568     }
569 
570     // Verify results
571     {
572         invalidateAlloc(vk, device, *resultBufferAlloc);
573 
574         const tcu::ConstPixelBufferAccess imagePixelAccess(mapVkFormat(outputFormat), m_renderSize.x(),
575                                                            m_renderSize.y(), 1, resultBufferAlloc->getHostPtr());
576         tcu::TextureLevel referenceImage(mapVkFormat(outputFormat), m_renderSize.x(), m_renderSize.y());
577         const tcu::Vec4 clearColor = m_testMode == TestMode::MODE_COLOR ? tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f) :
578                                      m_testMode == TestMode::MODE_DEPTH ? tcu::Vec4(0.5f, 0.0f, 0.0f, 1.0f) :
579                                                                           tcu::Vec4(0.0f, 0.0f, 0.5f, 1.0f);
580 
581         tcu::clear(referenceImage.getAccess(), clearColor);
582 
583         if (!tcu::floatThresholdCompare(m_context.getTestContext().getLog(), "Compare", "Result comparison",
584                                         referenceImage.getAccess(), imagePixelAccess, tcu::Vec4(0.02f),
585                                         tcu::COMPARE_LOG_RESULT))
586         {
587             return tcu::TestStatus::fail("Rendered color image is not correct");
588         }
589     }
590 
591     return tcu::TestStatus::pass("Success");
592 }
593 
createInstance(Context & context) const594 TestInstance *TransientAttachmentTest::createInstance(Context &context) const
595 {
596     return new TransientAttachmentTestInstance(context, m_testMode, m_flags, m_renderSize);
597 }
598 
599 } // namespace
600 
createTransientAttachmentTests(tcu::TestContext & testCtx)601 tcu::TestCaseGroup *createTransientAttachmentTests(tcu::TestContext &testCtx)
602 {
603     // image usage transient attachment bit load and store op test
604     de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "transient_attachment_bit"));
605 
606     {
607         static const struct
608         {
609             std::string caseName;
610             TestMode testMode;
611             const VkMemoryPropertyFlags flags;
612         } cases[] = {
613             {"color_load_store_op_test_lazy_bit", TestMode::MODE_COLOR, VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT},
614             {"depth_load_store_op_test_lazy_bit", TestMode::MODE_DEPTH, VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT},
615             {"stencil_load_store_op_test_lazy_bit", TestMode::MODE_STENCIL, VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT},
616             {"color_load_store_op_test_local_bit", TestMode::MODE_COLOR, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT},
617             {"depth_load_store_op_test_local_bit", TestMode::MODE_DEPTH, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT},
618             {"stencil_load_store_op_test_local_bit", TestMode::MODE_STENCIL, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT}};
619 
620         for (const auto &testCase : cases)
621         {
622             testGroup->addChild(new TransientAttachmentTest(testCtx, testCase.caseName, testCase.testMode,
623                                                             testCase.flags, tcu::IVec2(32, 32)));
624         }
625     }
626 
627     return testGroup.release();
628 }
629 
630 } // namespace FragmentOperations
631 } // namespace vkt
632