chromium/ui/ozone/platform/wayland/wayland_buffer_manager_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.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif

#include <drm_fourcc.h>
#include <overlay-prioritizer-client-protocol.h>

#include <cstdint>
#include <memory>

#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "base/test/mock_callback.h"
#include "build/chromeos_buildflags.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/geometry/rounded_corners_f.h"
#include "ui/gfx/geometry/rrect_f.h"
#include "ui/gfx/gpu_fence_handle.h"
#include "ui/gfx/linux/drm_util_linux.h"
#include "ui/gfx/overlay_priority_hint.h"
#include "ui/gfx/presentation_feedback.h"
#include "ui/ozone/platform/wayland/common/wayland_overlay_config.h"
#include "ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.h"
#include "ui/ozone/platform/wayland/gpu/wayland_surface_gpu.h"
#include "ui/ozone/platform/wayland/host/wayland_buffer_factory.h"
#include "ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
#include "ui/ozone/platform/wayland/host/wayland_frame_manager.h"
#include "ui/ozone/platform/wayland/host/wayland_subsurface.h"
#include "ui/ozone/platform/wayland/host/wayland_zwp_linux_dmabuf.h"
#include "ui/ozone/platform/wayland/test/mock_surface.h"
#include "ui/ozone/platform/wayland/test/mock_zwp_linux_dmabuf.h"
#include "ui/ozone/platform/wayland/test/test_overlay_prioritized_surface.h"
#include "ui/ozone/platform/wayland/test/test_zwp_linux_buffer_params.h"
#include "ui/ozone/platform/wayland/test/wayland_test.h"
#include "ui/platform_window/platform_window_init_properties.h"

_;
Truly;
Values;

namespace ui {

namespace {

MockTerminateGpuCallback;

constexpr gfx::Size kDefaultSize(1024, 768);

constexpr uint32_t kAugmentedSurfaceNotSupportedVersion =;

// TODO(msisov): add a test to exercise buffer management with non-default scale
// once all the patches land.
constexpr float kDefaultScale =;

struct InputData {};

class MockSurfaceGpu : public WaylandSurfaceGpu {};

}  // namespace

class WaylandBufferManagerTest : public WaylandTest {};

TEST_P(WaylandBufferManagerTest, CreateDmabufBasedBuffers) {}

TEST_P(WaylandBufferManagerTest, VerifyModifiers) {}

TEST_P(WaylandBufferManagerTest, CreateShmBasedBuffers) {}

TEST_P(WaylandBufferManagerTest, ValidateDataFromGpu) {}

TEST_P(WaylandBufferManagerTest, CreateAndDestroyBuffer) {}

TEST_P(WaylandBufferManagerTest, CommitBufferNonExistingBufferId) {}

TEST_P(WaylandBufferManagerTest, CommitOverlaysNonExistingBufferId) {}

TEST_P(WaylandBufferManagerTest, CommitOverlaysWithSameBufferId) {}

TEST_P(WaylandBufferManagerTest, CommitBufferNullWidget) {}

// Tests that committing overlays with bounds_rect containing NaN or infinity
// values is illegal - the host terminates the gpu process.
TEST_P(WaylandBufferManagerTest, CommitOverlaysNonsensicalBoundsRect) {}

// A similar test to the above with the only difference that a background
// dummy buffer is not used as delegation is disabled.
TEST_P(WaylandBufferManagerTest,
       CommitOverlaysNonsensicalBoundsRectSingleOverlay) {}

TEST_P(WaylandBufferManagerTest, EnsureCorrectOrderOfCallbacks) {}

TEST_P(WaylandBufferManagerTest,
       DestroyedBuffersGeneratePresentationFeedbackFailure) {}

// This test ensures that a discarded presentation feedback sent prior receiving
// results for the previous presentation feedback does not make them
// automatically failed.
TEST_P(WaylandBufferManagerTest,
       EnsureDiscardedPresentationDoesNotMakePreviousFeedbacksFailed) {}

#if BUILDFLAG(IS_CHROMEOS_LACROS)
// This test ensures that a failed presentation feedback (with flags set as
// `gfx::PresentationFeedback::kFailure`) is received by the client and
// propagated as a failed presentation.
TEST_P(WaylandBufferManagerTest, EnsureFailedPresentationIsSent) {
  constexpr uint32_t kBufferId1 = 1;

  PostToServerAndWait([](wl::TestWaylandServerThread* server) {
    // Enable wp_presentation support.
    auto* mock_wp_presentation = server->EnsureAndGetWpPresentation();
    ASSERT_TRUE(mock_wp_presentation);
  });

  const gfx::AcceleratedWidget widget = window_->GetWidget();
  const gfx::Rect bounds = gfx::Rect({0, 0}, kDefaultSize);
  window_->SetBoundsInDIP(bounds);

  MockSurfaceGpu mock_surface_gpu(buffer_manager_gpu_.get(), widget_);

  PostToServerAndWait([](wl::TestWaylandServerThread* server) {
    EXPECT_CALL(*server->zwp_linux_dmabuf_v1(), CreateParams(_, _, _)).Times(1);
  });
  CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/, kBufferId1);
  ProcessCreatedBufferResourcesWithExpectation(1u /* expected size */,
                                               false /* fail */);

  PostToServerAndWait([id = surface_id_](wl::TestWaylandServerThread* server) {
    auto* mock_surface = server->GetObject<wl::MockSurface>(id);

    constexpr uint32_t kNumberOfCommits = 1;
    EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(kNumberOfCommits);
    EXPECT_CALL(*mock_surface, Frame(_)).Times(kNumberOfCommits);
    EXPECT_CALL(*mock_surface, Commit()).Times(kNumberOfCommits);
  });

  // All the other expectations must come in order.
  ::testing::InSequence sequence;
  EXPECT_CALL(mock_surface_gpu,
              OnSubmission(kBufferId1, gfx::SwapResult::SWAP_ACK, _))
      .Times(1);
  EXPECT_CALL(mock_surface_gpu, OnPresentation(_, _)).Times(0);

  // Commit the buffer
  CommitBuffer(widget, kBufferId1, kBufferId1,
               gfx::FrameData(delegate_.viz_seq()), bounds,
               gfx::RoundedCornersF(), kDefaultScale, bounds);

  // Let the mojo message for OnSubmission go back.
  base::RunLoop().RunUntilIdle();

  testing::Mock::VerifyAndClearExpectations(&mock_surface_gpu);

  PostToServerAndWait([id = surface_id_](wl::TestWaylandServerThread* server) {
    // Verify we have a presentation callback now. This will be sent later.
    EXPECT_EQ(
        1u,
        server->EnsureAndGetWpPresentation()->num_of_presentation_callbacks());

    server->GetObject<wl::MockSurface>(id)->SendFrameCallback();
  });

  // Its all setup until this point.
  // The main part of the test starts here.
  EXPECT_CALL(
      mock_surface_gpu,
      OnPresentation(
          kBufferId1,
          ::testing::Field(
              &gfx::PresentationFeedback::flags,
              ::testing::Eq(gfx::PresentationFeedback::Flags::kFailure))))
      .Times(1);

  // Set `.flags` as `gfx::PresentationFeedback::kFailure`.
  wl::MockWpPresentation::PresentationFeedbackParams params{
      .tv_sec_hi = 1,
      .tv_sec_lo = 1,
      .tv_nsec = 1,
      .refresh = 1,
      .seq_hi = 1,
      .seq_lo = 1,
      .flags = gfx::PresentationFeedback::kFailure};

  PostToServerAndWait([params](wl::TestWaylandServerThread* server) {
    auto* mock_wp_presentation = server->EnsureAndGetWpPresentation();
    EXPECT_EQ(1u, mock_wp_presentation->num_of_presentation_callbacks());
    mock_wp_presentation->SendPresentationFeedbackToClient(/*last=*/false,
                                                           params);
  });

  // Ensure that presentation feedback is flushed.
  task_environment_.FastForwardBy(
      WaylandFrameManager::GetPresentationFlushTimerDurationForTesting());

  testing::Mock::VerifyAndClearExpectations(&mock_surface_gpu);

  DestroyBufferAndSetTerminateExpectation(kBufferId1, false /*fail*/);
}
#endif

TEST_P(WaylandBufferManagerTest, TestCommitBufferConditions) {}

// Tests the surface does not have buffers attached until it's configured at
// least once.
TEST_P(WaylandBufferManagerTest, TestCommitBufferConditionsAckConfigured) {}

// Verifies toplevel surfaces do not have buffers attached until configured,
// even when the initial configure sequence is not acked in response to
// xdg_surface.configure event, i.e: done asynchronously when OnSequencePoint()
// is called by they FrameManager).
//
// Regression test for https://crbug.com/1313023.
TEST_P(WaylandBufferManagerTest,
       CommitBufferConditionsWithDeferredAckConfigure) {}

// The buffer that is not originally attached to any of the surfaces,
// must be attached when a commit request comes. Also, it must setup a buffer
// release listener and OnSubmission must be called for that buffer if it is
// released.
TEST_P(WaylandBufferManagerTest, AnonymousBufferAttachedAndReleased) {}

TEST_P(WaylandBufferManagerTest, DestroyBufferForDestroyedWindow) {}

TEST_P(WaylandBufferManagerTest, DestroyedWindowNoSubmissionSingleBuffer) {}

TEST_P(WaylandBufferManagerTest, DestroyedWindowNoSubmissionMultipleBuffers) {}

// Tests that OnSubmission and OnPresentation are properly triggered if a buffer
// is committed twice in a row and those buffers are destroyed.
TEST_P(WaylandBufferManagerTest, DestroyBufferCommittedTwiceInARow) {}

// Tests that OnSubmission and OnPresentation are properly triggered if a buffer
// is committed twice in a row and then released.
TEST_P(WaylandBufferManagerTest, ReleaseBufferCommittedTwiceInARow) {}

// Tests that OnSubmission and OnPresentation callbacks are properly called
// even if buffers are not released in the same order they were committed.
TEST_P(WaylandBufferManagerTest, ReleaseOrderDifferentToCommitOrder) {}

// This test verifies that submitting the buffer more than once results in
// OnSubmission callback as Wayland compositor is not supposed to release the
// buffer committed twice.
TEST_P(WaylandBufferManagerTest,
       OnSubmissionCalledForBufferCommitedTwiceInARow) {}

// Tests that submitting a single buffer only receives an OnSubmission. This is
// required behaviour to make sure that submitting buffers in a quiescent state
// will be immediately acked.
TEST_P(WaylandBufferManagerTest, OnSubmissionCalledForSingleBuffer) {}

// Tests that when CommitOverlays(), root_surface can only be committed once all
// overlays in the frame are committed.
TEST_P(WaylandBufferManagerTest, RootSurfaceIsCommittedLast) {}

TEST_P(WaylandBufferManagerTest, FencedRelease) {}

// Tests that destroying a channel doesn't result in resetting surface state
// and buffers can be attached after the channel has been reinitialized.
TEST_P(WaylandBufferManagerTest,
       CanSubmitBufferAfterChannelDestroyedAndInitialized) {}

// Tests that destroying a channel results in attaching null buffers to the root
// surface, and hiding primary subsurface and overlay surfaces. This is required
// to make it possible for a GPU service to switch from hw acceleration to sw
// compositing. Otherwise, there will be frozen graphics represented by a
// primary subsurface as sw compositing uses the root surface to draw new
// frames. Verifies the fix for https://crbug.com/1201314
TEST_P(WaylandBufferManagerTest, HidesSubsurfacesOnChannelDestroyed) {}

TEST_P(WaylandBufferManagerTest,
       DoesNotAttachAndCommitOnHideIfNoBuffersAttached) {}

TEST_P(WaylandBufferManagerTest, HasOverlayPrioritizer) {}

TEST_P(WaylandBufferManagerTest, CanSubmitOverlayPriority) {}

TEST_P(WaylandBufferManagerTest, HasSurfaceAugmenter) {}

TEST_P(WaylandBufferManagerTest, CanSetRoundedCorners) {}

// Verifies that there are no more than certain number of submitted frames that
// wait presentation feedbacks. If the number of pending frames hit the
// threshold, the feedbacks are marked as failed and discarded. See the comments
// below in the test.
TEST_P(WaylandBufferManagerTest, FeedbacksAreDiscardedIfClientMisbehaves) {}

TEST_P(WaylandBufferManagerTest, ExecutesTasksAfterInitialization) {}

TEST_P(WaylandBufferManagerTest, DoesNotRequestReleaseForSolidColorBuffers) {}

class WaylandBufferManagerViewportTest : public WaylandBufferManagerTest {};

// Tests viewport destination is set correctly when the augmenter subsurface
// protocol is not available and then becomes available.
TEST_P(WaylandBufferManagerViewportTest, ViewportDestinationNonInteger) {}

// Tests viewport destination is set correctly when the augmenter subsurface
// protocol is not available (the destination is rounded), and the protocol is
// available (the destination is set with floating point precision).
TEST_P(WaylandBufferManagerViewportTest, ViewportDestinationInteger) {}

INSTANTIATE_TEST_SUITE_P();

INSTANTIATE_TEST_SUITE_P();

INSTANTIATE_TEST_SUITE_P();
INSTANTIATE_TEST_SUITE_P();

INSTANTIATE_TEST_SUITE_P();
INSTANTIATE_TEST_SUITE_P();

}  // namespace ui