| 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 base::win::ScopedComPtr<IDirect3DSurface9> default_color_target; | |
| 147 device()->GetRenderTarget(0, default_color_target.Receive()); | |
| 148 | |
| 149 if (!SetShaderCombo(SIMPLE_TEXTURE)) | |
| 150 return false; | |
| 151 | |
| 152 device()->SetRenderTarget(0, dst_surface); | |
| 153 device()->SetTexture(0, src_texture); | |
| 154 | |
| 155 D3DVIEWPORT9 viewport = { | |
| 156 0, 0, | |
| 157 dst_size.width(), dst_size.height(), | |
| 158 0, 1 | |
| 159 }; | |
| 160 device()->SetViewport(&viewport); | |
| 161 | |
| 162 float halfPixelX = -1.0f / dst_size.width(); | |
| 163 float halfPixelY = 1.0f / dst_size.height(); | |
| 164 Vertex vertices[] = { | |
| 165 { halfPixelX - 1, halfPixelY + 1, 0.5f, 1, 0, 1 }, | |
| 166 { halfPixelX + 1, halfPixelY + 1, 0.5f, 1, 1, 1 }, | |
| 167 { halfPixelX + 1, halfPixelY - 1, 0.5f, 1, 1, 0 }, | |
| 168 { halfPixelX - 1, halfPixelY - 1, 0.5f, 1, 0, 0 } | |
| 169 }; | |
| 170 | |
| 171 device()->BeginScene(); | |
| 172 device()->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, | |
| 173 2, | |
| 174 vertices, | |
| 175 sizeof(vertices[0])); | |
| 176 device()->EndScene(); | |
| 177 | |
| 178 // Clear surface references. | |
| 179 device()->SetRenderTarget(0, default_color_target); | |
| 180 device()->SetTexture(0, NULL); | |
| 181 return true; | |
| 182 } | |
| 183 | |
| 184 // Resize an RGB surface using repeated linear interpolation. | |
| 185 bool AcceleratedSurfaceTransformer::ResizeBilinear( | |
| 186 IDirect3DSurface9* src_surface, | |
| 187 const gfx::Rect& src_subrect, | |
| 188 IDirect3DSurface9* dst_surface) { | |
| 189 gfx::Size src_size = GetSize(src_surface); | |
| 190 gfx::Size dst_size = GetSize(dst_surface); | |
| 191 | |
| 192 if (src_size.IsEmpty() || dst_size.IsEmpty()) | |
| 193 return false; | |
| 194 | |
| 195 HRESULT hr = S_OK; | |
| 196 // Set up intermediate buffers needed for downsampling. | |
| 197 const int resample_count = | |
| 198 GetResampleCount(src_subrect, dst_size, src_size); | |
| 199 base::win::ScopedComPtr<IDirect3DSurface9> temp_buffer[2]; | |
| 200 const gfx::Size half_size = | |
| 201 GetHalfSizeNoLessThan(src_subrect.size(), dst_size); | |
| 202 if (resample_count > 1) { | |
| 203 TRACE_EVENT0("gpu", "CreateTemporarySurface"); | |
| 204 if (!d3d_utils::CreateTemporaryLockableSurface(device(), | |
| 205 half_size, | |
| 206 temp_buffer[0].Receive())) | |
| 207 return false; | |
| 208 } | |
| 209 if (resample_count > 2) { | |
| 210 TRACE_EVENT0("gpu", "CreateTemporarySurface"); | |
| 211 const gfx::Size quarter_size = GetHalfSizeNoLessThan(half_size, dst_size); | |
| 212 if (!d3d_utils::CreateTemporaryLockableSurface(device(), | |
| 213 quarter_size, | |
| 214 temp_buffer[1].Receive())) | |
| 215 return false; | |
| 216 } | |
| 217 | |
| 218 // Repeat downsampling the surface until its size becomes identical to | |
| 219 // |dst_size|. We keep the factor of each downsampling no more than two | |
| 220 // because using a factor more than two can introduce aliasing. | |
| 221 RECT read_rect = src_subrect.ToRECT(); | |
| 222 gfx::Size write_size = half_size; | |
| 223 int read_buffer_index = 1; | |
| 224 int write_buffer_index = 0; | |
| 225 for (int i = 0; i < resample_count; ++i) { | |
| 226 TRACE_EVENT0("gpu", "StretchRect"); | |
| 227 IDirect3DSurface9* read_buffer = | |
| 228 (i == 0) ? src_surface : temp_buffer[read_buffer_index]; | |
| 229 IDirect3DSurface9* write_buffer = | |
| 230 (i == resample_count - 1) ? dst_surface : | |
| 231 temp_buffer[write_buffer_index]; | |
| 232 RECT write_rect = gfx::Rect(write_size).ToRECT(); | |
| 233 hr = device()->StretchRect(read_buffer, | |
| 234 &read_rect, | |
| 235 write_buffer, | |
| 236 &write_rect, | |
| 237 D3DTEXF_LINEAR); | |
| 238 | |
| 239 if (FAILED(hr)) | |
| 240 return false; | |
| 241 read_rect = write_rect; | |
| 242 write_size = GetHalfSizeNoLessThan(write_size, dst_size); | |
| 243 std::swap(read_buffer_index, write_buffer_index); | |
| 244 } | |
| 245 | |
| 246 return true; | |
| 247 } | |
| 248 | |
| 249 IDirect3DDevice9* AcceleratedSurfaceTransformer::device() { | |
| 250 return device_; | |
| 251 } | |
| 252 | |
| 253 bool AcceleratedSurfaceTransformer::SetShaderCombo(ShaderCombo combo) { | |
| 254 HRESULT hr = device()->SetVertexShader(vertex_shaders_[combo]); | |
| 255 if (!SUCCEEDED(hr)) | |
| 256 return false; | |
| 257 hr = device()->SetPixelShader(pixel_shaders_[combo]); | |
| 258 if (!SUCCEEDED(hr)) | |
| 259 return false; | |
| 260 return true; | |
| 261 } | |
| OLD | NEW |