mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Use drawImage for picture layer cache (#5315)
Fixes 1. https://github.com/flutter/flutter/issues/12148 2. most part of https://github.com/flutter/flutter/issues/17731 except some tiny AA diffs.
This commit is contained in:
parent
87944d84a3
commit
1ef8cd2f11
@ -73,13 +73,9 @@ std::ostream& operator<<(std::ostream& os, const SkPoint& r) {
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const flow::RasterCacheKey& k) {
|
||||
os << "Picture: " << k.picture_id() << " Scale: " << k.scale_key().width()
|
||||
<< ", " << k.scale_key().height()
|
||||
#if defined(OS_FUCHSIA)
|
||||
<< " Metrics scale: (" << k.metrics_scale_x() << ", "
|
||||
<< k.metrics_scale_y() << ")"
|
||||
#endif
|
||||
;
|
||||
SkString matrix_string;
|
||||
k.matrix().toString(&matrix_string);
|
||||
os << "Picture: " << k.picture_id() << " matrix: " << matrix_string.c_str();
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
@ -16,8 +16,13 @@ void PictureLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
|
||||
SkPicture* sk_picture = picture();
|
||||
|
||||
if (auto cache = context->raster_cache) {
|
||||
SkMatrix ctm = matrix;
|
||||
ctm.postTranslate(offset_.x(), offset_.y());
|
||||
#ifndef SUPPORT_FRACTIONAL_TRANSLATION
|
||||
ctm = RasterCache::GetIntegralTransCTM(ctm);
|
||||
#endif
|
||||
raster_cache_result_ = cache->GetPrerolledImage(
|
||||
context->gr_context, sk_picture, matrix, context->dst_color_space,
|
||||
context->gr_context, sk_picture, ctm, context->dst_color_space,
|
||||
is_complex_, will_change_);
|
||||
} else {
|
||||
raster_cache_result_ = RasterCacheResult();
|
||||
@ -34,17 +39,13 @@ void PictureLayer::Paint(PaintContext& context) const {
|
||||
|
||||
SkAutoCanvasRestore save(&context.canvas, true);
|
||||
context.canvas.translate(offset_.x(), offset_.y());
|
||||
#ifndef SUPPORT_FRACTIONAL_TRANSLATION
|
||||
context.canvas.setMatrix(
|
||||
RasterCache::GetIntegralTransCTM(context.canvas.getTotalMatrix()));
|
||||
#endif
|
||||
|
||||
if (raster_cache_result_.is_valid()) {
|
||||
SkPaint paint;
|
||||
paint.setFilterQuality(kLow_SkFilterQuality);
|
||||
context.canvas.drawImageRect(
|
||||
raster_cache_result_.image(), // image
|
||||
raster_cache_result_.source_rect(), // source
|
||||
raster_cache_result_.destination_rect(), // destination
|
||||
&paint, // paint
|
||||
SkCanvas::kStrict_SrcRectConstraint // source constraint
|
||||
);
|
||||
raster_cache_result_.draw(context.canvas);
|
||||
} else {
|
||||
context.canvas.drawPicture(picture());
|
||||
}
|
||||
|
||||
@ -17,6 +17,15 @@
|
||||
|
||||
namespace flow {
|
||||
|
||||
void RasterCacheResult::draw(SkCanvas& canvas) const {
|
||||
SkAutoCanvasRestore auto_restore(&canvas, false);
|
||||
SkIRect bounds =
|
||||
RasterCache::GetDeviceBounds(logical_rect_, canvas.getTotalMatrix());
|
||||
FXL_DCHECK(bounds.size() == image_->dimensions());
|
||||
canvas.resetMatrix();
|
||||
canvas.drawImage(image_, bounds.fLeft, bounds.fTop);
|
||||
}
|
||||
|
||||
RasterCache::RasterCache(size_t threshold)
|
||||
: threshold_(threshold), checkerboard_images_(false), weak_factory_(this) {}
|
||||
|
||||
@ -70,23 +79,16 @@ static bool IsPictureWorthRasterizing(SkPicture* picture,
|
||||
|
||||
RasterCacheResult RasterizePicture(SkPicture* picture,
|
||||
GrContext* context,
|
||||
const MatrixDecomposition& matrix,
|
||||
const SkMatrix& ctm,
|
||||
SkColorSpace* dst_color_space,
|
||||
bool checkerboard) {
|
||||
TRACE_EVENT0("flutter", "RasterCachePopulate");
|
||||
|
||||
const SkVector3& scale = matrix.scale();
|
||||
|
||||
const SkRect logical_rect = picture->cullRect();
|
||||
SkIRect cache_rect = RasterCache::GetDeviceBounds(logical_rect, ctm);
|
||||
|
||||
const SkRect physical_rect =
|
||||
SkRect::MakeWH(std::fabs(logical_rect.width() * scale.x()),
|
||||
std::fabs(logical_rect.height() * scale.y()));
|
||||
|
||||
const SkImageInfo image_info = SkImageInfo::MakeN32Premul(
|
||||
std::ceil(physical_rect.width()), // physical width
|
||||
std::ceil(physical_rect.height()) // physical height
|
||||
);
|
||||
const SkImageInfo image_info =
|
||||
SkImageInfo::MakeN32Premul(cache_rect.width(), cache_rect.height());
|
||||
|
||||
sk_sp<SkSurface> surface =
|
||||
context
|
||||
@ -108,19 +110,15 @@ RasterCacheResult RasterizePicture(SkPicture* picture,
|
||||
}
|
||||
|
||||
canvas->clear(SK_ColorTRANSPARENT);
|
||||
canvas->scale(std::abs(scale.x()), std::abs(scale.y()));
|
||||
canvas->translate(-logical_rect.left(), -logical_rect.top());
|
||||
canvas->translate(-cache_rect.left(), -cache_rect.top());
|
||||
canvas->concat(ctm);
|
||||
canvas->drawPicture(picture);
|
||||
|
||||
if (checkerboard) {
|
||||
DrawCheckerboard(canvas, logical_rect);
|
||||
}
|
||||
|
||||
return {
|
||||
surface->makeImageSnapshot(), // image
|
||||
physical_rect, // source rect
|
||||
logical_rect // destination rect
|
||||
};
|
||||
return {surface->makeImageSnapshot(), logical_rect};
|
||||
}
|
||||
|
||||
static inline size_t ClampSize(size_t value, size_t min, size_t max) {
|
||||
@ -156,7 +154,7 @@ RasterCacheResult RasterCache::GetPrerolledImage(
|
||||
return {};
|
||||
}
|
||||
|
||||
RasterCacheKey cache_key(*picture, matrix);
|
||||
RasterCacheKey cache_key(*picture, transformation_matrix);
|
||||
|
||||
Entry& entry = cache_[cache_key];
|
||||
entry.access_count = ClampSize(entry.access_count + 1, 0, threshold_);
|
||||
@ -168,8 +166,8 @@ RasterCacheResult RasterCache::GetPrerolledImage(
|
||||
}
|
||||
|
||||
if (!entry.image.is_valid()) {
|
||||
entry.image = RasterizePicture(picture, context, matrix, dst_color_space,
|
||||
checkerboard_images_);
|
||||
entry.image = RasterizePicture(picture, context, transformation_matrix,
|
||||
dst_color_space, checkerboard_images_);
|
||||
}
|
||||
|
||||
return entry.image;
|
||||
|
||||
@ -19,29 +19,20 @@ namespace flow {
|
||||
|
||||
class RasterCacheResult {
|
||||
public:
|
||||
RasterCacheResult()
|
||||
: source_rect_(SkRect::MakeEmpty()),
|
||||
destination_rect_(SkRect::MakeEmpty()) {}
|
||||
RasterCacheResult() {}
|
||||
|
||||
RasterCacheResult(sk_sp<SkImage> image, SkRect source, SkRect destination)
|
||||
: image_(std::move(image)),
|
||||
source_rect_(source),
|
||||
destination_rect_(destination) {}
|
||||
RasterCacheResult(sk_sp<SkImage> image, const SkRect& logical_rect)
|
||||
: image_(std::move(image)), logical_rect_(logical_rect) {}
|
||||
|
||||
operator bool() const { return static_cast<bool>(image_); }
|
||||
|
||||
bool is_valid() const { return static_cast<bool>(image_); };
|
||||
|
||||
sk_sp<SkImage> image() const { return image_; }
|
||||
|
||||
const SkRect& source_rect() const { return source_rect_; }
|
||||
|
||||
const SkRect& destination_rect() const { return destination_rect_; }
|
||||
void draw(SkCanvas& canvas) const;
|
||||
|
||||
private:
|
||||
sk_sp<SkImage> image_;
|
||||
SkRect source_rect_;
|
||||
SkRect destination_rect_;
|
||||
SkRect logical_rect_;
|
||||
};
|
||||
|
||||
class RasterCache {
|
||||
@ -50,6 +41,21 @@ class RasterCache {
|
||||
|
||||
~RasterCache();
|
||||
|
||||
static SkIRect GetDeviceBounds(const SkRect& rect, const SkMatrix& ctm) {
|
||||
SkRect device_rect;
|
||||
ctm.mapRect(&device_rect, rect);
|
||||
SkIRect bounds;
|
||||
device_rect.roundOut(&bounds);
|
||||
return bounds;
|
||||
}
|
||||
|
||||
static SkMatrix GetIntegralTransCTM(const SkMatrix& ctm) {
|
||||
SkMatrix result = ctm;
|
||||
result[SkMatrix::kMTransX] = SkScalarRoundToScalar(ctm.getTranslateX());
|
||||
result[SkMatrix::kMTransY] = SkScalarRoundToScalar(ctm.getTranslateY());
|
||||
return result;
|
||||
}
|
||||
|
||||
RasterCacheResult GetPrerolledImage(GrContext* context,
|
||||
SkPicture* picture,
|
||||
const SkMatrix& transformation_matrix,
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
|
||||
#include <unordered_map>
|
||||
#include "flutter/flow/matrix_decomposition.h"
|
||||
#include "lib/fxl/logging.h"
|
||||
#include "lib/fxl/macros.h"
|
||||
#include "third_party/skia/include/core/SkImage.h"
|
||||
#include "third_party/skia/include/core/SkPicture.h"
|
||||
@ -15,14 +16,17 @@ namespace flow {
|
||||
|
||||
class RasterCacheKey {
|
||||
public:
|
||||
RasterCacheKey(const SkPicture& picture, const MatrixDecomposition& matrix)
|
||||
: picture_id_(picture.uniqueID()),
|
||||
scale_key_(SkISize::Make(matrix.scale().x() * 1e3,
|
||||
matrix.scale().y() * 1e3)) {}
|
||||
RasterCacheKey(const SkPicture& picture, const SkMatrix& ctm)
|
||||
: picture_id_(picture.uniqueID()), matrix_(ctm) {
|
||||
matrix_[SkMatrix::kMTransX] = SkScalarFraction(ctm.getTranslateX());
|
||||
matrix_[SkMatrix::kMTransY] = SkScalarFraction(ctm.getTranslateY());
|
||||
#ifndef SUPPORT_FRACTIONAL_TRANSLATION
|
||||
FXL_DCHECK(matrix_.getTranslateX() == 0 && matrix_.getTranslateY() == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t picture_id() const { return picture_id_; }
|
||||
|
||||
const SkISize& scale_key() const { return scale_key_; }
|
||||
const SkMatrix& matrix() const { return matrix_; }
|
||||
|
||||
struct Hash {
|
||||
std::size_t operator()(RasterCacheKey const& key) const {
|
||||
@ -33,8 +37,7 @@ class RasterCacheKey {
|
||||
struct Equal {
|
||||
constexpr bool operator()(const RasterCacheKey& lhs,
|
||||
const RasterCacheKey& rhs) const {
|
||||
return lhs.picture_id_ == rhs.picture_id_ &&
|
||||
lhs.scale_key_ == rhs.scale_key_;
|
||||
return lhs.picture_id_ == rhs.picture_id_ && lhs.matrix_ == rhs.matrix_;
|
||||
}
|
||||
};
|
||||
|
||||
@ -43,7 +46,12 @@ class RasterCacheKey {
|
||||
|
||||
private:
|
||||
uint32_t picture_id_;
|
||||
SkISize scale_key_;
|
||||
|
||||
// ctm where only fractional (0-1) translations are preserved:
|
||||
// matrix_ = ctm;
|
||||
// matrix_[SkMatrix::kMTransX] = SkScalarFraction(ctm.getTranslateX());
|
||||
// matrix_[SkMatrix::kMTransY] = SkScalarFraction(ctm.getTranslateY());
|
||||
SkMatrix matrix_;
|
||||
};
|
||||
|
||||
} // namespace flow
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user