blob: 5608749bdc77e398218390974b38a1be177a0248 [file]
/* 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();
}