1 /*-------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
5 * Copyright (c) 2015 Google Inc.
6 * Copyright (c) 2019-2020 NVIDIA Corporation
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 * \brief Fragment Shading Rate tests
23 *//*--------------------------------------------------------------------*/
25 #include "vktFragmentShadingRateTests.hpp"
26 #include "vktFragmentShadingRateBasic.hpp"
27 #include "vktFragmentShadingRatePixelConsistency.hpp"
28 #include "vktTestGroupUtil.hpp"
29 #include "vktTestCaseUtil.hpp"
30 #include "tcuTestLog.hpp"
35 namespace FragmentShadingRate
41 tcu::TestStatus testLimits(Context& context)
43 bool allChecksPassed = true;
44 tcu::TestLog& log = context.getTestContext().getLog();
45 const auto& features = context.getDeviceFeatures();
46 const auto& properties = context.getDeviceProperties();
47 const auto& vulkan12Features = context.getDeviceVulkan12Features();
48 const auto& fragmentShadingRateFeatures = context.getFragmentShadingRateFeatures();
49 const auto& fragmentShadingRateProperties = context.getFragmentShadingRateProperties();
51 if (!fragmentShadingRateFeatures.pipelineFragmentShadingRate)
53 log << tcu::TestLog::Message << "pipelineFragmentShadingRate is not supported" << tcu::TestLog::EndMessage;
54 allChecksPassed = false;
57 if (context.getFragmentShadingRateProperties().primitiveFragmentShadingRateWithMultipleViewports && !context.getFragmentShadingRateFeatures().primitiveFragmentShadingRate)
59 log << tcu::TestLog::Message << "primitiveFragmentShadingRateWithMultipleViewports "
60 "limit should only be supported if primitiveFragmentShadingRate is supported" << tcu::TestLog::EndMessage;
61 allChecksPassed = false;
64 bool requiredFeatures = features.geometryShader || vulkan12Features.shaderOutputViewportIndex || context.isDeviceFunctionalitySupported("VK_EXT_shader_viewport_index_layer");
65 if (context.getFragmentShadingRateProperties().primitiveFragmentShadingRateWithMultipleViewports && !requiredFeatures)
67 log << tcu::TestLog::Message << "primitiveFragmentShadingRateWithMultipleViewports limit should only "
68 "be supported if at least one of the geometryShader feature, shaderOutputViewportIndex feature, "
69 "or VK_EXT_shader_viewport_index_layer extension is supported" << tcu::TestLog::EndMessage;
70 allChecksPassed = false;
73 if (fragmentShadingRateProperties.layeredShadingRateAttachments && !fragmentShadingRateFeatures.attachmentFragmentShadingRate)
75 log << tcu::TestLog::Message << "layeredShadingRateAttachments should only be supported if attachmentFragmentShadingRate is supported" << tcu::TestLog::EndMessage;
76 allChecksPassed = false;
79 requiredFeatures = features.geometryShader || context.getMultiviewFeatures().multiview || vulkan12Features.shaderOutputViewportIndex ||
80 context.isDeviceFunctionalitySupported("VK_EXT_shader_viewport_index_layer");
81 if (fragmentShadingRateProperties.layeredShadingRateAttachments && !requiredFeatures)
83 log << tcu::TestLog::Message << "layeredShadingRateAttachments should only be supported if at least one of the geometryShader feature, multiview feature, "
84 "shaderOutputViewportIndex feature, or VK_EXT_shader_viewport_index_layer extension is supported" << tcu::TestLog::EndMessage;
85 allChecksPassed = false;
88 requiredFeatures = fragmentShadingRateFeatures.primitiveFragmentShadingRate || fragmentShadingRateFeatures.attachmentFragmentShadingRate;
89 if (fragmentShadingRateProperties.fragmentShadingRateNonTrivialCombinerOps && !requiredFeatures)
91 log << tcu::TestLog::Message << "fragmentShadingRateNonTrivialCombinerOps should only be supported if at least one of primitiveFragmentShadingRate "
92 "or attachmentFragmentShadingRate is supported" << tcu::TestLog::EndMessage;
93 allChecksPassed = false;
96 if (fragmentShadingRateProperties.maxFragmentSizeAspectRatio > std::max(fragmentShadingRateProperties.maxFragmentSize.width, fragmentShadingRateProperties.maxFragmentSize.height))
98 log << tcu::TestLog::Message << "maxFragmentSizeAspectRatio should be less than or equal to the maximum width / height of maxFragmentSize" << tcu::TestLog::EndMessage;
99 allChecksPassed = false;
102 if (fragmentShadingRateProperties.maxFragmentSizeAspectRatio < 2)
104 log << tcu::TestLog::Message << "maxFragmentSizeAspectRatio should be at least 2" << tcu::TestLog::EndMessage;
105 allChecksPassed = false;
108 if (!deIntIsPow2(static_cast<int>(fragmentShadingRateProperties.maxFragmentSizeAspectRatio)))
110 log << tcu::TestLog::Message << "maxFragmentSizeAspectRatio should be power of 2" << tcu::TestLog::EndMessage;
111 allChecksPassed = false;
114 if (fragmentShadingRateProperties.fragmentShadingRateWithShaderSampleMask && (fragmentShadingRateProperties.maxFragmentShadingRateCoverageSamples > (properties.limits.maxSampleMaskWords * 32)))
116 log << tcu::TestLog::Message << "maxFragmentShadingRateCoverageSamples should be less than or equal maxSampleMaskWords * 32 "
117 "if fragmentShadingRateWithShaderSampleMask is supported" << tcu::TestLog::EndMessage;
118 allChecksPassed = false;
121 deUint32 requiredValue = fragmentShadingRateProperties.maxFragmentSize.width * fragmentShadingRateProperties.maxFragmentSize.height *
122 fragmentShadingRateProperties.maxFragmentShadingRateRasterizationSamples;
123 if (fragmentShadingRateProperties.maxFragmentShadingRateCoverageSamples > requiredValue)
125 log << tcu::TestLog::Message << "maxFragmentShadingRateCoverageSamples should be less than or equal to the product of the width and height of "
126 "maxFragmentSize and the samples reported by maxFragmentShadingRateRasterizationSamples" << tcu::TestLog::EndMessage;
127 allChecksPassed = false;
130 if (fragmentShadingRateProperties.maxFragmentShadingRateCoverageSamples < 16)
132 log << tcu::TestLog::Message << "maxFragmentShadingRateCoverageSamples should at least be 16" << tcu::TestLog::EndMessage;
133 allChecksPassed = false;
136 if (fragmentShadingRateProperties.maxFragmentShadingRateRasterizationSamples < vk::VK_SAMPLE_COUNT_4_BIT)
138 log << tcu::TestLog::Message << "maxFragmentShadingRateRasterizationSamples should supports at least VK_SAMPLE_COUNT_4_BIT" << tcu::TestLog::EndMessage;
139 allChecksPassed = false;
142 if (fragmentShadingRateProperties.fragmentShadingRateWithConservativeRasterization && !context.isDeviceFunctionalitySupported("VK_EXT_conservative_rasterization"))
144 log << tcu::TestLog::Message << "fragmentShadingRateWithConservativeRasterization should only be supported if VK_EXT_conservative_rasterization is supported" << tcu::TestLog::EndMessage;
145 allChecksPassed = false;
148 if (fragmentShadingRateProperties.fragmentShadingRateWithFragmentShaderInterlock && !context.isDeviceFunctionalitySupported("VK_EXT_fragment_shader_interlock"))
150 log << tcu::TestLog::Message << "fragmentShadingRateWithFragmentShaderInterlock should only be supported if VK_EXT_fragment_shader_interlock is supported" << tcu::TestLog::EndMessage;
151 allChecksPassed = false;
154 if (fragmentShadingRateProperties.fragmentShadingRateWithCustomSampleLocations && !context.isDeviceFunctionalitySupported("VK_EXT_sample_locations"))
156 log << tcu::TestLog::Message << "fragmentShadingRateWithCustomSampleLocations should only be supported if VK_EXT_sample_locations is supported" << tcu::TestLog::EndMessage;
157 allChecksPassed = false;
160 if (fragmentShadingRateFeatures.attachmentFragmentShadingRate)
162 if ((fragmentShadingRateProperties.maxFragmentShadingRateAttachmentTexelSize.width < 8) ||
163 (fragmentShadingRateProperties.maxFragmentShadingRateAttachmentTexelSize.height < 8))
165 log << tcu::TestLog::Message << "maxFragmentShadingRateAttachmentTexelSize should at least be { 8,8 }" << tcu::TestLog::EndMessage;
166 allChecksPassed = false;
169 if ((fragmentShadingRateProperties.minFragmentShadingRateAttachmentTexelSize.width > 32) ||
170 (fragmentShadingRateProperties.minFragmentShadingRateAttachmentTexelSize.height > 32))
172 log << tcu::TestLog::Message << "minFragmentShadingRateAttachmentTexelSize should't be greater than { 32,32 }" << tcu::TestLog::EndMessage;
173 allChecksPassed = false;
176 if ((fragmentShadingRateProperties.maxFragmentShadingRateAttachmentTexelSize.width < fragmentShadingRateProperties.minFragmentShadingRateAttachmentTexelSize.width) ||
177 (fragmentShadingRateProperties.maxFragmentShadingRateAttachmentTexelSize.height < fragmentShadingRateProperties.minFragmentShadingRateAttachmentTexelSize.height))
179 log << tcu::TestLog::Message << "maxFragmentShadingRateAttachmentTexelSize should be greater than or equal to "
180 "minFragmentShadingRateAttachmentTexelSize in each dimension" << tcu::TestLog::EndMessage;
181 allChecksPassed = false;
184 if (!deIntIsPow2(static_cast<int>(fragmentShadingRateProperties.maxFragmentShadingRateAttachmentTexelSize.width)) ||
185 !deIntIsPow2(static_cast<int>(fragmentShadingRateProperties.maxFragmentShadingRateAttachmentTexelSize.height)))
187 log << tcu::TestLog::Message << "maxFragmentShadingRateAttachmentTexelSize should be power of 2" << tcu::TestLog::EndMessage;
188 allChecksPassed = false;
191 if (!deIntIsPow2(static_cast<int>(fragmentShadingRateProperties.minFragmentShadingRateAttachmentTexelSize.width)) ||
192 !deIntIsPow2(static_cast<int>(fragmentShadingRateProperties.minFragmentShadingRateAttachmentTexelSize.height)))
194 log << tcu::TestLog::Message << "minFragmentShadingRateAttachmentTexelSize should be power of 2" << tcu::TestLog::EndMessage;
195 allChecksPassed = false;
200 if ((fragmentShadingRateProperties.maxFragmentShadingRateAttachmentTexelSize.width != 0) ||
201 (fragmentShadingRateProperties.maxFragmentShadingRateAttachmentTexelSize.height != 0))
203 log << tcu::TestLog::Message << "maxFragmentShadingRateAttachmentTexelSize should be { 0,0 } when "
204 "attachmentFragmentShadingRate is not supported" << tcu::TestLog::EndMessage;
205 allChecksPassed = false;
208 if ((fragmentShadingRateProperties.minFragmentShadingRateAttachmentTexelSize.width != 0) ||
209 (fragmentShadingRateProperties.minFragmentShadingRateAttachmentTexelSize.height != 0))
211 log << tcu::TestLog::Message << "minFragmentShadingRateAttachmentTexelSize should be { 0,0 } when "
212 "attachmentFragmentShadingRate is not supported" << tcu::TestLog::EndMessage;
213 allChecksPassed = false;
217 if ((fragmentShadingRateProperties.maxFragmentSize.width < 2) ||
218 (fragmentShadingRateProperties.maxFragmentSize.height < 2))
220 log << tcu::TestLog::Message << "maxFragmentSize should at least be { 2,2 }" << tcu::TestLog::EndMessage;
221 allChecksPassed = false;
224 if ((fragmentShadingRateProperties.maxFragmentSize.width > 4) ||
225 (fragmentShadingRateProperties.maxFragmentSize.height > 4))
227 log << tcu::TestLog::Message << "maxFragmentSize should't be greater than{ 4,4 }" << tcu::TestLog::EndMessage;
228 allChecksPassed = false;
232 return tcu::TestStatus::pass("pass");
233 return tcu::TestStatus::fail("fail");
236 tcu::TestStatus testShadingRates(Context& context)
238 bool someChecksFailed = false;
239 tcu::TestLog& log = context.getTestContext().getLog();
240 const vk::InstanceInterface& vki = context.getInstanceInterface();
241 vk::VkPhysicalDevice physicalDevice = context.getPhysicalDevice();
242 const auto& fragmentShadingRateProperties = context.getFragmentShadingRateProperties();
243 deUint32 supportedFragmentShadingRateCount = 0;
245 vk::VkResult result = vki.getPhysicalDeviceFragmentShadingRatesKHR(physicalDevice, &supportedFragmentShadingRateCount, DE_NULL);
246 if ((result != vk::VK_SUCCESS) && (result != vk::VK_ERROR_OUT_OF_HOST_MEMORY))
248 someChecksFailed = true;
249 log << tcu::TestLog::Message << "vkGetPhysicalDeviceFragmentShadingRatesKHR returned invalid result" << tcu::TestLog::EndMessage;
252 std::vector<vk::VkPhysicalDeviceFragmentShadingRateKHR> fragmentShadingRateVect(supportedFragmentShadingRateCount);
253 for (auto& fragmentShadingRate : fragmentShadingRateVect)
255 fragmentShadingRate.sType = vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR;
256 fragmentShadingRate.pNext = DE_NULL;
259 // Pass a value of 1 into pFragmentShadingRateCount, and an array of at least length one into pFragmentShadingRates.
260 // Check that the returned value is either VK_INCOMPLETE or VK_ERROR_OUT_OF_HOST_MEMORY(and issue a quality warning in the latter case).
261 supportedFragmentShadingRateCount = 1u;
262 result = vki.getPhysicalDeviceFragmentShadingRatesKHR(physicalDevice, &supportedFragmentShadingRateCount, fragmentShadingRateVect.data());
263 if ((result != vk::VK_INCOMPLETE) && (result != vk::VK_ERROR_OUT_OF_HOST_MEMORY))
265 someChecksFailed = true;
266 log << tcu::TestLog::Message << "vkGetPhysicalDeviceFragmentShadingRatesKHR returned invalid result" << tcu::TestLog::EndMessage;
269 // Get all available fragment shading rates
270 supportedFragmentShadingRateCount = static_cast<deUint32>(fragmentShadingRateVect.size());
271 result = vki.getPhysicalDeviceFragmentShadingRatesKHR(physicalDevice, &supportedFragmentShadingRateCount, fragmentShadingRateVect.data());
272 if ((result != vk::VK_SUCCESS) && (result != vk::VK_ERROR_OUT_OF_HOST_MEMORY))
274 someChecksFailed = true;
275 log << tcu::TestLog::Message << "vkGetPhysicalDeviceFragmentShadingRatesKHR returned invalid result" << tcu::TestLog::EndMessage;
278 bool widthCheckPassed = true;
279 bool heightCheckPassed = true;
280 deUint32 previousWidth = std::numeric_limits<deUint32>::max();
281 deUint32 previousHeight = std::numeric_limits<deUint32>::max();
283 for (const auto& fsr : fragmentShadingRateVect)
285 const auto& fragmentSize = fsr.fragmentSize;
287 // Check that rate width and height are power-of-two
288 if (!deIntIsPow2(static_cast<int>(fragmentSize.width)) ||
289 !deIntIsPow2(static_cast<int>(fragmentSize.height)))
291 log << tcu::TestLog::Message << "fragmentSize should be power of 2" << tcu::TestLog::EndMessage;
292 someChecksFailed = true;
295 // Check that the width and height are less than the values in the maxFragmentSize limit
296 if ((fragmentSize.width > fragmentShadingRateProperties.maxFragmentSize.width) ||
297 (fragmentSize.height > fragmentShadingRateProperties.maxFragmentSize.height))
299 log << tcu::TestLog::Message << "fragmentSize width and height are not less than the values in the maxFragmentSize" << tcu::TestLog::EndMessage;
300 someChecksFailed = true;
303 if ((fragmentSize.width * fragmentSize.height) == 1)
305 // special case for fragmentSize {1, 1}
306 if (fsr.sampleCounts != ~0u)
308 log << tcu::TestLog::Message << "implementations must support sampleCounts equal to ~0 for fragmentSize {1, 1}" << tcu::TestLog::EndMessage;
309 someChecksFailed = true;
314 // get highest sample count value
315 deUint32 highestSampleCount = 0x80000000;
316 while (highestSampleCount)
318 if (fsr.sampleCounts & highestSampleCount)
320 highestSampleCount >>= 1;
323 // Check that the highest sample count in sampleCounts is less than or equal to maxFragmentShadingRateRasterizationSamples limit
324 if (highestSampleCount > static_cast<deUint32>(fragmentShadingRateProperties.maxFragmentShadingRateRasterizationSamples))
326 log << tcu::TestLog::Message << "highest sample count value is not less than or equal to the maxFragmentShadingRateRasterizationSamples limit" << tcu::TestLog::EndMessage;
327 someChecksFailed = true;
330 // Check that the product of the width, height, and highest sample count value is less than the maxFragmentShadingRateCoverageSamples limit
331 if ((fragmentSize.width * fragmentSize.height * highestSampleCount) > fragmentShadingRateProperties.maxFragmentShadingRateCoverageSamples)
333 log << tcu::TestLog::Message << "product of the width, height, and highest sample count value is not less than the maxFragmentShadingRateCoverageSamples limit" << tcu::TestLog::EndMessage;
334 someChecksFailed = true;
338 // Check that the entries in the array are ordered first by largest to smallest width, then largest to smallest height
340 const deUint32 currentWidth = fragmentSize.width;
341 if (widthCheckPassed && (currentWidth > previousWidth))
343 log << tcu::TestLog::Message << "vkGetPhysicalDeviceFragmentShadingRatesKHR returned entries that are not ordered by largest to smallest width" << tcu::TestLog::EndMessage;
344 widthCheckPassed = false;
347 deUint32 currentHeight = fragmentSize.height;
348 if (heightCheckPassed)
350 // we can check order of height only for entries that have same width
351 if (currentWidth == previousWidth)
353 if (currentHeight > previousHeight)
355 log << tcu::TestLog::Message << "vkGetPhysicalDeviceFragmentShadingRatesKHR returned entries with same width but height is not ordered by largest to smallest" << tcu::TestLog::EndMessage;
356 heightCheckPassed = false;
360 currentHeight = std::numeric_limits<deUint32>::max();
363 previousWidth = currentWidth;
364 previousHeight = currentHeight;
367 // Check that no two entries in the array have the same fragmentSize.width and fragmentSize.height value
370 for (const auto& fsrB : fragmentShadingRateVect)
372 if ((fragmentSize.width == fsrB.fragmentSize.width) &&
373 (fragmentSize.height == fsrB.fragmentSize.height))
377 log << tcu::TestLog::Message << "vkGetPhysicalDeviceFragmentShadingRatesKHR returned entries with same fragmentSize" << tcu::TestLog::EndMessage;
378 someChecksFailed = true;
385 // Check that 1x1, 1x2, 2x1, and 2x2 rates are supported with sample counts of 1 and 4
386 if ((fragmentSize.width < 3) && (fragmentSize.height < 3) &&
387 (!(fsr.sampleCounts & vk::VK_SAMPLE_COUNT_1_BIT) || !(fsr.sampleCounts & vk::VK_SAMPLE_COUNT_4_BIT)))
389 log << tcu::TestLog::Message << "vkGetPhysicalDeviceFragmentShadingRatesKHR returned 1x1, 1x2, 2x1, and 2x2 rates with sample counts not supporting 1 and 4" << tcu::TestLog::EndMessage;
390 someChecksFailed = true;
393 // If the framebufferColorSampleCounts limit includes a sample count of 2, ensure that a sample count of 2 is also reported for the 1x1, 1x2, 2x1, and 2x2 rates.
394 if (context.getDeviceProperties().limits.framebufferColorSampleCounts & vk::VK_SAMPLE_COUNT_2_BIT)
396 if ((fragmentSize.width < 3) && (fragmentSize.height < 3) &&
397 !(fsr.sampleCounts & vk::VK_SAMPLE_COUNT_2_BIT))
399 log << tcu::TestLog::Message << "vkGetPhysicalDeviceFragmentShadingRatesKHR returned 1x1, 1x2, 2x1, and 2x2 rates with sample counts not supporting 2 while framebufferColorSampleCounts does" << tcu::TestLog::EndMessage;
400 someChecksFailed = true;
405 if (someChecksFailed || !widthCheckPassed || !heightCheckPassed)
406 return tcu::TestStatus::fail("fail");
408 return tcu::TestStatus::pass("pass");
411 void checkSupport(Context& context)
413 context.requireDeviceFunctionality("VK_KHR_fragment_shading_rate");
416 void createMiscTests(tcu::TestContext& testCtx, tcu::TestCaseGroup* parentGroup)
418 de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "misc", ""));
420 addFunctionCase(group.get(), "limits", "", checkSupport, testLimits);
421 addFunctionCase(group.get(), "shading_rates", "", checkSupport, testShadingRates);
423 parentGroup->addChild(group.release());
426 void createChildren (tcu::TestContext& testCtx, tcu::TestCaseGroup* group, bool useDynamicRendering)
428 createBasicTests(testCtx, group, useDynamicRendering);
430 if (!useDynamicRendering)
432 // there is no point in duplicating those tests for dynamic rendering
433 createMiscTests(testCtx, group);
435 // subpasses can't be translated to dynamic rendering
436 createPixelConsistencyTests(testCtx, group);
442 tcu::TestCaseGroup* createTests (tcu::TestContext& testCtx)
444 de::MovePtr<tcu::TestCaseGroup> mainGroup (new tcu::TestCaseGroup(testCtx, "fragment_shading_rate", "Fragment shading rate tests"));
445 de::MovePtr<tcu::TestCaseGroup> renderpass2Group (new tcu::TestCaseGroup(testCtx, "renderpass2", "Draw using render pass object"));
446 de::MovePtr<tcu::TestCaseGroup> dynamicRenderingGroup (new tcu::TestCaseGroup(testCtx, "dynamic_rendering", "Draw using VK_KHR_dynamic_rendering"));
448 createChildren(testCtx, renderpass2Group.get(), false);
449 createChildren(testCtx, dynamicRenderingGroup.get(), true);
451 mainGroup->addChild(renderpass2Group.release());
452 mainGroup->addChild(dynamicRenderingGroup.release());
454 return mainGroup.release();
457 } // FragmentShadingRate