1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2022 The Khronos Group Inc.
6 * Copyright (c) 2022 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 vktDrawMultisampleLinearInterpolationTests.cpp
22 * \brief InterpolateAt tests with linear interpolation
23 *//*--------------------------------------------------------------------*/
24
25 #include "vktDrawMultisampleLinearInterpolationTests.hpp"
26
27 #include "vktDrawBaseClass.hpp"
28 #include "vkQueryUtil.hpp"
29 #include "vkCmdUtil.hpp"
30 #include "vkTypeUtil.hpp"
31 #include "vktTestGroupUtil.hpp"
32
33 namespace vkt
34 {
35 namespace Draw
36 {
37 namespace
38 {
39 using namespace vk;
40
41 class MultisampleLinearInterpolationTestInstance : public TestInstance
42 {
43 public:
MultisampleLinearInterpolationTestInstance(Context & context,const tcu::IVec2 renderSize,const float interpolationRange,const VkSampleCountFlagBits sampleCountFlagBits,const SharedGroupParams groupParams)44 MultisampleLinearInterpolationTestInstance(Context &context, const tcu::IVec2 renderSize,
45 const float interpolationRange,
46 const VkSampleCountFlagBits sampleCountFlagBits,
47 const SharedGroupParams groupParams)
48 : vkt::TestInstance(context)
49 , m_renderSize(renderSize)
50 , m_interpolationRange(interpolationRange)
51 , m_sampleCountFlagBits(sampleCountFlagBits)
52 , m_groupParams(groupParams)
53 {
54 }
55
~MultisampleLinearInterpolationTestInstance(void)56 ~MultisampleLinearInterpolationTestInstance(void)
57 {
58 }
59
60 tcu::TestStatus iterate(void);
61
62 private:
63 const tcu::IVec2 m_renderSize;
64 const float m_interpolationRange;
65 const VkSampleCountFlagBits m_sampleCountFlagBits;
66 const SharedGroupParams m_groupParams;
67 };
68
iterate(void)69 tcu::TestStatus MultisampleLinearInterpolationTestInstance::iterate(void)
70 {
71 const DeviceInterface &vk = m_context.getDeviceInterface();
72 const VkDevice device = m_context.getDevice();
73
74 tcu::ConstPixelBufferAccess resultPixelBufferAccesses[2];
75 de::SharedPtr<Image> colorTargetImages[2];
76 de::SharedPtr<Image> multisampleImages[2];
77
78 const VkFormat imageColorFormat = VK_FORMAT_R8G8B8A8_UNORM;
79
80 const std::string vertShadernames[2] = {"vertRef", "vertNoPer"};
81 const std::string fragShadernames[2] = {"fragRef", "fragNoPer"};
82
83 tcu::TestLog &log = m_context.getTestContext().getLog();
84
85 const bool useMultisampling = m_sampleCountFlagBits == VK_SAMPLE_COUNT_1_BIT ? false : true;
86
87 for (int draw = 0; draw < 2; draw++)
88 {
89 const Unique<VkShaderModule> vs(
90 createShaderModule(vk, device, m_context.getBinaryCollection().get(vertShadernames[draw].c_str()), 0));
91 const Unique<VkShaderModule> fs(
92 createShaderModule(vk, device, m_context.getBinaryCollection().get(fragShadernames[draw].c_str()), 0));
93
94 de::SharedPtr<Buffer> vertexBuffer;
95
96 const CmdPoolCreateInfo cmdPoolCreateInfo(m_context.getUniversalQueueFamilyIndex());
97 Move<VkCommandPool> cmdPool = createCommandPool(vk, device, &cmdPoolCreateInfo);
98 Move<VkCommandBuffer> cmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
99 Move<VkCommandBuffer> secCmdBuffer;
100
101 Move<VkRenderPass> renderPass;
102
103 std::vector<Move<VkImageView>> colorTargetViews;
104 std::vector<Move<VkImageView>> multisampleViews;
105
106 Move<VkFramebuffer> framebuffer;
107
108 Move<VkPipeline> pipeline;
109 const PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
110 Move<VkPipelineLayout> pipelineLayout = createPipelineLayout(vk, device, &pipelineLayoutCreateInfo);
111
112 const VkVertexInputAttributeDescription vertInAttrDescs[2] = {
113 {0u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, 0u},
114 {1u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, static_cast<uint32_t>(sizeof(float) * 4)}};
115
116 // Create color buffer images
117 {
118 const VkExtent3D targetImageExtent = {static_cast<uint32_t>(m_renderSize.x()),
119 static_cast<uint32_t>(m_renderSize.y()), 1u};
120 const VkImageUsageFlags usage =
121 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
122 const ImageCreateInfo targetImageCreateInfo(VK_IMAGE_TYPE_2D, imageColorFormat, targetImageExtent, 1u, 1u,
123 VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_TILING_OPTIMAL, usage);
124
125 colorTargetImages[draw] =
126 Image::createAndAlloc(vk, device, targetImageCreateInfo, m_context.getDefaultAllocator(),
127 m_context.getUniversalQueueFamilyIndex());
128
129 if (useMultisampling)
130 {
131 const ImageCreateInfo multisampleImageCreateInfo(VK_IMAGE_TYPE_2D, imageColorFormat, targetImageExtent,
132 1u, 1u, m_sampleCountFlagBits, VK_IMAGE_TILING_OPTIMAL,
133 usage);
134
135 multisampleImages[draw] =
136 Image::createAndAlloc(vk, device, multisampleImageCreateInfo, m_context.getDefaultAllocator(),
137 m_context.getUniversalQueueFamilyIndex());
138 }
139 }
140
141 {
142 const ImageViewCreateInfo colorTargetViewInfo(colorTargetImages[draw]->object(), VK_IMAGE_VIEW_TYPE_2D,
143 imageColorFormat);
144
145 colorTargetViews.push_back(createImageView(vk, device, &colorTargetViewInfo));
146
147 if (useMultisampling)
148 {
149 const ImageViewCreateInfo multisamplingTargetViewInfo(multisampleImages[draw]->object(),
150 VK_IMAGE_VIEW_TYPE_2D, imageColorFormat);
151
152 multisampleViews.push_back(createImageView(vk, device, &multisamplingTargetViewInfo));
153 }
154 }
155
156 // Create render pass and frame buffer.
157 if (!m_groupParams->useDynamicRendering)
158 {
159 RenderPassCreateInfo renderPassCreateInfo;
160 std::vector<VkImageView> attachments;
161 std::vector<VkAttachmentReference> colorAttachmentRefs;
162 std::vector<VkAttachmentReference> multisampleAttachmentRefs;
163 uint32_t attachmentNdx = 0;
164
165 {
166 const VkAttachmentReference colorAttachmentReference = {
167 attachmentNdx++, // uint32_t attachment;
168 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout;
169 };
170
171 colorAttachmentRefs.push_back(colorAttachmentReference);
172
173 renderPassCreateInfo.addAttachment(AttachmentDescription(
174 imageColorFormat, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE,
175 VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_UNDEFINED,
176 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL));
177
178 if (useMultisampling)
179 {
180 const VkAttachmentReference multiSampleAttachmentReference = {
181 attachmentNdx++, // uint32_t attachment;
182 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout;
183 };
184
185 multisampleAttachmentRefs.push_back(multiSampleAttachmentReference);
186
187 renderPassCreateInfo.addAttachment(
188 AttachmentDescription(imageColorFormat, m_sampleCountFlagBits, VK_ATTACHMENT_LOAD_OP_CLEAR,
189 VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_ATTACHMENT_LOAD_OP_DONT_CARE,
190 VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_UNDEFINED,
191 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL));
192 }
193 }
194
195 renderPassCreateInfo.addSubpass(SubpassDescription(
196 VK_PIPELINE_BIND_POINT_GRAPHICS, 0, 0, DE_NULL, (uint32_t)colorAttachmentRefs.size(),
197 useMultisampling ? &multisampleAttachmentRefs[0] : &colorAttachmentRefs[0],
198 useMultisampling ? &colorAttachmentRefs[0] : DE_NULL, AttachmentReference(), 0, DE_NULL));
199
200 renderPass = createRenderPass(vk, device, &renderPassCreateInfo);
201
202 for (uint32_t frameNdx = 0; frameNdx < colorTargetViews.size(); frameNdx++)
203 {
204 attachments.push_back(*colorTargetViews[frameNdx]);
205
206 if (useMultisampling)
207 attachments.push_back(*multisampleViews[frameNdx]);
208 }
209
210 const VkFramebufferCreateInfo framebufferCreateInfo = {
211 VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
212 DE_NULL, // const void* pNext;
213 0u, // VkFramebufferCreateFlags flags;
214 *renderPass, // VkRenderPass renderPass;
215 static_cast<uint32_t>(attachments.size()), // uint32_t attachmentCount;
216 &attachments[0], // const VkImageView* pAttachments;
217 static_cast<uint32_t>(m_renderSize.x()), // uint32_t width;
218 static_cast<uint32_t>(m_renderSize.y()), // uint32_t height;
219 1u // uint32_t layers;
220 };
221
222 framebuffer = createFramebuffer(vk, device, &framebufferCreateInfo);
223 }
224
225 // Create vertex buffer.
226 {
227 const PositionColorVertex vertices[] = {
228 // The first draw is for reference image.
229 /* ____ ____ */
230 /* / \ | | */
231 /* / \ |____| */
232 /* / \ */
233 /* /__________\ */
234 /* */
235 /* result reference */
236 /* */
237 // In result shape the bottom vertices are deeper. When the drawn result image is a perfect square,
238 // and color comparison with reference image is easy to make.
239 PositionColorVertex(tcu::Vec4(1.0f, -1.0f, 0.0f, 1.0f),
240 tcu::Vec4(0.0f, m_interpolationRange, 0.0f, m_interpolationRange)), // Top Right
241 PositionColorVertex(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
242 tcu::Vec4(m_interpolationRange * 0.5f, m_interpolationRange * 0.5f, 0.0f,
243 m_interpolationRange)), // Top Left
244 PositionColorVertex(
245 tcu::Vec4(draw == 0 ? 1.0f : 2.0f, draw == 0 ? 1.0f : 2.0f, 0.0f, draw == 0 ? 1.0f : 2.0f),
246 tcu::Vec4(m_interpolationRange * 0.5f, m_interpolationRange * 0.5f, 0.0f,
247 m_interpolationRange)), // Bottom Right
248 PositionColorVertex(
249 tcu::Vec4(draw == 0 ? -1.0f : -2.0f, draw == 0 ? 1.0f : 2.0f, 0.0f, draw == 0 ? 1.0f : 2.0f),
250 tcu::Vec4(m_interpolationRange, 0.0f, 0.0f, m_interpolationRange)), // Bottom Left
251 PositionColorVertex(
252 tcu::Vec4(draw == 0 ? 1.0f : 2.0f, draw == 0 ? 1.0f : 2.0f, 0.0f, draw == 0 ? 1.0f : 2.0f),
253 tcu::Vec4(m_interpolationRange * 0.5f, m_interpolationRange * 0.5f, 0.0f,
254 m_interpolationRange)), // Bottom Right
255 PositionColorVertex(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
256 tcu::Vec4(m_interpolationRange * 0.5f, m_interpolationRange * 0.5f, 0.0f,
257 m_interpolationRange)) // Top Left
258 };
259
260 const VkDeviceSize dataSize = sizeof(vertices);
261 vertexBuffer =
262 Buffer::createAndAlloc(vk, device, BufferCreateInfo(dataSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT),
263 m_context.getDefaultAllocator(), MemoryRequirement::HostVisible);
264 uint8_t *ptr = static_cast<uint8_t *>(vertexBuffer->getBoundMemory().getHostPtr());
265
266 deMemcpy(ptr, vertices, static_cast<size_t>(dataSize));
267 flushMappedMemoryRange(vk, device, vertexBuffer->getBoundMemory().getMemory(),
268 vertexBuffer->getBoundMemory().getOffset(), VK_WHOLE_SIZE);
269 }
270
271 // Create pipeline.
272 {
273 const PipelineCreateInfo::ColorBlendState::Attachment vkCbAttachmentState;
274
275 VkViewport viewport = makeViewport(m_renderSize.x(), m_renderSize.y());
276 VkRect2D scissor = makeRect2D(m_renderSize.x(), m_renderSize.y());
277
278 const std::vector<uint32_t> sampleMask = {0xfffffff, 0xfffffff};
279
280 const VkVertexInputBindingDescription vertexInputBindingDescription = {0, (uint32_t)sizeof(tcu::Vec4) * 2,
281 VK_VERTEX_INPUT_RATE_VERTEX};
282 PipelineCreateInfo::VertexInputState vertexInputState =
283 PipelineCreateInfo::VertexInputState(1, &vertexInputBindingDescription, 2, vertInAttrDescs);
284
285 PipelineCreateInfo pipelineCreateInfo(*pipelineLayout, *renderPass, 0, 0);
286
287 pipelineCreateInfo.addShader(
288 PipelineCreateInfo::PipelineShaderStage(*vs, "main", VK_SHADER_STAGE_VERTEX_BIT));
289 pipelineCreateInfo.addShader(
290 PipelineCreateInfo::PipelineShaderStage(*fs, "main", VK_SHADER_STAGE_FRAGMENT_BIT));
291 pipelineCreateInfo.addState(PipelineCreateInfo::VertexInputState(vertexInputState));
292 pipelineCreateInfo.addState(PipelineCreateInfo::InputAssemblerState(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST));
293 pipelineCreateInfo.addState(PipelineCreateInfo::ColorBlendState(1, &vkCbAttachmentState));
294 pipelineCreateInfo.addState(PipelineCreateInfo::ViewportState(1, std::vector<VkViewport>(1, viewport),
295 std::vector<VkRect2D>(1, scissor)));
296 pipelineCreateInfo.addState(PipelineCreateInfo::DepthStencilState());
297 pipelineCreateInfo.addState(PipelineCreateInfo::RasterizerState());
298 pipelineCreateInfo.addState(
299 PipelineCreateInfo::MultiSampleState(m_sampleCountFlagBits, false, 0.0f, sampleMask));
300
301 #ifndef CTS_USES_VULKANSC
302 VkPipelineRenderingCreateInfo renderingCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR,
303 DE_NULL,
304 0u,
305 1u,
306 &imageColorFormat,
307 VK_FORMAT_UNDEFINED,
308 VK_FORMAT_UNDEFINED};
309
310 if (m_groupParams->useDynamicRendering)
311 pipelineCreateInfo.pNext = &renderingCreateInfo;
312 #endif // CTS_USES_VULKANSC
313
314 pipeline = createGraphicsPipeline(vk, device, DE_NULL, &pipelineCreateInfo);
315 }
316
317 // Draw quad and read results.
318 {
319 const VkQueue queue = m_context.getUniversalQueue();
320 const VkClearValue clearColor = {{{0.0f, 0.0f, 0.0f, 1.0f}}};
321 const ImageSubresourceRange subresourceRange(VK_IMAGE_ASPECT_COLOR_BIT);
322 const VkRect2D renderArea = makeRect2D(m_renderSize.x(), m_renderSize.y());
323 const VkBuffer buffer = vertexBuffer->object();
324 const VkOffset3D zeroOffset = {0, 0, 0};
325
326 std::vector<VkClearValue> clearValues(2, clearColor);
327
328 auto drawCommands = [&](VkCommandBuffer cmdBuff)
329 {
330 const VkDeviceSize vertexBufferOffset = 0;
331 vk.cmdBindVertexBuffers(cmdBuff, 0, 1, &buffer, &vertexBufferOffset);
332 vk.cmdBindPipeline(cmdBuff, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
333 vk.cmdDraw(cmdBuff, 6u, 1u, 0u, 0u);
334 };
335
336 clearColorImage(vk, device, queue, m_context.getUniversalQueueFamilyIndex(),
337 colorTargetImages[draw]->object(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f),
338 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
339 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0u, 1u);
340
341 #ifndef CTS_USES_VULKANSC
342 auto preRenderBarriers = [&]()
343 {
344 // Transition Images
345 initialTransitionColor2DImage(
346 vk, *cmdBuffer, colorTargetImages[draw]->object(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
347 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
348
349 if (useMultisampling)
350 {
351 initialTransitionColor2DImage(
352 vk, *cmdBuffer, multisampleImages[draw]->object(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
353 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
354 }
355 };
356
357 if (m_groupParams->useDynamicRendering)
358 {
359 const uint32_t imagesCount = static_cast<uint32_t>(colorTargetViews.size());
360
361 std::vector<VkRenderingAttachmentInfo> colorAttachments(
362 imagesCount,
363 {
364 VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR, // VkStructureType sType;
365 DE_NULL, // const void* pNext;
366 DE_NULL, // VkImageView imageView;
367 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout imageLayout;
368 VK_RESOLVE_MODE_NONE, // VkResolveModeFlagBits resolveMode;
369 DE_NULL, // VkImageView resolveImageView;
370 VK_IMAGE_LAYOUT_GENERAL, // VkImageLayout resolveImageLayout;
371 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
372 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
373 clearColor // VkClearValue clearValue;
374 });
375
376 for (uint32_t i = 0; i < imagesCount; ++i)
377 {
378 if (useMultisampling)
379 {
380 colorAttachments[i].imageView = *multisampleViews[i];
381 colorAttachments[i].resolveMode = VK_RESOLVE_MODE_AVERAGE_BIT;
382 colorAttachments[i].resolveImageView = *colorTargetViews[i];
383 }
384 else
385 {
386 colorAttachments[i].imageView = *colorTargetViews[i];
387 }
388 }
389
390 VkRenderingInfo renderingInfo{
391 VK_STRUCTURE_TYPE_RENDERING_INFO, // VkStructureType sType;
392 DE_NULL, // const void* pNext;
393 0, // VkRenderingFlagsKHR flags;
394 renderArea, // VkRect2D renderArea;
395 1u, // uint32_t layerCount;
396 0u, // uint32_t viewMask;
397 imagesCount, // uint32_t colorAttachmentCount;
398 colorAttachments.data(), // const VkRenderingAttachmentInfoKHR* pColorAttachments;
399 DE_NULL, // const VkRenderingAttachmentInfoKHR* pDepthAttachment;
400 DE_NULL, // const VkRenderingAttachmentInfoKHR* pStencilAttachment;
401 };
402
403 if (m_groupParams->useSecondaryCmdBuffer)
404 {
405 VkCommandBufferInheritanceRenderingInfoKHR inheritanceRenderingInfo{
406 VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR, // VkStructureType sType;
407 DE_NULL, // const void* pNext;
408 0u, // VkRenderingFlagsKHR flags;
409 0u, // uint32_t viewMask;
410 1u, // uint32_t colorAttachmentCount;
411 &imageColorFormat, // const VkFormat* pColorAttachmentFormats;
412 VK_FORMAT_UNDEFINED, // VkFormat depthAttachmentFormat;
413 VK_FORMAT_UNDEFINED, // VkFormat stencilAttachmentFormat;
414 m_sampleCountFlagBits // VkSampleCountFlagBits rasterizationSamples;
415 };
416
417 const VkCommandBufferInheritanceInfo bufferInheritanceInfo =
418 initVulkanStructure(&inheritanceRenderingInfo);
419 VkCommandBufferBeginInfo commandBufBeginParams{
420 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType;
421 DE_NULL, // const void* pNext;
422 VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, // VkCommandBufferUsageFlags flags;
423 &bufferInheritanceInfo};
424
425 secCmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
426
427 // record secondary command buffer
428 if (m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
429 {
430 inheritanceRenderingInfo.flags = VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT;
431 VK_CHECK(vk.beginCommandBuffer(*secCmdBuffer, &commandBufBeginParams));
432 vk.cmdBeginRendering(*secCmdBuffer, &renderingInfo);
433 }
434 else
435 {
436 commandBufBeginParams.flags |= VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
437 VK_CHECK(vk.beginCommandBuffer(*secCmdBuffer, &commandBufBeginParams));
438 }
439
440 drawCommands(*secCmdBuffer);
441
442 if (m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
443 endRendering(vk, *secCmdBuffer);
444
445 endCommandBuffer(vk, *secCmdBuffer);
446
447 // record primary command buffer
448 beginCommandBuffer(vk, *cmdBuffer, 0u);
449
450 preRenderBarriers();
451
452 if (!m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
453 {
454 renderingInfo.flags = VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS;
455 vk.cmdBeginRendering(*cmdBuffer, &renderingInfo);
456 }
457 vk.cmdExecuteCommands(*cmdBuffer, 1u, &*secCmdBuffer);
458
459 if (!m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
460 endRendering(vk, *cmdBuffer);
461 endCommandBuffer(vk, *cmdBuffer);
462 }
463 else
464 {
465 beginCommandBuffer(vk, *cmdBuffer, 0u);
466 preRenderBarriers();
467
468 vk.cmdBeginRendering(*cmdBuffer, &renderingInfo);
469 drawCommands(*cmdBuffer);
470 endRendering(vk, *cmdBuffer);
471
472 endCommandBuffer(vk, *cmdBuffer);
473 }
474 }
475 else
476 #endif // CTS_USES_VULKANSC
477 {
478 beginCommandBuffer(vk, *cmdBuffer, 0u);
479
480 const uint32_t imagesCount = static_cast<uint32_t>(colorTargetViews.size() + multisampleViews.size());
481
482 beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, imagesCount, &clearValues[0]);
483 drawCommands(*cmdBuffer);
484 endRenderPass(vk, *cmdBuffer);
485
486 endCommandBuffer(vk, *cmdBuffer);
487 }
488
489 submitCommandsAndWait(vk, device, queue, cmdBuffer.get());
490
491 resultPixelBufferAccesses[draw] = colorTargetImages[draw]->readSurface(
492 queue, m_context.getDefaultAllocator(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, zeroOffset,
493 m_renderSize.x(), m_renderSize.y(), VK_IMAGE_ASPECT_COLOR_BIT);
494 }
495 }
496
497 if (!tcu::floatThresholdCompare(log, "Result", "Image comparison result", resultPixelBufferAccesses[0],
498 resultPixelBufferAccesses[1], tcu::Vec4(0.005f), tcu::COMPARE_LOG_RESULT))
499 return tcu::TestStatus::fail("Rendered color image is not correct");
500
501 return tcu::TestStatus::pass("Success");
502 }
503
504 class MultisampleLinearInterpolationTestCase : public TestCase
505 {
506 public:
MultisampleLinearInterpolationTestCase(tcu::TestContext & context,const char * name,const tcu::IVec2 renderSize,const float interpolationRange,const tcu::Vec2 offset,const VkSampleCountFlagBits sampleCountFlagBits,const SharedGroupParams groupParams)507 MultisampleLinearInterpolationTestCase(tcu::TestContext &context, const char *name, const tcu::IVec2 renderSize,
508 const float interpolationRange, const tcu::Vec2 offset,
509 const VkSampleCountFlagBits sampleCountFlagBits,
510 const SharedGroupParams groupParams)
511 : vkt::TestCase(context, name)
512 , m_renderSize(renderSize)
513 , m_interpolationRange(interpolationRange)
514 , m_offset(offset)
515 , m_sampleCountFlagBits(sampleCountFlagBits)
516 , m_groupParams(groupParams)
517 {
518 }
519
~MultisampleLinearInterpolationTestCase(void)520 ~MultisampleLinearInterpolationTestCase(void)
521 {
522 }
523
524 virtual void initPrograms(SourceCollections &programCollection) const;
525 virtual void checkSupport(Context &context) const;
526 virtual TestInstance *createInstance(Context &context) const;
527
528 private:
529 const tcu::IVec2 m_renderSize;
530 const float m_interpolationRange;
531 const tcu::Vec2 m_offset;
532 const VkSampleCountFlagBits m_sampleCountFlagBits;
533 const SharedGroupParams m_groupParams;
534 };
535
initPrograms(SourceCollections & programCollection) const536 void MultisampleLinearInterpolationTestCase::initPrograms(SourceCollections &programCollection) const
537 {
538 // Reference vertex shader.
539 {
540 std::ostringstream vrt;
541
542 vrt << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
543 << "\n"
544 << "layout(location = 0) in vec4 in_position;\n"
545 << "layout(location = 1) in vec4 in_color;\n"
546 << "layout(location = 0) out vec4 out_color;\n"
547 << "\n"
548 << "void main()\n"
549 << "{\n"
550 << " gl_PointSize = 1.0;\n"
551 << " gl_Position = in_position;\n"
552 << " out_color = in_color;\n"
553 << "}\n";
554
555 programCollection.glslSources.add("vertRef") << glu::VertexSource(vrt.str());
556 }
557
558 // Noperspective vertex shader.
559 {
560 std::ostringstream vrt;
561
562 vrt << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
563 << "\n"
564 << "layout(location = 0) in vec4 in_position;\n"
565 << "layout(location = 1) in vec4 in_color;\n"
566 << "layout(location = 0) noperspective out vec4 out_color;\n"
567 << "\n"
568 << "void main()\n"
569 << "{\n"
570 << " gl_PointSize = 1.0;\n"
571 << " gl_Position = in_position;\n"
572 << " out_color = in_color;\n"
573 << "}\n";
574
575 programCollection.glslSources.add("vertNoPer") << glu::VertexSource(vrt.str());
576 }
577
578 // Reference fragment shader.
579 {
580 std::ostringstream frg;
581
582 frg << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
583 << "layout(location = 0) in vec4 in_color;\n"
584 << "layout(location = 0) out vec4 out_color;\n"
585 << "void main()\n"
586 << "{\n"
587 << " vec4 out_color_y = mix(vec4(0.0, 1.0, 0.0, 1.0), vec4(1.0, 0.0, 0.0, 1.0), gl_FragCoord.y / "
588 << static_cast<float>(m_renderSize.y()) << " + " << m_offset.y() / static_cast<float>(m_renderSize.y())
589 << ");\n"
590 << " vec4 out_color_x = mix(vec4(1.0, 0.0, 0.0, 1.0), vec4(0.0, 1.0, 0.0, 1.0), gl_FragCoord.x / "
591 << static_cast<float>(m_renderSize.x()) << " + " << m_offset.x() / static_cast<float>(m_renderSize.x())
592 << ");\n"
593 << " out_color = 0.5 * (out_color_y + out_color_x);\n"
594 << "}\n";
595
596 programCollection.glslSources.add("fragRef") << glu::FragmentSource(frg.str());
597 }
598
599 // Noperspective fragment shader.
600 {
601 std::ostringstream frg;
602
603 frg << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
604 << "layout(location = 0) noperspective in vec4 in_color;\n"
605 << "layout(location = 0) out vec4 out_color;\n"
606 << "void main()\n"
607 << "{\n"
608 << " vec4 out_color_offset = interpolateAtOffset(in_color, vec2(" << m_offset.x() << ", " << m_offset.y()
609 << "));\n"
610 << " vec4 out_color_sample = interpolateAtSample(in_color, gl_SampleID);\n"
611 << " out_color = (0.5 * (out_color_offset + out_color_sample));\n"
612 << " out_color /= " << m_interpolationRange << ";\n";
613
614 // Run additional sample comparison test. If it fails, we write 1.0 to blue color channel.
615 frg << " vec4 diff = out_color_sample - interpolateAtOffset(in_color, gl_SamplePosition - vec2(0.5));"
616 << " float min_precision = 0.000001;\n"
617 << " if (diff.x > min_precision && diff.y > min_precision && diff.z > min_precision && diff.w > "
618 "min_precision)\n"
619 << " {\n"
620 << " out_color.z = 1.0;\n"
621 << " }\n";
622
623 frg << "}\n";
624
625 programCollection.glslSources.add("fragNoPer") << glu::FragmentSource(frg.str());
626 }
627 }
628
checkSupport(Context & context) const629 void MultisampleLinearInterpolationTestCase::checkSupport(Context &context) const
630 {
631 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SAMPLE_RATE_SHADING);
632
633 if (!(m_sampleCountFlagBits & context.getDeviceProperties().limits.framebufferColorSampleCounts))
634 TCU_THROW(NotSupportedError,
635 "Multisampling with " + de::toString(m_sampleCountFlagBits) + " samples not supported");
636
637 #ifndef CTS_USES_VULKANSC
638 if (m_groupParams->useDynamicRendering)
639 context.requireDeviceFunctionality("VK_KHR_dynamic_rendering");
640
641 if (context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") &&
642 !context.getPortabilitySubsetFeatures().shaderSampleRateInterpolationFunctions)
643 {
644 TCU_THROW(NotSupportedError, "VK_KHR_portability_subset: Shader sample rate interpolation functions are not "
645 "supported by this implementation");
646 }
647 #endif // CTS_USES_VULKANSC
648 }
649
createInstance(Context & context) const650 TestInstance *MultisampleLinearInterpolationTestCase::createInstance(Context &context) const
651 {
652 return new MultisampleLinearInterpolationTestInstance(context, m_renderSize, m_interpolationRange,
653 m_sampleCountFlagBits, m_groupParams);
654 }
655
createTests(tcu::TestCaseGroup * testGroup,const SharedGroupParams groupParams)656 void createTests(tcu::TestCaseGroup *testGroup, const SharedGroupParams groupParams)
657 {
658 tcu::TestContext &testCtx = testGroup->getTestContext();
659
660 struct
661 {
662 const std::string name;
663 const tcu::Vec2 value;
664 } offsets[] = {{"no_offset", tcu::Vec2(0.0f, 0.0f)},
665 {"offset_min", tcu::Vec2(-0.5f, -0.5f)},
666 {"offset_max", tcu::Vec2(0.4375f, 0.4375f)}};
667
668 struct
669 {
670 const std::string name;
671 VkSampleCountFlagBits value;
672 } flagBits[] = {{"1_sample", VK_SAMPLE_COUNT_1_BIT}, {"2_samples", VK_SAMPLE_COUNT_2_BIT},
673 {"4_samples", VK_SAMPLE_COUNT_4_BIT}, {"8_samples", VK_SAMPLE_COUNT_8_BIT},
674 {"16_samples", VK_SAMPLE_COUNT_16_BIT}, {"32_samples", VK_SAMPLE_COUNT_32_BIT},
675 {"64_samples", VK_SAMPLE_COUNT_64_BIT}};
676
677 for (const auto &offset : offsets)
678 {
679 for (const auto &flagBit : flagBits)
680 {
681 // reduce number of tests for dynamic rendering cases where secondary command buffer is used
682 if (groupParams->useSecondaryCmdBuffer && (flagBit.value > VK_SAMPLE_COUNT_4_BIT))
683 break;
684
685 testGroup->addChild(new MultisampleLinearInterpolationTestCase(
686 testCtx, (offset.name + "_" + flagBit.name).c_str(), tcu::IVec2(16, 16), 1.0f, offset.value,
687 flagBit.value, groupParams));
688 }
689 }
690 }
691
692 } // namespace
693
createMultisampleLinearInterpolationTests(tcu::TestContext & testCtx,const SharedGroupParams groupParams)694 tcu::TestCaseGroup *createMultisampleLinearInterpolationTests(tcu::TestContext &testCtx,
695 const SharedGroupParams groupParams)
696 {
697 // Tests for linear interpolation decorations.
698 return createTestGroup(testCtx, "linear_interpolation", createTests, groupParams);
699 }
700
701 } // namespace Draw
702 } // namespace vkt
703