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