Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(179)

Side by Side Diff: gpu/ipc/service/direct_composition_surface_win_unittest.cc

Issue 2749023011: Add DirectComposition overlay support. (Closed)
Patch Set: remove skia usage in unit test Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « gpu/ipc/service/direct_composition_surface_win.cc ('k') | ui/gl/dc_renderer_layer_params.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2017 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "gpu/ipc/service/direct_composition_surface_win.h" 5 #include "gpu/ipc/service/direct_composition_surface_win.h"
6 #include "base/memory/weak_ptr.h" 6 #include "base/memory/weak_ptr.h"
7 #include "base/run_loop.h" 7 #include "base/run_loop.h"
8 #include "base/synchronization/waitable_event.h" 8 #include "base/synchronization/waitable_event.h"
9 #include "base/threading/thread_task_runner_handle.h"
10 #include "base/win/scoped_gdi_object.h"
11 #include "base/win/scoped_hdc.h"
12 #include "base/win/scoped_select_object.h"
9 #include "testing/gtest/include/gtest/gtest.h" 13 #include "testing/gtest/include/gtest/gtest.h"
10 #include "ui/base/win/hidden_window.h" 14 #include "ui/base/win/hidden_window.h"
15 #include "ui/gfx/gdi_util.h"
16 #include "ui/gfx/transform.h"
17 #include "ui/gl/dc_renderer_layer_params.h"
11 #include "ui/gl/gl_angle_util_win.h" 18 #include "ui/gl/gl_angle_util_win.h"
12 #include "ui/gl/gl_context.h" 19 #include "ui/gl/gl_context.h"
20 #include "ui/gl/gl_image_dxgi.h"
13 #include "ui/gl/init/gl_factory.h" 21 #include "ui/gl/init/gl_factory.h"
22 #include "ui/platform_window/platform_window_delegate.h"
23 #include "ui/platform_window/win/win_window.h"
14 24
15 namespace gpu { 25 namespace gpu {
16 namespace { 26 namespace {
17 27
28 bool CheckIfDCSupported() {
29 if (!gl::QueryDirectCompositionDevice(
30 gl::QueryD3D11DeviceObjectFromANGLE())) {
31 LOG(WARNING)
32 << "GL implementation not using DirectComposition, skipping test.";
33 return false;
34 }
35 return true;
36 }
37
18 class TestImageTransportSurfaceDelegate 38 class TestImageTransportSurfaceDelegate
19 : public ImageTransportSurfaceDelegate, 39 : public ImageTransportSurfaceDelegate,
20 public base::SupportsWeakPtr<TestImageTransportSurfaceDelegate> { 40 public base::SupportsWeakPtr<TestImageTransportSurfaceDelegate> {
21 public: 41 public:
22 ~TestImageTransportSurfaceDelegate() override {} 42 ~TestImageTransportSurfaceDelegate() override {}
23 43
24 // ImageTransportSurfaceDelegate implementation. 44 // ImageTransportSurfaceDelegate implementation.
25 void DidCreateAcceleratedSurfaceChildWindow( 45 void DidCreateAcceleratedSurfaceChildWindow(
26 SurfaceHandle parent_window, 46 SurfaceHandle parent_window,
27 SurfaceHandle child_window) override {} 47 SurfaceHandle child_window) override {
48 if (parent_window)
49 ::SetParent(child_window, parent_window);
50 }
28 void DidSwapBuffersComplete(SwapBuffersCompleteParams params) override {} 51 void DidSwapBuffersComplete(SwapBuffersCompleteParams params) override {}
29 const gles2::FeatureInfo* GetFeatureInfo() const override { return nullptr; } 52 const gles2::FeatureInfo* GetFeatureInfo() const override { return nullptr; }
30 void SetLatencyInfoCallback(const LatencyInfoCallback& callback) override {} 53 void SetLatencyInfoCallback(const LatencyInfoCallback& callback) override {}
31 void UpdateVSyncParameters(base::TimeTicks timebase, 54 void UpdateVSyncParameters(base::TimeTicks timebase,
32 base::TimeDelta interval) override {} 55 base::TimeDelta interval) override {}
33 void AddFilter(IPC::MessageFilter* message_filter) override {} 56 void AddFilter(IPC::MessageFilter* message_filter) override {}
34 int32_t GetRouteID() const override { return 0; } 57 int32_t GetRouteID() const override { return 0; }
35 }; 58 };
36 59
60 class TestPlatformDelegate : public ui::PlatformWindowDelegate {
61 public:
62 // ui::PlatformWindowDelegate implementation.
63 void OnBoundsChanged(const gfx::Rect& new_bounds) override {}
64 void OnDamageRect(const gfx::Rect& damaged_region) override {}
65 void DispatchEvent(ui::Event* event) override {}
66 void OnCloseRequest() override {}
67 void OnClosed() override {}
68 void OnWindowStateChanged(ui::PlatformWindowState new_state) override {}
69 void OnLostCapture() override {}
70 void OnAcceleratedWidgetAvailable(gfx::AcceleratedWidget widget,
71 float device_pixel_ratio) override {}
72 void OnAcceleratedWidgetDestroyed() override {}
73 void OnActivationChanged(bool active) override {}
74 };
75
37 void RunPendingTasks(scoped_refptr<base::TaskRunner> task_runner) { 76 void RunPendingTasks(scoped_refptr<base::TaskRunner> task_runner) {
38 base::WaitableEvent done(base::WaitableEvent::ResetPolicy::AUTOMATIC, 77 base::WaitableEvent done(base::WaitableEvent::ResetPolicy::AUTOMATIC,
39 base::WaitableEvent::InitialState::NOT_SIGNALED); 78 base::WaitableEvent::InitialState::NOT_SIGNALED);
40 task_runner->PostTask(FROM_HERE, 79 task_runner->PostTask(FROM_HERE,
41 Bind(&base::WaitableEvent::Signal, Unretained(&done))); 80 Bind(&base::WaitableEvent::Signal, Unretained(&done)));
42 done.Wait(); 81 done.Wait();
43 } 82 }
44 83
45 void DestroySurface(scoped_refptr<DirectCompositionSurfaceWin> surface) { 84 void DestroySurface(scoped_refptr<DirectCompositionSurfaceWin> surface) {
46 scoped_refptr<base::TaskRunner> task_runner = 85 scoped_refptr<base::TaskRunner> task_runner =
47 surface->GetWindowTaskRunnerForTesting(); 86 surface->GetWindowTaskRunnerForTesting();
48 DCHECK(surface->HasOneRef()); 87 DCHECK(surface->HasOneRef());
49 88
50 surface = nullptr; 89 surface = nullptr;
51 90
52 // Ensure that the ChildWindowWin posts the task to delete the thread to the 91 // Ensure that the ChildWindowWin posts the task to delete the thread to the
53 // main loop before doing RunUntilIdle. Otherwise the child threads could 92 // main loop before doing RunUntilIdle. Otherwise the child threads could
54 // outlive the main thread. 93 // outlive the main thread.
55 RunPendingTasks(task_runner); 94 RunPendingTasks(task_runner);
56 95
57 base::RunLoop().RunUntilIdle(); 96 base::RunLoop().RunUntilIdle();
58 } 97 }
59 98
60 TEST(DirectCompositionSurfaceTest, TestMakeCurrent) { 99 TEST(DirectCompositionSurfaceTest, TestMakeCurrent) {
61 if (!gl::QueryDirectCompositionDevice( 100 if (!CheckIfDCSupported())
62 gl::QueryD3D11DeviceObjectFromANGLE())) {
63 LOG(WARNING)
64 << "GL implementation not using DirectComposition, skipping test.";
65 return; 101 return;
66 }
67 102
68 TestImageTransportSurfaceDelegate delegate; 103 TestImageTransportSurfaceDelegate delegate;
69 104
70 scoped_refptr<DirectCompositionSurfaceWin> surface1( 105 scoped_refptr<DirectCompositionSurfaceWin> surface1(
71 new DirectCompositionSurfaceWin(delegate.AsWeakPtr(), 106 new DirectCompositionSurfaceWin(delegate.AsWeakPtr(),
72 ui::GetHiddenWindow())); 107 ui::GetHiddenWindow()));
73 EXPECT_TRUE(surface1->Initialize()); 108 EXPECT_TRUE(surface1->Initialize());
74 surface1->SetEnableDCLayers(true); 109 surface1->SetEnableDCLayers(true);
75 110
76 scoped_refptr<gl::GLContext> context1 = gl::init::CreateGLContext( 111 scoped_refptr<gl::GLContext> context1 = gl::init::CreateGLContext(
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
119 EXPECT_TRUE(context1->MakeCurrent(surface1.get())); 154 EXPECT_TRUE(context1->MakeCurrent(surface1.get()));
120 context2 = nullptr; 155 context2 = nullptr;
121 context1 = nullptr; 156 context1 = nullptr;
122 157
123 DestroySurface(std::move(surface1)); 158 DestroySurface(std::move(surface1));
124 DestroySurface(std::move(surface2)); 159 DestroySurface(std::move(surface2));
125 } 160 }
126 161
127 // Tests that switching using EnableDCLayers works. 162 // Tests that switching using EnableDCLayers works.
128 TEST(DirectCompositionSurfaceTest, DXGIDCLayerSwitch) { 163 TEST(DirectCompositionSurfaceTest, DXGIDCLayerSwitch) {
129 if (!gl::QueryDirectCompositionDevice( 164 if (!CheckIfDCSupported())
130 gl::QueryD3D11DeviceObjectFromANGLE())) {
131 LOG(WARNING)
132 << "GL implementation not using DirectComposition, skipping test.";
133 return; 165 return;
134 }
135 166
136 TestImageTransportSurfaceDelegate delegate; 167 TestImageTransportSurfaceDelegate delegate;
137 168
138 scoped_refptr<DirectCompositionSurfaceWin> surface( 169 scoped_refptr<DirectCompositionSurfaceWin> surface(
139 new DirectCompositionSurfaceWin(delegate.AsWeakPtr(), 170 new DirectCompositionSurfaceWin(delegate.AsWeakPtr(),
140 ui::GetHiddenWindow())); 171 ui::GetHiddenWindow()));
141 EXPECT_TRUE(surface->Initialize()); 172 EXPECT_TRUE(surface->Initialize());
142 173
143 scoped_refptr<gl::GLContext> context = 174 scoped_refptr<gl::GLContext> context =
144 gl::init::CreateGLContext(nullptr, surface.get(), gl::GLContextAttribs()); 175 gl::init::CreateGLContext(nullptr, surface.get(), gl::GLContextAttribs());
(...skipping 29 matching lines...) Expand all
174 205
175 // Surface switched to use IDXGISwapChain, so must draw to entire 206 // Surface switched to use IDXGISwapChain, so must draw to entire
176 // surface. 207 // surface.
177 EXPECT_FALSE(surface->SetDrawRectangle(gfx::Rect(0, 0, 50, 50))); 208 EXPECT_FALSE(surface->SetDrawRectangle(gfx::Rect(0, 0, 50, 50)));
178 EXPECT_TRUE(surface->SetDrawRectangle(gfx::Rect(0, 0, 100, 100))); 209 EXPECT_TRUE(surface->SetDrawRectangle(gfx::Rect(0, 0, 100, 100)));
179 EXPECT_TRUE(surface->swap_chain()); 210 EXPECT_TRUE(surface->swap_chain());
180 211
181 context = nullptr; 212 context = nullptr;
182 DestroySurface(std::move(surface)); 213 DestroySurface(std::move(surface));
183 } 214 }
215
216 COLORREF ReadBackWindowPixel(HWND window, const gfx::Point& point) {
217 base::win::ScopedCreateDC mem_hdc(::CreateCompatibleDC(nullptr));
218 void* bits = nullptr;
219 BITMAPV4HEADER hdr;
220 gfx::CreateBitmapV4Header(point.x() + 1, point.y() + 1, &hdr);
221 DCHECK(mem_hdc.IsValid());
222 base::win::ScopedBitmap bitmap(
223 ::CreateDIBSection(mem_hdc.Get(), reinterpret_cast<BITMAPINFO*>(&hdr),
224 DIB_RGB_COLORS, &bits, nullptr, 0));
225 DCHECK(bitmap.is_valid());
226
227 base::win::ScopedSelectObject select_object(mem_hdc.Get(), bitmap.get());
228
229 // Grab a copy of the window. Use PrintWindow because it works even when the
230 // window's partially occluded. The PW_RENDERFULLCONTENT flag is undocumented,
231 // but works starting in Windows 8.1. It allows for capturing the contents of
232 // the window that are drawn using DirectComposition.
233 UINT flags = PW_CLIENTONLY | PW_RENDERFULLCONTENT;
234
235 BOOL result = PrintWindow(window, mem_hdc.Get(), flags);
236 if (!result)
237 PLOG(ERROR) << "Failed to print window";
238
239 GdiFlush();
240
241 uint32_t pixel_value =
242 static_cast<uint32_t*>(bits)[hdr.bV4Width * point.y() + point.x()];
243
244 return pixel_value;
245 }
246
247 class DirectCompositionPixelTest : public testing::Test {
248 public:
249 DirectCompositionPixelTest()
250 : window_(&platform_delegate_, gfx::Rect(0, 0, 100, 100)) {}
251
252 protected:
253 void InitializeSurface() {
254 static_cast<ui::PlatformWindow*>(&window_)->Show();
255
256 surface_ =
257 new DirectCompositionSurfaceWin(delegate_.AsWeakPtr(), window_.hwnd());
258 EXPECT_TRUE(surface_->Initialize());
259 }
260
261 void PixelTestSwapChain(bool layers_enabled) {
262 if (!CheckIfDCSupported())
263 return;
264
265 InitializeSurface();
266
267 surface_->SetEnableDCLayers(layers_enabled);
268 gfx::Size window_size(100, 100);
269
270 scoped_refptr<gl::GLContext> context = gl::init::CreateGLContext(
271 nullptr, surface_.get(), gl::GLContextAttribs());
272 EXPECT_TRUE(surface_->Resize(window_size, 1.0, true));
273 EXPECT_TRUE(surface_->SetDrawRectangle(gfx::Rect(window_size)));
274 EXPECT_TRUE(context->MakeCurrent(surface_.get()));
275
276 glClearColor(1.0, 0.0, 0.0, 1.0);
277 glClear(GL_COLOR_BUFFER_BIT);
278
279 EXPECT_EQ(gfx::SwapResult::SWAP_ACK, surface_->SwapBuffers());
280
281 // Ensure DWM swap completed.
282 Sleep(1000);
283
284 SkColor actual_color =
285 ReadBackWindowPixel(window_.hwnd(), gfx::Point(75, 75));
286 EXPECT_EQ(SK_ColorRED, actual_color);
287
288 EXPECT_TRUE(context->IsCurrent(surface_.get()));
289
290 context = nullptr;
291 DestroySurface(std::move(surface_));
292 }
293
294 TestPlatformDelegate platform_delegate_;
295 TestImageTransportSurfaceDelegate delegate_;
296 ui::WinWindow window_;
297 scoped_refptr<DirectCompositionSurfaceWin> surface_;
298 };
299
300 TEST_F(DirectCompositionPixelTest, DCLayersEnabled) {
301 PixelTestSwapChain(true);
302 }
303
304 TEST_F(DirectCompositionPixelTest, DCLayersDisabled) {
305 PixelTestSwapChain(false);
306 }
307
308 base::win::ScopedComPtr<ID3D11Texture2D> CreateNV12Texture(
309 const base::win::ScopedComPtr<ID3D11Device>& d3d11_device,
310 const gfx::Size& size) {
311 D3D11_TEXTURE2D_DESC desc = {};
312 desc.Width = size.width();
313 desc.Height = size.height();
314 desc.MipLevels = 1;
315 desc.ArraySize = 1;
316 desc.Format = DXGI_FORMAT_NV12;
317 desc.Usage = D3D11_USAGE_DEFAULT;
318 desc.SampleDesc.Count = 1;
319 desc.BindFlags = 0;
320
321 std::vector<char> image_data(size.width() * size.height() * 3 / 2);
322 // Y, U, and V should all be Oxff. Output color should be pink.
323 memset(&image_data[0], 0xff, size.width() * size.height() * 3 / 2);
324
325 D3D11_SUBRESOURCE_DATA data = {};
326 data.pSysMem = (const void*)&image_data[0];
327 data.SysMemPitch = size.width();
328
329 base::win::ScopedComPtr<ID3D11Texture2D> texture;
330 HRESULT hr = d3d11_device->CreateTexture2D(&desc, &data, texture.Receive());
331 CHECK(SUCCEEDED(hr));
332 return texture;
333 }
334
335 bool AreColorsSimilar(int a, int b) {
336 // The precise colors may differ depending on the video processor, so allow
337 // a margin for error.
338 const int kMargin = 10;
339 return abs(SkColorGetA(a) - SkColorGetA(b)) < kMargin &&
340 abs(SkColorGetR(a) - SkColorGetR(b)) < kMargin &&
341 abs(SkColorGetG(a) - SkColorGetG(b)) < kMargin &&
342 abs(SkColorGetB(a) - SkColorGetB(b)) < kMargin;
343 }
344
345 TEST_F(DirectCompositionPixelTest, VideoSwapchain) {
346 if (!CheckIfDCSupported())
347 return;
348 InitializeSurface();
349 surface_->SetEnableDCLayers(true);
350 gfx::Size window_size(100, 100);
351
352 scoped_refptr<gl::GLContext> context = gl::init::CreateGLContext(
353 nullptr, surface_.get(), gl::GLContextAttribs());
354 EXPECT_TRUE(surface_->Resize(window_size, 1.0, true));
355
356 base::win::ScopedComPtr<ID3D11Device> d3d11_device =
357 gl::QueryD3D11DeviceObjectFromANGLE();
358
359 gfx::Size texture_size(50, 50);
360 base::win::ScopedComPtr<ID3D11Texture2D> texture =
361 CreateNV12Texture(d3d11_device, texture_size);
362
363 scoped_refptr<gl::GLImageDXGI> image_dxgi(
364 new gl::GLImageDXGI(texture_size, nullptr));
365 image_dxgi->SetTexture(texture, 0);
366
367 ui::DCRendererLayerParams params(false, gfx::Rect(), 1, gfx::Transform(),
368 image_dxgi.get(),
369 gfx::RectF(gfx::Rect(texture_size)),
370 gfx::Rect(window_size), 0, 0, 1.0, 0);
371 surface_->ScheduleDCLayer(params);
372
373 EXPECT_EQ(gfx::SwapResult::SWAP_ACK, surface_->SwapBuffers());
374 Sleep(1000);
375
376 SkColor expected_color = SkColorSetRGB(0xff, 0xb7, 0xff);
377 SkColor actual_color =
378 ReadBackWindowPixel(window_.hwnd(), gfx::Point(75, 75));
379 EXPECT_TRUE(AreColorsSimilar(expected_color, actual_color))
380 << std::hex << "Expected " << expected_color << " Actual "
381 << actual_color;
382
383 context = nullptr;
384 DestroySurface(std::move(surface_));
385 }
386
184 } // namespace 387 } // namespace
185 } // namespace gpu 388 } // namespace gpu
OLDNEW
« no previous file with comments | « gpu/ipc/service/direct_composition_surface_win.cc ('k') | ui/gl/dc_renderer_layer_params.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698