Updated spirv-cross.

This commit is contained in:
Бранимир Караџић 2023-02-02 19:01:23 -08:00
parent 3d390308dc
commit 709d33f2c5
6 changed files with 668 additions and 117 deletions

View File

@ -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;

View File

@ -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();

View File

@ -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:

View File

@ -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.

View File

@ -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

View File

@ -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;