Use sampling instead of (deprecated) filter-quality (flutter/engine#24101)

This commit is contained in:
Michael Reed
2021-02-01 03:16:02 -05:00
committed by GitHub
parent b69adb9232
commit 7ef5d67e1b
21 changed files with 79 additions and 66 deletions

View File

@@ -10,6 +10,7 @@
#include "flutter/fml/macros.h"
#include "flutter/fml/synchronization/waitable_event.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkSamplingOptions.h"
class GrDirectContext;
@@ -25,7 +26,7 @@ class Texture {
const SkRect& bounds,
bool freeze,
GrDirectContext* context,
SkFilterQuality quality) = 0;
const SkSamplingOptions& sampling) = 0;
// Called from raster thread.
virtual void OnGrContextCreated() = 0;

View File

@@ -12,12 +12,12 @@ TextureLayer::TextureLayer(const SkPoint& offset,
const SkSize& size,
int64_t texture_id,
bool freeze,
SkFilterQuality filter_quality)
const SkSamplingOptions& sampling)
: offset_(offset),
size_(size),
texture_id_(texture_id),
freeze_(freeze),
filter_quality_(filter_quality) {}
sampling_(sampling) {}
void TextureLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
TRACE_EVENT0("flutter", "TextureLayer::Preroll");
@@ -42,7 +42,7 @@ void TextureLayer::Paint(PaintContext& context) const {
return;
}
texture->Paint(*context.leaf_nodes_canvas, paint_bounds(), freeze_,
context.gr_context, filter_quality_);
context.gr_context, sampling_);
}
} // namespace flutter

View File

@@ -18,7 +18,7 @@ class TextureLayer : public Layer {
const SkSize& size,
int64_t texture_id,
bool freeze,
SkFilterQuality filter_quality);
const SkSamplingOptions& sampling);
void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
void Paint(PaintContext& context) const override;
@@ -28,7 +28,7 @@ class TextureLayer : public Layer {
SkSize size_;
int64_t texture_id_;
bool freeze_;
SkFilterQuality filter_quality_;
SkSamplingOptions sampling_;
FML_DISALLOW_COPY_AND_ASSIGN(TextureLayer);
};

View File

@@ -19,7 +19,7 @@ TEST_F(TextureLayerTest, InvalidTexture) {
const SkPoint layer_offset = SkPoint::Make(0.0f, 0.0f);
const SkSize layer_size = SkSize::Make(8.0f, 8.0f);
auto layer = std::make_shared<TextureLayer>(layer_offset, layer_size, 0,
false, kNone_SkFilterQuality);
false, SkSamplingOptions());
layer->Preroll(preroll_context(), SkMatrix());
EXPECT_EQ(layer->paint_bounds(),
@@ -38,7 +38,7 @@ TEST_F(TextureLayerTest, PaintingEmptyLayerDies) {
const int64_t texture_id = 0;
auto mock_texture = std::make_shared<MockTexture>(texture_id);
auto layer = std::make_shared<TextureLayer>(
layer_offset, layer_size, texture_id, false, kNone_SkFilterQuality);
layer_offset, layer_size, texture_id, false, SkSamplingOptions());
// Ensure the texture is located by the Layer.
preroll_context()->texture_registry.RegisterTexture(mock_texture);
@@ -57,7 +57,8 @@ TEST_F(TextureLayerTest, PaintBeforePreollDies) {
const int64_t texture_id = 0;
auto mock_texture = std::make_shared<MockTexture>(texture_id);
auto layer = std::make_shared<TextureLayer>(
layer_offset, layer_size, texture_id, false, kLow_SkFilterQuality);
layer_offset, layer_size, texture_id, false,
SkSamplingOptions(SkFilterMode::kLinear));
// Ensure the texture is located by the Layer.
preroll_context()->texture_registry.RegisterTexture(mock_texture);
@@ -73,7 +74,8 @@ TEST_F(TextureLayerTest, PaintingWithLowFilterQuality) {
const int64_t texture_id = 0;
auto mock_texture = std::make_shared<MockTexture>(texture_id);
auto layer = std::make_shared<TextureLayer>(
layer_offset, layer_size, texture_id, false, kLow_SkFilterQuality);
layer_offset, layer_size, texture_id, false,
SkSamplingOptions(SkFilterMode::kLinear));
// Ensure the texture is located by the Layer.
preroll_context()->texture_registry.RegisterTexture(mock_texture);
@@ -88,7 +90,7 @@ TEST_F(TextureLayerTest, PaintingWithLowFilterQuality) {
EXPECT_EQ(mock_texture->paint_calls(),
std::vector({MockTexture::PaintCall{
mock_canvas(), layer->paint_bounds(), false, nullptr,
kLow_SkFilterQuality}}));
SkSamplingOptions(SkFilterMode::kLinear)}}));
EXPECT_EQ(mock_canvas().draw_calls(), std::vector<MockCanvas::DrawCall>());
}

View File

@@ -32,7 +32,8 @@ void RasterCacheResult::draw(SkCanvas& canvas, const SkPaint* paint) const {
std::abs(bounds.size().width() - image_->dimensions().width()) <= 1 &&
std::abs(bounds.size().height() - image_->dimensions().height()) <= 1);
canvas.resetMatrix();
canvas.drawImage(image_, bounds.fLeft, bounds.fTop, paint);
canvas.drawImage(image_, bounds.fLeft, bounds.fTop, SkSamplingOptions(),
paint);
}
RasterCache::RasterCache(size_t access_threshold,

View File

@@ -13,21 +13,21 @@ void MockTexture::Paint(SkCanvas& canvas,
const SkRect& bounds,
bool freeze,
GrDirectContext* context,
SkFilterQuality filter_quality) {
const SkSamplingOptions& sampling) {
paint_calls_.emplace_back(
PaintCall{canvas, bounds, freeze, context, filter_quality});
PaintCall{canvas, bounds, freeze, context, sampling});
}
bool operator==(const MockTexture::PaintCall& a,
const MockTexture::PaintCall& b) {
return &a.canvas == &b.canvas && a.bounds == b.bounds &&
a.context == b.context && a.freeze == b.freeze &&
a.filter_quality == b.filter_quality;
a.sampling == b.sampling;
}
std::ostream& operator<<(std::ostream& os, const MockTexture::PaintCall& data) {
return os << &data.canvas << " " << data.bounds << " " << data.context << " "
<< data.freeze << " " << data.filter_quality;
<< data.freeze << " " << data.sampling;
}
} // namespace testing

View File

@@ -21,7 +21,7 @@ class MockTexture : public Texture {
SkRect bounds;
bool freeze;
GrDirectContext* context;
SkFilterQuality filter_quality;
SkSamplingOptions sampling;
};
explicit MockTexture(int64_t textureId);
@@ -31,7 +31,7 @@ class MockTexture : public Texture {
const SkRect& bounds,
bool freeze,
GrDirectContext* context,
SkFilterQuality filter_quality) override;
const SkSamplingOptions& sampling) override;
void OnGrContextCreated() override { gr_context_created_ = true; }
void OnGrContextDestroyed() override { gr_context_destroyed_ = true; }

View File

@@ -29,15 +29,14 @@ TEST(MockTextureTest, PaintCalls) {
SkCanvas canvas;
const SkRect paint_bounds1 = SkRect::MakeWH(1.0f, 1.0f);
const SkRect paint_bounds2 = SkRect::MakeWH(2.0f, 2.0f);
const auto expected_paint_calls =
std::vector{MockTexture::PaintCall{canvas, paint_bounds1, false, nullptr,
kNone_SkFilterQuality},
MockTexture::PaintCall{canvas, paint_bounds2, true, nullptr,
kNone_SkFilterQuality}};
const SkSamplingOptions sampling;
const auto expected_paint_calls = std::vector{
MockTexture::PaintCall{canvas, paint_bounds1, false, nullptr, sampling},
MockTexture::PaintCall{canvas, paint_bounds2, true, nullptr, sampling}};
auto texture = std::make_shared<MockTexture>(0);
texture->Paint(canvas, paint_bounds1, false, nullptr, kNone_SkFilterQuality);
texture->Paint(canvas, paint_bounds2, true, nullptr, kNone_SkFilterQuality);
texture->Paint(canvas, paint_bounds1, false, nullptr, sampling);
texture->Paint(canvas, paint_bounds2, true, nullptr, sampling);
EXPECT_EQ(texture->paint_calls(), expected_paint_calls);
}
@@ -45,15 +44,14 @@ TEST(MockTextureTest, PaintCallsWithLowFilterQuality) {
SkCanvas canvas;
const SkRect paint_bounds1 = SkRect::MakeWH(1.0f, 1.0f);
const SkRect paint_bounds2 = SkRect::MakeWH(2.0f, 2.0f);
const auto expected_paint_calls =
std::vector{MockTexture::PaintCall{canvas, paint_bounds1, false, nullptr,
kLow_SkFilterQuality},
MockTexture::PaintCall{canvas, paint_bounds2, true, nullptr,
kLow_SkFilterQuality}};
const auto sampling = SkSamplingOptions(SkFilterMode::kLinear);
const auto expected_paint_calls = std::vector{
MockTexture::PaintCall{canvas, paint_bounds1, false, nullptr, sampling},
MockTexture::PaintCall{canvas, paint_bounds2, true, nullptr, sampling}};
auto texture = std::make_shared<MockTexture>(0);
texture->Paint(canvas, paint_bounds1, false, nullptr, kLow_SkFilterQuality);
texture->Paint(canvas, paint_bounds2, true, nullptr, kLow_SkFilterQuality);
texture->Paint(canvas, paint_bounds1, false, nullptr, sampling);
texture->Paint(canvas, paint_bounds2, true, nullptr, sampling);
EXPECT_EQ(texture->paint_calls(), expected_paint_calls);
}

View File

@@ -231,9 +231,12 @@ void SceneBuilder::addTexture(double dx,
int64_t textureId,
bool freeze,
int filterQuality) {
// TODO: take sampling directly from caller: filter-quality is deprecated
auto sampling = SkSamplingOptions(static_cast<SkFilterQuality>(filterQuality),
SkSamplingOptions::kMedium_asMipmapLinear);
auto layer = std::make_unique<flutter::TextureLayer>(
SkPoint::Make(dx, dy), SkSize::Make(width, height), textureId, freeze,
static_cast<SkFilterQuality>(filterQuality));
sampling);
AddLayer(std::move(layer));
}

View File

@@ -311,6 +311,12 @@ void Canvas::drawPath(const CanvasPath* path,
canvas_->drawPath(path->path(), *paint.paint());
}
static SkSamplingOptions paint_to_sampling(const SkPaint* paint) {
return SkSamplingOptions(
paint ? paint->getFilterQuality() : kNone_SkFilterQuality,
SkSamplingOptions::kMedium_asMipmapLinear);
}
void Canvas::drawImage(const CanvasImage* image,
double x,
double y,
@@ -324,7 +330,9 @@ void Canvas::drawImage(const CanvasImage* image,
ToDart("Canvas.drawImage called with non-genuine Image."));
return;
}
canvas_->drawImage(image->image(), x, y, paint.paint());
// TODO: add filtering to public API, since paint's quality is deprecated
SkSamplingOptions sampling = paint_to_sampling(paint.paint());
canvas_->drawImage(image->image(), x, y, sampling, paint.paint());
}
void Canvas::drawImageRect(const CanvasImage* image,
@@ -348,7 +356,9 @@ void Canvas::drawImageRect(const CanvasImage* image,
}
SkRect src = SkRect::MakeLTRB(src_left, src_top, src_right, src_bottom);
SkRect dst = SkRect::MakeLTRB(dst_left, dst_top, dst_right, dst_bottom);
canvas_->drawImageRect(image->image(), src, dst, paint.paint(),
// TODO: add filtering to public API, since paint's quality is deprecated
SkSamplingOptions sampling = paint_to_sampling(paint.paint());
canvas_->drawImageRect(image->image(), src, dst, sampling, paint.paint(),
SkCanvas::kFast_SrcRectConstraint);
}
@@ -358,12 +368,6 @@ static SkFilterMode paint_to_filter(const SkPaint* paint) {
: SkFilterMode::kNearest;
}
static SkSamplingOptions paint_to_sampling(const SkPaint* paint) {
return SkSamplingOptions(
paint ? paint->getFilterQuality() : kNone_SkFilterQuality,
SkSamplingOptions::kMedium_asMipmapLinear);
}
void Canvas::drawImageNine(const CanvasImage* image,
double center_left,
double center_top,

View File

@@ -1650,7 +1650,7 @@ class MockTexture : public Texture {
const SkRect& bounds,
bool freeze,
GrDirectContext* context,
SkFilterQuality filter_quality) override {}
const SkSamplingOptions&) override {}
void OnGrContextCreated() override {}

View File

@@ -38,7 +38,7 @@ void AndroidExternalTextureGL::Paint(SkCanvas& canvas,
const SkRect& bounds,
bool freeze,
GrDirectContext* context,
SkFilterQuality filter_quality) {
const SkSamplingOptions& sampling) {
if (state_ == AttachmentState::detached) {
return;
}
@@ -69,9 +69,7 @@ void AndroidExternalTextureGL::Paint(SkCanvas& canvas,
transformAroundCenter.postTranslate(0.5, 0.5);
canvas.concat(transformAroundCenter);
}
SkPaint paint;
paint.setFilterQuality(filter_quality);
canvas.drawImage(image, 0, 0, &paint);
canvas.drawImage(image, 0, 0, sampling, nullptr);
}
}

View File

@@ -26,7 +26,7 @@ class AndroidExternalTextureGL : public flutter::Texture {
const SkRect& bounds,
bool freeze,
GrDirectContext* context,
SkFilterQuality filter_quality) override;
const SkSamplingOptions& sampling) override;
void OnGrContextCreated() override;

View File

@@ -34,7 +34,7 @@ class IOSExternalTextureGL final : public Texture {
const SkRect& bounds,
bool freeze,
GrDirectContext* context,
SkFilterQuality filter_quality) override;
const SkSamplingOptions& sampling) override;
// |Texture|
void OnGrContextCreated() override;

View File

@@ -142,7 +142,7 @@ void IOSExternalTextureGL::Paint(SkCanvas& canvas,
const SkRect& bounds,
bool freeze,
GrDirectContext* context,
SkFilterQuality filter_quality) {
const SkSamplingOptions& sampling) {
EnsureTextureCacheExists();
if (NeedUpdateTexture(freeze)) {
auto pixelBuffer = [external_texture_.get() copyPixelBuffer];
@@ -167,9 +167,7 @@ void IOSExternalTextureGL::Paint(SkCanvas& canvas,
FML_DCHECK(image) << "Failed to create SkImage from Texture.";
if (image) {
SkPaint paint;
paint.setFilterQuality(filter_quality);
canvas.drawImage(image, bounds.x(), bounds.y(), &paint);
canvas.drawImage(image, bounds.x(), bounds.y(), sampling, nullptr);
}
}

View File

@@ -40,7 +40,7 @@ class IOSExternalTextureMetal final : public Texture {
const SkRect& bounds,
bool freeze,
GrDirectContext* context,
SkFilterQuality filter_quality) override;
const SkSamplingOptions& sampling) override;
// |Texture|
void OnGrContextCreated() override;

View File

@@ -30,7 +30,7 @@ void IOSExternalTextureMetal::Paint(SkCanvas& canvas,
const SkRect& bounds,
bool freeze,
GrDirectContext* context,
SkFilterQuality filter_quality) {
const SkSamplingOptions& sampling) {
const bool needs_updated_texture = (!freeze && texture_frame_available_) || !external_image_;
if (needs_updated_texture) {
@@ -51,12 +51,11 @@ void IOSExternalTextureMetal::Paint(SkCanvas& canvas,
}
if (external_image_) {
SkPaint paint;
paint.setFilterQuality(filter_quality);
canvas.drawImageRect(external_image_, // image
external_image_->bounds(), // source rect
bounds, // destination rect
&paint, // paint
canvas.drawImageRect(external_image_, // image
SkRect::Make(external_image_->bounds()), // source rect
bounds, // destination rect
sampling,
nullptr, // paint
SkCanvas::SrcRectConstraint::kFast_SrcRectConstraint // constraint
);
}

View File

@@ -22,7 +22,7 @@ void EmbedderExternalTextureGL::Paint(SkCanvas& canvas,
const SkRect& bounds,
bool freeze,
GrDirectContext* context,
SkFilterQuality filter_quality) {
const SkSamplingOptions& sampling) {
if (auto image = external_texture_callback_(
Id(), //
context, //
@@ -32,12 +32,10 @@ void EmbedderExternalTextureGL::Paint(SkCanvas& canvas,
}
if (last_image_) {
SkPaint paint;
paint.setFilterQuality(filter_quality);
if (bounds != SkRect::Make(last_image_->bounds())) {
canvas.drawImageRect(last_image_, bounds, &paint);
canvas.drawImageRect(last_image_, bounds, sampling);
} else {
canvas.drawImage(last_image_, bounds.x(), bounds.y(), &paint);
canvas.drawImage(last_image_, bounds.x(), bounds.y(), sampling, nullptr);
}
}
}

View File

@@ -33,7 +33,7 @@ class EmbedderExternalTextureGL : public flutter::Texture {
const SkRect& bounds,
bool freeze,
GrDirectContext* context,
SkFilterQuality filter_quality) override;
const SkSamplingOptions& sampling) override;
// |flutter::Texture|
void OnGrContextCreated() override;

View File

@@ -110,5 +110,14 @@ std::ostream& operator<<(std::ostream& os, const SkPaint& r) {
<< ", AA: " << r.isAntiAlias() << ", Shader: " << r.getShader();
}
std::ostream& operator<<(std::ostream& os, const SkSamplingOptions& s) {
if (s.useCubic) {
return os << "CubicResampler: " << s.cubic.B << ", " << s.cubic.C;
} else {
return os << "Filter: " << static_cast<int>(s.filter)
<< ", Mipmap: " << static_cast<int>(s.mipmap);
}
}
} // namespace testing
} // namespace flutter

View File

@@ -14,6 +14,7 @@
#include "third_party/skia/include/core/SkPath.h"
#include "third_party/skia/include/core/SkPoint3.h"
#include "third_party/skia/include/core/SkRRect.h"
#include "third_party/skia/include/core/SkSamplingOptions.h"
namespace flutter {
namespace testing {
@@ -29,6 +30,7 @@ extern std::ostream& operator<<(std::ostream& os, const SkPoint& r);
extern std::ostream& operator<<(std::ostream& os, const SkISize& size);
extern std::ostream& operator<<(std::ostream& os, const SkColor4f& r);
extern std::ostream& operator<<(std::ostream& os, const SkPaint& r);
extern std::ostream& operator<<(std::ostream& os, const SkSamplingOptions& s);
} // namespace testing
} // namespace flutter