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 { |
| 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 CHECK(dcomp); |
| 260 create_surface_handle_function_ = |
| 261 reinterpret_cast<PFN_DCOMPOSITION_CREATE_SURFACE_HANDLE>( |
| 262 GetProcAddress(dcomp, "DCompositionCreateSurfaceHandle")); |
| 263 CHECK(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 InitializeVideoProcessor(ceiled_input_size, swap_chain_size); |
| 289 |
| 290 bool first_present = false; |
| 291 if (!swap_chain_ || swap_chain_size_ != swap_chain_size) { |
| 292 first_present = true; |
| 293 swap_chain_size_ = swap_chain_size; |
| 294 swap_chain_.Release(); |
| 295 ReallocateSwapChain(); |
| 296 } |
| 297 |
| 298 if (!out_view_) { |
| 299 base::win::ScopedComPtr<ID3D11Texture2D> texture; |
| 300 swap_chain_->GetBuffer(0, IID_PPV_ARGS(texture.Receive())); |
| 301 D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC out_desc = {}; |
| 302 out_desc.ViewDimension = D3D11_VPOV_DIMENSION_TEXTURE2D; |
| 303 out_desc.Texture2D.MipSlice = 0; |
| 304 HRESULT hr = video_device_->CreateVideoProcessorOutputView( |
| 305 texture.get(), video_processor_enumerator_.get(), &out_desc, |
| 306 out_view_.Receive()); |
| 307 CHECK(SUCCEEDED(hr)); |
| 308 } |
| 309 { |
| 310 D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC in_desc = {}; |
| 311 in_desc.ViewDimension = D3D11_VPIV_DIMENSION_TEXTURE2D; |
| 312 in_desc.Texture2D.ArraySlice = (UINT)image_dxgi->level(); |
| 313 base::win::ScopedComPtr<ID3D11VideoProcessorInputView> in_view; |
| 314 HRESULT hr = video_device_->CreateVideoProcessorInputView( |
| 315 image_dxgi->texture().get(), video_processor_enumerator_.get(), |
| 316 &in_desc, in_view.Receive()); |
| 317 CHECK(SUCCEEDED(hr)); |
| 318 |
| 319 D3D11_VIDEO_PROCESSOR_STREAM stream = {}; |
| 320 stream.Enable = true; |
| 321 stream.OutputIndex = 0; |
| 322 stream.InputFrameOrField = 0; |
| 323 stream.PastFrames = 0; |
| 324 stream.FutureFrames = 0; |
| 325 stream.pInputSurface = in_view.get(); |
| 326 RECT dest_rect = gfx::Rect(swap_chain_size).ToRECT(); |
| 327 video_context_->VideoProcessorSetOutputTargetRect(video_processor_.get(), |
| 328 TRUE, &dest_rect); |
| 329 video_context_->VideoProcessorSetStreamDestRect(video_processor_.get(), 0, |
| 330 TRUE, &dest_rect); |
| 331 RECT source_rect = gfx::Rect(ceiled_input_size).ToRECT(); |
| 332 video_context_->VideoProcessorSetStreamSourceRect(video_processor_.get(), 0, |
| 333 TRUE, &source_rect); |
| 334 |
| 335 video_context_->VideoProcessorSetStreamAutoProcessingMode( |
| 336 video_processor_.get(), 0, FALSE); |
| 337 |
| 338 hr = video_context_->VideoProcessorBlt(video_processor_.get(), |
| 339 out_view_.get(), 0, 1, &stream); |
| 340 CHECK(SUCCEEDED(hr)); |
| 341 } |
| 342 |
| 343 swap_chain_scale_x_ = bounds_rect.width() * 1.0f / swap_chain_size.width(); |
| 344 swap_chain_scale_y_ = bounds_rect.height() * 1.0f / swap_chain_size.height(); |
| 345 |
| 346 swap_chain_->Present(first_present ? 0 : 1, 0); |
| 347 } |
| 348 |
| 349 bool DCLayerTree::SwapChainPresenter::InitializeVideoProcessor( |
| 350 const gfx::Size& in_size, |
| 351 const gfx::Size& out_size) { |
| 352 if (video_processor_ && SizeContains(processor_input_size_, in_size) && |
| 353 SizeContains(processor_output_size_, out_size)) |
| 354 return false; |
| 355 processor_input_size_ = in_size; |
| 356 processor_output_size_ = out_size; |
| 357 surface_->InitializeVideoProcessor(in_size, out_size); |
| 358 |
| 359 video_processor_enumerator_ = surface_->video_processor_enumerator(); |
| 360 video_processor_ = surface_->video_processor(); |
| 361 // out_view_ depends on video_processor_enumerator_, so ensure it's |
| 362 // recreated if the enumerator is. |
| 363 out_view_.Release(); |
| 364 return true; |
| 365 } |
| 366 |
| 367 void DCLayerTree::SwapChainPresenter::ReallocateSwapChain() { |
| 368 TRACE_EVENT0("gpu", "DCLayerTree::SwapChainPresenter::ReallocateSwapChain"); |
| 369 DCHECK(!swap_chain_); |
| 370 |
| 371 base::win::ScopedComPtr<IDXGIDevice> dxgi_device; |
| 372 d3d11_device_.QueryInterface(dxgi_device.Receive()); |
| 373 base::win::ScopedComPtr<IDXGIAdapter> dxgi_adapter; |
| 374 dxgi_device->GetAdapter(dxgi_adapter.Receive()); |
| 375 base::win::ScopedComPtr<IDXGIFactory2> dxgi_factory; |
| 376 dxgi_adapter->GetParent(IID_PPV_ARGS(dxgi_factory.Receive())); |
| 377 |
| 378 base::win::ScopedComPtr<IDXGIFactoryMedia> media_factory; |
| 379 dxgi_factory.QueryInterface(media_factory.Receive()); |
| 380 DXGI_SWAP_CHAIN_DESC1 desc = {}; |
| 381 desc.Width = swap_chain_size_.width(); |
| 382 desc.Height = swap_chain_size_.height(); |
| 383 desc.Format = DXGI_FORMAT_YUY2; |
| 384 desc.Stereo = FALSE; |
| 385 desc.SampleDesc.Count = 1; |
| 386 desc.BufferCount = 2; |
| 387 desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; |
| 388 desc.Scaling = DXGI_SCALING_STRETCH; |
| 389 desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; |
| 390 desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE; |
| 391 desc.Flags = |
| 392 DXGI_SWAP_CHAIN_FLAG_YUV_VIDEO | DXGI_SWAP_CHAIN_FLAG_FULLSCREEN_VIDEO; |
| 393 |
| 394 HANDLE handle; |
| 395 create_surface_handle_function_(COMPOSITIONOBJECT_ALL_ACCESS, nullptr, |
| 396 &handle); |
| 397 swap_chain_handle_.Set(handle); |
| 398 |
| 399 // The composition surface handle isn't actually used, but |
| 400 // CreateSwapChainForComposition can't create YUY2 swapchains. |
| 401 HRESULT hr = media_factory->CreateSwapChainForCompositionSurfaceHandle( |
| 402 d3d11_device_.get(), swap_chain_handle_.Get(), &desc, nullptr, |
| 403 swap_chain_.Receive()); |
| 404 |
| 405 if (FAILED(hr)) { |
| 406 // This should not be hit in production but is a simple fallback for |
| 407 // testing on systems without YUY2 swapchain support. |
| 408 DLOG(ERROR) << "YUY2 creation failed with " << std::hex << hr |
| 409 << ". Falling back to BGRA"; |
| 410 desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; |
| 411 desc.Flags = 0; |
| 412 hr = media_factory->CreateSwapChainForCompositionSurfaceHandle( |
| 413 d3d11_device_.get(), swap_chain_handle_.Get(), &desc, nullptr, |
| 414 swap_chain_.Receive()); |
| 415 CHECK(SUCCEEDED(hr)); |
| 416 } else { |
| 417 // This is a sensible default colorspace for most videos. |
| 418 // TODO(jbauman): Use correct colorspace. |
| 419 base::win::ScopedComPtr<IDXGISwapChain3> swap_chain3; |
| 420 swap_chain_.QueryInterface(swap_chain3.Receive()); |
| 421 hr = swap_chain3->SetColorSpace1( |
| 422 DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709); |
| 423 CHECK(SUCCEEDED(hr)); |
| 424 } |
| 425 out_view_.Release(); |
| 426 } |
| 427 |
| 428 void DCLayerTree::InitVisual(size_t i) { |
| 429 DCHECK_GT(visual_info_.size(), i); |
| 430 VisualInfo* visual_info = &visual_info_[i]; |
| 431 if (visual_info->content_visual) |
| 432 return; |
| 433 DCHECK(!visual_info->clip_visual); |
| 434 base::win::ScopedComPtr<IDCompositionVisual2> visual; |
| 435 dcomp_device_->CreateVisual(visual_info->clip_visual.Receive()); |
| 436 dcomp_device_->CreateVisual(visual.Receive()); |
| 437 visual_info->content_visual = visual; |
| 438 visual_info->clip_visual->AddVisual(visual.get(), FALSE, nullptr); |
| 439 |
| 440 IDCompositionVisual2* last_visual = |
| 441 (i > 0) ? visual_info_[i - 1].clip_visual.get() : nullptr; |
| 442 root_visual_->AddVisual(visual_info->clip_visual.get(), TRUE, last_visual); |
| 443 } |
| 444 |
| 445 void DCLayerTree::UpdateVisualForVideo( |
| 446 VisualInfo* visual_info, |
| 447 const ui::DCRendererLayerParams& params) { |
| 448 base::win::ScopedComPtr<IDCompositionVisual2> dc_visual = |
| 449 visual_info->content_visual; |
| 450 |
| 451 gfx::Rect bounds_rect = params.rect; |
| 452 visual_info->surface.Release(); |
| 453 if (!visual_info->swap_chain_presenter) { |
| 454 visual_info->swap_chain_presenter = |
| 455 base::MakeUnique<SwapChainPresenter>(this, d3d11_device_); |
| 456 } |
| 457 visual_info->swap_chain_presenter->PresentToSwapChain(params); |
| 458 if (visual_info->swap_chain != |
| 459 visual_info->swap_chain_presenter->swap_chain()) { |
| 460 visual_info->swap_chain = visual_info->swap_chain_presenter->swap_chain(); |
| 461 dc_visual->SetContent(visual_info->swap_chain.get()); |
| 462 } |
| 463 |
| 464 if (visual_info->swap_chain_presenter->swap_chain_scale_x() != |
| 465 visual_info->swap_chain_scale_x || |
| 466 visual_info->swap_chain_presenter->swap_chain_scale_y() != |
| 467 visual_info->swap_chain_scale_y || |
| 468 params.transform != visual_info->transform || |
| 469 visual_info->bounds != bounds_rect) { |
| 470 visual_info->swap_chain_scale_x = |
| 471 visual_info->swap_chain_presenter->swap_chain_scale_x(); |
| 472 visual_info->swap_chain_scale_y = |
| 473 visual_info->swap_chain_presenter->swap_chain_scale_y(); |
| 474 visual_info->transform = params.transform; |
| 475 visual_info->bounds = bounds_rect; |
| 476 |
| 477 gfx::Transform final_transform = params.transform; |
| 478 gfx::Transform scale_transform; |
| 479 scale_transform.Scale( |
| 480 visual_info->swap_chain_presenter->swap_chain_scale_x(), |
| 481 visual_info->swap_chain_presenter->swap_chain_scale_y()); |
| 482 final_transform.PreconcatTransform(scale_transform); |
| 483 final_transform.Transpose(); |
| 484 |
| 485 dc_visual->SetOffsetX(bounds_rect.x()); |
| 486 dc_visual->SetOffsetY(bounds_rect.y()); |
| 487 base::win::ScopedComPtr<IDCompositionMatrixTransform> dcomp_transform; |
| 488 dcomp_device_->CreateMatrixTransform(dcomp_transform.Receive()); |
| 489 D2D_MATRIX_3X2_F d2d_matrix = {{{final_transform.matrix().get(0, 0), |
| 490 final_transform.matrix().get(0, 1), |
| 491 final_transform.matrix().get(1, 0), |
| 492 final_transform.matrix().get(1, 1), |
| 493 final_transform.matrix().get(3, 0), |
| 494 final_transform.matrix().get(3, 1)}}}; |
| 495 dcomp_transform->SetMatrix(d2d_matrix); |
| 496 dc_visual->SetTransform(dcomp_transform.get()); |
| 497 } |
| 498 } |
| 499 |
| 500 void DCLayerTree::UpdateVisualForBackbuffer( |
| 501 VisualInfo* visual_info, |
| 502 const ui::DCRendererLayerParams& params) { |
| 503 base::win::ScopedComPtr<IDCompositionVisual2> dc_visual = |
| 504 visual_info->content_visual; |
| 505 |
| 506 visual_info->swap_chain_presenter = nullptr; |
| 507 if ((visual_info->surface != surface_->dcomp_surface()) || |
| 508 (visual_info->swap_chain != surface_->swap_chain())) { |
| 509 visual_info->surface = surface_->dcomp_surface(); |
| 510 visual_info->swap_chain = surface_->swap_chain(); |
| 511 if (visual_info->surface) { |
| 512 dc_visual->SetContent(visual_info->surface.get()); |
| 513 } else if (visual_info->swap_chain) { |
| 514 dc_visual->SetContent(visual_info->swap_chain.get()); |
| 515 } else { |
| 516 dc_visual->SetContent(nullptr); |
| 517 } |
| 518 } |
| 519 |
| 520 gfx::Rect bounds_rect = params.rect; |
| 521 if (visual_info->bounds != bounds_rect || |
| 522 !visual_info->transform.IsIdentity()) { |
| 523 dc_visual->SetOffsetX(bounds_rect.x()); |
| 524 dc_visual->SetOffsetY(bounds_rect.y()); |
| 525 visual_info->bounds = bounds_rect; |
| 526 dc_visual->SetTransform(nullptr); |
| 527 visual_info->transform = gfx::Transform(); |
| 528 } |
| 529 } |
| 530 |
| 531 void DCLayerTree::UpdateVisualClip(VisualInfo* visual_info, |
| 532 const ui::DCRendererLayerParams& params) { |
| 533 if (params.is_clipped != visual_info->is_clipped || |
| 534 params.clip_rect != visual_info->clip_rect) { |
| 535 // DirectComposition clips happen in the pre-transform visual |
| 536 // space, while cc/ clips happen post-transform. So the clip needs |
| 537 // to go on a separate parent visual that's untransformed. |
| 538 visual_info->is_clipped = params.is_clipped; |
| 539 visual_info->clip_rect = params.clip_rect; |
| 540 if (params.is_clipped) { |
| 541 base::win::ScopedComPtr<IDCompositionRectangleClip> clip; |
| 542 dcomp_device_->CreateRectangleClip(clip.Receive()); |
| 543 gfx::Rect offset_clip = params.clip_rect; |
| 544 clip->SetLeft(offset_clip.x()); |
| 545 clip->SetRight(offset_clip.right()); |
| 546 clip->SetBottom(offset_clip.bottom()); |
| 547 clip->SetTop(offset_clip.y()); |
| 548 visual_info->clip_visual->SetClip(clip.get()); |
| 549 } else { |
| 550 visual_info->clip_visual->SetClip(nullptr); |
| 551 } |
| 552 } |
| 553 } |
| 554 |
| 555 bool DCLayerTree::CommitAndClearPendingOverlays() { |
| 556 TRACE_EVENT1("gpu", "DCLayerTree::CommitAndClearPendingOverlays", "size", |
| 557 pending_overlays_.size()); |
| 558 // Add an overlay with z-order 0 representing the main plane. |
| 559 gfx::Size surface_size = surface_->GetSize(); |
| 560 pending_overlays_.push_back(base::MakeUnique<ui::DCRendererLayerParams>( |
| 561 false, gfx::Rect(), 0, gfx::Transform(), nullptr, |
| 562 gfx::RectF(gfx::SizeF(surface_size)), gfx::Rect(surface_size), 0, 0, 1.0, |
| 563 0)); |
| 564 |
| 565 // TODO(jbauman): Reuse swapchains that are switched between overlays and |
| 566 // underlays. |
| 567 std::sort(pending_overlays_.begin(), pending_overlays_.end(), |
| 568 [](const auto& a, const auto& b) -> bool { |
| 569 return a->z_order < b->z_order; |
| 570 }); |
| 571 |
| 572 while (visual_info_.size() > pending_overlays_.size()) { |
| 573 visual_info_.back().clip_visual->RemoveAllVisuals(); |
| 574 root_visual_->RemoveVisual(visual_info_.back().clip_visual.get()); |
| 575 visual_info_.pop_back(); |
| 576 } |
| 577 |
| 578 visual_info_.resize(pending_overlays_.size()); |
| 579 |
| 580 // The overall visual tree has one clip visual for every overlay (including |
| 581 // the main plane). The clip visuals are in z_order and are all children of |
| 582 // a root visual. Each clip visual has a child visual that has the actual |
| 583 // plane content. |
| 584 |
| 585 for (size_t i = 0; i < pending_overlays_.size(); i++) { |
| 586 ui::DCRendererLayerParams& params = *pending_overlays_[i]; |
| 587 VisualInfo* visual_info = &visual_info_[i]; |
| 588 |
| 589 InitVisual(i); |
| 590 if (params.image && |
| 591 params.image->GetType() == gl::GLImage::Type::DXGI_IMAGE) { |
| 592 UpdateVisualForVideo(visual_info, params); |
| 593 } else if (!params.image) { |
| 594 UpdateVisualForBackbuffer(visual_info, params); |
| 595 } else { |
| 596 CHECK(false); |
| 597 } |
| 598 UpdateVisualClip(visual_info, params); |
| 599 } |
| 600 |
| 601 HRESULT hr = dcomp_device_->Commit(); |
| 602 CHECK(SUCCEEDED(hr)); |
| 603 |
| 604 pending_overlays_.clear(); |
| 605 return true; |
| 606 } |
| 607 |
| 608 bool DCLayerTree::ScheduleDCLayer(const ui::DCRendererLayerParams& params) { |
| 609 pending_overlays_.push_back( |
| 610 base::MakeUnique<ui::DCRendererLayerParams>(params)); |
| 611 return true; |
| 612 } |
| 613 |
58 DirectCompositionSurfaceWin::DirectCompositionSurfaceWin( | 614 DirectCompositionSurfaceWin::DirectCompositionSurfaceWin( |
59 base::WeakPtr<ImageTransportSurfaceDelegate> delegate, | 615 base::WeakPtr<ImageTransportSurfaceDelegate> delegate, |
60 HWND parent_window) | 616 HWND parent_window) |
61 : gl::GLSurfaceEGL(), child_window_(delegate, parent_window) {} | 617 : gl::GLSurfaceEGL(), child_window_(delegate, parent_window) {} |
62 | 618 |
63 DirectCompositionSurfaceWin::~DirectCompositionSurfaceWin() { | 619 DirectCompositionSurfaceWin::~DirectCompositionSurfaceWin() { |
64 Destroy(); | 620 Destroy(); |
65 } | 621 } |
66 | 622 |
67 // static | 623 // static |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
124 return false; | 680 return false; |
125 | 681 |
126 EGLDisplay display = GetDisplay(); | 682 EGLDisplay display = GetDisplay(); |
127 if (!window_) { | 683 if (!window_) { |
128 if (!InitializeNativeWindow()) { | 684 if (!InitializeNativeWindow()) { |
129 DLOG(ERROR) << "Failed to initialize native window"; | 685 DLOG(ERROR) << "Failed to initialize native window"; |
130 return false; | 686 return false; |
131 } | 687 } |
132 } | 688 } |
133 | 689 |
134 base::win::ScopedComPtr<IDCompositionDesktopDevice> desktop_device; | 690 layer_tree_ = |
135 dcomp_device_.QueryInterface(desktop_device.Receive()); | 691 base::MakeUnique<DCLayerTree>(this, d3d11_device_, dcomp_device_); |
136 | 692 if (!layer_tree_->Initialize(window_)) |
137 HRESULT hr = desktop_device->CreateTargetForHwnd(window_, TRUE, | |
138 dcomp_target_.Receive()); | |
139 if (FAILED(hr)) | |
140 return false; | 693 return false; |
141 | 694 |
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; | 695 std::vector<EGLint> pbuffer_attribs; |
149 pbuffer_attribs.push_back(EGL_WIDTH); | 696 pbuffer_attribs.push_back(EGL_WIDTH); |
150 pbuffer_attribs.push_back(1); | 697 pbuffer_attribs.push_back(1); |
151 pbuffer_attribs.push_back(EGL_HEIGHT); | 698 pbuffer_attribs.push_back(EGL_HEIGHT); |
152 pbuffer_attribs.push_back(1); | 699 pbuffer_attribs.push_back(1); |
153 | 700 |
154 pbuffer_attribs.push_back(EGL_NONE); | 701 pbuffer_attribs.push_back(EGL_NONE); |
155 default_surface_ = | 702 default_surface_ = |
156 eglCreatePbufferSurface(display, GetConfig(), &pbuffer_attribs[0]); | 703 eglCreatePbufferSurface(display, GetConfig(), &pbuffer_attribs[0]); |
157 CHECK(!!default_surface_); | 704 CHECK(!!default_surface_); |
158 | 705 |
159 return true; | 706 return true; |
160 } | 707 } |
161 | 708 |
162 void DirectCompositionSurfaceWin::ReleaseCurrentSurface() { | 709 void DirectCompositionSurfaceWin::ReleaseCurrentSurface() { |
163 ReleaseDrawTexture(true); | 710 ReleaseDrawTexture(true); |
164 dcomp_surface_.Release(); | 711 dcomp_surface_.Release(); |
165 swap_chain_.Release(); | 712 swap_chain_.Release(); |
166 } | 713 } |
167 | 714 |
168 void DirectCompositionSurfaceWin::InitializeSurface() { | 715 void DirectCompositionSurfaceWin::InitializeSurface() { |
| 716 TRACE_EVENT1("gpu", "DirectCompositionSurfaceWin::InitializeSurface()", |
| 717 "enable_dc_layers_", enable_dc_layers_); |
169 DCHECK(!dcomp_surface_); | 718 DCHECK(!dcomp_surface_); |
170 DCHECK(!swap_chain_); | 719 DCHECK(!swap_chain_); |
171 DXGI_FORMAT output_format = | 720 DXGI_FORMAT output_format = |
172 base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableHDR) | 721 base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableHDR) |
173 ? DXGI_FORMAT_R16G16B16A16_FLOAT | 722 ? DXGI_FORMAT_R16G16B16A16_FLOAT |
174 : DXGI_FORMAT_B8G8R8A8_UNORM; | 723 : DXGI_FORMAT_B8G8R8A8_UNORM; |
175 if (enable_dc_layers_) { | 724 if (enable_dc_layers_) { |
176 HRESULT hr = dcomp_device_->CreateSurface( | 725 HRESULT hr = dcomp_device_->CreateSurface( |
177 size_.width(), size_.height(), output_format, | 726 size_.width(), size_.height(), output_format, |
178 DXGI_ALPHA_MODE_PREMULTIPLIED, dcomp_surface_.Receive()); | 727 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. | 844 // New surface will be initialized in SetDrawRectangle. |
296 ReleaseCurrentSurface(); | 845 ReleaseCurrentSurface(); |
297 | 846 |
298 return true; | 847 return true; |
299 } | 848 } |
300 | 849 |
301 gfx::SwapResult DirectCompositionSurfaceWin::SwapBuffers() { | 850 gfx::SwapResult DirectCompositionSurfaceWin::SwapBuffers() { |
302 { | 851 { |
303 ScopedReleaseCurrent release_current(this); | 852 ScopedReleaseCurrent release_current(this); |
304 ReleaseDrawTexture(false); | 853 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 | 854 |
311 CommitAndClearPendingOverlays(); | 855 layer_tree_->CommitAndClearPendingOverlays(); |
312 dcomp_device_->Commit(); | |
313 } | 856 } |
314 child_window_.ClearInvalidContents(); | 857 child_window_.ClearInvalidContents(); |
315 return gfx::SwapResult::SWAP_ACK; | 858 return gfx::SwapResult::SWAP_ACK; |
316 } | 859 } |
317 | 860 |
318 gfx::SwapResult DirectCompositionSurfaceWin::PostSubBuffer(int x, | 861 gfx::SwapResult DirectCompositionSurfaceWin::PostSubBuffer(int x, |
319 int y, | 862 int y, |
320 int width, | 863 int width, |
321 int height) { | 864 int height) { |
322 // The arguments are ignored because SetDrawRectangle specified the area to | 865 // The arguments are ignored because SetDrawRectangle specified the area to |
323 // be swapped. | 866 // be swapped. |
324 return SwapBuffers(); | 867 return SwapBuffers(); |
325 } | 868 } |
326 | 869 |
327 gfx::VSyncProvider* DirectCompositionSurfaceWin::GetVSyncProvider() { | 870 gfx::VSyncProvider* DirectCompositionSurfaceWin::GetVSyncProvider() { |
328 return vsync_provider_.get(); | 871 return vsync_provider_.get(); |
329 } | 872 } |
330 | 873 |
331 bool DirectCompositionSurfaceWin::ScheduleOverlayPlane( | 874 bool DirectCompositionSurfaceWin::ScheduleDCLayer( |
332 int z_order, | 875 const ui::DCRendererLayerParams& params) { |
333 gfx::OverlayTransform transform, | 876 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 } | 877 } |
341 | 878 |
342 bool DirectCompositionSurfaceWin::SetEnableDCLayers(bool enable) { | 879 bool DirectCompositionSurfaceWin::SetEnableDCLayers(bool enable) { |
343 enable_dc_layers_ = enable; | 880 enable_dc_layers_ = enable; |
344 return true; | 881 return true; |
345 } | 882 } |
346 | 883 |
347 bool DirectCompositionSurfaceWin::CommitAndClearPendingOverlays() { | |
348 pending_overlays_.clear(); | |
349 return true; | |
350 } | |
351 | 884 |
352 bool DirectCompositionSurfaceWin::FlipsVertically() const { | 885 bool DirectCompositionSurfaceWin::FlipsVertically() const { |
353 return true; | 886 return true; |
354 } | 887 } |
355 | 888 |
356 bool DirectCompositionSurfaceWin::SupportsPostSubBuffer() { | 889 bool DirectCompositionSurfaceWin::SupportsPostSubBuffer() { |
357 return true; | 890 return true; |
358 } | 891 } |
359 | 892 |
360 bool DirectCompositionSurfaceWin::OnMakeCurrent(gl::GLContext* context) { | 893 bool DirectCompositionSurfaceWin::OnMakeCurrent(gl::GLContext* context) { |
(...skipping 12 matching lines...) Expand all Loading... |
373 return true; | 906 return true; |
374 } | 907 } |
375 | 908 |
376 bool DirectCompositionSurfaceWin::SupportsDCLayers() const { | 909 bool DirectCompositionSurfaceWin::SupportsDCLayers() const { |
377 return true; | 910 return true; |
378 } | 911 } |
379 | 912 |
380 bool DirectCompositionSurfaceWin::SetDrawRectangle(const gfx::Rect& rectangle) { | 913 bool DirectCompositionSurfaceWin::SetDrawRectangle(const gfx::Rect& rectangle) { |
381 if (draw_texture_) | 914 if (draw_texture_) |
382 return false; | 915 return false; |
383 | |
384 DCHECK(!real_surface_); | 916 DCHECK(!real_surface_); |
385 ScopedReleaseCurrent release_current(this); | 917 ScopedReleaseCurrent release_current(this); |
386 | 918 |
387 if ((enable_dc_layers_ && !dcomp_surface_) || | 919 if ((enable_dc_layers_ && !dcomp_surface_) || |
388 (!enable_dc_layers_ && !swap_chain_)) { | 920 (!enable_dc_layers_ && !swap_chain_)) { |
389 ReleaseCurrentSurface(); | 921 ReleaseCurrentSurface(); |
390 InitializeSurface(); | 922 InitializeSurface(); |
391 } | 923 } |
392 | 924 |
393 if (!gfx::Rect(size_).Contains(rectangle)) { | 925 if (!gfx::Rect(size_).Contains(rectangle)) { |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
439 | 971 |
440 gfx::Vector2d DirectCompositionSurfaceWin::GetDrawOffset() const { | 972 gfx::Vector2d DirectCompositionSurfaceWin::GetDrawOffset() const { |
441 return draw_offset_; | 973 return draw_offset_; |
442 } | 974 } |
443 | 975 |
444 scoped_refptr<base::TaskRunner> | 976 scoped_refptr<base::TaskRunner> |
445 DirectCompositionSurfaceWin::GetWindowTaskRunnerForTesting() { | 977 DirectCompositionSurfaceWin::GetWindowTaskRunnerForTesting() { |
446 return child_window_.GetTaskRunnerForTesting(); | 978 return child_window_.GetTaskRunnerForTesting(); |
447 } | 979 } |
448 | 980 |
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 | 981 } // namespace gpu |
OLD | NEW |