Merge branch 'master' of github.com:KhronosGroup/SPIRV-Cross into fix
This commit is contained in:
Коммит
3804292c43
|
@ -10,7 +10,7 @@ dist: trusty
|
|||
|
||||
# We check out glslang at a specific revision to avoid test output mismatches
|
||||
env:
|
||||
- GLSLANG_REV=e4e8f7b7a31a751be285b64741465b769f5f146f
|
||||
- GLSLANG_REV=19ea56899cdcab0f480d257fcea100ad2160e833
|
||||
|
||||
before_script:
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install python3; fi
|
||||
|
@ -25,5 +25,5 @@ script:
|
|||
- make -j2
|
||||
- PATH=./glslang/StandAlone:./SPIRV-Tools/tools:$PATH
|
||||
- ./test_shaders.py shaders
|
||||
- ./test_shaders.py --metal shaders-msl
|
||||
- ./test_shaders.py --msl shaders-msl
|
||||
- ./test_shaders.py --hlsl shaders-hlsl
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
#version 450
|
||||
|
||||
layout(rgba32f) uniform writeonly imageBuffer RWTex;
|
||||
uniform samplerBuffer Tex;
|
||||
|
||||
layout(location = 0) out vec4 _entryPointOutput;
|
||||
|
||||
vec4 _main()
|
||||
{
|
||||
vec4 storeTemp = vec4(1.0, 2.0, 3.0, 4.0);
|
||||
imageStore(RWTex, 20, storeTemp);
|
||||
return texelFetch(Tex, 10);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 _28 = _main();
|
||||
_entryPointOutput = _28;
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
#version 450
|
||||
|
||||
struct VSInput
|
||||
{
|
||||
vec4 position;
|
||||
};
|
||||
|
||||
struct VSOutput
|
||||
{
|
||||
vec4 position;
|
||||
};
|
||||
|
||||
layout(location = 0) in vec4 position;
|
||||
|
||||
VSOutput _main(VSInput _input)
|
||||
{
|
||||
VSOutput _out;
|
||||
_out.position = _input.position;
|
||||
return _out;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
VSInput _input;
|
||||
_input.position = position;
|
||||
VSInput param = _input;
|
||||
gl_Position = _main(param).position;
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
#version 310 es
|
||||
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
|
||||
|
||||
void main()
|
||||
{
|
||||
int signed_value = 0;
|
||||
uint unsigned_value = 0u;
|
||||
int s = bitfieldExtract(signed_value, 5, 20);
|
||||
uint u = bitfieldExtract(unsigned_value, 6, 21);
|
||||
s = bitfieldInsert(s, 40, 5, 4);
|
||||
u = bitfieldInsert(u, 60u, 5, 4);
|
||||
u = bitfieldReverse(u);
|
||||
s = bitfieldReverse(s);
|
||||
int v0 = bitCount(u);
|
||||
int v1 = bitCount(s);
|
||||
int v2 = findMSB(u);
|
||||
int v3 = findLSB(s);
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
#version 310 es
|
||||
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
|
||||
|
||||
void out_test_0(int cond, out int i)
|
||||
{
|
||||
if (cond == 0)
|
||||
{
|
||||
i = 40;
|
||||
}
|
||||
else
|
||||
{
|
||||
i = 60;
|
||||
}
|
||||
}
|
||||
|
||||
void out_test_1(int cond, out int i)
|
||||
{
|
||||
switch (cond)
|
||||
{
|
||||
case 40:
|
||||
{
|
||||
i = 40;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
i = 70;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void inout_test_0(int cond, inout int i)
|
||||
{
|
||||
if (cond == 0)
|
||||
{
|
||||
i = 40;
|
||||
}
|
||||
}
|
||||
|
||||
void inout_test_1(int cond, inout int i)
|
||||
{
|
||||
switch (cond)
|
||||
{
|
||||
case 40:
|
||||
{
|
||||
i = 40;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
int cond = 40;
|
||||
int i = 50;
|
||||
int param = cond;
|
||||
int param_1 = i;
|
||||
out_test_0(param, param_1);
|
||||
i = param_1;
|
||||
int param_2 = cond;
|
||||
int param_3 = i;
|
||||
out_test_1(param_2, param_3);
|
||||
i = param_3;
|
||||
int param_4 = cond;
|
||||
int param_5 = i;
|
||||
inout_test_0(param_4, param_5);
|
||||
i = param_5;
|
||||
int param_6 = cond;
|
||||
int param_7 = i;
|
||||
inout_test_1(param_6, param_7);
|
||||
i = param_7;
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
; SPIR-V
|
||||
; Version: 1.0
|
||||
; Generator: Khronos Glslang Reference Front End; 1
|
||||
; Bound: 36
|
||||
; Schema: 0
|
||||
OpCapability Shader
|
||||
OpCapability SampledBuffer
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main" %_entryPointOutput
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpName %main "main"
|
||||
OpName %_main_ "@main("
|
||||
OpName %storeTemp "storeTemp"
|
||||
OpName %RWTex "RWTex"
|
||||
OpName %Tex "Tex"
|
||||
OpName %_entryPointOutput "@entryPointOutput"
|
||||
OpDecorate %RWTex DescriptorSet 0
|
||||
OpDecorate %Tex DescriptorSet 0
|
||||
OpDecorate %_entryPointOutput Location 0
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%v4float = OpTypeVector %float 4
|
||||
%8 = OpTypeFunction %v4float
|
||||
%_ptr_Function_v4float = OpTypePointer Function %v4float
|
||||
%13 = OpConstant %float 1
|
||||
%14 = OpConstant %float 2
|
||||
%15 = OpConstant %float 3
|
||||
%16 = OpConstant %float 4
|
||||
%17 = OpConstantComposite %v4float %13 %14 %15 %16
|
||||
%18 = OpTypeImage %float Buffer 0 0 0 2 Rgba32f
|
||||
%_ptr_UniformConstant_18 = OpTypePointer UniformConstant %18
|
||||
%RWTex = OpVariable %_ptr_UniformConstant_18 UniformConstant
|
||||
%int = OpTypeInt 32 1
|
||||
%23 = OpConstant %int 20
|
||||
%25 = OpTypeImage %float Buffer 0 0 0 1 Rgba32f
|
||||
%_ptr_UniformConstant_25 = OpTypePointer UniformConstant %25
|
||||
%Tex = OpVariable %_ptr_UniformConstant_25 UniformConstant
|
||||
%29 = OpConstant %int 10
|
||||
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
||||
%_entryPointOutput = OpVariable %_ptr_Output_v4float Output
|
||||
%main = OpFunction %void None %3
|
||||
%5 = OpLabel
|
||||
%35 = OpFunctionCall %v4float %_main_
|
||||
OpStore %_entryPointOutput %35
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%_main_ = OpFunction %v4float None %8
|
||||
%10 = OpLabel
|
||||
%storeTemp = OpVariable %_ptr_Function_v4float Function
|
||||
OpStore %storeTemp %17
|
||||
%21 = OpLoad %18 %RWTex
|
||||
%24 = OpLoad %v4float %storeTemp
|
||||
OpImageWrite %21 %23 %24
|
||||
%28 = OpLoad %25 %Tex
|
||||
%30 = OpImageFetch %v4float %28 %29
|
||||
OpReturnValue %30
|
||||
OpFunctionEnd
|
|
@ -0,0 +1,70 @@
|
|||
; SPIR-V
|
||||
; Version: 1.0
|
||||
; Generator: Khronos Glslang Reference Front End; 1
|
||||
; Bound: 40
|
||||
; Schema: 0
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Vertex %main "main" %position %_entryPointOutput_position %_entryPointOutput
|
||||
OpName %main "main"
|
||||
OpName %VSInput "VSInput"
|
||||
OpMemberName %VSInput 0 "position"
|
||||
OpName %VSOutput "VSOutput"
|
||||
OpMemberName %VSOutput 0 "position"
|
||||
OpName %_main_struct_VSInput_vf41_ "@main(struct-VSInput-vf41;"
|
||||
OpName %_input "_input"
|
||||
OpName %_out "_out"
|
||||
OpName %_input_0 "_input"
|
||||
OpName %position "position"
|
||||
OpName %_entryPointOutput_position "@entryPointOutput_position"
|
||||
OpName %param "param"
|
||||
OpName %VSOutput_0 "VSOutput"
|
||||
OpName %_entryPointOutput "@entryPointOutput"
|
||||
OpDecorate %position Location 0
|
||||
OpDecorate %_entryPointOutput_position BuiltIn Position
|
||||
OpDecorate %_entryPointOutput Location 0
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%v4float = OpTypeVector %float 4
|
||||
%VSInput = OpTypeStruct %v4float
|
||||
%_ptr_Function_VSInput = OpTypePointer Function %VSInput
|
||||
%VSOutput = OpTypeStruct %v4float
|
||||
%11 = OpTypeFunction %VSOutput %_ptr_Function_VSInput
|
||||
%_ptr_Function_VSOutput = OpTypePointer Function %VSOutput
|
||||
%int = OpTypeInt 32 1
|
||||
%18 = OpConstant %int 0
|
||||
%_ptr_Function_v4float = OpTypePointer Function %v4float
|
||||
%_ptr_Input_v4float = OpTypePointer Input %v4float
|
||||
%position = OpVariable %_ptr_Input_v4float Input
|
||||
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
||||
%_entryPointOutput_position = OpVariable %_ptr_Output_v4float Output
|
||||
%VSOutput_0 = OpTypeStruct
|
||||
%_ptr_Output_VSOutput_0 = OpTypePointer Output %VSOutput_0
|
||||
%_entryPointOutput = OpVariable %_ptr_Output_VSOutput_0 Output
|
||||
%main = OpFunction %void None %3
|
||||
%5 = OpLabel
|
||||
%_input_0 = OpVariable %_ptr_Function_VSInput Function
|
||||
%param = OpVariable %_ptr_Function_VSInput Function
|
||||
%29 = OpLoad %v4float %position
|
||||
%30 = OpAccessChain %_ptr_Function_v4float %_input_0 %18
|
||||
OpStore %30 %29
|
||||
%34 = OpLoad %VSInput %_input_0
|
||||
OpStore %param %34
|
||||
%35 = OpFunctionCall %VSOutput %_main_struct_VSInput_vf41_ %param
|
||||
%36 = OpCompositeExtract %v4float %35 0
|
||||
OpStore %_entryPointOutput_position %36
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%_main_struct_VSInput_vf41_ = OpFunction %VSOutput None %11
|
||||
%_input = OpFunctionParameter %_ptr_Function_VSInput
|
||||
%14 = OpLabel
|
||||
%_out = OpVariable %_ptr_Function_VSOutput Function
|
||||
%20 = OpAccessChain %_ptr_Function_v4float %_input %18
|
||||
%21 = OpLoad %v4float %20
|
||||
%22 = OpAccessChain %_ptr_Function_v4float %_out %18
|
||||
OpStore %22 %21
|
||||
%23 = OpLoad %VSOutput %_out
|
||||
OpReturnValue %23
|
||||
OpFunctionEnd
|
|
@ -0,0 +1,21 @@
|
|||
#version 310 es
|
||||
|
||||
void main()
|
||||
{
|
||||
int signed_value = 0;
|
||||
uint unsigned_value = 0u;
|
||||
|
||||
int s = bitfieldExtract(signed_value, 5, 20);
|
||||
uint u = bitfieldExtract(unsigned_value, 6, 21);
|
||||
s = bitfieldInsert(s, 40, 5, 4);
|
||||
u = bitfieldInsert(u, 60u, 5, 4);
|
||||
|
||||
u = bitfieldReverse(u);
|
||||
s = bitfieldReverse(s);
|
||||
|
||||
int v0 = bitCount(u);
|
||||
int v1 = bitCount(s);
|
||||
|
||||
int v2 = findMSB(u);
|
||||
int v3 = findLSB(s);
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
#version 310 es
|
||||
|
||||
// We write in all paths (and no reads), so should just be out.
|
||||
void out_test_0(int cond, inout int i)
|
||||
{
|
||||
if (cond == 0)
|
||||
i = 40;
|
||||
else
|
||||
i = 60;
|
||||
}
|
||||
|
||||
// We write in all paths (and no reads), so should just be out.
|
||||
void out_test_1(int cond, inout int i)
|
||||
{
|
||||
switch (cond)
|
||||
{
|
||||
case 40:
|
||||
i = 40;
|
||||
break;
|
||||
|
||||
default:
|
||||
i = 70;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// We don't write in all paths, so should be inout.
|
||||
void inout_test_0(int cond, inout int i)
|
||||
{
|
||||
if (cond == 0)
|
||||
i = 40;
|
||||
}
|
||||
|
||||
void inout_test_1(int cond, inout int i)
|
||||
{
|
||||
switch (cond)
|
||||
{
|
||||
case 40:
|
||||
i = 40;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void main()
|
||||
{
|
||||
int cond = 40;
|
||||
int i = 50;
|
||||
|
||||
out_test_0(cond, i);
|
||||
out_test_1(cond, i);
|
||||
inout_test_0(cond, i);
|
||||
inout_test_1(cond, i);
|
||||
}
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
|
||||
#include "spirv_cfg.hpp"
|
||||
#include "spirv_cross.hpp"
|
||||
#include <algorithm>
|
||||
#include <assert.h>
|
||||
|
||||
|
|
|
@ -17,11 +17,12 @@
|
|||
#ifndef SPIRV_CROSS_CFG_HPP
|
||||
#define SPIRV_CROSS_CFG_HPP
|
||||
|
||||
#include "spirv_cross.hpp"
|
||||
#include "spirv_common.hpp"
|
||||
#include <assert.h>
|
||||
|
||||
namespace spirv_cross
|
||||
{
|
||||
class Compiler;
|
||||
class CFG
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -17,11 +17,21 @@
|
|||
#ifndef SPIRV_CROSS_COMMON_HPP
|
||||
#define SPIRV_CROSS_COMMON_HPP
|
||||
|
||||
#include "spirv.hpp"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <locale>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <stack>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace spirv_cross
|
||||
{
|
||||
|
|
|
@ -70,6 +70,12 @@ Compiler::Compiler(vector<uint32_t> ir)
|
|||
parse();
|
||||
}
|
||||
|
||||
Compiler::Compiler(const uint32_t *ir, size_t word_count)
|
||||
: spirv(ir, ir + word_count)
|
||||
{
|
||||
parse();
|
||||
}
|
||||
|
||||
string Compiler::compile()
|
||||
{
|
||||
// Force a classic "C" locale, reverts when function returns
|
||||
|
@ -1405,7 +1411,6 @@ void Compiler::parse(const Instruction &instruction)
|
|||
break;
|
||||
}
|
||||
|
||||
// Not really used.
|
||||
case OpTypeSampler:
|
||||
{
|
||||
uint32_t id = ops[0];
|
||||
|
@ -2802,6 +2807,71 @@ const SPIRConstant &Compiler::get_constant(uint32_t id) const
|
|||
return get<SPIRConstant>(id);
|
||||
}
|
||||
|
||||
static bool exists_unaccessed_path_to_return(const CFG &cfg, uint32_t block, const unordered_set<uint32_t> &blocks)
|
||||
{
|
||||
// This block accesses the variable.
|
||||
if (blocks.find(block) != end(blocks))
|
||||
return false;
|
||||
|
||||
// We are at the end of the CFG.
|
||||
if (cfg.get_succeeding_edges(block).empty())
|
||||
return true;
|
||||
|
||||
// If any of our successors have a path to the end, there exists a path from block.
|
||||
for (auto &succ : cfg.get_succeeding_edges(block))
|
||||
if (exists_unaccessed_path_to_return(cfg, succ, blocks))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Compiler::analyze_parameter_preservation(
|
||||
SPIRFunction &entry, const CFG &cfg, const unordered_map<uint32_t, unordered_set<uint32_t>> &variable_to_blocks)
|
||||
{
|
||||
for (auto &arg : entry.arguments)
|
||||
{
|
||||
// Non-pointers are always inputs.
|
||||
auto &type = get<SPIRType>(arg.type);
|
||||
if (!type.pointer)
|
||||
continue;
|
||||
|
||||
// Opaque argument types are always in
|
||||
bool potential_preserve;
|
||||
switch (type.basetype)
|
||||
{
|
||||
case SPIRType::Sampler:
|
||||
case SPIRType::Image:
|
||||
case SPIRType::SampledImage:
|
||||
case SPIRType::AtomicCounter:
|
||||
potential_preserve = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
potential_preserve = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!potential_preserve)
|
||||
continue;
|
||||
|
||||
auto itr = variable_to_blocks.find(arg.id);
|
||||
if (itr == end(variable_to_blocks))
|
||||
{
|
||||
// Variable is never accessed.
|
||||
continue;
|
||||
}
|
||||
|
||||
// If there is a path through the CFG where no block writes to the variable, the variable will be in an undefined state
|
||||
// when the function returns. We therefore need to implicitly preserve the variable in case there are writers in the function.
|
||||
// Major case here is if a function is
|
||||
// void foo(int &var) { if (cond) var = 10; }
|
||||
// Using read/write counts, we will think it's just an out variable, but it really needs to be inout,
|
||||
// because if we don't write anything whatever we put into the function must return back to the caller.
|
||||
if (exists_unaccessed_path_to_return(cfg, entry.entry_block, itr->second))
|
||||
arg.read_count++;
|
||||
}
|
||||
}
|
||||
|
||||
void Compiler::analyze_variable_scope(SPIRFunction &entry)
|
||||
{
|
||||
struct AccessHandler : OpcodeHandler
|
||||
|
@ -2971,6 +3041,9 @@ void Compiler::analyze_variable_scope(SPIRFunction &entry)
|
|||
// Compute the control flow graph for this function.
|
||||
CFG cfg(*this, entry);
|
||||
|
||||
// Analyze if there are parameters which need to be implicitly preserved with an "in" qualifier.
|
||||
analyze_parameter_preservation(entry, cfg, handler.accessed_variables_to_block);
|
||||
|
||||
unordered_map<uint32_t, uint32_t> potential_loop_variables;
|
||||
|
||||
// For each variable which is statically accessed.
|
||||
|
|
|
@ -18,19 +18,11 @@
|
|||
#define SPIRV_CROSS_HPP
|
||||
|
||||
#include "spirv.hpp"
|
||||
#include <memory>
|
||||
#include <stack>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "spirv_common.hpp"
|
||||
|
||||
namespace spirv_cross
|
||||
{
|
||||
class CFG;
|
||||
struct Resource
|
||||
{
|
||||
// Resources are identified with their SPIR-V ID.
|
||||
|
@ -114,6 +106,7 @@ public:
|
|||
|
||||
// The constructor takes a buffer of SPIR-V words and parses it.
|
||||
Compiler(std::vector<uint32_t> ir);
|
||||
Compiler(const uint32_t *ir, size_t word_count);
|
||||
|
||||
virtual ~Compiler() = default;
|
||||
|
||||
|
@ -614,6 +607,10 @@ protected:
|
|||
uint64_t active_output_builtins = 0;
|
||||
// Traverses all reachable opcodes and sets active_builtins to a bitmask of all builtin variables which are accessed in the shader.
|
||||
void update_active_builtins();
|
||||
|
||||
void analyze_parameter_preservation(
|
||||
SPIRFunction &entry, const CFG &cfg,
|
||||
const std::unordered_map<uint32_t, std::unordered_set<uint32_t>> &variable_to_blocks);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -483,6 +483,11 @@ void CompilerGLSL::emit_header()
|
|||
statement("");
|
||||
}
|
||||
|
||||
bool CompilerGLSL::type_is_empty(const SPIRType &type)
|
||||
{
|
||||
return type.basetype == SPIRType::Struct && type.member_types.empty();
|
||||
}
|
||||
|
||||
void CompilerGLSL::emit_struct(SPIRType &type)
|
||||
{
|
||||
// Struct types can be stamped out multiple times
|
||||
|
@ -492,6 +497,12 @@ void CompilerGLSL::emit_struct(SPIRType &type)
|
|||
if (type.type_alias != 0)
|
||||
return;
|
||||
|
||||
// Don't declare empty structs in GLSL, this is not allowed.
|
||||
// Empty structs is a corner case of HLSL output, and only sensible thing to do is avoiding to declare
|
||||
// these types.
|
||||
if (type_is_empty(type))
|
||||
return;
|
||||
|
||||
add_resource_name(type.self);
|
||||
auto name = type_to_glsl(type);
|
||||
|
||||
|
@ -985,7 +996,8 @@ string CompilerGLSL::layout_for_variable(const SPIRVariable &var)
|
|||
attr.push_back(ssbo_is_std430_packing(type) ? "std430" : "std140");
|
||||
|
||||
// For images, the type itself adds a layout qualifer.
|
||||
if (type.basetype == SPIRType::Image)
|
||||
// Only emit the format for storage images.
|
||||
if (type.basetype == SPIRType::Image && type.image.sampled == 2)
|
||||
{
|
||||
const char *fmt = format_to_glsl(type.image.format);
|
||||
if (fmt)
|
||||
|
@ -1586,9 +1598,11 @@ void CompilerGLSL::emit_resources()
|
|||
// If we're remapping separate samplers and images, only emit the combined samplers.
|
||||
if (skip_separate_image_sampler)
|
||||
{
|
||||
// Sampler buffers are always used without a sampler, and they will also work in regular GL.
|
||||
bool sampler_buffer = type.basetype == SPIRType::Image && type.image.dim == DimBuffer;
|
||||
bool separate_image = type.basetype == SPIRType::Image && type.image.sampled == 1;
|
||||
bool separate_sampler = type.basetype == SPIRType::Sampler;
|
||||
if (separate_image || separate_sampler)
|
||||
if (!sampler_buffer && (separate_image || separate_sampler))
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1614,6 +1628,11 @@ void CompilerGLSL::emit_resources()
|
|||
auto &var = id.get<SPIRVariable>();
|
||||
auto &type = get<SPIRType>(var.basetype);
|
||||
|
||||
// HLSL output from glslang may emit interface variables which are "empty".
|
||||
// Just avoid declaring them.
|
||||
if (type_is_empty(type))
|
||||
continue;
|
||||
|
||||
if (var.storage != StorageClassFunction && type.pointer &&
|
||||
(var.storage == StorageClassInput || var.storage == StorageClassOutput) &&
|
||||
interface_variable_exists_in_entry_point(var.self) && !is_hidden_variable(var))
|
||||
|
@ -5087,12 +5106,14 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
|||
|
||||
// Bitfield
|
||||
case OpBitFieldInsert:
|
||||
// TODO: The signedness of inputs is strict in GLSL, but not in SPIR-V, bitcast if necessary.
|
||||
QFOP(bitfieldInsert);
|
||||
break;
|
||||
|
||||
case OpBitFieldSExtract:
|
||||
case OpBitFieldUExtract:
|
||||
QFOP(bitfieldExtract);
|
||||
// TODO: The signedness of inputs is strict in GLSL, but not in SPIR-V, bitcast if necessary.
|
||||
TFOP(bitfieldExtract);
|
||||
break;
|
||||
|
||||
case OpBitReverse:
|
||||
|
@ -5900,7 +5921,13 @@ string CompilerGLSL::image_type_glsl(const SPIRType &type)
|
|||
// If we're emulating subpassInput with samplers, force sampler2D
|
||||
// so we don't have to specify format.
|
||||
if (type.basetype == SPIRType::Image && type.image.dim != DimSubpassData)
|
||||
res += type.image.sampled == 2 ? "image" : "texture";
|
||||
{
|
||||
// Sampler buffers are always declared as samplerBuffer even though they might be separate images in the SPIR-V.
|
||||
if (type.image.dim == DimBuffer && type.image.sampled == 1)
|
||||
res += "sampler";
|
||||
else
|
||||
res += type.image.sampled == 2 ? "image" : "texture";
|
||||
}
|
||||
else
|
||||
res += "sampler";
|
||||
|
||||
|
@ -5974,7 +6001,6 @@ string CompilerGLSL::type_to_glsl(const SPIRType &type)
|
|||
return image_type_glsl(type);
|
||||
|
||||
case SPIRType::Sampler:
|
||||
// Not really used.
|
||||
return "sampler";
|
||||
|
||||
case SPIRType::Void:
|
||||
|
|
|
@ -444,6 +444,8 @@ protected:
|
|||
std::string emit_for_loop_initializers(const SPIRBlock &block);
|
||||
bool optimize_read_modify_write(const std::string &lhs, const std::string &rhs);
|
||||
void fixup_image_load_store_access();
|
||||
|
||||
bool type_is_empty(const SPIRType &type);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -61,7 +61,6 @@ string CompilerHLSL::type_to_glsl(const SPIRType &type)
|
|||
return image_type_glsl(type);
|
||||
|
||||
case SPIRType::Sampler:
|
||||
// Not really used.
|
||||
return "sampler";
|
||||
|
||||
case SPIRType::Void:
|
||||
|
@ -1404,7 +1403,7 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction)
|
|||
if (expression_type(ops[2]).vecsize > 1)
|
||||
emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "==");
|
||||
else
|
||||
BOP_CAST(== , SPIRType::Int);
|
||||
BOP_CAST(==, SPIRType::Int);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1417,7 +1416,7 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction)
|
|||
if (expression_type(ops[2]).vecsize > 1)
|
||||
emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "==");
|
||||
else
|
||||
BOP(== );
|
||||
BOP(==);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1429,7 +1428,7 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction)
|
|||
if (expression_type(ops[2]).vecsize > 1)
|
||||
emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "!=");
|
||||
else
|
||||
BOP_CAST(!= , SPIRType::Int);
|
||||
BOP_CAST(!=, SPIRType::Int);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1442,7 +1441,7 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction)
|
|||
if (expression_type(ops[2]).vecsize > 1)
|
||||
emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "!=");
|
||||
else
|
||||
BOP(!= );
|
||||
BOP(!=);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1482,7 +1481,7 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction)
|
|||
if (expression_type(ops[2]).vecsize > 1)
|
||||
emit_unrolled_binary_op(result_type, id, ops[2], ops[3], ">=");
|
||||
else
|
||||
BOP_CAST(>= , type);
|
||||
BOP_CAST(>=, type);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1494,7 +1493,7 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction)
|
|||
if (expression_type(ops[2]).vecsize > 1)
|
||||
emit_unrolled_binary_op(result_type, id, ops[2], ops[3], ">=");
|
||||
else
|
||||
BOP(>= );
|
||||
BOP(>=);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1534,7 +1533,7 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction)
|
|||
if (expression_type(ops[2]).vecsize > 1)
|
||||
emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "<=");
|
||||
else
|
||||
BOP_CAST(<= , type);
|
||||
BOP_CAST(<=, type);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1546,7 +1545,7 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction)
|
|||
if (expression_type(ops[2]).vecsize > 1)
|
||||
emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "<=");
|
||||
else
|
||||
BOP(<= );
|
||||
BOP(<=);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -1851,7 +1851,6 @@ string CompilerMSL::type_to_glsl(const SPIRType &type)
|
|||
return image_type_glsl(type);
|
||||
|
||||
case SPIRType::Sampler:
|
||||
// Not really used.
|
||||
return "sampler";
|
||||
|
||||
case SPIRType::Void:
|
||||
|
|
Загрузка…
Ссылка в новой задаче