Commit 196982d4 authored by jbauman's avatar jbauman Committed by Commit Bot

Split DirectCompositionSurfaceWin into two parts.

DirectCompositionSurfaceWin remains as the host of the DCLayerTree,
while DirectCompositionChildSurfaceWin handles drawing to the
IDCompositionSurface itself. This will allow us to have more Surfaces
in the layer tree in the future.

BUG=726957
CQ_INCLUDE_TRYBOTS=master.tryserver.chromium.android:android_optional_gpu_tests_rel;master.tryserver.chromium.linux:linux_optional_gpu_tests_rel;master.tryserver.chromium.mac:mac_optional_gpu_tests_rel;master.tryserver.chromium.win:win_optional_gpu_tests_rel

Review-Url: https://codereview.chromium.org/2926763002
Cr-Commit-Position: refs/heads/master@{#478794}
parent 7dd8521b
...@@ -83,6 +83,8 @@ target(link_target_type, "ipc_service_sources") { ...@@ -83,6 +83,8 @@ target(link_target_type, "ipc_service_sources") {
"child_window_surface_win.h", "child_window_surface_win.h",
"child_window_win.cc", "child_window_win.cc",
"child_window_win.h", "child_window_win.h",
"direct_composition_child_surface_win.cc",
"direct_composition_child_surface_win.h",
"direct_composition_surface_win.cc", "direct_composition_surface_win.cc",
"direct_composition_surface_win.h", "direct_composition_surface_win.h",
"image_transport_surface_win.cc", "image_transport_surface_win.cc",
......
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "gpu/ipc/service/direct_composition_child_surface_win.h"
#include <d3d11_1.h>
#include <dcomptypes.h>
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "base/synchronization/waitable_event.h"
#include "base/trace_event/trace_event.h"
#include "ui/display/display_switches.h"
#include "ui/gfx/native_widget_types.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_surface_egl.h"
#include "ui/gl/scoped_make_current.h"
#ifndef EGL_ANGLE_flexible_surface_compatibility
#define EGL_ANGLE_flexible_surface_compatibility 1
#define EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE 0x33A6
#endif /* EGL_ANGLE_flexible_surface_compatibility */
#ifndef EGL_ANGLE_d3d_texture_client_buffer
#define EGL_ANGLE_d3d_texture_client_buffer 1
#define EGL_D3D_TEXTURE_ANGLE 0x33A3
#endif /* EGL_ANGLE_d3d_texture_client_buffer */
namespace gpu {
namespace {
// 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.
IDCompositionSurface* g_current_surface;
}
DirectCompositionChildSurfaceWin::DirectCompositionChildSurfaceWin(
const gfx::Size& size,
bool has_alpha,
bool enable_dc_layers)
: gl::GLSurfaceEGL(),
size_(size),
has_alpha_(has_alpha),
enable_dc_layers_(enable_dc_layers) {}
DirectCompositionChildSurfaceWin::~DirectCompositionChildSurfaceWin() {
Destroy();
}
bool DirectCompositionChildSurfaceWin::Initialize(gl::GLSurfaceFormat format) {
d3d11_device_ = gl::QueryD3D11DeviceObjectFromANGLE();
dcomp_device_ = gl::QueryDirectCompositionDevice(d3d11_device_);
if (!dcomp_device_)
return false;
EGLDisplay display = GetDisplay();
std::vector<EGLint> pbuffer_attribs;
pbuffer_attribs.push_back(EGL_WIDTH);
pbuffer_attribs.push_back(1);
pbuffer_attribs.push_back(EGL_HEIGHT);
pbuffer_attribs.push_back(1);
pbuffer_attribs.push_back(EGL_NONE);
default_surface_ =
eglCreatePbufferSurface(display, GetConfig(), &pbuffer_attribs[0]);
CHECK(!!default_surface_);
return true;
}
void DirectCompositionChildSurfaceWin::ReleaseCurrentSurface() {
ReleaseDrawTexture(true);
dcomp_surface_.Reset();
swap_chain_.Reset();
}
void DirectCompositionChildSurfaceWin::InitializeSurface() {
TRACE_EVENT1("gpu", "DirectCompositionChildSurfaceWin::InitializeSurface()",
"enable_dc_layers_", enable_dc_layers_);
DCHECK(!dcomp_surface_);
DCHECK(!swap_chain_);
DXGI_FORMAT output_format =
base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableHDR)
? DXGI_FORMAT_R16G16B16A16_FLOAT
: DXGI_FORMAT_B8G8R8A8_UNORM;
if (enable_dc_layers_) {
// Always treat as premultiplied, because an underlay could cause it to
// become transparent.
HRESULT hr = dcomp_device_->CreateSurface(
size_.width(), size_.height(), output_format,
DXGI_ALPHA_MODE_PREMULTIPLIED, dcomp_surface_.GetAddressOf());
has_been_rendered_to_ = false;
CHECK(SUCCEEDED(hr));
} else {
DXGI_ALPHA_MODE alpha_mode =
has_alpha_ ? DXGI_ALPHA_MODE_PREMULTIPLIED : DXGI_ALPHA_MODE_IGNORE;
base::win::ScopedComPtr<IDXGIDevice> dxgi_device;
d3d11_device_.CopyTo(dxgi_device.GetAddressOf());
base::win::ScopedComPtr<IDXGIAdapter> dxgi_adapter;
dxgi_device->GetAdapter(dxgi_adapter.GetAddressOf());
base::win::ScopedComPtr<IDXGIFactory2> dxgi_factory;
dxgi_adapter->GetParent(IID_PPV_ARGS(dxgi_factory.GetAddressOf()));
DXGI_SWAP_CHAIN_DESC1 desc = {};
desc.Width = size_.width();
desc.Height = size_.height();
desc.Format = output_format;
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 = alpha_mode;
desc.Flags = 0;
HRESULT hr = dxgi_factory->CreateSwapChainForComposition(
d3d11_device_.Get(), &desc, nullptr, swap_chain_.GetAddressOf());
has_been_rendered_to_ = false;
first_swap_ = true;
CHECK(SUCCEEDED(hr));
}
}
void DirectCompositionChildSurfaceWin::ReleaseDrawTexture(bool will_discard) {
if (real_surface_) {
eglDestroySurface(GetDisplay(), real_surface_);
real_surface_ = nullptr;
}
if (draw_texture_) {
draw_texture_.Reset();
if (dcomp_surface_) {
HRESULT hr = dcomp_surface_->EndDraw();
CHECK(SUCCEEDED(hr));
} else if (!will_discard) {
DXGI_PRESENT_PARAMETERS params = {};
RECT dirty_rect = swap_rect_.ToRECT();
params.DirtyRectsCount = 1;
params.pDirtyRects = &dirty_rect;
swap_chain_->Present1(first_swap_ ? 0 : 1, 0, &params);
if (first_swap_) {
// Wait for the GPU to finish executing its commands before
// committing the DirectComposition tree, or else the swapchain
// may flicker black when it's first presented.
base::win::ScopedComPtr<IDXGIDevice2> dxgi_device2;
HRESULT hr = d3d11_device_.CopyTo(dxgi_device2.GetAddressOf());
DCHECK(SUCCEEDED(hr));
base::WaitableEvent event(
base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::NOT_SIGNALED);
dxgi_device2->EnqueueSetEvent(event.handle());
event.Wait();
first_swap_ = false;
}
}
}
if (dcomp_surface_ == g_current_surface)
g_current_surface = nullptr;
}
void DirectCompositionChildSurfaceWin::Destroy() {
if (default_surface_) {
if (!eglDestroySurface(GetDisplay(), default_surface_)) {
DLOG(ERROR) << "eglDestroySurface failed with error "
<< ui::GetLastEGLErrorString();
}
default_surface_ = nullptr;
}
if (real_surface_) {
if (!eglDestroySurface(GetDisplay(), real_surface_)) {
DLOG(ERROR) << "eglDestroySurface failed with error "
<< ui::GetLastEGLErrorString();
}
real_surface_ = nullptr;
}
if (dcomp_surface_ && (dcomp_surface_ == g_current_surface)) {
HRESULT hr = dcomp_surface_->EndDraw();
CHECK(SUCCEEDED(hr));
g_current_surface = nullptr;
}
draw_texture_.Reset();
dcomp_surface_.Reset();
}
gfx::Size DirectCompositionChildSurfaceWin::GetSize() {
return size_;
}
bool DirectCompositionChildSurfaceWin::IsOffscreen() {
return false;
}
void* DirectCompositionChildSurfaceWin::GetHandle() {
return real_surface_ ? real_surface_ : default_surface_;
}
gfx::SwapResult DirectCompositionChildSurfaceWin::SwapBuffers() {
ReleaseDrawTexture(false);
return gfx::SwapResult::SWAP_ACK;
}
bool DirectCompositionChildSurfaceWin::FlipsVertically() const {
return true;
}
bool DirectCompositionChildSurfaceWin::SupportsPostSubBuffer() {
return true;
}
bool DirectCompositionChildSurfaceWin::OnMakeCurrent(gl::GLContext* context) {
if (g_current_surface != dcomp_surface_) {
if (g_current_surface) {
HRESULT hr = g_current_surface->SuspendDraw();
CHECK(SUCCEEDED(hr));
g_current_surface = nullptr;
}
if (draw_texture_) {
HRESULT hr = dcomp_surface_->ResumeDraw();
CHECK(SUCCEEDED(hr));
g_current_surface = dcomp_surface_.Get();
}
}
return true;
}
bool DirectCompositionChildSurfaceWin::SupportsDCLayers() const {
return true;
}
bool DirectCompositionChildSurfaceWin::SetDrawRectangle(
const gfx::Rect& rectangle) {
if (draw_texture_)
return false;
DCHECK(!real_surface_);
ui::ScopedReleaseCurrent release_current(this);
if ((enable_dc_layers_ && !dcomp_surface_) ||
(!enable_dc_layers_ && !swap_chain_)) {
ReleaseCurrentSurface();
InitializeSurface();
}
if (!gfx::Rect(size_).Contains(rectangle)) {
DLOG(ERROR) << "Draw rectangle must be contained within size of surface";
return false;
}
if (gfx::Rect(size_) != rectangle && !has_been_rendered_to_) {
DLOG(ERROR) << "First draw to surface must draw to everything";
return false;
}
CHECK(!g_current_surface);
RECT rect = rectangle.ToRECT();
if (dcomp_surface_) {
POINT update_offset;
HRESULT hr = dcomp_surface_->BeginDraw(
&rect, IID_PPV_ARGS(draw_texture_.GetAddressOf()), &update_offset);
draw_offset_ = gfx::Point(update_offset) - gfx::Rect(rect).origin();
CHECK(SUCCEEDED(hr));
} else {
HRESULT hr =
swap_chain_->GetBuffer(0, IID_PPV_ARGS(draw_texture_.GetAddressOf()));
swap_rect_ = rectangle;
draw_offset_ = gfx::Vector2d();
CHECK(SUCCEEDED(hr));
}
has_been_rendered_to_ = true;
g_current_surface = dcomp_surface_.Get();
std::vector<EGLint> pbuffer_attribs{
EGL_WIDTH,
size_.width(),
EGL_HEIGHT,
size_.height(),
EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE,
EGL_TRUE,
EGL_NONE};
EGLClientBuffer buffer =
reinterpret_cast<EGLClientBuffer>(draw_texture_.Get());
real_surface_ = eglCreatePbufferFromClientBuffer(
GetDisplay(), EGL_D3D_TEXTURE_ANGLE, buffer, GetConfig(),
&pbuffer_attribs[0]);
return true;
}
gfx::Vector2d DirectCompositionChildSurfaceWin::GetDrawOffset() const {
return draw_offset_;
}
} // namespace gpu
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef GPU_IPC_SERVICE_DIRECT_COMPOSITION_CHILD_SURFACE_WIN_H_
#define GPU_IPC_SERVICE_DIRECT_COMPOSITION_CHILD_SURFACE_WIN_H_
#include <d3d11.h>
#include <dcomp.h>
#include <windows.h>
#include "base/win/scoped_comptr.h"
#include "gpu/gpu_export.h"
#include "ui/gl/gl_surface_egl.h"
namespace gpu {
class GPU_EXPORT DirectCompositionChildSurfaceWin : public gl::GLSurfaceEGL {
public:
DirectCompositionChildSurfaceWin(const gfx::Size& size,
bool has_alpha,
bool enable_dc_layers);
// GLSurfaceEGL implementation.
using GLSurfaceEGL::Initialize;
bool Initialize(gl::GLSurfaceFormat format) override;
void Destroy() override;
gfx::Size GetSize() override;
bool IsOffscreen() override;
void* GetHandle() override;
gfx::SwapResult SwapBuffers() override;
bool FlipsVertically() const override;
bool SupportsPostSubBuffer() override;
bool OnMakeCurrent(gl::GLContext* context) override;
bool SupportsDCLayers() const override;
bool SetDrawRectangle(const gfx::Rect& rect) override;
gfx::Vector2d GetDrawOffset() const override;
const base::win::ScopedComPtr<IDCompositionSurface>& dcomp_surface() const {
return dcomp_surface_;
}
const base::win::ScopedComPtr<IDXGISwapChain1>& swap_chain() const {
return swap_chain_;
}
protected:
~DirectCompositionChildSurfaceWin() override;
private:
void ReleaseCurrentSurface();
void InitializeSurface();
// Release the texture that's currently being drawn to. If will_discard is
// true then the surface should be discarded without swapping any contents
// to it.
void ReleaseDrawTexture(bool will_discard);
// This is a placeholder surface used when not rendering to the
// DirectComposition surface.
EGLSurface default_surface_ = 0;
// This is the real surface representing the backbuffer. It may be null
// outside of a BeginDraw/EndDraw pair.
EGLSurface real_surface_ = 0;
bool first_swap_ = true;
const gfx::Size size_;
const bool has_alpha_;
const bool enable_dc_layers_;
gfx::Rect swap_rect_;
gfx::Vector2d draw_offset_;
base::win::ScopedComPtr<ID3D11Device> d3d11_device_;
base::win::ScopedComPtr<IDCompositionDevice2> dcomp_device_;
base::win::ScopedComPtr<IDCompositionSurface> dcomp_surface_;
base::win::ScopedComPtr<IDXGISwapChain1> swap_chain_;
base::win::ScopedComPtr<ID3D11Texture2D> draw_texture_;
// Keep track of whether the texture has been rendered to, as the first draw
// to it must overwrite the entire thing.
bool has_been_rendered_to_ = false;
DISALLOW_COPY_AND_ASSIGN(DirectCompositionChildSurfaceWin);
};
} // namespace gpu
#endif // GPU_IPC_SERVICE_DIRECT_COMPOSITION_CHILD_SURFACE_WIN_H_
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
namespace gpu { namespace gpu {
class DCLayerTree; class DCLayerTree;
class DirectCompositionChildSurfaceWin;
class GPU_EXPORT DirectCompositionSurfaceWin : public gl::GLSurfaceEGL { class GPU_EXPORT DirectCompositionSurfaceWin : public gl::GLSurfaceEGL {
public: public:
...@@ -64,14 +65,10 @@ class GPU_EXPORT DirectCompositionSurfaceWin : public gl::GLSurfaceEGL { ...@@ -64,14 +65,10 @@ class GPU_EXPORT DirectCompositionSurfaceWin : public gl::GLSurfaceEGL {
// tree at z-order 0. // tree at z-order 0.
bool ScheduleDCLayer(const ui::DCRendererLayerParams& params) override; bool ScheduleDCLayer(const ui::DCRendererLayerParams& params) override;
const base::win::ScopedComPtr<IDCompositionSurface>& dcomp_surface() const { const base::win::ScopedComPtr<IDCompositionSurface> dcomp_surface() const;
return dcomp_surface_; const base::win::ScopedComPtr<IDXGISwapChain1> swap_chain() const;
}
scoped_refptr<base::TaskRunner> GetWindowTaskRunnerForTesting(); scoped_refptr<base::TaskRunner> GetWindowTaskRunnerForTesting();
const base::win::ScopedComPtr<IDXGISwapChain1>& swap_chain() const {
return swap_chain_;
}
base::win::ScopedComPtr<IDXGISwapChain1> GetLayerSwapChainForTesting( base::win::ScopedComPtr<IDXGISwapChain1> GetLayerSwapChainForTesting(
size_t index) const; size_t index) const;
...@@ -82,12 +79,7 @@ class GPU_EXPORT DirectCompositionSurfaceWin : public gl::GLSurfaceEGL { ...@@ -82,12 +79,7 @@ class GPU_EXPORT DirectCompositionSurfaceWin : public gl::GLSurfaceEGL {
~DirectCompositionSurfaceWin() override; ~DirectCompositionSurfaceWin() override;
private: private:
void ReleaseCurrentSurface(); bool RecreateRootSurface();
void InitializeSurface();
// Release the texture that's currently being drawn to. If will_discard is
// true then the surface should be discarded without swapping any contents
// to it.
void ReleaseDrawTexture(bool will_discard);
ChildWindowWin child_window_; ChildWindowWin child_window_;
...@@ -98,27 +90,15 @@ class GPU_EXPORT DirectCompositionSurfaceWin : public gl::GLSurfaceEGL { ...@@ -98,27 +90,15 @@ class GPU_EXPORT DirectCompositionSurfaceWin : public gl::GLSurfaceEGL {
// DirectComposition surface. // DirectComposition surface.
EGLSurface default_surface_ = 0; EGLSurface default_surface_ = 0;
// This is the real surface representing the backbuffer. It may be null
// outside of a BeginDraw/EndDraw pair.
EGLSurface real_surface_ = 0;
gfx::Size size_ = gfx::Size(1, 1); gfx::Size size_ = gfx::Size(1, 1);
bool first_swap_ = true;
bool enable_dc_layers_ = false; bool enable_dc_layers_ = false;
bool has_alpha_ = true; bool has_alpha_ = true;
std::unique_ptr<gfx::VSyncProvider> vsync_provider_; std::unique_ptr<gfx::VSyncProvider> vsync_provider_;
gfx::Rect swap_rect_; scoped_refptr<DirectCompositionChildSurfaceWin> root_surface_;
std::unique_ptr<DCLayerTree> layer_tree_; std::unique_ptr<DCLayerTree> layer_tree_;
gfx::Vector2d draw_offset_;
base::win::ScopedComPtr<ID3D11Device> d3d11_device_; base::win::ScopedComPtr<ID3D11Device> d3d11_device_;
base::win::ScopedComPtr<IDCompositionDevice2> dcomp_device_; base::win::ScopedComPtr<IDCompositionDevice2> dcomp_device_;
base::win::ScopedComPtr<IDCompositionSurface> dcomp_surface_;
base::win::ScopedComPtr<IDXGISwapChain1> swap_chain_;
base::win::ScopedComPtr<ID3D11Texture2D> draw_texture_;
// Keep track of whether the texture has been rendered to, as the first draw
// to it must overwrite the entire thing.
bool has_been_rendered_to_ = false;
DISALLOW_COPY_AND_ASSIGN(DirectCompositionSurfaceWin); DISALLOW_COPY_AND_ASSIGN(DirectCompositionSurfaceWin);
}; };
......
...@@ -35,4 +35,16 @@ bool ScopedMakeCurrent::Succeeded() const { ...@@ -35,4 +35,16 @@ bool ScopedMakeCurrent::Succeeded() const {
return succeeded_; return succeeded_;
} }
ScopedReleaseCurrent::ScopedReleaseCurrent(gl::GLSurface* this_surface) {
gl::GLContext* current_context = gl::GLContext::GetCurrent();
bool was_current =
current_context && current_context->IsCurrent(this_surface);
if (was_current) {
make_current_.emplace(current_context, this_surface);
current_context->ReleaseCurrent(this_surface);
}
}
ScopedReleaseCurrent::~ScopedReleaseCurrent() {}
} // namespace ui } // namespace ui
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/optional.h"
#include "ui/gl/gl_export.h" #include "ui/gl/gl_export.h"
namespace gl { namespace gl {
...@@ -33,6 +34,20 @@ class GL_EXPORT ScopedMakeCurrent { ...@@ -33,6 +34,20 @@ class GL_EXPORT ScopedMakeCurrent {
DISALLOW_COPY_AND_ASSIGN(ScopedMakeCurrent); DISALLOW_COPY_AND_ASSIGN(ScopedMakeCurrent);
}; };
// This class is used to make sure a specified surface isn't current, and upon
// destruction it will make the surface current again if it had been before.
class GL_EXPORT ScopedReleaseCurrent {
public:
explicit ScopedReleaseCurrent(gl::GLSurface* this_surface);
~ScopedReleaseCurrent();
private:
base::Optional<ScopedMakeCurrent> make_current_;
DISALLOW_COPY_AND_ASSIGN(ScopedReleaseCurrent);
};
} // namespace ui } // namespace ui
#endif // UI_GL_SCOPED_MAKE_CURRENT_H_ #endif // UI_GL_SCOPED_MAKE_CURRENT_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment