4404 {
4406 std::stringstream desc_str;
4408 desc_str << "blend[" << mode_string << ", " << color << "]";
4409 std::string desc = desc_str.str();
4410 DlBlendColorFilter filter(color, mode);
4411 if (filter.modifies_transparent_black()) {
4412 ASSERT_NE(DlColorFilter::MakeBlend(color, mode), nullptr) << desc;
4413 }
4414
4417
4418 DisplayListBuilder builder1;
4420 builder1.Rotate(45);
4422 builder1.DrawRect(kRenderBounds, paint);
4423 auto display_list1 = builder1.Build();
4424
4425 DisplayListBuilder builder2;
4427 builder2.Rotate(45);
4429 builder2.SaveLayer(kTestBounds2, &filter_save_paint);
4430 builder2.DrawRect(kRenderBounds, paint);
4431 builder2.Restore();
4432 auto display_list2 = builder2.Build();
4433
4434 for (auto& back_end : CanvasCompareTester::TestBackends) {
4435 auto provider = CanvasCompareTester::GetProvider(back_end);
4436 auto env = std::make_unique<RenderEnvironment>(
4437 provider.get(), PixelFormat::kN32PremulPixelFormat);
4438 auto results1 = env->getResult(display_list1);
4439 auto results2 = env->getResult(display_list2);
4440 int modified_transparent_pixels =
4441 CanvasCompareTester::countModifiedTransparentPixels(results1.get(),
4442 results2.get());
4443 EXPECT_EQ(filter.modifies_transparent_black(),
4444 modified_transparent_pixels != 0)
4445 << desc;
4446 }
4447 };
4448
4450 test_mode_color(mode, DlColor::kTransparent());
4451 test_mode_color(mode, DlColor::kWhite());
4452 test_mode_color(mode, DlColor::kWhite().modulateOpacity(0.5));
4453 test_mode_color(mode, DlColor::kBlack());
4454 test_mode_color(mode, DlColor::kBlack().modulateOpacity(0.5));
4455 };
4456
4457#define TEST_MODE(V) test_mode(DlBlendMode::V);
4459#undef TEST_MODE
4460}
4461
4462TEST_F(DisplayListRendering, BlendColorFilterOpacityCommuteCheck) {
4464 std::stringstream desc_str;
4466 desc_str << "blend[" << mode_string << ", " << color << "]";
4467 std::string desc = desc_str.str();
4468 DlBlendColorFilter filter(color, mode);
4469 if (filter.can_commute_with_opacity()) {
4470
4471
4472 } else {
4473 ASSERT_NE(DlColorFilter::MakeBlend(color, mode), nullptr) << desc;
4474 }
4475
4479
4480 DisplayListBuilder builder1;
4481 builder1.SaveLayer(kTestBounds2, &opacity_save_paint);
4482 builder1.SaveLayer(kTestBounds2, &filter_save_paint);
4483
4484 builder1.DrawRect(kRenderBounds, paint);
4485 builder1.Restore();
4486 builder1.Restore();
4487 auto display_list1 = builder1.Build();
4488
4489 DisplayListBuilder builder2;
4490 builder2.SaveLayer(kTestBounds2, &filter_save_paint);
4491 builder2.SaveLayer(kTestBounds2, &opacity_save_paint);
4492
4493 builder2.DrawRect(kRenderBounds, paint);
4494 builder2.Restore();
4495 builder2.Restore();
4496 auto display_list2 = builder2.Build();
4497
4498 for (auto& back_end : CanvasCompareTester::TestBackends) {
4499 auto provider = CanvasCompareTester::GetProvider(back_end);
4500 auto env = std::make_unique<RenderEnvironment>(
4501 provider.get(), PixelFormat::kN32PremulPixelFormat);
4502 auto results1 = env->getResult(display_list1);
4503 auto results2 = env->getResult(display_list2);
4504 if (filter.can_commute_with_opacity()) {
4505 CanvasCompareTester::compareToReference(
4506 results2.get(), results1.get(), desc, nullptr, nullptr,
4507 DlColor::kTransparent(), true, kTestWidth, kTestHeight, true);
4508 } else {
4509 CanvasCompareTester::quickCompareToReference(
4510 results1.get(), results2.get(), false, desc);
4511 }
4512 }
4513 };
4514
4516 test_mode_color(mode, DlColor::kTransparent());
4517 test_mode_color(mode, DlColor::kWhite());
4518 test_mode_color(mode, DlColor::kWhite().modulateOpacity(0.5));
4519 test_mode_color(mode, DlColor::kBlack());
4520 test_mode_color(mode, DlColor::kBlack().modulateOpacity(0.5));
4521 };
4522
4523#define TEST_MODE(V) test_mode(DlBlendMode::V);
4525#undef TEST_MODE
4526}
4527
4529
4530
4531 protected:
4533 test_src_colors = {
4534 DlColor::kBlack().withAlpha(0),
4535 DlColor::kBlack().withAlpha(0x7f),
4536 DlColor::kWhite().withAlpha(0x7f),
4537 DlColor::kBlack(),
4538 DlColor::kWhite(),
4539 DlColor::kRed(),
4540 DlColor::kGreen(),
4541 DlColor::kBlue(),
4542 DlColor::kDarkGrey(),
4543 DlColor::kLightGrey(),
4544 };
4545
4546
4547
4548 test_dst_colors.push_back(DlColor::kTransparent());
4549 const int step = 0x55;
4550 static_assert(step * 3 == 255);
4551 for (int a = step; a < 256; a += step) {
4552 for (int r = step; r < 256; r += step) {
4553 for (int g = step; g < 256; g += step) {
4554 for (
int b = step;
b < 256;
b += step) {
4555 test_dst_colors.push_back(
DlColor(a << 24 | r << 16 | g << 8 | b));
4556 }
4557 }
4558 }
4559 }
4560
4561 static constexpr float color_filter_matrix_nomtb[] = {
4562 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
4563 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
4564 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
4565 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
4566 };
4567 static constexpr float color_filter_matrix_mtb[] = {
4568 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
4569 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
4570 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
4571 0.0001, 0.0001, 0.0001, 0.9997, 0.1,
4572 };
4573 color_filter_nomtb = DlColorFilter::MakeMatrix(color_filter_matrix_nomtb);
4574 color_filter_mtb = DlColorFilter::MakeMatrix(color_filter_matrix_mtb);
4575 EXPECT_FALSE(color_filter_nomtb->modifies_transparent_black());
4576 EXPECT_TRUE(color_filter_mtb->modifies_transparent_black());
4577
4578 test_data =
4579 get_output(test_dst_colors.size(), 1, true, [this](SkCanvas* canvas) {
4580 int x = 0;
4581 for (DlColor color : test_dst_colors) {
4582 SkPaint paint;
4583 paint.setColor(ToSkColor4f(color));
4584 paint.setBlendMode(SkBlendMode::kSrc);
4585 canvas->drawRect(SkRect::MakeXYWH(x, 0, 1, 1), paint);
4586 x++;
4587 }
4588 });
4589
4590
4591
4592
4593
4594 int data_count = test_data->image()->width();
4595 test_image_dst_data = get_output(
4596 data_count, data_count, true, [this, data_count](SkCanvas* canvas) {
4597 ASSERT_EQ(test_data->width(), data_count);
4598 ASSERT_EQ(test_data->height(), 1);
4599 for (
int y = 0;
y < data_count;
y++) {
4600 canvas->drawImage(test_data->image().get(), 0,
y);
4601 }
4602 });
4603 test_image_src_data = get_output(
4604 data_count, data_count, true, [this, data_count](SkCanvas* canvas) {
4605 ASSERT_EQ(test_data->width(), data_count);
4606 ASSERT_EQ(test_data->height(), 1);
4607 canvas->translate(data_count, 0);
4608 canvas->rotate(90);
4609 for (
int y = 0;
y < data_count;
y++) {
4610 canvas->drawImage(test_data->image().get(), 0,
y);
4611 }
4612 });
4613
4614 for (
int y = 0;
y < data_count;
y++) {
4615 for (
int x = 0;
x < data_count;
x++) {
4616 EXPECT_EQ(*test_image_dst_data->addr32(
x,
y), *test_data->addr32(
x, 0));
4617 EXPECT_EQ(*test_image_src_data->addr32(
x,
y), *test_data->addr32(
y, 0));
4618 }
4619 }
4620 }
4621
4622
4623
4624 static constexpr int kWasNotNop = 0x1;
4625 static constexpr int kWasMTB = 0x2;
4626
4627 std::vector<DlColor> test_src_colors;
4628 std::vector<DlColor> test_dst_colors;
4629
4630 std::shared_ptr<const DlColorFilter> color_filter_nomtb;
4631 std::shared_ptr<const DlColorFilter> color_filter_mtb;
4632
4633
4634 std::unique_ptr<RenderResult> test_data;
4635
4636
4637 std::unique_ptr<RenderResult> test_image_dst_data;
4638
4639
4640 std::unique_ptr<RenderResult> test_image_src_data;
4641
4642 std::unique_ptr<RenderResult> get_output(
4643 int w,
4644 int h,
4645 bool snapshot,
4646 const std::function<void(SkCanvas*)>& renderer) {
4647 auto surface = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(w, h));
4648 SkCanvas* canvas =
surface->getCanvas();
4649 renderer(canvas);
4650 return std::make_unique<SkRenderResult>(surface, snapshot);
4651 }
4652
4653 int check_color_result(DlColor dst_color,
4654 DlColor result_color,
4655 const sk_sp<DisplayList>& dl,
4656 const std::string& desc) {
4657 int ret = 0;
4658 bool is_error = false;
4659 if (dst_color.isTransparent() && !result_color.isTransparent()) {
4660 ret |= kWasMTB;
4661 is_error = !dl->modifies_transparent_black();
4662 }
4663 if (result_color != dst_color) {
4664 ret |= kWasNotNop;
4665 is_error = (dl->op_count() == 0u);
4666 }
4667 if (is_error) {
4668 FML_LOG(ERROR) << std::hex << dst_color <<
" filters to " << result_color
4669 << desc;
4670 }
4671 return ret;
4672 }
4673
4674 int check_image_result(const std::unique_ptr<RenderResult>& dst_data,
4675 const std::unique_ptr<RenderResult>& result_data,
4676 const sk_sp<DisplayList>& dl,
4677 const std::string& desc) {
4678 EXPECT_EQ(dst_data->width(), result_data->width());
4679 EXPECT_EQ(dst_data->height(), result_data->height());
4680 int all_flags = 0;
4681 for (
int y = 0;
y < dst_data->height();
y++) {
4682 const uint32_t* dst_pixels = dst_data->addr32(0,
y);
4683 const uint32_t* result_pixels = result_data->addr32(0,
y);
4684 for (
int x = 0;
x < dst_data->width();
x++) {
4685 all_flags |= check_color_result(
DlColor(dst_pixels[
x]),
4686 DlColor(result_pixels[
x]), dl, desc);
4687 }
4688 }
4689 return all_flags;
4690 }
4691
4692 void report_results(int all_flags,
4693 const sk_sp<DisplayList>& dl,
4694 const std::string& desc) {
4695 if (!dl->modifies_transparent_black()) {
4696 EXPECT_TRUE((all_flags & kWasMTB) == 0);
4697 } else if ((all_flags & kWasMTB) == 0) {
4698 FML_LOG(INFO) <<
"combination does not affect transparency: " << desc;
4699 }
4700 if (dl->op_count() == 0u) {
4701 EXPECT_TRUE((all_flags & kWasNotNop) == 0);
4702 } else if ((all_flags & kWasNotNop) == 0) {
4703 FML_LOG(INFO) <<
"combination could be classified as a nop: " << desc;
4704 }
4705 };
4706
4707 void test_mode_color_via_filter(DlBlendMode mode, DlColor color) {
4708 std::stringstream desc_stream;
4709 desc_stream << " using SkColorFilter::filterColor() with: ";
4711 desc_stream << "/" << color;
4712 std::string desc = desc_stream.str();
4713 DisplayListBuilder builder(DlRect::MakeWH(100.0f, 100.0f));
4715 builder.DrawRect(DlRect::MakeLTRB(0.0f, 0.0f, 10.0f, 10.0f), paint);
4716 auto dl = builder.Build();
4717 if (dl->modifies_transparent_black()) {
4718 ASSERT_TRUE(dl->op_count() != 0u);
4719 }
4720
4721 auto sk_mode =
static_cast<SkBlendMode
>(
mode);
4722 auto sk_color_filter =
4723 SkColorFilters::Blend(
ToSkColor4f(color),
nullptr, sk_mode);
4724 auto srgb = SkColorSpace::MakeSRGB();
4725 int all_flags = 0;
4726 if (sk_color_filter) {
4727 for (DlColor dst_color : test_dst_colors) {
4730 sk_color_filter->filterColor4f(dst_color_f, srgb.get(), srgb.get())
4731 .toSkColor());
4732 all_flags |= check_color_result(dst_color, result, dl, desc);
4733 }
4734 if ((all_flags & kWasMTB) != 0) {
4735 EXPECT_FALSE(sk_color_filter->isAlphaUnchanged());
4736 }
4737 }
4738 report_results(all_flags, dl, desc);
4739 };
4740
4741 void test_mode_color_via_rendering(DlBlendMode mode, DlColor color) {
4742 std::stringstream desc_stream;
4743 desc_stream << " rendering with: ";
4745 desc_stream << "/" << color;
4746 std::string desc = desc_stream.str();
4747 auto test_image = test_data->image();
4749 DlRect::MakeWH(test_image->width(), test_image->height());
4750 DisplayListBuilder builder(test_bounds);
4752 builder.DrawRect(test_bounds, dl_paint);
4753 auto dl = builder.Build();
4754 bool dl_is_elided = dl->op_count() == 0u;
4755 bool dl_affects_transparent_pixels = dl->modifies_transparent_black();
4756 ASSERT_TRUE(!dl_is_elided || !dl_affects_transparent_pixels);
4757
4758 auto sk_mode =
static_cast<SkBlendMode
>(
mode);
4759 SkPaint sk_paint;
4760 sk_paint.setBlendMode(sk_mode);
4762 for (auto& back_end : CanvasCompareTester::TestBackends) {
4763 auto provider = CanvasCompareTester::GetProvider(back_end);
4764 auto result_surface = provider->MakeOffscreenSurface(
4765 test_image->width(), test_image->height(),
4766 DlSurfaceProvider::kN32PremulPixelFormat);
4767 SkCanvas* result_canvas = result_surface->sk_surface()->getCanvas();
4768 result_canvas->clear(SK_ColorTRANSPARENT);
4769 result_canvas->drawImage(test_image.get(), 0, 0);
4770 result_canvas->drawRect(
ToSkRect(test_bounds), sk_paint);
4771 if (GrDirectContext* direct_context = GrAsDirectContext(
4772 result_surface->sk_surface()->recordingContext())) {
4773 direct_context->flushAndSubmit();
4774 direct_context->flushAndSubmit(result_surface->sk_surface().get(),
4775 GrSyncCpu::kYes);
4776 }
4777 const std::unique_ptr<RenderResult> result_pixels =
4778 std::make_unique<SkRenderResult>(result_surface->sk_surface());
4779
4780 int all_flags = check_image_result(test_data, result_pixels, dl, desc);
4781 report_results(all_flags, dl, desc);
4782 }
4783 };
4784
4785 void test_attributes_image(DlBlendMode mode,
4786 DlColor color,
4787 const DlColorFilter* color_filter,
4788 DlImageFilter* image_filter) {
4789
4790 std::stringstream desc_stream;
4791 desc_stream << " rendering with: ";
4793 desc_stream << "/" << color;
4794 std::string cf_mtb = color_filter
4795 ? color_filter->modifies_transparent_black()
4796 ? "modifies transparency"
4797 : "preserves transparency"
4798 : "no filter";
4799 desc_stream << ", CF: " << cf_mtb;
4800 std::string if_mtb = image_filter
4801 ? image_filter->modifies_transparent_black()
4802 ? "modifies transparency"
4803 : "preserves transparency"
4804 : "no filter";
4805 desc_stream << ", IF: " << if_mtb;
4806 std::string desc = desc_stream.str();
4807
4808 DisplayListBuilder builder(DlRect::MakeWH(100.0f, 100.0f));
4813 builder.DrawImage(DlImage::Make(test_image_src_data->image()),
4814 DlPoint(0, 0), DlImageSampling::kNearestNeighbor, &paint);
4815 auto dl = builder.Build();
4816
4817 int w = test_image_src_data->width();
4818 int h = test_image_src_data->height();
4819 auto sk_mode =
static_cast<SkBlendMode
>(
mode);
4820 SkPaint sk_paint;
4821 sk_paint.setBlendMode(sk_mode);
4823 sk_paint.setColorFilter(
ToSk(color_filter));
4824 sk_paint.setImageFilter(
ToSk(image_filter));
4825 for (auto& back_end : CanvasCompareTester::TestBackends) {
4826 auto provider = CanvasCompareTester::GetProvider(back_end);
4827 auto result_surface = provider->MakeOffscreenSurface(
4828 w, h, DlSurfaceProvider::kN32PremulPixelFormat);
4829 SkCanvas* result_canvas = result_surface->sk_surface()->getCanvas();
4830 result_canvas->clear(SK_ColorTRANSPARENT);
4831 result_canvas->drawImage(test_image_dst_data->image(), 0, 0);
4832 result_canvas->drawImage(test_image_src_data->image(), 0, 0,
4833 SkSamplingOptions(), &sk_paint);
4834 if (GrDirectContext* direct_context = GrAsDirectContext(
4835 result_surface->sk_surface()->recordingContext())) {
4836 direct_context->flushAndSubmit();
4837 direct_context->flushAndSubmit(result_surface->sk_surface().get(),
4838 GrSyncCpu::kYes);
4839 }
4840 std::unique_ptr<RenderResult> result_pixels =
4841 std::make_unique<SkRenderResult>(result_surface->sk_surface());
4842
4843 int all_flags =
4844 check_image_result(test_image_dst_data, result_pixels, dl, desc);
4845 report_results(all_flags, dl, desc);
4846 }
4847 };
4848};
4849
4850TEST_F(DisplayListNopTest, BlendModeAndColorViaColorFilter) {
4852 for (DlColor color : test_src_colors) {
4853 test_mode_color_via_filter(mode, color);
4854 }
4855 };
4856
4857#define TEST_MODE(V) test_mode_filter(DlBlendMode::V);
4859#undef TEST_MODE
4860}
4861
4862TEST_F(DisplayListNopTest, BlendModeAndColorByRendering) {
4864
4865 for (DlColor color : test_src_colors) {
4866 test_mode_color_via_rendering(mode, color);
4867 }
4868 };
4869
4870#define TEST_MODE(V) test_mode_render(DlBlendMode::V);
4872#undef TEST_MODE
4873}
4874
4875TEST_F(DisplayListNopTest, BlendModeAndColorAndFiltersByRendering) {
4877 auto image_filter_nomtb = DlColorFilterImageFilter(color_filter_nomtb);
4878 auto image_filter_mtb = DlColorFilterImageFilter(color_filter_mtb);
4879 for (DlColor color : test_src_colors) {
4880 test_attributes_image(mode, color, nullptr, nullptr);
4881 test_attributes_image(mode, color, color_filter_nomtb.get(), nullptr);
4882 test_attributes_image(mode, color, color_filter_mtb.get(), nullptr);
4883 test_attributes_image(mode, color, nullptr, &image_filter_nomtb);
4884 test_attributes_image(mode, color, nullptr, &image_filter_mtb);
4885 }
4886 };
4887
4888#define TEST_MODE(V) test_mode_render(DlBlendMode::V);
4890#undef TEST_MODE
4891}
4892
4893#undef FOR_EACH_BLEND_MODE_ENUM
4894
4895}
4896}
TEST_F(FlutterDisplayLinkTest, ViewAddedToWindowFirst)
DlPaint & setBlendMode(DlBlendMode mode)
DlPaint & setImageFilter(std::nullptr_t filter)
DlPaint & setOpacity(DlScalar opacity)
DlPaint & setColorFilter(std::nullptr_t filter)
#define FOR_EACH_BLEND_MODE_ENUM(FUNC)
#define FML_LOG(severity)
DisplayListRenderingTestBase<::testing::Test > DisplayListRendering
const DlPoint kTestCenter2
SkPaint ToSk(const DlPaint &paint)
SkColor4f ToSkColor4f(DlColor color)
it will be possible to load the file into Perfetto s trace viewer use test Running tests that layout and measure text will not yield consistent results across various platforms Enabling this option will make font resolution default to the Ahem test font on all disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive mode
impeller::BlendMode DlBlendMode
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder h
const SkRect & ToSkRect(const DlRect &rect)
const char * BlendModeToString(BlendMode blend_mode)