image_transfer_cache_entry.cc 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694
  1. // Copyright (c) 2017 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "cc/paint/image_transfer_cache_entry.h"
  5. #include <array>
  6. #include <type_traits>
  7. #include <utility>
  8. #include "base/callback_helpers.h"
  9. #include "base/logging.h"
  10. #include "base/notreached.h"
  11. #include "base/numerics/checked_math.h"
  12. #include "base/numerics/safe_conversions.h"
  13. #include "cc/paint/paint_op_reader.h"
  14. #include "cc/paint/paint_op_writer.h"
  15. #include "third_party/skia/include/core/SkColorSpace.h"
  16. #include "third_party/skia/include/core/SkImage.h"
  17. #include "third_party/skia/include/core/SkPixmap.h"
  18. #include "third_party/skia/include/core/SkYUVAInfo.h"
  19. #include "third_party/skia/include/gpu/GrBackendSurface.h"
  20. #include "third_party/skia/include/gpu/GrDirectContext.h"
  21. #include "third_party/skia/include/gpu/GrYUVABackendTextures.h"
  22. #include "ui/gfx/color_conversion_sk_filter_cache.h"
  23. namespace cc {
  24. namespace {
  25. struct Context {
  26. const std::vector<sk_sp<SkImage>> sk_planes_;
  27. };
  28. void ReleaseContext(SkImage::ReleaseContext context) {
  29. auto* texture_context = static_cast<Context*>(context);
  30. delete texture_context;
  31. }
  32. // Creates a SkImage backed by the YUV textures corresponding to |plane_images|.
  33. // The layout is specified by |plane_images_format|). The backend textures are
  34. // first extracted out of the |plane_images| (and work is flushed on each one).
  35. // Note that we assume that the image is opaque (no alpha plane). Then, a
  36. // SkImage is created out of those textures using the
  37. // SkImage::MakeFromYUVATextures() API. Finally, |image_color_space| is the
  38. // color space of the resulting image after applying |yuv_color_space|
  39. // (converting from YUV to RGB). This is assumed to be sRGB if nullptr.
  40. //
  41. // On success, the resulting SkImage is
  42. // returned. On failure, nullptr is returned (e.g., if one of the backend
  43. // textures is invalid or a Skia error occurs).
  44. sk_sp<SkImage> MakeYUVImageFromUploadedPlanes(
  45. GrDirectContext* context,
  46. const std::vector<sk_sp<SkImage>>& plane_images,
  47. SkYUVAInfo::PlaneConfig plane_config,
  48. SkYUVAInfo::Subsampling subsampling,
  49. SkYUVColorSpace yuv_color_space,
  50. sk_sp<SkColorSpace> image_color_space) {
  51. // 1) Extract the textures.
  52. DCHECK_NE(SkYUVAInfo::PlaneConfig::kUnknown, plane_config);
  53. DCHECK_NE(SkYUVAInfo::Subsampling::kUnknown, subsampling);
  54. DCHECK_EQ(static_cast<size_t>(SkYUVAInfo::NumPlanes(plane_config)),
  55. plane_images.size());
  56. DCHECK_LE(plane_images.size(),
  57. base::checked_cast<size_t>(SkYUVAInfo::kMaxPlanes));
  58. std::array<GrBackendTexture, SkYUVAInfo::kMaxPlanes> plane_backend_textures;
  59. for (size_t plane = 0u; plane < plane_images.size(); plane++) {
  60. plane_backend_textures[plane] = plane_images[plane]->getBackendTexture(
  61. true /* flushPendingGrContextIO */);
  62. if (!plane_backend_textures[plane].isValid()) {
  63. DLOG(ERROR) << "Invalid backend texture found";
  64. return nullptr;
  65. }
  66. }
  67. // 2) Create the YUV image.
  68. SkYUVAInfo yuva_info(plane_images[0]->dimensions(), plane_config, subsampling,
  69. yuv_color_space);
  70. GrYUVABackendTextures yuva_backend_textures(
  71. yuva_info, plane_backend_textures.data(), kTopLeft_GrSurfaceOrigin);
  72. Context* ctx = new Context{plane_images};
  73. sk_sp<SkImage> image = SkImage::MakeFromYUVATextures(
  74. context, yuva_backend_textures, std::move(image_color_space),
  75. ReleaseContext, ctx);
  76. if (!image) {
  77. DLOG(ERROR) << "Could not create YUV image";
  78. return nullptr;
  79. }
  80. return image;
  81. }
  82. base::CheckedNumeric<uint32_t> SafeSizeForPixmap(const SkPixmap& pixmap) {
  83. base::CheckedNumeric<uint32_t> safe_size;
  84. safe_size += sizeof(uint64_t); // color type
  85. safe_size += sizeof(uint64_t); // width
  86. safe_size += sizeof(uint64_t); // height
  87. safe_size += sizeof(uint64_t); // has color space
  88. if (pixmap.colorSpace())
  89. safe_size += pixmap.colorSpace()->writeToMemory(nullptr); // color space
  90. safe_size += sizeof(uint64_t); // row bytes
  91. safe_size += sizeof(uint64_t); // data size
  92. safe_size += sizeof(16u); // alignment
  93. safe_size += pixmap.computeByteSize(); // data
  94. return safe_size;
  95. }
  96. size_t GetAlignmentForColorType(SkColorType color_type) {
  97. size_t bpp = SkColorTypeBytesPerPixel(color_type);
  98. if (bpp <= 4)
  99. return 4;
  100. if (bpp <= 16)
  101. return 16;
  102. NOTREACHED();
  103. return 0;
  104. }
  105. bool WritePixmap(PaintOpWriter& writer, const SkPixmap& pixmap) {
  106. if (pixmap.width() == 0 || pixmap.height() == 0) {
  107. DLOG(ERROR) << "Cannot write empty pixmap";
  108. return false;
  109. }
  110. writer.Write(pixmap.colorType());
  111. writer.Write(pixmap.width());
  112. writer.Write(pixmap.height());
  113. writer.Write(pixmap.colorSpace());
  114. size_t data_size = pixmap.computeByteSize();
  115. if (data_size == SIZE_MAX) {
  116. DLOG(ERROR) << "Size overflow writing pixmap";
  117. return false;
  118. }
  119. writer.WriteSize(pixmap.rowBytes());
  120. writer.WriteSize(data_size);
  121. // The memory for the pixmap must be aligned to a byte boundary, or mipmap
  122. // generation can fail.
  123. // https://crbug.com/863659, https://crbug.com/1300188
  124. writer.AlignMemory(GetAlignmentForColorType(pixmap.colorType()));
  125. writer.WriteData(data_size, pixmap.addr());
  126. return true;
  127. }
  128. bool ReadPixmap(PaintOpReader& reader, SkPixmap& pixmap) {
  129. if (!reader.valid())
  130. return false;
  131. SkColorType color_type = kUnknown_SkColorType;
  132. reader.Read(&color_type);
  133. const size_t alignment = GetAlignmentForColorType(color_type);
  134. if (color_type == kUnknown_SkColorType ||
  135. color_type == kRGB_101010x_SkColorType ||
  136. color_type > kLastEnum_SkColorType) {
  137. DLOG(ERROR) << "Invalid color type";
  138. return false;
  139. }
  140. uint32_t width = 0;
  141. reader.Read(&width);
  142. uint32_t height = 0;
  143. reader.Read(&height);
  144. if (width == 0 || height == 0) {
  145. DLOG(ERROR) << "Empty width or height";
  146. return false;
  147. }
  148. sk_sp<SkColorSpace> color_space;
  149. reader.Read(&color_space);
  150. auto image_info = SkImageInfo::Make(width, height, color_type,
  151. kPremul_SkAlphaType, color_space);
  152. size_t row_bytes = 0;
  153. reader.ReadSize(&row_bytes);
  154. if (row_bytes < image_info.minRowBytes()) {
  155. DLOG(ERROR) << "Row bytes " << row_bytes << " less than minimum "
  156. << image_info.minRowBytes();
  157. return false;
  158. }
  159. size_t data_size = 0;
  160. reader.ReadSize(&data_size);
  161. if (image_info.computeByteSize(row_bytes) > data_size) {
  162. DLOG(ERROR) << "Data size too small";
  163. return false;
  164. }
  165. reader.AlignMemory(alignment);
  166. const volatile void* data = reader.ExtractReadableMemory(data_size);
  167. if (!reader.valid()) {
  168. DLOG(ERROR) << "Failed to read pixels";
  169. return false;
  170. }
  171. if (reinterpret_cast<uintptr_t>(data) % alignment) {
  172. DLOG(ERROR) << "Pixel pointer not aligned";
  173. return false;
  174. }
  175. // Const-cast away the "volatile" on |pixel_data|. We specifically understand
  176. // that a malicious caller may change our pixels under us, and are OK with
  177. // this as the worst case scenario is visual corruption.
  178. pixmap = SkPixmap(image_info, const_cast<const void*>(data), row_bytes);
  179. return true;
  180. }
  181. size_t TargetColorParamsSize(
  182. const absl::optional<TargetColorParams>& target_color_params) {
  183. // uint32 for whether or not there are going to be parameters.
  184. size_t target_color_params_size = sizeof(uint32_t);
  185. if (target_color_params) {
  186. // The target color space.
  187. target_color_params_size +=
  188. sizeof(uint64_t) +
  189. target_color_params->color_space.ToSkColorSpace()->writeToMemory(
  190. nullptr);
  191. // Floats for the SDR and HDR maximum luminance.
  192. target_color_params_size += sizeof(float);
  193. target_color_params_size += sizeof(float);
  194. // uint32_t for tone mapping enabled or disabled.
  195. target_color_params_size += sizeof(uint32_t);
  196. }
  197. return target_color_params_size;
  198. }
  199. void WriteTargetColorParams(
  200. PaintOpWriter& writer,
  201. const absl::optional<TargetColorParams>& target_color_params) {
  202. const uint32_t has_target_color_params = target_color_params ? 1 : 0;
  203. writer.Write(has_target_color_params);
  204. if (target_color_params) {
  205. writer.Write(target_color_params->color_space.ToSkColorSpace().get());
  206. writer.Write(target_color_params->sdr_max_luminance_nits);
  207. writer.Write(target_color_params->hdr_max_luminance_relative);
  208. writer.Write(target_color_params->enable_tone_mapping);
  209. }
  210. }
  211. bool ReadTargetColorParams(
  212. PaintOpReader& reader,
  213. absl::optional<TargetColorParams>& target_color_params) {
  214. uint32_t has_target_color_params = 0;
  215. reader.Read(&has_target_color_params);
  216. if (!has_target_color_params) {
  217. target_color_params = absl::nullopt;
  218. return true;
  219. }
  220. target_color_params = TargetColorParams();
  221. sk_sp<SkColorSpace> target_color_space;
  222. reader.Read(&target_color_space);
  223. if (!target_color_space)
  224. return false;
  225. target_color_params->color_space = gfx::ColorSpace(*target_color_space);
  226. reader.Read(&target_color_params->sdr_max_luminance_nits);
  227. reader.Read(&target_color_params->hdr_max_luminance_relative);
  228. reader.Read(&target_color_params->enable_tone_mapping);
  229. return true;
  230. }
  231. } // namespace
  232. size_t NumberOfPlanesForYUVDecodeFormat(YUVDecodeFormat format) {
  233. switch (format) {
  234. case YUVDecodeFormat::kYUVA4:
  235. return 4u;
  236. case YUVDecodeFormat::kYUV3:
  237. case YUVDecodeFormat::kYVU3:
  238. return 3u;
  239. case YUVDecodeFormat::kYUV2:
  240. return 2u;
  241. case YUVDecodeFormat::kUnknown:
  242. return 0u;
  243. }
  244. }
  245. ClientImageTransferCacheEntry::ClientImageTransferCacheEntry(
  246. const SkPixmap* pixmap,
  247. bool needs_mips,
  248. absl::optional<TargetColorParams> target_color_params)
  249. : needs_mips_(needs_mips),
  250. target_color_params_(target_color_params),
  251. id_(GetNextId()),
  252. pixmap_(pixmap),
  253. decoded_color_space_(nullptr) {
  254. size_t pixmap_color_space_size =
  255. pixmap_->colorSpace() ? pixmap_->colorSpace()->writeToMemory(nullptr)
  256. : 0u;
  257. // x64 has 8-byte alignment for uint64_t even though x86 has 4-byte
  258. // alignment. Always use 8 byte alignment.
  259. const size_t align = sizeof(uint64_t);
  260. // Compute and cache the size of the data.
  261. base::CheckedNumeric<uint32_t> safe_size;
  262. safe_size += PaintOpWriter::HeaderBytes();
  263. safe_size += sizeof(uint32_t); // is_yuv
  264. safe_size += sizeof(uint32_t); // color type
  265. safe_size += sizeof(uint32_t); // width
  266. safe_size += sizeof(uint32_t); // height
  267. safe_size += sizeof(uint32_t); // has mips
  268. safe_size += sizeof(uint64_t) + align; // pixels size + alignment
  269. safe_size += sizeof(uint64_t) + align; // row bytes + alignment
  270. safe_size += TargetColorParamsSize(target_color_params_);
  271. safe_size += pixmap_color_space_size + sizeof(uint64_t) + align;
  272. // Include 4 bytes of padding so we can always align our data pointer to a
  273. // 4-byte boundary.
  274. safe_size += 4;
  275. safe_size += pixmap_->computeByteSize();
  276. size_ = base::bits::AlignUp(size_t{safe_size.ValueOrDefault(0)},
  277. PaintOpWriter::Alignment());
  278. }
  279. ClientImageTransferCacheEntry::ClientImageTransferCacheEntry(
  280. const SkPixmap yuva_pixmaps[],
  281. SkYUVAInfo::PlaneConfig plane_config,
  282. SkYUVAInfo::Subsampling subsampling,
  283. const SkColorSpace* decoded_color_space,
  284. SkYUVColorSpace yuv_color_space,
  285. bool needs_mips,
  286. absl::optional<TargetColorParams> target_color_params)
  287. : needs_mips_(needs_mips),
  288. target_color_params_(target_color_params),
  289. plane_config_(plane_config),
  290. id_(GetNextId()),
  291. pixmap_(nullptr),
  292. decoded_color_space_(decoded_color_space),
  293. subsampling_(subsampling),
  294. yuv_color_space_(yuv_color_space) {
  295. yuv_pixmaps_.emplace(std::array<const SkPixmap*, SkYUVAInfo::kMaxPlanes>());
  296. size_t num_yuva_pixmaps =
  297. static_cast<size_t>(SkYUVAInfo::NumPlanes(plane_config));
  298. DCHECK_GT(num_yuva_pixmaps, 0U);
  299. DCHECK_LE(num_yuva_pixmaps, yuv_pixmaps_->size());
  300. for (size_t i = 0; i < num_yuva_pixmaps; ++i) {
  301. yuv_pixmaps_->at(i) = &yuva_pixmaps[i];
  302. }
  303. DCHECK(IsYuv());
  304. size_t decoded_color_space_size =
  305. decoded_color_space ? decoded_color_space->writeToMemory(nullptr) : 0u;
  306. // x64 has 8-byte alignment for uint64_t even though x86 has 4-byte
  307. // alignment. Always use 8 byte alignment.
  308. const size_t align = sizeof(uint64_t);
  309. // Compute and cache the size of the data.
  310. base::CheckedNumeric<uint32_t> safe_size;
  311. safe_size += PaintOpWriter::HeaderBytes();
  312. safe_size += sizeof(uint32_t); // has mips
  313. safe_size += sizeof(uint64_t); // target color space stub (is nullptr)
  314. safe_size += TargetColorParamsSize(target_color_params_);
  315. safe_size += sizeof(uint32_t); // plane_config
  316. safe_size += sizeof(uint32_t); // subsampling
  317. safe_size += sizeof(uint32_t); // YUVA color matrix for YUVA image
  318. safe_size += decoded_color_space_size + align; // SkColorSpace for YUVA image
  319. for (size_t i = 0; i < num_yuva_pixmaps; ++i)
  320. safe_size += SafeSizeForPixmap(*yuv_pixmaps_->at(i));
  321. size_ = base::bits::AlignUp(size_t{safe_size.ValueOrDefault(0)},
  322. PaintOpWriter::Alignment());
  323. }
  324. ClientImageTransferCacheEntry::~ClientImageTransferCacheEntry() = default;
  325. // static
  326. base::AtomicSequenceNumber ClientImageTransferCacheEntry::s_next_id_;
  327. uint32_t ClientImageTransferCacheEntry::SerializedSize() const {
  328. return size_;
  329. }
  330. uint32_t ClientImageTransferCacheEntry::Id() const {
  331. return id_;
  332. }
  333. void ClientImageTransferCacheEntry::ValidateYUVDataBeforeSerializing() const {
  334. DCHECK(!pixmap_);
  335. DCHECK_NE(subsampling_, SkYUVAInfo::Subsampling::kUnknown);
  336. DCHECK_LE(yuv_pixmaps_->size(), static_cast<size_t>(SkYUVAInfo::kMaxPlanes));
  337. size_t num_planes = static_cast<size_t>(SkYUVAInfo::NumPlanes(plane_config_));
  338. DCHECK_LE(num_planes, yuv_pixmaps_->size());
  339. for (size_t i = 0; i < num_planes; ++i) {
  340. DCHECK(yuv_pixmaps_->at(i));
  341. const SkPixmap* plane = yuv_pixmaps_->at(i);
  342. DCHECK_GT(plane->width(), 0);
  343. DCHECK_GT(plane->height(), 0);
  344. DCHECK_GT(plane->rowBytes(), 0u);
  345. }
  346. }
  347. bool ClientImageTransferCacheEntry::Serialize(base::span<uint8_t> data) const {
  348. DCHECK_GE(data.size(), SerializedSize());
  349. // We don't need to populate the SerializeOptions here since the writer is
  350. // only used for serializing primitives.
  351. PaintOp::SerializeOptions options;
  352. PaintOpWriter writer(data.data(), data.size(), options);
  353. writer.Write(static_cast<uint32_t>(needs_mips_ ? 1 : 0));
  354. WriteTargetColorParams(writer, target_color_params_);
  355. writer.Write(plane_config_);
  356. if (plane_config_ != SkYUVAInfo::PlaneConfig::kUnknown) {
  357. ValidateYUVDataBeforeSerializing();
  358. writer.Write(subsampling_);
  359. int num_planes = SkYUVAInfo::NumPlanes(plane_config_);
  360. writer.Write(yuv_color_space_);
  361. writer.Write(decoded_color_space_);
  362. for (int i = 0; i < num_planes; ++i) {
  363. DCHECK(yuv_pixmaps_->at(i));
  364. if (!WritePixmap(writer, *yuv_pixmaps_->at(i)))
  365. return false;
  366. }
  367. } else {
  368. if (!WritePixmap(writer, *pixmap_))
  369. return false;
  370. }
  371. // Size can't be 0 after serialization unless the writer has become invalid.
  372. if (writer.size() == 0u)
  373. return false;
  374. return true;
  375. }
  376. ServiceImageTransferCacheEntry::ServiceImageTransferCacheEntry() = default;
  377. ServiceImageTransferCacheEntry::~ServiceImageTransferCacheEntry() = default;
  378. ServiceImageTransferCacheEntry::ServiceImageTransferCacheEntry(
  379. ServiceImageTransferCacheEntry&& other) = default;
  380. ServiceImageTransferCacheEntry& ServiceImageTransferCacheEntry::operator=(
  381. ServiceImageTransferCacheEntry&& other) = default;
  382. bool ServiceImageTransferCacheEntry::BuildFromHardwareDecodedImage(
  383. GrDirectContext* context,
  384. std::vector<sk_sp<SkImage>> plane_images,
  385. SkYUVAInfo::PlaneConfig plane_config,
  386. SkYUVAInfo::Subsampling subsampling,
  387. SkYUVColorSpace yuv_color_space,
  388. size_t buffer_byte_size,
  389. bool needs_mips) {
  390. context_ = context;
  391. size_ = buffer_byte_size;
  392. // 1) Generate mipmap chains if requested.
  393. if (needs_mips) {
  394. DCHECK(plane_sizes_.empty());
  395. base::CheckedNumeric<size_t> safe_total_size(0u);
  396. for (size_t plane = 0; plane < plane_images.size(); plane++) {
  397. plane_images[plane] = plane_images[plane]->makeTextureImage(
  398. context_, GrMipMapped::kYes, SkBudgeted::kNo);
  399. if (!plane_images[plane]) {
  400. DLOG(ERROR) << "Could not generate mipmap chain for plane " << plane;
  401. return false;
  402. }
  403. plane_sizes_.push_back(plane_images[plane]->textureSize());
  404. safe_total_size += plane_sizes_.back();
  405. }
  406. if (!safe_total_size.AssignIfValid(&size_)) {
  407. DLOG(ERROR) << "Could not calculate the total image size";
  408. return false;
  409. }
  410. }
  411. plane_images_ = std::move(plane_images);
  412. plane_config_ = plane_config;
  413. subsampling_ = subsampling;
  414. yuv_color_space_ = yuv_color_space;
  415. // 2) Create a SkImage backed by |plane_images|.
  416. // TODO(andrescj): support embedded color profiles for hardware decodes and
  417. // pass the color space to MakeYUVImageFromUploadedPlanes.
  418. image_ = MakeYUVImageFromUploadedPlanes(context_, plane_images_, plane_config,
  419. subsampling, yuv_color_space,
  420. SkColorSpace::MakeSRGB());
  421. if (!image_)
  422. return false;
  423. // 3) Fill out the rest of the information.
  424. has_mips_ = needs_mips;
  425. fits_on_gpu_ = true;
  426. return true;
  427. }
  428. size_t ServiceImageTransferCacheEntry::CachedSize() const {
  429. return size_;
  430. }
  431. bool ServiceImageTransferCacheEntry::Deserialize(
  432. GrDirectContext* context,
  433. base::span<const uint8_t> data) {
  434. context_ = context;
  435. const int32_t max_size = context_->maxTextureSize();
  436. // We don't need to populate the DeSerializeOptions here since the reader is
  437. // only used for de-serializing primitives.
  438. std::vector<uint8_t> scratch_buffer;
  439. PaintOp::DeserializeOptions options(nullptr, nullptr, nullptr,
  440. &scratch_buffer, false, nullptr);
  441. PaintOpReader reader(data.data(), data.size(), options);
  442. // Parameters common to RGBA and YUVA images.
  443. uint32_t needs_mips = 0;
  444. reader.Read(&needs_mips);
  445. has_mips_ = needs_mips;
  446. absl::optional<TargetColorParams> target_color_params;
  447. ReadTargetColorParams(reader, target_color_params);
  448. plane_config_ = SkYUVAInfo::PlaneConfig::kUnknown;
  449. reader.Read(&plane_config_);
  450. const GrMipMapped mip_mapped_for_upload =
  451. has_mips_ && !target_color_params ? GrMipMapped::kYes : GrMipMapped::kNo;
  452. SkPixmap rgba_pixmap;
  453. sk_sp<SkImage> rgba_pixmap_image;
  454. if (plane_config_ != SkYUVAInfo::PlaneConfig::kUnknown) {
  455. SkYUVAInfo::Subsampling subsampling = SkYUVAInfo::Subsampling::kUnknown;
  456. reader.Read(&subsampling);
  457. if (subsampling == SkYUVAInfo::Subsampling::kUnknown) {
  458. DLOG(ERROR) << "Invalid subsampling";
  459. return false;
  460. }
  461. subsampling_ = subsampling;
  462. SkYUVColorSpace yuv_color_space = kIdentity_SkYUVColorSpace;
  463. reader.Read(&yuv_color_space);
  464. yuv_color_space_ = yuv_color_space;
  465. sk_sp<SkColorSpace> decoded_color_space;
  466. reader.Read(&decoded_color_space);
  467. int num_planes = SkYUVAInfo::NumPlanes(plane_config_);
  468. // Read in each plane and reconstruct pixmaps.
  469. for (int i = 0; i < num_planes; i++) {
  470. SkPixmap pixmap;
  471. if (!ReadPixmap(reader, pixmap)) {
  472. DLOG(ERROR) << "Failed to read plane pixmap";
  473. return false;
  474. }
  475. pixmap.setColorSpace(decoded_color_space);
  476. // In the GpuImageDecodeCache, we should veto YUV decoding if the planes
  477. // would be too big. Check again here for the case a malicious renderer .
  478. fits_on_gpu_ = pixmap.width() <= max_size && pixmap.height() <= max_size;
  479. if (!fits_on_gpu_) {
  480. DLOG(ERROR) << "Plane pixmap too large";
  481. return false;
  482. }
  483. sk_sp<SkImage> plane = SkImage::MakeFromRaster(pixmap, nullptr, nullptr);
  484. if (!plane) {
  485. DLOG(ERROR) << "Failed to create image from plane pixmap";
  486. return false;
  487. }
  488. plane = plane->makeTextureImage(context_, mip_mapped_for_upload,
  489. SkBudgeted::kNo);
  490. if (!plane) {
  491. DLOG(ERROR) << "Failed to upload plane pixmap to texture image";
  492. return false;
  493. }
  494. DCHECK(plane->isTextureBacked());
  495. plane->getBackendTexture(/*flushPendingGrContextIO=*/true);
  496. plane_sizes_.push_back(plane->textureSize());
  497. plane_images_.push_back(std::move(plane));
  498. }
  499. DCHECK(yuv_color_space_.has_value());
  500. image_ = MakeYUVImageFromUploadedPlanes(
  501. context_, plane_images_, plane_config_, subsampling_.value(),
  502. yuv_color_space_.value(), decoded_color_space);
  503. } else {
  504. if (!ReadPixmap(reader, rgba_pixmap)) {
  505. DLOG(ERROR) << "Failed to read pixmap";
  506. return false;
  507. }
  508. rgba_pixmap_image = SkImage::MakeFromRaster(rgba_pixmap, nullptr, nullptr);
  509. if (!rgba_pixmap_image) {
  510. DLOG(ERROR) << "Failed to create image from plane pixmap";
  511. return false;
  512. }
  513. fits_on_gpu_ =
  514. rgba_pixmap.width() <= max_size && rgba_pixmap.height() <= max_size;
  515. if (fits_on_gpu_) {
  516. image_ = rgba_pixmap_image->makeTextureImage(
  517. context, mip_mapped_for_upload, SkBudgeted::kNo);
  518. if (!image_) {
  519. DLOG(ERROR) << "Failed to upload pixmap to texture image";
  520. return false;
  521. }
  522. } else {
  523. // If the image is on the CPU, no work is needed to generate mips.
  524. has_mips_ = true;
  525. image_ = rgba_pixmap_image;
  526. }
  527. }
  528. DCHECK(image_);
  529. // Perform color conversion.
  530. if (target_color_params) {
  531. // TODO(https://crbug.com/1286088): Pass a shared cache as a parameter.
  532. gfx::ColorConversionSkFilterCache cache;
  533. image_ = cache.ConvertImage(
  534. image_, target_color_params->color_space.ToSkColorSpace(),
  535. target_color_params->sdr_max_luminance_nits,
  536. target_color_params->hdr_max_luminance_relative,
  537. target_color_params->enable_tone_mapping,
  538. fits_on_gpu_ ? context_ : nullptr);
  539. if (!image_) {
  540. DLOG(ERROR) << "Failed image color conversion";
  541. return false;
  542. }
  543. // Color conversion converts to RGBA. Remove all YUV state.
  544. plane_images_.clear();
  545. plane_sizes_.clear();
  546. plane_config_ = SkYUVAInfo::PlaneConfig::kUnknown;
  547. plane_sizes_.clear();
  548. subsampling_ = absl::nullopt;
  549. yuv_color_space_ = absl::nullopt;
  550. // If mipmaps were requested, create them after color conversion.
  551. if (has_mips_ && fits_on_gpu_) {
  552. image_ =
  553. image_->makeTextureImage(context, GrMipMapped::kYes, SkBudgeted::kNo);
  554. if (!image_) {
  555. DLOG(ERROR) << "Failed to generate mipmaps after color conversion";
  556. return false;
  557. }
  558. }
  559. }
  560. // If `image_` is still pointing at the original data from `rgba_pixmap`, make
  561. // a copy of it, because `rgba_pixmap` is directly referencing the transfer
  562. // buffer's memory, and will go away after this this call.
  563. if (image_ == rgba_pixmap_image) {
  564. image_ = SkImage::MakeRasterCopy(rgba_pixmap);
  565. if (!image_) {
  566. DLOG(ERROR) << "Failed to create raster copy";
  567. return false;
  568. }
  569. }
  570. size_ = image_->textureSize();
  571. return true;
  572. }
  573. const sk_sp<SkImage>& ServiceImageTransferCacheEntry::GetPlaneImage(
  574. size_t index) const {
  575. DCHECK_GE(index, 0u);
  576. DCHECK_LT(index, plane_images_.size());
  577. DCHECK(plane_images_.at(index));
  578. return plane_images_.at(index);
  579. }
  580. void ServiceImageTransferCacheEntry::EnsureMips() {
  581. if (has_mips_)
  582. return;
  583. DCHECK(fits_on_gpu_);
  584. if (is_yuv()) {
  585. DCHECK(image_);
  586. DCHECK(yuv_color_space_.has_value());
  587. DCHECK_NE(SkYUVAInfo::PlaneConfig::kUnknown, plane_config_);
  588. DCHECK_EQ(static_cast<size_t>(SkYUVAInfo::NumPlanes(plane_config_)),
  589. plane_images_.size());
  590. // We first do all the work with local variables. Then, if everything
  591. // succeeds, we update the object's state. That way, we don't leave it in an
  592. // inconsistent state if one step of mip generation fails.
  593. std::vector<sk_sp<SkImage>> mipped_planes;
  594. std::vector<size_t> mipped_plane_sizes;
  595. for (size_t plane = 0; plane < plane_images_.size(); plane++) {
  596. DCHECK(plane_images_.at(plane));
  597. sk_sp<SkImage> mipped_plane = plane_images_.at(plane)->makeTextureImage(
  598. context_, GrMipMapped::kYes, SkBudgeted::kNo);
  599. if (!mipped_plane)
  600. return;
  601. mipped_planes.push_back(std::move(mipped_plane));
  602. mipped_plane_sizes.push_back(mipped_planes.back()->textureSize());
  603. }
  604. sk_sp<SkImage> mipped_image = MakeYUVImageFromUploadedPlanes(
  605. context_, mipped_planes, plane_config_, subsampling_.value(),
  606. yuv_color_space_.value(),
  607. image_->refColorSpace() /* image_color_space */);
  608. if (!mipped_image) {
  609. DLOG(ERROR) << "Failed to create YUV image from mipmapped planes";
  610. return;
  611. }
  612. // Note that we cannot update |size_| because the transfer cache keeps track
  613. // of a total size that is not updated after EnsureMips(). The original size
  614. // is used when the image is deleted from the cache.
  615. plane_images_ = std::move(mipped_planes);
  616. plane_sizes_ = std::move(mipped_plane_sizes);
  617. image_ = std::move(mipped_image);
  618. } else {
  619. sk_sp<SkImage> mipped_image =
  620. image_->makeTextureImage(context_, GrMipMapped::kYes, SkBudgeted::kNo);
  621. if (!mipped_image) {
  622. DLOG(ERROR) << "Failed to mipmapped image";
  623. return;
  624. }
  625. image_ = std::move(mipped_image);
  626. }
  627. has_mips_ = true;
  628. }
  629. } // namespace cc