summaryrefslogtreecommitdiff
path: root/chromium/ui/gl/swap_chain_presenter.h
blob: 14fc56459ccf5059d9b58fb4b094200587b4d6fb (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
229
230
231
232
233
234
235
236
237
238
239
// Copyright 2019 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_GL_SWAP_CHAIN_PRESENTER_H_
#define UI_GL_SWAP_CHAIN_PRESENTER_H_

#include <windows.h>
#include <d3d11.h>
#include <dcomp.h>
#include <wrl/client.h>

#include "base/containers/circular_deque.h"
#include "base/power_monitor/power_monitor.h"
#include "base/win/scoped_handle.h"
#include "ui/gfx/color_space.h"
#include "ui/gl/dc_renderer_layer_params.h"

namespace gl {
class DCLayerTree;
class GLImageDXGI;
class GLImageMemory;

// SwapChainPresenter holds a swap chain, direct composition visuals, and other
// associated resources for a single overlay layer.  It is updated by calling
// PresentToSwapChain(), and can update or recreate resources as necessary.
class SwapChainPresenter : public base::PowerObserver {
 public:
  SwapChainPresenter(DCLayerTree* layer_tree,
                     Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device,
                     Microsoft::WRL::ComPtr<IDCompositionDevice2> dcomp_device);
  ~SwapChainPresenter() override;

  // Present the given overlay to swap chain.  Returns true on success.
  bool PresentToSwapChain(const ui::DCRendererLayerParams& overlay);

  const Microsoft::WRL::ComPtr<IDXGISwapChain1>& swap_chain() const {
    return swap_chain_;
  }

  const Microsoft::WRL::ComPtr<IDCompositionVisual2>& visual() const {
    return clip_visual_;
  }

 private:
  // Mapped to DirectCompositonVideoPresentationMode UMA enum.  Do not remove or
  // remap existing entries!
  enum class VideoPresentationMode {
    kZeroCopyDecodeSwapChain = 0,
    kUploadAndVideoProcessorBlit = 1,
    kBindAndVideoProcessorBlit = 2,
    kMaxValue = kBindAndVideoProcessorBlit,
  };

  // Mapped to DecodeSwapChainNotUsedReason UMA enum.  Do not remove or remap
  // existing entries.
  enum class DecodeSwapChainNotUsedReason {
    kSoftwareFrame = 0,
    kNv12NotSupported = 1,
    kFailedToPresent = 2,
    kNonDecoderTexture = 3,
    kSharedTexture = 4,
    kIncompatibleTransform = 5,
    kUnitaryTextureArray = 6,
    kMaxValue = kUnitaryTextureArray,
  };

  // This keeps track of whether the previous 30 frames used Overlays or GPU
  // composition to present.
  class PresentationHistory {
   public:
    static const int kPresentsToStore = 30;

    PresentationHistory();
    ~PresentationHistory();

    void AddSample(DXGI_FRAME_PRESENTATION_MODE mode);

    void Clear();
    bool Valid() const;
    int composed_count() const;

   private:
    base::circular_deque<DXGI_FRAME_PRESENTATION_MODE> presents_;
    int composed_count_ = 0;

    DISALLOW_COPY_AND_ASSIGN(PresentationHistory);
  };

  // Upload given YUV buffers to an NV12 texture that can be used to create
  // video processor input view.  Returns nullptr on failure.
  Microsoft::WRL::ComPtr<ID3D11Texture2D> UploadVideoImages(
      GLImageMemory* y_image_memory,
      GLImageMemory* uv_image_memory);

  // Releases resources that might hold indirect references to the swap chain.
  void ReleaseSwapChainResources();

  // Recreate swap chain using given size.  Use preferred YUV format if
  // |use_yuv_swap_chain| is true, or BGRA otherwise.  Sets flags based on
  // |protected_video_type|. Returns true on success.
  bool ReallocateSwapChain(const gfx::Size& swap_chain_size,
                           bool use_yuv_swap_chain,
                           gfx::ProtectedVideoType protected_video_type,
                           bool z_order);

  // Returns true if YUV swap chain should be preferred over BGRA swap chain.
  // This changes over time based on stats recorded in |presentation_history|.
  bool ShouldUseYUVSwapChain(gfx::ProtectedVideoType protected_video_type);

  // Perform a blit using video processor from given input texture to swap chain
  // backbuffer. |input_texture| is the input texture (array), and |input_level|
  // is the index of the texture in the texture array.  |keyed_mutex| is
  // optional, and is used to lock the resource for reading.  |content_rect| is
  // subrectangle of the input texture that should be blitted to swap chain, and
  // |src_color_space| is the color space of the video.
  bool VideoProcessorBlt(Microsoft::WRL::ComPtr<ID3D11Texture2D> input_texture,
                         UINT input_level,
                         Microsoft::WRL::ComPtr<IDXGIKeyedMutex> keyed_mutex,
                         const gfx::Rect& content_rect,
                         const gfx::ColorSpace& src_color_space);

  // Returns optimal swap chain size for given layer.
  gfx::Size CalculateSwapChainSize(const ui::DCRendererLayerParams& params);

  // Update direct composition visuals for layer with given swap chain size.
  void UpdateVisuals(const ui::DCRendererLayerParams& params,
                     const gfx::Size& swap_chain_size);

  // Try presenting to a decode swap chain based on various conditions such as
  // global state (e.g. finch, NV12 support), texture flags, and transform.
  // Returns true on success.  See PresentToDecodeSwapChain() for more info.
  bool TryPresentToDecodeSwapChain(GLImageDXGI* nv12_image,
                                   const gfx::Rect& content_rect,
                                   const gfx::Size& swap_chain_size);

  // Present to a decode swap chain created from compatible video decoder
  // buffers using given |nv12_image| with destination size |swap_chain_size|.
  // Returns true on success.
  bool PresentToDecodeSwapChain(GLImageDXGI* nv12_image,
                                const gfx::Rect& content_rect,
                                const gfx::Size& swap_chain_size);

  // Records presentation statistics in UMA and traces (for pixel tests) for the
  // current swap chain which could either be a regular flip swap chain or a
  // decode swap chain.
  void RecordPresentationStatistics();

  // base::PowerObserver
  void OnPowerStateChange(bool on_battery_power) override;

  // If connected with a power source, let the Intel video processor to do
  // the upscaling because it produces better results.
  bool ShouldUseVideoProcessorScaling();

  // Layer tree instance that owns this swap chain presenter.
  DCLayerTree* layer_tree_ = nullptr;

  // Current size of swap chain.
  gfx::Size swap_chain_size_;

  // Whether the current swap chain is using the preferred YUV format.
  bool is_yuv_swapchain_ = false;

  // Whether the swap chain was reallocated, and next present will be the first.
  bool first_present_ = false;

  // Whether the current swap chain is presenting protected video, software
  // or hardware protection.
  gfx::ProtectedVideoType protected_video_type_ =
      gfx::ProtectedVideoType::kClear;

  // Presentation history to track if swap chain was composited or used hardware
  // overlays.
  PresentationHistory presentation_history_;

  // Whether creating a YUV swap chain failed.
  bool failed_to_create_yuv_swapchain_ = false;

  // Set to true when PresentToDecodeSwapChain fails for the first time after
  // which we won't attempt to use decode swap chain again.
  bool failed_to_present_decode_swapchain_ = false;

  // Number of frames since we switched from YUV to BGRA swap chain, or
  // vice-versa.
  int frames_since_color_space_change_ = 0;

  // This struct is used to cache information about what visuals are currently
  // being presented so that properties that aren't changed aren't sent to
  // DirectComposition.
  struct VisualInfo {
    gfx::Point offset;
    gfx::Transform transform;
    bool is_clipped = false;
    gfx::Rect clip_rect;
    int z_order = 0;
  } visual_info_;

  // Direct composition visual containing the swap chain content.  Child of
  // |clip_visual_|.
  Microsoft::WRL::ComPtr<IDCompositionVisual2> content_visual_;

  // Direct composition visual that applies the clip rect.  Parent of
  // |content_visual_|, and root of the visual tree for this layer.
  Microsoft::WRL::ComPtr<IDCompositionVisual2> clip_visual_;

  // GLImages that were presented in the last frame.
  ui::DCRendererLayerParams::OverlayImages last_presented_images_;

  // NV12 staging texture used for software decoded YUV buffers.  Mapped to CPU
  // for copying from YUV buffers.  Texture usage is DYNAMIC or STAGING.
  Microsoft::WRL::ComPtr<ID3D11Texture2D> staging_texture_;
  // Used to copy from staging texture with usage STAGING for workarounds.
  Microsoft::WRL::ComPtr<ID3D11Texture2D> copy_texture_;
  gfx::Size staging_texture_size_;

  Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device_;
  Microsoft::WRL::ComPtr<IDCompositionDevice2> dcomp_device_;
  Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain_;

  // Handle returned by DCompositionCreateSurfaceHandle() used to create YUV
  // swap chain that can be used for direct composition.
  base::win::ScopedHandle swap_chain_handle_;

  // Video processor output view created from swap chain back buffer.  Must be
  // cached for performance reasons.
  Microsoft::WRL::ComPtr<ID3D11VideoProcessorOutputView> output_view_;

  Microsoft::WRL::ComPtr<IDXGIResource> decode_resource_;
  Microsoft::WRL::ComPtr<IDXGIDecodeSwapChain> decode_swap_chain_;
  Microsoft::WRL::ComPtr<IUnknown> decode_surface_;
  bool is_on_battery_power_;

  DISALLOW_COPY_AND_ASSIGN(SwapChainPresenter);
};

}  // namespace gl

#endif  // UI_GL_SWAP_CHAIN_PRESENTER_H_