direct_composition_surface_win_unittest.cc 58 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597
  1. // Copyright 2017 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ui/gl/direct_composition_surface_win.h"
  5. #include <wrl/client.h>
  6. #include <wrl/implements.h>
  7. #include "base/callback_helpers.h"
  8. #include "base/memory/raw_ptr.h"
  9. #include "base/memory/ref_counted_memory.h"
  10. #include "base/memory/weak_ptr.h"
  11. #include "base/run_loop.h"
  12. #include "base/synchronization/waitable_event.h"
  13. #include "base/test/power_monitor_test.h"
  14. #include "base/test/scoped_feature_list.h"
  15. #include "base/threading/thread_task_runner_handle.h"
  16. #include "base/win/scoped_gdi_object.h"
  17. #include "base/win/scoped_hdc.h"
  18. #include "base/win/scoped_select_object.h"
  19. #include "testing/gtest/include/gtest/gtest.h"
  20. #include "ui/base/win/hidden_window.h"
  21. #include "ui/gfx/buffer_format_util.h"
  22. #include "ui/gfx/gdi_util.h"
  23. #include "ui/gfx/geometry/rect_conversions.h"
  24. #include "ui/gfx/geometry/transform.h"
  25. #include "ui/gl/dc_renderer_layer_params.h"
  26. #include "ui/gl/direct_composition_child_surface_win.h"
  27. #include "ui/gl/direct_composition_support.h"
  28. #include "ui/gl/gl_angle_util_win.h"
  29. #include "ui/gl/gl_bindings.h"
  30. #include "ui/gl/gl_context.h"
  31. #include "ui/gl/gl_image_d3d.h"
  32. #include "ui/gl/gl_image_dxgi.h"
  33. #include "ui/gl/gl_image_ref_counted_memory.h"
  34. #include "ui/gl/gl_switches.h"
  35. #include "ui/gl/gl_version_info.h"
  36. #include "ui/gl/init/gl_factory.h"
  37. #include "ui/platform_window/platform_window_delegate.h"
  38. #include "ui/platform_window/win/win_window.h"
  39. namespace gl {
  40. namespace {
  41. class TestPlatformDelegate : public ui::PlatformWindowDelegate {
  42. public:
  43. // ui::PlatformWindowDelegate implementation.
  44. void OnBoundsChanged(const BoundsChange& change) override {}
  45. void OnDamageRect(const gfx::Rect& damaged_region) override {}
  46. void DispatchEvent(ui::Event* event) override {}
  47. void OnCloseRequest() override {}
  48. void OnClosed() override {}
  49. void OnWindowStateChanged(ui::PlatformWindowState old_state,
  50. ui::PlatformWindowState new_state) override {}
  51. void OnLostCapture() override {}
  52. void OnAcceleratedWidgetAvailable(gfx::AcceleratedWidget widget) override {}
  53. void OnWillDestroyAcceleratedWidget() override {}
  54. void OnAcceleratedWidgetDestroyed() override {}
  55. void OnActivationChanged(bool active) override {}
  56. void OnMouseEnter() override {}
  57. };
  58. void RunPendingTasks(scoped_refptr<base::TaskRunner> task_runner) {
  59. base::WaitableEvent done(base::WaitableEvent::ResetPolicy::AUTOMATIC,
  60. base::WaitableEvent::InitialState::NOT_SIGNALED);
  61. task_runner->PostTask(
  62. FROM_HERE, BindOnce(&base::WaitableEvent::Signal, Unretained(&done)));
  63. done.Wait();
  64. }
  65. void DestroySurface(scoped_refptr<DirectCompositionSurfaceWin> surface) {
  66. scoped_refptr<base::TaskRunner> task_runner =
  67. surface->GetWindowTaskRunnerForTesting();
  68. DCHECK(surface->HasOneRef());
  69. surface = nullptr;
  70. // Ensure that the ChildWindowWin posts the task to delete the thread to the
  71. // main loop before doing RunUntilIdle. Otherwise the child threads could
  72. // outlive the main thread.
  73. RunPendingTasks(task_runner);
  74. base::RunLoop().RunUntilIdle();
  75. }
  76. Microsoft::WRL::ComPtr<ID3D11Texture2D> CreateNV12Texture(
  77. const Microsoft::WRL::ComPtr<ID3D11Device>& d3d11_device,
  78. const gfx::Size& size,
  79. bool shared) {
  80. D3D11_TEXTURE2D_DESC desc = {};
  81. desc.Width = size.width();
  82. desc.Height = size.height();
  83. desc.MipLevels = 1;
  84. desc.ArraySize = 1;
  85. desc.Format = DXGI_FORMAT_NV12;
  86. desc.Usage = D3D11_USAGE_DEFAULT;
  87. desc.SampleDesc.Count = 1;
  88. desc.BindFlags = 0;
  89. if (shared) {
  90. desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX |
  91. D3D11_RESOURCE_MISC_SHARED_NTHANDLE;
  92. }
  93. std::vector<char> image_data(size.width() * size.height() * 3 / 2);
  94. // Y, U, and V should all be 160. Output color should be pink.
  95. memset(&image_data[0], 160, size.width() * size.height() * 3 / 2);
  96. D3D11_SUBRESOURCE_DATA data = {};
  97. data.pSysMem = (const void*)&image_data[0];
  98. data.SysMemPitch = size.width();
  99. Microsoft::WRL::ComPtr<ID3D11Texture2D> texture;
  100. HRESULT hr = d3d11_device->CreateTexture2D(&desc, &data, &texture);
  101. CHECK(SUCCEEDED(hr));
  102. return texture;
  103. }
  104. class DirectCompositionSurfaceTest : public testing::Test {
  105. public:
  106. DirectCompositionSurfaceTest() : parent_window_(ui::GetHiddenWindow()) {}
  107. protected:
  108. void SetUp() override {
  109. // These tests are assumed to run on battery.
  110. fake_power_monitor_source_.SetOnBatteryPower(true);
  111. // Without this, the following check always fails.
  112. display_ = gl::init::InitializeGLNoExtensionsOneOff(
  113. /*init_bindings=*/true, /*system_device_id=*/0);
  114. if (!DirectCompositionSupported()) {
  115. LOG(WARNING) << "DirectComposition not supported, skipping test.";
  116. return;
  117. }
  118. surface_ = CreateDirectCompositionSurfaceWin();
  119. context_ = CreateGLContext(surface_);
  120. if (surface_)
  121. surface_->SetEnableDCLayers(true);
  122. SetDirectCompositionScaledOverlaysSupportedForTesting(false);
  123. SetDirectCompositionOverlayFormatUsedForTesting(DXGI_FORMAT_NV12);
  124. }
  125. void TearDown() override {
  126. context_ = nullptr;
  127. if (surface_)
  128. DestroySurface(std::move(surface_));
  129. gl::init::ShutdownGL(display_, false);
  130. }
  131. scoped_refptr<DirectCompositionSurfaceWin>
  132. CreateDirectCompositionSurfaceWin() {
  133. DirectCompositionSurfaceWin::Settings settings;
  134. scoped_refptr<DirectCompositionSurfaceWin> surface =
  135. base::MakeRefCounted<DirectCompositionSurfaceWin>(
  136. gl::GLSurfaceEGL::GetGLDisplayEGL(), parent_window_,
  137. DirectCompositionSurfaceWin::VSyncCallback(), settings);
  138. EXPECT_TRUE(surface->Initialize(GLSurfaceFormat()));
  139. // ImageTransportSurfaceDelegate::DidCreateAcceleratedSurfaceChildWindow()
  140. // is called in production code here. However, to remove dependency from
  141. // gpu/ipc/service/image_transport_surface_delegate.h, here we directly
  142. // executes the required minimum code.
  143. if (parent_window_)
  144. ::SetParent(surface->window(), parent_window_);
  145. return surface;
  146. }
  147. scoped_refptr<GLContext> CreateGLContext(
  148. scoped_refptr<DirectCompositionSurfaceWin> surface) {
  149. scoped_refptr<GLContext> context =
  150. gl::init::CreateGLContext(nullptr, surface.get(), GLContextAttribs());
  151. EXPECT_TRUE(context->MakeCurrent(surface.get()));
  152. return context;
  153. }
  154. HWND parent_window_;
  155. scoped_refptr<DirectCompositionSurfaceWin> surface_;
  156. scoped_refptr<GLContext> context_;
  157. base::test::ScopedPowerMonitorTestSource fake_power_monitor_source_;
  158. raw_ptr<GLDisplay> display_ = nullptr;
  159. };
  160. TEST_F(DirectCompositionSurfaceTest, TestMakeCurrent) {
  161. if (!surface_)
  162. return;
  163. EXPECT_TRUE(
  164. surface_->Resize(gfx::Size(100, 100), 1.0, gfx::ColorSpace(), true));
  165. // First SetDrawRectangle must be full size of surface.
  166. EXPECT_FALSE(surface_->SetDrawRectangle(gfx::Rect(0, 0, 50, 50)));
  167. EXPECT_TRUE(surface_->SetDrawRectangle(gfx::Rect(0, 0, 100, 100)));
  168. // SetDrawRectangle can't be called again until swap.
  169. EXPECT_FALSE(surface_->SetDrawRectangle(gfx::Rect(0, 0, 100, 100)));
  170. EXPECT_EQ(gfx::SwapResult::SWAP_ACK,
  171. surface_->SwapBuffers(base::DoNothing()));
  172. EXPECT_TRUE(context_->IsCurrent(surface_.get()));
  173. // SetDrawRectangle must be contained within surface.
  174. EXPECT_FALSE(surface_->SetDrawRectangle(gfx::Rect(0, 0, 101, 101)));
  175. EXPECT_TRUE(surface_->SetDrawRectangle(gfx::Rect(0, 0, 100, 100)));
  176. EXPECT_TRUE(context_->IsCurrent(surface_.get()));
  177. EXPECT_TRUE(
  178. surface_->Resize(gfx::Size(50, 50), 1.0, gfx::ColorSpace(), true));
  179. EXPECT_TRUE(context_->IsCurrent(surface_.get()));
  180. EXPECT_TRUE(surface_->SetDrawRectangle(gfx::Rect(0, 0, 50, 50)));
  181. EXPECT_TRUE(context_->IsCurrent(surface_.get()));
  182. scoped_refptr<DirectCompositionSurfaceWin> surface2 =
  183. CreateDirectCompositionSurfaceWin();
  184. scoped_refptr<GLContext> context2 = CreateGLContext(surface2.get());
  185. surface2->SetEnableDCLayers(true);
  186. EXPECT_TRUE(
  187. surface2->Resize(gfx::Size(100, 100), 1.0, gfx::ColorSpace(), true));
  188. // The previous IDCompositionSurface should be suspended when another
  189. // surface is being drawn to.
  190. EXPECT_TRUE(surface2->SetDrawRectangle(gfx::Rect(0, 0, 100, 100)));
  191. EXPECT_TRUE(context2->IsCurrent(surface2.get()));
  192. // It should be possible to switch back to the previous surface and
  193. // unsuspend it.
  194. EXPECT_TRUE(context_->MakeCurrent(surface_.get()));
  195. context2 = nullptr;
  196. DestroySurface(std::move(surface2));
  197. }
  198. // Tests that switching using EnableDCLayers works.
  199. TEST_F(DirectCompositionSurfaceTest, DXGIDCLayerSwitch) {
  200. if (!surface_)
  201. return;
  202. surface_->SetEnableDCLayers(false);
  203. EXPECT_TRUE(
  204. surface_->Resize(gfx::Size(100, 100), 1.0, gfx::ColorSpace(), true));
  205. EXPECT_FALSE(surface_->GetBackbufferSwapChainForTesting());
  206. // First SetDrawRectangle must be full size of surface for DXGI swapchain.
  207. EXPECT_FALSE(surface_->SetDrawRectangle(gfx::Rect(0, 0, 50, 50)));
  208. EXPECT_TRUE(surface_->SetDrawRectangle(gfx::Rect(0, 0, 100, 100)));
  209. EXPECT_TRUE(surface_->GetBackbufferSwapChainForTesting());
  210. // SetDrawRectangle and SetEnableDCLayers can't be called again until swap.
  211. EXPECT_FALSE(surface_->SetDrawRectangle(gfx::Rect(0, 0, 100, 100)));
  212. EXPECT_EQ(gfx::SwapResult::SWAP_ACK,
  213. surface_->SwapBuffers(base::DoNothing()));
  214. EXPECT_TRUE(context_->IsCurrent(surface_.get()));
  215. surface_->SetEnableDCLayers(true);
  216. // Surface switched to use IDCompositionSurface, so must draw to entire
  217. // surface.
  218. EXPECT_FALSE(surface_->SetDrawRectangle(gfx::Rect(0, 0, 50, 50)));
  219. EXPECT_TRUE(surface_->SetDrawRectangle(gfx::Rect(0, 0, 100, 100)));
  220. EXPECT_FALSE(surface_->GetBackbufferSwapChainForTesting());
  221. EXPECT_EQ(gfx::SwapResult::SWAP_ACK,
  222. surface_->SwapBuffers(base::DoNothing()));
  223. EXPECT_TRUE(context_->IsCurrent(surface_.get()));
  224. surface_->SetEnableDCLayers(false);
  225. // Surface switched to use IDXGISwapChain, so must draw to entire surface.
  226. EXPECT_FALSE(surface_->SetDrawRectangle(gfx::Rect(0, 0, 50, 50)));
  227. EXPECT_TRUE(surface_->SetDrawRectangle(gfx::Rect(0, 0, 100, 100)));
  228. EXPECT_TRUE(surface_->GetBackbufferSwapChainForTesting());
  229. EXPECT_EQ(gfx::SwapResult::SWAP_ACK,
  230. surface_->SwapBuffers(base::DoNothing()));
  231. EXPECT_TRUE(context_->IsCurrent(surface_.get()));
  232. }
  233. // Ensure that the swapchain's alpha is correct.
  234. TEST_F(DirectCompositionSurfaceTest, SwitchAlpha) {
  235. if (!surface_)
  236. return;
  237. surface_->SetEnableDCLayers(false);
  238. EXPECT_TRUE(
  239. surface_->Resize(gfx::Size(100, 100), 1.0, gfx::ColorSpace(), true));
  240. EXPECT_FALSE(surface_->GetBackbufferSwapChainForTesting());
  241. EXPECT_TRUE(surface_->SetDrawRectangle(gfx::Rect(0, 0, 100, 100)));
  242. Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain =
  243. surface_->GetBackbufferSwapChainForTesting();
  244. ASSERT_TRUE(swap_chain);
  245. DXGI_SWAP_CHAIN_DESC1 desc;
  246. swap_chain->GetDesc1(&desc);
  247. EXPECT_EQ(DXGI_ALPHA_MODE_PREMULTIPLIED, desc.AlphaMode);
  248. // Resize to the same parameters should have no effect.
  249. EXPECT_TRUE(
  250. surface_->Resize(gfx::Size(100, 100), 1.0, gfx::ColorSpace(), true));
  251. EXPECT_TRUE(surface_->GetBackbufferSwapChainForTesting());
  252. EXPECT_TRUE(
  253. surface_->Resize(gfx::Size(100, 100), 1.0, gfx::ColorSpace(), false));
  254. EXPECT_FALSE(surface_->GetBackbufferSwapChainForTesting());
  255. EXPECT_TRUE(surface_->SetDrawRectangle(gfx::Rect(0, 0, 100, 100)));
  256. swap_chain = surface_->GetBackbufferSwapChainForTesting();
  257. ASSERT_TRUE(swap_chain);
  258. swap_chain->GetDesc1(&desc);
  259. EXPECT_EQ(DXGI_ALPHA_MODE_IGNORE, desc.AlphaMode);
  260. }
  261. // Ensure that the GLImage isn't presented again unless it changes.
  262. TEST_F(DirectCompositionSurfaceTest, NoPresentTwice) {
  263. if (!surface_)
  264. return;
  265. Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
  266. QueryD3D11DeviceObjectFromANGLE();
  267. gfx::Size texture_size(50, 50);
  268. Microsoft::WRL::ComPtr<ID3D11Texture2D> texture =
  269. CreateNV12Texture(d3d11_device, texture_size, false);
  270. scoped_refptr<GLImageDXGI> image_dxgi(new GLImageDXGI(texture_size, nullptr));
  271. image_dxgi->SetTexture(texture, 0);
  272. image_dxgi->SetColorSpace(gfx::ColorSpace::CreateREC709());
  273. {
  274. std::unique_ptr<ui::DCRendererLayerParams> params =
  275. std::make_unique<ui::DCRendererLayerParams>();
  276. params->images[0] = image_dxgi;
  277. params->content_rect = gfx::Rect(texture_size);
  278. params->quad_rect = gfx::Rect(100, 100);
  279. surface_->ScheduleDCLayer(std::move(params));
  280. }
  281. Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain =
  282. surface_->GetLayerSwapChainForTesting(0);
  283. ASSERT_FALSE(swap_chain);
  284. EXPECT_EQ(gfx::SwapResult::SWAP_ACK,
  285. surface_->SwapBuffers(base::DoNothing()));
  286. swap_chain = surface_->GetLayerSwapChainForTesting(0);
  287. ASSERT_TRUE(swap_chain);
  288. UINT last_present_count = 0;
  289. EXPECT_TRUE(SUCCEEDED(swap_chain->GetLastPresentCount(&last_present_count)));
  290. // One present is normal, and a second present because it's the first frame
  291. // and the other buffer needs to be drawn to.
  292. EXPECT_EQ(2u, last_present_count);
  293. {
  294. std::unique_ptr<ui::DCRendererLayerParams> params =
  295. std::make_unique<ui::DCRendererLayerParams>();
  296. params->images[0] = image_dxgi;
  297. params->content_rect = gfx::Rect(texture_size);
  298. params->quad_rect = gfx::Rect(100, 100);
  299. surface_->ScheduleDCLayer(std::move(params));
  300. }
  301. EXPECT_EQ(gfx::SwapResult::SWAP_ACK,
  302. surface_->SwapBuffers(base::DoNothing()));
  303. Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain2 =
  304. surface_->GetLayerSwapChainForTesting(0);
  305. EXPECT_EQ(swap_chain2.Get(), swap_chain.Get());
  306. // It's the same image, so it should have the same swapchain.
  307. EXPECT_TRUE(SUCCEEDED(swap_chain->GetLastPresentCount(&last_present_count)));
  308. EXPECT_EQ(2u, last_present_count);
  309. // The image changed, we should get a new present
  310. scoped_refptr<GLImageDXGI> image_dxgi2(
  311. new GLImageDXGI(texture_size, nullptr));
  312. image_dxgi2->SetTexture(texture, 0);
  313. image_dxgi2->SetColorSpace(gfx::ColorSpace::CreateREC709());
  314. {
  315. std::unique_ptr<ui::DCRendererLayerParams> params =
  316. std::make_unique<ui::DCRendererLayerParams>();
  317. params->content_rect = gfx::Rect(texture_size);
  318. params->quad_rect = gfx::Rect(100, 100);
  319. params->images[0] = image_dxgi2;
  320. params->images[1] = image_dxgi2;
  321. surface_->ScheduleDCLayer(std::move(params));
  322. }
  323. EXPECT_EQ(gfx::SwapResult::SWAP_ACK,
  324. surface_->SwapBuffers(base::DoNothing()));
  325. Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain3 =
  326. surface_->GetLayerSwapChainForTesting(0);
  327. EXPECT_TRUE(SUCCEEDED(swap_chain3->GetLastPresentCount(&last_present_count)));
  328. // the present count should increase with the new present
  329. EXPECT_EQ(3u, last_present_count);
  330. }
  331. // Ensure the swapchain size is set to the correct size if HW overlay scaling
  332. // is support - swapchain should be set to the onscreen video size.
  333. TEST_F(DirectCompositionSurfaceTest, SwapchainSizeWithScaledOverlays) {
  334. if (!surface_)
  335. return;
  336. Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
  337. QueryD3D11DeviceObjectFromANGLE();
  338. gfx::Size texture_size(64, 64);
  339. Microsoft::WRL::ComPtr<ID3D11Texture2D> texture =
  340. CreateNV12Texture(d3d11_device, texture_size, false);
  341. scoped_refptr<GLImageDXGI> image_dxgi(new GLImageDXGI(texture_size, nullptr));
  342. image_dxgi->SetTexture(texture, 0);
  343. image_dxgi->SetColorSpace(gfx::ColorSpace::CreateREC709());
  344. // HW supports scaled overlays.
  345. // The input texture size is maller than the window size.
  346. SetDirectCompositionScaledOverlaysSupportedForTesting(true);
  347. // Onscreen quad.
  348. gfx::Rect quad_rect = gfx::Rect(100, 100);
  349. {
  350. std::unique_ptr<ui::DCRendererLayerParams> params =
  351. std::make_unique<ui::DCRendererLayerParams>();
  352. params->images[0] = image_dxgi;
  353. params->content_rect = gfx::Rect(texture_size);
  354. params->quad_rect = quad_rect;
  355. surface_->ScheduleDCLayer(std::move(params));
  356. }
  357. EXPECT_EQ(gfx::SwapResult::SWAP_ACK,
  358. surface_->SwapBuffers(base::DoNothing()));
  359. Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain =
  360. surface_->GetLayerSwapChainForTesting(0);
  361. ASSERT_TRUE(swap_chain);
  362. DXGI_SWAP_CHAIN_DESC desc;
  363. EXPECT_TRUE(SUCCEEDED(swap_chain->GetDesc(&desc)));
  364. // Onscreen quad_rect.size is (100, 100).
  365. EXPECT_EQ(100u, desc.BufferDesc.Width);
  366. EXPECT_EQ(100u, desc.BufferDesc.Height);
  367. // Clear SwapChainPresenters
  368. // Must do Clear first because the swap chain won't resize immediately if
  369. // a new size is given unless this is the very first time after Clear.
  370. EXPECT_EQ(gfx::SwapResult::SWAP_ACK,
  371. surface_->SwapBuffers(base::DoNothing()));
  372. // The input texture size is bigger than the window size.
  373. quad_rect = gfx::Rect(32, 48);
  374. {
  375. std::unique_ptr<ui::DCRendererLayerParams> params =
  376. std::make_unique<ui::DCRendererLayerParams>();
  377. params->images[0] = image_dxgi;
  378. params->content_rect = gfx::Rect(texture_size);
  379. params->quad_rect = quad_rect;
  380. surface_->ScheduleDCLayer(std::move(params));
  381. }
  382. EXPECT_EQ(gfx::SwapResult::SWAP_ACK,
  383. surface_->SwapBuffers(base::DoNothing()));
  384. Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain2 =
  385. surface_->GetLayerSwapChainForTesting(0);
  386. ASSERT_TRUE(swap_chain2);
  387. EXPECT_TRUE(SUCCEEDED(swap_chain2->GetDesc(&desc)));
  388. // Onscreen quad_rect.size is (32, 48).
  389. EXPECT_EQ(32u, desc.BufferDesc.Width);
  390. EXPECT_EQ(48u, desc.BufferDesc.Height);
  391. }
  392. // Ensure the swapchain size is set to the correct size if HW overlay scaling
  393. // is not support - swapchain should be the onscreen video size.
  394. TEST_F(DirectCompositionSurfaceTest, SwapchainSizeWithoutScaledOverlays) {
  395. if (!surface_)
  396. return;
  397. Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
  398. QueryD3D11DeviceObjectFromANGLE();
  399. gfx::Size texture_size(80, 80);
  400. Microsoft::WRL::ComPtr<ID3D11Texture2D> texture =
  401. CreateNV12Texture(d3d11_device, texture_size, false);
  402. scoped_refptr<GLImageDXGI> image_dxgi(new GLImageDXGI(texture_size, nullptr));
  403. image_dxgi->SetTexture(texture, 0);
  404. image_dxgi->SetColorSpace(gfx::ColorSpace::CreateREC709());
  405. gfx::Rect quad_rect = gfx::Rect(42, 42);
  406. {
  407. std::unique_ptr<ui::DCRendererLayerParams> params =
  408. std::make_unique<ui::DCRendererLayerParams>();
  409. params->images[0] = image_dxgi;
  410. params->content_rect = gfx::Rect(texture_size);
  411. params->quad_rect = quad_rect;
  412. surface_->ScheduleDCLayer(std::move(params));
  413. }
  414. EXPECT_EQ(gfx::SwapResult::SWAP_ACK,
  415. surface_->SwapBuffers(base::DoNothing()));
  416. Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain =
  417. surface_->GetLayerSwapChainForTesting(0);
  418. ASSERT_TRUE(swap_chain);
  419. DXGI_SWAP_CHAIN_DESC desc;
  420. EXPECT_TRUE(SUCCEEDED(swap_chain->GetDesc(&desc)));
  421. // Onscreen quad_rect.size is (42, 42).
  422. EXPECT_EQ(42u, desc.BufferDesc.Width);
  423. EXPECT_EQ(42u, desc.BufferDesc.Height);
  424. // The input texture size is smaller than the window size.
  425. quad_rect = gfx::Rect(124, 136);
  426. {
  427. std::unique_ptr<ui::DCRendererLayerParams> params =
  428. std::make_unique<ui::DCRendererLayerParams>();
  429. params->images[0] = image_dxgi;
  430. params->content_rect = gfx::Rect(texture_size);
  431. params->quad_rect = quad_rect;
  432. surface_->ScheduleDCLayer(std::move(params));
  433. }
  434. EXPECT_EQ(gfx::SwapResult::SWAP_ACK,
  435. surface_->SwapBuffers(base::DoNothing()));
  436. Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain2 =
  437. surface_->GetLayerSwapChainForTesting(0);
  438. ASSERT_TRUE(swap_chain2);
  439. EXPECT_TRUE(SUCCEEDED(swap_chain2->GetDesc(&desc)));
  440. // Onscreen quad_rect.size is (124, 136).
  441. EXPECT_EQ(124u, desc.BufferDesc.Width);
  442. EXPECT_EQ(136u, desc.BufferDesc.Height);
  443. }
  444. // Test protected video flags
  445. TEST_F(DirectCompositionSurfaceTest, ProtectedVideos) {
  446. if (!surface_)
  447. return;
  448. Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
  449. QueryD3D11DeviceObjectFromANGLE();
  450. gfx::Size texture_size(1280, 720);
  451. Microsoft::WRL::ComPtr<ID3D11Texture2D> texture =
  452. CreateNV12Texture(d3d11_device, texture_size, false);
  453. scoped_refptr<GLImageDXGI> image_dxgi(new GLImageDXGI(texture_size, nullptr));
  454. image_dxgi->SetTexture(texture, 0);
  455. image_dxgi->SetColorSpace(gfx::ColorSpace::CreateREC709());
  456. gfx::Size window_size(640, 360);
  457. // Clear video
  458. {
  459. std::unique_ptr<ui::DCRendererLayerParams> params =
  460. std::make_unique<ui::DCRendererLayerParams>();
  461. params->images[0] = image_dxgi;
  462. params->quad_rect = gfx::Rect(window_size);
  463. params->content_rect = gfx::Rect(texture_size);
  464. params->protected_video_type = gfx::ProtectedVideoType::kClear;
  465. surface_->ScheduleDCLayer(std::move(params));
  466. EXPECT_EQ(gfx::SwapResult::SWAP_ACK,
  467. surface_->SwapBuffers(base::DoNothing()));
  468. Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain =
  469. surface_->GetLayerSwapChainForTesting(0);
  470. ASSERT_TRUE(swap_chain);
  471. DXGI_SWAP_CHAIN_DESC desc;
  472. EXPECT_TRUE(SUCCEEDED(swap_chain->GetDesc(&desc)));
  473. auto display_only_flag = desc.Flags & DXGI_SWAP_CHAIN_FLAG_DISPLAY_ONLY;
  474. auto hw_protected_flag = desc.Flags & DXGI_SWAP_CHAIN_FLAG_HW_PROTECTED;
  475. EXPECT_EQ(0u, display_only_flag);
  476. EXPECT_EQ(0u, hw_protected_flag);
  477. }
  478. // Software protected video
  479. {
  480. std::unique_ptr<ui::DCRendererLayerParams> params =
  481. std::make_unique<ui::DCRendererLayerParams>();
  482. params->images[0] = image_dxgi;
  483. params->quad_rect = gfx::Rect(window_size);
  484. params->content_rect = gfx::Rect(texture_size);
  485. params->protected_video_type = gfx::ProtectedVideoType::kSoftwareProtected;
  486. surface_->ScheduleDCLayer(std::move(params));
  487. EXPECT_EQ(gfx::SwapResult::SWAP_ACK,
  488. surface_->SwapBuffers(base::DoNothing()));
  489. Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain =
  490. surface_->GetLayerSwapChainForTesting(0);
  491. ASSERT_TRUE(swap_chain);
  492. DXGI_SWAP_CHAIN_DESC Desc;
  493. EXPECT_TRUE(SUCCEEDED(swap_chain->GetDesc(&Desc)));
  494. auto display_only_flag = Desc.Flags & DXGI_SWAP_CHAIN_FLAG_DISPLAY_ONLY;
  495. auto hw_protected_flag = Desc.Flags & DXGI_SWAP_CHAIN_FLAG_HW_PROTECTED;
  496. EXPECT_EQ(DXGI_SWAP_CHAIN_FLAG_DISPLAY_ONLY, display_only_flag);
  497. EXPECT_EQ(0u, hw_protected_flag);
  498. }
  499. // TODO(magchen): Add a hardware protected video test when hardware procted
  500. // video support is enabled by defaut in the Intel driver and Chrome
  501. }
  502. std::vector<SkColor> ReadBackWindow(HWND window, const gfx::Size& size) {
  503. base::win::ScopedCreateDC mem_hdc(::CreateCompatibleDC(nullptr));
  504. DCHECK(mem_hdc.IsValid());
  505. BITMAPV4HEADER hdr;
  506. gfx::CreateBitmapV4HeaderForARGB888(size.width(), size.height(), &hdr);
  507. void* bits = nullptr;
  508. base::win::ScopedBitmap bitmap(
  509. ::CreateDIBSection(mem_hdc.Get(), reinterpret_cast<BITMAPINFO*>(&hdr),
  510. DIB_RGB_COLORS, &bits, nullptr, 0));
  511. DCHECK(bitmap.is_valid());
  512. base::win::ScopedSelectObject select_object(mem_hdc.Get(), bitmap.get());
  513. // Grab a copy of the window. Use PrintWindow because it works even when the
  514. // window's partially occluded. The PW_RENDERFULLCONTENT flag is undocumented,
  515. // but works starting in Windows 8.1. It allows for capturing the contents of
  516. // the window that are drawn using DirectComposition.
  517. UINT flags = PW_CLIENTONLY | PW_RENDERFULLCONTENT;
  518. BOOL result = PrintWindow(window, mem_hdc.Get(), flags);
  519. if (!result)
  520. PLOG(ERROR) << "Failed to print window";
  521. GdiFlush();
  522. std::vector<SkColor> pixels(size.width() * size.height());
  523. memcpy(pixels.data(), bits, pixels.size() * sizeof(SkColor));
  524. return pixels;
  525. }
  526. SkColor ReadBackWindowPixel(HWND window, const gfx::Point& point) {
  527. gfx::Size size(point.x() + 1, point.y() + 1);
  528. auto pixels = ReadBackWindow(window, size);
  529. return pixels[size.width() * point.y() + point.x()];
  530. }
  531. class DirectCompositionPixelTest : public DirectCompositionSurfaceTest {
  532. public:
  533. DirectCompositionPixelTest()
  534. : window_(&platform_delegate_, gfx::Rect(100, 100)) {
  535. parent_window_ = window_.hwnd();
  536. }
  537. protected:
  538. void SetUp() override {
  539. static_cast<ui::PlatformWindow*>(&window_)->Show();
  540. DirectCompositionSurfaceTest::SetUp();
  541. }
  542. void TearDown() override {
  543. // Test harness times out without DestroyWindow() here.
  544. if (IsWindow(parent_window_))
  545. DestroyWindow(parent_window_);
  546. DirectCompositionSurfaceTest::TearDown();
  547. }
  548. void InitializeForPixelTest(const gfx::Size& window_size,
  549. const gfx::Size& texture_size,
  550. const gfx::Rect& content_rect,
  551. const gfx::Rect& quad_rect) {
  552. EXPECT_TRUE(surface_->Resize(window_size, 1.0, gfx::ColorSpace(), true));
  553. EXPECT_TRUE(surface_->SetDrawRectangle(gfx::Rect(window_size)));
  554. glClearColor(0.0, 0.0, 0.0, 1.0);
  555. glClear(GL_COLOR_BUFFER_BIT);
  556. Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
  557. QueryD3D11DeviceObjectFromANGLE();
  558. Microsoft::WRL::ComPtr<ID3D11Texture2D> texture =
  559. CreateNV12Texture(d3d11_device, texture_size, true);
  560. Microsoft::WRL::ComPtr<IDXGIResource1> resource;
  561. texture.As(&resource);
  562. HANDLE handle = 0;
  563. resource->CreateSharedHandle(nullptr, DXGI_SHARED_RESOURCE_READ, nullptr,
  564. &handle);
  565. // The format doesn't matter, since we aren't binding.
  566. scoped_refptr<GLImageDXGI> image_dxgi(
  567. new GLImageDXGI(texture_size, nullptr));
  568. ASSERT_TRUE(image_dxgi->InitializeHandle(base::win::ScopedHandle(handle), 0,
  569. gfx::BufferFormat::RGBA_8888));
  570. // Pass content rect with odd with and height. Surface should round up
  571. // width and height when creating swap chain.
  572. std::unique_ptr<ui::DCRendererLayerParams> params =
  573. std::make_unique<ui::DCRendererLayerParams>();
  574. params->images[0] = image_dxgi;
  575. params->content_rect = content_rect;
  576. params->quad_rect = quad_rect;
  577. surface_->ScheduleDCLayer(std::move(params));
  578. EXPECT_EQ(gfx::SwapResult::SWAP_ACK,
  579. surface_->SwapBuffers(base::DoNothing()));
  580. Sleep(1000);
  581. }
  582. void PixelTestSwapChain(bool layers_enabled) {
  583. if (!surface_)
  584. return;
  585. if (!layers_enabled)
  586. surface_->SetEnableDCLayers(false);
  587. gfx::Size window_size(100, 100);
  588. EXPECT_TRUE(surface_->Resize(window_size, 1.0, gfx::ColorSpace(), true));
  589. EXPECT_TRUE(surface_->SetDrawRectangle(gfx::Rect(window_size)));
  590. glClearColor(1.0, 0.0, 0.0, 1.0);
  591. glClear(GL_COLOR_BUFFER_BIT);
  592. EXPECT_EQ(gfx::SwapResult::SWAP_ACK,
  593. surface_->SwapBuffers(base::DoNothing()));
  594. // Ensure DWM swap completed.
  595. Sleep(1000);
  596. SkColor expected_color = SK_ColorRED;
  597. SkColor actual_color =
  598. ReadBackWindowPixel(window_.hwnd(), gfx::Point(75, 75));
  599. EXPECT_EQ(expected_color, actual_color)
  600. << std::hex << "Expected " << expected_color << " Actual "
  601. << actual_color;
  602. EXPECT_TRUE(context_->IsCurrent(surface_.get()));
  603. }
  604. TestPlatformDelegate platform_delegate_;
  605. ui::WinWindow window_;
  606. };
  607. TEST_F(DirectCompositionPixelTest, DCLayersEnabled) {
  608. PixelTestSwapChain(true);
  609. }
  610. TEST_F(DirectCompositionPixelTest, DCLayersDisabled) {
  611. PixelTestSwapChain(false);
  612. }
  613. bool AreColorsSimilar(int a, int b) {
  614. // The precise colors may differ depending on the video processor, so allow
  615. // a margin for error.
  616. const int kMargin = 10;
  617. return abs(SkColorGetA(a) - SkColorGetA(b)) < kMargin &&
  618. abs(SkColorGetR(a) - SkColorGetR(b)) < kMargin &&
  619. abs(SkColorGetG(a) - SkColorGetG(b)) < kMargin &&
  620. abs(SkColorGetB(a) - SkColorGetB(b)) < kMargin;
  621. }
  622. class DirectCompositionVideoPixelTest : public DirectCompositionPixelTest {
  623. protected:
  624. void TestVideo(const gfx::ColorSpace& color_space,
  625. SkColor expected_color,
  626. bool check_color) {
  627. if (!surface_)
  628. return;
  629. gfx::Size window_size(100, 100);
  630. EXPECT_TRUE(surface_->Resize(window_size, 1.0, gfx::ColorSpace(), true));
  631. Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
  632. QueryD3D11DeviceObjectFromANGLE();
  633. gfx::Size texture_size(50, 50);
  634. Microsoft::WRL::ComPtr<ID3D11Texture2D> texture =
  635. CreateNV12Texture(d3d11_device, texture_size, false);
  636. scoped_refptr<GLImageDXGI> image_dxgi(
  637. new GLImageDXGI(texture_size, nullptr));
  638. image_dxgi->SetTexture(texture, 0);
  639. image_dxgi->SetColorSpace(color_space);
  640. {
  641. std::unique_ptr<ui::DCRendererLayerParams> params =
  642. std::make_unique<ui::DCRendererLayerParams>();
  643. params->images[0] = image_dxgi;
  644. params->content_rect = gfx::Rect(texture_size);
  645. params->quad_rect = gfx::Rect(texture_size);
  646. surface_->ScheduleDCLayer(std::move(params));
  647. }
  648. EXPECT_EQ(gfx::SwapResult::SWAP_ACK,
  649. surface_->SwapBuffers(base::DoNothing()));
  650. // Scaling up the swapchain with the same image should cause it to be
  651. // transformed again, but not presented again.
  652. {
  653. std::unique_ptr<ui::DCRendererLayerParams> params =
  654. std::make_unique<ui::DCRendererLayerParams>();
  655. params->images[0] = image_dxgi;
  656. params->content_rect = gfx::Rect(texture_size);
  657. params->quad_rect = gfx::Rect(window_size);
  658. surface_->ScheduleDCLayer(std::move(params));
  659. }
  660. EXPECT_EQ(gfx::SwapResult::SWAP_ACK,
  661. surface_->SwapBuffers(base::DoNothing()));
  662. Sleep(1000);
  663. if (check_color) {
  664. SkColor actual_color =
  665. ReadBackWindowPixel(window_.hwnd(), gfx::Point(75, 75));
  666. EXPECT_TRUE(AreColorsSimilar(expected_color, actual_color))
  667. << std::hex << "Expected " << expected_color << " Actual "
  668. << actual_color;
  669. }
  670. }
  671. };
  672. TEST_F(DirectCompositionVideoPixelTest, BT601) {
  673. TestVideo(gfx::ColorSpace::CreateREC601(), SkColorSetRGB(0xdb, 0x81, 0xe8),
  674. true);
  675. }
  676. TEST_F(DirectCompositionVideoPixelTest, BT709) {
  677. TestVideo(gfx::ColorSpace::CreateREC709(), SkColorSetRGB(0xe1, 0x90, 0xeb),
  678. true);
  679. }
  680. TEST_F(DirectCompositionVideoPixelTest, SRGB) {
  681. // SRGB doesn't make sense on an NV12 input, but don't crash.
  682. TestVideo(gfx::ColorSpace::CreateSRGB(), SK_ColorTRANSPARENT, false);
  683. }
  684. TEST_F(DirectCompositionVideoPixelTest, SCRGBLinear) {
  685. // SCRGB doesn't make sense on an NV12 input, but don't crash.
  686. TestVideo(gfx::ColorSpace::CreateSRGBLinear(), SK_ColorTRANSPARENT, false);
  687. }
  688. TEST_F(DirectCompositionVideoPixelTest, InvalidColorSpace) {
  689. // Invalid color space should be treated as BT.709
  690. TestVideo(gfx::ColorSpace(), SkColorSetRGB(0xe1, 0x90, 0xeb), true);
  691. }
  692. TEST_F(DirectCompositionPixelTest, SoftwareVideoSwapchain) {
  693. if (!surface_)
  694. return;
  695. gfx::Size window_size(100, 100);
  696. EXPECT_TRUE(surface_->Resize(window_size, 1.0, gfx::ColorSpace(), true));
  697. Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
  698. QueryD3D11DeviceObjectFromANGLE();
  699. gfx::Size y_size(50, 50);
  700. gfx::Size uv_size(25, 25);
  701. size_t y_stride =
  702. gfx::RowSizeForBufferFormat(y_size.width(), gfx::BufferFormat::R_8, 0);
  703. size_t uv_stride =
  704. gfx::RowSizeForBufferFormat(uv_size.width(), gfx::BufferFormat::RG_88, 0);
  705. std::vector<uint8_t> y_data(y_stride * y_size.height(), 0xff);
  706. std::vector<uint8_t> uv_data(uv_stride * uv_size.height(), 0xff);
  707. auto y_image = base::MakeRefCounted<GLImageRefCountedMemory>(y_size);
  708. y_image->Initialize(new base::RefCountedBytes(y_data),
  709. gfx::BufferFormat::R_8);
  710. auto uv_image = base::MakeRefCounted<GLImageRefCountedMemory>(uv_size);
  711. uv_image->Initialize(new base::RefCountedBytes(uv_data),
  712. gfx::BufferFormat::RG_88);
  713. y_image->SetColorSpace(gfx::ColorSpace::CreateREC709());
  714. std::unique_ptr<ui::DCRendererLayerParams> params =
  715. std::make_unique<ui::DCRendererLayerParams>();
  716. params->images[0] = y_image;
  717. params->images[1] = uv_image;
  718. params->content_rect = gfx::Rect(y_size);
  719. params->quad_rect = gfx::Rect(window_size);
  720. surface_->ScheduleDCLayer(std::move(params));
  721. EXPECT_EQ(gfx::SwapResult::SWAP_ACK,
  722. surface_->SwapBuffers(base::DoNothing()));
  723. Sleep(1000);
  724. SkColor expected_color = SkColorSetRGB(0xff, 0xb7, 0xff);
  725. SkColor actual_color =
  726. ReadBackWindowPixel(window_.hwnd(), gfx::Point(75, 75));
  727. EXPECT_TRUE(AreColorsSimilar(expected_color, actual_color))
  728. << std::hex << "Expected " << expected_color << " Actual "
  729. << actual_color;
  730. }
  731. TEST_F(DirectCompositionPixelTest, VideoHandleSwapchain) {
  732. if (!surface_)
  733. return;
  734. gfx::Size window_size(100, 100);
  735. gfx::Size texture_size(50, 50);
  736. gfx::Rect content_rect(texture_size);
  737. gfx::Rect quad_rect(window_size);
  738. InitializeForPixelTest(window_size, texture_size, content_rect, quad_rect);
  739. SkColor expected_color = SkColorSetRGB(0xe1, 0x90, 0xeb);
  740. SkColor actual_color =
  741. ReadBackWindowPixel(window_.hwnd(), gfx::Point(75, 75));
  742. EXPECT_TRUE(AreColorsSimilar(expected_color, actual_color))
  743. << std::hex << "Expected " << expected_color << " Actual "
  744. << actual_color;
  745. }
  746. TEST_F(DirectCompositionPixelTest, SkipVideoLayerEmptyBoundsRect) {
  747. if (!surface_)
  748. return;
  749. gfx::Size window_size(100, 100);
  750. gfx::Size texture_size(50, 50);
  751. gfx::Rect content_rect(texture_size);
  752. gfx::Rect quad_rect; // Layer with empty bounds rect.
  753. InitializeForPixelTest(window_size, texture_size, content_rect, quad_rect);
  754. // No color is written since the visual committed to DirectComposition has no
  755. // content.
  756. SkColor expected_color = SK_ColorBLACK;
  757. SkColor actual_color =
  758. ReadBackWindowPixel(window_.hwnd(), gfx::Point(75, 75));
  759. EXPECT_TRUE(AreColorsSimilar(expected_color, actual_color))
  760. << std::hex << "Expected " << expected_color << " Actual "
  761. << actual_color;
  762. }
  763. TEST_F(DirectCompositionPixelTest, SkipVideoLayerEmptyContentsRect) {
  764. if (!surface_)
  765. return;
  766. // Swap chain size is overridden to onscreen size only if scaled overlays
  767. // are supported.
  768. SetDirectCompositionScaledOverlaysSupportedForTesting(true);
  769. gfx::Size window_size(100, 100);
  770. EXPECT_TRUE(surface_->Resize(window_size, 1.0, gfx::ColorSpace(), true));
  771. EXPECT_TRUE(surface_->SetDrawRectangle(gfx::Rect(window_size)));
  772. glClearColor(0.0, 0.0, 0.0, 1.0);
  773. glClear(GL_COLOR_BUFFER_BIT);
  774. Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
  775. QueryD3D11DeviceObjectFromANGLE();
  776. gfx::Size texture_size(50, 50);
  777. Microsoft::WRL::ComPtr<ID3D11Texture2D> texture =
  778. CreateNV12Texture(d3d11_device, texture_size, true);
  779. Microsoft::WRL::ComPtr<IDXGIResource1> resource;
  780. texture.As(&resource);
  781. HANDLE handle = 0;
  782. resource->CreateSharedHandle(nullptr, DXGI_SHARED_RESOURCE_READ, nullptr,
  783. &handle);
  784. // The format doesn't matter, since we aren't binding.
  785. scoped_refptr<GLImageDXGI> image_dxgi(new GLImageDXGI(texture_size, nullptr));
  786. ASSERT_TRUE(image_dxgi->InitializeHandle(base::win::ScopedHandle(handle), 0,
  787. gfx::BufferFormat::RGBA_8888));
  788. // Layer with empty content rect.
  789. std::unique_ptr<ui::DCRendererLayerParams> params =
  790. std::make_unique<ui::DCRendererLayerParams>();
  791. params->images[0] = image_dxgi;
  792. params->quad_rect = gfx::Rect(window_size);
  793. surface_->ScheduleDCLayer(std::move(params));
  794. EXPECT_EQ(gfx::SwapResult::SWAP_ACK,
  795. surface_->SwapBuffers(base::DoNothing()));
  796. Sleep(1000);
  797. // No color is written since the visual committed to DirectComposition has no
  798. // content.
  799. SkColor expected_color = SK_ColorBLACK;
  800. SkColor actual_color =
  801. ReadBackWindowPixel(window_.hwnd(), gfx::Point(75, 75));
  802. EXPECT_TRUE(AreColorsSimilar(expected_color, actual_color))
  803. << std::hex << "Expected " << expected_color << " Actual "
  804. << actual_color;
  805. }
  806. TEST_F(DirectCompositionPixelTest, NV12SwapChain) {
  807. if (!surface_)
  808. return;
  809. // Swap chain size is overridden to onscreen rect size only if scaled overlays
  810. // are supported.
  811. SetDirectCompositionScaledOverlaysSupportedForTesting(true);
  812. gfx::Size window_size(100, 100);
  813. gfx::Size texture_size(50, 50);
  814. // Pass content rect with odd with and height. Surface should round up
  815. // width and height when creating swap chain.
  816. gfx::Rect content_rect(0, 0, 49, 49);
  817. gfx::Rect quad_rect(window_size);
  818. InitializeForPixelTest(window_size, texture_size, content_rect, quad_rect);
  819. Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain =
  820. surface_->GetLayerSwapChainForTesting(0);
  821. ASSERT_TRUE(swap_chain);
  822. DXGI_SWAP_CHAIN_DESC1 desc;
  823. EXPECT_TRUE(SUCCEEDED(swap_chain->GetDesc1(&desc)));
  824. // Onscreen window_size is (100, 100).
  825. EXPECT_EQ(DXGI_FORMAT_NV12, desc.Format);
  826. EXPECT_EQ(100u, desc.Width);
  827. EXPECT_EQ(100u, desc.Height);
  828. SkColor expected_color = SkColorSetRGB(0xe1, 0x90, 0xeb);
  829. SkColor actual_color =
  830. ReadBackWindowPixel(window_.hwnd(), gfx::Point(75, 75));
  831. EXPECT_TRUE(AreColorsSimilar(expected_color, actual_color))
  832. << std::hex << "Expected " << expected_color << " Actual "
  833. << actual_color;
  834. }
  835. TEST_F(DirectCompositionPixelTest, YUY2SwapChain) {
  836. if (!surface_)
  837. return;
  838. // CreateSwapChainForCompositionSurfaceHandle fails with YUY2 format on
  839. // Win10/AMD bot (Radeon RX550). See https://crbug.com/967860.
  840. if (context_ && context_->GetVersionInfo() &&
  841. context_->GetVersionInfo()->driver_vendor.find("AMD") !=
  842. std::string::npos)
  843. return;
  844. // Swap chain size is overridden to onscreen rect size only if scaled overlays
  845. // are supported.
  846. SetDirectCompositionScaledOverlaysSupportedForTesting(true);
  847. // By default NV12 is used, so set it to YUY2 explicitly.
  848. SetDirectCompositionOverlayFormatUsedForTesting(DXGI_FORMAT_YUY2);
  849. gfx::Size window_size(100, 100);
  850. gfx::Size texture_size(50, 50);
  851. // Pass content rect with odd with and height. Surface should round up
  852. // width and height when creating swap chain.
  853. gfx::Rect content_rect(0, 0, 49, 49);
  854. gfx::Rect quad_rect(window_size);
  855. InitializeForPixelTest(window_size, texture_size, content_rect, quad_rect);
  856. Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain =
  857. surface_->GetLayerSwapChainForTesting(0);
  858. ASSERT_TRUE(swap_chain);
  859. DXGI_SWAP_CHAIN_DESC1 desc;
  860. EXPECT_TRUE(SUCCEEDED(swap_chain->GetDesc1(&desc)));
  861. // Onscreen window_size is (100, 100).
  862. EXPECT_EQ(DXGI_FORMAT_YUY2, desc.Format);
  863. EXPECT_EQ(100u, desc.Width);
  864. EXPECT_EQ(100u, desc.Height);
  865. SkColor expected_color = SkColorSetRGB(0xe1, 0x90, 0xeb);
  866. SkColor actual_color =
  867. ReadBackWindowPixel(window_.hwnd(), gfx::Point(75, 75));
  868. EXPECT_TRUE(AreColorsSimilar(expected_color, actual_color))
  869. << std::hex << "Expected " << expected_color << " Actual "
  870. << actual_color;
  871. }
  872. TEST_F(DirectCompositionPixelTest, NonZeroBoundsOffset) {
  873. if (!surface_)
  874. return;
  875. // Swap chain size is overridden to onscreen rect size only if scaled overlays
  876. // are supported.
  877. SetDirectCompositionScaledOverlaysSupportedForTesting(true);
  878. gfx::Size window_size(100, 100);
  879. gfx::Size texture_size(50, 50);
  880. gfx::Rect content_rect(texture_size);
  881. gfx::Rect quad_rect(gfx::Point(25, 25), texture_size);
  882. InitializeForPixelTest(window_size, texture_size, content_rect, quad_rect);
  883. SkColor video_color = SkColorSetRGB(0xe1, 0x90, 0xeb);
  884. struct {
  885. gfx::Point point;
  886. SkColor expected_color;
  887. } test_cases[] = {
  888. // Outside bounds
  889. {{24, 24}, SK_ColorBLACK},
  890. {{75, 75}, SK_ColorBLACK},
  891. // Inside bounds
  892. {{25, 25}, video_color},
  893. {{74, 74}, video_color},
  894. };
  895. auto pixels = ReadBackWindow(window_.hwnd(), window_size);
  896. for (const auto& test_case : test_cases) {
  897. const auto& point = test_case.point;
  898. const auto& expected_color = test_case.expected_color;
  899. SkColor actual_color = pixels[window_size.width() * point.y() + point.x()];
  900. EXPECT_TRUE(AreColorsSimilar(expected_color, actual_color))
  901. << std::hex << "Expected " << expected_color << " Actual "
  902. << actual_color << " at " << point.ToString();
  903. }
  904. }
  905. TEST_F(DirectCompositionPixelTest, ResizeVideoLayer) {
  906. if (!surface_)
  907. return;
  908. // Swap chain size is overridden to onscreen rect size only if scaled overlays
  909. // are supported.
  910. SetDirectCompositionScaledOverlaysSupportedForTesting(true);
  911. gfx::Size window_size(100, 100);
  912. EXPECT_TRUE(surface_->Resize(window_size, 1.0, gfx::ColorSpace(), true));
  913. EXPECT_TRUE(surface_->SetDrawRectangle(gfx::Rect(window_size)));
  914. glClearColor(0.0, 0.0, 0.0, 1.0);
  915. glClear(GL_COLOR_BUFFER_BIT);
  916. Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
  917. QueryD3D11DeviceObjectFromANGLE();
  918. gfx::Size texture_size(50, 50);
  919. Microsoft::WRL::ComPtr<ID3D11Texture2D> texture =
  920. CreateNV12Texture(d3d11_device, texture_size, true);
  921. Microsoft::WRL::ComPtr<IDXGIResource1> resource;
  922. texture.As(&resource);
  923. HANDLE handle = 0;
  924. resource->CreateSharedHandle(nullptr, DXGI_SHARED_RESOURCE_READ, nullptr,
  925. &handle);
  926. // The format doesn't matter, since we aren't binding.
  927. scoped_refptr<GLImageDXGI> image_dxgi(new GLImageDXGI(texture_size, nullptr));
  928. ASSERT_TRUE(image_dxgi->InitializeHandle(base::win::ScopedHandle(handle), 0,
  929. gfx::BufferFormat::RGBA_8888));
  930. // (1) Test if swap chain is overridden to window size (100, 100).
  931. {
  932. std::unique_ptr<ui::DCRendererLayerParams> params =
  933. std::make_unique<ui::DCRendererLayerParams>();
  934. params->images[0] = image_dxgi;
  935. params->content_rect = gfx::Rect(texture_size);
  936. params->quad_rect = gfx::Rect(window_size);
  937. surface_->ScheduleDCLayer(std::move(params));
  938. EXPECT_EQ(gfx::SwapResult::SWAP_ACK,
  939. surface_->SwapBuffers(base::DoNothing()));
  940. }
  941. Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain =
  942. surface_->GetLayerSwapChainForTesting(0);
  943. ASSERT_TRUE(swap_chain);
  944. DXGI_SWAP_CHAIN_DESC1 desc;
  945. EXPECT_TRUE(SUCCEEDED(swap_chain->GetDesc1(&desc)));
  946. // Onscreen window_size is (100, 100).
  947. EXPECT_EQ(100u, desc.Width);
  948. EXPECT_EQ(100u, desc.Height);
  949. // (2) Test if swap chain is overridden to window size (100, 100).
  950. {
  951. std::unique_ptr<ui::DCRendererLayerParams> params =
  952. std::make_unique<ui::DCRendererLayerParams>();
  953. params->images[0] = image_dxgi;
  954. params->content_rect = gfx::Rect(30, 30);
  955. params->quad_rect = gfx::Rect(window_size);
  956. surface_->ScheduleDCLayer(std::move(params));
  957. EXPECT_EQ(gfx::SwapResult::SWAP_ACK,
  958. surface_->SwapBuffers(base::DoNothing()));
  959. }
  960. swap_chain = surface_->GetLayerSwapChainForTesting(0);
  961. EXPECT_TRUE(SUCCEEDED(swap_chain->GetDesc1(&desc)));
  962. // Onscreen window_size is (100, 100).
  963. EXPECT_EQ(100u, desc.Width);
  964. EXPECT_EQ(100u, desc.Height);
  965. // (3) Test if swap chain is adjusted to fit the monitor when overlay scaling
  966. // is not supported and video on-screen size is slightly smaller than the
  967. // monitor. Clipping is on.
  968. SetDirectCompositionScaledOverlaysSupportedForTesting(false);
  969. gfx::Size monitor_size = window_size;
  970. SetDirectCompositionMonitorInfoForTesting(1, window_size);
  971. gfx::Rect on_screen_rect =
  972. gfx::Rect(0, 0, monitor_size.width() - 2, monitor_size.height() - 2);
  973. {
  974. std::unique_ptr<ui::DCRendererLayerParams> params =
  975. std::make_unique<ui::DCRendererLayerParams>();
  976. params->images[0] = image_dxgi;
  977. params->content_rect = gfx::Rect(50, 50);
  978. params->quad_rect = on_screen_rect;
  979. params->clip_rect = on_screen_rect;
  980. surface_->ScheduleDCLayer(std::move(params));
  981. EXPECT_EQ(gfx::SwapResult::SWAP_ACK,
  982. surface_->SwapBuffers(base::DoNothing()));
  983. }
  984. // Swap chain is set to monitor/onscreen size.
  985. swap_chain = surface_->GetLayerSwapChainForTesting(0);
  986. EXPECT_TRUE(SUCCEEDED(swap_chain->GetDesc1(&desc)));
  987. EXPECT_EQ(static_cast<UINT>(monitor_size.width()), desc.Width);
  988. EXPECT_EQ(static_cast<UINT>(monitor_size.height()), desc.Height);
  989. gfx::Transform transform;
  990. gfx::Point offset;
  991. gfx::Rect clip_rect;
  992. surface_->GetSwapChainVisualInfoForTesting(0, &transform, &offset,
  993. &clip_rect);
  994. EXPECT_TRUE(transform.IsIdentity());
  995. EXPECT_EQ(gfx::Rect(monitor_size), clip_rect);
  996. // (4) Test if the final on-screen size is adjusted to fit the monitor when
  997. // overlay scaling is supported and video on-screen size is slightly bigger
  998. // than the monitor. Clipping is off.
  999. SetDirectCompositionScaledOverlaysSupportedForTesting(true);
  1000. on_screen_rect =
  1001. gfx::Rect(0, 0, monitor_size.width() + 2, monitor_size.height() + 2);
  1002. {
  1003. std::unique_ptr<ui::DCRendererLayerParams> params =
  1004. std::make_unique<ui::DCRendererLayerParams>();
  1005. params->images[0] = image_dxgi;
  1006. params->content_rect = gfx::Rect(50, 50);
  1007. params->quad_rect = on_screen_rect;
  1008. surface_->ScheduleDCLayer(std::move(params));
  1009. EXPECT_EQ(gfx::SwapResult::SWAP_ACK,
  1010. surface_->SwapBuffers(base::DoNothing()));
  1011. }
  1012. // Swap chain is set to monitor size (100, 100).
  1013. swap_chain = surface_->GetLayerSwapChainForTesting(0);
  1014. EXPECT_TRUE(SUCCEEDED(swap_chain->GetDesc1(&desc)));
  1015. EXPECT_EQ(100u, desc.Width);
  1016. EXPECT_EQ(100u, desc.Height);
  1017. // Make sure the new transform matrix is adjusted, so it transforms the swap
  1018. // chain to |new_on_screen_rect| which fits the monitor.
  1019. surface_->GetSwapChainVisualInfoForTesting(0, &transform, &offset,
  1020. &clip_rect);
  1021. gfx::RectF new_on_screen_rect = gfx::RectF(100, 100);
  1022. transform.TransformRect(&new_on_screen_rect);
  1023. EXPECT_EQ(gfx::Rect(monitor_size), gfx::ToEnclosingRect(new_on_screen_rect));
  1024. }
  1025. TEST_F(DirectCompositionPixelTest, SwapChainImage) {
  1026. if (!surface_)
  1027. return;
  1028. // Fails on AMD RX 5500 XT. https://crbug.com/1152565.
  1029. if (context_ && context_->GetVersionInfo() &&
  1030. context_->GetVersionInfo()->driver_vendor.find("AMD") !=
  1031. std::string::npos)
  1032. return;
  1033. Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
  1034. QueryD3D11DeviceObjectFromANGLE();
  1035. ASSERT_TRUE(d3d11_device);
  1036. Microsoft::WRL::ComPtr<IDXGIDevice> dxgi_device;
  1037. d3d11_device.As(&dxgi_device);
  1038. ASSERT_TRUE(dxgi_device);
  1039. Microsoft::WRL::ComPtr<IDXGIAdapter> dxgi_adapter;
  1040. dxgi_device->GetAdapter(&dxgi_adapter);
  1041. ASSERT_TRUE(dxgi_adapter);
  1042. Microsoft::WRL::ComPtr<IDXGIFactory2> dxgi_factory;
  1043. dxgi_adapter->GetParent(IID_PPV_ARGS(&dxgi_factory));
  1044. ASSERT_TRUE(dxgi_factory);
  1045. gfx::Size swap_chain_size(50, 50);
  1046. DXGI_SWAP_CHAIN_DESC1 desc = {};
  1047. desc.Width = swap_chain_size.width();
  1048. desc.Height = swap_chain_size.height();
  1049. desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
  1050. desc.Stereo = FALSE;
  1051. desc.SampleDesc.Count = 1;
  1052. desc.BufferCount = 2;
  1053. desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_SHADER_INPUT;
  1054. desc.Scaling = DXGI_SCALING_STRETCH;
  1055. desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
  1056. desc.Flags = 0;
  1057. Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain;
  1058. ASSERT_TRUE(SUCCEEDED(dxgi_factory->CreateSwapChainForComposition(
  1059. d3d11_device.Get(), &desc, nullptr, &swap_chain)));
  1060. ASSERT_TRUE(swap_chain);
  1061. Microsoft::WRL::ComPtr<ID3D11Texture2D> front_buffer_texture;
  1062. ASSERT_TRUE(SUCCEEDED(
  1063. swap_chain->GetBuffer(1u, IID_PPV_ARGS(&front_buffer_texture))));
  1064. ASSERT_TRUE(front_buffer_texture);
  1065. auto front_buffer_image = base::MakeRefCounted<GLImageD3D>(
  1066. swap_chain_size, GL_BGRA_EXT, GL_UNSIGNED_BYTE,
  1067. gfx::ColorSpace::CreateSRGB(), front_buffer_texture,
  1068. /*array_slice=*/0, /*plane_index=*/0, swap_chain);
  1069. ASSERT_TRUE(front_buffer_image->Initialize());
  1070. Microsoft::WRL::ComPtr<ID3D11Texture2D> back_buffer_texture;
  1071. ASSERT_TRUE(
  1072. SUCCEEDED(swap_chain->GetBuffer(0u, IID_PPV_ARGS(&back_buffer_texture))));
  1073. ASSERT_TRUE(back_buffer_texture);
  1074. Microsoft::WRL::ComPtr<ID3D11RenderTargetView> rtv;
  1075. ASSERT_TRUE(SUCCEEDED(d3d11_device->CreateRenderTargetView(
  1076. back_buffer_texture.Get(), nullptr, &rtv)));
  1077. ASSERT_TRUE(rtv);
  1078. Microsoft::WRL::ComPtr<ID3D11DeviceContext> context;
  1079. d3d11_device->GetImmediateContext(&context);
  1080. ASSERT_TRUE(context);
  1081. gfx::Size window_size(100, 100);
  1082. EXPECT_TRUE(surface_->Resize(window_size, 1.0, gfx::ColorSpace(), true));
  1083. EXPECT_TRUE(surface_->SetDrawRectangle(gfx::Rect(window_size)));
  1084. glClearColor(0.0, 0.0, 0.0, 1.0);
  1085. glClear(GL_COLOR_BUFFER_BIT);
  1086. DXGI_PRESENT_PARAMETERS present_params = {};
  1087. present_params.DirtyRectsCount = 0;
  1088. present_params.pDirtyRects = nullptr;
  1089. // Clear to red and present.
  1090. {
  1091. float clear_color[] = {1.0, 0.0, 0.0, 1.0};
  1092. context->ClearRenderTargetView(rtv.Get(), clear_color);
  1093. ASSERT_TRUE(SUCCEEDED(swap_chain->Present1(0, 0, &present_params)));
  1094. std::unique_ptr<ui::DCRendererLayerParams> dc_layer_params =
  1095. std::make_unique<ui::DCRendererLayerParams>();
  1096. dc_layer_params->images[0] = front_buffer_image;
  1097. dc_layer_params->content_rect = gfx::Rect(swap_chain_size);
  1098. dc_layer_params->quad_rect = gfx::Rect(window_size);
  1099. surface_->ScheduleDCLayer(std::move(dc_layer_params));
  1100. EXPECT_EQ(gfx::SwapResult::SWAP_ACK,
  1101. surface_->SwapBuffers(base::DoNothing()));
  1102. SkColor expected_color = SK_ColorRED;
  1103. SkColor actual_color =
  1104. ReadBackWindowPixel(window_.hwnd(), gfx::Point(75, 75));
  1105. EXPECT_TRUE(AreColorsSimilar(expected_color, actual_color))
  1106. << std::hex << "Expected " << expected_color << " Actual "
  1107. << actual_color;
  1108. }
  1109. // Clear to green and present.
  1110. {
  1111. float clear_color[] = {0.0, 1.0, 0.0, 1.0};
  1112. context->ClearRenderTargetView(rtv.Get(), clear_color);
  1113. ASSERT_TRUE(SUCCEEDED(swap_chain->Present1(0, 0, &present_params)));
  1114. std::unique_ptr<ui::DCRendererLayerParams> dc_layer_params =
  1115. std::make_unique<ui::DCRendererLayerParams>();
  1116. dc_layer_params->images[0] = front_buffer_image;
  1117. dc_layer_params->content_rect = gfx::Rect(swap_chain_size);
  1118. dc_layer_params->quad_rect = gfx::Rect(window_size);
  1119. surface_->ScheduleDCLayer(std::move(dc_layer_params));
  1120. EXPECT_EQ(gfx::SwapResult::SWAP_ACK,
  1121. surface_->SwapBuffers(base::DoNothing()));
  1122. SkColor expected_color = SK_ColorGREEN;
  1123. SkColor actual_color =
  1124. ReadBackWindowPixel(window_.hwnd(), gfx::Point(75, 75));
  1125. EXPECT_TRUE(AreColorsSimilar(expected_color, actual_color))
  1126. << std::hex << "Expected " << expected_color << " Actual "
  1127. << actual_color;
  1128. }
  1129. // Present without clearing. This will flip front and back buffers so the
  1130. // previous rendered contents (red) will become visible again.
  1131. {
  1132. ASSERT_TRUE(SUCCEEDED(swap_chain->Present1(0, 0, &present_params)));
  1133. std::unique_ptr<ui::DCRendererLayerParams> dc_layer_params =
  1134. std::make_unique<ui::DCRendererLayerParams>();
  1135. dc_layer_params->images[0] = front_buffer_image;
  1136. dc_layer_params->content_rect = gfx::Rect(swap_chain_size);
  1137. dc_layer_params->quad_rect = gfx::Rect(window_size);
  1138. surface_->ScheduleDCLayer(std::move(dc_layer_params));
  1139. EXPECT_EQ(gfx::SwapResult::SWAP_ACK,
  1140. surface_->SwapBuffers(base::DoNothing()));
  1141. SkColor expected_color = SK_ColorRED;
  1142. SkColor actual_color =
  1143. ReadBackWindowPixel(window_.hwnd(), gfx::Point(75, 75));
  1144. EXPECT_TRUE(AreColorsSimilar(expected_color, actual_color))
  1145. << std::hex << "Expected " << expected_color << " Actual "
  1146. << actual_color;
  1147. }
  1148. // Clear to blue without present.
  1149. {
  1150. float clear_color[] = {0.0, 0.0, 1.0, 1.0};
  1151. context->ClearRenderTargetView(rtv.Get(), clear_color);
  1152. std::unique_ptr<ui::DCRendererLayerParams> dc_layer_params =
  1153. std::make_unique<ui::DCRendererLayerParams>();
  1154. dc_layer_params->images[0] = front_buffer_image;
  1155. dc_layer_params->content_rect = gfx::Rect(swap_chain_size);
  1156. dc_layer_params->quad_rect = gfx::Rect(window_size);
  1157. surface_->ScheduleDCLayer(std::move(dc_layer_params));
  1158. EXPECT_EQ(gfx::SwapResult::SWAP_ACK,
  1159. surface_->SwapBuffers(base::DoNothing()));
  1160. SkColor expected_color = SK_ColorRED;
  1161. SkColor actual_color =
  1162. ReadBackWindowPixel(window_.hwnd(), gfx::Point(75, 75));
  1163. EXPECT_TRUE(AreColorsSimilar(expected_color, actual_color))
  1164. << std::hex << "Expected " << expected_color << " Actual "
  1165. << actual_color;
  1166. }
  1167. }
  1168. // Offsets BeginDraw update rect so that the returned update offset is also
  1169. // offset by at least the same amount from the original update rect.
  1170. class DrawOffsetOverridingDCompositionSurface
  1171. : public Microsoft::WRL::RuntimeClass<
  1172. Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>,
  1173. IDCompositionSurface> {
  1174. public:
  1175. DrawOffsetOverridingDCompositionSurface(
  1176. Microsoft::WRL::ComPtr<IDCompositionSurface> surface,
  1177. const gfx::Point& draw_offset)
  1178. : surface_(std::move(surface)), draw_offset_(draw_offset) {}
  1179. IFACEMETHODIMP BeginDraw(const RECT* updateRect,
  1180. REFIID iid,
  1181. void** updateObject,
  1182. POINT* updateOffset) override {
  1183. RECT offsetRect = *updateRect;
  1184. offsetRect.left += draw_offset_.x();
  1185. offsetRect.right += draw_offset_.x();
  1186. offsetRect.top += draw_offset_.y();
  1187. offsetRect.bottom += draw_offset_.y();
  1188. return surface_->BeginDraw(&offsetRect, iid, updateObject, updateOffset);
  1189. }
  1190. IFACEMETHODIMP EndDraw() override { return surface_->EndDraw(); }
  1191. IFACEMETHODIMP ResumeDraw() override { return surface_->ResumeDraw(); }
  1192. IFACEMETHODIMP SuspendDraw() override { return surface_->SuspendDraw(); }
  1193. IFACEMETHODIMP Scroll(const RECT* scrollRect,
  1194. const RECT* clipRect,
  1195. int offsetX,
  1196. int offsetY) override {
  1197. return surface_->Scroll(scrollRect, clipRect, offsetX, offsetY);
  1198. }
  1199. private:
  1200. Microsoft::WRL::ComPtr<IDCompositionSurface> surface_;
  1201. const gfx::Point draw_offset_;
  1202. };
  1203. TEST_F(DirectCompositionPixelTest, RootSurfaceDrawOffset) {
  1204. if (!surface_)
  1205. return;
  1206. constexpr gfx::Size window_size(100, 100);
  1207. EXPECT_TRUE(surface_->Resize(window_size, 1.0, gfx::ColorSpace(), true));
  1208. EXPECT_TRUE(surface_->SetDrawRectangle(gfx::Rect(window_size)));
  1209. glClearColor(0.0, 0.0, 1.0, 1.0);
  1210. glClear(GL_COLOR_BUFFER_BIT);
  1211. EXPECT_EQ(gfx::SwapResult::SWAP_ACK,
  1212. surface_->SwapBuffers(base::DoNothing()));
  1213. constexpr gfx::Point draw_offset(50, 50);
  1214. auto root_surface = surface_->GetRootSurfaceForTesting();
  1215. auto dcomp_surface =
  1216. Microsoft::WRL::Make<DrawOffsetOverridingDCompositionSurface>(
  1217. root_surface->dcomp_surface(), draw_offset);
  1218. root_surface->SetDCompSurfaceForTesting(std::move(dcomp_surface));
  1219. // Even though draw_rect is the first quadrant, the rendering will be limited
  1220. // to the third quadrant because the dcomp surface will return that offset.
  1221. constexpr gfx::Rect draw_rect(0, 0, 50, 50);
  1222. EXPECT_TRUE(surface_->SetDrawRectangle(draw_rect));
  1223. glClearColor(1.0, 0.0, 0.0, 1.0);
  1224. glClear(GL_COLOR_BUFFER_BIT);
  1225. EXPECT_EQ(gfx::SwapResult::SWAP_ACK,
  1226. surface_->SwapBuffers(base::DoNothing()));
  1227. Sleep(1000);
  1228. // Note: The colors read back are BGRA so the expected colors are inverted
  1229. // with respect to the clear color.
  1230. struct {
  1231. gfx::Point position;
  1232. SkColor expected_color;
  1233. } test_cases[] = {{gfx::Point(75, 75), SkColorSetRGB(255, 0, 0)},
  1234. {gfx::Point(25, 25), SkColorSetRGB(0, 0, 255)}};
  1235. for (const auto& test_case : test_cases) {
  1236. SkColor actual_color =
  1237. ReadBackWindowPixel(window_.hwnd(), test_case.position);
  1238. EXPECT_TRUE(AreColorsSimilar(test_case.expected_color, actual_color))
  1239. << std::hex << "Expected " << test_case.expected_color << " Actual "
  1240. << actual_color;
  1241. }
  1242. }
  1243. void RunBufferCountTest(scoped_refptr<DirectCompositionSurfaceWin> surface,
  1244. UINT buffer_count,
  1245. bool for_video) {
  1246. if (!surface)
  1247. return;
  1248. if (for_video) {
  1249. SetDirectCompositionScaledOverlaysSupportedForTesting(true);
  1250. EXPECT_TRUE(surface->SetEnableDCLayers(true));
  1251. } else {
  1252. EXPECT_TRUE(surface->SetEnableDCLayers(false));
  1253. }
  1254. constexpr gfx::Size window_size(100, 100);
  1255. EXPECT_TRUE(surface->Resize(window_size, 1.0, gfx::ColorSpace(), true));
  1256. EXPECT_TRUE(surface->SetDrawRectangle(gfx::Rect(window_size)));
  1257. glClearColor(0.0, 0.0, 0.0, 1.0);
  1258. glClear(GL_COLOR_BUFFER_BIT);
  1259. constexpr gfx::Size texture_size(50, 50);
  1260. if (for_video) {
  1261. Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
  1262. QueryD3D11DeviceObjectFromANGLE();
  1263. ASSERT_TRUE(d3d11_device);
  1264. Microsoft::WRL::ComPtr<ID3D11Texture2D> texture =
  1265. CreateNV12Texture(d3d11_device, texture_size, /*shared=*/false);
  1266. // The format doesn't matter, since we aren't binding.
  1267. scoped_refptr<GLImageDXGI> image_dxgi(
  1268. new GLImageDXGI(texture_size, nullptr));
  1269. image_dxgi->SetTexture(texture, /*level=*/0);
  1270. std::unique_ptr<ui::DCRendererLayerParams> params =
  1271. std::make_unique<ui::DCRendererLayerParams>();
  1272. params->images[0] = image_dxgi;
  1273. params->content_rect = gfx::Rect(texture_size);
  1274. params->quad_rect = gfx::Rect(window_size);
  1275. EXPECT_TRUE(surface->ScheduleDCLayer(std::move(params)));
  1276. }
  1277. EXPECT_EQ(gfx::SwapResult::SWAP_ACK, surface->SwapBuffers(base::DoNothing()));
  1278. auto swap_chain = for_video ? surface->GetLayerSwapChainForTesting(0)
  1279. : surface->GetBackbufferSwapChainForTesting();
  1280. ASSERT_TRUE(swap_chain);
  1281. DXGI_SWAP_CHAIN_DESC1 desc;
  1282. EXPECT_TRUE(SUCCEEDED(swap_chain->GetDesc1(&desc)));
  1283. // The expected size is window_size(100, 100).
  1284. EXPECT_EQ(100u, desc.Width);
  1285. EXPECT_EQ(100u, desc.Height);
  1286. EXPECT_EQ(buffer_count, desc.BufferCount);
  1287. }
  1288. TEST_F(DirectCompositionSurfaceTest, RootSwapChainBufferCount) {
  1289. RunBufferCountTest(surface_, /*buffer_count=*/2u, /*for_video=*/false);
  1290. }
  1291. TEST_F(DirectCompositionSurfaceTest, VideoSwapChainBufferCount) {
  1292. RunBufferCountTest(surface_, /*buffer_count=*/2u, /*for_video=*/true);
  1293. }
  1294. class DirectCompositionTripleBufferingTest
  1295. : public DirectCompositionSurfaceTest {
  1296. public:
  1297. DirectCompositionTripleBufferingTest() = default;
  1298. ~DirectCompositionTripleBufferingTest() override = default;
  1299. protected:
  1300. void SetUp() override {
  1301. feature_list_.InitWithFeatures({features::kDCompTripleBufferRootSwapChain,
  1302. features::kDCompTripleBufferVideoSwapChain},
  1303. {});
  1304. DirectCompositionSurfaceTest::SetUp();
  1305. }
  1306. private:
  1307. base::test::ScopedFeatureList feature_list_;
  1308. };
  1309. TEST_F(DirectCompositionTripleBufferingTest, MainSwapChainBufferCount) {
  1310. RunBufferCountTest(surface_, /*buffer_count=*/3u, /*for_video=*/false);
  1311. }
  1312. TEST_F(DirectCompositionTripleBufferingTest, VideoSwapChainBufferCount) {
  1313. RunBufferCountTest(surface_, /*buffer_count=*/3u, /*for_video=*/true);
  1314. }
  1315. } // namespace
  1316. } // namespace gl