Title: [294864] trunk
Revision
294864
Author
[email protected]
Date
2022-05-25 20:15:16 -0700 (Wed, 25 May 2022)

Log Message

Capturing a canvas that is not in the DOM can lead to erratic frame rates or no frame emission at all
https://bugs.webkit.org/show_bug.cgi?id=240380

Patch by Dan Glastonbury <[email protected]> on 2022-05-25
Reviewed by Simon Fraser.

* Source/WebCore/dom/Document.cpp:
(WebCore::Document::canvasChanged):
Schedule a rendering update whenever a canvas with out a rect needing display
preparation is added. This ensures that the prepareForDisplay is called on all
pending canvases, since this is handled in doAfterUpdateRendering.
* Source/WebCore/dom/Document.h:
Update size of RenderingUpdateState to accomodate PrepareCanvasesForDisplay.
* Source/WebCore/page/Page.cpp:
* Source/WebCore/page/Page.h:
Introduce new RenderingUpdateStep, PrepareCanvasesForDisplay, which signals that
prepareCanvasesForDisplayInNeeded() needs to be called from
doAfterRenderingUpdate(). Update size of RenderingUpdateState to accomodate
PrepareCanvasesForDisplay.
* LayoutTests/fast/mediacapturefromelement/CanvasCaptureMediaStream-capture-out-of-DOM-canvas-expected.txt: Added.
* LayoutTests/fast/mediacapturefromelement/CanvasCaptureMediaStream-capture-out-of-DOM-canvas.html:
Test that frame rate of captured video from out-of-DOM canvas is with in 25% of
the generating frame rate.

Canonical link: https://commits.webkit.org/250996@main

Modified Paths

Added Paths

Diff

Added: trunk/LayoutTests/fast/mediacapturefromelement/CanvasCaptureMediaStream-capture-out-of-DOM-canvas-expected.txt (0 => 294864)


--- trunk/LayoutTests/fast/mediacapturefromelement/CanvasCaptureMediaStream-capture-out-of-DOM-canvas-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/mediacapturefromelement/CanvasCaptureMediaStream-capture-out-of-DOM-canvas-expected.txt	2022-05-26 03:15:16 UTC (rev 294864)
@@ -0,0 +1,4 @@
+
+
+PASS check frame of capture canvas is sufficient
+

Added: trunk/LayoutTests/fast/mediacapturefromelement/CanvasCaptureMediaStream-capture-out-of-DOM-canvas.html (0 => 294864)


--- trunk/LayoutTests/fast/mediacapturefromelement/CanvasCaptureMediaStream-capture-out-of-DOM-canvas.html	                        (rev 0)
+++ trunk/LayoutTests/fast/mediacapturefromelement/CanvasCaptureMediaStream-capture-out-of-DOM-canvas.html	2022-05-26 03:15:16 UTC (rev 294864)
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="utf-8">
+    <title>Capture canvas to video track framerate</title>
+    <script src=""
+    <script src=""
+    <script src=""
+</head>
+<body>
+    <video id="video" autoplay playsInline controls width="200px"></video>
+    <script>
+promise_test(async (t) => {
+    const canvas = document.createElement('canvas');
+    canvas.width = 200;
+    canvas.height = 200;
+
+    const ctx = canvas.getContext('2d');
+
+    let frames = 0;
+    const loop = () => {
+        frames += 1;
+        ctx.fillStyle = (ctx.fillStyle !== '#ff0000') ? 'red' : 'green';
+        ctx.fillRect(0, 0, canvas.width, canvas.height);
+        setTimeout(loop, 1000/30);
+    }
+
+    loop();
+
+    const stream = canvas.captureStream();
+    video.srcObject = stream;
+    video.play();
+
+    const frameRate = await computeFrameRate(stream, video);
+
+    // If the test was unable to generate any frames then nothing meaningful can be determined. Our test only makes sense if we have sufficient fps.
+    if (frames <= 10)
+        return;
+
+    // Check that the difference in expected and observed frame rates is < 25%
+    const percentDiff = Math.abs(frameRate - frames) / frames * 100;
+    assert_less_than(percentDiff, 25, `frame rate difference between ${frames} & ${frameRate} is below 25%`);
+}, "check frame of capture canvas is sufficient");
+    </script>
+</body>
+</html>
\ No newline at end of file

Modified: trunk/LayoutTests/platform/win/TestExpectations (294863 => 294864)


--- trunk/LayoutTests/platform/win/TestExpectations	2022-05-26 02:56:49 UTC (rev 294863)
+++ trunk/LayoutTests/platform/win/TestExpectations	2022-05-26 03:15:16 UTC (rev 294864)
@@ -3704,6 +3704,8 @@
 fast/events/webkit-media-key-events-constructor.html [ Failure ]
 fast/forms/validation-message-maxLength.html [ Failure ]
 fast/mediacapturefromelement/CanvasCaptureMediaStream-2d-events.html [ Failure ]
+# canvas.captureStream is not a function
+webkit.org/b/240380 fast/mediacapturefromelement/CanvasCaptureMediaStream-capture-out-of-DOM-canvas.html [ Failure ]
 fast/mediacapturefromelement/CanvasCaptureMediaStream-capture-out-of-DOM-element.html [ Failure ]
 fast/mediacapturefromelement/CanvasCaptureMediaStream-clone-track.html [ Failure ]
 fast/mediacapturefromelement/CanvasCaptureMediaStream-creation.html [ Failure ]

Modified: trunk/Source/WebCore/dom/Document.cpp (294863 => 294864)


--- trunk/Source/WebCore/dom/Document.cpp	2022-05-26 02:56:49 UTC (rev 294863)
+++ trunk/Source/WebCore/dom/Document.cpp	2022-05-26 03:15:16 UTC (rev 294864)
@@ -9095,13 +9095,20 @@
     m_canvasesNeedingDisplayPreparation.remove(canvas);
 }
 
-void Document::canvasChanged(CanvasBase& canvasBase, const std::optional<FloatRect>&)
+void Document::canvasChanged(CanvasBase& canvasBase, const std::optional<FloatRect>& changedRect)
 {
     if (!is<HTMLCanvasElement>(canvasBase))
         return;
     auto& canvas = downcast<HTMLCanvasElement>(canvasBase);
-    if (canvas.needsPreparationForDisplay())
+    if (canvas.needsPreparationForDisplay()) {
         m_canvasesNeedingDisplayPreparation.add(canvas);
+        // Schedule a rendering update to force handling of prepareForDisplay
+        // for any queued canvases. This is especially important for any canvas
+        // that is not in the DOM, as those don't have a rect to invalidate to
+        // trigger an update. <http://bugs.webkit.org/show_bug.cgi?id=240380>.
+        if (!changedRect)
+            scheduleRenderingUpdate(RenderingUpdateStep::PrepareCanvasesForDisplay);
+    }
 }
 
 void Document::canvasDestroyed(CanvasBase& canvasBase)

Modified: trunk/Source/WebCore/dom/Document.h (294863 => 294864)


--- trunk/Source/WebCore/dom/Document.h	2022-05-26 02:56:49 UTC (rev 294863)
+++ trunk/Source/WebCore/dom/Document.h	2022-05-26 03:15:16 UTC (rev 294864)
@@ -265,7 +265,7 @@
 enum class MediaProducerMutedState : uint8_t;
 enum class RouteSharingPolicy : uint8_t;
 enum class ShouldOpenExternalURLsPolicy : uint8_t;
-enum class RenderingUpdateStep : uint16_t;
+enum class RenderingUpdateStep : uint32_t;
 enum class StyleColorOptions : uint8_t;
 enum class MutationObserverOptionType : uint8_t;
 

Modified: trunk/Source/WebCore/page/Page.cpp (294863 => 294864)


--- trunk/Source/WebCore/page/Page.cpp	2022-05-26 02:56:49 UTC (rev 294863)
+++ trunk/Source/WebCore/page/Page.cpp	2022-05-26 03:15:16 UTC (rev 294864)
@@ -1793,6 +1793,8 @@
 
     DebugPageOverlays::doAfterUpdateRendering(*this);
 
+    m_renderingUpdateRemainingSteps.last().remove(RenderingUpdateStep::PrepareCanvasesForDisplay);
+
     forEachDocument([] (Document& document) {
         document.prepareCanvasesForDisplayIfNeeded();
     });
@@ -3836,6 +3838,7 @@
     case RenderingUpdateStep::ScrollingTreeUpdate: ts << "ScrollingTreeUpdate"; break;
 #endif
     case RenderingUpdateStep::VideoFrameCallbacks: ts << "VideoFrameCallbacks"; break;
+    case RenderingUpdateStep::PrepareCanvasesForDisplay: ts << "PrepareCanvasesForDisplay"; break;
     }
     return ts;
 }

Modified: trunk/Source/WebCore/page/Page.h (294863 => 294864)


--- trunk/Source/WebCore/page/Page.h	2022-05-26 02:56:49 UTC (rev 294863)
+++ trunk/Source/WebCore/page/Page.h	2022-05-26 03:15:16 UTC (rev 294864)
@@ -208,7 +208,7 @@
     InvalidateImagesWithAsyncDecodes    = 1 << 1,
 };
 
-enum class RenderingUpdateStep : uint16_t {
+enum class RenderingUpdateStep : uint32_t {
     Resize                          = 1 << 0,
     Scroll                          = 1 << 1,
     MediaQueryEvaluation            = 1 << 2,
@@ -227,6 +227,7 @@
 #endif
     FlushAutofocusCandidates        = 1 << 14,
     VideoFrameCallbacks             = 1 << 15,
+    PrepareCanvasesForDisplay       = 1 << 16,
 };
 
 constexpr OptionSet<RenderingUpdateStep> updateRenderingSteps = {
@@ -243,6 +244,7 @@
     RenderingUpdateStep::WheelEventMonitorCallbacks,
     RenderingUpdateStep::CursorUpdate,
     RenderingUpdateStep::EventRegionUpdate,
+    RenderingUpdateStep::PrepareCanvasesForDisplay,
 };
 
 constexpr auto allRenderingUpdateSteps = updateRenderingSteps | OptionSet<RenderingUpdateStep> {
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to