blob: 8d0b2b9a2c7407fa4a6060376c394cf65a5be4f7 [file] [log] [blame]
// Copyright 2018 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 "third_party/blink/renderer/platform/graphics/canvas_resource_provider.h"
#include "components/viz/common/resources/single_release_callback.h"
#include "components/viz/test/test_context_provider.h"
#include "components/viz/test/test_gles2_interface.h"
#include "components/viz/test/test_gpu_memory_buffer_manager.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.h"
#include "third_party/blink/renderer/platform/graphics/canvas_resource_params.h"
#include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h"
#include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h"
#include "third_party/blink/renderer/platform/graphics/test/fake_gles2_interface.h"
#include "third_party/blink/renderer/platform/graphics/test/fake_web_graphics_context_3d_provider.h"
#include "third_party/blink/renderer/platform/graphics/test/gpu_memory_buffer_test_platform.h"
#include "third_party/blink/renderer/platform/graphics/test/gpu_test_utils.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
#include "third_party/skia/include/core/SkFilterQuality.h"
#include "ui/gfx/buffer_types.h"
using testing::_;
using testing::InSequence;
using testing::Return;
using testing::Test;
namespace blink {
namespace {
constexpr int kMaxTextureSize = 1024;
class MockCanvasResourceDispatcherClient
: public CanvasResourceDispatcherClient {
public:
MockCanvasResourceDispatcherClient() = default;
MOCK_METHOD0(BeginFrame, bool());
MOCK_METHOD1(SetFilterQualityInResource, void(SkFilterQuality));
};
} // anonymous namespace
class CanvasResourceProviderTest : public Test {
public:
void SetUp() override {
test_context_provider_ = viz::TestContextProvider::Create();
auto* test_gl = test_context_provider_->UnboundTestContextGL();
test_gl->set_max_texture_size(kMaxTextureSize);
test_gl->set_support_texture_storage_image(true);
test_gl->set_supports_shared_image_swap_chain(true);
test_gl->set_supports_gpu_memory_buffer_format(gfx::BufferFormat::RGBA_8888,
true);
test_gl->set_supports_gpu_memory_buffer_format(gfx::BufferFormat::BGRA_8888,
true);
test_gl->set_supports_gpu_memory_buffer_format(gfx::BufferFormat::RGBA_F16,
true);
InitializeSharedGpuContext(test_context_provider_.get(),
&image_decode_cache_);
context_provider_wrapper_ = SharedGpuContext::ContextProviderWrapper();
}
void TearDown() override { SharedGpuContext::ResetForTesting(); }
protected:
cc::StubDecodeCache image_decode_cache_;
scoped_refptr<viz::TestContextProvider> test_context_provider_;
base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper_;
ScopedTestingPlatformSupport<GpuMemoryBufferTestPlatform> platform_;
};
TEST_F(CanvasResourceProviderTest, CanvasResourceProviderAcceleratedOverlay) {
const IntSize kSize(10, 10);
const CanvasResourceParams kColorParams(
CanvasColorSpace::kSRGB, kN32_SkColorType, kPremul_SkAlphaType);
const uint32_t shared_image_usage_flags =
gpu::SHARED_IMAGE_USAGE_DISPLAY | gpu::SHARED_IMAGE_USAGE_SCANOUT |
gpu::SHARED_IMAGE_USAGE_CONCURRENT_READ_WRITE;
auto provider = CanvasResourceProvider::CreateSharedImageProvider(
kSize, kMedium_SkFilterQuality, kColorParams,
CanvasResourceProvider::ShouldInitialize::kCallClear,
context_provider_wrapper_, RasterMode::kGPU, true /*is_origin_top_left*/,
shared_image_usage_flags);
EXPECT_EQ(provider->Size(), kSize);
EXPECT_TRUE(provider->IsValid());
EXPECT_TRUE(provider->IsAccelerated());
EXPECT_TRUE(provider->SupportsDirectCompositing());
EXPECT_TRUE(provider->SupportsSingleBuffering());
EXPECT_EQ(provider->ColorParams().ColorSpace(), kColorParams.ColorSpace());
// As it is an CanvasResourceProviderSharedImage and an accelerated canvas, it
// will internally force it to kRGBA8
EXPECT_EQ(provider->ColorParams().GetSkColorType(), kRGBA_8888_SkColorType);
EXPECT_EQ(provider->ColorParams().GetSkAlphaType(),
kColorParams.GetSkAlphaType());
EXPECT_FALSE(provider->IsSingleBuffered());
provider->TryEnableSingleBuffering();
EXPECT_TRUE(provider->IsSingleBuffered());
}
TEST_F(CanvasResourceProviderTest, CanvasResourceProviderTexture) {
const IntSize kSize(10, 10);
const CanvasResourceParams kColorParams(
CanvasColorSpace::kSRGB, kN32_SkColorType, kPremul_SkAlphaType);
auto provider = CanvasResourceProvider::CreateSharedImageProvider(
kSize, kLow_SkFilterQuality, kColorParams,
CanvasResourceProvider::ShouldInitialize::kCallClear,
context_provider_wrapper_, RasterMode::kGPU, true /*is_origin_top_left*/,
0u /*shared_image_usage_flags*/);
EXPECT_EQ(provider->Size(), kSize);
EXPECT_TRUE(provider->IsValid());
EXPECT_TRUE(provider->IsAccelerated());
EXPECT_TRUE(provider->SupportsDirectCompositing());
EXPECT_FALSE(provider->SupportsSingleBuffering());
EXPECT_EQ(provider->ColorParams().ColorSpace(), kColorParams.ColorSpace());
// As it is an CanvasResourceProviderSharedImage and an accelerated canvas, it
// will internally force it to kRGBA8
EXPECT_EQ(provider->ColorParams().GetSkColorType(), kRGBA_8888_SkColorType);
EXPECT_EQ(provider->ColorParams().GetSkAlphaType(),
kColorParams.GetSkAlphaType());
EXPECT_FALSE(provider->IsSingleBuffered());
}
TEST_F(CanvasResourceProviderTest, CanvasResourceProviderUnacceleratedOverlay) {
const IntSize kSize(10, 10);
const CanvasResourceParams kColorParams(
CanvasColorSpace::kSRGB, kN32_SkColorType, kPremul_SkAlphaType);
const uint32_t shared_image_usage_flags =
gpu::SHARED_IMAGE_USAGE_DISPLAY | gpu::SHARED_IMAGE_USAGE_SCANOUT;
auto provider = CanvasResourceProvider::CreateSharedImageProvider(
kSize, kLow_SkFilterQuality, kColorParams,
CanvasResourceProvider::ShouldInitialize::kCallClear,
context_provider_wrapper_, RasterMode::kCPU, true /*is_origin_top_left*/,
shared_image_usage_flags);
EXPECT_EQ(provider->Size(), kSize);
EXPECT_TRUE(provider->IsValid());
EXPECT_FALSE(provider->IsAccelerated());
EXPECT_TRUE(provider->SupportsDirectCompositing());
// We do not support single buffering for unaccelerated low latency canvas.
EXPECT_FALSE(provider->SupportsSingleBuffering());
EXPECT_EQ(provider->ColorParams().ColorSpace(), kColorParams.ColorSpace());
EXPECT_EQ(provider->ColorParams().GetSkColorType(),
kColorParams.GetSkColorType());
EXPECT_EQ(provider->ColorParams().GetSkAlphaType(),
kColorParams.GetSkAlphaType());
EXPECT_FALSE(provider->IsSingleBuffered());
}
TEST_F(CanvasResourceProviderTest,
CanvasResourceProviderSharedImageResourceRecycling) {
const IntSize kSize(10, 10);
const CanvasResourceParams kColorParams(
CanvasColorSpace::kSRGB, kN32_SkColorType, kPremul_SkAlphaType);
const uint32_t shared_image_usage_flags =
gpu::SHARED_IMAGE_USAGE_DISPLAY | gpu::SHARED_IMAGE_USAGE_SCANOUT;
auto provider = CanvasResourceProvider::CreateSharedImageProvider(
kSize, kMedium_SkFilterQuality, kColorParams,
CanvasResourceProvider::ShouldInitialize::kCallClear,
context_provider_wrapper_, RasterMode::kGPU, true /*is_origin_top_left*/,
shared_image_usage_flags);
EXPECT_EQ(provider->Size(), kSize);
EXPECT_TRUE(provider->IsValid());
EXPECT_TRUE(provider->IsAccelerated());
EXPECT_FALSE(provider->IsSingleBuffered());
EXPECT_FALSE(provider->SupportsSingleBuffering());
EXPECT_EQ(provider->ColorParams().ColorSpace(), kColorParams.ColorSpace());
// As it is an CanvasResourceProviderSharedImage and an accelerated canvas, it
// will internally force it to kRGBA8
EXPECT_EQ(provider->ColorParams().GetSkColorType(), kRGBA_8888_SkColorType);
EXPECT_EQ(provider->ColorParams().GetSkAlphaType(),
kColorParams.GetSkAlphaType());
// Same resource and sync token if we query again without updating.
auto resource = provider->ProduceCanvasResource();
auto sync_token = resource->GetSyncToken();
ASSERT_TRUE(resource);
EXPECT_EQ(resource, provider->ProduceCanvasResource());
EXPECT_EQ(sync_token, resource->GetSyncToken());
// Resource updated after draw.
provider->Canvas()->clear(SK_ColorWHITE);
auto new_resource = provider->ProduceCanvasResource();
EXPECT_NE(resource, new_resource);
EXPECT_NE(sync_token, new_resource->GetSyncToken());
// Resource recycled.
viz::TransferableResource transferable_resource;
std::unique_ptr<viz::SingleReleaseCallback> release_callback;
ASSERT_TRUE(resource->PrepareTransferableResource(
&transferable_resource, &release_callback, kUnverifiedSyncToken));
auto* resource_ptr = resource.get();
resource = nullptr;
release_callback->Run(sync_token, false);
provider->Canvas()->clear(SK_ColorBLACK);
auto resource_again = provider->ProduceCanvasResource();
EXPECT_EQ(resource_ptr, resource_again);
EXPECT_NE(sync_token, resource_again->GetSyncToken());
}
TEST_F(CanvasResourceProviderTest,
CanvasResourceProviderSharedImageStaticBitmapImage) {
const IntSize kSize(10, 10);
const CanvasResourceParams kColorParams(
CanvasColorSpace::kSRGB, kN32_SkColorType, kPremul_SkAlphaType);
const uint32_t shared_image_usage_flags =
gpu::SHARED_IMAGE_USAGE_DISPLAY | gpu::SHARED_IMAGE_USAGE_SCANOUT;
auto provider = CanvasResourceProvider::CreateSharedImageProvider(
kSize, kMedium_SkFilterQuality, kColorParams,
CanvasResourceProvider::ShouldInitialize::kCallClear,
context_provider_wrapper_, RasterMode::kGPU, true /*is_origin_top_left*/,
shared_image_usage_flags);
ASSERT_TRUE(provider->IsValid());
// Same resource returned until the canvas is updated.
auto image = provider->Snapshot();
ASSERT_TRUE(image);
auto new_image = provider->Snapshot();
EXPECT_EQ(image->GetMailboxHolder().mailbox,
new_image->GetMailboxHolder().mailbox);
EXPECT_EQ(provider->ProduceCanvasResource()->GetOrCreateGpuMailbox(
kOrderingBarrier),
image->GetMailboxHolder().mailbox);
// Resource updated after draw.
provider->Canvas()->clear(SK_ColorWHITE);
provider->FlushCanvas();
new_image = provider->Snapshot();
EXPECT_NE(new_image->GetMailboxHolder().mailbox,
image->GetMailboxHolder().mailbox);
// Resource recycled.
auto original_mailbox = image->GetMailboxHolder().mailbox;
image.reset();
provider->Canvas()->clear(SK_ColorBLACK);
provider->FlushCanvas();
EXPECT_EQ(original_mailbox, provider->Snapshot()->GetMailboxHolder().mailbox);
}
TEST_F(CanvasResourceProviderTest,
CanvasResourceProviderSharedImageCopyOnWriteDisabled) {
auto* fake_context = static_cast<FakeWebGraphicsContext3DProvider*>(
context_provider_wrapper_->ContextProvider());
auto caps = fake_context->GetCapabilities();
caps.disable_2d_canvas_copy_on_write = true;
fake_context->SetCapabilities(caps);
const IntSize kSize(10, 10);
const CanvasResourceParams kColorParams(
CanvasColorSpace::kSRGB, kN32_SkColorType, kPremul_SkAlphaType);
const uint32_t shared_image_usage_flags =
gpu::SHARED_IMAGE_USAGE_DISPLAY | gpu::SHARED_IMAGE_USAGE_SCANOUT;
auto provider = CanvasResourceProvider::CreateSharedImageProvider(
kSize, kMedium_SkFilterQuality, kColorParams,
CanvasResourceProvider::ShouldInitialize::kCallClear,
context_provider_wrapper_, RasterMode::kGPU,
true /* is_origin_top_left */, shared_image_usage_flags);
ASSERT_TRUE(provider->IsValid());
// Disabling copy-on-write forces a copy each time the resource is queried.
auto resource = provider->ProduceCanvasResource();
EXPECT_NE(resource->GetOrCreateGpuMailbox(kOrderingBarrier),
provider->ProduceCanvasResource()->GetOrCreateGpuMailbox(
kOrderingBarrier));
}
TEST_F(CanvasResourceProviderTest, CanvasResourceProviderBitmap) {
const IntSize kSize(10, 10);
const CanvasResourceParams kColorParams(
CanvasColorSpace::kSRGB, kN32_SkColorType, kPremul_SkAlphaType);
auto provider = CanvasResourceProvider::CreateBitmapProvider(
kSize, kLow_SkFilterQuality, kColorParams,
CanvasResourceProvider::ShouldInitialize::kCallClear);
EXPECT_EQ(provider->Size(), kSize);
EXPECT_TRUE(provider->IsValid());
EXPECT_FALSE(provider->IsAccelerated());
EXPECT_FALSE(provider->SupportsDirectCompositing());
EXPECT_FALSE(provider->SupportsSingleBuffering());
EXPECT_EQ(provider->ColorParams().ColorSpace(), kColorParams.ColorSpace());
EXPECT_EQ(provider->ColorParams().GetSkColorType(),
kColorParams.GetSkColorType());
EXPECT_EQ(provider->ColorParams().GetSkAlphaType(),
kColorParams.GetSkAlphaType());
EXPECT_FALSE(provider->IsSingleBuffered());
}
TEST_F(CanvasResourceProviderTest, CanvasResourceProviderSharedBitmap) {
const IntSize kSize(10, 10);
const CanvasResourceParams kColorParams(
CanvasColorSpace::kSRGB, kN32_SkColorType, kPremul_SkAlphaType);
MockCanvasResourceDispatcherClient client;
CanvasResourceDispatcher resource_dispatcher(
&client, base::ThreadTaskRunnerHandle::Get(), 1 /* client_id */,
1 /* sink_id */, 1 /* placeholder_canvas_id */, kSize);
auto provider = CanvasResourceProvider::CreateSharedBitmapProvider(
kSize, kLow_SkFilterQuality, kColorParams,
CanvasResourceProvider::ShouldInitialize::kCallClear,
resource_dispatcher.GetWeakPtr());
EXPECT_EQ(provider->Size(), kSize);
EXPECT_TRUE(provider->IsValid());
EXPECT_FALSE(provider->IsAccelerated());
EXPECT_TRUE(provider->SupportsDirectCompositing());
EXPECT_FALSE(provider->SupportsSingleBuffering());
EXPECT_EQ(provider->ColorParams().ColorSpace(), kColorParams.ColorSpace());
EXPECT_EQ(provider->ColorParams().GetSkColorType(),
kColorParams.GetSkColorType());
EXPECT_EQ(provider->ColorParams().GetSkAlphaType(),
kColorParams.GetSkAlphaType());
EXPECT_FALSE(provider->IsSingleBuffered());
provider->TryEnableSingleBuffering();
EXPECT_FALSE(provider->IsSingleBuffered());
}
TEST_F(CanvasResourceProviderTest,
CanvasResourceProviderDirect2DGpuMemoryBuffer) {
const IntSize kSize(10, 10);
const CanvasResourceParams kColorParams(
CanvasColorSpace::kSRGB, kN32_SkColorType, kPremul_SkAlphaType);
const uint32_t shared_image_usage_flags =
gpu::SHARED_IMAGE_USAGE_DISPLAY | gpu::SHARED_IMAGE_USAGE_SCANOUT |
gpu::SHARED_IMAGE_USAGE_CONCURRENT_READ_WRITE;
auto provider = CanvasResourceProvider::CreateSharedImageProvider(
kSize, kMedium_SkFilterQuality, kColorParams,
CanvasResourceProvider::ShouldInitialize::kCallClear,
context_provider_wrapper_, RasterMode::kGPU, true /*is_origin_top_left*/,
shared_image_usage_flags);
EXPECT_EQ(provider->Size(), kSize);
EXPECT_TRUE(provider->IsValid());
EXPECT_TRUE(provider->IsAccelerated());
EXPECT_TRUE(provider->SupportsDirectCompositing());
EXPECT_TRUE(provider->SupportsSingleBuffering());
EXPECT_EQ(provider->ColorParams().ColorSpace(), kColorParams.ColorSpace());
// As it is an CanvasResourceProviderSharedImage and an accelerated canvas, it
// will internally force it to kRGBA8
EXPECT_EQ(provider->ColorParams().GetSkColorType(), kRGBA_8888_SkColorType);
EXPECT_EQ(provider->ColorParams().GetSkAlphaType(),
kColorParams.GetSkAlphaType());
EXPECT_FALSE(provider->IsSingleBuffered());
provider->TryEnableSingleBuffering();
EXPECT_TRUE(provider->IsSingleBuffered());
}
TEST_F(CanvasResourceProviderTest,
CanvasResourceProviderDirect3DGpuMemoryBuffer) {
const IntSize kSize(10, 10);
const CanvasResourceParams kColorParams(
CanvasColorSpace::kSRGB, kN32_SkColorType, kPremul_SkAlphaType);
auto provider = CanvasResourceProvider::CreatePassThroughProvider(
kSize, kLow_SkFilterQuality, kColorParams, context_provider_wrapper_,
nullptr /*resource_dispatcher */, true /*is_origin_top_left*/);
EXPECT_EQ(provider->Size(), kSize);
EXPECT_TRUE(provider->IsValid());
EXPECT_TRUE(provider->IsAccelerated());
EXPECT_TRUE(provider->SupportsDirectCompositing());
EXPECT_TRUE(provider->SupportsSingleBuffering());
EXPECT_EQ(provider->ColorParams().ColorSpace(), kColorParams.ColorSpace());
EXPECT_EQ(provider->ColorParams().GetSkColorType(),
kColorParams.GetSkColorType());
EXPECT_EQ(provider->ColorParams().GetSkAlphaType(),
kColorParams.GetSkAlphaType());
EXPECT_FALSE(provider->IsSingleBuffered());
provider->TryEnableSingleBuffering();
EXPECT_TRUE(provider->IsSingleBuffered());
gpu::Mailbox mailbox = gpu::Mailbox::Generate();
scoped_refptr<ExternalCanvasResource> resource =
ExternalCanvasResource::Create(
mailbox, nullptr, gpu::SyncToken(), kSize, GL_TEXTURE_2D,
kColorParams, SharedGpuContext::ContextProviderWrapper(),
provider->CreateWeakPtr(), kMedium_SkFilterQuality,
true /*is_origin_top_left*/, true /*is_overlay_candidate*/);
// NewOrRecycledResource() would return nullptr before an ImportResource().
EXPECT_TRUE(provider->ImportResource(resource));
EXPECT_EQ(provider->NewOrRecycledResource(), resource);
// NewOrRecycledResource() will always return the same |resource|.
EXPECT_EQ(provider->NewOrRecycledResource(), resource);
}
TEST_F(CanvasResourceProviderTest, DimensionsExceedMaxTextureSize_Bitmap) {
const CanvasResourceParams kColorParams(
CanvasColorSpace::kSRGB, kN32_SkColorType, kPremul_SkAlphaType);
auto provider = CanvasResourceProvider::CreateBitmapProvider(
IntSize(kMaxTextureSize - 1, kMaxTextureSize), kLow_SkFilterQuality,
kColorParams, CanvasResourceProvider::ShouldInitialize::kCallClear);
EXPECT_FALSE(provider->SupportsDirectCompositing());
provider = CanvasResourceProvider::CreateBitmapProvider(
IntSize(kMaxTextureSize, kMaxTextureSize), kLow_SkFilterQuality,
kColorParams, CanvasResourceProvider::ShouldInitialize::kCallClear);
EXPECT_FALSE(provider->SupportsDirectCompositing());
provider = CanvasResourceProvider::CreateBitmapProvider(
IntSize(kMaxTextureSize + 1, kMaxTextureSize), kLow_SkFilterQuality,
kColorParams, CanvasResourceProvider::ShouldInitialize::kCallClear);
EXPECT_FALSE(provider->SupportsDirectCompositing());
}
TEST_F(CanvasResourceProviderTest, DimensionsExceedMaxTextureSize_SharedImage) {
const CanvasResourceParams kColorParams(
CanvasColorSpace::kSRGB, kN32_SkColorType, kPremul_SkAlphaType);
auto provider = CanvasResourceProvider::CreateSharedImageProvider(
IntSize(kMaxTextureSize - 1, kMaxTextureSize), kLow_SkFilterQuality,
kColorParams, CanvasResourceProvider::ShouldInitialize::kCallClear,
context_provider_wrapper_, RasterMode::kGPU, true /*is_origin_top_left*/,
0u /*shared_image_usage_flags*/);
EXPECT_TRUE(provider->SupportsDirectCompositing());
provider = CanvasResourceProvider::CreateSharedImageProvider(
IntSize(kMaxTextureSize, kMaxTextureSize), kLow_SkFilterQuality,
kColorParams, CanvasResourceProvider::ShouldInitialize::kCallClear,
context_provider_wrapper_, RasterMode::kGPU, true /*is_origin_top_left*/,
0u /*shared_image_usage_flags*/);
EXPECT_TRUE(provider->SupportsDirectCompositing());
provider = CanvasResourceProvider::CreateSharedImageProvider(
IntSize(kMaxTextureSize + 1, kMaxTextureSize), kLow_SkFilterQuality,
kColorParams, CanvasResourceProvider::ShouldInitialize::kCallClear,
context_provider_wrapper_, RasterMode::kGPU, true /*is_origin_top_left*/,
0u /*shared_image_usage_flags*/);
// The CanvasResourceProvider for SharedImage should not be created or valid
// if the texture size is greater than the maximum value
EXPECT_TRUE(!provider || !provider->IsValid());
}
TEST_F(CanvasResourceProviderTest, DimensionsExceedMaxTextureSize_SwapChain) {
const CanvasResourceParams kColorParams(
CanvasColorSpace::kSRGB, kN32_SkColorType, kPremul_SkAlphaType);
auto provider = CanvasResourceProvider::CreateSwapChainProvider(
IntSize(kMaxTextureSize - 1, kMaxTextureSize), kLow_SkFilterQuality,
kColorParams, CanvasResourceProvider::ShouldInitialize::kCallClear,
context_provider_wrapper_, nullptr /* resource_dispatcher */,
true /*is_origin_top_left*/);
EXPECT_TRUE(provider->SupportsDirectCompositing());
provider = CanvasResourceProvider::CreateSwapChainProvider(
IntSize(kMaxTextureSize, kMaxTextureSize), kLow_SkFilterQuality,
kColorParams, CanvasResourceProvider::ShouldInitialize::kCallClear,
context_provider_wrapper_, nullptr /* resource_dispatcher */,
true /*is_origin_top_left*/);
EXPECT_TRUE(provider->SupportsDirectCompositing());
provider = CanvasResourceProvider::CreateSwapChainProvider(
IntSize(kMaxTextureSize + 1, kMaxTextureSize), kLow_SkFilterQuality,
kColorParams, CanvasResourceProvider::ShouldInitialize::kCallClear,
context_provider_wrapper_, nullptr /* resource_dispatcher */,
true /*is_origin_top_left*/);
// The CanvasResourceProvider for SwapChain should not be created or valid
// if the texture size is greater than the maximum value
EXPECT_TRUE(!provider || !provider->IsValid());
}
TEST_F(CanvasResourceProviderTest, DimensionsExceedMaxTextureSize_PassThrough) {
const CanvasResourceParams kColorParams(
CanvasColorSpace::kSRGB, kN32_SkColorType, kPremul_SkAlphaType);
auto provider = CanvasResourceProvider::CreatePassThroughProvider(
IntSize(kMaxTextureSize - 1, kMaxTextureSize), kLow_SkFilterQuality,
kColorParams, context_provider_wrapper_,
nullptr /* resource_dispatcher */, true /*is_origin_top_left*/);
EXPECT_TRUE(provider->SupportsDirectCompositing());
provider = CanvasResourceProvider::CreatePassThroughProvider(
IntSize(kMaxTextureSize, kMaxTextureSize), kLow_SkFilterQuality,
kColorParams, context_provider_wrapper_,
nullptr /* resource_dispatcher */, true /*is_origin_top_left*/);
EXPECT_TRUE(provider->SupportsDirectCompositing());
provider = CanvasResourceProvider::CreatePassThroughProvider(
IntSize(kMaxTextureSize + 1, kMaxTextureSize), kLow_SkFilterQuality,
kColorParams, context_provider_wrapper_,
nullptr /* resource_dispatcher */, true /*is_origin_top_left*/);
// The CanvasResourceProvider for PassThrough should not be created or valid
// if the texture size is greater than the maximum value
EXPECT_TRUE(!provider || !provider->IsValid());
}
TEST_F(CanvasResourceProviderTest, CanvasResourceProviderDirect2DSwapChain) {
const IntSize kSize(10, 10);
const CanvasResourceParams kColorParams(
CanvasColorSpace::kSRGB, kN32_SkColorType, kPremul_SkAlphaType);
auto provider = CanvasResourceProvider::CreateSwapChainProvider(
kSize, kLow_SkFilterQuality, kColorParams,
CanvasResourceProvider::ShouldInitialize::kCallClear,
context_provider_wrapper_, nullptr /* resource_dispatcher */,
true /*is_origin_top_left*/);
ASSERT_TRUE(provider);
EXPECT_EQ(provider->Size(), kSize);
EXPECT_TRUE(provider->IsValid());
EXPECT_TRUE(provider->IsAccelerated());
EXPECT_TRUE(provider->SupportsDirectCompositing());
EXPECT_TRUE(provider->SupportsSingleBuffering());
EXPECT_TRUE(provider->IsSingleBuffered());
EXPECT_EQ(provider->ColorParams().ColorSpace(), kColorParams.ColorSpace());
EXPECT_EQ(provider->ColorParams().GetSkColorType(),
kColorParams.GetSkColorType());
EXPECT_EQ(provider->ColorParams().GetSkAlphaType(),
kColorParams.GetSkAlphaType());
}
TEST_F(CanvasResourceProviderTest, FlushForImage) {
const IntSize kSize(10, 10);
const CanvasResourceParams kColorParams(
CanvasColorSpace::kSRGB, kN32_SkColorType, kPremul_SkAlphaType);
auto src_provider = CanvasResourceProvider::CreateSharedImageProvider(
kSize, kMedium_SkFilterQuality, kColorParams,
CanvasResourceProvider::ShouldInitialize::kCallClear,
context_provider_wrapper_, RasterMode::kGPU, true /*is_origin_top_left*/,
0u /*shared_image_usage_flags*/);
auto dst_provider = CanvasResourceProvider::CreateSharedImageProvider(
kSize, kMedium_SkFilterQuality, kColorParams,
CanvasResourceProvider::ShouldInitialize::kCallClear,
context_provider_wrapper_, RasterMode::kGPU, true /*is_origin_top_left*/,
0u /*shared_image_usage_flags*/);
MemoryManagedPaintCanvas* dst_canvas =
static_cast<MemoryManagedPaintCanvas*>(dst_provider->Canvas());
PaintImage paint_image =
src_provider->Snapshot()->PaintImageForCurrentFrame();
PaintImage::ContentId src_content_id = paint_image.GetContentIdForFrame(0u);
EXPECT_FALSE(dst_canvas->IsCachingImage(src_content_id));
dst_canvas->drawImage(paint_image, 0, 0, SkSamplingOptions(), nullptr);
EXPECT_TRUE(dst_canvas->IsCachingImage(src_content_id));
src_provider->Canvas()->clear(
SK_ColorWHITE); // Modify the canvas to trigger OnFlushForImage
src_provider
->ProduceCanvasResource(); // So that all the cached draws are executed
// The paint canvas may have moved
dst_canvas = static_cast<MemoryManagedPaintCanvas*>(dst_provider->Canvas());
// TODO(aaronhk): The resource on the src_provider should be the same before
// and after the draw. Something about the program flow within
// this testing framework (but not in layout tests) makes a reference to
// the src_resource stick around throughout the FlushForImage call so the
// src_resource changes in this test. Things work as expected for actual
// browser code like canvas_to_canvas_draw.html.
// OnFlushForImage should detect the modification of the source resource and
// clear the cache of the destination canvas to avoid a copy-on-write.
EXPECT_FALSE(dst_canvas->IsCachingImage(src_content_id));
}
} // namespace blink