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

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

Issue 8060045: Use shared D3D9 texture to transport the compositor's backing buffer to the browser... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years, 2 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
Index: ui/gfx/surface/accelerated_surface_win.cc
===================================================================
--- ui/gfx/surface/accelerated_surface_win.cc (revision 0)
+++ ui/gfx/surface/accelerated_surface_win.cc (revision 0)
@@ -0,0 +1,335 @@
+// Copyright (c) 2011 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 "base/bind.h"
+#include "base/callback.h"
+#include "base/lazy_instance.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/stringprintf.h"
+#include "base/threading/thread.h"
+#include "base/tracked_objects.h"
+#include "base/win/wrapped_window_proc.h"
+#include "ipc/ipc_message.h"
+#include "ui/base/win/hwnd_util.h"
+
+#pragma comment(lib, "d3d9.lib")
+
+namespace {
+
+class PresentThreadPool {
+ public:
+ static const int kNumPresentThreads = 4;
+
+ PresentThreadPool();
+
+ int NextThread();
+
+ void PostTask(int thread,
+ const tracked_objects::Location& from_here,
+ base::Closure task);
+ private:
+ int next_thread_;
+ scoped_ptr<base::Thread> present_threads_[kNumPresentThreads];
+
+ DISALLOW_COPY_AND_ASSIGN(PresentThreadPool);
+};
+
+base::LazyInstance<PresentThreadPool>
+ g_present_thread_pool(base::LINKER_INITIALIZED);
+
+PresentThreadPool::PresentThreadPool() : next_thread_(0) {
+ for (int i = 0; i < kNumPresentThreads; ++i) {
+ present_threads_[i].reset(new base::Thread(
+ base::StringPrintf("PresentThread #%d", i).c_str()));
+ present_threads_[i]->Start();
+ }
+}
+
+int PresentThreadPool::NextThread() {
+ next_thread_ = (next_thread_ + 1) % kNumPresentThreads;
+ return next_thread_;
+}
+
+void PresentThreadPool::PostTask(int thread,
+ const tracked_objects::Location& from_here,
+ base::Closure task) {
+ DCHECK_GE(thread, 0);
+ DCHECK_LT(thread, kNumPresentThreads);
+
+ present_threads_[thread]->message_loop()->PostTask(from_here, task);
+}
+
+} // namespace anonymous
+
+AcceleratedSurface::AcceleratedSurface(HWND parent)
+ : thread_affinity_(g_present_thread_pool.Pointer()->NextThread()),
+ window_(parent),
+ num_pending_resizes_(0) {
+}
+
+AcceleratedSurface::~AcceleratedSurface() {
+ // Destroy should have been called prior to the last reference going away.
+ DCHECK(!device_);
+}
+
+void AcceleratedSurface::Initialize() {
+ g_present_thread_pool.Pointer()->PostTask(
+ thread_affinity_,
+ FROM_HERE,
+ base::Bind(&AcceleratedSurface::DoInitialize, this));
+}
+
+void AcceleratedSurface::Destroy() {
+ g_present_thread_pool.Pointer()->PostTask(
+ thread_affinity_,
+ FROM_HERE,
+ base::Bind(&AcceleratedSurface::DoDestroy,
+ this,
+ MessageLoop::current()->message_loop_proxy()));
+}
+
+void AcceleratedSurface::AsyncPresentAndAcknowledge(
+ const gfx::Size& size,
+ int64 surface_id,
+ base::Closure completion_task) {
+ 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));
+
+ if (pending_size_ != quantized_size) {
+ pending_size_ = quantized_size;
+ base::AtomicRefCountInc(&num_pending_resizes_);
+
+ g_present_thread_pool.Pointer()->PostTask(
+ thread_affinity_,
+ FROM_HERE,
+ base::Bind(&AcceleratedSurface::DoResize, this, quantized_size));
+ }
+
+ // This might unnecessarily post to the thread with which the swap chain has
+ // affinity. This will only result in potentially delaying the present.
+ g_present_thread_pool.Pointer()->PostTask(
+ num_pending_resizes_ ?
+ thread_affinity_ : g_present_thread_pool.Pointer()->NextThread(),
+ FROM_HERE,
+ base::Bind(&AcceleratedSurface::DoPresentAndAcknowledge,
+ this,
+ size,
+ surface_id,
+ completion_task));
+}
+
+void AcceleratedSurface::Present() {
+ HRESULT hr;
+
+ base::AutoLock locked(lock_);
+
+ if (!device_)
+ return;
+
+ RECT rect;
+ if (!GetClientRect(window_, &rect))
+ return;
+
+ hr = device_->PresentEx(&rect,
+ &rect,
+ NULL,
+ NULL,
+ D3DPRESENT_INTERVAL_IMMEDIATE);
+ if (FAILED(hr))
+ return;
+
+ hr = query_->Issue(D3DISSUE_END);
+ if (FAILED(hr))
+ return;
+
+ do {
+ hr = query_->GetData(NULL, 0, D3DGETDATA_FLUSH);
+
+ if (hr == S_FALSE)
+ Sleep(0);
+ } while (hr == S_FALSE);
+}
+
+void AcceleratedSurface::DoInitialize() {
+ HRESULT hr;
+
+ base::win::ScopedComPtr<IDirect3D9Ex> d3d;
+ hr = Direct3DCreate9Ex(D3D_SDK_VERSION, d3d.Receive());
+ if (FAILED(hr))
+ return;
+
+ 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 = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
+ parameters.SwapEffect = D3DSWAPEFFECT_COPY;
+
+ hr = d3d->CreateDeviceEx(
+ D3DADAPTER_DEFAULT,
+ D3DDEVTYPE_HAL,
+ window_,
+ D3DCREATE_FPU_PRESERVE | D3DCREATE_SOFTWARE_VERTEXPROCESSING |
+ D3DCREATE_MULTITHREADED,
+ &parameters,
+ NULL,
+ device_.Receive());
+ if (FAILED(hr))
+ return;
+
+ hr = device_->CreateQuery(D3DQUERYTYPE_EVENT, query_.Receive());
+ if (FAILED(hr)) {
+ device_ = NULL;
+ return;
+ }
+
+ return;
+}
+
+void AcceleratedSurface::DoDestroy(
+ const scoped_refptr<base::MessageLoopProxy>& ui_message_loop) {
+ base::AutoLock locked(lock_);
+
+ device_ = NULL;
+ query_ = NULL;
+}
+
+void AcceleratedSurface::DoResize(const gfx::Size& size) {
+ HRESULT hr;
+
+ base::AtomicRefCountDec(&num_pending_resizes_);
+
+ D3DPRESENT_PARAMETERS parameters = { 0 };
+ parameters.BackBufferWidth = size.width();
+ parameters.BackBufferHeight = size.height();
+ parameters.BackBufferCount = 1;
+ parameters.BackBufferFormat = D3DFMT_A8R8G8B8;
+ parameters.hDeviceWindow = window_;
+ parameters.Windowed = TRUE;
+ parameters.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
+ parameters.SwapEffect = D3DSWAPEFFECT_COPY;
+
+ hr = device_->ResetEx(&parameters, NULL);
+ if (FAILED(hr))
+ return;
+
+ size_ = size;
+
+ device_->Clear(0, NULL, D3DCLEAR_TARGET, 0xFFFFFFFF, 0, 0);
+}
+
+void AcceleratedSurface::DoPresentAndAcknowledge(
+ const gfx::Size& size,
+ int64 surface_id,
+ base::Closure completion_task) {
+ HRESULT hr;
+
+ base::AutoLock locked(lock_);
+
+ if (!window_)
+ return;
+
+ HANDLE handle = reinterpret_cast<HANDLE>(surface_id);
+ if (!handle)
+ return;
+
+ base::win::ScopedComPtr<IDirect3DTexture9> source_texture;
+ hr = 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 = device_->GetRenderTarget(0, dest_surface.Receive());
+ if (FAILED(hr))
+ return;
+
+ RECT rect = {
+ 0, 0,
+ size.width(), size.height()
+ };
+
+ hr = device_->StretchRect(source_surface,
+ &rect,
+ dest_surface,
+ &rect,
+ D3DTEXF_NONE);
+ if (FAILED(hr))
+ return;
+
+ hr = query_->Issue(D3DISSUE_END);
+ if (FAILED(hr))
+ return;
+
+ // Flush so the StretchRect can be processed by the GPU while the window is
+ // being resized.
+ 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);
+
+ // Wait for the StretchRect to complete before notifying the GPU process
+ // that it is safe to write to its backing store again.
+ do {
+ hr = query_->GetData(NULL, 0, D3DGETDATA_FLUSH);
+
+ if (hr == S_FALSE)
+ Sleep(0);
+ } while (hr == S_FALSE);
+
+ if (!completion_task.is_null())
+ completion_task.Run();
+
+ hr = device_->Present(&rect, &rect, NULL, NULL);
+ if (FAILED(hr))
+ return;
+}
+
+LRESULT CALLBACK AcceleratedSurface::ChildWndProc(HWND window,
+ unsigned int message,
+ WPARAM wparam,
+ LPARAM lparam) {
+ AcceleratedSurface* self = static_cast<AcceleratedSurface*>(
+ ui::GetWindowUserData(window));
+ switch (message) {
+ case WM_PAINT: {
+ PAINTSTRUCT paint_struct;
+ if (BeginPaint(window, &paint_struct)) {
+ self->Present();
+ EndPaint(window, &paint_struct);
+ }
+ return 0;
+ }
+ case WM_ERASEBKGND:
+ return 1;
+ }
+
+ return DefWindowProc(window, message, wparam, lparam);
+}
Property changes on: ui\gfx\surface\accelerated_surface_win.cc
___________________________________________________________________
Added: svn:eol-style
+ LF

Powered by Google App Engine
This is Rietveld 408576698