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