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 #ifndef UI_SURFACE_ACCELERATED_SURFACE_TRANSFORMER_WIN_H_ 6 #define UI_SURFACE_ACCELERATED_SURFACE_TRANSFORMER_WIN_H_ 7 8 #include <d3d9.h> 9 10 #include "base/gtest_prod_util.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/size.h" 18 #include "ui/surface/surface_export.h" 19 20 namespace gfx { 21 class Size; 22 class Rect; 23 } // namespace gfx 24 25 // Provides useful image filtering operations that are implemented 26 // efficiently on DirectX9-class hardware using fragment programs. 27 class SURFACE_EXPORT AcceleratedSurfaceTransformer { 28 public: 29 // Constructs an uninitialized surface transformer. Call Init() before 30 // using the resulting object. 31 AcceleratedSurfaceTransformer(); 32 33 // Init() initializes the transformer to operate on a device. This must be 34 // called before any other method of this class, and it must be called 35 // again after ReleaseAll() or DetachAll() before the class is used. 36 // 37 // Returns true if successful. 38 bool Init(IDirect3DDevice9* device); 39 40 // ReleaseAll() releases all direct3d resource references. 41 void ReleaseAll(); 42 43 // DetachAll() leaks all direct3d resource references. This exists in order to 44 // work around particular driver bugs, and should only be called at shutdown. 45 // TODO(ncarter): Update the leak expectations before checkin. 46 void DetachAll(); 47 48 // Draw a textured quad to a surface, flipping orientation in the y direction. 49 bool CopyInverted( 50 IDirect3DTexture9* src_texture, 51 IDirect3DSurface9* dst_surface, 52 const gfx::Size& dst_size); 53 54 // Draw a textured quad to a surface. 55 bool Copy( 56 IDirect3DTexture9* src_texture, 57 IDirect3DSurface9* dst_surface, 58 const gfx::Size& dst_size); 59 60 // Get an intermediate buffer of a particular |size|, that can be used as the 61 // output of one transformation and the to another. The returned surface 62 // belongs to an internal cache, and is invalidated by a subsequent call to 63 // this method. 64 bool GetIntermediateTexture( 65 const gfx::Size& size, 66 IDirect3DTexture9** texture, 67 IDirect3DSurface9** texture_level_zero); 68 69 // Resize a surface using repeated bilinear interpolation. 70 bool ResizeBilinear( 71 IDirect3DSurface9* src_surface, 72 const gfx::Rect& src_subrect, 73 IDirect3DSurface9* dst_surface, 74 const gfx::Rect& dst_subrect); 75 76 // Color format conversion from RGB to planar YV12 (also known as YUV420). 77 // 78 // YV12 is effectively a twelve bit per pixel format consisting of a full- 79 // size y (luminance) plane and half-width, half-height u and v (blue and 80 // red chrominance) planes. This method will allocate three lockable surfaces, 81 // one for each plane, and return them via the arguments |dst_y|, |dst_u|, 82 // and |dst_v|. These surface will be created with an ARGB D3DFORMAT, but 83 // should be interpreted as the appropriate single-byte format when locking. 84 // 85 // The dimensions of the outputs (when interpreted as single-component data) 86 // are as follows: 87 // |dst_y| : width and height exactly |dst_size| 88 // |dst_u| : width and height are each half of |dst_size|, rounded up. 89 // |dst_v| : width and height are each half of |dst_size|, rounded up. 90 // 91 // If |src_texture|'s dimensions do not match |dst_size|, the source will be 92 // bilinearly interpolated during conversion. 93 // 94 // Returns true if successful. Caller must be certain to release the surfaces 95 // even if this function returns false. The returned surfaces belong to an 96 // internal cache, and are invalidated by a subsequent call to this method. 97 bool TransformRGBToYV12( 98 IDirect3DTexture9* src_texture, 99 const gfx::Size& dst_size, 100 IDirect3DSurface9** dst_y, 101 IDirect3DSurface9** dst_u, 102 IDirect3DSurface9** dst_v); 103 104 // Synchronously copy from a D3D surface into a caller-allocated buffer. This 105 // will dispatch to one of a couple techniques, depending on which is 106 // determined to be the faster method for the current device. 107 bool ReadFast(IDirect3DSurface9* gpu_surface, 108 uint8* dst, 109 int dst_bytes_per_row, 110 int dst_num_rows, 111 int dst_stride); 112 113 // Do a read using a particular technique. Which of these is faster depends on 114 // the hardware. Intended for testing; production code ought to call 115 // ReadFast(). 116 bool ReadByLockAndCopy(IDirect3DSurface9* gpu_surface, 117 uint8* dst, 118 int dst_bytes_per_row, 119 int dst_num_rows, 120 int dst_stride); 121 bool ReadByGetRenderTargetData(IDirect3DSurface9* gpu_surface, 122 uint8* dst, 123 int dst_bytes_per_row, 124 int dst_num_rows, 125 int dst_stride); 126 127 private: 128 friend class AcceleratedSurfaceTransformerTest; 129 FRIEND_TEST_ALL_PREFIXES(AcceleratedSurfaceTransformerTest, Init); 130 131 enum ShaderCombo { 132 ONE_TEXTURE, 133 RGB_TO_YV12_FAST__PASS_1_OF_2, 134 RGB_TO_YV12_FAST__PASS_2_OF_2, 135 RGB_TO_YV12_SLOW__PASS_1_OF_3, 136 RGB_TO_YV12_SLOW__PASS_2_OF_3, 137 RGB_TO_YV12_SLOW__PASS_3_OF_3, 138 NUM_SHADERS 139 }; 140 141 // Efficient RGB->YV12 in two passes, but requires a device capable of writing 142 // multiple render targets at the same time. 143 // 144 // Returns true if successful. 145 bool TransformRGBToYV12_MRT( 146 IDirect3DTexture9* src_surface, 147 const gfx::Size& dst_size, 148 const gfx::Size& packed_y_size, 149 const gfx::Size& packed_uv_size, 150 IDirect3DSurface9* dst_y, 151 IDirect3DSurface9* dst_u, 152 IDirect3DSurface9* dst_v); 153 154 // Slower, less efficient RGB->YV12; does not require the device to have 155 // multiple render target capability. Runs at about half speed of the fast 156 // path. 157 // 158 // Returns true if successful. 159 bool TransformRGBToYV12_WithoutMRT( 160 IDirect3DTexture9* src_surface, 161 const gfx::Size& dst_size, 162 const gfx::Size& packed_y_size, 163 const gfx::Size& packed_uv_size, 164 IDirect3DSurface9* dst_y, 165 IDirect3DSurface9* dst_u, 166 IDirect3DSurface9* dst_v); 167 168 // Helper to allocate appropriately size YUV buffers, accounting for various 169 // roundings. The sizes of the buffers (in terms of ARGB pixels) are returned 170 // as |packed_y_size| and |packed_uv_size|. 171 // 172 // Returns true if successful. Caller must be certain to release the surfaces 173 // even if this function returns false. The returned belong to an internal 174 // cache. 175 bool AllocYUVBuffers( 176 const gfx::Size& dst_size, 177 gfx::Size* packed_y_size, 178 gfx::Size* packed_uv_size, 179 IDirect3DSurface9** dst_y, 180 IDirect3DSurface9** dst_u, 181 IDirect3DSurface9** dst_v); 182 183 bool CopyWithTextureScale( 184 IDirect3DTexture9* src_texture, 185 IDirect3DSurface9* dst_surface, 186 const gfx::Size& dst_size, 187 float texture_scale_x, 188 float texture_scale_y); 189 190 // Set the active vertex and pixel shader combination. 191 // 192 // Returns true if successful. 193 bool SetShaderCombo(ShaderCombo combo); 194 195 // Compiles a vertex and pixel shader combination, if not already compiled. 196 // 197 // Returns true if successful. 198 bool CompileShaderCombo(ShaderCombo shader_combo_name); 199 200 bool DoInit(IDirect3DDevice9* device); 201 202 void DrawScreenAlignedQuad(const gfx::Size& dst_size); 203 204 bool device_supports_multiple_render_targets() const { 205 return device_supports_multiple_render_targets_; 206 } 207 208 IDirect3DDevice9* device(); 209 210 base::win::ScopedComPtr<IDirect3DDevice9> device_; 211 base::win::ScopedComPtr<IDirect3DVertexShader9> vertex_shaders_[NUM_SHADERS]; 212 base::win::ScopedComPtr<IDirect3DPixelShader9> pixel_shaders_[NUM_SHADERS]; 213 214 // Temporary and scratch surfaces; cached to avoid frequent reallocation. 215 base::win::ScopedComPtr<IDirect3DTexture9> user_scratch_texture_; 216 base::win::ScopedComPtr<IDirect3DTexture9> uv_scratch_texture_; 217 base::win::ScopedComPtr<IDirect3DSurface9> y_scratch_surface_; 218 base::win::ScopedComPtr<IDirect3DSurface9> u_scratch_surface_; 219 base::win::ScopedComPtr<IDirect3DSurface9> v_scratch_surface_; 220 base::win::ScopedComPtr<IDirect3DSurface9> scaler_scratch_surfaces_[2]; 221 222 bool device_supports_multiple_render_targets_; 223 const BYTE* vertex_shader_sources_[NUM_SHADERS]; 224 const BYTE* pixel_shader_sources_[NUM_SHADERS]; 225 DISALLOW_COPY_AND_ASSIGN(AcceleratedSurfaceTransformer); 226 }; 227 228 #endif // UI_SURFACE_ACCELERATED_SURFACE_TRANSFORMER_WIN_H_ 229