1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2020 The Khronos Group Inc.
6  * Copyright (c) 2020 Valve Corporation.
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 Test frag shader side effects are not removed by optimizations.
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktRasterizationFragShaderSideEffectsTests.hpp"
26 #include "vktTestCase.hpp"
27 
28 #include "vkQueryUtil.hpp"
29 #include "vkObjUtil.hpp"
30 #include "vkBuilderUtil.hpp"
31 #include "vkImageWithMemory.hpp"
32 #include "vkBufferWithMemory.hpp"
33 #include "vkTypeUtil.hpp"
34 #include "vkCmdUtil.hpp"
35 #include "vkBarrierUtil.hpp"
36 #include "vkImageUtil.hpp"
37 
38 #include "tcuVector.hpp"
39 #include "tcuMaybe.hpp"
40 #include "tcuTestLog.hpp"
41 
42 #include "deUniquePtr.hpp"
43 
44 #include <sstream>
45 #include <string>
46 #include <memory>
47 #include <vector>
48 #include <algorithm>
49 
50 namespace vkt
51 {
52 namespace rasterization
53 {
54 
55 namespace
56 {
57 
58 enum class CaseType
59 {
60     KILL,
61     DEMOTE,
62     TERMINATE_INVOCATION,
63     SAMPLE_MASK_BEFORE,
64     SAMPLE_MASK_AFTER,
65     ALPHA_COVERAGE_BEFORE,
66     ALPHA_COVERAGE_AFTER,
67     DEPTH_BOUNDS,
68     STENCIL_NEVER,
69     DEPTH_NEVER,
70 };
71 
72 constexpr uint32_t kFramebufferWidth  = 32u;
73 constexpr uint32_t kFramebufferHeight = 32u;
74 constexpr uint32_t kTotalPixels       = kFramebufferWidth * kFramebufferHeight;
75 
76 constexpr vk::VkFormat kColorFormat                  = vk::VK_FORMAT_R8G8B8A8_UNORM;
77 constexpr vk::VkFormatFeatureFlags kNeededDSFeatures = vk::VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
78 // VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT must be supported for one of these two, according to the spec.
79 const vk::VkFormat kDepthStencilFormats[] = {vk::VK_FORMAT_D32_SFLOAT_S8_UINT, vk::VK_FORMAT_D24_UNORM_S8_UINT};
80 
81 struct DepthBoundsParameters
82 {
83     float minDepthBounds;
84     float maxDepthBounds;
85     float depthValue;
86 };
87 
88 struct TestParams
89 {
90     CaseType caseType;
91     tcu::Vec4 clearColor;
92     tcu::Vec4 drawColor;
93     bool colorAtEnd;
94     tcu::Maybe<DepthBoundsParameters> depthBoundsParams;
95 
TestParamsvkt::rasterization::__anonf92836c60111::TestParams96     TestParams(CaseType type, const tcu::Vec4 &clearColor_, const tcu::Vec4 &drawColor_, bool colorAtEnd_,
97                const tcu::Maybe<DepthBoundsParameters> &depthBoundsParams_)
98         : caseType(type)
99         , clearColor(clearColor_)
100         , drawColor(drawColor_)
101         , colorAtEnd(colorAtEnd_)
102         , depthBoundsParams(depthBoundsParams_)
103     {
104         if (caseType == CaseType::DEPTH_BOUNDS)
105             DE_ASSERT(static_cast<bool>(depthBoundsParams));
106     }
107 };
108 
expectClearColor(CaseType caseType)109 bool expectClearColor(CaseType caseType)
110 {
111     return (caseType != CaseType::ALPHA_COVERAGE_BEFORE && caseType != CaseType::ALPHA_COVERAGE_AFTER);
112 }
113 
needsDepthStencilAttachment(CaseType caseType)114 bool needsDepthStencilAttachment(CaseType caseType)
115 {
116     return (caseType == CaseType::DEPTH_BOUNDS || caseType == CaseType::DEPTH_NEVER ||
117             caseType == CaseType::STENCIL_NEVER);
118 }
119 
makeVkBool32(bool value)120 vk::VkBool32 makeVkBool32(bool value)
121 {
122     return (value ? VK_TRUE : VK_FALSE);
123 }
124 
125 class FragSideEffectsTestCase : public vkt::TestCase
126 {
127 public:
128     FragSideEffectsTestCase(tcu::TestContext &testCtx, const std::string &name, const TestParams &params);
~FragSideEffectsTestCase(void)129     virtual ~FragSideEffectsTestCase(void)
130     {
131     }
132 
133     virtual void checkSupport(Context &context) const;
134     virtual void initPrograms(vk::SourceCollections &programCollection) const;
135     virtual TestInstance *createInstance(Context &context) const;
136 
137 private:
138     TestParams m_params;
139 };
140 
141 class FragSideEffectsInstance : public vkt::TestInstance
142 {
143 public:
144     FragSideEffectsInstance(Context &context, const TestParams &params);
~FragSideEffectsInstance(void)145     virtual ~FragSideEffectsInstance(void)
146     {
147     }
148 
149     virtual tcu::TestStatus iterate(void);
150 
151 private:
152     TestParams m_params;
153 };
154 
FragSideEffectsTestCase(tcu::TestContext & testCtx,const std::string & name,const TestParams & params)155 FragSideEffectsTestCase::FragSideEffectsTestCase(tcu::TestContext &testCtx, const std::string &name,
156                                                  const TestParams &params)
157     : vkt::TestCase(testCtx, name)
158     , m_params(params)
159 {
160 }
161 
checkSupport(Context & context) const162 void FragSideEffectsTestCase::checkSupport(Context &context) const
163 {
164     const auto &features = context.getDeviceFeatures();
165 
166     if (!features.fragmentStoresAndAtomics)
167         TCU_THROW(NotSupportedError, "Fragment shader stores and atomics not supported");
168 
169     if (m_params.caseType == CaseType::DEPTH_BOUNDS)
170     {
171         if (!features.depthBounds)
172             TCU_THROW(NotSupportedError, "Depth bounds test not supported");
173     }
174     else if (m_params.caseType == CaseType::DEMOTE)
175     {
176         context.requireDeviceFunctionality("VK_EXT_shader_demote_to_helper_invocation");
177     }
178     else if (m_params.caseType == CaseType::TERMINATE_INVOCATION)
179     {
180         context.requireDeviceFunctionality("VK_KHR_shader_terminate_invocation");
181     }
182 }
183 
initPrograms(vk::SourceCollections & programCollection) const184 void FragSideEffectsTestCase::initPrograms(vk::SourceCollections &programCollection) const
185 {
186     std::ostringstream headers;
187     std::ostringstream before;
188     std::ostringstream after;
189 
190     std::ostringstream vert;
191     std::ostringstream frag;
192 
193     // Depth should be 0 by default unless provided by the depth bounds parameters.
194     const float meshDepth = (m_params.depthBoundsParams ? m_params.depthBoundsParams.get().depthValue : 0.0f);
195     const auto &drawColor = m_params.drawColor;
196 
197     vert << "#version 450\n"
198          << "\n"
199          << "layout (location=0) in vec2 inPos;\n"
200          << "\n"
201          << "void main() {\n"
202          << "    gl_Position = vec4(inPos, " << meshDepth << ", 1.0);\n"
203          << "}\n";
204 
205     // Prepare output color statement to be used before or after SSBO write.
206     std::ostringstream colorStatement;
207     if (m_params.caseType == CaseType::ALPHA_COVERAGE_BEFORE || m_params.caseType == CaseType::ALPHA_COVERAGE_AFTER)
208     {
209         // In the alpha coverage cases the alpha color value is supposed to be 0.
210         DE_ASSERT(m_params.drawColor.w() == 0.0f);
211 
212         // Leave out the alpha component for these cases.
213         colorStatement << "    outColor.rgb = vec3(" << drawColor.x() << ", " << drawColor.y() << ", " << drawColor.z()
214                        << ");\n";
215     }
216     else
217     {
218         colorStatement << "    outColor = vec4(" << drawColor.x() << ", " << drawColor.y() << ", " << drawColor.z()
219                        << ", " << drawColor.w() << ");\n";
220     }
221 
222     switch (m_params.caseType)
223     {
224     case CaseType::KILL:
225         after << "    discard;\n";
226         break;
227     case CaseType::DEMOTE:
228         headers << "#extension GL_EXT_demote_to_helper_invocation : enable\n";
229         after << "    demote;\n";
230         break;
231     case CaseType::TERMINATE_INVOCATION:
232         headers << "#extension GL_EXT_terminate_invocation : enable\n";
233         after << "    terminateInvocation;\n";
234         break;
235     case CaseType::SAMPLE_MASK_BEFORE:
236         before << "    gl_SampleMask[0] = 0;\n";
237         break;
238     case CaseType::SAMPLE_MASK_AFTER:
239         after << "    gl_SampleMask[0] = 0;\n";
240         break;
241     case CaseType::ALPHA_COVERAGE_BEFORE:
242         before << "    outColor.a = float(" << drawColor.w() << ");\n";
243         break;
244     case CaseType::ALPHA_COVERAGE_AFTER:
245         after << "    outColor.a = float(" << drawColor.w() << ");\n";
246         break;
247     case CaseType::DEPTH_BOUNDS:
248     case CaseType::STENCIL_NEVER:
249     case CaseType::DEPTH_NEVER:
250         break;
251     default:
252         DE_ASSERT(false);
253         break;
254     }
255 
256     frag << "#version 450\n"
257          << "layout(set=0, binding=0, std430) buffer OutputBuffer {\n"
258          << "    int val[" << kTotalPixels << "];\n"
259          << "} outBuffer;\n"
260          << "layout (location=0) out vec4 outColor;\n"
261          << headers.str() << "\n"
262          << "void main() {\n"
263          << "    const ivec2 fragCoord = ivec2(gl_FragCoord);\n"
264          << "    const int bufferIndex = (fragCoord.y * " << kFramebufferWidth << ") + fragCoord.x;\n"
265          << (m_params.colorAtEnd ? "" : colorStatement.str()) << before.str() << "    outBuffer.val[bufferIndex] = 1;\n"
266          << after.str() << (m_params.colorAtEnd ? colorStatement.str() : "") << "}\n";
267 
268     programCollection.glslSources.add("vert") << glu::VertexSource(vert.str());
269     programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
270 }
271 
createInstance(Context & context) const272 TestInstance *FragSideEffectsTestCase::createInstance(Context &context) const
273 {
274     return new FragSideEffectsInstance(context, m_params);
275 }
276 
FragSideEffectsInstance(Context & context,const TestParams & params)277 FragSideEffectsInstance::FragSideEffectsInstance(Context &context, const TestParams &params)
278     : vkt::TestInstance(context)
279     , m_params(params)
280 {
281 }
282 
iterate(void)283 tcu::TestStatus FragSideEffectsInstance::iterate(void)
284 {
285     const auto &vki           = m_context.getInstanceInterface();
286     const auto physicalDevice = m_context.getPhysicalDevice();
287     const auto &vkd           = m_context.getDeviceInterface();
288     const auto device         = m_context.getDevice();
289     auto &alloc               = m_context.getDefaultAllocator();
290     const auto queue          = m_context.getUniversalQueue();
291     const auto queueIndex     = m_context.getUniversalQueueFamilyIndex();
292 
293     // Color and depth/stencil images.
294 
295     const vk::VkImageCreateInfo colorCreateInfo = {
296         vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,                     // VkStructureType sType;
297         nullptr,                                                     // const void* pNext;
298         0u,                                                          // VkImageCreateFlags flags;
299         vk::VK_IMAGE_TYPE_2D,                                        // VkImageType imageType;
300         kColorFormat,                                                // VkFormat format;
301         vk::makeExtent3D(kFramebufferWidth, kFramebufferHeight, 1u), // VkExtent3D extent;
302         1u,                                                          // uint32_t mipLevels;
303         1u,                                                          // uint32_t arrayLayers;
304         vk::VK_SAMPLE_COUNT_1_BIT,                                   // VkSampleCountFlagBits samples;
305         vk::VK_IMAGE_TILING_OPTIMAL,                                 // VkImageTiling tiling;
306         (vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT), // VkImageUsageFlags usage;
307         vk::VK_SHARING_MODE_EXCLUSIVE,                                                   // VkSharingMode sharingMode;
308         0u,                            // uint32_t queueFamilyIndexCount;
309         nullptr,                       // const uint32_t* pQueueFamilyIndices;
310         vk::VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
311     };
312     vk::ImageWithMemory colorImage(vkd, device, alloc, colorCreateInfo, vk::MemoryRequirement::Any);
313 
314     std::unique_ptr<vk::ImageWithMemory> depthStencilImage;
315     vk::VkFormat depthStencilFormat = vk::VK_FORMAT_UNDEFINED;
316 
317     if (needsDepthStencilAttachment(m_params.caseType))
318     {
319         // Find available image format first.
320         for (int i = 0; i < DE_LENGTH_OF_ARRAY(kDepthStencilFormats); ++i)
321         {
322             const auto dsFormatProperties =
323                 vk::getPhysicalDeviceFormatProperties(vki, physicalDevice, kDepthStencilFormats[i]);
324             if ((dsFormatProperties.optimalTilingFeatures & kNeededDSFeatures) == kNeededDSFeatures)
325             {
326                 depthStencilFormat = kDepthStencilFormats[i];
327                 break;
328             }
329         }
330 
331         if (depthStencilFormat == vk::VK_FORMAT_UNDEFINED)
332             TCU_FAIL("No suitable depth/stencil format found");
333 
334         const vk::VkImageCreateInfo depthStencilCreateInfo = {
335             vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,                     // VkStructureType sType;
336             nullptr,                                                     // const void* pNext;
337             0u,                                                          // VkImageCreateFlags flags;
338             vk::VK_IMAGE_TYPE_2D,                                        // VkImageType imageType;
339             depthStencilFormat,                                          // VkFormat format;
340             vk::makeExtent3D(kFramebufferWidth, kFramebufferHeight, 1u), // VkExtent3D extent;
341             1u,                                                          // uint32_t mipLevels;
342             1u,                                                          // uint32_t arrayLayers;
343             vk::VK_SAMPLE_COUNT_1_BIT,                                   // VkSampleCountFlagBits samples;
344             vk::VK_IMAGE_TILING_OPTIMAL,                                 // VkImageTiling tiling;
345             vk::VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,             // VkImageUsageFlags usage;
346             vk::VK_SHARING_MODE_EXCLUSIVE,                               // VkSharingMode sharingMode;
347             0u,                                                          // uint32_t queueFamilyIndexCount;
348             nullptr,                                                     // const uint32_t* pQueueFamilyIndices;
349             vk::VK_IMAGE_LAYOUT_UNDEFINED,                               // VkImageLayout initialLayout;
350         };
351 
352         depthStencilImage.reset(
353             new vk::ImageWithMemory(vkd, device, alloc, depthStencilCreateInfo, vk::MemoryRequirement::Any));
354     }
355 
356     // Image views.
357     const auto colorSubresourceRange = vk::makeImageSubresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
358     const auto colorImageView        = vk::makeImageView(vkd, device, colorImage.get(), vk::VK_IMAGE_VIEW_TYPE_2D,
359                                                          kColorFormat, colorSubresourceRange);
360 
361     vk::Move<vk::VkImageView> depthStencilImageView;
362     if (depthStencilImage)
363     {
364         const auto depthStencilSubresourceRange = vk::makeImageSubresourceRange(
365             (vk::VK_IMAGE_ASPECT_DEPTH_BIT | vk::VK_IMAGE_ASPECT_STENCIL_BIT), 0u, 1u, 0u, 1u);
366         depthStencilImageView =
367             vk::makeImageView(vkd, device, depthStencilImage.get()->get(), vk::VK_IMAGE_VIEW_TYPE_2D,
368                               depthStencilFormat, depthStencilSubresourceRange);
369     }
370 
371     // Color image buffer.
372     const auto tcuFormat            = vk::mapVkFormat(kColorFormat);
373     const auto colorImageBufferSize = static_cast<vk::VkDeviceSize>(kTotalPixels * tcuFormat.getPixelSize());
374     const auto colorImageBufferInfo =
375         vk::makeBufferCreateInfo(colorImageBufferSize, vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT);
376     vk::BufferWithMemory colorImageBuffer(vkd, device, alloc, colorImageBufferInfo, vk::MemoryRequirement::HostVisible);
377 
378     // Vertex buffer.
379     const std::vector<tcu::Vec2> fullScreenQuad = {
380         tcu::Vec2(-1.0f, 1.0f), tcu::Vec2(1.0f, 1.0f),  tcu::Vec2(1.0f, -1.0f),
381         tcu::Vec2(-1.0f, 1.0f), tcu::Vec2(1.0f, -1.0f), tcu::Vec2(-1.0f, -1.0f),
382     };
383 
384     const auto vertexBufferSize =
385         static_cast<vk::VkDeviceSize>(fullScreenQuad.size() * sizeof(decltype(fullScreenQuad)::value_type));
386     const auto vertexBufferInfo = vk::makeBufferCreateInfo(vertexBufferSize, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
387     const vk::VkDeviceSize vertexBufferOffset = 0ull;
388     vk::BufferWithMemory vertexBuffer(vkd, device, alloc, vertexBufferInfo, vk::MemoryRequirement::HostVisible);
389     const auto &vertexBufferAlloc = vertexBuffer.getAllocation();
390 
391     deMemcpy(vertexBufferAlloc.getHostPtr(), fullScreenQuad.data(), static_cast<size_t>(vertexBufferSize));
392     vk::flushAlloc(vkd, device, vertexBufferAlloc);
393 
394     // Storage buffer.
395     const auto storageBufferSize = static_cast<vk::VkDeviceSize>(kTotalPixels * sizeof(int32_t));
396     const auto storageBufferInfo = vk::makeBufferCreateInfo(
397         storageBufferSize, (vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | vk::VK_BUFFER_USAGE_TRANSFER_SRC_BIT));
398     vk::BufferWithMemory storageBuffer(vkd, device, alloc, storageBufferInfo, vk::MemoryRequirement::HostVisible);
399     const auto &storageBufferAlloc = storageBuffer.getAllocation();
400 
401     deMemset(storageBufferAlloc.getHostPtr(), 0, static_cast<size_t>(storageBufferSize));
402     vk::flushAlloc(vkd, device, storageBufferAlloc);
403 
404     // Descriptor set layout.
405     vk::DescriptorSetLayoutBuilder layoutBuilder;
406     layoutBuilder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_FRAGMENT_BIT);
407     const auto descriptorSetLayout = layoutBuilder.build(vkd, device);
408 
409     // Pipeline layout.
410     const auto pipelineLayout = vk::makePipelineLayout(vkd, device, descriptorSetLayout.get());
411 
412     // Descriptor pool.
413     vk::DescriptorPoolBuilder poolBuilder;
414     poolBuilder.addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
415     const auto descriptorPool =
416         poolBuilder.build(vkd, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
417 
418     // Descriptor set.
419     const auto descriptorSet = vk::makeDescriptorSet(vkd, device, descriptorPool.get(), descriptorSetLayout.get());
420 
421     // Update descriptor set.
422     vk::DescriptorSetUpdateBuilder updateBuilder;
423     const auto descriptorBufferInfo = vk::makeDescriptorBufferInfo(storageBuffer.get(), 0u, storageBufferSize);
424     updateBuilder.writeSingle(descriptorSet.get(), vk::DescriptorSetUpdateBuilder::Location::binding(0),
425                               vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptorBufferInfo);
426     updateBuilder.update(vkd, device);
427 
428     // Render pass.
429     const auto renderPass = vk::makeRenderPass(vkd, device, kColorFormat, depthStencilFormat);
430 
431     // Framebuffer.
432     std::vector<vk::VkImageView> imageViews(1u, colorImageView.get());
433     if (depthStencilImage)
434         imageViews.push_back(depthStencilImageView.get());
435 
436     const auto framebuffer =
437         vk::makeFramebuffer(vkd, device, renderPass.get(), static_cast<uint32_t>(imageViews.size()), imageViews.data(),
438                             kFramebufferWidth, kFramebufferHeight);
439 
440     // Shader modules.
441     const auto vertModule = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("vert"), 0u);
442     const auto fragModule = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("frag"), 0u);
443 
444     // Vertex input state.
445     const auto vertexBinding    = vk::makeVertexInputBindingDescription(0u, static_cast<uint32_t>(sizeof(tcu::Vec2)),
446                                                                         vk::VK_VERTEX_INPUT_RATE_VERTEX);
447     const auto vertexAttributes = vk::makeVertexInputAttributeDescription(0u, 0u, vk::VK_FORMAT_R32G32_SFLOAT, 0u);
448 
449     const vk::VkPipelineVertexInputStateCreateInfo vertexInputInfo = {
450         vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
451         nullptr,                                                       // const void* pNext;
452         0u,                                                            // VkPipelineVertexInputStateCreateFlags flags;
453         1u,                                                            // uint32_t vertexBindingDescriptionCount;
454         &vertexBinding,    // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
455         1u,                // uint32_t vertexAttributeDescriptionCount;
456         &vertexAttributes, // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
457     };
458 
459     // Input assembly state.
460     const vk::VkPipelineInputAssemblyStateCreateInfo inputAssemblyInfo = {
461         vk::VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType;
462         nullptr,                                                         // const void* pNext;
463         0u,                                      // VkPipelineInputAssemblyStateCreateFlags flags;
464         vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // VkPrimitiveTopology topology;
465         VK_FALSE,                                // VkBool32 primitiveRestartEnable;
466     };
467 
468     // Viewport state.
469     const auto viewport = vk::makeViewport(kFramebufferWidth, kFramebufferHeight);
470     const auto scissor  = vk::makeRect2D(kFramebufferWidth, kFramebufferHeight);
471 
472     const vk::VkPipelineViewportStateCreateInfo viewportInfo = {
473         vk::VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType;
474         nullptr,                                                   // const void* pNext;
475         0u,                                                        // VkPipelineViewportStateCreateFlags flags;
476         1u,                                                        // uint32_t viewportCount;
477         &viewport,                                                 // const VkViewport* pViewports;
478         1u,                                                        // uint32_t scissorCount;
479         &scissor,                                                  // const VkRect2D* pScissors;
480     };
481 
482     // Rasterization state.
483     const vk::VkPipelineRasterizationStateCreateInfo rasterizationInfo = {
484         vk::VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
485         nullptr,                                                        // const void* pNext;
486         0u,                                  // VkPipelineRasterizationStateCreateFlags flags;
487         VK_FALSE,                            // VkBool32 depthClampEnable;
488         VK_FALSE,                            // VkBool32 rasterizerDiscardEnable;
489         vk::VK_POLYGON_MODE_FILL,            // VkPolygonMode polygonMode;
490         vk::VK_CULL_MODE_NONE,               // VkCullModeFlags cullMode;
491         vk::VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace;
492         VK_FALSE,                            // VkBool32 depthBiasEnable;
493         0.0f,                                // float depthBiasConstantFactor;
494         0.0f,                                // float depthBiasClamp;
495         0.0f,                                // float depthBiasSlopeFactor;
496         1.0f,                                // float lineWidth;
497     };
498 
499     // Multisample state.
500     const bool alphaToCoverageEnable =
501         (m_params.caseType == CaseType::ALPHA_COVERAGE_BEFORE || m_params.caseType == CaseType::ALPHA_COVERAGE_AFTER);
502     const vk::VkPipelineMultisampleStateCreateInfo multisampleInfo = {
503         vk::VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
504         nullptr,                                                      // const void* pNext;
505         0u,                                                           // VkPipelineMultisampleStateCreateFlags flags;
506         vk::VK_SAMPLE_COUNT_1_BIT,                                    // VkSampleCountFlagBits rasterizationSamples;
507         VK_FALSE,                                                     // VkBool32 sampleShadingEnable;
508         0.0f,                                                         // float minSampleShading;
509         nullptr,                                                      // const VkSampleMask* pSampleMask;
510         makeVkBool32(alphaToCoverageEnable),                          // VkBool32 alphaToCoverageEnable;
511         VK_FALSE,                                                     // VkBool32 alphaToOneEnable;
512     };
513 
514     // Depth/stencil state.
515     const auto enableDepthBounds      = makeVkBool32(m_params.caseType == CaseType::DEPTH_BOUNDS);
516     const auto enableDepthStencilTest = static_cast<bool>(depthStencilImage);
517 
518     const auto depthCompareOp =
519         ((m_params.caseType == CaseType::DEPTH_NEVER) ? vk::VK_COMPARE_OP_NEVER : vk::VK_COMPARE_OP_ALWAYS);
520     const auto stencilCompareOp =
521         ((m_params.caseType == CaseType::STENCIL_NEVER) ? vk::VK_COMPARE_OP_NEVER : vk::VK_COMPARE_OP_ALWAYS);
522     const auto stencilOpState = vk::makeStencilOpState(vk::VK_STENCIL_OP_KEEP, vk::VK_STENCIL_OP_KEEP,
523                                                        vk::VK_STENCIL_OP_KEEP, stencilCompareOp, 0xFFu, 0xFFu, 0u);
524 
525     const vk::VkPipelineDepthStencilStateCreateInfo depthStencilInfo = {
526         vk::VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
527         nullptr,                                                        // const void* pNext;
528         0u,                                                             // VkPipelineDepthStencilStateCreateFlags flags;
529         enableDepthStencilTest,                                         // VkBool32 depthTestEnable;
530         enableDepthStencilTest,                                         // VkBool32 depthWriteEnable;
531         depthCompareOp,                                                 // VkCompareOp depthCompareOp;
532         enableDepthBounds,                                              // VkBool32 depthBoundsTestEnable;
533         enableDepthStencilTest,                                         // VkBool32 stencilTestEnable;
534         stencilOpState,                                                 // VkStencilOpState front;
535         stencilOpState,                                                 // VkStencilOpState back;
536         (enableDepthBounds ? m_params.depthBoundsParams.get().minDepthBounds : 0.0f), // float minDepthBounds;
537         (enableDepthBounds ? m_params.depthBoundsParams.get().maxDepthBounds : 1.0f), // float maxDepthBounds;
538     };
539 
540     // Color blend state.
541     const vk::VkPipelineColorBlendAttachmentState colorBlendAttachmentState = {
542         VK_FALSE,                    // VkBool32                 blendEnable
543         vk::VK_BLEND_FACTOR_ZERO,    // VkBlendFactor            srcColorBlendFactor
544         vk::VK_BLEND_FACTOR_ZERO,    // VkBlendFactor            dstColorBlendFactor
545         vk::VK_BLEND_OP_ADD,         // VkBlendOp                colorBlendOp
546         vk::VK_BLEND_FACTOR_ZERO,    // VkBlendFactor            srcAlphaBlendFactor
547         vk::VK_BLEND_FACTOR_ZERO,    // VkBlendFactor            dstAlphaBlendFactor
548         vk::VK_BLEND_OP_ADD,         // VkBlendOp                alphaBlendOp
549         vk::VK_COLOR_COMPONENT_R_BIT // VkColorComponentFlags    colorWriteMask
550             | vk::VK_COLOR_COMPONENT_G_BIT | vk::VK_COLOR_COMPONENT_B_BIT | vk::VK_COLOR_COMPONENT_A_BIT};
551 
552     const vk::VkPipelineColorBlendStateCreateInfo colorBlendInfo = {
553         vk::VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
554         nullptr,                                                      // const void* pNext;
555         0u,                                                           // VkPipelineColorBlendStateCreateFlags flags;
556         VK_FALSE,                                                     // VkBool32 logicOpEnable;
557         vk::VK_LOGIC_OP_NO_OP,                                        // VkLogicOp logicOp;
558         1u,                                                           // uint32_t attachmentCount;
559         &colorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments;
560         {.0f, .0f, .0f, .0f},       // float blendConstants[4];
561     };
562 
563     // Graphics pipeline.
564     const auto graphicsPipeline = vk::makeGraphicsPipeline(
565         vkd, device, pipelineLayout.get(), vertModule.get(), DE_NULL, DE_NULL, DE_NULL, fragModule.get(),
566         renderPass.get(), 0u, &vertexInputInfo, &inputAssemblyInfo, nullptr, &viewportInfo, &rasterizationInfo,
567         &multisampleInfo, &depthStencilInfo, &colorBlendInfo);
568 
569     // Command buffer.
570     const auto cmdPool = vk::makeCommandPool(vkd, device, queueIndex);
571     const auto cmdBufferPtr =
572         vk::allocateCommandBuffer(vkd, device, cmdPool.get(), vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
573     const auto cmdBuffer = cmdBufferPtr.get();
574 
575     // Draw full-screen quad.
576     std::vector<vk::VkClearValue> clearValues;
577     clearValues.push_back(vk::makeClearValueColor(m_params.clearColor));
578     clearValues.push_back(vk::makeClearValueDepthStencil(1.0f, 0u));
579 
580     vk::beginCommandBuffer(vkd, cmdBuffer);
581     vk::beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(),
582                         vk::makeRect2D(kFramebufferWidth, kFramebufferHeight),
583                         static_cast<uint32_t>(clearValues.size()), clearValues.data());
584     vkd.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline.get());
585     vkd.cmdBindDescriptorSets(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout.get(), 0u, 1u,
586                               &descriptorSet.get(), 0u, nullptr);
587     vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
588     vkd.cmdDraw(cmdBuffer, static_cast<uint32_t>(fullScreenQuad.size()), 1u, 0u, 0u);
589     vk::endRenderPass(vkd, cmdBuffer);
590 
591     // Image and buffer barriers.
592 
593     // Storage buffer frag-write to host-read barrier.
594     const auto storageBufferBarrier = vk::makeBufferMemoryBarrier(
595         vk::VK_ACCESS_SHADER_WRITE_BIT, vk::VK_ACCESS_HOST_READ_BIT, storageBuffer.get(), 0u, VK_WHOLE_SIZE);
596 
597     // Color image frag-write to transfer-read barrier.
598     const auto colorImageBarrier =
599         vk::makeImageMemoryBarrier(vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, vk::VK_ACCESS_TRANSFER_READ_BIT,
600                                    vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
601                                    vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorImage.get(), colorSubresourceRange);
602 
603     // Color buffer transfer-write to host-read barrier.
604     const auto colorBufferBarrier = vk::makeBufferMemoryBarrier(
605         vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_ACCESS_HOST_READ_BIT, colorImageBuffer.get(), 0u, VK_WHOLE_SIZE);
606 
607     vk::cmdPipelineBufferMemoryBarrier(vkd, cmdBuffer, vk::VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
608                                        vk::VK_PIPELINE_STAGE_HOST_BIT, &storageBufferBarrier);
609     vk::cmdPipelineImageMemoryBarrier(vkd, cmdBuffer, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
610                                       vk::VK_PIPELINE_STAGE_TRANSFER_BIT, &colorImageBarrier);
611     const auto copyRegion =
612         vk::makeBufferImageCopy(vk::makeExtent3D(kFramebufferWidth, kFramebufferHeight, 1u),
613                                 vk::makeImageSubresourceLayers(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u));
614     vkd.cmdCopyImageToBuffer(cmdBuffer, colorImage.get(), vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
615                              colorImageBuffer.get(), 1u, &copyRegion);
616     vk::cmdPipelineBufferMemoryBarrier(vkd, cmdBuffer, vk::VK_PIPELINE_STAGE_TRANSFER_BIT,
617                                        vk::VK_PIPELINE_STAGE_HOST_BIT, &colorBufferBarrier);
618 
619     vk::endCommandBuffer(vkd, cmdBuffer);
620     vk::submitCommandsAndWait(vkd, device, queue, cmdBuffer);
621 
622     // Check output.
623     {
624         // Check SSBO contents.
625         vk::invalidateAlloc(vkd, device, storageBufferAlloc);
626         const auto bufferElements = reinterpret_cast<const int32_t *>(storageBufferAlloc.getHostPtr());
627 
628         for (uint32_t i = 0; i < kTotalPixels; ++i)
629         {
630             if (bufferElements[i] != 1)
631             {
632                 std::ostringstream msg;
633                 msg << "Unexpected value in storage buffer element " << i;
634                 return tcu::TestStatus::fail("Fail: " + msg.str());
635             }
636         }
637     }
638 
639     {
640         // Check color attachment.
641         std::vector<tcu::Vec4> expectedColors(1u, m_params.clearColor);
642         if (!expectClearColor(m_params.caseType))
643             expectedColors.push_back(m_params.drawColor);
644 
645         const auto &colorImageBufferAlloc = colorImageBuffer.getAllocation();
646         vk::invalidateAlloc(vkd, device, colorImageBufferAlloc);
647 
648         const auto iWidth  = static_cast<int>(kFramebufferWidth);
649         const auto iHeight = static_cast<int>(kFramebufferHeight);
650 
651         tcu::ConstPixelBufferAccess colorPixels(tcuFormat, iWidth, iHeight, 1, colorImageBufferAlloc.getHostPtr());
652         std::vector<uint8_t> errorMaskBuffer(kTotalPixels * tcuFormat.getPixelSize(), 0u);
653         tcu::PixelBufferAccess errorMask(tcuFormat, iWidth, iHeight, 1, errorMaskBuffer.data());
654         const tcu::Vec4 green(0.0f, 1.0f, 0.0f, 1.0f);
655         const tcu::Vec4 red(1.0f, 0.0f, 0.0f, 1.0f);
656         bool allPixOk = true;
657 
658         for (int i = 0; i < iWidth; ++i)
659             for (int j = 0; j < iHeight; ++j)
660             {
661                 const auto pixel = colorPixels.getPixel(i, j);
662                 const bool pixOk =
663                     std::any_of(begin(expectedColors), end(expectedColors),
664                                 [&pixel](const tcu::Vec4 &expected) -> bool { return (pixel == expected); });
665                 errorMask.setPixel((pixOk ? green : red), i, j);
666                 if (!pixOk)
667                     allPixOk = false;
668             }
669 
670         if (!allPixOk)
671         {
672             auto &testLog = m_context.getTestContext().getLog();
673             testLog << tcu::TestLog::Image("ColorBuffer", "Result color buffer", colorPixels);
674             testLog << tcu::TestLog::Image("ErrorMask", "Error mask with errors marked in red", errorMask);
675             return tcu::TestStatus::fail("Fail: color buffer with unexpected values; check logged images");
676         }
677     }
678 
679     return tcu::TestStatus::pass("Pass");
680 }
681 
682 } // namespace
683 
createFragSideEffectsTests(tcu::TestContext & testCtx)684 tcu::TestCaseGroup *createFragSideEffectsTests(tcu::TestContext &testCtx)
685 {
686     de::MovePtr<tcu::TestCaseGroup> fragSideEffectsGroup(new tcu::TestCaseGroup(testCtx, "frag_side_effects"));
687 
688     const tcu::Vec4 kDefaultClearColor(0.0f, 0.0f, 0.0f, 1.0f);
689     const tcu::Vec4 kDefaultDrawColor(0.0f, 0.0f, 1.0f, 1.0f);
690     const auto kDefaultDepthBoundsParams = tcu::Nothing;
691 
692     static const struct
693     {
694         bool colorAtEnd;
695         std::string name;
696     } kColorOrders[] = {
697         // Fragment shader output assignment at the beginning of the shader
698         {false, "color_at_beginning"},
699         // Fragment shader output assignment at the end of the shader
700         {true, "color_at_end"},
701     };
702 
703     for (int i = 0; i < DE_LENGTH_OF_ARRAY(kColorOrders); ++i)
704     {
705         de::MovePtr<tcu::TestCaseGroup> colorOrderGroup(new tcu::TestCaseGroup(testCtx, kColorOrders[i].name.c_str()));
706         const bool colorAtEnd = kColorOrders[i].colorAtEnd;
707 
708         {
709             TestParams params(CaseType::KILL, kDefaultClearColor, kDefaultDrawColor, colorAtEnd,
710                               kDefaultDepthBoundsParams);
711             // OpKill after SSBO write
712             colorOrderGroup->addChild(new FragSideEffectsTestCase(testCtx, "kill", params));
713         }
714         {
715             TestParams params(CaseType::DEMOTE, kDefaultClearColor, kDefaultDrawColor, colorAtEnd,
716                               kDefaultDepthBoundsParams);
717             // OpDemoteToHelperInvocation after SSBO write
718             colorOrderGroup->addChild(new FragSideEffectsTestCase(testCtx, "demote", params));
719         }
720         {
721             TestParams params(CaseType::TERMINATE_INVOCATION, kDefaultClearColor, kDefaultDrawColor, colorAtEnd,
722                               kDefaultDepthBoundsParams);
723             // OpTerminateInvocation after SSBO write
724             colorOrderGroup->addChild(new FragSideEffectsTestCase(testCtx, "terminate_invocation", params));
725         }
726         {
727             TestParams params(CaseType::SAMPLE_MASK_BEFORE, kDefaultClearColor, kDefaultDrawColor, colorAtEnd,
728                               kDefaultDepthBoundsParams);
729             // Set sample mask to zero before SSBO write
730             colorOrderGroup->addChild(new FragSideEffectsTestCase(testCtx, "sample_mask_before", params));
731         }
732         {
733             TestParams params(CaseType::SAMPLE_MASK_AFTER, kDefaultClearColor, kDefaultDrawColor, colorAtEnd,
734                               kDefaultDepthBoundsParams);
735             // Set sample mask to zero after SSBO write
736             colorOrderGroup->addChild(new FragSideEffectsTestCase(testCtx, "sample_mask_after", params));
737         }
738         {
739             TestParams params(CaseType::STENCIL_NEVER, kDefaultClearColor, kDefaultDrawColor, colorAtEnd,
740                               kDefaultDepthBoundsParams);
741             // SSBO write with stencil test never passes
742             colorOrderGroup->addChild(new FragSideEffectsTestCase(testCtx, "stencil_never", params));
743         }
744         {
745             TestParams params(CaseType::DEPTH_NEVER, kDefaultClearColor, kDefaultDrawColor, colorAtEnd,
746                               kDefaultDepthBoundsParams);
747             // SSBO write with depth test never passes
748             colorOrderGroup->addChild(new FragSideEffectsTestCase(testCtx, "depth_never", params));
749         }
750         {
751             const tcu::Vec4 drawColor(kDefaultDrawColor.x(), kDefaultDrawColor.y(), kDefaultDrawColor.z(), 0.0f);
752             {
753                 TestParams params(CaseType::ALPHA_COVERAGE_BEFORE, kDefaultClearColor, drawColor, colorAtEnd,
754                                   kDefaultDepthBoundsParams);
755                 // Enable alpha coverage and draw with alpha zero before SSBO write
756                 colorOrderGroup->addChild(new FragSideEffectsTestCase(testCtx, "alpha_coverage_before", params));
757             }
758             {
759                 TestParams params(CaseType::ALPHA_COVERAGE_AFTER, kDefaultClearColor, drawColor, colorAtEnd,
760                                   kDefaultDepthBoundsParams);
761                 // Enable alpha coverage and draw with alpha zero after SSBO write
762                 colorOrderGroup->addChild(new FragSideEffectsTestCase(testCtx, "alpha_coverage_after", params));
763             }
764         }
765         {
766             DepthBoundsParameters depthBoundsParams = {0.25f, 0.5f, 0.75f}; // min, max, draw depth.
767             TestParams params(CaseType::DEPTH_BOUNDS, kDefaultClearColor, kDefaultDrawColor, colorAtEnd,
768                               tcu::just(depthBoundsParams));
769             // SSBO write with depth bounds test failing
770             colorOrderGroup->addChild(new FragSideEffectsTestCase(testCtx, "depth_bounds", params));
771         }
772 
773         fragSideEffectsGroup->addChild(colorOrderGroup.release());
774     }
775 
776     return fragSideEffectsGroup.release();
777 }
778 
779 } // namespace rasterization
780 } // namespace vkt
781