1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ui/surface/d3d9_utils_win.h"
6
7 #include "base/debug/trace_event.h"
8 #include "base/files/file_path.h"
9 #include "base/scoped_native_library.h"
10 #include "base/win/scoped_comptr.h"
11 #include "ui/gfx/size.h"
12
13 namespace {
14
15 const wchar_t kD3D9ModuleName[] = L"d3d9.dll";
16 const char kCreate3D9DeviceExName[] = "Direct3DCreate9Ex";
17 typedef HRESULT (WINAPI *Direct3DCreate9ExFunc)(UINT sdk_version,
18 IDirect3D9Ex **d3d);
19 } // namespace
20
21 namespace ui_surface_d3d9_utils {
22
LoadD3D9(base::ScopedNativeLibrary * storage)23 bool LoadD3D9(base::ScopedNativeLibrary* storage) {
24 storage->Reset(
25 base::LoadNativeLibrary(base::FilePath(kD3D9ModuleName), NULL));
26 return storage->is_valid();
27 }
28
CreateDevice(const base::ScopedNativeLibrary & d3d_module,uint64 adapter_luid,D3DDEVTYPE device_type,uint32 presentation_interval,IDirect3DDevice9Ex ** device)29 bool CreateDevice(const base::ScopedNativeLibrary& d3d_module,
30 uint64 adapter_luid,
31 D3DDEVTYPE device_type,
32 uint32 presentation_interval,
33 IDirect3DDevice9Ex** device) {
34 Direct3DCreate9ExFunc create_func = reinterpret_cast<Direct3DCreate9ExFunc>(
35 d3d_module.GetFunctionPointer(kCreate3D9DeviceExName));
36 if (!create_func)
37 return false;
38
39 base::win::ScopedComPtr<IDirect3D9Ex> d3d;
40 HRESULT hr = create_func(D3D_SDK_VERSION, d3d.Receive());
41 if (FAILED(hr))
42 return false;
43
44 UINT adapter = D3DADAPTER_DEFAULT;
45
46 if (adapter_luid) {
47 UINT adapter_count = d3d->GetAdapterCount();
48 for (adapter = 0; adapter < adapter_count; ++adapter) {
49 LUID luid;
50 HRESULT hr = d3d->GetAdapterLUID(adapter, &luid);
51 if (FAILED(hr))
52 return false;
53
54 if (memcmp(&luid, &adapter_luid, sizeof(adapter_luid)) == 0)
55 break;
56 }
57
58 if (adapter == adapter_count)
59 return false;
60 }
61
62 // Any old window will do to create the device. In practice the window to
63 // present to is an argument to IDirect3DDevice9::Present.
64 HWND window = GetDesktopWindow();
65
66 D3DPRESENT_PARAMETERS parameters = { 0 };
67 parameters.BackBufferWidth = 1;
68 parameters.BackBufferHeight = 1;
69 parameters.BackBufferCount = 1;
70 parameters.BackBufferFormat = D3DFMT_A8R8G8B8;
71 parameters.hDeviceWindow = window;
72 parameters.Windowed = TRUE;
73 parameters.Flags = 0;
74 parameters.PresentationInterval = presentation_interval;
75 parameters.SwapEffect = D3DSWAPEFFECT_COPY;
76
77 hr = d3d->CreateDeviceEx(
78 adapter,
79 device_type,
80 window,
81 D3DCREATE_FPU_PRESERVE | D3DCREATE_SOFTWARE_VERTEXPROCESSING |
82 D3DCREATE_DISABLE_PSGP_THREADING | D3DCREATE_MULTITHREADED,
83 ¶meters,
84 NULL,
85 device);
86 return SUCCEEDED(hr);
87 }
88
OpenSharedTexture(IDirect3DDevice9 * device,int64 surface_handle,const gfx::Size & size,IDirect3DTexture9 ** opened_texture)89 bool OpenSharedTexture(IDirect3DDevice9* device,
90 int64 surface_handle,
91 const gfx::Size& size,
92 IDirect3DTexture9** opened_texture) {
93 TRACE_EVENT0("gpu", "OpenSharedTexture");
94 HANDLE handle = reinterpret_cast<HANDLE>(surface_handle);
95 HRESULT hr = device->CreateTexture(size.width(),
96 size.height(),
97 1,
98 D3DUSAGE_RENDERTARGET,
99 D3DFMT_A8R8G8B8,
100 D3DPOOL_DEFAULT,
101 opened_texture,
102 &handle);
103 return SUCCEEDED(hr);
104 }
105
CreateOrReuseLockableSurface(IDirect3DDevice9 * device,const gfx::Size & size,base::win::ScopedComPtr<IDirect3DSurface9> * surface)106 bool CreateOrReuseLockableSurface(
107 IDirect3DDevice9* device,
108 const gfx::Size& size,
109 base::win::ScopedComPtr<IDirect3DSurface9>* surface) {
110 if (!*surface || GetSize(*surface) != size) {
111 TRACE_EVENT0("gpu", "CreateRenderTarget");
112 surface->Release();
113 HRESULT hr = device->CreateRenderTarget(
114 size.width(),
115 size.height(),
116 D3DFMT_A8R8G8B8,
117 D3DMULTISAMPLE_NONE,
118 0,
119 TRUE,
120 surface->Receive(),
121 NULL);
122 if (FAILED(hr))
123 return false;
124 }
125 return true;
126 }
127
CreateOrReuseRenderTargetTexture(IDirect3DDevice9 * device,const gfx::Size & size,base::win::ScopedComPtr<IDirect3DTexture9> * texture,IDirect3DSurface9 ** render_target)128 bool CreateOrReuseRenderTargetTexture(
129 IDirect3DDevice9* device,
130 const gfx::Size& size,
131 base::win::ScopedComPtr<IDirect3DTexture9>* texture,
132 IDirect3DSurface9** render_target) {
133 if (!*texture || GetSize(*texture) != size) {
134 TRACE_EVENT0("gpu", "CreateTexture");
135 texture->Release();
136 HRESULT hr = device->CreateTexture(
137 size.width(),
138 size.height(),
139 1, // Levels
140 D3DUSAGE_RENDERTARGET,
141 D3DFMT_A8R8G8B8,
142 D3DPOOL_DEFAULT,
143 texture->Receive(),
144 NULL);
145 if (!SUCCEEDED(hr))
146 return false;
147 }
148 HRESULT hr = (*texture)->GetSurfaceLevel(0, render_target);
149 return SUCCEEDED(hr);
150 }
151
GetSize(IDirect3DSurface9 * surface)152 gfx::Size GetSize(IDirect3DSurface9* surface) {
153 D3DSURFACE_DESC surface_description;
154 HRESULT hr = surface->GetDesc(&surface_description);
155 if (FAILED(hr))
156 return gfx::Size(0, 0);
157 return gfx::Size(surface_description.Width, surface_description.Height);
158 }
159
GetSize(IDirect3DTexture9 * texture)160 gfx::Size GetSize(IDirect3DTexture9* texture) {
161 D3DSURFACE_DESC surface_description;
162 HRESULT hr = texture->GetLevelDesc(0, &surface_description);
163 if (FAILED(hr))
164 return gfx::Size(0, 0);
165 return gfx::Size(surface_description.Width, surface_description.Height);
166 }
167
168 } // namespace ui_surface_d3d9_utils
169