1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2021 The Khronos Group Inc.
6  * Copyright (c) 2023 LunarG, Inc.
7  * Copyright (c) 2023 Nintendo
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 Tests for Color Write Enable
24 *//*--------------------------------------------------------------------*/
25 
26 #include "vktPipelineColorWriteEnableTests.hpp"
27 #include "vktPipelineImageUtil.hpp"
28 #include "vktTestCase.hpp"
29 
30 #include "vkDefs.hpp"
31 #include "vkTypeUtil.hpp"
32 #include "vkQueryUtil.hpp"
33 #include "vkObjUtil.hpp"
34 #include "vkBufferWithMemory.hpp"
35 #include "vkImageWithMemory.hpp"
36 #include "vkBarrierUtil.hpp"
37 #include "vkBuilderUtil.hpp"
38 #include "vkCmdUtil.hpp"
39 #include "vkImageUtil.hpp"
40 
41 #include "tcuVector.hpp"
42 #include "tcuMaybe.hpp"
43 #include "tcuTestLog.hpp"
44 #include "tcuVectorUtil.hpp"
45 
46 #include "deUniquePtr.hpp"
47 #include "deStringUtil.hpp"
48 
49 #include <vector>
50 #include <sstream>
51 #include <algorithm>
52 #include <utility>
53 #include <iterator>
54 #include <string>
55 #include <limits>
56 #include <memory>
57 #include <functional>
58 
59 namespace vkt
60 {
61 namespace pipeline
62 {
63 
64 namespace
65 {
66 
67 // Framebuffer size.
68 constexpr uint32_t kFramebufferWidth  = 64u;
69 constexpr uint32_t kFramebufferHeight = 64u;
70 
71 // Image formats.
72 constexpr vk::VkFormat kColorFormat = vk::VK_FORMAT_R8G8B8A8_UNORM;
73 const tcu::Vec4 kColorThreshold(0.005f); // 1/255 < 0.005 < 2/255.
74 
75 constexpr uint32_t kNumColorAttachments = 3u;
76 
77 const vk::VkFormat kDepthStencilFormats[] = {vk::VK_FORMAT_D32_SFLOAT_S8_UINT, vk::VK_FORMAT_D24_UNORM_S8_UINT};
78 
79 constexpr auto kCoordsSize = static_cast<uint32_t>(2 * sizeof(float));
80 
81 using Bool32Vec = std::vector<vk::VkBool32>;
82 
83 // Generic, to be used with any state than can be set statically and, as an option, dynamically.
84 template <typename T>
85 struct StaticAndDynamicPair
86 {
87     T staticValue;
88     tcu::Maybe<T> dynamicValue;
89 
90     // Helper constructor to set a static value and no dynamic value.
StaticAndDynamicPairvkt::pipeline::__anon06b7d4690111::StaticAndDynamicPair91     StaticAndDynamicPair(const T &value) : staticValue(value), dynamicValue(tcu::Nothing)
92     {
93     }
94 
95     // Helper constructor to set both.
StaticAndDynamicPairvkt::pipeline::__anon06b7d4690111::StaticAndDynamicPair96     StaticAndDynamicPair(const T &sVal, const T &dVal) : staticValue(sVal), dynamicValue(tcu::just<T>(dVal))
97     {
98     }
99 
100     // If the dynamic value is present, swap static and dynamic values.
swapValuesvkt::pipeline::__anon06b7d4690111::StaticAndDynamicPair101     void swapValues(void)
102     {
103         if (!dynamicValue)
104             return;
105         std::swap(staticValue, dynamicValue.get());
106     }
107 };
108 
109 const tcu::Vec4 kDefaultTriangleColor(0.0f, 0.0f, 1.0f, 1.0f); // Opaque blue.
110 const tcu::Vec4 kDefaultClearColor(0.0f, 0.0f, 0.0f, 1.0f);    // Opaque black.
111 
112 struct MeshParams
113 {
114     tcu::Vec4 color;
115     float depth;
116     float scaleX;
117     float scaleY;
118     float offsetX;
119     float offsetY;
120 
MeshParamsvkt::pipeline::__anon06b7d4690111::MeshParams121     MeshParams(const tcu::Vec4 &color_ = kDefaultTriangleColor, float depth_ = 0.0f, float scaleX_ = 1.0f,
122                float scaleY_ = 1.0f, float offsetX_ = 0.0f, float offsetY_ = 0.0f)
123         : color(color_)
124         , depth(depth_)
125         , scaleX(scaleX_)
126         , scaleY(scaleY_)
127         , offsetX(offsetX_)
128         , offsetY(offsetY_)
129     {
130     }
131 };
132 
133 enum class SequenceOrdering
134 {
135     CMD_BUFFER_START = 0, // Set state at the start of the command buffer.
136     BEFORE_DRAW      = 1, // After binding dynamic pipeline and just before drawing.
137     BETWEEN_PIPELINES =
138         2, // After a static state pipeline has been bound but before the dynamic state pipeline has been bound.
139     AFTER_PIPELINES    = 3, // After a static state pipeline and a second dynamic state pipeline have been bound.
140     BEFORE_GOOD_STATIC = 4, // Before a static state pipeline with the correct values has been bound.
141     TWO_DRAWS_DYNAMIC =
142         5, // Bind bad static pipeline and draw, followed by binding correct dynamic pipeline and drawing again.
143     TWO_DRAWS_STATIC =
144         6, // Bind bad dynamic pipeline and draw, followed by binding correct static pipeline and drawing again.
145 };
146 
147 struct TestConfig
148 {
149     vk::PipelineConstructionType pipelineConstructionType;
150 
151     // Main sequence ordering.
152     SequenceOrdering sequenceOrdering;
153 
154     // Drawing parameters.
155     MeshParams meshParams;
156 
157     // Clearing parameters for the framebuffer.
158     tcu::Vec4 clearColorValue;
159     float clearDepthValue;
160 
161     // Channels to enable
162     tcu::BVec4 channelMask;
163 
164     // Expected output in the attachments.
165     std::vector<tcu::Vec4> expectedColor;
166     float expectedDepth;
167 
168     // Static and dynamic pipeline configuration.
169     StaticAndDynamicPair<Bool32Vec> colorWriteEnableConfig;
170 
171     // Sane defaults.
TestConfigvkt::pipeline::__anon06b7d4690111::TestConfig172     TestConfig(vk::PipelineConstructionType constructionType, SequenceOrdering ordering)
173         : pipelineConstructionType(constructionType)
174         , sequenceOrdering(ordering)
175         , clearColorValue(kDefaultClearColor)
176         , clearDepthValue(1.0f)
177         , expectedColor(kNumColorAttachments, kDefaultTriangleColor)
178         , expectedDepth(1.0f)
179         , colorWriteEnableConfig(Bool32Vec(1u, VK_TRUE))
180         , m_swappedValues(false)
181     {
182     }
183 
184     // Returns true if we should use the static and dynamic values exchanged.
185     // This makes the static part of the pipeline have the actual expected values.
isReversedvkt::pipeline::__anon06b7d4690111::TestConfig186     bool isReversed() const
187     {
188         return (sequenceOrdering == SequenceOrdering::BEFORE_GOOD_STATIC ||
189                 sequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC);
190     }
191 
192     // Swaps static and dynamic configuration values.
swapValuesvkt::pipeline::__anon06b7d4690111::TestConfig193     void swapValues()
194     {
195         colorWriteEnableConfig.swapValues();
196         m_swappedValues = !m_swappedValues;
197     }
198 
199     // Returns the number of iterations when recording commands.
numIterationsvkt::pipeline::__anon06b7d4690111::TestConfig200     uint32_t numIterations() const
201     {
202         uint32_t iterations = 0u;
203 
204         switch (sequenceOrdering)
205         {
206         case SequenceOrdering::TWO_DRAWS_DYNAMIC:
207         case SequenceOrdering::TWO_DRAWS_STATIC:
208             iterations = 2u;
209             break;
210         default:
211             iterations = 1u;
212             break;
213         }
214 
215         return iterations;
216     }
217 
218 private:
219     // Color Write Enable cases as created by createColorWriteEnableTests() are based on the assumption that, when a state
220     // has a static and a dynamic value configured at the same time, the static value is wrong and the dynamic value will give
221     // expected results. That's appropriate for most test variants, but in some others we want to reverse the situation: a dynamic
222     // pipeline with wrong values and a static one with good values.
223     //
224     // Instead of modifying how tests are created, we use isReversed() and swapValues() above, allowing us to swap static and
225     // dynamic values and to know if we should do it for a given test case. However, we need to know were the good value is at any
226     // given point in time in order to correctly answer some questions while running the test. m_swappedValues tracks that state.
227     bool m_swappedValues;
228 };
229 
230 struct PushConstants
231 {
232     tcu::Vec4 triangleColor;
233     float meshDepth;
234     float scaleX;
235     float scaleY;
236     float offsetX;
237     float offsetY;
238 };
239 
240 class ColorWriteEnableTest : public vkt::TestCase
241 {
242 public:
243     ColorWriteEnableTest(tcu::TestContext &testCtx, const std::string &name, const TestConfig &testConfig);
~ColorWriteEnableTest(void)244     virtual ~ColorWriteEnableTest(void)
245     {
246     }
247 
248     virtual void checkSupport(Context &context) const;
249     virtual void initPrograms(vk::SourceCollections &programCollection) const;
250     virtual TestInstance *createInstance(Context &context) const;
251 
252 private:
253     TestConfig m_testConfig;
254 };
255 
256 class ColorWriteEnableInstance : public vkt::TestInstance
257 {
258 public:
259     ColorWriteEnableInstance(Context &context, const TestConfig &testConfig);
~ColorWriteEnableInstance(void)260     virtual ~ColorWriteEnableInstance(void)
261     {
262     }
263 
264     virtual tcu::TestStatus iterate(void);
265 
266 private:
267     TestConfig m_testConfig;
268 };
269 
ColorWriteEnableTest(tcu::TestContext & testCtx,const std::string & name,const TestConfig & testConfig)270 ColorWriteEnableTest::ColorWriteEnableTest(tcu::TestContext &testCtx, const std::string &name,
271                                            const TestConfig &testConfig)
272     : vkt::TestCase(testCtx, name)
273     , m_testConfig(testConfig)
274 {
275 }
276 
checkSupport(Context & context) const277 void ColorWriteEnableTest::checkSupport(Context &context) const
278 {
279     const auto &vki           = context.getInstanceInterface();
280     const auto physicalDevice = context.getPhysicalDevice();
281 
282     // This is always required.
283     context.requireDeviceFunctionality("VK_EXT_color_write_enable");
284 
285     // Check color image format support (depth/stencil will be chosen at runtime).
286     const vk::VkFormatFeatureFlags kColorFeatures =
287         (vk::VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | vk::VK_FORMAT_FEATURE_TRANSFER_SRC_BIT);
288     const auto colorProperties = vk::getPhysicalDeviceFormatProperties(vki, physicalDevice, kColorFormat);
289 
290     if ((colorProperties.optimalTilingFeatures & kColorFeatures) != kColorFeatures)
291         TCU_THROW(NotSupportedError, "Required color image features not supported");
292 
293     checkPipelineConstructionRequirements(vki, physicalDevice, m_testConfig.pipelineConstructionType);
294 }
295 
initPrograms(vk::SourceCollections & programCollection) const296 void ColorWriteEnableTest::initPrograms(vk::SourceCollections &programCollection) const
297 {
298     std::ostringstream pushSource;
299     pushSource << "layout(push_constant, std430) uniform PushConstantsBlock {\n"
300                << "    vec4  triangleColor;\n"
301                << "    float depthValue;\n"
302                << "    float scaleX;\n"
303                << "    float scaleY;\n"
304                << "    float offsetX;\n"
305                << "    float offsetY;\n"
306                << "} pushConstants;\n";
307 
308     std::ostringstream vertSource;
309     vertSource << "#version 450\n"
310                << pushSource.str() << "layout(location=0) in vec2 position;\n"
311                << "out gl_PerVertex\n"
312                << "{\n"
313                << "    vec4 gl_Position;\n"
314                << "};\n"
315                << "void main() {\n"
316                << "    vec2 vertexCoords = position;\n"
317                << "    gl_Position = vec4(vertexCoords.x * pushConstants.scaleX + pushConstants.offsetX, "
318                   "vertexCoords.y * pushConstants.scaleY + pushConstants.offsetY, pushConstants.depthValue, 1.0);\n"
319                << "}\n";
320 
321     std::ostringstream fragOutputs;
322     std::ostringstream colorWrite;
323     for (uint32_t i = 0u; i < kNumColorAttachments; ++i)
324     {
325         fragOutputs << "layout(location=" << i << ") out vec4 color" << i << ";\n";
326         colorWrite << "    color" << i << " = pushConstants.triangleColor * " << powf(0.5f, static_cast<float>(i))
327                    << ";\n";
328     }
329 
330     std::ostringstream fragSource;
331     fragSource << "#version 450\n"
332                << pushSource.str() << fragOutputs.str() << "void main() {\n"
333                << colorWrite.str() << "}\n";
334 
335     programCollection.glslSources.add("vert") << glu::VertexSource(vertSource.str());
336     programCollection.glslSources.add("frag") << glu::FragmentSource(fragSource.str());
337 }
338 
createInstance(Context & context) const339 TestInstance *ColorWriteEnableTest::createInstance(Context &context) const
340 {
341     return new ColorWriteEnableInstance(context, m_testConfig);
342 }
343 
ColorWriteEnableInstance(Context & context,const TestConfig & testConfig)344 ColorWriteEnableInstance::ColorWriteEnableInstance(Context &context, const TestConfig &testConfig)
345     : vkt::TestInstance(context)
346     , m_testConfig(testConfig)
347 {
348 }
349 
logErrors(tcu::TestLog & log,const std::string & setName,const std::string & setDesc,const tcu::ConstPixelBufferAccess & result,const tcu::ConstPixelBufferAccess & errorMask)350 void logErrors(tcu::TestLog &log, const std::string &setName, const std::string &setDesc,
351                const tcu::ConstPixelBufferAccess &result, const tcu::ConstPixelBufferAccess &errorMask)
352 {
353     log << tcu::TestLog::ImageSet(setName, setDesc) << tcu::TestLog::Image(setName + "Result", "Result image", result)
354         << tcu::TestLog::Image(setName + "ErrorMask", "Error mask with errors marked in red", errorMask)
355         << tcu::TestLog::EndImageSet;
356 }
357 
358 // Sets values for dynamic states if needed according to the test configuration.
setDynamicStates(const TestConfig & testConfig,const vk::DeviceInterface & vkd,vk::VkCommandBuffer cmdBuffer)359 void setDynamicStates(const TestConfig &testConfig, const vk::DeviceInterface &vkd, vk::VkCommandBuffer cmdBuffer)
360 {
361     if (testConfig.colorWriteEnableConfig.dynamicValue)
362     {
363         const auto &colorWriteEnables = testConfig.colorWriteEnableConfig.dynamicValue.get();
364         vkd.cmdSetColorWriteEnableEXT(cmdBuffer, static_cast<uint32_t>(colorWriteEnables.size()),
365                                       colorWriteEnables.data());
366     }
367 }
368 
iterate(void)369 tcu::TestStatus ColorWriteEnableInstance::iterate(void)
370 {
371     using ImageWithMemoryVec = std::vector<std::unique_ptr<vk::ImageWithMemory>>;
372     using ImageViewVec       = std::vector<vk::Move<vk::VkImageView>>;
373     using RenderPassVec      = std::vector<vk::RenderPassWrapper>;
374 
375     const auto &vki           = m_context.getInstanceInterface();
376     const auto &vkd           = m_context.getDeviceInterface();
377     const auto physicalDevice = m_context.getPhysicalDevice();
378     const auto device         = m_context.getDevice();
379     auto &allocator           = m_context.getDefaultAllocator();
380     const auto queue          = m_context.getUniversalQueue();
381     const auto queueIndex     = m_context.getUniversalQueueFamilyIndex();
382     auto &log                 = m_context.getTestContext().getLog();
383 
384     const auto kReversed         = m_testConfig.isReversed();
385     const auto kNumIterations    = m_testConfig.numIterations();
386     const auto kSequenceOrdering = m_testConfig.sequenceOrdering;
387 
388     const auto kFramebufferExtent = vk::makeExtent3D(kFramebufferWidth, kFramebufferHeight, 1u);
389     const vk::VkImageUsageFlags kColorUsage =
390         (vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
391     const vk::VkImageUsageFlags kDSUsage =
392         (vk::VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
393     const vk::VkFormatFeatureFlags kDSFeatures =
394         (vk::VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT | vk::VK_FORMAT_FEATURE_TRANSFER_SRC_BIT);
395 
396     // Choose depth/stencil format.
397     vk::VkFormat dsFormat = vk::VK_FORMAT_UNDEFINED;
398 
399     for (int formatIdx = 0; formatIdx < DE_LENGTH_OF_ARRAY(kDepthStencilFormats); ++formatIdx)
400     {
401         const auto dsProperties =
402             vk::getPhysicalDeviceFormatProperties(vki, physicalDevice, kDepthStencilFormats[formatIdx]);
403         if ((dsProperties.optimalTilingFeatures & kDSFeatures) == kDSFeatures)
404         {
405             dsFormat = kDepthStencilFormats[formatIdx];
406             break;
407         }
408     }
409 
410     // Note: Not Supported insted of Fail because the transfer feature is not mandatory.
411     if (dsFormat == vk::VK_FORMAT_UNDEFINED)
412         TCU_THROW(NotSupportedError, "Required depth/stencil image features not supported");
413     log << tcu::TestLog::Message << "Chosen depth/stencil format: " << dsFormat << tcu::TestLog::EndMessage;
414 
415     // Swap static and dynamic values in the test configuration so the static pipeline ends up with the expected values for cases
416     // where we will bind the static pipeline last before drawing.
417     if (kReversed)
418         m_testConfig.swapValues();
419 
420     // Create color and depth/stencil images.
421     ImageWithMemoryVec colorImages;
422     ImageWithMemoryVec dsImages;
423 
424     const vk::VkImageCreateInfo colorImageInfo = {
425         vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
426         nullptr,                                 // const void* pNext;
427         0u,                                      // VkImageCreateFlags flags;
428         vk::VK_IMAGE_TYPE_2D,                    // VkImageType imageType;
429         kColorFormat,                            // VkFormat format;
430         kFramebufferExtent,                      // VkExtent3D extent;
431         1u,                                      // uint32_t mipLevels;
432         1u,                                      // uint32_t arrayLayers;
433         vk::VK_SAMPLE_COUNT_1_BIT,               // VkSampleCountFlagBits samples;
434         vk::VK_IMAGE_TILING_OPTIMAL,             // VkImageTiling tiling;
435         kColorUsage,                             // VkImageUsageFlags usage;
436         vk::VK_SHARING_MODE_EXCLUSIVE,           // VkSharingMode sharingMode;
437         1u,                                      // uint32_t queueFamilyIndexCount;
438         &queueIndex,                             // const uint32_t* pQueueFamilyIndices;
439         vk::VK_IMAGE_LAYOUT_UNDEFINED,           // VkImageLayout initialLayout;
440     };
441     for (uint32_t i = 0u; i < kNumIterations * kNumColorAttachments; ++i)
442         colorImages.emplace_back(
443             new vk::ImageWithMemory(vkd, device, allocator, colorImageInfo, vk::MemoryRequirement::Any));
444 
445     const vk::VkImageCreateInfo dsImageInfo = {
446         vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
447         nullptr,                                 // const void* pNext;
448         0u,                                      // VkImageCreateFlags flags;
449         vk::VK_IMAGE_TYPE_2D,                    // VkImageType imageType;
450         dsFormat,                                // VkFormat format;
451         kFramebufferExtent,                      // VkExtent3D extent;
452         1u,                                      // uint32_t mipLevels;
453         1u,                                      // uint32_t arrayLayers;
454         vk::VK_SAMPLE_COUNT_1_BIT,               // VkSampleCountFlagBits samples;
455         vk::VK_IMAGE_TILING_OPTIMAL,             // VkImageTiling tiling;
456         kDSUsage,                                // VkImageUsageFlags usage;
457         vk::VK_SHARING_MODE_EXCLUSIVE,           // VkSharingMode sharingMode;
458         1u,                                      // uint32_t queueFamilyIndexCount;
459         &queueIndex,                             // const uint32_t* pQueueFamilyIndices;
460         vk::VK_IMAGE_LAYOUT_UNDEFINED,           // VkImageLayout initialLayout;
461     };
462     for (uint32_t i = 0u; i < kNumIterations; ++i)
463         dsImages.emplace_back(new vk::ImageWithMemory(vkd, device, allocator, dsImageInfo, vk::MemoryRequirement::Any));
464 
465     const auto colorSubresourceRange = vk::makeImageSubresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
466     const auto dsSubresourceRange    = vk::makeImageSubresourceRange(
467         (vk::VK_IMAGE_ASPECT_DEPTH_BIT | vk::VK_IMAGE_ASPECT_STENCIL_BIT), 0u, 1u, 0u, 1u);
468 
469     ImageViewVec colorImageViews;
470     ImageViewVec dsImageViews;
471 
472     for (const auto &img : colorImages)
473         colorImageViews.emplace_back(
474             vk::makeImageView(vkd, device, img->get(), vk::VK_IMAGE_VIEW_TYPE_2D, kColorFormat, colorSubresourceRange));
475 
476     for (const auto &img : dsImages)
477         dsImageViews.emplace_back(
478             vk::makeImageView(vkd, device, img->get(), vk::VK_IMAGE_VIEW_TYPE_2D, dsFormat, dsSubresourceRange));
479 
480     // Vertex buffer.
481     // Full-screen triangle fan with 6 vertices.
482     //
483     // 4        3        2
484     //  +-------+-------+
485     //  |X      X      X|
486     //  | X     X     X |
487     //  |  X    X    X  |
488     //  |   X   X   X   |
489     //  |    X  X  X    |
490     //  |     X X X     |
491     //  |      XXX      |
492     //  +-------+-------+
493     // 5        0        1
494     std::vector<float> vertices = {
495         0.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 0.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f,
496     };
497 
498     const auto vertDataSize = vertices.size() * sizeof(float);
499     const auto vertBufferInfo =
500         vk::makeBufferCreateInfo(static_cast<vk::VkDeviceSize>(vertDataSize), vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
501     vk::BufferWithMemory vertBuffer(vkd, device, allocator, vertBufferInfo, vk::MemoryRequirement::HostVisible);
502     auto &alloc = vertBuffer.getAllocation();
503 
504     deMemcpy(reinterpret_cast<char *>(alloc.getHostPtr()), vertices.data(), vertDataSize);
505     vk::flushAlloc(vkd, device, alloc);
506 
507     // Descriptor set layout.
508     vk::DescriptorSetLayoutBuilder layoutBuilder;
509     const auto descriptorSetLayout = layoutBuilder.build(vkd, device);
510 
511     // Pipeline layout.
512     vk::VkShaderStageFlags pushConstantStageFlags = (vk::VK_SHADER_STAGE_VERTEX_BIT | vk::VK_SHADER_STAGE_FRAGMENT_BIT);
513 
514     const vk::VkPushConstantRange pushConstantRange = {
515         pushConstantStageFlags,                       // VkShaderStageFlags stageFlags;
516         0u,                                           // uint32_t offset;
517         static_cast<uint32_t>(sizeof(PushConstants)), // uint32_t size;
518     };
519 
520     const vk::VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
521         vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
522         nullptr,                                           // const void* pNext;
523         0u,                                                // VkPipelineLayoutCreateFlags flags;
524         1u,                                                // uint32_t setLayoutCount;
525         &descriptorSetLayout.get(),                        // const VkDescriptorSetLayout* pSetLayouts;
526         1u,                                                // uint32_t pushConstantRangeCount;
527         &pushConstantRange,                                // const VkPushConstantRange* pPushConstantRanges;
528     };
529     const vk::PipelineLayoutWrapper pipelineLayout(m_testConfig.pipelineConstructionType, vkd, device,
530                                                    &pipelineLayoutCreateInfo);
531 
532     // Render pass with single subpass.
533     std::vector<vk::VkAttachmentReference> colorAttachmentReference;
534     for (uint32_t i = 0u; i < kNumColorAttachments; ++i)
535     {
536         colorAttachmentReference.push_back(vk::VkAttachmentReference{
537             i,                                           // uint32_t attachment;
538             vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout;
539         });
540     }
541 
542     const vk::VkAttachmentReference dsAttachmentReference = {
543         kNumColorAttachments,                                 // uint32_t attachment;
544         vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout layout;
545     };
546 
547     const vk::VkSubpassDescription subpassDescription = {
548         0u,                                  // VkSubpassDescriptionFlags flags;
549         vk::VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
550         0u,                                  // uint32_t inputAttachmentCount;
551         nullptr,                             // const VkAttachmentReference* pInputAttachments;
552         kNumColorAttachments,                // uint32_t colorAttachmentCount;
553         colorAttachmentReference.data(),     // const VkAttachmentReference* pColorAttachments;
554         nullptr,                             // const VkAttachmentReference* pResolveAttachments;
555         &dsAttachmentReference,              // const VkAttachmentReference* pDepthStencilAttachment;
556         0u,                                  // uint32_t preserveAttachmentCount;
557         nullptr,                             // const uint32_t* pPreserveAttachments;
558     };
559 
560     std::vector<vk::VkAttachmentDescription> attachmentDescriptions(
561         kNumColorAttachments,
562         vk::VkAttachmentDescription{
563             0u,                                           // VkAttachmentDescriptionFlags flags;
564             kColorFormat,                                 // VkFormat format;
565             vk::VK_SAMPLE_COUNT_1_BIT,                    // VkSampleCountFlagBits samples;
566             vk::VK_ATTACHMENT_LOAD_OP_CLEAR,              // VkAttachmentLoadOp loadOp;
567             vk::VK_ATTACHMENT_STORE_OP_STORE,             // VkAttachmentStoreOp storeOp;
568             vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,          // VkAttachmentLoadOp stencilLoadOp;
569             vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,         // VkAttachmentStoreOp stencilStoreOp;
570             vk::VK_IMAGE_LAYOUT_UNDEFINED,                // VkImageLayout initialLayout;
571             vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout;
572         });
573 
574     attachmentDescriptions.push_back(vk::VkAttachmentDescription{
575         0u,                                                   // VkAttachmentDescriptionFlags flags;
576         dsFormat,                                             // VkFormat format;
577         vk::VK_SAMPLE_COUNT_1_BIT,                            // VkSampleCountFlagBits samples;
578         vk::VK_ATTACHMENT_LOAD_OP_CLEAR,                      // VkAttachmentLoadOp loadOp;
579         vk::VK_ATTACHMENT_STORE_OP_STORE,                     // VkAttachmentStoreOp storeOp;
580         vk::VK_ATTACHMENT_LOAD_OP_CLEAR,                      // VkAttachmentLoadOp stencilLoadOp;
581         vk::VK_ATTACHMENT_STORE_OP_STORE,                     // VkAttachmentStoreOp stencilStoreOp;
582         vk::VK_IMAGE_LAYOUT_UNDEFINED,                        // VkImageLayout initialLayout;
583         vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout;
584     });
585 
586     const vk::VkRenderPassCreateInfo renderPassCreateInfo = {
587         vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,        // VkStructureType sType;
588         nullptr,                                              // const void* pNext;
589         0u,                                                   // VkRenderPassCreateFlags flags;
590         static_cast<uint32_t>(attachmentDescriptions.size()), // uint32_t attachmentCount;
591         attachmentDescriptions.data(),                        // const VkAttachmentDescription* pAttachments;
592         1u,                                                   // uint32_t subpassCount;
593         &subpassDescription,                                  // const VkSubpassDescription* pSubpasses;
594         0u,                                                   // uint32_t dependencyCount;
595         nullptr,                                              // const VkSubpassDependency* pDependencies;
596     };
597 
598     // Framebuffers.
599     RenderPassVec framebuffers;
600 
601     DE_ASSERT(colorImageViews.size() == dsImageViews.size() * kNumColorAttachments);
602     for (size_t imgIdx = 0; imgIdx < dsImageViews.size(); ++imgIdx)
603     {
604         std::vector<vk::VkImage> images;
605         std::vector<vk::VkImageView> attachments;
606         for (uint32_t i = 0u; i < kNumColorAttachments; ++i)
607         {
608             images.push_back(colorImages[imgIdx * kNumColorAttachments + i].get()->get());
609             attachments.push_back(colorImageViews[imgIdx * kNumColorAttachments + i].get());
610         }
611 
612         images.push_back(**(dsImages[imgIdx]));
613         attachments.push_back(dsImageViews[imgIdx].get());
614 
615         framebuffers.emplace_back(
616             vk::RenderPassWrapper(m_testConfig.pipelineConstructionType, vkd, device, &renderPassCreateInfo));
617 
618         const vk::VkFramebufferCreateInfo framebufferCreateInfo = {
619             vk::VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
620             nullptr,                                       // const void* pNext;
621             0u,                                            // VkFramebufferCreateFlags flags;
622             framebuffers[imgIdx].get(),                    // VkRenderPass renderPass;
623             static_cast<uint32_t>(attachments.size()),     // uint32_t attachmentCount;
624             attachments.data(),                            // const VkImageView* pAttachments;
625             kFramebufferWidth,                             // uint32_t width;
626             kFramebufferHeight,                            // uint32_t height;
627             1u,                                            // uint32_t layers;
628         };
629 
630         framebuffers[imgIdx].createFramebuffer(vkd, device, &framebufferCreateInfo, images);
631     }
632 
633     // Shader modules.
634     const auto vertModule = vk::ShaderWrapper(vkd, device, m_context.getBinaryCollection().get("vert"), 0u);
635     const auto fragModule = vk::ShaderWrapper(vkd, device, m_context.getBinaryCollection().get("frag"), 0u);
636 
637     // Input state.
638     const auto vertexBinding = vk::makeVertexInputBindingDescription(0u, kCoordsSize, vk::VK_VERTEX_INPUT_RATE_VERTEX);
639     const std::vector<vk::VkVertexInputAttributeDescription> vertexAttributes = {
640         vk::makeVertexInputAttributeDescription(0u, 0u, vk::VK_FORMAT_R32G32_SFLOAT, 0u)};
641 
642     const vk::VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = {
643         vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
644         nullptr,                                                       // const void* pNext;
645         0u,                                                            // VkPipelineVertexInputStateCreateFlags flags;
646         1u,                                                            // uint32_t vertexBindingDescriptionCount;
647         &vertexBinding, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
648         static_cast<uint32_t>(vertexAttributes.size()), // uint32_t vertexAttributeDescriptionCount;
649         vertexAttributes.data(), // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
650     };
651 
652     // Input assembly.
653     const vk::VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo = {
654         vk::VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType;
655         nullptr,                                                         // const void* pNext;
656         0u,                                     // VkPipelineInputAssemblyStateCreateFlags flags;
657         vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN, // VkPrimitiveTopology topology;
658         VK_FALSE,                               // VkBool32 primitiveRestartEnable;
659     };
660 
661     // Viewport state.
662     const std::vector<vk::VkViewport> viewport{vk::makeViewport(kFramebufferWidth, kFramebufferHeight)};
663     const std::vector<vk::VkRect2D> scissor{vk::makeRect2D(kFramebufferWidth, kFramebufferHeight)};
664 
665     // Rasterization state.
666     const vk::VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo = {
667         vk::VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
668         nullptr,                                                        // const void* pNext;
669         0u,                                  // VkPipelineRasterizationStateCreateFlags flags;
670         VK_FALSE,                            // VkBool32 depthClampEnable;
671         VK_FALSE,                            // VkBool32 rasterizerDiscardEnable;
672         vk::VK_POLYGON_MODE_FILL,            // VkPolygonMode polygonMode;
673         vk::VK_CULL_MODE_NONE,               // VkCullModeFlags cullMode;
674         vk::VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace;
675         VK_FALSE,                            // VkBool32 depthBiasEnable;
676         0.0f,                                // float depthBiasConstantFactor;
677         0.0f,                                // float depthBiasClamp;
678         0.0f,                                // float depthBiasSlopeFactor;
679         1.0f,                                // float lineWidth;
680     };
681 
682     // Multisample state.
683     const vk::VkPipelineMultisampleStateCreateInfo multisampleStateCreateInfo = {
684         vk::VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
685         nullptr,                                                      // const void* pNext;
686         0u,                                                           // VkPipelineMultisampleStateCreateFlags flags;
687         vk::VK_SAMPLE_COUNT_1_BIT,                                    // VkSampleCountFlagBits rasterizationSamples;
688         VK_FALSE,                                                     // VkBool32 sampleShadingEnable;
689         0.0f,                                                         // float minSampleShading;
690         nullptr,                                                      // const VkSampleMask* pSampleMask;
691         VK_FALSE,                                                     // VkBool32 alphaToCoverageEnable;
692         VK_FALSE,                                                     // VkBool32 alphaToOneEnable;
693     };
694 
695     // Depth/stencil state.
696     const vk::VkStencilOpState stencil = {
697         vk::VK_STENCIL_OP_KEEP,   // VkStencilOp failOp;
698         vk::VK_STENCIL_OP_KEEP,   // VkStencilOp passOp;
699         vk::VK_STENCIL_OP_KEEP,   // VkStencilOp depthFailOp;
700         vk::VK_COMPARE_OP_ALWAYS, // VkCompareOp compareOp;
701         0xFFu,                    // uint32_t compareMask;
702         0xFFu,                    // uint32_t writeMask;
703         0u,                       // uint32_t reference;
704     };
705 
706     const vk::VkPipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo = {
707         vk::VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
708         nullptr,                                                        // const void* pNext;
709         0u,                                                             // VkPipelineDepthStencilStateCreateFlags flags;
710         VK_TRUE,                                                        // VkBool32 depthTestEnable;
711         VK_TRUE,                                                        // VkBool32 depthWriteEnable;
712         vk::VK_COMPARE_OP_LESS,                                         // VkCompareOp depthCompareOp;
713         VK_FALSE,                                                       // VkBool32 depthBoundsTestEnable;
714         VK_FALSE,                                                       // VkBool32 stencilTestEnable;
715         stencil,                                                        // VkStencilOpState front;
716         stencil,                                                        // VkStencilOpState back;
717         0.0f,                                                           // float minDepthBounds;
718         1.0f,                                                           // float maxDepthBounds;
719     };
720 
721     // Dynamic state. Here we will set all states which have a dynamic value.
722     std::vector<vk::VkDynamicState> dynamicStates;
723 
724     if (m_testConfig.colorWriteEnableConfig.dynamicValue)
725         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_COLOR_WRITE_ENABLE_EXT);
726 
727     const vk::VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo = {
728         vk::VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType;
729         nullptr,                                                  // const void* pNext;
730         0u,                                                       // VkPipelineDynamicStateCreateFlags flags;
731         static_cast<uint32_t>(dynamicStates.size()),              // uint32_t dynamicStateCount;
732         dynamicStates.data(),                                     // const VkDynamicState* pDynamicStates;
733     };
734 
735     std::vector<vk::VkPipelineColorBlendAttachmentState> colorBlendAttachmentState(
736         kNumColorAttachments,
737         vk::VkPipelineColorBlendAttachmentState{
738             VK_FALSE,                               // VkBool32                 blendEnable
739             vk::VK_BLEND_FACTOR_ZERO,               // VkBlendFactor            srcColorBlendFactor
740             vk::VK_BLEND_FACTOR_ZERO,               // VkBlendFactor            dstColorBlendFactor
741             vk::VK_BLEND_OP_ADD,                    // VkBlendOp                colorBlendOp
742             vk::VK_BLEND_FACTOR_ZERO,               // VkBlendFactor            srcAlphaBlendFactor
743             vk::VK_BLEND_FACTOR_ZERO,               // VkBlendFactor            dstAlphaBlendFactor
744             vk::VK_BLEND_OP_ADD,                    // VkBlendOp                alphaBlendOp
745             static_cast<vk::VkColorComponentFlags>( // VkColorComponentFlags    colorWriteMask
746                 (m_testConfig.channelMask.x() ? vk::VK_COLOR_COMPONENT_R_BIT : 0) |
747                 (m_testConfig.channelMask.y() ? vk::VK_COLOR_COMPONENT_G_BIT : 0) |
748                 (m_testConfig.channelMask.z() ? vk::VK_COLOR_COMPONENT_B_BIT : 0) |
749                 (m_testConfig.channelMask.w() ? vk::VK_COLOR_COMPONENT_A_BIT : 0))});
750 
751     const vk::VkPipelineColorWriteCreateInfoEXT colorWriteCreateInfo = {
752         vk::VK_STRUCTURE_TYPE_PIPELINE_COLOR_WRITE_CREATE_INFO_EXT, // VkStructureType sType;
753         nullptr,                                                    // const void* pNext;
754         kNumColorAttachments,                                       // uint32_t attachmentCount;
755         m_testConfig.colorWriteEnableConfig.staticValue.data()      // const VkBool32* pColorWriteEnables;
756     };
757 
758     const vk::VkPipelineColorBlendStateCreateInfo colorBlendStateCreateInfo = {
759         vk::VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType                               sType
760         &colorWriteCreateInfo,            // const void*                                   pNext
761         0u,                               // VkPipelineColorBlendStateCreateFlags          flags
762         VK_FALSE,                         // VkBool32                                      logicOpEnable
763         vk::VK_LOGIC_OP_CLEAR,            // VkLogicOp                                     logicOp
764         kNumColorAttachments,             // uint32_t                                      attachmentCount
765         colorBlendAttachmentState.data(), // const VkPipelineColorBlendAttachmentState*    pAttachments
766         {0.0f, 0.0f, 0.0f, 0.0f}          // float                                         blendConstants[4]
767     };
768 
769     vk::GraphicsPipelineWrapper staticPipeline(vki, vkd, physicalDevice, device, m_context.getDeviceExtensions(),
770                                                m_testConfig.pipelineConstructionType);
771     const bool bindStaticFirst   = (kSequenceOrdering == SequenceOrdering::BETWEEN_PIPELINES ||
772                                   kSequenceOrdering == SequenceOrdering::AFTER_PIPELINES ||
773                                   kSequenceOrdering == SequenceOrdering::TWO_DRAWS_DYNAMIC);
774     const bool useStaticPipeline = (bindStaticFirst || kReversed);
775 
776     // Create static pipeline when needed.
777     if (useStaticPipeline)
778     {
779         staticPipeline.setupVertexInputState(&vertexInputStateCreateInfo, &inputAssemblyStateCreateInfo)
780             .setupPreRasterizationShaderState(viewport, scissor, pipelineLayout, *framebuffers[0], 0u, vertModule,
781                                               &rasterizationStateCreateInfo)
782             .setupFragmentShaderState(pipelineLayout, *framebuffers[0], 0u, fragModule, &depthStencilStateCreateInfo,
783                                       &multisampleStateCreateInfo)
784             .setupFragmentOutputState(*framebuffers[0], 0u, &colorBlendStateCreateInfo, &multisampleStateCreateInfo)
785             .setMonolithicPipelineLayout(pipelineLayout)
786             .buildPipeline();
787     }
788 
789     // Create dynamic pipeline.
790     vk::GraphicsPipelineWrapper graphicsPipeline(vki, vkd, physicalDevice, device, m_context.getDeviceExtensions(),
791                                                  m_testConfig.pipelineConstructionType);
792     ;
793     graphicsPipeline.setDynamicState(&dynamicStateCreateInfo)
794         .setupVertexInputState(&vertexInputStateCreateInfo, &inputAssemblyStateCreateInfo)
795         .setupPreRasterizationShaderState(viewport, scissor, pipelineLayout, *framebuffers[0], 0u, vertModule,
796                                           &rasterizationStateCreateInfo)
797         .setupFragmentShaderState(pipelineLayout, *framebuffers[0], 0u, fragModule, &depthStencilStateCreateInfo,
798                                   &multisampleStateCreateInfo)
799         .setupFragmentOutputState(*framebuffers[0], 0u, &colorBlendStateCreateInfo, &multisampleStateCreateInfo)
800         .setMonolithicPipelineLayout(pipelineLayout)
801         .buildPipeline();
802 
803     // Command buffer.
804     const auto cmdPool = vk::makeCommandPool(vkd, device, queueIndex);
805     const auto cmdBufferPtr =
806         vk::allocateCommandBuffer(vkd, device, cmdPool.get(), vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
807     const auto cmdBuffer = cmdBufferPtr.get();
808 
809     // Clear values.
810     std::vector<vk::VkClearValue> clearValues;
811     auto colorClearValue = vk::makeClearValueColor(m_testConfig.clearColorValue);
812     for (uint32_t i = 0u; i < kNumColorAttachments; ++i)
813         clearValues.push_back(colorClearValue);
814     clearValues.push_back(vk::makeClearValueDepthStencil(m_testConfig.clearDepthValue, 0u));
815 
816     // Record command buffer.
817     vk::beginCommandBuffer(vkd, cmdBuffer);
818 
819     for (uint32_t iteration = 0u; iteration < kNumIterations; ++iteration)
820     {
821         // Maybe set dynamic state here.
822         if (kSequenceOrdering == SequenceOrdering::CMD_BUFFER_START)
823         {
824             setDynamicStates(m_testConfig, vkd, cmdBuffer);
825         }
826 
827         // Begin render pass.
828         framebuffers[iteration].begin(vkd, cmdBuffer, vk::makeRect2D(kFramebufferWidth, kFramebufferHeight),
829                                       static_cast<uint32_t>(clearValues.size()), clearValues.data());
830 
831         // Bind a static pipeline first if needed.
832         if (bindStaticFirst && iteration == 0u)
833         {
834             staticPipeline.bind(cmdBuffer);
835         }
836 
837         // Maybe set dynamic state here.
838         if (kSequenceOrdering == SequenceOrdering::BETWEEN_PIPELINES)
839         {
840             setDynamicStates(m_testConfig, vkd, cmdBuffer);
841         }
842 
843         // Bind dynamic pipeline.
844         if ((kSequenceOrdering != SequenceOrdering::TWO_DRAWS_DYNAMIC &&
845              kSequenceOrdering != SequenceOrdering::TWO_DRAWS_STATIC) ||
846             (kSequenceOrdering == SequenceOrdering::TWO_DRAWS_DYNAMIC && iteration > 0u) ||
847             (kSequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC && iteration == 0u))
848         {
849             graphicsPipeline.bind(cmdBuffer);
850         }
851 
852         if (kSequenceOrdering == SequenceOrdering::BEFORE_GOOD_STATIC ||
853             (kSequenceOrdering == SequenceOrdering::TWO_DRAWS_DYNAMIC && iteration > 0u) ||
854             (kSequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC && iteration == 0u))
855         {
856             setDynamicStates(m_testConfig, vkd, cmdBuffer);
857         }
858 
859         // Bind a static pipeline last if needed.
860         if (kSequenceOrdering == SequenceOrdering::BEFORE_GOOD_STATIC ||
861             (kSequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC && iteration > 0u))
862         {
863             staticPipeline.bind(cmdBuffer);
864         }
865 
866         // Push constants.
867         PushConstants pushConstants = {
868             m_testConfig.meshParams.color,   // tcu::Vec4 triangleColor;
869             m_testConfig.meshParams.depth,   // float meshDepth;
870             m_testConfig.meshParams.scaleX,  // float scaleX;
871             m_testConfig.meshParams.scaleY,  // float scaleY;
872             m_testConfig.meshParams.offsetX, // float offsetX;
873             m_testConfig.meshParams.offsetY, // float offsetY;
874         };
875         vkd.cmdPushConstants(cmdBuffer, pipelineLayout.get(), pushConstantStageFlags, 0u,
876                              static_cast<uint32_t>(sizeof(pushConstants)), &pushConstants);
877 
878         // Maybe set dynamic state here.
879         if (kSequenceOrdering == SequenceOrdering::BEFORE_DRAW ||
880             kSequenceOrdering == SequenceOrdering::AFTER_PIPELINES)
881         {
882             setDynamicStates(m_testConfig, vkd, cmdBuffer);
883         }
884 
885         // Bind vertex buffer and draw.
886         vk::VkDeviceSize offset = 0ull;
887         vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &vertBuffer.get(), &offset);
888         vkd.cmdDraw(cmdBuffer, 6u, 1u, 0u, 0u);
889 
890         framebuffers[iteration].end(vkd, cmdBuffer);
891     }
892 
893     vk::endCommandBuffer(vkd, cmdBuffer);
894 
895     // Submit commands.
896     vk::submitCommandsAndWait(vkd, device, queue, cmdBuffer);
897 
898     // Read result image aspects from the last used framebuffer.
899     const tcu::UVec2 renderSize(kFramebufferWidth, kFramebufferHeight);
900 
901     const int kWidth  = static_cast<int>(kFramebufferWidth);
902     const int kHeight = static_cast<int>(kFramebufferHeight);
903 
904     const tcu::Vec4 kGood(0.0f, 1.0f, 0.0f, 1.0f);
905     const tcu::Vec4 kBad(1.0f, 0.0f, 0.0f, 1.0f);
906 
907     const tcu::TextureFormat errorFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8);
908 
909     bool colorMatchAll = true;
910 
911     // Check expected values.
912     auto nextAttachmentImage = colorImages.end() - kNumColorAttachments;
913     for (uint32_t attachmentIndex = 0u; attachmentIndex < kNumColorAttachments;
914          ++attachmentIndex, ++nextAttachmentImage)
915     {
916         const auto colorBuffer = readColorAttachment(vkd, device, queue, queueIndex, allocator,
917                                                      (*nextAttachmentImage)->get(), kColorFormat, renderSize);
918         const auto colorAccess = colorBuffer->getAccess();
919 
920         tcu::TextureLevel colorError(errorFormat, kWidth, kHeight);
921         const auto colorErrorAccess = colorError.getAccess();
922 
923         bool colorMatch = true;
924 
925         for (int y = 0; y < kHeight; ++y)
926             for (int x = 0; x < kWidth; ++x)
927             {
928                 const auto colorPixel = colorAccess.getPixel(x, y);
929 
930                 bool match = tcu::boolAll(tcu::lessThan(
931                     tcu::absDiff(colorPixel, m_testConfig.expectedColor[attachmentIndex]), kColorThreshold));
932                 colorErrorAccess.setPixel((match ? kGood : kBad), x, y);
933                 if (!match)
934                     colorMatch = false;
935             }
936 
937         if (!colorMatch)
938         {
939             std::ostringstream desc;
940             desc << "Result color image and error mask for attachment #" << attachmentIndex;
941             logErrors(log, "Color", desc.str(), colorAccess, colorErrorAccess);
942             colorMatchAll = false;
943         }
944     }
945 
946     const auto depthBuffer =
947         readDepthAttachment(vkd, device, queue, queueIndex, allocator, dsImages.back()->get(), dsFormat, renderSize);
948     const auto depthAccess = depthBuffer->getAccess();
949     tcu::TextureLevel depthError(errorFormat, kWidth, kHeight);
950     const auto depthErrorAccess = depthError.getAccess();
951 
952     const auto minDepth = m_testConfig.expectedDepth - 1.0e-07f;
953     const auto maxDepth = m_testConfig.expectedDepth + 1.0e-07f;
954     bool depthMatch     = true;
955 
956     for (int y = 0; y < kHeight; ++y)
957         for (int x = 0; x < kWidth; ++x)
958         {
959             const auto depthPixel = depthAccess.getPixDepth(x, y);
960             bool match            = de::inRange(depthPixel, minDepth, maxDepth);
961             depthErrorAccess.setPixel((match ? kGood : kBad), x, y);
962             if (!match)
963                 depthMatch = false;
964         }
965 
966     if (!depthMatch)
967     {
968         logErrors(log, "Depth", "Result depth image and error mask", depthAccess, depthErrorAccess);
969     }
970 
971     if (!(colorMatchAll && depthMatch))
972     {
973         return tcu::TestStatus::fail("Incorrect value found in attachments; please check logged images");
974     }
975 
976     return tcu::TestStatus::pass("Pass");
977 }
978 
979 template <typename VectorType>
MaskVector(const VectorType & valueIfMaskIsFalse,const VectorType & valueIfMaskIsTrue,const std::vector<bool> & mask,bool inverse=false)980 VectorType MaskVector(const VectorType &valueIfMaskIsFalse, const VectorType &valueIfMaskIsTrue,
981                       const std::vector<bool> &mask, bool inverse = false)
982 {
983     DE_ASSERT(valueIfMaskIsFalse.size() == valueIfMaskIsTrue.size() && valueIfMaskIsFalse.size() == mask.size());
984 
985     VectorType ret(mask.size());
986 
987     for (size_t i = 0; i < mask.size(); ++i)
988     {
989         bool m = mask[i];
990         if (inverse)
991             m = !m;
992         ret[i] = m ? valueIfMaskIsTrue[i] : valueIfMaskIsFalse[i];
993     }
994 
995     return ret;
996 }
997 
ApplyChannelMask(std::vector<tcu::Vec4> & meshColors,const tcu::BVec4 & channelMask,const tcu::Vec4 & clearColor)998 void ApplyChannelMask(std::vector<tcu::Vec4> &meshColors, const tcu::BVec4 &channelMask, const tcu::Vec4 &clearColor)
999 {
1000     for (auto &&attachmentColor : meshColors)
1001         attachmentColor = tcu::Vec4(channelMask.x() ? attachmentColor.x() : clearColor.x(),
1002                                     channelMask.y() ? attachmentColor.y() : clearColor.y(),
1003                                     channelMask.z() ? attachmentColor.z() : clearColor.z(),
1004                                     channelMask.w() ? attachmentColor.w() : clearColor.w());
1005 }
1006 
AddSingleTestCaseStatic(const std::string & name,vk::PipelineConstructionType pipelineConstructionType,const std::vector<bool> mask,const tcu::BVec4 channelMask,bool inverse,tcu::TestCaseGroup * orderingGroup,tcu::TestContext & testCtx)1007 void AddSingleTestCaseStatic(const std::string &name, vk::PipelineConstructionType pipelineConstructionType,
1008                              const std::vector<bool> mask, const tcu::BVec4 channelMask, bool inverse,
1009                              tcu::TestCaseGroup *orderingGroup, tcu::TestContext &testCtx)
1010 {
1011     TestConfig config(pipelineConstructionType, SequenceOrdering::CMD_BUFFER_START);
1012 
1013     // Enable writes and expect the mesh color, or disable writes and expect the clear color.
1014 
1015     config.clearColorValue  = tcu::Vec4(0.25f, 0.5f, 0.75f, 0.5f);
1016     config.meshParams.color = tcu::Vec4(1.0f, 0.75f, 0.5f, 0.25f);
1017 
1018     const auto allVkFalse = Bool32Vec(kNumColorAttachments, VK_FALSE);
1019     const auto allVkTrue  = Bool32Vec(kNumColorAttachments, VK_TRUE);
1020 
1021     config.channelMask = channelMask;
1022 
1023     config.colorWriteEnableConfig.staticValue = MaskVector(allVkFalse, allVkTrue, mask, inverse);
1024 
1025     // Note colorWriteEnableConfig.dynamicValue is unset, defaults to an empty Maybe<T>
1026 
1027     std::vector<tcu::Vec4> meshColorsPerAttachment(kNumColorAttachments);
1028     meshColorsPerAttachment[0] = config.meshParams.color;
1029     for (uint32_t i = 1u; i < kNumColorAttachments; ++i)
1030         meshColorsPerAttachment[i] = meshColorsPerAttachment[i - 1] * 0.5f;
1031 
1032     std::vector<tcu::Vec4> clearColorsPerAttachment(kNumColorAttachments, config.clearColorValue);
1033 
1034     ApplyChannelMask(meshColorsPerAttachment, channelMask, config.clearColorValue);
1035 
1036     config.expectedColor = MaskVector(clearColorsPerAttachment, meshColorsPerAttachment, mask, inverse);
1037 
1038     // Depth should always be written even when color is not
1039     config.clearDepthValue  = 0.5f;
1040     config.meshParams.depth = 0.25f;
1041     config.expectedDepth    = 0.25f;
1042 
1043     orderingGroup->addChild(new ColorWriteEnableTest(testCtx, name, config));
1044 }
1045 
AddSingleTestCaseDynamic(const std::string & name,vk::PipelineConstructionType pipelineConstructionType,const std::vector<bool> mask,const tcu::BVec4 channelMask,bool inverse,tcu::TestCaseGroup * orderingGroup,tcu::TestContext & testCtx,SequenceOrdering ordering)1046 void AddSingleTestCaseDynamic(const std::string &name, vk::PipelineConstructionType pipelineConstructionType,
1047                               const std::vector<bool> mask, const tcu::BVec4 channelMask, bool inverse,
1048                               tcu::TestCaseGroup *orderingGroup, tcu::TestContext &testCtx, SequenceOrdering ordering)
1049 {
1050     TestConfig config(pipelineConstructionType, ordering);
1051 
1052     // Enable writes and expect the mesh color, or disable writes and expect the clear color.
1053 
1054     config.clearColorValue  = tcu::Vec4(0.25f, 0.5f, 0.75f, 0.5f);
1055     config.meshParams.color = tcu::Vec4(1.0f, 0.75f, 0.5f, 0.25f);
1056 
1057     const auto allVkFalse = Bool32Vec(kNumColorAttachments, VK_FALSE);
1058     const auto allVkTrue  = Bool32Vec(kNumColorAttachments, VK_TRUE);
1059 
1060     config.channelMask = channelMask;
1061 
1062     config.colorWriteEnableConfig.staticValue  = inverse ? allVkTrue : allVkFalse;
1063     config.colorWriteEnableConfig.dynamicValue = MaskVector(allVkFalse, allVkTrue, mask, inverse);
1064 
1065     std::vector<tcu::Vec4> meshColorsPerAttachment(kNumColorAttachments);
1066     meshColorsPerAttachment[0] = config.meshParams.color;
1067     for (uint32_t i = 1u; i < kNumColorAttachments; ++i)
1068         meshColorsPerAttachment[i] = meshColorsPerAttachment[i - 1] * 0.5f;
1069 
1070     std::vector<tcu::Vec4> clearColorsPerAttachment(kNumColorAttachments, config.clearColorValue);
1071 
1072     ApplyChannelMask(meshColorsPerAttachment, channelMask, config.clearColorValue);
1073 
1074     config.expectedColor = MaskVector(clearColorsPerAttachment, meshColorsPerAttachment, mask, inverse);
1075 
1076     // Depth should always be written even when color is not
1077     config.clearDepthValue  = 0.5f;
1078     config.meshParams.depth = 0.25f;
1079     config.expectedDepth    = 0.25f;
1080 
1081     orderingGroup->addChild(new ColorWriteEnableTest(testCtx, name, config));
1082 }
1083 
1084 } // anonymous namespace
1085 
1086 namespace
1087 {
1088 using namespace vk;
1089 using namespace tcu;
1090 
1091 struct TestParams
1092 {
1093     uint32_t width;
1094     uint32_t height;
1095     VkFormat format;
1096     uint32_t attachmentCount;
1097     uint32_t attachmentMore;
1098     bool setCweBeforePlBind;
1099     bool colorWriteEnables;
1100     PipelineConstructionType pct;
1101     bool selectOptimalBlendableFormat(const InstanceInterface &, VkPhysicalDevice);
1102 };
1103 
1104 class ColorWriteEnable2Test : public vkt::TestCase
1105 {
1106 public:
ColorWriteEnable2Test(TestContext & testCtx,const std::string & name,const TestParams & testParams)1107     ColorWriteEnable2Test(TestContext &testCtx, const std::string &name, const TestParams &testParams)
1108         : vkt::TestCase(testCtx, name)
1109         , m_params(testParams)
1110     {
1111     }
1112 
1113     virtual ~ColorWriteEnable2Test() = default;
1114 
1115     virtual void checkSupport(Context &context) const override;
1116     virtual void initPrograms(SourceCollections &programCollection) const override;
1117     virtual vkt::TestInstance *createInstance(Context &context) const override;
1118 
1119 private:
1120     mutable TestParams m_params;
1121 };
1122 
1123 class ColorWriteEnable2Instance : public vkt::TestInstance
1124 {
1125 public:
1126     typedef std::vector<VkBool32> ColorWriteEnables;
1127     struct Attachment
1128     {
1129         de::MovePtr<ImageWithMemory> image;
1130         Move<VkImageView> view;
1131         Attachment() = default;
1132         DE_UNUSED_FUNCTION Attachment(Attachment &&other);
1133     };
1134     struct Framebuffer
1135     {
1136         std::vector<Attachment> attachments;
1137         RenderPassWrapper framebuffer;
1138         Framebuffer() = default;
1139         Framebuffer(Framebuffer &&other);
1140     };
1141     struct GraphicsPipelineWrapperEx : public GraphicsPipelineWrapper
1142     {
GraphicsPipelineWrapperExvkt::pipeline::__anon06b7d4690211::ColorWriteEnable2Instance::GraphicsPipelineWrapperEx1143         GraphicsPipelineWrapperEx(const InstanceInterface &vki, const DeviceInterface &vkd,
1144                                   const VkPhysicalDevice physDev, const VkDevice dev,
1145                                   const std::vector<std::string> &exts, const PipelineConstructionType pct)
1146             : GraphicsPipelineWrapper(vki, vkd, physDev, dev, exts, pct)
1147             , m_isDynamicColorWriteEnable(false)
1148         {
1149         }
isDynamicColorWriteEnablevkt::pipeline::__anon06b7d4690211::ColorWriteEnable2Instance::GraphicsPipelineWrapperEx1150         bool isDynamicColorWriteEnable() const
1151         {
1152             return m_isDynamicColorWriteEnable;
1153         }
1154 
1155     private:
1156         friend class ColorWriteEnable2Instance;
1157         bool m_isDynamicColorWriteEnable;
1158     };
1159     ColorWriteEnable2Instance(Context &context, const TestParams &testParams);
1160     virtual ~ColorWriteEnable2Instance() = default;
1161 
1162     de::MovePtr<BufferWithMemory> createVerrtexBuffer() const;
1163     RenderPassWrapper createRenderPass(uint32_t colorAttachmentCount) const;
1164     Framebuffer createFramebuffer(uint32_t colorAttachmentCount) const;
1165     void setupAndBuildPipeline(GraphicsPipelineWrapperEx &owner, PipelineLayoutWrapper &pipelineLayout,
1166                                VkRenderPass renderPass, uint32_t colorAttachmentCount,
1167                                const ColorWriteEnables &colorWriteEnables, float blendComp, bool dynamic) const;
1168     virtual TestStatus iterate() override;
1169     tcu::TestStatus verifyAttachment(const uint32_t attachmentIndex, const uint32_t attachmentCount,
1170                                      const ConstPixelBufferAccess &attachmentContent,
1171                                      const ColorWriteEnables &colorWriteEnables, const Vec4 &background,
1172                                      const float blendComp) const;
1173 
1174 private:
1175     const TestParams m_params;
1176     const DeviceInterface &m_vkd;
1177     const VkDevice m_device;
1178     Allocator &m_allocator;
1179     const ShaderWrapper m_vertex;
1180     const ShaderWrapper m_fragment;
1181 };
1182 
Attachment(Attachment && other)1183 ColorWriteEnable2Instance::Attachment::Attachment(Attachment &&other)
1184     : image(std::move(other.image))
1185     , view(std::move(other.view))
1186 {
1187 }
Framebuffer(Framebuffer && other)1188 ColorWriteEnable2Instance::Framebuffer::Framebuffer(Framebuffer &&other)
1189     : attachments(std::move(other.attachments))
1190     , framebuffer(std::move(other.framebuffer))
1191 {
1192 }
1193 
selectOptimalBlendableFormat(const InstanceInterface & vk,VkPhysicalDevice dev)1194 bool TestParams::selectOptimalBlendableFormat(const InstanceInterface &vk, VkPhysicalDevice dev)
1195 {
1196     auto doesFormatMatch = [](const VkFormat fmt) -> bool
1197     {
1198         const auto tcuFmt = mapVkFormat(fmt);
1199         return tcuFmt.order == TextureFormat::ChannelOrder::RGBA || tcuFmt.order == TextureFormat::ChannelOrder::sRGBA;
1200     };
1201 
1202     VkFormatProperties2 props{};
1203     const VkFormatFeatureFlags flags = VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT |
1204                                        VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT;
1205     for (int f = VK_FORMAT_R64G64B64A64_SFLOAT; f > 0; --f)
1206     {
1207         props.sType            = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
1208         props.pNext            = nullptr;
1209         props.formatProperties = {};
1210         const VkFormat fmt     = static_cast<VkFormat>(f);
1211         vk.getPhysicalDeviceFormatProperties2(dev, fmt, &props);
1212         if (doesFormatMatch(fmt) && ((props.formatProperties.optimalTilingFeatures & flags) == flags))
1213         {
1214             this->format = fmt;
1215             return true;
1216         }
1217     }
1218     return false;
1219 }
1220 
checkSupport(Context & context) const1221 void ColorWriteEnable2Test::checkSupport(Context &context) const
1222 {
1223     const auto &vki           = context.getInstanceInterface();
1224     const auto physicalDevice = context.getPhysicalDevice();
1225 
1226     if (m_params.colorWriteEnables)
1227     {
1228         context.requireDeviceFunctionality("VK_EXT_color_write_enable");
1229     }
1230 
1231     DE_ASSERT(m_params.attachmentCount >= 1);
1232     auto maxColorAttachments = context.getDeviceProperties().limits.maxColorAttachments;
1233     if ((m_params.attachmentCount + m_params.attachmentMore) > maxColorAttachments)
1234     {
1235         std::stringstream ss;
1236         if (m_params.attachmentMore)
1237         {
1238             ss << "Sum of color attachments (" << m_params.attachmentCount << " + " << m_params.attachmentMore << ")";
1239         }
1240         else
1241         {
1242             ss << "Color attachment count of " << m_params.attachmentCount;
1243         }
1244         ss << " exceeds maximum number of color attachments supported by device which is " << maxColorAttachments;
1245         ss.flush();
1246         TCU_THROW(NotSupportedError, ss.str());
1247     }
1248 
1249     if (!m_params.selectOptimalBlendableFormat(vki, physicalDevice))
1250         TCU_THROW(NotSupportedError, "Required color image features not supported");
1251 
1252     checkPipelineConstructionRequirements(vki, physicalDevice, m_params.pct);
1253 }
1254 
initPrograms(SourceCollections & programCollection) const1255 void ColorWriteEnable2Test::initPrograms(SourceCollections &programCollection) const
1256 {
1257     const char nl     = '\n';
1258     const uint32_t ac = m_params.attachmentCount;
1259     std::ostringstream vs;
1260     std::ostringstream fs;
1261 
1262     vs << "#version 450" << nl << "layout(location = 0) in vec4 position;" << nl
1263        << "layout(location = 0) out flat int instance;" << nl << "void main() {" << nl
1264        << "    gl_Position = vec4(position.xy, 0.0, 1.0);" << nl << "    instance = gl_InstanceIndex;" << nl << "}"
1265        << nl;
1266     programCollection.glslSources.add("vert") << glu::VertexSource(vs.str());
1267 
1268     fs << "#version 450" << nl << "layout(location = 0) in flat int attachments;" << nl
1269        << "layout(location = 0) out vec4 colors[" << ac << "];" << nl << "void main() {" << nl
1270        << "    for (int a = 0; a < attachments; ++a) {" << nl << "        float c = float(attachments - a);" << nl
1271        << "        colors[a] = vec4(pow(0.5, c));" << nl << "}}" << nl;
1272     programCollection.glslSources.add("frag") << glu::FragmentSource(fs.str());
1273 }
1274 
createInstance(Context & context) const1275 TestInstance *ColorWriteEnable2Test::createInstance(Context &context) const
1276 {
1277     return new ColorWriteEnable2Instance(context, m_params);
1278 }
1279 
ColorWriteEnable2Instance(Context & context,const TestParams & testParams)1280 ColorWriteEnable2Instance::ColorWriteEnable2Instance(Context &context, const TestParams &testParams)
1281     : vkt::TestInstance(context)
1282     , m_params(testParams)
1283     , m_vkd(context.getDeviceInterface())
1284     , m_device(context.getDevice())
1285     , m_allocator(context.getDefaultAllocator())
1286     , m_vertex(ShaderWrapper(m_vkd, m_device, context.getBinaryCollection().get("vert")))
1287     , m_fragment(ShaderWrapper(m_vkd, m_device, context.getBinaryCollection().get("frag")))
1288 {
1289 }
1290 
createRenderPass(uint32_t colorAttachmentCount) const1291 RenderPassWrapper ColorWriteEnable2Instance::createRenderPass(uint32_t colorAttachmentCount) const
1292 {
1293     const std::vector<VkAttachmentDescription> attachmentDescriptions(
1294         colorAttachmentCount,
1295         VkAttachmentDescription{
1296             0u,                                       // VkAttachmentDescriptionFlags flags;
1297             m_params.format,                          // VkFormat format;
1298             VK_SAMPLE_COUNT_1_BIT,                    // VkSampleCountFlagBits samples;
1299             VK_ATTACHMENT_LOAD_OP_CLEAR,              // VkAttachmentLoadOp loadOp;
1300             VK_ATTACHMENT_STORE_OP_STORE,             // VkAttachmentStoreOp storeOp;
1301             VK_ATTACHMENT_LOAD_OP_DONT_CARE,          // VkAttachmentLoadOp stencilLoadOp;
1302             VK_ATTACHMENT_STORE_OP_DONT_CARE,         // VkAttachmentStoreOp stencilStoreOp;
1303             VK_IMAGE_LAYOUT_UNDEFINED,                // VkImageLayout initialLayout;
1304             VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout;
1305         });
1306 
1307     std::vector<VkAttachmentReference> colorAttachmentReference;
1308     for (uint32_t i = 0u; i < colorAttachmentCount; ++i)
1309     {
1310         colorAttachmentReference.push_back(VkAttachmentReference{
1311             i,                                       // uint32_t attachment;
1312             VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout;
1313         });
1314     }
1315 
1316     const VkSubpassDescription subpassDescription{
1317         0u,                              // VkSubpassDescriptionFlags flags;
1318         VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
1319         0u,                              // uint32_t inputAttachmentCount;
1320         nullptr,                         // const VkAttachmentReference* pInputAttachments;
1321         colorAttachmentCount,            // uint32_t colorAttachmentCount;
1322         colorAttachmentReference.data(), // const VkAttachmentReference* pColorAttachments;
1323         nullptr,                         // const VkAttachmentReference* pResolveAttachments;
1324         nullptr,                         // const VkAttachmentReference* pDepthStencilAttachment;
1325         0u,                              // uint32_t preserveAttachmentCount;
1326         nullptr,                         // const uint32_t* pPreserveAttachments;
1327     };
1328 
1329     const VkRenderPassCreateInfo renderPassCreateInfo{
1330         VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType;
1331         nullptr,                                   // const void* pNext;
1332         0u,                                        // VkRenderPassCreateFlags flags;
1333         colorAttachmentCount,                      // uint32_t attachmentCount;
1334         attachmentDescriptions.data(),             // const VkAttachmentDescription* pAttachments;
1335         1u,                                        // uint32_t subpassCount;
1336         &subpassDescription,                       // const VkSubpassDescription* pSubpasses;
1337         0u,                                        // uint32_t dependencyCount;
1338         nullptr,                                   // const VkSubpassDependency* pDependencies;
1339     };
1340 
1341     return RenderPassWrapper(m_params.pct, m_vkd, m_device, &renderPassCreateInfo);
1342 }
1343 
createVerrtexBuffer() const1344 de::MovePtr<BufferWithMemory> ColorWriteEnable2Instance::createVerrtexBuffer() const
1345 {
1346     const std::vector<float> quad{-1.0f, -1.0f, 0.0f, 0.0f, +1.0f, -1.0f, 0.0f, 0.0f, -1.0f, +1.0f, 0.0f, 0.0f,
1347                                   -1.0f, +1.0f, 0.0f, 0.0f, +1.0f, -1.0f, 0.0f, 0.0f, +1.0f, +1.0f, 0.0f, 0.0f};
1348 
1349     const auto vertDataSize = quad.size() * sizeof(float);
1350     const auto vertBufferInfo =
1351         makeBufferCreateInfo(static_cast<VkDeviceSize>(vertDataSize), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
1352     de::MovePtr<BufferWithMemory> vertBuffer(
1353         new BufferWithMemory(m_vkd, m_device, m_allocator, vertBufferInfo, vk::MemoryRequirement::HostVisible));
1354     auto &alloc = vertBuffer->getAllocation();
1355 
1356     deMemcpy(reinterpret_cast<char *>(alloc.getHostPtr()), quad.data(), vertDataSize);
1357     flushAlloc(m_vkd, m_device, alloc);
1358 
1359     return vertBuffer;
1360 }
1361 
createFramebuffer(uint32_t colorAttachmentCount) const1362 ColorWriteEnable2Instance::Framebuffer ColorWriteEnable2Instance::createFramebuffer(uint32_t colorAttachmentCount) const
1363 {
1364     const VkExtent3D extent{m_params.width, m_params.height, 1u};
1365     const VkImageUsageFlags imageUsage =
1366         (vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
1367     const auto imageSubresource = vk::makeImageSubresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
1368     const uint32_t queueIndex   = m_context.getUniversalQueueFamilyIndex();
1369     Allocator &allocator        = m_context.getDefaultAllocator();
1370 
1371     std::vector<Attachment> attachments(colorAttachmentCount);
1372     std::vector<VkImage> images(colorAttachmentCount);
1373     std::vector<VkImageView> views(colorAttachmentCount);
1374 
1375     for (uint32_t i = 0; i < colorAttachmentCount; ++i)
1376     {
1377         auto &attachment = attachments[i];
1378 
1379         const VkImageCreateInfo imageCreateInfo{
1380             VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
1381             nullptr,                             // const void* pNext;
1382             0u,                                  // VkImageCreateFlags flags;
1383             VK_IMAGE_TYPE_2D,                    // VkImageType imageType;
1384             m_params.format,                     // VkFormat format;
1385             extent,                              // VkExtent3D extent;
1386             1u,                                  // uint32_t mipLevels;
1387             1u,                                  // uint32_t arrayLayers;
1388             VK_SAMPLE_COUNT_1_BIT,               // VkSampleCountFlagBits samples;
1389             VK_IMAGE_TILING_OPTIMAL,             // VkImageTiling tiling;
1390             imageUsage,                          // VkImageUsageFlags usage;
1391             VK_SHARING_MODE_EXCLUSIVE,           // VkSharingMode sharingMode;
1392             1u,                                  // uint32_t queueFamilyIndexCount;
1393             &queueIndex,                         // const uint32_t* pQueueFamilyIndices;
1394             VK_IMAGE_LAYOUT_UNDEFINED,           // VkImageLayout initialLayout;
1395         };
1396         attachment.image = de::MovePtr<ImageWithMemory>(
1397             new ImageWithMemory(m_vkd, m_device, allocator, imageCreateInfo, MemoryRequirement::Any));
1398 
1399         attachment.view = makeImageView(m_vkd, m_device, **attachment.image, VK_IMAGE_VIEW_TYPE_2D, m_params.format,
1400                                         imageSubresource);
1401 
1402         images[i] = **attachment.image;
1403         views[i]  = *attachment.view;
1404     }
1405 
1406     Framebuffer result;
1407     result.attachments = std::move(attachments);
1408     result.framebuffer = createRenderPass(colorAttachmentCount);
1409 
1410     const VkFramebufferCreateInfo framebufferCreateInfo{
1411         VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
1412         nullptr,                                   // const void* pNext;
1413         0u,                                        // VkFramebufferCreateFlags flags;
1414         result.framebuffer.get(),                  // VkRenderPass renderPass;
1415         colorAttachmentCount,                      // uint32_t attachmentCount;
1416         views.data(),                              // const VkImageView* pAttachments;
1417         m_params.width,                            // uint32_t width;
1418         m_params.height,                           // uint32_t height;
1419         1u,                                        // uint32_t layers;
1420     };
1421 
1422     result.framebuffer.createFramebuffer(m_vkd, m_device, &framebufferCreateInfo, images);
1423 
1424     return result;
1425 }
1426 
setupAndBuildPipeline(GraphicsPipelineWrapperEx & owner,PipelineLayoutWrapper & pipelineLayout,VkRenderPass renderPass,uint32_t colorAttachmentCount,const ColorWriteEnables & colorWriteEnables,float blendComp,bool dynamic) const1427 void ColorWriteEnable2Instance::setupAndBuildPipeline(GraphicsPipelineWrapperEx &owner,
1428                                                       PipelineLayoutWrapper &pipelineLayout, VkRenderPass renderPass,
1429                                                       uint32_t colorAttachmentCount,
1430                                                       const ColorWriteEnables &colorWriteEnables, float blendComp,
1431                                                       bool dynamic) const
1432 {
1433     const std::vector<VkViewport> viewports{makeViewport(m_params.width, m_params.height)};
1434     const std::vector<VkRect2D> scissors{makeRect2D(m_params.width, m_params.height)};
1435 
1436     const auto vertexBinding =
1437         makeVertexInputBindingDescription(0u, static_cast<uint32_t>(4 * sizeof(float)), VK_VERTEX_INPUT_RATE_VERTEX);
1438     const auto vertexAttrib = makeVertexInputAttributeDescription(0u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, 0u);
1439 
1440     const VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo{
1441         vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
1442         nullptr,                                                       // const void* pNext;
1443         0u,                                                            // VkPipelineVertexInputStateCreateFlags flags;
1444         1u,                                                            // uint32_t vertexBindingDescriptionCount;
1445         &vertexBinding, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
1446         1u,             // uint32_t vertexAttributeDescriptionCount;
1447         &vertexAttrib   // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
1448     };
1449 
1450     const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo{
1451         VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType;
1452         nullptr,                                                     // const void* pNext;
1453         0u,                                                          // VkPipelineInputAssemblyStateCreateFlags flags;
1454         VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,                         // VkPrimitiveTopology topology;
1455         VK_FALSE,                                                    // VkBool32 primitiveRestartEnable;
1456     };
1457 
1458     const VkDynamicState cweDynamicStates[1]{VK_DYNAMIC_STATE_COLOR_WRITE_ENABLE_EXT};
1459     const VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo{
1460         VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType;
1461         nullptr,                                              // const void* pNext;
1462         0u,                                                   // VkPipelineDynamicStateCreateFlags flags;
1463         1u,                                                   // uint32_t dynamicStateCount;
1464         cweDynamicStates                                      // const VkDynamicState* pDynamicStates;
1465     };
1466 
1467     DE_ASSERT(colorAttachmentCount <= colorWriteEnables.size());
1468 
1469     std::vector<vk::VkPipelineColorBlendAttachmentState> colorBlendAttachmentStates(
1470         colorAttachmentCount,
1471         VkPipelineColorBlendAttachmentState{
1472             VK_TRUE,                        // VkBool32                 blendEnable
1473             VK_BLEND_FACTOR_CONSTANT_COLOR, // VkBlendFactor            srcColorBlendFactor
1474             VK_BLEND_FACTOR_ZERO,           // VkBlendFactor            dstColorBlendFactor
1475             VK_BLEND_OP_ADD,                // VkBlendOp                colorBlendOp
1476             VK_BLEND_FACTOR_CONSTANT_ALPHA, // VkBlendFactor            srcAlphaBlendFactor
1477             VK_BLEND_FACTOR_ZERO,           // VkBlendFactor            dstAlphaBlendFactor
1478             VK_BLEND_OP_ADD,                // VkBlendOp                alphaBlendOp
1479             VkColorComponentFlags(0)        // VkColorComponentFlags    colorWriteMask
1480         });
1481     for (uint32_t i = 0; i < colorAttachmentCount; ++i)
1482     {
1483         VkColorComponentFlags colorWriteMask(VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
1484                                              VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT);
1485         switch (i % 4)
1486         {
1487         case 0:
1488             colorWriteMask &= (~(VK_COLOR_COMPONENT_R_BIT));
1489             break;
1490         case 1:
1491             colorWriteMask &= (~(VK_COLOR_COMPONENT_G_BIT));
1492             break;
1493         case 2:
1494             colorWriteMask &= (~(VK_COLOR_COMPONENT_B_BIT));
1495             break;
1496         case 3:
1497             colorWriteMask &= (~(VK_COLOR_COMPONENT_A_BIT));
1498             break;
1499         }
1500         colorBlendAttachmentStates[i].colorWriteMask = colorWriteMask;
1501         colorBlendAttachmentStates[i].blendEnable    = colorWriteEnables[i];
1502     }
1503 
1504     const VkPipelineColorWriteCreateInfoEXT colorWriteCreateInfo{
1505         VK_STRUCTURE_TYPE_PIPELINE_COLOR_WRITE_CREATE_INFO_EXT, // VkStructureType sType;
1506         nullptr,                                                // const void* pNext;
1507         colorAttachmentCount,                                   // uint32_t attachmentCount;
1508         colorWriteEnables.data()                                // const VkBool32* pColorWriteEnables;
1509     };
1510 
1511     const bool cweAllowed             = (dynamic && m_params.colorWriteEnables);
1512     owner.m_isDynamicColorWriteEnable = cweAllowed;
1513 
1514     const VkPipelineColorBlendStateCreateInfo colorBlendStateCreateInfo{
1515         VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType                               sType
1516         cweAllowed ? nullptr : &colorWriteCreateInfo,             // const void*                                   pNext
1517         0u,                                                       // VkPipelineColorBlendStateCreateFlags          flags
1518         VK_FALSE,                                    // VkBool32                                      logicOpEnable
1519         VK_LOGIC_OP_CLEAR,                           // VkLogicOp                                     logicOp
1520         colorAttachmentCount,                        // uint32_t                                      attachmentCount
1521         colorBlendAttachmentStates.data(),           // const VkPipelineColorBlendAttachmentState*    pAttachments
1522         {blendComp, blendComp, blendComp, blendComp} // float                                         blendConstants[4]
1523     };
1524 
1525     owner.setDefaultRasterizationState()
1526         .setDefaultDepthStencilState()
1527         .setDefaultMultisampleState()
1528         .setDynamicState(cweAllowed ? &dynamicStateCreateInfo : nullptr)
1529         .setupVertexInputState(&vertexInputStateCreateInfo, &inputAssemblyStateCreateInfo)
1530         .setupPreRasterizationShaderState(viewports, scissors, pipelineLayout, renderPass, 0u, m_vertex)
1531         .setupFragmentShaderState(pipelineLayout, renderPass, 0u, m_fragment)
1532         .setupFragmentOutputState(renderPass, 0u, &colorBlendStateCreateInfo)
1533         .setMonolithicPipelineLayout(pipelineLayout)
1534         .buildPipeline();
1535 }
1536 
verifyAttachment(const uint32_t attachmentIndex,const uint32_t attachmentCount,const ConstPixelBufferAccess & attachmentContent,const ColorWriteEnables & colorWriteEnables,const Vec4 & background,const float blendComp) const1537 tcu::TestStatus ColorWriteEnable2Instance::verifyAttachment(const uint32_t attachmentIndex,
1538                                                             const uint32_t attachmentCount,
1539                                                             const ConstPixelBufferAccess &attachmentContent,
1540                                                             const ColorWriteEnables &colorWriteEnables,
1541                                                             const Vec4 &background, const float blendComp) const
1542 {
1543     const auto maskColor = [&](Vec4 color) -> Vec4
1544     {
1545         color[attachmentIndex % 4] = background[attachmentIndex % 4];
1546         return color;
1547     };
1548     const Vec4 source(powf(0.5f, static_cast<float>(attachmentCount - attachmentIndex)));
1549     const Vec4 expected = colorWriteEnables[attachmentIndex] ? maskColor(source * blendComp) : background;
1550 
1551     for (uint32_t y = 0; y < m_params.height; ++y)
1552     {
1553         for (uint32_t x = 0; x < m_params.width; ++x)
1554         {
1555             const auto result = attachmentContent.getPixel(x, y);
1556             if (!tcu::boolAll(tcu::lessThan(tcu::absDiff(result, expected), kColorThreshold)))
1557             {
1558                 std::ostringstream msg;
1559                 msg << "Unexpected output value found at position (" << x << ", " << y << "): expected\n"
1560                     << expected << " but got\n"
1561                     << result << ")";
1562                 return tcu::TestStatus::fail(msg.str());
1563             }
1564         }
1565     }
1566 
1567     return tcu::TestStatus::pass("");
1568 }
1569 
iterate(void)1570 TestStatus ColorWriteEnable2Instance::iterate(void)
1571 {
1572     const InstanceInterface &vki          = m_context.getInstanceInterface();
1573     const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice();
1574     const VkQueue queue                   = m_context.getUniversalQueue();
1575     const uint32_t queueIndex             = m_context.getUniversalQueueFamilyIndex();
1576     const VkRect2D renderArea             = makeRect2D(m_params.width, m_params.height);
1577     const uint32_t attachmentCount        = m_params.attachmentCount;
1578 
1579     const float blendComp = 0.5f;
1580     const Vec4 background(0.75f, 0.75f, 0.75f, 0.75f);
1581     std::vector<VkClearValue> clearValues(attachmentCount, makeClearValueColor(background));
1582     de::MovePtr<BufferWithMemory> vertexBuffer = createVerrtexBuffer();
1583     ColorWriteEnables writeEnables(attachmentCount + m_params.attachmentMore, VK_TRUE);
1584     for (uint32_t i = 0; i < attachmentCount; ++i)
1585         writeEnables[i] = (i % 2) ? VK_TRUE : VK_FALSE;
1586 
1587     PipelineLayoutWrapper pipelineLayout(m_params.pct, m_vkd, m_device, 0u, nullptr, 0u, nullptr);
1588     std::vector<Framebuffer> framebuffers;
1589     std::vector<GraphicsPipelineWrapperEx> pipelines;
1590     for (uint32_t i = 0; i < attachmentCount; ++i)
1591     {
1592         framebuffers.emplace_back(createFramebuffer(i + 1));
1593 
1594         const bool dynamicColorWriteEnable = (((attachmentCount - i) % 2) == 1);
1595 
1596         // build dynamics and statics pipelines alternately in reverse order
1597         pipelines.emplace_back(vki, m_vkd, physicalDevice, m_device, m_context.getDeviceExtensions(), m_params.pct);
1598         setupAndBuildPipeline(pipelines.back(), pipelineLayout, framebuffers[i].framebuffer.get(), (i + 1),
1599                               writeEnables, blendComp, dynamicColorWriteEnable);
1600     }
1601 
1602     Move<VkCommandPool> cmdPool   = makeCommandPool(m_vkd, m_device, queueIndex);
1603     Move<VkCommandBuffer> cmdBuff = allocateCommandBuffer(m_vkd, m_device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1604 
1605     beginCommandBuffer(m_vkd, *cmdBuff);
1606     m_vkd.cmdBindVertexBuffers(*cmdBuff, 0u, 1u, &vertexBuffer->get(), &static_cast<const VkDeviceSize &>(0));
1607 
1608     for (uint32_t a = 0; a < attachmentCount; ++a)
1609     {
1610         if (m_params.setCweBeforePlBind)
1611         {
1612             if (pipelines[a].isDynamicColorWriteEnable())
1613                 m_vkd.cmdSetColorWriteEnableEXT(*cmdBuff, static_cast<uint32_t>(writeEnables.size()),
1614                                                 writeEnables.data());
1615             pipelines[a].bind(*cmdBuff);
1616         }
1617         else
1618         {
1619             pipelines[a].bind(*cmdBuff);
1620             if (pipelines[a].isDynamicColorWriteEnable())
1621                 m_vkd.cmdSetColorWriteEnableEXT(*cmdBuff, static_cast<uint32_t>(writeEnables.size()),
1622                                                 writeEnables.data());
1623         }
1624 
1625         framebuffers[a].framebuffer.begin(m_vkd, *cmdBuff, renderArea, attachmentCount, clearValues.data());
1626         m_vkd.cmdDraw(*cmdBuff, 6u, 1u, 0u, (a + 1));
1627         framebuffers[a].framebuffer.end(m_vkd, *cmdBuff);
1628     }
1629 
1630     endCommandBuffer(m_vkd, *cmdBuff);
1631     submitCommandsAndWait(m_vkd, m_device, queue, *cmdBuff);
1632 
1633     for (uint32_t i = 0; i < attachmentCount; ++i)
1634         for (uint32_t a = 0; a < (i + 1); ++a)
1635         {
1636             const auto colorBuffer = readColorAttachment(m_vkd, m_device, queue, queueIndex, m_allocator,
1637                                                          **framebuffers.at(i).attachments.at(a).image, m_params.format,
1638                                                          UVec2(m_params.width, m_params.height));
1639             tcu::TestStatus status =
1640                 verifyAttachment(a, (i + 1), colorBuffer->getAccess(), writeEnables, background, blendComp);
1641             if (status.isFail())
1642                 return status;
1643         }
1644 
1645     return TestStatus::pass("");
1646 }
1647 
1648 } // unnamed namespace
1649 
createColorWriteEnableTests(tcu::TestContext & testCtx,vk::PipelineConstructionType pct)1650 tcu::TestCaseGroup *createColorWriteEnableTests(tcu::TestContext &testCtx, vk::PipelineConstructionType pct)
1651 {
1652     de::MovePtr<tcu::TestCaseGroup> colorWriteEnableGroup(new tcu::TestCaseGroup(testCtx, "color_write_enable"));
1653 
1654     DE_ASSERT(kNumColorAttachments >= 2);
1655 
1656     std::vector<bool> mask_all(kNumColorAttachments, true);
1657     std::vector<bool> mask_first(kNumColorAttachments, false);
1658     mask_first[0] = true;
1659     std::vector<bool> mask_second(kNumColorAttachments, false);
1660     mask_second[1] = true;
1661     std::vector<bool> mask_last(kNumColorAttachments, false);
1662     mask_last.back() = true;
1663     std::vector<bool> mask_first_and_second(kNumColorAttachments, false);
1664     mask_first_and_second[0] = mask_first_and_second[1] = true;
1665     std::vector<bool> mask_second_and_last(kNumColorAttachments, false);
1666     mask_second_and_last[1] = mask_second_and_last.back() = true;
1667 
1668     // Test cases for channel enables
1669     static const struct
1670     {
1671         tcu::BVec4 enabledChannels;
1672         std::string name;
1673         std::string desc;
1674     } kChannelCases[] = {
1675         {tcu::BVec4(true, true, true, true), "all_channels", "Enable all channels in colorWriteMask"},
1676         {tcu::BVec4(true, false, false, false), "red_channel", "Red channel enabled in colorWriteMask"},
1677         {tcu::BVec4(false, true, false, false), "green_channel", "Green channel enabled in colorWriteMask"},
1678         {tcu::BVec4(false, false, true, false), "blue_channel", "Blue channel enabled in colorWriteMask"},
1679         {tcu::BVec4(false, false, false, true), "alpha_channel", "Alpha channel enabled in colorWriteMask"},
1680         {tcu::BVec4(false, false, false, false), "no_channels", "Disable all channels in colorWriteMask"},
1681     };
1682 
1683     // Test cases for the dynamic state
1684     static const struct
1685     {
1686         SequenceOrdering ordering;
1687         std::string name;
1688     } kOrderingCases[] = {
1689         // Dynamic state set after command buffer start
1690         {SequenceOrdering::CMD_BUFFER_START, "cmd_buffer_start"},
1691         // Dynamic state set just before drawing
1692         {SequenceOrdering::BEFORE_DRAW, "before_draw"},
1693         // Dynamic after a pipeline with static states has been bound and before a pipeline with dynamic states has been bound
1694         {SequenceOrdering::BETWEEN_PIPELINES, "between_pipelines"},
1695         // Dynamic state set after both a static-state pipeline and a second dynamic-state pipeline have been bound
1696         {SequenceOrdering::AFTER_PIPELINES, "after_pipelines"},
1697         // Dynamic state set after a dynamic pipeline has been bound and before a second static-state pipeline with the right values has been bound
1698         {SequenceOrdering::BEFORE_GOOD_STATIC, "before_good_static"},
1699         // Bind bad static pipeline and draw, followed by binding correct dynamic pipeline and drawing again
1700         {SequenceOrdering::TWO_DRAWS_DYNAMIC, "two_draws_dynamic"},
1701         // Bind bad dynamic pipeline and draw, followed by binding correct static pipeline and drawing again
1702         {SequenceOrdering::TWO_DRAWS_STATIC, "two_draws_static"},
1703     };
1704 
1705     for (int channelCaseIdx = 0; channelCaseIdx < DE_LENGTH_OF_ARRAY(kChannelCases); ++channelCaseIdx)
1706     {
1707         const auto &kChannelCase = kChannelCases[channelCaseIdx];
1708         de::MovePtr<tcu::TestCaseGroup> channelGroup(new tcu::TestCaseGroup(testCtx, kChannelCase.name.c_str()));
1709 
1710         for (int orderingIdx = 0; orderingIdx < DE_LENGTH_OF_ARRAY(kOrderingCases); ++orderingIdx)
1711         {
1712             const auto &kOrderingCase = kOrderingCases[orderingIdx];
1713             const auto &kOrdering     = kOrderingCase.ordering;
1714 
1715             if (vk::isConstructionTypeShaderObject(pct) &&
1716                 (kOrderingCase.ordering == SequenceOrdering::BETWEEN_PIPELINES ||
1717                  kOrderingCase.ordering == SequenceOrdering::AFTER_PIPELINES))
1718                 continue;
1719 
1720             de::MovePtr<tcu::TestCaseGroup> orderingGroup(new tcu::TestCaseGroup(testCtx, kOrderingCase.name.c_str()));
1721 
1722             // Dynamically enable writes to all color attachments
1723             AddSingleTestCaseDynamic("enable_all", pct, mask_all, kChannelCase.enabledChannels, false,
1724                                      orderingGroup.get(), testCtx, kOrdering);
1725             // Dynamically enable writes to the first color attachment
1726             AddSingleTestCaseDynamic("enable_first", pct, mask_first, kChannelCase.enabledChannels, false,
1727                                      orderingGroup.get(), testCtx, kOrdering);
1728             // Dynamically enable writes to the second color attachment
1729             AddSingleTestCaseDynamic("enable_second", pct, mask_second, kChannelCase.enabledChannels, false,
1730                                      orderingGroup.get(), testCtx, kOrdering);
1731             // Dynamically enable writes to the last color attachment
1732             AddSingleTestCaseDynamic("enable_last", pct, mask_last, kChannelCase.enabledChannels, false,
1733                                      orderingGroup.get(), testCtx, kOrdering);
1734             // Dynamically enable writes to the first two color attachments
1735             AddSingleTestCaseDynamic("enable_first_and_second", pct, mask_first_and_second,
1736                                      kChannelCase.enabledChannels, false, orderingGroup.get(), testCtx, kOrdering);
1737             // Dynamically enable writes to the second and last color attachments
1738             AddSingleTestCaseDynamic("enable_second_and_last", pct, mask_second_and_last, kChannelCase.enabledChannels,
1739                                      false, orderingGroup.get(), testCtx, kOrdering);
1740 
1741             // Dynamically disable writes to all color attachments
1742             AddSingleTestCaseDynamic("disable_all", pct, mask_all, kChannelCase.enabledChannels, true,
1743                                      orderingGroup.get(), testCtx, kOrdering);
1744             // Dynamically disable writes to the first color attachment
1745             AddSingleTestCaseDynamic("disable_first", pct, mask_first, kChannelCase.enabledChannels, true,
1746                                      orderingGroup.get(), testCtx, kOrdering);
1747             // Dynamically disable writes to the second color attachment
1748             AddSingleTestCaseDynamic("disable_second", pct, mask_second, kChannelCase.enabledChannels, true,
1749                                      orderingGroup.get(), testCtx, kOrdering);
1750             // Dynamically disable writes to the last color attachment
1751             AddSingleTestCaseDynamic("disable_last", pct, mask_last, kChannelCase.enabledChannels, true,
1752                                      orderingGroup.get(), testCtx, kOrdering);
1753             // Dynamically disable writes to the first two color attachments
1754             AddSingleTestCaseDynamic("disable_first_and_second", pct, mask_first_and_second,
1755                                      kChannelCase.enabledChannels, true, orderingGroup.get(), testCtx, kOrdering);
1756             // Dynamically disable writes to the second and last color attachments
1757             AddSingleTestCaseDynamic("disable_second_and_last", pct, mask_second_and_last, kChannelCase.enabledChannels,
1758                                      true, orderingGroup.get(), testCtx, kOrdering);
1759 
1760             channelGroup->addChild(orderingGroup.release());
1761         }
1762 
1763         // Test cases for the static state
1764         // Note that the dynamic state test cases above also test pipelines with static state (when ordering is BEFORE_GOOD_STATIC and TWO_DRAWS_STATIC).
1765         // However they all bind a pipeline with the static state AFTER binding a pipeline with the dynamic state.
1766         // The only case missing, then, is static state alone without any dynamic pipelines in the same render pass or command buffer.
1767         de::MovePtr<tcu::TestCaseGroup> staticOrderingGroup(new tcu::TestCaseGroup(testCtx, "static"));
1768 
1769         // Statically enable writes to all color attachments
1770         AddSingleTestCaseStatic("enable_all", pct, mask_all, kChannelCase.enabledChannels, false,
1771                                 staticOrderingGroup.get(), testCtx);
1772         // Statically enable writes to the first color attachment
1773         AddSingleTestCaseStatic("enable_first", pct, mask_first, kChannelCase.enabledChannels, false,
1774                                 staticOrderingGroup.get(), testCtx);
1775         // Statically enable writes to the second color attachment
1776         AddSingleTestCaseStatic("enable_second", pct, mask_second, kChannelCase.enabledChannels, false,
1777                                 staticOrderingGroup.get(), testCtx);
1778         // Statically enable writes to the last color attachment
1779         AddSingleTestCaseStatic("enable_last", pct, mask_last, kChannelCase.enabledChannels, false,
1780                                 staticOrderingGroup.get(), testCtx);
1781         // Statically enable writes to the first two color attachments
1782         AddSingleTestCaseStatic("enable_first_and_second", pct, mask_first_and_second, kChannelCase.enabledChannels,
1783                                 false, staticOrderingGroup.get(), testCtx);
1784         // Statically enable writes to the second and last color attachments
1785         AddSingleTestCaseStatic("enable_second_and_last", pct, mask_second_and_last, kChannelCase.enabledChannels,
1786                                 false, staticOrderingGroup.get(), testCtx);
1787 
1788         // Statically disable writes to all color attachments
1789         AddSingleTestCaseStatic("disable_all", pct, mask_all, kChannelCase.enabledChannels, true,
1790                                 staticOrderingGroup.get(), testCtx);
1791         // Statically disable writes to the first color attachment
1792         AddSingleTestCaseStatic("disable_first", pct, mask_first, kChannelCase.enabledChannels, true,
1793                                 staticOrderingGroup.get(), testCtx);
1794         // Statically disable writes to the second color attachment
1795         AddSingleTestCaseStatic("disable_second", pct, mask_second, kChannelCase.enabledChannels, true,
1796                                 staticOrderingGroup.get(), testCtx);
1797         // Statically disable writes to the last color attachment
1798         AddSingleTestCaseStatic("disable_last", pct, mask_last, kChannelCase.enabledChannels, true,
1799                                 staticOrderingGroup.get(), testCtx);
1800         // Statically disable writes to the first two color attachments
1801         AddSingleTestCaseStatic("disable_first_and_second", pct, mask_first_and_second, kChannelCase.enabledChannels,
1802                                 true, staticOrderingGroup.get(), testCtx);
1803         // Statically disable writes to the second and last color attachments
1804         AddSingleTestCaseStatic("disable_second_and_last", pct, mask_second_and_last, kChannelCase.enabledChannels,
1805                                 true, staticOrderingGroup.get(), testCtx);
1806 
1807         channelGroup->addChild(staticOrderingGroup.release());
1808 
1809         colorWriteEnableGroup->addChild(channelGroup.release());
1810     }
1811 
1812     return colorWriteEnableGroup.release();
1813 }
1814 
createColorWriteEnable2Tests(tcu::TestContext & testCtx,vk::PipelineConstructionType pct)1815 tcu::TestCaseGroup *createColorWriteEnable2Tests(tcu::TestContext &testCtx, vk::PipelineConstructionType pct)
1816 {
1817     const uint32_t attachmentCounts[]{3, 4, 5};
1818     const uint32_t attachentMores[]{0, 1, 2, 3};
1819 
1820     std::pair<bool, const char *> static const setCweMoments[]{{true, "cwe_before_bind"}, {false, "cwe_after_bind"}};
1821 
1822     tcu::TestCaseGroup *rootGroup = new tcu::TestCaseGroup(testCtx, "color_write_enable_maxa");
1823 
1824     for (const auto &setCweMoment : setCweMoments)
1825     {
1826         // A moment when cmdSetColorWriteEnableEXT() is called
1827         tcu::TestCaseGroup *setCweGroup = new tcu::TestCaseGroup(testCtx, setCweMoment.second);
1828 
1829         for (auto attachmentCount : attachmentCounts)
1830         {
1831             for (auto attachentMore : attachentMores)
1832             {
1833                 const std::string title =
1834                     "attachments" + std::to_string(attachmentCount) + "_more" + std::to_string(attachentMore);
1835 
1836                 TestParams p;
1837                 p.format             = VK_FORMAT_UNDEFINED;
1838                 p.width              = 32;
1839                 p.height             = 32;
1840                 p.setCweBeforePlBind = setCweMoment.first;
1841                 p.colorWriteEnables  = true;
1842                 p.attachmentCount    = attachmentCount;
1843                 p.attachmentMore     = attachentMore;
1844                 p.pct                = pct;
1845                 setCweGroup->addChild(new ColorWriteEnable2Test(testCtx, title, p));
1846             }
1847         }
1848         rootGroup->addChild(setCweGroup);
1849     }
1850     return rootGroup;
1851 }
1852 
1853 } // namespace pipeline
1854 } // namespace vkt
1855