Chromium Code Reviews| Index: gpu/ipc/service/direct_composition_surface_win.cc |
| diff --git a/gpu/ipc/service/direct_composition_surface_win.cc b/gpu/ipc/service/direct_composition_surface_win.cc |
| index 7f65213481bc0c2f4b7a61aa60731668c3259097..01ab4799128d8009fc87ca364d54d518a1fab382 100644 |
| --- a/gpu/ipc/service/direct_composition_surface_win.cc |
| +++ b/gpu/ipc/service/direct_composition_surface_win.cc |
| @@ -4,15 +4,25 @@ |
| #include "gpu/ipc/service/direct_composition_surface_win.h" |
| +#include <d3d11_1.h> |
| +#include <dcomptypes.h> |
| + |
| +#include "base/memory/ptr_util.h" |
| #include "base/optional.h" |
| #include "base/synchronization/waitable_event.h" |
| +#include "base/trace_event/trace_event.h" |
| +#include "base/win/scoped_handle.h" |
| #include "gpu/ipc/service/gpu_channel_manager.h" |
| #include "gpu/ipc/service/gpu_channel_manager_delegate.h" |
| #include "gpu/ipc/service/switches.h" |
| +#include "ui/gfx/geometry/size_conversions.h" |
| #include "ui/gfx/native_widget_types.h" |
| +#include "ui/gfx/transform.h" |
| +#include "ui/gl/dc_renderer_layer_params.h" |
| #include "ui/gl/egl_util.h" |
| #include "ui/gl/gl_angle_util_win.h" |
| #include "ui/gl/gl_context.h" |
| +#include "ui/gl/gl_image_dxgi.h" |
| #include "ui/gl/gl_surface_egl.h" |
| #include "ui/gl/scoped_make_current.h" |
| @@ -47,6 +57,9 @@ class ScopedReleaseCurrent { |
| base::Optional<ui::ScopedMakeCurrent> make_current_; |
| }; |
| +bool SizeContains(const gfx::Size& a, const gfx::Size& b) { |
| + return gfx::Rect(a).Contains(gfx::Rect(b)); |
| +} |
| // Only one DirectComposition surface can be rendered into at a time. Track |
| // here which IDCompositionSurface is being rendered into. If another context |
| // is made current, then this surface will be suspended. |
| @@ -54,6 +67,515 @@ IDCompositionSurface* g_current_surface; |
| } // namespace |
| +class DCLayerTree { |
| + public: |
| + DCLayerTree(DirectCompositionSurfaceWin* surface, |
| + const base::win::ScopedComPtr<ID3D11Device>& d3d11_device, |
| + const base::win::ScopedComPtr<IDCompositionDevice2>& dcomp_device) |
| + : surface_(surface), |
| + d3d11_device_(d3d11_device), |
| + dcomp_device_(dcomp_device) {} |
| + |
| + bool Initialize(HWND window); |
| + bool CommitAndClearPendingOverlays(); |
| + bool ScheduleDCLayer(const ui::DCRendererLayerParams& params); |
| + void InitializeVideoProcessor(const gfx::Size& input_size, |
| + const gfx::Size& output_size); |
| + |
| + base::win::ScopedComPtr<ID3D11VideoProcessor> video_processor() { |
|
sunnyps
2017/03/28 00:42:23
nit: const method and const ref return here and be
|
| + return video_processor_; |
| + } |
| + base::win::ScopedComPtr<ID3D11VideoProcessorEnumerator> |
| + video_processor_enumerator() { |
| + return video_processor_enumerator_; |
| + } |
| + |
| + private: |
| + class SwapChainPresenter; |
| + |
| + // This struct is used to cache information about what visuals are currently |
| + // being presented so that properties that aren't changed aren't sent to |
| + // DirectComposition. |
| + struct VisualInfo { |
| + base::win::ScopedComPtr<IDCompositionVisual2> visual; |
|
sunnyps
2017/03/28 00:42:23
nit: content_visual?
|
| + base::win::ScopedComPtr<IDCompositionVisual2> clip_visual; |
| + |
| + std::unique_ptr<SwapChainPresenter> swap_chain_presenter; |
| + base::win::ScopedComPtr<IDXGISwapChain1> swap_chain; |
| + base::win::ScopedComPtr<IDCompositionSurface> surface; |
| + |
| + gfx::Rect bounds; |
| + float swap_chain_scale_x = 0.0f; |
| + float swap_chain_scale_y = 0.0f; |
| + bool is_clipped = false; |
| + gfx::Rect clip_rect; |
| + gfx::Transform transform; |
| + }; |
| + |
| + DirectCompositionSurfaceWin* surface_; |
| + std::vector<std::unique_ptr<ui::DCRendererLayerParams>> pending_overlays_; |
| + |
| + base::win::ScopedComPtr<ID3D11Device> d3d11_device_; |
| + base::win::ScopedComPtr<IDCompositionDevice2> dcomp_device_; |
| + base::win::ScopedComPtr<IDCompositionTarget> dcomp_target_; |
| + base::win::ScopedComPtr<IDCompositionVisual2> root_visual_; |
| + |
| + // The video processor is cached so SwapChains don't have to recreate it |
| + // whenever they're created. |
| + base::win::ScopedComPtr<ID3D11VideoDevice> video_device_; |
| + base::win::ScopedComPtr<ID3D11VideoContext> video_context_; |
| + base::win::ScopedComPtr<ID3D11VideoProcessor> video_processor_; |
| + base::win::ScopedComPtr<ID3D11VideoProcessorEnumerator> |
| + video_processor_enumerator_; |
| + gfx::Size video_input_size_; |
| + gfx::Size video_output_size_; |
| + |
| + std::vector<VisualInfo> visual_info_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(DCLayerTree); |
| +}; |
| + |
| +class DCLayerTree::SwapChainPresenter { |
| + public: |
| + SwapChainPresenter(DCLayerTree* surface, |
| + base::win::ScopedComPtr<ID3D11Device> d3d11_device); |
| + |
| + ~SwapChainPresenter(); |
| + |
| + void PresentToSwapChain(const ui::DCRendererLayerParams& overlay); |
| + |
| + float swap_chain_scale_x() const { return swap_chain_scale_x_; } |
| + float swap_chain_scale_y() const { return swap_chain_scale_y_; } |
| + const base::win::ScopedComPtr<IDXGISwapChain1> swap_chain() const { |
| + return swap_chain_; |
| + } |
| + |
| + private: |
| + using PFN_DCOMPOSITION_CREATE_SURFACE_HANDLE = |
| + HRESULT(WINAPI*)(DWORD, SECURITY_ATTRIBUTES*, HANDLE*); |
| + |
| + // Returns true if the video processor changed. |
| + bool InitializeVideoProcessor(const gfx::Size& in_size, |
| + const gfx::Size& out_size); |
| + void ReallocateSwapChain(); |
| + |
| + DCLayerTree* surface_; |
| + PFN_DCOMPOSITION_CREATE_SURFACE_HANDLE create_surface_handle_function_; |
| + |
| + gfx::Size swap_chain_size_; |
| + gfx::Size processor_input_size_; |
| + gfx::Size processor_output_size_; |
| + |
| + // This is the scale from the swapchain size to the size of the contents |
| + // onscreen. |
| + float swap_chain_scale_x_ = 0.0f; |
| + float swap_chain_scale_y_ = 0.0f; |
| + |
| + base::win::ScopedComPtr<ID3D11Device> d3d11_device_; |
| + base::win::ScopedComPtr<IDXGISwapChain1> swap_chain_; |
| + base::win::ScopedComPtr<ID3D11VideoProcessorOutputView> out_view_; |
| + base::win::ScopedComPtr<ID3D11VideoProcessor> video_processor_; |
| + base::win::ScopedComPtr<ID3D11VideoProcessorEnumerator> |
| + video_processor_enumerator_; |
| + base::win::ScopedComPtr<ID3D11VideoDevice> video_device_; |
| + base::win::ScopedComPtr<ID3D11VideoContext> video_context_; |
| + |
| + base::win::ScopedHandle swap_chain_handle_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(SwapChainPresenter); |
| +}; |
| + |
| +bool DCLayerTree::Initialize(HWND window) { |
| + d3d11_device_.QueryInterface(video_device_.Receive()); |
| + base::win::ScopedComPtr<ID3D11DeviceContext> context; |
| + d3d11_device_->GetImmediateContext(context.Receive()); |
| + context.QueryInterface(video_context_.Receive()); |
| + |
| + base::win::ScopedComPtr<IDCompositionDesktopDevice> desktop_device; |
| + dcomp_device_.QueryInterface(desktop_device.Receive()); |
| + |
| + HRESULT hr = desktop_device->CreateTargetForHwnd(window, TRUE, |
| + dcomp_target_.Receive()); |
| + if (FAILED(hr)) |
| + return false; |
| + |
| + hr = dcomp_device_->CreateVisual(root_visual_.Receive()); |
| + if (FAILED(hr)) |
| + return false; |
| + |
| + dcomp_target_->SetRoot(root_visual_.get()); |
| + return true; |
| +} |
| + |
| +void DCLayerTree::InitializeVideoProcessor(const gfx::Size& input_size, |
| + const gfx::Size& output_size) { |
| + if (SizeContains(video_input_size_, input_size) && |
| + SizeContains(video_output_size_, output_size)) |
| + return; |
| + video_input_size_ = input_size; |
| + video_output_size_ = output_size; |
| + |
| + video_processor_.Release(); |
| + video_processor_enumerator_.Receive(); |
| + D3D11_VIDEO_PROCESSOR_CONTENT_DESC desc = {}; |
| + desc.InputFrameFormat = D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE; |
| + desc.InputFrameRate.Numerator = 60; |
| + desc.InputFrameRate.Denominator = 1; |
| + desc.InputWidth = input_size.width(); |
| + desc.InputHeight = input_size.height(); |
| + desc.OutputFrameRate.Numerator = 60; |
| + desc.OutputFrameRate.Denominator = 1; |
| + desc.OutputWidth = output_size.width(); |
| + desc.OutputHeight = output_size.height(); |
| + desc.Usage = D3D11_VIDEO_USAGE_PLAYBACK_NORMAL; |
| + HRESULT hr = video_device_->CreateVideoProcessorEnumerator( |
| + &desc, video_processor_enumerator_.Receive()); |
| + CHECK(SUCCEEDED(hr)); |
| + |
| + D3D11_VIDEO_PROCESSOR_CAPS caps; |
| + hr = video_processor_enumerator_->GetVideoProcessorCaps(&caps); |
| + for (size_t i = 0; i < caps.RateConversionCapsCount; i++) { |
|
sunnyps
2017/03/28 00:42:23
Why is this loop needed?
|
| + D3D11_VIDEO_PROCESSOR_RATE_CONVERSION_CAPS rc_caps; |
| + hr = video_processor_enumerator_->GetVideoProcessorRateConversionCaps( |
| + (UINT)i, &rc_caps); |
| + } |
| + |
| + hr = video_device_->CreateVideoProcessor(video_processor_enumerator_.get(), 0, |
| + video_processor_.Receive()); |
| + CHECK(SUCCEEDED(hr)); |
| +} |
| + |
| +DCLayerTree::SwapChainPresenter::SwapChainPresenter( |
| + DCLayerTree* surface, |
| + base::win::ScopedComPtr<ID3D11Device> d3d11_device) |
| + : surface_(surface), d3d11_device_(d3d11_device) { |
| + d3d11_device_.QueryInterface(video_device_.Receive()); |
| + base::win::ScopedComPtr<ID3D11DeviceContext> context; |
| + d3d11_device_->GetImmediateContext(context.Receive()); |
| + context.QueryInterface(video_context_.Receive()); |
| + HMODULE dcomp = ::GetModuleHandleA("dcomp.dll"); |
| + DCHECK(dcomp); |
| + create_surface_handle_function_ = |
|
sunnyps
2017/03/28 00:42:24
nit: should this be a CHECK?
sunnyps
2017/03/28 22:28:58
I actually meant the check for dcomp.dll.
|
| + reinterpret_cast<PFN_DCOMPOSITION_CREATE_SURFACE_HANDLE>( |
| + GetProcAddress(dcomp, "DCompositionCreateSurfaceHandle")); |
| +} |
| + |
| +DCLayerTree::SwapChainPresenter::~SwapChainPresenter() {} |
| + |
| +void DCLayerTree::SwapChainPresenter::PresentToSwapChain( |
| + const ui::DCRendererLayerParams& params) { |
| + gl::GLImageDXGI* image_dxgi = |
| + gl::GLImageDXGI::FromGLImage(params.image.get()); |
| + DCHECK(image_dxgi); |
| + |
| + // Swap chain size is the minimum of the on-screen size and the source |
| + // size so the video processor can do the minimal amount of work and |
| + // the overlay has to read the minimal amount of data. |
| + // DWM is also less likely to promote a surface to an overlay if it's |
| + // much larger than its area on-screen. |
| + gfx::Rect bounds_rect = params.rect; |
| + gfx::Size ceiled_input_size = gfx::ToCeiledSize(params.contents_rect.size()); |
| + gfx::Size swap_chain_size = bounds_rect.size(); |
| + swap_chain_size.SetToMin(ceiled_input_size); |
| + |
| + // YUY2 surfaces must have an even width. |
| + if (swap_chain_size.width() % 2 == 1) |
| + swap_chain_size.set_width(swap_chain_size.width() + 1); |
| + |
| + if (InitializeVideoProcessor(ceiled_input_size, swap_chain_size)) |
| + out_view_.Release(); |
| + |
| + bool first_present = false; |
| + if (!swap_chain_ || swap_chain_size_ != swap_chain_size) { |
| + first_present = true; |
| + swap_chain_size_ = swap_chain_size; |
| + swap_chain_.Release(); |
| + ReallocateSwapChain(); |
| + } |
| + |
| + if (!out_view_) { |
| + base::win::ScopedComPtr<ID3D11Texture2D> texture; |
| + swap_chain_->GetBuffer(0, IID_PPV_ARGS(texture.Receive())); |
|
sunnyps
2017/03/28 00:42:24
Do we need to cycle through the back buffers of th
|
| + D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC out_desc = {}; |
| + out_desc.ViewDimension = D3D11_VPOV_DIMENSION_TEXTURE2D; |
| + out_desc.Texture2D.MipSlice = 0; |
| + out_view_.Release(); |
|
sunnyps
2017/03/28 00:42:23
nit: out_view_.Release isn't needed here
|
| + HRESULT hr = video_device_->CreateVideoProcessorOutputView( |
| + texture.get(), video_processor_enumerator_.get(), &out_desc, |
| + out_view_.Receive()); |
| + CHECK(SUCCEEDED(hr)); |
| + } |
| + { |
| + D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC in_desc = {}; |
| + in_desc.ViewDimension = D3D11_VPIV_DIMENSION_TEXTURE2D; |
| + in_desc.Texture2D.ArraySlice = (UINT)image_dxgi->level(); |
| + base::win::ScopedComPtr<ID3D11VideoProcessorInputView> in_view; |
| + HRESULT hr = video_device_->CreateVideoProcessorInputView( |
| + image_dxgi->texture().get(), video_processor_enumerator_.get(), |
| + &in_desc, in_view.Receive()); |
| + CHECK(SUCCEEDED(hr)); |
| + |
| + D3D11_VIDEO_PROCESSOR_STREAM stream = {}; |
| + stream.Enable = true; |
| + stream.OutputIndex = 0; |
| + stream.InputFrameOrField = 0; |
| + stream.PastFrames = 0; |
| + stream.FutureFrames = 0; |
| + stream.pInputSurface = in_view.get(); |
| + RECT dest_rect = gfx::Rect(swap_chain_size).ToRECT(); |
| + video_context_->VideoProcessorSetOutputTargetRect(video_processor_.get(), |
| + TRUE, &dest_rect); |
| + video_context_->VideoProcessorSetStreamDestRect(video_processor_.get(), 0, |
| + TRUE, &dest_rect); |
| + RECT source_rect = gfx::Rect(ceiled_input_size).ToRECT(); |
| + video_context_->VideoProcessorSetStreamSourceRect(video_processor_.get(), 0, |
| + TRUE, &source_rect); |
| + |
| + video_context_->VideoProcessorSetStreamAutoProcessingMode( |
| + video_processor_.get(), 0, FALSE); |
| + |
| + hr = video_context_->VideoProcessorBlt(video_processor_.get(), |
| + out_view_.get(), 0, 1, &stream); |
| + CHECK(SUCCEEDED(hr)); |
| + } |
| + |
| + swap_chain_scale_x_ = bounds_rect.width() * 1.0f / swap_chain_size.width(); |
| + swap_chain_scale_y_ = bounds_rect.height() * 1.0f / swap_chain_size.height(); |
| + |
| + swap_chain_->Present(first_present ? 0 : 1, 0); |
| +} |
| + |
| +bool DCLayerTree::SwapChainPresenter::InitializeVideoProcessor( |
| + const gfx::Size& in_size, |
| + const gfx::Size& out_size) { |
| + if (video_processor_ && SizeContains(processor_input_size_, in_size) && |
| + SizeContains(processor_output_size_, out_size)) |
| + return false; |
| + processor_input_size_ = in_size; |
| + processor_output_size_ = out_size; |
| + surface_->InitializeVideoProcessor(in_size, out_size); |
| + |
| + video_processor_enumerator_ = surface_->video_processor_enumerator(); |
| + video_processor_ = surface_->video_processor(); |
| + return true; |
| +} |
| + |
| +void DCLayerTree::SwapChainPresenter::ReallocateSwapChain() { |
| + TRACE_EVENT0("gpu", "DCLayerTree::SwapChainPresenter::ReallocateSwapChain"); |
| + DCHECK(!swap_chain_); |
| + |
| + base::win::ScopedComPtr<IDXGIDevice> dxgi_device; |
| + d3d11_device_.QueryInterface(dxgi_device.Receive()); |
| + base::win::ScopedComPtr<IDXGIAdapter> dxgi_adapter; |
| + dxgi_device->GetAdapter(dxgi_adapter.Receive()); |
| + base::win::ScopedComPtr<IDXGIFactory2> dxgi_factory; |
| + dxgi_adapter->GetParent(IID_PPV_ARGS(dxgi_factory.Receive())); |
| + |
| + base::win::ScopedComPtr<IDXGIFactoryMedia> media_factory; |
| + dxgi_factory.QueryInterface(media_factory.Receive()); |
| + DXGI_SWAP_CHAIN_DESC1 desc = {}; |
| + desc.Width = swap_chain_size_.width(); |
| + desc.Height = swap_chain_size_.height(); |
| + LOG(ERROR) << "Width " << desc.Width << " height " << desc.Height; |
| + desc.Format = DXGI_FORMAT_YUY2; |
| + desc.Stereo = FALSE; |
| + desc.SampleDesc.Count = 1; |
| + desc.BufferCount = 2; |
| + desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; |
| + desc.Scaling = DXGI_SCALING_STRETCH; |
| + desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; |
| + desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE; |
| + desc.Flags = |
| + DXGI_SWAP_CHAIN_FLAG_YUV_VIDEO | DXGI_SWAP_CHAIN_FLAG_FULLSCREEN_VIDEO; |
| + |
| + HANDLE handle; |
| + create_surface_handle_function_(COMPOSITIONOBJECT_ALL_ACCESS, nullptr, |
| + &handle); |
| + swap_chain_handle_.Set(handle); |
| + |
| + // The composition surface handle isn't actually used, but |
| + // CreateSwapChainForComposition can't create YUY2 swapchains. |
| + HRESULT hr = media_factory->CreateSwapChainForCompositionSurfaceHandle( |
| + d3d11_device_.get(), swap_chain_handle_.Get(), &desc, nullptr, |
| + swap_chain_.Receive()); |
| + |
| + if (FAILED(hr)) { |
| + // This should be hit in production but is a simple fallback for |
|
sunnyps
2017/03/28 00:42:24
nit: should not be hit?
|
| + // testing on systems without YUY2 swapchain support. |
| + DLOG(ERROR) << "YUY2 creation failed with " << std::hex << hr |
| + << ". Falling back to BGRA"; |
| + desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; |
| + desc.Flags = 0; |
| + hr = media_factory->CreateSwapChainForCompositionSurfaceHandle( |
| + d3d11_device_.get(), swap_chain_handle_.Get(), &desc, nullptr, |
| + swap_chain_.Receive()); |
| + CHECK(SUCCEEDED(hr)); |
| + } else { |
| + base::win::ScopedComPtr<IDXGISwapChain3> swap_chain3; |
| + swap_chain_.QueryInterface(swap_chain3.Receive()); |
| + hr = swap_chain3->SetColorSpace1( |
|
sunnyps
2017/03/28 00:42:24
What's the significance of setting the color space
|
| + DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709); |
| + CHECK(SUCCEEDED(hr)); |
| + } |
| + out_view_.Release(); |
| +} |
| + |
| +bool DCLayerTree::CommitAndClearPendingOverlays() { |
| + TRACE_EVENT1("gpu", "DCLayerTree::CommitAndClearPendingOverlays", "size", |
| + pending_overlays_.size()); |
| + // Add an overlay with z-order 0 representing the main plane. |
| + gfx::Size surface_size = surface_->GetSize(); |
| + pending_overlays_.push_back(base::MakeUnique<ui::DCRendererLayerParams>( |
| + false, gfx::Rect(), 0, gfx::Transform(), nullptr, |
| + gfx::RectF(gfx::SizeF(surface_size)), gfx::Rect(surface_size), 0, 0, 1.0, |
| + 0)); |
| + |
| + // TODO(jbauman): Reuse swapchains that are switched between overlays and |
| + // underlays. |
| + std::sort(pending_overlays_.begin(), pending_overlays_.end(), |
| + [](const auto& a, const auto& b) -> bool { |
| + return a->z_order < b->z_order; |
| + }); |
| + |
| + while (visual_info_.size() > pending_overlays_.size()) { |
|
sunnyps
2017/03/28 00:42:23
I think it's OK to keep extra visual infos around
|
| + visual_info_.back().clip_visual->RemoveAllVisuals(); |
| + root_visual_->RemoveVisual(visual_info_.back().clip_visual.get()); |
| + visual_info_.pop_back(); |
| + } |
| + |
| + visual_info_.resize(pending_overlays_.size()); |
| + |
| + for (size_t i = 0; i < pending_overlays_.size(); i++) { |
|
sunnyps
2017/03/28 00:42:24
Can you add a comment saying what the visual tree
|
| + ui::DCRendererLayerParams& params = *pending_overlays_[i]; |
| + VisualInfo* visual_info = &visual_info_[i]; |
| + |
| + base::win::ScopedComPtr<IDCompositionVisual2> this_visual; |
|
sunnyps
2017/03/28 00:42:23
nit: content_visual?
|
| + |
| + if (!visual_info->visual) { |
|
sunnyps
2017/03/28 00:42:23
Can you factor this into InitVisual(VisualInfo*)?
|
| + dcomp_device_->CreateVisual(visual_info->clip_visual.Receive()); |
| + dcomp_device_->CreateVisual(this_visual.Receive()); |
| + visual_info->visual = this_visual; |
| + visual_info->clip_visual->AddVisual(this_visual.get(), FALSE, nullptr); |
| + |
| + IDCompositionVisual2* last_visual = |
| + (i > 0) ? visual_info_[i - 1].clip_visual.get() : nullptr; |
| + root_visual_->AddVisual(visual_info->clip_visual.get(), TRUE, |
| + last_visual); |
| + } else { |
| + this_visual = visual_info->visual; |
| + } |
| + |
| + gfx::Rect bounds_rect = params.rect; |
| + |
| + if (params.image && |
| + params.image->GetType() == gl::GLImage::Type::DXGI_IMAGE) { |
|
sunnyps
2017/03/28 00:42:23
Can you factor the body of this into UpdateVisualF
|
| + visual_info->surface.Release(); |
| + if (!visual_info->swap_chain_presenter) { |
| + visual_info->swap_chain_presenter = |
| + base::MakeUnique<SwapChainPresenter>(this, d3d11_device_); |
| + } |
| + visual_info->swap_chain_presenter->PresentToSwapChain(params); |
| + if (visual_info->swap_chain != |
| + visual_info->swap_chain_presenter->swap_chain()) { |
| + visual_info->swap_chain = |
| + visual_info->swap_chain_presenter->swap_chain(); |
| + this_visual->SetContent(visual_info->swap_chain.get()); |
| + } |
| + |
| + if (visual_info->swap_chain_presenter->swap_chain_scale_x() != |
| + visual_info->swap_chain_scale_x || |
| + visual_info->swap_chain_presenter->swap_chain_scale_y() != |
| + visual_info->swap_chain_scale_y || |
| + params.transform != visual_info->transform || |
| + visual_info->bounds != bounds_rect) { |
| + visual_info->swap_chain_scale_x = |
| + visual_info->swap_chain_presenter->swap_chain_scale_x(); |
| + visual_info->swap_chain_scale_y = |
| + visual_info->swap_chain_presenter->swap_chain_scale_y(); |
| + visual_info->transform = params.transform; |
| + visual_info->bounds = bounds_rect; |
| + |
| + gfx::Transform final_transform = params.transform; |
| + gfx::Transform scale_transform; |
| + scale_transform.Scale( |
| + visual_info->swap_chain_presenter->swap_chain_scale_x(), |
| + visual_info->swap_chain_presenter->swap_chain_scale_y()); |
| + final_transform.PreconcatTransform(scale_transform); |
| + final_transform.Transpose(); |
| + |
| + this_visual->SetOffsetX(bounds_rect.x()); |
| + this_visual->SetOffsetY(bounds_rect.y()); |
| + base::win::ScopedComPtr<IDCompositionMatrixTransform> dcomp_transform; |
| + dcomp_device_->CreateMatrixTransform(dcomp_transform.Receive()); |
| + D2D_MATRIX_3X2_F d2d_matrix = {{{final_transform.matrix().get(0, 0), |
| + final_transform.matrix().get(0, 1), |
| + final_transform.matrix().get(1, 0), |
| + final_transform.matrix().get(1, 1), |
| + final_transform.matrix().get(3, 0), |
| + final_transform.matrix().get(3, 1)}}}; |
| + dcomp_transform->SetMatrix(d2d_matrix); |
| + this_visual->SetTransform(dcomp_transform.get()); |
| + } |
| + } else if (!params.image) { |
| + // Main backbuffer. |
|
sunnyps
2017/03/28 00:42:23
Can you factor this into UpdateVisualForBackbuffer
sunnyps
2017/03/28 00:42:23
If visual_info was used by a video overlay in the
|
| + if (visual_info->surface != surface_->dcomp_surface()) { |
| + this_visual->SetContent(surface_->dcomp_surface().get()); |
| + visual_info->surface = surface_->dcomp_surface(); |
| + visual_info->swap_chain_presenter = nullptr; |
| + visual_info->swap_chain.Release(); |
| + } |
| + if (visual_info->swap_chain != surface_->swap_chain()) { |
| + this_visual->SetContent(surface_->swap_chain().get()); |
| + visual_info->surface = nullptr; |
| + visual_info->swap_chain_presenter = nullptr; |
| + visual_info->swap_chain = surface_->swap_chain(); |
| + } |
| + if (visual_info->bounds != bounds_rect || |
| + !visual_info->transform.IsIdentity()) { |
| + this_visual->SetOffsetX(bounds_rect.x()); |
| + this_visual->SetOffsetY(bounds_rect.y()); |
| + visual_info->bounds = bounds_rect; |
| + this_visual->SetTransform(nullptr); |
| + visual_info->transform = gfx::Transform(); |
| + } |
| + } else { |
| + CHECK(false); |
| + } |
| + if (params.is_clipped != visual_info->is_clipped || |
|
sunnyps
2017/03/28 00:42:23
Can you factor this into UpdateVisualClip?
|
| + params.clip_rect != visual_info->clip_rect) { |
| + // DirectComposition clips happen in the pre-transform visual |
| + // space, while cc/ clips happen post-transform. So the clip needs |
| + // to go on a separate parent visual that's untransformed. |
| + visual_info->is_clipped = params.is_clipped; |
| + visual_info->clip_rect = params.clip_rect; |
| + if (params.is_clipped) { |
| + base::win::ScopedComPtr<IDCompositionRectangleClip> clip; |
| + dcomp_device_->CreateRectangleClip(clip.Receive()); |
| + gfx::Rect offset_clip = params.clip_rect; |
| + clip->SetLeft(offset_clip.x()); |
| + clip->SetRight(offset_clip.right()); |
| + clip->SetBottom(offset_clip.bottom()); |
| + clip->SetTop(offset_clip.y()); |
| + visual_info->clip_visual->SetClip(clip.get()); |
| + } else { |
| + visual_info->clip_visual->SetClip(nullptr); |
| + } |
| + } |
| + } |
| + |
| + HRESULT hr = dcomp_device_->Commit(); |
| + CHECK(SUCCEEDED(hr)); |
| + |
| + pending_overlays_.clear(); |
| + return true; |
| +} |
| + |
| +bool DCLayerTree::ScheduleDCLayer(const ui::DCRendererLayerParams& params) { |
| + pending_overlays_.push_back( |
|
sunnyps
2017/03/28 00:42:23
Is there a reason for heap allocating DCRendererLa
|
| + base::MakeUnique<ui::DCRendererLayerParams>(params)); |
| + return true; |
| +} |
| + |
| DirectCompositionSurfaceWin::DirectCompositionSurfaceWin( |
| base::WeakPtr<ImageTransportSurfaceDelegate> delegate, |
| HWND parent_window) |
| @@ -130,20 +652,11 @@ bool DirectCompositionSurfaceWin::Initialize(gl::GLSurfaceFormat format) { |
| } |
| } |
| - base::win::ScopedComPtr<IDCompositionDesktopDevice> desktop_device; |
| - dcomp_device_.QueryInterface(desktop_device.Receive()); |
| - |
| - HRESULT hr = desktop_device->CreateTargetForHwnd(window_, TRUE, |
| - dcomp_target_.Receive()); |
| - if (FAILED(hr)) |
| + layer_tree_ = |
| + base::MakeUnique<DCLayerTree>(this, d3d11_device_, dcomp_device_); |
| + if (!layer_tree_->Initialize(window_)) |
| return false; |
| - hr = dcomp_device_->CreateVisual(visual_.Receive()); |
| - if (FAILED(hr)) |
| - return false; |
| - |
| - dcomp_target_->SetRoot(visual_.get()); |
| - |
| std::vector<EGLint> pbuffer_attribs; |
| pbuffer_attribs.push_back(EGL_WIDTH); |
| pbuffer_attribs.push_back(1); |
| @@ -165,6 +678,8 @@ void DirectCompositionSurfaceWin::ReleaseCurrentSurface() { |
| } |
| void DirectCompositionSurfaceWin::InitializeSurface() { |
| + TRACE_EVENT1("gpu", "DirectCompositionSurfaceWin::InitializeSurface()", |
| + "enable_dc_layers_", enable_dc_layers_); |
| DCHECK(!dcomp_surface_); |
| DCHECK(!swap_chain_); |
| if (enable_dc_layers_) { |
| @@ -297,14 +812,8 @@ gfx::SwapResult DirectCompositionSurfaceWin::SwapBuffers() { |
| { |
| ScopedReleaseCurrent release_current(this); |
| ReleaseDrawTexture(false); |
| - DCHECK(dcomp_surface_ || swap_chain_); |
| - if (dcomp_surface_) |
| - visual_->SetContent(dcomp_surface_.get()); |
| - else |
| - visual_->SetContent(swap_chain_.get()); |
| - |
| - CommitAndClearPendingOverlays(); |
| - dcomp_device_->Commit(); |
| + |
| + layer_tree_->CommitAndClearPendingOverlays(); |
| } |
| child_window_.ClearInvalidContents(); |
| return gfx::SwapResult::SWAP_ACK; |
| @@ -323,15 +832,9 @@ gfx::VSyncProvider* DirectCompositionSurfaceWin::GetVSyncProvider() { |
| return vsync_provider_.get(); |
| } |
| -bool DirectCompositionSurfaceWin::ScheduleOverlayPlane( |
| - int z_order, |
| - gfx::OverlayTransform transform, |
| - gl::GLImage* image, |
| - const gfx::Rect& bounds_rect, |
| - const gfx::RectF& crop_rect) { |
| - pending_overlays_.push_back( |
| - Overlay(z_order, transform, image, bounds_rect, crop_rect)); |
| - return true; |
| +bool DirectCompositionSurfaceWin::ScheduleDCLayer( |
| + const ui::DCRendererLayerParams& params) { |
| + return layer_tree_->ScheduleDCLayer(params); |
| } |
| bool DirectCompositionSurfaceWin::SetEnableDCLayers(bool enable) { |
| @@ -339,10 +842,6 @@ bool DirectCompositionSurfaceWin::SetEnableDCLayers(bool enable) { |
| return true; |
| } |
| -bool DirectCompositionSurfaceWin::CommitAndClearPendingOverlays() { |
| - pending_overlays_.clear(); |
| - return true; |
| -} |
| bool DirectCompositionSurfaceWin::FlipsVertically() const { |
| return true; |
| @@ -375,7 +874,6 @@ bool DirectCompositionSurfaceWin::SupportsDCLayers() const { |
| bool DirectCompositionSurfaceWin::SetDrawRectangle(const gfx::Rect& rectangle) { |
| if (draw_texture_) |
| return false; |
| - |
| DCHECK(!real_surface_); |
| ScopedReleaseCurrent release_current(this); |
| @@ -441,19 +939,4 @@ DirectCompositionSurfaceWin::GetWindowTaskRunnerForTesting() { |
| return child_window_.GetTaskRunnerForTesting(); |
| } |
| -DirectCompositionSurfaceWin::Overlay::Overlay(int z_order, |
| - gfx::OverlayTransform transform, |
| - scoped_refptr<gl::GLImage> image, |
| - gfx::Rect bounds_rect, |
| - gfx::RectF crop_rect) |
| - : z_order(z_order), |
| - transform(transform), |
| - image(image), |
| - bounds_rect(bounds_rect), |
| - crop_rect(crop_rect) {} |
| - |
| -DirectCompositionSurfaceWin::Overlay::Overlay(const Overlay& overlay) = default; |
| - |
| -DirectCompositionSurfaceWin::Overlay::~Overlay() {} |
| - |
| } // namespace gpu |