chromium/components/viz/service/display_embedder/skia_output_device_buffer_queue_unittest.cc

// 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.

#include "components/viz/service/display_embedder/skia_output_device_buffer_queue.h"

#include <stddef.h>
#include <stdint.h>

#include <set>
#include <string>
#include <utility>

#include "base/functional/callback_helpers.h"
#include "base/memory/ptr_util.h"
#include "base/memory/raw_ptr.h"
#include "base/test/bind.h"
#include "base/test/mock_callback.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/simple_test_tick_clock.h"
#include "build/build_config.h"
#include "components/viz/common/features.h"
#include "components/viz/common/resources/resource_sizes.h"
#include "components/viz/service/display_embedder/output_presenter_gl.h"
#include "components/viz/service/display_embedder/skia_output_device.h"
#include "components/viz/service/display_embedder/skia_output_surface_dependency_impl.h"
#include "components/viz/service/gl/gpu_service_impl.h"
#include "components/viz/test/test_gpu_service_holder.h"
#include "gpu/command_buffer/common/shared_image_usage.h"
#include "gpu/command_buffer/service/shared_image/shared_image_backing_factory.h"
#include "gpu/command_buffer/service/shared_image/shared_image_factory.h"
#include "gpu/command_buffer/service/shared_image/test_image_backing.h"
#include "gpu/config/gpu_finch_features.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gl/gl_utils.h"
#include "ui/gl/presenter.h"

#if BUILDFLAG(IS_OZONE)
#include "ui/ozone/public/ozone_platform.h"
#endif

_;
Expectation;
Ne;
Return;

namespace viz {
namespace {

// These MACRO and TestOnGpu class make it easier to write tests that runs on
// GPU Thread
// Use TEST_F_GPU instead of TEST_F in the same manner and in your subclass
// of TestOnGpu implement SetUpOnMain/SetUpOnGpu and
// TearDownOnMain/TearDownOnGpu instead of SetUp and TearDown respectively.
//
// NOTE: Most likely you need to implement TearDownOnGpu instead of relying on
// destructor to ensure that necessary cleanup happens on GPU Thread.

// TODO(vasilyt): Extract this for others to use?

#define GTEST_TEST_GPU_(test_suite_name, test_name, parent_class, parent_id)

#define TEST_F_GPU(test_fixture, test_name)

const gfx::Size kScreenSize =;
const SkColorType kDefaultColorType =;

class TestOnGpu : public ::testing::Test {};

// Here starts SkiaOutputDeviceBufferQueue test related code

class TestImageBackingFactory : public gpu::SharedImageBackingFactory {};

class MockPresenter : public gl::Presenter {};

class MemoryTrackerStub : public gpu::MemoryTracker {};

}  // namespace

DidSwapBufferCompleteCallback;
BufferPresentedCallback;

class SkiaOutputDeviceBufferQueueTest : public TestOnGpu {};

namespace {

SkiaOutputSurface::OverlayList MakeOverlayList(
    std::vector<gpu::Mailbox> mailboxes) {}

TEST_F_GPU(SkiaOutputDeviceBufferQueueTest, ScheduleOverlaysNoPrimaryPlane) {}

#if BUILDFLAG(IS_APPLE)
TEST_F_GPU(SkiaOutputDeviceBufferQueueTest, ScheduleOverlaysStillInUse) {
  FirstReshape();

  std::unique_ptr<gpu::OverlayImageRepresentation> overlay_1 = MakeOverlay();
  std::unique_ptr<gpu::OverlayImageRepresentation> overlay_2 = MakeOverlay();

  output_device_->ScheduleOverlays(MakeOverlayList({overlay_1->mailbox()}));

  EXPECT_THAT(pending_overlay_mailboxes(),
              testing::ElementsAre(overlay_1->mailbox()));

  Present();
  EXPECT_THAT(pending_overlay_mailboxes(), testing::IsEmpty());
  EXPECT_THAT(committed_overlay_mailboxes(),
              testing::ElementsAre(overlay_1->mailbox()));

  PageFlipComplete();
  EXPECT_EQ(1u, params_.size());
  EXPECT_EQ(0u, params_[0].released_overlays.size());

  auto* overlay2 =
      static_cast<gpu::TestOverlayImageRepresentation*>(overlay_2.get());
  overlay2->MarkBackingInUse(true);

  output_device_->ScheduleOverlays(MakeOverlayList({overlay_2->mailbox()}));
  Present();
  PageFlipComplete();
  EXPECT_EQ(2u, params_.size());
  EXPECT_THAT(params_[1].released_overlays,
              testing::ElementsAre(overlay_1->mailbox()));

  // The overlay is still in use, cannot release it.
  output_device_->ScheduleOverlays(MakeOverlayList({overlay_1->mailbox()}));
  Present();
  PageFlipComplete();
  EXPECT_EQ(3u, params_.size());
  EXPECT_TRUE(params_[2].released_overlays.empty());

  // Now that the overlay is no longer in use, the next frame will release it.
  overlay2->MarkBackingInUse(false);
  output_device_->ScheduleOverlays(MakeOverlayList({overlay_1->mailbox()}));
  Present();
  PageFlipComplete();
  EXPECT_EQ(4u, params_.size());
  EXPECT_THAT(params_[3].released_overlays,
              testing::ElementsAre(overlay_2->mailbox()));
}

TEST_F_GPU(SkiaOutputDeviceBufferQueueTest, InUseOverlaysAreCollected) {
  output_device_->SetSwapTimeClockForTesting(&test_tick_clock_);
  FirstReshape();

  std::unique_ptr<gpu::OverlayImageRepresentation> overlay_1 = MakeOverlay();
  std::unique_ptr<gpu::OverlayImageRepresentation> overlay_2 = MakeOverlay();

  output_device_->ScheduleOverlays(MakeOverlayList({overlay_1->mailbox()}));

  EXPECT_THAT(pending_overlay_mailboxes(),
              testing::ElementsAre(overlay_1->mailbox()));

  Present();
  EXPECT_THAT(pending_overlay_mailboxes(), testing::IsEmpty());
  EXPECT_THAT(committed_overlay_mailboxes(),
              testing::ElementsAre(overlay_1->mailbox()));

  PageFlipComplete();
  EXPECT_EQ(1u, params_.size());
  EXPECT_EQ(0u, params_[0].released_overlays.size());

  auto* overlay2 =
      static_cast<gpu::TestOverlayImageRepresentation*>(overlay_2.get());
  overlay2->MarkBackingInUse(true);

  output_device_->ScheduleOverlays(MakeOverlayList({overlay_2->mailbox()}));
  Present();
  PageFlipComplete();
  EXPECT_EQ(2u, params_.size());
  EXPECT_THAT(params_[1].released_overlays,
              testing::ElementsAre(overlay_1->mailbox()));
  EXPECT_FALSE(output_device_->OverlaysReclaimTimerForTesting().IsRunning());

  // The overlay is still in use, cannot release it.
  output_device_->ScheduleOverlays(MakeOverlayList({overlay_1->mailbox()}));
  Present();
  PageFlipComplete();
  EXPECT_EQ(3u, params_.size());
  EXPECT_TRUE(params_[2].released_overlays.empty());
  EXPECT_TRUE(output_device_->OverlaysReclaimTimerForTesting().IsRunning());

  overlay2->MarkBackingInUse(false);

  // Not enough time since last commit, reschedule.
  test_tick_clock_.Advance(base::Milliseconds(1));
  output_device_->OverlaysReclaimTimerForTesting().FireNow();
  EXPECT_TRUE(output_device_->OverlaysReclaimTimerForTesting().IsRunning());

  // Now we can release it.
  test_tick_clock_.Advance(base::Seconds(1));
  output_device_->OverlaysReclaimTimerForTesting().FireNow();
  EXPECT_FALSE(output_device_->OverlaysReclaimTimerForTesting().IsRunning());
  EXPECT_EQ(1u, released_overlays_params_.size());
  EXPECT_THAT(released_overlays_params_[0],
              testing::ElementsAre(overlay_2->mailbox()));
}
#endif  // BUILDFLAG(IS_APPLE)

}  // namespace
}  // namespace viz