OLD | NEW |
1 // Copyright 2017 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "gpu/ipc/service/direct_composition_surface_win.h" | 5 #include "gpu/ipc/service/direct_composition_surface_win.h" |
6 | 6 |
7 #include "base/optional.h" | 7 #include "base/optional.h" |
| 8 #include "base/synchronization/waitable_event.h" |
8 #include "gpu/ipc/service/gpu_channel_manager.h" | 9 #include "gpu/ipc/service/gpu_channel_manager.h" |
9 #include "gpu/ipc/service/gpu_channel_manager_delegate.h" | 10 #include "gpu/ipc/service/gpu_channel_manager_delegate.h" |
10 #include "ui/gfx/native_widget_types.h" | 11 #include "ui/gfx/native_widget_types.h" |
11 #include "ui/gl/egl_util.h" | 12 #include "ui/gl/egl_util.h" |
12 #include "ui/gl/gl_angle_util_win.h" | 13 #include "ui/gl/gl_angle_util_win.h" |
13 #include "ui/gl/gl_context.h" | 14 #include "ui/gl/gl_context.h" |
14 #include "ui/gl/gl_surface_egl.h" | 15 #include "ui/gl/gl_surface_egl.h" |
15 #include "ui/gl/scoped_make_current.h" | 16 #include "ui/gl/scoped_make_current.h" |
16 | 17 |
17 #ifndef EGL_ANGLE_flexible_surface_compatibility | 18 #ifndef EGL_ANGLE_flexible_surface_compatibility |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
108 pbuffer_attribs.push_back(EGL_WIDTH); | 109 pbuffer_attribs.push_back(EGL_WIDTH); |
109 pbuffer_attribs.push_back(1); | 110 pbuffer_attribs.push_back(1); |
110 pbuffer_attribs.push_back(EGL_HEIGHT); | 111 pbuffer_attribs.push_back(EGL_HEIGHT); |
111 pbuffer_attribs.push_back(1); | 112 pbuffer_attribs.push_back(1); |
112 | 113 |
113 pbuffer_attribs.push_back(EGL_NONE); | 114 pbuffer_attribs.push_back(EGL_NONE); |
114 default_surface_ = | 115 default_surface_ = |
115 eglCreatePbufferSurface(display, GetConfig(), &pbuffer_attribs[0]); | 116 eglCreatePbufferSurface(display, GetConfig(), &pbuffer_attribs[0]); |
116 CHECK(!!default_surface_); | 117 CHECK(!!default_surface_); |
117 | 118 |
118 InitializeSurface(); | |
119 | |
120 return true; | 119 return true; |
121 } | 120 } |
122 | 121 |
123 void DirectCompositionSurfaceWin::InitializeSurface() { | 122 void DirectCompositionSurfaceWin::ReleaseCurrentSurface() { |
124 ScopedReleaseCurrent release_current(this); | 123 ReleaseDrawTexture(true); |
125 ReleaseDrawTexture(); | |
126 dcomp_surface_.Release(); | 124 dcomp_surface_.Release(); |
127 HRESULT hr = dcomp_device_->CreateSurface( | 125 swap_chain_.Release(); |
128 size_.width(), size_.height(), DXGI_FORMAT_B8G8R8A8_UNORM, | |
129 DXGI_ALPHA_MODE_PREMULTIPLIED, dcomp_surface_.Receive()); | |
130 has_been_rendered_to_ = false; | |
131 | |
132 CHECK(SUCCEEDED(hr)); | |
133 } | 126 } |
134 | 127 |
135 void DirectCompositionSurfaceWin::ReleaseDrawTexture() { | 128 void DirectCompositionSurfaceWin::InitializeSurface() { |
| 129 DCHECK(!dcomp_surface_); |
| 130 DCHECK(!swap_chain_); |
| 131 if (enable_dc_layers_) { |
| 132 HRESULT hr = dcomp_device_->CreateSurface( |
| 133 size_.width(), size_.height(), DXGI_FORMAT_B8G8R8A8_UNORM, |
| 134 DXGI_ALPHA_MODE_PREMULTIPLIED, dcomp_surface_.Receive()); |
| 135 has_been_rendered_to_ = false; |
| 136 CHECK(SUCCEEDED(hr)); |
| 137 } else { |
| 138 base::win::ScopedComPtr<IDXGIDevice> dxgi_device; |
| 139 d3d11_device_.QueryInterface(dxgi_device.Receive()); |
| 140 base::win::ScopedComPtr<IDXGIAdapter> dxgi_adapter; |
| 141 dxgi_device->GetAdapter(dxgi_adapter.Receive()); |
| 142 base::win::ScopedComPtr<IDXGIFactory2> dxgi_factory; |
| 143 dxgi_adapter->GetParent(IID_PPV_ARGS(dxgi_factory.Receive())); |
| 144 |
| 145 DXGI_SWAP_CHAIN_DESC1 desc = {}; |
| 146 desc.Width = size_.width(); |
| 147 desc.Height = size_.height(); |
| 148 desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; |
| 149 desc.Stereo = FALSE; |
| 150 desc.SampleDesc.Count = 1; |
| 151 desc.BufferCount = 2; |
| 152 desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; |
| 153 desc.Scaling = DXGI_SCALING_STRETCH; |
| 154 desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; |
| 155 desc.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED; |
| 156 desc.Flags = 0; |
| 157 HRESULT hr = dxgi_factory->CreateSwapChainForComposition( |
| 158 d3d11_device_.get(), &desc, nullptr, swap_chain_.Receive()); |
| 159 has_been_rendered_to_ = false; |
| 160 first_swap_ = true; |
| 161 CHECK(SUCCEEDED(hr)); |
| 162 } |
| 163 } |
| 164 |
| 165 void DirectCompositionSurfaceWin::ReleaseDrawTexture(bool will_discard) { |
136 if (real_surface_) { | 166 if (real_surface_) { |
137 eglDestroySurface(GetDisplay(), real_surface_); | 167 eglDestroySurface(GetDisplay(), real_surface_); |
138 real_surface_ = nullptr; | 168 real_surface_ = nullptr; |
139 } | 169 } |
140 if (draw_texture_) { | 170 if (draw_texture_) { |
141 draw_texture_.Release(); | 171 draw_texture_.Release(); |
142 HRESULT hr = dcomp_surface_->EndDraw(); | 172 if (dcomp_surface_) { |
143 CHECK(SUCCEEDED(hr)); | 173 HRESULT hr = dcomp_surface_->EndDraw(); |
| 174 CHECK(SUCCEEDED(hr)); |
| 175 } else if (!will_discard) { |
| 176 DXGI_PRESENT_PARAMETERS params = {}; |
| 177 RECT dirty_rect = swap_rect_.ToRECT(); |
| 178 params.DirtyRectsCount = 1; |
| 179 params.pDirtyRects = &dirty_rect; |
| 180 swap_chain_->Present1(first_swap_ ? 0 : 1, 0, ¶ms); |
| 181 if (first_swap_) { |
| 182 // Wait for the GPU to finish executing its commands before |
| 183 // committing the DirectComposition tree, or else the swapchain |
| 184 // may flicker black when it's first presented. |
| 185 base::win::ScopedComPtr<IDXGIDevice2> dxgi_device2; |
| 186 HRESULT hr = d3d11_device_.QueryInterface(dxgi_device2.Receive()); |
| 187 DCHECK(SUCCEEDED(hr)); |
| 188 base::WaitableEvent event( |
| 189 base::WaitableEvent::ResetPolicy::AUTOMATIC, |
| 190 base::WaitableEvent::InitialState::NOT_SIGNALED); |
| 191 dxgi_device2->EnqueueSetEvent(event.handle()); |
| 192 event.Wait(); |
| 193 first_swap_ = false; |
| 194 } |
| 195 } |
144 } | 196 } |
145 if (dcomp_surface_ == g_current_surface) | 197 if (dcomp_surface_ == g_current_surface) |
146 g_current_surface = nullptr; | 198 g_current_surface = nullptr; |
147 } | 199 } |
148 | 200 |
149 void DirectCompositionSurfaceWin::Destroy() { | 201 void DirectCompositionSurfaceWin::Destroy() { |
150 if (default_surface_) { | 202 if (default_surface_) { |
151 if (!eglDestroySurface(GetDisplay(), default_surface_)) { | 203 if (!eglDestroySurface(GetDisplay(), default_surface_)) { |
152 DLOG(ERROR) << "eglDestroySurface failed with error " | 204 DLOG(ERROR) << "eglDestroySurface failed with error " |
153 << ui::GetLastEGLErrorString(); | 205 << ui::GetLastEGLErrorString(); |
154 } | 206 } |
155 default_surface_ = nullptr; | 207 default_surface_ = nullptr; |
156 } | 208 } |
157 if (real_surface_) { | 209 if (real_surface_) { |
158 if (!eglDestroySurface(GetDisplay(), real_surface_)) { | 210 if (!eglDestroySurface(GetDisplay(), real_surface_)) { |
159 DLOG(ERROR) << "eglDestroySurface failed with error " | 211 DLOG(ERROR) << "eglDestroySurface failed with error " |
160 << ui::GetLastEGLErrorString(); | 212 << ui::GetLastEGLErrorString(); |
161 } | 213 } |
162 real_surface_ = nullptr; | 214 real_surface_ = nullptr; |
163 } | 215 } |
164 if (dcomp_surface_ == g_current_surface) | 216 if (dcomp_surface_ && (dcomp_surface_ == g_current_surface)) { |
| 217 HRESULT hr = dcomp_surface_->EndDraw(); |
| 218 CHECK(SUCCEEDED(hr)); |
165 g_current_surface = nullptr; | 219 g_current_surface = nullptr; |
| 220 } |
166 draw_texture_.Release(); | 221 draw_texture_.Release(); |
167 dcomp_surface_.Release(); | 222 dcomp_surface_.Release(); |
168 } | 223 } |
169 | 224 |
170 gfx::Size DirectCompositionSurfaceWin::GetSize() { | 225 gfx::Size DirectCompositionSurfaceWin::GetSize() { |
171 return size_; | 226 return size_; |
172 } | 227 } |
173 | 228 |
174 bool DirectCompositionSurfaceWin::IsOffscreen() { | 229 bool DirectCompositionSurfaceWin::IsOffscreen() { |
175 return false; | 230 return false; |
176 } | 231 } |
177 | 232 |
178 void* DirectCompositionSurfaceWin::GetHandle() { | 233 void* DirectCompositionSurfaceWin::GetHandle() { |
179 return real_surface_ ? real_surface_ : default_surface_; | 234 return real_surface_ ? real_surface_ : default_surface_; |
180 } | 235 } |
181 | 236 |
182 bool DirectCompositionSurfaceWin::Resize(const gfx::Size& size, | 237 bool DirectCompositionSurfaceWin::Resize(const gfx::Size& size, |
183 float scale_factor, | 238 float scale_factor, |
184 bool has_alpha) { | 239 bool has_alpha) { |
185 if (size == GetSize()) | 240 if (size == GetSize()) |
186 return true; | 241 return true; |
187 | 242 |
188 // Force a resize and redraw (but not a move, activate, etc.). | 243 // Force a resize and redraw (but not a move, activate, etc.). |
189 if (!SetWindowPos(window_, nullptr, 0, 0, size.width(), size.height(), | 244 if (!SetWindowPos(window_, nullptr, 0, 0, size.width(), size.height(), |
190 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOCOPYBITS | | 245 SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOCOPYBITS | |
191 SWP_NOOWNERZORDER | SWP_NOZORDER)) { | 246 SWP_NOOWNERZORDER | SWP_NOZORDER)) { |
192 return false; | 247 return false; |
193 } | 248 } |
194 size_ = size; | 249 size_ = size; |
195 InitializeSurface(); | 250 ScopedReleaseCurrent release_current(this); |
| 251 // New surface will be initialized in SetDrawRectangle. |
| 252 ReleaseCurrentSurface(); |
196 | 253 |
197 return true; | 254 return true; |
198 } | 255 } |
199 | 256 |
200 gfx::SwapResult DirectCompositionSurfaceWin::SwapBuffers() { | 257 gfx::SwapResult DirectCompositionSurfaceWin::SwapBuffers() { |
201 { | 258 { |
202 ScopedReleaseCurrent release_current(this); | 259 ScopedReleaseCurrent release_current(this); |
203 ReleaseDrawTexture(); | 260 ReleaseDrawTexture(false); |
204 visual_->SetContent(dcomp_surface_.get()); | 261 DCHECK(dcomp_surface_ || swap_chain_); |
| 262 if (dcomp_surface_) |
| 263 visual_->SetContent(dcomp_surface_.get()); |
| 264 else |
| 265 visual_->SetContent(swap_chain_.get()); |
205 | 266 |
206 CommitAndClearPendingOverlays(); | 267 CommitAndClearPendingOverlays(); |
207 dcomp_device_->Commit(); | 268 dcomp_device_->Commit(); |
208 } | 269 } |
209 // Force the driver to finish drawing before clearing the contents to | |
210 // transparent, to reduce or eliminate the period of time where the contents | |
211 // have flashed black. | |
212 if (first_swap_) { | |
213 glFinish(); | |
214 first_swap_ = false; | |
215 } | |
216 child_window_.ClearInvalidContents(); | 270 child_window_.ClearInvalidContents(); |
217 return gfx::SwapResult::SWAP_ACK; | 271 return gfx::SwapResult::SWAP_ACK; |
218 } | 272 } |
219 | 273 |
220 gfx::SwapResult DirectCompositionSurfaceWin::PostSubBuffer(int x, | 274 gfx::SwapResult DirectCompositionSurfaceWin::PostSubBuffer(int x, |
221 int y, | 275 int y, |
222 int width, | 276 int width, |
223 int height) { | 277 int height) { |
224 ScopedReleaseCurrent release_current(this); | 278 // The arguments are ignored because SetDrawRectangle specified the area to |
225 ReleaseDrawTexture(); | 279 // be swapped. |
226 visual_->SetContent(dcomp_surface_.get()); | 280 return SwapBuffers(); |
227 CommitAndClearPendingOverlays(); | |
228 dcomp_device_->Commit(); | |
229 child_window_.ClearInvalidContents(); | |
230 return gfx::SwapResult::SWAP_ACK; | |
231 } | 281 } |
232 | 282 |
233 gfx::VSyncProvider* DirectCompositionSurfaceWin::GetVSyncProvider() { | 283 gfx::VSyncProvider* DirectCompositionSurfaceWin::GetVSyncProvider() { |
234 return vsync_provider_.get(); | 284 return vsync_provider_.get(); |
235 } | 285 } |
236 | 286 |
237 bool DirectCompositionSurfaceWin::ScheduleOverlayPlane( | 287 bool DirectCompositionSurfaceWin::ScheduleOverlayPlane( |
238 int z_order, | 288 int z_order, |
239 gfx::OverlayTransform transform, | 289 gfx::OverlayTransform transform, |
240 gl::GLImage* image, | 290 gl::GLImage* image, |
241 const gfx::Rect& bounds_rect, | 291 const gfx::Rect& bounds_rect, |
242 const gfx::RectF& crop_rect) { | 292 const gfx::RectF& crop_rect) { |
243 pending_overlays_.push_back( | 293 pending_overlays_.push_back( |
244 Overlay(z_order, transform, image, bounds_rect, crop_rect)); | 294 Overlay(z_order, transform, image, bounds_rect, crop_rect)); |
245 return true; | 295 return true; |
246 } | 296 } |
247 | 297 |
| 298 bool DirectCompositionSurfaceWin::SetEnableDCLayers(bool enable) { |
| 299 enable_dc_layers_ = enable; |
| 300 return true; |
| 301 } |
| 302 |
248 bool DirectCompositionSurfaceWin::CommitAndClearPendingOverlays() { | 303 bool DirectCompositionSurfaceWin::CommitAndClearPendingOverlays() { |
249 pending_overlays_.clear(); | 304 pending_overlays_.clear(); |
250 return true; | 305 return true; |
251 } | 306 } |
252 | 307 |
253 bool DirectCompositionSurfaceWin::FlipsVertically() const { | 308 bool DirectCompositionSurfaceWin::FlipsVertically() const { |
254 return true; | 309 return true; |
255 } | 310 } |
256 | 311 |
257 bool DirectCompositionSurfaceWin::SupportsPostSubBuffer() { | 312 bool DirectCompositionSurfaceWin::SupportsPostSubBuffer() { |
258 return true; | 313 return true; |
259 } | 314 } |
260 | 315 |
261 bool DirectCompositionSurfaceWin::OnMakeCurrent(gl::GLContext* context) { | 316 bool DirectCompositionSurfaceWin::OnMakeCurrent(gl::GLContext* context) { |
262 if (g_current_surface != dcomp_surface_) { | 317 if (g_current_surface != dcomp_surface_) { |
263 if (g_current_surface) { | 318 if (g_current_surface) { |
264 HRESULT hr = g_current_surface->SuspendDraw(); | 319 HRESULT hr = g_current_surface->SuspendDraw(); |
265 CHECK(SUCCEEDED(hr)); | 320 CHECK(SUCCEEDED(hr)); |
266 g_current_surface = nullptr; | 321 g_current_surface = nullptr; |
267 } | 322 } |
268 if (draw_texture_) { | 323 if (draw_texture_) { |
269 HRESULT hr = dcomp_surface_->ResumeDraw(); | 324 HRESULT hr = dcomp_surface_->ResumeDraw(); |
270 CHECK(SUCCEEDED(hr)); | 325 CHECK(SUCCEEDED(hr)); |
271 g_current_surface = dcomp_surface_.get(); | 326 g_current_surface = dcomp_surface_.get(); |
272 } | 327 } |
273 } | 328 } |
274 return true; | 329 return true; |
275 } | 330 } |
276 | 331 |
277 bool DirectCompositionSurfaceWin::SupportsSetDrawRectangle() const { | 332 bool DirectCompositionSurfaceWin::SupportsDCLayers() const { |
278 return true; | 333 return true; |
279 } | 334 } |
280 | 335 |
281 bool DirectCompositionSurfaceWin::SetDrawRectangle(const gfx::Rect& rectangle) { | 336 bool DirectCompositionSurfaceWin::SetDrawRectangle(const gfx::Rect& rectangle) { |
282 if (draw_texture_) | 337 if (draw_texture_) |
283 return false; | 338 return false; |
| 339 |
| 340 DCHECK(!real_surface_); |
| 341 ScopedReleaseCurrent release_current(this); |
| 342 |
| 343 if ((enable_dc_layers_ && !dcomp_surface_) || |
| 344 (!enable_dc_layers_ && !swap_chain_)) { |
| 345 ReleaseCurrentSurface(); |
| 346 InitializeSurface(); |
| 347 } |
| 348 |
284 if (!gfx::Rect(size_).Contains(rectangle)) { | 349 if (!gfx::Rect(size_).Contains(rectangle)) { |
285 DLOG(ERROR) << "Draw rectangle must be contained within size of surface"; | 350 DLOG(ERROR) << "Draw rectangle must be contained within size of surface"; |
286 return false; | 351 return false; |
287 } | 352 } |
288 if (gfx::Rect(size_) != rectangle && !has_been_rendered_to_) { | 353 if (gfx::Rect(size_) != rectangle && !has_been_rendered_to_) { |
289 DLOG(ERROR) << "First draw to surface must draw to everything"; | 354 DLOG(ERROR) << "First draw to surface must draw to everything"; |
290 return false; | 355 return false; |
291 } | 356 } |
292 | 357 |
293 DCHECK(!real_surface_); | |
294 CHECK(!g_current_surface); | 358 CHECK(!g_current_surface); |
295 ScopedReleaseCurrent release_current(this); | |
296 | 359 |
297 RECT rect = rectangle.ToRECT(); | 360 RECT rect = rectangle.ToRECT(); |
298 POINT update_offset; | 361 if (dcomp_surface_) { |
299 | 362 POINT update_offset; |
300 HRESULT hr = dcomp_surface_->BeginDraw( | 363 HRESULT hr = dcomp_surface_->BeginDraw( |
301 &rect, IID_PPV_ARGS(draw_texture_.Receive()), &update_offset); | 364 &rect, IID_PPV_ARGS(draw_texture_.Receive()), &update_offset); |
302 CHECK(SUCCEEDED(hr)); | 365 draw_offset_ = gfx::Point(update_offset) - gfx::Rect(rect).origin(); |
| 366 CHECK(SUCCEEDED(hr)); |
| 367 } else { |
| 368 HRESULT hr = |
| 369 swap_chain_->GetBuffer(0, IID_PPV_ARGS(draw_texture_.Receive())); |
| 370 swap_rect_ = rectangle; |
| 371 draw_offset_ = gfx::Vector2d(); |
| 372 CHECK(SUCCEEDED(hr)); |
| 373 } |
303 has_been_rendered_to_ = true; | 374 has_been_rendered_to_ = true; |
304 | 375 |
305 draw_offset_ = gfx::Point(update_offset) - gfx::Rect(rect).origin(); | |
306 | |
307 g_current_surface = dcomp_surface_.get(); | 376 g_current_surface = dcomp_surface_.get(); |
308 | 377 |
309 std::vector<EGLint> pbuffer_attribs{ | 378 std::vector<EGLint> pbuffer_attribs{ |
310 EGL_WIDTH, | 379 EGL_WIDTH, |
311 size_.width(), | 380 size_.width(), |
312 EGL_HEIGHT, | 381 EGL_HEIGHT, |
313 size_.height(), | 382 size_.height(), |
314 EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE, | 383 EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE, |
315 EGL_TRUE, | 384 EGL_TRUE, |
316 EGL_NONE}; | 385 EGL_NONE}; |
(...skipping 25 matching lines...) Expand all Loading... |
342 transform(transform), | 411 transform(transform), |
343 image(image), | 412 image(image), |
344 bounds_rect(bounds_rect), | 413 bounds_rect(bounds_rect), |
345 crop_rect(crop_rect) {} | 414 crop_rect(crop_rect) {} |
346 | 415 |
347 DirectCompositionSurfaceWin::Overlay::Overlay(const Overlay& overlay) = default; | 416 DirectCompositionSurfaceWin::Overlay::Overlay(const Overlay& overlay) = default; |
348 | 417 |
349 DirectCompositionSurfaceWin::Overlay::~Overlay() {} | 418 DirectCompositionSurfaceWin::Overlay::~Overlay() {} |
350 | 419 |
351 } // namespace gpu | 420 } // namespace gpu |
OLD | NEW |