Browse Source

chore: cherry-pick 3910c9f5cde6 from chromium (#28094)

* chore: cherry-pick 3910c9f5cde6 from chromium

* update patches

Co-authored-by: Electron Bot <[email protected]>
Pedro Pontes 4 years ago
parent
commit
e744ac042a
2 changed files with 225 additions and 0 deletions
  1. 1 0
      patches/chromium/.patches
  2. 224 0
      patches/chromium/cherry-pick-3910c9f5cde6.patch

+ 1 - 0
patches/chromium/.patches

@@ -152,3 +152,4 @@ cherry-pick-7e0e52df283c.patch
 cherry-pick-dea071d8b30f.patch
 cherry-pick-a4faa754a9ef.patch
 mediarecorder_tolerate_non-gmb_nv12_frames_for_h264.patch
+cherry-pick-3910c9f5cde6.patch

+ 224 - 0
patches/chromium/cherry-pick-3910c9f5cde6.patch

@@ -0,0 +1,224 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Raymond Toy <[email protected]>
+Date: Tue, 2 Mar 2021 15:15:29 +0000
+Subject: Convert AudioParam NaN values to the default value
+
+If any output value of an AudioParam (including the intrinsic values
+and any inputs to the AudioParam), should be NaN, replace the NaN
+value with the associated defaultValue.
+
+This causes some slowdowns so SIMD/NEON code was added to mitigate the
+degradation.  There is still some slowdown, but the worst case is now
+about 7% slower on x86 and 10% on arm. Generally, the slowdown is less
+than 2% and 5%, respectively.  (Perversely, some results got faster,
+and the differences are statistically significant.)
+
+Full details can be found at
+https://docs.google.com/spreadsheets/d/1EhbLHm-9cUoEO5aj1vYemVBLQ3Dh4dCJPPLTfZPrZt4/edit?usp=sharing
+
+Manually tested the test case from the bug and the issue no longer
+occurs.
+
+(cherry picked from commit ab1862017b5717271a28376659944dddc602195c)
+
+(cherry picked from commit eb0c0353bf245885797d8ce0d1b864d88a381fbb)
+
+Bug: 1170531
+Change-Id: I00d902b40a9ef9da990c6d68b664b1dcfc31b091
+Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2658724
+Commit-Queue: Raymond Toy <[email protected]>
+Reviewed-by: Hongchan Choi <[email protected]>
+Cr-Original-Original-Commit-Position: refs/heads/master@{#851733}
+Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2686369
+Reviewed-by: Raymond Toy <[email protected]>
+Cr-Original-Commit-Position: refs/branch-heads/4389@{#880}
+Cr-Original-Branched-From: 9251c5db2b6d5a59fe4eac7aafa5fed37c139bb7-refs/heads/master@{#843830}
+Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2727697
+Reviewed-by: Victor-Gabriel Savu <[email protected]>
+Commit-Queue: Artem Sumaneev <[email protected]>
+Cr-Commit-Position: refs/branch-heads/4240@{#1551}
+Cr-Branched-From: f297677702651916bbf65e59c0d4bbd4ce57d1ee-refs/heads/master@{#800218}
+
+diff --git a/third_party/blink/renderer/modules/webaudio/audio_param.cc b/third_party/blink/renderer/modules/webaudio/audio_param.cc
+index c5d329479a412d52ee39167ff841b1cea417a217..135588f56ebceabd3e0a12f9f506955bb58b20ca 100644
+--- a/third_party/blink/renderer/modules/webaudio/audio_param.cc
++++ b/third_party/blink/renderer/modules/webaudio/audio_param.cc
+@@ -25,6 +25,7 @@
+ 
+ #include "third_party/blink/renderer/modules/webaudio/audio_param.h"
+ 
++#include "build/build_config.h"
+ #include "third_party/blink/renderer/core/inspector/console_message.h"
+ #include "third_party/blink/renderer/modules/webaudio/audio_graph_tracer.h"
+ #include "third_party/blink/renderer/modules/webaudio/audio_node.h"
+@@ -235,6 +236,49 @@ void AudioParamHandler::CalculateSampleAccurateValues(
+   CalculateFinalValues(values, number_of_values, IsAudioRate());
+ }
+ 
++// Replace NaN values in |values| with |default_value|.
++static void HandleNaNValues(float* values,
++                            unsigned number_of_values,
++                            float default_value) {
++  unsigned k = 0;
++#if defined(ARCH_CPU_X86_FAMILY)
++  if (number_of_values >= 4) {
++    __m128 defaults = _mm_set1_ps(default_value);
++    for (k = 0; k < number_of_values; k += 4) {
++      __m128 v = _mm_loadu_ps(values + k);
++      // cmpuord returns all 1's if v is NaN for each elmeent of v.
++      __m128 isnan = _mm_cmpunord_ps(v, v);
++      // Replace NaN parts with default.
++      __m128 result = _mm_and_ps(isnan, defaults);
++      // Merge in the parts that aren't NaN
++      result = _mm_or_ps(_mm_andnot_ps(isnan, v), result);
++      _mm_storeu_ps(values + k, result);
++    }
++  }
++#elif defined(CPU_ARM_NEON)
++  if (number_of_values >= 4) {
++    uint32x4_t defaults = static_cast<uint32x4_t>(vdupq_n_f32(default_value));
++    for (k = 0; k < number_of_values; k += 4) {
++      float32x4_t v = vld1q_f32(values + k);
++      // Returns true (all ones) if v is not NaN
++      uint32x4_t is_not_nan = vceqq_f32(v, v);
++      // Get the parts that are not NaN
++      uint32x4_t result = vandq_u32(is_not_nan, v);
++      // Replace the parts that are NaN with the default and merge with previous
++      // result.  (Note: vbic_u32(x, y) = x and not y)
++      result = vorrq_u32(result, vbicq_u32(defaults, is_not_nan));
++      vst1q_f32(values + k, static_cast<float32x4_t>(result));
++    }
++  }
++#endif
++
++  for (; k < number_of_values; ++k) {
++    if (std::isnan(values[k])) {
++      values[k] = default_value;
++    }
++  }
++}
++
+ void AudioParamHandler::CalculateFinalValues(float* values,
+                                              unsigned number_of_values,
+                                              bool sample_accurate) {
+@@ -297,10 +341,21 @@ void AudioParamHandler::CalculateFinalValues(float* values,
+       }
+     }
+ 
+-    // Clamp the values now to the nominal range
+     float min_value = MinValue();
+     float max_value = MaxValue();
+ 
++    if (NumberOfRenderingConnections() > 0) {
++      // AudioParams by themselves don't produce NaN because of the finite min
++      // and max values.  But an input to an AudioParam could have NaNs.
++      //
++      // NaN values in AudioParams must be replaced by the AudioParam's
++      // defaultValue.  Then these values must be clamped to lie in the nominal
++      // range between the AudioParam's minValue and maxValue.
++      //
++      // See https://webaudio.github.io/web-audio-api/#computation-of-value.
++      HandleNaNValues(values, number_of_values, DefaultValue());
++    }
++
+     vector_math::Vclip(values, 1, &min_value, &max_value, values, 1,
+                        number_of_values);
+   }
+diff --git a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioparam-interface/nan-param.html b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioparam-interface/nan-param.html
+new file mode 100644
+index 0000000000000000000000000000000000000000..e9b8f0accbd1b0359275615f3ef12bd7e9317c4f
+--- /dev/null
++++ b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioparam-interface/nan-param.html
+@@ -0,0 +1,92 @@
++<!doctype html>
++<html>
++  <head>
++    <title>Test Flushing of NaN to Zero in AudioParams</title>
++    <script src="/resources/testharness.js"></script>
++    <script src="/resources/testharnessreport.js"></script>
++    <script src="/webaudio/resources/audit-util.js"></script>
++    <script src="/webaudio/resources/audit.js"></script>
++  </head>
++
++  <body>
++    <script>
++      let audit = Audit.createTaskRunner();
++
++      // See
++      // https://webaudio.github.io/web-audio-api/#computation-of-value.
++      //
++      // The computed value must replace NaN values in the output with
++      // the default value of the param.
++      audit.define('AudioParam NaN', async (task, should) => {
++        // For testing, we only need a small number of frames; and
++        // a low sample rate is perfectly fine.  Use two channels.
++        // The first channel is for the AudioParam output.  The
++        // second channel is for the AudioParam input.
++        let context = new OfflineAudioContext(
++            {numberOfChannels: 2, length: 256, sampleRate: 8192});
++        let merger = new ChannelMergerNode(
++            context, {numberOfInputs: context.destination.channelCount});
++        merger.connect(context.destination);
++
++        // A constant source with a huge value.
++        let mod = new ConstantSourceNode(context, {offset: 1e30});
++
++        // Gain nodes with a huge positive gain and huge negative
++        // gain.  Combined with the huge offset in |mod|, the
++        // output of the gain nodes are +Infinity and -Infinity.
++        let gainPos = new GainNode(context, {gain: 1e30});
++        let gainNeg = new GainNode(context, {gain: -1e30});
++
++        mod.connect(gainPos);
++        mod.connect(gainNeg);
++
++        // Connect these to the second merger channel. This is a
++        // sanity check that the AudioParam input really is NaN.
++        gainPos.connect(merger, 0, 1);
++        gainNeg.connect(merger, 0, 1);
++
++        // Source whose AudioParam is connected to the graph
++        // that produces NaN values.  Use a non-default value offset
++        // just in case something is wrong we get default for some
++        // other reason.
++        let src = new ConstantSourceNode(context, {offset: 100});
++
++        gainPos.connect(src.offset);
++        gainNeg.connect(src.offset);
++
++        // AudioParam output goes to channel 1 of the destination.
++        src.connect(merger, 0, 0);
++
++        // Let's go!
++        mod.start();
++        src.start();
++
++        let buffer = await context.startRendering();
++
++        let input = buffer.getChannelData(1);
++        let output = buffer.getChannelData(0);
++
++        // Have to test manually for NaN values in the input because
++        // NaN fails all comparisons.
++        let isNaN = true;
++        for (let k = 0; k < input.length; ++k) {
++          if (!Number.isNaN(input[k])) {
++            isNaN = false;
++            break;
++          }
++        }
++
++        should(isNaN, 'AudioParam input contains only NaN').beTrue();
++
++        // Output of the AudioParam should have all NaN values
++        // replaced by the default.
++        should(output, 'AudioParam output')
++            .beConstantValueOf(src.offset.defaultValue);
++
++        task.done();
++      });
++
++      audit.run();
++    </script>
++  </body>
++</html>