Updated spirv-cross.
This commit is contained in:
parent
3d390308dc
commit
709d33f2c5
701
3rdparty/spirv-cross/spirv_glsl.cpp
vendored
701
3rdparty/spirv-cross/spirv_glsl.cpp
vendored
@ -636,6 +636,17 @@ void CompilerGLSL::find_static_extensions()
|
||||
barycentric_is_nv = true;
|
||||
}
|
||||
|
||||
void CompilerGLSL::require_polyfill(Polyfill polyfill, bool relaxed)
|
||||
{
|
||||
uint32_t &polyfills = (relaxed && options.es) ? required_polyfills_relaxed : required_polyfills;
|
||||
|
||||
if ((polyfills & polyfill) == 0)
|
||||
{
|
||||
polyfills |= polyfill;
|
||||
force_recompile();
|
||||
}
|
||||
}
|
||||
|
||||
void CompilerGLSL::ray_tracing_khr_fixup_locations()
|
||||
{
|
||||
uint32_t location = 0;
|
||||
@ -701,6 +712,11 @@ string CompilerGLSL::compile()
|
||||
emit_resources();
|
||||
emit_extension_workarounds(get_execution_model());
|
||||
|
||||
if (required_polyfills != 0)
|
||||
emit_polyfills(required_polyfills, false);
|
||||
if (options.es && required_polyfills_relaxed != 0)
|
||||
emit_polyfills(required_polyfills_relaxed, true);
|
||||
|
||||
emit_function(get<SPIRFunction>(ir.default_entry_point), Bitset());
|
||||
|
||||
pass_count++;
|
||||
@ -1249,14 +1265,33 @@ string CompilerGLSL::to_interpolation_qualifiers(const Bitset &flags)
|
||||
if (flags.get(DecorationFlat))
|
||||
res += "flat ";
|
||||
if (flags.get(DecorationNoPerspective))
|
||||
{
|
||||
if (options.es)
|
||||
{
|
||||
if (options.version < 300)
|
||||
SPIRV_CROSS_THROW("noperspective requires ESSL 300.");
|
||||
require_extension_internal("GL_NV_shader_noperspective_interpolation");
|
||||
}
|
||||
else if (is_legacy_desktop())
|
||||
require_extension_internal("GL_EXT_gpu_shader4");
|
||||
res += "noperspective ";
|
||||
}
|
||||
if (flags.get(DecorationCentroid))
|
||||
res += "centroid ";
|
||||
if (flags.get(DecorationPatch))
|
||||
res += "patch ";
|
||||
if (flags.get(DecorationSample))
|
||||
{
|
||||
if (options.es)
|
||||
{
|
||||
if (options.version < 300)
|
||||
SPIRV_CROSS_THROW("sample requires ESSL 300.");
|
||||
else if (options.version < 320)
|
||||
require_extension_internal("GL_OES_shader_multisample_interpolation");
|
||||
}
|
||||
res += "sample ";
|
||||
if (flags.get(DecorationInvariant))
|
||||
}
|
||||
if (flags.get(DecorationInvariant) && (options.es || options.version >= 120))
|
||||
res += "invariant ";
|
||||
if (flags.get(DecorationPerPrimitiveEXT))
|
||||
res += "perprimitiveEXT ";
|
||||
@ -1529,7 +1564,7 @@ uint32_t CompilerGLSL::type_to_packed_alignment(const SPIRType &type, const Bits
|
||||
|
||||
// In std140, struct alignment is rounded up to 16.
|
||||
if (packing_is_vec4_padded(packing))
|
||||
alignment = max(alignment, 16u);
|
||||
alignment = max<uint32_t>(alignment, 16u);
|
||||
|
||||
return alignment;
|
||||
}
|
||||
@ -1757,7 +1792,7 @@ bool CompilerGLSL::buffer_is_packing_standard(const SPIRType &type, BufferPackin
|
||||
uint32_t begin_word = offset / 16;
|
||||
uint32_t end_word = (offset + packed_size - 1) / 16;
|
||||
if (begin_word != end_word)
|
||||
packed_alignment = max(packed_alignment, 16u);
|
||||
packed_alignment = max<uint32_t>(packed_alignment, 16u);
|
||||
}
|
||||
|
||||
uint32_t actual_offset = type_struct_member_offset(type, i);
|
||||
@ -2713,30 +2748,26 @@ void CompilerGLSL::emit_interface_block(const SPIRVariable &var)
|
||||
{
|
||||
add_resource_name(var.self);
|
||||
|
||||
// Tessellation control and evaluation shaders must have either gl_MaxPatchVertices or unsized arrays for input arrays.
|
||||
// Legacy GLSL did not support int attributes, we automatically
|
||||
// declare them as float and cast them on load/store
|
||||
SPIRType newtype = type;
|
||||
if (is_legacy() && var.storage == StorageClassInput && type.basetype == SPIRType::Int)
|
||||
newtype.basetype = SPIRType::Float;
|
||||
|
||||
// Tessellation control and evaluation shaders must have either
|
||||
// gl_MaxPatchVertices or unsized arrays for input arrays.
|
||||
// Opt for unsized as it's the more "correct" variant to use.
|
||||
bool control_point_input_array = type.storage == StorageClassInput && !type.array.empty() &&
|
||||
!has_decoration(var.self, DecorationPatch) &&
|
||||
(get_entry_point().model == ExecutionModelTessellationControl ||
|
||||
get_entry_point().model == ExecutionModelTessellationEvaluation);
|
||||
|
||||
uint32_t old_array_size = 0;
|
||||
bool old_array_size_literal = true;
|
||||
|
||||
if (control_point_input_array)
|
||||
if (type.storage == StorageClassInput && !type.array.empty() &&
|
||||
!has_decoration(var.self, DecorationPatch) &&
|
||||
(get_entry_point().model == ExecutionModelTessellationControl ||
|
||||
get_entry_point().model == ExecutionModelTessellationEvaluation))
|
||||
{
|
||||
swap(type.array.back(), old_array_size);
|
||||
swap(type.array_size_literal.back(), old_array_size_literal);
|
||||
newtype.array.back() = 0;
|
||||
newtype.array_size_literal.back() = true;
|
||||
}
|
||||
|
||||
statement(layout_for_variable(var), to_qualifiers_glsl(var.self),
|
||||
variable_decl(type, to_name(var.self), var.self), ";");
|
||||
|
||||
if (control_point_input_array)
|
||||
{
|
||||
swap(type.array.back(), old_array_size);
|
||||
swap(type.array_size_literal.back(), old_array_size_literal);
|
||||
}
|
||||
variable_decl(newtype, to_name(var.self), var.self), ";");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3511,7 +3542,7 @@ void CompilerGLSL::emit_resources()
|
||||
statement("");
|
||||
}
|
||||
|
||||
if (position_invariant)
|
||||
if (position_invariant && (options.es || options.version >= 120))
|
||||
{
|
||||
statement("invariant gl_Position;");
|
||||
statement("");
|
||||
@ -4386,34 +4417,135 @@ void CompilerGLSL::emit_extension_workarounds(spv::ExecutionModel model)
|
||||
}
|
||||
statement("");
|
||||
}
|
||||
}
|
||||
|
||||
if (requires_transpose_2x2)
|
||||
void CompilerGLSL::emit_polyfills(uint32_t polyfills, bool relaxed)
|
||||
{
|
||||
const char *qual = "";
|
||||
const char *suffix = (options.es && relaxed) ? "MP" : "";
|
||||
if (options.es)
|
||||
qual = relaxed ? "mediump " : "highp ";
|
||||
|
||||
if (polyfills & PolyfillTranspose2x2)
|
||||
{
|
||||
statement("mat2 spvTranspose(mat2 m)");
|
||||
statement(qual, "mat2 spvTranspose", suffix, "(", qual, "mat2 m)");
|
||||
begin_scope();
|
||||
statement("return mat2(m[0][0], m[1][0], m[0][1], m[1][1]);");
|
||||
end_scope();
|
||||
statement("");
|
||||
}
|
||||
|
||||
if (requires_transpose_3x3)
|
||||
if (polyfills & PolyfillTranspose3x3)
|
||||
{
|
||||
statement("mat3 spvTranspose(mat3 m)");
|
||||
statement(qual, "mat3 spvTranspose", suffix, "(", qual, "mat3 m)");
|
||||
begin_scope();
|
||||
statement("return mat3(m[0][0], m[1][0], m[2][0], m[0][1], m[1][1], m[2][1], m[0][2], m[1][2], m[2][2]);");
|
||||
end_scope();
|
||||
statement("");
|
||||
}
|
||||
|
||||
if (requires_transpose_4x4)
|
||||
if (polyfills & PolyfillTranspose4x4)
|
||||
{
|
||||
statement("mat4 spvTranspose(mat4 m)");
|
||||
statement(qual, "mat4 spvTranspose", suffix, "(", qual, "mat4 m)");
|
||||
begin_scope();
|
||||
statement("return mat4(m[0][0], m[1][0], m[2][0], m[3][0], m[0][1], m[1][1], m[2][1], m[3][1], m[0][2], "
|
||||
"m[1][2], m[2][2], m[3][2], m[0][3], m[1][3], m[2][3], m[3][3]);");
|
||||
end_scope();
|
||||
statement("");
|
||||
}
|
||||
|
||||
if (polyfills & PolyfillDeterminant2x2)
|
||||
{
|
||||
statement(qual, "float spvDeterminant", suffix, "(", qual, "mat2 m)");
|
||||
begin_scope();
|
||||
statement("return m[0][0] * m[1][1] - m[0][1] * m[1][0];");
|
||||
end_scope();
|
||||
statement("");
|
||||
}
|
||||
|
||||
if (polyfills & PolyfillDeterminant3x3)
|
||||
{
|
||||
statement(qual, "float spvDeterminant", suffix, "(", qual, "mat3 m)");
|
||||
begin_scope();
|
||||
statement("return dot(m[0], vec3(m[1][1] * m[2][2] - m[1][2] * m[2][1], "
|
||||
"m[1][2] * m[2][0] - m[1][0] * m[2][2], "
|
||||
"m[1][0] * m[2][1] - m[1][1] * m[2][0]));");
|
||||
end_scope();
|
||||
statement("");
|
||||
}
|
||||
|
||||
if (polyfills & PolyfillDeterminant4x4)
|
||||
{
|
||||
statement(qual, "float spvDeterminant", suffix, "(", qual, "mat4 m)");
|
||||
begin_scope();
|
||||
statement("return dot(m[0], vec4("
|
||||
"m[2][1] * m[3][2] * m[1][3] - m[3][1] * m[2][2] * m[1][3] + m[3][1] * m[1][2] * m[2][3] - m[1][1] * m[3][2] * m[2][3] - m[2][1] * m[1][2] * m[3][3] + m[1][1] * m[2][2] * m[3][3], "
|
||||
"m[3][0] * m[2][2] * m[1][3] - m[2][0] * m[3][2] * m[1][3] - m[3][0] * m[1][2] * m[2][3] + m[1][0] * m[3][2] * m[2][3] + m[2][0] * m[1][2] * m[3][3] - m[1][0] * m[2][2] * m[3][3], "
|
||||
"m[2][0] * m[3][1] * m[1][3] - m[3][0] * m[2][1] * m[1][3] + m[3][0] * m[1][1] * m[2][3] - m[1][0] * m[3][1] * m[2][3] - m[2][0] * m[1][1] * m[3][3] + m[1][0] * m[2][1] * m[3][3], "
|
||||
"m[3][0] * m[2][1] * m[1][2] - m[2][0] * m[3][1] * m[1][2] - m[3][0] * m[1][1] * m[2][2] + m[1][0] * m[3][1] * m[2][2] + m[2][0] * m[1][1] * m[3][2] - m[1][0] * m[2][1] * m[3][2]));");
|
||||
end_scope();
|
||||
statement("");
|
||||
}
|
||||
|
||||
if (polyfills & PolyfillMatrixInverse2x2)
|
||||
{
|
||||
statement(qual, "mat2 spvInverse", suffix, "(", qual, "mat2 m)");
|
||||
begin_scope();
|
||||
statement("return mat2(m[1][1], -m[0][1], -m[1][0], m[0][0]) "
|
||||
"* (1.0 / (m[0][0] * m[1][1] - m[1][0] * m[0][1]));");
|
||||
end_scope();
|
||||
statement("");
|
||||
}
|
||||
|
||||
if (polyfills & PolyfillMatrixInverse3x3)
|
||||
{
|
||||
statement(qual, "mat3 spvInverse", suffix, "(", qual, "mat3 m)");
|
||||
begin_scope();
|
||||
statement(qual, "vec3 t = vec3(m[1][1] * m[2][2] - m[1][2] * m[2][1], m[1][2] * m[2][0] - m[1][0] * m[2][2], m[1][0] * m[2][1] - m[1][1] * m[2][0]);");
|
||||
statement("return mat3(t[0], "
|
||||
"m[0][2] * m[2][1] - m[0][1] * m[2][2], "
|
||||
"m[0][1] * m[1][2] - m[0][2] * m[1][1], "
|
||||
"t[1], "
|
||||
"m[0][0] * m[2][2] - m[0][2] * m[2][0], "
|
||||
"m[0][2] * m[1][0] - m[0][0] * m[1][2], "
|
||||
"t[2], "
|
||||
"m[0][1] * m[2][0] - m[0][0] * m[2][1], "
|
||||
"m[0][0] * m[1][1] - m[0][1] * m[1][0]) "
|
||||
"* (1.0 / dot(m[0], t));");
|
||||
end_scope();
|
||||
statement("");
|
||||
}
|
||||
|
||||
if (polyfills & PolyfillMatrixInverse4x4)
|
||||
{
|
||||
statement(qual, "mat4 spvInverse", suffix, "(", qual, "mat4 m)");
|
||||
begin_scope();
|
||||
statement(qual, "vec4 t = vec4("
|
||||
"m[2][1] * m[3][2] * m[1][3] - m[3][1] * m[2][2] * m[1][3] + m[3][1] * m[1][2] * m[2][3] - m[1][1] * m[3][2] * m[2][3] - m[2][1] * m[1][2] * m[3][3] + m[1][1] * m[2][2] * m[3][3], "
|
||||
"m[3][0] * m[2][2] * m[1][3] - m[2][0] * m[3][2] * m[1][3] - m[3][0] * m[1][2] * m[2][3] + m[1][0] * m[3][2] * m[2][3] + m[2][0] * m[1][2] * m[3][3] - m[1][0] * m[2][2] * m[3][3], "
|
||||
"m[2][0] * m[3][1] * m[1][3] - m[3][0] * m[2][1] * m[1][3] + m[3][0] * m[1][1] * m[2][3] - m[1][0] * m[3][1] * m[2][3] - m[2][0] * m[1][1] * m[3][3] + m[1][0] * m[2][1] * m[3][3], "
|
||||
"m[3][0] * m[2][1] * m[1][2] - m[2][0] * m[3][1] * m[1][2] - m[3][0] * m[1][1] * m[2][2] + m[1][0] * m[3][1] * m[2][2] + m[2][0] * m[1][1] * m[3][2] - m[1][0] * m[2][1] * m[3][2]);");
|
||||
statement("return mat4("
|
||||
"t[0], "
|
||||
"m[3][1] * m[2][2] * m[0][3] - m[2][1] * m[3][2] * m[0][3] - m[3][1] * m[0][2] * m[2][3] + m[0][1] * m[3][2] * m[2][3] + m[2][1] * m[0][2] * m[3][3] - m[0][1] * m[2][2] * m[3][3], "
|
||||
"m[1][1] * m[3][2] * m[0][3] - m[3][1] * m[1][2] * m[0][3] + m[3][1] * m[0][2] * m[1][3] - m[0][1] * m[3][2] * m[1][3] - m[1][1] * m[0][2] * m[3][3] + m[0][1] * m[1][2] * m[3][3], "
|
||||
"m[2][1] * m[1][2] * m[0][3] - m[1][1] * m[2][2] * m[0][3] - m[2][1] * m[0][2] * m[1][3] + m[0][1] * m[2][2] * m[1][3] + m[1][1] * m[0][2] * m[2][3] - m[0][1] * m[1][2] * m[2][3], "
|
||||
"t[1], "
|
||||
"m[2][0] * m[3][2] * m[0][3] - m[3][0] * m[2][2] * m[0][3] + m[3][0] * m[0][2] * m[2][3] - m[0][0] * m[3][2] * m[2][3] - m[2][0] * m[0][2] * m[3][3] + m[0][0] * m[2][2] * m[3][3], "
|
||||
"m[3][0] * m[1][2] * m[0][3] - m[1][0] * m[3][2] * m[0][3] - m[3][0] * m[0][2] * m[1][3] + m[0][0] * m[3][2] * m[1][3] + m[1][0] * m[0][2] * m[3][3] - m[0][0] * m[1][2] * m[3][3], "
|
||||
"m[1][0] * m[2][2] * m[0][3] - m[2][0] * m[1][2] * m[0][3] + m[2][0] * m[0][2] * m[1][3] - m[0][0] * m[2][2] * m[1][3] - m[1][0] * m[0][2] * m[2][3] + m[0][0] * m[1][2] * m[2][3], "
|
||||
"t[2], "
|
||||
"m[3][0] * m[2][1] * m[0][3] - m[2][0] * m[3][1] * m[0][3] - m[3][0] * m[0][1] * m[2][3] + m[0][0] * m[3][1] * m[2][3] + m[2][0] * m[0][1] * m[3][3] - m[0][0] * m[2][1] * m[3][3], "
|
||||
"m[1][0] * m[3][1] * m[0][3] - m[3][0] * m[1][1] * m[0][3] + m[3][0] * m[0][1] * m[1][3] - m[0][0] * m[3][1] * m[1][3] - m[1][0] * m[0][1] * m[3][3] + m[0][0] * m[1][1] * m[3][3], "
|
||||
"m[2][0] * m[1][1] * m[0][3] - m[1][0] * m[2][1] * m[0][3] - m[2][0] * m[0][1] * m[1][3] + m[0][0] * m[2][1] * m[1][3] + m[1][0] * m[0][1] * m[2][3] - m[0][0] * m[1][1] * m[2][3], "
|
||||
"t[3], "
|
||||
"m[2][0] * m[3][1] * m[0][2] - m[3][0] * m[2][1] * m[0][2] + m[3][0] * m[0][1] * m[2][2] - m[0][0] * m[3][1] * m[2][2] - m[2][0] * m[0][1] * m[3][2] + m[0][0] * m[2][1] * m[3][2], "
|
||||
"m[3][0] * m[1][1] * m[0][2] - m[1][0] * m[3][1] * m[0][2] - m[3][0] * m[0][1] * m[1][2] + m[0][0] * m[3][1] * m[1][2] + m[1][0] * m[0][1] * m[3][2] - m[0][0] * m[1][1] * m[3][2], "
|
||||
"m[1][0] * m[2][1] * m[0][2] - m[2][0] * m[1][1] * m[0][2] + m[2][0] * m[0][1] * m[1][2] - m[0][0] * m[2][1] * m[1][2] - m[1][0] * m[0][1] * m[2][2] + m[0][0] * m[1][1] * m[2][2]) "
|
||||
"* (1.0 / dot(m[0], t));");
|
||||
end_scope();
|
||||
statement("");
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a string representation of the ID, usable as a function arg.
|
||||
@ -4849,8 +4981,9 @@ string CompilerGLSL::to_expression(uint32_t id, bool register_expression_read)
|
||||
// when consuming an access chain expression.
|
||||
uint32_t physical_type_id = get_extended_decoration(id, SPIRVCrossDecorationPhysicalTypeID);
|
||||
bool is_packed = has_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked);
|
||||
bool relaxed = has_decoration(id, DecorationRelaxedPrecision);
|
||||
return convert_row_major_matrix(e.expression, get<SPIRType>(e.expression_type), physical_type_id,
|
||||
is_packed);
|
||||
is_packed, relaxed);
|
||||
}
|
||||
else if (flattened_structs.count(id))
|
||||
{
|
||||
@ -6691,6 +6824,9 @@ string CompilerGLSL::legacy_tex_op(const std::string &op, const SPIRType &imgtyp
|
||||
require_extension_internal("GL_EXT_shadow_samplers");
|
||||
else
|
||||
SPIRV_CROSS_THROW(join(op, " not allowed on depth samplers in legacy ES"));
|
||||
|
||||
if (imgtype.image.dim == spv::DimCube)
|
||||
return "shadowCubeNV";
|
||||
}
|
||||
|
||||
if (op == "textureSize")
|
||||
@ -7845,8 +7981,22 @@ void CompilerGLSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop,
|
||||
break;
|
||||
|
||||
case GLSLstd450Trunc:
|
||||
emit_unary_func_op(result_type, id, args[0], "trunc");
|
||||
if (!is_legacy())
|
||||
emit_unary_func_op(result_type, id, args[0], "trunc");
|
||||
else
|
||||
{
|
||||
// Implement by value-casting to int and back.
|
||||
bool forward = should_forward(args[0]);
|
||||
auto op0 = to_unpacked_expression(args[0]);
|
||||
auto &op0_type = expression_type(args[0]);
|
||||
auto via_type = op0_type;
|
||||
via_type.basetype = SPIRType::Int;
|
||||
auto expr = join(type_to_glsl(op0_type), "(", type_to_glsl(via_type), "(", op0, "))");
|
||||
emit_op(result_type, id, expr, forward);
|
||||
inherit_expression_dependencies(id, args[0]);
|
||||
}
|
||||
break;
|
||||
|
||||
case GLSLstd450SAbs:
|
||||
emit_unary_func_op_cast(result_type, id, args[0], "abs", int_type, int_type);
|
||||
break;
|
||||
@ -7888,18 +8038,47 @@ void CompilerGLSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop,
|
||||
else
|
||||
emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "fma");
|
||||
break;
|
||||
|
||||
case GLSLstd450Modf:
|
||||
register_call_out_argument(args[1]);
|
||||
forced_temporaries.insert(id);
|
||||
emit_binary_func_op(result_type, id, args[0], args[1], "modf");
|
||||
if (!is_legacy())
|
||||
{
|
||||
forced_temporaries.insert(id);
|
||||
emit_binary_func_op(result_type, id, args[0], args[1], "modf");
|
||||
}
|
||||
else
|
||||
{
|
||||
//NB. legacy GLSL doesn't have trunc() either, so we do a value cast
|
||||
auto &op1_type = expression_type(args[1]);
|
||||
auto via_type = op1_type;
|
||||
via_type.basetype = SPIRType::Int;
|
||||
statement(to_expression(args[1]), " = ",
|
||||
type_to_glsl(op1_type), "(", type_to_glsl(via_type),
|
||||
"(", to_expression(args[0]), "));");
|
||||
emit_binary_op(result_type, id, args[0], args[1], "-");
|
||||
}
|
||||
break;
|
||||
|
||||
case GLSLstd450ModfStruct:
|
||||
{
|
||||
auto &type = get<SPIRType>(result_type);
|
||||
emit_uninitialized_temporary_expression(result_type, id);
|
||||
statement(to_expression(id), ".", to_member_name(type, 0), " = ", "modf(", to_expression(args[0]), ", ",
|
||||
to_expression(id), ".", to_member_name(type, 1), ");");
|
||||
if (!is_legacy())
|
||||
{
|
||||
statement(to_expression(id), ".", to_member_name(type, 0), " = ", "modf(", to_expression(args[0]), ", ",
|
||||
to_expression(id), ".", to_member_name(type, 1), ");");
|
||||
}
|
||||
else
|
||||
{
|
||||
//NB. legacy GLSL doesn't have trunc() either, so we do a value cast
|
||||
auto &op0_type = expression_type(args[0]);
|
||||
auto via_type = op0_type;
|
||||
via_type.basetype = SPIRType::Int;
|
||||
statement(to_expression(id), ".", to_member_name(type, 1), " = ", type_to_glsl(op0_type),
|
||||
"(", type_to_glsl(via_type), "(", to_expression(args[0]), "));");
|
||||
statement(to_expression(id), ".", to_member_name(type, 0), " = ", to_enclosed_expression(args[0]), " - ",
|
||||
to_expression(id), ".", to_member_name(type, 1), ";");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -7960,22 +8139,77 @@ void CompilerGLSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop,
|
||||
emit_unary_func_op(result_type, id, args[0], "atan");
|
||||
break;
|
||||
case GLSLstd450Sinh:
|
||||
emit_unary_func_op(result_type, id, args[0], "sinh");
|
||||
if (!is_legacy())
|
||||
emit_unary_func_op(result_type, id, args[0], "sinh");
|
||||
else
|
||||
{
|
||||
bool forward = should_forward(args[0]);
|
||||
auto expr = join("(exp(", to_expression(args[0]), ") - exp(-", to_enclosed_expression(args[0]), ")) * 0.5");
|
||||
emit_op(result_type, id, expr, forward);
|
||||
inherit_expression_dependencies(id, args[0]);
|
||||
}
|
||||
break;
|
||||
case GLSLstd450Cosh:
|
||||
emit_unary_func_op(result_type, id, args[0], "cosh");
|
||||
if (!is_legacy())
|
||||
emit_unary_func_op(result_type, id, args[0], "cosh");
|
||||
else
|
||||
{
|
||||
bool forward = should_forward(args[0]);
|
||||
auto expr = join("(exp(", to_expression(args[0]), ") + exp(-", to_enclosed_expression(args[0]), ")) * 0.5");
|
||||
emit_op(result_type, id, expr, forward);
|
||||
inherit_expression_dependencies(id, args[0]);
|
||||
}
|
||||
break;
|
||||
case GLSLstd450Tanh:
|
||||
emit_unary_func_op(result_type, id, args[0], "tanh");
|
||||
if (!is_legacy())
|
||||
emit_unary_func_op(result_type, id, args[0], "tanh");
|
||||
else
|
||||
{
|
||||
// Create temporaries to store the result of exp(arg) and exp(-arg).
|
||||
uint32_t &ids = extra_sub_expressions[id];
|
||||
if (!ids)
|
||||
{
|
||||
ids = ir.increase_bound_by(2);
|
||||
|
||||
// Inherit precision qualifier (legacy has no NoContraction).
|
||||
if (has_decoration(id, DecorationRelaxedPrecision))
|
||||
{
|
||||
set_decoration(ids, DecorationRelaxedPrecision);
|
||||
set_decoration(ids + 1, DecorationRelaxedPrecision);
|
||||
}
|
||||
}
|
||||
uint32_t epos_id = ids;
|
||||
uint32_t eneg_id = ids + 1;
|
||||
|
||||
emit_op(result_type, epos_id, join("exp(", to_expression(args[0]), ")"), false);
|
||||
emit_op(result_type, eneg_id, join("exp(-", to_enclosed_expression(args[0]), ")"), false);
|
||||
inherit_expression_dependencies(epos_id, args[0]);
|
||||
inherit_expression_dependencies(eneg_id, args[0]);
|
||||
|
||||
auto expr = join("(", to_enclosed_expression(epos_id), " - ", to_enclosed_expression(eneg_id), ") / "
|
||||
"(", to_enclosed_expression(epos_id), " + ", to_enclosed_expression(eneg_id), ")");
|
||||
emit_op(result_type, id, expr, true);
|
||||
inherit_expression_dependencies(id, epos_id);
|
||||
inherit_expression_dependencies(id, eneg_id);
|
||||
}
|
||||
break;
|
||||
case GLSLstd450Asinh:
|
||||
emit_unary_func_op(result_type, id, args[0], "asinh");
|
||||
if (!is_legacy())
|
||||
emit_unary_func_op(result_type, id, args[0], "asinh");
|
||||
else
|
||||
emit_emulated_ahyper_op(result_type, id, args[0], GLSLstd450Asinh);
|
||||
break;
|
||||
case GLSLstd450Acosh:
|
||||
emit_unary_func_op(result_type, id, args[0], "acosh");
|
||||
if (!is_legacy())
|
||||
emit_unary_func_op(result_type, id, args[0], "acosh");
|
||||
else
|
||||
emit_emulated_ahyper_op(result_type, id, args[0], GLSLstd450Acosh);
|
||||
break;
|
||||
case GLSLstd450Atanh:
|
||||
emit_unary_func_op(result_type, id, args[0], "atanh");
|
||||
if (!is_legacy())
|
||||
emit_unary_func_op(result_type, id, args[0], "atanh");
|
||||
else
|
||||
emit_emulated_ahyper_op(result_type, id, args[0], GLSLstd450Atanh);
|
||||
break;
|
||||
case GLSLstd450Atan2:
|
||||
emit_binary_func_op(result_type, id, args[0], args[1], "atan");
|
||||
@ -8006,11 +8240,74 @@ void CompilerGLSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop,
|
||||
|
||||
// Matrix math
|
||||
case GLSLstd450Determinant:
|
||||
emit_unary_func_op(result_type, id, args[0], "determinant");
|
||||
{
|
||||
// No need to transpose - it doesn't affect the determinant
|
||||
auto *e = maybe_get<SPIRExpression>(args[0]);
|
||||
bool old_transpose = e && e->need_transpose;
|
||||
if (old_transpose)
|
||||
e->need_transpose = false;
|
||||
|
||||
if (options.version < 150) // also matches ES 100
|
||||
{
|
||||
auto &type = expression_type(args[0]);
|
||||
assert(type.vecsize >= 2 && type.vecsize <= 4);
|
||||
assert(type.vecsize == type.columns);
|
||||
|
||||
// ARB_gpu_shader_fp64 needs GLSL 150, other types are not valid
|
||||
if (type.basetype != SPIRType::Float)
|
||||
SPIRV_CROSS_THROW("Unsupported type for matrix determinant");
|
||||
|
||||
bool relaxed = has_decoration(id, DecorationRelaxedPrecision);
|
||||
require_polyfill(static_cast<Polyfill>(PolyfillDeterminant2x2 << (type.vecsize - 2)),
|
||||
relaxed);
|
||||
emit_unary_func_op(result_type, id, args[0],
|
||||
(options.es && relaxed) ? "spvDeterminantMP" : "spvDeterminant");
|
||||
}
|
||||
else
|
||||
emit_unary_func_op(result_type, id, args[0], "determinant");
|
||||
|
||||
if (old_transpose)
|
||||
e->need_transpose = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case GLSLstd450MatrixInverse:
|
||||
emit_unary_func_op(result_type, id, args[0], "inverse");
|
||||
{
|
||||
// The inverse of the transpose is the same as the transpose of
|
||||
// the inverse, so we can just flip need_transpose of the result.
|
||||
auto *a = maybe_get<SPIRExpression>(args[0]);
|
||||
bool old_transpose = a && a->need_transpose;
|
||||
if (old_transpose)
|
||||
a->need_transpose = false;
|
||||
|
||||
const char *func = "inverse";
|
||||
if (options.version < 140) // also matches ES 100
|
||||
{
|
||||
auto &type = get<SPIRType>(result_type);
|
||||
assert(type.vecsize >= 2 && type.vecsize <= 4);
|
||||
assert(type.vecsize == type.columns);
|
||||
|
||||
// ARB_gpu_shader_fp64 needs GLSL 150, other types are invalid
|
||||
if (type.basetype != SPIRType::Float)
|
||||
SPIRV_CROSS_THROW("Unsupported type for matrix inverse");
|
||||
|
||||
bool relaxed = has_decoration(id, DecorationRelaxedPrecision);
|
||||
require_polyfill(static_cast<Polyfill>(PolyfillMatrixInverse2x2 << (type.vecsize - 2)),
|
||||
relaxed);
|
||||
func = (options.es && relaxed) ? "spvInverseMP" : "spvInverse";
|
||||
}
|
||||
|
||||
bool forward = should_forward(args[0]);
|
||||
auto &e = emit_op(result_type, id, join(func, "(", to_unpacked_expression(args[0]), ")"), forward);
|
||||
inherit_expression_dependencies(id, args[0]);
|
||||
|
||||
if (old_transpose)
|
||||
{
|
||||
e.need_transpose = true;
|
||||
a->need_transpose = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Lerping
|
||||
case GLSLstd450FMix:
|
||||
@ -8203,13 +8500,60 @@ void CompilerGLSL::emit_nminmax_op(uint32_t result_type, uint32_t id, uint32_t o
|
||||
ir.meta[tmp_id] = ir.meta[id];
|
||||
ir.meta[mixed_first_id] = ir.meta[id];
|
||||
|
||||
emit_unary_func_op(btype_id, left_nan_id, op0, "isnan");
|
||||
emit_unary_func_op(btype_id, right_nan_id, op1, "isnan");
|
||||
if (!is_legacy())
|
||||
{
|
||||
emit_unary_func_op(btype_id, left_nan_id, op0, "isnan");
|
||||
emit_unary_func_op(btype_id, right_nan_id, op1, "isnan");
|
||||
}
|
||||
else if (expression_type(op0).vecsize > 1)
|
||||
{
|
||||
// If the number doesn't equal itself, it must be NaN
|
||||
emit_binary_func_op(btype_id, left_nan_id, op0, op0, "notEqual");
|
||||
emit_binary_func_op(btype_id, right_nan_id, op1, op1, "notEqual");
|
||||
}
|
||||
else
|
||||
{
|
||||
emit_binary_op(btype_id, left_nan_id, op0, op0, "!=");
|
||||
emit_binary_op(btype_id, right_nan_id, op1, op1, "!=");
|
||||
}
|
||||
emit_binary_func_op(result_type, tmp_id, op0, op1, op == GLSLstd450NMin ? "min" : "max");
|
||||
emit_mix_op(result_type, mixed_first_id, tmp_id, op1, left_nan_id);
|
||||
emit_mix_op(result_type, id, mixed_first_id, op0, right_nan_id);
|
||||
}
|
||||
|
||||
void CompilerGLSL::emit_emulated_ahyper_op(uint32_t result_type, uint32_t id, uint32_t op0, GLSLstd450 op)
|
||||
{
|
||||
const char *one = backend.float_literal_suffix ? "1.0f" : "1.0";
|
||||
std::string expr;
|
||||
bool forward = should_forward(op0);
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case GLSLstd450Asinh:
|
||||
expr = join("log(", to_enclosed_expression(op0), " + sqrt(",
|
||||
to_enclosed_expression(op0), " * ", to_enclosed_expression(op0), " + ", one, "))");
|
||||
emit_op(result_type, id, expr, forward);
|
||||
break;
|
||||
|
||||
case GLSLstd450Acosh:
|
||||
expr = join("log(", to_enclosed_expression(op0), " + sqrt(",
|
||||
to_enclosed_expression(op0), " * ", to_enclosed_expression(op0), " - ", one, "))");
|
||||
break;
|
||||
|
||||
case GLSLstd450Atanh:
|
||||
expr = join("log((", one, " + ", to_enclosed_expression(op0), ") / "
|
||||
"(", one, " - ", to_enclosed_expression(op0), ")) * 0.5",
|
||||
backend.float_literal_suffix ? "f" : "");
|
||||
break;
|
||||
|
||||
default:
|
||||
SPIRV_CROSS_THROW("Invalid op.");
|
||||
}
|
||||
|
||||
emit_op(result_type, id, expr, forward);
|
||||
inherit_expression_dependencies(id, op0);
|
||||
}
|
||||
|
||||
void CompilerGLSL::emit_spv_amd_shader_ballot_op(uint32_t result_type, uint32_t id, uint32_t eop, const uint32_t *args,
|
||||
uint32_t)
|
||||
{
|
||||
@ -8793,9 +9137,17 @@ string CompilerGLSL::builtin_to_glsl(BuiltIn builtin, StorageClass storage)
|
||||
case BuiltInPointSize:
|
||||
return "gl_PointSize";
|
||||
case BuiltInClipDistance:
|
||||
{
|
||||
if (options.es)
|
||||
require_extension_internal("GL_EXT_clip_cull_distance");
|
||||
return "gl_ClipDistance";
|
||||
}
|
||||
case BuiltInCullDistance:
|
||||
{
|
||||
if (options.es)
|
||||
require_extension_internal("GL_EXT_clip_cull_distance");
|
||||
return "gl_CullDistance";
|
||||
}
|
||||
case BuiltInVertexId:
|
||||
if (options.vulkan_semantics)
|
||||
SPIRV_CROSS_THROW("Cannot implement gl_VertexID in Vulkan GLSL. This shader was created "
|
||||
@ -8940,17 +9292,21 @@ string CompilerGLSL::builtin_to_glsl(BuiltIn builtin, StorageClass storage)
|
||||
return "gl_DrawIDARB";
|
||||
|
||||
case BuiltInSampleId:
|
||||
if (options.es && options.version < 320)
|
||||
if (is_legacy())
|
||||
SPIRV_CROSS_THROW("Sample variables not supported in legacy GLSL.");
|
||||
else if (options.es && options.version < 320)
|
||||
require_extension_internal("GL_OES_sample_variables");
|
||||
if (!options.es && options.version < 400)
|
||||
SPIRV_CROSS_THROW("gl_SampleID not supported before GLSL 400.");
|
||||
else if (!options.es && options.version < 400)
|
||||
require_extension_internal("GL_ARB_sample_shading");
|
||||
return "gl_SampleID";
|
||||
|
||||
case BuiltInSampleMask:
|
||||
if (options.es && options.version < 320)
|
||||
if (is_legacy())
|
||||
SPIRV_CROSS_THROW("Sample variables not supported in legacy GLSL.");
|
||||
else if (options.es && options.version < 320)
|
||||
require_extension_internal("GL_OES_sample_variables");
|
||||
if (!options.es && options.version < 400)
|
||||
SPIRV_CROSS_THROW("gl_SampleMask/gl_SampleMaskIn not supported before GLSL 400.");
|
||||
else if (!options.es && options.version < 400)
|
||||
require_extension_internal("GL_ARB_sample_shading");
|
||||
|
||||
if (storage == StorageClassInput)
|
||||
return "gl_SampleMaskIn";
|
||||
@ -8958,10 +9314,12 @@ string CompilerGLSL::builtin_to_glsl(BuiltIn builtin, StorageClass storage)
|
||||
return "gl_SampleMask";
|
||||
|
||||
case BuiltInSamplePosition:
|
||||
if (options.es && options.version < 320)
|
||||
if (is_legacy())
|
||||
SPIRV_CROSS_THROW("Sample variables not supported in legacy GLSL.");
|
||||
else if (options.es && options.version < 320)
|
||||
require_extension_internal("GL_OES_sample_variables");
|
||||
if (!options.es && options.version < 400)
|
||||
SPIRV_CROSS_THROW("gl_SamplePosition not supported before GLSL 400.");
|
||||
else if (!options.es && options.version < 400)
|
||||
require_extension_internal("GL_ARB_sample_shading");
|
||||
return "gl_SamplePosition";
|
||||
|
||||
case BuiltInViewIndex:
|
||||
@ -9777,10 +10135,13 @@ std::string CompilerGLSL::flattened_access_chain_struct(uint32_t base, const uin
|
||||
// The access chain terminates at the struct, so we need to find matrix strides and row-major information
|
||||
// ahead of time.
|
||||
bool need_transpose = false;
|
||||
bool relaxed = false;
|
||||
uint32_t matrix_stride = 0;
|
||||
if (member_type.columns > 1)
|
||||
{
|
||||
need_transpose = combined_decoration_for_member(target_type, i).get(DecorationRowMajor);
|
||||
auto decorations = combined_decoration_for_member(target_type, i);
|
||||
need_transpose = decorations.get(DecorationRowMajor);
|
||||
relaxed = decorations.get(DecorationRelaxedPrecision);
|
||||
matrix_stride = type_struct_member_matrix_stride(target_type, i);
|
||||
}
|
||||
|
||||
@ -9789,7 +10150,7 @@ std::string CompilerGLSL::flattened_access_chain_struct(uint32_t base, const uin
|
||||
|
||||
// Cannot forward transpositions, so resolve them here.
|
||||
if (need_transpose)
|
||||
expr += convert_row_major_matrix(tmp, member_type, 0, false);
|
||||
expr += convert_row_major_matrix(tmp, member_type, 0, false, relaxed);
|
||||
else
|
||||
expr += tmp;
|
||||
}
|
||||
@ -11809,11 +12170,57 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
||||
|
||||
// ALU
|
||||
case OpIsNan:
|
||||
GLSL_UFOP(isnan);
|
||||
if (!is_legacy())
|
||||
GLSL_UFOP(isnan);
|
||||
else
|
||||
{
|
||||
// Check if the number doesn't equal itself
|
||||
auto &type = get<SPIRType>(ops[0]);
|
||||
if (type.vecsize > 1)
|
||||
emit_binary_func_op(ops[0], ops[1], ops[2], ops[2], "notEqual");
|
||||
else
|
||||
emit_binary_op(ops[0], ops[1], ops[2], ops[2], "!=");
|
||||
}
|
||||
break;
|
||||
|
||||
case OpIsInf:
|
||||
GLSL_UFOP(isinf);
|
||||
if (!is_legacy())
|
||||
GLSL_UFOP(isinf);
|
||||
else
|
||||
{
|
||||
// inf * 2 == inf by IEEE 754 rules, note this also applies to 0.0
|
||||
// This is more reliable than checking if product with zero is NaN
|
||||
uint32_t result_type = ops[0];
|
||||
uint32_t result_id = ops[1];
|
||||
uint32_t operand = ops[2];
|
||||
|
||||
auto &type = get<SPIRType>(result_type);
|
||||
std::string expr;
|
||||
if (type.vecsize > 1)
|
||||
{
|
||||
expr = type_to_glsl_constructor(type);
|
||||
expr += '(';
|
||||
for (uint32_t i = 0; i < type.vecsize; i++)
|
||||
{
|
||||
auto comp = to_extract_component_expression(operand, i);
|
||||
expr += join(comp, " != 0.0 && 2.0 * ", comp, " == ", comp);
|
||||
|
||||
if (i + 1 < type.vecsize)
|
||||
expr += ", ";
|
||||
}
|
||||
expr += ')';
|
||||
}
|
||||
else
|
||||
{
|
||||
// Register an extra read to force writing out a temporary
|
||||
auto oper = to_enclosed_expression(operand);
|
||||
track_expression_read(operand);
|
||||
expr += join(oper, " != 0.0 && 2.0 * ", oper, " == ", oper);
|
||||
}
|
||||
emit_op(result_type, result_id, expr, should_forward(operand));
|
||||
|
||||
inherit_expression_dependencies(result_id, operand);
|
||||
}
|
||||
break;
|
||||
|
||||
case OpSNegate:
|
||||
@ -11912,14 +12319,59 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
||||
break;
|
||||
}
|
||||
|
||||
case OpFMul:
|
||||
case OpMatrixTimesScalar:
|
||||
{
|
||||
auto *a = maybe_get<SPIRExpression>(ops[2]);
|
||||
|
||||
// If the matrix need transpose, just mark the result as needing so.
|
||||
if (a && a->need_transpose)
|
||||
{
|
||||
a->need_transpose = false;
|
||||
auto expr = join(enclose_expression(to_unpacked_row_major_matrix_expression(ops[2])), " * ",
|
||||
to_enclosed_unpacked_expression(ops[3]));
|
||||
bool forward = should_forward(ops[2]) && should_forward(ops[3]);
|
||||
auto &e = emit_op(ops[0], ops[1], expr, forward);
|
||||
e.need_transpose = true;
|
||||
a->need_transpose = true;
|
||||
inherit_expression_dependencies(ops[1], ops[2]);
|
||||
inherit_expression_dependencies(ops[1], ops[3]);
|
||||
}
|
||||
else
|
||||
GLSL_BOP(*);
|
||||
break;
|
||||
}
|
||||
|
||||
case OpFMul:
|
||||
case OpVectorTimesScalar:
|
||||
GLSL_BOP(*);
|
||||
break;
|
||||
|
||||
case OpOuterProduct:
|
||||
GLSL_BFOP(outerProduct);
|
||||
if (options.version < 120) // Matches GLSL 1.10 / ESSL 1.00
|
||||
{
|
||||
uint32_t result_type = ops[0];
|
||||
uint32_t id = ops[1];
|
||||
uint32_t a = ops[2];
|
||||
uint32_t b = ops[3];
|
||||
|
||||
auto &type = get<SPIRType>(result_type);
|
||||
string expr = type_to_glsl_constructor(type);
|
||||
expr += "(";
|
||||
for (uint32_t col = 0; col < type.columns; col++)
|
||||
{
|
||||
expr += to_enclosed_expression(a);
|
||||
expr += " * ";
|
||||
expr += to_extract_component_expression(b, col);
|
||||
if (col + 1 < type.columns)
|
||||
expr += ", ";
|
||||
}
|
||||
expr += ")";
|
||||
emit_op(result_type, id, expr, should_forward(a) && should_forward(b));
|
||||
inherit_expression_dependencies(id, a);
|
||||
inherit_expression_dependencies(id, b);
|
||||
}
|
||||
else
|
||||
GLSL_BFOP(outerProduct);
|
||||
break;
|
||||
|
||||
case OpDot:
|
||||
@ -12087,10 +12539,6 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
||||
|
||||
case OpFRem:
|
||||
{
|
||||
if (is_legacy())
|
||||
SPIRV_CROSS_THROW("OpFRem requires trunc() and is only supported on non-legacy targets. A workaround is "
|
||||
"needed for legacy.");
|
||||
|
||||
uint32_t result_type = ops[0];
|
||||
uint32_t result_id = ops[1];
|
||||
uint32_t op0 = ops[2];
|
||||
@ -12098,8 +12546,22 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
||||
|
||||
// Needs special handling.
|
||||
bool forward = should_forward(op0) && should_forward(op1);
|
||||
auto expr = join(to_enclosed_expression(op0), " - ", to_enclosed_expression(op1), " * ", "trunc(",
|
||||
to_enclosed_expression(op0), " / ", to_enclosed_expression(op1), ")");
|
||||
std::string expr;
|
||||
if (!is_legacy())
|
||||
{
|
||||
expr = join(to_enclosed_expression(op0), " - ", to_enclosed_expression(op1), " * ", "trunc(",
|
||||
to_enclosed_expression(op0), " / ", to_enclosed_expression(op1), ")");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Legacy GLSL has no trunc, emulate by casting to int and back
|
||||
auto &op0_type = expression_type(op0);
|
||||
auto via_type = op0_type;
|
||||
via_type.basetype = SPIRType::Int;
|
||||
expr = join(to_enclosed_expression(op0), " - ", to_enclosed_expression(op1), " * ",
|
||||
type_to_glsl(op0_type), "(", type_to_glsl(via_type), "(",
|
||||
to_enclosed_expression(op0), " / ", to_enclosed_expression(op1), "))");
|
||||
}
|
||||
|
||||
emit_op(result_type, result_id, expr, forward);
|
||||
inherit_expression_dependencies(result_id, op0);
|
||||
@ -12753,7 +13215,12 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
||||
op = "textureQueryLOD";
|
||||
}
|
||||
else if (options.es)
|
||||
SPIRV_CROSS_THROW("textureQueryLod not supported in ES profile.");
|
||||
{
|
||||
if (options.version < 300)
|
||||
SPIRV_CROSS_THROW("textureQueryLod not supported in legacy ES");
|
||||
require_extension_internal("GL_EXT_texture_query_lod");
|
||||
op = "textureQueryLOD";
|
||||
}
|
||||
else
|
||||
op = "textureQueryLod";
|
||||
|
||||
@ -12799,6 +13266,11 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
||||
uint32_t result_type = ops[0];
|
||||
uint32_t id = ops[1];
|
||||
|
||||
if (options.es)
|
||||
SPIRV_CROSS_THROW("textureSamples and imageSamples not supported in ES profile.");
|
||||
else if (options.version < 450)
|
||||
require_extension_internal("GL_ARB_texture_query_samples");
|
||||
|
||||
string expr;
|
||||
if (type.image.sampled == 2)
|
||||
expr = join("imageSamples(", to_non_uniform_aware_expression(ops[2]), ")");
|
||||
@ -13841,6 +14313,42 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
||||
statement("SetMeshOutputsEXT(", to_unpacked_expression(ops[0]), ", ", to_unpacked_expression(ops[1]), ");");
|
||||
break;
|
||||
|
||||
case OpReadClockKHR:
|
||||
{
|
||||
auto &type = get<SPIRType>(ops[0]);
|
||||
auto scope = static_cast<Scope>(evaluate_constant_u32(ops[2]));
|
||||
const char *op = nullptr;
|
||||
// Forwarding clock statements leads to a scenario where an SSA value can take on different
|
||||
// values every time it's evaluated. Block any forwarding attempt.
|
||||
// We also might want to invalidate all expressions to function as a sort of optimization
|
||||
// barrier, but might be overkill for now.
|
||||
if (scope == ScopeDevice)
|
||||
{
|
||||
require_extension_internal("GL_EXT_shader_realtime_clock");
|
||||
if (type.basetype == SPIRType::BaseType::UInt64)
|
||||
op = "clockRealtimeEXT()";
|
||||
else if (type.basetype == SPIRType::BaseType::UInt && type.vecsize == 2)
|
||||
op = "clockRealtime2x32EXT()";
|
||||
else
|
||||
SPIRV_CROSS_THROW("Unsupported result type for OpReadClockKHR opcode.");
|
||||
}
|
||||
else if (scope == ScopeSubgroup)
|
||||
{
|
||||
require_extension_internal("GL_ARB_shader_clock");
|
||||
if (type.basetype == SPIRType::BaseType::UInt64)
|
||||
op = "clockARB()";
|
||||
else if (type.basetype == SPIRType::BaseType::UInt && type.vecsize == 2)
|
||||
op = "clock2x32ARB()";
|
||||
else
|
||||
SPIRV_CROSS_THROW("Unsupported result type for OpReadClockKHR opcode.");
|
||||
}
|
||||
else
|
||||
SPIRV_CROSS_THROW("Unsupported scope for OpReadClockKHR opcode.");
|
||||
|
||||
emit_op(ops[0], ops[1], op, false);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
statement("// unimplemented op ", instruction.op);
|
||||
break;
|
||||
@ -13973,7 +14481,7 @@ bool CompilerGLSL::member_is_packed_physical_type(const SPIRType &type, uint32_t
|
||||
// Base implementation uses the standard library transpose() function.
|
||||
// Subclasses may override to use a different function.
|
||||
string CompilerGLSL::convert_row_major_matrix(string exp_str, const SPIRType &exp_type, uint32_t /* physical_type_id */,
|
||||
bool /*is_packed*/)
|
||||
bool /*is_packed*/, bool relaxed)
|
||||
{
|
||||
strip_enclosed_expression(exp_str);
|
||||
if (!is_matrix(exp_type))
|
||||
@ -14003,32 +14511,14 @@ string CompilerGLSL::convert_row_major_matrix(string exp_str, const SPIRType &ex
|
||||
// GLSL 110, ES 100 do not have transpose(), so emulate it. Note that
|
||||
// these GLSL versions do not support non-square matrices.
|
||||
if (exp_type.vecsize == 2 && exp_type.columns == 2)
|
||||
{
|
||||
if (!requires_transpose_2x2)
|
||||
{
|
||||
requires_transpose_2x2 = true;
|
||||
force_recompile();
|
||||
}
|
||||
}
|
||||
require_polyfill(PolyfillTranspose2x2, relaxed);
|
||||
else if (exp_type.vecsize == 3 && exp_type.columns == 3)
|
||||
{
|
||||
if (!requires_transpose_3x3)
|
||||
{
|
||||
requires_transpose_3x3 = true;
|
||||
force_recompile();
|
||||
}
|
||||
}
|
||||
require_polyfill(PolyfillTranspose3x3, relaxed);
|
||||
else if (exp_type.vecsize == 4 && exp_type.columns == 4)
|
||||
{
|
||||
if (!requires_transpose_4x4)
|
||||
{
|
||||
requires_transpose_4x4 = true;
|
||||
force_recompile();
|
||||
}
|
||||
}
|
||||
require_polyfill(PolyfillTranspose4x4, relaxed);
|
||||
else
|
||||
SPIRV_CROSS_THROW("Non-square matrices are not supported in legacy GLSL, cannot transpose.");
|
||||
return join("spvTranspose(", exp_str, ")");
|
||||
return join("spvTranspose", (options.es && relaxed) ? "MP" : "", "(", exp_str, ")");
|
||||
}
|
||||
else
|
||||
return join("transpose(", exp_str, ")");
|
||||
@ -14531,6 +15021,17 @@ string CompilerGLSL::image_type_glsl(const SPIRType &type, uint32_t id)
|
||||
is_depth_image(type, id))
|
||||
{
|
||||
res += "Shadow";
|
||||
|
||||
if (type.image.dim == DimCube && is_legacy())
|
||||
{
|
||||
if (!options.es)
|
||||
require_extension_internal("GL_EXT_gpu_shader4");
|
||||
else
|
||||
{
|
||||
require_extension_internal("GL_NV_shadow_samplers_cube");
|
||||
res += "NV";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
@ -14610,7 +15111,20 @@ string CompilerGLSL::type_to_glsl(const SPIRType &type, uint32_t id)
|
||||
}
|
||||
|
||||
if (type.basetype == SPIRType::UInt && is_legacy())
|
||||
SPIRV_CROSS_THROW("Unsigned integers are not supported on legacy targets.");
|
||||
{
|
||||
if (options.es)
|
||||
SPIRV_CROSS_THROW("Unsigned integers are not supported on legacy ESSL.");
|
||||
else
|
||||
require_extension_internal("GL_EXT_gpu_shader4");
|
||||
}
|
||||
|
||||
if (type.basetype == SPIRType::AtomicCounter)
|
||||
{
|
||||
if (options.es && options.version < 310)
|
||||
SPIRV_CROSS_THROW("At least ESSL 3.10 required for atomic counters.");
|
||||
else if (!options.es && options.version < 420)
|
||||
require_extension_internal("GL_ARB_shader_atomic_counters");
|
||||
}
|
||||
|
||||
if (type.vecsize == 1 && type.columns == 1) // Scalar builtin
|
||||
{
|
||||
@ -16654,7 +17168,12 @@ void CompilerGLSL::cast_from_variable_load(uint32_t source_id, std::string &expr
|
||||
|
||||
// Only interested in standalone builtin variables.
|
||||
if (!has_decoration(source_id, DecorationBuiltIn))
|
||||
{
|
||||
// Except for int attributes in legacy GLSL, which are cast from float.
|
||||
if (is_legacy() && expr_type.basetype == SPIRType::Int && var && var->storage == StorageClassInput)
|
||||
expr = join(type_to_glsl(expr_type), "(", expr, ")");
|
||||
return;
|
||||
}
|
||||
|
||||
auto builtin = static_cast<BuiltIn>(get_decoration(source_id, DecorationBuiltIn));
|
||||
auto expected_type = expr_type.basetype;
|
||||
|
25
3rdparty/spirv-cross/spirv_glsl.hpp
vendored
25
3rdparty/spirv-cross/spirv_glsl.hpp
vendored
@ -552,7 +552,8 @@ protected:
|
||||
bool member_is_remapped_physical_type(const SPIRType &type, uint32_t index) const;
|
||||
bool member_is_packed_physical_type(const SPIRType &type, uint32_t index) const;
|
||||
virtual std::string convert_row_major_matrix(std::string exp_str, const SPIRType &exp_type,
|
||||
uint32_t physical_type_id, bool is_packed);
|
||||
uint32_t physical_type_id, bool is_packed,
|
||||
bool relaxed = false);
|
||||
|
||||
std::unordered_set<std::string> local_variable_names;
|
||||
std::unordered_set<std::string> resource_names;
|
||||
@ -626,6 +627,7 @@ protected:
|
||||
void emit_struct(SPIRType &type);
|
||||
void emit_resources();
|
||||
void emit_extension_workarounds(spv::ExecutionModel model);
|
||||
void emit_polyfills(uint32_t polyfills, bool relaxed);
|
||||
void emit_buffer_block_native(const SPIRVariable &var);
|
||||
void emit_buffer_reference_block(uint32_t type_id, bool forward_declaration);
|
||||
void emit_buffer_block_legacy(const SPIRVariable &var);
|
||||
@ -663,6 +665,7 @@ protected:
|
||||
bool should_suppress_usage_tracking(uint32_t id) const;
|
||||
void emit_mix_op(uint32_t result_type, uint32_t id, uint32_t left, uint32_t right, uint32_t lerp);
|
||||
void emit_nminmax_op(uint32_t result_type, uint32_t id, uint32_t op0, uint32_t op1, GLSLstd450 op);
|
||||
void emit_emulated_ahyper_op(uint32_t result_type, uint32_t result_id, uint32_t op0, GLSLstd450 op);
|
||||
bool to_trivial_mix_op(const SPIRType &type, std::string &op, uint32_t left, uint32_t right, uint32_t lerp);
|
||||
void emit_quaternary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, uint32_t op2,
|
||||
uint32_t op3, const char *op);
|
||||
@ -883,9 +886,23 @@ protected:
|
||||
return !options.es && options.version < 130;
|
||||
}
|
||||
|
||||
bool requires_transpose_2x2 = false;
|
||||
bool requires_transpose_3x3 = false;
|
||||
bool requires_transpose_4x4 = false;
|
||||
enum Polyfill : uint32_t
|
||||
{
|
||||
PolyfillTranspose2x2 = 1 << 0,
|
||||
PolyfillTranspose3x3 = 1 << 1,
|
||||
PolyfillTranspose4x4 = 1 << 2,
|
||||
PolyfillDeterminant2x2 = 1 << 3,
|
||||
PolyfillDeterminant3x3 = 1 << 4,
|
||||
PolyfillDeterminant4x4 = 1 << 5,
|
||||
PolyfillMatrixInverse2x2 = 1 << 6,
|
||||
PolyfillMatrixInverse3x3 = 1 << 7,
|
||||
PolyfillMatrixInverse4x4 = 1 << 8,
|
||||
};
|
||||
|
||||
uint32_t required_polyfills = 0;
|
||||
uint32_t required_polyfills_relaxed = 0;
|
||||
void require_polyfill(Polyfill polyfill, bool relaxed);
|
||||
|
||||
bool ray_tracing_is_khr = false;
|
||||
bool barycentric_is_nv = false;
|
||||
void ray_tracing_khr_fixup_locations();
|
||||
|
33
3rdparty/spirv-cross/spirv_hlsl.cpp
vendored
33
3rdparty/spirv-cross/spirv_hlsl.cpp
vendored
@ -682,10 +682,14 @@ void CompilerHLSL::emit_builtin_outputs_in_struct()
|
||||
// If point_size_compat is enabled, just ignore PointSize.
|
||||
// PointSize does not exist in HLSL, but some code bases might want to be able to use these shaders,
|
||||
// even if it means working around the missing feature.
|
||||
if (hlsl_options.point_size_compat)
|
||||
break;
|
||||
else
|
||||
if (legacy)
|
||||
{
|
||||
type = "float";
|
||||
semantic = "PSIZE";
|
||||
}
|
||||
else if (!hlsl_options.point_size_compat)
|
||||
SPIRV_CROSS_THROW("Unsupported builtin in HLSL.");
|
||||
break;
|
||||
|
||||
case BuiltInLayer:
|
||||
case BuiltInPrimitiveId:
|
||||
@ -1016,6 +1020,7 @@ void CompilerHLSL::emit_interface_block_in_struct(const SPIRVariable &var, unord
|
||||
|
||||
string binding;
|
||||
bool use_location_number = true;
|
||||
bool need_matrix_unroll = false;
|
||||
bool legacy = hlsl_options.shader_model <= 30;
|
||||
if (execution.model == ExecutionModelFragment && var.storage == StorageClassOutput)
|
||||
{
|
||||
@ -1031,6 +1036,12 @@ void CompilerHLSL::emit_interface_block_in_struct(const SPIRVariable &var, unord
|
||||
if (legacy) // COLOR must be a four-component vector on legacy shader model targets (HLSL ERR_COLOR_4COMP)
|
||||
type.vecsize = 4;
|
||||
}
|
||||
else if (var.storage == StorageClassInput && execution.model == ExecutionModelVertex)
|
||||
{
|
||||
need_matrix_unroll = true;
|
||||
if (legacy) // Inputs must be floating-point in legacy targets.
|
||||
type.basetype = SPIRType::Float;
|
||||
}
|
||||
|
||||
const auto get_vacant_location = [&]() -> uint32_t {
|
||||
for (uint32_t i = 0; i < 64; i++)
|
||||
@ -1039,8 +1050,6 @@ void CompilerHLSL::emit_interface_block_in_struct(const SPIRVariable &var, unord
|
||||
SPIRV_CROSS_THROW("All locations from 0 to 63 are exhausted.");
|
||||
};
|
||||
|
||||
bool need_matrix_unroll = var.storage == StorageClassInput && execution.model == ExecutionModelVertex;
|
||||
|
||||
auto name = to_name(var.self);
|
||||
if (use_location_number)
|
||||
{
|
||||
@ -1221,7 +1230,7 @@ void CompilerHLSL::emit_builtin_variables()
|
||||
break;
|
||||
|
||||
case BuiltInPointSize:
|
||||
if (hlsl_options.point_size_compat)
|
||||
if (hlsl_options.point_size_compat || hlsl_options.shader_model <= 30)
|
||||
{
|
||||
// Just emit the global variable, it will be ignored.
|
||||
type = "float";
|
||||
@ -3218,8 +3227,8 @@ void CompilerHLSL::emit_hlsl_entry_point()
|
||||
|
||||
// Copy builtins from globals to return struct.
|
||||
active_output_builtins.for_each_bit([&](uint32_t i) {
|
||||
// PointSize doesn't exist in HLSL.
|
||||
if (i == BuiltInPointSize)
|
||||
// PointSize doesn't exist in HLSL SM 4+.
|
||||
if (i == BuiltInPointSize && !legacy)
|
||||
return;
|
||||
|
||||
switch (static_cast<BuiltIn>(i))
|
||||
@ -4115,10 +4124,16 @@ void CompilerHLSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop,
|
||||
emit_unary_func_op(result_type, id, args[0], "round");
|
||||
break;
|
||||
|
||||
case GLSLstd450Trunc:
|
||||
emit_unary_func_op(result_type, id, args[0], "trunc");
|
||||
break;
|
||||
|
||||
case GLSLstd450Acosh:
|
||||
case GLSLstd450Asinh:
|
||||
case GLSLstd450Atanh:
|
||||
SPIRV_CROSS_THROW("Inverse hyperbolics are not supported on HLSL.");
|
||||
// These are not supported in HLSL, always emulate them.
|
||||
emit_emulated_ahyper_op(result_type, id, args[0], op);
|
||||
break;
|
||||
|
||||
case GLSLstd450FMix:
|
||||
case GLSLstd450IMix:
|
||||
|
2
3rdparty/spirv-cross/spirv_hlsl.hpp
vendored
2
3rdparty/spirv-cross/spirv_hlsl.hpp
vendored
@ -110,7 +110,7 @@ public:
|
||||
{
|
||||
uint32_t shader_model = 30; // TODO: map ps_4_0_level_9_0,... somehow
|
||||
|
||||
// Allows the PointSize builtin, and ignores it, as PointSize is not supported in HLSL.
|
||||
// Allows the PointSize builtin in SM 4.0+, and ignores it, as PointSize is not supported in SM 4+.
|
||||
bool point_size_compat = false;
|
||||
|
||||
// Allows the PointCoord builtin, returns float2(0.5, 0.5), as PointCoord is not supported in HLSL.
|
||||
|
22
3rdparty/spirv-cross/spirv_msl.cpp
vendored
22
3rdparty/spirv-cross/spirv_msl.cpp
vendored
@ -2364,7 +2364,7 @@ bool CompilerMSL::add_component_variable_to_interface_block(spv::StorageClass st
|
||||
if (pad_fragment_output)
|
||||
{
|
||||
uint32_t locn = get_decoration(var.self, DecorationLocation);
|
||||
num_components = std::max(num_components, get_target_components_for_fragment_location(locn));
|
||||
num_components = max<uint32_t>(num_components, get_target_components_for_fragment_location(locn));
|
||||
}
|
||||
|
||||
// We have already declared an IO block member as m_location_N.
|
||||
@ -3846,7 +3846,7 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch)
|
||||
for (uint32_t location_offset = 0; location_offset < array_size; location_offset++)
|
||||
{
|
||||
auto &location_meta = meta.location_meta[location + location_offset];
|
||||
location_meta.num_components = std::max(location_meta.num_components, component + type.vecsize);
|
||||
location_meta.num_components = max<uint32_t>(location_meta.num_components, component + type.vecsize);
|
||||
|
||||
// For variables sharing location, decorations and base type must match.
|
||||
location_meta.base_type_id = type.self;
|
||||
@ -4515,7 +4515,7 @@ void CompilerMSL::mark_scalar_layout_structs(const SPIRType &type)
|
||||
for (uint32_t dim = 0; dim < dimensions; dim++)
|
||||
{
|
||||
uint32_t array_size = to_array_size_literal(mbr_type, dim);
|
||||
array_stride /= max(array_size, 1u);
|
||||
array_stride /= max<uint32_t>(array_size, 1u);
|
||||
}
|
||||
|
||||
// Set expected struct size based on ArrayStride.
|
||||
@ -4722,7 +4722,7 @@ void CompilerMSL::ensure_member_packing_rules_msl(SPIRType &ib_type, uint32_t in
|
||||
// Hack off array-of-arrays until we find the array stride per element we must have to make it work.
|
||||
uint32_t dimensions = uint32_t(mbr_type.array.size() - 1);
|
||||
for (uint32_t dim = 0; dim < dimensions; dim++)
|
||||
array_stride /= max(to_array_size_literal(mbr_type, dim), 1u);
|
||||
array_stride /= max<uint32_t>(to_array_size_literal(mbr_type, dim), 1u);
|
||||
|
||||
// Pointers are 8 bytes
|
||||
uint32_t mbr_width_in_bytes = is_buff_ptr ? 8 : (mbr_type.width / 8);
|
||||
@ -7206,7 +7206,7 @@ static string inject_top_level_storage_qualifier(const string &expr, const strin
|
||||
else if (last_pointer == string::npos)
|
||||
last_significant = last_reference;
|
||||
else
|
||||
last_significant = std::max(last_reference, last_pointer);
|
||||
last_significant = max<size_t>(last_reference, last_pointer);
|
||||
|
||||
if (last_significant == string::npos)
|
||||
return join(qualifier, " ", expr);
|
||||
@ -11487,11 +11487,11 @@ bool CompilerMSL::member_is_non_native_row_major_matrix(const SPIRType &type, ui
|
||||
}
|
||||
|
||||
string CompilerMSL::convert_row_major_matrix(string exp_str, const SPIRType &exp_type, uint32_t physical_type_id,
|
||||
bool is_packed)
|
||||
bool is_packed, bool relaxed)
|
||||
{
|
||||
if (!is_matrix(exp_type))
|
||||
{
|
||||
return CompilerGLSL::convert_row_major_matrix(std::move(exp_str), exp_type, physical_type_id, is_packed);
|
||||
return CompilerGLSL::convert_row_major_matrix(std::move(exp_str), exp_type, physical_type_id, is_packed, relaxed);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -15920,7 +15920,7 @@ uint32_t CompilerMSL::get_declared_type_array_stride_msl(const SPIRType &type, b
|
||||
for (uint32_t dim = 0; dim < dimensions; dim++)
|
||||
{
|
||||
uint32_t array_size = to_array_size_literal(type, dim);
|
||||
value_size *= max(array_size, 1u);
|
||||
value_size *= max<uint32_t>(array_size, 1u);
|
||||
}
|
||||
|
||||
return value_size;
|
||||
@ -16031,7 +16031,7 @@ uint32_t CompilerMSL::get_declared_type_size_msl(const SPIRType &type, bool is_p
|
||||
if (!type.array.empty())
|
||||
{
|
||||
uint32_t array_size = to_array_size_literal(type);
|
||||
return get_declared_type_array_stride_msl(type, is_packed, row_major) * max(array_size, 1u);
|
||||
return get_declared_type_array_stride_msl(type, is_packed, row_major) * max<uint32_t>(array_size, 1u);
|
||||
}
|
||||
|
||||
if (type.basetype == SPIRType::Struct)
|
||||
@ -16705,7 +16705,7 @@ void CompilerMSL::cast_from_variable_load(uint32_t source_id, std::string &expr,
|
||||
bool is_packed = has_extended_decoration(source_id, SPIRVCrossDecorationPhysicalTypePacked);
|
||||
auto *source_expr = maybe_get<SPIRExpression>(source_id);
|
||||
auto *var = maybe_get_backing_variable(source_id);
|
||||
const SPIRType *var_type, *phys_type;
|
||||
const SPIRType *var_type = nullptr, *phys_type = nullptr;
|
||||
if (uint32_t phys_id = get_extended_decoration(source_id, SPIRVCrossDecorationPhysicalTypeID))
|
||||
phys_type = &get<SPIRType>(phys_id);
|
||||
else
|
||||
@ -16831,7 +16831,7 @@ void CompilerMSL::cast_to_variable_store(uint32_t target_id, std::string &expr,
|
||||
bool is_packed = has_extended_decoration(target_id, SPIRVCrossDecorationPhysicalTypePacked);
|
||||
auto *target_expr = maybe_get<SPIRExpression>(target_id);
|
||||
auto *var = maybe_get_backing_variable(target_id);
|
||||
const SPIRType *var_type, *phys_type;
|
||||
const SPIRType *var_type = nullptr, *phys_type = nullptr;
|
||||
if (uint32_t phys_id = get_extended_decoration(target_id, SPIRVCrossDecorationPhysicalTypeID))
|
||||
phys_type = &get<SPIRType>(phys_id);
|
||||
else
|
||||
|
2
3rdparty/spirv-cross/spirv_msl.hpp
vendored
2
3rdparty/spirv-cross/spirv_msl.hpp
vendored
@ -864,7 +864,7 @@ protected:
|
||||
bool is_non_native_row_major_matrix(uint32_t id) override;
|
||||
bool member_is_non_native_row_major_matrix(const SPIRType &type, uint32_t index) override;
|
||||
std::string convert_row_major_matrix(std::string exp_str, const SPIRType &exp_type, uint32_t physical_type_id,
|
||||
bool is_packed) override;
|
||||
bool is_packed, bool relaxed) override;
|
||||
|
||||
bool is_tesc_shader() const;
|
||||
bool is_tese_shader() const;
|
||||
|
Loading…
Reference in New Issue
Block a user