GLSL: Fix row-major workaround wrapper for ES.

By default, the matrix would be declared as mediump, causing precision
issues. Need to dispatch to two separate functions since GLSL does not
support overload based on precision.
This commit is contained in:
Hans-Kristian Arntzen 2022-12-13 15:38:58 +01:00
parent 3c997e12eb
commit 03b1f66ef1
8 changed files with 121 additions and 11 deletions

View File

@ -11,7 +11,8 @@ uniform Buffer _13;
attribute vec4 Position;
mat4 spvWorkaroundRowMajor(mat4 wrap) { return wrap; }
highp mat4 spvWorkaroundRowMajor(highp mat4 wrap) { return wrap; }
mediump mat4 spvWorkaroundRowMajorMP(mediump mat4 wrap) { return wrap; }
mat4 spvTranspose(mat4 m)
{

View File

@ -8,7 +8,8 @@ layout(binding = 0, std140) uniform Block
layout(location = 0) in vec4 a_position;
layout(location = 0) out mediump float v_vtxResult;
mat2x3 spvWorkaroundRowMajor(mat2x3 wrap) { return wrap; }
highp mat2x3 spvWorkaroundRowMajor(highp mat2x3 wrap) { return wrap; }
mediump mat2x3 spvWorkaroundRowMajorMP(mediump mat2x3 wrap) { return wrap; }
void main()
{

View File

@ -0,0 +1,30 @@
#version 310 es
layout(binding = 0, std140) uniform Buffer
{
layout(row_major) mat4 HP;
layout(row_major) mediump mat4 MP;
} _21;
layout(binding = 1, std140) uniform Buffer2
{
layout(row_major) mediump mat4 MP2;
} _39;
layout(location = 0) out vec4 H;
layout(location = 0) in vec4 Hin;
layout(location = 1) out mediump vec4 M;
layout(location = 1) in mediump vec4 Min;
layout(location = 2) out mediump vec4 M2;
highp mat4 spvWorkaroundRowMajor(highp mat4 wrap) { return wrap; }
mediump mat4 spvWorkaroundRowMajorMP(mediump mat4 wrap) { return wrap; }
void main()
{
gl_Position = vec4(1.0);
H = spvWorkaroundRowMajor(_21.HP) * Hin;
M = spvWorkaroundRowMajor(_21.MP) * Min;
M2 = spvWorkaroundRowMajorMP(_39.MP2) * Min;
}

View File

@ -11,7 +11,8 @@ uniform Buffer _13;
attribute vec4 Position;
mat4 spvWorkaroundRowMajor(mat4 wrap) { return wrap; }
highp mat4 spvWorkaroundRowMajor(highp mat4 wrap) { return wrap; }
mediump mat4 spvWorkaroundRowMajorMP(mediump mat4 wrap) { return wrap; }
mat4 spvTranspose(mat4 m)
{

View File

@ -8,7 +8,8 @@ layout(binding = 0, std140) uniform Block
layout(location = 0) in vec4 a_position;
layout(location = 0) out mediump float v_vtxResult;
mat2x3 spvWorkaroundRowMajor(mat2x3 wrap) { return wrap; }
highp mat2x3 spvWorkaroundRowMajor(highp mat2x3 wrap) { return wrap; }
mediump mat2x3 spvWorkaroundRowMajorMP(mediump mat2x3 wrap) { return wrap; }
mediump float compare_float(float a, float b)
{

View File

@ -0,0 +1,30 @@
#version 310 es
layout(binding = 0, std140) uniform Buffer
{
layout(row_major) mat4 HP;
layout(row_major) mediump mat4 MP;
} _21;
layout(binding = 1, std140) uniform Buffer2
{
layout(row_major) mediump mat4 MP2;
} _39;
layout(location = 0) out vec4 H;
layout(location = 0) in vec4 Hin;
layout(location = 1) out mediump vec4 M;
layout(location = 1) in mediump vec4 Min;
layout(location = 2) out mediump vec4 M2;
highp mat4 spvWorkaroundRowMajor(highp mat4 wrap) { return wrap; }
mediump mat4 spvWorkaroundRowMajorMP(mediump mat4 wrap) { return wrap; }
void main()
{
gl_Position = vec4(1.0);
H = spvWorkaroundRowMajor(_21.HP) * Hin;
M = spvWorkaroundRowMajor(_21.MP) * Min;
M2 = spvWorkaroundRowMajorMP(_39.MP2) * Min;
}

View File

@ -0,0 +1,28 @@
#version 310 es
layout(binding = 0) uniform Buffer
{
layout(row_major) highp mat4 HP;
layout(row_major) mediump mat4 MP;
};
layout(binding = 1) uniform Buffer2
{
layout(row_major) mediump mat4 MP2;
};
layout(location = 0) in vec4 Hin;
layout(location = 1) in mediump vec4 Min;
layout(location = 0) out vec4 H;
layout(location = 1) out mediump vec4 M;
layout(location = 2) out mediump vec4 M2;
void main()
{
gl_Position = vec4(1.0);
H = HP * Hin;
M = MP * Min;
M2 = MP2 * Min;
}

View File

@ -4362,8 +4362,18 @@ void CompilerGLSL::emit_extension_workarounds(spv::ExecutionModel model)
for (auto &type_id : workaround_ubo_load_overload_types)
{
auto &type = get<SPIRType>(type_id);
statement(type_to_glsl(type), " spvWorkaroundRowMajor(", type_to_glsl(type),
" wrap) { return wrap; }");
if (options.es && is_matrix(type))
{
// Need both variants.
// GLSL cannot overload on precision, so need to dispatch appropriately.
statement("highp ", type_to_glsl(type), " spvWorkaroundRowMajor(highp ", type_to_glsl(type), " wrap) { return wrap; }");
statement("mediump ", type_to_glsl(type), " spvWorkaroundRowMajorMP(mediump ", type_to_glsl(type), " wrap) { return wrap; }");
}
else
{
statement(type_to_glsl(type), " spvWorkaroundRowMajor(", type_to_glsl(type), " wrap) { return wrap; }");
}
}
statement("");
}
@ -17335,6 +17345,7 @@ void CompilerGLSL::rewrite_load_for_wrapped_row_major(std::string &expr, TypeID
auto *type = &get<SPIRType>(loaded_type);
bool rewrite = false;
bool relaxed = options.es;
if (is_matrix(*type))
{
@ -17345,24 +17356,31 @@ void CompilerGLSL::rewrite_load_for_wrapped_row_major(std::string &expr, TypeID
// If an access chain occurred, the workaround is not required, so loading vectors or scalars don't need workaround.
type = &backing_type;
}
else
{
// If we're loading a composite, we don't have overloads like these.
relaxed = false;
}
if (type->basetype == SPIRType::Struct)
{
// If we're loading a struct where any member is a row-major matrix, apply the workaround.
for (uint32_t i = 0; i < uint32_t(type->member_types.size()); i++)
{
if (combined_decoration_for_member(*type, i).get(DecorationRowMajor))
{
auto decorations = combined_decoration_for_member(*type, i);
if (decorations.get(DecorationRowMajor))
rewrite = true;
break;
}
// Since we decide on a per-struct basis, only use mediump wrapper if all candidates are mediump.
if (!decorations.get(DecorationRelaxedPrecision))
relaxed = false;
}
}
if (rewrite)
{
request_workaround_wrapper_overload(loaded_type);
expr = join("spvWorkaroundRowMajor(", expr, ")");
expr = join("spvWorkaroundRowMajor", (relaxed ? "MP" : ""), "(", expr, ")");
}
}