#include "ui/gl/dcomp_presenter.h"
#include <wrl/client.h>
#include <wrl/implements.h>
#include "base/functional/callback_helpers.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted_memory.h"
#include "base/memory/weak_ptr.h"
#include "base/run_loop.h"
#include "base/synchronization/waitable_event.h"
#include "base/test/power_monitor_test.h"
#include "base/test/scoped_feature_list.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/win/hidden_window.h"
#include "ui/gfx/buffer_format_util.h"
#include "ui/gfx/frame_data.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/geometry/transform.h"
#include "ui/gfx/geometry/vector2d_f.h"
#include "ui/gfx/test/sk_color_eq.h"
#include "ui/gl/dc_layer_overlay_params.h"
#include "ui/gl/direct_composition_child_surface_win.h"
#include "ui/gl/direct_composition_support.h"
#include "ui/gl/direct_composition_surface_win.h"
#include "ui/gl/gl_angle_util_win.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_switches.h"
#include "ui/gl/gl_version_info.h"
#include "ui/gl/init/gl_factory.h"
#include "ui/gl/test/gl_test_helper.h"
#include "ui/platform_window/platform_window_delegate.h"
#include "ui/platform_window/win/win_window.h"
namespace gl {
namespace {
class TestPlatformDelegate : public ui::PlatformWindowDelegate {
public:
void OnBoundsChanged(const BoundsChange& change) override {}
void OnDamageRect(const gfx::Rect& damaged_region) override {}
void DispatchEvent(ui::Event* event) override {}
void OnCloseRequest() override {}
void OnClosed() override {}
void OnWindowStateChanged(ui::PlatformWindowState old_state,
ui::PlatformWindowState new_state) override {}
void OnLostCapture() override {}
void OnAcceleratedWidgetAvailable(gfx::AcceleratedWidget widget) override {}
void OnWillDestroyAcceleratedWidget() override {}
void OnAcceleratedWidgetDestroyed() override {}
void OnActivationChanged(bool active) override {}
void OnMouseEnter() override {}
};
void RunPendingTasks(scoped_refptr<base::TaskRunner> task_runner) {
base::WaitableEvent done(base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::NOT_SIGNALED);
task_runner->PostTask(
FROM_HERE, BindOnce(&base::WaitableEvent::Signal, Unretained(&done)));
done.Wait();
}
void DestroyPresenter(scoped_refptr<DCompPresenter> presenter) {
scoped_refptr<base::TaskRunner> task_runner =
presenter->GetWindowTaskRunnerForTesting();
DCHECK(presenter->HasOneRef());
presenter.reset();
RunPendingTasks(task_runner);
base::RunLoop().RunUntilIdle();
}
Microsoft::WRL::ComPtr<ID3D11Texture2D> CreateNV12Texture(
const Microsoft::WRL::ComPtr<ID3D11Device>& d3d11_device,
const gfx::Size& size) {
D3D11_TEXTURE2D_DESC desc = {};
desc.Width = size.width();
desc.Height = size.height();
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_NV12;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.SampleDesc.Count = 1;
desc.BindFlags = 0;
desc.MiscFlags = 0;
std::vector<char> image_data(size.width() * size.height() * 3 / 2);
memset(&image_data[0], 160, size.width() * size.height() * 3 / 2);
D3D11_SUBRESOURCE_DATA data = {};
data.pSysMem = (const void*)&image_data[0];
data.SysMemPitch = size.width();
Microsoft::WRL::ComPtr<ID3D11Texture2D> texture;
HRESULT hr = d3d11_device->CreateTexture2D(&desc, &data, &texture);
EXPECT_HRESULT_SUCCEEDED(hr);
return texture;
}
const int kMaxColorChannelDeviation = 10;
}
class DCompPresenterTest : public testing::Test {
public:
DCompPresenterTest() : parent_window_(ui::GetHiddenWindow()) {}
protected:
void SetUp() override {
fake_power_monitor_source_.SetOnBatteryPower(true);
display_ = gl::init::InitializeGLNoExtensionsOneOff(
true, gl::GpuPreference::kDefault);
if (!DirectCompositionSupported()) {
LOG(WARNING) << "DirectComposition not supported, skipping test.";
return;
}
presenter_ = CreateDCompPresenter();
gl_surface_ = init::CreateOffscreenGLSurface(
gl::GLSurfaceEGL::GetGLDisplayEGL(), gfx::Size());
context_ = CreateGLContext(gl_surface_);
SetDirectCompositionScaledOverlaysSupportedForTesting(false);
SetDirectCompositionOverlayFormatUsedForTesting(DXGI_FORMAT_NV12);
}
void TearDown() override {
context_ = nullptr;
if (presenter_) {
DestroyPresenter(std::move(presenter_));
}
gl::init::ShutdownGL(display_, false);
}
scoped_refptr<DCompPresenter> CreateDCompPresenter() {
DirectCompositionSurfaceWin::Settings settings;
scoped_refptr<DCompPresenter> presenter =
base::MakeRefCounted<DCompPresenter>(
gl::GLSurfaceEGL::GetGLDisplayEGL(),
DCompPresenter::VSyncCallback(), settings);
EXPECT_TRUE(presenter->Initialize());
if (parent_window_)
::SetParent(presenter->window(), parent_window_);
return presenter;
}
scoped_refptr<GLContext> CreateGLContext(scoped_refptr<GLSurface> surface) {
scoped_refptr<GLContext> context =
gl::init::CreateGLContext(nullptr, surface.get(), GLContextAttribs());
EXPECT_TRUE(context->MakeCurrent(surface.get()));
return context;
}
void PresentAndCheckSwapResult(gfx::SwapResult expected_swap_result) {
base::RunLoop wait_for_present;
presenter_->Present(
base::BindOnce(
[](base::RepeatingClosure quit_closure,
gfx::SwapResult expected_swap_result,
gfx::SwapCompletionResult result) {
EXPECT_EQ(expected_swap_result, result.swap_result);
quit_closure.Run();
},
wait_for_present.QuitClosure(), expected_swap_result),
base::DoNothing(), gfx::FrameData());
wait_for_present.Run();
}
HWND parent_window_;
scoped_refptr<DCompPresenter> presenter_;
scoped_refptr<GLSurface> gl_surface_;
scoped_refptr<GLContext> context_;
base::test::ScopedPowerMonitorTestSource fake_power_monitor_source_;
raw_ptr<GLDisplay> display_ = nullptr;
};
TEST_F(DCompPresenterTest, NoPresentTwice) {
if (!presenter_) {
return;
}
Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
QueryD3D11DeviceObjectFromANGLE();
gfx::Size texture_size(50, 50);
Microsoft::WRL::ComPtr<ID3D11Texture2D> texture =
CreateNV12Texture(d3d11_device, texture_size);
ASSERT_NE(texture, nullptr);
{
auto params = std::make_unique<DCLayerOverlayParams>();
params->overlay_image.emplace(texture_size, texture);
params->content_rect = gfx::Rect(texture_size);
params->quad_rect = gfx::Rect(100, 100);
params->color_space = gfx::ColorSpace::CreateREC709();
presenter_->ScheduleDCLayer(std::move(params));
}
Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain =
presenter_->GetLayerSwapChainForTesting(0);
ASSERT_FALSE(swap_chain);
PresentAndCheckSwapResult(gfx::SwapResult::SWAP_ACK);
swap_chain = presenter_->GetLayerSwapChainForTesting(0);
ASSERT_TRUE(swap_chain);
UINT last_present_count = 0;
EXPECT_HRESULT_SUCCEEDED(
swap_chain->GetLastPresentCount(&last_present_count));
EXPECT_EQ(2u, last_present_count);
{
auto params = std::make_unique<DCLayerOverlayParams>();
params->overlay_image.emplace(texture_size, texture);
params->content_rect = gfx::Rect(texture_size);
params->quad_rect = gfx::Rect(100, 100);
params->color_space = gfx::ColorSpace::CreateREC709();
presenter_->ScheduleDCLayer(std::move(params));
}
PresentAndCheckSwapResult(gfx::SwapResult::SWAP_ACK);
Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain2 =
presenter_->GetLayerSwapChainForTesting(0);
EXPECT_EQ(swap_chain2.Get(), swap_chain.Get());
EXPECT_HRESULT_SUCCEEDED(
swap_chain->GetLastPresentCount(&last_present_count));
EXPECT_EQ(2u, last_present_count);
texture = CreateNV12Texture(d3d11_device, texture_size);
ASSERT_NE(texture, nullptr);
{
auto params = std::make_unique<DCLayerOverlayParams>();
params->overlay_image.emplace(texture_size, texture);
params->content_rect = gfx::Rect(texture_size);
params->quad_rect = gfx::Rect(100, 100);
params->color_space = gfx::ColorSpace::CreateREC709();
presenter_->ScheduleDCLayer(std::move(params));
}
PresentAndCheckSwapResult(gfx::SwapResult::SWAP_ACK);
Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain3 =
presenter_->GetLayerSwapChainForTesting(0);
EXPECT_HRESULT_SUCCEEDED(
swap_chain3->GetLastPresentCount(&last_present_count));
EXPECT_EQ(3u, last_present_count);
}
TEST_F(DCompPresenterTest, SwapchainSizeWithScaledOverlays) {
if (!presenter_) {
return;
}
Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
QueryD3D11DeviceObjectFromANGLE();
gfx::Size texture_size(64, 64);
Microsoft::WRL::ComPtr<ID3D11Texture2D> texture =
CreateNV12Texture(d3d11_device, texture_size);
ASSERT_NE(texture, nullptr);
SetDirectCompositionScaledOverlaysSupportedForTesting(true);
gfx::Rect quad_rect = gfx::Rect(100, 100);
{
auto params = std::make_unique<DCLayerOverlayParams>();
params->overlay_image.emplace(texture_size, texture);
params->content_rect = gfx::Rect(texture_size);
params->quad_rect = quad_rect;
params->color_space = gfx::ColorSpace::CreateREC709();
presenter_->ScheduleDCLayer(std::move(params));
}
PresentAndCheckSwapResult(gfx::SwapResult::SWAP_ACK);
Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain =
presenter_->GetLayerSwapChainForTesting(0);
ASSERT_TRUE(swap_chain);
DXGI_SWAP_CHAIN_DESC desc;
EXPECT_HRESULT_SUCCEEDED(swap_chain->GetDesc(&desc));
EXPECT_EQ(100u, desc.BufferDesc.Width);
EXPECT_EQ(100u, desc.BufferDesc.Height);
PresentAndCheckSwapResult(gfx::SwapResult::SWAP_ACK);
quad_rect = gfx::Rect(32, 48);
{
auto params = std::make_unique<DCLayerOverlayParams>();
params->overlay_image.emplace(texture_size, texture);
params->content_rect = gfx::Rect(texture_size);
params->quad_rect = quad_rect;
params->color_space = gfx::ColorSpace::CreateREC709();
presenter_->ScheduleDCLayer(std::move(params));
}
PresentAndCheckSwapResult(gfx::SwapResult::SWAP_ACK);
Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain2 =
presenter_->GetLayerSwapChainForTesting(0);
ASSERT_TRUE(swap_chain2);
EXPECT_HRESULT_SUCCEEDED(swap_chain2->GetDesc(&desc));
EXPECT_EQ(32u, desc.BufferDesc.Width);
EXPECT_EQ(48u, desc.BufferDesc.Height);
}
TEST_F(DCompPresenterTest, SwapchainSizeWithoutScaledOverlays) {
if (!presenter_) {
return;
}
Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
QueryD3D11DeviceObjectFromANGLE();
gfx::Size texture_size(80, 80);
Microsoft::WRL::ComPtr<ID3D11Texture2D> texture =
CreateNV12Texture(d3d11_device, texture_size);
ASSERT_NE(texture, nullptr);
gfx::Rect quad_rect = gfx::Rect(42, 42);
{
auto params = std::make_unique<DCLayerOverlayParams>();
params->overlay_image.emplace(texture_size, texture);
params->content_rect = gfx::Rect(texture_size);
params->quad_rect = quad_rect;
params->color_space = gfx::ColorSpace::CreateREC709();
presenter_->ScheduleDCLayer(std::move(params));
}
PresentAndCheckSwapResult(gfx::SwapResult::SWAP_ACK);
Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain =
presenter_->GetLayerSwapChainForTesting(0);
ASSERT_TRUE(swap_chain);
DXGI_SWAP_CHAIN_DESC desc;
EXPECT_HRESULT_SUCCEEDED(swap_chain->GetDesc(&desc));
EXPECT_EQ(42u, desc.BufferDesc.Width);
EXPECT_EQ(42u, desc.BufferDesc.Height);
quad_rect = gfx::Rect(124, 136);
{
auto params = std::make_unique<DCLayerOverlayParams>();
params->overlay_image.emplace(texture_size, texture);
params->content_rect = gfx::Rect(texture_size);
params->quad_rect = quad_rect;
params->color_space = gfx::ColorSpace::CreateREC709();
presenter_->ScheduleDCLayer(std::move(params));
}
PresentAndCheckSwapResult(gfx::SwapResult::SWAP_ACK);
Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain2 =
presenter_->GetLayerSwapChainForTesting(0);
ASSERT_TRUE(swap_chain2);
EXPECT_HRESULT_SUCCEEDED(swap_chain2->GetDesc(&desc));
EXPECT_EQ(124u, desc.BufferDesc.Width);
EXPECT_EQ(136u, desc.BufferDesc.Height);
}
TEST_F(DCompPresenterTest, ProtectedVideos) {
if (!presenter_) {
return;
}
Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
QueryD3D11DeviceObjectFromANGLE();
gfx::Size texture_size(1280, 720);
Microsoft::WRL::ComPtr<ID3D11Texture2D> texture =
CreateNV12Texture(d3d11_device, texture_size);
ASSERT_NE(texture, nullptr);
gfx::Size window_size(640, 360);
{
auto params = std::make_unique<DCLayerOverlayParams>();
params->overlay_image.emplace(texture_size, texture);
params->quad_rect = gfx::Rect(window_size);
params->content_rect = gfx::Rect(texture_size);
params->color_space = gfx::ColorSpace::CreateREC709();
params->protected_video_type = gfx::ProtectedVideoType::kClear;
presenter_->ScheduleDCLayer(std::move(params));
PresentAndCheckSwapResult(gfx::SwapResult::SWAP_ACK);
Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain =
presenter_->GetLayerSwapChainForTesting(0);
ASSERT_TRUE(swap_chain);
DXGI_SWAP_CHAIN_DESC desc;
EXPECT_HRESULT_SUCCEEDED(swap_chain->GetDesc(&desc));
auto display_only_flag = desc.Flags & DXGI_SWAP_CHAIN_FLAG_DISPLAY_ONLY;
auto hw_protected_flag = desc.Flags & DXGI_SWAP_CHAIN_FLAG_HW_PROTECTED;
EXPECT_EQ(0u, display_only_flag);
EXPECT_EQ(0u, hw_protected_flag);
}
{
auto params = std::make_unique<DCLayerOverlayParams>();
params->overlay_image.emplace(texture_size, texture);
params->quad_rect = gfx::Rect(window_size);
params->content_rect = gfx::Rect(texture_size);
params->color_space = gfx::ColorSpace::CreateREC709();
params->protected_video_type = gfx::ProtectedVideoType::kSoftwareProtected;
presenter_->ScheduleDCLayer(std::move(params));
PresentAndCheckSwapResult(gfx::SwapResult::SWAP_ACK);
Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain =
presenter_->GetLayerSwapChainForTesting(0);
ASSERT_TRUE(swap_chain);
DXGI_SWAP_CHAIN_DESC Desc;
EXPECT_HRESULT_SUCCEEDED(swap_chain->GetDesc(&Desc));
auto display_only_flag = Desc.Flags & DXGI_SWAP_CHAIN_FLAG_DISPLAY_ONLY;
auto hw_protected_flag = Desc.Flags & DXGI_SWAP_CHAIN_FLAG_HW_PROTECTED;
EXPECT_EQ(DXGI_SWAP_CHAIN_FLAG_DISPLAY_ONLY, display_only_flag);
EXPECT_EQ(0u, hw_protected_flag);
}
}
class DCompPresenterPixelTest : public DCompPresenterTest {
public:
DCompPresenterPixelTest()
: window_(&platform_delegate_, gfx::Rect(100, 100)) {
parent_window_ = window_.hwnd();
}
protected:
void SetUp() override {
static_cast<ui::PlatformWindow*>(&window_)->Show();
DCompPresenterTest::SetUp();
}
void TearDown() override {
if (IsWindow(parent_window_))
DestroyWindow(parent_window_);
DCompPresenterTest::TearDown();
}
void InitializeRootAndScheduleRootSurface(const gfx::Size& window_size,
SkColor4f initial_color) {
Microsoft::WRL::ComPtr<IDCompositionDevice2> dcomp_device =
gl::GetDirectCompositionDevice();
Microsoft::WRL::ComPtr<IDCompositionSurface> root_surface;
ASSERT_HRESULT_SUCCEEDED(dcomp_device->CreateSurface(
window_size.width(), window_size.height(), DXGI_FORMAT_B8G8R8A8_UNORM,
DXGI_ALPHA_MODE_IGNORE, &root_surface));
Microsoft::WRL::ComPtr<ID3D11Texture2D> update_texture;
RECT rect = gfx::Rect(window_size).ToRECT();
POINT update_offset;
ASSERT_HRESULT_SUCCEEDED(root_surface->BeginDraw(
&rect, IID_PPV_ARGS(&update_texture), &update_offset));
Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
gl::QueryD3D11DeviceObjectFromANGLE();
Microsoft::WRL::ComPtr<ID3D11DeviceContext> immediate_context;
d3d11_device->GetImmediateContext(&immediate_context);
Microsoft::WRL::ComPtr<ID3D11RenderTargetView> rtv;
D3D11_RENDER_TARGET_VIEW_DESC desc;
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
desc.Texture2D.MipSlice = 0;
ASSERT_HRESULT_SUCCEEDED(d3d11_device->CreateRenderTargetView(
update_texture.Get(), &desc, &rtv));
immediate_context->ClearRenderTargetView(rtv.Get(), initial_color.vec());
ASSERT_HRESULT_SUCCEEDED(root_surface->EndDraw());
std::unique_ptr<DCLayerOverlayParams> params =
std::make_unique<DCLayerOverlayParams>();
params->z_order = 0;
params->quad_rect = gfx::Rect(window_size);
params->content_rect = params->quad_rect;
params->overlay_image = DCLayerOverlayImage(window_size, root_surface,
0);
EXPECT_TRUE(presenter_->ScheduleDCLayer(std::move(params)));
}
void InitializeForPixelTest(const gfx::Size& window_size,
const gfx::Size& texture_size,
const gfx::Rect& content_rect,
const gfx::Rect& quad_rect) {
EXPECT_TRUE(presenter_->Resize(window_size, 1.0, gfx::ColorSpace(), true));
InitializeRootAndScheduleRootSurface(window_size, SkColors::kBlack);
Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
QueryD3D11DeviceObjectFromANGLE();
Microsoft::WRL::ComPtr<ID3D11Texture2D> texture =
CreateNV12Texture(d3d11_device, texture_size);
ASSERT_NE(texture, nullptr);
auto params = std::make_unique<DCLayerOverlayParams>();
params->overlay_image.emplace(texture_size, texture);
params->content_rect = content_rect;
params->quad_rect = quad_rect;
params->color_space = gfx::ColorSpace::CreateREC709();
presenter_->ScheduleDCLayer(std::move(params));
PresentAndCheckSwapResult(gfx::SwapResult::SWAP_ACK);
Sleep(1000);
}
TestPlatformDelegate platform_delegate_;
ui::WinWindow window_;
};
class DCompPresenterVideoPixelTest : public DCompPresenterPixelTest {
protected:
void TestVideo(const gfx::ColorSpace& color_space,
SkColor expected_color,
bool check_color) {
if (!presenter_) {
return;
}
gfx::Size window_size(100, 100);
EXPECT_TRUE(presenter_->Resize(window_size, 1.0, gfx::ColorSpace(), true));
Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
QueryD3D11DeviceObjectFromANGLE();
gfx::Size texture_size(50, 50);
Microsoft::WRL::ComPtr<ID3D11Texture2D> texture =
CreateNV12Texture(d3d11_device, texture_size);
ASSERT_NE(texture, nullptr);
{
auto params = std::make_unique<DCLayerOverlayParams>();
params->overlay_image.emplace(texture_size, texture);
params->content_rect = gfx::Rect(texture_size);
params->quad_rect = gfx::Rect(texture_size);
params->color_space = color_space;
presenter_->ScheduleDCLayer(std::move(params));
}
PresentAndCheckSwapResult(gfx::SwapResult::SWAP_ACK);
{
auto params = std::make_unique<DCLayerOverlayParams>();
params->overlay_image.emplace(texture_size, texture);
params->content_rect = gfx::Rect(texture_size);
params->quad_rect = gfx::Rect(window_size);
params->color_space = color_space;
presenter_->ScheduleDCLayer(std::move(params));
}
PresentAndCheckSwapResult(gfx::SwapResult::SWAP_ACK);
Sleep(1000);
if (check_color) {
EXPECT_SKCOLOR_CLOSE(
expected_color,
GLTestHelper::ReadBackWindowPixel(window_.hwnd(), gfx::Point(75, 75)),
kMaxColorChannelDeviation);
}
}
};
TEST_F(DCompPresenterVideoPixelTest, BT601) {
TestVideo(gfx::ColorSpace::CreateREC601(), SkColorSetRGB(0xdb, 0x81, 0xe8),
true);
}
TEST_F(DCompPresenterVideoPixelTest, BT709) {
TestVideo(gfx::ColorSpace::CreateREC709(), SkColorSetRGB(0xe1, 0x90, 0xeb),
true);
}
TEST_F(DCompPresenterVideoPixelTest, SRGB) {
TestVideo(gfx::ColorSpace::CreateSRGB(), SK_ColorTRANSPARENT, false);
}
TEST_F(DCompPresenterVideoPixelTest, SCRGBLinear) {
TestVideo(gfx::ColorSpace::CreateSRGBLinear(), SK_ColorTRANSPARENT, false);
}
TEST_F(DCompPresenterVideoPixelTest, InvalidColorSpace) {
TestVideo(gfx::ColorSpace(), SkColorSetRGB(0xe1, 0x90, 0xeb), true);
}
TEST_F(DCompPresenterPixelTest, SoftwareVideoSwapchain) {
if (!presenter_) {
return;
}
gfx::Size window_size(100, 100);
EXPECT_TRUE(presenter_->Resize(window_size, 1.0, gfx::ColorSpace(), true));
Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
QueryD3D11DeviceObjectFromANGLE();
gfx::Size y_size(50, 50);
size_t stride = y_size.width();
std::vector<uint8_t> nv12_pixmap(stride * 3 * y_size.height() / 2, 0xff);
auto params = std::make_unique<DCLayerOverlayParams>();
params->overlay_image =
DCLayerOverlayImage(y_size, nv12_pixmap.data(), stride);
params->content_rect = gfx::Rect(y_size);
params->quad_rect = gfx::Rect(window_size);
params->color_space = gfx::ColorSpace::CreateREC709();
presenter_->ScheduleDCLayer(std::move(params));
PresentAndCheckSwapResult(gfx::SwapResult::SWAP_ACK);
Sleep(1000);
SkColor expected_color = SkColorSetRGB(0xff, 0xb7, 0xff);
EXPECT_SKCOLOR_CLOSE(
expected_color,
GLTestHelper::ReadBackWindowPixel(window_.hwnd(), gfx::Point(75, 75)),
kMaxColorChannelDeviation);
}
TEST_F(DCompPresenterPixelTest, VideoHandleSwapchain) {
if (!presenter_) {
return;
}
gfx::Size window_size(100, 100);
gfx::Size texture_size(50, 50);
gfx::Rect content_rect(texture_size);
gfx::Rect quad_rect(window_size);
InitializeForPixelTest(window_size, texture_size, content_rect, quad_rect);
SkColor expected_color = SkColorSetRGB(0xe1, 0x90, 0xeb);
EXPECT_SKCOLOR_CLOSE(
expected_color,
GLTestHelper::ReadBackWindowPixel(window_.hwnd(), gfx::Point(75, 75)),
kMaxColorChannelDeviation);
}
TEST_F(DCompPresenterPixelTest, SkipVideoLayerEmptyBoundsRect) {
if (!presenter_) {
return;
}
gfx::Size window_size(100, 100);
gfx::Size texture_size(50, 50);
gfx::Rect content_rect(texture_size);
gfx::Rect quad_rect;
InitializeForPixelTest(window_size, texture_size, content_rect, quad_rect);
SkColor expected_color = SK_ColorBLACK;
EXPECT_SKCOLOR_CLOSE(
expected_color,
GLTestHelper::ReadBackWindowPixel(window_.hwnd(), gfx::Point(75, 75)),
kMaxColorChannelDeviation);
}
TEST_F(DCompPresenterPixelTest, SkipVideoLayerEmptyContentsRect) {
if (!presenter_) {
return;
}
SetDirectCompositionScaledOverlaysSupportedForTesting(true);
gfx::Size window_size(100, 100);
EXPECT_TRUE(presenter_->Resize(window_size, 1.0, gfx::ColorSpace(), true));
EXPECT_TRUE(presenter_->SetDrawRectangle(gfx::Rect(window_size)));
InitializeRootAndScheduleRootSurface(window_size, SkColors::kBlack);
Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
QueryD3D11DeviceObjectFromANGLE();
gfx::Size texture_size(50, 50);
Microsoft::WRL::ComPtr<ID3D11Texture2D> texture =
CreateNV12Texture(d3d11_device, texture_size);
ASSERT_NE(texture, nullptr);
auto params = std::make_unique<DCLayerOverlayParams>();
params->overlay_image.emplace(texture_size, texture);
params->quad_rect = gfx::Rect(window_size);
params->color_space = gfx::ColorSpace::CreateREC709();
presenter_->ScheduleDCLayer(std::move(params));
PresentAndCheckSwapResult(gfx::SwapResult::SWAP_ACK);
Sleep(1000);
SkColor expected_color = SK_ColorBLACK;
EXPECT_SKCOLOR_CLOSE(
expected_color,
GLTestHelper::ReadBackWindowPixel(window_.hwnd(), gfx::Point(75, 75)),
kMaxColorChannelDeviation);
}
TEST_F(DCompPresenterPixelTest, NV12SwapChain) {
if (!presenter_) {
return;
}
SetDirectCompositionScaledOverlaysSupportedForTesting(true);
gfx::Size window_size(100, 100);
gfx::Size texture_size(50, 50);
gfx::Rect content_rect(0, 0, 49, 49);
gfx::Rect quad_rect(window_size);
InitializeForPixelTest(window_size, texture_size, content_rect, quad_rect);
Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain =
presenter_->GetLayerSwapChainForTesting(0);
ASSERT_TRUE(swap_chain);
DXGI_SWAP_CHAIN_DESC1 desc;
EXPECT_HRESULT_SUCCEEDED(swap_chain->GetDesc1(&desc));
EXPECT_EQ(DXGI_FORMAT_NV12, desc.Format);
EXPECT_EQ(100u, desc.Width);
EXPECT_EQ(100u, desc.Height);
SkColor expected_color = SkColorSetRGB(0xe1, 0x90, 0xeb);
EXPECT_SKCOLOR_CLOSE(
expected_color,
GLTestHelper::ReadBackWindowPixel(window_.hwnd(), gfx::Point(75, 75)),
kMaxColorChannelDeviation);
}
TEST_F(DCompPresenterPixelTest, YUY2SwapChain) {
if (!presenter_) {
return;
}
if (context_ && context_->GetVersionInfo() &&
context_->GetVersionInfo()->driver_vendor.find("AMD") !=
std::string::npos)
return;
SetDirectCompositionScaledOverlaysSupportedForTesting(true);
SetDirectCompositionOverlayFormatUsedForTesting(DXGI_FORMAT_YUY2);
gfx::Size window_size(100, 100);
gfx::Size texture_size(50, 50);
gfx::Rect content_rect(0, 0, 49, 49);
gfx::Rect quad_rect(window_size);
InitializeForPixelTest(window_size, texture_size, content_rect, quad_rect);
Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain =
presenter_->GetLayerSwapChainForTesting(0);
ASSERT_TRUE(swap_chain);
DXGI_SWAP_CHAIN_DESC1 desc;
EXPECT_HRESULT_SUCCEEDED(swap_chain->GetDesc1(&desc));
EXPECT_EQ(DXGI_FORMAT_YUY2, desc.Format);
EXPECT_EQ(100u, desc.Width);
EXPECT_EQ(100u, desc.Height);
SkColor expected_color = SkColorSetRGB(0xe1, 0x90, 0xeb);
EXPECT_SKCOLOR_CLOSE(
expected_color,
GLTestHelper::ReadBackWindowPixel(window_.hwnd(), gfx::Point(75, 75)),
kMaxColorChannelDeviation);
}
TEST_F(DCompPresenterPixelTest, NonZeroBoundsOffset) {
if (!presenter_) {
return;
}
SetDirectCompositionScaledOverlaysSupportedForTesting(true);
gfx::Size window_size(100, 100);
gfx::Size texture_size(50, 50);
gfx::Rect content_rect(texture_size);
gfx::Rect quad_rect(gfx::Point(25, 25), texture_size);
InitializeForPixelTest(window_size, texture_size, content_rect, quad_rect);
SkColor video_color = SkColorSetRGB(0xe1, 0x90, 0xeb);
struct {
gfx::Point point;
SkColor expected_color;
} test_cases[] = {
{{24, 24}, SK_ColorBLACK},
{{75, 75}, SK_ColorBLACK},
{{25, 25}, video_color},
{{74, 74}, video_color},
};
auto pixels = GLTestHelper::ReadBackWindow(window_.hwnd(), window_size);
for (const auto& test_case : test_cases) {
const auto& point = test_case.point;
const auto& expected_color = test_case.expected_color;
EXPECT_SKCOLOR_CLOSE(expected_color, pixels.GetPixel(point),
kMaxColorChannelDeviation)
<< " at " << point.ToString();
}
}
TEST_F(DCompPresenterPixelTest, ResizeVideoLayer) {
if (!presenter_) {
return;
}
SetDirectCompositionScaledOverlaysSupportedForTesting(true);
gfx::Size window_size(100, 100);
EXPECT_TRUE(presenter_->Resize(window_size, 1.0, gfx::ColorSpace(), true));
EXPECT_TRUE(presenter_->SetDrawRectangle(gfx::Rect(window_size)));
InitializeRootAndScheduleRootSurface(window_size, SkColors::kBlack);
Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
QueryD3D11DeviceObjectFromANGLE();
gfx::Size texture_size(50, 50);
Microsoft::WRL::ComPtr<ID3D11Texture2D> texture =
CreateNV12Texture(d3d11_device, texture_size);
ASSERT_NE(texture, nullptr);
{
auto params = std::make_unique<DCLayerOverlayParams>();
params->overlay_image.emplace(texture_size, texture);
params->content_rect = gfx::Rect(texture_size);
params->quad_rect = gfx::Rect(window_size);
params->color_space = gfx::ColorSpace::CreateREC709();
presenter_->ScheduleDCLayer(std::move(params));
PresentAndCheckSwapResult(gfx::SwapResult::SWAP_ACK);
}
Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain =
presenter_->GetLayerSwapChainForTesting(0);
ASSERT_TRUE(swap_chain);
DXGI_SWAP_CHAIN_DESC1 desc;
EXPECT_HRESULT_SUCCEEDED(swap_chain->GetDesc1(&desc));
EXPECT_EQ(100u, desc.Width);
EXPECT_EQ(100u, desc.Height);
{
auto params = std::make_unique<DCLayerOverlayParams>();
params->overlay_image.emplace(texture_size, texture);
params->content_rect = gfx::Rect(30, 30);
params->quad_rect = gfx::Rect(window_size);
params->color_space = gfx::ColorSpace::CreateREC709();
presenter_->ScheduleDCLayer(std::move(params));
PresentAndCheckSwapResult(gfx::SwapResult::SWAP_ACK);
}
swap_chain = presenter_->GetLayerSwapChainForTesting(0);
EXPECT_HRESULT_SUCCEEDED(swap_chain->GetDesc1(&desc));
EXPECT_EQ(100u, desc.Width);
EXPECT_EQ(100u, desc.Height);
SetDirectCompositionScaledOverlaysSupportedForTesting(false);
gfx::Size monitor_size = window_size;
SetDirectCompositionMonitorInfoForTesting(1, window_size);
gfx::Rect on_screen_rect =
gfx::Rect(0, 0, monitor_size.width() - 2, monitor_size.height() - 2);
{
auto params = std::make_unique<DCLayerOverlayParams>();
params->overlay_image.emplace(texture_size, texture);
params->content_rect = gfx::Rect(50, 50);
params->quad_rect = on_screen_rect;
params->clip_rect = on_screen_rect;
params->color_space = gfx::ColorSpace::CreateREC709();
presenter_->ScheduleDCLayer(std::move(params));
PresentAndCheckSwapResult(gfx::SwapResult::SWAP_ACK);
}
swap_chain = presenter_->GetLayerSwapChainForTesting(0);
EXPECT_HRESULT_SUCCEEDED(swap_chain->GetDesc1(&desc));
EXPECT_EQ(static_cast<UINT>(monitor_size.width()), desc.Width);
EXPECT_EQ(static_cast<UINT>(monitor_size.height()), desc.Height);
gfx::Transform transform;
gfx::Point offset;
gfx::Rect clip_rect;
presenter_->GetSwapChainVisualInfoForTesting(0, &transform, &offset,
&clip_rect);
EXPECT_TRUE(transform.IsIdentity());
EXPECT_EQ(gfx::Rect(monitor_size), clip_rect);
SetDirectCompositionScaledOverlaysSupportedForTesting(true);
on_screen_rect =
gfx::Rect(0, 0, monitor_size.width() + 2, monitor_size.height() + 2);
{
auto params = std::make_unique<DCLayerOverlayParams>();
params->overlay_image.emplace(texture_size, texture);
params->content_rect = gfx::Rect(50, 50);
params->quad_rect = on_screen_rect;
params->color_space = gfx::ColorSpace::CreateREC709();
presenter_->ScheduleDCLayer(std::move(params));
PresentAndCheckSwapResult(gfx::SwapResult::SWAP_ACK);
}
swap_chain = presenter_->GetLayerSwapChainForTesting(0);
EXPECT_HRESULT_SUCCEEDED(swap_chain->GetDesc1(&desc));
EXPECT_EQ(100u, desc.Width);
EXPECT_EQ(100u, desc.Height);
presenter_->GetSwapChainVisualInfoForTesting(0, &transform, &offset,
&clip_rect);
EXPECT_EQ(gfx::Rect(monitor_size), transform.MapRect(gfx::Rect(100, 100)));
}
TEST_F(DCompPresenterPixelTest, SwapChainImage) {
if (!presenter_) {
return;
}
if (context_ && context_->GetVersionInfo() &&
context_->GetVersionInfo()->driver_vendor.find("AMD") !=
std::string::npos)
return;
Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
QueryD3D11DeviceObjectFromANGLE();
ASSERT_TRUE(d3d11_device);
Microsoft::WRL::ComPtr<IDXGIDevice> dxgi_device;
d3d11_device.As(&dxgi_device);
ASSERT_TRUE(dxgi_device);
Microsoft::WRL::ComPtr<IDXGIAdapter> dxgi_adapter;
dxgi_device->GetAdapter(&dxgi_adapter);
ASSERT_TRUE(dxgi_adapter);
Microsoft::WRL::ComPtr<IDXGIFactory2> dxgi_factory;
dxgi_adapter->GetParent(IID_PPV_ARGS(&dxgi_factory));
ASSERT_TRUE(dxgi_factory);
gfx::Size swap_chain_size(50, 50);
DXGI_SWAP_CHAIN_DESC1 desc = {};
desc.Width = swap_chain_size.width();
desc.Height = swap_chain_size.height();
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
desc.Stereo = FALSE;
desc.SampleDesc.Count = 1;
desc.BufferCount = 2;
desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_SHADER_INPUT;
desc.Scaling = DXGI_SCALING_STRETCH;
desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
desc.Flags = 0;
Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain;
ASSERT_HRESULT_SUCCEEDED(dxgi_factory->CreateSwapChainForComposition(
d3d11_device.Get(), &desc, nullptr, &swap_chain));
ASSERT_TRUE(swap_chain);
Microsoft::WRL::ComPtr<ID3D11Texture2D> front_buffer_texture;
ASSERT_HRESULT_SUCCEEDED(
swap_chain->GetBuffer(1u, IID_PPV_ARGS(&front_buffer_texture)));
ASSERT_TRUE(front_buffer_texture);
Microsoft::WRL::ComPtr<ID3D11Texture2D> back_buffer_texture;
ASSERT_TRUE(
SUCCEEDED(swap_chain->GetBuffer(0u, IID_PPV_ARGS(&back_buffer_texture))));
ASSERT_TRUE(back_buffer_texture);
Microsoft::WRL::ComPtr<ID3D11RenderTargetView> rtv;
ASSERT_HRESULT_SUCCEEDED(d3d11_device->CreateRenderTargetView(
back_buffer_texture.Get(), nullptr, &rtv));
ASSERT_TRUE(rtv);
Microsoft::WRL::ComPtr<ID3D11DeviceContext> context;
d3d11_device->GetImmediateContext(&context);
ASSERT_TRUE(context);
gfx::Size window_size(100, 100);
EXPECT_TRUE(presenter_->Resize(window_size, 1.0, gfx::ColorSpace(), true));
EXPECT_TRUE(presenter_->SetDrawRectangle(gfx::Rect(window_size)));
InitializeRootAndScheduleRootSurface(window_size, SkColors::kBlack);
DXGI_PRESENT_PARAMETERS present_params = {};
present_params.DirtyRectsCount = 0;
present_params.pDirtyRects = nullptr;
{
float clear_color[] = {1.0, 0.0, 0.0, 1.0};
context->ClearRenderTargetView(rtv.Get(), clear_color);
ASSERT_HRESULT_SUCCEEDED(swap_chain->Present1(0, 0, &present_params));
auto dc_layer_params = std::make_unique<DCLayerOverlayParams>();
dc_layer_params->overlay_image =
DCLayerOverlayImage(swap_chain_size, swap_chain);
dc_layer_params->content_rect = gfx::Rect(swap_chain_size);
dc_layer_params->quad_rect = gfx::Rect(window_size);
dc_layer_params->color_space = gfx::ColorSpace::CreateSRGB();
dc_layer_params->z_order = 1;
presenter_->ScheduleDCLayer(std::move(dc_layer_params));
PresentAndCheckSwapResult(gfx::SwapResult::SWAP_ACK);
SkColor expected_color = SK_ColorRED;
EXPECT_SKCOLOR_CLOSE(
expected_color,
GLTestHelper::ReadBackWindowPixel(window_.hwnd(), gfx::Point(75, 75)),
kMaxColorChannelDeviation);
}
{
float clear_color[] = {0.0, 1.0, 0.0, 1.0};
context->ClearRenderTargetView(rtv.Get(), clear_color);
ASSERT_HRESULT_SUCCEEDED(swap_chain->Present1(0, 0, &present_params));
auto dc_layer_params = std::make_unique<DCLayerOverlayParams>();
dc_layer_params->overlay_image =
DCLayerOverlayImage(swap_chain_size, swap_chain);
dc_layer_params->content_rect = gfx::Rect(swap_chain_size);
dc_layer_params->quad_rect = gfx::Rect(window_size);
dc_layer_params->color_space = gfx::ColorSpace::CreateSRGB();
presenter_->ScheduleDCLayer(std::move(dc_layer_params));
PresentAndCheckSwapResult(gfx::SwapResult::SWAP_ACK);
SkColor expected_color = SK_ColorGREEN;
EXPECT_SKCOLOR_CLOSE(
expected_color,
GLTestHelper::ReadBackWindowPixel(window_.hwnd(), gfx::Point(75, 75)),
kMaxColorChannelDeviation);
}
{
ASSERT_HRESULT_SUCCEEDED(swap_chain->Present1(0, 0, &present_params));
auto dc_layer_params = std::make_unique<DCLayerOverlayParams>();
dc_layer_params->overlay_image =
DCLayerOverlayImage(swap_chain_size, swap_chain);
dc_layer_params->content_rect = gfx::Rect(swap_chain_size);
dc_layer_params->quad_rect = gfx::Rect(window_size);
dc_layer_params->color_space = gfx::ColorSpace::CreateSRGB();
presenter_->ScheduleDCLayer(std::move(dc_layer_params));
PresentAndCheckSwapResult(gfx::SwapResult::SWAP_ACK);
SkColor expected_color = SK_ColorRED;
EXPECT_SKCOLOR_CLOSE(
expected_color,
GLTestHelper::ReadBackWindowPixel(window_.hwnd(), gfx::Point(75, 75)),
kMaxColorChannelDeviation);
}
{
float clear_color[] = {0.0, 0.0, 1.0, 1.0};
context->ClearRenderTargetView(rtv.Get(), clear_color);
auto dc_layer_params = std::make_unique<DCLayerOverlayParams>();
dc_layer_params->overlay_image =
DCLayerOverlayImage(swap_chain_size, swap_chain);
dc_layer_params->content_rect = gfx::Rect(swap_chain_size);
dc_layer_params->quad_rect = gfx::Rect(window_size);
dc_layer_params->color_space = gfx::ColorSpace::CreateSRGB();
presenter_->ScheduleDCLayer(std::move(dc_layer_params));
PresentAndCheckSwapResult(gfx::SwapResult::SWAP_ACK);
SkColor expected_color = SK_ColorRED;
EXPECT_SKCOLOR_CLOSE(
expected_color,
GLTestHelper::ReadBackWindowPixel(window_.hwnd(), gfx::Point(75, 75)),
kMaxColorChannelDeviation);
}
}
TEST_F(DCompPresenterPixelTest, QuadOffsetAppliedAfterTransform) {
if (!presenter_) {
return;
}
if (context_ && context_->GetVersionInfo() &&
context_->GetVersionInfo()->driver_vendor.find("AMD") !=
std::string::npos) {
return;
}
const gfx::Rect quad_rect(gfx::Point(0, 50), gfx::Size(50, 50));
const gfx::Transform quad_to_root_transform(
gfx::AxisTransform2d(0.5, gfx::Vector2dF()));
Microsoft::WRL::ComPtr<IDCompositionDevice2> dcomp_device =
GetDirectCompositionDevice();
Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
QueryD3D11DeviceObjectFromANGLE();
ASSERT_TRUE(d3d11_device);
Microsoft::WRL::ComPtr<ID3D11DeviceContext> context;
d3d11_device->GetImmediateContext(&context);
ASSERT_TRUE(context);
gfx::Size window_size(100, 100);
EXPECT_TRUE(presenter_->Resize(window_size, 1.0, gfx::ColorSpace(), true));
EXPECT_TRUE(presenter_->SetDrawRectangle(gfx::Rect(window_size)));
InitializeRootAndScheduleRootSurface(window_size, SkColors::kBlack);
Microsoft::WRL::ComPtr<IDCompositionSurface> surface;
ASSERT_HRESULT_SUCCEEDED(dcomp_device->CreateSurface(
quad_rect.width(), quad_rect.height(), DXGI_FORMAT_B8G8R8A8_UNORM,
DXGI_ALPHA_MODE_IGNORE, &surface));
RECT update_rect = D2D1::Rect(0, 0, quad_rect.width(), quad_rect.height());
Microsoft::WRL::ComPtr<ID3D11Texture2D> update_texture;
POINT update_offset;
ASSERT_HRESULT_SUCCEEDED(surface->BeginDraw(
&update_rect, IID_PPV_ARGS(&update_texture), &update_offset));
Microsoft::WRL::ComPtr<ID3D11RenderTargetView> rtv;
ASSERT_HRESULT_SUCCEEDED(d3d11_device->CreateRenderTargetView(
update_texture.Get(), nullptr, &rtv));
context->ClearRenderTargetView(rtv.Get(), SkColors::kRed.vec());
ASSERT_HRESULT_SUCCEEDED(surface->EndDraw());
auto dc_layer_params = std::make_unique<DCLayerOverlayParams>();
dc_layer_params->overlay_image =
DCLayerOverlayImage(quad_rect.size(), surface);
dc_layer_params->content_rect = gfx::Rect(quad_rect.size());
dc_layer_params->quad_rect = quad_rect;
dc_layer_params->transform = quad_to_root_transform;
dc_layer_params->color_space = gfx::ColorSpace::CreateSRGB();
dc_layer_params->z_order = 1;
presenter_->ScheduleDCLayer(std::move(dc_layer_params));
PresentAndCheckSwapResult(gfx::SwapResult::SWAP_ACK);
const gfx::Rect mapped_quad_rect = quad_to_root_transform.MapRect(quad_rect);
GLTestHelper::WindowPixels pixels =
GLTestHelper::ReadBackWindow(window_.hwnd(), window_size);
EXPECT_SKCOLOR_CLOSE(SK_ColorBLACK,
pixels.GetPixel(gfx::Point(0, mapped_quad_rect.y() - 1)),
kMaxColorChannelDeviation);
EXPECT_SKCOLOR_CLOSE(SK_ColorRED,
GLTestHelper::ReadBackWindowPixel(
window_.hwnd(), gfx::Point(0, mapped_quad_rect.y())),
kMaxColorChannelDeviation);
EXPECT_SKCOLOR_CLOSE(
SK_ColorRED,
pixels.GetPixel(gfx::Point(0, mapped_quad_rect.bottom() - 1)),
kMaxColorChannelDeviation);
EXPECT_SKCOLOR_CLOSE(
SK_ColorBLACK, pixels.GetPixel(gfx::Point(0, mapped_quad_rect.bottom())),
kMaxColorChannelDeviation);
}
class DCompPresenterBufferCountTest : public DCompPresenterTest,
public testing::WithParamInterface<bool> {
public:
static const char* GetParamName(
const testing::TestParamInfo<ParamType>& info) {
return info.param ? "DCompTripleBufferVideoSwapChain" : "default";
}
protected:
void SetUp() override {
if (GetParam()) {
enabled_features_.InitWithFeatures(
{features::kDCompTripleBufferVideoSwapChain}, {});
} else {
enabled_features_.InitWithFeatures(
{}, {features::kDCompTripleBufferVideoSwapChain});
}
DCompPresenterTest::SetUp();
}
base::test::ScopedFeatureList enabled_features_;
};
TEST_P(DCompPresenterBufferCountTest, VideoSwapChainBufferCount) {
if (!presenter_) {
return;
}
SetDirectCompositionScaledOverlaysSupportedForTesting(true);
constexpr gfx::Size window_size(100, 100);
EXPECT_TRUE(presenter_->Resize(window_size, 1.0, gfx::ColorSpace(), true));
EXPECT_TRUE(presenter_->SetDrawRectangle(gfx::Rect(window_size)));
constexpr gfx::Size texture_size(50, 50);
Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
QueryD3D11DeviceObjectFromANGLE();
ASSERT_TRUE(d3d11_device);
Microsoft::WRL::ComPtr<ID3D11Texture2D> texture =
CreateNV12Texture(d3d11_device, texture_size);
ASSERT_NE(texture, nullptr);
auto params = std::make_unique<DCLayerOverlayParams>();
params->overlay_image.emplace(texture_size, texture);
params->content_rect = gfx::Rect(texture_size);
params->quad_rect = gfx::Rect(window_size);
params->color_space = gfx::ColorSpace::CreateREC709();
EXPECT_TRUE(presenter_->ScheduleDCLayer(std::move(params)));
PresentAndCheckSwapResult(gfx::SwapResult::SWAP_ACK);
auto swap_chain = presenter_->GetLayerSwapChainForTesting(0);
ASSERT_TRUE(swap_chain);
DXGI_SWAP_CHAIN_DESC1 desc;
EXPECT_HRESULT_SUCCEEDED(swap_chain->GetDesc1(&desc));
EXPECT_EQ(100u, desc.Width);
EXPECT_EQ(100u, desc.Height);
if (GetParam()) {
EXPECT_EQ(3u, desc.BufferCount);
} else {
EXPECT_EQ(2u, desc.BufferCount);
}
}
INSTANTIATE_TEST_SUITE_P(All,
DCompPresenterBufferCountTest,
testing::Bool(),
&DCompPresenterBufferCountTest::GetParamName);
}