diff --git a/reference/shaders-no-opt/asm/frag/opaque-id-literal-alias.preserve.asm.frag b/reference/shaders-no-opt/asm/frag/opaque-id-literal-alias.preserve.asm.frag new file mode 100644 index 00000000..74592287 --- /dev/null +++ b/reference/shaders-no-opt/asm/frag/opaque-id-literal-alias.preserve.asm.frag @@ -0,0 +1,20 @@ +#version 450 + +layout(binding = 0) uniform sampler2DMS uSampled; + +layout(location = 0) out vec4 FragColor; +layout(location = 0) in vec2 vUV; + +void main() +{ + FragColor = vec4(0.0); + if (gl_FragCoord.x < 10.0) + { + FragColor += texelFetch(uSampled, ivec2(vUV), 0); + } + else + { + FragColor += texelFetch(uSampled, ivec2(vUV), 1); + } +} + diff --git a/reference/shaders-reflection/asm/aliased-entry-point-names.asm.multi.json b/reference/shaders-reflection/asm/aliased-entry-point-names.asm.multi.json index 45adf50b..a56a06f3 100644 --- a/reference/shaders-reflection/asm/aliased-entry-point-names.asm.multi.json +++ b/reference/shaders-reflection/asm/aliased-entry-point-names.asm.multi.json @@ -1,19 +1,19 @@ { "entryPoints" : [ { - "name" : "main", - "mode" : "vert" - }, - { - "name" : "main2", + "name" : "maim", "mode" : "vert" }, { "name" : "main", + "mode" : "vert" + }, + { + "name" : "maim", "mode" : "frag" }, { - "name" : "main2", + "name" : "main", "mode" : "frag" } ], diff --git a/shaders-no-opt/asm/frag/opaque-id-literal-alias.preserve.asm.frag b/shaders-no-opt/asm/frag/opaque-id-literal-alias.preserve.asm.frag new file mode 100644 index 00000000..c77c9a17 --- /dev/null +++ b/shaders-no-opt/asm/frag/opaque-id-literal-alias.preserve.asm.frag @@ -0,0 +1,78 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 7 +; Bound: 50 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %FragColor %gl_FragCoord %vUV + OpExecutionMode %main OriginUpperLeft + OpSource GLSL 450 + OpName %main "main" + OpName %FragColor "FragColor" + OpName %gl_FragCoord "gl_FragCoord" + OpName %uSampled "uSampled" + OpName %vUV "vUV" + OpDecorate %FragColor Location 0 + OpDecorate %gl_FragCoord BuiltIn FragCoord + OpDecorate %uSampled DescriptorSet 0 + OpDecorate %uSampled Binding 0 + OpDecorate %vUV Location 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%_ptr_Output_v4float = OpTypePointer Output %v4float + %FragColor = OpVariable %_ptr_Output_v4float Output + %float_0 = OpConstant %float 0 + %11 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 +%_ptr_Input_float = OpTypePointer Input %float + %float_10 = OpConstant %float 10 + %bool = OpTypeBool + %24 = OpTypeImage %float 2D 0 0 1 1 Unknown + %25 = OpTypeSampledImage %24 +%_ptr_UniformConstant_25 = OpTypePointer UniformConstant %25 + %uSampled = OpVariable %_ptr_UniformConstant_25 UniformConstant + %v2float = OpTypeVector %float 2 +%_ptr_Input_v2float = OpTypePointer Input %v2float + %vUV = OpVariable %_ptr_Input_v2float Input + %int = OpTypeInt 32 1 + %v2int = OpTypeVector %int 2 + %int_0 = OpConstant %int 0 + %int_1 = OpConstant %int 1 + %main = OpFunction %void None %3 + %5 = OpLabel + OpStore %FragColor %11 + %17 = OpAccessChain %_ptr_Input_float %gl_FragCoord %uint_0 + %18 = OpLoad %float %17 + %21 = OpFOrdLessThan %bool %18 %float_10 + OpSelectionMerge %23 None + OpBranchConditional %21 %22 %41 + %22 = OpLabel + %28 = OpLoad %25 %uSampled + %32 = OpLoad %v2float %vUV + %35 = OpConvertFToS %v2int %32 + %64 = OpImage %24 %28 + %38 = OpImageFetch %v4float %64 %35 Sample %int_0 + %39 = OpLoad %v4float %FragColor + %40 = OpFAdd %v4float %39 %38 + OpStore %FragColor %40 + OpBranch %23 + %41 = OpLabel + %42 = OpLoad %25 %uSampled + %43 = OpLoad %v2float %vUV + %44 = OpConvertFToS %v2int %43 + %46 = OpImage %24 %42 + %47 = OpImageFetch %v4float %46 %44 Sample %int_1 + %48 = OpLoad %v4float %FragColor + %49 = OpFAdd %v4float %48 %47 + OpStore %FragColor %49 + OpBranch %23 + %23 = OpLabel + OpReturn + OpFunctionEnd diff --git a/shaders-reflection/asm/aliased-entry-point-names.asm.multi b/shaders-reflection/asm/aliased-entry-point-names.asm.multi index d60cf303..4a8e60ef 100644 --- a/shaders-reflection/asm/aliased-entry-point-names.asm.multi +++ b/shaders-reflection/asm/aliased-entry-point-names.asm.multi @@ -7,9 +7,9 @@ %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Vertex %main "main" %_ - OpEntryPoint Vertex %main2 "main2" %_ + OpEntryPoint Vertex %main2 "maim" %_ OpEntryPoint Fragment %main3 "main" %FragColor - OpEntryPoint Fragment %main4 "main2" %FragColor + OpEntryPoint Fragment %main4 "maim" %FragColor OpSource GLSL 450 OpMemberDecorate %gl_PerVertex 0 BuiltIn Position OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize diff --git a/spirv_cross.cpp b/spirv_cross.cpp index e0817fd0..611dc925 100644 --- a/spirv_cross.cpp +++ b/spirv_cross.cpp @@ -3053,7 +3053,7 @@ bool Compiler::AnalyzeVariableScopeAccessHandler::handle(spv::Op op, const uint3 } case OpArrayLength: - // Uses literals, but cannot be a phi variable, so ignore. + // Uses literals, but cannot be a phi variable or temporary, so ignore. break; // Atomics shouldn't be able to access function-local variables. @@ -3072,6 +3072,55 @@ bool Compiler::AnalyzeVariableScopeAccessHandler::handle(spv::Op op, const uint3 notify_variable_access(args[i], current_block->self); break; + case OpImageWrite: + for (uint32_t i = 0; i < length; i++) + { + // Argument 3 is a literal. + if (i != 3) + notify_variable_access(args[i], current_block->self); + } + break; + + case OpImageSampleImplicitLod: + case OpImageSampleExplicitLod: + case OpImageSparseSampleImplicitLod: + case OpImageSparseSampleExplicitLod: + case OpImageSampleProjImplicitLod: + case OpImageSampleProjExplicitLod: + case OpImageSparseSampleProjImplicitLod: + case OpImageSparseSampleProjExplicitLod: + case OpImageFetch: + case OpImageSparseFetch: + case OpImageRead: + case OpImageSparseRead: + for (uint32_t i = 1; i < length; i++) + { + // Argument 4 is a literal. + if (i != 4) + notify_variable_access(args[i], current_block->self); + } + break; + + case OpImageSampleDrefImplicitLod: + case OpImageSampleDrefExplicitLod: + case OpImageSparseSampleDrefImplicitLod: + case OpImageSparseSampleDrefExplicitLod: + case OpImageSampleProjDrefImplicitLod: + case OpImageSampleProjDrefExplicitLod: + case OpImageSparseSampleProjDrefImplicitLod: + case OpImageSparseSampleProjDrefExplicitLod: + case OpImageGather: + case OpImageSparseGather: + case OpImageDrefGather: + case OpImageSparseDrefGather: + for (uint32_t i = 1; i < length; i++) + { + // Argument 5 is a literal. + if (i != 5) + notify_variable_access(args[i], current_block->self); + } + break; + default: { // Rather dirty way of figuring out where Phi variables are used. @@ -3310,6 +3359,11 @@ void Compiler::analyze_variable_scope(SPIRFunction &entry, AnalyzeVariableScopeA continue; } + // There is no point in doing domination analysis for opaque types. + auto &type = get(itr->second); + if (type_is_opaque_value(type)) + continue; + DominatorBuilder builder(cfg); bool force_temporary = false; @@ -3996,7 +4050,7 @@ bool Compiler::instruction_to_result_type(uint32_t &result_type, uint32_t &resul return false; default: - if (length > 1) + if (length > 1 && maybe_get(args[0]) != nullptr) { result_type = args[0]; result_id = args[1]; @@ -4065,3 +4119,9 @@ bool Compiler::image_is_comparison(const spirv_cross::SPIRType &type, uint32_t i { return type.image.depth || (comparison_ids.count(id) != 0); } + +bool Compiler::type_is_opaque_value(const spirv_cross::SPIRType &type) const +{ + return !type.pointer && (type.basetype == SPIRType::SampledImage || type.basetype == SPIRType::Image || + type.basetype == SPIRType::Sampler); +} diff --git a/spirv_cross.hpp b/spirv_cross.hpp index 0aae06c6..2b8449df 100644 --- a/spirv_cross.hpp +++ b/spirv_cross.hpp @@ -565,7 +565,9 @@ protected: template T *maybe_get(uint32_t id) { - if (ir.ids[id].get_type() == static_cast(T::type)) + if (id >= ir.ids.size()) + return nullptr; + else if (ir.ids[id].get_type() == static_cast(T::type)) return &get(id); else return nullptr; @@ -982,6 +984,7 @@ private: void fixup_type_alias(); bool type_is_block_like(const SPIRType &type) const; + bool type_is_opaque_value(const SPIRType &type) const; }; } // namespace spirv_cross diff --git a/spirv_reflect.cpp b/spirv_reflect.cpp index 54eb64fb..43c416ca 100644 --- a/spirv_reflect.cpp +++ b/spirv_reflect.cpp @@ -391,6 +391,16 @@ void CompilerReflection::emit_entry_points() auto entries = get_entry_points_and_stages(); if (!entries.empty()) { + // Needed to make output deterministic. + sort(begin(entries), end(entries), [](const EntryPoint &a, const EntryPoint &b) -> bool { + if (a.execution_model < b.execution_model) + return true; + else if (a.execution_model > b.execution_model) + return false; + else + return a.name < b.name; + }); + json_stream->emit_json_key_array("entryPoints"); for (auto &e : entries) { diff --git a/test_shaders.py b/test_shaders.py index 9f4d1e3b..cf233e60 100755 --- a/test_shaders.py +++ b/test_shaders.py @@ -135,8 +135,12 @@ def cross_compile_msl(shader, spirv, opt): spirv_path = create_temporary() msl_path = create_temporary(os.path.basename(shader)) + spirv_cmd = ['spirv-as', '-o', spirv_path, shader] + if '.preserve.' in shader: + spirv_cmd.append('--preserve-numeric-ids') + if spirv: - subprocess.check_call(['spirv-as', '-o', spirv_path, shader]) + subprocess.check_call(spirv_cmd) else: subprocess.check_call(['glslangValidator', '--target-env', 'vulkan1.1', '-V', '-o', spirv_path, shader]) @@ -231,8 +235,12 @@ def cross_compile_hlsl(shader, spirv, opt, force_no_external_validation): spirv_path = create_temporary() hlsl_path = create_temporary(os.path.basename(shader)) + spirv_cmd = ['spirv-as', '-o', spirv_path, shader] + if '.preserve.' in shader: + spirv_cmd.append('--preserve-numeric-ids') + if spirv: - subprocess.check_call(['spirv-as', '-o', spirv_path, shader]) + subprocess.check_call(spirv_cmd) else: subprocess.check_call(['glslangValidator', '--target-env', 'vulkan1.1', '-V', '-o', spirv_path, shader]) @@ -255,8 +263,12 @@ def cross_compile_reflect(shader, spirv, opt): spirv_path = create_temporary() reflect_path = create_temporary(os.path.basename(shader)) + spirv_cmd = ['spirv-as', '-o', spirv_path, shader] + if '.preserve.' in shader: + spirv_cmd.append('--preserve-numeric-ids') + if spirv: - subprocess.check_call(['spirv-as', '-o', spirv_path, shader]) + subprocess.check_call(spirv_cmd) else: subprocess.check_call(['glslangValidator', '--target-env', 'vulkan1.1', '-V', '-o', spirv_path, shader]) @@ -282,8 +294,12 @@ def cross_compile(shader, vulkan, spirv, invalid_spirv, eliminate, is_legacy, fl if vulkan or spirv: vulkan_glsl_path = create_temporary('vk' + os.path.basename(shader)) + spirv_cmd = ['spirv-as', '-o', spirv_path, shader] + if '.preserve.' in shader: + spirv_cmd.append('--preserve-numeric-ids') + if spirv: - subprocess.check_call(['spirv-as', '-o', spirv_path, shader]) + subprocess.check_call(spirv_cmd) else: subprocess.check_call(['glslangValidator', '--target-env', 'vulkan1.1', '-V', '-o', spirv_path, shader])