File: swap_chain_presenter.h

package info (click to toggle)
chromium 120.0.6099.224-1~deb11u1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 6,112,112 kB
  • sloc: cpp: 32,907,025; ansic: 8,148,123; javascript: 3,679,536; python: 2,031,248; asm: 959,718; java: 804,675; xml: 617,256; sh: 111,417; objc: 100,835; perl: 88,443; cs: 53,032; makefile: 29,579; fortran: 24,137; php: 21,162; tcl: 21,147; sql: 20,809; ruby: 17,735; pascal: 12,864; yacc: 8,045; lisp: 3,388; lex: 1,323; ada: 727; awk: 329; jsp: 267; csh: 117; exp: 43; sed: 37
file content (340 lines) | stat: -rw-r--r-- 14,301 bytes parent folder | download
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
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
// Copyright 2019 The Chromium Authors
// 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 <d3d11.h>
#include <dcomp.h>
#include <windows.h>
#include <wrl/client.h>

#include "base/containers/circular_deque.h"
#include "base/memory/raw_ptr.h"
#include "base/power_monitor/power_monitor.h"
#include "base/time/time.h"
#include "base/win/scoped_handle.h"
#include "ui/gfx/color_space.h"
#include "ui/gl/dc_layer_overlay_params.h"
#include "ui/gl/dc_layer_tree.h"

namespace gl {

// 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::PowerStateObserver {
 public:
  SwapChainPresenter(DCLayerTree* layer_tree,
                     Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device,
                     Microsoft::WRL::ComPtr<IDCompositionDevice2> dcomp_device);

  SwapChainPresenter(const SwapChainPresenter&) = delete;
  SwapChainPresenter& operator=(const SwapChainPresenter&) = delete;

  ~SwapChainPresenter() override;

  // Present the given overlay to swap chain. The backing content may not match
  // |overlay.quad_rect| (e.g. in the case of full screen) so this method
  // returns a modified |visual_transform| and |visual_clip_rect| that should be
  // used instead of the ones on |overlay|.
  // Returns true on success.
  bool PresentToSwapChain(DCLayerOverlayParams& overlay,
                          gfx::Transform* visual_transform,
                          gfx::Rect* visual_clip_rect);

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

  const Microsoft::WRL::ComPtr<IUnknown>& content() const { return content_; }

  const gfx::Size& content_size() const { return content_size_; }

  void SetFrameRate(float frame_rate);

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

  // 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(const PresentationHistory&) = delete;
    PresentationHistory& operator=(const PresentationHistory&) = delete;

    ~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;
  };

  // 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> UploadVideoImage(
      const gfx::Size& size,
      const uint8_t* nv12_pixmap,
      size_t stride);

  // 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,
                           DXGI_FORMAT swap_chain_format,
                           gfx::ProtectedVideoType protected_video_type);

  // Returns DXGI format that swap chain uses.
  // This changes over time based on stats recorded in |presentation_history|.
  DXGI_FORMAT GetSwapChainFormat(gfx::ProtectedVideoType protected_video_type,
                                 bool content_is_hdr);

  // 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. |content_rect| is the
  // sub-rectangle 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,
      const gfx::Rect& content_rect,
      const gfx::ColorSpace& src_color_space,
      absl::optional<DXGI_HDR_METADATA_HDR10> stream_hdr_metadata,
      bool use_vp_auto_hdr);

  // Get the size of the monitor on which the window handle is displayed.
  gfx::Size GetMonitorSize() const;

  // Update the |visual_transform| and |visual_clip_rect| accordingly after
  // succeeded presentation with letterboxing for overaly scenario. This will
  // make sure the video full screen letterboxing take the whole monitor area,
  // and DWM will take care of the letterboxing info setup automatically.
  void SetTargetToFullScreen(gfx::Transform* visual_transform,
                             gfx::Rect* visual_clip_rect);

  // Takes in input DC layer params and the video overlay quad. The swap chain
  // backbuffer size will be rounded to the monitor size if it is within a close
  // margin. The |visual_transform| will be calculated by what scaling factor is
  // needed to scale the swap chain backbuffer to the monitor size.
  // The |visual_clip_rect| will be adjusted to the monitor size for full screen
  // mode, and to the video overlay quad for letterboxing mode.
  // The returned optional |dest_size| and |target_rect| have the same meaning
  // as in AdjustTargetForFullScreenLetterboxing.
  void AdjustTargetToOptimalSizeIfNeeded(
      const DCLayerOverlayParams& params,
      const gfx::Rect& overlay_onscreen_rect,
      gfx::Size* swap_chain_size,
      gfx::Transform* visual_transform,
      gfx::Rect* visual_clip_rect,
      absl::optional<gfx::Size>* dest_size,
      absl::optional<gfx::Rect>* target_rect) const;

  // If the swap chain size is very close to the screen size but not exactly the
  // same, the swap chain should be adjusted to fit the screen size in order to
  // get the full screen DWM optimizations.
  bool AdjustTargetToFullScreenSizeIfNeeded(
      const gfx::Size& monitor_size,
      const DCLayerOverlayParams& params,
      const gfx::Rect& overlay_onscreen_rect,
      gfx::Size* swap_chain_size,
      gfx::Transform* visual_transform,
      gfx::Rect* visual_clip_rect) const;

  // If the returned optional |dest_size| and |target_rect| contain valid
  // values, it means this is a good overlay for full screen letterboxing after
  // some necessary adjustment or no size adjustment required. Otherwise, it's
  // either not a letterboxing video or not a case for further optimizations for
  // full screen letterboxing. |swap_chain_| will then run SetDestSize to
  // |dest_size| and SetTargetRect to |target_rect| in order to make sure
  // Desktop Window Manager(DWM) take over the letterboxing/positioning job, and
  // turn off the topmost desktop plane at the same time.
  void AdjustTargetForFullScreenLetterboxing(
      const gfx::Size& monitor_size,
      const DCLayerOverlayParams& params,
      const gfx::Rect& overlay_onscreen_rect,
      gfx::Size* swap_chain_size,
      gfx::Transform* visual_transform,
      gfx::Rect* visual_clip_rect,
      absl::optional<gfx::Size>* dest_size,
      absl::optional<gfx::Rect>* target_rect) const;

  // Returns optimal swap chain size for given layer.
  gfx::Size CalculateSwapChainSize(
      const DCLayerOverlayParams& params,
      gfx::Transform* visual_transform,
      gfx::Rect* visual_clip_rect,
      absl::optional<gfx::Size>* dest_size,
      absl::optional<gfx::Rect>* target_rect) const;

  // 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(
      Microsoft::WRL::ComPtr<ID3D11Texture2D> texture,
      unsigned array_slice,
      const gfx::ColorSpace& color_space,
      const gfx::Rect& content_rect,
      const gfx::Size& swap_chain_size,
      DXGI_FORMAT swap_chain_format,
      const gfx::Transform& transform_to_root,
      const absl::optional<gfx::Size> dest_size,
      const absl::optional<gfx::Rect> target_rect);

  // Present to a decode swap chain created from compatible video decoder
  // buffers using given |nv12_image|.
  // Use |dest_size| for destination size and |target_rect| for target rectangle
  // if valid. Otherwise, |swap_chain_size| would be used instead.
  // Returns true on success.
  bool PresentToDecodeSwapChain(Microsoft::WRL::ComPtr<ID3D11Texture2D> texture,
                                unsigned array_slice,
                                const gfx::ColorSpace& color_space,
                                const gfx::Rect& content_rect,
                                const gfx::Size& swap_chain_size,
                                const absl::optional<gfx::Size> dest_size,
                                const absl::optional<gfx::Rect> target_rect);

  // 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::PowerStateObserver
  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();

  // This is called when a new swap chain is created, or when a new frame
  // rate is received.
  void SetSwapChainPresentDuration();

  // Returns swap chain media for either |swap_chain_| or |decode_swap_chain_|,
  // whichever is currently used.
  Microsoft::WRL::ComPtr<IDXGISwapChainMedia> GetSwapChainMedia() const;

  // Present the Direct Composition surface from MediaFoundationRenderer.
  bool PresentDCOMPSurface(DCLayerOverlayParams& overlay,
                           gfx::Transform* visual_transform,
                           gfx::Rect* visual_clip_rect);

  // Release resources related to `PresentDCOMPSurface()`.
  void ReleaseDCOMPSurfaceResourcesIfNeeded();

  bool RevertSwapChainToSDR(
      Microsoft::WRL::ComPtr<ID3D11VideoDevice> video_device,
      Microsoft::WRL::ComPtr<ID3D11VideoProcessor> video_processor,
      Microsoft::WRL::ComPtr<ID3D11VideoProcessorEnumerator>
          video_processor_enumerator,
      Microsoft::WRL::ComPtr<IDXGISwapChain3> swap_chain3,
      Microsoft::WRL::ComPtr<ID3D11VideoContext1> context1,
      const gfx::ColorSpace& input_color_space);

  // The Direct Composition surface handle from MediaFoundationRenderer.
  HANDLE dcomp_surface_handle_ = INVALID_HANDLE_VALUE;

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

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

  // Current buffer count of swap chain.
  const UINT swap_chain_buffer_count_;

  // Current swap chain format.
  DXGI_FORMAT swap_chain_format_ = DXGI_FORMAT_B8G8R8A8_UNORM;

  // Last time tick when switching to BGRA8888 format.
  base::TimeTicks switched_to_BGRA8888_time_tick_;

  // 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 swap_chain_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;

  // The swap chain content, sometimes a IDCompositionSurface. This is updated
  // during |PresentToSwapChain| and copied to VisualSubtree owned by
  // DCLayerTree and set as the content of the content visual when the subtree
  // is updated.
  Microsoft::WRL::ComPtr<IUnknown> content_;
  // Size of the swap chain or dcomp surface assigned to |content_|.
  gfx::Size content_size_;

  // Overlay image that was presented in the last frame.
  absl::optional<DCLayerOverlayImage> last_overlay_image_;
  // Desktop plane removal status from the presentation of last frame.
  bool last_desktop_plane_removed_ = false;

  // 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_;

  bool enable_vp_auto_hdr_ = false;
  bool enable_vp_super_resolution_ = false;

  UINT gpu_vendor_id_ = 0;

  // Number of frames per second.
  float frame_rate_ = 0.f;
};

}  // namespace gl

#endif  // UI_GL_SWAP_CHAIN_PRESENTER_H_