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 "vkBuilderUtil.hpp"
35 #include "vkCmdUtil.hpp"
36 #include "vkImageUtil.hpp"
37
38 #include "tcuVector.hpp"
39 #include "tcuMaybe.hpp"
40 #include "tcuTestLog.hpp"
41 #include "tcuVectorUtil.hpp"
42
43 #include "deUniquePtr.hpp"
44 #include "deStringUtil.hpp"
45
46 #include <vector>
47 #include <sstream>
48 #include <algorithm>
49 #include <utility>
50 #include <iterator>
51 #include <string>
52 #include <limits>
53 #include <memory>
54 #include <functional>
55
56 namespace vkt
57 {
58 namespace pipeline
59 {
60
61 namespace
62 {
63
64 // Framebuffer size.
65 constexpr deUint32 kFramebufferWidth = 64u;
66 constexpr deUint32 kFramebufferHeight = 64u;
67
68 // Image formats.
69 constexpr vk::VkFormat kColorFormat = vk::VK_FORMAT_R8G8B8A8_UNORM;
70 const tcu::Vec4 kColorThreshold (0.005f); // 1/255 < 0.005 < 2/255.
71
72 constexpr deUint32 kNumColorAttachments = 3u;
73
74 const vk::VkFormat kDepthStencilFormats[] =
75 {
76 vk::VK_FORMAT_D32_SFLOAT_S8_UINT,
77 vk::VK_FORMAT_D24_UNORM_S8_UINT
78 };
79
80 constexpr auto kCoordsSize = static_cast<deUint32>(2 * sizeof(float));
81
82 using Bool32Vec = std::vector<vk::VkBool32>;
83
84 // Generic, to be used with any state than can be set statically and, as an option, dynamically.
85 template<typename T>
86 struct StaticAndDynamicPair
87 {
88 T staticValue;
89 tcu::Maybe<T> dynamicValue;
90
91 // Helper constructor to set a static value and no dynamic value.
StaticAndDynamicPairvkt::pipeline::__anon042430540111::StaticAndDynamicPair92 StaticAndDynamicPair (const T& value)
93 : staticValue (value)
94 , dynamicValue (tcu::Nothing)
95 {
96 }
97
98 // Helper constructor to set both.
StaticAndDynamicPairvkt::pipeline::__anon042430540111::StaticAndDynamicPair99 StaticAndDynamicPair (const T& sVal, const T& dVal)
100 : staticValue (sVal)
101 , dynamicValue (tcu::just<T>(dVal))
102 {
103 }
104
105 // If the dynamic value is present, swap static and dynamic values.
swapValuesvkt::pipeline::__anon042430540111::StaticAndDynamicPair106 void swapValues (void)
107 {
108 if (!dynamicValue)
109 return;
110 std::swap(staticValue, dynamicValue.get());
111 }
112 };
113
114 const tcu::Vec4 kDefaultTriangleColor (0.0f, 0.0f, 1.0f, 1.0f); // Opaque blue.
115 const tcu::Vec4 kDefaultClearColor (0.0f, 0.0f, 0.0f, 1.0f); // Opaque black.
116
117 struct MeshParams
118 {
119 tcu::Vec4 color;
120 float depth;
121 float scaleX;
122 float scaleY;
123 float offsetX;
124 float offsetY;
125
MeshParamsvkt::pipeline::__anon042430540111::MeshParams126 MeshParams (const tcu::Vec4& color_ = kDefaultTriangleColor,
127 float depth_ = 0.0f,
128 float scaleX_ = 1.0f,
129 float scaleY_ = 1.0f,
130 float offsetX_ = 0.0f,
131 float offsetY_ = 0.0f)
132 : color (color_)
133 , depth (depth_)
134 , scaleX (scaleX_)
135 , scaleY (scaleY_)
136 , offsetX (offsetX_)
137 , offsetY (offsetY_)
138 {}
139 };
140
141 enum class SequenceOrdering
142 {
143 CMD_BUFFER_START = 0, // Set state at the start of the command buffer.
144 BEFORE_DRAW = 1, // After binding dynamic pipeline and just before drawing.
145 BETWEEN_PIPELINES = 2, // After a static state pipeline has been bound but before the dynamic state pipeline has been bound.
146 AFTER_PIPELINES = 3, // After a static state pipeline and a second dynamic state pipeline have been bound.
147 BEFORE_GOOD_STATIC = 4, // Before a static state pipeline with the correct values has been bound.
148 TWO_DRAWS_DYNAMIC = 5, // Bind bad static pipeline and draw, followed by binding correct dynamic pipeline and drawing again.
149 TWO_DRAWS_STATIC = 6, // Bind bad dynamic pipeline and draw, followed by binding correct static pipeline and drawing again.
150 };
151
152 struct TestConfig
153 {
154 // Main sequence ordering.
155 SequenceOrdering sequenceOrdering;
156
157 // Drawing parameters.
158 MeshParams meshParams;
159
160 // Clearing parameters for the framebuffer.
161 tcu::Vec4 clearColorValue;
162 float clearDepthValue;
163
164 // Channels to enable
165 tcu::BVec4 channelMask;
166
167 // Expected output in the attachments.
168 std::vector<tcu::Vec4> expectedColor;
169 float expectedDepth;
170
171 // Static and dynamic pipeline configuration.
172 StaticAndDynamicPair<Bool32Vec> colorWriteEnableConfig;
173
174 // Sane defaults.
TestConfigvkt::pipeline::__anon042430540111::TestConfig175 TestConfig (SequenceOrdering ordering)
176 : sequenceOrdering (ordering)
177 , clearColorValue (kDefaultClearColor)
178 , clearDepthValue (1.0f)
179 , expectedColor (kNumColorAttachments, kDefaultTriangleColor)
180 , expectedDepth (1.0f)
181 , colorWriteEnableConfig (Bool32Vec(1u, VK_TRUE))
182 , m_swappedValues (false)
183 {
184 }
185
186 // Returns true if we should use the static and dynamic values exchanged.
187 // This makes the static part of the pipeline have the actual expected values.
isReversedvkt::pipeline::__anon042430540111::TestConfig188 bool isReversed () const
189 {
190 return (sequenceOrdering == SequenceOrdering::BEFORE_GOOD_STATIC ||
191 sequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC);
192 }
193
194 // Swaps static and dynamic configuration values.
swapValuesvkt::pipeline::__anon042430540111::TestConfig195 void swapValues ()
196 {
197 colorWriteEnableConfig.swapValues();
198 m_swappedValues = !m_swappedValues;
199 }
200
201 // Returns the number of iterations when recording commands.
numIterationsvkt::pipeline::__anon042430540111::TestConfig202 deUint32 numIterations () const
203 {
204 deUint32 iterations = 0u;
205
206 switch (sequenceOrdering)
207 {
208 case SequenceOrdering::TWO_DRAWS_DYNAMIC:
209 case SequenceOrdering::TWO_DRAWS_STATIC:
210 iterations = 2u;
211 break;
212 default:
213 iterations = 1u;
214 break;
215 }
216
217 return iterations;
218 }
219
220 private:
221 // Color Write Enable cases as created by createColorWriteEnableTests() are based on the assumption that, when a state
222 // has a static and a dynamic value configured at the same time, the static value is wrong and the dynamic value will give
223 // expected results. That's appropriate for most test variants, but in some others we want to reverse the situation: a dynamic
224 // pipeline with wrong values and a static one with good values.
225 //
226 // Instead of modifying how tests are created, we use isReversed() and swapValues() above, allowing us to swap static and
227 // 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
228 // given point in time in order to correctly answer some questions while running the test. m_swappedValues tracks that state.
229 bool m_swappedValues;
230 };
231
232 struct PushConstants
233 {
234 tcu::Vec4 triangleColor;
235 float meshDepth;
236 float scaleX;
237 float scaleY;
238 float offsetX;
239 float offsetY;
240 };
241
242 class ColorWriteEnableTest : public vkt::TestCase
243 {
244 public:
245 ColorWriteEnableTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestConfig& testConfig);
~ColorWriteEnableTest(void)246 virtual ~ColorWriteEnableTest (void) {}
247
248 virtual void checkSupport (Context& context) const;
249 virtual void initPrograms (vk::SourceCollections& programCollection) const;
250 virtual TestInstance* createInstance (Context& context) const;
251
252 private:
253 TestConfig m_testConfig;
254 };
255
256 class ColorWriteEnableInstance : public vkt::TestInstance
257 {
258 public:
259 ColorWriteEnableInstance (Context& context, const TestConfig& testConfig);
~ColorWriteEnableInstance(void)260 virtual ~ColorWriteEnableInstance (void) {}
261
262 virtual tcu::TestStatus iterate (void);
263
264 private:
265 TestConfig m_testConfig;
266 };
267
ColorWriteEnableTest(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const TestConfig & testConfig)268 ColorWriteEnableTest::ColorWriteEnableTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestConfig& testConfig)
269 : vkt::TestCase (testCtx, name, description)
270 , m_testConfig (testConfig)
271 {
272 }
273
checkSupport(Context & context) const274 void ColorWriteEnableTest::checkSupport (Context& context) const
275 {
276 const auto& vki = context.getInstanceInterface();
277 const auto physicalDevice = context.getPhysicalDevice();
278
279 // This is always required.
280 context.requireDeviceFunctionality("VK_EXT_color_write_enable");
281
282 // Check color image format support (depth/stencil will be chosen at runtime).
283 const vk::VkFormatFeatureFlags kColorFeatures = (vk::VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | vk::VK_FORMAT_FEATURE_TRANSFER_SRC_BIT);
284 const auto colorProperties = vk::getPhysicalDeviceFormatProperties(vki, physicalDevice, kColorFormat);
285
286 if ((colorProperties.optimalTilingFeatures & kColorFeatures) != kColorFeatures)
287 TCU_THROW(NotSupportedError, "Required color image features not supported");
288 }
289
initPrograms(vk::SourceCollections & programCollection) const290 void ColorWriteEnableTest::initPrograms (vk::SourceCollections& programCollection) const
291 {
292 std::ostringstream pushSource;
293 pushSource
294 << "layout(push_constant, std430) uniform PushConstantsBlock {\n"
295 << " vec4 triangleColor;\n"
296 << " float depthValue;\n"
297 << " float scaleX;\n"
298 << " float scaleY;\n"
299 << " float offsetX;\n"
300 << " float offsetY;\n"
301 << "} pushConstants;\n"
302 ;
303
304 std::ostringstream vertSource;
305 vertSource
306 << "#version 450\n"
307 << pushSource.str()
308 << "layout(location=0) in vec2 position;\n"
309 << "out gl_PerVertex\n"
310 << "{\n"
311 << " vec4 gl_Position;\n"
312 << "};\n"
313 << "void main() {\n"
314 << " vec2 vertexCoords = position;\n"
315 << " gl_Position = vec4(vertexCoords.x * pushConstants.scaleX + pushConstants.offsetX, vertexCoords.y * pushConstants.scaleY + pushConstants.offsetY, pushConstants.depthValue, 1.0);\n"
316 << "}\n"
317 ;
318
319 std::ostringstream fragOutputs;
320 std::ostringstream colorWrite;
321 for (deUint32 i = 0u; i < kNumColorAttachments; ++i)
322 {
323 fragOutputs << "layout(location=" << i << ") out vec4 color" << i << ";\n";
324 colorWrite << " color" << i << " = pushConstants.triangleColor * " << powf(0.5f, static_cast<float>(i)) << ";\n";
325 }
326
327 std::ostringstream fragSource;
328 fragSource
329 << "#version 450\n"
330 << pushSource.str()
331 << fragOutputs.str()
332 << "void main() {\n"
333 << colorWrite.str()
334 << "}\n"
335 ;
336
337 programCollection.glslSources.add("vert") << glu::VertexSource(vertSource.str());
338 programCollection.glslSources.add("frag") << glu::FragmentSource(fragSource.str());
339 }
340
createInstance(Context & context) const341 TestInstance* ColorWriteEnableTest::createInstance (Context& context) const
342 {
343 return new ColorWriteEnableInstance(context, m_testConfig);
344 }
345
ColorWriteEnableInstance(Context & context,const TestConfig & testConfig)346 ColorWriteEnableInstance::ColorWriteEnableInstance(Context& context, const TestConfig& testConfig)
347 : vkt::TestInstance (context)
348 , m_testConfig (testConfig)
349 {
350 }
351
logErrors(tcu::TestLog & log,const std::string & setName,const std::string & setDesc,const tcu::ConstPixelBufferAccess & result,const tcu::ConstPixelBufferAccess & errorMask)352 void logErrors(tcu::TestLog& log, const std::string& setName, const std::string& setDesc, const tcu::ConstPixelBufferAccess& result, const tcu::ConstPixelBufferAccess& errorMask)
353 {
354 log << tcu::TestLog::ImageSet(setName, setDesc)
355 << tcu::TestLog::Image(setName + "Result", "Result image", result)
356 << tcu::TestLog::Image(setName + "ErrorMask", "Error mask with errors marked in red", errorMask)
357 << tcu::TestLog::EndImageSet;
358 }
359
360 // Sets values for dynamic states if needed according to the test configuration.
setDynamicStates(const TestConfig & testConfig,const vk::DeviceInterface & vkd,vk::VkCommandBuffer cmdBuffer)361 void setDynamicStates(const TestConfig& testConfig, const vk::DeviceInterface& vkd, vk::VkCommandBuffer cmdBuffer)
362 {
363 if (testConfig.colorWriteEnableConfig.dynamicValue)
364 {
365 const auto& colorWriteEnables = testConfig.colorWriteEnableConfig.dynamicValue.get();
366 vkd.cmdSetColorWriteEnableEXT(cmdBuffer, static_cast<deUint32>(colorWriteEnables.size()), colorWriteEnables.data());
367 }
368 }
369
iterate(void)370 tcu::TestStatus ColorWriteEnableInstance::iterate (void)
371 {
372 using ImageWithMemoryVec = std::vector<std::unique_ptr<vk::ImageWithMemory>>;
373 using ImageViewVec = std::vector<vk::Move<vk::VkImageView>>;
374 using FramebufferVec = std::vector<vk::Move<vk::VkFramebuffer>>;
375
376 const auto& vki = m_context.getInstanceInterface();
377 const auto& vkd = m_context.getDeviceInterface();
378 const auto physicalDevice = m_context.getPhysicalDevice();
379 const auto device = m_context.getDevice();
380 auto& allocator = m_context.getDefaultAllocator();
381 const auto queue = m_context.getUniversalQueue();
382 const auto queueIndex = m_context.getUniversalQueueFamilyIndex();
383 auto& log = m_context.getTestContext().getLog();
384
385 const auto kReversed = m_testConfig.isReversed();
386 const auto kNumIterations = m_testConfig.numIterations();
387 const auto kSequenceOrdering = m_testConfig.sequenceOrdering;
388
389 const auto kFramebufferExtent = vk::makeExtent3D(kFramebufferWidth, kFramebufferHeight, 1u);
390 const vk::VkImageUsageFlags kColorUsage = (vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
391 const vk::VkImageUsageFlags kDSUsage = (vk::VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
392 const vk::VkFormatFeatureFlags kDSFeatures = (vk::VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT | vk::VK_FORMAT_FEATURE_TRANSFER_SRC_BIT);
393
394 // Choose depth/stencil format.
395 vk::VkFormat dsFormat = vk::VK_FORMAT_UNDEFINED;
396
397 for (int formatIdx = 0; formatIdx < DE_LENGTH_OF_ARRAY(kDepthStencilFormats); ++formatIdx)
398 {
399 const auto dsProperties = vk::getPhysicalDeviceFormatProperties(vki, physicalDevice, kDepthStencilFormats[formatIdx]);
400 if ((dsProperties.optimalTilingFeatures & kDSFeatures) == kDSFeatures)
401 {
402 dsFormat = kDepthStencilFormats[formatIdx];
403 break;
404 }
405 }
406
407 // Note: Not Supported insted of Fail because the transfer feature is not mandatory.
408 if (dsFormat == vk::VK_FORMAT_UNDEFINED)
409 TCU_THROW(NotSupportedError, "Required depth/stencil image features not supported");
410 log << tcu::TestLog::Message << "Chosen depth/stencil format: " << dsFormat << tcu::TestLog::EndMessage;
411
412 // Swap static and dynamic values in the test configuration so the static pipeline ends up with the expected values for cases
413 // where we will bind the static pipeline last before drawing.
414 if (kReversed)
415 m_testConfig.swapValues();
416
417 // Create color and depth/stencil images.
418 ImageWithMemoryVec colorImages;
419 ImageWithMemoryVec dsImages;
420
421 const vk::VkImageCreateInfo colorImageInfo =
422 {
423 vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
424 nullptr, // const void* pNext;
425 0u, // VkImageCreateFlags flags;
426 vk::VK_IMAGE_TYPE_2D, // VkImageType imageType;
427 kColorFormat, // VkFormat format;
428 kFramebufferExtent, // VkExtent3D extent;
429 1u, // deUint32 mipLevels;
430 1u, // deUint32 arrayLayers;
431 vk::VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
432 vk::VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
433 kColorUsage, // VkImageUsageFlags usage;
434 vk::VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
435 1u, // deUint32 queueFamilyIndexCount;
436 &queueIndex, // const deUint32* pQueueFamilyIndices;
437 vk::VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
438 };
439 for (deUint32 i = 0u; i < kNumIterations * kNumColorAttachments; ++i)
440 colorImages.emplace_back(new vk::ImageWithMemory(vkd, device, allocator, colorImageInfo, vk::MemoryRequirement::Any));
441
442 const vk::VkImageCreateInfo dsImageInfo =
443 {
444 vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
445 nullptr, // const void* pNext;
446 0u, // VkImageCreateFlags flags;
447 vk::VK_IMAGE_TYPE_2D, // VkImageType imageType;
448 dsFormat, // VkFormat format;
449 kFramebufferExtent, // VkExtent3D extent;
450 1u, // deUint32 mipLevels;
451 1u, // deUint32 arrayLayers;
452 vk::VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
453 vk::VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
454 kDSUsage, // VkImageUsageFlags usage;
455 vk::VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
456 1u, // deUint32 queueFamilyIndexCount;
457 &queueIndex, // const deUint32* pQueueFamilyIndices;
458 vk::VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
459 };
460 for (deUint32 i = 0u; i < kNumIterations; ++i)
461 dsImages.emplace_back(new vk::ImageWithMemory(vkd, device, allocator, dsImageInfo, vk::MemoryRequirement::Any));
462
463 const auto colorSubresourceRange = vk::makeImageSubresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
464 const auto dsSubresourceRange = vk::makeImageSubresourceRange((vk::VK_IMAGE_ASPECT_DEPTH_BIT | vk::VK_IMAGE_ASPECT_STENCIL_BIT), 0u, 1u, 0u, 1u);
465
466 ImageViewVec colorImageViews;
467 ImageViewVec dsImageViews;
468
469 for (const auto& img : colorImages)
470 colorImageViews.emplace_back(vk::makeImageView(vkd, device, img->get(), vk::VK_IMAGE_VIEW_TYPE_2D, kColorFormat, colorSubresourceRange));
471
472 for (const auto& img : dsImages)
473 dsImageViews.emplace_back(vk::makeImageView(vkd, device, img->get(), vk::VK_IMAGE_VIEW_TYPE_2D, dsFormat, dsSubresourceRange));
474
475 // Vertex buffer.
476 // Full-screen triangle fan with 6 vertices.
477 //
478 // 4 3 2
479 // +-------+-------+
480 // |X X X|
481 // | X X X |
482 // | X X X |
483 // | X X X |
484 // | X X X |
485 // | X X X |
486 // | XXX |
487 // +-------+-------+
488 // 5 0 1
489 std::vector<float> vertices = {
490 0.0f, 1.0f,
491 1.0f, 1.0f,
492 1.0f, -1.0f,
493 0.0f, -1.0f,
494 -1.0f, -1.0f,
495 -1.0f, 1.0f,
496 };
497
498 const auto vertDataSize = vertices.size() * sizeof(float);
499 const auto vertBufferInfo = vk::makeBufferCreateInfo(static_cast<vk::VkDeviceSize>(vertDataSize), vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
500 vk::BufferWithMemory vertBuffer (vkd, device, allocator, vertBufferInfo, vk::MemoryRequirement::HostVisible);
501 auto& alloc = vertBuffer.getAllocation();
502
503 deMemcpy(reinterpret_cast<char*>(alloc.getHostPtr()), vertices.data(), vertDataSize);
504 vk::flushAlloc(vkd, device, alloc);
505
506 // Descriptor set layout.
507 vk::DescriptorSetLayoutBuilder layoutBuilder;
508 const auto descriptorSetLayout = layoutBuilder.build(vkd, device);
509
510 // Pipeline layout.
511 vk::VkShaderStageFlags pushConstantStageFlags = (vk::VK_SHADER_STAGE_VERTEX_BIT | vk::VK_SHADER_STAGE_FRAGMENT_BIT);
512
513 const vk::VkPushConstantRange pushConstantRange =
514 {
515 pushConstantStageFlags, // VkShaderStageFlags stageFlags;
516 0u, // deUint32 offset;
517 static_cast<deUint32>(sizeof(PushConstants)), // deUint32 size;
518 };
519
520 const vk::VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo =
521 {
522 vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
523 nullptr, // const void* pNext;
524 0u, // VkPipelineLayoutCreateFlags flags;
525 1u, // deUint32 setLayoutCount;
526 &descriptorSetLayout.get(), // const VkDescriptorSetLayout* pSetLayouts;
527 1u, // deUint32 pushConstantRangeCount;
528 &pushConstantRange, // const VkPushConstantRange* pPushConstantRanges;
529 };
530 const auto pipelineLayout = vk::createPipelineLayout(vkd, device, &pipelineLayoutCreateInfo);
531
532 // Render pass with single subpass.
533 std::vector<vk::VkAttachmentReference> colorAttachmentReference;
534 for (deUint32 i = 0u; i < kNumColorAttachments; ++i)
535 {
536 colorAttachmentReference.push_back(vk::VkAttachmentReference
537 {
538 i, // deUint32 attachment;
539 vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout;
540 }
541 );
542 }
543
544 const vk::VkAttachmentReference dsAttachmentReference =
545 {
546 kNumColorAttachments, // deUint32 attachment;
547 vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout layout;
548 };
549
550 const vk::VkSubpassDescription subpassDescription =
551 {
552 0u, // VkSubpassDescriptionFlags flags;
553 vk::VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
554 0u, // deUint32 inputAttachmentCount;
555 nullptr, // const VkAttachmentReference* pInputAttachments;
556 kNumColorAttachments, // deUint32 colorAttachmentCount;
557 colorAttachmentReference.data(), // const VkAttachmentReference* pColorAttachments;
558 nullptr, // const VkAttachmentReference* pResolveAttachments;
559 &dsAttachmentReference, // const VkAttachmentReference* pDepthStencilAttachment;
560 0u, // deUint32 preserveAttachmentCount;
561 nullptr, // const deUint32* pPreserveAttachments;
562 };
563
564 std::vector<vk::VkAttachmentDescription> attachmentDescriptions(
565 kNumColorAttachments,
566 vk::VkAttachmentDescription
567 {
568 0u, // VkAttachmentDescriptionFlags flags;
569 kColorFormat, // VkFormat format;
570 vk::VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
571 vk::VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
572 vk::VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
573 vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
574 vk::VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
575 vk::VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
576 vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout;
577 }
578 );
579
580 attachmentDescriptions.push_back(vk::VkAttachmentDescription
581 {
582 0u, // VkAttachmentDescriptionFlags flags;
583 dsFormat, // VkFormat format;
584 vk::VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
585 vk::VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
586 vk::VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
587 vk::VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp stencilLoadOp;
588 vk::VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp stencilStoreOp;
589 vk::VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
590 vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout;
591 });
592
593 const vk::VkRenderPassCreateInfo renderPassCreateInfo =
594 {
595 vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType;
596 nullptr, // const void* pNext;
597 0u, // VkRenderPassCreateFlags flags;
598 static_cast<deUint32>(attachmentDescriptions.size()), // deUint32 attachmentCount;
599 attachmentDescriptions.data(), // const VkAttachmentDescription* pAttachments;
600 1u, // deUint32 subpassCount;
601 &subpassDescription, // const VkSubpassDescription* pSubpasses;
602 0u, // deUint32 dependencyCount;
603 nullptr, // const VkSubpassDependency* pDependencies;
604 };
605 const auto renderPass = vk::createRenderPass(vkd, device, &renderPassCreateInfo);
606
607 // Framebuffers.
608 FramebufferVec framebuffers;
609
610 DE_ASSERT(colorImageViews.size() == dsImageViews.size() * kNumColorAttachments);
611 for (size_t imgIdx = 0; imgIdx < dsImageViews.size(); ++imgIdx)
612 {
613 std::vector<vk::VkImageView> attachments;
614 for (deUint32 i = 0u; i < kNumColorAttachments; ++i)
615 attachments.push_back(colorImageViews[imgIdx * kNumColorAttachments + i].get());
616
617 attachments.push_back(dsImageViews[imgIdx].get());
618
619 const vk::VkFramebufferCreateInfo framebufferCreateInfo =
620 {
621 vk::VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
622 nullptr, // const void* pNext;
623 0u, // VkFramebufferCreateFlags flags;
624 renderPass.get(), // VkRenderPass renderPass;
625 static_cast<deUint32>(attachments.size()), // deUint32 attachmentCount;
626 attachments.data(), // const VkImageView* pAttachments;
627 kFramebufferWidth, // deUint32 width;
628 kFramebufferHeight, // deUint32 height;
629 1u, // deUint32 layers;
630 };
631
632 framebuffers.emplace_back(vk::createFramebuffer(vkd, device, &framebufferCreateInfo));
633 }
634
635 // Shader modules.
636 const auto vertModule = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("vert"), 0u);
637 const auto fragModule = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("frag"), 0u);
638
639 // Shader stages.
640 std::vector<vk::VkPipelineShaderStageCreateInfo> shaderStages;
641
642 vk::VkPipelineShaderStageCreateInfo shaderStageCreateInfo =
643 {
644 vk::VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
645 nullptr, // const void* pNext;
646 0u, // VkPipelineShaderStageCreateFlags flags;
647 vk::VK_SHADER_STAGE_VERTEX_BIT, // VkShaderStageFlagBits stage;
648 vertModule.get(), // VkShaderModule module;
649 "main", // const char* pName;
650 nullptr, // const VkSpecializationInfo* pSpecializationInfo;
651 };
652
653 shaderStages.push_back(shaderStageCreateInfo);
654 shaderStageCreateInfo.stage = vk::VK_SHADER_STAGE_FRAGMENT_BIT;
655 shaderStageCreateInfo.module = fragModule.get();
656 shaderStages.push_back(shaderStageCreateInfo);
657
658 // Input state.
659 const auto vertexBinding = vk::makeVertexInputBindingDescription(0u, kCoordsSize, vk::VK_VERTEX_INPUT_RATE_VERTEX);
660 const std::vector<vk::VkVertexInputAttributeDescription> vertexAttributes = {
661 vk::makeVertexInputAttributeDescription(0u, 0u, vk::VK_FORMAT_R32G32_SFLOAT, 0u)
662 };
663
664 const vk::VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo =
665 {
666 vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
667 nullptr, // const void* pNext;
668 0u, // VkPipelineVertexInputStateCreateFlags flags;
669 1u, // deUint32 vertexBindingDescriptionCount;
670 &vertexBinding, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
671 static_cast<deUint32>(vertexAttributes.size()), // deUint32 vertexAttributeDescriptionCount;
672 vertexAttributes.data(), // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
673 };
674
675 // Input assembly.
676 const vk::VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo =
677 {
678 vk::VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType;
679 nullptr, // const void* pNext;
680 0u, // VkPipelineInputAssemblyStateCreateFlags flags;
681 vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN, // VkPrimitiveTopology topology;
682 VK_FALSE, // VkBool32 primitiveRestartEnable;
683 };
684
685 // Viewport state.
686 const vk::VkViewport viewport (vk::makeViewport(kFramebufferWidth, kFramebufferHeight));
687 const vk::VkRect2D scissor (vk::makeRect2D(kFramebufferWidth, kFramebufferHeight));
688
689 // For the static pipeline.
690 const vk::VkPipelineViewportStateCreateInfo viewportStateCreateInfo =
691 {
692 vk::VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType;
693 nullptr, // const void* pNext;
694 0u, // VkPipelineViewportStateCreateFlags flags;
695 1u, // deUint32 viewportCount;
696 &viewport, // const VkViewport* pViewports;
697 1u, // deUint32 scissorCount;
698 &scissor, // const VkRect2D* pScissors;
699 };
700
701 // Rasterization state.
702 const vk::VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo =
703 {
704 vk::VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
705 nullptr, // const void* pNext;
706 0u, // VkPipelineRasterizationStateCreateFlags flags;
707 VK_FALSE, // VkBool32 depthClampEnable;
708 VK_FALSE, // VkBool32 rasterizerDiscardEnable;
709 vk::VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode;
710 vk::VK_CULL_MODE_NONE, // VkCullModeFlags cullMode;
711 vk::VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace;
712 VK_FALSE, // VkBool32 depthBiasEnable;
713 0.0f, // float depthBiasConstantFactor;
714 0.0f, // float depthBiasClamp;
715 0.0f, // float depthBiasSlopeFactor;
716 1.0f, // float lineWidth;
717 };
718
719 // Multisample state.
720 const vk::VkPipelineMultisampleStateCreateInfo multisampleStateCreateInfo =
721 {
722 vk::VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
723 nullptr, // const void* pNext;
724 0u, // VkPipelineMultisampleStateCreateFlags flags;
725 vk::VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples;
726 VK_FALSE, // VkBool32 sampleShadingEnable;
727 0.0f, // float minSampleShading;
728 nullptr, // const VkSampleMask* pSampleMask;
729 VK_FALSE, // VkBool32 alphaToCoverageEnable;
730 VK_FALSE, // VkBool32 alphaToOneEnable;
731 };
732
733 // Depth/stencil state.
734 const vk::VkStencilOpState stencil =
735 {
736 vk::VK_STENCIL_OP_KEEP, // VkStencilOp failOp;
737 vk::VK_STENCIL_OP_KEEP, // VkStencilOp passOp;
738 vk::VK_STENCIL_OP_KEEP, // VkStencilOp depthFailOp;
739 vk::VK_COMPARE_OP_ALWAYS, // VkCompareOp compareOp;
740 0xFFu, // deUint32 compareMask;
741 0xFFu, // deUint32 writeMask;
742 0u, // deUint32 reference;
743 };
744
745 const vk::VkPipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo =
746 {
747 vk::VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
748 nullptr, // const void* pNext;
749 0u, // VkPipelineDepthStencilStateCreateFlags flags;
750 VK_TRUE, // VkBool32 depthTestEnable;
751 VK_TRUE, // VkBool32 depthWriteEnable;
752 vk::VK_COMPARE_OP_LESS, // VkCompareOp depthCompareOp;
753 VK_FALSE, // VkBool32 depthBoundsTestEnable;
754 VK_FALSE, // VkBool32 stencilTestEnable;
755 stencil, // VkStencilOpState front;
756 stencil, // VkStencilOpState back;
757 0.0f, // float minDepthBounds;
758 1.0f, // float maxDepthBounds;
759 };
760
761 // Dynamic state. Here we will set all states which have a dynamic value.
762 std::vector<vk::VkDynamicState> dynamicStates;
763
764 if (m_testConfig.colorWriteEnableConfig.dynamicValue)
765 dynamicStates.push_back(vk::VK_DYNAMIC_STATE_COLOR_WRITE_ENABLE_EXT);
766
767 const vk::VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo =
768 {
769 vk::VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType;
770 nullptr, // const void* pNext;
771 0u, // VkPipelineDynamicStateCreateFlags flags;
772 static_cast<deUint32>(dynamicStates.size()), // deUint32 dynamicStateCount;
773 dynamicStates.data(), // const VkDynamicState* pDynamicStates;
774 };
775
776 std::vector<vk::VkPipelineColorBlendAttachmentState> colorBlendAttachmentState(
777 kNumColorAttachments,
778 vk::VkPipelineColorBlendAttachmentState
779 {
780 VK_FALSE, // VkBool32 blendEnable
781 vk::VK_BLEND_FACTOR_ZERO, // VkBlendFactor srcColorBlendFactor
782 vk::VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstColorBlendFactor
783 vk::VK_BLEND_OP_ADD, // VkBlendOp colorBlendOp
784 vk::VK_BLEND_FACTOR_ZERO, // VkBlendFactor srcAlphaBlendFactor
785 vk::VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstAlphaBlendFactor
786 vk::VK_BLEND_OP_ADD, // VkBlendOp alphaBlendOp
787 static_cast<vk::VkColorComponentFlags>( // VkColorComponentFlags colorWriteMask
788 (m_testConfig.channelMask.x() ? vk::VK_COLOR_COMPONENT_R_BIT : 0)
789 | (m_testConfig.channelMask.y() ? vk::VK_COLOR_COMPONENT_G_BIT : 0)
790 | (m_testConfig.channelMask.z() ? vk::VK_COLOR_COMPONENT_B_BIT : 0)
791 | (m_testConfig.channelMask.w() ? vk::VK_COLOR_COMPONENT_A_BIT : 0)
792 )
793 }
794 );
795
796 const vk::VkPipelineColorWriteCreateInfoEXT colorWriteCreateInfo =
797 {
798 vk::VK_STRUCTURE_TYPE_PIPELINE_COLOR_WRITE_CREATE_INFO_EXT, // VkStructureType sType;
799 nullptr, // const void* pNext;
800 kNumColorAttachments, // deUint32 attachmentCount;
801 m_testConfig.colorWriteEnableConfig.staticValue.data() // const VkBool32* pColorWriteEnables;
802 };
803
804 const vk::VkPipelineColorBlendStateCreateInfo colorBlendStateCreateInfo =
805 {
806 vk::VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType
807 &colorWriteCreateInfo, // const void* pNext
808 0u, // VkPipelineColorBlendStateCreateFlags flags
809 VK_FALSE, // VkBool32 logicOpEnable
810 vk::VK_LOGIC_OP_CLEAR, // VkLogicOp logicOp
811 kNumColorAttachments, // deUint32 attachmentCount
812 colorBlendAttachmentState.data(), // const VkPipelineColorBlendAttachmentState* pAttachments
813 { 0.0f, 0.0f, 0.0f, 0.0f } // float blendConstants[4]
814 };
815
816 const vk::VkGraphicsPipelineCreateInfo graphicsPipelineCreateInfoTemplate =
817 {
818 vk::VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // VkStructureType sType;
819 nullptr, // const void* pNext;
820 0u, // VkPipelineCreateFlags flags;
821 static_cast<deUint32>(shaderStages.size()), // deUint32 stageCount;
822 shaderStages.data(), // const VkPipelineShaderStageCreateInfo* pStages;
823 &vertexInputStateCreateInfo, // const VkPipelineVertexInputStateCreateInfo* pVertexInputState;
824 &inputAssemblyStateCreateInfo, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState;
825 nullptr, // const VkPipelineTessellationStateCreateInfo* pTessellationState;
826 nullptr, // const VkPipelineViewportStateCreateInfo* pViewportState;
827 &rasterizationStateCreateInfo, // const VkPipelineRasterizationStateCreateInfo* pRasterizationState;
828 &multisampleStateCreateInfo, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState;
829 &depthStencilStateCreateInfo, // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState;
830 &colorBlendStateCreateInfo, // const VkPipelineColorBlendStateCreateInfo* pColorBlendState;
831 nullptr, // const VkPipelineDynamicStateCreateInfo* pDynamicState;
832 pipelineLayout.get(), // VkPipelineLayout layout;
833 renderPass.get(), // VkRenderPass renderPass;
834 0u, // deUint32 subpass;
835 DE_NULL, // VkPipeline basePipelineHandle;
836 0, // deInt32 basePipelineIndex;
837 };
838
839 vk::Move<vk::VkPipeline> staticPipeline;
840 const bool bindStaticFirst = (kSequenceOrdering == SequenceOrdering::BETWEEN_PIPELINES ||
841 kSequenceOrdering == SequenceOrdering::AFTER_PIPELINES ||
842 kSequenceOrdering == SequenceOrdering::TWO_DRAWS_DYNAMIC);
843 const bool useStaticPipeline = (bindStaticFirst || kReversed);
844
845 // Create static pipeline when needed.
846 if (useStaticPipeline)
847 {
848 auto staticPipelineCreateInfo = graphicsPipelineCreateInfoTemplate;
849 staticPipelineCreateInfo.pViewportState = &viewportStateCreateInfo;
850 staticPipeline = vk::createGraphicsPipeline(vkd, device, DE_NULL, &staticPipelineCreateInfo);
851 }
852
853 // Create dynamic pipeline.
854 vk::Move<vk::VkPipeline> graphicsPipeline;
855 {
856 auto dynamicPipelineCreateInfo = graphicsPipelineCreateInfoTemplate;
857 dynamicPipelineCreateInfo.pDynamicState = &dynamicStateCreateInfo;
858 dynamicPipelineCreateInfo.pViewportState = &viewportStateCreateInfo;
859 graphicsPipeline = vk::createGraphicsPipeline(vkd, device, DE_NULL, &dynamicPipelineCreateInfo);
860 }
861
862 // Command buffer.
863 const auto cmdPool = vk::makeCommandPool(vkd, device, queueIndex);
864 const auto cmdBufferPtr = vk::allocateCommandBuffer(vkd , device, cmdPool.get(), vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
865 const auto cmdBuffer = cmdBufferPtr.get();
866
867 // Clear values.
868 std::vector<vk::VkClearValue> clearValues;
869 auto colorClearValue = vk::makeClearValueColor(m_testConfig.clearColorValue);
870 for (deUint32 i = 0u; i < kNumColorAttachments; ++i)
871 clearValues.push_back(colorClearValue);
872 clearValues.push_back(vk::makeClearValueDepthStencil(m_testConfig.clearDepthValue, 0u));
873
874 // Record command buffer.
875 vk::beginCommandBuffer(vkd, cmdBuffer);
876
877 for (deUint32 iteration = 0u; iteration < kNumIterations; ++iteration)
878 {
879 // Maybe set dynamic state here.
880 if (kSequenceOrdering == SequenceOrdering::CMD_BUFFER_START)
881 {
882 setDynamicStates(m_testConfig, vkd, cmdBuffer);
883 }
884
885 // Begin render pass.
886 vk::beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffers[iteration].get(), vk::makeRect2D(kFramebufferWidth, kFramebufferHeight), static_cast<deUint32>(clearValues.size()), clearValues.data());
887
888 // Bind a static pipeline first if needed.
889 if (bindStaticFirst && iteration == 0u)
890 {
891 vkd.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, staticPipeline.get());
892 }
893
894 // Maybe set dynamic state here.
895 if (kSequenceOrdering == SequenceOrdering::BETWEEN_PIPELINES)
896 {
897 setDynamicStates(m_testConfig, vkd, cmdBuffer);
898 }
899
900 // Bind dynamic pipeline.
901 if ((kSequenceOrdering != SequenceOrdering::TWO_DRAWS_DYNAMIC &&
902 kSequenceOrdering != SequenceOrdering::TWO_DRAWS_STATIC) ||
903 (kSequenceOrdering == SequenceOrdering::TWO_DRAWS_DYNAMIC && iteration > 0u) ||
904 (kSequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC && iteration == 0u))
905 {
906 vkd.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline.get());
907 }
908
909 if (kSequenceOrdering == SequenceOrdering::BEFORE_GOOD_STATIC ||
910 (kSequenceOrdering == SequenceOrdering::TWO_DRAWS_DYNAMIC && iteration > 0u) ||
911 (kSequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC && iteration == 0u))
912 {
913 setDynamicStates(m_testConfig, vkd, cmdBuffer);
914 }
915
916 // Bind a static pipeline last if needed.
917 if (kSequenceOrdering == SequenceOrdering::BEFORE_GOOD_STATIC ||
918 (kSequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC && iteration > 0u))
919 {
920 vkd.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, staticPipeline.get());
921 }
922
923 // Push constants.
924 PushConstants pushConstants =
925 {
926 m_testConfig.meshParams.color, // tcu::Vec4 triangleColor;
927 m_testConfig.meshParams.depth, // float meshDepth;
928 m_testConfig.meshParams.scaleX, // float scaleX;
929 m_testConfig.meshParams.scaleY, // float scaleY;
930 m_testConfig.meshParams.offsetX, // float offsetX;
931 m_testConfig.meshParams.offsetY, // float offsetY;
932 };
933 vkd.cmdPushConstants(cmdBuffer, pipelineLayout.get(), pushConstantStageFlags, 0u, static_cast<deUint32>(sizeof(pushConstants)), &pushConstants);
934
935 // Maybe set dynamic state here.
936 if (kSequenceOrdering == SequenceOrdering::BEFORE_DRAW || kSequenceOrdering == SequenceOrdering::AFTER_PIPELINES)
937 {
938 setDynamicStates(m_testConfig, vkd, cmdBuffer);
939 }
940
941 // Bind vertex buffer and draw.
942 vk::VkDeviceSize offset = 0ull;
943 vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &vertBuffer.get(), &offset);
944 vkd.cmdDraw(cmdBuffer, 6u, 1u, 0u, 0u);
945
946 vk::endRenderPass(vkd, cmdBuffer);
947 }
948
949 vk::endCommandBuffer(vkd, cmdBuffer);
950
951 // Submit commands.
952 vk::submitCommandsAndWait(vkd, device, queue, cmdBuffer);
953
954 // Read result image aspects from the last used framebuffer.
955 const tcu::UVec2 renderSize(kFramebufferWidth, kFramebufferHeight);
956
957 const int kWidth = static_cast<int>(kFramebufferWidth);
958 const int kHeight = static_cast<int>(kFramebufferHeight);
959
960 const tcu::Vec4 kGood(0.0f, 1.0f, 0.0f, 1.0f);
961 const tcu::Vec4 kBad(1.0f, 0.0f, 0.0f, 1.0f);
962
963 const tcu::TextureFormat errorFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8);
964
965 bool colorMatchAll = true;
966
967 // Check expected values.
968 auto nextAttachmentImage = colorImages.end() - kNumColorAttachments;
969 for (deUint32 attachmentIndex = 0u; attachmentIndex < kNumColorAttachments; ++attachmentIndex, ++nextAttachmentImage)
970 {
971 const auto colorBuffer = readColorAttachment(vkd, device, queue, queueIndex, allocator, (*nextAttachmentImage)->get(), kColorFormat, renderSize);
972 const auto colorAccess = colorBuffer->getAccess();
973
974 tcu::TextureLevel colorError (errorFormat, kWidth, kHeight);
975 const auto colorErrorAccess = colorError.getAccess();
976
977 bool colorMatch = true;
978
979 for (int y = 0; y < kHeight; ++y)
980 for (int x = 0; x < kWidth; ++x)
981 {
982 const auto colorPixel = colorAccess.getPixel(x, y);
983
984 bool match = tcu::boolAll(tcu::lessThan(tcu::absDiff(colorPixel, m_testConfig.expectedColor[attachmentIndex]), kColorThreshold));
985 colorErrorAccess.setPixel((match ? kGood : kBad), x, y);
986 if (!match)
987 colorMatch = false;
988 }
989
990 if (!colorMatch)
991 {
992 std::ostringstream desc;
993 desc << "Result color image and error mask for attachment #" << attachmentIndex;
994 logErrors(log, "Color", desc.str(), colorAccess, colorErrorAccess);
995 colorMatchAll = false;
996 }
997 }
998
999 const auto depthBuffer = readDepthAttachment(vkd, device, queue, queueIndex, allocator, dsImages.back()->get(), dsFormat, renderSize);
1000 const auto depthAccess = depthBuffer->getAccess();
1001 tcu::TextureLevel depthError(errorFormat, kWidth, kHeight);
1002 const auto depthErrorAccess = depthError.getAccess();
1003
1004 const auto minDepth = m_testConfig.expectedDepth - 1.0e-07f;
1005 const auto maxDepth = m_testConfig.expectedDepth + 1.0e-07f;
1006 bool depthMatch = true;
1007
1008 for (int y = 0; y < kHeight; ++y)
1009 for (int x = 0; x < kWidth; ++x)
1010 {
1011 const auto depthPixel = depthAccess.getPixDepth(x, y);
1012 bool match = de::inRange(depthPixel, minDepth, maxDepth);
1013 depthErrorAccess.setPixel((match ? kGood : kBad), x, y);
1014 if (!match)
1015 depthMatch = false;
1016 }
1017
1018 if (!depthMatch)
1019 {
1020 logErrors(log, "Depth", "Result depth image and error mask", depthAccess, depthErrorAccess);
1021 }
1022
1023 if (!(colorMatchAll && depthMatch))
1024 {
1025 return tcu::TestStatus::fail("Incorrect value found in attachments; please check logged images");
1026 }
1027
1028 return tcu::TestStatus::pass("Pass");
1029 }
1030
1031 template <typename VectorType>
MaskVector(const VectorType & valueIfMaskIsFalse,const VectorType & valueIfMaskIsTrue,const std::vector<bool> & mask,bool inverse=false)1032 VectorType MaskVector(const VectorType& valueIfMaskIsFalse, const VectorType& valueIfMaskIsTrue, const std::vector<bool>& mask, bool inverse = false)
1033 {
1034 DE_ASSERT(valueIfMaskIsFalse.size() == valueIfMaskIsTrue.size() && valueIfMaskIsFalse.size() == mask.size());
1035
1036 VectorType ret(mask.size());
1037
1038 for (size_t i = 0; i < mask.size(); ++i)
1039 {
1040 bool m = mask[i];
1041 if (inverse)
1042 m = !m;
1043 ret[i] = m ? valueIfMaskIsTrue[i] : valueIfMaskIsFalse[i];
1044 }
1045
1046 return ret;
1047 }
1048
ApplyChannelMask(std::vector<tcu::Vec4> & meshColors,const tcu::BVec4 & channelMask,const tcu::Vec4 & clearColor)1049 void ApplyChannelMask(std::vector<tcu::Vec4>& meshColors, const tcu::BVec4& channelMask, const tcu::Vec4& clearColor)
1050 {
1051 for (auto&& attachmentColor : meshColors)
1052 attachmentColor = tcu::Vec4(
1053 channelMask.x() ? attachmentColor.x() : clearColor.x(),
1054 channelMask.y() ? attachmentColor.y() : clearColor.y(),
1055 channelMask.z() ? attachmentColor.z() : clearColor.z(),
1056 channelMask.w() ? attachmentColor.w() : clearColor.w()
1057 );
1058 }
1059
AddSingleTestCaseStatic(const std::string & name,const std::string & description,const std::vector<bool> mask,const tcu::BVec4 channelMask,bool inverse,tcu::TestCaseGroup * orderingGroup,tcu::TestContext & testCtx)1060 void AddSingleTestCaseStatic(
1061 const std::string& name,
1062 const std::string& description,
1063 const std::vector<bool> mask,
1064 const tcu::BVec4 channelMask,
1065 bool inverse,
1066 tcu::TestCaseGroup* orderingGroup,
1067 tcu::TestContext& testCtx)
1068 {
1069 TestConfig config(SequenceOrdering::CMD_BUFFER_START);
1070
1071 // Enable writes and expect the mesh color, or disable writes and expect the clear color.
1072
1073 config.clearColorValue = tcu::Vec4(0.25f, 0.5f, 0.75f, 0.5f);
1074 config.meshParams.color = tcu::Vec4(1.0f, 0.75f, 0.5f, 0.25f);
1075
1076 const auto allVkFalse = Bool32Vec(kNumColorAttachments, VK_FALSE);
1077 const auto allVkTrue = Bool32Vec(kNumColorAttachments, VK_TRUE);
1078
1079 config.channelMask = channelMask;
1080
1081 config.colorWriteEnableConfig.staticValue = MaskVector(allVkFalse, allVkTrue, mask, inverse);
1082
1083 // Note colorWriteEnableConfig.dynamicValue is unset, defaults to an empty Maybe<T>
1084
1085 std::vector<tcu::Vec4> meshColorsPerAttachment(kNumColorAttachments);
1086 meshColorsPerAttachment[0] = config.meshParams.color;
1087 for (deUint32 i = 1u; i < kNumColorAttachments; ++i)
1088 meshColorsPerAttachment[i] = meshColorsPerAttachment[i - 1] * 0.5f;
1089
1090 std::vector<tcu::Vec4> clearColorsPerAttachment(kNumColorAttachments, config.clearColorValue);
1091
1092 ApplyChannelMask(meshColorsPerAttachment, channelMask, config.clearColorValue);
1093
1094 config.expectedColor = MaskVector(clearColorsPerAttachment, meshColorsPerAttachment, mask, inverse);
1095
1096 // Depth should always be written even when color is not
1097 config.clearDepthValue = 0.5f;
1098 config.meshParams.depth = 0.25f;
1099 config.expectedDepth = 0.25f;
1100
1101 orderingGroup->addChild(new ColorWriteEnableTest(testCtx, name, description, config));
1102 }
1103
AddSingleTestCaseDynamic(const std::string & name,const std::string & description,const std::vector<bool> mask,const tcu::BVec4 channelMask,bool inverse,tcu::TestCaseGroup * orderingGroup,tcu::TestContext & testCtx,SequenceOrdering ordering)1104 void AddSingleTestCaseDynamic(
1105 const std::string& name,
1106 const std::string& description,
1107 const std::vector<bool> mask,
1108 const tcu::BVec4 channelMask,
1109 bool inverse,
1110 tcu::TestCaseGroup* orderingGroup,
1111 tcu::TestContext& testCtx,
1112 SequenceOrdering ordering)
1113 {
1114 TestConfig config(ordering);
1115
1116 // Enable writes and expect the mesh color, or disable writes and expect the clear color.
1117
1118 config.clearColorValue = tcu::Vec4(0.25f, 0.5f, 0.75f, 0.5f);
1119 config.meshParams.color = tcu::Vec4(1.0f, 0.75f, 0.5f, 0.25f);
1120
1121 const auto allVkFalse = Bool32Vec(kNumColorAttachments, VK_FALSE);
1122 const auto allVkTrue = Bool32Vec(kNumColorAttachments, VK_TRUE);
1123
1124 config.channelMask = channelMask;
1125
1126 config.colorWriteEnableConfig.staticValue = inverse ? allVkTrue : allVkFalse;
1127 config.colorWriteEnableConfig.dynamicValue = MaskVector(allVkFalse, allVkTrue, mask, inverse);
1128
1129 std::vector<tcu::Vec4> meshColorsPerAttachment(kNumColorAttachments);
1130 meshColorsPerAttachment[0] = config.meshParams.color;
1131 for (deUint32 i = 1u; i < kNumColorAttachments; ++i)
1132 meshColorsPerAttachment[i] = meshColorsPerAttachment[i - 1] * 0.5f;
1133
1134 std::vector<tcu::Vec4> clearColorsPerAttachment(kNumColorAttachments, config.clearColorValue);
1135
1136 ApplyChannelMask(meshColorsPerAttachment, channelMask, config.clearColorValue);
1137
1138 config.expectedColor = MaskVector(clearColorsPerAttachment, meshColorsPerAttachment, mask, inverse);
1139
1140 // Depth should always be written even when color is not
1141 config.clearDepthValue = 0.5f;
1142 config.meshParams.depth = 0.25f;
1143 config.expectedDepth = 0.25f;
1144
1145 orderingGroup->addChild(new ColorWriteEnableTest(testCtx, name, description, config));
1146 }
1147
1148 } // anonymous namespace
1149
createColorWriteEnableTests(tcu::TestContext & testCtx)1150 tcu::TestCaseGroup* createColorWriteEnableTests (tcu::TestContext& testCtx)
1151 {
1152 de::MovePtr<tcu::TestCaseGroup> colorWriteEnableGroup(new tcu::TestCaseGroup(testCtx, "color_write_enable", "Tests for VK_EXT_color_write_enable"));
1153
1154 DE_ASSERT(kNumColorAttachments >= 2);
1155
1156 std::vector<bool> mask_all (kNumColorAttachments, true);
1157 std::vector<bool> mask_first (kNumColorAttachments, false); mask_first[0] = true;
1158 std::vector<bool> mask_second (kNumColorAttachments, false); mask_second[1] = true;
1159 std::vector<bool> mask_last (kNumColorAttachments, false); mask_last.back() = true;
1160 std::vector<bool> mask_first_and_second (kNumColorAttachments, false); mask_first_and_second[0] = mask_first_and_second[1] = true;
1161 std::vector<bool> mask_second_and_last (kNumColorAttachments, false); mask_second_and_last[1] = mask_second_and_last.back() = true;
1162
1163 // Test cases for channel enables
1164 static const struct
1165 {
1166 tcu::BVec4 enabledChannels;
1167 std::string name;
1168 std::string desc;
1169 } kChannelCases[] =
1170 {
1171 { tcu::BVec4(true, true, true, true), "all_channels", "Enable all channels in colorWriteMask"},
1172 { tcu::BVec4(true, false, false, false), "red_channel", "Red channel enabled in colorWriteMask"},
1173 { tcu::BVec4(false, true, false, false), "green_channel", "Green channel enabled in colorWriteMask"},
1174 { tcu::BVec4(false, false, true, false), "blue_channel", "Blue channel enabled in colorWriteMask"},
1175 { tcu::BVec4(false, false, false, true), "alpha_channel", "Alpha channel enabled in colorWriteMask"},
1176 { tcu::BVec4(false, false, false, false), "no_channels", "Disable all channels in colorWriteMask"},
1177 };
1178
1179 // Test cases for the dynamic state
1180 static const struct
1181 {
1182 SequenceOrdering ordering;
1183 std::string name;
1184 std::string desc;
1185 } kOrderingCases[] =
1186 {
1187 { SequenceOrdering::CMD_BUFFER_START, "cmd_buffer_start", "Dynamic state set after command buffer start" },
1188 { SequenceOrdering::BEFORE_DRAW, "before_draw", "Dynamic state set just before drawing" },
1189 { 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" },
1190 { SequenceOrdering::AFTER_PIPELINES, "after_pipelines", "Dynamic state set after both a static-state pipeline and a second dynamic-state pipeline have been bound" },
1191 { 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" },
1192 { SequenceOrdering::TWO_DRAWS_DYNAMIC, "two_draws_dynamic", "Bind bad static pipeline and draw, followed by binding correct dynamic pipeline and drawing again" },
1193 { SequenceOrdering::TWO_DRAWS_STATIC, "two_draws_static", "Bind bad dynamic pipeline and draw, followed by binding correct static pipeline and drawing again" },
1194 };
1195
1196 for (int channelCaseIdx = 0; channelCaseIdx < DE_LENGTH_OF_ARRAY(kChannelCases); ++channelCaseIdx)
1197 {
1198 const auto& kChannelCase = kChannelCases[channelCaseIdx];
1199 de::MovePtr<tcu::TestCaseGroup> channelGroup(new tcu::TestCaseGroup(testCtx, kChannelCase.name.c_str(), kChannelCase.desc.c_str()));
1200
1201 for (int orderingIdx = 0; orderingIdx < DE_LENGTH_OF_ARRAY(kOrderingCases); ++orderingIdx)
1202 {
1203 const auto& kOrderingCase = kOrderingCases[orderingIdx];
1204 const auto& kOrdering = kOrderingCase.ordering;
1205
1206 de::MovePtr<tcu::TestCaseGroup> orderingGroup(new tcu::TestCaseGroup(testCtx, kOrderingCase.name.c_str(), kOrderingCase.desc.c_str()));
1207
1208 AddSingleTestCaseDynamic("enable_all", "Dynamically enable writes to all color attachments", mask_all, kChannelCase.enabledChannels, false, orderingGroup.get(), testCtx, kOrdering);
1209 AddSingleTestCaseDynamic("enable_first", "Dynamically enable writes to the first color attachment", mask_first, kChannelCase.enabledChannels, false, orderingGroup.get(), testCtx, kOrdering);
1210 AddSingleTestCaseDynamic("enable_second", "Dynamically enable writes to the second color attachment", mask_second, kChannelCase.enabledChannels, false, orderingGroup.get(), testCtx, kOrdering);
1211 AddSingleTestCaseDynamic("enable_last", "Dynamically enable writes to the last color attachment", mask_last, kChannelCase.enabledChannels, false, orderingGroup.get(), testCtx, kOrdering);
1212 AddSingleTestCaseDynamic("enable_first_and_second", "Dynamically enable writes to the first two color attachments", mask_first_and_second, kChannelCase.enabledChannels, false, orderingGroup.get(), testCtx, kOrdering);
1213 AddSingleTestCaseDynamic("enable_second_and_last", "Dynamically enable writes to the second and last color attachments", mask_second_and_last, kChannelCase.enabledChannels, false, orderingGroup.get(), testCtx, kOrdering);
1214
1215 AddSingleTestCaseDynamic("disable_all", "Dynamically disable writes to all color attachments", mask_all, kChannelCase.enabledChannels, true, orderingGroup.get(), testCtx, kOrdering);
1216 AddSingleTestCaseDynamic("disable_first", "Dynamically disable writes to the first color attachment", mask_first, kChannelCase.enabledChannels, true, orderingGroup.get(), testCtx, kOrdering);
1217 AddSingleTestCaseDynamic("disable_second", "Dynamically disable writes to the second color attachment", mask_second, kChannelCase.enabledChannels, true, orderingGroup.get(), testCtx, kOrdering);
1218 AddSingleTestCaseDynamic("disable_last", "Dynamically disable writes to the last color attachment", mask_last, kChannelCase.enabledChannels, true, orderingGroup.get(), testCtx, kOrdering);
1219 AddSingleTestCaseDynamic("disable_first_and_second", "Dynamically disable writes to the first two color attachments", mask_first_and_second, kChannelCase.enabledChannels, true, orderingGroup.get(), testCtx, kOrdering);
1220 AddSingleTestCaseDynamic("disable_second_and_last", "Dynamically disable writes to the second and last color attachments", mask_second_and_last, kChannelCase.enabledChannels, true, orderingGroup.get(), testCtx, kOrdering);
1221
1222 channelGroup->addChild(orderingGroup.release());
1223 }
1224
1225 // Test cases for the static state
1226 // Note that the dynamic state test cases above also test pipelines with static state (when ordering is BEFORE_GOOD_STATIC and TWO_DRAWS_STATIC).
1227 // However they all bind a pipeline with the static state AFTER binding a pipeline with the dynamic state.
1228 // The only case missing, then, is static state alone without any dynamic pipelines in the same render pass or command buffer.
1229 de::MovePtr<tcu::TestCaseGroup> staticOrderingGroup(new tcu::TestCaseGroup(testCtx, "static", "Static state set"));
1230
1231 AddSingleTestCaseStatic("enable_all", "Statically enable writes to all color attachments", mask_all, kChannelCase.enabledChannels, false, staticOrderingGroup.get(), testCtx);
1232 AddSingleTestCaseStatic("enable_first", "Statically enable writes to the first color attachment", mask_first, kChannelCase.enabledChannels, false, staticOrderingGroup.get(), testCtx);
1233 AddSingleTestCaseStatic("enable_second", "Statically enable writes to the second color attachment", mask_second, kChannelCase.enabledChannels, false, staticOrderingGroup.get(), testCtx);
1234 AddSingleTestCaseStatic("enable_last", "Statically enable writes to the last color attachment", mask_last, kChannelCase.enabledChannels, false, staticOrderingGroup.get(), testCtx);
1235 AddSingleTestCaseStatic("enable_first_and_second", "Statically enable writes to the first two color attachments", mask_first_and_second, kChannelCase.enabledChannels, false, staticOrderingGroup.get(), testCtx);
1236 AddSingleTestCaseStatic("enable_second_and_last", "Statically enable writes to the second and last color attachments", mask_second_and_last, kChannelCase.enabledChannels, false, staticOrderingGroup.get(), testCtx);
1237
1238 AddSingleTestCaseStatic("disable_all", "Statically disable writes to all color attachments", mask_all, kChannelCase.enabledChannels, true, staticOrderingGroup.get(), testCtx);
1239 AddSingleTestCaseStatic("disable_first", "Statically disable writes to the first color attachment", mask_first, kChannelCase.enabledChannels, true, staticOrderingGroup.get(), testCtx);
1240 AddSingleTestCaseStatic("disable_second", "Statically disable writes to the second color attachment", mask_second, kChannelCase.enabledChannels, true, staticOrderingGroup.get(), testCtx);
1241 AddSingleTestCaseStatic("disable_last", "Statically disable writes to the last color attachment", mask_last, kChannelCase.enabledChannels, true, staticOrderingGroup.get(), testCtx);
1242 AddSingleTestCaseStatic("disable_first_and_second", "Statically disable writes to the first two color attachments", mask_first_and_second, kChannelCase.enabledChannels, true, staticOrderingGroup.get(), testCtx);
1243 AddSingleTestCaseStatic("disable_second_and_last", "Statically disable writes to the second and last color attachments", mask_second_and_last, kChannelCase.enabledChannels, true, staticOrderingGroup.get(), testCtx);
1244
1245 channelGroup->addChild(staticOrderingGroup.release());
1246
1247 colorWriteEnableGroup->addChild(channelGroup.release());
1248 }
1249
1250 return colorWriteEnableGroup.release();
1251 }
1252
1253 } // pipeline
1254 } // vkt
1255