blob: 69ceb34d2c5ddeda6404f65dcc2c657ec91c9d76 [file] [log] [blame]
/*
* Copyright (c) 2015-2023 The Khronos Group Inc.
* Copyright (c) 2015-2023 Valve Corporation
* Copyright (c) 2015-2023 LunarG, Inc.
* Copyright (c) 2015-2023 Google, Inc.
* Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*/
#include "utils/cast_utils.h"
#include "../framework/layer_validation_tests.h"
#include "../framework/pipeline_helper.h"
TEST_F(NegativeSubgroup, Properties) {
TEST_DESCRIPTION(
"Test shader validation support for subgroup VkPhysicalDeviceSubgroupProperties such as supportedStages, and "
"supportedOperations, quadOperationsInAllStages.");
SetTargetApiVersion(VK_API_VERSION_1_1);
RETURN_IF_SKIP(InitFramework())
VkPhysicalDeviceFeatures features{};
vk::GetPhysicalDeviceFeatures(gpu(), &features);
if (features.vertexPipelineStoresAndAtomics == VK_FALSE) {
GTEST_SKIP() << "vertexPipelineStoresAndAtomics not supported";
}
features = {};
features.vertexPipelineStoresAndAtomics = VK_TRUE;
RETURN_IF_SKIP(InitState(&features));
// Don't enable the extension on purpose
const bool extension_support_partitioned =
DeviceExtensionSupported(gpu(), nullptr, VK_NV_SHADER_SUBGROUP_PARTITIONED_EXTENSION_NAME);
InitRenderTarget();
// Gather all aspects supported
VkPhysicalDeviceSubgroupProperties subgroup_prop = vku::InitStructHelper();
GetPhysicalDeviceProperties2(subgroup_prop);
VkSubgroupFeatureFlags subgroup_operations = subgroup_prop.supportedOperations;
const bool feature_support_basic = ((subgroup_operations & VK_SUBGROUP_FEATURE_BASIC_BIT) != 0);
const bool feature_support_vote = ((subgroup_operations & VK_SUBGROUP_FEATURE_VOTE_BIT) != 0);
const bool feature_support_arithmetic = ((subgroup_operations & VK_SUBGROUP_FEATURE_ARITHMETIC_BIT) != 0);
const bool feature_support_ballot = ((subgroup_operations & VK_SUBGROUP_FEATURE_BALLOT_BIT) != 0);
const bool feature_support_shuffle = ((subgroup_operations & VK_SUBGROUP_FEATURE_SHUFFLE_BIT) != 0);
const bool feature_support_relative = ((subgroup_operations & VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT) != 0);
const bool feature_support_culstered = ((subgroup_operations & VK_SUBGROUP_FEATURE_CLUSTERED_BIT) != 0);
const bool feature_support_quad = ((subgroup_operations & VK_SUBGROUP_FEATURE_QUAD_BIT) != 0);
const bool feature_support_partitioned = ((subgroup_operations & VK_SUBGROUP_FEATURE_PARTITIONED_BIT_NV) != 0);
const bool vertex_support = ((subgroup_prop.supportedStages & VK_SHADER_STAGE_VERTEX_BIT) != 0);
const bool vertex_quad_support = (subgroup_prop.quadOperationsInAllStages == VK_TRUE);
if (!feature_support_basic) {
GTEST_SKIP() << "VK_SUBGROUP_FEATURE_BASIC_BIT not supported, all test will have issues";
}
std::string vsSource;
std::vector<const char *> errors;
// There is no 'supportedOperations' check due to it would be redundant to the Capability check done first in VUID 01091 since
// each 'supportedOperations' flag is 1:1 map to a SPIR-V Capability
const char *operation_vuid = "VUID-VkShaderModuleCreateInfo-pCode-08740";
const char *stage_vuid = "VUID-RuntimeSpirv-None-06343";
const char *quad_vuid = "VUID-RuntimeSpirv-None-06342";
// Same pipeline creation for each subgroup test
auto info_override = [&](CreatePipelineHelper &info) {
info.vs_ = std::make_unique<VkShaderObj>(this, vsSource.c_str(), VK_SHADER_STAGE_VERTEX_BIT, SPV_ENV_VULKAN_1_1);
info.shader_stages_ = {info.vs_->GetStageCreateInfo(), info.fs_->GetStageCreateInfo()};
info.dsl_bindings_ = {{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}};
};
// Basic
{
vsSource = R"glsl(
#version 450
#extension GL_KHR_shader_subgroup_basic: enable
layout(set = 0, binding = 0) buffer StorageBuffer { float x; uint y; } ssbo;
void main(){
if (subgroupElect()) { ssbo.x += 2.0; }
gl_Position = vec4(ssbo.x);
}
)glsl";
errors.clear();
if (vertex_support == false) {
errors.push_back(stage_vuid);
}
CreatePipelineHelper::OneshotTest(*this, info_override, kErrorBit, errors);
}
// Vote
{
vsSource = R"glsl(
#version 450
#extension GL_KHR_shader_subgroup_vote: enable
layout(set = 0, binding = 0) buffer StorageBuffer { float x; uint y; } ssbo;
void main(){
if (subgroupAll(ssbo.y == 0)) { ssbo.x += 2.0; }
gl_Position = vec4(ssbo.x);
}
)glsl";
errors.clear();
if (feature_support_vote == false) {
errors.push_back(operation_vuid);
}
if (vertex_support == false) {
errors.push_back(stage_vuid);
}
CreatePipelineHelper::OneshotTest(*this, info_override, kErrorBit, errors);
}
// Arithmetic
{
vsSource = R"glsl(
#version 450
#extension GL_KHR_shader_subgroup_arithmetic: enable
layout(set = 0, binding = 0) buffer StorageBuffer { float x; uint y; } ssbo;
void main(){
float z = subgroupMax(ssbo.x);
gl_Position = vec4(z);
}
)glsl";
errors.clear();
if (feature_support_arithmetic == false) {
errors.push_back(operation_vuid);
}
if (vertex_support == false) {
errors.push_back(stage_vuid);
}
CreatePipelineHelper::OneshotTest(*this, info_override, kErrorBit, errors);
}
// Ballot
{
vsSource = R"glsl(
#version 450
#extension GL_KHR_shader_subgroup_ballot: enable
layout(set = 0, binding = 0) buffer StorageBuffer { float x; uint y; } ssbo;
void main(){
float z = subgroupBroadcastFirst(ssbo.x);
gl_Position = vec4(z);
}
)glsl";
errors.clear();
if (feature_support_ballot == false) {
errors.push_back(operation_vuid);
}
if (vertex_support == false) {
errors.push_back(stage_vuid);
}
CreatePipelineHelper::OneshotTest(*this, info_override, kErrorBit, errors);
}
// Shuffle
{
vsSource = R"glsl(
#version 450
#extension GL_KHR_shader_subgroup_shuffle: enable
layout(set = 0, binding = 0) buffer StorageBuffer { float x; uint y; } ssbo;
void main(){
float z = subgroupShuffle(ssbo.x, 1);
gl_Position = vec4(z);
}
)glsl";
errors.clear();
if (feature_support_shuffle == false) {
errors.push_back(operation_vuid);
}
if (vertex_support == false) {
errors.push_back(stage_vuid);
}
CreatePipelineHelper::OneshotTest(*this, info_override, kErrorBit, errors);
}
// Shuffle Relative
{
vsSource = R"glsl(
#version 450
#extension GL_KHR_shader_subgroup_shuffle_relative: enable
layout(set = 0, binding = 0) buffer StorageBuffer { float x; uint y; } ssbo;
void main(){
float z = subgroupShuffleUp(ssbo.x, 1);
gl_Position = vec4(z);
}
)glsl";
errors.clear();
if (feature_support_relative == false) {
errors.push_back(operation_vuid);
}
if (vertex_support == false) {
errors.push_back(stage_vuid);
}
CreatePipelineHelper::OneshotTest(*this, info_override, kErrorBit, errors);
}
// Clustered
{
vsSource = R"glsl(
#version 450
#extension GL_KHR_shader_subgroup_clustered: enable
layout(set = 0, binding = 0) buffer StorageBuffer { float x; uint y; } ssbo;
void main(){
float z = subgroupClusteredAdd(ssbo.x, 2);
gl_Position = vec4(z);
}
)glsl";
errors.clear();
if (feature_support_culstered == false) {
errors.push_back(operation_vuid);
}
if (vertex_support == false) {
errors.push_back(stage_vuid);
}
CreatePipelineHelper::OneshotTest(*this, info_override, kErrorBit, errors);
}
// Quad
{
vsSource = R"glsl(
#version 450
#extension GL_KHR_shader_subgroup_quad: enable
layout(set = 0, binding = 0) buffer StorageBuffer { float x; uint y; } ssbo;
void main(){
float z = subgroupQuadSwapHorizontal(ssbo.x);
gl_Position = vec4(z);
}
)glsl";
errors.clear();
if (feature_support_quad == false) {
errors.push_back(operation_vuid);
}
if (vertex_quad_support == false) {
errors.push_back(quad_vuid);
}
if (vertex_support == false) {
errors.push_back(stage_vuid);
}
CreatePipelineHelper::OneshotTest(*this, info_override, kErrorBit, errors);
}
// Partitoned
if (extension_support_partitioned) {
vsSource = R"glsl(
#version 450
#extension GL_NV_shader_subgroup_partitioned: enable
layout(set = 0, binding = 0) buffer StorageBuffer { float x; uint y; } ssbo;
void main(){
uvec4 a = subgroupPartitionNV(ssbo.x); // forces OpGroupNonUniformPartitionNV
gl_Position = vec4(float(a.x));
}
)glsl";
errors.clear();
// Extension not enabled on purpose if supported
errors.push_back("VUID-VkShaderModuleCreateInfo-pCode-08742");
if (feature_support_partitioned == false) {
// errors.push_back(operation_vuid);
}
if (vertex_support == false) {
errors.push_back(stage_vuid);
}
CreatePipelineHelper::OneshotTest(*this, info_override, kErrorBit, errors);
}
}
// TODO 5600 - Not all pNext structs are being passed in to check version
TEST_F(NegativeSubgroup, DISABLED_pNextDisabled) {
TEST_DESCRIPTION("Try to use structs with 1.0");
SetTargetApiVersion(VK_API_VERSION_1_0);
AddRequiredExtensions(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
RETURN_IF_SKIP(InitState())
VkPhysicalDeviceSubgroupProperties subgroup_prop = vku::InitStructHelper();
VkPhysicalDeviceProperties2 props2 = vku::InitStructHelper(&subgroup_prop);
vk::GetPhysicalDeviceProperties2(gpu_, &props2);
}
TEST_F(NegativeSubgroup, ExtendedTypesEnabled) {
TEST_DESCRIPTION("Test VK_KHR_shader_subgroup_extended_types.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_SHADER_SUBGROUP_EXTENDED_TYPES_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
VkPhysicalDeviceFloat16Int8FeaturesKHR float16_features = vku::InitStructHelper();
VkPhysicalDeviceShaderSubgroupExtendedTypesFeaturesKHR extended_types_features = vku::InitStructHelper(&float16_features);
auto features2 = GetPhysicalDeviceFeatures2(extended_types_features);
VkPhysicalDeviceSubgroupProperties subgroup_prop = vku::InitStructHelper();
GetPhysicalDeviceProperties2(subgroup_prop);
if (!(subgroup_prop.supportedOperations & VK_SUBGROUP_FEATURE_ARITHMETIC_BIT) ||
!(subgroup_prop.supportedStages & VK_SHADER_STAGE_COMPUTE_BIT) || !float16_features.shaderFloat16 ||
!extended_types_features.shaderSubgroupExtendedTypes) {
GTEST_SKIP() << "Required features not supported";
}
RETURN_IF_SKIP(InitState(nullptr, &features2))
std::vector<VkDescriptorSetLayoutBinding> bindings(0);
const vkt::DescriptorSetLayout dsl(*m_device, bindings);
const vkt::PipelineLayout pl(*m_device, {&dsl});
char const *csSource = R"glsl(
#version 450
#extension GL_KHR_shader_subgroup_arithmetic : enable
#extension GL_EXT_shader_subgroup_extended_types_float16 : enable
#extension GL_EXT_shader_explicit_arithmetic_types_float16 : enable
layout(local_size_x = 32) in;
void main() {
subgroupAdd(float16_t(0.0));
}
)glsl";
CreateComputePipelineHelper pipe(*this);
pipe.cs_ = std::make_unique<VkShaderObj>(this, csSource, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_1);
pipe.InitState();
pipe.CreateComputePipeline();
}
TEST_F(NegativeSubgroup, ExtendedTypesDisabled) {
TEST_DESCRIPTION("Test VK_KHR_shader_subgroup_extended_types.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_SHADER_SUBGROUP_EXTENDED_TYPES_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
VkPhysicalDeviceFloat16Int8FeaturesKHR float16_features = vku::InitStructHelper();
VkPhysicalDeviceShaderSubgroupExtendedTypesFeaturesKHR extended_types_features = vku::InitStructHelper(&float16_features);
auto features2 = GetPhysicalDeviceFeatures2(extended_types_features);
VkPhysicalDeviceSubgroupProperties subgroup_prop = vku::InitStructHelper();
GetPhysicalDeviceProperties2(subgroup_prop);
if (!(subgroup_prop.supportedOperations & VK_SUBGROUP_FEATURE_ARITHMETIC_BIT) ||
!(subgroup_prop.supportedStages & VK_SHADER_STAGE_COMPUTE_BIT) || !float16_features.shaderFloat16) {
GTEST_SKIP() << "Required features not supported";
}
// Disabled extended types support, and expect an error
extended_types_features.shaderSubgroupExtendedTypes = VK_FALSE;
RETURN_IF_SKIP(InitState(nullptr, &features2))
std::vector<VkDescriptorSetLayoutBinding> bindings(0);
const vkt::DescriptorSetLayout dsl(*m_device, bindings);
const vkt::PipelineLayout pl(*m_device, {&dsl});
char const *csSource = R"glsl(
#version 450
#extension GL_KHR_shader_subgroup_arithmetic : enable
#extension GL_EXT_shader_subgroup_extended_types_float16 : enable
#extension GL_EXT_shader_explicit_arithmetic_types_float16 : enable
layout(local_size_x = 32) in;
void main() {
subgroupAdd(float16_t(0.0));
}
)glsl";
CreateComputePipelineHelper pipe(*this);
pipe.cs_ = std::make_unique<VkShaderObj>(this, csSource, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_1);
pipe.InitState();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-RuntimeSpirv-None-06275");
pipe.CreateComputePipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeSubgroup, PipelineSubgroupSizeControl) {
TEST_DESCRIPTION("Test Subgroub Size Control");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
VkPhysicalDeviceSubgroupSizeControlFeaturesEXT sscf = vku::InitStructHelper();
GetPhysicalDeviceFeatures2(sscf);
if (sscf.subgroupSizeControl == VK_FALSE || sscf.computeFullSubgroups == VK_FALSE) {
GTEST_SKIP() << "Required features are not supported";
}
RETURN_IF_SKIP(InitState(nullptr, &sscf));
VkPhysicalDeviceSubgroupSizeControlPropertiesEXT subgroup_properties = vku::InitStructHelper();
VkPhysicalDeviceVulkan11Properties props11 = vku::InitStructHelper(&subgroup_properties);
GetPhysicalDeviceProperties2(props11);
if ((subgroup_properties.requiredSubgroupSizeStages & VK_SHADER_STAGE_COMPUTE_BIT) == 0) {
GTEST_SKIP() << "Required shader stage not present in requiredSubgroupSizeStages";
}
VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT subgroup_size_control = vku::InitStructHelper();
subgroup_size_control.requiredSubgroupSize = subgroup_properties.minSubgroupSize;
{
CreateComputePipelineHelper cs_pipeline(*this);
cs_pipeline.InitState();
cs_pipeline.LateBindPipelineInfo();
cs_pipeline.cp_ci_.stage.pNext = &subgroup_size_control;
cs_pipeline.cp_ci_.stage.flags = VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT_EXT;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkPipelineShaderStageCreateInfo-pNext-02754");
cs_pipeline.CreateComputePipeline(false); // need false to prevent late binding
m_errorMonitor->VerifyFound();
}
if (subgroup_properties.maxSubgroupSize > 1) {
std::stringstream csSource;
csSource << R"glsl(
#version 450
layout(local_size_x = )glsl";
csSource << subgroup_properties.maxSubgroupSize + 1;
csSource << R"glsl() in;
void main() {}
)glsl";
CreateComputePipelineHelper cs_pipeline(*this);
cs_pipeline.cs_ = std::make_unique<VkShaderObj>(this, csSource.str().c_str(), VK_SHADER_STAGE_COMPUTE_BIT);
cs_pipeline.InitState();
cs_pipeline.LateBindPipelineInfo();
cs_pipeline.cp_ci_.stage.flags = VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT_EXT |
VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT_EXT;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkPipelineShaderStageCreateInfo-flags-02758");
cs_pipeline.CreateComputePipeline(false); // need false to prevent late binding
m_errorMonitor->VerifyFound();
}
if (props11.subgroupSize > 1) {
std::stringstream csSource;
csSource << R"glsl(
#version 450
layout(local_size_x = )glsl";
csSource << props11.subgroupSize + 1;
csSource << R"glsl() in;
void main() {}
)glsl";
CreateComputePipelineHelper cs_pipeline(*this);
cs_pipeline.cs_ = std::make_unique<VkShaderObj>(this, csSource.str().c_str(), VK_SHADER_STAGE_COMPUTE_BIT);
cs_pipeline.InitState();
cs_pipeline.LateBindPipelineInfo();
cs_pipeline.cp_ci_.stage.flags = VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT_EXT;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkPipelineShaderStageCreateInfo-flags-02759");
cs_pipeline.CreateComputePipeline(false); // need false to prevent late binding
m_errorMonitor->VerifyFound();
}
// if on a device with the min and max the same, there is no way to isolate this VUID
// Intel integrated GPU normally have a min of 8 and max of 32
if (subgroup_properties.minSubgroupSize >= 8 && subgroup_properties.minSubgroupSize < 16 &&
subgroup_properties.maxSubgroupSize >= 16) {
subgroup_size_control.requiredSubgroupSize = 10; // non-power of 2
CreateComputePipelineHelper cs_pipeline(*this);
cs_pipeline.InitState();
cs_pipeline.LateBindPipelineInfo();
cs_pipeline.cp_ci_.stage.pNext = &subgroup_size_control;
cs_pipeline.cp_ci_.stage.flags = 0;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit,
"VUID-VkPipelineShaderStageRequiredSubgroupSizeCreateInfo-requiredSubgroupSize-02760");
cs_pipeline.CreateComputePipeline(false); // need false to prevent late binding
m_errorMonitor->VerifyFound();
}
if (subgroup_properties.minSubgroupSize > 1) {
subgroup_size_control.requiredSubgroupSize = 1; // below min
CreateComputePipelineHelper cs_pipeline(*this);
cs_pipeline.InitState();
cs_pipeline.LateBindPipelineInfo();
cs_pipeline.cp_ci_.stage.pNext = &subgroup_size_control;
cs_pipeline.cp_ci_.stage.flags = 0;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit,
"VUID-VkPipelineShaderStageRequiredSubgroupSizeCreateInfo-requiredSubgroupSize-02761");
cs_pipeline.CreateComputePipeline(false); // need false to prevent late binding
m_errorMonitor->VerifyFound();
}
{
subgroup_size_control.requiredSubgroupSize = subgroup_properties.maxSubgroupSize * 2; // above max
CreateComputePipelineHelper cs_pipeline(*this);
cs_pipeline.InitState();
cs_pipeline.LateBindPipelineInfo();
cs_pipeline.cp_ci_.stage.pNext = &subgroup_size_control;
cs_pipeline.cp_ci_.stage.flags = 0;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit,
"VUID-VkPipelineShaderStageRequiredSubgroupSizeCreateInfo-requiredSubgroupSize-02762");
cs_pipeline.CreateComputePipeline(false); // need false to prevent late binding
m_errorMonitor->VerifyFound();
}
}
TEST_F(NegativeSubgroup, SubgroupSizeControlFeaturesNotEnabled) {
TEST_DESCRIPTION("Use subgroup size control features when they are not enabled");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
VkPhysicalDeviceSubgroupSizeControlFeaturesEXT sscf = vku::InitStructHelper();
sscf.subgroupSizeControl = VK_FALSE;
sscf.computeFullSubgroups = VK_FALSE;
VkPhysicalDeviceFeatures2 pd_features2 = vku::InitStructHelper(&sscf);
RETURN_IF_SKIP(InitState(nullptr, &pd_features2));
VkPhysicalDeviceVulkan11Properties props11 = vku::InitStructHelper();
GetPhysicalDeviceProperties2(props11);
std::stringstream csSource;
// Make sure compute pipeline has a compute shader stage set
csSource << R"(
#version 450
layout(local_size_x = )";
csSource << props11.subgroupSize;
csSource << R"() in;
void main(){
}
)";
CreateComputePipelineHelper pipe(*this);
pipe.cs_ = std::make_unique<VkShaderObj>(this, csSource.str().c_str(), VK_SHADER_STAGE_COMPUTE_BIT);
pipe.InitState();
pipe.LateBindPipelineInfo();
pipe.cp_ci_.stage.flags = VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT_EXT;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkPipelineShaderStageCreateInfo-flags-02784");
pipe.CreateComputePipeline(false);
m_errorMonitor->VerifyFound();
pipe.cp_ci_.stage.flags = VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT_EXT;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkPipelineShaderStageCreateInfo-flags-02785");
pipe.CreateComputePipeline(false);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeSubgroup, SubgroupSizeControlFeaturesWithIdentifierGraphics) {
TEST_DESCRIPTION("Use subgroup size control features when they are not enabled using a shader module identifier");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_SHADER_MODULE_IDENTIFIER_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
VkPhysicalDevicePipelineCreationCacheControlFeatures shader_cache_control_features = vku::InitStructHelper();
VkPhysicalDeviceShaderModuleIdentifierFeaturesEXT shader_module_id_features =
vku::InitStructHelper(&shader_cache_control_features);
GetPhysicalDeviceFeatures2(shader_module_id_features);
VkPhysicalDeviceSubgroupSizeControlFeaturesEXT subgroup_size_control_features = vku::InitStructHelper();
subgroup_size_control_features.subgroupSizeControl = VK_FALSE;
shader_cache_control_features.pNext = &subgroup_size_control_features;
RETURN_IF_SKIP(InitState(nullptr, &shader_module_id_features));
InitRenderTarget();
VkPipelineShaderStageModuleIdentifierCreateInfoEXT sm_id_create_info = vku::InitStructHelper();
VkShaderObj vs(this, kVertexMinimalGlsl, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderModuleIdentifierEXT get_identifier = vku::InitStructHelper();
vk::GetShaderModuleIdentifierEXT(device(), vs.handle(), &get_identifier);
sm_id_create_info.identifierSize = get_identifier.identifierSize;
sm_id_create_info.pIdentifier = get_identifier.identifier;
VkPipelineShaderStageCreateInfo stage_ci = vku::InitStructHelper(&sm_id_create_info);
stage_ci.stage = VK_SHADER_STAGE_VERTEX_BIT;
stage_ci.module = VK_NULL_HANDLE;
stage_ci.pName = "main";
CreatePipelineHelper pipe(*this);
pipe.gp_ci_.stageCount = 1;
pipe.gp_ci_.pStages = &stage_ci;
pipe.rs_state_ci_.rasterizerDiscardEnable = VK_TRUE;
pipe.InitState();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkPipelineShaderStageModuleIdentifierCreateInfoEXT-pNext-06851");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
pipe.gp_ci_.flags |= VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT;
stage_ci.flags = VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkPipelineShaderStageCreateInfo-flags-02784");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeSubgroup, SubgroupSizeControlFeaturesWithIdentifierCompute) {
TEST_DESCRIPTION("Use subgroup size control features when they are not enabled using a shader module identifier");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_SHADER_MODULE_IDENTIFIER_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
VkPhysicalDevicePipelineCreationCacheControlFeatures shader_cache_control_features = vku::InitStructHelper();
VkPhysicalDeviceShaderModuleIdentifierFeaturesEXT shader_module_id_features =
vku::InitStructHelper(&shader_cache_control_features);
GetPhysicalDeviceFeatures2(shader_module_id_features);
VkPhysicalDeviceSubgroupSizeControlFeaturesEXT subgroup_size_control_features = vku::InitStructHelper();
subgroup_size_control_features.subgroupSizeControl = VK_FALSE;
shader_cache_control_features.pNext = &subgroup_size_control_features;
RETURN_IF_SKIP(InitState(nullptr, &shader_module_id_features));
VkPipelineShaderStageModuleIdentifierCreateInfoEXT sm_id_create_info = vku::InitStructHelper();
VkShaderObj cs(this, kMinimalShaderGlsl, VK_SHADER_STAGE_COMPUTE_BIT);
VkShaderModuleIdentifierEXT get_identifier = vku::InitStructHelper();
vk::GetShaderModuleIdentifierEXT(device(), cs.handle(), &get_identifier);
sm_id_create_info.identifierSize = get_identifier.identifierSize;
sm_id_create_info.pIdentifier = get_identifier.identifier;
VkPipelineShaderStageCreateInfo stage_ci = vku::InitStructHelper(&sm_id_create_info);
stage_ci.stage = VK_SHADER_STAGE_COMPUTE_BIT;
stage_ci.module = VK_NULL_HANDLE;
stage_ci.pName = "main";
CreateComputePipelineHelper pipe(*this);
pipe.InitState();
pipe.cp_ci_.stage = stage_ci;
pipe.cp_ci_.layout = pipe.pipeline_layout_.handle();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkPipelineShaderStageModuleIdentifierCreateInfoEXT-pNext-06851");
pipe.CreateComputePipeline(false);
m_errorMonitor->VerifyFound();
pipe.cp_ci_.flags |= VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT;
pipe.cp_ci_.stage.flags = VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkPipelineShaderStageCreateInfo-flags-02784");
pipe.CreateComputePipeline(false);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeSubgroup, SubgroupSizeControlStage) {
TEST_DESCRIPTION("Use subgroup size control features with wrong shader stage");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
VkPhysicalDeviceSubgroupSizeControlFeaturesEXT sscf = vku::InitStructHelper();
auto features2 = GetPhysicalDeviceFeatures2(sscf);
if (sscf.subgroupSizeControl == VK_FALSE || sscf.computeFullSubgroups == VK_FALSE || sscf.subgroupSizeControl == VK_FALSE) {
GTEST_SKIP() << "Required features are not supported";
}
RETURN_IF_SKIP(InitState(nullptr, &features2))
InitRenderTarget();
VkPhysicalDeviceVulkan11Properties props11 = vku::InitStructHelper();
GetPhysicalDeviceProperties2(props11);
if ((props11.subgroupSupportedStages & VK_SHADER_STAGE_VERTEX_BIT) == 0) {
GTEST_SKIP() << "Vertex shader subgroup not supported.";
}
const char *vsSource = R"glsl(
#version 450
#extension GL_KHR_shader_subgroup_basic : require
void main() {
int x = int(gl_SubgroupSize);
}
)glsl";
VkShaderObj vs(this, vsSource, VK_SHADER_STAGE_VERTEX_BIT, SPV_ENV_VULKAN_1_2);
CreatePipelineHelper pipe(*this);
pipe.shader_stages_ = {vs.GetStageCreateInfo(), pipe.fs_->GetStageCreateInfo()};
pipe.shader_stages_[0].flags = VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT_EXT;
pipe.InitState();
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkPipelineShaderStageCreateInfo-flags-08988");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeSubgroup, SubgroupUniformControlFlow) {
TEST_DESCRIPTION("Test SubgroupUniformControlFlow spirv execution mode");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_SHADER_SUBGROUP_UNIFORM_CONTROL_FLOW_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
VkPhysicalDeviceShaderSubgroupUniformControlFlowFeaturesKHR ssucff = vku::InitStructHelper();
ssucff.shaderSubgroupUniformControlFlow = VK_FALSE;
RETURN_IF_SKIP(InitState(nullptr, &ssucff));
const char *source = R"(
OpCapability Shader
OpExtension "SPV_KHR_subgroup_uniform_control_flow"
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpExecutionMode %main SubgroupUniformControlFlowKHR
; Debug Information
OpSource GLSL 450
OpName %main "main" ; id %4
; Annotations
OpDecorate %gl_WorkGroupSize BuiltIn WorkgroupSize
; Types, variables and constants
%void = OpTypeVoid
%3 = OpTypeFunction %void
%uint = OpTypeInt 32 0
%v3uint = OpTypeVector %uint 3
%uint_1 = OpConstant %uint 1
%gl_WorkGroupSize = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1
; Function main
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CreateComputePipelineHelper pipe(*this);
pipe.cs_ = std::make_unique<VkShaderObj>(this, source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_0, SPV_SOURCE_ASM);
pipe.InitState();
pipe.pipeline_layout_ = vkt::PipelineLayout(*m_device, {});
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-RuntimeSpirv-SubgroupUniformControlFlowKHR-06379");
pipe.CreateComputePipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeSubgroup, ComputeLocalWorkgroupSize) {
TEST_DESCRIPTION("Test size of local workgroud with requiredSubgroupSize.");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
VkPhysicalDeviceSubgroupSizeControlFeaturesEXT sscf = vku::InitStructHelper();
auto features2 = GetPhysicalDeviceFeatures2(sscf);
if (sscf.subgroupSizeControl == VK_FALSE || sscf.computeFullSubgroups == VK_FALSE || sscf.subgroupSizeControl == VK_FALSE) {
GTEST_SKIP() << "Required features are not supported";
}
RETURN_IF_SKIP(InitState(nullptr, &features2))
VkPhysicalDeviceSubgroupSizeControlPropertiesEXT subgroup_properties = vku::InitStructHelper();
GetPhysicalDeviceProperties2(subgroup_properties);
if ((subgroup_properties.requiredSubgroupSizeStages & VK_SHADER_STAGE_COMPUTE_BIT) == 0) {
GTEST_SKIP() << "Required shader stage not present in requiredSubgroupSizeStages";
}
VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT subgroup_size_control = vku::InitStructHelper();
subgroup_size_control.requiredSubgroupSize = subgroup_properties.minSubgroupSize;
uint32_t size = static_cast<uint32_t>(
std::ceil(std::sqrt(subgroup_size_control.requiredSubgroupSize * subgroup_properties.maxComputeWorkgroupSubgroups)));
if (size <= 1024) {
std::stringstream csSource;
csSource << R"glsl(
#version 450
layout(local_size_x=
)glsl";
csSource << size;
csSource << R"glsl(, local_size_y=
)glsl";
csSource << size;
csSource << R"glsl(, local_size_z=2) in;
void main(){
if (gl_GlobalInvocationID.x >= 0) { return; }
}
)glsl";
CreateComputePipelineHelper pipe(*this);
pipe.cs_ = std::make_unique<VkShaderObj>(this, csSource.str().c_str(), VK_SHADER_STAGE_COMPUTE_BIT);
pipe.InitState();
pipe.LateBindPipelineInfo();
pipe.cp_ci_.stage.pNext = &subgroup_size_control;
if (size * size * 2 > m_device->phy().limits_.maxComputeWorkGroupInvocations) {
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-RuntimeSpirv-x-06432");
}
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkPipelineShaderStageCreateInfo-pNext-02756");
pipe.CreateComputePipeline(false);
m_errorMonitor->VerifyFound();
}
if (subgroup_properties.maxSubgroupSize > 1 && subgroup_properties.minSubgroupSize > 1) {
std::stringstream csSource;
csSource << R"glsl(
#version 450
layout(local_size_x=
)glsl";
csSource << subgroup_properties.maxSubgroupSize + 1;
csSource << R"glsl(, local_size_y=1, local_size_z=1) in;
void main(){
if (gl_GlobalInvocationID.x >= 0) { return; }
}
)glsl";
CreateComputePipelineHelper pipe(*this);
pipe.cs_ = std::make_unique<VkShaderObj>(this, csSource.str().c_str(), VK_SHADER_STAGE_COMPUTE_BIT);
pipe.InitState();
pipe.LateBindPipelineInfo();
pipe.cp_ci_.stage.pNext = &subgroup_size_control;
pipe.cp_ci_.stage.flags = VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkPipelineShaderStageCreateInfo-pNext-02757");
pipe.CreateComputePipeline(false);
m_errorMonitor->VerifyFound();
}
}
TEST_F(NegativeSubgroup, MeshLocalWorkgroupSize) {
TEST_DESCRIPTION("Test size of local workgroud with requiredSubgroupSize.");
SetTargetApiVersion(VK_API_VERSION_1_3);
AddRequiredExtensions(VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_MESH_SHADER_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_MAINTENANCE_4_EXTENSION_NAME);
RETURN_IF_SKIP(InitFramework())
VkPhysicalDeviceMaintenance4Features m4f = vku::InitStructHelper();
VkPhysicalDeviceMeshShaderFeaturesEXT msf = vku::InitStructHelper(&m4f);
VkPhysicalDeviceSubgroupSizeControlFeaturesEXT sscf = vku::InitStructHelper(&msf);
auto features2 = GetPhysicalDeviceFeatures2(sscf);
if (m4f.maintenance4 == VK_FALSE) {
GTEST_SKIP() << "maintenance4 not supported";
}
if (msf.taskShader == VK_FALSE) {
GTEST_SKIP() << "taskShader not supported";
}
if (msf.meshShader == VK_FALSE) {
GTEST_SKIP() << "meshShader not supported";
}
if (sscf.subgroupSizeControl == VK_FALSE || sscf.computeFullSubgroups == VK_FALSE || sscf.subgroupSizeControl == VK_FALSE) {
GTEST_SKIP() << "Required features are not supported";
}
RETURN_IF_SKIP(InitState(nullptr, &features2))
InitRenderTarget();
VkPhysicalDeviceMeshShaderPropertiesEXT mesh_properties = vku::InitStructHelper();
VkPhysicalDeviceSubgroupSizeControlPropertiesEXT subgroup_properties = vku::InitStructHelper(&mesh_properties);
GetPhysicalDeviceProperties2(subgroup_properties);
if ((subgroup_properties.requiredSubgroupSizeStages & VK_SHADER_STAGE_TASK_BIT_EXT) == 0) {
GTEST_SKIP() << "Required shader stage not present in requiredSubgroupSizeStages";
}
VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT subgroup_size_control = vku::InitStructHelper();
subgroup_size_control.requiredSubgroupSize = subgroup_properties.minSubgroupSize;
if (subgroup_size_control.requiredSubgroupSize * subgroup_properties.maxComputeWorkgroupSubgroups >
mesh_properties.maxTaskWorkGroupInvocations) {
GTEST_SKIP() << "maxTaskWorkGroupSize smaller than required";
}
uint32_t x = mesh_properties.maxTaskWorkGroupSize[0];
uint32_t y = mesh_properties.maxTaskWorkGroupInvocations / x;
uint32_t z = mesh_properties.maxTaskWorkGroupInvocations / x / y;
std::stringstream taskSrc;
taskSrc << R"(
OpCapability MeshShadingEXT
OpExtension "SPV_EXT_mesh_shader"
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint TaskEXT %main "main"
OpExecutionMode %main LocalSize )";
taskSrc << x << " " << y << " " << z;
taskSrc << R"(
; Debug Information
OpSource GLSL 450
OpSourceExtension "GL_EXT_mesh_shader"
OpName %main "main" ; id %4
; Annotations
OpDecorate %gl_WorkGroupSize BuiltIn WorkgroupSize
; Types, variables and constants
%void = OpTypeVoid
%3 = OpTypeFunction %void
%uint = OpTypeInt 32 0
%uint_1 = OpConstant %uint 1
%uint_2 = OpConstant %uint )";
taskSrc << x;
taskSrc << R"(
%uint_3 = OpConstant %uint )";
taskSrc << y;
taskSrc << R"(
%uint_4 = OpConstant %uint )";
taskSrc << z;
taskSrc << R"(
%v3uint = OpTypeVector %uint 3
%gl_WorkGroupSize = OpConstantComposite %v3uint %uint_2 %uint_3 %uint_4
; Function main
%main = OpFunction %void None %3
%5 = OpLabel
OpEmitMeshTasksEXT %uint_1 %uint_1 %uint_1
OpFunctionEnd)";
VkShaderObj task_shader(this, taskSrc.str().c_str(), VK_SHADER_STAGE_TASK_BIT_EXT, SPV_ENV_VULKAN_1_3, SPV_SOURCE_ASM);
VkShaderObj mesh_shader(this, kMeshMinimalGlsl, VK_SHADER_STAGE_MESH_BIT_EXT, SPV_ENV_VULKAN_1_3, SPV_SOURCE_GLSL);
CreatePipelineHelper pipe(*this);
pipe.InitState();
pipe.LateBindPipelineInfo();
pipe.shader_stages_ = {task_shader.GetStageCreateInfo(), mesh_shader.GetStageCreateInfo()};
pipe.shader_stages_[0].pNext = &subgroup_size_control;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkPipelineShaderStageCreateInfo-pNext-02756");
pipe.CreateGraphicsPipeline(false);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeSubgroup, SubgroupSizeControlFeature) {
TEST_DESCRIPTION("Test using subgroupSizeControl feature when it's not enabled");
SetTargetApiVersion(VK_API_VERSION_1_3);
RETURN_IF_SKIP(Init())
VkPhysicalDeviceSubgroupSizeControlPropertiesEXT subgroup_properties = vku::InitStructHelper();
GetPhysicalDeviceProperties2(subgroup_properties);
VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT subgroup_size_control = vku::InitStructHelper();
subgroup_size_control.requiredSubgroupSize = subgroup_properties.minSubgroupSize;
CreateComputePipelineHelper pipe(*this);
pipe.InitState();
pipe.LateBindPipelineInfo();
pipe.cp_ci_.stage.pNext = &subgroup_size_control;
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkPipelineShaderStageCreateInfo-pNext-02755");
if ((subgroup_properties.requiredSubgroupSizeStages & VK_SHADER_STAGE_COMPUTE_BIT) == 0) {
m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-VkPipelineShaderStageCreateInfo-pNext-02755");
}
pipe.CreateComputePipeline(false);
m_errorMonitor->VerifyFound();
}