// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef UI_SURFACE_ACCELERATED_SURFACE_TRANSFORMER_WIN_H_ #define UI_SURFACE_ACCELERATED_SURFACE_TRANSFORMER_WIN_H_ #include #include "base/gtest_prod_util.h" #include "base/memory/ref_counted.h" #include "base/single_thread_task_runner.h" #include "base/synchronization/lock.h" #include "base/synchronization/waitable_event.h" #include "base/win/scoped_comptr.h" #include "ui/gfx/native_widget_types.h" #include "ui/gfx/size.h" #include "ui/surface/surface_export.h" namespace gfx { class Size; class Rect; } // namespace gfx // Provides useful image filtering operations that are implemented // efficiently on DirectX9-class hardware using fragment programs. class SURFACE_EXPORT AcceleratedSurfaceTransformer { public: // Constructs an uninitialized surface transformer. Call Init() before // using the resulting object. AcceleratedSurfaceTransformer(); // Init() initializes the transformer to operate on a device. This must be // called before any other method of this class, and it must be called // again after ReleaseAll() or DetachAll() before the class is used. // // Returns true if successful. bool Init(IDirect3DDevice9* device); // ReleaseAll() releases all direct3d resource references. void ReleaseAll(); // DetachAll() leaks all direct3d resource references. This exists in order to // work around particular driver bugs, and should only be called at shutdown. // TODO(ncarter): Update the leak expectations before checkin. void DetachAll(); // Draw a textured quad to a surface, flipping orientation in the y direction. bool CopyInverted( IDirect3DTexture9* src_texture, IDirect3DSurface9* dst_surface, const gfx::Size& dst_size); // Draw a textured quad to a surface. bool Copy( IDirect3DTexture9* src_texture, IDirect3DSurface9* dst_surface, const gfx::Size& dst_size); // Get an intermediate buffer of a particular |size|, that can be used as the // output of one transformation and the to another. The returned surface // belongs to an internal cache, and is invalidated by a subsequent call to // this method. bool GetIntermediateTexture( const gfx::Size& size, IDirect3DTexture9** texture, IDirect3DSurface9** texture_level_zero); // Resize a surface using repeated bilinear interpolation. bool ResizeBilinear( IDirect3DSurface9* src_surface, const gfx::Rect& src_subrect, IDirect3DSurface9* dst_surface, const gfx::Rect& dst_subrect); // Color format conversion from RGB to planar YV12 (also known as YUV420). // // YV12 is effectively a twelve bit per pixel format consisting of a full- // size y (luminance) plane and half-width, half-height u and v (blue and // red chrominance) planes. This method will allocate three lockable surfaces, // one for each plane, and return them via the arguments |dst_y|, |dst_u|, // and |dst_v|. These surface will be created with an ARGB D3DFORMAT, but // should be interpreted as the appropriate single-byte format when locking. // // The dimensions of the outputs (when interpreted as single-component data) // are as follows: // |dst_y| : width and height exactly |dst_size| // |dst_u| : width and height are each half of |dst_size|, rounded up. // |dst_v| : width and height are each half of |dst_size|, rounded up. // // If |src_texture|'s dimensions do not match |dst_size|, the source will be // bilinearly interpolated during conversion. // // Returns true if successful. Caller must be certain to release the surfaces // even if this function returns false. The returned surfaces belong to an // internal cache, and are invalidated by a subsequent call to this method. bool TransformRGBToYV12( IDirect3DTexture9* src_texture, const gfx::Size& dst_size, IDirect3DSurface9** dst_y, IDirect3DSurface9** dst_u, IDirect3DSurface9** dst_v); // Synchronously copy from a D3D surface into a caller-allocated buffer. This // will dispatch to one of a couple techniques, depending on which is // determined to be the faster method for the current device. bool ReadFast(IDirect3DSurface9* gpu_surface, uint8* dst, int dst_bytes_per_row, int dst_num_rows, int dst_stride); // Do a read using a particular technique. Which of these is faster depends on // the hardware. Intended for testing; production code ought to call // ReadFast(). bool ReadByLockAndCopy(IDirect3DSurface9* gpu_surface, uint8* dst, int dst_bytes_per_row, int dst_num_rows, int dst_stride); bool ReadByGetRenderTargetData(IDirect3DSurface9* gpu_surface, uint8* dst, int dst_bytes_per_row, int dst_num_rows, int dst_stride); private: friend class AcceleratedSurfaceTransformerTest; FRIEND_TEST_ALL_PREFIXES(AcceleratedSurfaceTransformerTest, Init); enum ShaderCombo { ONE_TEXTURE, RGB_TO_YV12_FAST__PASS_1_OF_2, RGB_TO_YV12_FAST__PASS_2_OF_2, RGB_TO_YV12_SLOW__PASS_1_OF_3, RGB_TO_YV12_SLOW__PASS_2_OF_3, RGB_TO_YV12_SLOW__PASS_3_OF_3, NUM_SHADERS }; // Efficient RGB->YV12 in two passes, but requires a device capable of writing // multiple render targets at the same time. // // Returns true if successful. bool TransformRGBToYV12_MRT( IDirect3DTexture9* src_surface, const gfx::Size& dst_size, const gfx::Size& packed_y_size, const gfx::Size& packed_uv_size, IDirect3DSurface9* dst_y, IDirect3DSurface9* dst_u, IDirect3DSurface9* dst_v); // Slower, less efficient RGB->YV12; does not require the device to have // multiple render target capability. Runs at about half speed of the fast // path. // // Returns true if successful. bool TransformRGBToYV12_WithoutMRT( IDirect3DTexture9* src_surface, const gfx::Size& dst_size, const gfx::Size& packed_y_size, const gfx::Size& packed_uv_size, IDirect3DSurface9* dst_y, IDirect3DSurface9* dst_u, IDirect3DSurface9* dst_v); // Helper to allocate appropriately size YUV buffers, accounting for various // roundings. The sizes of the buffers (in terms of ARGB pixels) are returned // as |packed_y_size| and |packed_uv_size|. // // Returns true if successful. Caller must be certain to release the surfaces // even if this function returns false. The returned belong to an internal // cache. bool AllocYUVBuffers( const gfx::Size& dst_size, gfx::Size* packed_y_size, gfx::Size* packed_uv_size, IDirect3DSurface9** dst_y, IDirect3DSurface9** dst_u, IDirect3DSurface9** dst_v); bool CopyWithTextureScale( IDirect3DTexture9* src_texture, IDirect3DSurface9* dst_surface, const gfx::Size& dst_size, float texture_scale_x, float texture_scale_y); // Set the active vertex and pixel shader combination. // // Returns true if successful. bool SetShaderCombo(ShaderCombo combo); // Compiles a vertex and pixel shader combination, if not already compiled. // // Returns true if successful. bool CompileShaderCombo(ShaderCombo shader_combo_name); bool DoInit(IDirect3DDevice9* device); void DrawScreenAlignedQuad(const gfx::Size& dst_size); bool device_supports_multiple_render_targets() const { return device_supports_multiple_render_targets_; } IDirect3DDevice9* device(); base::win::ScopedComPtr device_; base::win::ScopedComPtr vertex_shaders_[NUM_SHADERS]; base::win::ScopedComPtr pixel_shaders_[NUM_SHADERS]; // Temporary and scratch surfaces; cached to avoid frequent reallocation. base::win::ScopedComPtr user_scratch_texture_; base::win::ScopedComPtr uv_scratch_texture_; base::win::ScopedComPtr y_scratch_surface_; base::win::ScopedComPtr u_scratch_surface_; base::win::ScopedComPtr v_scratch_surface_; base::win::ScopedComPtr scaler_scratch_surfaces_[2]; bool device_supports_multiple_render_targets_; const BYTE* vertex_shader_sources_[NUM_SHADERS]; const BYTE* pixel_shader_sources_[NUM_SHADERS]; DISALLOW_COPY_AND_ASSIGN(AcceleratedSurfaceTransformer); }; #endif // UI_SURFACE_ACCELERATED_SURFACE_TRANSFORMER_WIN_H_