Skip to content

Commit

Permalink
Wire up global frame rate to video and root swap chains on Windows.
Browse files Browse the repository at this point in the history
This may allow DWM and OS to reduce vsync when video is fullscreen
and iflip.

BUG=711140
TEST=manual
R=khushalsagar@chromium.org,sunnyps@chromium.org,Rafael.Cintron@microsoft.com

Change-Id: I77631a64f61961bccb983df6893d67cba71c99b2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2303646
Reviewed-by: Alexei Svitkine <asvitkine@chromium.org>
Reviewed-by: Sunny Sachanandani <sunnyps@chromium.org>
Reviewed-by: Rafael Cintron <rafael.cintron@microsoft.com>
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Reviewed-by: Khushal <khushalsagar@chromium.org>
Commit-Queue: Zhenyao Mo <zmo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#791672}
  • Loading branch information
zhenyao authored and Commit Bot committed Jul 26, 2020
1 parent c5e96cb commit 8b36acb
Show file tree
Hide file tree
Showing 19 changed files with 191 additions and 23 deletions.
12 changes: 12 additions & 0 deletions components/viz/common/features.cc
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@ const base::Feature kWebRtcLogCapturePipeline{
const base::FeatureParam<int> kNumOfFramesToToggleInterval{
&kUsePreferredIntervalForVideo, "NumOfFramesToToggleInterval", 60};

#if defined(OS_WIN)
// Enables swap chains to call SetPresentDuration to request DWM/OS to reduce
// vsync.
const base::Feature kUseSetPresentDuration{"UseSetPresentDuration",
base::FEATURE_DISABLED_BY_DEFAULT};
#endif // OS_WIN

bool IsForcePreferredIntervalForVideoEnabled() {
return base::FeatureList::IsEnabled(kForcePreferredIntervalForVideo);
}
Expand Down Expand Up @@ -156,4 +163,9 @@ bool ShouldWebRtcLogCapturePipeline() {
return base::FeatureList::IsEnabled(kWebRtcLogCapturePipeline);
}

#if defined(OS_WIN)
bool ShouldUseSetPresentDuration() {
return base::FeatureList::IsEnabled(kUseSetPresentDuration);
}
#endif // OS_WIN
} // namespace features
6 changes: 6 additions & 0 deletions components/viz/common/features.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ VIZ_COMMON_EXPORT extern const base::Feature kUseSkiaOutputDeviceBufferQueue;
#endif
VIZ_COMMON_EXPORT extern const base::Feature kSplitPartiallyOccludedQuads;
VIZ_COMMON_EXPORT extern const base::Feature kWebRtcLogCapturePipeline;
#if defined(OS_WIN)
VIZ_COMMON_EXPORT extern const base::Feature kUseSetPresentDuration;
#endif // OS_WIN

VIZ_COMMON_EXPORT bool IsForcePreferredIntervalForVideoEnabled();
VIZ_COMMON_EXPORT bool IsVizHitTestingDebugEnabled();
Expand All @@ -44,6 +47,9 @@ VIZ_COMMON_EXPORT int NumOfFramesToToggleInterval();
VIZ_COMMON_EXPORT bool ShouldUseRealBuffersForPageFlipTest();
VIZ_COMMON_EXPORT bool ShouldSplitPartiallyOccludedQuads();
VIZ_COMMON_EXPORT bool ShouldWebRtcLogCapturePipeline();
#if defined(OS_WIN)
VIZ_COMMON_EXPORT bool ShouldUseSetPresentDuration();
#endif // OS_WIN

} // namespace features

Expand Down
7 changes: 5 additions & 2 deletions components/viz/service/display/display.cc
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,9 @@ bool SupportsSetFrameRate(const OutputSurface* output_surface) {
#if defined(OS_ANDROID)
return output_surface->capabilities().supports_surfaceless &&
gl::SurfaceControl::SupportsSetFrameRate();
#elif defined(OS_WIN)
return output_surface->capabilities().supports_dc_layers &&
features::ShouldUseSetPresentDuration();
#endif
return false;
}
Expand Down Expand Up @@ -1239,8 +1242,8 @@ void Display::RemoveOverdrawQuads(AggregatedFrame* frame) {

void Display::SetPreferredFrameInterval(base::TimeDelta interval) {
if (frame_rate_decider_->supports_set_frame_rate()) {
float frame_rate =
interval.InSecondsF() == 0 ? 0 : (1 / interval.InSecondsF());
float interval_s = interval.InSecondsF();
float frame_rate = interval_s == 0 ? 0 : (1 / interval_s);
output_surface_->SetFrameRate(frame_rate);
return;
}
Expand Down
7 changes: 7 additions & 0 deletions components/viz/service/display/frame_rate_decider.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

#include "components/viz/service/display/frame_rate_decider.h"

#include <algorithm>
#include <utility>

#include "components/viz/common/frame_sinks/begin_frame_args.h"
#include "components/viz/service/surfaces/surface.h"
#include "components/viz/service/surfaces/surface_manager.h"
Expand Down Expand Up @@ -242,4 +245,8 @@ void FrameRateDecider::SetPreferredInterval(
}
}

bool FrameRateDecider::multiple_refresh_rates_supported() const {
return supports_set_frame_rate_ || supported_intervals_.size() > 1u;
}

} // namespace viz
6 changes: 3 additions & 3 deletions components/viz/service/display/frame_rate_decider.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_FRAME_RATE_DECIDER_H_
#define COMPONENTS_VIZ_SERVICE_DISPLAY_FRAME_RATE_DECIDER_H_

#include <vector>

#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/time/time.h"
Expand Down Expand Up @@ -79,9 +81,7 @@ class VIZ_SERVICE_EXPORT FrameRateDecider : public SurfaceObserver {
void EndAggregation();
void UpdatePreferredFrameIntervalIfNeeded();
void SetPreferredInterval(base::TimeDelta new_preferred_interval);
bool multiple_refresh_rates_supported() const {
return supported_intervals_.size() > 1u;
}
bool multiple_refresh_rates_supported() const;

bool inside_surface_aggregation_ = false;
base::flat_map<SurfaceId, uint64_t> current_surface_id_to_active_index_;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

#include "components/viz/service/frame_sinks/root_compositor_frame_sink_impl.h"

#include <algorithm>
#include <utility>
#include <vector>

#include "base/compiler_specific.h"
#include "base/memory/ptr_util.h"
Expand Down Expand Up @@ -87,6 +89,11 @@ RootCompositorFrameSinkImpl::Create(
std::make_unique<DelayBasedTimeSource>(
base::ThreadTaskRunnerHandle::Get().get()));
} else if (output_surface->capabilities().supports_gpu_vsync) {
#if defined(OS_WIN)
hw_support_for_multiple_refresh_rates =
output_surface->capabilities().supports_dc_layers &&
params->set_present_duration_allowed;
#endif
// Vsync updates are required to update the FrameRateDecider with
// supported refresh rates.
wants_vsync_updates = params->use_preferred_interval_for_video;
Expand Down
4 changes: 4 additions & 0 deletions content/browser/compositor/viz_process_transport_factory.cc
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,10 @@ void VizProcessTransportFactory::OnEstablishedGpuChannel(
features::IsUsingPreferredIntervalForVideo();
root_params->num_of_frames_to_toggle_interval =
features::NumOfFramesToToggleInterval();
#if defined(OS_WIN)
root_params->set_present_duration_allowed =
features::ShouldUseSetPresentDuration();
#endif // OS_WIN

// Connects the viz process end of CompositorFrameSink message pipes. The
// browser compositor may request a new CompositorFrameSink on context loss,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ struct RootCompositorFrameSinkParams {
[EnableIf=is_android]
float refresh_rate;

[EnableIf=is_win]
bool set_present_duration_allowed = false;

pending_associated_receiver<CompositorFrameSink> compositor_frame_sink;
pending_remote<CompositorFrameSinkClient> compositor_frame_sink_client;

Expand Down
11 changes: 11 additions & 0 deletions tools/metrics/histograms/histograms.xml
Original file line number Diff line number Diff line change
Expand Up @@ -64903,6 +64903,17 @@ reviews. Googlers can read more about this at go/gwsq-gerrit.
</summary>
</histogram>

<histogram name="GPU.DirectComposition.ApprovedPresentDuration" units="ms"
expires_after="2021-01-03">
<owner>sunnyps@chromium.org</owner>
<owner>zmo@chromium.org</owner>
<summary>
If the system approves a swap chain's custom present duration request, this
is the approved custom present duration. If the swap chain's custom present
duration request is not approved, this is zero.
</summary>
</histogram>

<histogram name="GPU.DirectComposition.CompositionMode"
enum="DxgiFramePresentationMode" expires_after="2021-01-03">
<owner>sunnyps@chromium.org</owner>
Expand Down
8 changes: 8 additions & 0 deletions ui/gl/dc_layer_tree.cc
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,8 @@ bool DCLayerTree::CommitAndClearPendingOverlays(
} else {
new_video_swap_chains.emplace_back(std::make_unique<SwapChainPresenter>(
this, d3d11_device_, dcomp_device_));
if (frame_rate_ > 0)
new_video_swap_chains.back()->SetFrameRate(frame_rate_);
}
}
video_swap_chains_.swap(new_video_swap_chains);
Expand Down Expand Up @@ -255,4 +257,10 @@ bool DCLayerTree::ScheduleDCLayer(const ui::DCRendererLayerParams& params) {
return true;
}

void DCLayerTree::SetFrameRate(float frame_rate) {
frame_rate_ = frame_rate;
for (size_t ii = 0; ii < video_swap_chains_.size(); ++ii)
video_swap_chains_[ii]->SetFrameRate(frame_rate);
}

} // namespace gl
5 changes: 5 additions & 0 deletions ui/gl/dc_layer_tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ class DCLayerTree {
Microsoft::WRL::ComPtr<IDXGISwapChain1> GetLayerSwapChainForTesting(
size_t index) const;

void SetFrameRate(float frame_rate);

private:
const bool disable_nv12_dynamic_textures_;
const bool disable_larger_than_screen_overlays_;
Expand Down Expand Up @@ -126,6 +128,9 @@ class DCLayerTree {
// List of swap chain presenters for previous frame.
std::vector<std::unique_ptr<SwapChainPresenter>> video_swap_chains_;

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

DISALLOW_COPY_AND_ASSIGN(DCLayerTree);
};

Expand Down
21 changes: 21 additions & 0 deletions ui/gl/direct_composition_child_surface_win.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_surface_egl.h"
#include "ui/gl/gl_switches.h"
#include "ui/gl/gl_utils.h"
#include "ui/gl/scoped_make_current.h"

#ifndef EGL_ANGLE_flexible_surface_compatibility
Expand Down Expand Up @@ -123,6 +124,7 @@ bool DirectCompositionChildSurfaceWin::ReleaseDrawTexture(bool will_discard) {
UINT interval =
first_swap_ || !vsync_enabled_ || use_swap_chain_tearing ? 0 : 1;
UINT flags = use_swap_chain_tearing ? DXGI_PRESENT_ALLOW_TEARING : 0;
flags |= DXGI_PRESENT_USE_DURATION;
DXGI_PRESENT_PARAMETERS params = {};
RECT dirty_rect = swap_rect_.ToRECT();
params.DirtyRectsCount = 1;
Expand Down Expand Up @@ -349,6 +351,8 @@ bool DirectCompositionChildSurfaceWin::SetDrawRectangle(
DCHECK(SUCCEEDED(hr))
<< "SetColorSpace1 failed with error " << std::hex << hr;
}

SetSwapChainPresentDuration();
}

swap_rect_ = rectangle;
Expand Down Expand Up @@ -473,6 +477,23 @@ bool DirectCompositionChildSurfaceWin::SetEnableDCLayers(bool enable) {
return true;
}

void DirectCompositionChildSurfaceWin::SetFrameRate(float frame_rate) {
frame_rate_ = frame_rate;
SetSwapChainPresentDuration();
}

void DirectCompositionChildSurfaceWin::SetSwapChainPresentDuration() {
if (!swap_chain_)
return;
Microsoft::WRL::ComPtr<IDXGISwapChainMedia> swap_chain_media;
if (SUCCEEDED(swap_chain_.As(&swap_chain_media))) {
UINT duration_100ns = FrameRateToPresentDuration(frame_rate_);
HRESULT hr = swap_chain_media->SetPresentDuration(duration_100ns);
if (FAILED(hr))
DLOG(ERROR) << "SetPresentDuration failed with error " << std::hex << hr;
}
}

// static
bool DirectCompositionChildSurfaceWin::IsDirectCompositionSwapChainFailed() {
return g_direct_composition_swap_chain_failed;
Expand Down
9 changes: 9 additions & 0 deletions ui/gl/direct_composition_child_surface_win.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ class GL_EXPORT DirectCompositionChildSurfaceWin : public GLSurfaceEGL {
const gfx::ColorSpace& color_space,
bool has_alpha) override;
bool SetEnableDCLayers(bool enable) override;
void SetFrameRate(float frame_rate) override;

static bool IsDirectCompositionSwapChainFailed();

const Microsoft::WRL::ComPtr<IDCompositionSurface>& dcomp_surface() const {
Expand All @@ -62,6 +64,10 @@ class GL_EXPORT DirectCompositionChildSurfaceWin : public GLSurfaceEGL {
// to it. Returns false if this fails.
bool ReleaseDrawTexture(bool will_discard);

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

const bool use_angle_texture_offset_;

gfx::Size size_ = gfx::Size(1, 1);
Expand Down Expand Up @@ -92,6 +98,9 @@ class GL_EXPORT DirectCompositionChildSurfaceWin : public GLSurfaceEGL {
Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain_;
Microsoft::WRL::ComPtr<ID3D11Texture2D> draw_texture_;

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

DISALLOW_COPY_AND_ASSIGN(DirectCompositionChildSurfaceWin);
};

Expand Down
5 changes: 5 additions & 0 deletions ui/gl/direct_composition_surface_win.cc
Original file line number Diff line number Diff line change
Expand Up @@ -767,6 +767,11 @@ bool DirectCompositionSurfaceWin::ScheduleDCLayer(
return layer_tree_->ScheduleDCLayer(params);
}

void DirectCompositionSurfaceWin::SetFrameRate(float frame_rate) {
layer_tree_->SetFrameRate(frame_rate);
root_surface_->SetFrameRate(frame_rate);
}

bool DirectCompositionSurfaceWin::SetEnableDCLayers(bool enable) {
return root_surface_->SetEnableDCLayers(enable);
}
Expand Down
1 change: 1 addition & 0 deletions ui/gl/direct_composition_surface_win.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ class GL_EXPORT DirectCompositionSurfaceWin : public GLSurfaceEGL,
// scheduled with ScheduleDCLayer, as it's automatically placed in the layer
// tree at z-order 0.
bool ScheduleDCLayer(const ui::DCRendererLayerParams& params) override;
void SetFrameRate(float frame_rate) override;

// VSyncObserver implementation.
void OnVSync(base::TimeTicks vsync_time, base::TimeDelta interval) override;
Expand Down
9 changes: 8 additions & 1 deletion ui/gl/gl_utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -105,5 +105,12 @@ bool PassthroughCommandDecoderSupported() {
bool AreOverlaysSupportedWin() {
return gl::DirectCompositionSurfaceWin::AreOverlaysSupported();
}
#endif

unsigned int FrameRateToPresentDuration(float frame_rate) {
if (frame_rate == 0)
return 0u;
// Present duration unit is 100 ns.
return static_cast<unsigned int>(1.0E7 / frame_rate);
}
#endif // OS_WIN
} // namespace gl
3 changes: 3 additions & 0 deletions ui/gl/gl_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ GL_EXPORT bool PassthroughCommandDecoderSupported();

#if defined(OS_WIN)
GL_EXPORT bool AreOverlaysSupportedWin();

// Calculates present during in 100 ns from number of frames per second.
GL_EXPORT unsigned int FrameRateToPresentDuration(float frame_rate);
#endif

} // namespace gl
Expand Down
Loading

0 comments on commit 8b36acb

Please sign in to comment.