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