| 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 d4255619863f407e078d8a830607130954966946..317964e52229a8212250631c6ba69032eba7f4c8 100644
|
| --- a/gpu/ipc/service/direct_composition_surface_win.cc
|
| +++ b/gpu/ipc/service/direct_composition_surface_win.cc
|
| @@ -4,23 +4,62 @@
|
|
|
| #include "gpu/ipc/service/direct_composition_surface_win.h"
|
|
|
| +#include "base/optional.h"
|
| #include "gpu/ipc/service/gpu_channel_manager.h"
|
| #include "gpu/ipc/service/gpu_channel_manager_delegate.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 {
|
| +
|
| +// 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 ScopedReleaseCurrent {
|
| + public:
|
| + explicit 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);
|
| + }
|
| + }
|
| +
|
| + private:
|
| + base::Optional<ui::ScopedMakeCurrent> make_current_;
|
| +};
|
| +
|
| +// 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;
|
| +
|
| +} // namespace
|
|
|
| DirectCompositionSurfaceWin::DirectCompositionSurfaceWin(
|
| base::WeakPtr<ImageTransportSurfaceDelegate> delegate,
|
| HWND parent_window)
|
| - : gl::GLSurfaceEGL(),
|
| - child_window_(delegate, parent_window),
|
| - window_(nullptr),
|
| - surface_(0),
|
| - first_swap_(true) {}
|
| + : gl::GLSurfaceEGL(), child_window_(delegate, parent_window) {}
|
| +
|
| +DirectCompositionSurfaceWin::~DirectCompositionSurfaceWin() {
|
| + Destroy();
|
| +}
|
|
|
| bool DirectCompositionSurfaceWin::InitializeNativeWindow() {
|
| if (window_)
|
| @@ -31,14 +70,40 @@ bool DirectCompositionSurfaceWin::InitializeNativeWindow() {
|
| return result;
|
| }
|
|
|
| +bool DirectCompositionSurfaceWin::Initialize(
|
| + std::unique_ptr<gfx::VSyncProvider> vsync_provider) {
|
| + vsync_provider_ = std::move(vsync_provider);
|
| + return Initialize(gl::GLSurfaceFormat());
|
| +}
|
| +
|
| bool DirectCompositionSurfaceWin::Initialize(gl::GLSurfaceFormat format) {
|
| + d3d11_device_ = gl::QueryD3D11DeviceObjectFromANGLE();
|
| + dcomp_device_ = gl::QueryDirectCompositionDevice(d3d11_device_);
|
| + if (!dcomp_device_)
|
| + return false;
|
| +
|
| EGLDisplay display = GetDisplay();
|
| if (!window_) {
|
| if (!InitializeNativeWindow()) {
|
| - LOG(ERROR) << "Failed to initialize native window";
|
| + DLOG(ERROR) << "Failed to initialize native window";
|
| return false;
|
| }
|
| }
|
| +
|
| + 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(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);
|
| @@ -46,20 +111,60 @@ bool DirectCompositionSurfaceWin::Initialize(gl::GLSurfaceFormat format) {
|
| pbuffer_attribs.push_back(1);
|
|
|
| pbuffer_attribs.push_back(EGL_NONE);
|
| - surface_ = eglCreatePbufferSurface(display, GetConfig(), &pbuffer_attribs[0]);
|
| - CHECK(!!surface_);
|
| + default_surface_ =
|
| + eglCreatePbufferSurface(display, GetConfig(), &pbuffer_attribs[0]);
|
| + CHECK(!!default_surface_);
|
| +
|
| + InitializeSurface();
|
|
|
| return true;
|
| }
|
|
|
| +void DirectCompositionSurfaceWin::InitializeSurface() {
|
| + ScopedReleaseCurrent release_current(this);
|
| + ReleaseDrawTexture();
|
| + dcomp_surface_.Release();
|
| + HRESULT hr = dcomp_device_->CreateSurface(
|
| + size_.width(), size_.height(), DXGI_FORMAT_B8G8R8A8_UNORM,
|
| + DXGI_ALPHA_MODE_PREMULTIPLIED, dcomp_surface_.Receive());
|
| + has_been_rendered_to_ = false;
|
| +
|
| + CHECK(SUCCEEDED(hr));
|
| +}
|
| +
|
| +void DirectCompositionSurfaceWin::ReleaseDrawTexture() {
|
| + if (real_surface_) {
|
| + eglDestroySurface(GetDisplay(), real_surface_);
|
| + real_surface_ = nullptr;
|
| + }
|
| + if (draw_texture_) {
|
| + draw_texture_.Release();
|
| + HRESULT hr = dcomp_surface_->EndDraw();
|
| + CHECK(SUCCEEDED(hr));
|
| + }
|
| + if (dcomp_surface_ == g_current_surface)
|
| + g_current_surface = nullptr;
|
| +}
|
| +
|
| void DirectCompositionSurfaceWin::Destroy() {
|
| - if (surface_) {
|
| - if (!eglDestroySurface(GetDisplay(), surface_)) {
|
| - LOG(ERROR) << "eglDestroySurface failed with error "
|
| - << ui::GetLastEGLErrorString();
|
| + 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();
|
| }
|
| - surface_ = NULL;
|
| + real_surface_ = nullptr;
|
| }
|
| + if (dcomp_surface_ == g_current_surface)
|
| + g_current_surface = nullptr;
|
| + draw_texture_.Release();
|
| + dcomp_surface_.Release();
|
| }
|
|
|
| gfx::Size DirectCompositionSurfaceWin::GetSize() {
|
| @@ -71,7 +176,7 @@ bool DirectCompositionSurfaceWin::IsOffscreen() {
|
| }
|
|
|
| void* DirectCompositionSurfaceWin::GetHandle() {
|
| - return surface_;
|
| + return real_surface_ ? real_surface_ : default_surface_;
|
| }
|
|
|
| bool DirectCompositionSurfaceWin::Resize(const gfx::Size& size,
|
| @@ -87,11 +192,20 @@ bool DirectCompositionSurfaceWin::Resize(const gfx::Size& size,
|
| return false;
|
| }
|
| size_ = size;
|
| + InitializeSurface();
|
| +
|
| return true;
|
| }
|
|
|
| gfx::SwapResult DirectCompositionSurfaceWin::SwapBuffers() {
|
| - CommitAndClearPendingOverlays();
|
| + {
|
| + ScopedReleaseCurrent release_current(this);
|
| + ReleaseDrawTexture();
|
| + visual_->SetContent(dcomp_surface_.get());
|
| +
|
| + CommitAndClearPendingOverlays();
|
| + dcomp_device_->Commit();
|
| + }
|
| // Force the driver to finish drawing before clearing the contents to
|
| // transparent, to reduce or eliminate the period of time where the contents
|
| // have flashed black.
|
| @@ -107,7 +221,11 @@ gfx::SwapResult DirectCompositionSurfaceWin::PostSubBuffer(int x,
|
| int y,
|
| int width,
|
| int height) {
|
| + ScopedReleaseCurrent release_current(this);
|
| + ReleaseDrawTexture();
|
| + visual_->SetContent(dcomp_surface_.get());
|
| CommitAndClearPendingOverlays();
|
| + dcomp_device_->Commit();
|
| child_window_.ClearInvalidContents();
|
| return gfx::SwapResult::SWAP_ACK;
|
| }
|
| @@ -116,12 +234,6 @@ gfx::VSyncProvider* DirectCompositionSurfaceWin::GetVSyncProvider() {
|
| return vsync_provider_.get();
|
| }
|
|
|
| -bool DirectCompositionSurfaceWin::Initialize(
|
| - std::unique_ptr<gfx::VSyncProvider> vsync_provider) {
|
| - vsync_provider_ = std::move(vsync_provider);
|
| - return Initialize(gl::GLSurfaceFormat());
|
| -}
|
| -
|
| bool DirectCompositionSurfaceWin::ScheduleOverlayPlane(
|
| int z_order,
|
| gfx::OverlayTransform transform,
|
| @@ -133,10 +245,84 @@ bool DirectCompositionSurfaceWin::ScheduleOverlayPlane(
|
| return true;
|
| }
|
|
|
| +bool DirectCompositionSurfaceWin::CommitAndClearPendingOverlays() {
|
| + pending_overlays_.clear();
|
| + return true;
|
| +}
|
| +
|
| +bool DirectCompositionSurfaceWin::FlipsVertically() const {
|
| + return true;
|
| +}
|
| +
|
| bool DirectCompositionSurfaceWin::SupportsPostSubBuffer() {
|
| return true;
|
| }
|
|
|
| +bool DirectCompositionSurfaceWin::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 DirectCompositionSurfaceWin::SupportsSetDrawRectangle() const {
|
| + return true;
|
| +}
|
| +
|
| +bool DirectCompositionSurfaceWin::SetDrawRectangle(const gfx::Rect& rectangle) {
|
| + if (draw_texture_)
|
| + return false;
|
| + 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;
|
| + }
|
| +
|
| + DCHECK(!real_surface_);
|
| + CHECK(!g_current_surface);
|
| + ScopedReleaseCurrent release_current(this);
|
| +
|
| + RECT rect = rectangle.ToRECT();
|
| + // TODO(jbauman): Use update_offset
|
| + POINT update_offset;
|
| +
|
| + HRESULT hr = dcomp_surface_->BeginDraw(
|
| + &rect, IID_PPV_ARGS(draw_texture_.Receive()), &update_offset);
|
| + 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;
|
| +}
|
| +
|
| DirectCompositionSurfaceWin::Overlay::Overlay(int z_order,
|
| gfx::OverlayTransform transform,
|
| scoped_refptr<gl::GLImage> image,
|
| @@ -152,11 +338,4 @@ DirectCompositionSurfaceWin::Overlay::Overlay(const Overlay& overlay) = default;
|
|
|
| DirectCompositionSurfaceWin::Overlay::~Overlay() {}
|
|
|
| -bool DirectCompositionSurfaceWin::CommitAndClearPendingOverlays() {
|
| - pending_overlays_.clear();
|
| - return true;
|
| -}
|
| -
|
| -DirectCompositionSurfaceWin::~DirectCompositionSurfaceWin() {}
|
| -
|
| } // namespace gpu
|
|
|