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