OLD | NEW |
---|---|
(Empty) | |
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/accelerated_surface_transformer_win.h" | |
6 | |
7 #include <vector> | |
8 | |
9 #include "accelerated_surface_transformer_win_hlsl_compiled.h" | |
10 #include "base/debug/trace_event.h" | |
11 #include "base/memory/ref_counted.h" | |
12 #include "base/single_thread_task_runner.h" | |
13 #include "base/synchronization/lock.h" | |
14 #include "base/synchronization/waitable_event.h" | |
15 #include "base/win/scoped_comptr.h" | |
16 #include "ui/gfx/native_widget_types.h" | |
17 #include "ui/gfx/rect.h" | |
18 #include "ui/gfx/size.h" | |
19 #include "ui/surface/d3d9_utils_win.h" | |
20 #include "ui/surface/surface_export.h" | |
21 | |
22 using base::win::ScopedComPtr; | |
23 using std::vector; | |
24 | |
25 namespace d3d_utils = ui_surface_d3d9_utils; | |
26 | |
27 namespace { | |
28 | |
29 struct Vertex { | |
30 float x, y, z, w; | |
31 float u, v; | |
32 }; | |
33 | |
34 const static D3DVERTEXELEMENT9 g_vertexElements[] = { | |
35 { 0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITION, 0 }, | |
36 { 0, 16, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0 }, | |
37 D3DDECL_END() | |
38 }; | |
39 | |
40 // Calculate the number necessary to transform |src_subrect| into |dst_size| | |
41 // by repeating downsampling of the image of |src_subrect| by a factor no more | |
42 // than 2. | |
43 int GetResampleCount(const gfx::Rect& src_subrect, | |
44 const gfx::Size& dst_size, | |
45 const gfx::Size& back_buffer_size) { | |
46 // At least one copy is required, since the back buffer itself is not | |
47 // lockable. | |
48 int min_resample_count = 1; | |
49 int width_count = 0; | |
50 int width = src_subrect.width(); | |
51 while (width > dst_size.width()) { | |
52 ++width_count; | |
53 width >>= 1; | |
54 } | |
55 int height_count = 0; | |
56 int height = src_subrect.height(); | |
57 while (height > dst_size.height()) { | |
58 ++height_count; | |
59 height >>= 1; | |
60 } | |
61 return std::max(std::max(width_count, height_count), | |
62 min_resample_count); | |
63 } | |
64 | |
65 // Returns half the size of |size| no smaller than |min_size|. | |
66 gfx::Size GetHalfSizeNoLessThan(const gfx::Size& size, | |
67 const gfx::Size& min_size) { | |
68 return gfx::Size(std::max(min_size.width(), size.width() / 2), | |
69 std::max(min_size.height(), size.height() / 2)); | |
70 } | |
71 | |
72 gfx::Size GetSize(IDirect3DSurface9* surface) { | |
73 D3DSURFACE_DESC surface_description; | |
74 HRESULT hr = surface->GetDesc(&surface_description); | |
75 if (FAILED(hr)) | |
76 return gfx::Size(0, 0); | |
77 return gfx::Size(surface_description.Width, surface_description.Height); | |
78 } | |
79 | |
80 } // namespace | |
81 | |
82 | |
83 AcceleratedSurfaceTransformer::AcceleratedSurfaceTransformer() {} | |
84 | |
85 bool AcceleratedSurfaceTransformer::Init(IDirect3DDevice9* device) { | |
86 device_ = device; | |
87 if (!InitShaderCombo( | |
88 ui_surface::AcceleratedSurfaceTransformerWinHLSL::kVsOneTexture, | |
89 ui_surface::AcceleratedSurfaceTransformerWinHLSL::kPsOneTexture, | |
90 SIMPLE_TEXTURE)) { | |
91 ReleaseAll(); | |
92 return false; | |
93 } | |
94 | |
95 base::win::ScopedComPtr<IDirect3DVertexDeclaration9> vertex_declaration; | |
96 HRESULT hr = device_->CreateVertexDeclaration(g_vertexElements, | |
97 vertex_declaration.Receive()); | |
98 if (!SUCCEEDED(hr)) { | |
99 ReleaseAll(); | |
100 return false; | |
101 } | |
102 device_->SetVertexDeclaration(vertex_declaration); | |
103 | |
104 return true; | |
105 } | |
106 | |
107 bool AcceleratedSurfaceTransformer::InitShaderCombo( | |
108 const BYTE vertex_shader_instructions[], | |
109 const BYTE pixel_shader_instructions[], | |
110 ShaderCombo shader_combo_name) { | |
111 HRESULT hr = device_->CreateVertexShader( | |
112 reinterpret_cast<const DWORD*>(vertex_shader_instructions), | |
113 vertex_shaders_[shader_combo_name].Receive()); | |
114 | |
115 if (FAILED(hr)) | |
116 return false; | |
117 | |
118 hr = device_->CreatePixelShader( | |
119 reinterpret_cast<const DWORD*>(pixel_shader_instructions), | |
120 pixel_shaders_[shader_combo_name].Receive()); | |
121 | |
122 return SUCCEEDED(hr); | |
123 } | |
124 | |
125 | |
126 void AcceleratedSurfaceTransformer::ReleaseAll() { | |
127 for (int i = 0; i < NUM_SHADERS; i++) { | |
128 vertex_shaders_[i] = NULL; | |
129 vertex_shaders_[i] = NULL; | |
130 } | |
131 device_ = NULL; | |
132 } | |
133 void AcceleratedSurfaceTransformer::DetachAll() { | |
134 for (int i = 0; i < NUM_SHADERS; i++) { | |
135 vertex_shaders_[i].Detach(); | |
136 vertex_shaders_[i].Detach(); | |
137 } | |
138 device_.Detach(); | |
139 } | |
140 | |
141 // Draw a textured quad to a surface. | |
142 bool AcceleratedSurfaceTransformer::CopyInverted( | |
143 IDirect3DTexture9* src_texture, | |
144 IDirect3DSurface9* dst_surface, | |
145 const gfx::Size& dst_size) { | |
146 SetShaderCombo(SIMPLE_TEXTURE); | |
147 device()->SetRenderTarget(0, dst_surface); | |
148 device()->SetTexture(0, src_texture); | |
149 | |
150 D3DVIEWPORT9 viewport = { | |
151 0, 0, | |
152 dst_size.width(), dst_size.height(), | |
153 0, 1 | |
154 }; | |
155 device()->SetViewport(&viewport); | |
156 | |
157 float halfPixelX = -1.0f / dst_size.width(); | |
158 float halfPixelY = 1.0f / dst_size.height(); | |
159 Vertex vertices[] = { | |
160 { halfPixelX - 1, halfPixelY + 1, 0.5f, 1, 0, 1 }, | |
161 { halfPixelX + 1, halfPixelY + 1, 0.5f, 1, 1, 1 }, | |
162 { halfPixelX + 1, halfPixelY - 1, 0.5f, 1, 1, 0 }, | |
163 { halfPixelX - 1, halfPixelY - 1, 0.5f, 1, 0, 0 } | |
164 }; | |
165 | |
166 device()->BeginScene(); | |
167 device()->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, | |
168 2, | |
169 vertices, | |
170 sizeof(vertices[0])); | |
171 device()->EndScene(); | |
172 | |
173 // Clear surface references. | |
174 device()->SetRenderTarget(0, NULL); | |
apatrick_chromium
2012/12/14 23:07:58
This will fail with D3DERR_INVALIDCALL I think.
ht
ncarter (slow)
2012/12/15 00:04:15
Good catch; I'll switch it to save/restore the def
ncarter (slow)
2012/12/17 18:58:59
Done. I verified that the tests don't pass with th
| |
175 device()->SetTexture(0, NULL); | |
176 return true; | |
177 } | |
178 | |
179 // Resize an RGB surface using repeated linear interpolation. | |
180 bool AcceleratedSurfaceTransformer::ResizeBilinear( | |
181 IDirect3DSurface9* src_surface, | |
182 const gfx::Rect& src_subrect, | |
183 IDirect3DSurface9* dst_surface) { | |
184 gfx::Size src_size = GetSize(src_surface); | |
185 gfx::Size dst_size = GetSize(dst_surface); | |
186 | |
187 if (src_size.IsEmpty() || dst_size.IsEmpty()) | |
188 return false; | |
189 | |
190 HRESULT hr = S_OK; | |
191 // Set up intermediate buffers needed for downsampling. | |
192 const int resample_count = | |
193 GetResampleCount(src_subrect, dst_size, src_size); | |
194 base::win::ScopedComPtr<IDirect3DSurface9> temp_buffer[2]; | |
195 const gfx::Size half_size = | |
196 GetHalfSizeNoLessThan(src_subrect.size(), dst_size); | |
197 if (resample_count > 1) { | |
198 TRACE_EVENT0("gpu", "CreateTemporarySurface"); | |
199 if (!d3d_utils::CreateTemporaryLockableSurface(device(), | |
200 half_size, | |
201 temp_buffer[0].Receive())) | |
202 return false; | |
203 } | |
204 if (resample_count > 2) { | |
205 TRACE_EVENT0("gpu", "CreateTemporarySurface"); | |
206 const gfx::Size quarter_size = GetHalfSizeNoLessThan(half_size, dst_size); | |
207 if (!d3d_utils::CreateTemporaryLockableSurface(device(), | |
208 quarter_size, | |
209 temp_buffer[1].Receive())) | |
210 return false; | |
211 } | |
212 | |
213 // Repeat downsampling the surface until its size becomes identical to | |
214 // |dst_size|. We keep the factor of each downsampling no more than two | |
215 // because using a factor more than two can introduce aliasing. | |
216 RECT read_rect = src_subrect.ToRECT(); | |
217 gfx::Size write_size = half_size; | |
218 int read_buffer_index = 1; | |
219 int write_buffer_index = 0; | |
220 for (int i = 0; i < resample_count; ++i) { | |
221 TRACE_EVENT0("gpu", "StretchRect"); | |
222 IDirect3DSurface9* read_buffer = | |
223 (i == 0) ? src_surface : temp_buffer[read_buffer_index]; | |
224 IDirect3DSurface9* write_buffer = | |
225 (i == resample_count - 1) ? dst_surface : | |
226 temp_buffer[write_buffer_index]; | |
227 RECT write_rect = gfx::Rect(write_size).ToRECT(); | |
228 hr = device()->StretchRect(read_buffer, | |
229 &read_rect, | |
230 write_buffer, | |
231 &write_rect, | |
232 D3DTEXF_LINEAR); | |
233 if (FAILED(hr)) | |
234 return false; | |
235 read_rect = write_rect; | |
236 write_size = GetHalfSizeNoLessThan(write_size, dst_size); | |
237 std::swap(read_buffer_index, write_buffer_index); | |
238 } | |
239 | |
240 return true; | |
241 } | |
242 | |
243 IDirect3DDevice9* AcceleratedSurfaceTransformer::device() { | |
244 return device_; | |
245 } | |
246 | |
247 bool AcceleratedSurfaceTransformer::SetShaderCombo(ShaderCombo combo) { | |
248 HRESULT hr = device()->SetVertexShader(vertex_shaders_[combo]); | |
249 if (!SUCCEEDED(hr)) | |
250 return false; | |
251 hr = device()->SetPixelShader(pixel_shaders_[combo]); | |
252 if (!SUCCEEDED(hr)) | |
253 return false; | |
254 return true; | |
255 } | |
OLD | NEW |