⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 283489 in webkit


Ignore:
Timestamp:
Oct 4, 2021, 12:48:10 AM (5 years ago)
Author:
commit-queue@webkit.org
Message:

Regression (r283238)[ MacOS wk1 ] fast/mediacapturefromelement/CanvasCaptureMediaStream-webgl-events.html is timing out
https://bugs.webkit.org/show_bug.cgi?id=231022

Patch by Kimmo Kinnunen <kkinnunen@apple.com> on 2021-10-04
Reviewed by Youenn Fablet.

Originally the implementation would always return red frame, and the test would pass.
r283238 changed the implementation to not return a sample if there is not a display buffer,
as logically such cannot be used as a sample.
This broke the test case since the CanvasCaptureMediaStreamTrack would try to capture
the canvas display buffer during next runloop iteration (0s timeout) after each modification.
This does not work, as the display buffer is composed during "prepare for display"
phase.

Add CanvasBase observers to observe that display buffer has been prepared, and capture
the media sample after that observer has fired.

The test would work for wk2 due to timing related differences, preparation would have
typically run before the canvas capture 0s timeout.

Fixes fast/mediastream/captureStream/canvas3d.html for wk1.

  • Modules/mediastream/CanvasCaptureMediaStreamTrack.cpp:

(WebCore::CanvasCaptureMediaStreamTrack::Source::startProducingData):
(WebCore::CanvasCaptureMediaStreamTrack::Source::canvasChanged):
(WebCore::CanvasCaptureMediaStreamTrack::Source::canvasDisplayBufferPrepared):

  • Modules/mediastream/CanvasCaptureMediaStreamTrack.h:
  • html/CanvasBase.cpp:

(WebCore::CanvasBase::addDisplayBufferObserver):
(WebCore::CanvasBase::removeDisplayBufferObserver):
(WebCore::CanvasBase::notifyObserversCanvasDisplayBufferPrepared):

  • html/CanvasBase.h:

(WebCore::CanvasBase::hasDisplayBufferObservers const):

  • html/canvas/WebGLRenderingContextBase.cpp:

(WebCore::WebGLRenderingContextBase::prepareForDisplay):
Move the "prepare only when the owner element is in the tree" logic to
its correct place to the caller, e.g. to the element itself.

Location:
trunk/Source/WebCore
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r283488 r283489  
     12021-10-04  Kimmo Kinnunen  <kkinnunen@apple.com>
     2
     3        Regression (r283238)[ MacOS wk1 ] fast/mediacapturefromelement/CanvasCaptureMediaStream-webgl-events.html is timing out
     4        https://bugs.webkit.org/show_bug.cgi?id=231022
     5
     6        Reviewed by Youenn Fablet.
     7
     8        Originally the implementation would always return red frame, and the test would pass.
     9        r283238 changed the implementation to not return a sample if there is not a display buffer,
     10        as logically such cannot be used as a sample.
     11        This broke the test case since the CanvasCaptureMediaStreamTrack would try to capture
     12        the canvas display buffer during next runloop iteration (0s timeout) after each modification.
     13        This does not work, as the display buffer is composed during "prepare for display"
     14        phase.
     15
     16        Add CanvasBase observers to observe that display buffer has been prepared, and capture
     17        the media sample after that observer has fired.
     18
     19        The test would work for wk2 due to timing related differences, preparation would have
     20        typically run before the canvas capture 0s timeout.
     21
     22        Fixes fast/mediastream/captureStream/canvas3d.html for wk1.
     23
     24        * Modules/mediastream/CanvasCaptureMediaStreamTrack.cpp:
     25        (WebCore::CanvasCaptureMediaStreamTrack::Source::startProducingData):
     26        (WebCore::CanvasCaptureMediaStreamTrack::Source::canvasChanged):
     27        (WebCore::CanvasCaptureMediaStreamTrack::Source::canvasDisplayBufferPrepared):
     28        * Modules/mediastream/CanvasCaptureMediaStreamTrack.h:
     29        * html/CanvasBase.cpp:
     30        (WebCore::CanvasBase::addDisplayBufferObserver):
     31        (WebCore::CanvasBase::removeDisplayBufferObserver):
     32        (WebCore::CanvasBase::notifyObserversCanvasDisplayBufferPrepared):
     33        * html/CanvasBase.h:
     34        (WebCore::CanvasBase::hasDisplayBufferObservers const):
     35        * html/canvas/WebGLRenderingContextBase.cpp:
     36        (WebCore::WebGLRenderingContextBase::prepareForDisplay):
     37        Move the "prepare only when the owner element is in the tree" logic to
     38        its correct place to the caller, e.g. to the element itself.
     39
    1402021-10-03  Antti Koivisto  <antti@apple.com>
    241
  • trunk/Source/WebCore/Modules/mediastream/CanvasCaptureMediaStreamTrack.cpp

    r283238 r283489  
    9090        return;
    9191    m_canvas->addObserver(*this);
     92    m_canvas->addDisplayBufferObserver(*this);
    9293
    9394    if (!m_frameRequestRate)
     
    105106        return;
    106107    m_canvas->removeObserver(*this);
     108    m_canvas->removeDisplayBufferObserver(*this);
    107109}
    108110
     
    153155{
    154156    ASSERT_UNUSED(canvas, m_canvas == &canvas);
    155 
     157    if (m_canvas->renderingContext() && m_canvas->renderingContext()->needsPreparationForDisplay())
     158        return;
     159    scheduleCaptureCanvas();
     160}
     161
     162void CanvasCaptureMediaStreamTrack::Source::scheduleCaptureCanvas()
     163{
    156164    // FIXME: We should try to generate the frame at the time the screen is being updated.
    157165    if (m_captureCanvasTimer.isActive())
    158166        return;
    159167    m_captureCanvasTimer.startOneShot(0_s);
     168}
     169
     170void CanvasCaptureMediaStreamTrack::Source::canvasDisplayBufferPrepared(CanvasBase& canvas)
     171{
     172    ASSERT_UNUSED(canvas, m_canvas == &canvas);
     173    // FIXME: Here we should capture the image instead.
     174    // However, submitting the sample to the receiver might cause layout,
     175    // and currently the display preparation is done after layout.
     176    scheduleCaptureCanvas();
    160177}
    161178
  • trunk/Source/WebCore/Modules/mediastream/CanvasCaptureMediaStreamTrack.h

    r278253 r283489  
    3131#include "Timer.h"
    3232#include <wtf/TypeCasts.h>
     33#include <wtf/WeakPtr.h>
    3334
    3435namespace WebCore {
     
    5152    const char* activeDOMObjectName() const override;
    5253
    53     class Source final : public RealtimeMediaSource, private CanvasObserver {
     54    class Source final : public RealtimeMediaSource, private CanvasObserver, private CanvasDisplayBufferObserver {
    5455    public:
    5556        static Ref<Source> create(HTMLCanvasElement&, std::optional<double>&& frameRequestRate);
     
    6162        Source(HTMLCanvasElement&, std::optional<double>&&);
    6263
    63         // CanvasObserver API
     64        // CanvasObserver overrides.
    6465        void canvasChanged(CanvasBase&, const std::optional<FloatRect>&) final;
    6566        void canvasResized(CanvasBase&) final;
    6667        void canvasDestroyed(CanvasBase&) final;
    6768
    68         // RealtimeMediaSource API
     69        // CanvasDisplayBufferObserver overrides.
     70        void canvasDisplayBufferPrepared(CanvasBase&) final;
     71
     72        // RealtimeMediaSource overrides.
    6973        void startProducingData() final;
    7074        void stopProducingData()  final;
     
    7276        const RealtimeMediaSourceSettings& settings() final;
    7377        void settingsDidChange(OptionSet<RealtimeMediaSourceSettings::Flag>) final;
    74 
     78        void scheduleCaptureCanvas();
    7579        void captureCanvas();
    7680        void requestFrameTimerFired();
  • trunk/Source/WebCore/html/CanvasBase.cpp

    r278253 r283489  
    163163}
    164164
     165void CanvasBase::addDisplayBufferObserver(CanvasDisplayBufferObserver& observer)
     166{
     167    m_displayBufferObservers.add(&observer);
     168}
     169
     170void CanvasBase::removeDisplayBufferObserver(CanvasDisplayBufferObserver& observer)
     171{
     172    m_displayBufferObservers.remove(observer);
     173}
     174
     175void CanvasBase::notifyObserversCanvasDisplayBufferPrepared()
     176{
     177    for (auto& observer : m_displayBufferObservers)
     178        observer.canvasDisplayBufferPrepared(*this);
     179}
     180
    165181HashSet<Element*> CanvasBase::cssCanvasClients() const
    166182{
  • trunk/Source/WebCore/html/CanvasBase.h

    r278253 r283489  
    2929#include <wtf/HashSet.h>
    3030#include <wtf/TypeCasts.h>
     31#include <wtf/WeakHashSet.h>
    3132
    3233namespace WebCore {
     
    5354    virtual void canvasResized(CanvasBase&) = 0;
    5455    virtual void canvasDestroyed(CanvasBase&) = 0;
     56};
     57
     58class CanvasDisplayBufferObserver : public CanMakeWeakPtr<CanvasDisplayBufferObserver> {
     59public:
     60    virtual ~CanvasDisplayBufferObserver() = default;
     61
     62    virtual void canvasDisplayBufferPrepared(CanvasBase&) = 0;
    5563};
    5664
     
    93101    void notifyObserversCanvasResized();
    94102    void notifyObserversCanvasDestroyed(); // Must be called in destruction before clearing m_context.
     103    void addDisplayBufferObserver(CanvasDisplayBufferObserver&);
     104    void removeDisplayBufferObserver(CanvasDisplayBufferObserver&);
     105    void notifyObserversCanvasDisplayBufferPrepared();
     106    bool hasDisplayBufferObservers() const { return !m_displayBufferObservers.computesEmpty(); }
    95107
    96108    HashSet<Element*> cssCanvasClients() const;
     
    133145#endif
    134146    HashSet<CanvasObserver*> m_observers;
     147    WeakHashSet<CanvasDisplayBufferObserver> m_displayBufferObservers;
    135148};
    136149
  • trunk/Source/WebCore/html/HTMLCanvasElement.cpp

    r283238 r283489  
    10551055    ASSERT(needsPreparationForDisplay());
    10561056
     1057    bool shouldPrepare = true;
     1058#if ENABLE(WEBGL)
     1059    // FIXME: Currently the below prepare skip logic is conservative and applies only to
     1060    // WebGL elements.
     1061    if (is<WebGLRenderingContextBase>(m_context)) {
     1062        // If the canvas is not in the document body, then it won't be
     1063        // composited and thus doesn't need preparation. Unfortunately
     1064        // it can't tell at the time it was added to the list, since it
     1065        // could be inserted or removed from the document body afterwards.
     1066        shouldPrepare = isInTreeScope() || hasDisplayBufferObservers();
     1067    }
     1068#endif
     1069    if (!shouldPrepare)
     1070        return;
    10571071    if (m_context)
    10581072        m_context->prepareForDisplay();
     1073    notifyObserversCanvasDisplayBufferPrepared();
    10591074}
    10601075
  • trunk/Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp

    r283238 r283489  
    81768176        return;
    81778177
    8178     // If the canvas is not in the document body, then it won't be
    8179     // composited and thus doesn't need preparation. Unfortunately
    8180     // it can't tell at the time it was added to the list, since it
    8181     // could be inserted or removed from the document body afterwards.
    8182     auto canvas = htmlCanvas();
    8183     if (!canvas || !canvas->isInTreeScope())
    8184         return;
    8185 
    81868178    m_context->prepareForDisplay();
    81878179}
Note: See TracChangeset for help on using the changeset viewer.