diff options
Diffstat (limited to 'ui/surface/accelerated_surface_win.cc')
-rw-r--r-- | ui/surface/accelerated_surface_win.cc | 280 |
1 files changed, 43 insertions, 237 deletions
diff --git a/ui/surface/accelerated_surface_win.cc b/ui/surface/accelerated_surface_win.cc index 0fa247d7..0ac8f1c 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); |