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