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

Unified Diff: ui/gfx/surface/accelerated_surface_win.cc

Issue 10351002: ui: Move surface/ directory out of gfx/, up to ui/. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix gpu DEPS Created 8 years, 8 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « ui/gfx/surface/accelerated_surface_win.h ('k') | ui/gfx/surface/io_surface_support_mac.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ui/gfx/surface/accelerated_surface_win.cc
diff --git a/ui/gfx/surface/accelerated_surface_win.cc b/ui/gfx/surface/accelerated_surface_win.cc
deleted file mode 100644
index c6d18d9b98835aa646eac1a530b97f96fffd9330..0000000000000000000000000000000000000000
--- a/ui/gfx/surface/accelerated_surface_win.cc
+++ /dev/null
@@ -1,683 +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/gfx/surface/accelerated_surface_win.h"
-
-#include <windows.h>
-#include <algorithm>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/callback.h"
-#include "base/command_line.h"
-#include "base/string_number_conversions.h"
-#include "base/time.h"
-#include "base/debug/trace_event.h"
-#include "base/file_path.h"
-#include "base/lazy_instance.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/scoped_native_library.h"
-#include "base/stringprintf.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/threading/thread.h"
-#include "base/threading/thread_restrictions.h"
-#include "base/tracked_objects.h"
-#include "base/win/wrapped_window_proc.h"
-#include "ui/base/win/hwnd_util.h"
-#include "ui/gfx/gl/gl_switches.h"
-
-namespace {
-
-typedef HRESULT (WINAPI *Direct3DCreate9ExFunc)(UINT sdk_version,
- IDirect3D9Ex **d3d);
-
-const wchar_t kD3D9ModuleName[] = L"d3d9.dll";
-const char kCreate3D9DeviceExName[] = "Direct3DCreate9Ex";
-
-UINT GetPresentationInterval() {
- if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableGpuVsync))
- return D3DPRESENT_INTERVAL_IMMEDIATE;
- else
- return D3DPRESENT_INTERVAL_ONE;
-}
-
-// Calculate the number necessary to transform |source_size| into |dest_size|
-// by repeating downsampling of the image of |source_size| by a factor no more
-// than 2.
-int GetResampleCount(const gfx::Size& source_size, const gfx::Size& dest_size) {
- int width_count = 0;
- int width = source_size.width();
- while (width > dest_size.width()) {
- ++width_count;
- width >>= 1;
- }
- int height_count = 0;
- int height = source_size.height();
- while (height > dest_size.height()) {
- ++height_count;
- height >>= 1;
- }
- return std::max(width_count, height_count);
-}
-
-// Returns half the size of |size| no smaller than |min_size|.
-gfx::Size GetHalfSizeNoLessThan(const gfx::Size& size,
- const gfx::Size& min_size) {
- return gfx::Size(std::max(min_size.width(), size.width() / 2),
- std::max(min_size.height(), size.height() / 2));
-}
-
-bool CreateTemporarySurface(IDirect3DDevice9* device,
- const gfx::Size& size,
- IDirect3DSurface9** surface) {
- HRESULT hr = device->CreateRenderTarget(
- size.width(),
- size.height(),
- D3DFMT_A8R8G8B8,
- D3DMULTISAMPLE_NONE,
- 0,
- TRUE,
- surface,
- NULL);
- return SUCCEEDED(hr);
-}
-
-} // namespace anonymous
-
-// 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:
- explicit PresentThread(const char* name);
-
- IDirect3DDevice9Ex* device() { return device_.get(); }
- IDirect3DQuery9* query() { return query_.get(); }
-
- void InitDevice();
- void ResetDevice();
-
- protected:
- virtual void CleanUp();
-
- private:
- friend class base::RefCountedThreadSafe<PresentThread>;
-
- ~PresentThread();
-
- base::ScopedNativeLibrary d3d_module_;
- 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_;
-
- 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();
-
- private:
- int next_thread_;
- scoped_refptr<PresentThread> present_threads_[kNumPresentThreads];
-
- 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::NativeWindow window);
- void RemovePresenter(const scoped_refptr<AcceleratedPresenter>& presenter);
- scoped_refptr<AcceleratedPresenter> GetPresenter(gfx::NativeWindow window);
- private:
- base::Lock lock_;
- typedef std::map<gfx::NativeWindow, AcceleratedPresenter*> PresenterMap;
- PresenterMap presenters_;
- 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) : base::Thread(name) {
-}
-
-void PresentThread::InitDevice() {
- if (device_)
- return;
-
- TRACE_EVENT0("surface", "PresentThread::Init");
- d3d_module_.Reset(base::LoadNativeLibrary(FilePath(kD3D9ModuleName), NULL));
- ResetDevice();
-}
-
-void PresentThread::ResetDevice() {
- TRACE_EVENT0("surface", "PresentThread::ResetDevice");
-
- // This will crash some Intel drivers but we can't render anything without
- // reseting the device, which would be disappointing.
- query_ = NULL;
- device_ = NULL;
-
- Direct3DCreate9ExFunc create_func = reinterpret_cast<Direct3DCreate9ExFunc>(
- d3d_module_.GetFunctionPointer(kCreate3D9DeviceExName));
- if (!create_func)
- return;
-
- base::win::ScopedComPtr<IDirect3D9Ex> d3d;
- HRESULT hr = create_func(D3D_SDK_VERSION, d3d.Receive());
- if (FAILED(hr))
- return;
-
- // Any old window will do to create the device. In practice the window to
- // present to is an argument to IDirect3DDevice9::Present.
- HWND window = GetShellWindow();
-
- D3DPRESENT_PARAMETERS parameters = { 0 };
- parameters.BackBufferWidth = 1;
- parameters.BackBufferHeight = 1;
- parameters.BackBufferCount = 1;
- parameters.BackBufferFormat = D3DFMT_A8R8G8B8;
- parameters.hDeviceWindow = window;
- parameters.Windowed = TRUE;
- parameters.Flags = 0;
- parameters.PresentationInterval = GetPresentationInterval();
- parameters.SwapEffect = D3DSWAPEFFECT_COPY;
-
- hr = d3d->CreateDeviceEx(
- D3DADAPTER_DEFAULT,
- D3DDEVTYPE_HAL,
- window,
- D3DCREATE_FPU_PRESERVE | D3DCREATE_SOFTWARE_VERTEXPROCESSING |
- D3DCREATE_DISABLE_PSGP_THREADING | D3DCREATE_MULTITHREADED,
- &parameters,
- NULL,
- device_.Receive());
- if (FAILED(hr))
- return;
-
- hr = device_->CreateQuery(D3DQUERYTYPE_EVENT, query_.Receive());
- if (FAILED(hr))
- device_ = NULL;
-}
-
-void PresentThread::CleanUp() {
- // The D3D device and query are leaked because destroying the associated D3D
- // query crashes some Intel drivers.
- device_.Detach();
- query_.Detach();
-}
-
-PresentThread::~PresentThread() {
- Stop();
-}
-
-PresentThreadPool::PresentThreadPool() : next_thread_(0) {
- // Do this in the constructor so present_threads_ is initialized before any
- // other thread sees it. See LazyInstance documentation.
- for (int i = 0; i < kNumPresentThreads; ++i) {
- present_threads_[i] = new PresentThread(
- base::StringPrintf("PresentThread #%d", i).c_str());
- present_threads_[i]->Start();
- }
-}
-
-PresentThread* PresentThreadPool::NextThread() {
- next_thread_ = (next_thread_ + 1) % kNumPresentThreads;
- return present_threads_[next_thread_].get();
-}
-
-AcceleratedPresenterMap::AcceleratedPresenterMap() {
-}
-
-scoped_refptr<AcceleratedPresenter> AcceleratedPresenterMap::CreatePresenter(
- gfx::NativeWindow 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::NativeWindow window) {
- base::AutoLock locked(lock_);
- PresenterMap::iterator it = presenters_.find(window);
- if (it == presenters_.end())
- return scoped_refptr<AcceleratedPresenter>();
-
- return it->second;
-}
-
-AcceleratedPresenter::AcceleratedPresenter(gfx::NativeWindow window)
- : present_thread_(g_present_thread_pool.Pointer()->NextThread()),
- window_(window),
- event_(false, false) {
-}
-
-scoped_refptr<AcceleratedPresenter> AcceleratedPresenter::GetForWindow(
- gfx::NativeWindow window) {
- return g_accelerated_presenter_map.Pointer()->GetPresenter(window);
-}
-
-void AcceleratedPresenter::AsyncPresentAndAcknowledge(
- const gfx::Size& size,
- int64 surface_handle,
- const base::Callback<void(bool)>& completion_task) {
- if (!surface_handle) {
- completion_task.Run(true);
- return;
- }
-
- present_thread_->message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&AcceleratedPresenter::DoPresentAndAcknowledge,
- this,
- size,
- surface_handle,
- completion_task));
-}
-
-bool AcceleratedPresenter::Present() {
- TRACE_EVENT0("surface", "Present");
-
- bool result;
-
- present_thread_->message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&AcceleratedPresenter::DoPresent,
- this,
- &result));
- // http://crbug.com/125391
- base::ThreadRestrictions::ScopedAllowWait allow_wait;
- event_.Wait();
- return result;
-}
-
-void AcceleratedPresenter::DoPresent(bool* result)
-{
- *result = DoRealPresent();
- event_.Signal();
-}
-
-bool AcceleratedPresenter::DoRealPresent()
-{
- TRACE_EVENT0("surface", "DoRealPresent");
- HRESULT hr;
-
- base::AutoLock locked(lock_);
-
- // Signal the caller to recomposite if the presenter has been suspended or no
- // surface has ever been presented.
- if (!swap_chain_)
- return false;
-
- // If invalidated, do nothing. The window is gone.
- if (!window_)
- return true;
-
- RECT rect = {
- 0, 0,
- size_.width(), size_.height()
- };
-
- {
- TRACE_EVENT0("surface", "PresentEx");
- hr = swap_chain_->Present(&rect,
- &rect,
- window_,
- NULL,
- D3DPRESENT_INTERVAL_IMMEDIATE);
- if (FAILED(hr))
- return false;
- }
-
- return true;
-}
-
-bool AcceleratedPresenter::CopyTo(const gfx::Size& size, void* buf) {
- base::AutoLock locked(lock_);
-
- if (!swap_chain_)
- return false;
-
- 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;
-
- // Set up intermediate buffers needed for downsampling.
- const int resample_count =
- GetResampleCount(gfx::Size(desc.Width, desc.Height), size);
- base::win::ScopedComPtr<IDirect3DSurface9> final_surface;
- base::win::ScopedComPtr<IDirect3DSurface9> temp_buffer[2];
- if (resample_count == 0)
- final_surface = back_buffer;
- if (resample_count > 0) {
- if (!CreateTemporarySurface(present_thread_->device(),
- size,
- final_surface.Receive()))
- return false;
- }
- const gfx::Size half_size = GetHalfSizeNoLessThan(back_buffer_size, size);
- if (resample_count > 1) {
- if (!CreateTemporarySurface(present_thread_->device(),
- half_size,
- temp_buffer[0].Receive()))
- return false;
- }
- if (resample_count > 2) {
- const gfx::Size quarter_size = GetHalfSizeNoLessThan(half_size, size);
- if (!CreateTemporarySurface(present_thread_->device(),
- quarter_size,
- temp_buffer[1].Receive()))
- return false;
- }
-
- // Repeat downsampling the surface until its size becomes identical to
- // |size|. We keep the factor of each downsampling no more than two because
- // using a factor more than two can introduce aliasing.
- gfx::Size read_size = back_buffer_size;
- gfx::Size write_size = half_size;
- int read_buffer_index = 1;
- int write_buffer_index = 0;
- for (int i = 0; i < resample_count; ++i) {
- base::win::ScopedComPtr<IDirect3DSurface9> read_buffer =
- (i == 0) ? back_buffer : temp_buffer[read_buffer_index];
- base::win::ScopedComPtr<IDirect3DSurface9> write_buffer =
- (i == resample_count - 1) ? final_surface :
- temp_buffer[write_buffer_index];
- RECT read_rect = {0, 0, read_size.width(), read_size.height()};
- RECT write_rect = {0, 0, write_size.width(), write_size.height()};
- hr = present_thread_->device()->StretchRect(read_buffer,
- &read_rect,
- write_buffer,
- &write_rect,
- D3DTEXF_LINEAR);
- if (FAILED(hr))
- return false;
- read_size = write_size;
- write_size = GetHalfSizeNoLessThan(write_size, size);
- std::swap(read_buffer_index, write_buffer_index);
- }
-
- DCHECK(size == read_size);
-
- base::win::ScopedComPtr<IDirect3DSurface9> temp_surface;
- HANDLE handle = reinterpret_cast<HANDLE>(buf);
- hr = present_thread_->device()->CreateOffscreenPlainSurface(
- size.width(),
- size.height(),
- D3DFMT_A8R8G8B8,
- D3DPOOL_SYSTEMMEM,
- temp_surface.Receive(),
- &handle);
- if (FAILED(hr))
- return false;
-
- // Copy the data in the temporary buffer to the surface backed by |buf|.
- hr = present_thread_->device()->GetRenderTargetData(final_surface,
- temp_surface);
- if (FAILED(hr))
- return false;
-
- return true;
-}
-
-void AcceleratedPresenter::Suspend() {
- present_thread_->message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&AcceleratedPresenter::DoSuspend,
- this));
-}
-
-void AcceleratedPresenter::ReleaseSurface() {
- present_thread_->message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&AcceleratedPresenter::DoReleaseSurface,
- this));
-}
-
-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(lock_);
- window_ = NULL;
-}
-
-AcceleratedPresenter::~AcceleratedPresenter() {
-}
-
-static base::TimeDelta GetSwapDelay() {
- CommandLine* cmd_line = CommandLine::ForCurrentProcess();
- int delay = 0;
- if (cmd_line->HasSwitch(switches::kGpuSwapDelay)) {
- base::StringToInt(cmd_line->GetSwitchValueNative(
- switches::kGpuSwapDelay).c_str(), &delay);
- }
- return base::TimeDelta::FromMilliseconds(delay);
-}
-
-void AcceleratedPresenter::DoPresentAndAcknowledge(
- const gfx::Size& size,
- int64 surface_handle,
- const base::Callback<void(bool)>& completion_task) {
- TRACE_EVENT1(
- "surface", "DoPresentAndAcknowledge", "surface_handle", surface_handle);
-
- HRESULT hr;
-
- base::AutoLock locked(lock_);
-
- // Initialize the device lazily since calling Direct3D can crash bots.
- present_thread_->InitDevice();
-
- if (!present_thread_->device()) {
- if (!completion_task.is_null())
- completion_task.Run(false);
- return;
- }
-
- // Ensure the task is always run and while the lock is taken.
- base::ScopedClosureRunner scoped_completion_runner(base::Bind(completion_task,
- true));
-
- // If invalidated, do nothing, the window is gone.
- if (!window_)
- return;
-
- // 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_ || size_ != quantized_size) {
- TRACE_EVENT0("surface", "CreateAdditionalSwapChain");
- 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 = GetShellWindow();
- 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))
- return;
- }
-
- if (!source_texture_.get()) {
- TRACE_EVENT0("surface", "CreateTexture");
- HANDLE handle = reinterpret_cast<HANDLE>(surface_handle);
- hr = present_thread_->device()->CreateTexture(size.width(),
- size.height(),
- 1,
- D3DUSAGE_RENDERTARGET,
- D3DFMT_A8R8G8B8,
- D3DPOOL_DEFAULT,
- source_texture_.Receive(),
- &handle);
- if (FAILED(hr))
- return;
- }
-
- base::win::ScopedComPtr<IDirect3DSurface9> source_surface;
- hr = source_texture_->GetSurfaceLevel(0, source_surface.Receive());
- if (FAILED(hr))
- return;
-
- base::win::ScopedComPtr<IDirect3DSurface9> dest_surface;
- hr = swap_chain_->GetBackBuffer(0,
- D3DBACKBUFFER_TYPE_MONO,
- dest_surface.Receive());
- if (FAILED(hr))
- return;
-
- RECT rect = {
- 0, 0,
- size.width(), size.height()
- };
-
- {
- TRACE_EVENT0("surface", "StretchRect");
- hr = present_thread_->device()->StretchRect(source_surface,
- &rect,
- dest_surface,
- &rect,
- D3DTEXF_NONE);
- if (FAILED(hr))
- return;
- }
-
- hr = present_thread_->query()->Issue(D3DISSUE_END);
- if (FAILED(hr))
- return;
-
- // Flush so the StretchRect can be processed by the GPU while the window is
- // being resized.
- present_thread_->query()->GetData(NULL, 0, D3DGETDATA_FLUSH);
-
- ::SetWindowPos(
- window_,
- NULL,
- 0, 0,
- size.width(), size.height(),
- SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOMOVE |SWP_NOOWNERZORDER |
- SWP_NOREDRAW | SWP_NOSENDCHANGING | SWP_NOSENDCHANGING |
- SWP_ASYNCWINDOWPOS | SWP_NOZORDER);
-
- // Wait for the StretchRect to complete before notifying the GPU process
- // that it is safe to write to its backing store again.
- {
- TRACE_EVENT0("surface", "spin");
- do {
- hr = present_thread_->query()->GetData(NULL, 0, D3DGETDATA_FLUSH);
-
- if (hr == S_FALSE)
- Sleep(1);
- } while (hr == S_FALSE);
- }
-
- static const base::TimeDelta swap_delay = GetSwapDelay();
- if (swap_delay.ToInternalValue())
- base::PlatformThread::Sleep(swap_delay);
-
- {
- TRACE_EVENT0("surface", "Present");
- hr = swap_chain_->Present(&rect, &rect, window_, NULL, 0);
- if (FAILED(hr) &&
- FAILED(present_thread_->device()->CheckDeviceState(window_))) {
- present_thread_->ResetDevice();
- }
- }
-}
-
-void AcceleratedPresenter::DoSuspend() {
- base::AutoLock locked(lock_);
- swap_chain_ = NULL;
-}
-
-void AcceleratedPresenter::DoReleaseSurface() {
- base::AutoLock locked(lock_);
- source_texture_.Release();
-}
-
-AcceleratedSurface::AcceleratedSurface(gfx::NativeWindow window)
- : presenter_(g_accelerated_presenter_map.Pointer()->CreatePresenter(
- window)) {
-}
-
-AcceleratedSurface::~AcceleratedSurface() {
- g_accelerated_presenter_map.Pointer()->RemovePresenter(presenter_);
- presenter_->Invalidate();
-}
-
-bool AcceleratedSurface::Present() {
- return presenter_->Present();
-}
-
-bool AcceleratedSurface::CopyTo(const gfx::Size& size, void* buf) {
- return presenter_->CopyTo(size, buf);
-}
-
-void AcceleratedSurface::Suspend() {
- presenter_->Suspend();
-}
« no previous file with comments | « ui/gfx/surface/accelerated_surface_win.h ('k') | ui/gfx/surface/io_surface_support_mac.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698