diff options
Diffstat (limited to 'chromium/ui/surface/accelerated_surface_win.cc')
-rw-r--r-- | chromium/ui/surface/accelerated_surface_win.cc | 1108 |
1 files changed, 0 insertions, 1108 deletions
diff --git a/chromium/ui/surface/accelerated_surface_win.cc b/chromium/ui/surface/accelerated_surface_win.cc deleted file mode 100644 index a8b57c5a450..00000000000 --- a/chromium/ui/surface/accelerated_surface_win.cc +++ /dev/null @@ -1,1108 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ui/surface/accelerated_surface_win.h" - -#include <windows.h> -#include <algorithm> - -#include "base/bind.h" -#include "base/callback.h" -#include "base/callback_helpers.h" -#include "base/command_line.h" -#include "base/debug/trace_event.h" -#include "base/files/file_path.h" -#include "base/lazy_instance.h" -#include "base/metrics/histogram.h" -#include "base/memory/scoped_ptr.h" -#include "base/message_loop/message_loop_proxy.h" -#include "base/scoped_native_library.h" -#include "base/strings/stringprintf.h" -#include "base/synchronization/waitable_event.h" -#include "base/threading/thread.h" -#include "base/threading/thread_restrictions.h" -#include "base/win/wrapped_window_proc.h" -#include "media/base/video_frame.h" -#include "media/base/video_util.h" -#include "third_party/skia/include/core/SkBitmap.h" -#include "ui/base/win/shell.h" -#include "ui/events/latency_info.h" -#include "ui/gfx/frame_time.h" -#include "ui/gfx/rect.h" -#include "ui/gfx/win/dpi.h" -#include "ui/gfx/win/hwnd_util.h" -#include "ui/gl/gl_switches.h" -#include "ui/surface/accelerated_surface_transformer_win.h" -#include "ui/surface/d3d9_utils_win.h" -#include "ui/surface/surface_switches.h" - -namespace d3d_utils = ui_surface_d3d9_utils; - -namespace { - -UINT GetPresentationInterval() { - if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableGpuVsync)) - return D3DPRESENT_INTERVAL_IMMEDIATE; - else - return D3DPRESENT_INTERVAL_ONE; -} - -bool DoFirstShowPresentWithGDI() { - return CommandLine::ForCurrentProcess()->HasSwitch( - switches::kDoFirstShowPresentWithGDI); -} - -bool DoAllShowPresentWithGDI() { - return CommandLine::ForCurrentProcess()->HasSwitch( - switches::kDoAllShowPresentWithGDI); -} - -// Use a SurfaceReader to copy into one plane of the VideoFrame. -bool CopyPlane(AcceleratedSurfaceTransformer* gpu_ops, - IDirect3DSurface9* src_surface, - media::VideoFrame* dst_frame, - size_t plane_id) { - int width_in_bytes = dst_frame->row_bytes(plane_id); - return gpu_ops->ReadFast(src_surface, dst_frame->data(plane_id), - width_in_bytes, dst_frame->rows(plane_id), - dst_frame->row_bytes(plane_id)); -} - -} // namespace - -// A PresentThread is a thread that is dedicated to presenting surfaces to a -// window. It owns a Direct3D device and a Direct3D query for this purpose. -class PresentThread : public base::Thread, - public base::RefCountedThreadSafe<PresentThread> { - public: - PresentThread(const char* name, uint64 adapter_luid); - - IDirect3DDevice9Ex* device() { return device_.get(); } - IDirect3DQuery9* query() { return query_.get(); } - AcceleratedSurfaceTransformer* surface_transformer() { - return &surface_transformer_; - } - - void SetAdapterLUID(uint64 adapter_luid); - void InitDevice(); - void LockAndResetDevice(); - void ResetDevice(); - bool IsDeviceLost(); - - base::Lock* lock() { - return &lock_; - } - - protected: - virtual void Init(); - virtual void CleanUp(); - - private: - friend class base::RefCountedThreadSafe<PresentThread>; - - ~PresentThread(); - - // The lock is taken while any thread is calling an AcceleratedPresenter - // associated with this thread. - base::Lock lock_; - - base::ScopedNativeLibrary d3d_module_; - uint64 adapter_luid_; - base::win::ScopedComPtr<IDirect3DDevice9Ex> device_; - - // This query is used to wait until a certain amount of progress has been - // made by the GPU and it is safe for the producer to modify its shared - // texture again. - base::win::ScopedComPtr<IDirect3DQuery9> query_; - AcceleratedSurfaceTransformer surface_transformer_; - - DISALLOW_COPY_AND_ASSIGN(PresentThread); -}; - -// There is a fixed sized pool of PresentThreads and therefore the maximum -// number of Direct3D devices owned by those threads is bounded. -class PresentThreadPool { - public: - static const int kNumPresentThreads = 4; - - PresentThreadPool(); - PresentThread* NextThread(); - - void SetAdapterLUID(uint64 adapter_luid); - - private: - base::Lock lock_; - int next_thread_; - scoped_refptr<PresentThread> present_threads_[kNumPresentThreads]; - uint64 adapter_luid_; - - DISALLOW_COPY_AND_ASSIGN(PresentThreadPool); -}; - -// A thread safe map of presenters by surface ID that returns presenters via -// a scoped_refptr to keep them alive while they are referenced. -class AcceleratedPresenterMap { - public: - AcceleratedPresenterMap(); - scoped_refptr<AcceleratedPresenter> CreatePresenter( - gfx::PluginWindowHandle window); - void RemovePresenter(const scoped_refptr<AcceleratedPresenter>& presenter); - scoped_refptr<AcceleratedPresenter> GetPresenter( - gfx::PluginWindowHandle window); - - // Destroy any D3D resources owned by the given present thread. Called on - // the given present thread. - void ResetPresentThread(PresentThread* present_thread); - - private: - base::Lock lock_; - typedef std::map<gfx::PluginWindowHandle, AcceleratedPresenter*> PresenterMap; - PresenterMap presenters_; - uint64 adapter_luid_; - DISALLOW_COPY_AND_ASSIGN(AcceleratedPresenterMap); -}; - -base::LazyInstance<PresentThreadPool> - g_present_thread_pool = LAZY_INSTANCE_INITIALIZER; - -base::LazyInstance<AcceleratedPresenterMap> - g_accelerated_presenter_map = LAZY_INSTANCE_INITIALIZER; - -PresentThread::PresentThread(const char* name, uint64 adapter_luid) - : base::Thread(name), - adapter_luid_(adapter_luid) { -} - -void PresentThread::SetAdapterLUID(uint64 adapter_luid) { - base::AutoLock locked(lock_); - - CHECK(message_loop() == base::MessageLoop::current()); - - if (adapter_luid_ == adapter_luid) - return; - - adapter_luid_ = adapter_luid; - if (device_) - ResetDevice(); -} - -void PresentThread::InitDevice() { - lock_.AssertAcquired(); - - if (device_) - return; - - TRACE_EVENT0("gpu", "PresentThread::Init"); - d3d_utils::LoadD3D9(&d3d_module_); - ResetDevice(); -} - -void PresentThread::LockAndResetDevice() { - base::AutoLock locked(lock_); - ResetDevice(); -} - -void PresentThread::ResetDevice() { - TRACE_EVENT0("gpu", "PresentThread::ResetDevice"); - - lock_.AssertAcquired(); - - // The D3D device must be created on the present thread. - CHECK(message_loop() == base::MessageLoop::current()); - - // This will crash some Intel drivers but we can't render anything without - // reseting the device, which would be disappointing. - query_ = NULL; - device_ = NULL; - surface_transformer_.ReleaseAll(); - - g_accelerated_presenter_map.Pointer()->ResetPresentThread(this); - - if (!d3d_utils::CreateDevice(d3d_module_, - adapter_luid_, - D3DDEVTYPE_HAL, - GetPresentationInterval(), - device_.Receive())) { - return; - } - - HRESULT hr = device_->CreateQuery(D3DQUERYTYPE_EVENT, query_.Receive()); - if (FAILED(hr)) { - LOG(ERROR) << "Failed to create query"; - device_ = NULL; - return; - } - - if (!surface_transformer_.Init(device_)) { - LOG(ERROR) << "Failed to initialize surface transformer"; - query_ = NULL; - device_ = NULL; - return; - } -} - -bool PresentThread::IsDeviceLost() { - lock_.AssertAcquired(); - - HRESULT hr = device_->CheckDeviceState(NULL); - return FAILED(hr) || hr == S_PRESENT_MODE_CHANGED; -} - -void PresentThread::Init() { - TRACE_EVENT0("gpu", "Initialize thread"); -} - -void PresentThread::CleanUp() { - // The D3D device and query are leaked because destroying the associated D3D - // query crashes some Intel drivers. - surface_transformer_.DetachAll(); - device_.Detach(); - query_.Detach(); -} - -PresentThread::~PresentThread() { - Stop(); -} - -PresentThreadPool::PresentThreadPool() : next_thread_(0) { -} - -PresentThread* PresentThreadPool::NextThread() { - base::AutoLock locked(lock_); - - next_thread_ = (next_thread_ + 1) % kNumPresentThreads; - PresentThread* thread = present_threads_[next_thread_].get(); - if (!thread) { - thread = new PresentThread( - base::StringPrintf("PresentThread #%d", next_thread_).c_str(), - adapter_luid_); - thread->Start(); - present_threads_[next_thread_] = thread; - } - - return thread; -} - -void PresentThreadPool::SetAdapterLUID(uint64 adapter_luid) { - base::AutoLock locked(lock_); - - adapter_luid_ = adapter_luid; - - for (int i = 0; i < kNumPresentThreads; ++i) { - if (!present_threads_[i]) - continue; - - present_threads_[i]->message_loop()->PostTask( - FROM_HERE, - base::Bind(&PresentThread::SetAdapterLUID, - present_threads_[i], - adapter_luid)); - } -} - -AcceleratedPresenterMap::AcceleratedPresenterMap() { -} - -scoped_refptr<AcceleratedPresenter> AcceleratedPresenterMap::CreatePresenter( - gfx::PluginWindowHandle window) { - scoped_refptr<AcceleratedPresenter> presenter( - new AcceleratedPresenter(window)); - - base::AutoLock locked(lock_); - DCHECK(presenters_.find(window) == presenters_.end()); - presenters_[window] = presenter.get(); - - return presenter; -} - -void AcceleratedPresenterMap::RemovePresenter( - const scoped_refptr<AcceleratedPresenter>& presenter) { - base::AutoLock locked(lock_); - for (PresenterMap::iterator it = presenters_.begin(); - it != presenters_.end(); - ++it) { - if (it->second == presenter.get()) { - presenters_.erase(it); - return; - } - } - - NOTREACHED(); -} - -scoped_refptr<AcceleratedPresenter> AcceleratedPresenterMap::GetPresenter( - gfx::PluginWindowHandle window) { - base::AutoLock locked(lock_); - PresenterMap::iterator it = presenters_.find(window); - if (it == presenters_.end()) - return scoped_refptr<AcceleratedPresenter>(); - - return it->second; -} - -void AcceleratedPresenterMap::ResetPresentThread( - PresentThread* present_thread) { - base::AutoLock locked(lock_); - - for (PresenterMap::iterator it = presenters_.begin(); - it != presenters_.end(); - ++it) { - it->second->ResetPresentThread(present_thread); - } -} - -AcceleratedPresenter::AcceleratedPresenter(gfx::PluginWindowHandle window) - : present_thread_(g_present_thread_pool.Pointer()->NextThread()), - window_(window), - event_(false, false), - hidden_(true), - do_present_with_GDI_(DoAllShowPresentWithGDI() || - DoFirstShowPresentWithGDI()), - is_session_locked_(false) { -} - -// static -void AcceleratedPresenter::SetAdapterLUID(uint64 adapter_luid) { - return g_present_thread_pool.Pointer()->SetAdapterLUID(adapter_luid); -} - - -// static -scoped_refptr<AcceleratedPresenter> AcceleratedPresenter::GetForWindow( - gfx::PluginWindowHandle window) { - return g_accelerated_presenter_map.Pointer()->GetPresenter(window); -} - -void AcceleratedPresenter::AsyncPresentAndAcknowledge( - const gfx::Size& size, - int64 surface_handle, - const ui::LatencyInfo& latency_info, - const CompletionTask& completion_task) { - if (!surface_handle) { - TRACE_EVENT1("gpu", "EarlyOut_ZeroSurfaceHandle", - "surface_handle", surface_handle); - completion_task.Run( - true, base::TimeTicks(), base::TimeDelta(), ui::LatencyInfo()); - return; - } - - present_thread_->message_loop()->PostTask( - FROM_HERE, - base::Bind(&AcceleratedPresenter::DoPresentAndAcknowledge, - this, - size, - surface_handle, - latency_info, - completion_task)); -} - -void AcceleratedPresenter::Present(HDC dc) { - TRACE_EVENT0("gpu", "Present"); - - base::AutoLock locked(*present_thread_->lock()); - - // If invalidated, do nothing. The window is gone. - if (!window_) - return; - - // Suspended or nothing has ever been presented. - if (!swap_chain_) - return; - - PresentWithGDI(dc); -} - -void AcceleratedPresenter::AsyncCopyTo( - const gfx::Rect& requested_src_subrect, - const gfx::Size& dst_size, - const base::Callback<void(bool, const SkBitmap&)>& callback) { - present_thread_->message_loop()->PostTask( - FROM_HERE, - base::Bind(&AcceleratedPresenter::DoCopyToAndAcknowledge, - this, - requested_src_subrect, - dst_size, - base::MessageLoopProxy::current(), - callback)); -} - -void AcceleratedPresenter::AsyncCopyToVideoFrame( - const gfx::Rect& requested_src_subrect, - const scoped_refptr<media::VideoFrame>& target, - const base::Callback<void(bool)>& callback) { - present_thread_->message_loop()->PostTask( - FROM_HERE, - base::Bind(&AcceleratedPresenter::DoCopyToVideoFrameAndAcknowledge, - this, - requested_src_subrect, - target, - base::MessageLoopProxy::current(), - callback)); -} - -void AcceleratedPresenter::DoCopyToAndAcknowledge( - const gfx::Rect& src_subrect, - const gfx::Size& dst_size, - scoped_refptr<base::SingleThreadTaskRunner> callback_runner, - const base::Callback<void(bool, const SkBitmap&)>& callback) { - SkBitmap target; - bool result = DoCopyToARGB(src_subrect, dst_size, &target); - if (!result) - target.reset(); - callback_runner->PostTask(FROM_HERE, base::Bind(callback, result, target)); -} - -void AcceleratedPresenter::DoCopyToVideoFrameAndAcknowledge( - const gfx::Rect& src_subrect, - const scoped_refptr<media::VideoFrame>& target, - const scoped_refptr<base::SingleThreadTaskRunner>& callback_runner, - const base::Callback<void(bool)>& callback) { - - bool result = DoCopyToYUV(src_subrect, target); - callback_runner->PostTask(FROM_HERE, base::Bind(callback, result)); -} - -bool AcceleratedPresenter::DoCopyToARGB(const gfx::Rect& requested_src_subrect, - const gfx::Size& dst_size, - SkBitmap* bitmap) { - TRACE_EVENT2( - "gpu", "CopyTo", - "width", dst_size.width(), - "height", dst_size.height()); - - base::AutoLock locked(*present_thread_->lock()); - - if (!swap_chain_) - return false; - - AcceleratedSurfaceTransformer* gpu_ops = - present_thread_->surface_transformer(); - - base::win::ScopedComPtr<IDirect3DSurface9> back_buffer; - HRESULT hr = swap_chain_->GetBackBuffer(0, - D3DBACKBUFFER_TYPE_MONO, - back_buffer.Receive()); - if (FAILED(hr)) { - LOG(ERROR) << "Failed to get back buffer"; - return false; - } - - D3DSURFACE_DESC desc; - hr = back_buffer->GetDesc(&desc); - if (FAILED(hr)) { - LOG(ERROR) << "Failed to get buffer description"; - return false; - } - - const gfx::Size back_buffer_size(desc.Width, desc.Height); - if (back_buffer_size.IsEmpty()) - return false; - - // With window resizing, it's possible that the back buffer is smaller than - // the requested src subset. Clip to the actual back buffer. - gfx::Rect src_subrect = requested_src_subrect; - src_subrect.Intersect(gfx::Rect(back_buffer_size)); - base::win::ScopedComPtr<IDirect3DSurface9> final_surface; - { - if (!d3d_utils::CreateOrReuseLockableSurface(present_thread_->device(), - dst_size, - &final_surface)) { - LOG(ERROR) << "Failed to create temporary lockable surface"; - return false; - } - } - - { - // Let the surface transformer start the resize into |final_surface|. - TRACE_EVENT0("gpu", "ResizeBilinear"); - if (!gpu_ops->ResizeBilinear(back_buffer, src_subrect, - final_surface, gfx::Rect(dst_size))) { - LOG(ERROR) << "Failed to resize bilinear"; - return false; - } - } - - bitmap->setConfig(SkBitmap::kARGB_8888_Config, dst_size.width(), - dst_size.height(), 0, kOpaque_SkAlphaType); - if (!bitmap->allocPixels()) - return false; - - // Copy |final_surface| to |bitmap|. This is always a synchronous operation. - return gpu_ops->ReadFast(final_surface, - reinterpret_cast<uint8*>(bitmap->getPixels()), - bitmap->width() * bitmap->bytesPerPixel(), - bitmap->height(), - static_cast<int>(bitmap->rowBytes())); -} - -bool AcceleratedPresenter::DoCopyToYUV( - const gfx::Rect& requested_src_subrect, - const scoped_refptr<media::VideoFrame>& frame) { - gfx::Size dst_size = frame->coded_size(); - TRACE_EVENT2( - "gpu", "CopyToYUV", - "width", dst_size.width(), - "height", dst_size.height()); - - base::AutoLock locked(*present_thread_->lock()); - - if (!swap_chain_) - return false; - - AcceleratedSurfaceTransformer* gpu_ops = - present_thread_->surface_transformer(); - - base::win::ScopedComPtr<IDirect3DSurface9> back_buffer; - HRESULT hr = swap_chain_->GetBackBuffer(0, - D3DBACKBUFFER_TYPE_MONO, - back_buffer.Receive()); - if (FAILED(hr)) - return false; - - D3DSURFACE_DESC desc; - hr = back_buffer->GetDesc(&desc); - if (FAILED(hr)) - return false; - - const gfx::Size back_buffer_size(desc.Width, desc.Height); - if (back_buffer_size.IsEmpty()) - return false; - - // With window resizing, it's possible that the back buffer is smaller than - // the requested src subset. Clip to the actual back buffer. - gfx::Rect src_subrect = requested_src_subrect; - src_subrect.Intersect(gfx::Rect(back_buffer_size)); - if (src_subrect.IsEmpty()) - return false; - - base::win::ScopedComPtr<IDirect3DSurface9> resized; - base::win::ScopedComPtr<IDirect3DTexture9> resized_as_texture; - if (!gpu_ops->GetIntermediateTexture(dst_size, - resized_as_texture.Receive(), - resized.Receive())) { - return false; - } - - // Shrink the source to fit entirely in the destination while preserving - // aspect ratio. Fill in any margin with black. - // TODO(nick): It would be more efficient all around to implement - // letterboxing as a memset() on the dst. - gfx::Rect letterbox = media::ComputeLetterboxRegion(gfx::Rect(dst_size), - src_subrect.size()); - if (letterbox != gfx::Rect(dst_size)) { - TRACE_EVENT0("gpu", "Letterbox"); - present_thread_->device()->ColorFill(resized, NULL, 0xFF000000); - } - - { - TRACE_EVENT0("gpu", "ResizeBilinear"); - if (!gpu_ops->ResizeBilinear(back_buffer, src_subrect, resized, letterbox)) - return false; - } - - base::win::ScopedComPtr<IDirect3DSurface9> y, u, v; - { - TRACE_EVENT0("gpu", "TransformRGBToYV12"); - if (!gpu_ops->TransformRGBToYV12(resized_as_texture, - dst_size, - y.Receive(), u.Receive(), v.Receive())) { - return false; - } - } - - if (!CopyPlane(gpu_ops, y, frame, media::VideoFrame::kYPlane)) - return false; - if (!CopyPlane(gpu_ops, u, frame, media::VideoFrame::kUPlane)) - return false; - if (!CopyPlane(gpu_ops, v, frame, media::VideoFrame::kVPlane)) - return false; - return true; -} - -void AcceleratedPresenter::Suspend() { - present_thread_->message_loop()->PostTask( - FROM_HERE, - base::Bind(&AcceleratedPresenter::DoSuspend, - this)); -} - -void AcceleratedPresenter::WasHidden() { - base::AutoLock locked(*present_thread_->lock()); - hidden_ = true; -} - -void AcceleratedPresenter::ReleaseSurface() { - present_thread_->message_loop()->PostTask( - FROM_HERE, - base::Bind(&AcceleratedPresenter::DoReleaseSurface, - this)); -} - -void AcceleratedPresenter::SetIsSessionLocked(bool locked) { - is_session_locked_ = locked; -} - -void AcceleratedPresenter::Invalidate() { - // Make any pending or future presentation tasks do nothing. Once the last - // last pending task has been ignored, the reference count on the presenter - // will go to zero and the presenter, and potentially also the present thread - // it has a reference count on, will be destroyed. - base::AutoLock locked(*present_thread_->lock()); - window_ = NULL; -} - -void AcceleratedPresenter::ResetPresentThread( - PresentThread* present_thread) { - TRACE_EVENT0("gpu", "ResetPresentThread"); - - // present_thread_ can be accessed without the lock because it is immutable. - if (present_thread_ != present_thread) - return; - - present_thread_->lock()->AssertAcquired(); - - source_texture_ = NULL; - swap_chain_ = NULL; - quantized_size_ = gfx::Size(); -} - -AcceleratedPresenter::~AcceleratedPresenter() { -} - -bool AcceleratedPresenter::IsSwapChainInitialized() const { - base::AutoLock locked(*present_thread_->lock()); - - return !!swap_chain_; -} - -void AcceleratedPresenter::DoPresentAndAcknowledge( - const gfx::Size& size, - int64 surface_handle, - const ui::LatencyInfo& latency_info, - const CompletionTask& completion_task) { - TRACE_EVENT2( - "gpu", "DoPresentAndAcknowledge", - "width", size.width(), - "height", size.height()); - - HRESULT hr; - - base::AutoLock locked(*present_thread_->lock()); - - latency_info_.MergeWith(latency_info); - - // Initialize the device lazily since calling Direct3D can crash bots. - present_thread_->InitDevice(); - - if (!present_thread_->device()) { - completion_task.Run( - false, base::TimeTicks(), base::TimeDelta(), ui::LatencyInfo()); - TRACE_EVENT0("gpu", "EarlyOut_NoDevice"); - return; - } - - // Ensure the task is acknowledged on early out after this point. - base::ScopedClosureRunner scoped_completion_runner( - base::Bind(completion_task, - true, - base::TimeTicks(), - base::TimeDelta(), - ui::LatencyInfo())); - - // If invalidated, do nothing, the window is gone. - if (!window_) { - TRACE_EVENT0("gpu", "EarlyOut_NoWindow"); - return; - } - -#if !defined(USE_AURA) - // If the window is a different size than the swap chain that is being - // presented then drop the frame. - gfx::Size window_size = GetWindowSize(); - bool size_mismatch = size != window_size; - if (gfx::IsInHighDPIMode()) { - // Check if the size mismatch is within allowable round off or truncation - // error. - gfx::Size dip_size = gfx::win::ScreenToDIPSize(window_size); - gfx::Size pixel_size = gfx::win::DIPToScreenSize(dip_size); - size_mismatch = abs(window_size.width() - size.width()) > - abs(window_size.width() - pixel_size.width()) || - abs(window_size.height() - size.height()) > - abs(window_size.height() - pixel_size.height()); - } - if (hidden_ && size_mismatch) { - TRACE_EVENT2("gpu", "EarlyOut_WrongWindowSize", - "backwidth", size.width(), "backheight", size.height()); - TRACE_EVENT2("gpu", "EarlyOut_WrongWindowSize2", - "windowwidth", window_size.width(), - "windowheight", window_size.height()); - return; - } -#endif - // Round up size so the swap chain is not continuously resized with the - // surface, which could lead to memory fragmentation. - const int kRound = 64; - gfx::Size quantized_size( - std::max(1, (size.width() + kRound - 1) / kRound * kRound), - std::max(1, (size.height() + kRound - 1) / kRound * kRound)); - - // Ensure the swap chain exists and is the same size (rounded up) as the - // surface to be presented. - if (!swap_chain_ || quantized_size_ != quantized_size) { - TRACE_EVENT0("gpu", "CreateAdditionalSwapChain"); - quantized_size_ = quantized_size; - - D3DPRESENT_PARAMETERS parameters = { 0 }; - parameters.BackBufferWidth = quantized_size.width(); - parameters.BackBufferHeight = quantized_size.height(); - parameters.BackBufferCount = 1; - parameters.BackBufferFormat = D3DFMT_A8R8G8B8; - parameters.hDeviceWindow = window_; - parameters.Windowed = TRUE; - parameters.Flags = 0; - parameters.PresentationInterval = GetPresentationInterval(); - parameters.SwapEffect = D3DSWAPEFFECT_COPY; - - swap_chain_ = NULL; - HRESULT hr = present_thread_->device()->CreateAdditionalSwapChain( - ¶meters, - swap_chain_.Receive()); - if (FAILED(hr)) { - LOG(ERROR) << "Failed to create swap chain " - << quantized_size.width() << " x " <<quantized_size.height(); - return; - } - } - - if (!source_texture_.get()) { - TRACE_EVENT0("gpu", "OpenSharedTexture"); - if (!d3d_utils::OpenSharedTexture(present_thread_->device(), - surface_handle, - size, - source_texture_.Receive())) { - LOG(ERROR) << "Failed to open shared texture"; - return; - } - } - - base::win::ScopedComPtr<IDirect3DSurface9> source_surface; - hr = source_texture_->GetSurfaceLevel(0, source_surface.Receive()); - if (FAILED(hr)) { - TRACE_EVENT0("gpu", "EarlyOut_NoSurfaceLevel"); - LOG(ERROR) << "Failed to get source surface"; - return; - } - - base::win::ScopedComPtr<IDirect3DSurface9> dest_surface; - hr = swap_chain_->GetBackBuffer(0, - D3DBACKBUFFER_TYPE_MONO, - dest_surface.Receive()); - if (FAILED(hr)) { - TRACE_EVENT0("gpu", "EarlyOut_NoBackbuffer"); - LOG(ERROR) << "Failed to get back buffer"; - return; - } - - RECT rect = { - 0, 0, - size.width(), size.height() - }; - - { - TRACE_EVENT0("gpu", "Copy"); - - // Copy while flipping the source texture on the vertical axis. - bool result = present_thread_->surface_transformer()->CopyInverted( - source_texture_, dest_surface, size); - if (!result) { - LOG(ERROR) << "Failed to copy shared texture"; - return; - } - } - - hr = present_thread_->query()->Issue(D3DISSUE_END); - if (FAILED(hr)) { - LOG(ERROR) << "Failed to issue query"; - return; - } - - present_size_ = size; - - // If it is expected that Direct3D cannot be used reliably because the window - // is resizing, fall back to presenting with GDI. - if (CheckDirect3DWillWork()) { - TRACE_EVENT0("gpu", "PresentD3D"); - - hr = swap_chain_->Present(&rect, &rect, window_, NULL, 0); - - if (FAILED(hr)) { - if (present_thread_->IsDeviceLost()) - present_thread_->ResetDevice(); - return; - } - } else { - HDC dc = GetDC(window_); - PresentWithGDI(dc); - ReleaseDC(window_, dc); - } - - latency_info_.AddLatencyNumber( - ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0); - - hidden_ = false; - - D3DDISPLAYMODE display_mode; - hr = present_thread_->device()->GetDisplayMode(0, &display_mode); - if (FAILED(hr)) { - LOG(ERROR) << "Failed to get display mode"; - return; - } - - D3DRASTER_STATUS raster_status; - hr = swap_chain_->GetRasterStatus(&raster_status); - if (FAILED(hr)) { - LOG(ERROR) << "Failed to get raster status"; - return; - } - - UMA_HISTOGRAM_CUSTOM_COUNTS("GPU.AcceleratedSurfaceRefreshRate", - display_mode.RefreshRate, 0, 121, 122); - - // I can't figure out how to determine how many scanlines are in the - // vertical blank so clamp it such that scanline / height <= 1. - int clamped_scanline = std::min(raster_status.ScanLine, display_mode.Height); - - // The Internet says that on some GPUs, the scanline is not available - // while in the vertical blank. - if (raster_status.InVBlank) - clamped_scanline = display_mode.Height; - - // Figure out approximately how far back in time the last vsync was based on - // the ratio of the raster scanline to the display height. - base::TimeTicks last_vsync_time; - base::TimeDelta refresh_period; - - if (display_mode.Height) { - refresh_period = base::TimeDelta::FromMicroseconds( - 1000000 / display_mode.RefreshRate); - // If FrameTime is not high resolution, we use a timebase of zero to avoid - // introducing jitter into our frame start times. - if (gfx::FrameTime::TimestampsAreHighRes()) { - base::TimeTicks current_time = gfx::FrameTime::Now(); - last_vsync_time = current_time - - base::TimeDelta::FromMilliseconds((clamped_scanline * 1000) / - (display_mode.RefreshRate * display_mode.Height)); - } - } - - // Wait for the StretchRect to complete before notifying the GPU process - // that it is safe to write to its backing store again. - { - TRACE_EVENT0("gpu", "spin"); - - do { - hr = present_thread_->query()->GetData(NULL, 0, D3DGETDATA_FLUSH); - if (hr == S_FALSE) { - Sleep(1); - - if (present_thread_->IsDeviceLost()) { - present_thread_->ResetDevice(); - return; - } - } - } while (hr == S_FALSE); - } - - scoped_completion_runner.Release(); - completion_task.Run(true, last_vsync_time, refresh_period, latency_info_); - latency_info_.Clear(); -} - -void AcceleratedPresenter::DoSuspend() { - base::AutoLock locked(*present_thread_->lock()); - swap_chain_ = NULL; -} - -void AcceleratedPresenter::DoReleaseSurface() { - base::AutoLock locked(*present_thread_->lock()); - present_thread_->InitDevice(); - source_texture_.Release(); -} - -void AcceleratedPresenter::PresentWithGDI(HDC dc) { - TRACE_EVENT0("gpu", "PresentWithGDI"); - - if (!present_thread_->device()) { - LOG(ERROR) << "No device"; - return; - } - - if (!swap_chain_) { - LOG(ERROR) << "No swap chain"; - return; - } - - base::win::ScopedComPtr<IDirect3DTexture9> system_texture; - { - TRACE_EVENT0("gpu", "CreateSystemTexture"); - HRESULT hr = present_thread_->device()->CreateTexture( - quantized_size_.width(), - quantized_size_.height(), - 1, - 0, - D3DFMT_A8R8G8B8, - D3DPOOL_SYSTEMMEM, - system_texture.Receive(), - NULL); - if (FAILED(hr)) { - LOG(ERROR) << "Failed to create system memory texture"; - return; - } - } - - base::win::ScopedComPtr<IDirect3DSurface9> system_surface; - HRESULT hr = system_texture->GetSurfaceLevel(0, system_surface.Receive()); - DCHECK(SUCCEEDED(hr)); - - base::win::ScopedComPtr<IDirect3DSurface9> back_buffer; - hr = swap_chain_->GetBackBuffer(0, - D3DBACKBUFFER_TYPE_MONO, - back_buffer.Receive()); - DCHECK(SUCCEEDED(hr)); - - { - TRACE_EVENT0("gpu", "GetRenderTargetData"); - hr = present_thread_->device()->GetRenderTargetData(back_buffer, - system_surface); - - if (FAILED(hr)) { - if (present_thread_->IsDeviceLost()) { - present_thread_->message_loop()->PostTask( - FROM_HERE, - base::Bind(&PresentThread::LockAndResetDevice, present_thread_)); - } - return; - } - - DCHECK(SUCCEEDED(hr)); - } - - D3DLOCKED_RECT locked_surface; - hr = system_surface->LockRect(&locked_surface, NULL, D3DLOCK_READONLY); - DCHECK(SUCCEEDED(hr)); - - BITMAPINFO bitmap_info = { - { - sizeof(BITMAPINFOHEADER), - quantized_size_.width(), - -quantized_size_.height(), - 1, // planes - 32, // bitcount - BI_RGB - }, - { - {0, 0, 0, 0} - } - }; - - { - TRACE_EVENT0("gpu", "StretchDIBits"); - StretchDIBits(dc, - 0, 0, - present_size_.width(), - present_size_.height(), - 0, 0, - present_size_.width(), - present_size_.height(), - locked_surface.pBits, - &bitmap_info, - DIB_RGB_COLORS, - SRCCOPY); - } - - system_surface->UnlockRect(); -} - -gfx::Size AcceleratedPresenter::GetWindowSize() { - RECT rect; - GetClientRect(window_, &rect); - return gfx::Rect(rect).size(); -} - -bool AcceleratedPresenter::CheckDirect3DWillWork() { - // On a composited desktop, when the screen saver or logon screen are - // active, D3D presents never make it to the window but GDI presents - // do. If the session is locked GDI presents can be avoided since - // the window gets a message on unlock and forces a repaint. - if (!is_session_locked_ && ui::win::IsAeroGlassEnabled()) { - // Failure to open the input desktop is a sign of running with a non-default - // desktop. - HDESK input_desktop = ::OpenInputDesktop(0, 0, GENERIC_READ); - if (!input_desktop) - return false; - ::CloseDesktop(input_desktop); - } - - gfx::Size window_size = GetWindowSize(); - if (window_size != last_window_size_ && last_window_size_.GetArea() != 0) { - last_window_size_ = window_size; - last_window_resize_time_ = base::Time::Now(); - return false; - } - - if (do_present_with_GDI_ && hidden_) { - if (DoFirstShowPresentWithGDI()) - do_present_with_GDI_ = false; - - return false; - } - - return base::Time::Now() - last_window_resize_time_ > - base::TimeDelta::FromMilliseconds(100); -} - -AcceleratedSurface::AcceleratedSurface(gfx::PluginWindowHandle window) - : presenter_(g_accelerated_presenter_map.Pointer()->CreatePresenter( - window)) { -} - -AcceleratedSurface::~AcceleratedSurface() { - g_accelerated_presenter_map.Pointer()->RemovePresenter(presenter_); - presenter_->Invalidate(); -} - -void AcceleratedSurface::Present(HDC dc) { - presenter_->Present(dc); -} - -bool AcceleratedSurface::IsReadyForCopy() const { - return !!presenter_ && presenter_->IsSwapChainInitialized(); -} - - -void AcceleratedSurface::AsyncCopyTo( - const gfx::Rect& src_subrect, - const gfx::Size& dst_size, - const base::Callback<void(bool, const SkBitmap&)>& callback) { - presenter_->AsyncCopyTo(src_subrect, dst_size, callback); -} - -void AcceleratedSurface::AsyncCopyToVideoFrame( - const gfx::Rect& src_subrect, - const scoped_refptr<media::VideoFrame>& target, - const base::Callback<void(bool)>& callback) { - presenter_->AsyncCopyToVideoFrame(src_subrect, target, callback); -} - -void AcceleratedSurface::Suspend() { - presenter_->Suspend(); -} - -void AcceleratedSurface::WasHidden() { - presenter_->WasHidden(); -} - -void AcceleratedSurface::SetIsSessionLocked(bool locked) { - presenter_->SetIsSessionLocked(locked); -} |