Commit 86c790e6 authored by Eric Karl's avatar Eric Karl Committed by Commit Bot

Remove use of DeferredTextureImageData APIs and Support Decode to Scale

We aren't benefitting from the complexity added by the
DeferredTextureImageData APIs, and this API blocks us from using
PaintImage::Decode's decode-to-scale functionality.

This change removes our usage of DeferredTextureImageData APIs,
instead using SkImage::makeTextureImage to handle upload. Additionally,
we now use the PaintImage::Decode API, adding decode-to-scale support.

Bug: 773799
Cq-Include-Trybots: master.tryserver.blink:linux_trusty_blink_rel
Change-Id: Ia5f480213c3a5c8225ccd289aa2c081056840f94
Reviewed-on: https://chromium-review.googlesource.com/713593Reviewed-by: default avatarvmpstr <vmpstr@chromium.org>
Commit-Queue: Eric Karl <ericrk@chromium.org>
Cr-Commit-Position: refs/heads/master@{#517206}
parent 4ce81f02
...@@ -126,36 +126,61 @@ gfx::Size CalculateSizeForMipLevel(const DrawImage& draw_image, int mip_level) { ...@@ -126,36 +126,61 @@ gfx::Size CalculateSizeForMipLevel(const DrawImage& draw_image, int mip_level) {
} }
// Draws and scales the provided |draw_image| into the |target_pixmap|. If the // Draws and scales the provided |draw_image| into the |target_pixmap|. If the
// draw/scale can be done directly, calls directly into SkImage::scalePixels, // draw/scale can be done directly, calls directly into PaintImage::Decode.
// if not, decodes to a compatible temporary pixmap and then converts that into // if not, decodes to a compatible temporary pixmap and then converts that into
// the |target_pixmap|. // the |target_pixmap|.
bool DrawAndScaleImage(const DrawImage& draw_image, SkPixmap* target_pixmap) { bool DrawAndScaleImage(const DrawImage& draw_image, SkPixmap* target_pixmap) {
sk_sp<SkImage> image = // We don't want to perform any color conversion here, so create a new pixmap
draw_image.paint_image().GetSkImageForFrame(draw_image.frame_index()); // with a null colorspace that shares |target_pixmap|'s memory.
if (image->dimensions() == target_pixmap->bounds().size() || SkPixmap pixmap(target_pixmap->info().makeColorSpace(nullptr),
target_pixmap->info().colorType() == kN32_SkColorType) { target_pixmap->writable_addr(), target_pixmap->rowBytes());
// If no scaling is occurring, or if the target colortype is already N32,
// just scale directly. const PaintImage& paint_image = draw_image.paint_image();
return image->scalePixels(*target_pixmap, SkISize supported_size =
CalculateDesiredFilterQuality(draw_image), paint_image.GetSupportedDecodeSize(pixmap.bounds().size());
SkImage::kDisallow_CachingHint);
} if (supported_size == pixmap.bounds().size()) {
SkImageInfo info = pixmap.info();
// If the target colortype is not N32, it may be impossible to scale return paint_image.Decode(pixmap.writable_addr(), &info, nullptr,
// directly. Instead scale into an N32 pixmap, and convert that into the draw_image.frame_index());
// |target_pixmap|. }
SkImageInfo decode_info =
target_pixmap->info().makeColorType(kN32_SkColorType); // If we can't decode/scale directly, we will handle this in up to 3 steps.
// Step 1: Decode at the nearest (larger) directly supported size.
SkImageInfo decode_info = SkImageInfo::MakeN32Premul(supported_size.width(),
supported_size.height());
SkBitmap decode_bitmap; SkBitmap decode_bitmap;
if (!decode_bitmap.tryAllocPixels(decode_info)) if (!decode_bitmap.tryAllocPixels(decode_info))
return false; return false;
SkPixmap decode_pixmap(decode_bitmap.info(), decode_bitmap.getPixels(), SkPixmap decode_pixmap(decode_bitmap.info(), decode_bitmap.getPixels(),
decode_bitmap.rowBytes()); decode_bitmap.rowBytes());
if (!image->scalePixels(decode_pixmap, if (!paint_image.Decode(decode_pixmap.writable_addr(), &decode_info, nullptr,
CalculateDesiredFilterQuality(draw_image), draw_image.frame_index())) {
SkImage::kDisallow_CachingHint)) return false;
}
// Step 2a: Scale to |pixmap| directly if kN32_SkColorType.
if (pixmap.info().colorType() == kN32_SkColorType) {
return decode_pixmap.scalePixels(pixmap,
CalculateDesiredFilterQuality(draw_image));
}
// Step 2b: Scale to temporary pixmap of kN32_SkColorType.
SkImageInfo scaled_info = pixmap.info().makeColorType(kN32_SkColorType);
SkBitmap scaled_bitmap;
if (!scaled_bitmap.tryAllocPixels(scaled_info))
return false;
SkPixmap scaled_pixmap(scaled_bitmap.info(), scaled_bitmap.getPixels(),
scaled_bitmap.rowBytes());
if (!decode_pixmap.scalePixels(scaled_pixmap,
CalculateDesiredFilterQuality(draw_image))) {
return false; return false;
return decode_pixmap.readPixels(*target_pixmap); }
// Step 3: Copy the temporary scaled pixmap to |pixmap|, performing
// color type conversion. We can't do the color conversion in step 1, as
// the scale in step 2 must happen in kN32_SkColorType.
return scaled_pixmap.readPixels(pixmap);
} }
// Returns the GL texture ID backing the given SkImage. // Returns the GL texture ID backing the given SkImage.
...@@ -382,16 +407,23 @@ void GpuImageDecodeCache::DecodedImageData::Unlock() { ...@@ -382,16 +407,23 @@ void GpuImageDecodeCache::DecodedImageData::Unlock() {
void GpuImageDecodeCache::DecodedImageData::SetLockedData( void GpuImageDecodeCache::DecodedImageData::SetLockedData(
std::unique_ptr<base::DiscardableMemory> data, std::unique_ptr<base::DiscardableMemory> data,
sk_sp<SkImage> image,
bool out_of_raster) { bool out_of_raster) {
DCHECK(data); DCHECK(data);
DCHECK(!data_); DCHECK(!data_);
DCHECK(image);
DCHECK(!image_);
data_ = std::move(data); data_ = std::move(data);
image_ = std::move(image);
OnSetLockedData(out_of_raster); OnSetLockedData(out_of_raster);
} }
void GpuImageDecodeCache::DecodedImageData::ResetData() { void GpuImageDecodeCache::DecodedImageData::ResetData() {
if (data_) if (data_) {
DCHECK(image_);
ReportUsageStats(); ReportUsageStats();
}
image_ = nullptr;
data_ = nullptr; data_ = nullptr;
OnResetData(); OnResetData();
} }
...@@ -443,11 +475,13 @@ GpuImageDecodeCache::ImageData::ImageData( ...@@ -443,11 +475,13 @@ GpuImageDecodeCache::ImageData::ImageData(
DecodedDataMode mode, DecodedDataMode mode,
size_t size, size_t size,
const gfx::ColorSpace& target_color_space, const gfx::ColorSpace& target_color_space,
const SkImage::DeferredTextureImageUsageParams& upload_params) SkFilterQuality quality,
int mip_level)
: mode(mode), : mode(mode),
size(size), size(size),
target_color_space(target_color_space), target_color_space(target_color_space),
upload_params(upload_params) {} quality(quality),
mip_level(mip_level) {}
GpuImageDecodeCache::ImageData::~ImageData() { GpuImageDecodeCache::ImageData::~ImageData() {
// We should never delete ImageData while it is in use or before it has been // We should never delete ImageData while it is in use or before it has been
...@@ -467,12 +501,11 @@ GpuImageDecodeCache::GpuImageDecodeCache(viz::ContextProvider* context, ...@@ -467,12 +501,11 @@ GpuImageDecodeCache::GpuImageDecodeCache(viz::ContextProvider* context,
context_(context), context_(context),
persistent_cache_(PersistentCache::NO_AUTO_EVICT), persistent_cache_(PersistentCache::NO_AUTO_EVICT),
max_working_set_bytes_(max_working_set_bytes) { max_working_set_bytes_(max_working_set_bytes) {
// Acquire the context_lock so that we can safely retrieve the // Acquire the context_lock so that we can safely retrieve
// GrContextThreadSafeProxy. This proxy can then be used with no lock held. // |max_texture_size_|.
{ {
viz::ContextProvider::ScopedContextLock context_lock(context_); viz::ContextProvider::ScopedContextLock context_lock(context_);
context_threadsafe_proxy_ = sk_sp<GrContextThreadSafeProxy>( max_texture_size_ = context_->GrContext()->caps()->maxTextureSize();
context_->GrContext()->threadSafeProxy());
} }
// In certain cases, ThreadTaskRunnerHandle isn't set (Android Webview). // In certain cases, ThreadTaskRunnerHandle isn't set (Android Webview).
...@@ -652,8 +685,8 @@ DecodedDrawImage GpuImageDecodeCache::GetDecodedImageForDraw( ...@@ -652,8 +685,8 @@ DecodedDrawImage GpuImageDecodeCache::GetDecodedImageForDraw(
image_data->upload.mark_used(); image_data->upload.mark_used();
DCHECK(image || image_data->decode.decode_failure); DCHECK(image || image_data->decode.decode_failure);
SkSize scale_factor = CalculateScaleFactorForMipLevel( SkSize scale_factor =
draw_image, image_data->upload_params.fPreScaleMipLevel); CalculateScaleFactorForMipLevel(draw_image, image_data->mip_level);
DecodedDrawImage decoded_draw_image( DecodedDrawImage decoded_draw_image(
std::move(image), SkSize(), scale_factor, std::move(image), SkSize(), scale_factor,
CalculateDesiredFilterQuality(draw_image)); CalculateDesiredFilterQuality(draw_image));
...@@ -1187,65 +1220,43 @@ void GpuImageDecodeCache::DecodeImageIfNecessary(const DrawImage& draw_image, ...@@ -1187,65 +1220,43 @@ void GpuImageDecodeCache::DecodeImageIfNecessary(const DrawImage& draw_image,
} }
TRACE_EVENT0("cc", "GpuImageDecodeCache::DecodeImage"); TRACE_EVENT0("cc", "GpuImageDecodeCache::DecodeImage");
RecordImageMipLevelUMA(image_data->upload_params.fPreScaleMipLevel); RecordImageMipLevelUMA(image_data->mip_level);
image_data->decode.ResetData(); image_data->decode.ResetData();
std::unique_ptr<base::DiscardableMemory> backing_memory; std::unique_ptr<base::DiscardableMemory> backing_memory;
sk_sp<SkImage> image;
{ {
base::AutoUnlock unlock(lock_); base::AutoUnlock unlock(lock_);
backing_memory = base::DiscardableMemoryAllocator::GetInstance() backing_memory = base::DiscardableMemoryAllocator::GetInstance()
->AllocateLockedDiscardableMemory(image_data->size); ->AllocateLockedDiscardableMemory(image_data->size);
SkImageInfo image_info =
switch (image_data->mode) { CreateImageInfoForDrawImage(draw_image, image_data->mip_level);
case DecodedDataMode::CPU: { SkPixmap pixmap(image_info, backing_memory->data(),
SkImageInfo image_info = CreateImageInfoForDrawImage( image_info.minRowBytes());
draw_image, image_data->upload_params.fPreScaleMipLevel); if (!DrawAndScaleImage(draw_image, &pixmap)) {
// In order to match GPU scaling quality (which uses mip-maps at high DLOG(ERROR) << "DrawAndScaleImage failed.";
// quality), we want to use at most medium filter quality for the
// scale.
SkPixmap image_pixmap(image_info.makeColorSpace(nullptr),
backing_memory->data(), image_info.minRowBytes());
// Note that scalePixels falls back to readPixels if the scale is 1x, so
// no need to special case that as an optimization.
if (!DrawAndScaleImage(draw_image, &image_pixmap)) {
DLOG(ERROR) << "scalePixels failed.";
backing_memory->Unlock();
backing_memory.reset();
}
break;
}
case DecodedDataMode::GPU: {
// TODO(crbug.com/649167): Params should not have changed since initial
// sizing. Somehow this still happens. We should investigate and re-add
// DCHECKs here to enforce this.
sk_sp<SkImage> image = draw_image.paint_image().GetSkImageForFrame(
draw_image.frame_index());
if (!image->getDeferredTextureImageData(
*context_threadsafe_proxy_.get(), &image_data->upload_params, 1,
backing_memory->data(), nullptr, color_type_)) {
DLOG(ERROR) << "getDeferredTextureImageData failed despite params "
<< "having validated.";
backing_memory->Unlock(); backing_memory->Unlock();
backing_memory.reset(); backing_memory.reset();
} } else {
break; image =
} SkImage::MakeFromRaster(pixmap, [](const void*, void*) {}, nullptr);
} }
} }
if (image_data->decode.data()) { if (image_data->decode.data()) {
DCHECK(image_data->decode.image());
// An at-raster task decoded this before us. Ingore our decode. // An at-raster task decoded this before us. Ingore our decode.
return; return;
} }
if (!backing_memory) { if (!backing_memory) {
DCHECK(!image);
// If |backing_memory| was not populated, we had a non-decodable image. // If |backing_memory| was not populated, we had a non-decodable image.
image_data->decode.decode_failure = true; image_data->decode.decode_failure = true;
return; return;
} }
image_data->decode.SetLockedData(std::move(backing_memory), image_data->decode.SetLockedData(std::move(backing_memory), std::move(image),
task_type == TaskType::kOutOfRaster); task_type == TaskType::kOutOfRaster);
} }
...@@ -1275,26 +1286,11 @@ void GpuImageDecodeCache::UploadImageIfNecessary(const DrawImage& draw_image, ...@@ -1275,26 +1286,11 @@ void GpuImageDecodeCache::UploadImageIfNecessary(const DrawImage& draw_image,
DCHECK_GT(image_data->decode.ref_count, 0u); DCHECK_GT(image_data->decode.ref_count, 0u);
DCHECK_GT(image_data->upload.ref_count, 0u); DCHECK_GT(image_data->upload.ref_count, 0u);
sk_sp<SkImage> uploaded_image; sk_sp<SkImage> uploaded_image = image_data->decode.image();
{ if (image_data->mode == DecodedDataMode::GPU) {
base::AutoUnlock unlock(lock_); base::AutoUnlock unlock(lock_);
switch (image_data->mode) {
case DecodedDataMode::CPU: {
SkImageInfo image_info = CreateImageInfoForDrawImage(
draw_image, image_data->upload_params.fPreScaleMipLevel);
SkPixmap pixmap(image_info, image_data->decode.data()->data(),
image_info.minRowBytes());
uploaded_image = uploaded_image =
SkImage::MakeFromRaster(pixmap, [](const void*, void*) {}, nullptr); uploaded_image->makeTextureImage(context_->GrContext(), nullptr);
break;
}
case DecodedDataMode::GPU: {
uploaded_image = SkImage::MakeFromDeferredTextureImageData(
context_->GrContext(), image_data->decode.data()->data(),
SkBudgeted::kNo);
break;
}
}
} }
image_data->decode.mark_used(); image_data->decode.mark_used();
...@@ -1339,30 +1335,22 @@ GpuImageDecodeCache::CreateImageData(const DrawImage& draw_image) { ...@@ -1339,30 +1335,22 @@ GpuImageDecodeCache::CreateImageData(const DrawImage& draw_image) {
"GpuImageDecodeCache::CreateImageData"); "GpuImageDecodeCache::CreateImageData");
lock_.AssertAcquired(); lock_.AssertAcquired();
int mip_level = CalculateUploadScaleMipLevel(draw_image);
SkImageInfo image_info = CreateImageInfoForDrawImage(draw_image, mip_level);
DecodedDataMode mode; DecodedDataMode mode;
int upload_scale_mip_level = CalculateUploadScaleMipLevel(draw_image); if (image_info.width() > max_texture_size_ ||
// TODO(ericrk): Remove the matrix parameter in this call. image_info.height() > max_texture_size_) {
auto params = SkImage::DeferredTextureImageUsageParams( // Image too large to upload. Try to use SW fallback.
SkMatrix::I(), CalculateDesiredFilterQuality(draw_image),
upload_scale_mip_level);
sk_sp<SkImage> image =
draw_image.paint_image().GetSkImageForFrame(draw_image.frame_index());
size_t data_size = image->getDeferredTextureImageData(
*context_threadsafe_proxy_.get(), &params, 1, nullptr, nullptr,
color_type_);
if (data_size == 0) {
// Can't upload image, too large or other failure. Try to use SW fallback.
SkImageInfo image_info =
CreateImageInfoForDrawImage(draw_image, upload_scale_mip_level);
data_size = image_info.computeMinByteSize();
mode = DecodedDataMode::CPU; mode = DecodedDataMode::CPU;
} else { } else {
mode = DecodedDataMode::GPU; mode = DecodedDataMode::GPU;
} }
return base::MakeRefCounted<ImageData>( size_t data_size = image_info.computeMinByteSize();
mode, data_size, draw_image.target_color_space(), params); return base::WrapRefCounted(
new ImageData(mode, data_size, draw_image.target_color_space(),
CalculateDesiredFilterQuality(draw_image), mip_level));
} }
void GpuImageDecodeCache::DeleteImage(ImageData* image_data) { void GpuImageDecodeCache::DeleteImage(ImageData* image_data) {
...@@ -1419,7 +1407,7 @@ SkImageInfo GpuImageDecodeCache::CreateImageInfoForDrawImage( ...@@ -1419,7 +1407,7 @@ SkImageInfo GpuImageDecodeCache::CreateImageInfoForDrawImage(
CalculateSizeForMipLevel(draw_image, upload_scale_mip_level); CalculateSizeForMipLevel(draw_image, upload_scale_mip_level);
return SkImageInfo::Make(mip_size.width(), mip_size.height(), color_type_, return SkImageInfo::Make(mip_size.width(), mip_size.height(), color_type_,
kPremul_SkAlphaType, kPremul_SkAlphaType,
draw_image.target_color_space().ToSkColorSpace()); sk_ref_sp(draw_image.paint_image().color_space()));
} }
bool GpuImageDecodeCache::TryLockImage(HaveContextLock have_context_lock, bool GpuImageDecodeCache::TryLockImage(HaveContextLock have_context_lock,
...@@ -1492,11 +1480,11 @@ GpuImageDecodeCache::ImageData* GpuImageDecodeCache::GetImageDataForDrawImage( ...@@ -1492,11 +1480,11 @@ GpuImageDecodeCache::ImageData* GpuImageDecodeCache::GetImageDataForDrawImage(
// the provided |draw_image|. // the provided |draw_image|.
bool GpuImageDecodeCache::IsCompatible(const ImageData* image_data, bool GpuImageDecodeCache::IsCompatible(const ImageData* image_data,
const DrawImage& draw_image) const { const DrawImage& draw_image) const {
bool is_scaled = image_data->upload_params.fPreScaleMipLevel != 0; bool is_scaled = image_data->mip_level != 0;
bool scale_is_compatible = CalculateUploadScaleMipLevel(draw_image) >= bool scale_is_compatible =
image_data->upload_params.fPreScaleMipLevel; CalculateUploadScaleMipLevel(draw_image) >= image_data->mip_level;
bool quality_is_compatible = CalculateDesiredFilterQuality(draw_image) <= bool quality_is_compatible =
image_data->upload_params.fQuality; CalculateDesiredFilterQuality(draw_image) <= image_data->quality;
bool color_is_compatible = bool color_is_compatible =
image_data->target_color_space == draw_image.target_color_space(); image_data->target_color_space == draw_image.target_color_space();
if (!color_is_compatible) if (!color_is_compatible)
......
...@@ -203,9 +203,14 @@ class CC_EXPORT GpuImageDecodeCache ...@@ -203,9 +203,14 @@ class CC_EXPORT GpuImageDecodeCache
void Unlock(); void Unlock();
void SetLockedData(std::unique_ptr<base::DiscardableMemory> data, void SetLockedData(std::unique_ptr<base::DiscardableMemory> data,
sk_sp<SkImage> image,
bool out_of_raster); bool out_of_raster);
void ResetData(); void ResetData();
base::DiscardableMemory* data() const { return data_.get(); } base::DiscardableMemory* data() const { return data_.get(); }
sk_sp<SkImage> image() const {
DCHECK(is_locked());
return image_;
}
bool decode_failure = false; bool decode_failure = false;
// Similar to |task|, but only is generated if there is no associated upload // Similar to |task|, but only is generated if there is no associated upload
...@@ -216,6 +221,7 @@ class CC_EXPORT GpuImageDecodeCache ...@@ -216,6 +221,7 @@ class CC_EXPORT GpuImageDecodeCache
void ReportUsageStats() const; void ReportUsageStats() const;
std::unique_ptr<base::DiscardableMemory> data_; std::unique_ptr<base::DiscardableMemory> data_;
sk_sp<SkImage> image_;
}; };
// Stores the GPU-side image and supporting fields. // Stores the GPU-side image and supporting fields.
...@@ -243,13 +249,15 @@ class CC_EXPORT GpuImageDecodeCache ...@@ -243,13 +249,15 @@ class CC_EXPORT GpuImageDecodeCache
ImageData(DecodedDataMode mode, ImageData(DecodedDataMode mode,
size_t size, size_t size,
const gfx::ColorSpace& target_color_space, const gfx::ColorSpace& target_color_space,
const SkImage::DeferredTextureImageUsageParams& upload_params); SkFilterQuality quality,
int mip_level);
const DecodedDataMode mode; const DecodedDataMode mode;
const size_t size; const size_t size;
gfx::ColorSpace target_color_space; gfx::ColorSpace target_color_space;
SkFilterQuality quality;
int mip_level;
bool is_at_raster = false; bool is_at_raster = false;
SkImage::DeferredTextureImageUsageParams upload_params;
// If true, this image is no longer in our |persistent_cache_| and will be // If true, this image is no longer in our |persistent_cache_| and will be
// deleted as soon as its ref count reaches zero. // deleted as soon as its ref count reaches zero.
...@@ -373,7 +381,7 @@ class CC_EXPORT GpuImageDecodeCache ...@@ -373,7 +381,7 @@ class CC_EXPORT GpuImageDecodeCache
const SkColorType color_type_; const SkColorType color_type_;
viz::ContextProvider* context_; viz::ContextProvider* context_;
sk_sp<GrContextThreadSafeProxy> context_threadsafe_proxy_; int max_texture_size_ = 0;
// All members below this point must only be accessed while holding |lock_|. // All members below this point must only be accessed while holding |lock_|.
// The exception are const members like |normal_max_cache_bytes_| that can // The exception are const members like |normal_max_cache_bytes_| that can
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment