OLD | NEW |
---|---|
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 | 6 |
7 #include <d3d11_1.h> | |
8 #include <dcomptypes.h> | |
9 | |
10 #include "base/memory/ptr_util.h" | |
7 #include "base/optional.h" | 11 #include "base/optional.h" |
8 #include "base/synchronization/waitable_event.h" | 12 #include "base/synchronization/waitable_event.h" |
13 #include "base/trace_event/trace_event.h" | |
14 #include "base/win/scoped_handle.h" | |
9 #include "gpu/ipc/service/gpu_channel_manager.h" | 15 #include "gpu/ipc/service/gpu_channel_manager.h" |
10 #include "gpu/ipc/service/gpu_channel_manager_delegate.h" | 16 #include "gpu/ipc/service/gpu_channel_manager_delegate.h" |
11 #include "gpu/ipc/service/switches.h" | 17 #include "gpu/ipc/service/switches.h" |
12 #include "ui/display/display_switches.h" | 18 #include "ui/display/display_switches.h" |
19 #include "ui/gfx/geometry/size_conversions.h" | |
13 #include "ui/gfx/native_widget_types.h" | 20 #include "ui/gfx/native_widget_types.h" |
21 #include "ui/gfx/transform.h" | |
22 #include "ui/gl/dc_renderer_layer_params.h" | |
14 #include "ui/gl/egl_util.h" | 23 #include "ui/gl/egl_util.h" |
15 #include "ui/gl/gl_angle_util_win.h" | 24 #include "ui/gl/gl_angle_util_win.h" |
16 #include "ui/gl/gl_context.h" | 25 #include "ui/gl/gl_context.h" |
26 #include "ui/gl/gl_image_dxgi.h" | |
17 #include "ui/gl/gl_surface_egl.h" | 27 #include "ui/gl/gl_surface_egl.h" |
18 #include "ui/gl/scoped_make_current.h" | 28 #include "ui/gl/scoped_make_current.h" |
19 | 29 |
20 #ifndef EGL_ANGLE_flexible_surface_compatibility | 30 #ifndef EGL_ANGLE_flexible_surface_compatibility |
21 #define EGL_ANGLE_flexible_surface_compatibility 1 | 31 #define EGL_ANGLE_flexible_surface_compatibility 1 |
22 #define EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE 0x33A6 | 32 #define EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE 0x33A6 |
23 #endif /* EGL_ANGLE_flexible_surface_compatibility */ | 33 #endif /* EGL_ANGLE_flexible_surface_compatibility */ |
24 | 34 |
25 #ifndef EGL_ANGLE_d3d_texture_client_buffer | 35 #ifndef EGL_ANGLE_d3d_texture_client_buffer |
26 #define EGL_ANGLE_d3d_texture_client_buffer 1 | 36 #define EGL_ANGLE_d3d_texture_client_buffer 1 |
(...skipping 14 matching lines...) Expand all Loading... | |
41 if (was_current) { | 51 if (was_current) { |
42 make_current_.emplace(current_context, this_surface); | 52 make_current_.emplace(current_context, this_surface); |
43 current_context->ReleaseCurrent(this_surface); | 53 current_context->ReleaseCurrent(this_surface); |
44 } | 54 } |
45 } | 55 } |
46 | 56 |
47 private: | 57 private: |
48 base::Optional<ui::ScopedMakeCurrent> make_current_; | 58 base::Optional<ui::ScopedMakeCurrent> make_current_; |
49 }; | 59 }; |
50 | 60 |
61 bool SizeContains(const gfx::Size& a, const gfx::Size& b) { | |
62 return gfx::Rect(a).Contains(gfx::Rect(b)); | |
63 } | |
64 | |
51 // Only one DirectComposition surface can be rendered into at a time. Track | 65 // Only one DirectComposition surface can be rendered into at a time. Track |
52 // here which IDCompositionSurface is being rendered into. If another context | 66 // here which IDCompositionSurface is being rendered into. If another context |
53 // is made current, then this surface will be suspended. | 67 // is made current, then this surface will be suspended. |
54 IDCompositionSurface* g_current_surface; | 68 IDCompositionSurface* g_current_surface; |
55 | 69 |
56 } // namespace | 70 } // namespace |
57 | 71 |
72 class DCLayerTree { | |
73 public: | |
74 DCLayerTree(DirectCompositionSurfaceWin* surface, | |
75 const base::win::ScopedComPtr<ID3D11Device>& d3d11_device, | |
76 const base::win::ScopedComPtr<IDCompositionDevice2>& dcomp_device) | |
77 : surface_(surface), | |
78 d3d11_device_(d3d11_device), | |
79 dcomp_device_(dcomp_device) {} | |
80 | |
81 bool Initialize(HWND window); | |
82 bool CommitAndClearPendingOverlays(); | |
83 bool ScheduleDCLayer(const ui::DCRendererLayerParams& params); | |
84 void InitializeVideoProcessor(const gfx::Size& input_size, | |
85 const gfx::Size& output_size); | |
86 | |
87 const base::win::ScopedComPtr<ID3D11VideoProcessor>& video_processor() const { | |
88 return video_processor_; | |
89 } | |
90 const base::win::ScopedComPtr<ID3D11VideoProcessorEnumerator>& | |
91 video_processor_enumerator() const { | |
92 return video_processor_enumerator_; | |
93 } | |
94 | |
95 private: | |
96 class SwapChainPresenter; | |
97 | |
98 // This struct is used to cache information about what visuals are currently | |
99 // being presented so that properties that aren't changed aren't sent to | |
100 // DirectComposition. | |
101 struct VisualInfo { | |
102 base::win::ScopedComPtr<IDCompositionVisual2> content_visual; | |
103 base::win::ScopedComPtr<IDCompositionVisual2> clip_visual; | |
104 | |
105 std::unique_ptr<SwapChainPresenter> swap_chain_presenter; | |
106 base::win::ScopedComPtr<IDXGISwapChain1> swap_chain; | |
107 base::win::ScopedComPtr<IDCompositionSurface> surface; | |
108 | |
109 gfx::Rect bounds; | |
110 float swap_chain_scale_x = 0.0f; | |
111 float swap_chain_scale_y = 0.0f; | |
112 bool is_clipped = false; | |
113 gfx::Rect clip_rect; | |
114 gfx::Transform transform; | |
115 }; | |
116 | |
117 void InitVisual(size_t i); | |
118 void UpdateVisualForVideo(VisualInfo* visual_info, | |
119 const ui::DCRendererLayerParams& params); | |
120 void UpdateVisualForBackbuffer(VisualInfo* visual_info, | |
121 const ui::DCRendererLayerParams& params); | |
122 void UpdateVisualClip(VisualInfo* visual_info, | |
123 const ui::DCRendererLayerParams& params); | |
124 | |
125 DirectCompositionSurfaceWin* surface_; | |
126 std::vector<std::unique_ptr<ui::DCRendererLayerParams>> pending_overlays_; | |
127 | |
128 base::win::ScopedComPtr<ID3D11Device> d3d11_device_; | |
129 base::win::ScopedComPtr<IDCompositionDevice2> dcomp_device_; | |
130 base::win::ScopedComPtr<IDCompositionTarget> dcomp_target_; | |
131 base::win::ScopedComPtr<IDCompositionVisual2> root_visual_; | |
132 | |
133 // The video processor is cached so SwapChains don't have to recreate it | |
134 // whenever they're created. | |
135 base::win::ScopedComPtr<ID3D11VideoDevice> video_device_; | |
136 base::win::ScopedComPtr<ID3D11VideoContext> video_context_; | |
137 base::win::ScopedComPtr<ID3D11VideoProcessor> video_processor_; | |
138 base::win::ScopedComPtr<ID3D11VideoProcessorEnumerator> | |
139 video_processor_enumerator_; | |
140 gfx::Size video_input_size_; | |
141 gfx::Size video_output_size_; | |
142 | |
143 std::vector<VisualInfo> visual_info_; | |
144 | |
145 DISALLOW_COPY_AND_ASSIGN(DCLayerTree); | |
146 }; | |
147 | |
148 class DCLayerTree::SwapChainPresenter { | |
149 public: | |
150 SwapChainPresenter(DCLayerTree* surface, | |
151 base::win::ScopedComPtr<ID3D11Device> d3d11_device); | |
152 | |
153 ~SwapChainPresenter(); | |
154 | |
155 void PresentToSwapChain(const ui::DCRendererLayerParams& overlay); | |
156 | |
157 float swap_chain_scale_x() const { return swap_chain_scale_x_; } | |
158 float swap_chain_scale_y() const { return swap_chain_scale_y_; } | |
159 const base::win::ScopedComPtr<IDXGISwapChain1> swap_chain() const { | |
sunnyps
2017/03/28 22:28:59
nit: I think you meant to return const ref here.
| |
160 return swap_chain_; | |
161 } | |
162 | |
163 private: | |
164 using PFN_DCOMPOSITION_CREATE_SURFACE_HANDLE = | |
165 HRESULT(WINAPI*)(DWORD, SECURITY_ATTRIBUTES*, HANDLE*); | |
166 | |
167 // Returns true if the video processor changed. | |
168 bool InitializeVideoProcessor(const gfx::Size& in_size, | |
169 const gfx::Size& out_size); | |
170 void ReallocateSwapChain(); | |
171 | |
172 DCLayerTree* surface_; | |
173 PFN_DCOMPOSITION_CREATE_SURFACE_HANDLE create_surface_handle_function_; | |
174 | |
175 gfx::Size swap_chain_size_; | |
176 gfx::Size processor_input_size_; | |
177 gfx::Size processor_output_size_; | |
178 | |
179 // This is the scale from the swapchain size to the size of the contents | |
180 // onscreen. | |
181 float swap_chain_scale_x_ = 0.0f; | |
182 float swap_chain_scale_y_ = 0.0f; | |
183 | |
184 base::win::ScopedComPtr<ID3D11Device> d3d11_device_; | |
185 base::win::ScopedComPtr<IDXGISwapChain1> swap_chain_; | |
186 base::win::ScopedComPtr<ID3D11VideoProcessorOutputView> out_view_; | |
187 base::win::ScopedComPtr<ID3D11VideoProcessor> video_processor_; | |
188 base::win::ScopedComPtr<ID3D11VideoProcessorEnumerator> | |
189 video_processor_enumerator_; | |
190 base::win::ScopedComPtr<ID3D11VideoDevice> video_device_; | |
191 base::win::ScopedComPtr<ID3D11VideoContext> video_context_; | |
192 | |
193 base::win::ScopedHandle swap_chain_handle_; | |
194 | |
195 DISALLOW_COPY_AND_ASSIGN(SwapChainPresenter); | |
196 }; | |
197 | |
198 bool DCLayerTree::Initialize(HWND window) { | |
199 d3d11_device_.QueryInterface(video_device_.Receive()); | |
200 base::win::ScopedComPtr<ID3D11DeviceContext> context; | |
201 d3d11_device_->GetImmediateContext(context.Receive()); | |
202 context.QueryInterface(video_context_.Receive()); | |
203 | |
204 base::win::ScopedComPtr<IDCompositionDesktopDevice> desktop_device; | |
205 dcomp_device_.QueryInterface(desktop_device.Receive()); | |
206 | |
207 HRESULT hr = desktop_device->CreateTargetForHwnd(window, TRUE, | |
208 dcomp_target_.Receive()); | |
209 if (FAILED(hr)) | |
210 return false; | |
211 | |
212 hr = dcomp_device_->CreateVisual(root_visual_.Receive()); | |
213 if (FAILED(hr)) | |
214 return false; | |
215 | |
216 dcomp_target_->SetRoot(root_visual_.get()); | |
217 return true; | |
218 } | |
219 | |
220 void DCLayerTree::InitializeVideoProcessor(const gfx::Size& input_size, | |
221 const gfx::Size& output_size) { | |
222 if (SizeContains(video_input_size_, input_size) && | |
223 SizeContains(video_output_size_, output_size)) | |
224 return; | |
225 video_input_size_ = input_size; | |
226 video_output_size_ = output_size; | |
227 | |
228 video_processor_.Release(); | |
229 video_processor_enumerator_.Receive(); | |
230 D3D11_VIDEO_PROCESSOR_CONTENT_DESC desc = {}; | |
231 desc.InputFrameFormat = D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE; | |
232 desc.InputFrameRate.Numerator = 60; | |
233 desc.InputFrameRate.Denominator = 1; | |
234 desc.InputWidth = input_size.width(); | |
235 desc.InputHeight = input_size.height(); | |
236 desc.OutputFrameRate.Numerator = 60; | |
237 desc.OutputFrameRate.Denominator = 1; | |
238 desc.OutputWidth = output_size.width(); | |
239 desc.OutputHeight = output_size.height(); | |
240 desc.Usage = D3D11_VIDEO_USAGE_PLAYBACK_NORMAL; | |
241 HRESULT hr = video_device_->CreateVideoProcessorEnumerator( | |
242 &desc, video_processor_enumerator_.Receive()); | |
243 CHECK(SUCCEEDED(hr)); | |
244 | |
245 hr = video_device_->CreateVideoProcessor(video_processor_enumerator_.get(), 0, | |
246 video_processor_.Receive()); | |
247 CHECK(SUCCEEDED(hr)); | |
248 } | |
249 | |
250 DCLayerTree::SwapChainPresenter::SwapChainPresenter( | |
251 DCLayerTree* surface, | |
252 base::win::ScopedComPtr<ID3D11Device> d3d11_device) | |
253 : surface_(surface), d3d11_device_(d3d11_device) { | |
254 d3d11_device_.QueryInterface(video_device_.Receive()); | |
255 base::win::ScopedComPtr<ID3D11DeviceContext> context; | |
256 d3d11_device_->GetImmediateContext(context.Receive()); | |
257 context.QueryInterface(video_context_.Receive()); | |
258 HMODULE dcomp = ::GetModuleHandleA("dcomp.dll"); | |
259 DCHECK(dcomp); | |
260 create_surface_handle_function_ = | |
261 reinterpret_cast<PFN_DCOMPOSITION_CREATE_SURFACE_HANDLE>( | |
262 GetProcAddress(dcomp, "DCompositionCreateSurfaceHandle")); | |
263 DCHECK(create_surface_handle_function_); | |
264 } | |
265 | |
266 DCLayerTree::SwapChainPresenter::~SwapChainPresenter() {} | |
267 | |
268 void DCLayerTree::SwapChainPresenter::PresentToSwapChain( | |
269 const ui::DCRendererLayerParams& params) { | |
270 gl::GLImageDXGI* image_dxgi = | |
271 gl::GLImageDXGI::FromGLImage(params.image.get()); | |
272 DCHECK(image_dxgi); | |
273 | |
274 // Swap chain size is the minimum of the on-screen size and the source | |
275 // size so the video processor can do the minimal amount of work and | |
276 // the overlay has to read the minimal amount of data. | |
277 // DWM is also less likely to promote a surface to an overlay if it's | |
278 // much larger than its area on-screen. | |
279 gfx::Rect bounds_rect = params.rect; | |
280 gfx::Size ceiled_input_size = gfx::ToCeiledSize(params.contents_rect.size()); | |
281 gfx::Size swap_chain_size = bounds_rect.size(); | |
282 swap_chain_size.SetToMin(ceiled_input_size); | |
283 | |
284 // YUY2 surfaces must have an even width. | |
285 if (swap_chain_size.width() % 2 == 1) | |
286 swap_chain_size.set_width(swap_chain_size.width() + 1); | |
287 | |
288 // out_view_ depends on video_processor_enumerator_, so ensure it's | |
289 // recreated if the enumerator is. | |
290 if (InitializeVideoProcessor(ceiled_input_size, swap_chain_size)) | |
291 out_view_.Release(); | |
292 | |
293 bool first_present = false; | |
294 if (!swap_chain_ || swap_chain_size_ != swap_chain_size) { | |
295 first_present = true; | |
296 swap_chain_size_ = swap_chain_size; | |
297 swap_chain_.Release(); | |
298 ReallocateSwapChain(); | |
299 } | |
300 | |
301 if (!out_view_) { | |
302 base::win::ScopedComPtr<ID3D11Texture2D> texture; | |
303 swap_chain_->GetBuffer(0, IID_PPV_ARGS(texture.Receive())); | |
304 D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC out_desc = {}; | |
305 out_desc.ViewDimension = D3D11_VPOV_DIMENSION_TEXTURE2D; | |
306 out_desc.Texture2D.MipSlice = 0; | |
307 out_view_.Release(); | |
sunnyps
2017/03/28 22:28:59
nit: out_view_.Release() here is a nop
| |
308 HRESULT hr = video_device_->CreateVideoProcessorOutputView( | |
309 texture.get(), video_processor_enumerator_.get(), &out_desc, | |
310 out_view_.Receive()); | |
311 CHECK(SUCCEEDED(hr)); | |
312 } | |
313 { | |
314 D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC in_desc = {}; | |
315 in_desc.ViewDimension = D3D11_VPIV_DIMENSION_TEXTURE2D; | |
316 in_desc.Texture2D.ArraySlice = (UINT)image_dxgi->level(); | |
317 base::win::ScopedComPtr<ID3D11VideoProcessorInputView> in_view; | |
318 HRESULT hr = video_device_->CreateVideoProcessorInputView( | |
319 image_dxgi->texture().get(), video_processor_enumerator_.get(), | |
320 &in_desc, in_view.Receive()); | |
321 CHECK(SUCCEEDED(hr)); | |
322 | |
323 D3D11_VIDEO_PROCESSOR_STREAM stream = {}; | |
324 stream.Enable = true; | |
325 stream.OutputIndex = 0; | |
326 stream.InputFrameOrField = 0; | |
327 stream.PastFrames = 0; | |
328 stream.FutureFrames = 0; | |
329 stream.pInputSurface = in_view.get(); | |
330 RECT dest_rect = gfx::Rect(swap_chain_size).ToRECT(); | |
331 video_context_->VideoProcessorSetOutputTargetRect(video_processor_.get(), | |
332 TRUE, &dest_rect); | |
333 video_context_->VideoProcessorSetStreamDestRect(video_processor_.get(), 0, | |
334 TRUE, &dest_rect); | |
335 RECT source_rect = gfx::Rect(ceiled_input_size).ToRECT(); | |
336 video_context_->VideoProcessorSetStreamSourceRect(video_processor_.get(), 0, | |
337 TRUE, &source_rect); | |
338 | |
339 video_context_->VideoProcessorSetStreamAutoProcessingMode( | |
340 video_processor_.get(), 0, FALSE); | |
341 | |
342 hr = video_context_->VideoProcessorBlt(video_processor_.get(), | |
343 out_view_.get(), 0, 1, &stream); | |
344 CHECK(SUCCEEDED(hr)); | |
345 } | |
346 | |
347 swap_chain_scale_x_ = bounds_rect.width() * 1.0f / swap_chain_size.width(); | |
348 swap_chain_scale_y_ = bounds_rect.height() * 1.0f / swap_chain_size.height(); | |
349 | |
350 swap_chain_->Present(first_present ? 0 : 1, 0); | |
351 } | |
352 | |
353 bool DCLayerTree::SwapChainPresenter::InitializeVideoProcessor( | |
354 const gfx::Size& in_size, | |
355 const gfx::Size& out_size) { | |
356 if (video_processor_ && SizeContains(processor_input_size_, in_size) && | |
357 SizeContains(processor_output_size_, out_size)) | |
358 return false; | |
359 processor_input_size_ = in_size; | |
360 processor_output_size_ = out_size; | |
361 surface_->InitializeVideoProcessor(in_size, out_size); | |
362 | |
363 video_processor_enumerator_ = surface_->video_processor_enumerator(); | |
364 video_processor_ = surface_->video_processor(); | |
sunnyps
2017/03/28 22:28:58
nit: should we call out_view_.Release() here like
| |
365 return true; | |
366 } | |
367 | |
368 void DCLayerTree::SwapChainPresenter::ReallocateSwapChain() { | |
369 TRACE_EVENT0("gpu", "DCLayerTree::SwapChainPresenter::ReallocateSwapChain"); | |
370 DCHECK(!swap_chain_); | |
371 | |
372 base::win::ScopedComPtr<IDXGIDevice> dxgi_device; | |
373 d3d11_device_.QueryInterface(dxgi_device.Receive()); | |
374 base::win::ScopedComPtr<IDXGIAdapter> dxgi_adapter; | |
375 dxgi_device->GetAdapter(dxgi_adapter.Receive()); | |
376 base::win::ScopedComPtr<IDXGIFactory2> dxgi_factory; | |
377 dxgi_adapter->GetParent(IID_PPV_ARGS(dxgi_factory.Receive())); | |
378 | |
379 base::win::ScopedComPtr<IDXGIFactoryMedia> media_factory; | |
380 dxgi_factory.QueryInterface(media_factory.Receive()); | |
381 DXGI_SWAP_CHAIN_DESC1 desc = {}; | |
382 desc.Width = swap_chain_size_.width(); | |
383 desc.Height = swap_chain_size_.height(); | |
384 desc.Format = DXGI_FORMAT_YUY2; | |
385 desc.Stereo = FALSE; | |
386 desc.SampleDesc.Count = 1; | |
387 desc.BufferCount = 2; | |
388 desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; | |
389 desc.Scaling = DXGI_SCALING_STRETCH; | |
390 desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; | |
391 desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE; | |
392 desc.Flags = | |
393 DXGI_SWAP_CHAIN_FLAG_YUV_VIDEO | DXGI_SWAP_CHAIN_FLAG_FULLSCREEN_VIDEO; | |
394 | |
395 HANDLE handle; | |
396 create_surface_handle_function_(COMPOSITIONOBJECT_ALL_ACCESS, nullptr, | |
397 &handle); | |
398 swap_chain_handle_.Set(handle); | |
399 | |
400 // The composition surface handle isn't actually used, but | |
401 // CreateSwapChainForComposition can't create YUY2 swapchains. | |
402 HRESULT hr = media_factory->CreateSwapChainForCompositionSurfaceHandle( | |
403 d3d11_device_.get(), swap_chain_handle_.Get(), &desc, nullptr, | |
404 swap_chain_.Receive()); | |
405 | |
406 if (FAILED(hr)) { | |
407 // This should not be hit in production but is a simple fallback for | |
408 // testing on systems without YUY2 swapchain support. | |
409 DLOG(ERROR) << "YUY2 creation failed with " << std::hex << hr | |
410 << ". Falling back to BGRA"; | |
411 desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; | |
412 desc.Flags = 0; | |
413 hr = media_factory->CreateSwapChainForCompositionSurfaceHandle( | |
414 d3d11_device_.get(), swap_chain_handle_.Get(), &desc, nullptr, | |
415 swap_chain_.Receive()); | |
416 CHECK(SUCCEEDED(hr)); | |
417 } else { | |
418 // This is a sensible default colorspace for most videos. | |
419 // TODO(jbauman): Use correct colorspace. | |
420 base::win::ScopedComPtr<IDXGISwapChain3> swap_chain3; | |
421 swap_chain_.QueryInterface(swap_chain3.Receive()); | |
422 hr = swap_chain3->SetColorSpace1( | |
423 DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709); | |
424 CHECK(SUCCEEDED(hr)); | |
425 } | |
426 out_view_.Release(); | |
427 } | |
428 | |
429 void DCLayerTree::InitVisual(size_t i) { | |
430 DCHECK_GT(visual_info_.size(), i); | |
431 VisualInfo* visual_info = &visual_info_[i]; | |
432 if (visual_info->content_visual) | |
433 return; | |
434 DCHECK(!visual_info->clip_visual); | |
435 base::win::ScopedComPtr<IDCompositionVisual2> visual; | |
436 dcomp_device_->CreateVisual(visual_info->clip_visual.Receive()); | |
437 dcomp_device_->CreateVisual(visual.Receive()); | |
438 visual_info->content_visual = visual; | |
439 visual_info->clip_visual->AddVisual(visual.get(), FALSE, nullptr); | |
440 | |
441 IDCompositionVisual2* last_visual = | |
442 (i > 0) ? visual_info_[i - 1].clip_visual.get() : nullptr; | |
443 root_visual_->AddVisual(visual_info->clip_visual.get(), TRUE, last_visual); | |
444 } | |
445 | |
446 void DCLayerTree::UpdateVisualForVideo( | |
447 VisualInfo* visual_info, | |
448 const ui::DCRendererLayerParams& params) { | |
449 base::win::ScopedComPtr<IDCompositionVisual2> dc_visual = | |
450 visual_info->content_visual; | |
451 | |
452 gfx::Rect bounds_rect = params.rect; | |
453 visual_info->surface.Release(); | |
454 if (!visual_info->swap_chain_presenter) { | |
455 visual_info->swap_chain_presenter = | |
456 base::MakeUnique<SwapChainPresenter>(this, d3d11_device_); | |
457 } | |
458 visual_info->swap_chain_presenter->PresentToSwapChain(params); | |
459 if (visual_info->swap_chain != | |
460 visual_info->swap_chain_presenter->swap_chain()) { | |
461 visual_info->swap_chain = visual_info->swap_chain_presenter->swap_chain(); | |
462 dc_visual->SetContent(visual_info->swap_chain.get()); | |
463 } | |
464 | |
465 if (visual_info->swap_chain_presenter->swap_chain_scale_x() != | |
466 visual_info->swap_chain_scale_x || | |
467 visual_info->swap_chain_presenter->swap_chain_scale_y() != | |
468 visual_info->swap_chain_scale_y || | |
469 params.transform != visual_info->transform || | |
470 visual_info->bounds != bounds_rect) { | |
471 visual_info->swap_chain_scale_x = | |
472 visual_info->swap_chain_presenter->swap_chain_scale_x(); | |
473 visual_info->swap_chain_scale_y = | |
474 visual_info->swap_chain_presenter->swap_chain_scale_y(); | |
475 visual_info->transform = params.transform; | |
476 visual_info->bounds = bounds_rect; | |
477 | |
478 gfx::Transform final_transform = params.transform; | |
479 gfx::Transform scale_transform; | |
480 scale_transform.Scale( | |
481 visual_info->swap_chain_presenter->swap_chain_scale_x(), | |
482 visual_info->swap_chain_presenter->swap_chain_scale_y()); | |
483 final_transform.PreconcatTransform(scale_transform); | |
484 final_transform.Transpose(); | |
485 | |
486 dc_visual->SetOffsetX(bounds_rect.x()); | |
487 dc_visual->SetOffsetY(bounds_rect.y()); | |
488 base::win::ScopedComPtr<IDCompositionMatrixTransform> dcomp_transform; | |
489 dcomp_device_->CreateMatrixTransform(dcomp_transform.Receive()); | |
490 D2D_MATRIX_3X2_F d2d_matrix = {{{final_transform.matrix().get(0, 0), | |
491 final_transform.matrix().get(0, 1), | |
492 final_transform.matrix().get(1, 0), | |
493 final_transform.matrix().get(1, 1), | |
494 final_transform.matrix().get(3, 0), | |
495 final_transform.matrix().get(3, 1)}}}; | |
496 dcomp_transform->SetMatrix(d2d_matrix); | |
497 dc_visual->SetTransform(dcomp_transform.get()); | |
498 } | |
499 } | |
500 | |
501 void DCLayerTree::UpdateVisualForBackbuffer( | |
502 VisualInfo* visual_info, | |
503 const ui::DCRendererLayerParams& params) { | |
504 base::win::ScopedComPtr<IDCompositionVisual2> dc_visual = | |
505 visual_info->content_visual; | |
506 | |
507 visual_info->swap_chain_presenter = nullptr; | |
508 if ((visual_info->surface != surface_->dcomp_surface()) || | |
509 (visual_info->swap_chain != surface_->swap_chain())) { | |
510 visual_info->surface = surface_->dcomp_surface(); | |
511 visual_info->swap_chain = surface_->swap_chain(); | |
512 if (visual_info->surface) { | |
513 dc_visual->SetContent(visual_info->surface.get()); | |
514 } else if (visual_info->swap_chain) { | |
515 dc_visual->SetContent(visual_info->swap_chain.get()); | |
516 } else { | |
517 dc_visual->SetContent(nullptr); | |
518 } | |
519 } | |
520 | |
521 gfx::Rect bounds_rect = params.rect; | |
522 if (visual_info->bounds != bounds_rect || | |
523 !visual_info->transform.IsIdentity()) { | |
524 dc_visual->SetOffsetX(bounds_rect.x()); | |
525 dc_visual->SetOffsetY(bounds_rect.y()); | |
526 visual_info->bounds = bounds_rect; | |
527 dc_visual->SetTransform(nullptr); | |
528 visual_info->transform = gfx::Transform(); | |
529 } | |
530 } | |
531 | |
532 void DCLayerTree::UpdateVisualClip(VisualInfo* visual_info, | |
533 const ui::DCRendererLayerParams& params) { | |
534 if (params.is_clipped != visual_info->is_clipped || | |
535 params.clip_rect != visual_info->clip_rect) { | |
536 // DirectComposition clips happen in the pre-transform visual | |
537 // space, while cc/ clips happen post-transform. So the clip needs | |
538 // to go on a separate parent visual that's untransformed. | |
539 visual_info->is_clipped = params.is_clipped; | |
540 visual_info->clip_rect = params.clip_rect; | |
541 if (params.is_clipped) { | |
542 base::win::ScopedComPtr<IDCompositionRectangleClip> clip; | |
543 dcomp_device_->CreateRectangleClip(clip.Receive()); | |
544 gfx::Rect offset_clip = params.clip_rect; | |
545 clip->SetLeft(offset_clip.x()); | |
546 clip->SetRight(offset_clip.right()); | |
547 clip->SetBottom(offset_clip.bottom()); | |
548 clip->SetTop(offset_clip.y()); | |
549 visual_info->clip_visual->SetClip(clip.get()); | |
550 } else { | |
551 visual_info->clip_visual->SetClip(nullptr); | |
552 } | |
553 } | |
554 } | |
555 | |
556 bool DCLayerTree::CommitAndClearPendingOverlays() { | |
557 TRACE_EVENT1("gpu", "DCLayerTree::CommitAndClearPendingOverlays", "size", | |
558 pending_overlays_.size()); | |
559 // Add an overlay with z-order 0 representing the main plane. | |
560 gfx::Size surface_size = surface_->GetSize(); | |
561 pending_overlays_.push_back(base::MakeUnique<ui::DCRendererLayerParams>( | |
562 false, gfx::Rect(), 0, gfx::Transform(), nullptr, | |
563 gfx::RectF(gfx::SizeF(surface_size)), gfx::Rect(surface_size), 0, 0, 1.0, | |
564 0)); | |
565 | |
566 // TODO(jbauman): Reuse swapchains that are switched between overlays and | |
567 // underlays. | |
568 std::sort(pending_overlays_.begin(), pending_overlays_.end(), | |
569 [](const auto& a, const auto& b) -> bool { | |
570 return a->z_order < b->z_order; | |
571 }); | |
572 | |
573 while (visual_info_.size() > pending_overlays_.size()) { | |
574 visual_info_.back().clip_visual->RemoveAllVisuals(); | |
575 root_visual_->RemoveVisual(visual_info_.back().clip_visual.get()); | |
576 visual_info_.pop_back(); | |
577 } | |
578 | |
579 visual_info_.resize(pending_overlays_.size()); | |
580 | |
581 // The overall visual tree has one clip visual for every overlay (including | |
582 // the main plane). The clip visuals are in z_order and are all children of | |
583 // a root visual. Each clip visual has a child visual that has the actual | |
584 // plane content. | |
585 | |
586 for (size_t i = 0; i < pending_overlays_.size(); i++) { | |
587 ui::DCRendererLayerParams& params = *pending_overlays_[i]; | |
588 VisualInfo* visual_info = &visual_info_[i]; | |
589 | |
590 InitVisual(i); | |
591 if (params.image && | |
592 params.image->GetType() == gl::GLImage::Type::DXGI_IMAGE) { | |
593 UpdateVisualForVideo(visual_info, params); | |
594 } else if (!params.image) { | |
595 UpdateVisualForBackbuffer(visual_info, params); | |
596 } else { | |
597 CHECK(false); | |
598 } | |
599 UpdateVisualClip(visual_info, params); | |
600 } | |
601 | |
602 HRESULT hr = dcomp_device_->Commit(); | |
603 CHECK(SUCCEEDED(hr)); | |
604 | |
605 pending_overlays_.clear(); | |
606 return true; | |
607 } | |
608 | |
609 bool DCLayerTree::ScheduleDCLayer(const ui::DCRendererLayerParams& params) { | |
610 pending_overlays_.push_back( | |
611 base::MakeUnique<ui::DCRendererLayerParams>(params)); | |
612 return true; | |
613 } | |
614 | |
58 DirectCompositionSurfaceWin::DirectCompositionSurfaceWin( | 615 DirectCompositionSurfaceWin::DirectCompositionSurfaceWin( |
59 base::WeakPtr<ImageTransportSurfaceDelegate> delegate, | 616 base::WeakPtr<ImageTransportSurfaceDelegate> delegate, |
60 HWND parent_window) | 617 HWND parent_window) |
61 : gl::GLSurfaceEGL(), child_window_(delegate, parent_window) {} | 618 : gl::GLSurfaceEGL(), child_window_(delegate, parent_window) {} |
62 | 619 |
63 DirectCompositionSurfaceWin::~DirectCompositionSurfaceWin() { | 620 DirectCompositionSurfaceWin::~DirectCompositionSurfaceWin() { |
64 Destroy(); | 621 Destroy(); |
65 } | 622 } |
66 | 623 |
67 // static | 624 // static |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
124 return false; | 681 return false; |
125 | 682 |
126 EGLDisplay display = GetDisplay(); | 683 EGLDisplay display = GetDisplay(); |
127 if (!window_) { | 684 if (!window_) { |
128 if (!InitializeNativeWindow()) { | 685 if (!InitializeNativeWindow()) { |
129 DLOG(ERROR) << "Failed to initialize native window"; | 686 DLOG(ERROR) << "Failed to initialize native window"; |
130 return false; | 687 return false; |
131 } | 688 } |
132 } | 689 } |
133 | 690 |
134 base::win::ScopedComPtr<IDCompositionDesktopDevice> desktop_device; | 691 layer_tree_ = |
135 dcomp_device_.QueryInterface(desktop_device.Receive()); | 692 base::MakeUnique<DCLayerTree>(this, d3d11_device_, dcomp_device_); |
136 | 693 if (!layer_tree_->Initialize(window_)) |
137 HRESULT hr = desktop_device->CreateTargetForHwnd(window_, TRUE, | |
138 dcomp_target_.Receive()); | |
139 if (FAILED(hr)) | |
140 return false; | 694 return false; |
141 | 695 |
142 hr = dcomp_device_->CreateVisual(visual_.Receive()); | |
143 if (FAILED(hr)) | |
144 return false; | |
145 | |
146 dcomp_target_->SetRoot(visual_.get()); | |
147 | |
148 std::vector<EGLint> pbuffer_attribs; | 696 std::vector<EGLint> pbuffer_attribs; |
149 pbuffer_attribs.push_back(EGL_WIDTH); | 697 pbuffer_attribs.push_back(EGL_WIDTH); |
150 pbuffer_attribs.push_back(1); | 698 pbuffer_attribs.push_back(1); |
151 pbuffer_attribs.push_back(EGL_HEIGHT); | 699 pbuffer_attribs.push_back(EGL_HEIGHT); |
152 pbuffer_attribs.push_back(1); | 700 pbuffer_attribs.push_back(1); |
153 | 701 |
154 pbuffer_attribs.push_back(EGL_NONE); | 702 pbuffer_attribs.push_back(EGL_NONE); |
155 default_surface_ = | 703 default_surface_ = |
156 eglCreatePbufferSurface(display, GetConfig(), &pbuffer_attribs[0]); | 704 eglCreatePbufferSurface(display, GetConfig(), &pbuffer_attribs[0]); |
157 CHECK(!!default_surface_); | 705 CHECK(!!default_surface_); |
158 | 706 |
159 return true; | 707 return true; |
160 } | 708 } |
161 | 709 |
162 void DirectCompositionSurfaceWin::ReleaseCurrentSurface() { | 710 void DirectCompositionSurfaceWin::ReleaseCurrentSurface() { |
163 ReleaseDrawTexture(true); | 711 ReleaseDrawTexture(true); |
164 dcomp_surface_.Release(); | 712 dcomp_surface_.Release(); |
165 swap_chain_.Release(); | 713 swap_chain_.Release(); |
166 } | 714 } |
167 | 715 |
168 void DirectCompositionSurfaceWin::InitializeSurface() { | 716 void DirectCompositionSurfaceWin::InitializeSurface() { |
717 TRACE_EVENT1("gpu", "DirectCompositionSurfaceWin::InitializeSurface()", | |
718 "enable_dc_layers_", enable_dc_layers_); | |
169 DCHECK(!dcomp_surface_); | 719 DCHECK(!dcomp_surface_); |
170 DCHECK(!swap_chain_); | 720 DCHECK(!swap_chain_); |
171 DXGI_FORMAT output_format = | 721 DXGI_FORMAT output_format = |
172 base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableHDR) | 722 base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableHDR) |
173 ? DXGI_FORMAT_R16G16B16A16_FLOAT | 723 ? DXGI_FORMAT_R16G16B16A16_FLOAT |
174 : DXGI_FORMAT_B8G8R8A8_UNORM; | 724 : DXGI_FORMAT_B8G8R8A8_UNORM; |
175 if (enable_dc_layers_) { | 725 if (enable_dc_layers_) { |
176 HRESULT hr = dcomp_device_->CreateSurface( | 726 HRESULT hr = dcomp_device_->CreateSurface( |
177 size_.width(), size_.height(), output_format, | 727 size_.width(), size_.height(), output_format, |
178 DXGI_ALPHA_MODE_PREMULTIPLIED, dcomp_surface_.Receive()); | 728 DXGI_ALPHA_MODE_PREMULTIPLIED, dcomp_surface_.Receive()); |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
295 // New surface will be initialized in SetDrawRectangle. | 845 // New surface will be initialized in SetDrawRectangle. |
296 ReleaseCurrentSurface(); | 846 ReleaseCurrentSurface(); |
297 | 847 |
298 return true; | 848 return true; |
299 } | 849 } |
300 | 850 |
301 gfx::SwapResult DirectCompositionSurfaceWin::SwapBuffers() { | 851 gfx::SwapResult DirectCompositionSurfaceWin::SwapBuffers() { |
302 { | 852 { |
303 ScopedReleaseCurrent release_current(this); | 853 ScopedReleaseCurrent release_current(this); |
304 ReleaseDrawTexture(false); | 854 ReleaseDrawTexture(false); |
305 DCHECK(dcomp_surface_ || swap_chain_); | |
306 if (dcomp_surface_) | |
307 visual_->SetContent(dcomp_surface_.get()); | |
308 else | |
309 visual_->SetContent(swap_chain_.get()); | |
310 | 855 |
311 CommitAndClearPendingOverlays(); | 856 layer_tree_->CommitAndClearPendingOverlays(); |
312 dcomp_device_->Commit(); | |
313 } | 857 } |
314 child_window_.ClearInvalidContents(); | 858 child_window_.ClearInvalidContents(); |
315 return gfx::SwapResult::SWAP_ACK; | 859 return gfx::SwapResult::SWAP_ACK; |
316 } | 860 } |
317 | 861 |
318 gfx::SwapResult DirectCompositionSurfaceWin::PostSubBuffer(int x, | 862 gfx::SwapResult DirectCompositionSurfaceWin::PostSubBuffer(int x, |
319 int y, | 863 int y, |
320 int width, | 864 int width, |
321 int height) { | 865 int height) { |
322 // The arguments are ignored because SetDrawRectangle specified the area to | 866 // The arguments are ignored because SetDrawRectangle specified the area to |
323 // be swapped. | 867 // be swapped. |
324 return SwapBuffers(); | 868 return SwapBuffers(); |
325 } | 869 } |
326 | 870 |
327 gfx::VSyncProvider* DirectCompositionSurfaceWin::GetVSyncProvider() { | 871 gfx::VSyncProvider* DirectCompositionSurfaceWin::GetVSyncProvider() { |
328 return vsync_provider_.get(); | 872 return vsync_provider_.get(); |
329 } | 873 } |
330 | 874 |
331 bool DirectCompositionSurfaceWin::ScheduleOverlayPlane( | 875 bool DirectCompositionSurfaceWin::ScheduleDCLayer( |
332 int z_order, | 876 const ui::DCRendererLayerParams& params) { |
333 gfx::OverlayTransform transform, | 877 return layer_tree_->ScheduleDCLayer(params); |
334 gl::GLImage* image, | |
335 const gfx::Rect& bounds_rect, | |
336 const gfx::RectF& crop_rect) { | |
337 pending_overlays_.push_back( | |
338 Overlay(z_order, transform, image, bounds_rect, crop_rect)); | |
339 return true; | |
340 } | 878 } |
341 | 879 |
342 bool DirectCompositionSurfaceWin::SetEnableDCLayers(bool enable) { | 880 bool DirectCompositionSurfaceWin::SetEnableDCLayers(bool enable) { |
343 enable_dc_layers_ = enable; | 881 enable_dc_layers_ = enable; |
344 return true; | 882 return true; |
345 } | 883 } |
346 | 884 |
347 bool DirectCompositionSurfaceWin::CommitAndClearPendingOverlays() { | |
348 pending_overlays_.clear(); | |
349 return true; | |
350 } | |
351 | 885 |
352 bool DirectCompositionSurfaceWin::FlipsVertically() const { | 886 bool DirectCompositionSurfaceWin::FlipsVertically() const { |
353 return true; | 887 return true; |
354 } | 888 } |
355 | 889 |
356 bool DirectCompositionSurfaceWin::SupportsPostSubBuffer() { | 890 bool DirectCompositionSurfaceWin::SupportsPostSubBuffer() { |
357 return true; | 891 return true; |
358 } | 892 } |
359 | 893 |
360 bool DirectCompositionSurfaceWin::OnMakeCurrent(gl::GLContext* context) { | 894 bool DirectCompositionSurfaceWin::OnMakeCurrent(gl::GLContext* context) { |
(...skipping 12 matching lines...) Expand all Loading... | |
373 return true; | 907 return true; |
374 } | 908 } |
375 | 909 |
376 bool DirectCompositionSurfaceWin::SupportsDCLayers() const { | 910 bool DirectCompositionSurfaceWin::SupportsDCLayers() const { |
377 return true; | 911 return true; |
378 } | 912 } |
379 | 913 |
380 bool DirectCompositionSurfaceWin::SetDrawRectangle(const gfx::Rect& rectangle) { | 914 bool DirectCompositionSurfaceWin::SetDrawRectangle(const gfx::Rect& rectangle) { |
381 if (draw_texture_) | 915 if (draw_texture_) |
382 return false; | 916 return false; |
383 | |
384 DCHECK(!real_surface_); | 917 DCHECK(!real_surface_); |
385 ScopedReleaseCurrent release_current(this); | 918 ScopedReleaseCurrent release_current(this); |
386 | 919 |
387 if ((enable_dc_layers_ && !dcomp_surface_) || | 920 if ((enable_dc_layers_ && !dcomp_surface_) || |
388 (!enable_dc_layers_ && !swap_chain_)) { | 921 (!enable_dc_layers_ && !swap_chain_)) { |
389 ReleaseCurrentSurface(); | 922 ReleaseCurrentSurface(); |
390 InitializeSurface(); | 923 InitializeSurface(); |
391 } | 924 } |
392 | 925 |
393 if (!gfx::Rect(size_).Contains(rectangle)) { | 926 if (!gfx::Rect(size_).Contains(rectangle)) { |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
439 | 972 |
440 gfx::Vector2d DirectCompositionSurfaceWin::GetDrawOffset() const { | 973 gfx::Vector2d DirectCompositionSurfaceWin::GetDrawOffset() const { |
441 return draw_offset_; | 974 return draw_offset_; |
442 } | 975 } |
443 | 976 |
444 scoped_refptr<base::TaskRunner> | 977 scoped_refptr<base::TaskRunner> |
445 DirectCompositionSurfaceWin::GetWindowTaskRunnerForTesting() { | 978 DirectCompositionSurfaceWin::GetWindowTaskRunnerForTesting() { |
446 return child_window_.GetTaskRunnerForTesting(); | 979 return child_window_.GetTaskRunnerForTesting(); |
447 } | 980 } |
448 | 981 |
449 DirectCompositionSurfaceWin::Overlay::Overlay(int z_order, | |
450 gfx::OverlayTransform transform, | |
451 scoped_refptr<gl::GLImage> image, | |
452 gfx::Rect bounds_rect, | |
453 gfx::RectF crop_rect) | |
454 : z_order(z_order), | |
455 transform(transform), | |
456 image(image), | |
457 bounds_rect(bounds_rect), | |
458 crop_rect(crop_rect) {} | |
459 | |
460 DirectCompositionSurfaceWin::Overlay::Overlay(const Overlay& overlay) = default; | |
461 | |
462 DirectCompositionSurfaceWin::Overlay::~Overlay() {} | |
463 | |
464 } // namespace gpu | 982 } // namespace gpu |
OLD | NEW |