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