Skip to content

Commit

Permalink
Support deferred GPU images in ImageShaders (flutter#35323)
Browse files Browse the repository at this point in the history
  • Loading branch information
dnfield authored Aug 18, 2022
1 parent 50cfc83 commit 4fbe41d
Show file tree
Hide file tree
Showing 27 changed files with 334 additions and 60 deletions.
1 change: 1 addition & 0 deletions display_list/display_list.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ namespace flutter {
V(SetPodColorSource) \
V(SetSkColorSource) \
V(SetImageColorSource) \
V(SetRuntimeEffectColorSource) \
\
V(ClearImageFilter) \
V(SetPodImageFilter) \
Expand Down
7 changes: 7 additions & 0 deletions display_list/display_list_builder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include "flutter/display_list/display_list.h"
#include "flutter/display_list/display_list_blend_mode.h"
#include "flutter/display_list/display_list_color_source.h"
#include "flutter/display_list/display_list_ops.h"

namespace flutter {
Expand Down Expand Up @@ -184,6 +185,12 @@ void DisplayListBuilder::onSetColorSource(const DlColorSource* source) {
new (pod) DlSweepGradientColorSource(sweep);
break;
}
case DlColorSourceType::kRuntimeEffect: {
const DlRuntimeEffectColorSource* effect = source->asRuntimeEffect();
FML_DCHECK(effect);
Push<SetRuntimeEffectColorSourceOp>(0, 0, effect);
break;
}
case DlColorSourceType::kUnknown:
Push<SetSkColorSourceOp>(0, 0, source->skia_object());
break;
Expand Down
9 changes: 9 additions & 0 deletions display_list/display_list_color_source.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// found in the LICENSE file.

#include "flutter/display_list/display_list_color_source.h"
#include "display_list_color_source.h"
#include "flutter/display_list/display_list_sampling_options.h"

namespace flutter {
Expand Down Expand Up @@ -128,4 +129,12 @@ std::shared_ptr<DlColorSource> DlColorSource::MakeSweep(
return std::move(ret);
}

std::shared_ptr<DlRuntimeEffectColorSource> DlColorSource::MakeRuntimeEffect(
sk_sp<SkRuntimeEffect> runtime_effect,
std::vector<std::shared_ptr<DlColorSource>> samplers,
sk_sp<SkData> uniform_data) {
return std::make_shared<DlRuntimeEffectColorSource>(
std::move(runtime_effect), std::move(samplers), std::move(uniform_data));
}

} // namespace flutter
106 changes: 100 additions & 6 deletions display_list/display_list_color_source.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "flutter/fml/logging.h"
#include "third_party/skia/include/core/SkShader.h"
#include "third_party/skia/include/effects/SkGradientShader.h"
#include "third_party/skia/include/effects/SkRuntimeEffect.h"

namespace flutter {

Expand All @@ -24,6 +25,7 @@ class DlLinearGradientColorSource;
class DlRadialGradientColorSource;
class DlConicalGradientColorSource;
class DlSweepGradientColorSource;
class DlRuntimeEffectColorSource;
class DlUnknownColorSource;

// The DisplayList ColorSource class. This class implements all of the
Expand All @@ -43,6 +45,7 @@ enum class DlColorSourceType {
kRadialGradient,
kConicalGradient,
kSweepGradient,
kRuntimeEffect,
kUnknown
};

Expand Down Expand Up @@ -104,6 +107,11 @@ class DlColorSource
DlTileMode tile_mode,
const SkMatrix* matrix = nullptr);

static std::shared_ptr<DlRuntimeEffectColorSource> MakeRuntimeEffect(
sk_sp<SkRuntimeEffect> runtime_effect,
std::vector<std::shared_ptr<DlColorSource>> samplers,
sk_sp<SkData> uniform_data);

virtual bool is_opaque() const = 0;

virtual std::shared_ptr<DlColorSource> with_sampling(
Expand Down Expand Up @@ -143,6 +151,19 @@ class DlColorSource
return nullptr;
}

virtual const DlRuntimeEffectColorSource* asRuntimeEffect() const {
return nullptr;
}

// If this filter contains images, specifies the owning context for those
// images.
// Images with a DlImage::OwningContext::kRaster must only call skia_object
// on the raster task runner.
// A nullopt return means there is no image.
virtual std::optional<DlImage::OwningContext> owning_context() const {
return std::nullopt;
}

protected:
DlColorSource() = default;

Expand Down Expand Up @@ -229,12 +250,10 @@ class DlImageColorSource final : public SkRefCnt,
DlColorSourceType type() const override { return DlColorSourceType::kImage; }
size_t size() const override { return sizeof(*this); }

bool is_opaque() const override {
// TODO(109286): Consider implementing 'isOpaque' on 'DlImage'.
if (!image_->skia_image()) {
return false;
}
return image_->skia_image()->isOpaque();
bool is_opaque() const override { return image_->isOpaque(); }

std::optional<DlImage::OwningContext> owning_context() const override {
return image_->owning_context();
}

sk_sp<const DlImage> image() const { return image_; }
Expand Down Expand Up @@ -636,6 +655,81 @@ class DlSweepGradientColorSource final : public DlGradientColorSourceBase {
FML_DISALLOW_COPY_ASSIGN_AND_MOVE(DlSweepGradientColorSource);
};

class DlRuntimeEffectColorSource final : public DlColorSource {
public:
DlRuntimeEffectColorSource(
sk_sp<SkRuntimeEffect> runtime_effect,
std::vector<std::shared_ptr<DlColorSource>> samplers,
sk_sp<SkData> uniform_data)
: runtime_effect_(std::move(runtime_effect)),
samplers_(std::move(samplers)),
uniform_data_(std::move(uniform_data)) {}

const DlRuntimeEffectColorSource* asRuntimeEffect() const override {
return this;
}

std::shared_ptr<DlColorSource> shared() const override {
return std::make_shared<DlRuntimeEffectColorSource>(
runtime_effect_, samplers_, uniform_data_);
}

DlColorSourceType type() const override {
return DlColorSourceType::kRuntimeEffect;
}
size_t size() const override { return sizeof(*this); }

bool is_opaque() const override { return false; }

const sk_sp<SkRuntimeEffect> runtime_effect() const {
return runtime_effect_;
}
const std::vector<std::shared_ptr<DlColorSource>> samplers() const {
return samplers_;
}
const sk_sp<SkData> uniform_data() const { return uniform_data_; }

sk_sp<SkShader> skia_object() const override {
if (!runtime_effect_) {
return nullptr;
}
std::vector<sk_sp<SkShader>> sk_samplers(samplers_.size());
for (size_t i = 0; i < samplers_.size(); i++) {
sk_samplers[i] = samplers_[i]->skia_object();
}
return runtime_effect_->makeShader(uniform_data_, sk_samplers.data(),
sk_samplers.size());
}

protected:
bool equals_(DlColorSource const& other) const override {
FML_DCHECK(other.type() == DlColorSourceType::kRuntimeEffect);
auto that = static_cast<DlRuntimeEffectColorSource const*>(&other);
if (runtime_effect_ != that->runtime_effect_) {
return false;
}
if (uniform_data_ != that->uniform_data_) {
return false;
}
if (samplers_.size() != that->samplers_.size()) {
return false;
}
for (size_t i = 0; i < samplers_.size(); i++) {
if (samplers_[i] != that->samplers_[i]) {
return false;
}
}
return true;
}

private:
sk_sp<SkRuntimeEffect> runtime_effect_;
std::vector<std::shared_ptr<DlColorSource>> samplers_;
sk_sp<SkData> uniform_data_;

FML_DISALLOW_COPY_ASSIGN_AND_MOVE(DlRuntimeEffectColorSource);
};

class DlUnknownColorSource final : public DlColorSource {
public:
DlUnknownColorSource(sk_sp<SkShader> shader) : sk_shader_(shader) {}
Expand Down
49 changes: 49 additions & 0 deletions display_list/display_list_color_source_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "flutter/display_list/display_list_image.h"
#include "flutter/display_list/display_list_sampling_options.h"
#include "flutter/display_list/types.h"
#include "third_party/skia/include/core/SkString.h"
#include "third_party/skia/include/core/SkSurface.h"

namespace flutter {
Expand All @@ -27,6 +28,15 @@ static sk_sp<DlImage> MakeTestImage(int w, int h, SkColor color) {
return DlImage::Make(surface->makeImageSnapshot());
}

static const sk_sp<SkRuntimeEffect> kTestRuntimeEffect1 =
SkRuntimeEffect::MakeForShader(
SkString("vec4 main(vec2 p) { return vec4(0); }"))
.effect;
static const sk_sp<SkRuntimeEffect> kTestRuntimeEffect2 =
SkRuntimeEffect::MakeForShader(
SkString("vec4 main(vec2 p) { return vec4(1); }"))
.effect;

static const sk_sp<DlImage> kTestImage1 = MakeTestImage(10, 10, SK_ColorGREEN);
static const sk_sp<DlImage> kTestAlphaImage1 =
MakeTestImage(10, 10, SK_ColorTRANSPARENT);
Expand Down Expand Up @@ -138,6 +148,7 @@ TEST(DisplayListColorSource, FromSkiaImageShader) {
ASSERT_EQ(source->asRadialGradient(), nullptr);
ASSERT_EQ(source->asConicalGradient(), nullptr);
ASSERT_EQ(source->asSweepGradient(), nullptr);
ASSERT_EQ(source->asRuntimeEffect(), nullptr);
}

TEST(DisplayListColorSource, FromSkiaLinearGradient) {
Expand Down Expand Up @@ -177,6 +188,7 @@ TEST(DisplayListColorSource, FromSkiaRadialGradient) {
ASSERT_EQ(source->asRadialGradient(), nullptr);
ASSERT_EQ(source->asConicalGradient(), nullptr);
ASSERT_EQ(source->asSweepGradient(), nullptr);
ASSERT_EQ(source->asRuntimeEffect(), nullptr);
}

TEST(DisplayListColorSource, FromSkiaConicalGradient) {
Expand All @@ -197,6 +209,7 @@ TEST(DisplayListColorSource, FromSkiaConicalGradient) {
ASSERT_EQ(source->asRadialGradient(), nullptr);
ASSERT_EQ(source->asConicalGradient(), nullptr);
ASSERT_EQ(source->asSweepGradient(), nullptr);
ASSERT_EQ(source->asRuntimeEffect(), nullptr);
}

TEST(DisplayListColorSource, FromSkiaSweepGradient) {
Expand All @@ -217,6 +230,7 @@ TEST(DisplayListColorSource, FromSkiaSweepGradient) {
ASSERT_EQ(source->asRadialGradient(), nullptr);
ASSERT_EQ(source->asConicalGradient(), nullptr);
ASSERT_EQ(source->asSweepGradient(), nullptr);
ASSERT_EQ(source->asRuntimeEffect(), nullptr);
}

TEST(DisplayListColorSource, FromSkiaUnrecognizedShader) {
Expand All @@ -231,6 +245,7 @@ TEST(DisplayListColorSource, FromSkiaUnrecognizedShader) {
ASSERT_EQ(source->asRadialGradient(), nullptr);
ASSERT_EQ(source->asConicalGradient(), nullptr);
ASSERT_EQ(source->asSweepGradient(), nullptr);
ASSERT_EQ(source->asRuntimeEffect(), nullptr);
}

TEST(DisplayListColorSource, ColorConstructor) {
Expand All @@ -253,6 +268,7 @@ TEST(DisplayListColorSource, ColorAsColor) {
ASSERT_EQ(source.asRadialGradient(), nullptr);
ASSERT_EQ(source.asConicalGradient(), nullptr);
ASSERT_EQ(source.asSweepGradient(), nullptr);
ASSERT_EQ(source.asRuntimeEffect(), nullptr);
}

TEST(DisplayListColorSource, ColorContents) {
Expand Down Expand Up @@ -400,6 +416,7 @@ TEST(DisplayListColorSource, LinearGradientAsLinear) {
ASSERT_EQ(source->asRadialGradient(), nullptr);
ASSERT_EQ(source->asConicalGradient(), nullptr);
ASSERT_EQ(source->asSweepGradient(), nullptr);
ASSERT_EQ(source->asRuntimeEffect(), nullptr);
}

TEST(DisplayListColorSource, LinearGradientContents) {
Expand Down Expand Up @@ -518,6 +535,7 @@ TEST(DisplayListColorSource, RadialGradientAsRadial) {
ASSERT_EQ(source->asLinearGradient(), nullptr);
ASSERT_EQ(source->asConicalGradient(), nullptr);
ASSERT_EQ(source->asSweepGradient(), nullptr);
ASSERT_EQ(source->asRuntimeEffect(), nullptr);
}

TEST(DisplayListColorSource, RadialGradientContents) {
Expand Down Expand Up @@ -636,6 +654,7 @@ TEST(DisplayListColorSource, ConicalGradientAsConical) {
ASSERT_EQ(source->asLinearGradient(), nullptr);
ASSERT_EQ(source->asRadialGradient(), nullptr);
ASSERT_EQ(source->asSweepGradient(), nullptr);
ASSERT_EQ(source->asRuntimeEffect(), nullptr);
}

TEST(DisplayListColorSource, ConicalGradientContents) {
Expand Down Expand Up @@ -770,6 +789,7 @@ TEST(DisplayListColorSource, SweepGradientAsSweep) {
ASSERT_EQ(source->asLinearGradient(), nullptr);
ASSERT_EQ(source->asRadialGradient(), nullptr);
ASSERT_EQ(source->asConicalGradient(), nullptr);
ASSERT_EQ(source->asRuntimeEffect(), nullptr);
}

TEST(DisplayListColorSource, SweepGradientContents) {
Expand Down Expand Up @@ -888,6 +908,7 @@ TEST(DisplayListColorSource, UnknownAsNone) {
ASSERT_EQ(source.asRadialGradient(), nullptr);
ASSERT_EQ(source.asConicalGradient(), nullptr);
ASSERT_EQ(source.asSweepGradient(), nullptr);
ASSERT_EQ(source.asRuntimeEffect(), nullptr);
}

TEST(DisplayListColorSource, UnknownContents) {
Expand Down Expand Up @@ -916,5 +937,33 @@ TEST(DisplayListColorSource, UnknownNotEquals) {
TestNotEquals(source1, source2, "SkShader differs");
}

TEST(DisplayListColorSource, RuntimeEffect) {
std::shared_ptr<DlRuntimeEffectColorSource> source1 =
DlColorSource::MakeRuntimeEffect(kTestRuntimeEffect1, {}, nullptr);
std::shared_ptr<DlRuntimeEffectColorSource> source2 =
DlColorSource::MakeRuntimeEffect(kTestRuntimeEffect2, {}, nullptr);
std::shared_ptr<DlRuntimeEffectColorSource> source3 =
DlColorSource::MakeRuntimeEffect(nullptr, {}, nullptr);

ASSERT_EQ(source1->type(), DlColorSourceType::kRuntimeEffect);
ASSERT_EQ(source1->asRuntimeEffect(), source1.get());
ASSERT_NE(source2->asRuntimeEffect(), source1.get());

ASSERT_EQ(source1->asImage(), nullptr);
ASSERT_EQ(source1->asColor(), nullptr);
ASSERT_EQ(source1->asLinearGradient(), nullptr);
ASSERT_EQ(source1->asRadialGradient(), nullptr);
ASSERT_EQ(source1->asConicalGradient(), nullptr);
ASSERT_EQ(source1->asSweepGradient(), nullptr);

ASSERT_NE(source1->skia_object(), nullptr);
ASSERT_EQ(source3->skia_object(), nullptr);

TestEquals(source1, source1);
TestEquals(source3, source3);
TestNotEquals(source1, source2, "SkRuntimeEffect differs");
TestNotEquals(source2, source3, "SkRuntimeEffect differs");
}

} // namespace testing
} // namespace flutter
11 changes: 11 additions & 0 deletions display_list/display_list_image.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,17 @@ class DlImage : public SkRefCnt {
///
virtual std::shared_ptr<impeller::Texture> impeller_texture() const = 0;

//----------------------------------------------------------------------------
/// @brief If the pixel format of this image ignores alpha, this returns
/// true. This method might conservatively return false when it
/// cannot guarnatee an opaque image, for example when the pixel
/// format of the image supports alpha but the image is made up of
/// entirely opaque pixels.
///
/// @return True if the pixel format of this image ignores alpha.
///
virtual bool isOpaque() const = 0;

virtual bool isTextureBacked() const = 0;

//----------------------------------------------------------------------------
Expand Down
5 changes: 5 additions & 0 deletions display_list/display_list_image_skia.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ std::shared_ptr<impeller::Texture> DlImageSkia::impeller_texture() const {
return nullptr;
}

// |DlImage|
bool DlImageSkia::isOpaque() const {
return image_ ? image_->isOpaque() : false;
}

// |DlImage|
bool DlImageSkia::isTextureBacked() const {
return image_ ? image_->isTextureBacked() : false;
Expand Down
3 changes: 3 additions & 0 deletions display_list/display_list_image_skia.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ class DlImageSkia final : public DlImage {
// |DlImage|
std::shared_ptr<impeller::Texture> impeller_texture() const override;

// |DlImage|
bool isOpaque() const override;

// |DlImage|
bool isTextureBacked() const override;

Expand Down
Loading

0 comments on commit 4fbe41d

Please sign in to comment.