// 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 #include #include #include #include "base/containers/circular_deque.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_renderer_layer_params.h" namespace gl { class DCLayerTree; 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::PowerStateObserver { public: SwapChainPresenter(DCLayerTree* layer_tree, HWND window, Microsoft::WRL::ComPtr d3d11_device, Microsoft::WRL::ComPtr dcomp_device); ~SwapChainPresenter() override; // Present the given overlay to swap chain. Returns true on success. bool PresentToSwapChain(ui::DCRendererLayerParams& overlay); const Microsoft::WRL::ComPtr& swap_chain() const { return swap_chain_; } const Microsoft::WRL::ComPtr& visual() const { return clip_visual_; } void SetFrameRate(float frame_rate); void GetSwapChainVisualInfoForTesting(gfx::Transform* transform, gfx::Point* offset, gfx::Rect* clip_rect) const { *transform = visual_info_.transform; *offset = visual_info_.offset; *clip_rect = visual_info_.clip_rect.value_or(gfx::Rect()); } 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 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 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, 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. |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 input_texture, UINT input_level, Microsoft::WRL::ComPtr keyed_mutex, const gfx::Rect& content_rect, const gfx::ColorSpace& src_color_space, bool content_is_hdr, absl::optional stream_hdr_metadata); gfx::Size GetMonitorSize(); // 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 fullscreen DWM optimizations. void AdjustSwapChainToFullScreenSizeIfNeeded( const ui::DCRendererLayerParams& params, const gfx::Rect& overlay_onscreen_rect, gfx::Size* swap_chain_size, gfx::Transform* transform, gfx::Rect* clip_rect); // Returns optimal swap chain size for given layer. gfx::Size CalculateSwapChainSize(const ui::DCRendererLayerParams& params, gfx::Transform* transform, gfx::Rect* clip_rect); // Update direct composition visuals for layer with given swap chain size. void UpdateVisuals(const ui::DCRendererLayerParams& params, const gfx::Size& swap_chain_size, const gfx::Transform& transform, const gfx::Rect& clip_rect); // 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 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); // 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(Microsoft::WRL::ComPtr texture, unsigned array_slice, const gfx::ColorSpace& color_space, 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::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 GetSwapChainMedia() const; // Present the Direct Compositon surface from MediaFoundationRenderer. bool PresentDCOMPSurface(const ui::DCRendererLayerParams& overlay); // Release resources related to `PresentDCOMPSurface()`. void ReleaseDCOMPSurfaceResourcesIfNeeded(); // The Direct Composition surface handle from MediaFoundationRenderer. HANDLE dcomp_surface_handle_ = INVALID_HANDLE_VALUE; // Layer tree instance that owns this swap chain presenter. DCLayerTree* layer_tree_ = nullptr; const HWND window_; // Current size of swap chain. gfx::Size swap_chain_size_; // 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 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; // 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 { VisualInfo(); ~VisualInfo(); gfx::Point offset; gfx::Transform transform; absl::optional clip_rect; int z_order = 0; } visual_info_; // Direct composition visual containing the swap chain content. Child of // |clip_visual_|. Microsoft::WRL::ComPtr 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 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 staging_texture_; // Used to copy from staging texture with usage STAGING for workarounds. Microsoft::WRL::ComPtr copy_texture_; gfx::Size staging_texture_size_; Microsoft::WRL::ComPtr d3d11_device_; Microsoft::WRL::ComPtr dcomp_device_; Microsoft::WRL::ComPtr 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 output_view_; Microsoft::WRL::ComPtr decode_resource_; Microsoft::WRL::ComPtr decode_swap_chain_; Microsoft::WRL::ComPtr decode_surface_; bool is_on_battery_power_; // Number of frames per second. float frame_rate_ = 0.f; DISALLOW_COPY_AND_ASSIGN(SwapChainPresenter); }; } // namespace gl #endif // UI_GL_SWAP_CHAIN_PRESENTER_H_