1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2019 The Khronos Group Inc.
6 * Copyright (c) 2019 Google Inc.
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 *//*!
21 * \file
22 * \brief Tests for multiple interpolation decorations in a shader stage
23 *//*--------------------------------------------------------------------*/
24
25 #include "vktDrawMultipleInterpolationTests.hpp"
26
27 #include "tcuStringTemplate.hpp"
28 #include "vkCmdUtil.hpp"
29 #include "vkQueryUtil.hpp"
30 #include "vkTypeUtil.hpp"
31 #include "vkQueryUtil.hpp"
32 #include "vktDrawBaseClass.hpp"
33 #include "vktTestGroupUtil.hpp"
34 #include "tcuVectorUtil.hpp"
35
36 namespace vkt
37 {
38 namespace Draw
39 {
40 namespace
41 {
42
43 enum Interpolation
44 {
45 SMOOTH = 0,
46 FLAT = 1,
47 NOPERSPECTIVE = 2,
48 CENTROID = 3,
49 SAMPLE = 4,
50 COUNT = 5,
51 };
52
53 struct DrawParams
54 {
55 vk::VkFormat format;
56 tcu::UVec2 size;
57 vk::VkSampleCountFlagBits samples;
58 // From the SPIR-V point of view, structured test variants will allow us to test interpolation decorations on struct members
59 // instead of plain ids.
60 bool useStructure;
61 bool includeSampleDecoration;
62 const SharedGroupParams groupParams;
63 };
64
65 template <typename T>
makeSharedPtr(vk::Move<T> move)66 inline de::SharedPtr<vk::Move<T>> makeSharedPtr(vk::Move<T> move)
67 {
68 return de::SharedPtr<vk::Move<T>>(new vk::Move<T>(move));
69 }
70
interpolationToString(Interpolation interpolation)71 const char *interpolationToString(Interpolation interpolation)
72 {
73 switch (interpolation)
74 {
75 case SMOOTH:
76 return "smooth";
77 case FLAT:
78 return "flat";
79 case NOPERSPECTIVE:
80 return "noperspective";
81 case CENTROID:
82 return "centroid";
83 case SAMPLE:
84 return "sample";
85 default:
86 DE_FATAL("Invalid interpolation enum");
87 }
88
89 return "";
90 }
91
92 class DrawTestInstance : public TestInstance
93 {
94 public:
95 DrawTestInstance(Context &context, DrawParams params);
96 void render(de::SharedPtr<Image> &colorTargetImage, tcu::ConstPixelBufferAccess *frame, const char *vsName,
97 const char *fsName, Interpolation interpolation, bool sampleRateShading);
98 bool compare(const tcu::ConstPixelBufferAccess &result, const tcu::ConstPixelBufferAccess &reference);
99 tcu::TestStatus iterate(void);
100
101 protected:
102 void preRenderCommands(vk::VkCommandBuffer cmdBuffer, vk::VkImage colorTargetImage) const;
103 void drawCommands(vk::VkCommandBuffer cmdBuffer, vk::VkPipeline pipeline, vk::VkPipelineLayout pipelineLayout,
104 vk::VkBuffer vertexBuffer, uint32_t pcData) const;
105
106 #ifndef CTS_USES_VULKANSC
107 void beginSecondaryCmdBuffer(vk::VkCommandBuffer cmdBuffer, vk::VkRenderingFlagsKHR renderingFlags = 0u) const;
108 void beginDynamicRender(vk::VkCommandBuffer cmdBuffer, vk::VkRect2D renderArea, vk::VkClearValue clearValue,
109 vk::VkRenderingFlagsKHR renderingFlags = 0u) const;
110 #endif // CTS_USES_VULKANSC
111
112 private:
113 DrawParams m_params;
114 de::SharedPtr<Image> m_multisampleImage;
115 std::vector<de::SharedPtr<vk::Move<vk::VkImageView>>> m_colorTargetViews;
116 std::vector<de::SharedPtr<vk::Move<vk::VkImageView>>> m_multisampleViews;
117 de::SharedPtr<Buffer> m_vertexBuffer;
118 vk::Move<vk::VkRenderPass> m_renderPass;
119 vk::Move<vk::VkFramebuffer> m_framebuffer;
120 vk::Move<vk::VkPipelineLayout> m_pipelineLayout;
121 vk::Move<vk::VkPipeline> m_pipeline;
122 };
123
DrawTestInstance(Context & context,DrawParams params)124 DrawTestInstance::DrawTestInstance(Context &context, DrawParams params) : TestInstance(context), m_params(params)
125 {
126 }
127
128 class DrawTestCase : public TestCase
129 {
130 public:
131 DrawTestCase(tcu::TestContext &testCtx, const std::string &name, const DrawParams params);
132 ~DrawTestCase(void);
133 virtual void initPrograms(vk::SourceCollections &programCollection) const;
134 virtual void checkSupport(Context &context) const;
135 virtual TestInstance *createInstance(Context &context) const;
136
137 private:
138 const DrawParams m_params;
139 };
140
DrawTestCase(tcu::TestContext & testCtx,const std::string & name,const DrawParams params)141 DrawTestCase::DrawTestCase(tcu::TestContext &testCtx, const std::string &name, const DrawParams params)
142 : TestCase(testCtx, name)
143 , m_params(params)
144 {
145 }
146
~DrawTestCase(void)147 DrawTestCase::~DrawTestCase(void)
148 {
149 }
150
initPrograms(vk::SourceCollections & programCollection) const151 void DrawTestCase::initPrograms(vk::SourceCollections &programCollection) const
152 {
153 const std::string blockName = "ifb";
154 const std::map<std::string, std::string> replacements = {
155 std::pair<std::string, std::string>{
156 "blockOpeningOut", (m_params.useStructure ? "layout(location = 0) out InterfaceBlock {\n" : "")},
157 std::pair<std::string, std::string>{
158 "blockOpeningIn", (m_params.useStructure ? "layout(location = 0) in InterfaceBlock {\n" : "")},
159 std::pair<std::string, std::string>{"blockClosure", (m_params.useStructure ? "} " + blockName + ";\n" : "")},
160 std::pair<std::string, std::string>{
161 "extensions", (m_params.useStructure ? "#extension GL_ARB_enhanced_layouts : require\n" : "")},
162 std::pair<std::string, std::string>{"accessPrefix", (m_params.useStructure ? blockName + "." : "")},
163 std::pair<std::string, std::string>{"outQual", (m_params.useStructure ? "" : "out ")},
164 std::pair<std::string, std::string>{"inQual", (m_params.useStructure ? "" : "in ")},
165 std::pair<std::string, std::string>{"indent", (m_params.useStructure ? " " : "")},
166 };
167
168 std::ostringstream vertShaderMultiStream;
169 vertShaderMultiStream << "#version 430\n"
170 << "${extensions}"
171 << "\n"
172 << "layout(location = 0) in vec4 in_position;\n"
173 << "layout(location = 1) in vec4 in_color;\n"
174 << "\n"
175 << "${blockOpeningOut}"
176 << "${indent}layout(location = 0) ${outQual}vec4 out_color_smooth;\n"
177 << "${indent}layout(location = 1) ${outQual}flat vec4 out_color_flat;\n"
178 << "${indent}layout(location = 2) ${outQual}noperspective vec4 out_color_noperspective;\n"
179 << "${indent}layout(location = 3) ${outQual}centroid vec4 out_color_centroid;\n"
180 << (m_params.includeSampleDecoration ?
181 "${indent}layout(location = 4) ${outQual}sample vec4 out_color_sample;\n" :
182 "")
183 << "${blockClosure}"
184 << "\n"
185 << "void main()\n"
186 << "{\n"
187 << " ${accessPrefix}out_color_smooth = in_color;\n"
188 << " ${accessPrefix}out_color_flat = in_color;\n"
189 << " ${accessPrefix}out_color_noperspective = in_color;\n"
190 << " ${accessPrefix}out_color_centroid = in_color;\n"
191 << (m_params.includeSampleDecoration ? " ${accessPrefix}out_color_sample = in_color;\n" :
192 "")
193 << " gl_Position = in_position;\n"
194 << "}\n";
195 const tcu::StringTemplate vertShaderMulti(vertShaderMultiStream.str());
196
197 const auto colorCount = (m_params.includeSampleDecoration ? COUNT : (COUNT - 1));
198
199 std::ostringstream fragShaderMultiStream;
200 fragShaderMultiStream << "#version 430\n"
201 << "${extensions}"
202 << "\n"
203 << "${blockOpeningIn}"
204 << "${indent}layout(location = 0) ${inQual}vec4 in_color_smooth;\n"
205 << "${indent}layout(location = 1) ${inQual}flat vec4 in_color_flat;\n"
206 << "${indent}layout(location = 2) ${inQual}noperspective vec4 in_color_noperspective;\n"
207 << "${indent}layout(location = 3) ${inQual}centroid vec4 in_color_centroid;\n"
208 << (m_params.includeSampleDecoration ?
209 "${indent}layout(location = 4) ${inQual}sample vec4 in_color_sample;\n" :
210 "")
211 << "${blockClosure}"
212 << "\n"
213 << "layout(push_constant, std430) uniform PushConstants {\n"
214 << " uint interpolationIndex;\n"
215 << "} pc;\n"
216 << "\n"
217 << "layout(location=0) out vec4 out_color;\n"
218 << "\n"
219 << "void main()\n"
220 << "{\n"
221 << " const vec4 in_colors[" + de::toString(colorCount) + "] = vec4[](\n"
222 << " ${accessPrefix}in_color_smooth,\n"
223 << " ${accessPrefix}in_color_flat,\n"
224 << " ${accessPrefix}in_color_noperspective,\n"
225 << " ${accessPrefix}in_color_centroid" << (m_params.includeSampleDecoration ? "," : "")
226 << "\n"
227 << (m_params.includeSampleDecoration ? " ${accessPrefix}in_color_sample\n" : "")
228 << " );\n"
229 << " out_color = in_colors[pc.interpolationIndex];\n"
230 << "}\n";
231 const tcu::StringTemplate fragShaderMulti(fragShaderMultiStream.str());
232
233 const tcu::StringTemplate vertShaderSingle{
234 "#version 430\n"
235 "${extensions}"
236 "\n"
237 "layout(location = 0) in vec4 in_position;\n"
238 "layout(location = 1) in vec4 in_color;\n"
239 "\n"
240 "${blockOpeningOut}"
241 "${indent}layout(location = 0) ${outQual}${qualifier:opt}vec4 out_color;\n"
242 "${blockClosure}"
243 "\n"
244 "void main()\n"
245 "{\n"
246 " ${accessPrefix}out_color = in_color;\n"
247 " gl_Position = in_position;\n"
248 "}\n"};
249
250 const tcu::StringTemplate fragShaderSingle{"#version 430\n"
251 "${extensions}"
252 "\n"
253 "${blockOpeningIn}"
254 "${indent}layout(location = 0) ${inQual}${qualifier:opt}vec4 in_color;\n"
255 "${blockClosure}"
256 "\n"
257 "layout(location = 0) out vec4 out_color;\n"
258 "\n"
259 "void main()\n"
260 "{\n"
261 " out_color = ${accessPrefix}in_color;\n"
262 "}\n"};
263
264 std::map<std::string, std::string> smooth = replacements;
265 std::map<std::string, std::string> flat = replacements;
266 std::map<std::string, std::string> noperspective = replacements;
267 std::map<std::string, std::string> centroid = replacements;
268 std::map<std::string, std::string> sample = replacements;
269
270 flat["qualifier"] = "flat ";
271 noperspective["qualifier"] = "noperspective ";
272 centroid["qualifier"] = "centroid ";
273 sample["qualifier"] = "sample ";
274
275 programCollection.glslSources.add("vert_multi") << glu::VertexSource(vertShaderMulti.specialize(replacements));
276 programCollection.glslSources.add("frag_multi") << glu::FragmentSource(fragShaderMulti.specialize(replacements));
277 programCollection.glslSources.add("vert_smooth") << glu::VertexSource(vertShaderSingle.specialize(smooth));
278 programCollection.glslSources.add("frag_smooth") << glu::FragmentSource(fragShaderSingle.specialize(smooth));
279 programCollection.glslSources.add("vert_flat") << glu::VertexSource(vertShaderSingle.specialize(flat));
280 programCollection.glslSources.add("frag_flat") << glu::FragmentSource(fragShaderSingle.specialize(flat));
281 programCollection.glslSources.add("vert_noperspective")
282 << glu::VertexSource(vertShaderSingle.specialize(noperspective));
283 programCollection.glslSources.add("frag_noperspective")
284 << glu::FragmentSource(fragShaderSingle.specialize(noperspective));
285 programCollection.glslSources.add("vert_centroid") << glu::VertexSource(vertShaderSingle.specialize(centroid));
286 programCollection.glslSources.add("frag_centroid") << glu::FragmentSource(fragShaderSingle.specialize(centroid));
287
288 if (m_params.includeSampleDecoration)
289 {
290 programCollection.glslSources.add("vert_sample") << glu::VertexSource(vertShaderSingle.specialize(sample));
291 programCollection.glslSources.add("frag_sample") << glu::FragmentSource(fragShaderSingle.specialize(sample));
292 }
293 }
294
checkSupport(Context & context) const295 void DrawTestCase::checkSupport(Context &context) const
296 {
297 if (!(m_params.samples & context.getDeviceProperties().limits.framebufferColorSampleCounts))
298 TCU_THROW(NotSupportedError, "Multisampling with " + de::toString(m_params.samples) + " samples not supported");
299
300 if (m_params.includeSampleDecoration && !context.getDeviceFeatures().sampleRateShading)
301 TCU_THROW(NotSupportedError, "Sample rate shading not supported");
302
303 if (m_params.groupParams->useDynamicRendering)
304 context.requireDeviceFunctionality("VK_KHR_dynamic_rendering");
305 }
306
createInstance(Context & context) const307 TestInstance *DrawTestCase::createInstance(Context &context) const
308 {
309 return new DrawTestInstance(context, m_params);
310 }
311
render(de::SharedPtr<Image> & colorTargetImage,tcu::ConstPixelBufferAccess * frame,const char * vsName,const char * fsName,Interpolation interpolation,bool sampleRateShading)312 void DrawTestInstance::render(de::SharedPtr<Image> &colorTargetImage, tcu::ConstPixelBufferAccess *frame,
313 const char *vsName, const char *fsName, Interpolation interpolation,
314 bool sampleRateShading)
315 {
316 const uint32_t pcData = static_cast<uint32_t>(interpolation);
317 const uint32_t pcDataSize = static_cast<uint32_t>(sizeof(pcData));
318 const bool useMultisampling = (m_params.samples != vk::VK_SAMPLE_COUNT_1_BIT);
319 const vk::VkBool32 sampleShadingEnable = (sampleRateShading ? VK_TRUE : VK_FALSE);
320 const vk::DeviceInterface &vk = m_context.getDeviceInterface();
321 const vk::VkDevice device = m_context.getDevice();
322 const vk::Unique<vk::VkShaderModule> vs(
323 createShaderModule(vk, device, m_context.getBinaryCollection().get(vsName), 0));
324 const vk::Unique<vk::VkShaderModule> fs(
325 createShaderModule(vk, device, m_context.getBinaryCollection().get(fsName), 0));
326 const CmdPoolCreateInfo cmdPoolCreateInfo = m_context.getUniversalQueueFamilyIndex();
327 vk::Move<vk::VkCommandPool> cmdPool = createCommandPool(vk, device, &cmdPoolCreateInfo);
328 vk::Move<vk::VkCommandBuffer> cmdBuffer =
329 vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
330 vk::Move<vk::VkCommandBuffer> secCmdBuffer;
331
332 m_colorTargetViews.clear();
333 m_multisampleViews.clear();
334
335 // Create color buffer images
336 {
337 const vk::VkExtent3D targetImageExtent = {m_params.size.x(), m_params.size.y(), 1};
338 const vk::VkImageUsageFlags usage = vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
339 vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT | vk::VK_IMAGE_USAGE_TRANSFER_DST_BIT;
340 const ImageCreateInfo targetImageCreateInfo(vk::VK_IMAGE_TYPE_2D, m_params.format, targetImageExtent, 1, 1,
341 vk::VK_SAMPLE_COUNT_1_BIT, vk::VK_IMAGE_TILING_OPTIMAL, usage);
342
343 colorTargetImage = Image::createAndAlloc(vk, device, targetImageCreateInfo, m_context.getDefaultAllocator(),
344 m_context.getUniversalQueueFamilyIndex());
345
346 if (useMultisampling)
347 {
348 const ImageCreateInfo multisampleImageCreateInfo(vk::VK_IMAGE_TYPE_2D, m_params.format, targetImageExtent,
349 1, 1, m_params.samples, vk::VK_IMAGE_TILING_OPTIMAL,
350 usage);
351
352 m_multisampleImage =
353 Image::createAndAlloc(vk, device, multisampleImageCreateInfo, m_context.getDefaultAllocator(),
354 m_context.getUniversalQueueFamilyIndex());
355 }
356 }
357
358 {
359 const ImageViewCreateInfo colorTargetViewInfo(colorTargetImage->object(), vk::VK_IMAGE_VIEW_TYPE_2D,
360 m_params.format);
361
362 m_colorTargetViews.push_back(makeSharedPtr(createImageView(vk, device, &colorTargetViewInfo)));
363
364 if (useMultisampling)
365 {
366 const ImageViewCreateInfo multisamplingTargetViewInfo(m_multisampleImage->object(),
367 vk::VK_IMAGE_VIEW_TYPE_2D, m_params.format);
368
369 m_multisampleViews.push_back(makeSharedPtr(createImageView(vk, device, &multisamplingTargetViewInfo)));
370 }
371 }
372
373 // Create render pass and framebuffer
374 if (!m_params.groupParams->useDynamicRendering)
375 {
376 RenderPassCreateInfo renderPassCreateInfo;
377 std::vector<vk::VkImageView> attachments;
378 std::vector<vk::VkAttachmentReference> colorAttachmentRefs;
379 std::vector<vk::VkAttachmentReference> multisampleAttachmentRefs;
380 uint32_t attachmentNdx = 0;
381
382 {
383 const vk::VkAttachmentReference colorAttachmentReference = {attachmentNdx++, vk::VK_IMAGE_LAYOUT_GENERAL};
384
385 colorAttachmentRefs.push_back(colorAttachmentReference);
386
387 renderPassCreateInfo.addAttachment(AttachmentDescription(
388 m_params.format, vk::VK_SAMPLE_COUNT_1_BIT, vk::VK_ATTACHMENT_LOAD_OP_CLEAR,
389 vk::VK_ATTACHMENT_STORE_OP_STORE, vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,
390 vk::VK_ATTACHMENT_STORE_OP_DONT_CARE, vk::VK_IMAGE_LAYOUT_UNDEFINED, vk::VK_IMAGE_LAYOUT_GENERAL));
391
392 if (useMultisampling)
393 {
394 const vk::VkAttachmentReference multiSampleAttachmentReference = {attachmentNdx++,
395 vk::VK_IMAGE_LAYOUT_GENERAL};
396
397 multisampleAttachmentRefs.push_back(multiSampleAttachmentReference);
398
399 renderPassCreateInfo.addAttachment(AttachmentDescription(
400 m_params.format, m_params.samples, vk::VK_ATTACHMENT_LOAD_OP_CLEAR,
401 vk::VK_ATTACHMENT_STORE_OP_STORE, vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,
402 vk::VK_ATTACHMENT_STORE_OP_DONT_CARE, vk::VK_IMAGE_LAYOUT_UNDEFINED, vk::VK_IMAGE_LAYOUT_GENERAL));
403 }
404 }
405
406 renderPassCreateInfo.addSubpass(SubpassDescription(
407 vk::VK_PIPELINE_BIND_POINT_GRAPHICS, 0, 0, DE_NULL, (uint32_t)colorAttachmentRefs.size(),
408 useMultisampling ? &multisampleAttachmentRefs[0] : &colorAttachmentRefs[0],
409 useMultisampling ? &colorAttachmentRefs[0] : DE_NULL, AttachmentReference(), 0, DE_NULL));
410
411 m_renderPass = createRenderPass(vk, device, &renderPassCreateInfo);
412
413 for (uint32_t frameNdx = 0; frameNdx < m_colorTargetViews.size(); frameNdx++)
414 {
415 attachments.push_back(**m_colorTargetViews[frameNdx]);
416
417 if (useMultisampling)
418 attachments.push_back(**m_multisampleViews[frameNdx]);
419 }
420
421 const vk::VkFramebufferCreateInfo framebufferCreateInfo = {vk::VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
422 DE_NULL,
423 0u,
424 *m_renderPass,
425 (uint32_t)attachments.size(),
426 &attachments[0],
427 m_params.size.x(),
428 m_params.size.y(),
429 1};
430
431 m_framebuffer = createFramebuffer(vk, device, &framebufferCreateInfo);
432 }
433
434 // Create vertex buffer.
435 {
436 const PositionColorVertex vertices[] = {
437 PositionColorVertex(tcu::Vec4(-1.5f, -0.4f, 1.0f, 2.0f), // Coord
438 tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f)), // Color
439
440 PositionColorVertex(tcu::Vec4(0.4f, -0.4f, 0.5f, 0.5f), // Coord
441 tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f)), // Color
442
443 PositionColorVertex(tcu::Vec4(0.3f, 0.8f, 0.0f, 1.0f), // Coord
444 tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f)) // Color
445 };
446
447 const vk::VkDeviceSize dataSize = DE_LENGTH_OF_ARRAY(vertices) * sizeof(PositionColorVertex);
448 m_vertexBuffer =
449 Buffer::createAndAlloc(vk, device, BufferCreateInfo(dataSize, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT),
450 m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
451 uint8_t *ptr = reinterpret_cast<uint8_t *>(m_vertexBuffer->getBoundMemory().getHostPtr());
452
453 deMemcpy(ptr, vertices, static_cast<size_t>(dataSize));
454 flushMappedMemoryRange(vk, device, m_vertexBuffer->getBoundMemory().getMemory(),
455 m_vertexBuffer->getBoundMemory().getOffset(), VK_WHOLE_SIZE);
456 }
457
458 // Create pipeline
459 {
460 const vk::VkViewport viewport = vk::makeViewport(m_params.size.x(), m_params.size.y());
461 const vk::VkRect2D scissor = vk::makeRect2D(m_params.size.x(), m_params.size.y());
462 const auto pcRange = vk::makePushConstantRange(vk::VK_SHADER_STAGE_FRAGMENT_BIT, 0u, pcDataSize);
463 const std::vector<vk::VkPushConstantRange> pcRanges(1u, pcRange);
464 const PipelineLayoutCreateInfo pipelineLayoutCreateInfo(0u, nullptr, static_cast<uint32_t>(pcRanges.size()),
465 pcRanges.data());
466
467 m_pipelineLayout = createPipelineLayout(vk, device, &pipelineLayoutCreateInfo);
468
469 PipelineCreateInfo pipelineCreateInfo(*m_pipelineLayout, *m_renderPass, 0, 0);
470
471 const vk::VkVertexInputBindingDescription vertexInputBindingDescription = {0, (uint32_t)sizeof(tcu::Vec4) * 2,
472 vk::VK_VERTEX_INPUT_RATE_VERTEX};
473
474 const vk::VkVertexInputAttributeDescription vertexInputAttributeDescriptions[2] = {
475 {0u, 0u, vk::VK_FORMAT_R32G32B32A32_SFLOAT, 0u},
476 {1u, 0u, vk::VK_FORMAT_R32G32B32A32_SFLOAT, (uint32_t)(sizeof(float) * 4)}};
477
478 std::vector<PipelineCreateInfo::ColorBlendState::Attachment> vkCbAttachmentStates(1u);
479 PipelineCreateInfo::VertexInputState vertexInputState = PipelineCreateInfo::VertexInputState(
480 1, &vertexInputBindingDescription, 2, vertexInputAttributeDescriptions);
481
482 pipelineCreateInfo.addShader(
483 PipelineCreateInfo::PipelineShaderStage(*vs, "main", vk::VK_SHADER_STAGE_VERTEX_BIT));
484 pipelineCreateInfo.addShader(
485 PipelineCreateInfo::PipelineShaderStage(*fs, "main", vk::VK_SHADER_STAGE_FRAGMENT_BIT));
486 pipelineCreateInfo.addState(PipelineCreateInfo::VertexInputState(vertexInputState));
487 pipelineCreateInfo.addState(PipelineCreateInfo::InputAssemblerState(vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST));
488 pipelineCreateInfo.addState(
489 PipelineCreateInfo::ColorBlendState((uint32_t)vkCbAttachmentStates.size(), &vkCbAttachmentStates[0]));
490 pipelineCreateInfo.addState(PipelineCreateInfo::ViewportState(1, std::vector<vk::VkViewport>(1, viewport),
491 std::vector<vk::VkRect2D>(1, scissor)));
492 pipelineCreateInfo.addState(PipelineCreateInfo::DepthStencilState());
493 pipelineCreateInfo.addState(PipelineCreateInfo::RasterizerState());
494 pipelineCreateInfo.addState(PipelineCreateInfo::MultiSampleState(m_params.samples, sampleShadingEnable, 1.0f));
495
496 #ifndef CTS_USES_VULKANSC
497 std::vector<vk::VkFormat> colorAttachmentFormats(m_colorTargetViews.size(), m_params.format);
498 vk::VkPipelineRenderingCreateInfoKHR renderingCreateInfo{
499 vk::VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR,
500 DE_NULL,
501 0u,
502 static_cast<uint32_t>(colorAttachmentFormats.size()),
503 colorAttachmentFormats.data(),
504 vk::VK_FORMAT_UNDEFINED,
505 vk::VK_FORMAT_UNDEFINED};
506
507 if (m_params.groupParams->useDynamicRendering)
508 pipelineCreateInfo.pNext = &renderingCreateInfo;
509 #endif // CTS_USES_VULKANSC
510
511 m_pipeline = createGraphicsPipeline(vk, device, DE_NULL, &pipelineCreateInfo);
512 }
513
514 // Queue draw and read results.
515 {
516 const vk::VkQueue queue = m_context.getUniversalQueue();
517 const vk::VkRect2D renderArea = vk::makeRect2D(m_params.size.x(), m_params.size.y());
518 const vk::VkBuffer buffer = m_vertexBuffer->object();
519 const vk::VkOffset3D zeroOffset = {0, 0, 0};
520 const auto clearValueColor = vk::makeClearValueColor(tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
521
522 #ifndef CTS_USES_VULKANSC
523 if (m_params.groupParams->useSecondaryCmdBuffer)
524 {
525 secCmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_SECONDARY);
526
527 // record secondary command buffer
528 if (m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
529 {
530 beginSecondaryCmdBuffer(*secCmdBuffer, vk::VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
531 beginDynamicRender(*secCmdBuffer, renderArea, clearValueColor);
532 }
533 else
534 beginSecondaryCmdBuffer(*secCmdBuffer);
535
536 drawCommands(*secCmdBuffer, *m_pipeline, *m_pipelineLayout, buffer, pcData);
537
538 if (m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
539 endRendering(vk, *secCmdBuffer);
540
541 endCommandBuffer(vk, *secCmdBuffer);
542
543 // record primary command buffer
544 beginCommandBuffer(vk, *cmdBuffer, 0u);
545 preRenderCommands(*cmdBuffer, colorTargetImage->object());
546
547 if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
548 beginDynamicRender(*cmdBuffer, renderArea, clearValueColor,
549 vk::VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
550
551 vk.cmdExecuteCommands(*cmdBuffer, 1u, &*secCmdBuffer);
552
553 if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
554 endRendering(vk, *cmdBuffer);
555
556 endCommandBuffer(vk, *cmdBuffer);
557 }
558 else if (m_params.groupParams->useDynamicRendering)
559 {
560 beginCommandBuffer(vk, *cmdBuffer);
561
562 preRenderCommands(*cmdBuffer, colorTargetImage->object());
563 beginDynamicRender(*cmdBuffer, renderArea, clearValueColor);
564 drawCommands(*cmdBuffer, *m_pipeline, *m_pipelineLayout, buffer, pcData);
565 endRendering(vk, *cmdBuffer);
566
567 endCommandBuffer(vk, *cmdBuffer);
568 }
569 #endif // CTS_USES_VULKANSC
570
571 if (!m_params.groupParams->useDynamicRendering)
572 {
573 const uint32_t imagesCount = static_cast<uint32_t>(m_colorTargetViews.size() + m_multisampleViews.size());
574 std::vector<vk::VkClearValue> clearValues(2, clearValueColor);
575
576 beginCommandBuffer(vk, *cmdBuffer);
577
578 preRenderCommands(*cmdBuffer, colorTargetImage->object());
579 beginRenderPass(vk, *cmdBuffer, *m_renderPass, *m_framebuffer, renderArea, imagesCount, &clearValues[0]);
580 drawCommands(*cmdBuffer, *m_pipeline, *m_pipelineLayout, buffer, pcData);
581 endRenderPass(vk, *cmdBuffer);
582
583 endCommandBuffer(vk, *cmdBuffer);
584 }
585
586 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
587
588 *frame = colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(), vk::VK_IMAGE_LAYOUT_GENERAL,
589 zeroOffset, (int)m_params.size.x(), (int)m_params.size.y(),
590 vk::VK_IMAGE_ASPECT_COLOR_BIT);
591 }
592 }
593
preRenderCommands(vk::VkCommandBuffer cmdBuffer,vk::VkImage colorTargetImage) const594 void DrawTestInstance::preRenderCommands(vk::VkCommandBuffer cmdBuffer, vk::VkImage colorTargetImage) const
595 {
596 if (!m_params.groupParams->useDynamicRendering)
597 return;
598
599 const vk::DeviceInterface &vk = m_context.getDeviceInterface();
600 initialTransitionColor2DImage(vk, cmdBuffer, colorTargetImage, vk::VK_IMAGE_LAYOUT_GENERAL,
601 vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
602 vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
603
604 if (m_params.samples != vk::VK_SAMPLE_COUNT_1_BIT)
605 {
606 initialTransitionColor2DImage(vk, cmdBuffer, m_multisampleImage->object(), vk::VK_IMAGE_LAYOUT_GENERAL,
607 vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
608 vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
609 }
610 }
611
drawCommands(vk::VkCommandBuffer cmdBuffer,vk::VkPipeline pipeline,vk::VkPipelineLayout pipelineLayout,vk::VkBuffer vertexBuffer,uint32_t pcData) const612 void DrawTestInstance::drawCommands(vk::VkCommandBuffer cmdBuffer, vk::VkPipeline pipeline,
613 vk::VkPipelineLayout pipelineLayout, vk::VkBuffer vertexBuffer,
614 uint32_t pcData) const
615 {
616 const vk::DeviceInterface &vk = m_context.getDeviceInterface();
617 const vk::VkDeviceSize vertexBufferOffset = 0;
618 const uint32_t pcDataSize = static_cast<uint32_t>(sizeof(pcData));
619
620 vk.cmdBindVertexBuffers(cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
621 vk.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
622 vk.cmdPushConstants(cmdBuffer, pipelineLayout, vk::VK_SHADER_STAGE_FRAGMENT_BIT, 0u, pcDataSize, &pcData);
623 vk.cmdDraw(cmdBuffer, 3u, 1u, 0u, 0u);
624 }
625
compare(const tcu::ConstPixelBufferAccess & result,const tcu::ConstPixelBufferAccess & reference)626 bool DrawTestInstance::compare(const tcu::ConstPixelBufferAccess &result, const tcu::ConstPixelBufferAccess &reference)
627 {
628 DE_ASSERT(result.getSize() == reference.getSize());
629
630 const tcu::IVec4 threshold(1u, 1u, 1u, 1u);
631
632 for (int y = 0; y < result.getHeight(); y++)
633 {
634 for (int x = 0; x < result.getWidth(); x++)
635 {
636 tcu::IVec4 refPix = reference.getPixelInt(x, y);
637 tcu::IVec4 cmpPix = result.getPixelInt(x, y);
638 tcu::IVec4 diff = tcu::abs(refPix - cmpPix);
639
640 if (!tcu::boolAll(tcu::lessThanEqual(diff, threshold)))
641 return false;
642 }
643 }
644
645 return true;
646 }
647
648 #ifndef CTS_USES_VULKANSC
beginSecondaryCmdBuffer(vk::VkCommandBuffer cmdBuffer,vk::VkRenderingFlagsKHR renderingFlags) const649 void DrawTestInstance::beginSecondaryCmdBuffer(vk::VkCommandBuffer cmdBuffer,
650 vk::VkRenderingFlagsKHR renderingFlags) const
651 {
652 std::vector<vk::VkFormat> colorAttachmentFormats(m_colorTargetViews.size(), m_params.format);
653 vk::VkCommandBufferInheritanceRenderingInfoKHR inheritanceRenderingInfo{
654 vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR, // VkStructureType sType;
655 DE_NULL, // const void* pNext;
656 renderingFlags, // VkRenderingFlagsKHR flags;
657 0u, // uint32_t viewMask;
658 (uint32_t)colorAttachmentFormats.size(), // uint32_t colorAttachmentCount;
659 colorAttachmentFormats.data(), // const VkFormat* pColorAttachmentFormats;
660 vk::VK_FORMAT_UNDEFINED, // VkFormat depthAttachmentFormat;
661 vk::VK_FORMAT_UNDEFINED, // VkFormat stencilAttachmentFormat;
662 m_params.samples, // VkSampleCountFlagBits rasterizationSamples;
663 };
664 const vk::VkCommandBufferInheritanceInfo bufferInheritanceInfo = vk::initVulkanStructure(&inheritanceRenderingInfo);
665
666 vk::VkCommandBufferUsageFlags usageFlags = vk::VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
667 if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
668 usageFlags |= vk::VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
669
670 const vk::VkCommandBufferBeginInfo commandBufBeginParams{
671 vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType;
672 DE_NULL, // const void* pNext;
673 usageFlags, // VkCommandBufferUsageFlags flags;
674 &bufferInheritanceInfo};
675
676 const vk::DeviceInterface &vk = m_context.getDeviceInterface();
677 VK_CHECK(vk.beginCommandBuffer(cmdBuffer, &commandBufBeginParams));
678 }
679
beginDynamicRender(vk::VkCommandBuffer cmdBuffer,vk::VkRect2D renderArea,vk::VkClearValue clearValue,vk::VkRenderingFlagsKHR renderingFlags) const680 void DrawTestInstance::beginDynamicRender(vk::VkCommandBuffer cmdBuffer, vk::VkRect2D renderArea,
681 vk::VkClearValue clearValue, vk::VkRenderingFlagsKHR renderingFlags) const
682 {
683 const vk::DeviceInterface &vk = m_context.getDeviceInterface();
684 const uint32_t imagesCount = static_cast<uint32_t>(m_colorTargetViews.size());
685
686 std::vector<vk::VkRenderingAttachmentInfoKHR> colorAttachments(
687 imagesCount,
688 {
689 vk::VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR, // VkStructureType sType;
690 DE_NULL, // const void* pNext;
691 DE_NULL, // VkImageView imageView;
692 vk::VK_IMAGE_LAYOUT_GENERAL, // VkImageLayout imageLayout;
693 vk::VK_RESOLVE_MODE_NONE, // VkResolveModeFlagBits resolveMode;
694 DE_NULL, // VkImageView resolveImageView;
695 vk::VK_IMAGE_LAYOUT_GENERAL, // VkImageLayout resolveImageLayout;
696 vk::VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
697 vk::VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
698 clearValue // VkClearValue clearValue;
699 });
700
701 for (uint32_t i = 0; i < imagesCount; ++i)
702 {
703 if (m_params.samples != vk::VK_SAMPLE_COUNT_1_BIT)
704 {
705 colorAttachments[i].imageView = **m_multisampleViews[i];
706 colorAttachments[i].resolveMode = vk::VK_RESOLVE_MODE_AVERAGE_BIT;
707 colorAttachments[i].resolveImageView = **m_colorTargetViews[i];
708 }
709 else
710 colorAttachments[i].imageView = **m_colorTargetViews[i];
711 }
712
713 vk::VkRenderingInfoKHR renderingInfo{
714 vk::VK_STRUCTURE_TYPE_RENDERING_INFO_KHR,
715 DE_NULL,
716 renderingFlags, // VkRenderingFlagsKHR flags;
717 renderArea, // VkRect2D renderArea;
718 1u, // uint32_t layerCount;
719 0u, // uint32_t viewMask;
720 imagesCount, // uint32_t colorAttachmentCount;
721 colorAttachments.data(), // const VkRenderingAttachmentInfoKHR* pColorAttachments;
722 DE_NULL, // const VkRenderingAttachmentInfoKHR* pDepthAttachment;
723 DE_NULL, // const VkRenderingAttachmentInfoKHR* pStencilAttachment;
724 };
725
726 vk.cmdBeginRendering(cmdBuffer, &renderingInfo);
727 }
728 #endif // CTS_USES_VULKANSC
729
iterate(void)730 tcu::TestStatus DrawTestInstance::iterate(void)
731 {
732 tcu::TestLog &log = m_context.getTestContext().getLog();
733 const bool useMultisampling = (m_params.samples != vk::VK_SAMPLE_COUNT_1_BIT);
734 const uint32_t frameCount = static_cast<uint32_t>(COUNT);
735 std::vector<de::SharedPtr<Image>> resImages(frameCount);
736 de::SharedPtr<Image> smoothImage[2];
737 de::SharedPtr<Image> flatImage[2];
738 de::SharedPtr<Image> noperspectiveImage[2];
739 de::SharedPtr<Image> centroidImage[2];
740 de::SharedPtr<Image> sampleImage[2];
741 tcu::ConstPixelBufferAccess resFrames[frameCount];
742 tcu::ConstPixelBufferAccess refFrames[frameCount];
743 tcu::ConstPixelBufferAccess refSRSFrames[frameCount]; // Using sample rate shading.
744
745 for (int interpolationType = 0; interpolationType < COUNT; ++interpolationType)
746 {
747 // Avoid generating a result image for the sample decoration if we're not using it.
748 if (!m_params.includeSampleDecoration && interpolationType == Interpolation::SAMPLE)
749 continue;
750
751 render(resImages[interpolationType], &resFrames[interpolationType], "vert_multi", "frag_multi",
752 static_cast<Interpolation>(interpolationType), false);
753 }
754
755 for (int i = 0; i < 2; ++i)
756 {
757 const bool useSampleRateShading = (i > 0);
758
759 // Sample rate shading is an alternative good result for cases using the sample decoration.
760 if (useSampleRateShading && !m_params.includeSampleDecoration)
761 continue;
762
763 tcu::ConstPixelBufferAccess *framesArray = (useSampleRateShading ? refSRSFrames : refFrames);
764
765 render(smoothImage[i], &framesArray[SMOOTH], "vert_smooth", "frag_smooth", SMOOTH, useSampleRateShading);
766 render(flatImage[i], &framesArray[FLAT], "vert_flat", "frag_flat", FLAT, useSampleRateShading);
767 render(noperspectiveImage[i], &framesArray[NOPERSPECTIVE], "vert_noperspective", "frag_noperspective",
768 NOPERSPECTIVE, useSampleRateShading);
769 render(centroidImage[i], &framesArray[CENTROID], "vert_centroid", "frag_centroid", CENTROID,
770 useSampleRateShading);
771
772 // Avoid generating a reference image for the sample interpolation if we're not using it.
773 if (m_params.includeSampleDecoration)
774 render(sampleImage[i], &framesArray[SAMPLE], "vert_sample", "frag_sample", SAMPLE, useSampleRateShading);
775 }
776
777 for (uint32_t resNdx = 0; resNdx < frameCount; resNdx++)
778 {
779 if (!m_params.includeSampleDecoration && resNdx == SAMPLE)
780 continue;
781
782 const std::string resName = interpolationToString((Interpolation)resNdx);
783
784 log << tcu::TestLog::ImageSet(resName, resName) << tcu::TestLog::Image("Result", "Result", resFrames[resNdx])
785 << tcu::TestLog::Image("Reference", "Reference", refFrames[resNdx]);
786 if (m_params.includeSampleDecoration)
787 log << tcu::TestLog::Image("ReferenceSRS", "Reference with sample shading", refSRSFrames[resNdx]);
788 log << tcu::TestLog::EndImageSet;
789
790 for (uint32_t refNdx = 0; refNdx < frameCount; refNdx++)
791 {
792 if (!m_params.includeSampleDecoration && refNdx == SAMPLE)
793 continue;
794
795 const std::string refName = interpolationToString((Interpolation)refNdx);
796
797 if (resNdx == refNdx)
798 {
799 if (!compare(resFrames[resNdx], refFrames[refNdx]) &&
800 (!m_params.includeSampleDecoration || !compare(resFrames[resNdx], refSRSFrames[refNdx])))
801 return tcu::TestStatus::fail(resName + " produced different results");
802 }
803 else if (!useMultisampling &&
804 ((resNdx == SMOOTH && refNdx == CENTROID) || (resNdx == CENTROID && refNdx == SMOOTH) ||
805 (resNdx == SMOOTH && refNdx == SAMPLE) || (resNdx == SAMPLE && refNdx == SMOOTH) ||
806 (resNdx == CENTROID && refNdx == SAMPLE) || (resNdx == SAMPLE && refNdx == CENTROID)))
807 {
808 if (!compare(resFrames[resNdx], refFrames[refNdx]))
809 return tcu::TestStatus::fail(resName + " and " + refName +
810 " produced different results without multisampling");
811 }
812 else
813 {
814 // "smooth" means lack of centroid and sample.
815 // Spec does not specify exactly what "smooth" should be, so it can match centroid or sample.
816 // "centroid" and "sample" may also produce the same results.
817 if (!((resNdx == SMOOTH && refNdx == CENTROID) || (resNdx == CENTROID && refNdx == SMOOTH) ||
818 (resNdx == SMOOTH && refNdx == SAMPLE) || (resNdx == SAMPLE && refNdx == SMOOTH) ||
819 (resNdx == CENTROID && refNdx == SAMPLE) || (resNdx == SAMPLE && refNdx == CENTROID)))
820 {
821 if (compare(resFrames[resNdx], refFrames[refNdx]))
822 return tcu::TestStatus::fail(resName + " and " + refName + " produced same result");
823 }
824 }
825 }
826 }
827
828 return tcu::TestStatus::pass("Results differ and references match");
829 }
830
createTests(tcu::TestCaseGroup * testGroup,const SharedGroupParams groupParams)831 void createTests(tcu::TestCaseGroup *testGroup, const SharedGroupParams groupParams)
832 {
833 tcu::TestContext &testCtx = testGroup->getTestContext();
834 const vk::VkFormat format = vk::VK_FORMAT_R8G8B8A8_UNORM;
835 const tcu::UVec2 size(128, 128);
836
837 struct TestVariant
838 {
839 const std::string name;
840 const vk::VkSampleCountFlagBits samples;
841 };
842
843 static const std::vector<TestVariant> testVariants{
844 {"1_sample", vk::VK_SAMPLE_COUNT_1_BIT}, {"2_samples", vk::VK_SAMPLE_COUNT_2_BIT},
845 {"4_samples", vk::VK_SAMPLE_COUNT_4_BIT}, {"8_samples", vk::VK_SAMPLE_COUNT_8_BIT},
846 {"16_samples", vk::VK_SAMPLE_COUNT_16_BIT}, {"32_samples", vk::VK_SAMPLE_COUNT_32_BIT},
847 {"64_samples", vk::VK_SAMPLE_COUNT_64_BIT},
848 };
849
850 struct GroupVariant
851 {
852 const bool useStructure;
853 const std::string groupName;
854 };
855
856 static const std::vector<GroupVariant> groupVariants{
857 {false, "separate"},
858 {true, "structured"},
859 };
860
861 const struct
862 {
863 const bool includeSampleDecoration;
864 const std::string groupName;
865 } sampleVariants[]{
866 {false, "no_sample_decoration"},
867 {true, "with_sample_decoration"},
868 };
869
870 for (const auto &grpVariant : groupVariants)
871 {
872 de::MovePtr<tcu::TestCaseGroup> group{new tcu::TestCaseGroup{testCtx, grpVariant.groupName.c_str()}};
873
874 for (const auto &sampleVariant : sampleVariants)
875 {
876 de::MovePtr<tcu::TestCaseGroup> sampleGroup{
877 new tcu::TestCaseGroup{testCtx, sampleVariant.groupName.c_str()}};
878
879 for (const auto &testVariant : testVariants)
880 {
881 const DrawParams params{format,
882 size,
883 testVariant.samples,
884 grpVariant.useStructure,
885 sampleVariant.includeSampleDecoration,
886 groupParams};
887 sampleGroup->addChild(new DrawTestCase(testCtx, testVariant.name, params));
888 }
889
890 group->addChild(sampleGroup.release());
891 }
892
893 testGroup->addChild(group.release());
894 }
895 }
896
897 } // namespace
898
createMultipleInterpolationTests(tcu::TestContext & testCtx,const SharedGroupParams groupParams)899 tcu::TestCaseGroup *createMultipleInterpolationTests(tcu::TestContext &testCtx, const SharedGroupParams groupParams)
900 {
901 // Tests for multiple interpolation decorations in a shader stage.
902 return createTestGroup(testCtx, "multiple_interpolation", createTests, groupParams);
903 }
904
905 } // namespace Draw
906 } // namespace vkt
907