| /* Copyright (c) 2024-2026 The Khronos Group Inc. |
| * Copyright (c) 2024-2026 Valve Corporation |
| * Copyright (c) 2024-2026 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 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "layer_validation_tests.h" |
| #include "pipeline_helper.h" |
| #include "descriptor_helper.h" |
| |
| class PositiveGpuAVSpirv : public GpuAVTest {}; |
| |
| TEST_F(PositiveGpuAVSpirv, LoopPhi) { |
| TEST_DESCRIPTION("Loop that has the Phi parent pointed to itself"); |
| RETURN_IF_SKIP(InitGpuAvFramework()); |
| RETURN_IF_SKIP(InitState()); |
| InitRenderTarget(); |
| |
| vkt::Buffer buffer_uniform(*m_device, 1024, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, kHostVisibleMemProps); |
| vkt::Buffer buffer_storage(*m_device, 1024, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, kHostVisibleMemProps); |
| |
| uint32_t* data = (uint32_t*)buffer_uniform.Memory().Map(); |
| data[0] = 4; // Scene.lightCount |
| |
| OneOffDescriptorSet descriptor_set(m_device, { |
| {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| {1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| }); |
| const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_}); |
| |
| descriptor_set.WriteDescriptorBufferInfo(0, buffer_uniform, 0, VK_WHOLE_SIZE); |
| descriptor_set.WriteDescriptorBufferInfo(1, buffer_storage, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| descriptor_set.UpdateDescriptorSets(); |
| |
| // compiled with |
| // dxc -spirv -T ps_6_0 -E psmain -fspv-target-env=vulkan1.1 |
| // |
| // struct SceneData { |
| // uint lightCount; |
| // }; |
| // struct Light { |
| // float3 position; |
| // }; |
| // ConstantBuffer<SceneData> Scene : register(b0, space0); |
| // StructuredBuffer<Light> Lights : register(t1, space0); |
| // |
| // float4 main(float4 Position : SV_POSITION, float2 TexCoord : TEXCOORD) : SV_TARGET { |
| // float3 color = (float3)0; |
| // for (uint i = 0; i < Scene.lightCount; ++i) { |
| // color += normalize(Lights[i].position); |
| // } |
| // return float4(color, 1.0); |
| // } |
| // |
| // Produces this nasty loop pattern where it seems at first glance the Phi 2nd Parent is actually after it |
| // |
| // %1 = OpLabel |
| // OpBranch %2 |
| // |
| // %2 = OpLabel |
| // %phi = OpPhi %int %A %1 %B %3 |
| // OpLoopMerge %4 %3 None |
| // OpBranchConditional %bool %3 %4 |
| // |
| // %3 = OpLabel |
| // %B = OpIAdd %int %_ %_ |
| // OpBranch %2 |
| // |
| // %4 = OpLabel |
| const char* fs_source = R"( |
| OpCapability Shader |
| %1 = OpExtInstImport "GLSL.std.450" |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint Fragment %psmain "main" %out_var_SV_TARGET |
| OpExecutionMode %psmain OriginUpperLeft |
| OpDecorate %out_var_SV_TARGET Location 0 |
| OpDecorate %Scene DescriptorSet 0 |
| OpDecorate %Scene Binding 0 |
| OpDecorate %Lights DescriptorSet 0 |
| OpDecorate %Lights Binding 1 |
| OpMemberDecorate %type_ConstantBuffer_SceneData 0 Offset 0 |
| OpDecorate %type_ConstantBuffer_SceneData Block |
| OpMemberDecorate %Light 0 Offset 0 |
| OpDecorate %_runtimearr_Light ArrayStride 16 |
| OpMemberDecorate %type_StructuredBuffer_Light 0 Offset 0 |
| OpMemberDecorate %type_StructuredBuffer_Light 0 NonWritable |
| OpDecorate %type_StructuredBuffer_Light BufferBlock |
| %float = OpTypeFloat 32 |
| %float_0 = OpConstant %float 0 |
| %v3float = OpTypeVector %float 3 |
| %13 = OpConstantComposite %v3float %float_0 %float_0 %float_0 |
| %uint = OpTypeInt 32 0 |
| %uint_0 = OpConstant %uint 0 |
| %int = OpTypeInt 32 1 |
| %int_0 = OpConstant %int 0 |
| %uint_1 = OpConstant %uint 1 |
| %float_1 = OpConstant %float 1 |
| %type_ConstantBuffer_SceneData = OpTypeStruct %uint |
| %_ptr_Uniform_type_ConstantBuffer_SceneData = OpTypePointer Uniform %type_ConstantBuffer_SceneData |
| %Light = OpTypeStruct %v3float |
| %_runtimearr_Light = OpTypeRuntimeArray %Light |
| %type_StructuredBuffer_Light = OpTypeStruct %_runtimearr_Light |
| %_ptr_Uniform_type_StructuredBuffer_Light = OpTypePointer Uniform %type_StructuredBuffer_Light |
| %v4float = OpTypeVector %float 4 |
| %_ptr_Output_v4float = OpTypePointer Output %v4float |
| %void = OpTypeVoid |
| %25 = OpTypeFunction %void |
| %_ptr_Uniform_uint = OpTypePointer Uniform %uint |
| %bool = OpTypeBool |
| %_ptr_Uniform_v3float = OpTypePointer Uniform %v3float |
| %Scene = OpVariable %_ptr_Uniform_type_ConstantBuffer_SceneData Uniform |
| %Lights = OpVariable %_ptr_Uniform_type_StructuredBuffer_Light Uniform |
| %out_var_SV_TARGET = OpVariable %_ptr_Output_v4float Output |
| %psmain = OpFunction %void None %25 |
| %29 = OpLabel |
| OpBranch %30 |
| %30 = OpLabel |
| %31 = OpPhi %v3float %13 %29 %32 %33 |
| %34 = OpPhi %uint %uint_0 %29 %35 %33 |
| %36 = OpAccessChain %_ptr_Uniform_uint %Scene %int_0 |
| %37 = OpLoad %uint %36 |
| %38 = OpULessThan %bool %34 %37 |
| OpLoopMerge %39 %33 None |
| OpBranchConditional %38 %33 %39 |
| %33 = OpLabel |
| %40 = OpAccessChain %_ptr_Uniform_v3float %Lights %int_0 %34 %int_0 |
| %41 = OpLoad %v3float %40 |
| %42 = OpExtInst %v3float %1 Normalize %41 |
| %32 = OpFAdd %v3float %31 %42 |
| %35 = OpIAdd %uint %34 %uint_1 |
| OpBranch %30 |
| %39 = OpLabel |
| %43 = OpCompositeExtract %float %31 0 |
| %44 = OpCompositeExtract %float %31 1 |
| %45 = OpCompositeExtract %float %31 2 |
| %46 = OpCompositeConstruct %v4float %43 %44 %45 %float_1 |
| OpStore %out_var_SV_TARGET %46 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| VkShaderObj fs(*m_device, fs_source, VK_SHADER_STAGE_FRAGMENT_BIT, SPV_ENV_VULKAN_1_0, SPV_SOURCE_ASM); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()}; |
| pipe.gp_ci_.layout = pipeline_layout; |
| pipe.CreateGraphicsPipeline(); |
| |
| m_command_buffer.Begin(); |
| m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &descriptor_set.set_, 0, |
| nullptr); |
| vk::CmdDraw(m_command_buffer, 3, 1, 0, 0); |
| vk::CmdEndRenderPass(m_command_buffer); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| } |
| |
| TEST_F(PositiveGpuAVSpirv, LoopHeaderPhi) { |
| TEST_DESCRIPTION("Require injection in the Loop Header block that contains a Phi"); |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| RETURN_IF_SKIP(InitGpuAvFramework()); |
| RETURN_IF_SKIP(InitState()); |
| |
| // The folling HLSL: |
| // |
| // RWStructuredBuffer<int> data : register(u0); |
| // [numthreads(1, 1, 1)] |
| // void main() { |
| // int i = 0; |
| // for (i = 0; i < data[i]; i++) { |
| // data[0] += i; |
| // } |
| // } |
| const char* cs_source = R"( |
| OpCapability Shader |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint GLCompute %main "main" %data |
| OpExecutionMode %main LocalSize 1 1 1 |
| OpDecorate %data DescriptorSet 0 |
| OpDecorate %data Binding 0 |
| OpDecorate %runtimearr ArrayStride 4 |
| OpMemberDecorate %type_RWStructuredBuffer 0 Offset 0 |
| OpDecorate %type_RWStructuredBuffer Block |
| %int = OpTypeInt 32 1 |
| %int_0 = OpConstant %int 0 |
| %uint = OpTypeInt 32 0 |
| %uint_0 = OpConstant %uint 0 |
| %int_1 = OpConstant %int 1 |
| %runtimearr = OpTypeRuntimeArray %int |
| %type_RWStructuredBuffer = OpTypeStruct %runtimearr |
| %ptr_RWStructuredBuffer = OpTypePointer StorageBuffer %type_RWStructuredBuffer |
| %void = OpTypeVoid |
| %12 = OpTypeFunction %void |
| %ptr_StorageBuffer = OpTypePointer StorageBuffer %int |
| %bool = OpTypeBool |
| %data = OpVariable %ptr_RWStructuredBuffer StorageBuffer |
| %main = OpFunction %void None %12 |
| %15 = OpLabel |
| OpBranch %16 |
| %16 = OpLabel |
| %17 = OpPhi %int %int_0 %15 %18 %19 |
| %20 = OpBitcast %uint %17 |
| %21 = OpAccessChain %ptr_StorageBuffer %data %int_0 %20 |
| %22 = OpLoad %int %21 |
| %23 = OpSLessThan %bool %17 %22 |
| OpLoopMerge %24 %19 None |
| OpBranchConditional %23 %19 %24 |
| %19 = OpLabel |
| %25 = OpAccessChain %ptr_StorageBuffer %data %int_0 %uint_0 |
| %26 = OpLoad %int %25 |
| %27 = OpIAdd %int %26 %17 |
| OpStore %25 %27 |
| %18 = OpIAdd %int %17 %int_1 |
| OpBranch %16 |
| %24 = OpLabel |
| OpReturn |
| OpFunctionEnd |
| )"; |
| |
| CreateComputePipelineHelper pipe(*this); |
| pipe.dsl_bindings_[0] = {0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}; |
| pipe.cs_ = VkShaderObj(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_2, SPV_SOURCE_ASM); |
| pipe.CreateComputePipeline(); |
| |
| vkt::Buffer buffer(*m_device, 16, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, kHostVisibleMemProps); |
| uint32_t* data = (uint32_t*)buffer.Memory().Map(); |
| data[0] = 1; // data[0] |
| data[1] = 2; // data[1] |
| data[2] = 3; // data[2] |
| data[3] = 0; // data[3] |
| |
| pipe.descriptor_set_.WriteDescriptorBufferInfo(0, buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| pipe.descriptor_set_.UpdateDescriptorSets(); |
| |
| m_command_buffer.Begin(); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe.pipeline_layout_, 0, 1, |
| &pipe.descriptor_set_.set_, 0, nullptr); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| ASSERT_EQ(4u, data[0]); |
| } |
| |
| TEST_F(PositiveGpuAVSpirv, VulkanMemoryModelDeviceScope) { |
| TEST_DESCRIPTION("Test adding VulkanMemoryModelDeviceScope support"); |
| SetTargetApiVersion(VK_API_VERSION_1_2); |
| AddRequiredFeature(vkt::Feature::bufferDeviceAddress); |
| AddRequiredFeature(vkt::Feature::vulkanMemoryModel); |
| AddRequiredFeature(vkt::Feature::vulkanMemoryModelDeviceScope); |
| RETURN_IF_SKIP(InitGpuAvFramework()); |
| RETURN_IF_SKIP(InitState()); |
| InitRenderTarget(); |
| |
| vkt::Buffer buffer(*m_device, 256, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, kHostVisibleMemProps); |
| |
| uint32_t* data = (uint32_t*)buffer.Memory().Map(); |
| data[0] = 1; |
| |
| OneOffDescriptorSet descriptor_set(m_device, { |
| {0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| }); |
| const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_}); |
| descriptor_set.WriteDescriptorBufferInfo(0, buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| descriptor_set.UpdateDescriptorSets(); |
| |
| // Simple shader with added MemoryModel capability |
| // |
| // layout(set=0, binding=0) buffer InOut { |
| // uint x; |
| // uint bar[8]; |
| // } foo; |
| // void main() { |
| // foo.bar[0] = foo.bar[foo.x]; |
| // } |
| const char* cs_source = R"( |
| OpCapability Shader |
| OpCapability VulkanMemoryModel |
| OpCapability PhysicalStorageBufferAddresses |
| %1 = OpExtInstImport "GLSL.std.450" |
| OpMemoryModel PhysicalStorageBuffer64 Vulkan |
| OpEntryPoint GLCompute %main "main" %foo |
| OpExecutionMode %main LocalSize 1 1 1 |
| OpDecorate %_arr_uint_uint_8 ArrayStride 4 |
| OpMemberDecorate %InOut 0 Offset 0 |
| OpMemberDecorate %InOut 1 Offset 4 |
| OpDecorate %InOut Block |
| OpDecorate %foo DescriptorSet 0 |
| OpDecorate %foo Binding 0 |
| %void = OpTypeVoid |
| %3 = OpTypeFunction %void |
| %uint = OpTypeInt 32 0 |
| %uint_8 = OpConstant %uint 8 |
| %_arr_uint_uint_8 = OpTypeArray %uint %uint_8 |
| %InOut = OpTypeStruct %uint %_arr_uint_uint_8 |
| %_ptr_StorageBuffer_InOut = OpTypePointer StorageBuffer %InOut |
| %foo = OpVariable %_ptr_StorageBuffer_InOut StorageBuffer |
| %int = OpTypeInt 32 1 |
| %int_1 = OpConstant %int 1 |
| %int_0 = OpConstant %int 0 |
| %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint |
| %main = OpFunction %void None %3 |
| %5 = OpLabel |
| %16 = OpAccessChain %_ptr_StorageBuffer_uint %foo %int_0 |
| %17 = OpLoad %uint %16 |
| %18 = OpAccessChain %_ptr_StorageBuffer_uint %foo %int_1 %17 |
| %19 = OpLoad %uint %18 |
| %20 = OpAccessChain %_ptr_StorageBuffer_uint %foo %int_1 %int_0 |
| OpStore %20 %19 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| |
| CreateComputePipelineHelper pipe(*this); |
| pipe.cs_ = VkShaderObj(*m_device, cs_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_2, SPV_SOURCE_ASM); |
| pipe.cp_ci_.layout = pipeline_layout; |
| pipe.CreateComputePipeline(); |
| |
| m_command_buffer.Begin(); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 0, 1, &descriptor_set.set_, 0, |
| nullptr); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| } |
| |
| TEST_F(PositiveGpuAVSpirv, FindMultipleStores) { |
| TEST_DESCRIPTION("Catches bug when various OpStore are in top of a function"); |
| RETURN_IF_SKIP(InitGpuAvFramework()); |
| RETURN_IF_SKIP(InitState()); |
| |
| const char shader_source[] = R"glsl( |
| #version 450 |
| layout(set = 0, binding = 0) buffer StorageBuffer { uint data[]; } Data; // data[4] |
| |
| layout(local_size_x = 1) in; |
| int foo() { |
| return (gl_WorkGroupSize.x > 1) ? 1 : 0; |
| } |
| |
| void main() { |
| int index = foo(); // first OpStore is not instrumented |
| Data.data[index] = 0xdeadca71; |
| Data.data[index + 1] = 0xdeadca71; |
| } |
| )glsl"; |
| |
| CreateComputePipelineHelper pipe(*this); |
| pipe.dsl_bindings_[0] = {0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}; |
| pipe.cs_ = VkShaderObj(*m_device, shader_source, VK_SHADER_STAGE_COMPUTE_BIT); |
| pipe.CreateComputePipeline(); |
| |
| vkt::Buffer write_buffer(*m_device, 64, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, kHostVisibleMemProps); |
| pipe.descriptor_set_.WriteDescriptorBufferInfo(0, write_buffer, 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| pipe.descriptor_set_.UpdateDescriptorSets(); |
| |
| m_command_buffer.Begin(); |
| vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); |
| vk::CmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipe.pipeline_layout_, 0, 1, |
| &pipe.descriptor_set_.set_, 0, nullptr); |
| vk::CmdDispatch(m_command_buffer, 1, 1, 1); |
| m_command_buffer.End(); |
| |
| m_default_queue->SubmitAndWait(m_command_buffer); |
| } |
| |
| TEST_F(PositiveGpuAVSpirv, UniformWithoutAccessChain) { |
| TEST_DESCRIPTION("dEQP-VK.spirv_assembly.instruction.compute.composite_insert.nested_struct"); |
| RETURN_IF_SKIP(InitGpuAvFramework()); |
| RETURN_IF_SKIP(InitState()); |
| |
| const char* spv_source = R"( |
| OpCapability Shader |
| %1 = OpExtInstImport "GLSL.std.450" |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint GLCompute %main "main" |
| OpExecutionMode %main LocalSize 1 1 1 |
| OpSource GLSL 430 |
| OpDecorate %_arr_mat4v4f32_uint_8 ArrayStride 64 |
| OpMemberDecorate %S 0 ColMajor |
| OpMemberDecorate %S 0 Offset 0 |
| OpMemberDecorate %S 0 MatrixStride 16 |
| OpMemberDecorate %Output 0 Offset 0 |
| OpDecorate %Output BufferBlock |
| OpDecorate %dataOutput DescriptorSet 0 |
| OpDecorate %dataOutput Binding 0 |
| %f32 = OpTypeFloat 32 |
| %v4f32 = OpTypeVector %f32 4 |
| %mat4v4f32 = OpTypeMatrix %v4f32 4 |
| %uint = OpTypeInt 32 0 |
| %uint_8 = OpConstant %uint 8 |
| %_arr_mat4v4f32_uint_8 = OpTypeArray %mat4v4f32 %uint_8 |
| %S = OpTypeStruct %_arr_mat4v4f32_uint_8 |
| %Output = OpTypeStruct %S |
| %_ptr_Uniform_Output = OpTypePointer Uniform %Output |
| %_ptr_Function_Output = OpTypePointer Function %Output |
| %dataOutput = OpVariable %_ptr_Uniform_Output Uniform |
| %c_f32_0 = OpConstant %f32 0 |
| %c_f32_1 = OpConstant %f32 1 |
| %identity0 = OpConstantComposite %v4f32 %c_f32_1 %c_f32_0 %c_f32_0 %c_f32_0 |
| %identity1 = OpConstantComposite %v4f32 %c_f32_0 %c_f32_1 %c_f32_0 %c_f32_0 |
| %identity2 = OpConstantComposite %v4f32 %c_f32_0 %c_f32_0 %c_f32_1 %c_f32_0 |
| %identity3 = OpConstantComposite %v4f32 %c_f32_0 %c_f32_0 %c_f32_0 %c_f32_1 |
| %void = OpTypeVoid |
| %3 = OpTypeFunction %void |
| %main = OpFunction %void None %3 |
| %entry = OpLabel |
| %nestedstruct = OpVariable %_ptr_Function_Output Function |
| %tmp0 = OpLoad %Output %nestedstruct |
| %tmp1 = OpCompositeInsert %Output %identity0 %tmp0 0 0 0 0 |
| %tmp2 = OpCompositeInsert %Output %identity1 %tmp1 0 0 0 1 |
| %tmp3 = OpCompositeInsert %Output %identity2 %tmp2 0 0 0 2 |
| %tmp4 = OpCompositeInsert %Output %identity3 %tmp3 0 0 0 3 |
| %tmp5 = OpCompositeInsert %Output %identity0 %tmp4 0 0 1 0 |
| %tmp6 = OpCompositeInsert %Output %identity1 %tmp5 0 0 1 1 |
| %tmp7 = OpCompositeInsert %Output %identity2 %tmp6 0 0 1 2 |
| %tmp8 = OpCompositeInsert %Output %identity3 %tmp7 0 0 1 3 |
| %tmp9 = OpCompositeInsert %Output %identity0 %tmp8 0 0 2 0 |
| %tmp10 = OpCompositeInsert %Output %identity1 %tmp9 0 0 2 1 |
| %tmp11 = OpCompositeInsert %Output %identity2 %tmp10 0 0 2 2 |
| %tmp12 = OpCompositeInsert %Output %identity3 %tmp11 0 0 2 3 |
| %tmp13 = OpCompositeInsert %Output %identity0 %tmp12 0 0 3 0 |
| %tmp14 = OpCompositeInsert %Output %identity1 %tmp13 0 0 3 1 |
| %tmp15 = OpCompositeInsert %Output %identity2 %tmp14 0 0 3 2 |
| %tmp16 = OpCompositeInsert %Output %identity3 %tmp15 0 0 3 3 |
| %tmp17 = OpCompositeInsert %Output %identity0 %tmp16 0 0 4 0 |
| %tmp18 = OpCompositeInsert %Output %identity1 %tmp17 0 0 4 1 |
| %tmp19 = OpCompositeInsert %Output %identity2 %tmp18 0 0 4 2 |
| %tmp20 = OpCompositeInsert %Output %identity3 %tmp19 0 0 4 3 |
| %tmp21 = OpCompositeInsert %Output %identity0 %tmp20 0 0 5 0 |
| %tmp22 = OpCompositeInsert %Output %identity1 %tmp21 0 0 5 1 |
| %tmp23 = OpCompositeInsert %Output %identity2 %tmp22 0 0 5 2 |
| %tmp24 = OpCompositeInsert %Output %identity3 %tmp23 0 0 5 3 |
| %tmp25 = OpCompositeInsert %Output %identity0 %tmp24 0 0 6 0 |
| %tmp26 = OpCompositeInsert %Output %identity1 %tmp25 0 0 6 1 |
| %tmp27 = OpCompositeInsert %Output %identity2 %tmp26 0 0 6 2 |
| %tmp28 = OpCompositeInsert %Output %identity3 %tmp27 0 0 6 3 |
| %tmp29 = OpCompositeInsert %Output %identity0 %tmp28 0 0 7 0 |
| %tmp30 = OpCompositeInsert %Output %identity1 %tmp29 0 0 7 1 |
| %tmp31 = OpCompositeInsert %Output %identity2 %tmp30 0 0 7 2 |
| %tmp32 = OpCompositeInsert %Output %identity3 %tmp31 0 0 7 3 |
| OpStore %dataOutput %tmp32 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| |
| CreateComputePipelineHelper pipe(*this); |
| pipe.dsl_bindings_[0] = {0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr}; |
| pipe.cs_ = VkShaderObj(*m_device, spv_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_0, SPV_SOURCE_ASM); |
| pipe.CreateComputePipeline(); |
| } |
| |
| TEST_F(PositiveGpuAVSpirv, TypeSamplerAsParameter) { |
| TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/12647"); |
| RETURN_IF_SKIP(InitGpuAvFramework()); |
| RETURN_IF_SKIP(InitState()); |
| InitRenderTarget(); |
| |
| const char* fs_source = R"( |
| OpCapability Shader |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint Fragment %main "main" %frag_color |
| OpExecutionMode %main OriginUpperLeft |
| OpDecorate %frag_color Location 0 |
| OpDecorate %image_var DescriptorSet 0 |
| OpDecorate %image_var Binding 0 |
| OpDecorate %sampler_var DescriptorSet 0 |
| OpDecorate %sampler_var Binding 1 |
| %void = OpTypeVoid |
| %void_func_t = OpTypeFunction %void |
| %float = OpTypeFloat 32 |
| %v2float = OpTypeVector %float 2 |
| %v4float = OpTypeVector %float 4 |
| %image_2d = OpTypeImage %float 2D 0 0 0 1 Unknown |
| %sampler_t = OpTypeSampler |
| %sampled_img_t = OpTypeSampledImage %image_2d |
| %sampling_func_t = OpTypeFunction %v4float %sampler_t %v2float |
| %image_ptr_t = OpTypePointer UniformConstant %image_2d |
| %sampler_ptr_t = OpTypePointer UniformConstant %sampler_t |
| %v4float_out_ptr = OpTypePointer Output %v4float |
| %float_0 = OpConstant %float 0 |
| %coords = OpConstantComposite %v2float %float_0 %float_0 |
| %frag_color = OpVariable %v4float_out_ptr Output |
| %image_var = OpVariable %image_ptr_t UniformConstant |
| %sampler_var = OpVariable %sampler_ptr_t UniformConstant |
| %main = OpFunction %void None %void_func_t |
| %main_label = OpLabel |
| %smpl_load = OpLoad %sampler_t %sampler_var |
| %color = OpFunctionCall %v4float %sampling_func %smpl_load %coords |
| OpStore %frag_color %color |
| OpReturn |
| OpFunctionEnd |
| %sampling_func = OpFunction %v4float None %sampling_func_t |
| %smpl_param = OpFunctionParameter %sampler_t |
| %tex_coords = OpFunctionParameter %v2float |
| %sampling_func_label = OpLabel |
| %img_load = OpLoad %image_2d %image_var |
| %combined_img = OpSampledImage %sampled_img_t %img_load %smpl_param |
| %retval = OpImageSampleImplicitLod %v4float %combined_img %tex_coords |
| OpReturnValue %retval |
| OpFunctionEnd |
| )"; |
| |
| OneOffDescriptorSet descriptor_set(m_device, { |
| {0, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| {1, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| }); |
| const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_}); |
| |
| VkShaderObj fs(*m_device, fs_source, VK_SHADER_STAGE_FRAGMENT_BIT, SPV_ENV_VULKAN_1_0, SPV_SOURCE_ASM); |
| CreatePipelineHelper pipe(*this); |
| pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()}; |
| pipe.gp_ci_.layout = pipeline_layout; |
| pipe.CreateGraphicsPipeline(); |
| } |
| |
| TEST_F(PositiveGpuAVSpirv, TypeSampledImageAsParameter) { |
| TEST_DESCRIPTION("dEQP-VK.spirv_assembly.instruction.function_params.sampler_param"); |
| RETURN_IF_SKIP(InitGpuAvFramework()); |
| RETURN_IF_SKIP(InitState()); |
| InitRenderTarget(); |
| |
| const char* fs_source = R"( |
| OpCapability Shader |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint Fragment %main "main" %frag_color |
| OpExecutionMode %main OriginUpperLeft |
| OpDecorate %frag_color Location 0 |
| OpDecorate %sampled_img_var DescriptorSet 0 |
| OpDecorate %sampled_img_var Binding 0 |
| %void = OpTypeVoid |
| %void_func_t = OpTypeFunction %void |
| %float = OpTypeFloat 32 |
| %v2float = OpTypeVector %float 2 |
| %v4float = OpTypeVector %float 4 |
| %image_2d = OpTypeImage %float 2D 0 0 0 1 Unknown |
| %sampled_img = OpTypeSampledImage %image_2d |
| %sampling_func_t = OpTypeFunction %v4float %sampled_img %v2float |
| %sampled_img_uniform_ptr = OpTypePointer UniformConstant %sampled_img |
| %v4float_out_ptr = OpTypePointer Output %v4float |
| %float_0 = OpConstant %float 0 |
| %coords = OpConstantComposite %v2float %float_0 %float_0 |
| %frag_color = OpVariable %v4float_out_ptr Output |
| %sampled_img_var = OpVariable %sampled_img_uniform_ptr UniformConstant |
| |
| %main = OpFunction %void None %void_func_t |
| %main_label = OpLabel |
| %sample_arg = OpLoad %sampled_img %sampled_img_var |
| %color = OpFunctionCall %v4float %sampling_func %sample_arg %coords |
| OpStore %frag_color %color |
| OpReturn |
| OpFunctionEnd |
| |
| %sampling_func = OpFunction %v4float None %sampling_func_t |
| %sampler = OpFunctionParameter %sampled_img |
| %tex_coords = OpFunctionParameter %v2float |
| %sampling_func_label = OpLabel |
| %retval = OpImageSampleImplicitLod %v4float %sampler %tex_coords |
| OpReturnValue %retval |
| OpFunctionEnd |
| )"; |
| |
| VkShaderObj fs(*m_device, fs_source, VK_SHADER_STAGE_FRAGMENT_BIT, SPV_ENV_VULKAN_1_0, SPV_SOURCE_ASM); |
| CreatePipelineHelper pipe(*this); |
| pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()}; |
| pipe.dsl_bindings_[0] = {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}; |
| pipe.CreateGraphicsPipeline(); |
| } |
| |
| TEST_F(PositiveGpuAVSpirv, ConstantFoldFConvert) { |
| SetTargetApiVersion(VK_API_VERSION_1_1); |
| AddRequiredExtensions(VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME); |
| AddRequiredExtensions(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::shaderFloat16); |
| AddRequiredFeature(vkt::Feature::fragmentStoresAndAtomics); |
| RETURN_IF_SKIP(InitGpuAvFramework()); |
| RETURN_IF_SKIP(InitState()); |
| InitRenderTarget(); |
| |
| const char* fs_source = R"( |
| OpCapability Shader |
| OpCapability Float16 |
| OpCapability RoundingModeRTE |
| OpExtension "SPV_KHR_float_controls" |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint Fragment %main "main" %frag_color |
| OpExecutionMode %main OriginUpperLeft |
| OpExecutionMode %main RoundingModeRTE 16 |
| OpDecorate %frag_color Location 0 |
| OpDecorate %type_u32_arr_1 ArrayStride 4 |
| OpMemberDecorate %SSBO_out 0 Offset 0 |
| OpDecorate %SSBO_out BufferBlock |
| OpDecorate %ssbo_out DescriptorSet 0 |
| OpDecorate %ssbo_out Binding 1 |
| %void = OpTypeVoid |
| %void_func = OpTypeFunction %void |
| %type_i32 = OpTypeInt 32 1 |
| %type_u32 = OpTypeInt 32 0 |
| %type_f16 = OpTypeFloat 16 |
| %type_f32 = OpTypeFloat 32 |
| %type_f16_vec2 = OpTypeVector %type_f16 2 |
| %type_f32_vec4 = OpTypeVector %type_f32 4 |
| %type_f32_vec4_optr = OpTypePointer Output %type_f32_vec4 |
| %c_i32_0 = OpConstant %type_i32 0 |
| %c_i32_1 = OpConstant %type_i32 1 |
| %c_f16_0 = OpConstant %type_f16 0.0 |
| %c_f32_1 = OpConstant %type_f32 1.0 |
| %c_arg = OpConstant %type_f32 !1198739455 |
| %result = OpSpecConstantOp %type_f16 FConvert %c_arg |
| %type_u32_arr_1 = OpTypeArray %type_u32 %c_i32_1 |
| %type_u32_uptr = OpTypePointer Uniform %type_u32 |
| %SSBO_out = OpTypeStruct %type_u32_arr_1 |
| %up_SSBO_out = OpTypePointer Uniform %SSBO_out |
| %frag_color = OpVariable %type_f32_vec4_optr Output |
| %ssbo_out = OpVariable %up_SSBO_out Uniform |
| %main = OpFunction %void None %void_func |
| %label = OpLabel |
| %color = OpCompositeConstruct %type_f32_vec4 %c_f32_1 %c_f32_1 %c_f32_1 %c_f32_1 |
| OpStore %frag_color %color |
| %result_f16_vec2 = OpCompositeConstruct %type_f16_vec2 %result %c_f16_0 |
| %result_u32 = OpBitcast %type_u32 %result_f16_vec2 |
| %outloc = OpAccessChain %type_u32_uptr %ssbo_out %c_i32_0 %c_i32_0 |
| OpStore %outloc %result_u32 |
| OpReturn |
| OpFunctionEnd |
| )"; |
| |
| VkShaderObj fs(*m_device, fs_source, VK_SHADER_STAGE_FRAGMENT_BIT, SPV_ENV_VULKAN_1_1, SPV_SOURCE_ASM); |
| CreatePipelineHelper pipe(*this); |
| pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()}; |
| pipe.dsl_bindings_ = {{1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr}}; |
| pipe.CreateGraphicsPipeline(); |
| } |
| |
| TEST_F(PositiveGpuAVSpirv, EndAccessChainWithCopyObject) { |
| RETURN_IF_SKIP(InitGpuAvFramework()); |
| RETURN_IF_SKIP(InitState()); |
| |
| const char* spv_source = R"( |
| OpCapability Shader |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint GLCompute %main "main" |
| OpExecutionMode %main LocalSize 1 1 1 |
| OpDecorate %struct BufferBlock |
| OpMemberDecorate %struct 0 Offset 0 |
| OpDecorate %buf_array DescriptorSet 0 |
| OpDecorate %buf_array Binding 0 |
| %void = OpTypeVoid |
| %func_type = OpTypeFunction %void |
| %int = OpTypeInt 32 1 |
| %int_0 = OpConstant %int 0 |
| %uint = OpTypeInt 32 0 |
| %uint_4 = OpConstant %uint 4 |
| %struct = OpTypeStruct %int |
| %struct_array = OpTypeArray %struct %uint_4 |
| %ptr_struct_array = OpTypePointer Uniform %struct_array |
| %ptr_struct = OpTypePointer Uniform %struct |
| %ptr_int = OpTypePointer Uniform %int |
| %buf_array = OpVariable %ptr_struct_array Uniform |
| %main = OpFunction %void None %func_type |
| %entry = OpLabel |
| |
| ; OpCopyObject on the descriptor array variable %buf_array |
| %var_copy = OpCopyObject %ptr_struct_array %buf_array |
| ; AccessChain through the copied handle |
| %buf_ptr = OpAccessChain %ptr_struct %var_copy %int_0 |
| %int_ptr = OpAccessChain %ptr_int %buf_ptr %int_0 |
| ; Memory access instruction that triggers AccessPath evaluation |
| %val = OpLoad %int %int_ptr |
| |
| OpReturn |
| OpFunctionEnd |
| )"; |
| |
| CreateComputePipelineHelper pipe(*this); |
| pipe.dsl_bindings_[0] = {0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}; |
| pipe.cs_ = VkShaderObj(*m_device, spv_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_0, SPV_SOURCE_ASM); |
| pipe.CreateComputePipeline(); |
| } |
| |
| TEST_F(PositiveGpuAVSpirv, SamplerCopyObject) { |
| AddRequiredExtensions(VK_KHR_COMPUTE_SHADER_DERIVATIVES_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::computeDerivativeGroupQuads); |
| RETURN_IF_SKIP(InitGpuAvFramework()); |
| RETURN_IF_SKIP(InitState()); |
| |
| const char* spv_source = R"( |
| OpCapability Shader |
| OpCapability ComputeDerivativeGroupQuadsKHR |
| OpExtension "SPV_KHR_compute_shader_derivatives" |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint GLCompute %main "main" |
| OpExecutionMode %main LocalSize 2 2 1 |
| OpExecutionMode %main DerivativeGroupQuadsKHR |
| OpDecorate %sampler_array DescriptorSet 0 |
| OpDecorate %sampler_array Binding 0 |
| OpDecorate %image DescriptorSet 0 |
| OpDecorate %image Binding 1 |
| %void = OpTypeVoid |
| %func_type = OpTypeFunction %void |
| %float = OpTypeFloat 32 |
| %vec2 = OpTypeVector %float 2 |
| %vec4 = OpTypeVector %float 4 |
| %int = OpTypeInt 32 1 |
| %int_0 = OpConstant %int 0 |
| %uint = OpTypeInt 32 0 |
| %uint_2 = OpConstant %uint 2 |
| %image_type = OpTypeImage %float 2D 0 0 0 1 Unknown |
| %sampler_type = OpTypeSampler |
| %sampled_image_type = OpTypeSampledImage %image_type |
| %sampler_array_type = OpTypeArray %sampler_type %uint_2 |
| %ptr_sampler_array = OpTypePointer UniformConstant %sampler_array_type |
| %ptr_sampler = OpTypePointer UniformConstant %sampler_type |
| %ptr_image = OpTypePointer UniformConstant %image_type |
| %sampler_array = OpVariable %ptr_sampler_array UniformConstant |
| %image = OpVariable %ptr_image UniformConstant |
| %main = OpFunction %void None %func_type |
| %entry = OpLabel |
| |
| %img_handle = OpLoad %image_type %image |
| %sampler_ptr = OpAccessChain %ptr_sampler %sampler_array %int_0 |
| %sampler_ptr_copy = OpCopyObject %ptr_sampler %sampler_ptr |
| %sampler_handle = OpLoad %sampler_type %sampler_ptr_copy |
| %sampled_img = OpSampledImage %sampled_image_type %img_handle %sampler_handle |
| %uv = OpUndef %vec2 |
| %color = OpImageSampleImplicitLod %vec4 %sampled_img %uv |
| |
| OpReturn |
| OpFunctionEnd |
| )"; |
| OneOffDescriptorSet descriptor_set(m_device, { |
| {0, VK_DESCRIPTOR_TYPE_SAMPLER, 2, VK_SHADER_STAGE_ALL, nullptr}, |
| {1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| }); |
| const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_}); |
| |
| CreateComputePipelineHelper pipe(*this); |
| pipe.cp_ci_.layout = pipeline_layout; |
| pipe.cs_ = VkShaderObj(*m_device, spv_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_0, SPV_SOURCE_ASM); |
| pipe.CreateComputePipeline(); |
| } |
| |
| TEST_F(PositiveGpuAVSpirv, SamplerCopyObject2) { |
| AddRequiredExtensions(VK_KHR_COMPUTE_SHADER_DERIVATIVES_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::computeDerivativeGroupQuads); |
| RETURN_IF_SKIP(InitGpuAvFramework()); |
| RETURN_IF_SKIP(InitState()); |
| |
| const char* spv_source = R"( |
| OpCapability Shader |
| OpCapability ComputeDerivativeGroupQuadsKHR |
| OpExtension "SPV_KHR_compute_shader_derivatives" |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint GLCompute %main "main" |
| OpExecutionMode %main LocalSize 2 2 1 |
| OpExecutionMode %main DerivativeGroupQuadsKHR |
| OpDecorate %sampler_var DescriptorSet 0 |
| OpDecorate %sampler_var Binding 0 |
| OpDecorate %image_var DescriptorSet 0 |
| OpDecorate %image_var Binding 1 |
| %void = OpTypeVoid |
| %func_type = OpTypeFunction %void |
| %float = OpTypeFloat 32 |
| %vec2 = OpTypeVector %float 2 |
| %vec4 = OpTypeVector %float 4 |
| %image_type = OpTypeImage %float 2D 0 0 0 1 Unknown |
| %sampler_type = OpTypeSampler |
| %sampled_image_type = OpTypeSampledImage %image_type |
| %ptr_sampler = OpTypePointer UniformConstant %sampler_type |
| %ptr_image = OpTypePointer UniformConstant %image_type |
| %sampler_var = OpVariable %ptr_sampler UniformConstant |
| %image_var = OpVariable %ptr_image UniformConstant |
| %main = OpFunction %void None %func_type |
| %entry = OpLabel |
| |
| %img_handle = OpLoad %image_type %image_var |
| %sampler_handle = OpLoad %sampler_type %sampler_var |
| %sampler_copy = OpCopyObject %sampler_type %sampler_handle |
| %sampled_img = OpSampledImage %sampled_image_type %img_handle %sampler_copy |
| %uv = OpUndef %vec2 |
| %color = OpImageSampleImplicitLod %vec4 %sampled_img %uv |
| |
| OpReturn |
| OpFunctionEnd |
| )"; |
| OneOffDescriptorSet descriptor_set(m_device, { |
| {0, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| {1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| }); |
| const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_}); |
| |
| CreateComputePipelineHelper pipe(*this); |
| pipe.cp_ci_.layout = pipeline_layout; |
| pipe.cs_ = VkShaderObj(*m_device, spv_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_0, SPV_SOURCE_ASM); |
| pipe.CreateComputePipeline(); |
| } |
| TEST_F(PositiveGpuAVSpirv, SamplerCopyObjectFunction) { |
| AddRequiredExtensions(VK_KHR_COMPUTE_SHADER_DERIVATIVES_EXTENSION_NAME); |
| AddRequiredFeature(vkt::Feature::computeDerivativeGroupQuads); |
| RETURN_IF_SKIP(InitGpuAvFramework()); |
| RETURN_IF_SKIP(InitState()); |
| |
| const char* spv_source = R"( |
| OpCapability Shader |
| OpCapability ComputeDerivativeGroupQuadsKHR |
| OpExtension "SPV_KHR_compute_shader_derivatives" |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint GLCompute %main "main" |
| OpExecutionMode %main LocalSize 2 2 1 |
| OpExecutionMode %main DerivativeGroupQuadsKHR |
| OpDecorate %sampler_var DescriptorSet 0 |
| OpDecorate %sampler_var Binding 0 |
| OpDecorate %image_var DescriptorSet 0 |
| OpDecorate %image_var Binding 1 |
| %void = OpTypeVoid |
| %func_type = OpTypeFunction %void |
| %float = OpTypeFloat 32 |
| %vec2 = OpTypeVector %float 2 |
| %vec4 = OpTypeVector %float 4 |
| %image_type = OpTypeImage %float 2D 0 0 0 1 Unknown |
| %sampler_type = OpTypeSampler |
| %sampled_image_type = OpTypeSampledImage %image_type |
| %helper_type = OpTypeFunction %vec4 %sampler_type |
| %ptr_image = OpTypePointer UniformConstant %image_type |
| %ptr_sampler = OpTypePointer UniformConstant %sampler_type |
| %image_var = OpVariable %ptr_image UniformConstant |
| %sampler_var = OpVariable %ptr_sampler UniformConstant |
| %sample_helper = OpFunction %vec4 None %helper_type |
| %sampler_param = OpFunctionParameter %sampler_type |
| %helper_entry = OpLabel |
| %img_handle = OpLoad %image_type %image_var |
| %sampler_param_copy = OpCopyObject %sampler_type %sampler_param |
| %sampled_img = OpSampledImage %sampled_image_type %img_handle %sampler_param_copy |
| %uv = OpUndef %vec2 |
| %color = OpImageSampleImplicitLod %vec4 %sampled_img %uv |
| OpReturnValue %color |
| OpFunctionEnd |
| %main = OpFunction %void None %func_type |
| %main_entry = OpLabel |
| %sampler_val = OpLoad %sampler_type %sampler_var |
| %res = OpFunctionCall %vec4 %sample_helper %sampler_val |
| OpReturn |
| OpFunctionEnd |
| )"; |
| OneOffDescriptorSet descriptor_set(m_device, { |
| {0, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| {1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_ALL, nullptr}, |
| }); |
| const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_}); |
| |
| CreateComputePipelineHelper pipe(*this); |
| pipe.cp_ci_.layout = pipeline_layout; |
| pipe.cs_ = VkShaderObj(*m_device, spv_source, VK_SHADER_STAGE_COMPUTE_BIT, SPV_ENV_VULKAN_1_0, SPV_SOURCE_ASM); |
| pipe.CreateComputePipeline(); |
| } |
| |
| TEST_F(PositiveGpuAVSpirv, MultiEntrypointVulkan11) { |
| TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/12871"); |
| RETURN_IF_SKIP(InitGpuAvFramework()); |
| RETURN_IF_SKIP(InitState()); |
| InitRenderTarget(); |
| |
| const char* spv_source = R"( |
| OpCapability Shader |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint Vertex %vert_main "main" %gl_Position |
| OpEntryPoint Fragment %frag_main "main" %uFragColor |
| OpExecutionMode %frag_main OriginUpperLeft |
| OpDecorate %gl_Position BuiltIn Position |
| OpDecorate %uFragColor Location 0 |
| %void = OpTypeVoid |
| %3 = OpTypeFunction %void |
| %float = OpTypeFloat 32 |
| %v4float = OpTypeVector %float 4 |
| %_ptr_Output_v4float = OpTypePointer Output %v4float |
| %gl_Position = OpVariable %_ptr_Output_v4float Output |
| %uFragColor = OpVariable %_ptr_Output_v4float Output |
| %float_1 = OpConstant %float 1 |
| %float_0 = OpConstant %float 0 |
| %v4_ones = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1 |
| %v4_green = OpConstantComposite %v4float %float_0 %float_1 %float_0 %float_1 |
| %vert_main = OpFunction %void None %3 |
| %label_v = OpLabel |
| OpStore %gl_Position %v4_ones |
| OpReturn |
| OpFunctionEnd |
| %frag_main = OpFunction %void None %3 |
| %label_f = OpLabel |
| OpStore %uFragColor %v4_green |
| OpReturn |
| OpFunctionEnd |
| )"; |
| VkShaderObj vs(*m_device, spv_source, VK_SHADER_STAGE_VERTEX_BIT, SPV_ENV_VULKAN_1_1, SPV_SOURCE_ASM); |
| VkShaderObj fs(*m_device, spv_source, VK_SHADER_STAGE_FRAGMENT_BIT, SPV_ENV_VULKAN_1_1, SPV_SOURCE_ASM); |
| |
| CreatePipelineHelper pipe(*this); |
| pipe.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()}; |
| pipe.CreateGraphicsPipeline(); |
| } |