chromium/cc/paint/oop_pixeltest.cc

// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif

#include <cmath>
#include <memory>
#include <tuple>
#include <vector>

#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/functional/bind.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/raw_ptr_exclusion.h"
#include "base/path_service.h"
#include "base/test/test_switches.h"
#include "build/build_config.h"
#include "cc/base/completion_event.h"
#include "cc/paint/display_item_list.h"
#include "cc/paint/paint_filter.h"
#include "cc/paint/paint_flags.h"
#include "cc/paint/paint_image_builder.h"
#include "cc/raster/playback_image_provider.h"
#include "cc/test/fake_paint_image_generator.h"
#include "cc/test/pixel_comparator.h"
#include "cc/test/pixel_test_utils.h"
#include "cc/tiles/gpu_image_decode_cache.h"
#include "components/viz/common/resources/shared_image_format.h"
#include "components/viz/service/gl/gpu_service_impl.h"
#include "components/viz/test/buildflags.h"
#include "components/viz/test/paths.h"
#include "components/viz/test/test_gpu_service_holder.h"
#include "components/viz/test/test_in_process_context_provider.h"
#include "gpu/command_buffer/client/client_shared_image.h"
#include "gpu/command_buffer/client/raster_implementation.h"
#include "gpu/command_buffer/client/shared_image_interface.h"
#include "gpu/command_buffer/common/shared_image_usage.h"
#include "gpu/command_buffer/service/gr_shader_cache.h"
#include "gpu/command_buffer/service/graphite_utils.h"
#include "gpu/config/gpu_finch_features.h"
#include "ipc/common/gpu_client_ids.h"
#include "skia/ext/font_utils.h"
#include "skia/ext/legacy_display_globals.h"
#include "skia/ext/skcolorspace_trfn.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkAlphaType.h"
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkColorSpace.h"
#include "third_party/skia/include/core/SkColorType.h"
#include "third_party/skia/include/core/SkGraphics.h"
#include "third_party/skia/include/core/SkImage.h"
#include "third_party/skia/include/core/SkPictureRecorder.h"
#include "third_party/skia/include/core/SkRect.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/skia/include/core/SkTextBlob.h"
#include "third_party/skia/include/core/SkYUVAInfo.h"
#include "third_party/skia/include/gpu/GpuTypes.h"
#include "third_party/skia/include/gpu/GrDirectContext.h"
#include "third_party/skia/include/gpu/GrTypes.h"
#include "third_party/skia/include/gpu/ganesh/SkSurfaceGanesh.h"
#include "third_party/skia/include/gpu/graphite/Context.h"
#include "third_party/skia/include/gpu/graphite/GraphiteTypes.h"
#include "third_party/skia/include/gpu/graphite/Surface.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/geometry/skia_conversions.h"
#include "ui/gl/gl_implementation.h"

#if BUILDFLAG(IS_ANDROID)
#include "base/android/build_info.h"
#endif

namespace cc {
namespace {
scoped_refptr<DisplayItemList> MakeNoopDisplayItemList() {}

// Creates a bitmap of |size| filled with pixels of |color|.
SkBitmap MakeSolidColorBitmap(gfx::Size size, SkColor4f color) {}

// Creates a SkImage filled with magenta and a 30x40 green rectangle.
sk_sp<SkImage> MakeSkImage(const gfx::Size& size,
                           sk_sp<SkColorSpace> color_space = nullptr) {}

constexpr size_t kCacheLimitBytes =;
constexpr PaintFlags::FilterQuality kDefaultFilterQuality =;

class OopPixelTest : public testing::Test,
                     public gpu::raster::GrShaderCache::Client {};

class OopClearPixelTest : public OopPixelTest,
                          public ::testing::WithParamInterface<bool> {};

TEST_F(OopPixelTest, DrawColor) {}

TEST_F(OopPixelTest, DrawColorWithTargetColorSpace) {}

TEST_F(OopPixelTest, DrawRect) {}

TEST_F(OopPixelTest, DrawRecordPaintFilterTranslatedBounds) {}

TEST_F(OopPixelTest, DrawImage) {}

TEST_F(OopPixelTest, DrawImageScaled) {}

TEST_F(OopPixelTest, DrawImageShaderScaled) {}

TEST_F(OopPixelTest, DrawRecordShaderWithImageScaled) {}

TEST_F(OopPixelTest, DrawRecordShaderTranslatedTileRect) {}

TEST_F(OopPixelTest, DrawImageWithTargetColorSpace) {}

TEST_F(OopPixelTest, DrawGainmapImage) {}

TEST_F(OopPixelTest, DrawGainmapImageFiltering) {}

TEST_F(OopPixelTest, DrawHdrImageWithMetadata) {}

TEST_F(OopPixelTest, DrawImageWithSourceColorSpace) {}

TEST_F(OopPixelTest, DrawImageWithSourceAndTargetColorSpace) {}

TEST_F(OopPixelTest, DrawImageWithSetMatrix) {}

namespace {
class TestMailboxBacking : public TextureBacking {};
}  // namespace

TEST_F(OopPixelTest, DrawMailboxBackedImage) {}

TEST_F(OopPixelTest, Preclear) {}

TEST_P(OopClearPixelTest, ClearingOpaqueCorner) {}

TEST_F(OopPixelTest, ClearingOpaqueCornerExactEdge) {}

TEST_F(OopPixelTest, ClearingOpaqueCornerPartialRaster) {}

TEST_P(OopClearPixelTest, ClearingOpaqueLeftEdge) {}

TEST_P(OopClearPixelTest, ClearingOpaqueRightEdge) {}

TEST_P(OopClearPixelTest, ClearingOpaqueTopEdge) {}

TEST_P(OopClearPixelTest, ClearingOpaqueBottomEdge) {}

TEST_F(OopPixelTest, ClearingOpaqueInternal) {}

TEST_F(OopPixelTest, ClearingTransparentCorner) {}

TEST_F(OopPixelTest, ClearingTransparentInternalTile) {}

TEST_F(OopPixelTest, ClearingTransparentCornerPartialRaster) {}

// Test bitmap and playback rects in the raster options.
TEST_F(OopPixelTest, DrawRectPlaybackRect) {}

TEST_F(OopPixelTest, DrawRectScaleTransformOptions) {}

TEST_F(OopPixelTest, DrawRectTransformOptionsFullRaster) {}

TEST_F(OopPixelTest, DrawRectQueryMiddleOfDisplayList) {}

TEST_F(OopPixelTest, DrawRectColorSpace) {}

sk_sp<SkTextBlob> BuildTextBlob(
    sk_sp<SkTypeface> typeface = skia::DefaultTypeface(),
    bool use_lcd_text = false) {}

// A reasonable Y offset given the font parameters of BuildTextBlob() that
// ensures the text is not just drawn above the top edge of the surface.
static constexpr SkScalar kTextBlobY =;

// OopTextBlobPixelTest's test suite runs through the cross product of these
// strategies.
enum class TextBlobStrategy {};
enum class FilterStrategy {};
enum class MatrixStrategy {};
enum class LCDStrategy {};

TextBlobTestConfig;

class OopTextBlobPixelTest
    : public OopPixelTest,
      public ::testing::WithParamInterface<TextBlobTestConfig> {};

TEST_P(OopTextBlobPixelTest, Config) {}

INSTANTIATE_TEST_SUITE_P();

void ClearFontCache(CompletionEvent* event) {}

TEST_F(OopPixelTest, DrawTextMultipleRasterCHROMIUM) {}

TEST_F(OopPixelTest, DrawTextBlobPersistentShaderCache) {}

TEST_F(OopPixelTest, WritePixels) {}

TEST_F(OopPixelTest, CopySharedImage) {}

// The Android emulator does not support RED_8 or RG_88 texture formats.
#if !BUILDFLAG(IS_ANDROID_EMULATOR)
using OopYUVToRGBConfig = ::testing::tuple<gfx::ColorSpace, bool>;

class OopYUVToRGBPixelTest
    : public OopPixelTest,
      public ::testing::WithParamInterface<OopYUVToRGBConfig> {
 public:
  bool TestColorSpaceConversion() const {
    return ::testing::get<1>(GetParam());
  }

  gfx::ColorSpace DestinationColorSpace() const {
    return ::testing::get<0>(GetParam());
  }
};

TEST_P(OopYUVToRGBPixelTest, ConvertYUVToRGB) {
  // The source color space for the YUV image. If color space conversion is
  // disabled, or if `dest_color_space` is invalid, then this will be ignored.
  const gfx::ColorSpace source_color_space(gfx::ColorSpace::PrimaryID::P3,
                                           gfx::ColorSpace::TransferID::SRGB);

  // The output SharedImage color space.
  const gfx::ColorSpace dest_color_space = DestinationColorSpace();

  RasterOptions options(gfx::Size(16, 16));
  RasterOptions uv_options(gfx::Size(options.resource_size.width() / 2,
                                     options.resource_size.height() / 2));
  auto* ri = raster_context_provider_->RasterInterface();
  auto* sii = raster_context_provider_->SharedImageInterface();

  auto dest_client_si = CreateClientSharedImage(
      ri, sii, options, viz::SinglePlaneFormat::kRGBA_8888, dest_color_space);

  constexpr viz::SharedImageFormat format = viz::SinglePlaneFormat::kR_8;
  scoped_refptr<gpu::ClientSharedImage> yuv_client_si[3]{
      CreateClientSharedImage(ri, sii, options, format),
      CreateClientSharedImage(ri, sii, uv_options, format),
      CreateClientSharedImage(ri, sii, uv_options, format)};

  gpu::Mailbox yuv_mailboxes[3]{
      yuv_client_si[0]->mailbox(),
      yuv_client_si[1]->mailbox(),
      yuv_client_si[2]->mailbox(),
  };

  SkImageInfo y_info = SkImageInfo::Make(
      options.resource_size.width(), options.resource_size.height(),
      kGray_8_SkColorType, kPremul_SkAlphaType,
      options.target_color_params.color_space.ToSkColorSpace());

  SkImageInfo uv_info = SkImageInfo::Make(
      uv_options.resource_size.width(), uv_options.resource_size.height(),
      kGray_8_SkColorType, kPremul_SkAlphaType,
      uv_options.target_color_params.color_space.ToSkColorSpace());

  // Create Y+U+V image planes for a solid blue image.
  SkBitmap y_bitmap;
  y_bitmap.allocPixels(y_info);
  memset(y_bitmap.getPixels(), 0x1d, y_bitmap.computeByteSize());

  SkBitmap u_bitmap;
  u_bitmap.allocPixels(uv_info);
  memset(u_bitmap.getPixels(), 0xff, u_bitmap.computeByteSize());

  SkBitmap v_bitmap;
  v_bitmap.allocPixels(uv_info);
  memset(v_bitmap.getPixels(), 0x6b, v_bitmap.computeByteSize());

  // Upload initial Y+U+V planes and convert to RGB.
  UploadPixels(ri, yuv_client_si[0]->mailbox(), y_info, y_bitmap);
  UploadPixels(ri, yuv_client_si[1]->mailbox(), uv_info, u_bitmap);
  UploadPixels(ri, yuv_client_si[2]->mailbox(), uv_info, v_bitmap);

  ri->ConvertYUVAMailboxesToRGB(
      dest_client_si->mailbox(), 0, 0, options.resource_size.width(),
      options.resource_size.height(), kJPEG_SkYUVColorSpace,
      TestColorSpaceConversion() ? source_color_space.ToSkColorSpace().get()
                                 : nullptr,
      SkYUVAInfo::PlaneConfig::kY_U_V, SkYUVAInfo::Subsampling::k420,
      yuv_mailboxes);
  SkBitmap actual_bitmap =
      ReadbackMailbox(ri, dest_client_si->mailbox(), options.resource_size,
                      dest_color_space.ToSkColorSpace());

  SkColor expected_color =
      (TestColorSpaceConversion() && dest_color_space.IsValid())
          ? SkColorSetARGB(255, 61, 29, 252)
          : SkColorSetARGB(255, 0, 0, 254);
  SkBitmap expected_bitmap = MakeSolidColorBitmap(
      options.resource_size, SkColor4f::FromColor(expected_color));

  // Allow slight rounding error on all pixels.
  auto comparator = FuzzyPixelComparator()
                        .SetErrorPixelsPercentageLimit(100.0f)
                        .SetAbsErrorLimit(2);
  ExpectEquals(actual_bitmap, expected_bitmap, comparator);

  gpu::SyncToken sync_token;
  sii->DestroySharedImage(sync_token, std::move(dest_client_si));
  sii->DestroySharedImage(sync_token, std::move(yuv_client_si[0]));
  sii->DestroySharedImage(sync_token, std::move(yuv_client_si[1]));
  sii->DestroySharedImage(sync_token, std::move(yuv_client_si[2]));
}

INSTANTIATE_TEST_SUITE_P(
    P,
    OopYUVToRGBPixelTest,
    ::testing::Combine(
        ::testing::Values(gfx::ColorSpace(gfx::ColorSpace::PrimaryID::BT2020,
                                          gfx::ColorSpace::TransferID::SRGB),
                          gfx::ColorSpace()),
        ::testing::Bool()));

TEST_F(OopPixelTest, ConvertNV12ToRGB) {
  RasterOptions options(gfx::Size(16, 16));
  RasterOptions uv_options(gfx::Size(options.resource_size.width() / 2,
                                     options.resource_size.height() / 2));
  auto* ri = raster_context_provider_->RasterInterface();
  auto* sii = raster_context_provider_->SharedImageInterface();

  scoped_refptr<gpu::ClientSharedImage> dest_client_si =
      CreateClientSharedImage(ri, sii, options,
                              viz::SinglePlaneFormat::kRGBA_8888);
  scoped_refptr<gpu::ClientSharedImage> y_uv_client_si[2]{
      CreateClientSharedImage(ri, sii, options, viz::SinglePlaneFormat::kR_8),
      CreateClientSharedImage(ri, sii, uv_options,
                              viz::SinglePlaneFormat::kRG_88),
  };

  gpu::Mailbox y_uv_mailboxes[2]{
      y_uv_client_si[0]->mailbox(),
      y_uv_client_si[1]->mailbox(),
  };

  SkImageInfo y_info = SkImageInfo::Make(
      options.resource_size.width(), options.resource_size.height(),
      kGray_8_SkColorType, kPremul_SkAlphaType,
      options.target_color_params.color_space.ToSkColorSpace());

  SkImageInfo uv_info = SkImageInfo::Make(
      uv_options.resource_size.width(), uv_options.resource_size.height(),
      kR8G8_unorm_SkColorType, kPremul_SkAlphaType,
      uv_options.target_color_params.color_space.ToSkColorSpace());

  // Create Y+UV image planes for a solid blue image.
  SkBitmap y_bitmap;
  y_bitmap.allocPixels(y_info);
  memset(y_bitmap.getPixels(), 0x1d, y_bitmap.computeByteSize());

  SkBitmap uv_bitmap;
  uv_bitmap.allocPixels(uv_info);
  uint8_t* uv_pix = static_cast<uint8_t*>(uv_bitmap.getPixels());
  for (size_t i = 0; i < uv_bitmap.computeByteSize(); i += 2) {
    uv_pix[i] = 0xff;
    uv_pix[i + 1] = 0x6d;
  }

  // Upload initial Y+UV planes and convert to RGB.
  UploadPixels(ri, y_uv_client_si[0]->mailbox(), y_info, y_bitmap);
  UploadPixels(ri, y_uv_client_si[1]->mailbox(), uv_info, uv_bitmap);

  ri->ConvertYUVAMailboxesToRGB(
      dest_client_si->mailbox(), 0, 0, options.resource_size.width(),
      options.resource_size.height(), kJPEG_SkYUVColorSpace,
      SkColorSpace::MakeSRGB().get(), SkYUVAInfo::PlaneConfig::kY_UV,
      SkYUVAInfo::Subsampling::k420, y_uv_mailboxes);
  SkBitmap actual_bitmap =
      ReadbackMailbox(ri, dest_client_si->mailbox(), options.resource_size);

  SkBitmap expected_bitmap = MakeSolidColorBitmap(
      options.resource_size,
      SkColor4f::FromColor(SkColorSetARGB(255, 2, 0, 254)));

  ExpectEquals(actual_bitmap, expected_bitmap);

  gpu::SyncToken sync_token;
  sii->DestroySharedImage(sync_token, std::move(dest_client_si));
  sii->DestroySharedImage(sync_token, std::move(y_uv_client_si[0]));
  sii->DestroySharedImage(sync_token, std::move(y_uv_client_si[1]));
}
#endif  // !BUILDFLAG(IS_ANDROID_EMULATOR)

class OopPathPixelTest : public OopPixelTest,
                         public ::testing::WithParamInterface<bool> {};

TEST_P(OopPathPixelTest, Basic) {}

TEST_F(OopPixelTest, RecordShaderExceedsMaxTextureSize) {}

INSTANTIATE_TEST_SUITE_P();
INSTANTIATE_TEST_SUITE_P();

}  // namespace
}  // namespace cc