| /* |
| * Copyright (c) 2015-2025 The Khronos Group Inc. |
| * Copyright (c) 2015-2025 Valve Corporation |
| * Copyright (c) 2015-2025 LunarG, Inc. |
| * Copyright (c) 2015-2025 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 "../framework/layer_validation_tests.h" |
| #include "../framework/pipeline_helper.h" |
| #include "shader_templates.h" |
| |
| class NegativeMesh : public MeshTest {}; |
| |
| TEST_F(NegativeMesh, BasicUsage) { |
| TEST_DESCRIPTION("Test VK_EXT_mesh_shader."); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_3); |
| AddRequiredExtensions(VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME); |
| AddRequiredExtensions(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_MULTIVIEW_EXTENSION_NAME); |
| AddRequiredExtensions(VK_EXT_MESH_SHADER_EXTENSION_NAME); |
| AddRequiredExtensions(VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::vertexInputDynamicState); |
| AddRequiredFeature(vkt::Feature::extendedDynamicState2); |
| AddRequiredFeature(vkt::Feature::extendedDynamicState2PatchControlPoints); |
| AddRequiredFeature(vkt::Feature::maintenance4); |
| AddRequiredFeature(vkt::Feature::multiview); |
| AddRequiredFeature(vkt::Feature::transformFeedback); |
| AddRequiredFeature(vkt::Feature::taskShader); |
| AddRequiredFeature(vkt::Feature::meshShader); |
| AddRequiredFeature(vkt::Feature::dynamicRendering); |
| |
| RETURN_IF_SKIP(Init()); |
| InitRenderTarget(); |
| |
| const char vert_shader_text[] = R"glsl( |
| #version 460 |
| vec2 vertices[3]; |
| void main() { |
| vertices[0] = vec2(-1.0, -1.0); |
| vertices[1] = vec2( 1.0, -1.0); |
| vertices[2] = vec2( 0.0, 1.0); |
| gl_Position = vec4(vertices[gl_VertexIndex % 3], 0.0, 1.0); |
| gl_PointSize = 1.0f; |
| } |
| )glsl"; |
| |
| const char mesh_shader_text[] = R"glsl( |
| #version 460 |
| #extension GL_EXT_mesh_shader : require |
| layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; |
| layout(max_vertices = 3) out; |
| layout(max_primitives = 1) out; |
| layout(triangles) out; |
| void main() { |
| SetMeshOutputsEXT(3,1); |
| gl_MeshVerticesEXT[0].gl_Position = vec4(-1.0, -1.0, 0, 1); |
| gl_MeshVerticesEXT[1].gl_Position = vec4( 1.0, -1.0, 0, 1); |
| gl_MeshVerticesEXT[2].gl_Position = vec4( 0.0, 1.0, 0, 1); |
| gl_PrimitiveTriangleIndicesEXT[0] = uvec3(0,1,2); |
| } |
| )glsl"; |
| |
| const char mesh_shader_xfb_text[] = R"( |
| OpCapability MeshShadingEXT |
| OpCapability TransformFeedback |
| OpExtension "SPV_EXT_mesh_shader" |
| %1 = OpExtInstImport "GLSL.std.450" |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint MeshEXT %main "main" %tf |
| OpExecutionModeId %main LocalSizeId %uint_2 %uint_1 %uint_1 |
| OpExecutionMode %main Xfb |
| OpExecutionMode %main OutputVertices 3 |
| OpExecutionMode %main OutputPrimitivesEXT 1 |
| OpExecutionMode %main OutputTrianglesEXT |
| OpSource GLSL 450 |
| OpSourceExtension "GL_EXT_mesh_shader" |
| OpName %main "main" |
| OpName %tf "tf" |
| %void = OpTypeVoid |
| %3 = OpTypeFunction %void |
| %float = OpTypeFloat 32 |
| %_ptr_Output_float = OpTypePointer Output %float |
| %tf = OpVariable %_ptr_Output_float Output |
| %uint = OpTypeInt 32 0 |
| %uint_2 = OpConstant %uint 2 |
| %uint_1 = OpConstant %uint 1 |
| %v3uint = OpTypeVector %uint 3 |
| %10 = OpConstantComposite %v3uint %uint_2 %uint_1 %uint_1 |
| %main = OpFunction %void None %3 |
| %5 = OpLabel |
| OpReturn |
| OpFunctionEnd |
| )"; |
| |
| VkShaderObj vs(*m_device, vert_shader_text, VK_SHADER_STAGE_VERTEX_BIT); |
| VkShaderObj ms(*m_device, mesh_shader_text, VK_SHADER_STAGE_MESH_BIT_EXT, SPV_ENV_VULKAN_1_3); |
| VkShaderObj ms_xfb(*m_device, mesh_shader_xfb_text, VK_SHADER_STAGE_MESH_BIT_EXT, SPV_ENV_VULKAN_1_3, SPV_SOURCE_ASM); |
| VkShaderObj fs(*m_device, kFragmentMinimalGlsl, VK_SHADER_STAGE_FRAGMENT_BIT); |
| |
| // Test pipeline creation |
| { |
| // can't mix mesh with vertex |
| const auto break_vp = [&](CreatePipelineHelper &helper) { |
| helper.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo(), ms.GetStageCreateInfo()}; |
| }; |
| CreatePipelineHelper::OneshotTest(*this, break_vp, kErrorBit, |
| std::vector<std::string>({"VUID-VkGraphicsPipelineCreateInfo-pStages-02095"})); |
| |
| // vertex or mesh must be present |
| // 02096 overlaps with 06896 |
| const auto break_vp2 = [&](CreatePipelineHelper &helper) { helper.shader_stages_ = {fs.GetStageCreateInfo()}; }; |
| CreatePipelineHelper::OneshotTest(*this, break_vp2, kErrorBit, |
| std::vector<std::string>({"VUID-VkGraphicsPipelineCreateInfo-stage-02096", |
| "VUID-VkGraphicsPipelineCreateInfo-pStages-06896"})); |
| |
| // vertexinput and inputassembly must be valid when vertex stage is present |
| const auto break_vp3 = [&](CreatePipelineHelper &helper) { |
| helper.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()}; |
| helper.gp_ci_.pVertexInputState = nullptr; |
| helper.gp_ci_.pInputAssemblyState = nullptr; |
| }; |
| CreatePipelineHelper::OneshotTest(*this, break_vp3, kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-pStages-02097"); |
| |
| // xfb with mesh shader |
| const auto break_vp4 = [&](CreatePipelineHelper &helper) { |
| helper.shader_stages_ = {ms_xfb.GetStageCreateInfo(), fs.GetStageCreateInfo()}; |
| }; |
| CreatePipelineHelper::OneshotTest(*this, break_vp4, kErrorBit, |
| std::vector<std::string>({"VUID-VkGraphicsPipelineCreateInfo-None-02322"})); |
| |
| // invalid dynamic state with mesh shader |
| std::vector<VkDynamicState> dyn_states[] = { |
| {VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY}, {VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE}, |
| {VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE}, {VK_DYNAMIC_STATE_PATCH_CONTROL_POINTS_EXT}, |
| {VK_DYNAMIC_STATE_VERTEX_INPUT_EXT}, |
| }; |
| const char *err_vuids[] = { |
| "VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-07065", "VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-07065", |
| "VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-07066", "VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-07066", |
| "VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-07067"}; |
| VkPipelineDynamicStateCreateInfo dyn_state = vku::InitStructHelper(); |
| for (int i = 0; i < 5; i++) { |
| dyn_state.dynamicStateCount = dyn_states[i].size(); |
| dyn_state.pDynamicStates = dyn_states[i].data(); |
| if (*dyn_state.pDynamicStates == VK_DYNAMIC_STATE_PATCH_CONTROL_POINTS_EXT) continue; |
| const auto break_vp5 = [&](CreatePipelineHelper &helper) { |
| helper.shader_stages_ = {ms.GetStageCreateInfo(), fs.GetStageCreateInfo()}; |
| helper.gp_ci_.pDynamicState = &dyn_state; |
| }; |
| CreatePipelineHelper::OneshotTest(*this, break_vp5, kErrorBit, std::vector<std::string>({err_vuids[i]})); |
| } |
| |
| // viewMask without enabling multiviewMeshShader feature |
| VkPipelineRenderingCreateInfo pipeline_rendering_info = vku::InitStructHelper(); |
| pipeline_rendering_info.viewMask = 0x2; |
| VkFormat color_formats[] = {VK_FORMAT_UNDEFINED}; |
| pipeline_rendering_info.colorAttachmentCount = 1; |
| pipeline_rendering_info.pColorAttachmentFormats = color_formats; |
| |
| const auto break_vp5 = [&](CreatePipelineHelper &helper) { |
| helper.shader_stages_ = {ms.GetStageCreateInfo(), fs.GetStageCreateInfo()}; |
| helper.gp_ci_.pNext = &pipeline_rendering_info; |
| helper.gp_ci_.renderPass = VK_NULL_HANDLE; |
| }; |
| CreatePipelineHelper::OneshotTest(*this, break_vp5, kErrorBit, |
| std::vector<std::string>({"VUID-VkGraphicsPipelineCreateInfo-renderPass-07720"})); |
| } |
| } |
| |
| TEST_F(NegativeMesh, ExtensionDisabled) { |
| TEST_DESCRIPTION("Test VK_EXT_mesh_shader VUs with EXT_mesh_shader disabled."); |
| SetTargetApiVersion(VK_API_VERSION_1_3); |
| AddRequiredExtensions(VK_EXT_MESH_SHADER_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::maintenance4); |
| RETURN_IF_SKIP(Init()); |
| InitRenderTarget(); |
| |
| VkShaderObj task_shader(*m_device, kTaskMinimalGlsl, VK_SHADER_STAGE_TASK_BIT_EXT, SPV_ENV_VULKAN_1_3); |
| VkShaderObj mesh_shader(*m_device, kMeshMinimalGlsl, VK_SHADER_STAGE_MESH_BIT_EXT, SPV_ENV_VULKAN_1_3); |
| VkShaderObj fs(*m_device, kFragmentMinimalGlsl, VK_SHADER_STAGE_FRAGMENT_BIT); |
| |
| // mesh and task shaders not supported |
| const auto break_vp = [&](CreatePipelineHelper &helper) { |
| helper.shader_stages_ = {task_shader.GetStageCreateInfo(), mesh_shader.GetStageCreateInfo(), fs.GetStageCreateInfo()}; |
| }; |
| CreatePipelineHelper::OneshotTest(*this, break_vp, kErrorBit, |
| std::vector<std::string>({"VUID-VkPipelineShaderStageCreateInfo-stage-02091", |
| "VUID-VkPipelineShaderStageCreateInfo-stage-02092"})); |
| } |
| |
| TEST_F(NegativeMesh, RuntimeSpirv) { |
| TEST_DESCRIPTION("Test VK_EXT_mesh_shader spirv related VUIDs."); |
| AddRequiredFeature(vkt::Feature::maintenance4); |
| RETURN_IF_SKIP(InitBasicMeshAndTask()); |
| InitRenderTarget(); |
| |
| VkPhysicalDeviceMeshShaderPropertiesEXT mesh_shader_properties = vku::InitStructHelper(); |
| GetPhysicalDeviceProperties2(mesh_shader_properties); |
| |
| std::vector<std::string> error_vuids; |
| uint32_t max_task_workgroup_size_x = mesh_shader_properties.maxTaskWorkGroupSize[0]; |
| uint32_t max_task_workgroup_size_y = mesh_shader_properties.maxTaskWorkGroupSize[1]; |
| uint32_t max_task_workgroup_size_z = mesh_shader_properties.maxTaskWorkGroupSize[2]; |
| |
| uint32_t max_mesh_workgroup_size_x = mesh_shader_properties.maxMeshWorkGroupSize[0]; |
| uint32_t max_mesh_workgroup_size_y = mesh_shader_properties.maxMeshWorkGroupSize[1]; |
| uint32_t max_mesh_workgroup_size_z = mesh_shader_properties.maxMeshWorkGroupSize[2]; |
| |
| if (max_task_workgroup_size_x < vvl::kU32Max) { |
| error_vuids.emplace_back("VUID-RuntimeSpirv-TaskEXT-07291"); |
| max_task_workgroup_size_x += 1; |
| } |
| |
| if (max_task_workgroup_size_y < vvl::kU32Max) { |
| error_vuids.emplace_back("VUID-RuntimeSpirv-TaskEXT-07292"); |
| max_task_workgroup_size_y += 1; |
| } |
| |
| if (max_task_workgroup_size_z < vvl::kU32Max) { |
| error_vuids.emplace_back("VUID-RuntimeSpirv-TaskEXT-07293"); |
| max_task_workgroup_size_z += 1; |
| } |
| error_vuids.emplace_back("VUID-RuntimeSpirv-TaskEXT-07294"); |
| |
| if (max_mesh_workgroup_size_x < vvl::kU32Max) { |
| error_vuids.emplace_back("VUID-RuntimeSpirv-MeshEXT-07295"); |
| max_mesh_workgroup_size_x += 1; |
| } |
| |
| if (max_mesh_workgroup_size_y < vvl::kU32Max) { |
| error_vuids.emplace_back("VUID-RuntimeSpirv-MeshEXT-07296"); |
| max_mesh_workgroup_size_y += 1; |
| } |
| |
| if (max_mesh_workgroup_size_z < vvl::kU32Max) { |
| error_vuids.emplace_back("VUID-RuntimeSpirv-MeshEXT-07297"); |
| max_mesh_workgroup_size_z += 1; |
| } |
| error_vuids.emplace_back("VUID-RuntimeSpirv-MeshEXT-07298"); |
| |
| std::string task_src = R"( |
| OpCapability MeshShadingEXT |
| OpExtension "SPV_EXT_mesh_shader" |
| %1 = OpExtInstImport "GLSL.std.450" |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint TaskEXT %main "main" %OUT |
| OpExecutionMode %main LocalSize )"; |
| task_src += std::to_string(max_task_workgroup_size_x); |
| task_src += " "; |
| task_src += std::to_string(max_task_workgroup_size_y); |
| task_src += " "; |
| task_src += std::to_string(max_task_workgroup_size_z); |
| task_src += R"( |
| %void = OpTypeVoid |
| %3 = OpTypeFunction %void |
| %uint = OpTypeInt 32 0 |
| %uint_1 = OpConstant %uint 1 |
| %v3uint = OpTypeVector %uint 3 |
| %9 = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1 |
| %Task = OpTypeStruct %uint |
| %_ptr_TaskPayloadWorkgroupEXT_Task = OpTypePointer TaskPayloadWorkgroupEXT %Task |
| %OUT = OpVariable %_ptr_TaskPayloadWorkgroupEXT_Task TaskPayloadWorkgroupEXT |
| %main = OpFunction %void None %3 |
| %5 = OpLabel |
| OpReturn |
| OpFunctionEnd |
| )"; |
| |
| std::string mesh_src = R"( |
| OpCapability MeshShadingEXT |
| OpExtension "SPV_EXT_mesh_shader" |
| %1 = OpExtInstImport "GLSL.std.450" |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint MeshEXT %main "main" |
| OpExecutionMode %main LocalSize )"; |
| mesh_src += std::to_string(max_mesh_workgroup_size_x); |
| mesh_src += " "; |
| mesh_src += std::to_string(max_mesh_workgroup_size_y); |
| mesh_src += " "; |
| mesh_src += std::to_string(max_mesh_workgroup_size_z); |
| mesh_src += R"( |
| OpExecutionMode %main OutputVertices 1 |
| OpExecutionMode %main OutputPrimitivesEXT 1 |
| OpExecutionMode %main OutputTrianglesEXT |
| %void = OpTypeVoid |
| %3 = OpTypeFunction %void |
| %uint = OpTypeInt 32 0 |
| %uint_1 = OpConstant %uint 1 |
| %v3uint = OpTypeVector %uint 3 |
| %9 = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1 |
| %main = OpFunction %void None %3 |
| %5 = OpLabel |
| OpReturn |
| OpFunctionEnd |
| )"; |
| |
| // lazy way to not check limits |
| m_errorMonitor->SetAllowedFailureMsg("VUID-RuntimeSpirv-MeshEXT-07115"); |
| m_errorMonitor->SetAllowedFailureMsg("VUID-RuntimeSpirv-MeshEXT-07116"); |
| VkShaderObj task_shader(*m_device, task_src.c_str(), VK_SHADER_STAGE_TASK_BIT_EXT, SPV_ENV_VULKAN_1_3, SPV_SOURCE_ASM); |
| VkShaderObj mesh_shader(*m_device, mesh_src.c_str(), VK_SHADER_STAGE_MESH_BIT_EXT, SPV_ENV_VULKAN_1_3, SPV_SOURCE_ASM); |
| VkShaderObj fs(*m_device, kFragmentMinimalGlsl, VK_SHADER_STAGE_FRAGMENT_BIT); |
| |
| // mesh and task shaders which exceeds workgroup size limits |
| const auto break_vp = [&](CreatePipelineHelper &helper) { |
| helper.shader_stages_ = {task_shader.GetStageCreateInfo(), mesh_shader.GetStageCreateInfo(), fs.GetStageCreateInfo()}; |
| }; |
| CreatePipelineHelper::OneshotTest(*this, break_vp, kErrorBit, error_vuids); |
| } |
| |
| TEST_F(NegativeMesh, RuntimeSpirv2) { |
| TEST_DESCRIPTION("Test VK_EXT_mesh_shader spirv related VUIDs."); |
| AddRequiredFeature(vkt::Feature::maintenance4); |
| RETURN_IF_SKIP(InitBasicMeshAndTask()); |
| InitRenderTarget(); |
| |
| VkPhysicalDeviceMeshShaderPropertiesEXT mesh_shader_properties = vku::InitStructHelper(); |
| GetPhysicalDeviceProperties2(mesh_shader_properties); |
| |
| uint32_t max_mesh_output_vertices = mesh_shader_properties.maxMeshOutputVertices; |
| uint32_t max_mesh_output_primitives = mesh_shader_properties.maxMeshOutputPrimitives; |
| |
| bool skip = true; |
| if (max_mesh_output_vertices < vvl::kU32Max) { |
| m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-MeshEXT-07115"); |
| skip = false; |
| max_mesh_output_vertices += 1; |
| } |
| |
| if (max_mesh_output_primitives < vvl::kU32Max) { |
| m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-MeshEXT-07116"); |
| skip = false; |
| max_mesh_output_primitives += 1; |
| } |
| |
| if (skip) { |
| GTEST_SKIP() << "No properties are invalid to check"; |
| } |
| |
| std::string mesh_src = R"( |
| OpCapability MeshShadingEXT |
| OpExtension "SPV_EXT_mesh_shader" |
| %1 = OpExtInstImport "GLSL.std.450" |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint MeshEXT %main "main" |
| OpExecutionModeId %main LocalSizeId %uint_2 %uint_1 %uint_1 |
| OpExecutionMode %main OutputVertices )"; |
| mesh_src += std::to_string(max_mesh_output_vertices); |
| mesh_src += R"( |
| OpExecutionMode %main OutputPrimitivesEXT )"; |
| mesh_src += std::to_string(max_mesh_output_primitives); |
| mesh_src += R"( |
| OpExecutionMode %main OutputTrianglesEXT |
| OpSource GLSL 450 |
| OpSourceExtension "GL_EXT_mesh_shader" |
| OpName %main "main" |
| %void = OpTypeVoid |
| %3 = OpTypeFunction %void |
| %uint = OpTypeInt 32 0 |
| %uint_2 = OpConstant %uint 2 |
| %uint_1 = OpConstant %uint 1 |
| %v3uint = OpTypeVector %uint 3 |
| %10 = OpConstantComposite %v3uint %uint_2 %uint_1 %uint_1 |
| %main = OpFunction %void None %3 |
| %5 = OpLabel |
| OpReturn |
| OpFunctionEnd |
| )"; |
| |
| VkShaderObj mesh_shader(*m_device, mesh_src.c_str(), VK_SHADER_STAGE_MESH_BIT_EXT, SPV_ENV_VULKAN_1_3, SPV_SOURCE_ASM); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeMesh, RuntimeSpirvNV) { |
| TEST_DESCRIPTION("Test VK_NV_mesh_shader spirv related VUIDs"); |
| |
| AddRequiredExtensions(VK_NV_MESH_SHADER_EXTENSION_NAME); |
| RETURN_IF_SKIP(InitFramework()); |
| |
| VkPhysicalDeviceMeshShaderFeaturesNV mesh_shader_features = vku::InitStructHelper(); |
| auto features2 = GetPhysicalDeviceFeatures2(mesh_shader_features); |
| if (mesh_shader_features.meshShader != VK_TRUE) { |
| GTEST_SKIP() << "Mesh shader feature not supported"; |
| } |
| |
| RETURN_IF_SKIP(InitState(nullptr, &features2)); |
| InitRenderTarget(); |
| |
| VkPhysicalDeviceMeshShaderPropertiesNV mesh_shader_properties = vku::InitStructHelper(); |
| GetPhysicalDeviceProperties2(mesh_shader_properties); |
| |
| std::string mesh_src = R"( |
| OpCapability MeshShadingNV |
| OpExtension "SPV_NV_mesh_shader" |
| %1 = OpExtInstImport "GLSL.std.450" |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint MeshNV %main "main" |
| OpExecutionMode %main LocalSize 1 1 1 |
| OpExecutionMode %main OutputVertices )"; |
| mesh_src += std::to_string(mesh_shader_properties.maxMeshOutputVertices + 1); |
| mesh_src += R"( |
| OpExecutionMode %main OutputPrimitivesNV )"; |
| mesh_src += std::to_string(mesh_shader_properties.maxMeshOutputPrimitives + 1); |
| mesh_src += R"( |
| OpExecutionMode %main OutputTrianglesNV |
| OpSource GLSL 450 |
| OpSourceExtension "GL_NV_mesh_shader" |
| OpName %main "main" |
| OpDecorate %gl_WorkGroupSize BuiltIn WorkgroupSize |
| %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 |
| %main = OpFunction %void None %3 |
| %5 = OpLabel |
| OpReturn |
| OpFunctionEnd |
| )"; |
| |
| m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-MeshNV-07113"); |
| m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-MeshNV-07114"); |
| VkShaderObj::CreateFromASM(this, mesh_src.c_str(), VK_SHADER_STAGE_MESH_BIT_NV, SPV_ENV_VULKAN_1_0); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeMesh, BasicUsageNV) { |
| TEST_DESCRIPTION("Test VK_NV_mesh_shader."); |
| |
| AddRequiredExtensions(VK_NV_MESH_SHADER_EXTENSION_NAME); |
| RETURN_IF_SKIP(InitFramework()); |
| |
| // Create a device that enables mesh_shader |
| VkPhysicalDeviceMeshShaderFeaturesNV mesh_shader_features = vku::InitStructHelper(); |
| auto features2 = GetPhysicalDeviceFeatures2(mesh_shader_features); |
| features2.features.multiDrawIndirect = VK_FALSE; |
| |
| RETURN_IF_SKIP(InitState(nullptr, &features2)); |
| InitRenderTarget(); |
| |
| const char vertShaderText[] = R"glsl( |
| #version 450 |
| vec2 vertices[3]; |
| void main() { |
| vertices[0] = vec2(-1.0, -1.0); |
| vertices[1] = vec2( 1.0, -1.0); |
| vertices[2] = vec2( 0.0, 1.0); |
| gl_Position = vec4(vertices[gl_VertexIndex % 3], 0.0, 1.0); |
| gl_PointSize = 1.0f; |
| } |
| )glsl"; |
| |
| const char meshShaderText[] = R"glsl( |
| #version 450 |
| #extension GL_NV_mesh_shader : require |
| layout(local_size_x = 1) in; |
| layout(max_vertices = 3) out; |
| layout(max_primitives = 1) out; |
| layout(triangles) out; |
| void main() { |
| gl_MeshVerticesNV[0].gl_Position = vec4(-1.0, -1.0, 0, 1); |
| gl_MeshVerticesNV[1].gl_Position = vec4( 1.0, -1.0, 0, 1); |
| gl_MeshVerticesNV[2].gl_Position = vec4( 0.0, 1.0, 0, 1); |
| gl_PrimitiveIndicesNV[0] = 0; |
| gl_PrimitiveIndicesNV[1] = 1; |
| gl_PrimitiveIndicesNV[2] = 2; |
| gl_PrimitiveCountNV = 1; |
| } |
| )glsl"; |
| |
| VkShaderObj vs(*m_device, vertShaderText, VK_SHADER_STAGE_VERTEX_BIT); |
| VkShaderObj ms(*m_device, meshShaderText, VK_SHADER_STAGE_MESH_BIT_NV); |
| VkShaderObj fs(*m_device, kFragmentMinimalGlsl, VK_SHADER_STAGE_FRAGMENT_BIT); |
| |
| // Test pipeline creation |
| { |
| // can't mix mesh with vertex |
| const auto break_vp = [&](CreatePipelineHelper &helper) { |
| helper.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo(), ms.GetStageCreateInfo()}; |
| }; |
| CreatePipelineHelper::OneshotTest(*this, break_vp, kErrorBit, |
| std::vector<std::string>({"VUID-VkGraphicsPipelineCreateInfo-pStages-02095"})); |
| |
| // vertex or mesh must be present |
| // 02096 overlaps with 06896 |
| const auto break_vp2 = [&](CreatePipelineHelper &helper) { helper.shader_stages_ = {fs.GetStageCreateInfo()}; }; |
| CreatePipelineHelper::OneshotTest(*this, break_vp2, kErrorBit, |
| std::vector<std::string>({"VUID-VkGraphicsPipelineCreateInfo-stage-02096", |
| "VUID-VkGraphicsPipelineCreateInfo-pStages-06896"})); |
| |
| // vertexinput and inputassembly must be valid when vertex stage is present |
| const auto break_vp3 = [&](CreatePipelineHelper &helper) { |
| helper.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()}; |
| helper.gp_ci_.pVertexInputState = nullptr; |
| helper.gp_ci_.pInputAssemblyState = nullptr; |
| }; |
| CreatePipelineHelper::OneshotTest(*this, break_vp3, kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-pStages-02097"); |
| } |
| |
| VkBufferCreateInfo buffer_create_info = vku::InitStructHelper(); |
| buffer_create_info.size = sizeof(uint32_t); |
| buffer_create_info.usage = VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT; |
| vkt::Buffer buffer(*m_device, buffer_create_info, vkt::no_mem); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDrawMeshTasksIndirectNV-None-08606"); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDrawMeshTasksIndirectNV-buffer-02708"); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDrawMeshTasksIndirectNV-drawCount-02157"); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDrawMeshTasksIndirectNV-drawCount-02146"); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDrawMeshTasksIndirectNV-drawCount-02718"); |
| vk::CmdDrawMeshTasksIndirectNV(m_command_buffer, buffer, 0, 2, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeMesh, ExtensionDisabledNV) { |
| TEST_DESCRIPTION("Test VK_NV_mesh_shader VUs with NV_mesh_shader disabled."); |
| |
| AddRequiredExtensions(VK_NV_MESH_SHADER_EXTENSION_NAME); |
| RETURN_IF_SKIP(InitFramework()); |
| |
| VkPhysicalDeviceMeshShaderFeaturesNV mesh_shader_features = vku::InitStructHelper(); |
| GetPhysicalDeviceFeatures2(mesh_shader_features); |
| if (mesh_shader_features.meshShader != VK_TRUE) { |
| GTEST_SKIP() << "Mesh shader feature not supported"; |
| } |
| |
| mesh_shader_features.meshShader = VK_FALSE; |
| mesh_shader_features.taskShader = VK_FALSE; |
| RETURN_IF_SKIP(InitState(nullptr, &mesh_shader_features)); |
| InitRenderTarget(); |
| |
| vkt::Event event(*m_device); |
| |
| m_command_buffer.Begin(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdSetEvent-stageMask-04095"); |
| vk::CmdSetEvent(m_command_buffer, event, VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdSetEvent-stageMask-04096"); |
| vk::CmdSetEvent(m_command_buffer, event, VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdResetEvent-stageMask-04095"); |
| vk::CmdResetEvent(m_command_buffer, event, VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdResetEvent-stageMask-04096"); |
| vk::CmdResetEvent(m_command_buffer, event, VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdWaitEvents-srcStageMask-04095"); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdWaitEvents-dstStageMask-04095"); |
| vk::CmdWaitEvents(m_command_buffer, 1, &event.handle(), VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV, |
| VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV, 0, nullptr, 0, nullptr, 0, nullptr); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdWaitEvents-srcStageMask-04096"); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdWaitEvents-dstStageMask-04096"); |
| vk::CmdWaitEvents(m_command_buffer, 1, &event.handle(), VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV, |
| VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV, 0, nullptr, 0, nullptr, 0, nullptr); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdPipelineBarrier-srcStageMask-04095"); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdPipelineBarrier-dstStageMask-04095"); |
| vk::CmdPipelineBarrier(m_command_buffer, VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV, VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV, 0, 0, |
| nullptr, 0, nullptr, 0, nullptr); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdPipelineBarrier-srcStageMask-04096"); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdPipelineBarrier-dstStageMask-04096"); |
| vk::CmdPipelineBarrier(m_command_buffer, VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV, VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV, 0, 0, |
| nullptr, 0, nullptr, 0, nullptr); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.End(); |
| |
| vkt::Semaphore semaphore(*m_device); |
| |
| VkPipelineStageFlags stage_flags = VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV | VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV; |
| VkSubmitInfo submit_info = vku::InitStructHelper(); |
| |
| // Signal the semaphore so the next test can wait on it. |
| submit_info.signalSemaphoreCount = 1; |
| submit_info.pSignalSemaphores = &semaphore.handle(); |
| vk::QueueSubmit(m_default_queue->handle(), 1, &submit_info, VK_NULL_HANDLE); |
| |
| submit_info.signalSemaphoreCount = 0; |
| submit_info.pSignalSemaphores = nullptr; |
| submit_info.waitSemaphoreCount = 1; |
| submit_info.pWaitSemaphores = &semaphore.handle(); |
| submit_info.pWaitDstStageMask = &stage_flags; |
| |
| m_errorMonitor->SetDesiredError("VUID-VkSubmitInfo-pWaitDstStageMask-04095"); |
| m_errorMonitor->SetDesiredError("VUID-VkSubmitInfo-pWaitDstStageMask-04096"); |
| vk::QueueSubmit(m_default_queue->handle(), 1, &submit_info, VK_NULL_HANDLE); |
| m_errorMonitor->VerifyFound(); |
| |
| m_default_queue->Wait(); |
| |
| VkShaderObj vs(*m_device, kVertexMinimalGlsl, VK_SHADER_STAGE_VERTEX_BIT); |
| // #version 450 |
| // #extension GL_NV_mesh_shader : require |
| // layout(local_size_x = 1) in; |
| // taskNV out Task { |
| // uint baseID; |
| // } OUT; |
| // void main() { |
| // OUT.baseID = 1; |
| // } |
| const char *task_src = R"( |
| OpCapability MeshShadingNV |
| OpExtension "SPV_NV_mesh_shader" |
| %1 = OpExtInstImport "GLSL.std.450" |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint TaskNV %main "main" %OUT |
| OpExecutionMode %main LocalSize 1 1 1 |
| OpMemberDecorate %Task 0 PerTaskNV |
| OpMemberDecorate %Task 0 Offset 0 |
| OpDecorate %Task Block |
| OpDecorate %gl_WorkGroupSize BuiltIn WorkgroupSize |
| %void = OpTypeVoid |
| %3 = OpTypeFunction %void |
| %uint = OpTypeInt 32 0 |
| %Task = OpTypeStruct %uint |
| %_ptr_Output_Task = OpTypePointer Output %Task |
| %OUT = OpVariable %_ptr_Output_Task Output |
| %int = OpTypeInt 32 1 |
| %int_0 = OpConstant %int 0 |
| %uint_1 = OpConstant %uint 1 |
| %_ptr_Output_uint = OpTypePointer Output %uint |
| %v3uint = OpTypeVector %uint 3 |
| %uint_32 = OpConstant %uint 32 |
| %gl_WorkGroupSize = OpConstantComposite %v3uint %uint_32 %uint_1 %uint_1 |
| %main = OpFunction %void None %3 |
| %5 = OpLabel |
| %14 = OpAccessChain %_ptr_Output_uint %OUT %int_0 |
| OpStore %14 %uint_1 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| |
| const char mesh_src[] = R"glsl( |
| #version 450 |
| |
| #extension GL_NV_mesh_shader : require |
| |
| layout(local_size_x = 1) in; |
| layout(max_vertices = 3) out; |
| layout(max_primitives = 1) out; |
| layout(triangles) out; |
| |
| taskNV in Task { |
| uint baseID; |
| } IN; |
| |
| void main() { |
| } |
| )glsl"; |
| |
| VkShaderObj task_shader(*m_device, task_src, VK_SHADER_STAGE_TASK_BIT_NV, SPV_ENV_VULKAN_1_0, SPV_SOURCE_ASM); |
| VkShaderObj mesh_shader(*m_device, mesh_src, VK_SHADER_STAGE_MESH_BIT_NV); |
| VkShaderObj fs(*m_device, kFragmentMinimalGlsl, VK_SHADER_STAGE_FRAGMENT_BIT); |
| |
| // mesh and task shaders not supported |
| const auto break_vp = [&](CreatePipelineHelper &helper) { |
| helper.shader_stages_ = {task_shader.GetStageCreateInfo(), mesh_shader.GetStageCreateInfo(), fs.GetStageCreateInfo()}; |
| }; |
| CreatePipelineHelper::OneshotTest(*this, break_vp, kErrorBit, |
| std::vector<std::string>({"VUID-VkPipelineShaderStageCreateInfo-stage-02091", |
| "VUID-VkPipelineShaderStageCreateInfo-stage-02092"})); |
| } |
| |
| TEST_F(NegativeMesh, DrawCmds) { |
| AddRequiredFeature(vkt::Feature::maintenance4); |
| RETURN_IF_SKIP(InitBasicMeshAndTask()); |
| InitRenderTarget(); |
| |
| VkPhysicalDeviceMeshShaderPropertiesEXT mesh_shader_properties = vku::InitStructHelper(); |
| GetPhysicalDeviceProperties2(mesh_shader_properties); |
| |
| VkShaderObj mesh_shader(*m_device, kMeshMinimalGlsl, VK_SHADER_STAGE_MESH_BIT_EXT, SPV_ENV_VULKAN_1_3); |
| |
| vkt::Buffer buffer(*m_device, 2 * sizeof(VkDrawMeshTasksIndirectCommandEXT), VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT); |
| vkt::Buffer count_buffer(*m_device, 64, VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.shader_stages_[0] = mesh_shader.GetStageCreateInfo(); |
| pipe.CreateGraphicsPipeline(); |
| |
| CreatePipelineHelper pipe1(*this); |
| pipe1.CreateGraphicsPipeline(); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| |
| uint32_t max_group_count_x = mesh_shader_properties.maxTaskWorkGroupCount[0]; |
| uint32_t max_group_count_y = mesh_shader_properties.maxTaskWorkGroupCount[1]; |
| uint32_t max_group_count_z = mesh_shader_properties.maxTaskWorkGroupCount[2]; |
| |
| if (max_group_count_x < vvl::kU32Max) { |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDrawMeshTasksEXT-TaskEXT-07326"); |
| max_group_count_x = vvl::kU32Max; |
| } |
| |
| if (max_group_count_y < vvl::kU32Max) { |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDrawMeshTasksEXT-TaskEXT-07327"); |
| max_group_count_y = vvl::kU32Max; |
| } |
| |
| if (max_group_count_z < vvl::kU32Max) { |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDrawMeshTasksEXT-TaskEXT-07328"); |
| max_group_count_z = vvl::kU32Max; |
| } |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDrawMeshTasksEXT-TaskEXT-07329"); |
| vk::CmdDrawMeshTasksEXT(m_command_buffer, max_group_count_x, max_group_count_y, max_group_count_z); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDrawMeshTasksIndirectEXT-drawCount-02718"); |
| vk::CmdDrawMeshTasksIndirectEXT(m_command_buffer, buffer, 0, 2, sizeof(VkDrawMeshTasksIndirectCommandEXT)); |
| m_errorMonitor->VerifyFound(); |
| |
| if (m_device->Physical().limits_.maxDrawIndirectCount < vvl::kU32Max) { |
| m_errorMonitor->SetUnexpectedError("VUID-vkCmdDrawMeshTasksIndirectEXT-drawCount-02718"); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDrawMeshTasksIndirectEXT-drawCount-07090"); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDrawMeshTasksIndirectEXT-drawCount-02719"); |
| vk::CmdDrawMeshTasksIndirectEXT(m_command_buffer, buffer, 0, m_device->Physical().limits_.maxDrawIndirectCount + 1, |
| sizeof(VkDrawMeshTasksIndirectCommandEXT)); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDrawMeshTasksIndirectEXT-drawCount-07089"); |
| vk::CmdDrawMeshTasksIndirectEXT(m_command_buffer, buffer, sizeof(VkDrawMeshTasksIndirectCommandEXT) * 2, 1, |
| sizeof(VkDrawMeshTasksIndirectCommandEXT)); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-stage-06481"); |
| vk::CmdDraw(m_command_buffer, 3, 1, 0, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe1); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDrawMeshTasksEXT-stage-06480"); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDrawMeshTasksEXT-MeshEXT-07087"); |
| vk::CmdDrawMeshTasksEXT(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDrawMeshTasksIndirectEXT-MeshEXT-07091"); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDrawMeshTasksIndirectEXT-stage-06480"); |
| vk::CmdDrawMeshTasksIndirectEXT(m_command_buffer, buffer, 0, 1, sizeof(VkDrawMeshTasksIndirectCommandEXT)); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDrawMeshTasksIndirectCountEXT-MeshEXT-07100"); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDrawMeshTasksIndirectCountEXT-stage-06480"); |
| vk::CmdDrawMeshTasksIndirectCountEXT(m_command_buffer, buffer, 0, count_buffer, 0, 1, |
| sizeof(VkDrawMeshTasksIndirectCommandEXT)); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeMesh, TaskShaderLimits) { |
| AddRequiredFeature(vkt::Feature::maintenance4); |
| RETURN_IF_SKIP(InitBasicMeshAndTask()); |
| InitRenderTarget(); |
| |
| VkPhysicalDeviceMeshShaderPropertiesEXT mesh_shader_properties = vku::InitStructHelper(); |
| GetPhysicalDeviceProperties2(mesh_shader_properties); |
| |
| VkShaderObj ts(*m_device, kTaskMinimalGlsl, VK_SHADER_STAGE_TASK_BIT_EXT, SPV_ENV_VULKAN_1_3); |
| VkShaderObj ms(*m_device, kMeshMinimalGlsl, VK_SHADER_STAGE_MESH_BIT_EXT, SPV_ENV_VULKAN_1_3); |
| VkShaderObj fs(*m_device, kMinimalShaderGlsl, VK_SHADER_STAGE_FRAGMENT_BIT, SPV_ENV_VULKAN_1_3); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.shader_stages_ = {ts.GetStageCreateInfo(), ms.GetStageCreateInfo(), fs.GetStageCreateInfo()}; |
| pipe.CreateGraphicsPipeline(); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| |
| uint32_t max_group_count_x = mesh_shader_properties.maxTaskWorkGroupCount[0]; |
| uint32_t max_group_count_y = mesh_shader_properties.maxTaskWorkGroupCount[1]; |
| uint32_t max_group_count_z = mesh_shader_properties.maxTaskWorkGroupCount[2]; |
| |
| if (max_group_count_x < vvl::kU32Max) { |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDrawMeshTasksEXT-TaskEXT-07322"); |
| max_group_count_x = vvl::kU32Max; |
| } |
| |
| if (max_group_count_y < vvl::kU32Max) { |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDrawMeshTasksEXT-TaskEXT-07323"); |
| max_group_count_y = vvl::kU32Max; |
| } |
| |
| if (max_group_count_z < vvl::kU32Max) { |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDrawMeshTasksEXT-TaskEXT-07324"); |
| max_group_count_z = vvl::kU32Max; |
| } |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDrawMeshTasksEXT-TaskEXT-07325"); |
| vk::CmdDrawMeshTasksEXT(m_command_buffer, max_group_count_x, max_group_count_y, max_group_count_z); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeMesh, MultiDrawIndirect) { |
| TEST_DESCRIPTION("Test VK_EXT_mesh_shader indirect draw command."); |
| AddRequiredFeature(vkt::Feature::maintenance4); |
| AddRequiredFeature(vkt::Feature::multiDrawIndirect); |
| RETURN_IF_SKIP(InitBasicMeshAndTask()); |
| InitRenderTarget(); |
| |
| VkPhysicalDeviceMeshShaderPropertiesEXT mesh_shader_properties = vku::InitStructHelper(); |
| GetPhysicalDeviceProperties2(mesh_shader_properties); |
| |
| VkShaderObj mesh_shader(*m_device, kMeshMinimalGlsl, VK_SHADER_STAGE_MESH_BIT_EXT, SPV_ENV_VULKAN_1_3); |
| |
| VkBufferCreateInfo buffer_create_info = vku::InitStructHelper(); |
| buffer_create_info.usage = VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT; |
| buffer_create_info.size = 2 * sizeof(VkDrawMeshTasksIndirectCommandEXT); |
| vkt::Buffer buffer(*m_device, buffer_create_info); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.shader_stages_[0] = mesh_shader.GetStageCreateInfo(); |
| pipe.CreateGraphicsPipeline(); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDrawMeshTasksIndirectEXT-drawCount-07088"); |
| vk::CmdDrawMeshTasksIndirectEXT(m_command_buffer, buffer, 0, 2, sizeof(VkDrawMeshTasksIndirectCommandEXT) - 2); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDrawMeshTasksIndirectEXT-drawCount-07090"); |
| vk::CmdDrawMeshTasksIndirectEXT(m_command_buffer, buffer, 0, 4, sizeof(VkDrawMeshTasksIndirectCommandEXT)); |
| m_errorMonitor->VerifyFound(); |
| |
| vkt::Buffer draw_buffer(*m_device, buffer_create_info, vkt::no_mem); |
| draw_buffer.AllocateAndBindMemory(*m_device); |
| |
| VkBufferCreateInfo count_buffer_create_info = vku::InitStructHelper(); |
| count_buffer_create_info.size = 64; |
| count_buffer_create_info.usage = VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT; |
| |
| vkt::Buffer count_buffer(*m_device, count_buffer_create_info); |
| vkt::Buffer count_buffer_unbound(*m_device, count_buffer_create_info, vkt::no_mem); |
| |
| count_buffer_create_info.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; |
| vkt::Buffer count_buffer_wrong_usage(*m_device, count_buffer_create_info); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDrawMeshTasksIndirectCountEXT-countBuffer-02714"); |
| vk::CmdDrawMeshTasksIndirectCountEXT(m_command_buffer, draw_buffer, 0, count_buffer_unbound, 0, 1, |
| sizeof(VkDrawMeshTasksIndirectCommandEXT)); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDrawMeshTasksIndirectCountEXT-countBuffer-02715"); |
| vk::CmdDrawMeshTasksIndirectCountEXT(m_command_buffer, draw_buffer, 0, count_buffer_wrong_usage, 0, 1, |
| sizeof(VkDrawMeshTasksIndirectCommandEXT)); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDrawMeshTasksIndirectCountEXT-stride-07096"); |
| vk::CmdDrawMeshTasksIndirectCountEXT(m_command_buffer, draw_buffer, 0, count_buffer, 0, 1, |
| sizeof(VkDrawMeshTasksIndirectCommandEXT) - 3); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDrawMeshTasksIndirectCountEXT-maxDrawCount-07097"); |
| vk::CmdDrawMeshTasksIndirectCountEXT(m_command_buffer, draw_buffer, 2 * sizeof(VkDrawMeshTasksIndirectCommandEXT), count_buffer, |
| 0, 4, sizeof(VkDrawMeshTasksIndirectCommandEXT)); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeMesh, DrawCmdsNV) { |
| TEST_DESCRIPTION("Test VK_NV_mesh_shader draw commands."); |
| |
| AddRequiredExtensions(VK_NV_MESH_SHADER_EXTENSION_NAME); |
| RETURN_IF_SKIP(InitFramework()); |
| |
| VkPhysicalDeviceMeshShaderFeaturesNV mesh_shader_features = vku::InitStructHelper(); |
| auto features2 = GetPhysicalDeviceFeatures2(mesh_shader_features); |
| if (mesh_shader_features.meshShader != VK_TRUE) { |
| GTEST_SKIP() << "Mesh shader feature not supported"; |
| } |
| features2.features.multiDrawIndirect = VK_FALSE; |
| |
| RETURN_IF_SKIP(InitState(nullptr, &features2)); |
| |
| InitRenderTarget(); |
| |
| const char mesh_src[] = R"glsl( |
| #version 450 |
| #extension GL_NV_mesh_shader : require |
| layout(local_size_x = 1) in; |
| layout(max_vertices = 3) out; |
| layout(max_primitives = 1) out; |
| layout(triangles) out; |
| void main() { |
| gl_MeshVerticesNV[0].gl_Position = vec4(-1.0, -1.0, 0, 1); |
| gl_MeshVerticesNV[1].gl_Position = vec4( 1.0, -1.0, 0, 1); |
| gl_MeshVerticesNV[2].gl_Position = vec4( 0.0, 1.0, 0, 1); |
| gl_PrimitiveIndicesNV[0] = 0; |
| gl_PrimitiveIndicesNV[1] = 1; |
| gl_PrimitiveIndicesNV[2] = 2; |
| gl_PrimitiveCountNV = 1; |
| } |
| )glsl"; |
| |
| VkShaderObj mesh_shader(*m_device, mesh_src, VK_SHADER_STAGE_MESH_BIT_NV); |
| |
| vkt::Buffer buffer(*m_device, 2 * sizeof(VkDrawMeshTasksIndirectCommandNV), VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT); |
| vkt::Buffer count_buffer(*m_device, 64, VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.shader_stages_[0] = mesh_shader.GetStageCreateInfo(); |
| pipe.CreateGraphicsPipeline(); |
| |
| CreatePipelineHelper pipe1(*this); |
| pipe1.CreateGraphicsPipeline(); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDrawMeshTasksIndirectNV-drawCount-02156"); |
| vk::CmdDrawMeshTasksIndirectNV(m_command_buffer, buffer, sizeof(VkDrawMeshTasksIndirectCommandNV) * 2, 1, |
| sizeof(VkDrawMeshTasksIndirectCommandNV)); |
| m_errorMonitor->VerifyFound(); |
| |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe1); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDrawMeshTasksNV-MeshNV-07080"); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDrawMeshTasksNV-stage-06480"); |
| vk::CmdDrawMeshTasksNV(m_command_buffer, 1, 0); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDrawMeshTasksIndirectNV-MeshNV-07081"); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDrawMeshTasksIndirectNV-stage-06480"); |
| vk::CmdDrawMeshTasksIndirectNV(m_command_buffer, buffer, 0, 1, sizeof(VkDrawMeshTasksIndirectCommandNV)); |
| m_errorMonitor->VerifyFound(); |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDrawMeshTasksIndirectCountNV-MeshNV-07082"); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDrawMeshTasksIndirectCountNV-stage-06480"); |
| vk::CmdDrawMeshTasksIndirectCountNV(m_command_buffer, buffer, 0, count_buffer, 0, 1, sizeof(VkDrawMeshTasksIndirectCommandNV)); |
| m_errorMonitor->VerifyFound(); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeMesh, MeshTasksWorkgroupCount) { |
| TEST_DESCRIPTION("Test mesh tasks emitted from task shader."); |
| AddRequiredExtensions(VK_KHR_SPIRV_1_4_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_MAINTENANCE_4_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::maintenance4); |
| RETURN_IF_SKIP(InitBasicMeshAndTask()); |
| InitRenderTarget(); |
| |
| VkPhysicalDeviceMeshShaderPropertiesEXT mesh_shader_properties = vku::InitStructHelper(); |
| GetPhysicalDeviceProperties2(mesh_shader_properties); |
| |
| std::string task_src_x = R"glsl( |
| #version 450 |
| #extension GL_EXT_mesh_shader : require |
| layout (local_size_x=1, local_size_y=1, local_size_z=1) in; |
| void main () { |
| EmitMeshTasksEXT()glsl"; |
| task_src_x += std::to_string(mesh_shader_properties.maxMeshWorkGroupCount[0] + 1); |
| task_src_x += R"glsl(u, 1u, 1u); |
| } |
| )glsl"; |
| |
| std::string task_src_y = R"glsl( |
| #version 450 |
| #extension GL_EXT_mesh_shader : require |
| layout (local_size_x=1, local_size_y=1, local_size_z=1) in; |
| void main () { |
| EmitMeshTasksEXT(1u, )glsl"; |
| task_src_y += std::to_string(mesh_shader_properties.maxMeshWorkGroupCount[1] + 1); |
| task_src_y += R"glsl(u, 1u); |
| } |
| )glsl"; |
| |
| std::string task_src_z = R"glsl( |
| #version 450 |
| #extension GL_EXT_mesh_shader : require |
| layout (local_size_x=1, local_size_y=1, local_size_z=1) in; |
| void main () { |
| EmitMeshTasksEXT(1u, 1u, )glsl"; |
| task_src_z += std::to_string(mesh_shader_properties.maxMeshWorkGroupCount[2] + 1); |
| task_src_z += R"glsl(u); |
| } |
| )glsl"; |
| |
| const char mesh_src[] = R"glsl( |
| #version 460 |
| #extension GL_EXT_mesh_shader : require |
| layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; |
| layout(max_vertices = 3) out; |
| layout(max_primitives = 1) out; |
| layout(triangles) out; |
| void main() { |
| SetMeshOutputsEXT(3, 1); |
| gl_MeshVerticesEXT[0].gl_Position = vec4(-1.0, -1.0, 0.0f, 1.0f); |
| gl_MeshVerticesEXT[1].gl_Position = vec4( 3.0, -1.0, 0.0f, 1.0f); |
| gl_MeshVerticesEXT[2].gl_Position = vec4(-1.0, 3.0, 0.0f, 1.0f); |
| gl_PrimitiveTriangleIndicesEXT[0] = uvec3(0, 1, 2); |
| } |
| )glsl"; |
| |
| const char frag_src[] = R"glsl( |
| #version 460 |
| layout(location = 0) out vec4 uFragColor; |
| void main(){ |
| uFragColor = vec4(0.2f, 0.4f, 0.6f, 0.8f); |
| } |
| )glsl"; |
| |
| VkShaderObj task_shader_x(*m_device, task_src_x.c_str(), VK_SHADER_STAGE_TASK_BIT_EXT, SPV_ENV_VULKAN_1_3); |
| VkShaderObj task_shader_y(*m_device, task_src_y.c_str(), VK_SHADER_STAGE_TASK_BIT_EXT, SPV_ENV_VULKAN_1_3); |
| VkShaderObj task_shader_z(*m_device, task_src_z.c_str(), VK_SHADER_STAGE_TASK_BIT_EXT, SPV_ENV_VULKAN_1_3); |
| VkShaderObj mesh_shader(*m_device, mesh_src, VK_SHADER_STAGE_MESH_BIT_EXT, SPV_ENV_VULKAN_1_3); |
| VkShaderObj frag_shader(*m_device, frag_src, VK_SHADER_STAGE_FRAGMENT_BIT, SPV_ENV_VULKAN_1_3); |
| |
| // mesh and task shaders not supported |
| const auto mesh_tasks_x = [&](CreatePipelineHelper &helper) { |
| helper.shader_stages_ = {task_shader_x.GetStageCreateInfo(), mesh_shader.GetStageCreateInfo(), |
| frag_shader.GetStageCreateInfo()}; |
| }; |
| const auto mesh_tasks_y = [&](CreatePipelineHelper &helper) { |
| helper.shader_stages_ = {task_shader_y.GetStageCreateInfo(), mesh_shader.GetStageCreateInfo(), |
| frag_shader.GetStageCreateInfo()}; |
| }; |
| const auto mesh_tasks_z = [&](CreatePipelineHelper &helper) { |
| helper.shader_stages_ = {task_shader_z.GetStageCreateInfo(), mesh_shader.GetStageCreateInfo(), |
| frag_shader.GetStageCreateInfo()}; |
| }; |
| std::vector<std::string> vuids = {"VUID-RuntimeSpirv-TaskEXT-07299"}; |
| if (mesh_shader_properties.maxMeshWorkGroupCount[0] == mesh_shader_properties.maxMeshWorkGroupTotalCount) { |
| vuids.emplace_back("VUID-RuntimeSpirv-TaskEXT-07302"); |
| } |
| if (mesh_shader_properties.maxMeshWorkGroupCount[0] != vvl::kU32Max) { |
| CreatePipelineHelper::OneshotTest(*this, mesh_tasks_x, kErrorBit, vuids); |
| } |
| if (mesh_shader_properties.maxMeshWorkGroupCount[1] != vvl::kU32Max) { |
| CreatePipelineHelper::OneshotTest(*this, mesh_tasks_y, kErrorBit, "VUID-RuntimeSpirv-TaskEXT-07300"); |
| } |
| if (mesh_shader_properties.maxMeshWorkGroupCount[2] != vvl::kU32Max) { |
| CreatePipelineHelper::OneshotTest(*this, mesh_tasks_z, kErrorBit, "VUID-RuntimeSpirv-TaskEXT-07301"); |
| } |
| } |
| |
| TEST_F(NegativeMesh, MeshShaderConservativeRasterization) { |
| TEST_DESCRIPTION("Use mesh shader with invalid conservative rasterization mode"); |
| AddRequiredExtensions(VK_KHR_SPIRV_1_4_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_MAINTENANCE_4_EXTENSION_NAME); |
| AddRequiredExtensions(VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::maintenance4); |
| RETURN_IF_SKIP(InitBasicMeshAndTask()); |
| InitRenderTarget(); |
| |
| const char meshShaderText[] = R"glsl( |
| #version 460 |
| #extension GL_EXT_mesh_shader : require |
| layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; |
| layout(max_vertices = 1) out; |
| layout(max_primitives = 1) out; |
| layout(points) out; |
| void main() { |
| } |
| )glsl"; |
| |
| VkShaderObj ms(*m_device, meshShaderText, VK_SHADER_STAGE_MESH_BIT_EXT, SPV_ENV_VULKAN_1_3); |
| |
| VkPhysicalDeviceConservativeRasterizationPropertiesEXT conservative_rasterization_props = vku::InitStructHelper(); |
| GetPhysicalDeviceProperties2(conservative_rasterization_props); |
| if (conservative_rasterization_props.conservativePointAndLineRasterization) { |
| GTEST_SKIP() << "Test requires conservativePointAndLineRasterization to be VK_FALSE"; |
| } |
| |
| VkPipelineRasterizationConservativeStateCreateInfoEXT conservative_state = vku::InitStructHelper(); |
| conservative_state.conservativeRasterizationMode = VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT; |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.rs_state_ci_.pNext = &conservative_state; |
| pipe.shader_stages_ = {ms.GetStageCreateInfo(), pipe.fs_->GetStageCreateInfo()}; |
| m_errorMonitor->SetDesiredError("VUID-VkGraphicsPipelineCreateInfo-conservativePointAndLineRasterization-08892"); |
| pipe.CreateGraphicsPipeline(); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeMesh, MeshIncompatibleActiveQueries) { |
| TEST_DESCRIPTION("Draw with mesh shaders when xfb or primitives generated queries are enabled"); |
| AddRequiredExtensions(VK_KHR_SPIRV_1_4_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_MAINTENANCE_4_EXTENSION_NAME); |
| AddRequiredExtensions(VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME); |
| AddRequiredExtensions(VK_EXT_PRIMITIVES_GENERATED_QUERY_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::maintenance4); |
| AddRequiredFeature(vkt::Feature::primitivesGeneratedQuery); |
| AddRequiredFeature(vkt::Feature::transformFeedback); |
| RETURN_IF_SKIP(InitBasicMeshAndTask()); |
| InitRenderTarget(); |
| |
| VkShaderObj ms(*m_device, kMeshMinimalGlsl, VK_SHADER_STAGE_MESH_BIT_EXT, SPV_ENV_VULKAN_1_3); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.shader_stages_ = {ms.GetStageCreateInfo(), pipe.fs_->GetStageCreateInfo()}; |
| pipe.CreateGraphicsPipeline(); |
| |
| vkt::QueryPool xfb_query_pool(*m_device, VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT, 1); |
| vkt::QueryPool pg_query_pool(*m_device, VK_QUERY_TYPE_PRIMITIVES_GENERATED_EXT, 1); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| |
| vk::CmdBeginQuery(m_command_buffer, xfb_query_pool, 0u, 0u); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDrawMeshTasksEXT-None-07074"); |
| vk::CmdDrawMeshTasksEXT(m_command_buffer, 1u, 1u, 1u); |
| m_errorMonitor->VerifyFound(); |
| vk::CmdEndQuery(m_command_buffer, xfb_query_pool, 0u); |
| |
| vk::CmdBeginQuery(m_command_buffer, pg_query_pool, 0u, 0u); |
| m_errorMonitor->SetDesiredError("VUID-vkCmdDrawMeshTasksEXT-None-07075"); |
| vk::CmdDrawMeshTasksEXT(m_command_buffer, 1u, 1u, 1u); |
| m_errorMonitor->VerifyFound(); |
| vk::CmdEndQuery(m_command_buffer, pg_query_pool, 0u); |
| |
| m_command_buffer.EndRenderPass(); |
| m_command_buffer.End(); |
| } |
| |
| TEST_F(NegativeMesh, DrawIndexMesh) { |
| TEST_DESCRIPTION("use DrawIndex in Mesh shader but there is a Task Shader."); |
| AddRequiredFeature(vkt::Feature::shaderDrawParameters); |
| RETURN_IF_SKIP(InitBasicMeshAndTask()); |
| InitRenderTarget(); |
| |
| const char *task_source = R"glsl( |
| #version 460 |
| #extension GL_EXT_mesh_shader : enable |
| taskPayloadSharedEXT uint mesh_payload[32]; |
| void main() { |
| mesh_payload[gl_LocalInvocationIndex] = gl_GlobalInvocationID.x; |
| EmitMeshTasksEXT(32u, 1u, 1u); |
| } |
| )glsl"; |
| |
| const char *mesh_source = R"glsl( |
| #version 460 |
| #extension GL_EXT_mesh_shader : enable |
| layout(max_vertices = 32, max_primitives = 32, triangles) out; |
| taskPayloadSharedEXT uint mesh_payload[32]; |
| void main() { |
| uint compacted_meshlet_index = uint(32768 * gl_DrawID) + gl_WorkGroupID.x; |
| SetMeshOutputsEXT(3,1); |
| } |
| )glsl"; |
| |
| VkShaderObj ts(*m_device, task_source, VK_SHADER_STAGE_TASK_BIT_EXT, SPV_ENV_VULKAN_1_2); |
| VkShaderObj ms(*m_device, mesh_source, VK_SHADER_STAGE_MESH_BIT_EXT, SPV_ENV_VULKAN_1_2); |
| VkShaderObj fs(*m_device, kFragmentMinimalGlsl, VK_SHADER_STAGE_FRAGMENT_BIT, SPV_ENV_VULKAN_1_2); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.shader_stages_ = {ts.GetStageCreateInfo(), ms.GetStageCreateInfo(), fs.GetStageCreateInfo()}; |
| m_errorMonitor->SetDesiredError("VUID-VkGraphicsPipelineCreateInfo-pStages-09631"); |
| pipe.CreateGraphicsPipeline(); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeMesh, DrawIndexMeshShaderObject) { |
| TEST_DESCRIPTION("use DrawIndex in Mesh shader but there is a Task Shader."); |
| AddRequiredExtensions(VK_EXT_SHADER_OBJECT_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::shaderObject); |
| AddRequiredFeature(vkt::Feature::shaderDrawParameters); |
| RETURN_IF_SKIP(InitBasicMeshAndTask()); |
| InitRenderTarget(); |
| |
| const char *mesh_src = R"glsl( |
| #version 460 |
| #extension GL_EXT_mesh_shader : enable |
| layout(max_vertices = 32, max_primitives = 32, triangles) out; |
| taskPayloadSharedEXT uint mesh_payload[32]; |
| void main() { |
| uint compacted_meshlet_index = uint(32768 * gl_DrawID) + gl_WorkGroupID.x; |
| SetMeshOutputsEXT(3,1); |
| } |
| )glsl"; |
| |
| m_errorMonitor->SetDesiredError("VUID-vkCreateShadersEXT-pCreateInfos-09632"); |
| const vkt::Shader meshShader(*m_device, VK_SHADER_STAGE_MESH_BIT_EXT, |
| GLSLToSPV(VK_SHADER_STAGE_MESH_BIT_EXT, mesh_src, SPV_ENV_VULKAN_1_2)); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeMesh, TaskPayloadSharedMissing) { |
| RETURN_IF_SKIP(InitBasicMeshAndTask()); |
| InitRenderTarget(); |
| |
| const char *task_source = R"glsl( |
| #version 460 |
| #extension GL_EXT_mesh_shader : enable |
| void main() { |
| EmitMeshTasksEXT(1u, 1u, 1u); |
| } |
| )glsl"; |
| |
| const char *mesh_source = R"glsl( |
| #version 460 |
| #extension GL_EXT_mesh_shader : enable |
| layout(max_vertices = 32, max_primitives = 32, triangles) out; |
| taskPayloadSharedEXT uint payload; |
| void main() { |
| uint x = payload; |
| SetMeshOutputsEXT(3,1); |
| } |
| )glsl"; |
| |
| VkShaderObj ts(*m_device, task_source, VK_SHADER_STAGE_TASK_BIT_EXT, SPV_ENV_VULKAN_1_2); |
| VkShaderObj ms(*m_device, mesh_source, VK_SHADER_STAGE_MESH_BIT_EXT, SPV_ENV_VULKAN_1_2); |
| VkShaderObj fs(*m_device, kFragmentMinimalGlsl, VK_SHADER_STAGE_FRAGMENT_BIT, SPV_ENV_VULKAN_1_2); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.shader_stages_ = {ts.GetStageCreateInfo(), ms.GetStageCreateInfo(), fs.GetStageCreateInfo()}; |
| m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-MeshEXT-10883"); |
| pipe.CreateGraphicsPipeline(); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeMesh, TaskPayloadSharedMissing2) { |
| RETURN_IF_SKIP(InitBasicMeshAndTask()); |
| InitRenderTarget(); |
| |
| const char *mesh_source = R"glsl( |
| #version 460 |
| #extension GL_EXT_mesh_shader : enable |
| layout(max_vertices = 32, max_primitives = 32, triangles) out; |
| taskPayloadSharedEXT uint payload; |
| void main() { |
| uint x = payload; |
| SetMeshOutputsEXT(3,1); |
| } |
| )glsl"; |
| |
| VkShaderObj ms(*m_device, mesh_source, VK_SHADER_STAGE_MESH_BIT_EXT, SPV_ENV_VULKAN_1_2); |
| VkShaderObj fs(*m_device, kFragmentMinimalGlsl, VK_SHADER_STAGE_FRAGMENT_BIT, SPV_ENV_VULKAN_1_2); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.shader_stages_ = {ms.GetStageCreateInfo(), fs.GetStageCreateInfo()}; |
| m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-MeshEXT-10883"); |
| pipe.CreateGraphicsPipeline(); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeMesh, TaskPayloadSharedDifferent) { |
| RETURN_IF_SKIP(InitBasicMeshAndTask()); |
| InitRenderTarget(); |
| |
| const char *task_source = R"glsl( |
| #version 460 |
| #extension GL_EXT_mesh_shader : enable |
| struct Foo { |
| uint a[3]; |
| uint b; |
| }; |
| taskPayloadSharedEXT Foo payload; |
| void main() { |
| payload.b = 4; |
| EmitMeshTasksEXT(1u, 1u, 1u); |
| } |
| )glsl"; |
| |
| const char *mesh_source = R"glsl( |
| #version 460 |
| #extension GL_EXT_mesh_shader : enable |
| layout(max_vertices = 32, max_primitives = 32, triangles) out; |
| taskPayloadSharedEXT uint payload; |
| void main() { |
| uint x = payload; |
| SetMeshOutputsEXT(3,1); |
| } |
| )glsl"; |
| |
| VkShaderObj ts(*m_device, task_source, VK_SHADER_STAGE_TASK_BIT_EXT, SPV_ENV_VULKAN_1_2); |
| VkShaderObj ms(*m_device, mesh_source, VK_SHADER_STAGE_MESH_BIT_EXT, SPV_ENV_VULKAN_1_2); |
| VkShaderObj fs(*m_device, kFragmentMinimalGlsl, VK_SHADER_STAGE_FRAGMENT_BIT, SPV_ENV_VULKAN_1_2); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.shader_stages_ = {ts.GetStageCreateInfo(), ms.GetStageCreateInfo(), fs.GetStageCreateInfo()}; |
| m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-MeshEXT-10883"); |
| pipe.CreateGraphicsPipeline(); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeMesh, TaskPayloadSharedMissingShaderObject) { |
| AddRequiredExtensions(VK_EXT_SHADER_OBJECT_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::dynamicRendering); |
| AddRequiredFeature(vkt::Feature::maintenance4); |
| AddRequiredFeature(vkt::Feature::shaderObject); |
| RETURN_IF_SKIP(InitBasicMeshAndTask()); |
| InitDynamicRenderTarget(); |
| |
| const char *task_source = R"glsl( |
| #version 460 |
| #extension GL_EXT_mesh_shader : enable |
| void main() { |
| EmitMeshTasksEXT(1u, 1u, 1u); |
| } |
| )glsl"; |
| |
| const char *mesh_source = R"glsl( |
| #version 460 |
| #extension GL_EXT_mesh_shader : enable |
| layout(max_vertices = 32, max_primitives = 32, triangles) out; |
| taskPayloadSharedEXT uint mesh_payload; |
| void main() { |
| uint x = mesh_payload; |
| SetMeshOutputsEXT(3,1); |
| } |
| )glsl"; |
| |
| const vkt::Shader task_shader(*m_device, VK_SHADER_STAGE_TASK_BIT_EXT, task_source); |
| const vkt::Shader mesh_shader(*m_device, VK_SHADER_STAGE_MESH_BIT_EXT, mesh_source); |
| const vkt::Shader frag_shader(*m_device, VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderingColor(GetDynamicRenderTarget(), GetRenderTargetArea()); |
| m_command_buffer.BindMeshShaders(task_shader, mesh_shader, frag_shader); |
| SetDefaultDynamicStatesExclude(); |
| m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-MeshEXT-10883"); |
| vk::CmdDrawMeshTasksEXT(m_command_buffer, 1, 1, 1); |
| m_errorMonitor->VerifyFound(); |
| m_command_buffer.EndRendering(); |
| m_command_buffer.End(); |
| } |