123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694 |
- // Copyright (c) 2017 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "cc/paint/image_transfer_cache_entry.h"
- #include <array>
- #include <type_traits>
- #include <utility>
- #include "base/callback_helpers.h"
- #include "base/logging.h"
- #include "base/notreached.h"
- #include "base/numerics/checked_math.h"
- #include "base/numerics/safe_conversions.h"
- #include "cc/paint/paint_op_reader.h"
- #include "cc/paint/paint_op_writer.h"
- #include "third_party/skia/include/core/SkColorSpace.h"
- #include "third_party/skia/include/core/SkImage.h"
- #include "third_party/skia/include/core/SkPixmap.h"
- #include "third_party/skia/include/core/SkYUVAInfo.h"
- #include "third_party/skia/include/gpu/GrBackendSurface.h"
- #include "third_party/skia/include/gpu/GrDirectContext.h"
- #include "third_party/skia/include/gpu/GrYUVABackendTextures.h"
- #include "ui/gfx/color_conversion_sk_filter_cache.h"
- namespace cc {
- namespace {
- struct Context {
- const std::vector<sk_sp<SkImage>> sk_planes_;
- };
- void ReleaseContext(SkImage::ReleaseContext context) {
- auto* texture_context = static_cast<Context*>(context);
- delete texture_context;
- }
- // Creates a SkImage backed by the YUV textures corresponding to |plane_images|.
- // The layout is specified by |plane_images_format|). The backend textures are
- // first extracted out of the |plane_images| (and work is flushed on each one).
- // Note that we assume that the image is opaque (no alpha plane). Then, a
- // SkImage is created out of those textures using the
- // SkImage::MakeFromYUVATextures() API. Finally, |image_color_space| is the
- // color space of the resulting image after applying |yuv_color_space|
- // (converting from YUV to RGB). This is assumed to be sRGB if nullptr.
- //
- // On success, the resulting SkImage is
- // returned. On failure, nullptr is returned (e.g., if one of the backend
- // textures is invalid or a Skia error occurs).
- sk_sp<SkImage> MakeYUVImageFromUploadedPlanes(
- GrDirectContext* context,
- const std::vector<sk_sp<SkImage>>& plane_images,
- SkYUVAInfo::PlaneConfig plane_config,
- SkYUVAInfo::Subsampling subsampling,
- SkYUVColorSpace yuv_color_space,
- sk_sp<SkColorSpace> image_color_space) {
- // 1) Extract the textures.
- DCHECK_NE(SkYUVAInfo::PlaneConfig::kUnknown, plane_config);
- DCHECK_NE(SkYUVAInfo::Subsampling::kUnknown, subsampling);
- DCHECK_EQ(static_cast<size_t>(SkYUVAInfo::NumPlanes(plane_config)),
- plane_images.size());
- DCHECK_LE(plane_images.size(),
- base::checked_cast<size_t>(SkYUVAInfo::kMaxPlanes));
- std::array<GrBackendTexture, SkYUVAInfo::kMaxPlanes> plane_backend_textures;
- for (size_t plane = 0u; plane < plane_images.size(); plane++) {
- plane_backend_textures[plane] = plane_images[plane]->getBackendTexture(
- true /* flushPendingGrContextIO */);
- if (!plane_backend_textures[plane].isValid()) {
- DLOG(ERROR) << "Invalid backend texture found";
- return nullptr;
- }
- }
- // 2) Create the YUV image.
- SkYUVAInfo yuva_info(plane_images[0]->dimensions(), plane_config, subsampling,
- yuv_color_space);
- GrYUVABackendTextures yuva_backend_textures(
- yuva_info, plane_backend_textures.data(), kTopLeft_GrSurfaceOrigin);
- Context* ctx = new Context{plane_images};
- sk_sp<SkImage> image = SkImage::MakeFromYUVATextures(
- context, yuva_backend_textures, std::move(image_color_space),
- ReleaseContext, ctx);
- if (!image) {
- DLOG(ERROR) << "Could not create YUV image";
- return nullptr;
- }
- return image;
- }
- base::CheckedNumeric<uint32_t> SafeSizeForPixmap(const SkPixmap& pixmap) {
- base::CheckedNumeric<uint32_t> safe_size;
- safe_size += sizeof(uint64_t); // color type
- safe_size += sizeof(uint64_t); // width
- safe_size += sizeof(uint64_t); // height
- safe_size += sizeof(uint64_t); // has color space
- if (pixmap.colorSpace())
- safe_size += pixmap.colorSpace()->writeToMemory(nullptr); // color space
- safe_size += sizeof(uint64_t); // row bytes
- safe_size += sizeof(uint64_t); // data size
- safe_size += sizeof(16u); // alignment
- safe_size += pixmap.computeByteSize(); // data
- return safe_size;
- }
- size_t GetAlignmentForColorType(SkColorType color_type) {
- size_t bpp = SkColorTypeBytesPerPixel(color_type);
- if (bpp <= 4)
- return 4;
- if (bpp <= 16)
- return 16;
- NOTREACHED();
- return 0;
- }
- bool WritePixmap(PaintOpWriter& writer, const SkPixmap& pixmap) {
- if (pixmap.width() == 0 || pixmap.height() == 0) {
- DLOG(ERROR) << "Cannot write empty pixmap";
- return false;
- }
- writer.Write(pixmap.colorType());
- writer.Write(pixmap.width());
- writer.Write(pixmap.height());
- writer.Write(pixmap.colorSpace());
- size_t data_size = pixmap.computeByteSize();
- if (data_size == SIZE_MAX) {
- DLOG(ERROR) << "Size overflow writing pixmap";
- return false;
- }
- writer.WriteSize(pixmap.rowBytes());
- writer.WriteSize(data_size);
- // The memory for the pixmap must be aligned to a byte boundary, or mipmap
- // generation can fail.
- // https://crbug.com/863659, https://crbug.com/1300188
- writer.AlignMemory(GetAlignmentForColorType(pixmap.colorType()));
- writer.WriteData(data_size, pixmap.addr());
- return true;
- }
- bool ReadPixmap(PaintOpReader& reader, SkPixmap& pixmap) {
- if (!reader.valid())
- return false;
- SkColorType color_type = kUnknown_SkColorType;
- reader.Read(&color_type);
- const size_t alignment = GetAlignmentForColorType(color_type);
- if (color_type == kUnknown_SkColorType ||
- color_type == kRGB_101010x_SkColorType ||
- color_type > kLastEnum_SkColorType) {
- DLOG(ERROR) << "Invalid color type";
- return false;
- }
- uint32_t width = 0;
- reader.Read(&width);
- uint32_t height = 0;
- reader.Read(&height);
- if (width == 0 || height == 0) {
- DLOG(ERROR) << "Empty width or height";
- return false;
- }
- sk_sp<SkColorSpace> color_space;
- reader.Read(&color_space);
- auto image_info = SkImageInfo::Make(width, height, color_type,
- kPremul_SkAlphaType, color_space);
- size_t row_bytes = 0;
- reader.ReadSize(&row_bytes);
- if (row_bytes < image_info.minRowBytes()) {
- DLOG(ERROR) << "Row bytes " << row_bytes << " less than minimum "
- << image_info.minRowBytes();
- return false;
- }
- size_t data_size = 0;
- reader.ReadSize(&data_size);
- if (image_info.computeByteSize(row_bytes) > data_size) {
- DLOG(ERROR) << "Data size too small";
- return false;
- }
- reader.AlignMemory(alignment);
- const volatile void* data = reader.ExtractReadableMemory(data_size);
- if (!reader.valid()) {
- DLOG(ERROR) << "Failed to read pixels";
- return false;
- }
- if (reinterpret_cast<uintptr_t>(data) % alignment) {
- DLOG(ERROR) << "Pixel pointer not aligned";
- return false;
- }
- // Const-cast away the "volatile" on |pixel_data|. We specifically understand
- // that a malicious caller may change our pixels under us, and are OK with
- // this as the worst case scenario is visual corruption.
- pixmap = SkPixmap(image_info, const_cast<const void*>(data), row_bytes);
- return true;
- }
- size_t TargetColorParamsSize(
- const absl::optional<TargetColorParams>& target_color_params) {
- // uint32 for whether or not there are going to be parameters.
- size_t target_color_params_size = sizeof(uint32_t);
- if (target_color_params) {
- // The target color space.
- target_color_params_size +=
- sizeof(uint64_t) +
- target_color_params->color_space.ToSkColorSpace()->writeToMemory(
- nullptr);
- // Floats for the SDR and HDR maximum luminance.
- target_color_params_size += sizeof(float);
- target_color_params_size += sizeof(float);
- // uint32_t for tone mapping enabled or disabled.
- target_color_params_size += sizeof(uint32_t);
- }
- return target_color_params_size;
- }
- void WriteTargetColorParams(
- PaintOpWriter& writer,
- const absl::optional<TargetColorParams>& target_color_params) {
- const uint32_t has_target_color_params = target_color_params ? 1 : 0;
- writer.Write(has_target_color_params);
- if (target_color_params) {
- writer.Write(target_color_params->color_space.ToSkColorSpace().get());
- writer.Write(target_color_params->sdr_max_luminance_nits);
- writer.Write(target_color_params->hdr_max_luminance_relative);
- writer.Write(target_color_params->enable_tone_mapping);
- }
- }
- bool ReadTargetColorParams(
- PaintOpReader& reader,
- absl::optional<TargetColorParams>& target_color_params) {
- uint32_t has_target_color_params = 0;
- reader.Read(&has_target_color_params);
- if (!has_target_color_params) {
- target_color_params = absl::nullopt;
- return true;
- }
- target_color_params = TargetColorParams();
- sk_sp<SkColorSpace> target_color_space;
- reader.Read(&target_color_space);
- if (!target_color_space)
- return false;
- target_color_params->color_space = gfx::ColorSpace(*target_color_space);
- reader.Read(&target_color_params->sdr_max_luminance_nits);
- reader.Read(&target_color_params->hdr_max_luminance_relative);
- reader.Read(&target_color_params->enable_tone_mapping);
- return true;
- }
- } // namespace
- size_t NumberOfPlanesForYUVDecodeFormat(YUVDecodeFormat format) {
- switch (format) {
- case YUVDecodeFormat::kYUVA4:
- return 4u;
- case YUVDecodeFormat::kYUV3:
- case YUVDecodeFormat::kYVU3:
- return 3u;
- case YUVDecodeFormat::kYUV2:
- return 2u;
- case YUVDecodeFormat::kUnknown:
- return 0u;
- }
- }
- ClientImageTransferCacheEntry::ClientImageTransferCacheEntry(
- const SkPixmap* pixmap,
- bool needs_mips,
- absl::optional<TargetColorParams> target_color_params)
- : needs_mips_(needs_mips),
- target_color_params_(target_color_params),
- id_(GetNextId()),
- pixmap_(pixmap),
- decoded_color_space_(nullptr) {
- size_t pixmap_color_space_size =
- pixmap_->colorSpace() ? pixmap_->colorSpace()->writeToMemory(nullptr)
- : 0u;
- // x64 has 8-byte alignment for uint64_t even though x86 has 4-byte
- // alignment. Always use 8 byte alignment.
- const size_t align = sizeof(uint64_t);
- // Compute and cache the size of the data.
- base::CheckedNumeric<uint32_t> safe_size;
- safe_size += PaintOpWriter::HeaderBytes();
- safe_size += sizeof(uint32_t); // is_yuv
- safe_size += sizeof(uint32_t); // color type
- safe_size += sizeof(uint32_t); // width
- safe_size += sizeof(uint32_t); // height
- safe_size += sizeof(uint32_t); // has mips
- safe_size += sizeof(uint64_t) + align; // pixels size + alignment
- safe_size += sizeof(uint64_t) + align; // row bytes + alignment
- safe_size += TargetColorParamsSize(target_color_params_);
- safe_size += pixmap_color_space_size + sizeof(uint64_t) + align;
- // Include 4 bytes of padding so we can always align our data pointer to a
- // 4-byte boundary.
- safe_size += 4;
- safe_size += pixmap_->computeByteSize();
- size_ = base::bits::AlignUp(size_t{safe_size.ValueOrDefault(0)},
- PaintOpWriter::Alignment());
- }
- ClientImageTransferCacheEntry::ClientImageTransferCacheEntry(
- const SkPixmap yuva_pixmaps[],
- SkYUVAInfo::PlaneConfig plane_config,
- SkYUVAInfo::Subsampling subsampling,
- const SkColorSpace* decoded_color_space,
- SkYUVColorSpace yuv_color_space,
- bool needs_mips,
- absl::optional<TargetColorParams> target_color_params)
- : needs_mips_(needs_mips),
- target_color_params_(target_color_params),
- plane_config_(plane_config),
- id_(GetNextId()),
- pixmap_(nullptr),
- decoded_color_space_(decoded_color_space),
- subsampling_(subsampling),
- yuv_color_space_(yuv_color_space) {
- yuv_pixmaps_.emplace(std::array<const SkPixmap*, SkYUVAInfo::kMaxPlanes>());
- size_t num_yuva_pixmaps =
- static_cast<size_t>(SkYUVAInfo::NumPlanes(plane_config));
- DCHECK_GT(num_yuva_pixmaps, 0U);
- DCHECK_LE(num_yuva_pixmaps, yuv_pixmaps_->size());
- for (size_t i = 0; i < num_yuva_pixmaps; ++i) {
- yuv_pixmaps_->at(i) = &yuva_pixmaps[i];
- }
- DCHECK(IsYuv());
- size_t decoded_color_space_size =
- decoded_color_space ? decoded_color_space->writeToMemory(nullptr) : 0u;
- // x64 has 8-byte alignment for uint64_t even though x86 has 4-byte
- // alignment. Always use 8 byte alignment.
- const size_t align = sizeof(uint64_t);
- // Compute and cache the size of the data.
- base::CheckedNumeric<uint32_t> safe_size;
- safe_size += PaintOpWriter::HeaderBytes();
- safe_size += sizeof(uint32_t); // has mips
- safe_size += sizeof(uint64_t); // target color space stub (is nullptr)
- safe_size += TargetColorParamsSize(target_color_params_);
- safe_size += sizeof(uint32_t); // plane_config
- safe_size += sizeof(uint32_t); // subsampling
- safe_size += sizeof(uint32_t); // YUVA color matrix for YUVA image
- safe_size += decoded_color_space_size + align; // SkColorSpace for YUVA image
- for (size_t i = 0; i < num_yuva_pixmaps; ++i)
- safe_size += SafeSizeForPixmap(*yuv_pixmaps_->at(i));
- size_ = base::bits::AlignUp(size_t{safe_size.ValueOrDefault(0)},
- PaintOpWriter::Alignment());
- }
- ClientImageTransferCacheEntry::~ClientImageTransferCacheEntry() = default;
- // static
- base::AtomicSequenceNumber ClientImageTransferCacheEntry::s_next_id_;
- uint32_t ClientImageTransferCacheEntry::SerializedSize() const {
- return size_;
- }
- uint32_t ClientImageTransferCacheEntry::Id() const {
- return id_;
- }
- void ClientImageTransferCacheEntry::ValidateYUVDataBeforeSerializing() const {
- DCHECK(!pixmap_);
- DCHECK_NE(subsampling_, SkYUVAInfo::Subsampling::kUnknown);
- DCHECK_LE(yuv_pixmaps_->size(), static_cast<size_t>(SkYUVAInfo::kMaxPlanes));
- size_t num_planes = static_cast<size_t>(SkYUVAInfo::NumPlanes(plane_config_));
- DCHECK_LE(num_planes, yuv_pixmaps_->size());
- for (size_t i = 0; i < num_planes; ++i) {
- DCHECK(yuv_pixmaps_->at(i));
- const SkPixmap* plane = yuv_pixmaps_->at(i);
- DCHECK_GT(plane->width(), 0);
- DCHECK_GT(plane->height(), 0);
- DCHECK_GT(plane->rowBytes(), 0u);
- }
- }
- bool ClientImageTransferCacheEntry::Serialize(base::span<uint8_t> data) const {
- DCHECK_GE(data.size(), SerializedSize());
- // We don't need to populate the SerializeOptions here since the writer is
- // only used for serializing primitives.
- PaintOp::SerializeOptions options;
- PaintOpWriter writer(data.data(), data.size(), options);
- writer.Write(static_cast<uint32_t>(needs_mips_ ? 1 : 0));
- WriteTargetColorParams(writer, target_color_params_);
- writer.Write(plane_config_);
- if (plane_config_ != SkYUVAInfo::PlaneConfig::kUnknown) {
- ValidateYUVDataBeforeSerializing();
- writer.Write(subsampling_);
- int num_planes = SkYUVAInfo::NumPlanes(plane_config_);
- writer.Write(yuv_color_space_);
- writer.Write(decoded_color_space_);
- for (int i = 0; i < num_planes; ++i) {
- DCHECK(yuv_pixmaps_->at(i));
- if (!WritePixmap(writer, *yuv_pixmaps_->at(i)))
- return false;
- }
- } else {
- if (!WritePixmap(writer, *pixmap_))
- return false;
- }
- // Size can't be 0 after serialization unless the writer has become invalid.
- if (writer.size() == 0u)
- return false;
- return true;
- }
- ServiceImageTransferCacheEntry::ServiceImageTransferCacheEntry() = default;
- ServiceImageTransferCacheEntry::~ServiceImageTransferCacheEntry() = default;
- ServiceImageTransferCacheEntry::ServiceImageTransferCacheEntry(
- ServiceImageTransferCacheEntry&& other) = default;
- ServiceImageTransferCacheEntry& ServiceImageTransferCacheEntry::operator=(
- ServiceImageTransferCacheEntry&& other) = default;
- bool ServiceImageTransferCacheEntry::BuildFromHardwareDecodedImage(
- GrDirectContext* context,
- std::vector<sk_sp<SkImage>> plane_images,
- SkYUVAInfo::PlaneConfig plane_config,
- SkYUVAInfo::Subsampling subsampling,
- SkYUVColorSpace yuv_color_space,
- size_t buffer_byte_size,
- bool needs_mips) {
- context_ = context;
- size_ = buffer_byte_size;
- // 1) Generate mipmap chains if requested.
- if (needs_mips) {
- DCHECK(plane_sizes_.empty());
- base::CheckedNumeric<size_t> safe_total_size(0u);
- for (size_t plane = 0; plane < plane_images.size(); plane++) {
- plane_images[plane] = plane_images[plane]->makeTextureImage(
- context_, GrMipMapped::kYes, SkBudgeted::kNo);
- if (!plane_images[plane]) {
- DLOG(ERROR) << "Could not generate mipmap chain for plane " << plane;
- return false;
- }
- plane_sizes_.push_back(plane_images[plane]->textureSize());
- safe_total_size += plane_sizes_.back();
- }
- if (!safe_total_size.AssignIfValid(&size_)) {
- DLOG(ERROR) << "Could not calculate the total image size";
- return false;
- }
- }
- plane_images_ = std::move(plane_images);
- plane_config_ = plane_config;
- subsampling_ = subsampling;
- yuv_color_space_ = yuv_color_space;
- // 2) Create a SkImage backed by |plane_images|.
- // TODO(andrescj): support embedded color profiles for hardware decodes and
- // pass the color space to MakeYUVImageFromUploadedPlanes.
- image_ = MakeYUVImageFromUploadedPlanes(context_, plane_images_, plane_config,
- subsampling, yuv_color_space,
- SkColorSpace::MakeSRGB());
- if (!image_)
- return false;
- // 3) Fill out the rest of the information.
- has_mips_ = needs_mips;
- fits_on_gpu_ = true;
- return true;
- }
- size_t ServiceImageTransferCacheEntry::CachedSize() const {
- return size_;
- }
- bool ServiceImageTransferCacheEntry::Deserialize(
- GrDirectContext* context,
- base::span<const uint8_t> data) {
- context_ = context;
- const int32_t max_size = context_->maxTextureSize();
- // We don't need to populate the DeSerializeOptions here since the reader is
- // only used for de-serializing primitives.
- std::vector<uint8_t> scratch_buffer;
- PaintOp::DeserializeOptions options(nullptr, nullptr, nullptr,
- &scratch_buffer, false, nullptr);
- PaintOpReader reader(data.data(), data.size(), options);
- // Parameters common to RGBA and YUVA images.
- uint32_t needs_mips = 0;
- reader.Read(&needs_mips);
- has_mips_ = needs_mips;
- absl::optional<TargetColorParams> target_color_params;
- ReadTargetColorParams(reader, target_color_params);
- plane_config_ = SkYUVAInfo::PlaneConfig::kUnknown;
- reader.Read(&plane_config_);
- const GrMipMapped mip_mapped_for_upload =
- has_mips_ && !target_color_params ? GrMipMapped::kYes : GrMipMapped::kNo;
- SkPixmap rgba_pixmap;
- sk_sp<SkImage> rgba_pixmap_image;
- if (plane_config_ != SkYUVAInfo::PlaneConfig::kUnknown) {
- SkYUVAInfo::Subsampling subsampling = SkYUVAInfo::Subsampling::kUnknown;
- reader.Read(&subsampling);
- if (subsampling == SkYUVAInfo::Subsampling::kUnknown) {
- DLOG(ERROR) << "Invalid subsampling";
- return false;
- }
- subsampling_ = subsampling;
- SkYUVColorSpace yuv_color_space = kIdentity_SkYUVColorSpace;
- reader.Read(&yuv_color_space);
- yuv_color_space_ = yuv_color_space;
- sk_sp<SkColorSpace> decoded_color_space;
- reader.Read(&decoded_color_space);
- int num_planes = SkYUVAInfo::NumPlanes(plane_config_);
- // Read in each plane and reconstruct pixmaps.
- for (int i = 0; i < num_planes; i++) {
- SkPixmap pixmap;
- if (!ReadPixmap(reader, pixmap)) {
- DLOG(ERROR) << "Failed to read plane pixmap";
- return false;
- }
- pixmap.setColorSpace(decoded_color_space);
- // In the GpuImageDecodeCache, we should veto YUV decoding if the planes
- // would be too big. Check again here for the case a malicious renderer .
- fits_on_gpu_ = pixmap.width() <= max_size && pixmap.height() <= max_size;
- if (!fits_on_gpu_) {
- DLOG(ERROR) << "Plane pixmap too large";
- return false;
- }
- sk_sp<SkImage> plane = SkImage::MakeFromRaster(pixmap, nullptr, nullptr);
- if (!plane) {
- DLOG(ERROR) << "Failed to create image from plane pixmap";
- return false;
- }
- plane = plane->makeTextureImage(context_, mip_mapped_for_upload,
- SkBudgeted::kNo);
- if (!plane) {
- DLOG(ERROR) << "Failed to upload plane pixmap to texture image";
- return false;
- }
- DCHECK(plane->isTextureBacked());
- plane->getBackendTexture(/*flushPendingGrContextIO=*/true);
- plane_sizes_.push_back(plane->textureSize());
- plane_images_.push_back(std::move(plane));
- }
- DCHECK(yuv_color_space_.has_value());
- image_ = MakeYUVImageFromUploadedPlanes(
- context_, plane_images_, plane_config_, subsampling_.value(),
- yuv_color_space_.value(), decoded_color_space);
- } else {
- if (!ReadPixmap(reader, rgba_pixmap)) {
- DLOG(ERROR) << "Failed to read pixmap";
- return false;
- }
- rgba_pixmap_image = SkImage::MakeFromRaster(rgba_pixmap, nullptr, nullptr);
- if (!rgba_pixmap_image) {
- DLOG(ERROR) << "Failed to create image from plane pixmap";
- return false;
- }
- fits_on_gpu_ =
- rgba_pixmap.width() <= max_size && rgba_pixmap.height() <= max_size;
- if (fits_on_gpu_) {
- image_ = rgba_pixmap_image->makeTextureImage(
- context, mip_mapped_for_upload, SkBudgeted::kNo);
- if (!image_) {
- DLOG(ERROR) << "Failed to upload pixmap to texture image";
- return false;
- }
- } else {
- // If the image is on the CPU, no work is needed to generate mips.
- has_mips_ = true;
- image_ = rgba_pixmap_image;
- }
- }
- DCHECK(image_);
- // Perform color conversion.
- if (target_color_params) {
- // TODO(https://crbug.com/1286088): Pass a shared cache as a parameter.
- gfx::ColorConversionSkFilterCache cache;
- image_ = cache.ConvertImage(
- image_, target_color_params->color_space.ToSkColorSpace(),
- target_color_params->sdr_max_luminance_nits,
- target_color_params->hdr_max_luminance_relative,
- target_color_params->enable_tone_mapping,
- fits_on_gpu_ ? context_ : nullptr);
- if (!image_) {
- DLOG(ERROR) << "Failed image color conversion";
- return false;
- }
- // Color conversion converts to RGBA. Remove all YUV state.
- plane_images_.clear();
- plane_sizes_.clear();
- plane_config_ = SkYUVAInfo::PlaneConfig::kUnknown;
- plane_sizes_.clear();
- subsampling_ = absl::nullopt;
- yuv_color_space_ = absl::nullopt;
- // If mipmaps were requested, create them after color conversion.
- if (has_mips_ && fits_on_gpu_) {
- image_ =
- image_->makeTextureImage(context, GrMipMapped::kYes, SkBudgeted::kNo);
- if (!image_) {
- DLOG(ERROR) << "Failed to generate mipmaps after color conversion";
- return false;
- }
- }
- }
- // If `image_` is still pointing at the original data from `rgba_pixmap`, make
- // a copy of it, because `rgba_pixmap` is directly referencing the transfer
- // buffer's memory, and will go away after this this call.
- if (image_ == rgba_pixmap_image) {
- image_ = SkImage::MakeRasterCopy(rgba_pixmap);
- if (!image_) {
- DLOG(ERROR) << "Failed to create raster copy";
- return false;
- }
- }
- size_ = image_->textureSize();
- return true;
- }
- const sk_sp<SkImage>& ServiceImageTransferCacheEntry::GetPlaneImage(
- size_t index) const {
- DCHECK_GE(index, 0u);
- DCHECK_LT(index, plane_images_.size());
- DCHECK(plane_images_.at(index));
- return plane_images_.at(index);
- }
- void ServiceImageTransferCacheEntry::EnsureMips() {
- if (has_mips_)
- return;
- DCHECK(fits_on_gpu_);
- if (is_yuv()) {
- DCHECK(image_);
- DCHECK(yuv_color_space_.has_value());
- DCHECK_NE(SkYUVAInfo::PlaneConfig::kUnknown, plane_config_);
- DCHECK_EQ(static_cast<size_t>(SkYUVAInfo::NumPlanes(plane_config_)),
- plane_images_.size());
- // We first do all the work with local variables. Then, if everything
- // succeeds, we update the object's state. That way, we don't leave it in an
- // inconsistent state if one step of mip generation fails.
- std::vector<sk_sp<SkImage>> mipped_planes;
- std::vector<size_t> mipped_plane_sizes;
- for (size_t plane = 0; plane < plane_images_.size(); plane++) {
- DCHECK(plane_images_.at(plane));
- sk_sp<SkImage> mipped_plane = plane_images_.at(plane)->makeTextureImage(
- context_, GrMipMapped::kYes, SkBudgeted::kNo);
- if (!mipped_plane)
- return;
- mipped_planes.push_back(std::move(mipped_plane));
- mipped_plane_sizes.push_back(mipped_planes.back()->textureSize());
- }
- sk_sp<SkImage> mipped_image = MakeYUVImageFromUploadedPlanes(
- context_, mipped_planes, plane_config_, subsampling_.value(),
- yuv_color_space_.value(),
- image_->refColorSpace() /* image_color_space */);
- if (!mipped_image) {
- DLOG(ERROR) << "Failed to create YUV image from mipmapped planes";
- return;
- }
- // Note that we cannot update |size_| because the transfer cache keeps track
- // of a total size that is not updated after EnsureMips(). The original size
- // is used when the image is deleted from the cache.
- plane_images_ = std::move(mipped_planes);
- plane_sizes_ = std::move(mipped_plane_sizes);
- image_ = std::move(mipped_image);
- } else {
- sk_sp<SkImage> mipped_image =
- image_->makeTextureImage(context_, GrMipMapped::kYes, SkBudgeted::kNo);
- if (!mipped_image) {
- DLOG(ERROR) << "Failed to mipmapped image";
- return;
- }
- image_ = std::move(mipped_image);
- }
- has_mips_ = true;
- }
- } // namespace cc
|