OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/surface/accelerated_surface_transformer_win.h" | 5 #include "ui/surface/accelerated_surface_transformer_win.h" |
6 | 6 |
7 #include <vector> | 7 #include <vector> |
8 | 8 |
9 #include "accelerated_surface_transformer_win_hlsl_compiled.h" | 9 #include "accelerated_surface_transformer_win_hlsl_compiled.h" |
10 #include "base/debug/trace_event.h" | 10 #include "base/debug/trace_event.h" |
11 #include "base/memory/ref_counted.h" | 11 #include "base/memory/ref_counted.h" |
12 #include "base/metrics/histogram.h" | |
12 #include "base/single_thread_task_runner.h" | 13 #include "base/single_thread_task_runner.h" |
13 #include "base/synchronization/lock.h" | 14 #include "base/synchronization/lock.h" |
14 #include "base/synchronization/waitable_event.h" | 15 #include "base/synchronization/waitable_event.h" |
15 #include "base/win/scoped_comptr.h" | 16 #include "base/win/scoped_comptr.h" |
16 #include "ui/gfx/native_widget_types.h" | 17 #include "ui/gfx/native_widget_types.h" |
17 #include "ui/gfx/rect.h" | 18 #include "ui/gfx/rect.h" |
18 #include "ui/gfx/size.h" | 19 #include "ui/gfx/size.h" |
19 #include "ui/surface/d3d9_utils_win.h" | 20 #include "ui/surface/d3d9_utils_win.h" |
20 #include "ui/surface/surface_export.h" | 21 #include "ui/surface/surface_export.h" |
21 | 22 |
22 using base::win::ScopedComPtr; | 23 using base::win::ScopedComPtr; |
23 using std::vector; | 24 using std::vector; |
25 using ui_surface::AcceleratedSurfaceTransformerWinHLSL::kPsConvertRGBtoY8UV44; | |
26 using ui_surface::AcceleratedSurfaceTransformerWinHLSL::kPsConvertUV44toU2V2; | |
27 using ui_surface::AcceleratedSurfaceTransformerWinHLSL::kPsOneTexture; | |
28 using ui_surface::AcceleratedSurfaceTransformerWinHLSL::kVsFetch2Pixels; | |
29 using ui_surface::AcceleratedSurfaceTransformerWinHLSL::kVsFetch4Pixels; | |
30 using ui_surface::AcceleratedSurfaceTransformerWinHLSL::kVsOneTextureFlipY; | |
31 using ui_surface::AcceleratedSurfaceTransformerWinHLSL::kVsFetch4PixelsScale2; | |
32 using ui_surface::AcceleratedSurfaceTransformerWinHLSL::kPsConvertRGBtoY; | |
33 using ui_surface::AcceleratedSurfaceTransformerWinHLSL::kPsConvertRGBtoU; | |
34 using ui_surface::AcceleratedSurfaceTransformerWinHLSL::kPsConvertRGBtoV; | |
24 | 35 |
25 namespace d3d_utils = ui_surface_d3d9_utils; | 36 namespace d3d_utils = ui_surface_d3d9_utils; |
26 | 37 |
27 namespace { | 38 namespace { |
28 | 39 |
29 struct Vertex { | 40 struct Vertex { |
30 float x, y, z, w; | 41 float x, y, z, w; |
31 float u, v; | 42 float u, v; |
32 }; | 43 }; |
33 | 44 |
34 const static D3DVERTEXELEMENT9 g_vertexElements[] = { | 45 const static D3DVERTEXELEMENT9 g_vertexElements[] = { |
35 { 0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITION, 0 }, | 46 { 0, 0, D3DDECLTYPE_FLOAT4, 0, D3DDECLUSAGE_POSITION, 0 }, |
36 { 0, 16, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0 }, | 47 { 0, 16, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0 }, |
37 D3DDECL_END() | 48 D3DDECL_END() |
38 }; | 49 }; |
39 | 50 |
51 class ScopedRenderTargetRestorer { | |
52 public: | |
53 ScopedRenderTargetRestorer(IDirect3DDevice9* device, | |
54 int render_target_id) | |
55 : device_(device), | |
56 target_id_(render_target_id) { | |
57 device_->GetRenderTarget(target_id_, original_render_target_.Receive()); | |
58 } | |
59 ~ScopedRenderTargetRestorer() { | |
60 device_->SetRenderTarget(target_id_, original_render_target_); | |
61 } | |
62 private: | |
63 ScopedComPtr<IDirect3DDevice9> device_; | |
64 int target_id_; | |
65 ScopedComPtr<IDirect3DSurface9> original_render_target_; | |
66 }; | |
67 | |
40 // Calculate the number necessary to transform |src_subrect| into |dst_size| | 68 // 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 | 69 // by repeating downsampling of the image of |src_subrect| by a factor no more |
42 // than 2. | 70 // than 2. |
43 int GetResampleCount(const gfx::Rect& src_subrect, | 71 int GetResampleCount(const gfx::Rect& src_subrect, |
44 const gfx::Size& dst_size, | 72 const gfx::Size& dst_size, |
45 const gfx::Size& back_buffer_size) { | 73 const gfx::Size& back_buffer_size) { |
46 // At least one copy is required, since the back buffer itself is not | 74 // At least one copy is required, since the back buffer itself is not |
47 // lockable. | 75 // lockable. |
48 int min_resample_count = 1; | 76 int min_resample_count = 1; |
49 int width_count = 0; | 77 int width_count = 0; |
(...skipping 12 matching lines...) Expand all Loading... | |
62 min_resample_count); | 90 min_resample_count); |
63 } | 91 } |
64 | 92 |
65 // Returns half the size of |size| no smaller than |min_size|. | 93 // Returns half the size of |size| no smaller than |min_size|. |
66 gfx::Size GetHalfSizeNoLessThan(const gfx::Size& size, | 94 gfx::Size GetHalfSizeNoLessThan(const gfx::Size& size, |
67 const gfx::Size& min_size) { | 95 const gfx::Size& min_size) { |
68 return gfx::Size(std::max(min_size.width(), size.width() / 2), | 96 return gfx::Size(std::max(min_size.width(), size.width() / 2), |
69 std::max(min_size.height(), size.height() / 2)); | 97 std::max(min_size.height(), size.height() / 2)); |
70 } | 98 } |
71 | 99 |
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 | 100 } // namespace |
81 | 101 |
82 | 102 AcceleratedSurfaceTransformer::AcceleratedSurfaceTransformer() |
83 AcceleratedSurfaceTransformer::AcceleratedSurfaceTransformer() {} | 103 : device_supports_multiple_render_targets_(false) { |
104 } | |
84 | 105 |
85 bool AcceleratedSurfaceTransformer::Init(IDirect3DDevice9* device) { | 106 bool AcceleratedSurfaceTransformer::Init(IDirect3DDevice9* device) { |
107 bool result = DoInit(device); // and DoInit() and DoInit well. | |
108 if (!result) { | |
109 ReleaseAll(); | |
110 } | |
111 return result; | |
112 } | |
113 | |
114 bool AcceleratedSurfaceTransformer::DoInit(IDirect3DDevice9* device) { | |
86 device_ = device; | 115 device_ = device; |
87 if (!InitShaderCombo( | 116 |
88 ui_surface::AcceleratedSurfaceTransformerWinHLSL::kVsOneTexture, | 117 { |
89 ui_surface::AcceleratedSurfaceTransformerWinHLSL::kPsOneTexture, | 118 D3DCAPS9 caps; |
90 SIMPLE_TEXTURE)) { | 119 HRESULT hr = device->GetDeviceCaps(&caps); |
91 ReleaseAll(); | 120 if (FAILED(hr)) |
121 return false; | |
122 | |
123 device_supports_multiple_render_targets_ = (caps.NumSimultaneousRTs >= 2); | |
124 | |
125 // Log statistics about which paths we take. | |
126 UMA_HISTOGRAM_BOOLEAN("GPU.AcceleratedSurfaceTransformerCanUseMRT", | |
127 device_supports_multiple_render_targets()); | |
128 } | |
129 | |
130 if (!InitShaderCombo(ONE_TEXTURE_FLIP_Y, | |
131 kVsOneTextureFlipY, | |
132 kPsOneTexture)) { | |
133 return false; | |
134 } | |
135 | |
136 if (device_supports_multiple_render_targets()) { | |
137 if (!InitShaderCombo(RGB_TO_YV12_FAST__PASS_1_OF_2, | |
138 kVsFetch4Pixels, | |
139 kPsConvertRGBtoY8UV44)) { | |
140 return false; | |
141 } | |
142 | |
143 if (!InitShaderCombo(RGB_TO_YV12_FAST__PASS_2_OF_2, | |
144 kVsFetch2Pixels, | |
145 kPsConvertUV44toU2V2)) { | |
146 return false; | |
147 } | |
148 } | |
149 | |
miu
2012/12/27 21:40:17
It doesn't seem like the InitShaderCombo() calls f
ncarter (slow)
2013/01/07 22:49:10
The tests actually needed both paths to work, thou
| |
150 if (!InitShaderCombo(RGB_TO_YV12_SLOW__PASS_1_OF_3, | |
151 kVsFetch4Pixels, | |
152 kPsConvertRGBtoY)) { | |
153 return false; | |
154 } | |
155 | |
156 if (!InitShaderCombo(RGB_TO_YV12_SLOW__PASS_2_OF_3, | |
157 kVsFetch4PixelsScale2, | |
158 kPsConvertRGBtoU)) { | |
159 return false; | |
160 } | |
161 | |
162 if (!InitShaderCombo(RGB_TO_YV12_SLOW__PASS_3_OF_3, | |
163 kVsFetch4PixelsScale2, | |
164 kPsConvertRGBtoV)) { | |
92 return false; | 165 return false; |
93 } | 166 } |
94 | 167 |
95 base::win::ScopedComPtr<IDirect3DVertexDeclaration9> vertex_declaration; | 168 base::win::ScopedComPtr<IDirect3DVertexDeclaration9> vertex_declaration; |
96 HRESULT hr = device_->CreateVertexDeclaration(g_vertexElements, | 169 HRESULT hr = device_->CreateVertexDeclaration(g_vertexElements, |
97 vertex_declaration.Receive()); | 170 vertex_declaration.Receive()); |
98 if (!SUCCEEDED(hr)) { | 171 if (FAILED(hr)) |
99 ReleaseAll(); | |
100 return false; | 172 return false; |
101 } | 173 hr = device_->SetVertexDeclaration(vertex_declaration); |
102 device_->SetVertexDeclaration(vertex_declaration); | 174 if (FAILED(hr)) |
175 return false; | |
103 | 176 |
104 return true; | 177 return true; |
105 } | 178 } |
106 | 179 |
107 bool AcceleratedSurfaceTransformer::InitShaderCombo( | 180 bool AcceleratedSurfaceTransformer::InitShaderCombo( |
181 ShaderCombo shader_combo_name, | |
108 const BYTE vertex_shader_instructions[], | 182 const BYTE vertex_shader_instructions[], |
109 const BYTE pixel_shader_instructions[], | 183 const BYTE pixel_shader_instructions[]) { |
110 ShaderCombo shader_combo_name) { | |
111 HRESULT hr = device_->CreateVertexShader( | 184 HRESULT hr = device_->CreateVertexShader( |
112 reinterpret_cast<const DWORD*>(vertex_shader_instructions), | 185 reinterpret_cast<const DWORD*>(vertex_shader_instructions), |
113 vertex_shaders_[shader_combo_name].Receive()); | 186 vertex_shaders_[shader_combo_name].Receive()); |
114 | 187 |
115 if (FAILED(hr)) | 188 if (FAILED(hr)) |
116 return false; | 189 return false; |
117 | 190 |
118 hr = device_->CreatePixelShader( | 191 hr = device_->CreatePixelShader( |
119 reinterpret_cast<const DWORD*>(pixel_shader_instructions), | 192 reinterpret_cast<const DWORD*>(pixel_shader_instructions), |
120 pixel_shaders_[shader_combo_name].Receive()); | 193 pixel_shaders_[shader_combo_name].Receive()); |
(...skipping 15 matching lines...) Expand all Loading... | |
136 vertex_shaders_[i].Detach(); | 209 vertex_shaders_[i].Detach(); |
137 } | 210 } |
138 device_.Detach(); | 211 device_.Detach(); |
139 } | 212 } |
140 | 213 |
141 // Draw a textured quad to a surface. | 214 // Draw a textured quad to a surface. |
142 bool AcceleratedSurfaceTransformer::CopyInverted( | 215 bool AcceleratedSurfaceTransformer::CopyInverted( |
143 IDirect3DTexture9* src_texture, | 216 IDirect3DTexture9* src_texture, |
144 IDirect3DSurface9* dst_surface, | 217 IDirect3DSurface9* dst_surface, |
145 const gfx::Size& dst_size) { | 218 const gfx::Size& dst_size) { |
146 base::win::ScopedComPtr<IDirect3DSurface9> default_color_target; | |
147 device()->GetRenderTarget(0, default_color_target.Receive()); | |
148 | 219 |
149 if (!SetShaderCombo(SIMPLE_TEXTURE)) | 220 if (!SetShaderCombo(ONE_TEXTURE_FLIP_Y)) |
150 return false; | 221 return false; |
151 | 222 |
223 ScopedRenderTargetRestorer render_target_restorer(device(), 0); | |
152 device()->SetRenderTarget(0, dst_surface); | 224 device()->SetRenderTarget(0, dst_surface); |
153 device()->SetTexture(0, src_texture); | 225 device()->SetTexture(0, src_texture); |
226 device()->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); | |
apatrick_chromium
2013/01/07 22:56:53
These render states might affect something else us
ncarter (slow)
2013/01/07 23:24:52
AcceleratedSurface isn't doing any 3D rendering at
| |
227 device()->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); | |
228 device()->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); | |
229 device()->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); | |
154 | 230 |
155 D3DVIEWPORT9 viewport = { | 231 DrawScreenAlignedQuad(dst_size); |
apatrick_chromium
2013/01/07 22:56:53
How did you get away without setting the viewport
ncarter (slow)
2013/01/07 23:24:52
http://msdn.microsoft.com/en-us/library/windows/de
| |
156 0, 0, | |
157 dst_size.width(), dst_size.height(), | |
158 0, 1 | |
159 }; | |
160 device()->SetViewport(&viewport); | |
161 | 232 |
162 float halfPixelX = -1.0f / dst_size.width(); | 233 // Clear surface references. |
163 float halfPixelY = 1.0f / dst_size.height(); | 234 device()->SetTexture(0, NULL); |
235 return true; | |
236 } | |
237 | |
238 void AcceleratedSurfaceTransformer::DrawScreenAlignedQuad( | |
239 const gfx::Size& size) { | |
240 const float target_size[] = { size.width(), size.height() }; | |
241 | |
242 // Set the uniform shader constant |kRenderTargetSize|, which is bound | |
243 // to register c0. | |
244 device()->SetVertexShaderConstantF(0, target_size, arraysize(target_size)); | |
245 | |
246 // We always send down the same vertices. The vertex program will take | |
247 // care of doing resolution-dependent position adjustment. | |
164 Vertex vertices[] = { | 248 Vertex vertices[] = { |
165 { halfPixelX - 1, halfPixelY + 1, 0.5f, 1, 0, 1 }, | 249 { -1, +1, 0.5f, 1, 0, 0 }, |
166 { halfPixelX + 1, halfPixelY + 1, 0.5f, 1, 1, 1 }, | 250 { +1, +1, 0.5f, 1, 1, 0 }, |
167 { halfPixelX + 1, halfPixelY - 1, 0.5f, 1, 1, 0 }, | 251 { +1, -1, 0.5f, 1, 1, 1 }, |
168 { halfPixelX - 1, halfPixelY - 1, 0.5f, 1, 0, 0 } | 252 { -1, -1, 0.5f, 1, 0, 1 } |
169 }; | 253 }; |
170 | 254 |
171 device()->BeginScene(); | 255 device()->BeginScene(); |
172 device()->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, | 256 device()->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, |
173 2, | 257 2, |
174 vertices, | 258 vertices, |
175 sizeof(vertices[0])); | 259 sizeof(vertices[0])); |
176 device()->EndScene(); | 260 device()->EndScene(); |
177 | 261 |
178 // Clear surface references. | |
179 device()->SetRenderTarget(0, default_color_target); | |
180 device()->SetTexture(0, NULL); | |
181 return true; | |
182 } | 262 } |
183 | 263 |
184 // Resize an RGB surface using repeated linear interpolation. | 264 // Resize an RGB surface using repeated linear interpolation. |
185 bool AcceleratedSurfaceTransformer::ResizeBilinear( | 265 bool AcceleratedSurfaceTransformer::ResizeBilinear( |
186 IDirect3DSurface9* src_surface, | 266 IDirect3DSurface9* src_surface, |
187 const gfx::Rect& src_subrect, | 267 const gfx::Rect& src_subrect, |
188 IDirect3DSurface9* dst_surface) { | 268 IDirect3DSurface9* dst_surface) { |
189 gfx::Size src_size = GetSize(src_surface); | 269 gfx::Size src_size = d3d_utils::GetSize(src_surface); |
190 gfx::Size dst_size = GetSize(dst_surface); | 270 gfx::Size dst_size = d3d_utils::GetSize(dst_surface); |
191 | 271 |
192 if (src_size.IsEmpty() || dst_size.IsEmpty()) | 272 if (src_size.IsEmpty() || dst_size.IsEmpty()) |
193 return false; | 273 return false; |
194 | 274 |
195 HRESULT hr = S_OK; | 275 HRESULT hr = S_OK; |
196 // Set up intermediate buffers needed for downsampling. | 276 // Set up intermediate buffers needed for downsampling. |
197 const int resample_count = | 277 const int resample_count = |
198 GetResampleCount(src_subrect, dst_size, src_size); | 278 GetResampleCount(src_subrect, dst_size, src_size); |
199 base::win::ScopedComPtr<IDirect3DSurface9> temp_buffer[2]; | 279 base::win::ScopedComPtr<IDirect3DSurface9> temp_buffer[2]; |
200 const gfx::Size half_size = | 280 const gfx::Size half_size = |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
239 if (FAILED(hr)) | 319 if (FAILED(hr)) |
240 return false; | 320 return false; |
241 read_rect = write_rect; | 321 read_rect = write_rect; |
242 write_size = GetHalfSizeNoLessThan(write_size, dst_size); | 322 write_size = GetHalfSizeNoLessThan(write_size, dst_size); |
243 std::swap(read_buffer_index, write_buffer_index); | 323 std::swap(read_buffer_index, write_buffer_index); |
244 } | 324 } |
245 | 325 |
246 return true; | 326 return true; |
247 } | 327 } |
248 | 328 |
329 bool AcceleratedSurfaceTransformer::TransformRGBToYV12( | |
330 IDirect3DTexture9* src_surface, | |
331 const gfx::Size& dst_size, | |
332 IDirect3DSurface9** dst_y, | |
333 IDirect3DSurface9** dst_u, | |
334 IDirect3DSurface9** dst_v) { | |
335 gfx::Size packed_y_size; | |
336 gfx::Size packed_uv_size; | |
337 if (!AllocYUVBuffers(dst_size, &packed_y_size, &packed_uv_size, | |
338 dst_y, dst_u, dst_v)) { | |
339 return false; | |
340 } | |
341 | |
342 if (device_supports_multiple_render_targets()) { | |
343 return TransformRGBToYV12_MRT(src_surface, | |
344 dst_size, | |
345 packed_y_size, | |
346 packed_uv_size, | |
347 *dst_y, | |
348 *dst_u, | |
349 *dst_v); | |
350 } else { | |
351 return TransformRGBToYV12_WithoutMRT(src_surface, | |
352 dst_size, | |
353 packed_y_size, | |
354 packed_uv_size, | |
355 *dst_y, | |
356 *dst_u, | |
357 *dst_v); | |
358 } | |
359 } | |
360 | |
361 bool AcceleratedSurfaceTransformer::AllocYUVBuffers( | |
362 const gfx::Size& dst_size, | |
363 gfx::Size* y_size, | |
364 gfx::Size* uv_size, | |
365 IDirect3DSurface9** dst_y, | |
366 IDirect3DSurface9** dst_u, | |
367 IDirect3DSurface9** dst_v) { | |
368 | |
369 // Y is full height, packed into 4 components. | |
370 *y_size = gfx::Size((dst_size.width() + 3) / 4, dst_size.height()); | |
371 | |
372 // U and V are half the size (rounded up) of Y. | |
373 *uv_size = gfx::Size((y_size->width() + 1) / 2, (y_size->height() + 1) / 2); | |
374 | |
375 if (!d3d_utils::CreateTemporaryLockableSurface(device(), *y_size, dst_y)) | |
376 return false; | |
377 if (!d3d_utils::CreateTemporaryLockableSurface(device(), *uv_size, dst_u)) | |
378 return false; | |
379 if (!d3d_utils::CreateTemporaryLockableSurface(device(), *uv_size, dst_v)) | |
380 return false; | |
381 return true; | |
382 } | |
383 | |
384 bool AcceleratedSurfaceTransformer::TransformRGBToYV12_MRT( | |
385 IDirect3DTexture9* src_surface, | |
386 const gfx::Size& dst_size, | |
387 const gfx::Size& packed_y_size, | |
388 const gfx::Size& packed_uv_size, | |
389 IDirect3DSurface9* dst_y, | |
390 IDirect3DSurface9* dst_u, | |
391 IDirect3DSurface9* dst_v) { | |
392 TRACE_EVENT0("gpu", "RGBToYV12_MRT"); | |
393 | |
394 ScopedRenderTargetRestorer color0_restorer(device(), 0); | |
395 ScopedRenderTargetRestorer color1_restorer(device(), 1); | |
396 | |
397 // Create an intermediate surface to hold the UUVV values. This is color | |
398 // target 1 for the first pass, and texture 0 for the second pass. Its | |
399 // values are not read afterwards. | |
400 base::win::ScopedComPtr<IDirect3DTexture9> uv_as_texture; | |
401 base::win::ScopedComPtr<IDirect3DSurface9> uv_as_surface; | |
402 if (!d3d_utils::CreateTemporaryRenderTargetTexture(device(), | |
403 packed_y_size, | |
404 uv_as_texture.Receive(), | |
405 uv_as_surface.Receive())) { | |
406 return false; | |
407 } | |
408 | |
409 // Clamping is required if (dst_size.width() % 8 != 0) or if | |
410 // (dst_size.height != 0), so we set it always. Both passes rely on this. | |
411 device()->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); | |
412 device()->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); | |
413 | |
414 ///////////////////////////////////////// | |
415 // Pass 1: RGB --(scaled)--> YYYY + UUVV | |
416 SetShaderCombo(RGB_TO_YV12_FAST__PASS_1_OF_2); | |
417 | |
418 // Enable bilinear filtering if scaling is required. The filtering will take | |
419 // place entirely in the first pass. | |
420 if (d3d_utils::GetSize(src_surface) != dst_size) { | |
421 device()->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); | |
422 device()->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); | |
423 } else { | |
424 device()->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); | |
425 device()->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); | |
426 } | |
427 | |
428 device()->SetTexture(0, src_surface); | |
429 device()->SetRenderTarget(0, dst_y); | |
430 device()->SetRenderTarget(1, uv_as_surface); | |
431 DrawScreenAlignedQuad(dst_size); | |
432 | |
433 ///////////////////////////////////////// | |
434 // Pass 2: UUVV -> UUUU + VVVV | |
435 SetShaderCombo(RGB_TO_YV12_FAST__PASS_2_OF_2); | |
436 | |
437 // The second pass uses bilinear minification to achieve vertical scaling, | |
438 // so enable it always. | |
439 device()->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); | |
440 device()->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); | |
441 | |
442 device()->SetTexture(0, uv_as_texture); | |
443 device()->SetRenderTarget(0, dst_u); | |
444 device()->SetRenderTarget(1, dst_v); | |
445 DrawScreenAlignedQuad(packed_y_size); | |
446 | |
447 // Clear surface references. | |
448 device()->SetTexture(0, NULL); | |
449 return true; | |
450 } | |
451 | |
452 bool AcceleratedSurfaceTransformer::TransformRGBToYV12_WithoutMRT( | |
453 IDirect3DTexture9* src_surface, | |
454 const gfx::Size& dst_size, | |
455 const gfx::Size& packed_y_size, | |
456 const gfx::Size& packed_uv_size, | |
457 IDirect3DSurface9* dst_y, | |
458 IDirect3DSurface9* dst_u, | |
459 IDirect3DSurface9* dst_v) { | |
460 TRACE_EVENT0("gpu", "RGBToYV12_WithoutMRT"); | |
461 | |
462 ScopedRenderTargetRestorer color0_restorer(device(), 0); | |
463 | |
464 base::win::ScopedComPtr<IDirect3DTexture9> scaled_src_surface; | |
465 | |
466 // If scaling is requested, do it to a temporary texture. The MRT path | |
467 // gets a scale for free, so we need to support it here too (even though | |
468 // it's an extra operation). | |
469 if (d3d_utils::GetSize(src_surface) == dst_size) { | |
470 scaled_src_surface = src_surface; | |
471 } else { | |
472 base::win::ScopedComPtr<IDirect3DSurface9> src_level0; | |
473 HRESULT hr = src_surface->GetSurfaceLevel(0, src_level0.Receive()); | |
474 if (FAILED(hr)) | |
475 return false; | |
476 | |
477 base::win::ScopedComPtr<IDirect3DSurface9> dst_level0; | |
478 if (!d3d_utils::CreateTemporaryRenderTargetTexture( | |
479 device(), dst_size, | |
480 scaled_src_surface.Receive(), dst_level0.Receive())) { | |
481 return false; | |
482 } | |
483 | |
484 device()->StretchRect(src_level0, NULL, dst_level0, NULL, D3DTEXF_LINEAR); | |
apatrick_chromium
2013/01/07 22:56:53
Maybe this isn't an issue for your purposes but if
ncarter (slow)
2013/01/07 23:24:52
Yes, definitely; for the first phase I'm planning
| |
485 } | |
486 | |
487 // Input texture is the same for all three passes. | |
488 device()->SetTexture(0, scaled_src_surface); | |
489 | |
490 // Clamping is required if (dst_size.width() % 8 != 0) or if | |
491 // (dst_size.height != 0), so we set it always. All passes rely on this. | |
492 device()->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); | |
493 device()->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); | |
494 | |
495 ///////////////////// | |
496 // Pass 1: RGB -> Y. | |
497 SetShaderCombo(RGB_TO_YV12_SLOW__PASS_1_OF_3); | |
498 | |
499 // Pass 1 just needs point sampling. | |
500 device()->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); | |
501 device()->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); | |
502 | |
503 device()->SetRenderTarget(0, dst_y); | |
504 DrawScreenAlignedQuad(dst_size); | |
505 | |
506 // Passes 2 and 3 rely on bilinear minification to downsample U and V. | |
507 device()->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); | |
508 device()->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); | |
509 | |
510 ///////////////////// | |
511 // Pass 2: RGB -> U. | |
512 SetShaderCombo(RGB_TO_YV12_SLOW__PASS_2_OF_3); | |
513 device()->SetRenderTarget(0, dst_u); | |
514 DrawScreenAlignedQuad(dst_size); | |
515 | |
516 ///////////////////// | |
517 // Pass 3: RGB -> V. | |
518 SetShaderCombo(RGB_TO_YV12_SLOW__PASS_3_OF_3); | |
519 device()->SetRenderTarget(0, dst_v); | |
520 DrawScreenAlignedQuad(dst_size); | |
521 | |
522 // Clear surface references. | |
523 device()->SetTexture(0, NULL); | |
524 return true; | |
525 } | |
526 | |
249 IDirect3DDevice9* AcceleratedSurfaceTransformer::device() { | 527 IDirect3DDevice9* AcceleratedSurfaceTransformer::device() { |
250 return device_; | 528 return device_; |
251 } | 529 } |
252 | 530 |
531 bool AcceleratedSurfaceTransformer::device_supports_multiple_render_targets() { | |
miu
2012/12/27 21:40:17
nit: Consider inlining (allowed for simple accesso
ncarter (slow)
2013/01/07 22:49:10
Done.
| |
532 return device_supports_multiple_render_targets_; | |
533 } | |
534 | |
253 bool AcceleratedSurfaceTransformer::SetShaderCombo(ShaderCombo combo) { | 535 bool AcceleratedSurfaceTransformer::SetShaderCombo(ShaderCombo combo) { |
254 HRESULT hr = device()->SetVertexShader(vertex_shaders_[combo]); | 536 HRESULT hr = device()->SetVertexShader(vertex_shaders_[combo]); |
255 if (!SUCCEEDED(hr)) | 537 if (!SUCCEEDED(hr)) |
256 return false; | 538 return false; |
257 hr = device()->SetPixelShader(pixel_shaders_[combo]); | 539 hr = device()->SetPixelShader(pixel_shaders_[combo]); |
258 if (!SUCCEEDED(hr)) | 540 if (!SUCCEEDED(hr)) |
259 return false; | 541 return false; |
260 return true; | 542 return true; |
261 } | 543 } |
OLD | NEW |