fast_ink_host.cc 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472
  1. // Copyright 2017 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 "ash/fast_ink/fast_ink_host.h"
  5. #include <GLES2/gl2.h>
  6. #include <GLES2/gl2ext.h>
  7. #include <GLES2/gl2extchromium.h>
  8. #include <memory>
  9. #include "ash/constants/ash_switches.h"
  10. #include "base/bind.h"
  11. #include "base/threading/thread_task_runner_handle.h"
  12. #include "base/trace_event/trace_event.h"
  13. #include "cc/base/math_util.h"
  14. #include "cc/trees/layer_tree_frame_sink.h"
  15. #include "cc/trees/layer_tree_frame_sink_client.h"
  16. #include "components/viz/common/frame_timing_details.h"
  17. #include "components/viz/common/gpu/context_provider.h"
  18. #include "components/viz/common/hit_test/hit_test_region_list.h"
  19. #include "components/viz/common/quads/compositor_frame.h"
  20. #include "components/viz/common/quads/texture_draw_quad.h"
  21. #include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
  22. #include "gpu/command_buffer/client/shared_image_interface.h"
  23. #include "gpu/command_buffer/common/shared_image_usage.h"
  24. #include "ui/aura/env.h"
  25. #include "ui/aura/window.h"
  26. #include "ui/aura/window_observer.h"
  27. #include "ui/aura/window_tree_host.h"
  28. #include "ui/compositor/compositor.h"
  29. #include "ui/compositor/layer.h"
  30. #include "ui/gfx/geometry/dip_util.h"
  31. #include "ui/gfx/geometry/rect.h"
  32. #include "ui/gfx/geometry/rect_conversions.h"
  33. #include "ui/gfx/geometry/size_conversions.h"
  34. #include "ui/gfx/gpu_memory_buffer.h"
  35. namespace fast_ink {
  36. // static
  37. gfx::Rect FastInkHost::BufferRectFromWindowRect(
  38. const gfx::Transform& window_to_buffer_transform,
  39. const gfx::Size& buffer_size,
  40. const gfx::Rect& window_rect) {
  41. gfx::Rect buffer_rect = cc::MathUtil::MapEnclosingClippedRect(
  42. window_to_buffer_transform, window_rect);
  43. // Buffer rect is not bigger than actual buffer.
  44. buffer_rect.Intersect(gfx::Rect(buffer_size));
  45. return buffer_rect;
  46. }
  47. struct FastInkHost::Resource {
  48. Resource() = default;
  49. ~Resource() {
  50. // context_provider might be null in unit tests when ran with --mash
  51. // TODO(kaznacheev) Have MASH provide a context provider for tests
  52. // when https://crbug/772562 is fixed
  53. if (!context_provider)
  54. return;
  55. gpu::SharedImageInterface* sii = context_provider->SharedImageInterface();
  56. DCHECK(!mailbox.IsZero());
  57. sii->DestroySharedImage(sync_token, mailbox);
  58. }
  59. scoped_refptr<viz::ContextProvider> context_provider;
  60. gpu::Mailbox mailbox;
  61. gpu::SyncToken sync_token;
  62. bool damaged = true;
  63. };
  64. class FastInkHost::LayerTreeFrameSinkHolder
  65. : public cc::LayerTreeFrameSinkClient,
  66. public aura::WindowObserver {
  67. public:
  68. LayerTreeFrameSinkHolder(FastInkHost* host,
  69. std::unique_ptr<cc::LayerTreeFrameSink> frame_sink)
  70. : host_(host), frame_sink_(std::move(frame_sink)) {
  71. frame_sink_->BindToClient(this);
  72. }
  73. ~LayerTreeFrameSinkHolder() override {
  74. if (frame_sink_)
  75. frame_sink_->DetachFromClient();
  76. if (root_window_)
  77. root_window_->RemoveObserver(this);
  78. }
  79. LayerTreeFrameSinkHolder(const LayerTreeFrameSinkHolder&) = delete;
  80. LayerTreeFrameSinkHolder& operator=(const LayerTreeFrameSinkHolder&) = delete;
  81. // Delete frame sink after having reclaimed all exported resources.
  82. // Returns false if the it should be released instead of reset and it will
  83. // self destruct.
  84. // TODO(reveman): Find a better way to handle deletion of in-flight resources.
  85. // https://crbug.com/765763
  86. bool DeleteWhenLastResourceHasBeenReclaimed() {
  87. if (last_frame_size_in_pixels_.IsEmpty()) {
  88. // Delete sink holder immediately if no frame has been submitted.
  89. DCHECK(exported_resources_.empty());
  90. return true;
  91. }
  92. // Submit an empty frame to ensure that pending release callbacks will be
  93. // processed in a finite amount of time.
  94. viz::CompositorFrame frame;
  95. frame.metadata.begin_frame_ack.frame_id =
  96. viz::BeginFrameId(viz::BeginFrameArgs::kManualSourceId,
  97. viz::BeginFrameArgs::kStartingFrameNumber);
  98. frame.metadata.begin_frame_ack.has_damage = true;
  99. frame.metadata.device_scale_factor = last_frame_device_scale_factor_;
  100. frame.metadata.frame_token = ++next_frame_token_;
  101. auto pass = viz::CompositorRenderPass::Create();
  102. pass->SetNew(viz::CompositorRenderPassId{1},
  103. gfx::Rect(last_frame_size_in_pixels_),
  104. gfx::Rect(last_frame_size_in_pixels_), gfx::Transform());
  105. frame.render_pass_list.push_back(std::move(pass));
  106. frame_sink_->SubmitCompositorFrame(std::move(frame),
  107. /*hit_test_data_changed=*/true);
  108. // Delete sink holder immediately if not waiting for exported resources to
  109. // be reclaimed.
  110. if (exported_resources_.empty())
  111. return true;
  112. // If we have exported resources to reclaim then extend the lifetime of
  113. // holder by deleting it later.
  114. // itself when the root window is removed or when all exported resources
  115. // have been reclaimed.
  116. root_window_ = host_->host_window()->GetRootWindow();
  117. // This can be null during shutdown.
  118. if (!root_window_)
  119. return true;
  120. root_window_->AddObserver(this);
  121. host_ = nullptr;
  122. return false;
  123. }
  124. void SubmitCompositorFrame(viz::CompositorFrame frame,
  125. viz::ResourceId resource_id,
  126. std::unique_ptr<Resource> resource) {
  127. exported_resources_[resource_id] = std::move(resource);
  128. last_frame_size_in_pixels_ = frame.size_in_pixels();
  129. last_frame_device_scale_factor_ = frame.metadata.device_scale_factor;
  130. frame.metadata.frame_token = ++next_frame_token_;
  131. frame_sink_->SubmitCompositorFrame(std::move(frame),
  132. /*hit_test_data_changed=*/true);
  133. }
  134. void DamageExportedResources() {
  135. for (auto& entry : exported_resources_)
  136. entry.second->damaged = true;
  137. }
  138. // Overridden from cc::LayerTreeFrameSinkClient:
  139. void SetBeginFrameSource(viz::BeginFrameSource* source) override {}
  140. absl::optional<viz::HitTestRegionList> BuildHitTestData() override {
  141. return {};
  142. }
  143. void ReclaimResources(std::vector<viz::ReturnedResource> resources) override {
  144. if (delete_pending_)
  145. return;
  146. for (auto& entry : resources) {
  147. auto it = exported_resources_.find(entry.id);
  148. DCHECK(it != exported_resources_.end());
  149. std::unique_ptr<Resource> resource = std::move(it->second);
  150. exported_resources_.erase(it);
  151. resource->sync_token = entry.sync_token;
  152. if (host_ && !entry.lost)
  153. host_->ReclaimResource(std::move(resource));
  154. }
  155. if (root_window_ && exported_resources_.empty())
  156. ScheduleDelete();
  157. }
  158. void SetTreeActivationCallback(base::RepeatingClosure callback) override {}
  159. void DidReceiveCompositorFrameAck() override {
  160. if (host_)
  161. host_->DidReceiveCompositorFrameAck();
  162. }
  163. void DidPresentCompositorFrame(
  164. uint32_t frame_token,
  165. const viz::FrameTimingDetails& details) override {
  166. if (host_)
  167. host_->DidPresentCompositorFrame(details.presentation_feedback);
  168. }
  169. void DidLoseLayerTreeFrameSink() override {
  170. exported_resources_.clear();
  171. if (root_window_)
  172. ScheduleDelete();
  173. }
  174. void OnDraw(const gfx::Transform& transform,
  175. const gfx::Rect& viewport,
  176. bool resourceless_software_draw,
  177. bool skip_draw) override {}
  178. void SetMemoryPolicy(const cc::ManagedMemoryPolicy& policy) override {}
  179. void SetExternalTilePriorityConstraints(
  180. const gfx::Rect& viewport_rect,
  181. const gfx::Transform& transform) override {}
  182. void OnWindowDestroying(aura::Window* window) override {
  183. root_window_->RemoveObserver(this);
  184. root_window_ = nullptr;
  185. frame_sink_->DetachFromClient();
  186. frame_sink_.reset();
  187. ScheduleDelete();
  188. }
  189. private:
  190. void ScheduleDelete() {
  191. if (delete_pending_)
  192. return;
  193. delete_pending_ = true;
  194. base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
  195. }
  196. FastInkHost* host_;
  197. std::unique_ptr<cc::LayerTreeFrameSink> frame_sink_;
  198. base::flat_map<viz::ResourceId, std::unique_ptr<Resource>>
  199. exported_resources_;
  200. viz::FrameTokenGenerator next_frame_token_;
  201. gfx::Size last_frame_size_in_pixels_;
  202. float last_frame_device_scale_factor_ = 1.0f;
  203. aura::Window* root_window_ = nullptr;
  204. bool delete_pending_ = false;
  205. };
  206. FastInkHost::FastInkHost(aura::Window* host_window,
  207. const PresentationCallback& presentation_callback)
  208. : host_window_(host_window), presentation_callback_(presentation_callback) {
  209. // Take the root transform and apply this during buffer update instead of
  210. // leaving this up to the compositor. The benefit is that HW requirements
  211. // for being able to take advantage of overlays and direct scanout are
  212. // reduced significantly. Frames are submitted to the compositor with the
  213. // inverse transform to cancel out the transformation that would otherwise
  214. // be done by the compositor.
  215. window_to_buffer_transform_ = host_window_->GetHost()->GetRootTransform();
  216. gfx::Rect bounds(host_window_->GetBoundsInScreen().size());
  217. buffer_size_ =
  218. gfx::ToEnclosedRect(cc::MathUtil::MapClippedRect(
  219. window_to_buffer_transform_,
  220. gfx::RectF(bounds.width(), bounds.height())))
  221. .size();
  222. // Create a single GPU memory buffer. Content will be written into this
  223. // buffer without any buffering. The result is that we might be modifying
  224. // the buffer while it's being displayed. This provides minimal latency
  225. // but with potential tearing. Note that we have to draw into a temporary
  226. // surface and copy it into GPU memory buffer to avoid flicker.
  227. gpu_memory_buffer_ =
  228. aura::Env::GetInstance()
  229. ->context_factory()
  230. ->GetGpuMemoryBufferManager()
  231. ->CreateGpuMemoryBuffer(buffer_size_,
  232. SK_B32_SHIFT ? gfx::BufferFormat::RGBA_8888
  233. : gfx::BufferFormat::BGRA_8888,
  234. gfx::BufferUsage::SCANOUT_CPU_READ_WRITE,
  235. gpu::kNullSurfaceHandle, nullptr);
  236. LOG_IF(ERROR, !gpu_memory_buffer_) << "Failed to create GPU memory buffer";
  237. if (ash::switches::ShouldClearFastInkBuffer()) {
  238. bool map_result = gpu_memory_buffer_->Map();
  239. LOG_IF(ERROR, !map_result) << "Failed to map gpu buffer";
  240. uint8_t* memory = static_cast<uint8_t*>(gpu_memory_buffer_->memory(0));
  241. if (memory != nullptr) {
  242. gfx::Size size = gpu_memory_buffer_->GetSize();
  243. int stride = gpu_memory_buffer_->stride(0);
  244. // Clear the buffer before usage, since it may be uninitialized.
  245. // (http://b/168735625)
  246. for (int i = 0; i < size.height(); ++i)
  247. memset(memory + i * stride, 0, size.width() * 4);
  248. }
  249. gpu_memory_buffer_->Unmap();
  250. }
  251. frame_sink_holder_ = std::make_unique<LayerTreeFrameSinkHolder>(
  252. this, host_window_->CreateLayerTreeFrameSink());
  253. }
  254. FastInkHost::~FastInkHost() {
  255. if (!frame_sink_holder_->DeleteWhenLastResourceHasBeenReclaimed())
  256. frame_sink_holder_.release();
  257. }
  258. void FastInkHost::UpdateSurface(const gfx::Rect& content_rect,
  259. const gfx::Rect& damage_rect,
  260. bool auto_refresh) {
  261. content_rect_ = content_rect;
  262. damage_rect_.Union(damage_rect);
  263. auto_refresh_ = auto_refresh;
  264. pending_compositor_frame_ = true;
  265. if (!damage_rect.IsEmpty()) {
  266. frame_sink_holder_->DamageExportedResources();
  267. for (auto& resource : returned_resources_)
  268. resource->damaged = true;
  269. }
  270. if (!pending_compositor_frame_ack_)
  271. SubmitCompositorFrame();
  272. }
  273. void FastInkHost::SubmitCompositorFrame() {
  274. TRACE_EVENT1("ui", "FastInkHost::SubmitCompositorFrame", "damage",
  275. damage_rect_.ToString());
  276. float device_scale_factor = host_window_->layer()->device_scale_factor();
  277. gfx::Size window_size_in_dip = host_window_->GetBoundsInScreen().size();
  278. // TODO(crbug.com/1131619): Should this be ceil? Why do we choose floor?
  279. gfx::Size window_size_in_pixel = gfx::ToFlooredSize(
  280. gfx::ConvertSizeToPixels(window_size_in_dip, device_scale_factor));
  281. gfx::Rect output_rect(window_size_in_pixel);
  282. gfx::Rect quad_rect;
  283. gfx::Rect damage_rect;
  284. // Continuously redraw the full output rectangle when in auto-refresh mode.
  285. // This is necessary in order to allow single buffered updates without having
  286. // buffer changes outside the contents area cause artifacts.
  287. if (auto_refresh_) {
  288. quad_rect = gfx::Rect(buffer_size_);
  289. damage_rect = gfx::Rect(output_rect);
  290. } else {
  291. // Use minimal quad and damage rectangles when auto-refresh mode is off.
  292. quad_rect = BufferRectFromWindowRect(window_to_buffer_transform_,
  293. buffer_size_, content_rect_);
  294. damage_rect = gfx::ToEnclosingRect(
  295. gfx::ConvertRectToPixels(damage_rect_, device_scale_factor));
  296. damage_rect.Intersect(output_rect);
  297. pending_compositor_frame_ = false;
  298. }
  299. damage_rect_ = gfx::Rect();
  300. std::unique_ptr<Resource> resource;
  301. // Reuse returned resource if available.
  302. if (!returned_resources_.empty()) {
  303. resource = std::move(returned_resources_.back());
  304. returned_resources_.pop_back();
  305. }
  306. // Create new resource if needed.
  307. if (!resource)
  308. resource = std::make_unique<Resource>();
  309. if (resource->damaged) {
  310. // Acquire context provider for resource if needed.
  311. // Note: We make no attempts to recover if the context provider is later
  312. // lost. It is expected that this class is short-lived and requiring a
  313. // new instance to be created in lost context situations is acceptable and
  314. // keeps the code simple.
  315. if (!resource->context_provider) {
  316. resource->context_provider = aura::Env::GetInstance()
  317. ->context_factory()
  318. ->SharedMainThreadContextProvider();
  319. if (!resource->context_provider) {
  320. LOG(ERROR) << "Failed to acquire a context provider";
  321. return;
  322. }
  323. }
  324. gpu::SharedImageInterface* sii =
  325. resource->context_provider->SharedImageInterface();
  326. if (resource->mailbox.IsZero()) {
  327. DCHECK(!resource->sync_token.HasData());
  328. const uint32_t usage =
  329. gpu::SHARED_IMAGE_USAGE_DISPLAY | gpu::SHARED_IMAGE_USAGE_SCANOUT;
  330. gpu::GpuMemoryBufferManager* gmb_manager =
  331. aura::Env::GetInstance()
  332. ->context_factory()
  333. ->GetGpuMemoryBufferManager();
  334. resource->mailbox = sii->CreateSharedImage(
  335. gpu_memory_buffer_.get(), gmb_manager, gfx::ColorSpace(),
  336. kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, usage);
  337. } else {
  338. sii->UpdateSharedImage(resource->sync_token, resource->mailbox);
  339. }
  340. resource->sync_token = sii->GenVerifiedSyncToken();
  341. resource->damaged = false;
  342. }
  343. viz::TransferableResource transferable_resource;
  344. transferable_resource.id = id_generator_.GenerateNextId();
  345. transferable_resource.format =
  346. SK_B32_SHIFT ? viz::RGBA_8888 : viz::BGRA_8888;
  347. transferable_resource.filter = GL_LINEAR;
  348. transferable_resource.size = buffer_size_;
  349. transferable_resource.mailbox_holder = gpu::MailboxHolder(
  350. resource->mailbox, resource->sync_token, GL_TEXTURE_2D);
  351. // Use HW overlay if continuous updates are expected.
  352. transferable_resource.is_overlay_candidate = auto_refresh_;
  353. gfx::Transform target_to_buffer_transform(window_to_buffer_transform_);
  354. target_to_buffer_transform.Scale(1.f / device_scale_factor,
  355. 1.f / device_scale_factor);
  356. gfx::Transform buffer_to_target_transform;
  357. bool rv = target_to_buffer_transform.GetInverse(&buffer_to_target_transform);
  358. DCHECK(rv);
  359. const viz::CompositorRenderPassId kRenderPassId{1};
  360. auto render_pass = viz::CompositorRenderPass::Create();
  361. render_pass->SetNew(kRenderPassId, output_rect, damage_rect,
  362. buffer_to_target_transform);
  363. viz::SharedQuadState* quad_state =
  364. render_pass->CreateAndAppendSharedQuadState();
  365. quad_state->SetAll(buffer_to_target_transform,
  366. /*quad_layer_rect=*/output_rect,
  367. /*visible_layer_rect=*/output_rect,
  368. /*mask_filter_info=*/gfx::MaskFilterInfo(),
  369. /*clip_rect=*/absl::nullopt, /*are_contents_opaque=*/false,
  370. /*opacity=*/1.f,
  371. /*blend_mode=*/SkBlendMode::kSrcOver,
  372. /*sorting_context_id=*/0);
  373. viz::CompositorFrame frame;
  374. // TODO(eseckler): FastInkHost should use BeginFrames and set the ack
  375. // accordingly.
  376. frame.metadata.begin_frame_ack =
  377. viz::BeginFrameAck::CreateManualAckWithDamage();
  378. frame.metadata.device_scale_factor = device_scale_factor;
  379. viz::TextureDrawQuad* texture_quad =
  380. render_pass->CreateAndAppendDrawQuad<viz::TextureDrawQuad>();
  381. float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f};
  382. gfx::RectF uv_crop(quad_rect);
  383. uv_crop.Scale(1.f / buffer_size_.width(), 1.f / buffer_size_.height());
  384. texture_quad->SetNew(
  385. quad_state, quad_rect, quad_rect,
  386. /*needs_blending=*/true, transferable_resource.id,
  387. /*premultiplied_alpha=*/true, uv_crop.origin(), uv_crop.bottom_right(),
  388. /*background_color=*/SkColors::kTransparent, vertex_opacity,
  389. /*y_flipped=*/false,
  390. /*nearest_neighbor=*/false,
  391. /*secure_output_only=*/false, gfx::ProtectedVideoType::kClear);
  392. texture_quad->set_resource_size_in_pixels(transferable_resource.size);
  393. frame.resource_list.push_back(transferable_resource);
  394. DCHECK(!pending_compositor_frame_ack_);
  395. pending_compositor_frame_ack_ = true;
  396. frame.render_pass_list.push_back(std::move(render_pass));
  397. frame_sink_holder_->SubmitCompositorFrame(
  398. std::move(frame), transferable_resource.id, std::move(resource));
  399. }
  400. void FastInkHost::SubmitPendingCompositorFrame() {
  401. if (pending_compositor_frame_ && !pending_compositor_frame_ack_)
  402. SubmitCompositorFrame();
  403. }
  404. void FastInkHost::DidReceiveCompositorFrameAck() {
  405. pending_compositor_frame_ack_ = false;
  406. if (pending_compositor_frame_) {
  407. base::ThreadTaskRunnerHandle::Get()->PostTask(
  408. FROM_HERE, base::BindOnce(&FastInkHost::SubmitPendingCompositorFrame,
  409. weak_ptr_factory_.GetWeakPtr()));
  410. }
  411. }
  412. void FastInkHost::DidPresentCompositorFrame(
  413. const gfx::PresentationFeedback& feedback) {
  414. if (!presentation_callback_.is_null())
  415. presentation_callback_.Run(feedback);
  416. }
  417. void FastInkHost::ReclaimResource(std::unique_ptr<Resource> resource) {
  418. returned_resources_.push_back(std::move(resource));
  419. }
  420. } // namespace fast_ink