|
19 | 19 | #include "ui/gfx/gpu_fence_handle.h"
|
20 | 20 | #include "ui/gfx/linux/drm_util_linux.h"
|
21 | 21 | #include "ui/gfx/overlay_priority_hint.h"
|
| 22 | +#include "ui/gfx/presentation_feedback.h" |
22 | 23 | #include "ui/ozone/platform/wayland/gpu/wayland_buffer_manager_gpu.h"
|
23 | 24 | #include "ui/ozone/platform/wayland/gpu/wayland_surface_gpu.h"
|
24 | 25 | #include "ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h"
|
@@ -2113,6 +2114,101 @@ TEST_P(WaylandBufferManagerTest, CanSetRoundedCorners) {
|
2113 | 2114 | }
|
2114 | 2115 | }
|
2115 | 2116 |
|
| 2117 | +// Verifies that there are no more than certain number of submitted frames that |
| 2118 | +// wait presentation feedbacks. If the number of pending frames hit the |
| 2119 | +// threshold, the feedbacks are marked as failed and discarded. See the comments |
| 2120 | +// below in the test. |
| 2121 | +TEST_P(WaylandBufferManagerTest, FeedbacksAreDiscardedIfClientMisbehaves) { |
| 2122 | + auto* mock_wp_presentation = server_.EnsureWpPresentation(); |
| 2123 | + ASSERT_TRUE(mock_wp_presentation); |
| 2124 | + |
| 2125 | + // 2 buffers are enough. |
| 2126 | + constexpr uint32_t kBufferId1 = 1; |
| 2127 | + constexpr uint32_t kBufferId2 = 2; |
| 2128 | + |
| 2129 | + const gfx::AcceleratedWidget widget = window_->GetWidget(); |
| 2130 | + const gfx::Rect bounds = gfx::Rect({0, 0}, kDefaultSize); |
| 2131 | + window_->SetBounds(bounds); |
| 2132 | + |
| 2133 | + MockSurfaceGpu mock_surface_gpu(buffer_manager_gpu_.get(), widget_); |
| 2134 | + |
| 2135 | + auto* linux_dmabuf = server_.zwp_linux_dmabuf_v1(); |
| 2136 | + EXPECT_CALL(*linux_dmabuf, CreateParams(_, _, _)).Times(2); |
| 2137 | + CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/, kBufferId1); |
| 2138 | + CreateDmabufBasedBufferAndSetTerminateExpectation(false /*fail*/, kBufferId2); |
| 2139 | + |
| 2140 | + Sync(); |
| 2141 | + |
| 2142 | + ProcessCreatedBufferResourcesWithExpectation(2u /* expected size */, |
| 2143 | + false /* fail */); |
| 2144 | + |
| 2145 | + auto* mock_surface = server_.GetObject<wl::MockSurface>( |
| 2146 | + window_->root_surface()->GetSurfaceId()); |
| 2147 | + |
| 2148 | + // There will be 235 frames/commits. |
| 2149 | + constexpr uint32_t kNumberOfCommits = 235u; |
| 2150 | + EXPECT_CALL(*mock_surface, Attach(_, _, _)).Times(kNumberOfCommits); |
| 2151 | + EXPECT_CALL(*mock_surface, Frame(_)).Times(kNumberOfCommits); |
| 2152 | + EXPECT_CALL(*mock_wp_presentation, Feedback(_, _, _, _)) |
| 2153 | + .Times(kNumberOfCommits); |
| 2154 | + EXPECT_CALL(*mock_surface, Commit()).Times(kNumberOfCommits); |
| 2155 | + |
| 2156 | + // The presentation feedbacks should fail after first 20 commits (that's the |
| 2157 | + // threshold that WaylandFrameManager maintains). Next, the presentation |
| 2158 | + // feedbacks will fail every consequent 17 commits as 3 frames out of 20 |
| 2159 | + // previous frames that WaylandFrameManager stores are always preserved in |
| 2160 | + // case if the client restores the behavior (which is very unlikely). |
| 2161 | + uint32_t expect_presentation_failure_on_commit_seq = 20u; |
| 2162 | + // Chooses the next buffer id that should be committed. |
| 2163 | + uint32_t next_buffer_id_commit = 0; |
| 2164 | + // Specifies the expected number of failing feedbacks if the client |
| 2165 | + // misbehaves. |
| 2166 | + constexpr uint32_t kExpectedFailedFeedbacks = 17u; |
| 2167 | + for (auto commit_seq = 1u; commit_seq <= kNumberOfCommits; commit_seq++) { |
| 2168 | + // All the other expectations must come in order. |
| 2169 | + if (next_buffer_id_commit == kBufferId1) |
| 2170 | + next_buffer_id_commit = kBufferId2; |
| 2171 | + else |
| 2172 | + next_buffer_id_commit = kBufferId1; |
| 2173 | + |
| 2174 | + EXPECT_CALL(mock_surface_gpu, OnSubmission(next_buffer_id_commit, |
| 2175 | + gfx::SwapResult::SWAP_ACK, _)) |
| 2176 | + .Times(1); |
| 2177 | + |
| 2178 | + if (commit_seq % expect_presentation_failure_on_commit_seq == 0) { |
| 2179 | + EXPECT_CALL(mock_surface_gpu, |
| 2180 | + OnPresentation(_, gfx::PresentationFeedback::Failure())) |
| 2181 | + .Times(kExpectedFailedFeedbacks); |
| 2182 | + // See comment near |expect_presentation_failure_on_commit_seq|. |
| 2183 | + expect_presentation_failure_on_commit_seq += kExpectedFailedFeedbacks; |
| 2184 | + } else { |
| 2185 | + // The client misbehaves and doesn't send presentation feedbacks. The |
| 2186 | + // frame manager doesn't mark the feedbacks as failed until the threshold |
| 2187 | + // is hit. |
| 2188 | + EXPECT_CALL(mock_surface_gpu, OnPresentation(_, _)).Times(0); |
| 2189 | + } |
| 2190 | + |
| 2191 | + buffer_manager_gpu_->CommitBuffer(widget, next_buffer_id_commit, bounds, |
| 2192 | + kDefaultScale, bounds); |
| 2193 | + |
| 2194 | + Sync(); |
| 2195 | + |
| 2196 | + if (auto* buffer = mock_surface->prev_attached_buffer()) |
| 2197 | + mock_surface->ReleaseBuffer(buffer); |
| 2198 | + |
| 2199 | + wl_resource_destroy(mock_wp_presentation->ReleasePresentationCallback()); |
| 2200 | + |
| 2201 | + mock_surface->SendFrameCallback(); |
| 2202 | + |
| 2203 | + Sync(); |
| 2204 | + |
| 2205 | + testing::Mock::VerifyAndClearExpectations(&mock_surface_gpu); |
| 2206 | + } |
| 2207 | + |
| 2208 | + DestroyBufferAndSetTerminateExpectation(widget, kBufferId1, false /*fail*/); |
| 2209 | + DestroyBufferAndSetTerminateExpectation(widget, kBufferId2, false /*fail*/); |
| 2210 | +} |
| 2211 | + |
2116 | 2212 | INSTANTIATE_TEST_SUITE_P(XdgVersionStableTest,
|
2117 | 2213 | WaylandBufferManagerTest,
|
2118 | 2214 | Values(wl::ServerConfig{
|
|
0 commit comments