Implement array casts in Metal.

These are not very interesting right now, because the in and out types
boil down to the same thing (int/int, float/float). When half-
precision types are enabled, these helpers will be more useful. They
will return an array which casts each element from int-to-short or
float-to-half (or vice versa).

Change-Id: Ida716ddd27d370ba33fd23f17a1b07fa5a201e40
Bug: skia:12339
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/463337
Commit-Queue: John Stiles <johnstiles@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
This commit is contained in:
John Stiles 2021-10-26 10:51:35 -04:00 committed by SkCQ
parent 2a372177e8
commit 8ed23eb917
4 changed files with 95 additions and 16 deletions

View File

@ -148,7 +148,7 @@ void MetalCodeGenerator::writeExpression(const Expression& expr, Precedence pare
this->writeAnyConstructor(expr.asAnyConstructor(), "{", "}", parentPrecedence);
break;
case Expression::Kind::kConstructorArrayCast:
this->writeExpression(*expr.as<ConstructorArrayCast>().argument(), parentPrecedence);
this->writeConstructorArrayCast(expr.as<ConstructorArrayCast>(), parentPrecedence);
break;
case Expression::Kind::kConstructorCompound:
this->writeConstructorCompound(expr.as<ConstructorCompound>(), parentPrecedence);
@ -1157,6 +1157,37 @@ void MetalCodeGenerator::writeConstructorCompound(const ConstructorCompound& c,
}
}
void MetalCodeGenerator::writeConstructorArrayCast(const ConstructorArrayCast& c,
Precedence parentPrecedence) {
const Type& inType = c.argument()->type().componentType();
const Type& outType = c.type().componentType();
String inTypeName = this->typeName(inType);
String outTypeName = this->typeName(outType);
String name = "array_of_" + outTypeName + "_from_" + inTypeName;
auto [iter, didInsert] = fHelpers.insert(name);
if (didInsert) {
fExtraFunctions.printf(R"(
template <size_t N>
array<%s, N> %s(thread const array<%s, N>& x) {
array<%s, N> result;
for (int i = 0; i < N; ++i) {
result[i] = %s(x[i]);
}
return result;
}
)",
outTypeName.c_str(), name.c_str(), inTypeName.c_str(),
outTypeName.c_str(),
outTypeName.c_str());
}
this->write(name);
this->write("(");
this->writeExpression(*c.argument(), Precedence::kSequence);
this->write(")");
}
String MetalCodeGenerator::getVectorFromMat2x2ConstructorHelper(const Type& matrixType) {
SkASSERT(matrixType.isMatrix());
SkASSERT(matrixType.rows() == 2);

View File

@ -19,6 +19,7 @@ namespace SkSL {
class BinaryExpression;
class Block;
class ConstructorArrayCast;
class ConstructorCompound;
class ConstructorMatrixResize;
class DoStatement;
@ -210,6 +211,8 @@ protected:
const char* rightBracket,
Precedence parentPrecedence);
void writeConstructorArrayCast(const ConstructorArrayCast& c, Precedence parentPrecedence);
void writeFieldAccess(const FieldAccess& f);
void writeSwizzle(const Swizzle& swizzle);

View File

@ -19,6 +19,33 @@ bool operator!=(thread const array<T1, N>& left, thread const array<T2, N>& righ
thread bool operator==(const float2x2 left, const float2x2 right);
thread bool operator!=(const float2x2 left, const float2x2 right);
template <size_t N>
array<float, N> array_of_float_from_float(thread const array<float, N>& x) {
array<float, N> result;
for (int i = 0; i < N; ++i) {
result[i] = float(x[i]);
}
return result;
}
template <size_t N>
array<int3, N> array_of_int3_from_int3(thread const array<int3, N>& x) {
array<int3, N> result;
for (int i = 0; i < N; ++i) {
result[i] = int3(x[i]);
}
return result;
}
template <size_t N>
array<float2x2, N> array_of_float2x2_from_float2x2(thread const array<float2x2, N>& x) {
array<float2x2, N> result;
for (int i = 0; i < N; ++i) {
result[i] = float2x2(x[i]);
}
return result;
}
template <typename T1, typename T2, size_t N>
bool operator==(thread const array<T1, N>& left, thread const array<T2, N>& right) {
for (size_t index = 0; index < N; ++index) {
@ -44,17 +71,17 @@ fragment Outputs fragmentMain(Inputs _in [[stage_in]], constant Uniforms& _unifo
Outputs _out;
(void)_out;
array<float, 4> f = array<float, 4>{1.0, 2.0, 3.0, 4.0};
array<float, 4> h = f;
f = h;
h = f;
array<float, 4> h = array_of_float_from_float(f);
f = array_of_float_from_float(h);
h = array_of_float_from_float(f);
array<int3, 3> i3 = array<int3, 3>{int3(1), int3(2), int3(3)};
array<int3, 3> s3 = i3;
i3 = s3;
s3 = i3;
array<int3, 3> s3 = array_of_int3_from_int3(i3);
i3 = array_of_int3_from_int3(s3);
s3 = array_of_int3_from_int3(i3);
array<float2x2, 2> h2x2 = array<float2x2, 2>{float2x2(float2(1.0, 2.0), float2(3.0, 4.0)), float2x2(float2(5.0, 6.0), float2(7.0, 8.0))};
array<float2x2, 2> f2x2 = h2x2;
f2x2 = h2x2;
h2x2 = f2x2;
_out.sk_FragColor = (f == h && i3 == s3) && f2x2 == h2x2 ? _uniforms.colorGreen : _uniforms.colorRed;
array<float2x2, 2> f2x2 = array_of_float2x2_from_float2x2(h2x2);
f2x2 = array_of_float2x2_from_float2x2(h2x2);
h2x2 = array_of_float2x2_from_float2x2(f2x2);
_out.sk_FragColor = (f == array_of_float_from_float(h) && i3 == array_of_int3_from_int3(s3)) && f2x2 == array_of_float2x2_from_float2x2(h2x2) ? _uniforms.colorGreen : _uniforms.colorRed;
return _out;
}

View File

@ -16,6 +16,24 @@ bool operator==(thread const array<T1, N>& left, thread const array<T2, N>& righ
template <typename T1, typename T2, size_t N>
bool operator!=(thread const array<T1, N>& left, thread const array<T2, N>& right);
template <size_t N>
array<int, N> array_of_int_from_int(thread const array<int, N>& x) {
array<int, N> result;
for (int i = 0; i < N; ++i) {
result[i] = int(x[i]);
}
return result;
}
template <size_t N>
array<float, N> array_of_float_from_float(thread const array<float, N>& x) {
array<float, N> result;
for (int i = 0; i < N; ++i) {
result[i] = float(x[i]);
}
return result;
}
template <typename T1, typename T2, size_t N>
bool operator==(thread const array<T1, N>& left, thread const array<T2, N>& right) {
for (size_t index = 0; index < N; ++index) {
@ -37,11 +55,11 @@ fragment Outputs fragmentMain(Inputs _in [[stage_in]], constant Uniforms& _unifo
array<int, 2> s2 = array<int, 2>{1, 2};
array<float, 2> f2 = array<float, 2>{1.0, 2.0};
array<float, 2> h2 = array<float, 2>{1.0, 2.0};
i2 = s2;
s2 = i2;
f2 = h2;
h2 = f2;
i2 = array_of_int_from_int(s2);
s2 = array_of_int_from_int(i2);
f2 = array_of_float_from_float(h2);
h2 = array_of_float_from_float(f2);
const array<float, 2> cf2 = array<float, 2>{1.0, 2.0};
_out.sk_FragColor = ((i2 == s2 && f2 == h2) && i2 == array<int, 2>{1, 2}) && h2 == cf2 ? _uniforms.colorGreen : _uniforms.colorRed;
_out.sk_FragColor = ((i2 == array_of_int_from_int(s2) && f2 == array_of_float_from_float(h2)) && i2 == array<int, 2>{1, 2}) && array_of_float_from_float(h2) == cf2 ? _uniforms.colorGreen : _uniforms.colorRed;
return _out;
}