summaryrefslogtreecommitdiffstats
path: root/chromium/ui/surface/accelerated_surface_win.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/ui/surface/accelerated_surface_win.cc')
-rw-r--r--chromium/ui/surface/accelerated_surface_win.cc1108
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(
- &parameters,
- 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);
-}