Skip to content

[web] sink pictures/platform views to the lowest available overlay #149863

@yjbanov

Description

@yjbanov

The overlay minimization fails in the situation described in the test below. It could do better.

Scenario

Consider the following scene:

Screenshot 2024-06-06 at 1 35 53 PM

The scene is structured into the following layers, listed in paint order:

  1. Picture 1 (big green square on the left)
  2. Platform view 1 (red square on the left)
  3. Picture 2 (small green square on the left)
  4. Picture 3 (big green square on the right)
  5. Platform view 2 (red square on the right)
  6. Picture 4 (small green square on the right)

Layers 1-3 form one cluster of layers, and 4-6 form a second cluster of layers.

Compositing this naively, you'd need the following stack of overlays:

  1. Picture 1
  2. Platform view 1
  3. Picture 2 and picture 3
  4. Platform view 2
  5. Picture 4

This is exactly what the web engine does today.

However, notice that the two clusters do not overlap. This means, that the paint order can be changed as follows:

  1. Picture 1 (big green square on the left)
  2. Picture 3 (big green square on the right)
  3. Platform view 1 (red square on the left)
  4. Platform view 2 (red square on the right)
  5. Picture 2 (small green square on the left)
  6. Picture 4 (small green square on the right)

Essentially, you "sink" picture 3 as far back as possible, below platform view 1 and picture 2 (safe to do since they don't overlap). You do the same for platform view 2. Now, to render this, you need fewer overlays:

  1. Picture 1 and picture 3
  2. Platform view 1 and platform view 2
  3. Picture 2 and picture 4

In this contrived example, the overlay count only goes from 5 to 3, but imagine 10 non-overlapping clusters like that. That will blow up the number of overlays today. However, you never need more than 3 overlays.

To reproduce, add the following test to the web engine's embedded_views_test.dart:

    test('sinks platform view under the canvas if it does not overlap with the picture',
        () async {
      ui_web.platformViewRegistry.registerViewFactory(
        'test-view',
        (int viewId) => createDomHTMLDivElement()..className = 'platform-view',
      );

      CkPicture rectPicture(double l, double t, double w, double h) {
        final ui.Rect rect = ui.Rect.fromLTWH(l, t, w, h);
        return paintPicture(rect, (CkCanvas canvas) {
          canvas.drawRect(
              rect, CkPaint()..color = const ui.Color.fromARGB(255, 255, 0, 0));
        });
      }

      await createPlatformView(0, 'test-view');
      await createPlatformView(1, 'test-view');

      expect(PlatformViewManager.instance.isVisible(0), isTrue);
      expect(PlatformViewManager.instance.isVisible(1), isTrue);

      final LayerSceneBuilder sb = LayerSceneBuilder();

      // First picture-view-picture stack.
      {
        sb.pushOffset(0, 0);
        sb.addPicture(
          ui.Offset.zero,
          rectPicture(0, 0, 10, 10),
        );
        sb.addPlatformView(
          0,
          width: 10,
          height: 10,
        );
        sb.addPicture(
          ui.Offset.zero,
          rectPicture(2, 2, 5, 5),
        );
        sb.pop();
      }

      // Second picture-view-picture stack that does not overlap with the first one.
      {
        sb.pushOffset(20, 0);
        sb.addPicture(
          ui.Offset.zero,
          rectPicture(0, 0, 10, 10),
        );
        sb.addPlatformView(
          1,
          width: 10,
          height: 10,
        );
        sb.addPicture(
          ui.Offset.zero,
          rectPicture(2, 2, 5, 5),
        );
        sb.pop();
      }

      final LayerScene scene1 = sb.build();
      await renderScene(scene1);

      // Observe inefficient overlay allocation
      _expectSceneMatches(<_EmbeddedViewMarker>[
        _overlay,
        _platformView,
        _overlay,
        _platformView,
        _overlay,
      ]);
    });

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Important issues not at the top of the work liste: web_canvaskitCanvasKit (a.k.a. Skia-on-WebGL) rendering backend for Webplatform-webWeb applications specificallyteam-webOwned by Web platform teamtriaged-webTriaged by Web platform team

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions