Implement log and log2 intrinsics in SkRP.
These already existed in Raster Pipeline, so they just needed to be
wired up into the SkRP builder and codegen. I also ported over the
SkVM unit test for log2 since we didn't have an RP equivalent.
Change-Id: Ida15486084ebd76f50f9aaa3c3c0e7d0c1b399f8
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/658080
Auto-Submit: John Stiles <johnstiles@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: John Stiles <johnstiles@google.com>
diff --git a/src/core/SkRasterPipelineOpList.h b/src/core/SkRasterPipelineOpList.h
index d1246b4..2d4a4f8 100644
--- a/src/core/SkRasterPipelineOpList.h
+++ b/src/core/SkRasterPipelineOpList.h
@@ -130,6 +130,7 @@
M(sin_float) M(cos_float) M(tan_float) \
M(asin_float) M(acos_float) M(atan_float) M(atan2_n_floats) \
M(sqrt_float) M(pow_n_floats) M(exp_float) \
+ M(log_float) M(log2_float) \
M(copy_constant) M(copy_2_constants) M(copy_3_constants) M(copy_4_constants) \
M(copy_slot_masked) M(copy_2_slots_masked) M(copy_3_slots_masked) M(copy_4_slots_masked) \
M(copy_from_indirect_unmasked) M(copy_from_indirect_uniform_unmasked) \
diff --git a/src/opts/SkRasterPipeline_opts.h b/src/opts/SkRasterPipeline_opts.h
index 3eaeed0..49ab5de 100644
--- a/src/opts/SkRasterPipeline_opts.h
+++ b/src/opts/SkRasterPipeline_opts.h
@@ -1035,7 +1035,7 @@
SI F fract(F v) { return v - floor_(v); }
-// See http://www.machinedlearnings.com/2011/06/fast-approximate-logarithm-exponential.html.
+// See http://www.machinedlearnings.com/2011/06/fast-approximate-logarithm-exponential.html
SI F approx_log2(F x) {
// e - 127 is a fair approximation of log2(x) in its own right...
F e = cast(sk_bit_cast<U32>(x)) * (1.0f / (1<<23));
@@ -3719,6 +3719,8 @@
STAGE_TAIL(atan_float, F* dst) { *dst = atan_(*dst); }
STAGE_TAIL(sqrt_float, F* dst) { *dst = sqrt_(*dst); }
STAGE_TAIL(exp_float, F* dst) { *dst = approx_exp(*dst); }
+STAGE_TAIL(log_float, F* dst) { *dst = approx_log(*dst); }
+STAGE_TAIL(log2_float, F* dst) { *dst = approx_log2(*dst); }
// Binary operations take two adjacent inputs, and write their output in the first position.
template <typename T, void (*ApplyFn)(T*, T*)>
diff --git a/src/sksl/codegen/SkSLRasterPipelineBuilder.cpp b/src/sksl/codegen/SkSLRasterPipelineBuilder.cpp
index 395cb94..b42a585 100644
--- a/src/sksl/codegen/SkSLRasterPipelineBuilder.cpp
+++ b/src/sksl/codegen/SkSLRasterPipelineBuilder.cpp
@@ -42,6 +42,8 @@
case BuilderOp::atan_float: \
case BuilderOp::cos_float: \
case BuilderOp::exp_float: \
+ case BuilderOp::log_float: \
+ case BuilderOp::log2_float: \
case BuilderOp::sin_float: \
case BuilderOp::sqrt_float: \
case BuilderOp::tan_float
@@ -2045,6 +2047,8 @@
case POp::ceil_float:
case POp::cos_float:
case POp::exp_float:
+ case POp::log_float:
+ case POp::log2_float:
case POp::floor_float:
case POp::sin_float:
case POp::sqrt_float:
@@ -2486,6 +2490,14 @@
opText = opArg1 + " = exp(" + opArg1 + ")";
break;
+ case POp::log_float:
+ opText = opArg1 + " = log(" + opArg1 + ")";
+ break;
+
+ case POp::log2_float:
+ opText = opArg1 + " = log2(" + opArg1 + ")";
+ break;
+
case POp::pow_n_floats:
opText = opArg1 + " = pow(" + opArg1 + ", " + opArg2 + ")";
break;
diff --git a/src/sksl/codegen/SkSLRasterPipelineCodeGenerator.cpp b/src/sksl/codegen/SkSLRasterPipelineCodeGenerator.cpp
index 5a0e7d1..396f4b6 100644
--- a/src/sksl/codegen/SkSLRasterPipelineCodeGenerator.cpp
+++ b/src/sksl/codegen/SkSLRasterPipelineCodeGenerator.cpp
@@ -2570,6 +2570,20 @@
return this->pushExpression(arg0) &&
this->pushLengthIntrinsic(arg0.type().slotCount());
+ case IntrinsicKind::k_log_IntrinsicKind:
+ if (!this->pushExpression(arg0)) {
+ return unsupported();
+ }
+ fBuilder.unary_op(BuilderOp::log_float, arg0.type().slotCount());
+ return true;
+
+ case IntrinsicKind::k_log2_IntrinsicKind:
+ if (!this->pushExpression(arg0)) {
+ return unsupported();
+ }
+ fBuilder.unary_op(BuilderOp::log2_float, arg0.type().slotCount());
+ return true;
+
case IntrinsicKind::k_normalize_IntrinsicKind:
// Implement normalize as `x / length(x)`. First, push the expression.
if (!this->pushExpression(arg0)) {
diff --git a/tests/SkRasterPipelineOptsTest.cpp b/tests/SkRasterPipelineOptsTest.cpp
index d4e4cea..162bf2d 100644
--- a/tests/SkRasterPipelineOptsTest.cpp
+++ b/tests/SkRasterPipelineOptsTest.cpp
@@ -175,3 +175,16 @@
}
}
}
+
+DEF_TEST(SkRasterPipelineOpts_Log2, r) {
+ using F = SK_OPTS_NS::F;
+
+ constexpr float kTolerance = 0.001f;
+ for (float value : {0.25f, 0.5f, 1.0f, 2.0f, 4.0f, 8.0f}) {
+ F result = SK_OPTS_NS::approx_log2(value);
+ F expected = std::log2(value);
+ F delta = SK_OPTS_NS::abs_(expected - result);
+
+ REPORTER_ASSERT(r, SK_OPTS_NS::all(delta < kTolerance));
+ }
+}
diff --git a/tests/sksl/intrinsics/Log.skrp b/tests/sksl/intrinsics/Log.skrp
index 3ef3d71..eaa03e3 100644
--- a/tests/sksl/intrinsics/Log.skrp
+++ b/tests/sksl/intrinsics/Log.skrp
@@ -1,4 +1,60 @@
-### Compilation failed:
-
-error: code is not supported
-1 error
+ 1. store_src_rg coords = src.rg
+ 2. init_lane_masks CondMask = LoopMask = RetMask = true
+ 3. copy_constant $4 = inputVal(0)
+ 4. log_float $4 = log($4)
+ 5. copy_constant $5 = expected(0)
+ 6. cmpeq_float $4 = equal($4, $5)
+ 7. copy_2_constants $5..6 = inputVal(0..1)
+ 8. log_float $5 = log($5)
+ 9. log_float $6 = log($6)
+ 10. copy_2_constants $7..8 = expected(0..1)
+ 11. cmpeq_2_floats $5..6 = equal($5..6, $7..8)
+ 12. bitwise_and_int $5 &= $6
+ 13. bitwise_and_int $4 &= $5
+ 14. copy_3_constants $5..7 = inputVal(0..2)
+ 15. log_float $5 = log($5)
+ 16. log_float $6 = log($6)
+ 17. log_float $7 = log($7)
+ 18. copy_3_constants $8..10 = expected(0..2)
+ 19. cmpeq_3_floats $5..7 = equal($5..7, $8..10)
+ 20. bitwise_and_int $6 &= $7
+ 21. bitwise_and_int $5 &= $6
+ 22. bitwise_and_int $4 &= $5
+ 23. copy_4_constants $5..8 = inputVal
+ 24. log_float $5 = log($5)
+ 25. log_float $6 = log($6)
+ 26. log_float $7 = log($7)
+ 27. log_float $8 = log($8)
+ 28. copy_4_constants $9..12 = expected
+ 29. cmpeq_4_floats $5..8 = equal($5..8, $9..12)
+ 30. bitwise_and_2_ints $5..6 &= $7..8
+ 31. bitwise_and_int $5 &= $6
+ 32. bitwise_and_int $4 &= $5
+ 33. zero_slot_unmasked $5 = 0
+ 34. copy_constant $6 = expected(0)
+ 35. cmpeq_float $5 = equal($5, $6)
+ 36. bitwise_and_int $4 &= $5
+ 37. zero_2_slots_unmasked $5..6 = 0
+ 38. copy_2_constants $7..8 = expected(0..1)
+ 39. cmpeq_2_floats $5..6 = equal($5..6, $7..8)
+ 40. bitwise_and_int $5 &= $6
+ 41. bitwise_and_int $4 &= $5
+ 42. zero_3_slots_unmasked $5..7 = 0
+ 43. copy_3_constants $8..10 = expected(0..2)
+ 44. cmpeq_3_floats $5..7 = equal($5..7, $8..10)
+ 45. bitwise_and_int $6 &= $7
+ 46. bitwise_and_int $5 &= $6
+ 47. bitwise_and_int $4 &= $5
+ 48. zero_4_slots_unmasked $5..8 = 0
+ 49. copy_4_constants $9..12 = expected
+ 50. cmpeq_4_floats $5..8 = equal($5..8, $9..12)
+ 51. bitwise_and_2_ints $5..6 &= $7..8
+ 52. bitwise_and_int $5 &= $6
+ 53. bitwise_and_int $4 &= $5
+ 54. branch_if_no_active_lanes_eq branch +3 (label 0 at #57) if no lanes of $4 == 0xFFFFFFFF
+ 55. copy_4_constants $0..3 = colorGreen
+ 56. jump jump +3 (label 1 at #59)
+ 57. label label 0x00000000
+ 58. copy_4_constants $0..3 = colorRed
+ 59. label label 0x00000001
+ 60. load_src src.rgba = $0..3
diff --git a/tests/sksl/intrinsics/Log2.skrp b/tests/sksl/intrinsics/Log2.skrp
index 3ef3d71..bd4817c 100644
--- a/tests/sksl/intrinsics/Log2.skrp
+++ b/tests/sksl/intrinsics/Log2.skrp
@@ -1,4 +1,66 @@
-### Compilation failed:
-
-error: code is not supported
-1 error
+ 1. store_src_rg coords = src.rg
+ 2. init_lane_masks CondMask = LoopMask = RetMask = true
+ 3. copy_constant $4 = inputVal(0)
+ 4. log2_float $4 = log2($4)
+ 5. copy_constant $5 = expected(0)
+ 6. cmpeq_float $4 = equal($4, $5)
+ 7. copy_2_constants $5..6 = inputVal(0..1)
+ 8. log2_float $5 = log2($5)
+ 9. log2_float $6 = log2($6)
+ 10. copy_2_constants $7..8 = expected(0..1)
+ 11. cmpeq_2_floats $5..6 = equal($5..6, $7..8)
+ 12. bitwise_and_int $5 &= $6
+ 13. bitwise_and_int $4 &= $5
+ 14. copy_3_constants $5..7 = inputVal(0..2)
+ 15. log2_float $5 = log2($5)
+ 16. log2_float $6 = log2($6)
+ 17. log2_float $7 = log2($7)
+ 18. copy_3_constants $8..10 = expected(0..2)
+ 19. cmpeq_3_floats $5..7 = equal($5..7, $8..10)
+ 20. bitwise_and_int $6 &= $7
+ 21. bitwise_and_int $5 &= $6
+ 22. bitwise_and_int $4 &= $5
+ 23. copy_4_constants $5..8 = inputVal
+ 24. log2_float $5 = log2($5)
+ 25. log2_float $6 = log2($6)
+ 26. log2_float $7 = log2($7)
+ 27. log2_float $8 = log2($8)
+ 28. copy_4_constants $9..12 = expected
+ 29. cmpeq_4_floats $5..8 = equal($5..8, $9..12)
+ 30. bitwise_and_2_ints $5..6 &= $7..8
+ 31. bitwise_and_int $5 &= $6
+ 32. bitwise_and_int $4 &= $5
+ 33. zero_slot_unmasked $5 = 0
+ 34. copy_constant $6 = expected(0)
+ 35. cmpeq_float $5 = equal($5, $6)
+ 36. bitwise_and_int $4 &= $5
+ 37. zero_slot_unmasked $5 = 0
+ 38. copy_constant $6 = 0x3F800000 (1.0)
+ 39. copy_2_constants $7..8 = expected(0..1)
+ 40. cmpeq_2_floats $5..6 = equal($5..6, $7..8)
+ 41. bitwise_and_int $5 &= $6
+ 42. bitwise_and_int $4 &= $5
+ 43. zero_slot_unmasked $5 = 0
+ 44. copy_constant $6 = 0x3F800000 (1.0)
+ 45. copy_constant $7 = 0x40000000 (2.0)
+ 46. copy_3_constants $8..10 = expected(0..2)
+ 47. cmpeq_3_floats $5..7 = equal($5..7, $8..10)
+ 48. bitwise_and_int $6 &= $7
+ 49. bitwise_and_int $5 &= $6
+ 50. bitwise_and_int $4 &= $5
+ 51. zero_slot_unmasked $5 = 0
+ 52. copy_constant $6 = 0x3F800000 (1.0)
+ 53. copy_constant $7 = 0x40000000 (2.0)
+ 54. copy_constant $8 = 0x40400000 (3.0)
+ 55. copy_4_constants $9..12 = expected
+ 56. cmpeq_4_floats $5..8 = equal($5..8, $9..12)
+ 57. bitwise_and_2_ints $5..6 &= $7..8
+ 58. bitwise_and_int $5 &= $6
+ 59. bitwise_and_int $4 &= $5
+ 60. branch_if_no_active_lanes_eq branch +3 (label 0 at #63) if no lanes of $4 == 0xFFFFFFFF
+ 61. copy_4_constants $0..3 = colorGreen
+ 62. jump jump +3 (label 1 at #65)
+ 63. label label 0x00000000
+ 64. copy_4_constants $0..3 = colorRed
+ 65. label label 0x00000001
+ 66. load_src src.rgba = $0..3