blob: 125945f8bb42e6c9704c38049a5170dc069c8909 [file] [log] [blame]
// Copyright 2021 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/video_frame_image_util.h"
#include "base/test/task_environment.h"
#include "build/build_config.h"
#include "components/viz/common/gpu/raster_context_provider.h"
#include "components/viz/test/test_context_provider.h"
#include "gpu/command_buffer/common/capabilities.h"
#include "media/base/video_frame.h"
#include "media/renderers/shared_image_video_frame_test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/platform/graphics/canvas_resource_provider.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/gpu_test_utils.h"
#include "third_party/blink/renderer/platform/testing/video_frame_utils.h"
namespace blink {
namespace {
constexpr auto kTestSize = gfx::Size(64, 64);
class ScopedFakeGpuContext {
public:
explicit ScopedFakeGpuContext(bool disable_imagebitmap) {
SharedGpuContext::ResetForTesting();
test_context_provider_ = viz::TestContextProvider::Create();
if (disable_imagebitmap) {
// Disable CanvasResourceProvider using GPU.
auto& feature_info = test_context_provider_->GetWritableGpuFeatureInfo();
feature_info.enabled_gpu_driver_bug_workarounds.push_back(
DISABLE_IMAGEBITMAP_FROM_VIDEO_USING_GPU);
}
InitializeSharedGpuContext(test_context_provider_.get());
}
scoped_refptr<viz::ContextProvider> context_provider() const {
return test_context_provider_;
}
viz::RasterContextProvider* raster_context_provider() const {
return test_context_provider_.get();
}
~ScopedFakeGpuContext() {
task_environment_.RunUntilIdle();
SharedGpuContext::ResetForTesting();
}
private:
base::test::SingleThreadTaskEnvironment task_environment_;
scoped_refptr<viz::TestContextProvider> test_context_provider_;
};
} // namespace
TEST(VideoFrameImageUtilTest, WillCreateAcceleratedImagesFromVideoFrame) {
// I420A isn't a supported zero copy format.
{
auto alpha_frame = media::VideoFrame::CreateTransparentFrame(kTestSize);
EXPECT_FALSE(WillCreateAcceleratedImagesFromVideoFrame(alpha_frame.get()));
}
// Software RGB frames aren't supported.
{
auto cpu_frame = CreateTestFrame(kTestSize, gfx::Rect(kTestSize), kTestSize,
media::VideoFrame::STORAGE_OWNED_MEMORY,
media::PIXEL_FORMAT_XRGB);
EXPECT_FALSE(WillCreateAcceleratedImagesFromVideoFrame(cpu_frame.get()));
}
// GpuMemoryBuffer frames aren't supported.
{
auto cpu_frame = CreateTestFrame(
kTestSize, gfx::Rect(kTestSize), kTestSize,
media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER, media::PIXEL_FORMAT_XRGB);
EXPECT_FALSE(WillCreateAcceleratedImagesFromVideoFrame(cpu_frame.get()));
}
// Single mailbox shared images should be supported except on Android.
{
auto shared_image_frame = CreateTestFrame(
kTestSize, gfx::Rect(kTestSize), kTestSize,
media::VideoFrame::STORAGE_OPAQUE, media::PIXEL_FORMAT_XRGB);
EXPECT_EQ(shared_image_frame->NumTextures(), 1u);
EXPECT_TRUE(shared_image_frame->mailbox_holder(0).mailbox.IsSharedImage());
#if defined(OS_ANDROID)
EXPECT_FALSE(
WillCreateAcceleratedImagesFromVideoFrame(shared_image_frame.get()));
#else
EXPECT_TRUE(
WillCreateAcceleratedImagesFromVideoFrame(shared_image_frame.get()));
#endif
}
}
// Android doesn't support zero copy images.
#if !defined(OS_ANDROID)
TEST(VideoFrameImageUtilTest, CreateImageFromVideoFrameZeroCopy) {
ScopedFakeGpuContext fake_context(/*disable_imagebitmap=*/false);
auto shared_image_frame = CreateTestFrame(
kTestSize, gfx::Rect(kTestSize), kTestSize,
media::VideoFrame::STORAGE_OPAQUE, media::PIXEL_FORMAT_XRGB);
EXPECT_EQ(shared_image_frame->NumTextures(), 1u);
EXPECT_TRUE(shared_image_frame->mailbox_holder(0).mailbox.IsSharedImage());
auto image = CreateImageFromVideoFrame(shared_image_frame);
ASSERT_TRUE(image->IsTextureBacked());
EXPECT_EQ(memcmp(image->GetMailboxHolder().mailbox.name,
shared_image_frame->mailbox_holder(0).mailbox.name,
sizeof(gpu::Mailbox::Name)),
0);
}
#endif
TEST(VideoFrameImageUtilTest, CreateImageFromVideoFrameSoftwareFrame) {
base::test::SingleThreadTaskEnvironment task_environment_;
auto cpu_frame = CreateTestFrame(kTestSize, gfx::Rect(kTestSize), kTestSize,
media::VideoFrame::STORAGE_OWNED_MEMORY,
media::PIXEL_FORMAT_XRGB);
auto image = CreateImageFromVideoFrame(cpu_frame);
ASSERT_FALSE(image->IsTextureBacked());
task_environment_.RunUntilIdle();
}
TEST(VideoFrameImageUtilTest, CreateImageFromVideoFrameGpuMemoryBufferFrame) {
base::test::SingleThreadTaskEnvironment task_environment_;
auto cpu_frame = CreateTestFrame(kTestSize, gfx::Rect(kTestSize), kTestSize,
media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER,
media::PIXEL_FORMAT_NV12);
auto image = CreateImageFromVideoFrame(cpu_frame);
ASSERT_FALSE(image->IsTextureBacked());
task_environment_.RunUntilIdle();
}
TEST(VideoFrameImageUtilTest, CreateImageFromVideoFrameTextureFrame) {
base::test::SingleThreadTaskEnvironment task_environment_;
auto cpu_frame = CreateTestFrame(kTestSize, gfx::Rect(kTestSize), kTestSize,
media::VideoFrame::STORAGE_OPAQUE,
media::PIXEL_FORMAT_NV12);
auto image = CreateImageFromVideoFrame(cpu_frame);
// An unaccelerated image can't be created from a texture based VideoFrame
// without a viz::RasterContextProvider.
ASSERT_FALSE(image);
task_environment_.RunUntilIdle();
}
TEST(VideoFrameImageUtilTest,
CreateAcceleratedImageFromVideoFrameBasicSoftwareFrame) {
ScopedFakeGpuContext fake_context(/*disable_imagebitmap=*/false);
auto cpu_frame = CreateTestFrame(kTestSize, gfx::Rect(kTestSize), kTestSize,
media::VideoFrame::STORAGE_OWNED_MEMORY,
media::PIXEL_FORMAT_XRGB);
auto image = CreateImageFromVideoFrame(cpu_frame);
ASSERT_TRUE(image->IsTextureBacked());
}
TEST(VideoFrameImageUtilTest, CreateAcceleratedImageFromGpuMemoryBufferFrame) {
ScopedFakeGpuContext fake_context(/*disable_imagebitmap=*/false);
auto gmb_frame = CreateTestFrame(kTestSize, gfx::Rect(kTestSize), kTestSize,
media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER,
media::PIXEL_FORMAT_NV12);
auto image = CreateImageFromVideoFrame(gmb_frame);
ASSERT_TRUE(image->IsTextureBacked());
}
TEST(VideoFrameImageUtilTest, CreateAcceleratedImageFromTextureFrame) {
ScopedFakeGpuContext fake_context(/*disable_imagebitmap=*/false);
auto texture_frame = media::CreateSharedImageRGBAFrame(
fake_context.context_provider(), kTestSize, gfx::Rect(kTestSize),
base::DoNothing::Once());
auto image = CreateImageFromVideoFrame(texture_frame,
/*allow_zero_copy_images=*/false);
ASSERT_TRUE(image->IsTextureBacked());
}
TEST(VideoFrameImageUtilTest, FlushedAcceleratedImage) {
ScopedFakeGpuContext fake_context(/*disable_imagebitmap=*/false);
auto texture_frame = media::CreateSharedImageRGBAFrame(
fake_context.context_provider(), kTestSize, gfx::Rect(kTestSize),
base::DoNothing::Once());
auto* raster_context_provider = fake_context.raster_context_provider();
ASSERT_TRUE(raster_context_provider);
auto provider = CreateResourceProviderForVideoFrame(IntSize(kTestSize),
raster_context_provider);
ASSERT_TRUE(provider);
EXPECT_TRUE(provider->IsAccelerated());
auto image = CreateImageFromVideoFrame(texture_frame,
/*allow_zero_copy_images=*/false,
provider.get());
EXPECT_TRUE(image->IsTextureBacked());
image = CreateImageFromVideoFrame(texture_frame,
/*allow_zero_copy_images=*/false,
provider.get());
EXPECT_TRUE(image->IsTextureBacked());
ASSERT_FALSE(provider->needs_flush());
ASSERT_FALSE(provider->HasRecordedDrawOps());
}
TEST(VideoFrameImageUtilTest, SoftwareCreateResourceProviderForVideoFrame) {
// Creating a provider with a null viz::RasterContextProvider should result in
// a non-accelerated provider being created.
auto provider =
CreateResourceProviderForVideoFrame(IntSize(kTestSize), nullptr);
ASSERT_TRUE(provider);
EXPECT_FALSE(provider->IsAccelerated());
}
TEST(VideoFrameImageUtilTest, AcceleratedCreateResourceProviderForVideoFrame) {
ScopedFakeGpuContext fake_context(/*disable_imagebitmap=*/false);
ASSERT_TRUE(SharedGpuContext::IsGpuCompositingEnabled());
auto* raster_context_provider = fake_context.raster_context_provider();
ASSERT_TRUE(raster_context_provider);
// Creating a provider with a null viz::RasterContextProvider should result in
// a non-accelerated provider being created.
{
auto provider =
CreateResourceProviderForVideoFrame(IntSize(kTestSize), nullptr);
ASSERT_TRUE(provider);
EXPECT_FALSE(provider->IsAccelerated());
}
// Creating a provider with a real raster context provider should result in
// an accelerated provider being created.
{
auto provider = CreateResourceProviderForVideoFrame(
IntSize(kTestSize), raster_context_provider);
ASSERT_TRUE(provider);
EXPECT_TRUE(provider->IsAccelerated());
}
}
TEST(VideoFrameImageUtilTest, WorkaroundCreateResourceProviderForVideoFrame) {
ScopedFakeGpuContext fake_context(/*disable_imagebitmap=*/true);
ASSERT_TRUE(SharedGpuContext::IsGpuCompositingEnabled());
auto* raster_context_provider = fake_context.raster_context_provider();
ASSERT_TRUE(raster_context_provider);
// Creating a provider with a real raster context provider should result in
// an unaccelerated provider being created due to the workaround.
{
auto provider = CreateResourceProviderForVideoFrame(
IntSize(kTestSize), raster_context_provider);
ASSERT_TRUE(provider);
EXPECT_FALSE(provider->IsAccelerated());
}
}
TEST(VideoFrameImageUtilTest, DestRectWithoutCanvasResourceProvider) {
base::test::SingleThreadTaskEnvironment task_environment_;
auto cpu_frame = CreateTestFrame(kTestSize, gfx::Rect(kTestSize), kTestSize,
media::VideoFrame::STORAGE_OWNED_MEMORY,
media::PIXEL_FORMAT_XRGB);
// A CanvasResourceProvider must be provided with a custom destination rect.
auto image = CreateImageFromVideoFrame(cpu_frame, true, nullptr, nullptr,
gfx::Rect(0, 0, 10, 10));
ASSERT_FALSE(image);
task_environment_.RunUntilIdle();
}
TEST(VideoFrameImageUtilTest, CanvasResourceProviderTooSmallForDestRect) {
base::test::SingleThreadTaskEnvironment task_environment_;
auto cpu_frame = CreateTestFrame(kTestSize, gfx::Rect(kTestSize), kTestSize,
media::VideoFrame::STORAGE_OWNED_MEMORY,
media::PIXEL_FORMAT_XRGB);
auto provider =
CreateResourceProviderForVideoFrame(IntSize(gfx::Size(16, 16)), nullptr);
ASSERT_TRUE(provider);
EXPECT_FALSE(provider->IsAccelerated());
auto image = CreateImageFromVideoFrame(cpu_frame, true, provider.get(),
nullptr, gfx::Rect(kTestSize));
ASSERT_FALSE(image);
task_environment_.RunUntilIdle();
}
TEST(VideoFrameImageUtilTest, CanvasResourceProviderDestRect) {
base::test::SingleThreadTaskEnvironment task_environment_;
auto cpu_frame = CreateTestFrame(kTestSize, gfx::Rect(kTestSize), kTestSize,
media::VideoFrame::STORAGE_OWNED_MEMORY,
media::PIXEL_FORMAT_XRGB);
auto provider = CreateResourceProviderForVideoFrame(
IntSize(gfx::Size(128, 128)), nullptr);
ASSERT_TRUE(provider);
EXPECT_FALSE(provider->IsAccelerated());
auto image = CreateImageFromVideoFrame(cpu_frame, true, provider.get(),
nullptr, gfx::Rect(16, 16, 64, 64));
ASSERT_TRUE(image);
task_environment_.RunUntilIdle();
}
} // namespace blink