Chromium Code Reviews| 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 |