Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Conversation

@cyanglaz
Copy link
Contributor

@cyanglaz cyanglaz commented Mar 23, 2023

Adopt DisplayListEmbedderViewSlice in EmbedderExternalView

Fixes flutter/flutter#123349

Pre-launch Checklist

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • I read the Tree Hygiene wiki page, which explains my responsibilities.
  • I read and followed the Flutter Style Guide and the C++, Objective-C, Java style guides.
  • I listed at least one issue that this PR fixes in the description above.
  • I added new tests to check the change I am making or feature I am adding, or Hixie said the PR is test-exempt. See testing the engine for instructions on writing and running engine tests.
  • I updated/added relevant documentation (doc comments with ///).
  • I signed the CLA.
  • All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel on Discord.

@flutter-dashboard flutter-dashboard bot added the embedder Related to the embedder API label Mar 23, 2023
@cyanglaz cyanglaz requested a review from flar March 23, 2023 20:32
auto dl_canvas = std::make_unique<DlSkCanvasAdapter>(canvas);
int restore_count = dl_canvas->GetSaveCount();
dl_canvas->SetTransform(surface_transformation_);
dl_canvas->Clear(SK_ColorTRANSPARENT);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically, while SK_Color constants are automatically interchangeable with DlColor instances (they both just boil down to a uint32_t), It would be better to use DlColor::kTransparent() here to continue the theme of non-skia use while talking to Dl objects.

@cyanglaz cyanglaz force-pushed the dl_embedder_external_view branch 3 times, most recently from 34b2609 to f73d8cd Compare March 28, 2023 23:00
@cyanglaz cyanglaz marked this pull request as ready for review March 28, 2023 23:00
@cyanglaz
Copy link
Contributor Author

cyanglaz commented Mar 28, 2023

@flar This is ready to be reviewed!

@cyanglaz cyanglaz force-pushed the dl_embedder_external_view branch from e4fb81f to e0f867c Compare March 29, 2023 20:10
@cyanglaz cyanglaz self-assigned this Mar 29, 2023
ORIGIN: ../../../flutter/display_list/dl_op_receiver.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/display_list/dl_op_records.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/display_list/dl_op_records.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/display_list/dl_op_spy.cc + ../../../flutter/LICENSE
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a need to add these files to the display_list code? The mechanism is only used by one "client" module of DL and isn't generally something that developers query about their display lists. I provided the general utilities in this package (such as the Ignore classes) to help with implementing OpReceiver classes, with the intention that other modules or packages could roll their own for their own purposes.

For example, Impeller processes OpReceiver streams using a class that lives in their source hierarchy.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I initially put it in the platform/embedder/ but saw canvas_spy is in /common, so I thought maybe this class should be in a common place.

Do you have a preference where it should be?

":display_list_fixtures",
"//flutter/display_list/testing:display_list_testing",
"//flutter/testing",
"//third_party/skia",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this needed? I'm guessing if the spy stuff gets moved out of here into the embedder source directories then it doesn't need to be added here, but I would have thought that you could implement an OpReceiver without having to add this dependency...?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is for the unittest, to generate a concrete DlImage for testing.


namespace flutter {

bool DlOpSpy::DidDraw() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been using lower case for getters which I think is compliant with the style guidelines - did_draw()...

}
}
void DlOpSpy::setColorSource(const DlColorSource* source) {
const DlColorColorSource* color_source = source->asColor();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if source is null?

if (did_draw_) {
return;
}
did_draw_ = dirty_ && p0 != p1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p0 == p1 draws something

if (did_draw_) {
return;
}
did_draw_ = !color.isTransparent() && elevation > 0 && !path.isEmpty();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about elevation == 0. I think it might also depend on transparent_occluder as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what does transparent_occluder do?

class DlOpSpy final : public IgnoreAttributeDispatchHelper,
public IgnoreClipDispatchHelper,
public IgnoreTransformDispatchHelper,
public IgnoreDrawDispatchHelper {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this compile without inheriting from IgnoreDraw? I think you probably cover all of the draw commands yourself.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are still calls in ignoreDraw: save, savelayer, restore.

}

bool DisplayListEmbedderViewSlice::recording_ended() {
return recording_ended_;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could also be deduced from display_list_ being non-null or builder_ being null.

return canvas_spy_->DidDrawIntoCanvas();
TryEndRecording();
slice_->dispatch(*dl_op_spy_);
return dl_op_spy_->DidDraw() && !slice_->is_empty();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this method is called more than once it will repeat the op_spy operation. Also, it will re-use the op_spy object which means the second answer might not be correct. I would change this so that it only does the spy operation once and remembers the answer.

Also, you don't need to permanently store an op_spy object, just create one on the fly when you need to compute the answer and remove the dl_op_spy field from the object.

std::unique_ptr<SkPictureRecorder> recorder_;
std::unique_ptr<CanvasSpy> canvas_spy_;
std::unique_ptr<DisplayListEmbedderViewSlice> slice_;
std::unique_ptr<DlOpSpy> dl_op_spy_;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You only need dl_op_spy for the short time when you are computing the answer. It can be created on the stack in that method.

@cyanglaz
Copy link
Contributor Author

@flar Updated per review comments and offline discussions. PTAL.

@cyanglaz cyanglaz requested a review from flar April 6, 2023 18:00
Copy link
Contributor

@flar flar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor edits suggested, but the basic concept is good.

/// on the canvas.
/// All the drawImage operations are considered drawing non-transparent pixels.
///
/// To use this class, dispatching the operations from DisplayList to a concrete
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dispatching => dispatch

class DlOpSpy final : public IgnoreAttributeDispatchHelper,
public IgnoreClipDispatchHelper,
public IgnoreTransformDispatchHelper,
public IgnoreDrawDispatchHelper {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you want to ignore any Draw calls, I'd remove the IgnoreDraw inheritance to make sure you've implemented all of them.

Also, since you are intending for DlOpSpy to implement DlOpReceiver, that should be your first public inheritance even though you get it indirectly from any or all of the Ignore classes you inherit from - it's good to explicitly document that this class is first and foremost intending to be a Receiver (and the rest of the inheritance clauses are just implementation details).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So:

class DlOpSpy final : public DlOpReceiver,
                      public IgnoreAttributeDispatchHelper,
                      public IgnoreClipDispatchHelper,
                      public IgnoreTransformDispatchHelper {

And if this works without the public inheritance from the Ignore classes that might indicate the purpose even better, as in:

class DlOpSpy final : public DlOpReceiver,
                      IgnoreAttributeDispatchHelper,
                      IgnoreClipDispatchHelper,
                      IgnoreTransformDispatchHelper {

(I realize we aren't consistent about this in other places, but we probably should be)

bool transparent_occluder,
SkScalar dpr) override;

// Whether there is a color set before drawing and the last color set is not
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps simplify the comment to

"Indicates if the attributes are set to values that will modify the destination. For now, the test only checks if there is a non-transparent color set."

and maybe change the name to "will_draw_"?

did_draw_ |= dirty_;
}
void DlOpSpy::drawPath(const SkPath& path) {
if (did_draw_) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test seems out of place compared to the other draw methods. If some complicated operation on path was being saved, then it might make sense, but is there a reason why it doesn't just use did_draw_ |= dirty_ like the rest?

const SkScalar elevation,
bool transparent_occluder,
SkScalar dpr) {
if (did_draw_) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as with drawPath, is this saving enough work to justify an early return? This method is very much like drawColor and should have a similar implementation.

kTrue,
kFalse,
};
HasEngineRenderedContentResult has_engine_rendered_contents_ =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could also be std::optional<bool>?

@cyanglaz cyanglaz added autosubmit Merge PR when tree becomes green via auto submit App and removed autosubmit Merge PR when tree becomes green via auto submit App labels Apr 7, 2023
@auto-submit auto-submit bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Apr 7, 2023
@auto-submit
Copy link
Contributor

auto-submit bot commented Apr 7, 2023

auto label is removed for flutter/engine, pr: 40578, due to - The status or check suite Linux Framework Smoke Tests has failed. Please fix the issues identified (or deflake) before re-applying this label.

Copy link
Contributor

@flar flar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reiterating LGTM after review updates...

@cyanglaz cyanglaz force-pushed the dl_embedder_external_view branch 2 times, most recently from 43a59ab to 478b99b Compare April 9, 2023 05:53
golden image

draft

comments

format

draft

format

fix

format

minor fixes

fix license, fix test on non-linux machines

fix license file

forma

review

remove content validation

review

format

format

remove unnecessary dep

review

revuiew
@cyanglaz cyanglaz force-pushed the dl_embedder_external_view branch from 478b99b to a0e6b88 Compare April 9, 2023 20:11
@cyanglaz cyanglaz added the autosubmit Merge PR when tree becomes green via auto submit App label Apr 10, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

autosubmit Merge PR when tree becomes green via auto submit App embedder Related to the embedder API

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Migrate EmbedderExternalView to use DisplayListEmbedderViewSlice

2 participants