#include "vktFragmentShadingRateBasic.hpp"
#include "vktFragmentShadingRatePixelConsistency.hpp"
#include "vktTestGroupUtil.hpp"
+#include "vktTestCaseUtil.hpp"
+#include "tcuTestLog.hpp"
+#include <limits>
namespace vkt
{
namespace
{
+tcu::TestStatus testLimits(Context& context)
+{
+ bool allChecksPassed = true;
+ tcu::TestLog& log = context.getTestContext().getLog();
+ const auto& features = context.getDeviceFeatures();
+ const auto& properties = context.getDeviceProperties();
+ const auto& vulkan12Features = context.getDeviceVulkan12Features();
+ const auto& fragmentShadingRateFeatures = context.getFragmentShadingRateFeatures();
+ const auto& fragmentShadingRateProperties = context.getFragmentShadingRateProperties();
+
+ if (!fragmentShadingRateFeatures.pipelineFragmentShadingRate)
+ {
+ log << tcu::TestLog::Message << "pipelineFragmentShadingRate is not supported" << tcu::TestLog::EndMessage;
+ allChecksPassed = false;
+ }
+
+ if (context.getFragmentShadingRateProperties().primitiveFragmentShadingRateWithMultipleViewports && !context.getFragmentShadingRateFeatures().primitiveFragmentShadingRate)
+ {
+ log << tcu::TestLog::Message << "primitiveFragmentShadingRateWithMultipleViewports "
+ "limit should only be supported if primitiveFragmentShadingRate is supported" << tcu::TestLog::EndMessage;
+ allChecksPassed = false;
+ }
+
+ bool requiredFeatures = features.geometryShader || vulkan12Features.shaderOutputViewportIndex || context.isDeviceFunctionalitySupported("VK_EXT_shader_viewport_index_layer");
+ if (context.getFragmentShadingRateProperties().primitiveFragmentShadingRateWithMultipleViewports && !requiredFeatures)
+ {
+ log << tcu::TestLog::Message << "primitiveFragmentShadingRateWithMultipleViewports limit should only "
+ "be supported if at least one of the geometryShader feature, shaderOutputViewportIndex feature, "
+ "or VK_EXT_shader_viewport_index_layer extension is supported" << tcu::TestLog::EndMessage;
+ allChecksPassed = false;
+ }
+
+ if (fragmentShadingRateProperties.layeredShadingRateAttachments && !fragmentShadingRateFeatures.attachmentFragmentShadingRate)
+ {
+ log << tcu::TestLog::Message << "layeredShadingRateAttachments should only be supported if attachmentFragmentShadingRate is supported" << tcu::TestLog::EndMessage;
+ allChecksPassed = false;
+ }
+
+ requiredFeatures = features.geometryShader || context.getMultiviewFeatures().multiview || vulkan12Features.shaderOutputViewportIndex ||
+ context.isDeviceFunctionalitySupported("VK_EXT_shader_viewport_index_layer");
+ if (fragmentShadingRateProperties.layeredShadingRateAttachments && !requiredFeatures)
+ {
+ log << tcu::TestLog::Message << "layeredShadingRateAttachments should only be supported if at least one of the geometryShader feature, multiview feature, "
+ "shaderOutputViewportIndex feature, or VK_EXT_shader_viewport_index_layer extension is supported" << tcu::TestLog::EndMessage;
+ allChecksPassed = false;
+ }
+
+ requiredFeatures = fragmentShadingRateFeatures.primitiveFragmentShadingRate || fragmentShadingRateFeatures.attachmentFragmentShadingRate;
+ if (fragmentShadingRateProperties.fragmentShadingRateNonTrivialCombinerOps && !requiredFeatures)
+ {
+ log << tcu::TestLog::Message << "fragmentShadingRateNonTrivialCombinerOps should only be supported if at least one of primitiveFragmentShadingRate "
+ "or attachmentFragmentShadingRate is supported" << tcu::TestLog::EndMessage;
+ allChecksPassed = false;
+ }
+
+ if (fragmentShadingRateProperties.maxFragmentSizeAspectRatio > std::max(fragmentShadingRateProperties.maxFragmentSize.width, fragmentShadingRateProperties.maxFragmentSize.height))
+ {
+ log << tcu::TestLog::Message << "maxFragmentSizeAspectRatio should be less than or equal to the maximum width / height of maxFragmentSize" << tcu::TestLog::EndMessage;
+ allChecksPassed = false;
+ }
+
+ if (fragmentShadingRateProperties.maxFragmentSizeAspectRatio < 2)
+ {
+ log << tcu::TestLog::Message << "maxFragmentSizeAspectRatio should be at least 2" << tcu::TestLog::EndMessage;
+ allChecksPassed = false;
+ }
+
+ if (!deIntIsPow2(static_cast<int>(fragmentShadingRateProperties.maxFragmentSizeAspectRatio)))
+ {
+ log << tcu::TestLog::Message << "maxFragmentSizeAspectRatio should be power of 2" << tcu::TestLog::EndMessage;
+ allChecksPassed = false;
+ }
+
+ if (fragmentShadingRateProperties.fragmentShadingRateWithShaderSampleMask && (fragmentShadingRateProperties.maxFragmentShadingRateCoverageSamples > (properties.limits.maxSampleMaskWords * 32)))
+ {
+ log << tcu::TestLog::Message << "maxFragmentShadingRateCoverageSamples should be less than or equal maxSampleMaskWords * 32 "
+ "if fragmentShadingRateWithShaderSampleMask is supported" << tcu::TestLog::EndMessage;
+ allChecksPassed = false;
+ }
+
+ deUint32 requiredValue = fragmentShadingRateProperties.maxFragmentSize.width * fragmentShadingRateProperties.maxFragmentSize.height *
+ fragmentShadingRateProperties.maxFragmentShadingRateRasterizationSamples;
+ if (fragmentShadingRateProperties.maxFragmentShadingRateCoverageSamples > requiredValue)
+ {
+ log << tcu::TestLog::Message << "maxFragmentShadingRateCoverageSamples should be less than or equal to the product of the width and height of "
+ "maxFragmentSize and the samples reported by maxFragmentShadingRateRasterizationSamples" << tcu::TestLog::EndMessage;
+ allChecksPassed = false;
+ }
+
+ if (fragmentShadingRateProperties.maxFragmentShadingRateCoverageSamples < 16)
+ {
+ log << tcu::TestLog::Message << "maxFragmentShadingRateCoverageSamples should at least be 16" << tcu::TestLog::EndMessage;
+ allChecksPassed = false;
+ }
+
+ if (fragmentShadingRateProperties.maxFragmentShadingRateRasterizationSamples < vk::VK_SAMPLE_COUNT_4_BIT)
+ {
+ log << tcu::TestLog::Message << "maxFragmentShadingRateRasterizationSamples should supports at least VK_SAMPLE_COUNT_4_BIT" << tcu::TestLog::EndMessage;
+ allChecksPassed = false;
+ }
+
+ if (fragmentShadingRateProperties.fragmentShadingRateWithConservativeRasterization && !context.isDeviceFunctionalitySupported("VK_EXT_conservative_rasterization"))
+ {
+ log << tcu::TestLog::Message << "fragmentShadingRateWithConservativeRasterization should only be supported if VK_EXT_conservative_rasterization is supported" << tcu::TestLog::EndMessage;
+ allChecksPassed = false;
+ }
+
+ if (fragmentShadingRateProperties.fragmentShadingRateWithFragmentShaderInterlock && !context.isDeviceFunctionalitySupported("VK_EXT_fragment_shader_interlock"))
+ {
+ log << tcu::TestLog::Message << "fragmentShadingRateWithFragmentShaderInterlock should only be supported if VK_EXT_fragment_shader_interlock is supported" << tcu::TestLog::EndMessage;
+ allChecksPassed = false;
+ }
+
+ if (fragmentShadingRateProperties.fragmentShadingRateWithCustomSampleLocations && !context.isDeviceFunctionalitySupported("VK_EXT_sample_locations"))
+ {
+ log << tcu::TestLog::Message << "fragmentShadingRateWithCustomSampleLocations should only be supported if VK_EXT_sample_locations is supported" << tcu::TestLog::EndMessage;
+ allChecksPassed = false;
+ }
+
+ if (fragmentShadingRateFeatures.attachmentFragmentShadingRate)
+ {
+ if ((fragmentShadingRateProperties.maxFragmentShadingRateAttachmentTexelSize.width < 8) ||
+ (fragmentShadingRateProperties.maxFragmentShadingRateAttachmentTexelSize.height < 8))
+ {
+ log << tcu::TestLog::Message << "maxFragmentShadingRateAttachmentTexelSize should at least be { 8,8 }" << tcu::TestLog::EndMessage;
+ allChecksPassed = false;
+ }
+
+ if ((fragmentShadingRateProperties.minFragmentShadingRateAttachmentTexelSize.width > 32) ||
+ (fragmentShadingRateProperties.minFragmentShadingRateAttachmentTexelSize.height > 32))
+ {
+ log << tcu::TestLog::Message << "minFragmentShadingRateAttachmentTexelSize should't be greater than { 32,32 }" << tcu::TestLog::EndMessage;
+ allChecksPassed = false;
+ }
+
+ if ((fragmentShadingRateProperties.maxFragmentShadingRateAttachmentTexelSize.width < fragmentShadingRateProperties.minFragmentShadingRateAttachmentTexelSize.width) ||
+ (fragmentShadingRateProperties.maxFragmentShadingRateAttachmentTexelSize.height < fragmentShadingRateProperties.minFragmentShadingRateAttachmentTexelSize.height))
+ {
+ log << tcu::TestLog::Message << "maxFragmentShadingRateAttachmentTexelSize should be greater than or equal to "
+ "minFragmentShadingRateAttachmentTexelSize in each dimension" << tcu::TestLog::EndMessage;
+ allChecksPassed = false;
+ }
+
+ if (!deIntIsPow2(static_cast<int>(fragmentShadingRateProperties.maxFragmentShadingRateAttachmentTexelSize.width)) ||
+ !deIntIsPow2(static_cast<int>(fragmentShadingRateProperties.maxFragmentShadingRateAttachmentTexelSize.height)))
+ {
+ log << tcu::TestLog::Message << "maxFragmentShadingRateAttachmentTexelSize should be power of 2" << tcu::TestLog::EndMessage;
+ allChecksPassed = false;
+ }
+
+ if (!deIntIsPow2(static_cast<int>(fragmentShadingRateProperties.minFragmentShadingRateAttachmentTexelSize.width)) ||
+ !deIntIsPow2(static_cast<int>(fragmentShadingRateProperties.minFragmentShadingRateAttachmentTexelSize.height)))
+ {
+ log << tcu::TestLog::Message << "minFragmentShadingRateAttachmentTexelSize should be power of 2" << tcu::TestLog::EndMessage;
+ allChecksPassed = false;
+ }
+ }
+ else
+ {
+ if ((fragmentShadingRateProperties.maxFragmentShadingRateAttachmentTexelSize.width != 0) ||
+ (fragmentShadingRateProperties.maxFragmentShadingRateAttachmentTexelSize.height != 0))
+ {
+ log << tcu::TestLog::Message << "maxFragmentShadingRateAttachmentTexelSize should be { 0,0 } when "
+ "attachmentFragmentShadingRate is not supported" << tcu::TestLog::EndMessage;
+ allChecksPassed = false;
+ }
+
+ if ((fragmentShadingRateProperties.minFragmentShadingRateAttachmentTexelSize.width != 0) ||
+ (fragmentShadingRateProperties.minFragmentShadingRateAttachmentTexelSize.height != 0))
+ {
+ log << tcu::TestLog::Message << "minFragmentShadingRateAttachmentTexelSize should be { 0,0 } when "
+ "attachmentFragmentShadingRate is not supported" << tcu::TestLog::EndMessage;
+ allChecksPassed = false;
+ }
+ }
+
+ if ((fragmentShadingRateProperties.maxFragmentSize.width < 2) ||
+ (fragmentShadingRateProperties.maxFragmentSize.height < 2))
+ {
+ log << tcu::TestLog::Message << "maxFragmentSize should at least be { 2,2 }" << tcu::TestLog::EndMessage;
+ allChecksPassed = false;
+ }
+
+ if ((fragmentShadingRateProperties.maxFragmentSize.width > 4) ||
+ (fragmentShadingRateProperties.maxFragmentSize.height > 4))
+ {
+ log << tcu::TestLog::Message << "maxFragmentSize should't be greater than{ 4,4 }" << tcu::TestLog::EndMessage;
+ allChecksPassed = false;
+ }
+
+ if (allChecksPassed)
+ return tcu::TestStatus::pass("pass");
+ return tcu::TestStatus::fail("fail");
+}
+
+tcu::TestStatus testShadingRates(Context& context)
+{
+ bool someChecksFailed = false;
+ tcu::TestLog& log = context.getTestContext().getLog();
+ const vk::InstanceInterface& vki = context.getInstanceInterface();
+ vk::VkPhysicalDevice physicalDevice = context.getPhysicalDevice();
+ const auto& fragmentShadingRateProperties = context.getFragmentShadingRateProperties();
+ deUint32 supportedFragmentShadingRateCount = 0;
+
+ vk::VkResult result = vki.getPhysicalDeviceFragmentShadingRatesKHR(physicalDevice, &supportedFragmentShadingRateCount, DE_NULL);
+ if ((result != vk::VK_SUCCESS) && (result != vk::VK_ERROR_OUT_OF_HOST_MEMORY))
+ {
+ someChecksFailed = true;
+ log << tcu::TestLog::Message << "vkGetPhysicalDeviceFragmentShadingRatesKHR returned invalid result" << tcu::TestLog::EndMessage;
+ }
+
+ std::vector<vk::VkPhysicalDeviceFragmentShadingRateKHR> fragmentShadingRateVect(supportedFragmentShadingRateCount);
+ for (auto& fragmentShadingRate : fragmentShadingRateVect)
+ {
+ fragmentShadingRate.sType = vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR;
+ fragmentShadingRate.pNext = DE_NULL;
+ }
+
+ // Pass a value of 1 into pFragmentShadingRateCount, and an array of at least length one into pFragmentShadingRates.
+ // 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).
+ supportedFragmentShadingRateCount = 1u;
+ result = vki.getPhysicalDeviceFragmentShadingRatesKHR(physicalDevice, &supportedFragmentShadingRateCount, fragmentShadingRateVect.data());
+ if ((result != vk::VK_INCOMPLETE) && (result != vk::VK_ERROR_OUT_OF_HOST_MEMORY))
+ {
+ someChecksFailed = true;
+ log << tcu::TestLog::Message << "vkGetPhysicalDeviceFragmentShadingRatesKHR returned invalid result" << tcu::TestLog::EndMessage;
+ }
+
+ // Get all available fragment shading rates
+ supportedFragmentShadingRateCount = static_cast<deUint32>(fragmentShadingRateVect.size());
+ result = vki.getPhysicalDeviceFragmentShadingRatesKHR(physicalDevice, &supportedFragmentShadingRateCount, fragmentShadingRateVect.data());
+ if ((result != vk::VK_SUCCESS) && (result != vk::VK_ERROR_OUT_OF_HOST_MEMORY))
+ {
+ someChecksFailed = true;
+ log << tcu::TestLog::Message << "vkGetPhysicalDeviceFragmentShadingRatesKHR returned invalid result" << tcu::TestLog::EndMessage;
+ }
+
+ bool widthCheckPassed = true;
+ bool heightCheckPassed = true;
+ deUint32 previousWidth = std::numeric_limits<deUint32>::max();
+ deUint32 previousHeight = std::numeric_limits<deUint32>::max();
+
+ for (const auto& fsr : fragmentShadingRateVect)
+ {
+ const auto& fragmentSize = fsr.fragmentSize;
+
+ // Check that rate width and height are power-of-two
+ if (!deIntIsPow2(static_cast<int>(fragmentSize.width)) ||
+ !deIntIsPow2(static_cast<int>(fragmentSize.height)))
+ {
+ log << tcu::TestLog::Message << "fragmentSize should be power of 2" << tcu::TestLog::EndMessage;
+ someChecksFailed = true;
+ }
+
+ // Check that the width and height are less than the values in the maxFragmentSize limit
+ if ((fragmentSize.width > fragmentShadingRateProperties.maxFragmentSize.width) ||
+ (fragmentSize.height > fragmentShadingRateProperties.maxFragmentSize.height))
+ {
+ log << tcu::TestLog::Message << "fragmentSize width and height are not less than the values in the maxFragmentSize" << tcu::TestLog::EndMessage;
+ someChecksFailed = true;
+ }
+
+ if ((fragmentSize.width * fragmentSize.height) == 1)
+ {
+ // special case for fragmentSize {1, 1}
+ if (fsr.sampleCounts != ~0u)
+ {
+ log << tcu::TestLog::Message << "implementations must support sampleCounts equal to ~0 for fragmentSize {1, 1}" << tcu::TestLog::EndMessage;
+ someChecksFailed = true;
+ }
+ }
+ else
+ {
+ // get highest sample count value
+ deUint32 highestSampleCount = 0x80000000;
+ while (highestSampleCount)
+ {
+ if (fsr.sampleCounts & highestSampleCount)
+ break;
+ highestSampleCount >>= 1;
+ };
+
+ // Check that the highest sample count in sampleCounts is less than or equal to maxFragmentShadingRateRasterizationSamples limit
+ if (highestSampleCount > static_cast<deUint32>(fragmentShadingRateProperties.maxFragmentShadingRateRasterizationSamples))
+ {
+ log << tcu::TestLog::Message << "highest sample count value is not less than or equal to the maxFragmentShadingRateRasterizationSamples limit" << tcu::TestLog::EndMessage;
+ someChecksFailed = true;
+ }
+
+ // Check that the product of the width, height, and highest sample count value is less than the maxFragmentShadingRateCoverageSamples limit
+ if ((fragmentSize.width * fragmentSize.height * highestSampleCount) > fragmentShadingRateProperties.maxFragmentShadingRateCoverageSamples)
+ {
+ log << tcu::TestLog::Message << "product of the width, height, and highest sample count value is not less than the maxFragmentShadingRateCoverageSamples limit" << tcu::TestLog::EndMessage;
+ someChecksFailed = true;
+ }
+ }
+
+ // Check that the entries in the array are ordered first by largest to smallest width, then largest to smallest height
+ {
+ const deUint32 currentWidth = fragmentSize.width;
+ if (widthCheckPassed && (currentWidth > previousWidth))
+ {
+ log << tcu::TestLog::Message << "vkGetPhysicalDeviceFragmentShadingRatesKHR returned entries that are not ordered by largest to smallest width" << tcu::TestLog::EndMessage;
+ widthCheckPassed = false;
+ }
+
+ deUint32 currentHeight = fragmentSize.height;
+ if (heightCheckPassed)
+ {
+ // we can check order of height only for entries that have same width
+ if (currentWidth == previousWidth)
+ {
+ if (currentHeight > previousHeight)
+ {
+ log << tcu::TestLog::Message << "vkGetPhysicalDeviceFragmentShadingRatesKHR returned entries with same width but height is not ordered by largest to smallest" << tcu::TestLog::EndMessage;
+ heightCheckPassed = false;
+ }
+ }
+ else
+ currentHeight = std::numeric_limits<deUint32>::max();
+ }
+
+ previousWidth = currentWidth;
+ previousHeight = currentHeight;
+ }
+
+ // Check that no two entries in the array have the same fragmentSize.width and fragmentSize.height value
+ {
+ deUint32 count = 0;
+ for (const auto& fsrB : fragmentShadingRateVect)
+ {
+ if ((fragmentSize.width == fsrB.fragmentSize.width) &&
+ (fragmentSize.height == fsrB.fragmentSize.height))
+ {
+ if (++count > 1)
+ {
+ log << tcu::TestLog::Message << "vkGetPhysicalDeviceFragmentShadingRatesKHR returned entries with same fragmentSize" << tcu::TestLog::EndMessage;
+ someChecksFailed = true;
+ break;
+ }
+ }
+ }
+ }
+
+ // Check that 1x1, 1x2, 2x1, and 2x2 rates are supported with sample counts of 1 and 4
+ if ((fragmentSize.width < 3) && (fragmentSize.height < 3) &&
+ (!(fsr.sampleCounts & vk::VK_SAMPLE_COUNT_1_BIT) || !(fsr.sampleCounts & vk::VK_SAMPLE_COUNT_4_BIT)))
+ {
+ log << tcu::TestLog::Message << "vkGetPhysicalDeviceFragmentShadingRatesKHR returned 1x1, 1x2, 2x1, and 2x2 rates with sample counts not supporting 1 and 4" << tcu::TestLog::EndMessage;
+ someChecksFailed = true;
+ }
+
+ // 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.
+ if (context.getDeviceProperties().limits.framebufferColorSampleCounts & vk::VK_SAMPLE_COUNT_2_BIT)
+ {
+ if ((fragmentSize.width < 3) && (fragmentSize.height < 3) &&
+ !(fsr.sampleCounts & vk::VK_SAMPLE_COUNT_2_BIT))
+ {
+ log << tcu::TestLog::Message << "vkGetPhysicalDeviceFragmentShadingRatesKHR returned 1x1, 1x2, 2x1, and 2x2 rates with sample counts not supporting 2 while framebufferColorSampleCounts does" << tcu::TestLog::EndMessage;
+ someChecksFailed = true;
+ }
+ }
+ }
+
+ if (someChecksFailed || !widthCheckPassed || !heightCheckPassed)
+ return tcu::TestStatus::fail("fail");
+
+ return tcu::TestStatus::pass("pass");
+}
+
+void checkSupport(Context& context)
+{
+ context.requireDeviceFunctionality("VK_KHR_fragment_shading_rate");
+}
+
+void createMiscTests(tcu::TestContext& testCtx, tcu::TestCaseGroup* parentGroup)
+{
+ de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "misc", ""));
+
+ addFunctionCase(group.get(), "limits", "", checkSupport, testLimits);
+ addFunctionCase(group.get(), "shading_rates", "", checkSupport, testShadingRates);
+
+ parentGroup->addChild(group.release());
+}
+
void createChildren (tcu::TestCaseGroup* group)
{
tcu::TestContext& testCtx = group->getTestContext();
+ createMiscTests (testCtx, group);
createBasicTests (testCtx, group);
createPixelConsistencyTests(testCtx, group);
}
return createTestGroup(testCtx, "fragment_shading_rate", "Fragment shading rate tests", createChildren);
}
-} // FragmentShaderInterlock
+} // FragmentShadingRate
} // vkt