Add GLSL workaround for 4x2 diagonal matrix bug.

GLSL now emits 4x2 diagonal matrices as:
	`(mat4x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0) * n)`
instead of
	`mat4x2(n)`.

This works around a long-standing GLSL bug in both Mesa and glslang that
affects several drivers:
https://github.com/KhronosGroup/glslang/issues/2645

Change-Id: If529d5cd150ce720f436cb3634a2fd3423919278
Bug: skia:12003
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/410137
Auto-Submit: John Stiles <johnstiles@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
This commit is contained in:
John Stiles 2021-05-18 17:31:48 -04:00 committed by Skia Commit-Bot
parent a5569ac9c4
commit 3c74a5357a
7 changed files with 734 additions and 595 deletions

View File

@ -18,11 +18,10 @@ bool test_float() {
0, 5, 0, 0,
0, 0, 5, 0));
float4x2 m42 = float4x2(6);
// Some Intel and Radeon GLSL drivers don't assemble the mat4x2 properly. (skia:12003)
// ok = ok && (m42 == float4x2(6, 0,
// 0, 6,
// 0, 0,
// 0, 0));
ok = ok && (m42 == float4x2(6, 0,
0, 6,
0, 0,
0, 0));
float4x3 m43 = float4x3(7);
ok = ok && (m43 == float4x3(7, 0, 0,
0, 7, 0,
@ -65,11 +64,10 @@ bool test_half() {
0, 5, 0, 0,
0, 0, 5, 0));
half4x2 m42 = half4x2(6);
// Some Intel and Radeon GLSL drivers don't assemble the mat4x2 properly. (skia:12003)
// ok = ok && (m42 == half4x2(6, 0,
// 0, 6,
// 0, 0,
// 0, 0));
ok = ok && (m42 == half4x2(6, 0,
0, 6,
0, 0,
0, 0));
half4x3 m43 = half4x3(7);
ok = ok && (m43 == half4x3(7, 0, 0,
0, 7, 0,

View File

@ -190,9 +190,12 @@ void GLSLCodeGenerator::writeExpression(const Expression& expr, Precedence paren
case Expression::Kind::kBoolLiteral:
this->writeBoolLiteral(expr.as<BoolLiteral>());
break;
case Expression::Kind::kConstructorDiagonalMatrix:
this->writeConstructorDiagonalMatrix(expr.as<ConstructorDiagonalMatrix>(),
parentPrecedence);
break;
case Expression::Kind::kConstructorArray:
case Expression::Kind::kConstructorCompound:
case Expression::Kind::kConstructorDiagonalMatrix:
case Expression::Kind::kConstructorMatrixResize:
case Expression::Kind::kConstructorSplat:
case Expression::Kind::kConstructorStruct:
@ -688,6 +691,24 @@ void GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) {
this->write(")");
}
void GLSLCodeGenerator::writeConstructorDiagonalMatrix(const ConstructorDiagonalMatrix& c,
Precedence parentPrecedence) {
if (c.type().columns() == 4 && c.type().rows() == 2) {
// Due to a longstanding bug in glslang and Mesa, several GPU drivers generate diagonal 4x2
// matrices incorrectly. (skia:12003, https://github.com/KhronosGroup/glslang/pull/2646)
// We can work around this issue by multiplying a scalar by the identity matrix.
// In practice, this doesn't come up naturally in real code and we don't know every affected
// driver, so we just apply this workaround everywhere.
this->write("(");
this->writeType(c.type());
this->write("(1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0) * ");
this->writeExpression(*c.argument(), Precedence::kMultiplicative);
this->write(")");
return;
}
this->writeAnyConstructor(c, parentPrecedence);
}
void GLSLCodeGenerator::writeCastConstructor(const AnyConstructor& c, Precedence parentPrecedence) {
const auto arguments = c.argumentSpan();
SkASSERT(arguments.size() == 1);

View File

@ -21,6 +21,7 @@
#include "src/sksl/ir/SkSLBinaryExpression.h"
#include "src/sksl/ir/SkSLBoolLiteral.h"
#include "src/sksl/ir/SkSLConstructor.h"
#include "src/sksl/ir/SkSLConstructorDiagonalMatrix.h"
#include "src/sksl/ir/SkSLConstructorScalarCast.h"
#include "src/sksl/ir/SkSLDoStatement.h"
#include "src/sksl/ir/SkSLExtension.h"
@ -135,6 +136,9 @@ protected:
virtual void writeFunctionCall(const FunctionCall& c);
void writeConstructorDiagonalMatrix(const ConstructorDiagonalMatrix& c,
Precedence parentPrecedence);
virtual void writeAnyConstructor(const AnyConstructor& c, Precedence parentPrecedence);
virtual void writeCastConstructor(const AnyConstructor& c, Precedence parentPrecedence);

File diff suppressed because it is too large Load Diff

View File

@ -12,6 +12,8 @@ bool test_half_b() {
ok = ok && m32 == mat3x2(4.0, 0.0, 0.0, 4.0, 0.0, 0.0);
mat3x4 m34 = mat3x4(5.0);
ok = ok && m34 == mat3x4(5.0, 0.0, 0.0, 0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 5.0, 0.0);
mat4x2 m42 = (mat4x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0) * 6.0);
ok = ok && m42 == mat4x2(6.0, 0.0, 0.0, 6.0, 0.0, 0.0, 0.0, 0.0);
mat4x3 m43 = mat4x3(7.0);
ok = ok && m43 == mat4x3(7.0, 0.0, 0.0, 0.0, 7.0, 0.0, 0.0, 0.0, 7.0, 0.0, 0.0, 0.0);
mat2 m22 = m32 * m23;
@ -36,6 +38,8 @@ vec4 main() {
_0_ok = _0_ok && _3_m32 == mat3x2(4.0, 0.0, 0.0, 4.0, 0.0, 0.0);
mat3x4 _4_m34 = mat3x4(5.0);
_0_ok = _0_ok && _4_m34 == mat3x4(5.0, 0.0, 0.0, 0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 5.0, 0.0);
mat4x2 _5_m42 = (mat4x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0) * 6.0);
_0_ok = _0_ok && _5_m42 == mat4x2(6.0, 0.0, 0.0, 6.0, 0.0, 0.0, 0.0, 0.0);
mat4x3 _6_m43 = mat4x3(7.0);
_0_ok = _0_ok && _6_m43 == mat4x3(7.0, 0.0, 0.0, 0.0, 7.0, 0.0, 0.0, 0.0, 7.0, 0.0, 0.0, 0.0);
mat2 _7_m22 = _3_m32 * _1_m23;

View File

@ -40,6 +40,15 @@ thread bool operator==(const float3x4 left, const float3x4 right) {
thread bool operator!=(const float3x4 left, const float3x4 right) {
return !(left == right);
}
thread bool operator==(const float4x2 left, const float4x2 right) {
return all(left[0] == right[0]) &&
all(left[1] == right[1]) &&
all(left[2] == right[2]) &&
all(left[3] == right[3]);
}
thread bool operator!=(const float4x2 left, const float4x2 right) {
return !(left == right);
}
thread bool operator==(const float4x3 left, const float4x3 right) {
return all(left[0] == right[0]) &&
all(left[1] == right[1]) &&
@ -81,6 +90,8 @@ bool test_half_b() {
ok = ok && m32 == float3x2(float2(4.0, 0.0), float2(0.0, 4.0), float2(0.0, 0.0));
float3x4 m34 = float3x4(5.0);
ok = ok && m34 == float3x4(float4(5.0, 0.0, 0.0, 0.0), float4(0.0, 5.0, 0.0, 0.0), float4(0.0, 0.0, 5.0, 0.0));
float4x2 m42 = float4x2(6.0);
ok = ok && m42 == float4x2(float2(6.0, 0.0), float2(0.0, 6.0), float2(0.0, 0.0), float2(0.0, 0.0));
float4x3 m43 = float4x3(7.0);
ok = ok && m43 == float4x3(float3(7.0, 0.0, 0.0), float3(0.0, 7.0, 0.0), float3(0.0, 0.0, 7.0), float3(0.0, 0.0, 0.0));
float2x2 m22 = m32 * m23;
@ -107,6 +118,8 @@ fragment Outputs fragmentMain(Inputs _in [[stage_in]], constant Uniforms& _unifo
_0_ok = _0_ok && _3_m32 == float3x2(float2(4.0, 0.0), float2(0.0, 4.0), float2(0.0, 0.0));
float3x4 _4_m34 = float3x4(5.0);
_0_ok = _0_ok && _4_m34 == float3x4(float4(5.0, 0.0, 0.0, 0.0), float4(0.0, 5.0, 0.0, 0.0), float4(0.0, 0.0, 5.0, 0.0));
float4x2 _5_m42 = float4x2(6.0);
_0_ok = _0_ok && _5_m42 == float4x2(float2(6.0, 0.0), float2(0.0, 6.0), float2(0.0, 0.0), float2(0.0, 0.0));
float4x3 _6_m43 = float4x3(7.0);
_0_ok = _0_ok && _6_m43 == float4x3(float3(7.0, 0.0, 0.0), float3(0.0, 7.0, 0.0), float3(0.0, 0.0, 7.0), float3(0.0, 0.0, 0.0));
float2x2 _7_m22 = _3_m32 * _1_m23;

View File

@ -8,11 +8,11 @@ vec4 main() {
result += g[0].x;
mat3 h = mat3(mat3x2(1.0));
result += h[0].x;
mat4 i = mat4(mat4x3(mat4x2(1.0)));
mat4 i = mat4(mat4x3((mat4x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0) * 1.0)));
result += i[0].x;
mat4 j = mat4(mat3x4(mat2x4(1.0)));
result += j[0].x;
mat2x4 k = mat2x4(mat4x2(1.0));
mat2x4 k = mat2x4((mat4x2(1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0) * 1.0));
result += k[0].x;
mat4x2 l = mat4x2(mat2x4(1.0));
result += l[0].x;