Commit 8d79a26a authored by Sunny Sachanandani's avatar Sunny Sachanandani Committed by Commit Bot

Remove swap chain resize delay optimization

This causes video corruption when swap chain is resized to a small size
and then resized back to a large size.  If the swap chain doesn't update
after resizing back, it will remain with the smaller size.

It's also likely that this causes video corruption issues with minimize
and restore, and with the Aero peek live preview Windows feature.

Split out from crrev.com/1305198 because that change is more risky and
we want to wait until M72 branches to land it.

Bug: 908069
Change-Id: I8a3edde507bca836dbf321b8ebc4e486415d193b
Reviewed-on: https://chromium-review.googlesource.com/c/1352771Reviewed-by: default avatarZhenyao Mo <zmo@chromium.org>
Commit-Queue: Sunny Sachanandani <sunnyps@chromium.org>
Cr-Commit-Position: refs/heads/master@{#611554}
parent 9f3efe05
...@@ -45,9 +45,6 @@ ...@@ -45,9 +45,6 @@
namespace gpu { namespace gpu {
namespace { namespace {
// Number of stable frames before the swap chain can be resized
static constexpr int kNumFramesBeforeSwapChainResize = 30;
// Some drivers fail to correctly handle BT.709 video in overlays. This flag // Some drivers fail to correctly handle BT.709 video in overlays. This flag
// converts them to BT.601 in the video processor. // converts them to BT.601 in the video processor.
const base::Feature kFallbackBT709VideoToBT601{ const base::Feature kFallbackBT709VideoToBT601{
...@@ -490,10 +487,6 @@ class DCLayerTree::SwapChainPresenter { ...@@ -490,10 +487,6 @@ class DCLayerTree::SwapChainPresenter {
// Returns optimal swap chain size for given layer. // Returns optimal swap chain size for given layer.
gfx::Size CalculateSwapChainSize(const ui::DCRendererLayerParams& params); gfx::Size CalculateSwapChainSize(const ui::DCRendererLayerParams& params);
// Returns a stable swap chain size to prevent frequently recreating the swap
// chain until a number of frames with the size have been presented.
gfx::Size GetStableSwapChainSize(gfx::Size requested_swap_chain_size);
// Update direct composition visuals for layer with given swap chain size, and // Update direct composition visuals for layer with given swap chain size, and
// returns true if a commit is needed. // returns true if a commit is needed.
bool UpdateVisuals(const ui::DCRendererLayerParams& params, bool UpdateVisuals(const ui::DCRendererLayerParams& params,
...@@ -527,8 +520,6 @@ class DCLayerTree::SwapChainPresenter { ...@@ -527,8 +520,6 @@ class DCLayerTree::SwapChainPresenter {
// Number of frames since we switched from YUV to BGRA swap chain, or // Number of frames since we switched from YUV to BGRA swap chain, or
// vice-versa. // vice-versa.
int frames_since_color_space_change_ = 0; int frames_since_color_space_change_ = 0;
int frames_since_stable_swap_chain_resize_ = 0;
gfx::Size last_requested_swap_chain_size_;
// This struct is used to cache information about what visuals are currently // 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 // being presented so that properties that aren't changed aren't sent to
...@@ -701,36 +692,6 @@ bool DCLayerTree::SwapChainPresenter::ShouldUseYUVSwapChain() { ...@@ -701,36 +692,6 @@ bool DCLayerTree::SwapChainPresenter::ShouldUseYUVSwapChain() {
} }
} }
// To avoid frequent swap chain recreation during video resizing, keep
// the same swap chain size until the onscreen video size is stable for
// at least 30 frames.
gfx::Size DCLayerTree::SwapChainPresenter::GetStableSwapChainSize(
gfx::Size requested_swap_chain_size) {
if (requested_swap_chain_size == swap_chain_size_ ||
swap_chain_size_.IsEmpty() || requested_swap_chain_size.IsEmpty()) {
frames_since_stable_swap_chain_resize_ = 0;
last_requested_swap_chain_size_ = requested_swap_chain_size;
return requested_swap_chain_size;
}
if (requested_swap_chain_size == last_requested_swap_chain_size_) {
frames_since_stable_swap_chain_resize_++;
// Resize after seeing the same requested size for 30 consecutive frames.
if (frames_since_stable_swap_chain_resize_ >=
kNumFramesBeforeSwapChainResize) {
frames_since_stable_swap_chain_resize_ = 0;
last_requested_swap_chain_size_ = requested_swap_chain_size;
return requested_swap_chain_size;
}
} else {
frames_since_stable_swap_chain_resize_ = 0;
last_requested_swap_chain_size_ = requested_swap_chain_size;
}
// Keep the previous swap chain size
return swap_chain_size_;
}
bool DCLayerTree::SwapChainPresenter::UploadVideoImages( bool DCLayerTree::SwapChainPresenter::UploadVideoImages(
gl::GLImageMemory* y_image_memory, gl::GLImageMemory* y_image_memory,
gl::GLImageMemory* uv_image_memory) { gl::GLImageMemory* uv_image_memory) {
...@@ -856,11 +817,6 @@ gfx::Size DCLayerTree::SwapChainPresenter::CalculateSwapChainSize( ...@@ -856,11 +817,6 @@ gfx::Size DCLayerTree::SwapChainPresenter::CalculateSwapChainSize(
gfx::Size ceiled_input_size = gfx::Size ceiled_input_size =
gfx::ToCeiledSize(params.contents_rect.size()); gfx::ToCeiledSize(params.contents_rect.size());
swap_chain_size.SetToMin(ceiled_input_size); swap_chain_size.SetToMin(ceiled_input_size);
// We don't want to recreate the swap chain too frequently, so override the
// swap chain size with GetStableSwapChainSize().
// TODO(magchen): This might cause overlay downscaling if the new size is
// bigger than display_rect.
swap_chain_size = GetStableSwapChainSize(swap_chain_size);
} }
// 4:2:2 subsampled formats like YUY2 must have an even width, and 4:2:0 // 4:2:2 subsampled formats like YUY2 must have an even width, and 4:2:0
...@@ -1566,11 +1522,6 @@ void DirectCompositionSurfaceWin::SetScaledOverlaysSupportedForTesting( ...@@ -1566,11 +1522,6 @@ void DirectCompositionSurfaceWin::SetScaledOverlaysSupportedForTesting(
g_supports_scaled_overlays = value; g_supports_scaled_overlays = value;
} }
// static
int DirectCompositionSurfaceWin::GetNumFramesBeforeSwapChainResizeForTesting() {
return kNumFramesBeforeSwapChainResize;
}
// static // static
void DirectCompositionSurfaceWin::SetPreferNV12OverlaysForTesting() { void DirectCompositionSurfaceWin::SetPreferNV12OverlaysForTesting() {
g_overlay_format_used = OverlayFormat::kNV12; g_overlay_format_used = OverlayFormat::kNV12;
......
...@@ -60,8 +60,6 @@ class GPU_IPC_SERVICE_EXPORT DirectCompositionSurfaceWin ...@@ -60,8 +60,6 @@ class GPU_IPC_SERVICE_EXPORT DirectCompositionSurfaceWin
static void SetScaledOverlaysSupportedForTesting(bool value); static void SetScaledOverlaysSupportedForTesting(bool value);
static int GetNumFramesBeforeSwapChainResizeForTesting();
static void SetPreferNV12OverlaysForTesting(); static void SetPreferNV12OverlaysForTesting();
bool InitializeNativeWindow(); bool InitializeNativeWindow();
......
...@@ -409,94 +409,6 @@ TEST(DirectCompositionSurfaceTest, NoPresentTwice) { ...@@ -409,94 +409,6 @@ TEST(DirectCompositionSurfaceTest, NoPresentTwice) {
DestroySurface(std::move(surface)); DestroySurface(std::move(surface));
} }
// Ensure no frequent swap chain recreation due to size changes
TEST(DirectCompositionSurfaceTest, NoFrequentSwapchainRecreation) {
if (!CheckIfDCSupported())
return;
TestImageTransportSurfaceDelegate delegate;
scoped_refptr<DirectCompositionSurfaceWin> surface(
new DirectCompositionSurfaceWin(nullptr, delegate.AsWeakPtr(),
ui::GetHiddenWindow()));
EXPECT_TRUE(surface->Initialize());
scoped_refptr<gl::GLContext> context =
gl::init::CreateGLContext(nullptr, surface.get(), gl::GLContextAttribs());
EXPECT_TRUE(context->MakeCurrent(surface.get()));
surface->SetEnableDCLayers(true);
surface->SetScaledOverlaysSupportedForTesting(true);
Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
gl::QueryD3D11DeviceObjectFromANGLE();
// Initial frame
gfx::Size texture_size(50, 50);
Microsoft::WRL::ComPtr<ID3D11Texture2D> texture =
CreateNV12Texture(d3d11_device, texture_size, false);
scoped_refptr<gl::GLImageDXGI> image_dxgi(
new gl::GLImageDXGI(texture_size, nullptr));
image_dxgi->SetTexture(texture, 0);
image_dxgi->SetColorSpace(gfx::ColorSpace::CreateREC709());
gfx::Size window_size(100, 100);
ui::DCRendererLayerParams params(
false, gfx::Rect(), 1, gfx::Transform(),
std::vector<scoped_refptr<gl::GLImage>>{image_dxgi},
gfx::RectF(gfx::Rect(texture_size)), gfx::Rect(window_size), 0, 0, 1.0, 0,
ui::ProtectedVideoType::kClear);
surface->ScheduleDCLayer(params);
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, surface->SwapBuffers(base::DoNothing()));
Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain =
surface->GetLayerSwapChainForTesting(0);
ASSERT_TRUE(swap_chain);
// A new frame with the same swapchian size
surface->ScheduleDCLayer(params);
EXPECT_EQ(gfx::SwapResult::SWAP_ACK, surface->SwapBuffers(base::DoNothing()));
Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain2 =
surface->GetLayerSwapChainForTesting(0);
EXPECT_EQ(swap_chain2.Get(), swap_chain.Get());
// Start to change the swapchain size. It should not be recreated for the
// first few frames after the size change.
ui::DCRendererLayerParams params3(
false, gfx::Rect(), 1, gfx::Transform(),
std::vector<scoped_refptr<gl::GLImage>>{image_dxgi},
gfx::RectF(gfx::Rect(texture_size)), gfx::Rect(0, 0, 25, 25), 0, 0, 1.0,
0, ui::ProtectedVideoType::kClear);
for (int i = 1; i <= 5; ++i) {
surface->ScheduleDCLayer(params3);
EXPECT_EQ(gfx::SwapResult::SWAP_ACK,
surface->SwapBuffers(base::DoNothing()));
}
Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain3 =
surface->GetLayerSwapChainForTesting(0);
EXPECT_EQ(swap_chain3.Get(), swap_chain.Get());
// 31 frames with the same swapchain size
int frames = surface->GetNumFramesBeforeSwapChainResizeForTesting() + 1;
for (int i = 6; i <= frames; ++i) {
surface->ScheduleDCLayer(params3);
EXPECT_EQ(gfx::SwapResult::SWAP_ACK,
surface->SwapBuffers(base::DoNothing()));
}
// The swapchain should be recreated now
Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain4 =
surface->GetLayerSwapChainForTesting(0);
EXPECT_NE(swap_chain4.Get(), swap_chain.Get());
context = nullptr;
DestroySurface(std::move(surface));
}
// Ensure the swapchain size is set to the correct size if HW overlay scaling // Ensure the swapchain size is set to the correct size if HW overlay scaling
// is support - swapchain should be the minimum of the decoded // is support - swapchain should be the minimum of the decoded
// video buffer size and the onscreen video size // video buffer size and the onscreen video size
...@@ -1197,5 +1109,80 @@ TEST(DirectCompositionSurfaceTest, ProtectedVideos) { ...@@ -1197,5 +1109,80 @@ TEST(DirectCompositionSurfaceTest, ProtectedVideos) {
DestroySurface(std::move(surface)); DestroySurface(std::move(surface));
} }
TEST_F(DirectCompositionPixelTest, ResizeVideoLayer) {
if (!CheckIfDCSupported())
return;
InitializeSurface();
surface_->SetEnableDCLayers(true);
gfx::Size window_size(100, 100);
EXPECT_TRUE(surface_->Resize(window_size, 1.0,
gl::GLSurface::ColorSpace::UNSPECIFIED, true));
EXPECT_TRUE(surface_->SetDrawRectangle(gfx::Rect(window_size)));
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
gl::QueryD3D11DeviceObjectFromANGLE();
gfx::Size texture_size(50, 50);
Microsoft::WRL::ComPtr<ID3D11Texture2D> texture =
CreateNV12Texture(d3d11_device, texture_size, true);
Microsoft::WRL::ComPtr<IDXGIResource1> resource;
texture.CopyTo(resource.GetAddressOf());
HANDLE handle = 0;
resource->CreateSharedHandle(nullptr, DXGI_SHARED_RESOURCE_READ, nullptr,
&handle);
// The format doesn't matter, since we aren't binding.
scoped_refptr<gl::GLImageDXGIHandle> image_dxgi(
new gl::GLImageDXGIHandle(texture_size, 0, gfx::BufferFormat::RGBA_8888));
ASSERT_TRUE(image_dxgi->Initialize(base::win::ScopedHandle(handle)));
{
gfx::RectF contents_rect = gfx::RectF(gfx::Rect(texture_size));
ui::DCRendererLayerParams params(
false, gfx::Rect(), 1, gfx::Transform(),
std::vector<scoped_refptr<gl::GLImage>>{image_dxgi}, contents_rect,
gfx::Rect(window_size), 0, 0, 1.0, 0, ui::ProtectedVideoType::kClear);
surface_->ScheduleDCLayer(params);
EXPECT_EQ(gfx::SwapResult::SWAP_ACK,
surface_->SwapBuffers(base::DoNothing()));
Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain =
surface_->GetLayerSwapChainForTesting(0);
ASSERT_TRUE(swap_chain);
DXGI_SWAP_CHAIN_DESC1 desc;
EXPECT_TRUE(SUCCEEDED(swap_chain->GetDesc1(&desc)));
EXPECT_EQ(desc.Width, 50u);
EXPECT_EQ(desc.Height, 50u);
}
{
gfx::RectF contents_rect(30, 30);
ui::DCRendererLayerParams params(
false, gfx::Rect(), 1, gfx::Transform(),
std::vector<scoped_refptr<gl::GLImage>>{image_dxgi}, contents_rect,
gfx::Rect(window_size), 0, 0, 1.0, 0, ui::ProtectedVideoType::kClear);
surface_->ScheduleDCLayer(params);
EXPECT_EQ(gfx::SwapResult::SWAP_ACK,
surface_->SwapBuffers(base::DoNothing()));
Microsoft::WRL::ComPtr<IDXGISwapChain1> swap_chain =
surface_->GetLayerSwapChainForTesting(0).Get();
ASSERT_TRUE(swap_chain);
DXGI_SWAP_CHAIN_DESC1 desc;
EXPECT_TRUE(SUCCEEDED(swap_chain->GetDesc1(&desc)));
EXPECT_EQ(desc.Width, 30u);
EXPECT_EQ(desc.Height, 30u);
}
}
} // namespace } // namespace
} // namespace gpu } // namespace gpu
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment