Index: ui/surface/accelerated_surface_win.cc |
diff --git a/ui/surface/accelerated_surface_win.cc b/ui/surface/accelerated_surface_win.cc |
index 0fa247d7210c8dcfa3307cc7c14e1c95a367fa1d..0ac8f1c841c069f80fec47d895820472aab746e2 100644 |
--- a/ui/surface/accelerated_surface_win.cc |
+++ b/ui/surface/accelerated_surface_win.cc |
@@ -8,7 +8,6 @@ |
#include <windows.h> |
#include <algorithm> |
-#include "accelerated_surface_win_hlsl_compiled.h" |
#include "base/bind.h" |
#include "base/bind_helpers.h" |
#include "base/callback.h" |
@@ -30,33 +29,15 @@ |
#include "ui/base/win/hwnd_util.h" |
#include "ui/gfx/rect.h" |
#include "ui/gl/gl_switches.h" |
+#include "ui/surface/accelerated_surface_transformer_win.h" |
+#include "ui/surface/d3d9_utils_win.h" |
- |
-using ui_surface::AcceleratedSurfaceWinHLSL::kVsOneTexture; |
-using ui_surface::AcceleratedSurfaceWinHLSL::kPsOneTexture; |
- |
+namespace d3d_utils = ui_surface_d3d9_utils; |
namespace { |
-typedef HRESULT (WINAPI *Direct3DCreate9ExFunc)(UINT sdk_version, |
- IDirect3D9Ex **d3d); |
- |
-const wchar_t kD3D9ModuleName[] = L"d3d9.dll"; |
-const char kCreate3D9DeviceExName[] = "Direct3DCreate9Ex"; |
- |
const char kUseOcclusionQuery[] = "use-occlusion-query"; |
-struct Vertex { |
- float x, y, z, w; |
- float u, v; |
-}; |
- |
-const static D3DVERTEXELEMENT9 g_vertexElements[] = { |
- { 0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITION, 0 }, |
- { 0, 16, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0 }, |
- D3DDECL_END() |
-}; |
- |
UINT GetPresentationInterval() { |
if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableGpuVsync)) |
return D3DPRESENT_INTERVAL_IMMEDIATE; |
@@ -68,53 +49,6 @@ bool UsingOcclusionQuery() { |
return CommandLine::ForCurrentProcess()->HasSwitch(kUseOcclusionQuery); |
} |
-// Calculate the number necessary to transform |src_subrect| into |dst_size| |
-// by repeating downsampling of the image of |src_subrect| by a factor no more |
-// than 2. |
-int GetResampleCount(const gfx::Rect& src_subrect, |
- const gfx::Size& dst_size, |
- const gfx::Size& back_buffer_size) { |
- // At least one copy is required, since the back buffer itself is not |
- // lockable. |
- int min_resample_count = 1; |
- int width_count = 0; |
- int width = src_subrect.width(); |
- while (width > dst_size.width()) { |
- ++width_count; |
- width >>= 1; |
- } |
- int height_count = 0; |
- int height = src_subrect.height(); |
- while (height > dst_size.height()) { |
- ++height_count; |
- height >>= 1; |
- } |
- return std::max(std::max(width_count, height_count), |
- min_resample_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 |
// A PresentThread is a thread that is dedicated to presenting surfaces to a |
@@ -126,6 +60,9 @@ class PresentThread : public base::Thread, |
IDirect3DDevice9Ex* device() { return device_.get(); } |
IDirect3DQuery9* query() { return query_.get(); } |
+ AcceleratedSurfaceTransformer* surface_transformer() { |
+ return &surface_transformer_; |
+ } |
void InitDevice(); |
void ResetDevice(); |
@@ -141,11 +78,11 @@ class PresentThread : public base::Thread, |
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_; |
+ AcceleratedSurfaceTransformer surface_transformer_; |
DISALLOW_COPY_AND_ASSIGN(PresentThread); |
}; |
@@ -198,7 +135,7 @@ void PresentThread::InitDevice() { |
return; |
TRACE_EVENT0("gpu", "PresentThread::Init"); |
- d3d_module_.Reset(base::LoadNativeLibrary(FilePath(kD3D9ModuleName), NULL)); |
+ d3d_utils::LoadD3D9(&d3d_module_); |
ResetDevice(); |
} |
@@ -210,92 +147,32 @@ void PresentThread::ResetDevice() { |
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, |
- ¶meters, |
- NULL, |
- device_.Receive()); |
- if (FAILED(hr)) |
+ if (!d3d_utils::CreateDevice(d3d_module_, |
+ D3DDEVTYPE_HAL, |
+ GetPresentationInterval(), |
+ device_.Receive())) { |
return; |
+ } |
if (UsingOcclusionQuery()) { |
- hr = device_->CreateQuery(D3DQUERYTYPE_OCCLUSION, query_.Receive()); |
+ HRESULT hr = device_->CreateQuery(D3DQUERYTYPE_OCCLUSION, query_.Receive()); |
if (FAILED(hr)) { |
device_ = NULL; |
return; |
} |
} else { |
- hr = device_->CreateQuery(D3DQUERYTYPE_EVENT, query_.Receive()); |
+ HRESULT hr = device_->CreateQuery(D3DQUERYTYPE_EVENT, query_.Receive()); |
if (FAILED(hr)) { |
device_ = NULL; |
return; |
} |
} |
- base::win::ScopedComPtr<IDirect3DVertexShader9> vertex_shader; |
- hr = device_->CreateVertexShader( |
- reinterpret_cast<const DWORD*>(kVsOneTexture), |
- vertex_shader.Receive()); |
- if (FAILED(hr)) { |
- device_ = NULL; |
+ if (!surface_transformer_.Init(device_)) { |
query_ = NULL; |
- return; |
- } |
- |
- device_->SetVertexShader(vertex_shader); |
- |
- base::win::ScopedComPtr<IDirect3DPixelShader9> pixel_shader; |
- hr = device_->CreatePixelShader( |
- reinterpret_cast<const DWORD*>(kPsOneTexture), |
- pixel_shader.Receive()); |
- |
- if (FAILED(hr)) { |
device_ = NULL; |
- query_ = NULL; |
return; |
} |
- |
- device_->SetPixelShader(pixel_shader); |
- |
- base::win::ScopedComPtr<IDirect3DVertexDeclaration9> vertex_declaration; |
- hr = device_->CreateVertexDeclaration(g_vertexElements, |
- vertex_declaration.Receive()); |
- if (FAILED(hr)) { |
- device_ = NULL; |
- query_ = NULL; |
- return; |
- } |
- |
- device_->SetVertexDeclaration(vertex_declaration); |
} |
void PresentThread::Init() { |
@@ -305,6 +182,7 @@ void PresentThread::Init() { |
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(); |
} |
@@ -382,6 +260,7 @@ AcceleratedPresenter::AcceleratedPresenter(gfx::PluginWindowHandle window) |
hidden_(true) { |
} |
+// static |
scoped_refptr<AcceleratedPresenter> AcceleratedPresenter::GetForWindow( |
gfx::PluginWindowHandle window) { |
return g_accelerated_presenter_map.Pointer()->GetPresenter(window); |
@@ -470,6 +349,9 @@ bool AcceleratedPresenter::DoCopyTo(const gfx::Rect& requested_src_subrect, |
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, |
@@ -490,65 +372,23 @@ bool AcceleratedPresenter::DoCopyTo(const gfx::Rect& requested_src_subrect, |
// 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)); |
- |
- // Set up intermediate buffers needed for downsampling. |
- const int resample_count = |
- GetResampleCount(src_subrect, dst_size, back_buffer_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) { |
- TRACE_EVENT0("gpu", "CreateTemporarySurface"); |
- if (!CreateTemporarySurface(present_thread_->device(), |
- dst_size, |
- final_surface.Receive())) |
- return false; |
- } |
- const gfx::Size half_size = |
- GetHalfSizeNoLessThan(src_subrect.size(), dst_size); |
- if (resample_count > 1) { |
- TRACE_EVENT0("gpu", "CreateTemporarySurface"); |
- if (!CreateTemporarySurface(present_thread_->device(), |
- half_size, |
- temp_buffer[0].Receive())) |
- return false; |
- } |
- if (resample_count > 2) { |
- TRACE_EVENT0("gpu", "CreateTemporarySurface"); |
- const gfx::Size quarter_size = GetHalfSizeNoLessThan(half_size, dst_size); |
- if (!CreateTemporarySurface(present_thread_->device(), |
- quarter_size, |
- temp_buffer[1].Receive())) |
+ { |
+ TRACE_EVENT0("gpu", "CreateTemporaryLockableSurface"); |
+ if (!d3d_utils::CreateTemporaryLockableSurface(present_thread_->device(), |
+ dst_size, |
+ final_surface.Receive())) { |
return false; |
+ } |
} |
- // Repeat downsampling the surface until its size becomes identical to |
- // |dst_size|. We keep the factor of each downsampling no more than two |
- // because using a factor more than two can introduce aliasing. |
- RECT read_rect = src_subrect.ToRECT(); |
- gfx::Size write_size = half_size; |
- int read_buffer_index = 1; |
- int write_buffer_index = 0; |
- for (int i = 0; i < resample_count; ++i) { |
- TRACE_EVENT0("gpu", "StretchRect"); |
- 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 write_rect = gfx::Rect(write_size).ToRECT(); |
- hr = present_thread_->device()->StretchRect(read_buffer, |
- &read_rect, |
- write_buffer, |
- &write_rect, |
- D3DTEXF_LINEAR); |
- if (FAILED(hr)) |
+ { |
+ // Let the surface transformer start the resize into |final_surface|. |
+ TRACE_EVENT0("gpu", "ResizeBilinear"); |
+ if (!gpu_ops->ResizeBilinear(back_buffer, src_subrect, final_surface)) |
return false; |
- read_rect = write_rect; |
- write_size = GetHalfSizeNoLessThan(write_size, dst_size); |
- std::swap(read_buffer_index, write_buffer_index); |
} |
+ |
D3DLOCKED_RECT locked_rect; |
// Empirical evidence seems to suggest that LockRect and memcpy are faster |
@@ -716,18 +556,13 @@ void AcceleratedPresenter::DoPresentAndAcknowledge( |
} |
if (!source_texture_.get()) { |
- TRACE_EVENT0("gpu", "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)) |
+ TRACE_EVENT0("gpu", "OpenSharedTexture"); |
+ if (!d3d_utils::OpenSharedTexture(present_thread_->device(), |
+ surface_handle, |
+ size, |
+ source_texture_.Receive())) { |
return; |
+ } |
} |
base::win::ScopedComPtr<IDirect3DSurface9> source_surface; |
@@ -754,44 +589,15 @@ void AcceleratedPresenter::DoPresentAndAcknowledge( |
{ |
TRACE_EVENT0("gpu", "Copy"); |
- // Use a simple pixel / vertex shader pair to render a quad that flips the |
- // source texture on the vertical axis. |
- IDirect3DSurface9 *default_render_target = NULL; |
- present_thread_->device()->GetRenderTarget(0, &default_render_target); |
- |
- present_thread_->device()->SetRenderTarget(0, dest_surface); |
- present_thread_->device()->SetTexture(0, source_texture_); |
- |
- D3DVIEWPORT9 viewport = { |
- 0, 0, |
- size.width(), size.height(), |
- 0, 1 |
- }; |
- present_thread_->device()->SetViewport(&viewport); |
- |
- float halfPixelX = -1.0f / size.width(); |
- float halfPixelY = 1.0f / size.height(); |
- Vertex vertices[] = { |
- { halfPixelX - 1, halfPixelY + 1, 0.5f, 1, 0, 1 }, |
- { halfPixelX + 1, halfPixelY + 1, 0.5f, 1, 1, 1 }, |
- { halfPixelX + 1, halfPixelY - 1, 0.5f, 1, 1, 0 }, |
- { halfPixelX - 1, halfPixelY - 1, 0.5f, 1, 0, 0 } |
- }; |
- |
if (UsingOcclusionQuery()) { |
present_thread_->query()->Issue(D3DISSUE_BEGIN); |
} |
- present_thread_->device()->BeginScene(); |
- present_thread_->device()->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, |
- 2, |
- vertices, |
- sizeof(vertices[0])); |
- present_thread_->device()->EndScene(); |
- |
- present_thread_->device()->SetTexture(0, NULL); |
- present_thread_->device()->SetRenderTarget(0, default_render_target); |
- default_render_target->Release(); |
+ // Copy while flipping the source texture on the vertical axis. |
+ bool result = present_thread_->surface_transformer()->CopyInverted( |
+ source_texture_, dest_surface, size); |
+ if (!result) |
+ return; |
} |
hr = present_thread_->query()->Issue(D3DISSUE_END); |