| Index: gpu/ipc/service/direct_composition_child_surface_win.cc
|
| diff --git a/gpu/ipc/service/direct_composition_child_surface_win.cc b/gpu/ipc/service/direct_composition_child_surface_win.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..e93aae934e96235c9c618ec1761d61ad93ce2054
|
| --- /dev/null
|
| +++ b/gpu/ipc/service/direct_composition_child_surface_win.cc
|
| @@ -0,0 +1,298 @@
|
| +// 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, ¶ms);
|
| + 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
|
|
|