SkSL: Add test for scalar versions of geometric intrinsics
Fix code generation for Metal and Vulkan with geometric intrinsics that have scalar versions in GLSL/SkSL, but no native support in MSL/SPIR-V. Change-Id: Id4538a00172e0d233ad9d5ed8d33db6436b83208 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/338276 Commit-Queue: Brian Osman <brianosman@google.com> Reviewed-by: John Stiles <johnstiles@google.com>
This commit is contained in:
parent
8636e13c2d
commit
46787d5d7e
@ -207,6 +207,7 @@ sksl_shared_tests = [
|
||||
"$_tests/sksl/shared/FunctionPrototype.sksl",
|
||||
"$_tests/sksl/shared/Functions.sksl",
|
||||
"$_tests/sksl/shared/GaussianBlur.sksl",
|
||||
"$_tests/sksl/shared/GeometricIntrinsics.sksl",
|
||||
"$_tests/sksl/shared/Geometry.geom",
|
||||
"$_tests/sksl/shared/GeometryExtension.geom",
|
||||
"$_tests/sksl/shared/GeometryGSInvocations.geom",
|
||||
|
@ -32,8 +32,12 @@ public:
|
||||
void MetalCodeGenerator::setupIntrinsics() {
|
||||
#define METAL(x) std::make_pair(kMetal_IntrinsicKind, k ## x ## _MetalIntrinsic)
|
||||
#define SPECIAL(x) std::make_pair(kSpecial_IntrinsicKind, k ## x ## _SpecialIntrinsic)
|
||||
fIntrinsicMap[String("sample")] = SPECIAL(Texture);
|
||||
fIntrinsicMap[String("distance")] = SPECIAL(Distance);
|
||||
fIntrinsicMap[String("dot")] = SPECIAL(Dot);
|
||||
fIntrinsicMap[String("length")] = SPECIAL(Length);
|
||||
fIntrinsicMap[String("mod")] = SPECIAL(Mod);
|
||||
fIntrinsicMap[String("normalize")] = SPECIAL(Normalize);
|
||||
fIntrinsicMap[String("sample")] = SPECIAL(Texture);
|
||||
fIntrinsicMap[String("equal")] = METAL(Equal);
|
||||
fIntrinsicMap[String("notEqual")] = METAL(NotEqual);
|
||||
fIntrinsicMap[String("lessThan")] = METAL(LessThan);
|
||||
@ -405,6 +409,51 @@ void MetalCodeGenerator::writeSpecialIntrinsic(const FunctionCall & c, SpecialIn
|
||||
this->write(", " + tmpX + " - " + tmpY + " * floor(" + tmpX + " / " + tmpY + "))");
|
||||
break;
|
||||
}
|
||||
// GLSL declares scalar versions of most geometric intrinsics, but these don't exist in MSL
|
||||
case kDistance_SpecialIntrinsic: {
|
||||
if (arguments[0]->type().columns() == 1) {
|
||||
this->write("abs(");
|
||||
this->writeExpression(*arguments[0], kAdditive_Precedence);
|
||||
this->write(" - ");
|
||||
this->writeExpression(*arguments[1], kAdditive_Precedence);
|
||||
this->write(")");
|
||||
} else {
|
||||
this->write("distance(");
|
||||
this->writeExpression(*arguments[0], kSequence_Precedence);
|
||||
this->write(", ");
|
||||
this->writeExpression(*arguments[1], kSequence_Precedence);
|
||||
this->write(")");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kDot_SpecialIntrinsic: {
|
||||
if (arguments[0]->type().columns() == 1) {
|
||||
this->write("(");
|
||||
this->writeExpression(*arguments[0], kMultiplicative_Precedence);
|
||||
this->write(" * ");
|
||||
this->writeExpression(*arguments[1], kMultiplicative_Precedence);
|
||||
this->write(")");
|
||||
} else {
|
||||
this->write("dot(");
|
||||
this->writeExpression(*arguments[0], kSequence_Precedence);
|
||||
this->write(", ");
|
||||
this->writeExpression(*arguments[1], kSequence_Precedence);
|
||||
this->write(")");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kLength_SpecialIntrinsic: {
|
||||
this->write(arguments[0]->type().columns() == 1 ? "abs(" : "length(");
|
||||
this->writeExpression(*arguments[0], kSequence_Precedence);
|
||||
this->write(")");
|
||||
break;
|
||||
}
|
||||
case kNormalize_SpecialIntrinsic: {
|
||||
this->write(arguments[0]->type().columns() == 1 ? "sign(" : "normalize(");
|
||||
this->writeExpression(*arguments[0], kSequence_Precedence);
|
||||
this->write(")");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ABORT("unsupported special intrinsic kind");
|
||||
}
|
||||
|
@ -104,8 +104,12 @@ protected:
|
||||
};
|
||||
|
||||
enum SpecialIntrinsic {
|
||||
kTexture_SpecialIntrinsic,
|
||||
kDistance_SpecialIntrinsic,
|
||||
kDot_SpecialIntrinsic,
|
||||
kLength_SpecialIntrinsic,
|
||||
kMod_SpecialIntrinsic,
|
||||
kNormalize_SpecialIntrinsic,
|
||||
kTexture_SpecialIntrinsic,
|
||||
};
|
||||
|
||||
enum MetalIntrinsic {
|
||||
|
@ -743,6 +743,11 @@ SpvId SPIRVCodeGenerator::writeIntrinsicCall(const FunctionCall& c, OutputStream
|
||||
return result;
|
||||
}
|
||||
case kSPIRV_IntrinsicKind: {
|
||||
// GLSL supports dot(float, float), but SPIR-V does not. Convert it to FMul
|
||||
if (intrinsicId == SpvOpDot &&
|
||||
arguments[0]->type().typeKind() == Type::TypeKind::kScalar) {
|
||||
intrinsicId = SpvOpFMul;
|
||||
}
|
||||
SpvId result = this->nextId();
|
||||
std::vector<SpvId> argumentIds;
|
||||
for (size_t i = 0; i < arguments.size(); i++) {
|
||||
|
21
tests/sksl/shared/GeometricIntrinsics.sksl
Normal file
21
tests/sksl/shared/GeometricIntrinsics.sksl
Normal file
@ -0,0 +1,21 @@
|
||||
float scalar(float x, float y) {
|
||||
x = length(x);
|
||||
x = distance(x, y);
|
||||
x = dot(x, y);
|
||||
x = normalize(x);
|
||||
return x;
|
||||
}
|
||||
|
||||
float2 vector(float2 x, float2 y) {
|
||||
x = length(x).xx;
|
||||
x = distance(x, y).xx;
|
||||
x = dot(x, y).xx;
|
||||
x = normalize(x);
|
||||
return x;
|
||||
}
|
||||
|
||||
void main() {
|
||||
float x = scalar(1, 2);
|
||||
float2 y = vector(float2(1, 2), float2(3, 4));
|
||||
sk_FragColor = half4(half(x), half2(y), 1);
|
||||
}
|
91
tests/sksl/shared/golden/GeometricIntrinsics.asm.frag
Normal file
91
tests/sksl/shared/golden/GeometricIntrinsics.asm.frag
Normal file
@ -0,0 +1,91 @@
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main" %sk_FragColor %sk_Clockwise
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpName %sk_FragColor "sk_FragColor"
|
||||
OpName %sk_Clockwise "sk_Clockwise"
|
||||
OpName %main "main"
|
||||
OpName %_0_scalar "_0_scalar"
|
||||
OpName %_1_x "_1_x"
|
||||
OpName %x "x"
|
||||
OpName %_2_vector "_2_vector"
|
||||
OpName %_3_x "_3_x"
|
||||
OpName %y "y"
|
||||
OpDecorate %sk_FragColor RelaxedPrecision
|
||||
OpDecorate %sk_FragColor Location 0
|
||||
OpDecorate %sk_FragColor Index 0
|
||||
OpDecorate %sk_Clockwise RelaxedPrecision
|
||||
OpDecorate %sk_Clockwise BuiltIn FrontFacing
|
||||
%float = OpTypeFloat 32
|
||||
%v4float = OpTypeVector %float 4
|
||||
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
||||
%sk_FragColor = OpVariable %_ptr_Output_v4float Output
|
||||
%bool = OpTypeBool
|
||||
%_ptr_Input_bool = OpTypePointer Input %bool
|
||||
%sk_Clockwise = OpVariable %_ptr_Input_bool Input
|
||||
%void = OpTypeVoid
|
||||
%11 = OpTypeFunction %void
|
||||
%_ptr_Function_float = OpTypePointer Function %float
|
||||
%float_1 = OpConstant %float 1
|
||||
%float_2 = OpConstant %float 2
|
||||
%v2float = OpTypeVector %float 2
|
||||
%_ptr_Function_v2float = OpTypePointer Function %v2float
|
||||
%32 = OpConstantComposite %v2float %float_1 %float_2
|
||||
%34 = OpConstantComposite %v2float %float_1 %float_2
|
||||
%float_3 = OpConstant %float 3
|
||||
%float_4 = OpConstant %float 4
|
||||
%38 = OpConstantComposite %v2float %float_3 %float_4
|
||||
%44 = OpConstantComposite %v2float %float_3 %float_4
|
||||
%float_1_0 = OpConstant %float 1
|
||||
%main = OpFunction %void None %11
|
||||
%12 = OpLabel
|
||||
%_0_scalar = OpVariable %_ptr_Function_float Function
|
||||
%_1_x = OpVariable %_ptr_Function_float Function
|
||||
%x = OpVariable %_ptr_Function_float Function
|
||||
%_2_vector = OpVariable %_ptr_Function_v2float Function
|
||||
%_3_x = OpVariable %_ptr_Function_v2float Function
|
||||
%y = OpVariable %_ptr_Function_v2float Function
|
||||
OpStore %_1_x %float_1
|
||||
%17 = OpExtInst %float %1 Length %float_1
|
||||
OpStore %_1_x %17
|
||||
%19 = OpLoad %float %_1_x
|
||||
%18 = OpExtInst %float %1 Distance %19 %float_2
|
||||
OpStore %_1_x %18
|
||||
%22 = OpLoad %float %_1_x
|
||||
%21 = OpFMul %float %22 %float_2
|
||||
OpStore %_1_x %21
|
||||
%24 = OpLoad %float %_1_x
|
||||
%23 = OpExtInst %float %1 Normalize %24
|
||||
OpStore %_1_x %23
|
||||
%25 = OpLoad %float %_1_x
|
||||
OpStore %_0_scalar %25
|
||||
%27 = OpLoad %float %_0_scalar
|
||||
OpStore %x %27
|
||||
OpStore %_3_x %32
|
||||
%33 = OpExtInst %float %1 Length %34
|
||||
%35 = OpCompositeConstruct %v2float %33 %33
|
||||
OpStore %_3_x %35
|
||||
%37 = OpLoad %v2float %_3_x
|
||||
%36 = OpExtInst %float %1 Distance %37 %38
|
||||
%41 = OpCompositeConstruct %v2float %36 %36
|
||||
OpStore %_3_x %41
|
||||
%43 = OpLoad %v2float %_3_x
|
||||
%42 = OpDot %float %43 %44
|
||||
%45 = OpCompositeConstruct %v2float %42 %42
|
||||
OpStore %_3_x %45
|
||||
%47 = OpLoad %v2float %_3_x
|
||||
%46 = OpExtInst %v2float %1 Normalize %47
|
||||
OpStore %_3_x %46
|
||||
%48 = OpLoad %v2float %_3_x
|
||||
OpStore %_2_vector %48
|
||||
%50 = OpLoad %v2float %_2_vector
|
||||
OpStore %y %50
|
||||
%51 = OpLoad %float %x
|
||||
%52 = OpLoad %v2float %y
|
||||
%53 = OpCompositeExtract %float %52 0
|
||||
%54 = OpCompositeExtract %float %52 1
|
||||
%56 = OpCompositeConstruct %v4float %51 %53 %54 %float_1_0
|
||||
OpStore %sk_FragColor %56
|
||||
OpReturn
|
||||
OpFunctionEnd
|
27
tests/sksl/shared/golden/GeometricIntrinsics.glsl
Normal file
27
tests/sksl/shared/golden/GeometricIntrinsics.glsl
Normal file
@ -0,0 +1,27 @@
|
||||
|
||||
out vec4 sk_FragColor;
|
||||
void main() {
|
||||
float _0_scalar;
|
||||
float _1_x = 1.0;
|
||||
{
|
||||
_1_x = length(1.0);
|
||||
_1_x = distance(_1_x, 2.0);
|
||||
_1_x = dot(_1_x, 2.0);
|
||||
_1_x = normalize(_1_x);
|
||||
_0_scalar = _1_x;
|
||||
}
|
||||
float x = _0_scalar;
|
||||
|
||||
vec2 _2_vector;
|
||||
vec2 _3_x = vec2(1.0, 2.0);
|
||||
{
|
||||
_3_x = vec2(length(vec2(1.0, 2.0)));
|
||||
_3_x = vec2(distance(_3_x, vec2(3.0, 4.0)));
|
||||
_3_x = vec2(dot(_3_x, vec2(3.0, 4.0)));
|
||||
_3_x = normalize(_3_x);
|
||||
_2_vector = _3_x;
|
||||
}
|
||||
vec2 y = _2_vector;
|
||||
|
||||
sk_FragColor = vec4(x, y, 1.0);
|
||||
}
|
36
tests/sksl/shared/golden/GeometricIntrinsics.metal
Normal file
36
tests/sksl/shared/golden/GeometricIntrinsics.metal
Normal file
@ -0,0 +1,36 @@
|
||||
#include <metal_stdlib>
|
||||
#include <simd/simd.h>
|
||||
using namespace metal;
|
||||
struct Inputs {
|
||||
};
|
||||
struct Outputs {
|
||||
float4 sk_FragColor [[color(0)]];
|
||||
};
|
||||
fragment Outputs fragmentMain(Inputs _in [[stage_in]], bool _frontFacing [[front_facing]], float4 _fragCoord [[position]]) {
|
||||
Outputs _outputStruct;
|
||||
thread Outputs* _out = &_outputStruct;
|
||||
float _0_scalar;
|
||||
float _1_x = 1.0;
|
||||
{
|
||||
_1_x = abs(1.0);
|
||||
_1_x = abs(_1_x - 2.0);
|
||||
_1_x = (_1_x * 2.0);
|
||||
_1_x = sign(_1_x);
|
||||
_0_scalar = _1_x;
|
||||
}
|
||||
float x = _0_scalar;
|
||||
|
||||
float2 _2_vector;
|
||||
float2 _3_x = float2(1.0, 2.0);
|
||||
{
|
||||
_3_x = float2(length(float2(1.0, 2.0)));
|
||||
_3_x = float2(distance(_3_x, float2(3.0, 4.0)));
|
||||
_3_x = float2(dot(_3_x, float2(3.0, 4.0)));
|
||||
_3_x = normalize(_3_x);
|
||||
_2_vector = _3_x;
|
||||
}
|
||||
float2 y = _2_vector;
|
||||
|
||||
_out->sk_FragColor = float4(x, y, 1.0);
|
||||
return *_out;
|
||||
}
|
Loading…
Reference in New Issue
Block a user