Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(499)

Side by Side Diff: ui/surface/accelerated_surface_win.cc

Issue 12090109: Tab Capture: Backing store readbacks to YV12 VideoFrames. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Patch for review. Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "ui/surface/accelerated_surface_win.h" 5 #include "ui/surface/accelerated_surface_win.h"
6 6
7 #include <windows.h> 7 #include <windows.h>
8 #include <algorithm> 8 #include <algorithm>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/bind_helpers.h" 11 #include "base/bind_helpers.h"
12 #include "base/callback.h" 12 #include "base/callback.h"
13 #include "base/command_line.h" 13 #include "base/command_line.h"
14 #include "base/debug/trace_event.h" 14 #include "base/debug/trace_event.h"
15 #include "base/file_path.h" 15 #include "base/file_path.h"
16 #include "base/lazy_instance.h" 16 #include "base/lazy_instance.h"
17 #include "base/memory/scoped_ptr.h" 17 #include "base/memory/scoped_ptr.h"
18 #include "base/message_loop_proxy.h" 18 #include "base/message_loop_proxy.h"
19 #include "base/scoped_native_library.h" 19 #include "base/scoped_native_library.h"
20 #include "base/stringprintf.h" 20 #include "base/stringprintf.h"
21 #include "base/synchronization/waitable_event.h" 21 #include "base/synchronization/waitable_event.h"
22 #include "base/threading/thread.h" 22 #include "base/threading/thread.h"
23 #include "base/threading/thread_restrictions.h" 23 #include "base/threading/thread_restrictions.h"
24 #include "base/time.h"
25 #include "base/win/wrapped_window_proc.h" 24 #include "base/win/wrapped_window_proc.h"
25 #include "media/base/video_frame.h"
26 #include "media/base/video_util.h"
26 #include "third_party/skia/include/core/SkBitmap.h" 27 #include "third_party/skia/include/core/SkBitmap.h"
27 #include "ui/base/win/dpi.h" 28 #include "ui/base/win/dpi.h"
28 #include "ui/base/win/hwnd_util.h" 29 #include "ui/base/win/hwnd_util.h"
29 #include "ui/base/win/shell.h" 30 #include "ui/base/win/shell.h"
30 #include "ui/gfx/rect.h" 31 #include "ui/gfx/rect.h"
31 #include "ui/gl/gl_switches.h" 32 #include "ui/gl/gl_switches.h"
32 #include "ui/surface/accelerated_surface_transformer_win.h" 33 #include "ui/surface/accelerated_surface_transformer_win.h"
33 #include "ui/surface/d3d9_utils_win.h" 34 #include "ui/surface/d3d9_utils_win.h"
34 #include "ui/surface/surface_switches.h" 35 #include "ui/surface/surface_switches.h"
35 36
(...skipping 11 matching lines...) Expand all
47 bool DoFirstShowPresentWithGDI() { 48 bool DoFirstShowPresentWithGDI() {
48 return CommandLine::ForCurrentProcess()->HasSwitch( 49 return CommandLine::ForCurrentProcess()->HasSwitch(
49 switches::kDoFirstShowPresentWithGDI); 50 switches::kDoFirstShowPresentWithGDI);
50 } 51 }
51 52
52 bool DoAllShowPresentWithGDI() { 53 bool DoAllShowPresentWithGDI() {
53 return CommandLine::ForCurrentProcess()->HasSwitch( 54 return CommandLine::ForCurrentProcess()->HasSwitch(
54 switches::kDoAllShowPresentWithGDI); 55 switches::kDoAllShowPresentWithGDI);
55 } 56 }
56 57
58 // Lock a D3D surface, and invoke a copier function on the result.
59 bool LockAndCopyPlane(IDirect3DSurface9* src_surface,
60 media::VideoFrame* dst_frame,
61 void (*copier)(const uint8* source,
apatrick_chromium 2013/02/04 19:16:43 Any reason not to use a base::Callback here?
ncarter (slow) 2013/02/04 19:38:04 Not really; I just thought this was more straightf
apatrick_chromium 2013/02/04 19:58:58 Fair enough. I would have done it for consistency
ncarter (slow) 2013/02/07 00:00:12 This has been addressed.
62 int stride,
63 int rows,
64 media::VideoFrame* frame)) {
65 gfx::Size src_size = d3d_utils::GetSize(src_surface);
66
67 D3DLOCKED_RECT locked_rect;
68 {
69 TRACE_EVENT0("gpu", "LockRect");
70 HRESULT hr = src_surface->LockRect(&locked_rect, NULL,
71 D3DLOCK_READONLY | D3DLOCK_NOSYSLOCK);
72 if (FAILED(hr))
73 return false;
74 }
75
76 {
77 TRACE_EVENT0("gpu", "memcpy");
78 uint8* src = reinterpret_cast<uint8*>(locked_rect.pBits);
79 int src_stride = locked_rect.Pitch;
80 copier(src, src_stride, src_size.height(), dst_frame);
81 }
82 src_surface->UnlockRect();
83 return true;
84 }
85
86 // Return the largest centered rectangle with the same aspect ratio of |content|
87 // that fits entirely inside of |bounds|.
88 gfx::Rect ComputeLetterboxRegion(
89 const gfx::Rect& bounds,
90 const gfx::Size& content) {
91 int64 x = static_cast<int64>(content.width()) * bounds.height();
92 int64 y = static_cast<int64>(bounds.width()) * content.height();
93
94 gfx::Size letterbox(bounds.width(), bounds.height());
95 if (y < x)
96 letterbox.set_height(static_cast<int>(y / content.width()));
97 else
98 letterbox.set_width(static_cast<int>(x / content.height()));
99 gfx::Rect result = bounds;
100 result.ClampToCenteredSize(letterbox);
101 return result;
102 }
103
57 } // namespace 104 } // namespace
58 105
59 // A PresentThread is a thread that is dedicated to presenting surfaces to a 106 // A PresentThread is a thread that is dedicated to presenting surfaces to a
60 // window. It owns a Direct3D device and a Direct3D query for this purpose. 107 // window. It owns a Direct3D device and a Direct3D query for this purpose.
61 class PresentThread : public base::Thread, 108 class PresentThread : public base::Thread,
62 public base::RefCountedThreadSafe<PresentThread> { 109 public base::RefCountedThreadSafe<PresentThread> {
63 public: 110 public:
64 explicit PresentThread(const char* name); 111 explicit PresentThread(const char* name);
65 112
66 IDirect3DDevice9Ex* device() { return device_.get(); } 113 IDirect3DDevice9Ex* device() { return device_.get(); }
(...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after
311 present_thread_->message_loop()->PostTask( 358 present_thread_->message_loop()->PostTask(
312 FROM_HERE, 359 FROM_HERE,
313 base::Bind(&AcceleratedPresenter::DoCopyToAndAcknowledge, 360 base::Bind(&AcceleratedPresenter::DoCopyToAndAcknowledge,
314 this, 361 this,
315 requested_src_subrect, 362 requested_src_subrect,
316 dst_size, 363 dst_size,
317 base::MessageLoopProxy::current(), 364 base::MessageLoopProxy::current(),
318 callback)); 365 callback));
319 } 366 }
320 367
368 void AcceleratedPresenter::AsyncCopyToVideoFrame(
369 const gfx::Rect& requested_src_subrect,
370 const gfx::Size& dst_size,
371 const base::Callback<void(media::VideoFrame*)>& callback) {
372 present_thread_->message_loop()->PostTask(
373 FROM_HERE,
374 base::Bind(&AcceleratedPresenter::DoCopyToVideoFrameAndAcknowledge,
375 this,
376 requested_src_subrect,
377 dst_size,
378 base::MessageLoopProxy::current(),
379 callback));
380 }
381
321 void AcceleratedPresenter::DoCopyToAndAcknowledge( 382 void AcceleratedPresenter::DoCopyToAndAcknowledge(
322 const gfx::Rect& src_subrect, 383 const gfx::Rect& src_subrect,
323 const gfx::Size& dst_size, 384 const gfx::Size& dst_size,
324 scoped_refptr<base::SingleThreadTaskRunner> callback_runner, 385 scoped_refptr<base::SingleThreadTaskRunner> callback_runner,
325 const base::Callback<void(bool, const SkBitmap&)>& callback) { 386 const base::Callback<void(bool, const SkBitmap&)>& callback) {
326 387
327 SkBitmap target; 388 SkBitmap target;
328 bool result = DoCopyTo(src_subrect, dst_size, &target); 389 bool result = DoCopyToARGB(src_subrect, dst_size, &target);
329 if (!result) 390 if (!result)
330 target.reset(); 391 target.reset();
331 callback_runner->PostTask( 392 callback_runner->PostTask(
332 FROM_HERE, 393 FROM_HERE,
333 base::Bind(callback, result, target)); 394 base::Bind(callback, result, target));
334 } 395 }
335 396
336 bool AcceleratedPresenter::DoCopyTo(const gfx::Rect& requested_src_subrect, 397 void AcceleratedPresenter::DoCopyToVideoFrameAndAcknowledge(
337 const gfx::Size& dst_size, 398 const gfx::Rect& src_subrect,
338 SkBitmap* bitmap) { 399 const gfx::Size& dst_size,
400 scoped_refptr<base::SingleThreadTaskRunner> callback_runner,
401 const base::Callback<void(media::VideoFrame*)>& callback) {
402
403 scoped_refptr<media::VideoFrame> target(
404 media::VideoFrame::CreateFrame(
405 media::VideoFrame::YV12,
406 dst_size,
407 gfx::Rect(dst_size),
408 dst_size,
409 base::TimeDelta()));
410 bool result = DoCopyToYUV(src_subrect, dst_size, target);
411 if (!result)
412 target = media::VideoFrame::CreateEmptyFrame();
413 callback_runner->PostTask(FROM_HERE, base::Bind(callback, target));
414 }
415
416 bool AcceleratedPresenter::DoCopyToARGB(const gfx::Rect& requested_src_subrect,
417 const gfx::Size& dst_size,
418 SkBitmap* bitmap) {
339 TRACE_EVENT2( 419 TRACE_EVENT2(
340 "gpu", "CopyTo", 420 "gpu", "CopyTo",
341 "width", dst_size.width(), 421 "width", dst_size.width(),
342 "height", dst_size.height()); 422 "height", dst_size.height());
343 423
344 base::AutoLock locked(lock_); 424 base::AutoLock locked(lock_);
345 425
346 TRACE_EVENT0("gpu", "CopyTo_locked");
347
348 if (!swap_chain_) 426 if (!swap_chain_)
349 return false; 427 return false;
350 428
351 AcceleratedSurfaceTransformer* gpu_ops = 429 AcceleratedSurfaceTransformer* gpu_ops =
352 present_thread_->surface_transformer(); 430 present_thread_->surface_transformer();
353 431
354 base::win::ScopedComPtr<IDirect3DSurface9> back_buffer; 432 base::win::ScopedComPtr<IDirect3DSurface9> back_buffer;
355 HRESULT hr = swap_chain_->GetBackBuffer(0, 433 HRESULT hr = swap_chain_->GetBackBuffer(0,
356 D3DBACKBUFFER_TYPE_MONO, 434 D3DBACKBUFFER_TYPE_MONO,
357 back_buffer.Receive()); 435 back_buffer.Receive());
(...skipping 24 matching lines...) Expand all
382 dst_size, 460 dst_size,
383 final_surface.Receive())) { 461 final_surface.Receive())) {
384 LOG(ERROR) << "Failed to create temporary lockable surface"; 462 LOG(ERROR) << "Failed to create temporary lockable surface";
385 return false; 463 return false;
386 } 464 }
387 } 465 }
388 466
389 { 467 {
390 // Let the surface transformer start the resize into |final_surface|. 468 // Let the surface transformer start the resize into |final_surface|.
391 TRACE_EVENT0("gpu", "ResizeBilinear"); 469 TRACE_EVENT0("gpu", "ResizeBilinear");
392 if (!gpu_ops->ResizeBilinear(back_buffer, src_subrect, final_surface)) { 470 if (!gpu_ops->ResizeBilinear(back_buffer, src_subrect,
471 final_surface, gfx::Rect(dst_size))) {
393 LOG(ERROR) << "Failed to resize bilinear"; 472 LOG(ERROR) << "Failed to resize bilinear";
394 return false; 473 return false;
395 } 474 }
396 } 475 }
397 476
398 D3DLOCKED_RECT locked_rect; 477 D3DLOCKED_RECT locked_rect;
399 478
400 // Empirical evidence seems to suggest that LockRect and memcpy are faster 479 // Empirical evidence seems to suggest that LockRect and memcpy are faster
401 // than would be GetRenderTargetData to an offscreen surface wrapping *buf. 480 // than would be GetRenderTargetData to an offscreen surface wrapping *buf.
402 { 481 {
(...skipping 20 matching lines...) Expand all
423 502
424 memcpy(reinterpret_cast<int8*>(bitmap->getPixels()), 503 memcpy(reinterpret_cast<int8*>(bitmap->getPixels()),
425 reinterpret_cast<int8*>(locked_rect.pBits), 504 reinterpret_cast<int8*>(locked_rect.pBits),
426 locked_rect.Pitch * dst_size.height()); 505 locked_rect.Pitch * dst_size.height());
427 } 506 }
428 final_surface->UnlockRect(); 507 final_surface->UnlockRect();
429 508
430 return true; 509 return true;
431 } 510 }
432 511
512 bool AcceleratedPresenter::DoCopyToYUV(const gfx::Rect& requested_src_subrect,
513 const gfx::Size& dst_size,
514 media::VideoFrame* frame) {
515 TRACE_EVENT2(
516 "gpu", "CopyToYUV",
517 "width", dst_size.width(),
518 "height", dst_size.height());
519
520 base::AutoLock locked(lock_);
521
522 if (!swap_chain_)
523 return false;
524
525 AcceleratedSurfaceTransformer* gpu_ops =
526 present_thread_->surface_transformer();
527
528 base::win::ScopedComPtr<IDirect3DSurface9> back_buffer;
529 HRESULT hr = swap_chain_->GetBackBuffer(0,
530 D3DBACKBUFFER_TYPE_MONO,
531 back_buffer.Receive());
532 if (FAILED(hr))
533 return false;
534
535 D3DSURFACE_DESC desc;
536 hr = back_buffer->GetDesc(&desc);
537 if (FAILED(hr))
538 return false;
539
540 const gfx::Size back_buffer_size(desc.Width, desc.Height);
541 if (back_buffer_size.IsEmpty())
542 return false;
543
544 // With window resizing, it's possible that the back buffer is smaller than
545 // the requested src subset. Clip to the actual back buffer.
546 gfx::Rect src_subrect = requested_src_subrect;
547 src_subrect.Intersect(gfx::Rect(back_buffer_size));
548
549 base::win::ScopedComPtr<IDirect3DTexture9> resized_as_texture;
550 base::win::ScopedComPtr<IDirect3DSurface9> resized;
551 {
552 TRACE_EVENT0("gpu", "CreateTemporaryRenderTargetTexture");
553 if (!d3d_utils::CreateTemporaryRenderTargetTexture(
554 present_thread_->device(),
555 dst_size,
556 resized_as_texture.Receive(),
557 resized.Receive())) {
558 return false;
559 }
560 }
561
562 // Shrink the source to fit entirely in the destination while preserving
563 // aspect ratio. Fill in any margin with black.
564 // TODO(nick): It would be more efficient all around to implement
565 // letterboxing as a memset() on the dst.
566 gfx::Rect letterbox = ComputeLetterboxRegion(gfx::Rect(dst_size),
567 src_subrect.size());
568 if (letterbox != gfx::Rect(dst_size)) {
569 TRACE_EVENT0("gpu", "Letterbox");
570 present_thread_->device()->ColorFill(resized, NULL, 0xFF000000);
571 }
572
573 {
574 TRACE_EVENT0("gpu", "ResizeBilinear");
575 if (!gpu_ops->ResizeBilinear(back_buffer, src_subrect, resized, letterbox))
576 return false;
577 }
578
579 base::win::ScopedComPtr<IDirect3DSurface9> y, u, v;
580 {
581 TRACE_EVENT0("gpu", "TransformRGBToYV12");
582 if (!gpu_ops->TransformRGBToYV12(resized_as_texture,
583 dst_size,
584 y.Receive(), u.Receive(), v.Receive())) {
585 return false;
586 }
587 }
588
589 if (!LockAndCopyPlane(y, frame, &media::CopyYPlane))
590 return false;
591 if (!LockAndCopyPlane(u, frame, &media::CopyUPlane))
592 return false;
593 if (!LockAndCopyPlane(v, frame, &media::CopyVPlane))
594 return false;
595 return true;
596 }
597
433 void AcceleratedPresenter::Suspend() { 598 void AcceleratedPresenter::Suspend() {
434 present_thread_->message_loop()->PostTask( 599 present_thread_->message_loop()->PostTask(
435 FROM_HERE, 600 FROM_HERE,
436 base::Bind(&AcceleratedPresenter::DoSuspend, 601 base::Bind(&AcceleratedPresenter::DoSuspend,
437 this)); 602 this));
438 } 603 }
439 604
440 void AcceleratedPresenter::WasHidden() { 605 void AcceleratedPresenter::WasHidden() {
441 base::AutoLock locked(lock_); 606 base::AutoLock locked(lock_);
442 hidden_ = true; 607 hidden_ = true;
(...skipping 409 matching lines...) Expand 10 before | Expand all | Expand 10 after
852 presenter_->Present(dc); 1017 presenter_->Present(dc);
853 } 1018 }
854 1019
855 void AcceleratedSurface::AsyncCopyTo( 1020 void AcceleratedSurface::AsyncCopyTo(
856 const gfx::Rect& src_subrect, 1021 const gfx::Rect& src_subrect,
857 const gfx::Size& dst_size, 1022 const gfx::Size& dst_size,
858 const base::Callback<void(bool, const SkBitmap&)>& callback) { 1023 const base::Callback<void(bool, const SkBitmap&)>& callback) {
859 presenter_->AsyncCopyTo(src_subrect, dst_size, callback); 1024 presenter_->AsyncCopyTo(src_subrect, dst_size, callback);
860 } 1025 }
861 1026
1027 void AcceleratedSurface::AsyncCopyToVideoFrame(
1028 const gfx::Rect& src_subrect,
1029 const gfx::Size& dst_size,
1030 const base::Callback<void(media::VideoFrame*)>& callback) {
1031 presenter_->AsyncCopyToVideoFrame(src_subrect, dst_size, callback);
1032 }
1033
862 void AcceleratedSurface::Suspend() { 1034 void AcceleratedSurface::Suspend() {
863 presenter_->Suspend(); 1035 presenter_->Suspend();
864 } 1036 }
865 1037
866 void AcceleratedSurface::WasHidden() { 1038 void AcceleratedSurface::WasHidden() {
867 presenter_->WasHidden(); 1039 presenter_->WasHidden();
868 } 1040 }
869 1041
870 void AcceleratedSurface::SetIsSessionLocked(bool locked) { 1042 void AcceleratedSurface::SetIsSessionLocked(bool locked) {
871 presenter_->SetIsSessionLocked(locked); 1043 presenter_->SetIsSessionLocked(locked);
872 } 1044 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698