blob: b04d0ab6977b0cf37c004f5be12e29c331395a50 [file] [log] [blame]
// 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 <d3d9.h>
#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<IDirect3DDevice9> device_;
base::win::ScopedComPtr<IDirect3DVertexShader9> vertex_shaders_[NUM_SHADERS];
base::win::ScopedComPtr<IDirect3DPixelShader9> pixel_shaders_[NUM_SHADERS];
// Temporary and scratch surfaces; cached to avoid frequent reallocation.
base::win::ScopedComPtr<IDirect3DTexture9> user_scratch_texture_;
base::win::ScopedComPtr<IDirect3DTexture9> uv_scratch_texture_;
base::win::ScopedComPtr<IDirect3DSurface9> y_scratch_surface_;
base::win::ScopedComPtr<IDirect3DSurface9> u_scratch_surface_;
base::win::ScopedComPtr<IDirect3DSurface9> v_scratch_surface_;
base::win::ScopedComPtr<IDirect3DSurface9> 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_