summaryrefslogtreecommitdiffstats
path: root/ui/surface/accelerated_surface_transformer_win.h
blob: b04d0ab6977b0cf37c004f5be12e29c331395a50 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
// 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_