| /* |
| * Copyright (c) 2023-2025 Valve Corporation |
| * Copyright (c) 2023-2025 LunarG, Inc. |
| * |
| * 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" |
| |
| class NegativeShaderMesh : public VkLayerTest {}; |
| |
| TEST_F(NegativeShaderMesh, SharedMemoryOverLimit) { |
| TEST_DESCRIPTION("Validate mesh shader shared memory does not exceed maxMeshSharedMemorySize"); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_EXT_MESH_SHADER_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::meshShader); |
| |
| RETURN_IF_SKIP(Init()); |
| InitRenderTarget(); |
| |
| VkPhysicalDeviceMeshShaderPropertiesEXT mesh_shader_properties = vku::InitStructHelper(); |
| GetPhysicalDeviceProperties2(mesh_shader_properties); |
| |
| const uint32_t max_shared_memory_size = mesh_shader_properties.maxMeshSharedMemorySize; |
| const uint32_t max_shared_ints = max_shared_memory_size / 4; |
| |
| std::ostringstream mesh_source; |
| mesh_source << R"glsl( |
| #version 460 |
| #extension GL_EXT_mesh_shader : require |
| layout(max_vertices = 3, max_primitives=1) out; |
| layout(triangles) out; |
| shared int a[)glsl"; |
| mesh_source << (max_shared_ints + 16); |
| mesh_source << R"glsl(]; |
| void main(){} |
| )glsl"; |
| |
| VkShaderObj mesh(*m_device, mesh_source.str().c_str(), VK_SHADER_STAGE_MESH_BIT_EXT, SPV_ENV_VULKAN_1_2); |
| |
| const auto set_info = [&](CreatePipelineHelper &helper) { |
| helper.shader_stages_ = {helper.fs_->GetStageCreateInfo(), mesh.GetStageCreateInfo()}; |
| }; |
| CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-RuntimeSpirv-maxMeshSharedMemorySize-08754"); |
| } |
| |
| TEST_F(NegativeShaderMesh, SharedMemoryOverLimitWorkgroupMemoryExplicitLayout) { |
| TEST_DESCRIPTION( |
| "Validate mesh shader shared memory does not exceed maxMeshSharedMemorySize when using " |
| "VK_KHR_workgroup_memory_explicit_layout"); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_EXT_MESH_SHADER_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::meshShader); |
| AddRequiredFeature(vkt::Feature::workgroupMemoryExplicitLayout); |
| |
| RETURN_IF_SKIP(Init()); |
| InitRenderTarget(); |
| |
| VkPhysicalDeviceMeshShaderPropertiesEXT mesh_shader_properties = vku::InitStructHelper(); |
| GetPhysicalDeviceProperties2(mesh_shader_properties); |
| |
| const uint32_t max_shared_memory_size = mesh_shader_properties.maxMeshSharedMemorySize; |
| const uint32_t max_shared_ints = max_shared_memory_size / 4; |
| |
| std::ostringstream mesh_source; |
| mesh_source << R"glsl( |
| #version 460 |
| #extension GL_EXT_mesh_shader : require |
| #extension GL_EXT_shared_memory_block : enable |
| layout(max_vertices = 3, max_primitives=1) out; |
| layout(triangles) out; |
| |
| shared X { |
| int x; |
| }; |
| |
| shared Y { |
| int y1[)glsl"; |
| mesh_source << (max_shared_ints + 16); |
| mesh_source << R"glsl(]; |
| int y2; |
| }; |
| |
| void main() { |
| x = 0; // prevent dead-code elimination |
| y2 = 0; |
| } |
| )glsl"; |
| |
| VkShaderObj mesh(*m_device, mesh_source.str().c_str(), VK_SHADER_STAGE_MESH_BIT_EXT, SPV_ENV_VULKAN_1_2); |
| |
| const auto set_info = [&](CreatePipelineHelper &helper) { |
| helper.shader_stages_ = {helper.fs_->GetStageCreateInfo(), mesh.GetStageCreateInfo()}; |
| }; |
| CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-RuntimeSpirv-maxMeshSharedMemorySize-08754"); |
| } |
| |
| TEST_F(NegativeShaderMesh, SharedMemorySpecConstantDefault) { |
| TEST_DESCRIPTION("Validate shared memory exceed maxMeshSharedMemorySize limit with spec constants default"); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_EXT_MESH_SHADER_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::meshShader); |
| |
| RETURN_IF_SKIP(Init()); |
| InitRenderTarget(); |
| |
| VkPhysicalDeviceMeshShaderPropertiesEXT mesh_shader_properties = vku::InitStructHelper(); |
| GetPhysicalDeviceProperties2(mesh_shader_properties); |
| |
| const uint32_t max_shared_memory_size = mesh_shader_properties.maxMeshSharedMemorySize; |
| const uint32_t max_shared_ints = max_shared_memory_size / 4; |
| |
| std::ostringstream mesh_source; |
| mesh_source << R"glsl( |
| #version 460 |
| #extension GL_EXT_mesh_shader : require |
| layout(max_vertices = 3, max_primitives=1) out; |
| layout(triangles) out; |
| layout(constant_id = 0) const uint Condition = 1; |
| layout(constant_id = 1) const uint SharedSize = )glsl"; |
| mesh_source << (max_shared_ints + 16); |
| mesh_source << R"glsl(; |
| |
| #define enableSharedMemoryOpt (Condition == 1) |
| shared uint arr[enableSharedMemoryOpt ? SharedSize : 1]; |
| void main(){} |
| )glsl"; |
| |
| VkShaderObj mesh(*m_device, mesh_source.str().c_str(), VK_SHADER_STAGE_MESH_BIT_EXT, SPV_ENV_VULKAN_1_2); |
| |
| const auto set_info = [&](CreatePipelineHelper &helper) { |
| helper.shader_stages_ = {helper.fs_->GetStageCreateInfo(), mesh.GetStageCreateInfo()}; |
| }; |
| CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-RuntimeSpirv-maxMeshSharedMemorySize-08754"); |
| } |
| |
| TEST_F(NegativeShaderMesh, SharedMemorySpecConstantSet) { |
| TEST_DESCRIPTION("Validate shared memory exceed maxMeshSharedMemorySize limit with spec constants set"); |
| |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_EXT_MESH_SHADER_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::meshShader); |
| |
| RETURN_IF_SKIP(Init()); |
| InitRenderTarget(); |
| |
| VkPhysicalDeviceMeshShaderPropertiesEXT mesh_shader_properties = vku::InitStructHelper(); |
| GetPhysicalDeviceProperties2(mesh_shader_properties); |
| |
| const uint32_t max_shared_memory_size = mesh_shader_properties.maxMeshSharedMemorySize; |
| const uint32_t max_shared_ints = max_shared_memory_size / 4; |
| |
| std::ostringstream mesh_source; |
| mesh_source << R"glsl( |
| #version 460 |
| #extension GL_EXT_mesh_shader : require |
| layout(max_vertices = 3, max_primitives=1) out; |
| layout(triangles) out; |
| layout(constant_id = 0) const uint Condition = 1; |
| layout(constant_id = 1) const uint SharedSize = )glsl"; |
| mesh_source << (max_shared_ints + 16); |
| mesh_source << R"glsl(; |
| |
| #define enableSharedMemoryOpt (Condition == 1) |
| shared uint arr[enableSharedMemoryOpt ? SharedSize : 1]; |
| void main(){} |
| )glsl"; |
| |
| uint32_t data = 1; // set Condition |
| |
| VkSpecializationMapEntry entry; |
| entry.constantID = 0; |
| entry.offset = 0; |
| entry.size = sizeof(uint32_t); |
| |
| VkSpecializationInfo specialization_info = {}; |
| specialization_info.mapEntryCount = 1; |
| specialization_info.pMapEntries = &entry; |
| specialization_info.dataSize = sizeof(uint32_t); |
| specialization_info.pData = &data; |
| |
| VkShaderObj mesh(*m_device, mesh_source.str().c_str(), VK_SHADER_STAGE_MESH_BIT_EXT, SPV_ENV_VULKAN_1_2, SPV_SOURCE_GLSL, |
| &specialization_info); |
| |
| const auto set_info = [&](CreatePipelineHelper &helper) { |
| helper.shader_stages_ = {helper.fs_->GetStageCreateInfo(), mesh.GetStageCreateInfo()}; |
| }; |
| CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-RuntimeSpirv-maxMeshSharedMemorySize-08754"); |
| } |
| |
| TEST_F(NegativeShaderMesh, TaskSharedMemoryOverLimit) { |
| TEST_DESCRIPTION("Validate Task shader shared memory does not exceed maxTaskSharedMemorySize"); |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_EXT_MESH_SHADER_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::meshShader); |
| AddRequiredFeature(vkt::Feature::taskShader); |
| RETURN_IF_SKIP(Init()); |
| InitRenderTarget(); |
| |
| VkPhysicalDeviceMeshShaderPropertiesEXT mesh_shader_properties = vku::InitStructHelper(); |
| GetPhysicalDeviceProperties2(mesh_shader_properties); |
| |
| const uint32_t max_shared_memory_size = mesh_shader_properties.maxTaskSharedMemorySize; |
| const uint32_t max_shared_ints = max_shared_memory_size / 4; |
| |
| std::ostringstream task_source; |
| task_source << R"glsl( |
| #version 460 |
| #extension GL_EXT_mesh_shader : require |
| shared int a[)glsl"; |
| task_source << (max_shared_ints + 16); |
| task_source << R"glsl(]; |
| void main(){} |
| )glsl"; |
| |
| VkShaderObj task(*m_device, task_source.str().c_str(), VK_SHADER_STAGE_TASK_BIT_EXT, SPV_ENV_VULKAN_1_2); |
| VkShaderObj mesh(*m_device, kMeshMinimalGlsl, VK_SHADER_STAGE_MESH_BIT_EXT, SPV_ENV_VULKAN_1_2); |
| |
| if (mesh_shader_properties.maxTaskSharedMemorySize == mesh_shader_properties.maxTaskPayloadAndSharedMemorySize) { |
| m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-maxTaskPayloadAndSharedMemorySize-08760"); |
| } |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.shader_stages_ = {task.GetStageCreateInfo(), mesh.GetStageCreateInfo()}; |
| m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-maxTaskSharedMemorySize-08759"); |
| pipe.CreateGraphicsPipeline(); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeShaderMesh, MeshAndTaskShaderDerivatives) { |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_EXT_MESH_SHADER_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_COMPUTE_SHADER_DERIVATIVES_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::computeDerivativeGroupQuads); |
| AddRequiredFeature(vkt::Feature::meshShader); |
| |
| RETURN_IF_SKIP(Init()); |
| InitRenderTarget(); |
| |
| VkPhysicalDeviceComputeShaderDerivativesPropertiesKHR derivatives_properties = vku::InitStructHelper(); |
| GetPhysicalDeviceProperties2(derivatives_properties); |
| if (derivatives_properties.meshAndTaskShaderDerivatives) { |
| GTEST_SKIP() << "meshAndTaskShaderDerivatives is supported"; |
| } |
| |
| const char *ms_source = R"( |
| OpCapability ComputeDerivativeGroupQuadsKHR |
| OpCapability MeshShadingEXT |
| OpExtension "SPV_EXT_mesh_shader" |
| OpExtension "SPV_KHR_compute_shader_derivatives" |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint MeshEXT %main "main" %gl_Position %3 |
| OpExecutionMode %main LocalSize 4 4 1 |
| OpExecutionMode %main DerivativeGroupQuadsKHR |
| OpExecutionMode %main OutputTrianglesEXT |
| OpExecutionMode %main OutputVertices 3 |
| OpExecutionMode %main OutputPrimitivesEXT 1 |
| OpSource HLSL 660 |
| OpName %main "main" |
| OpDecorate %gl_Position BuiltIn Position |
| OpDecorate %3 BuiltIn PrimitiveTriangleIndicesEXT |
| %uint = OpTypeInt 32 0 |
| %v3uint = OpTypeVector %uint 3 |
| %uint_3 = OpConstant %uint 3 |
| %float = OpTypeFloat 32 |
| %v4float = OpTypeVector %float 4 |
| %_arr_v4float_uint_3 = OpTypeArray %v4float %uint_3 |
| %_ptr_Output__arr_v4float_uint_3 = OpTypePointer Output %_arr_v4float_uint_3 |
| %uint_1 = OpConstant %uint 1 |
| %_arr_v3uint_uint_1 = OpTypeArray %v3uint %uint_1 |
| %_ptr_Output__arr_v3uint_uint_1 = OpTypePointer Output %_arr_v3uint_uint_1 |
| %void = OpTypeVoid |
| %15 = OpTypeFunction %void |
| %gl_Position = OpVariable %_ptr_Output__arr_v4float_uint_3 Output |
| %3 = OpVariable %_ptr_Output__arr_v3uint_uint_1 Output |
| %main = OpFunction %void None %15 |
| %16 = OpLabel |
| OpReturn |
| OpFunctionEnd |
| )"; |
| |
| m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-meshAndTaskShaderDerivatives-10153"); |
| VkShaderObj ms(*m_device, ms_source, VK_SHADER_STAGE_MESH_BIT_EXT, SPV_ENV_VULKAN_1_2, SPV_SOURCE_ASM); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeShaderMesh, MeshShaderPayloadMemoryOverLimit) { |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_EXT_MESH_SHADER_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::taskShader); |
| AddRequiredFeature(vkt::Feature::meshShader); |
| RETURN_IF_SKIP(Init()); |
| InitRenderTarget(); |
| |
| if (!IsPlatformMockICD()) { |
| GTEST_SKIP() << "Hard to get limit tests to work everywhere without being too complex"; |
| } |
| |
| VkPhysicalDeviceMeshShaderPropertiesEXT mesh_shader_properties = vku::InitStructHelper(); |
| GetPhysicalDeviceProperties2(mesh_shader_properties); |
| |
| const uint32_t max_mesh_payload_and_shared_memory_size = mesh_shader_properties.maxMeshPayloadAndSharedMemorySize; |
| const uint32_t max_mesh_payload_and_shared_ints = max_mesh_payload_and_shared_memory_size / 4; |
| |
| std::ostringstream task_source; |
| task_source << R"glsl( |
| #version 460 |
| #extension GL_EXT_mesh_shader : require |
| struct Task { |
| uint baseID[)glsl"; |
| task_source << (max_mesh_payload_and_shared_ints / 2 + 1); |
| task_source << R"glsl(]; |
| }; |
| taskPayloadSharedEXT Task IN; |
| void main(){ |
| IN.baseID[0] = 0; |
| EmitMeshTasksEXT(1u, 1u, 1u); |
| } |
| )glsl"; |
| |
| std::ostringstream mesh_source; |
| mesh_source << R"glsl( |
| #version 460 |
| #extension GL_EXT_mesh_shader : require |
| layout(max_vertices = 3, max_primitives=1) out; |
| layout(triangles) out; |
| struct Task { |
| uint baseID[)glsl"; |
| mesh_source << (max_mesh_payload_and_shared_ints / 2 + 1); |
| mesh_source << R"glsl(]; |
| }; |
| taskPayloadSharedEXT Task IN; |
| shared int a[)glsl"; |
| mesh_source << (max_mesh_payload_and_shared_ints / 2 + 1); |
| mesh_source << R"glsl(]; |
| void main(){} |
| )glsl"; |
| |
| VkShaderObj task(*m_device, task_source.str().c_str(), VK_SHADER_STAGE_TASK_BIT_EXT, SPV_ENV_VULKAN_1_2); |
| VkShaderObj mesh(*m_device, mesh_source.str().c_str(), VK_SHADER_STAGE_MESH_BIT_EXT, SPV_ENV_VULKAN_1_2); |
| const auto set_info = [&](CreatePipelineHelper &helper) { |
| helper.shader_stages_ = {task.GetStageCreateInfo(), mesh.GetStageCreateInfo()}; |
| }; |
| CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-RuntimeSpirv-maxMeshPayloadAndSharedMemorySize-08755"); |
| } |
| |
| TEST_F(NegativeShaderMesh, MeshShaderPayloadSpecConstantSet) { |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_EXT_MESH_SHADER_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::meshShader); |
| AddRequiredFeature(vkt::Feature::taskShader); |
| RETURN_IF_SKIP(Init()); |
| InitRenderTarget(); |
| |
| if (!IsPlatformMockICD()) { |
| GTEST_SKIP() << "Hard to get limit tests to work everywhere without being too complex"; |
| } |
| |
| VkPhysicalDeviceMeshShaderPropertiesEXT mesh_shader_properties = vku::InitStructHelper(); |
| GetPhysicalDeviceProperties2(mesh_shader_properties); |
| |
| const uint32_t max_mesh_payload_and_shared_memory_size = mesh_shader_properties.maxMeshPayloadAndSharedMemorySize; |
| const uint32_t max_mesh_payload_and_shared_ints = max_mesh_payload_and_shared_memory_size / 4; |
| |
| const char *task_source = R"glsl( |
| #version 460 |
| #extension GL_EXT_mesh_shader : require |
| layout(constant_id = 0) const int SIZE = 64; |
| struct Task { |
| uint baseID[SIZE]; |
| }; |
| taskPayloadSharedEXT Task IN; |
| void main() { |
| IN.baseID[0] = 0; |
| EmitMeshTasksEXT(1u, 1u, 1u); |
| } |
| )glsl"; |
| |
| const char *mesh_source = R"glsl( |
| #version 460 |
| #extension GL_EXT_mesh_shader : require |
| layout(max_vertices = 3, max_primitives=1) out; |
| layout(triangles) out; |
| layout(constant_id = 0) const int SIZE = 64; |
| struct Task { |
| uint baseID[SIZE]; |
| }; |
| taskPayloadSharedEXT Task IN; |
| shared int a[SIZE]; |
| void main(){} |
| )glsl"; |
| |
| uint32_t size = max_mesh_payload_and_shared_ints / 2 + 1; |
| |
| VkSpecializationMapEntry map_entry; |
| map_entry.constantID = 0u; |
| map_entry.offset = 0u; |
| map_entry.size = sizeof(uint32_t); |
| |
| VkSpecializationInfo spec_info; |
| spec_info.mapEntryCount = 1u; |
| spec_info.pMapEntries = &map_entry; |
| spec_info.dataSize = sizeof(uint32_t); |
| spec_info.pData = &size; |
| |
| VkShaderObj task(*m_device, task_source, VK_SHADER_STAGE_TASK_BIT_EXT, SPV_ENV_VULKAN_1_2); |
| VkShaderObj mesh(*m_device, mesh_source, VK_SHADER_STAGE_MESH_BIT_EXT, SPV_ENV_VULKAN_1_2, SPV_SOURCE_GLSL, &spec_info); |
| const auto set_info = [&](CreatePipelineHelper &helper) { |
| helper.shader_stages_ = {task.GetStageCreateInfo(), mesh.GetStageCreateInfo()}; |
| ; |
| }; |
| CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-RuntimeSpirv-maxMeshPayloadAndSharedMemorySize-08755"); |
| } |
| |
| TEST_F(NegativeShaderMesh, TaskPayloadMemoryOverLimit) { |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_EXT_MESH_SHADER_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::taskShader); |
| AddRequiredFeature(vkt::Feature::meshShader); |
| RETURN_IF_SKIP(Init()); |
| InitRenderTarget(); |
| |
| VkPhysicalDeviceMeshShaderPropertiesEXT mesh_shader_properties = vku::InitStructHelper(); |
| GetPhysicalDeviceProperties2(mesh_shader_properties); |
| |
| const uint32_t max_payload_memory_size = mesh_shader_properties.maxTaskPayloadSize; |
| const uint32_t max_payload_ints = max_payload_memory_size / 4; |
| |
| VkShaderObj mesh(*m_device, kMeshMinimalGlsl, VK_SHADER_STAGE_MESH_BIT_EXT, SPV_ENV_VULKAN_1_2); |
| |
| std::ostringstream task_source; |
| task_source << R"glsl( |
| #version 460 |
| #extension GL_EXT_mesh_shader : require |
| struct Task { |
| uint baseID[)glsl"; |
| task_source << (max_payload_ints + 16); |
| task_source << R"glsl(]; |
| }; |
| taskPayloadSharedEXT Task OUT; |
| void main(){} |
| )glsl"; |
| |
| VkShaderObj task(*m_device, task_source.str().c_str(), VK_SHADER_STAGE_TASK_BIT_EXT, SPV_ENV_VULKAN_1_2); |
| if (mesh_shader_properties.maxTaskPayloadSize == mesh_shader_properties.maxTaskPayloadAndSharedMemorySize) { |
| m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-maxTaskPayloadAndSharedMemorySize-08760"); |
| } |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.shader_stages_ = {task.GetStageCreateInfo(), mesh.GetStageCreateInfo()}; |
| m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-maxTaskPayloadSize-08758"); |
| pipe.CreateGraphicsPipeline(); |
| m_errorMonitor->VerifyFound(); |
| } |
| |
| TEST_F(NegativeShaderMesh, TaskShaderAndPayloadMemoryOverLimit) { |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredExtensions(VK_EXT_MESH_SHADER_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::taskShader); |
| AddRequiredFeature(vkt::Feature::meshShader); |
| RETURN_IF_SKIP(Init()); |
| InitRenderTarget(); |
| |
| VkPhysicalDeviceMeshShaderPropertiesEXT mesh_shader_properties = vku::InitStructHelper(); |
| GetPhysicalDeviceProperties2(mesh_shader_properties); |
| |
| const uint32_t max_shared_memory_size = mesh_shader_properties.maxTaskSharedMemorySize; |
| const uint32_t max_shared_ints = max_shared_memory_size / 4; |
| const uint32_t max_payload_memory_size = mesh_shader_properties.maxTaskPayloadSize; |
| const uint32_t max_payload_ints = max_payload_memory_size / 4; |
| const uint32_t max_payload_and_shared_memory_size = mesh_shader_properties.maxTaskPayloadAndSharedMemorySize; |
| const uint32_t max_payload_and_shared_ints = max_payload_and_shared_memory_size / 4; |
| |
| VkShaderObj mesh(*m_device, kMeshMinimalGlsl, VK_SHADER_STAGE_MESH_BIT_EXT, SPV_ENV_VULKAN_1_2); |
| |
| std::ostringstream task_source; |
| task_source << R"glsl( |
| #version 460 |
| #extension GL_EXT_mesh_shader : require |
| struct Task { |
| uint baseID[)glsl"; |
| task_source << (max_payload_and_shared_ints / 2 + 1); |
| task_source << R"glsl(]; |
| }; |
| taskPayloadSharedEXT Task OUT; |
| shared int a[)glsl"; |
| task_source << (max_payload_and_shared_ints / 2 + 1); |
| task_source << R"glsl(]; |
| void main(){} |
| )glsl"; |
| |
| VkShaderObj task(*m_device, task_source.str().c_str(), VK_SHADER_STAGE_TASK_BIT_EXT, SPV_ENV_VULKAN_1_2); |
| |
| if (max_payload_and_shared_ints / 2 + 1 > max_payload_ints) { |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-RuntimeSpirv-maxTaskPayloadSize-08758"); |
| } |
| if (max_payload_and_shared_ints / 2 + 1 > max_shared_ints) { |
| m_errorMonitor->SetDesiredFailureMsg(kErrorBit, "VUID-RuntimeSpirv-maxTaskSharedMemorySize-08759"); |
| } |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.shader_stages_ = {task.GetStageCreateInfo(), mesh.GetStageCreateInfo()}; |
| m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-maxTaskPayloadAndSharedMemorySize-08760"); |
| pipe.CreateGraphicsPipeline(); |
| m_errorMonitor->VerifyFound(); |
| } |