delegated_ink_point_renderer_gpu_unittest.cc 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  1. // Copyright 2021 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ui/gl/delegated_ink_point_renderer_gpu.h"
  5. #include <memory>
  6. #include "base/memory/raw_ptr.h"
  7. #include "base/run_loop.h"
  8. #include "base/time/time.h"
  9. #include "testing/gtest/include/gtest/gtest.h"
  10. #include "ui/base/win/hidden_window.h"
  11. #include "ui/gfx/geometry/vector2d_f.h"
  12. #include "ui/gl/dc_layer_tree.h"
  13. #include "ui/gl/direct_composition_support.h"
  14. #include "ui/gl/direct_composition_surface_win.h"
  15. #include "ui/gl/gl_angle_util_win.h"
  16. #include "ui/gl/gl_context.h"
  17. #include "ui/gl/init/gl_factory.h"
  18. namespace gl {
  19. namespace {
  20. // Standard number of microseconds that is put between each DelegatedInkPoint.
  21. const int kMicrosecondsBetweenEachPoint = 10;
  22. class DelegatedInkPointRendererGpuTest : public testing::Test {
  23. public:
  24. DelegatedInkPointRendererGpuTest() : parent_window_(ui::GetHiddenWindow()) {}
  25. DirectCompositionSurfaceWin* surface() { return surface_.get(); }
  26. DCLayerTree* layer_tree() { return surface()->GetLayerTreeForTesting(); }
  27. DCLayerTree::DelegatedInkRenderer* ink_renderer() {
  28. return layer_tree()->GetInkRendererForTesting();
  29. }
  30. void SendDelegatedInkPoint(const gfx::DelegatedInkPoint& point) {
  31. stored_points_[point.pointer_id()].push_back(point);
  32. ink_renderer()->StoreDelegatedInkPoint(point);
  33. }
  34. void SendDelegatedInkPointBasedOnPrevious(uint32_t pointer_id) {
  35. DCHECK(stored_points_.find(pointer_id) != stored_points_.end());
  36. DCHECK(!stored_points_[pointer_id].empty());
  37. auto last_point = stored_points_[pointer_id].back();
  38. SendDelegatedInkPoint(gfx::DelegatedInkPoint(
  39. last_point.point() + gfx::Vector2dF(5, 5),
  40. last_point.timestamp() +
  41. base::Microseconds(kMicrosecondsBetweenEachPoint),
  42. last_point.pointer_id()));
  43. }
  44. void SendDelegatedInkPointBasedOnPrevious() {
  45. DCHECK_EQ(stored_points_.size(), 1u);
  46. SendDelegatedInkPointBasedOnPrevious(stored_points_.begin()->first);
  47. }
  48. void SendMetadata(const gfx::DelegatedInkMetadata& metadata) {
  49. surface()->SetDelegatedInkTrailStartPoint(
  50. std::make_unique<gfx::DelegatedInkMetadata>(metadata));
  51. }
  52. gfx::DelegatedInkMetadata SendMetadataBasedOnStoredPoint(int32_t pointer_id,
  53. uint64_t point) {
  54. DCHECK(stored_points_.find(pointer_id) != stored_points_.end());
  55. DCHECK_GE(stored_points_[pointer_id].size(), point);
  56. const gfx::DelegatedInkPoint& ink_point = stored_points_[pointer_id][point];
  57. gfx::DelegatedInkMetadata metadata(
  58. ink_point.point(), /*diameter=*/3, SK_ColorBLACK, ink_point.timestamp(),
  59. gfx::RectF(0, 0, 100, 100), /*hovering=*/false);
  60. SendMetadata(metadata);
  61. return metadata;
  62. }
  63. gfx::DelegatedInkMetadata SendMetadataBasedOnStoredPoint(uint64_t point) {
  64. DCHECK_EQ(stored_points_.size(), 1u);
  65. return SendMetadataBasedOnStoredPoint(stored_points_.begin()->first, point);
  66. }
  67. void StoredMetadataMatchesSentMetadata(
  68. const gfx::DelegatedInkMetadata& sent_metadata) {
  69. gfx::DelegatedInkMetadata* renderer_metadata =
  70. ink_renderer()->MetadataForTesting();
  71. EXPECT_TRUE(renderer_metadata);
  72. EXPECT_EQ(renderer_metadata->point(), sent_metadata.point());
  73. EXPECT_EQ(renderer_metadata->diameter(), sent_metadata.diameter());
  74. EXPECT_EQ(renderer_metadata->color(), sent_metadata.color());
  75. EXPECT_EQ(renderer_metadata->timestamp(), sent_metadata.timestamp());
  76. EXPECT_EQ(renderer_metadata->presentation_area(),
  77. sent_metadata.presentation_area());
  78. EXPECT_EQ(renderer_metadata->is_hovering(), sent_metadata.is_hovering());
  79. }
  80. protected:
  81. void SetUp() override {
  82. // Without this, the following check always fails.
  83. display_ = gl::init::InitializeGLNoExtensionsOneOff(/*init_bindings=*/true,
  84. /*system_device_id=*/0);
  85. if (!gl::DirectCompositionSupported()) {
  86. LOG(WARNING)
  87. << "GL implementation not using DirectComposition, skipping test.";
  88. return;
  89. }
  90. CreateDirectCompositionSurfaceWin();
  91. if (!surface_->SupportsDelegatedInk()) {
  92. LOG(WARNING) << "Delegated ink unsupported, skipping test.";
  93. return;
  94. }
  95. CreateGLContext();
  96. surface_->SetEnableDCLayers(true);
  97. // Create the swap chain
  98. constexpr gfx::Size window_size(100, 100);
  99. EXPECT_TRUE(surface_->Resize(window_size, 1.0, gfx::ColorSpace(), true));
  100. EXPECT_TRUE(surface_->SetDrawRectangle(gfx::Rect(window_size)));
  101. }
  102. void TearDown() override {
  103. context_ = nullptr;
  104. if (surface_)
  105. DestroySurface(std::move(surface_));
  106. gl::init::ShutdownGL(display_, false);
  107. }
  108. private:
  109. void CreateDirectCompositionSurfaceWin() {
  110. DirectCompositionSurfaceWin::Settings settings;
  111. surface_ = base::MakeRefCounted<DirectCompositionSurfaceWin>(
  112. gl::GLSurfaceEGL::GetGLDisplayEGL(), parent_window_,
  113. DirectCompositionSurfaceWin::VSyncCallback(), settings);
  114. EXPECT_TRUE(surface_->Initialize(GLSurfaceFormat()));
  115. // ImageTransportSurfaceDelegate::DidCreateAcceleratedSurfaceChildWindow()
  116. // is called in production code here. However, to remove dependency from
  117. // gpu/ipc/service/image_transport_surface_delegate.h, here we directly
  118. // executes the required minimum code.
  119. if (parent_window_)
  120. ::SetParent(surface_->window(), parent_window_);
  121. }
  122. void CreateGLContext() {
  123. context_ =
  124. gl::init::CreateGLContext(nullptr, surface_.get(), GLContextAttribs());
  125. EXPECT_TRUE(context_->MakeCurrent(surface_.get()));
  126. }
  127. void DestroySurface(scoped_refptr<DirectCompositionSurfaceWin> surface) {
  128. scoped_refptr<base::TaskRunner> task_runner =
  129. surface->GetWindowTaskRunnerForTesting();
  130. DCHECK(surface->HasOneRef());
  131. surface = nullptr;
  132. base::RunLoop run_loop;
  133. task_runner->PostTask(FROM_HERE, run_loop.QuitClosure());
  134. run_loop.Run();
  135. }
  136. HWND parent_window_;
  137. scoped_refptr<DirectCompositionSurfaceWin> surface_;
  138. scoped_refptr<GLContext> context_;
  139. raw_ptr<GLDisplay> display_ = nullptr;
  140. // Used as a reference when making DelegatedInkMetadatas based on previously
  141. // sent points.
  142. std::map<int32_t, std::vector<gfx::DelegatedInkPoint>> stored_points_;
  143. };
  144. // Test to confirm that points and tokens are stored and removed correctly based
  145. // on when the metadata and points arrive.
  146. TEST_F(DelegatedInkPointRendererGpuTest, StoreAndRemovePointsAndTokens) {
  147. if (!surface() || !surface()->SupportsDelegatedInk())
  148. return;
  149. // Send some points and make sure they are all stored even with no metadata.
  150. const int32_t kPointerId = 1;
  151. SendDelegatedInkPoint(gfx::DelegatedInkPoint(
  152. gfx::PointF(10, 10), base::TimeTicks::Now(), kPointerId));
  153. const uint64_t kPointsToStore = 5u;
  154. for (uint64_t i = 1; i < kPointsToStore; ++i)
  155. SendDelegatedInkPointBasedOnPrevious();
  156. EXPECT_EQ(ink_renderer()->DelegatedInkPointsForTesting(kPointerId).size(),
  157. kPointsToStore);
  158. EXPECT_EQ(ink_renderer()->InkTrailTokenCountForTesting(), 0u);
  159. EXPECT_FALSE(ink_renderer()->MetadataForTesting());
  160. EXPECT_TRUE(ink_renderer()->WaitForNewTrailToDrawForTesting());
  161. // Now send metadata that matches the first stored point. This should result
  162. // in all of the points being drawn and matching tokens stored. None of the
  163. // points should be removed from the circular deque because they are stored
  164. // until a metadata arrives with a later timestamp
  165. gfx::DelegatedInkMetadata metadata = SendMetadataBasedOnStoredPoint(0);
  166. EXPECT_EQ(ink_renderer()->DelegatedInkPointsForTesting(kPointerId).size(),
  167. kPointsToStore);
  168. EXPECT_EQ(ink_renderer()->InkTrailTokenCountForTesting(), kPointsToStore);
  169. EXPECT_FALSE(ink_renderer()->WaitForNewTrailToDrawForTesting());
  170. StoredMetadataMatchesSentMetadata(metadata);
  171. // Now send a metadata that matches a later one of the points. It should
  172. // result in all of the points up to and including the point that matches
  173. // the metadata being erased. Then, all remaining points should be drawn and
  174. // should therefore have tokens associated with them.
  175. const uint64_t kPointToSend = 3u;
  176. metadata = SendMetadataBasedOnStoredPoint(kPointToSend);
  177. EXPECT_EQ(ink_renderer()->DelegatedInkPointsForTesting(kPointerId).size(),
  178. kPointsToStore - kPointToSend - 1);
  179. EXPECT_EQ(ink_renderer()->InkTrailTokenCountForTesting(),
  180. kPointsToStore - kPointToSend - 1);
  181. StoredMetadataMatchesSentMetadata(metadata);
  182. // Now send a metadata after all of the stored point to make sure that it
  183. // results in all the tokens and stored points being erased because a new
  184. // trail is started.
  185. gfx::DelegatedInkPoint last_point =
  186. ink_renderer()->DelegatedInkPointsForTesting(kPointerId).rbegin()->first;
  187. metadata = gfx::DelegatedInkMetadata(
  188. last_point.point() + gfx::Vector2dF(2, 2), /*diameter=*/3, SK_ColorBLACK,
  189. last_point.timestamp() + base::Microseconds(20),
  190. gfx::RectF(0, 0, 100, 100), /*hovering=*/false);
  191. SendMetadata(metadata);
  192. EXPECT_EQ(ink_renderer()->DelegatedInkPointPointerIdCountForTesting(), 0u);
  193. StoredMetadataMatchesSentMetadata(metadata);
  194. }
  195. // Basic test to confirm that points are drawn as they arrive if they are in the
  196. // presentation area and after the metadata's timestamp.
  197. TEST_F(DelegatedInkPointRendererGpuTest, DrawPointsAsTheyArrive) {
  198. if (!surface() || !surface()->SupportsDelegatedInk())
  199. return;
  200. gfx::DelegatedInkMetadata metadata(
  201. gfx::PointF(12, 12), /*diameter=*/3, SK_ColorBLACK,
  202. base::TimeTicks::Now(), gfx::RectF(10, 10, 90, 90), /*hovering=*/false);
  203. SendMetadata(metadata);
  204. // Send some points that should all be drawn to ensure that they are all drawn
  205. // as they arrive.
  206. const int32_t kPointerId = 1;
  207. const uint64_t kPointsToSend = 5u;
  208. for (uint64_t i = 1u; i <= kPointsToSend; ++i) {
  209. if (i == 1) {
  210. SendDelegatedInkPoint(gfx::DelegatedInkPoint(
  211. metadata.point(), metadata.timestamp(), kPointerId));
  212. } else {
  213. SendDelegatedInkPointBasedOnPrevious();
  214. }
  215. EXPECT_EQ(ink_renderer()->DelegatedInkPointsForTesting(kPointerId).size(),
  216. i);
  217. EXPECT_EQ(ink_renderer()->InkTrailTokenCountForTesting(), i);
  218. }
  219. // Now send a point that is outside of the presentation area to ensure that
  220. // it is not drawn. It will still be stored - this is so if a future metadata
  221. // arrives with a presentation area that would contain this point, it can
  222. // still be drawn.
  223. gfx::DelegatedInkPoint last_point =
  224. ink_renderer()->DelegatedInkPointsForTesting(kPointerId).rbegin()->first;
  225. gfx::DelegatedInkPoint outside_point(
  226. gfx::PointF(5, 5), last_point.timestamp() + base::Microseconds(10),
  227. /*pointer_id=*/1);
  228. EXPECT_FALSE(metadata.presentation_area().Contains(outside_point.point()));
  229. SendDelegatedInkPoint(outside_point);
  230. const uint64_t kTotalPointsSent = kPointsToSend + 1u;
  231. EXPECT_EQ(ink_renderer()->DelegatedInkPointsForTesting(kPointerId).size(),
  232. kTotalPointsSent);
  233. EXPECT_EQ(ink_renderer()->InkTrailTokenCountForTesting(), kPointsToSend);
  234. // Then send a metadata with a larger presentation area and timestamp earlier
  235. // than the above point to confirm it will be the only point drawn, but all
  236. // the points with later timestamps will be stored.
  237. const uint64_t kMetadataToSend = 3u;
  238. SendMetadataBasedOnStoredPoint(kMetadataToSend);
  239. EXPECT_EQ(ink_renderer()->DelegatedInkPointsForTesting(kPointerId).size(),
  240. kTotalPointsSent - kMetadataToSend - 1);
  241. EXPECT_EQ(ink_renderer()->InkTrailTokenCountForTesting(), 1u);
  242. }
  243. // Confirm that points with different pointer ids are handled correctly.
  244. TEST_F(DelegatedInkPointRendererGpuTest, MultiplePointerIds) {
  245. if (!surface() || !surface()->SupportsDelegatedInk())
  246. return;
  247. const int32_t kPointerId1 = 1;
  248. const int32_t kPointerId2 = 2;
  249. // First send a few points with different pointer ids to make sure they are
  250. // stored separately and correctly. Separate the timestamps so that we can
  251. // test how sending metadatas impacts them each separately.
  252. const base::TimeTicks timestamp = base::TimeTicks::Now();
  253. const int kPointerId2PointsAheadOfPointerId1 = 3;
  254. SendDelegatedInkPoint(
  255. gfx::DelegatedInkPoint(gfx::PointF(16, 22), timestamp, kPointerId1));
  256. SendDelegatedInkPoint(gfx::DelegatedInkPoint(
  257. gfx::PointF(40, 13.3f),
  258. timestamp + base::Microseconds(kPointerId2PointsAheadOfPointerId1 *
  259. kMicrosecondsBetweenEachPoint),
  260. kPointerId2));
  261. uint64_t pointer_id_1_count = 1u;
  262. uint64_t pointer_id_2_count = 1u;
  263. const uint64_t kTotalPoints = 9u;
  264. for (uint64_t i = 0u; i < kTotalPoints; ++i) {
  265. if (i % 2 == 0) {
  266. SendDelegatedInkPointBasedOnPrevious(kPointerId1);
  267. pointer_id_1_count++;
  268. } else {
  269. SendDelegatedInkPointBasedOnPrevious(kPointerId2);
  270. pointer_id_2_count++;
  271. }
  272. }
  273. EXPECT_EQ(ink_renderer()->DelegatedInkPointsForTesting(kPointerId1).size(),
  274. pointer_id_1_count);
  275. EXPECT_EQ(ink_renderer()->DelegatedInkPointsForTesting(kPointerId2).size(),
  276. pointer_id_2_count);
  277. // Send a metadata matching one of the points with |kPointerId1|. This should
  278. // erase all points with a timestamp before that from the trail with
  279. // |kPointerId1| but none from the other pointer id.
  280. const uint64_t kMetadataToSendForPointerId1 = 1u;
  281. SendMetadataBasedOnStoredPoint(kPointerId1, kMetadataToSendForPointerId1);
  282. EXPECT_EQ(ink_renderer()->DelegatedInkPointsForTesting(kPointerId1).size(),
  283. pointer_id_1_count - kMetadataToSendForPointerId1);
  284. EXPECT_EQ(ink_renderer()->DelegatedInkPointsForTesting(kPointerId2).size(),
  285. pointer_id_2_count);
  286. // Now send a metadata matching one of the points with |kPointerId2|. Since
  287. // |kPointerId2| points have timestamps greater than |kPointerId1|, it should
  288. // cause some points with |kPointerId1| to be erased too.
  289. const uint64_t kMetadataToSendForPointerId2 = 2u;
  290. SendMetadataBasedOnStoredPoint(kPointerId2, kMetadataToSendForPointerId2);
  291. EXPECT_EQ(ink_renderer()->DelegatedInkPointsForTesting(kPointerId1).size(),
  292. pointer_id_1_count - kPointerId2PointsAheadOfPointerId1 -
  293. kMetadataToSendForPointerId2);
  294. EXPECT_EQ(ink_renderer()->DelegatedInkPointsForTesting(kPointerId2).size(),
  295. pointer_id_2_count - kMetadataToSendForPointerId2);
  296. // Add another pointer id into the mix and make sure the counts are all what
  297. // we expect.
  298. const int32_t kPointerId3 = 3;
  299. const int kPointerId3PointsAheadOfPointerId1 = 5;
  300. SendDelegatedInkPoint(gfx::DelegatedInkPoint(
  301. gfx::PointF(23, 64),
  302. timestamp + base::Microseconds(kPointerId3PointsAheadOfPointerId1 *
  303. kMicrosecondsBetweenEachPoint),
  304. kPointerId3));
  305. const uint64_t kPointsWithPointerId3 = 4u;
  306. for (uint64_t i = 1u; i < kPointsWithPointerId3; ++i)
  307. SendDelegatedInkPointBasedOnPrevious(kPointerId3);
  308. EXPECT_EQ(ink_renderer()->DelegatedInkPointsForTesting(kPointerId1).size(),
  309. pointer_id_1_count - kPointerId2PointsAheadOfPointerId1 -
  310. kMetadataToSendForPointerId2);
  311. EXPECT_EQ(ink_renderer()->DelegatedInkPointsForTesting(kPointerId2).size(),
  312. pointer_id_2_count - kMetadataToSendForPointerId2);
  313. EXPECT_EQ(ink_renderer()->DelegatedInkPointsForTesting(kPointerId3).size(),
  314. kPointsWithPointerId3);
  315. // Then send a point with |kPointerId3| that is beyond all the points with
  316. // |kPointerId1| to make sure that |kPointerId1| is removed from the flat map
  317. // completely.
  318. const uint64_t kMetadataToSendForPointerId3 = 1u;
  319. SendMetadataBasedOnStoredPoint(kPointerId3, kMetadataToSendForPointerId3);
  320. EXPECT_EQ(ink_renderer()->DelegatedInkPointPointerIdCountForTesting(), 2u);
  321. EXPECT_EQ(ink_renderer()->DelegatedInkPointsForTesting(kPointerId2).size(),
  322. pointer_id_2_count - kMetadataToSendForPointerId2 -
  323. kMetadataToSendForPointerId3);
  324. EXPECT_EQ(ink_renderer()->DelegatedInkPointsForTesting(kPointerId3).size(),
  325. kPointsWithPointerId3 - kMetadataToSendForPointerId3);
  326. }
  327. // Make sure that the DelegatedInkPoint with the earliest timestamp is removed
  328. // if we have reached the maximum number of pointer ids.
  329. TEST_F(DelegatedInkPointRendererGpuTest, MaximumPointerIds) {
  330. if (!surface() || !surface()->SupportsDelegatedInk())
  331. return;
  332. // First add DelegatedInkPoints with unique pointer ids up to the limit and
  333. // make sure they are all correctly added separately.
  334. const base::TimeTicks kEarliestTimestamp =
  335. base::TimeTicks::Now() -
  336. base::Microseconds(kMicrosecondsBetweenEachPoint);
  337. const int32_t kEarliestTimestampPointerId = 4;
  338. base::TimeTicks timestamp = base::TimeTicks::Now();
  339. gfx::PointF point(34.4f, 20);
  340. const uint64_t kMaxNumberOfPointerIds =
  341. ink_renderer()->GetMaximumNumberOfPointerIdsForTesting();
  342. for (uint64_t pointer_id = 0; pointer_id < kMaxNumberOfPointerIds;
  343. ++pointer_id) {
  344. SendDelegatedInkPoint(gfx::DelegatedInkPoint(
  345. point,
  346. pointer_id == kEarliestTimestampPointerId ? kEarliestTimestamp
  347. : timestamp,
  348. pointer_id));
  349. point += gfx::Vector2dF(5, 5);
  350. timestamp += base::Microseconds(kMicrosecondsBetweenEachPoint);
  351. }
  352. EXPECT_EQ(ink_renderer()->DelegatedInkPointPointerIdCountForTesting(),
  353. kMaxNumberOfPointerIds);
  354. EXPECT_TRUE(
  355. ink_renderer()->CheckForPointerIdForTesting(kEarliestTimestampPointerId));
  356. // Now send one more with a later timestamp to ensure that the one with the
  357. // earliest timestamp was removed.
  358. SendDelegatedInkPoint(
  359. gfx::DelegatedInkPoint(point, timestamp, kMaxNumberOfPointerIds));
  360. EXPECT_EQ(ink_renderer()->DelegatedInkPointPointerIdCountForTesting(),
  361. kMaxNumberOfPointerIds);
  362. EXPECT_FALSE(
  363. ink_renderer()->CheckForPointerIdForTesting(kEarliestTimestampPointerId));
  364. // Finally, add a point with a earlier timestamp than everything else and make
  365. // sure that it is not added to the map of pointer ids.
  366. point += gfx::Vector2dF(5, 5);
  367. timestamp = kEarliestTimestamp + base::Microseconds(5);
  368. const int32_t kEarlyTimestampPointerId = kMaxNumberOfPointerIds + 1;
  369. SendDelegatedInkPoint(
  370. gfx::DelegatedInkPoint(point, timestamp, kEarlyTimestampPointerId));
  371. EXPECT_EQ(ink_renderer()->DelegatedInkPointPointerIdCountForTesting(),
  372. kMaxNumberOfPointerIds);
  373. EXPECT_FALSE(
  374. ink_renderer()->CheckForPointerIdForTesting(kEarlyTimestampPointerId));
  375. }
  376. } // namespace
  377. } // namespace gl