| 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 |