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