| OLD | NEW | 
|---|
| (Empty) |  | 
|  | 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 | 
|  | 3 // found in the LICENSE file. | 
|  | 4 | 
|  | 5 #include "gpu/ipc/service/direct_composition_child_surface_win.h" | 
|  | 6 | 
|  | 7 #include <d3d11_1.h> | 
|  | 8 #include <dcomptypes.h> | 
|  | 9 | 
|  | 10 #include "base/memory/ptr_util.h" | 
|  | 11 #include "base/metrics/histogram_macros.h" | 
|  | 12 #include "base/synchronization/waitable_event.h" | 
|  | 13 #include "base/trace_event/trace_event.h" | 
|  | 14 #include "ui/display/display_switches.h" | 
|  | 15 #include "ui/gfx/native_widget_types.h" | 
|  | 16 #include "ui/gl/egl_util.h" | 
|  | 17 #include "ui/gl/gl_angle_util_win.h" | 
|  | 18 #include "ui/gl/gl_context.h" | 
|  | 19 #include "ui/gl/gl_surface_egl.h" | 
|  | 20 #include "ui/gl/scoped_make_current.h" | 
|  | 21 | 
|  | 22 #ifndef EGL_ANGLE_flexible_surface_compatibility | 
|  | 23 #define EGL_ANGLE_flexible_surface_compatibility 1 | 
|  | 24 #define EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE 0x33A6 | 
|  | 25 #endif /* EGL_ANGLE_flexible_surface_compatibility */ | 
|  | 26 | 
|  | 27 #ifndef EGL_ANGLE_d3d_texture_client_buffer | 
|  | 28 #define EGL_ANGLE_d3d_texture_client_buffer 1 | 
|  | 29 #define EGL_D3D_TEXTURE_ANGLE 0x33A3 | 
|  | 30 #endif /* EGL_ANGLE_d3d_texture_client_buffer */ | 
|  | 31 | 
|  | 32 namespace gpu { | 
|  | 33 | 
|  | 34 namespace { | 
|  | 35 // Only one DirectComposition surface can be rendered into at a time. Track | 
|  | 36 // here which IDCompositionSurface is being rendered into. If another context | 
|  | 37 // is made current, then this surface will be suspended. | 
|  | 38 IDCompositionSurface* g_current_surface; | 
|  | 39 } | 
|  | 40 | 
|  | 41 DirectCompositionChildSurfaceWin::DirectCompositionChildSurfaceWin( | 
|  | 42     const gfx::Size& size, | 
|  | 43     bool has_alpha, | 
|  | 44     bool enable_dc_layers) | 
|  | 45     : gl::GLSurfaceEGL(), | 
|  | 46       size_(size), | 
|  | 47       has_alpha_(has_alpha), | 
|  | 48       enable_dc_layers_(enable_dc_layers) {} | 
|  | 49 | 
|  | 50 DirectCompositionChildSurfaceWin::~DirectCompositionChildSurfaceWin() { | 
|  | 51   Destroy(); | 
|  | 52 } | 
|  | 53 | 
|  | 54 bool DirectCompositionChildSurfaceWin::Initialize(gl::GLSurfaceFormat format) { | 
|  | 55   d3d11_device_ = gl::QueryD3D11DeviceObjectFromANGLE(); | 
|  | 56   dcomp_device_ = gl::QueryDirectCompositionDevice(d3d11_device_); | 
|  | 57   if (!dcomp_device_) | 
|  | 58     return false; | 
|  | 59 | 
|  | 60   EGLDisplay display = GetDisplay(); | 
|  | 61 | 
|  | 62   std::vector<EGLint> pbuffer_attribs; | 
|  | 63   pbuffer_attribs.push_back(EGL_WIDTH); | 
|  | 64   pbuffer_attribs.push_back(1); | 
|  | 65   pbuffer_attribs.push_back(EGL_HEIGHT); | 
|  | 66   pbuffer_attribs.push_back(1); | 
|  | 67 | 
|  | 68   pbuffer_attribs.push_back(EGL_NONE); | 
|  | 69   default_surface_ = | 
|  | 70       eglCreatePbufferSurface(display, GetConfig(), &pbuffer_attribs[0]); | 
|  | 71   CHECK(!!default_surface_); | 
|  | 72 | 
|  | 73   return true; | 
|  | 74 } | 
|  | 75 | 
|  | 76 void DirectCompositionChildSurfaceWin::ReleaseCurrentSurface() { | 
|  | 77   ReleaseDrawTexture(true); | 
|  | 78   dcomp_surface_.Reset(); | 
|  | 79   swap_chain_.Reset(); | 
|  | 80 } | 
|  | 81 | 
|  | 82 void DirectCompositionChildSurfaceWin::InitializeSurface() { | 
|  | 83   TRACE_EVENT1("gpu", "DirectCompositionChildSurfaceWin::InitializeSurface()", | 
|  | 84                "enable_dc_layers_", enable_dc_layers_); | 
|  | 85   DCHECK(!dcomp_surface_); | 
|  | 86   DCHECK(!swap_chain_); | 
|  | 87   DXGI_FORMAT output_format = | 
|  | 88       base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableHDR) | 
|  | 89           ? DXGI_FORMAT_R16G16B16A16_FLOAT | 
|  | 90           : DXGI_FORMAT_B8G8R8A8_UNORM; | 
|  | 91   if (enable_dc_layers_) { | 
|  | 92     // Always treat as premultiplied, because an underlay could cause it to | 
|  | 93     // become transparent. | 
|  | 94     HRESULT hr = dcomp_device_->CreateSurface( | 
|  | 95         size_.width(), size_.height(), output_format, | 
|  | 96         DXGI_ALPHA_MODE_PREMULTIPLIED, dcomp_surface_.GetAddressOf()); | 
|  | 97     has_been_rendered_to_ = false; | 
|  | 98     CHECK(SUCCEEDED(hr)); | 
|  | 99   } else { | 
|  | 100     DXGI_ALPHA_MODE alpha_mode = | 
|  | 101         has_alpha_ ? DXGI_ALPHA_MODE_PREMULTIPLIED : DXGI_ALPHA_MODE_IGNORE; | 
|  | 102     base::win::ScopedComPtr<IDXGIDevice> dxgi_device; | 
|  | 103     d3d11_device_.CopyTo(dxgi_device.GetAddressOf()); | 
|  | 104     base::win::ScopedComPtr<IDXGIAdapter> dxgi_adapter; | 
|  | 105     dxgi_device->GetAdapter(dxgi_adapter.GetAddressOf()); | 
|  | 106     base::win::ScopedComPtr<IDXGIFactory2> dxgi_factory; | 
|  | 107     dxgi_adapter->GetParent(IID_PPV_ARGS(dxgi_factory.GetAddressOf())); | 
|  | 108 | 
|  | 109     DXGI_SWAP_CHAIN_DESC1 desc = {}; | 
|  | 110     desc.Width = size_.width(); | 
|  | 111     desc.Height = size_.height(); | 
|  | 112     desc.Format = output_format; | 
|  | 113     desc.Stereo = FALSE; | 
|  | 114     desc.SampleDesc.Count = 1; | 
|  | 115     desc.BufferCount = 2; | 
|  | 116     desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; | 
|  | 117     desc.Scaling = DXGI_SCALING_STRETCH; | 
|  | 118     desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; | 
|  | 119     desc.AlphaMode = alpha_mode; | 
|  | 120     desc.Flags = 0; | 
|  | 121     HRESULT hr = dxgi_factory->CreateSwapChainForComposition( | 
|  | 122         d3d11_device_.Get(), &desc, nullptr, swap_chain_.GetAddressOf()); | 
|  | 123     has_been_rendered_to_ = false; | 
|  | 124     first_swap_ = true; | 
|  | 125     CHECK(SUCCEEDED(hr)); | 
|  | 126   } | 
|  | 127 } | 
|  | 128 | 
|  | 129 void DirectCompositionChildSurfaceWin::ReleaseDrawTexture(bool will_discard) { | 
|  | 130   if (real_surface_) { | 
|  | 131     eglDestroySurface(GetDisplay(), real_surface_); | 
|  | 132     real_surface_ = nullptr; | 
|  | 133   } | 
|  | 134   if (draw_texture_) { | 
|  | 135     draw_texture_.Reset(); | 
|  | 136     if (dcomp_surface_) { | 
|  | 137       HRESULT hr = dcomp_surface_->EndDraw(); | 
|  | 138       CHECK(SUCCEEDED(hr)); | 
|  | 139     } else if (!will_discard) { | 
|  | 140       DXGI_PRESENT_PARAMETERS params = {}; | 
|  | 141       RECT dirty_rect = swap_rect_.ToRECT(); | 
|  | 142       params.DirtyRectsCount = 1; | 
|  | 143       params.pDirtyRects = &dirty_rect; | 
|  | 144       swap_chain_->Present1(first_swap_ ? 0 : 1, 0, ¶ms); | 
|  | 145       if (first_swap_) { | 
|  | 146         // Wait for the GPU to finish executing its commands before | 
|  | 147         // committing the DirectComposition tree, or else the swapchain | 
|  | 148         // may flicker black when it's first presented. | 
|  | 149         base::win::ScopedComPtr<IDXGIDevice2> dxgi_device2; | 
|  | 150         HRESULT hr = d3d11_device_.CopyTo(dxgi_device2.GetAddressOf()); | 
|  | 151         DCHECK(SUCCEEDED(hr)); | 
|  | 152         base::WaitableEvent event( | 
|  | 153             base::WaitableEvent::ResetPolicy::AUTOMATIC, | 
|  | 154             base::WaitableEvent::InitialState::NOT_SIGNALED); | 
|  | 155         dxgi_device2->EnqueueSetEvent(event.handle()); | 
|  | 156         event.Wait(); | 
|  | 157         first_swap_ = false; | 
|  | 158       } | 
|  | 159     } | 
|  | 160   } | 
|  | 161   if (dcomp_surface_ == g_current_surface) | 
|  | 162     g_current_surface = nullptr; | 
|  | 163 } | 
|  | 164 | 
|  | 165 void DirectCompositionChildSurfaceWin::Destroy() { | 
|  | 166   if (default_surface_) { | 
|  | 167     if (!eglDestroySurface(GetDisplay(), default_surface_)) { | 
|  | 168       DLOG(ERROR) << "eglDestroySurface failed with error " | 
|  | 169                   << ui::GetLastEGLErrorString(); | 
|  | 170     } | 
|  | 171     default_surface_ = nullptr; | 
|  | 172   } | 
|  | 173   if (real_surface_) { | 
|  | 174     if (!eglDestroySurface(GetDisplay(), real_surface_)) { | 
|  | 175       DLOG(ERROR) << "eglDestroySurface failed with error " | 
|  | 176                   << ui::GetLastEGLErrorString(); | 
|  | 177     } | 
|  | 178     real_surface_ = nullptr; | 
|  | 179   } | 
|  | 180   if (dcomp_surface_ && (dcomp_surface_ == g_current_surface)) { | 
|  | 181     HRESULT hr = dcomp_surface_->EndDraw(); | 
|  | 182     CHECK(SUCCEEDED(hr)); | 
|  | 183     g_current_surface = nullptr; | 
|  | 184   } | 
|  | 185   draw_texture_.Reset(); | 
|  | 186   dcomp_surface_.Reset(); | 
|  | 187 } | 
|  | 188 | 
|  | 189 gfx::Size DirectCompositionChildSurfaceWin::GetSize() { | 
|  | 190   return size_; | 
|  | 191 } | 
|  | 192 | 
|  | 193 bool DirectCompositionChildSurfaceWin::IsOffscreen() { | 
|  | 194   return false; | 
|  | 195 } | 
|  | 196 | 
|  | 197 void* DirectCompositionChildSurfaceWin::GetHandle() { | 
|  | 198   return real_surface_ ? real_surface_ : default_surface_; | 
|  | 199 } | 
|  | 200 | 
|  | 201 gfx::SwapResult DirectCompositionChildSurfaceWin::SwapBuffers() { | 
|  | 202   ReleaseDrawTexture(false); | 
|  | 203   return gfx::SwapResult::SWAP_ACK; | 
|  | 204 } | 
|  | 205 | 
|  | 206 bool DirectCompositionChildSurfaceWin::FlipsVertically() const { | 
|  | 207   return true; | 
|  | 208 } | 
|  | 209 | 
|  | 210 bool DirectCompositionChildSurfaceWin::SupportsPostSubBuffer() { | 
|  | 211   return true; | 
|  | 212 } | 
|  | 213 | 
|  | 214 bool DirectCompositionChildSurfaceWin::OnMakeCurrent(gl::GLContext* context) { | 
|  | 215   if (g_current_surface != dcomp_surface_) { | 
|  | 216     if (g_current_surface) { | 
|  | 217       HRESULT hr = g_current_surface->SuspendDraw(); | 
|  | 218       CHECK(SUCCEEDED(hr)); | 
|  | 219       g_current_surface = nullptr; | 
|  | 220     } | 
|  | 221     if (draw_texture_) { | 
|  | 222       HRESULT hr = dcomp_surface_->ResumeDraw(); | 
|  | 223       CHECK(SUCCEEDED(hr)); | 
|  | 224       g_current_surface = dcomp_surface_.Get(); | 
|  | 225     } | 
|  | 226   } | 
|  | 227   return true; | 
|  | 228 } | 
|  | 229 | 
|  | 230 bool DirectCompositionChildSurfaceWin::SupportsDCLayers() const { | 
|  | 231   return true; | 
|  | 232 } | 
|  | 233 | 
|  | 234 bool DirectCompositionChildSurfaceWin::SetDrawRectangle( | 
|  | 235     const gfx::Rect& rectangle) { | 
|  | 236   if (draw_texture_) | 
|  | 237     return false; | 
|  | 238   DCHECK(!real_surface_); | 
|  | 239   ui::ScopedReleaseCurrent release_current(this); | 
|  | 240 | 
|  | 241   if ((enable_dc_layers_ && !dcomp_surface_) || | 
|  | 242       (!enable_dc_layers_ && !swap_chain_)) { | 
|  | 243     ReleaseCurrentSurface(); | 
|  | 244     InitializeSurface(); | 
|  | 245   } | 
|  | 246 | 
|  | 247   if (!gfx::Rect(size_).Contains(rectangle)) { | 
|  | 248     DLOG(ERROR) << "Draw rectangle must be contained within size of surface"; | 
|  | 249     return false; | 
|  | 250   } | 
|  | 251   if (gfx::Rect(size_) != rectangle && !has_been_rendered_to_) { | 
|  | 252     DLOG(ERROR) << "First draw to surface must draw to everything"; | 
|  | 253     return false; | 
|  | 254   } | 
|  | 255 | 
|  | 256   CHECK(!g_current_surface); | 
|  | 257 | 
|  | 258   RECT rect = rectangle.ToRECT(); | 
|  | 259   if (dcomp_surface_) { | 
|  | 260     POINT update_offset; | 
|  | 261     HRESULT hr = dcomp_surface_->BeginDraw( | 
|  | 262         &rect, IID_PPV_ARGS(draw_texture_.GetAddressOf()), &update_offset); | 
|  | 263     draw_offset_ = gfx::Point(update_offset) - gfx::Rect(rect).origin(); | 
|  | 264     CHECK(SUCCEEDED(hr)); | 
|  | 265   } else { | 
|  | 266     HRESULT hr = | 
|  | 267         swap_chain_->GetBuffer(0, IID_PPV_ARGS(draw_texture_.GetAddressOf())); | 
|  | 268     swap_rect_ = rectangle; | 
|  | 269     draw_offset_ = gfx::Vector2d(); | 
|  | 270     CHECK(SUCCEEDED(hr)); | 
|  | 271   } | 
|  | 272   has_been_rendered_to_ = true; | 
|  | 273 | 
|  | 274   g_current_surface = dcomp_surface_.Get(); | 
|  | 275 | 
|  | 276   std::vector<EGLint> pbuffer_attribs{ | 
|  | 277       EGL_WIDTH, | 
|  | 278       size_.width(), | 
|  | 279       EGL_HEIGHT, | 
|  | 280       size_.height(), | 
|  | 281       EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE, | 
|  | 282       EGL_TRUE, | 
|  | 283       EGL_NONE}; | 
|  | 284 | 
|  | 285   EGLClientBuffer buffer = | 
|  | 286       reinterpret_cast<EGLClientBuffer>(draw_texture_.Get()); | 
|  | 287   real_surface_ = eglCreatePbufferFromClientBuffer( | 
|  | 288       GetDisplay(), EGL_D3D_TEXTURE_ANGLE, buffer, GetConfig(), | 
|  | 289       &pbuffer_attribs[0]); | 
|  | 290 | 
|  | 291   return true; | 
|  | 292 } | 
|  | 293 | 
|  | 294 gfx::Vector2d DirectCompositionChildSurfaceWin::GetDrawOffset() const { | 
|  | 295   return draw_offset_; | 
|  | 296 } | 
|  | 297 | 
|  | 298 }  // namespace gpu | 
| OLD | NEW | 
|---|