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

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: Style fix per wjia 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
« no previous file with comments | « ui/surface/accelerated_surface_win.h ('k') | ui/surface/surface.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 VideoFrame copier on the result.
59 bool LockAndCopyPlane(IDirect3DSurface9* src_surface,
60 media::VideoFrame* dst_frame,
61 size_t plane_id) {
62 gfx::Size src_size = d3d_utils::GetSize(src_surface);
63
64 D3DLOCKED_RECT locked_rect;
65 {
66 TRACE_EVENT0("gpu", "LockRect");
67 HRESULT hr = src_surface->LockRect(&locked_rect, NULL,
68 D3DLOCK_READONLY | D3DLOCK_NOSYSLOCK);
69 if (FAILED(hr))
70 return false;
71 }
72
73 {
74 TRACE_EVENT0("gpu", "memcpy");
75 uint8* src = reinterpret_cast<uint8*>(locked_rect.pBits);
76 int src_stride = locked_rect.Pitch;
77 media::CopyPlane(plane_id, src, src_stride, src_size.height(), dst_frame);
78 }
79 src_surface->UnlockRect();
80 return true;
81 }
82
83 // Return the largest centered rectangle with the same aspect ratio of |content|
84 // that fits entirely inside of |bounds|.
85 gfx::Rect ComputeLetterboxRegion(
86 const gfx::Rect& bounds,
87 const gfx::Size& content) {
88 int64 x = static_cast<int64>(content.width()) * bounds.height();
89 int64 y = static_cast<int64>(bounds.width()) * content.height();
90
91 gfx::Size letterbox(bounds.width(), bounds.height());
92 if (y < x)
93 letterbox.set_height(static_cast<int>(y / content.width()));
94 else
95 letterbox.set_width(static_cast<int>(x / content.height()));
96 gfx::Rect result = bounds;
97 result.ClampToCenteredSize(letterbox);
98 return result;
99 }
100
57 } // namespace 101 } // namespace
58 102
59 // A PresentThread is a thread that is dedicated to presenting surfaces to a 103 // 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. 104 // window. It owns a Direct3D device and a Direct3D query for this purpose.
61 class PresentThread : public base::Thread, 105 class PresentThread : public base::Thread,
62 public base::RefCountedThreadSafe<PresentThread> { 106 public base::RefCountedThreadSafe<PresentThread> {
63 public: 107 public:
64 explicit PresentThread(const char* name); 108 explicit PresentThread(const char* name);
65 109
66 IDirect3DDevice9Ex* device() { return device_.get(); } 110 IDirect3DDevice9Ex* device() { return device_.get(); }
(...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after
311 present_thread_->message_loop()->PostTask( 355 present_thread_->message_loop()->PostTask(
312 FROM_HERE, 356 FROM_HERE,
313 base::Bind(&AcceleratedPresenter::DoCopyToAndAcknowledge, 357 base::Bind(&AcceleratedPresenter::DoCopyToAndAcknowledge,
314 this, 358 this,
315 requested_src_subrect, 359 requested_src_subrect,
316 dst_size, 360 dst_size,
317 base::MessageLoopProxy::current(), 361 base::MessageLoopProxy::current(),
318 callback)); 362 callback));
319 } 363 }
320 364
365 void AcceleratedPresenter::AsyncCopyToVideoFrame(
366 const gfx::Rect& requested_src_subrect,
367 const scoped_refptr<media::VideoFrame>& target,
368 const base::Callback<void(bool)>& callback) {
369 present_thread_->message_loop()->PostTask(
370 FROM_HERE,
371 base::Bind(&AcceleratedPresenter::DoCopyToVideoFrameAndAcknowledge,
372 this,
373 requested_src_subrect,
374 target,
375 base::MessageLoopProxy::current(),
376 callback));
377 }
378
321 void AcceleratedPresenter::DoCopyToAndAcknowledge( 379 void AcceleratedPresenter::DoCopyToAndAcknowledge(
322 const gfx::Rect& src_subrect, 380 const gfx::Rect& src_subrect,
323 const gfx::Size& dst_size, 381 const gfx::Size& dst_size,
324 scoped_refptr<base::SingleThreadTaskRunner> callback_runner, 382 scoped_refptr<base::SingleThreadTaskRunner> callback_runner,
325 const base::Callback<void(bool, const SkBitmap&)>& callback) { 383 const base::Callback<void(bool, const SkBitmap&)>& callback) {
326
327 SkBitmap target; 384 SkBitmap target;
328 bool result = DoCopyTo(src_subrect, dst_size, &target); 385 bool result = DoCopyToARGB(src_subrect, dst_size, &target);
329 if (!result) 386 if (!result)
330 target.reset(); 387 target.reset();
331 callback_runner->PostTask( 388 callback_runner->PostTask(FROM_HERE, base::Bind(callback, result, target));
332 FROM_HERE,
333 base::Bind(callback, result, target));
334 } 389 }
335 390
336 bool AcceleratedPresenter::DoCopyTo(const gfx::Rect& requested_src_subrect, 391 void AcceleratedPresenter::DoCopyToVideoFrameAndAcknowledge(
337 const gfx::Size& dst_size, 392 const gfx::Rect& src_subrect,
338 SkBitmap* bitmap) { 393 const scoped_refptr<media::VideoFrame>& target,
394 const scoped_refptr<base::SingleThreadTaskRunner>& callback_runner,
395 const base::Callback<void(bool)>& callback) {
396
397 bool result = DoCopyToYUV(src_subrect, target);
398 callback_runner->PostTask(FROM_HERE, base::Bind(callback, result));
399 }
400
401 bool AcceleratedPresenter::DoCopyToARGB(const gfx::Rect& requested_src_subrect,
402 const gfx::Size& dst_size,
403 SkBitmap* bitmap) {
339 TRACE_EVENT2( 404 TRACE_EVENT2(
340 "gpu", "CopyTo", 405 "gpu", "CopyTo",
341 "width", dst_size.width(), 406 "width", dst_size.width(),
342 "height", dst_size.height()); 407 "height", dst_size.height());
343 408
344 base::AutoLock locked(lock_); 409 base::AutoLock locked(lock_);
345 410
346 TRACE_EVENT0("gpu", "CopyTo_locked");
347
348 if (!swap_chain_) 411 if (!swap_chain_)
349 return false; 412 return false;
350 413
351 AcceleratedSurfaceTransformer* gpu_ops = 414 AcceleratedSurfaceTransformer* gpu_ops =
352 present_thread_->surface_transformer(); 415 present_thread_->surface_transformer();
353 416
354 base::win::ScopedComPtr<IDirect3DSurface9> back_buffer; 417 base::win::ScopedComPtr<IDirect3DSurface9> back_buffer;
355 HRESULT hr = swap_chain_->GetBackBuffer(0, 418 HRESULT hr = swap_chain_->GetBackBuffer(0,
356 D3DBACKBUFFER_TYPE_MONO, 419 D3DBACKBUFFER_TYPE_MONO,
357 back_buffer.Receive()); 420 back_buffer.Receive());
(...skipping 24 matching lines...) Expand all
382 dst_size, 445 dst_size,
383 final_surface.Receive())) { 446 final_surface.Receive())) {
384 LOG(ERROR) << "Failed to create temporary lockable surface"; 447 LOG(ERROR) << "Failed to create temporary lockable surface";
385 return false; 448 return false;
386 } 449 }
387 } 450 }
388 451
389 { 452 {
390 // Let the surface transformer start the resize into |final_surface|. 453 // Let the surface transformer start the resize into |final_surface|.
391 TRACE_EVENT0("gpu", "ResizeBilinear"); 454 TRACE_EVENT0("gpu", "ResizeBilinear");
392 if (!gpu_ops->ResizeBilinear(back_buffer, src_subrect, final_surface)) { 455 if (!gpu_ops->ResizeBilinear(back_buffer, src_subrect,
456 final_surface, gfx::Rect(dst_size))) {
393 LOG(ERROR) << "Failed to resize bilinear"; 457 LOG(ERROR) << "Failed to resize bilinear";
394 return false; 458 return false;
395 } 459 }
396 } 460 }
397 461
398 D3DLOCKED_RECT locked_rect; 462 D3DLOCKED_RECT locked_rect;
399 463
400 // Empirical evidence seems to suggest that LockRect and memcpy are faster 464 // Empirical evidence seems to suggest that LockRect and memcpy are faster
401 // than would be GetRenderTargetData to an offscreen surface wrapping *buf. 465 // than would be GetRenderTargetData to an offscreen surface wrapping *buf.
402 { 466 {
(...skipping 20 matching lines...) Expand all
423 487
424 memcpy(reinterpret_cast<int8*>(bitmap->getPixels()), 488 memcpy(reinterpret_cast<int8*>(bitmap->getPixels()),
425 reinterpret_cast<int8*>(locked_rect.pBits), 489 reinterpret_cast<int8*>(locked_rect.pBits),
426 locked_rect.Pitch * dst_size.height()); 490 locked_rect.Pitch * dst_size.height());
427 } 491 }
428 final_surface->UnlockRect(); 492 final_surface->UnlockRect();
429 493
430 return true; 494 return true;
431 } 495 }
432 496
497 bool AcceleratedPresenter::DoCopyToYUV(
498 const gfx::Rect& requested_src_subrect,
499 const scoped_refptr<media::VideoFrame>& frame) {
500 gfx::Size dst_size = frame->coded_size();
501 TRACE_EVENT2(
502 "gpu", "CopyToYUV",
503 "width", dst_size.width(),
504 "height", dst_size.height());
505
506 base::AutoLock locked(lock_);
507
508 if (!swap_chain_)
509 return false;
510
511 AcceleratedSurfaceTransformer* gpu_ops =
512 present_thread_->surface_transformer();
513
514 base::win::ScopedComPtr<IDirect3DSurface9> back_buffer;
515 HRESULT hr = swap_chain_->GetBackBuffer(0,
516 D3DBACKBUFFER_TYPE_MONO,
517 back_buffer.Receive());
518 if (FAILED(hr))
519 return false;
520
521 D3DSURFACE_DESC desc;
522 hr = back_buffer->GetDesc(&desc);
523 if (FAILED(hr))
524 return false;
525
526 const gfx::Size back_buffer_size(desc.Width, desc.Height);
527 if (back_buffer_size.IsEmpty())
528 return false;
529
530 // With window resizing, it's possible that the back buffer is smaller than
531 // the requested src subset. Clip to the actual back buffer.
532 gfx::Rect src_subrect = requested_src_subrect;
533 src_subrect.Intersect(gfx::Rect(back_buffer_size));
534
535 base::win::ScopedComPtr<IDirect3DTexture9> resized_as_texture;
536 base::win::ScopedComPtr<IDirect3DSurface9> resized;
537 {
538 TRACE_EVENT0("gpu", "CreateTemporaryRenderTargetTexture");
539 if (!d3d_utils::CreateTemporaryRenderTargetTexture(
540 present_thread_->device(),
541 dst_size,
542 resized_as_texture.Receive(),
543 resized.Receive())) {
544 return false;
545 }
546 }
547
548 // Shrink the source to fit entirely in the destination while preserving
549 // aspect ratio. Fill in any margin with black.
550 // TODO(nick): It would be more efficient all around to implement
551 // letterboxing as a memset() on the dst.
552 gfx::Rect letterbox = ComputeLetterboxRegion(gfx::Rect(dst_size),
553 src_subrect.size());
554 if (letterbox != gfx::Rect(dst_size)) {
555 TRACE_EVENT0("gpu", "Letterbox");
556 present_thread_->device()->ColorFill(resized, NULL, 0xFF000000);
557 }
558
559 {
560 TRACE_EVENT0("gpu", "ResizeBilinear");
561 if (!gpu_ops->ResizeBilinear(back_buffer, src_subrect, resized, letterbox))
562 return false;
563 }
564
565 base::win::ScopedComPtr<IDirect3DSurface9> y, u, v;
566 {
567 TRACE_EVENT0("gpu", "TransformRGBToYV12");
568 if (!gpu_ops->TransformRGBToYV12(resized_as_texture,
569 dst_size,
570 y.Receive(), u.Receive(), v.Receive())) {
571 return false;
572 }
573 }
574
575 if (!LockAndCopyPlane(y, frame, media::VideoFrame::kYPlane))
576 return false;
577 if (!LockAndCopyPlane(u, frame, media::VideoFrame::kUPlane))
578 return false;
579 if (!LockAndCopyPlane(v, frame, media::VideoFrame::kVPlane))
580 return false;
581 return true;
582 }
583
433 void AcceleratedPresenter::Suspend() { 584 void AcceleratedPresenter::Suspend() {
434 present_thread_->message_loop()->PostTask( 585 present_thread_->message_loop()->PostTask(
435 FROM_HERE, 586 FROM_HERE,
436 base::Bind(&AcceleratedPresenter::DoSuspend, 587 base::Bind(&AcceleratedPresenter::DoSuspend,
437 this)); 588 this));
438 } 589 }
439 590
440 void AcceleratedPresenter::WasHidden() { 591 void AcceleratedPresenter::WasHidden() {
441 base::AutoLock locked(lock_); 592 base::AutoLock locked(lock_);
442 hidden_ = true; 593 hidden_ = true;
(...skipping 409 matching lines...) Expand 10 before | Expand all | Expand 10 after
852 presenter_->Present(dc); 1003 presenter_->Present(dc);
853 } 1004 }
854 1005
855 void AcceleratedSurface::AsyncCopyTo( 1006 void AcceleratedSurface::AsyncCopyTo(
856 const gfx::Rect& src_subrect, 1007 const gfx::Rect& src_subrect,
857 const gfx::Size& dst_size, 1008 const gfx::Size& dst_size,
858 const base::Callback<void(bool, const SkBitmap&)>& callback) { 1009 const base::Callback<void(bool, const SkBitmap&)>& callback) {
859 presenter_->AsyncCopyTo(src_subrect, dst_size, callback); 1010 presenter_->AsyncCopyTo(src_subrect, dst_size, callback);
860 } 1011 }
861 1012
1013 void AcceleratedSurface::AsyncCopyToVideoFrame(
1014 const gfx::Rect& src_subrect,
1015 const scoped_refptr<media::VideoFrame>& target,
1016 const base::Callback<void(bool)>& callback) {
1017 presenter_->AsyncCopyToVideoFrame(src_subrect, target, callback);
1018 }
1019
862 void AcceleratedSurface::Suspend() { 1020 void AcceleratedSurface::Suspend() {
863 presenter_->Suspend(); 1021 presenter_->Suspend();
864 } 1022 }
865 1023
866 void AcceleratedSurface::WasHidden() { 1024 void AcceleratedSurface::WasHidden() {
867 presenter_->WasHidden(); 1025 presenter_->WasHidden();
868 } 1026 }
869 1027
870 void AcceleratedSurface::SetIsSessionLocked(bool locked) { 1028 void AcceleratedSurface::SetIsSessionLocked(bool locked) {
871 presenter_->SetIsSessionLocked(locked); 1029 presenter_->SetIsSessionLocked(locked);
872 } 1030 }
OLDNEW
« no previous file with comments | « ui/surface/accelerated_surface_win.h ('k') | ui/surface/surface.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698