buffer.cc 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729
  1. // Copyright 2015 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 "components/exo/buffer.h"
  5. #include <stdint.h>
  6. #include <algorithm>
  7. #include <utility>
  8. #include "base/bind.h"
  9. #include "base/callback_helpers.h"
  10. #include "base/logging.h"
  11. #include "base/memory/weak_ptr.h"
  12. #include "base/threading/thread_task_runner_handle.h"
  13. #include "base/time/time.h"
  14. #include "base/trace_event/trace_event.h"
  15. #include "base/trace_event/traced_value.h"
  16. #include "build/build_config.h"
  17. #include "components/exo/frame_sink_resource_manager.h"
  18. #include "components/viz/common/gpu/context_lost_observer.h"
  19. #include "components/viz/common/gpu/context_provider.h"
  20. #include "components/viz/common/resources/resource_format.h"
  21. #include "components/viz/common/resources/resource_format_utils.h"
  22. #include "components/viz/common/resources/resource_id.h"
  23. #include "components/viz/common/resources/returned_resource.h"
  24. #include "gpu/GLES2/gl2extchromium.h"
  25. #include "gpu/command_buffer/client/context_support.h"
  26. #include "gpu/command_buffer/client/raster_interface.h"
  27. #include "gpu/command_buffer/client/shared_image_interface.h"
  28. #include "gpu/command_buffer/common/mailbox.h"
  29. #include "gpu/command_buffer/common/shared_image_usage.h"
  30. #include "gpu/command_buffer/common/sync_token.h"
  31. #include "ui/aura/env.h"
  32. #include "ui/compositor/compositor.h"
  33. #include "ui/gfx/gpu_fence_handle.h"
  34. #include "ui/gfx/gpu_memory_buffer.h"
  35. #if BUILDFLAG(USE_ARC_PROTECTED_MEDIA)
  36. #include "base/files/scoped_file.h"
  37. #include "base/posix/eintr_wrapper.h"
  38. #endif // BUILDFLAG(USE_ARC_PROTECTED_MEDIA)
  39. namespace exo {
  40. namespace {
  41. // The amount of time before we wait for release queries using
  42. // GetQueryObjectuivEXT(GL_QUERY_RESULT_EXT).
  43. const int kWaitForReleaseDelayMs = 500;
  44. constexpr char kBufferInUse[] = "BufferInUse";
  45. } // namespace
  46. ////////////////////////////////////////////////////////////////////////////////
  47. // Buffer::Texture
  48. // Encapsulates the state and logic needed to bind a buffer to a SharedImage.
  49. class Buffer::Texture : public viz::ContextLostObserver {
  50. public:
  51. Texture(scoped_refptr<viz::RasterContextProvider> context_provider,
  52. const gfx::Size& size);
  53. Texture(scoped_refptr<viz::RasterContextProvider> context_provider,
  54. gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
  55. gfx::GpuMemoryBuffer* gpu_memory_buffer,
  56. unsigned texture_target,
  57. unsigned query_type,
  58. base::TimeDelta wait_for_release_time,
  59. bool is_overlay_candidate);
  60. Texture(const Texture&) = delete;
  61. Texture& operator=(const Texture&) = delete;
  62. ~Texture() override;
  63. // Overridden from viz::ContextLostObserver:
  64. void OnContextLost() override;
  65. // Returns true if the RasterInterface context has been lost.
  66. bool IsLost();
  67. // Allow texture to be reused after |sync_token| has passed and runs
  68. // |callback|.
  69. void Release(base::OnceCallback<void(gfx::GpuFenceHandle)> callback,
  70. viz::ReturnedResource resource);
  71. // Updates the contents referenced by |gpu_memory_buffer_| returned by
  72. // mailbox().
  73. // Returns a sync token that can be used when accessing the SharedImage from a
  74. // different context.
  75. gpu::SyncToken UpdateSharedImage(
  76. std::unique_ptr<gfx::GpuFence> acquire_fence);
  77. // Releases the contents referenced by |mailbox_| after |sync_token| has
  78. // passed and runs |callback| when completed.
  79. void ReleaseSharedImage(
  80. base::OnceCallback<void(gfx::GpuFenceHandle)> callback,
  81. viz::ReturnedResource resource);
  82. // Copy the contents of texture to |destination| and runs |callback| when
  83. // completed. Returns a sync token that can be used when accessing texture
  84. // from a different context.
  85. gpu::SyncToken CopyTexImage(std::unique_ptr<gfx::GpuFence> acquire_fence,
  86. Texture* destination,
  87. base::OnceClosure callback);
  88. // Returns the mailbox for this texture.
  89. gpu::Mailbox mailbox() const { return mailbox_; }
  90. private:
  91. void DestroyResources();
  92. void ReleaseWhenQueryResultIsAvailable(base::OnceClosure callback);
  93. void Released();
  94. void ScheduleWaitForRelease(base::TimeDelta delay);
  95. void WaitForRelease();
  96. gfx::GpuMemoryBuffer* const gpu_memory_buffer_;
  97. const gfx::Size size_;
  98. scoped_refptr<viz::RasterContextProvider> context_provider_;
  99. const unsigned texture_target_;
  100. const unsigned query_type_;
  101. unsigned query_id_ = 0;
  102. gpu::Mailbox mailbox_;
  103. base::OnceClosure release_callback_;
  104. const base::TimeDelta wait_for_release_delay_;
  105. base::TimeTicks wait_for_release_time_;
  106. bool wait_for_release_pending_ = false;
  107. base::WeakPtrFactory<Texture> weak_ptr_factory_{this};
  108. };
  109. Buffer::Texture::Texture(
  110. scoped_refptr<viz::RasterContextProvider> context_provider,
  111. const gfx::Size& size)
  112. : gpu_memory_buffer_(nullptr),
  113. size_(size),
  114. context_provider_(std::move(context_provider)),
  115. texture_target_(GL_TEXTURE_2D),
  116. query_type_(GL_COMMANDS_COMPLETED_CHROMIUM) {
  117. gpu::SharedImageInterface* sii = context_provider_->SharedImageInterface();
  118. // Add GLES2 usage as it is used by RasterImplementationGLES.
  119. const uint32_t usage = gpu::SHARED_IMAGE_USAGE_RASTER |
  120. gpu::SHARED_IMAGE_USAGE_DISPLAY |
  121. gpu::SHARED_IMAGE_USAGE_GLES2;
  122. mailbox_ = sii->CreateSharedImage(
  123. viz::ResourceFormat::RGBA_8888, size, gfx::ColorSpace::CreateSRGB(),
  124. kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, usage,
  125. gpu::kNullSurfaceHandle);
  126. DCHECK(!mailbox_.IsZero());
  127. gpu::raster::RasterInterface* ri = context_provider_->RasterInterface();
  128. ri->WaitSyncTokenCHROMIUM(sii->GenUnverifiedSyncToken().GetConstData());
  129. // Provides a notification when |context_provider_| is lost.
  130. context_provider_->AddObserver(this);
  131. }
  132. Buffer::Texture::Texture(
  133. scoped_refptr<viz::RasterContextProvider> context_provider,
  134. gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
  135. gfx::GpuMemoryBuffer* gpu_memory_buffer,
  136. unsigned texture_target,
  137. unsigned query_type,
  138. base::TimeDelta wait_for_release_delay,
  139. bool is_overlay_candidate)
  140. : gpu_memory_buffer_(gpu_memory_buffer),
  141. size_(gpu_memory_buffer->GetSize()),
  142. context_provider_(std::move(context_provider)),
  143. texture_target_(texture_target),
  144. query_type_(query_type),
  145. wait_for_release_delay_(wait_for_release_delay) {
  146. gpu::SharedImageInterface* sii = context_provider_->SharedImageInterface();
  147. // Add GLES2 usage as it is used by RasterImplementationGLES.
  148. uint32_t usage = gpu::SHARED_IMAGE_USAGE_RASTER |
  149. gpu::SHARED_IMAGE_USAGE_DISPLAY |
  150. gpu::SHARED_IMAGE_USAGE_GLES2;
  151. if (is_overlay_candidate) {
  152. usage |= gpu::SHARED_IMAGE_USAGE_SCANOUT;
  153. }
  154. mailbox_ = sii->CreateSharedImage(
  155. gpu_memory_buffer_, gpu_memory_buffer_manager,
  156. gfx::ColorSpace::CreateSRGB(), kTopLeft_GrSurfaceOrigin,
  157. kPremul_SkAlphaType, usage);
  158. DCHECK(!mailbox_.IsZero());
  159. gpu::raster::RasterInterface* ri = context_provider_->RasterInterface();
  160. ri->WaitSyncTokenCHROMIUM(sii->GenUnverifiedSyncToken().GetConstData());
  161. ri->GenQueriesEXT(1, &query_id_);
  162. // Provides a notification when |context_provider_| is lost.
  163. context_provider_->AddObserver(this);
  164. }
  165. Buffer::Texture::~Texture() {
  166. DestroyResources();
  167. if (context_provider_)
  168. context_provider_->RemoveObserver(this);
  169. }
  170. void Buffer::Texture::OnContextLost() {
  171. DestroyResources();
  172. context_provider_->RemoveObserver(this);
  173. context_provider_.reset();
  174. }
  175. bool Buffer::Texture::IsLost() {
  176. if (context_provider_) {
  177. gpu::raster::RasterInterface* ri = context_provider_->RasterInterface();
  178. return ri->GetGraphicsResetStatusKHR() != GL_NO_ERROR;
  179. }
  180. return true;
  181. }
  182. void Buffer::Texture::Release(
  183. base::OnceCallback<void(gfx::GpuFenceHandle)> callback,
  184. viz::ReturnedResource resource) {
  185. if (context_provider_) {
  186. // Only need to wait on the sync token if we don't have a release fence.
  187. if (resource.sync_token.HasData() && resource.release_fence.is_null()) {
  188. gpu::raster::RasterInterface* ri = context_provider_->RasterInterface();
  189. ri->WaitSyncTokenCHROMIUM(resource.sync_token.GetConstData());
  190. }
  191. }
  192. // Run callback as texture can be reused immediately after waiting for sync
  193. // token.
  194. std::move(callback).Run(std::move(resource.release_fence));
  195. }
  196. gpu::SyncToken Buffer::Texture::UpdateSharedImage(
  197. std::unique_ptr<gfx::GpuFence> acquire_fence) {
  198. gpu::SyncToken sync_token;
  199. if (context_provider_) {
  200. gpu::SharedImageInterface* sii = context_provider_->SharedImageInterface();
  201. DCHECK(!mailbox_.IsZero());
  202. // UpdateSharedImage gets called only after |mailbox_| can be reused.
  203. // A buffer can be reattached to a surface only after it has been returned
  204. // to wayland clients. We return buffers to clients only after the query
  205. // |query_type_| is available.
  206. sii->UpdateSharedImage(gpu::SyncToken(), std::move(acquire_fence),
  207. mailbox_);
  208. sync_token = sii->GenUnverifiedSyncToken();
  209. TRACE_EVENT_ASYNC_STEP_INTO0("exo", kBufferInUse, gpu_memory_buffer_,
  210. "bound");
  211. }
  212. return sync_token;
  213. }
  214. void Buffer::Texture::ReleaseSharedImage(
  215. base::OnceCallback<void(gfx::GpuFenceHandle)> callback,
  216. viz::ReturnedResource resource) {
  217. // Only need to wait on the sync token and query if we don't have a release
  218. // fence.
  219. if (context_provider_ && resource.release_fence.is_null()) {
  220. gpu::raster::RasterInterface* ri = context_provider_->RasterInterface();
  221. if (resource.sync_token.HasData())
  222. ri->WaitSyncTokenCHROMIUM(resource.sync_token.GetConstData());
  223. ri->BeginQueryEXT(query_type_, query_id_);
  224. ri->EndQueryEXT(query_type_);
  225. // Run callback when query result is available (i.e., when all operations on
  226. // the shared image have completed and it's ready to be reused) if sync
  227. // token has data and buffer has been used. If buffer was never used then
  228. // run the callback immediately.
  229. if (resource.sync_token.HasData()) {
  230. ReleaseWhenQueryResultIsAvailable(base::BindOnce(
  231. std::move(callback), /*release_fence=*/gfx::GpuFenceHandle()));
  232. return;
  233. }
  234. }
  235. std::move(callback).Run(std::move(resource.release_fence));
  236. }
  237. gpu::SyncToken Buffer::Texture::CopyTexImage(
  238. std::unique_ptr<gfx::GpuFence> acquire_fence,
  239. Texture* destination,
  240. base::OnceClosure callback) {
  241. gpu::SyncToken sync_token;
  242. if (context_provider_) {
  243. DCHECK(!mailbox_.IsZero());
  244. gpu::SharedImageInterface* sii = context_provider_->SharedImageInterface();
  245. sii->UpdateSharedImage(gpu::SyncToken(), std::move(acquire_fence),
  246. mailbox_);
  247. sync_token = sii->GenUnverifiedSyncToken();
  248. gpu::raster::RasterInterface* ri = context_provider_->RasterInterface();
  249. ri->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
  250. DCHECK_NE(query_id_, 0u);
  251. ri->BeginQueryEXT(query_type_, query_id_);
  252. ri->CopySubTexture(mailbox_, destination->mailbox_,
  253. destination->texture_target_, 0, 0, 0, 0, size_.width(),
  254. size_.height(), /*unpack_flip_y=*/false,
  255. /*unpack_premultiply_alpha=*/false);
  256. ri->EndQueryEXT(query_type_);
  257. // Run callback when query result is available.
  258. ReleaseWhenQueryResultIsAvailable(std::move(callback));
  259. // Create and return a sync token that can be used to ensure that the
  260. // CopySubTexture call is processed before issuing any commands
  261. // that will read from the target texture on a different context.
  262. ri->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData());
  263. }
  264. return sync_token;
  265. }
  266. void Buffer::Texture::DestroyResources() {
  267. if (context_provider_) {
  268. if (query_id_) {
  269. gpu::raster::RasterInterface* ri = context_provider_->RasterInterface();
  270. ri->DeleteQueriesEXT(1, &query_id_);
  271. query_id_ = 0;
  272. }
  273. gpu::SharedImageInterface* sii = context_provider_->SharedImageInterface();
  274. sii->DestroySharedImage(gpu::SyncToken(), mailbox_);
  275. }
  276. }
  277. void Buffer::Texture::ReleaseWhenQueryResultIsAvailable(
  278. base::OnceClosure callback) {
  279. DCHECK(context_provider_);
  280. DCHECK(release_callback_.is_null());
  281. release_callback_ = std::move(callback);
  282. wait_for_release_time_ = base::TimeTicks::Now() + wait_for_release_delay_;
  283. ScheduleWaitForRelease(wait_for_release_delay_);
  284. TRACE_EVENT_ASYNC_STEP_INTO0("exo", kBufferInUse, gpu_memory_buffer_,
  285. "pending_query");
  286. context_provider_->ContextSupport()->SignalQuery(
  287. query_id_, base::BindOnce(&Buffer::Texture::Released,
  288. weak_ptr_factory_.GetWeakPtr()));
  289. }
  290. void Buffer::Texture::Released() {
  291. if (!release_callback_.is_null())
  292. std::move(release_callback_).Run();
  293. }
  294. void Buffer::Texture::ScheduleWaitForRelease(base::TimeDelta delay) {
  295. if (wait_for_release_pending_)
  296. return;
  297. wait_for_release_pending_ = true;
  298. base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
  299. FROM_HERE,
  300. base::BindOnce(&Buffer::Texture::WaitForRelease,
  301. weak_ptr_factory_.GetWeakPtr()),
  302. delay);
  303. }
  304. void Buffer::Texture::WaitForRelease() {
  305. DCHECK(wait_for_release_pending_);
  306. wait_for_release_pending_ = false;
  307. if (release_callback_.is_null())
  308. return;
  309. base::TimeTicks current_time = base::TimeTicks::Now();
  310. if (current_time < wait_for_release_time_) {
  311. ScheduleWaitForRelease(wait_for_release_time_ - current_time);
  312. return;
  313. }
  314. base::OnceClosure callback = std::move(release_callback_);
  315. if (context_provider_) {
  316. TRACE_EVENT0("exo", "Buffer::Texture::WaitForQueryResult");
  317. // We need to wait for the result to be available. Getting the result of
  318. // the query implies waiting for it to become available. The actual result
  319. // is unimportant and also not well defined.
  320. unsigned result = 0;
  321. gpu::raster::RasterInterface* ri = context_provider_->RasterInterface();
  322. ri->GetQueryObjectuivEXT(query_id_, GL_QUERY_RESULT_EXT, &result);
  323. }
  324. std::move(callback).Run();
  325. }
  326. Buffer::BufferRelease::BufferRelease(
  327. gfx::GpuFenceHandle release_fence,
  328. std::unique_ptr<base::FileDescriptorWatcher::Controller> controller,
  329. base::OnceClosure buffer_release_callback)
  330. : release_fence(std::move(release_fence)),
  331. controller(std::move(controller)),
  332. buffer_release_callback(std::move(buffer_release_callback)) {}
  333. Buffer::BufferRelease::~BufferRelease() = default;
  334. Buffer::BufferRelease::BufferRelease(BufferRelease&&) = default;
  335. Buffer::BufferRelease& Buffer::BufferRelease::operator=(BufferRelease&&) =
  336. default;
  337. ////////////////////////////////////////////////////////////////////////////////
  338. // Buffer, public:
  339. Buffer::Buffer(std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer)
  340. : Buffer(std::move(gpu_memory_buffer),
  341. GL_TEXTURE_2D /* texture_target */,
  342. GL_COMMANDS_COMPLETED_CHROMIUM /* query_type */,
  343. true /* use_zero_copy */,
  344. false /* is_overlay_candidate */,
  345. false /* y_invert */) {}
  346. Buffer::Buffer(std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer,
  347. unsigned texture_target,
  348. unsigned query_type,
  349. bool use_zero_copy,
  350. bool is_overlay_candidate,
  351. bool y_invert)
  352. : gpu_memory_buffer_(std::move(gpu_memory_buffer)),
  353. texture_target_(texture_target),
  354. query_type_(query_type),
  355. use_zero_copy_(use_zero_copy),
  356. is_overlay_candidate_(is_overlay_candidate),
  357. y_invert_(y_invert),
  358. wait_for_release_delay_(base::Milliseconds(kWaitForReleaseDelayMs)) {}
  359. Buffer::~Buffer() {}
  360. bool Buffer::ProduceTransferableResource(
  361. FrameSinkResourceManager* resource_manager,
  362. std::unique_ptr<gfx::GpuFence> acquire_fence,
  363. bool secure_output_only,
  364. viz::TransferableResource* resource,
  365. ProtectedNativePixmapQueryDelegate* protected_native_pixmap_query,
  366. PerCommitExplicitReleaseCallback per_commit_explicit_release_callback) {
  367. TRACE_EVENT1("exo", "Buffer::ProduceTransferableResource", "buffer_id",
  368. static_cast<const void*>(gfx_buffer()));
  369. DCHECK(attach_count_);
  370. next_commit_id_++;
  371. // If textures are lost, destroy them to ensure that we create new ones below.
  372. if (contents_texture_ && contents_texture_->IsLost())
  373. contents_texture_.reset();
  374. if (texture_ && texture_->IsLost())
  375. texture_.reset();
  376. ui::ContextFactory* context_factory =
  377. aura::Env::GetInstance()->context_factory();
  378. // Note: This can fail if GPU acceleration has been disabled.
  379. scoped_refptr<viz::RasterContextProvider> context_provider =
  380. context_factory->SharedMainThreadRasterContextProvider();
  381. if (!context_provider) {
  382. DLOG(WARNING) << "Failed to acquire a context provider";
  383. resource->id = viz::kInvalidResourceId;
  384. resource->size = gfx::Size();
  385. if (per_commit_explicit_release_callback)
  386. std::move(per_commit_explicit_release_callback)
  387. .Run(/*release_fence=*/gfx::GpuFenceHandle());
  388. return false;
  389. }
  390. const bool request_release_fence =
  391. !per_commit_explicit_release_callback.is_null();
  392. if (per_commit_explicit_release_callback)
  393. pending_explicit_releases_.emplace(
  394. next_commit_id_, std::move(per_commit_explicit_release_callback));
  395. resource->id = resource_manager->AllocateResourceId();
  396. resource->format = viz::RGBA_8888;
  397. resource->filter = GL_LINEAR;
  398. resource->size = gpu_memory_buffer_->GetSize();
  399. // Create a new image texture for |gpu_memory_buffer_| with |texture_target_|
  400. // if one doesn't already exist. The contents of this buffer are copied to
  401. // |texture| using a call to CopyTexImage.
  402. if (!contents_texture_) {
  403. contents_texture_ = std::make_unique<Texture>(
  404. context_provider, context_factory->GetGpuMemoryBufferManager(),
  405. gpu_memory_buffer_.get(), texture_target_, query_type_,
  406. wait_for_release_delay_, is_overlay_candidate_);
  407. }
  408. Texture* contents_texture = contents_texture_.get();
  409. if (release_contents_callback_.IsCancelled())
  410. TRACE_EVENT_ASYNC_BEGIN1("exo", kBufferInUse, gpu_memory_buffer_.get(),
  411. "buffer_id",
  412. static_cast<const void*>(gfx_buffer()));
  413. // Cancel pending contents release callback.
  414. release_contents_callback_.Reset(
  415. base::BindOnce(&Buffer::ReleaseContents, base::Unretained(this)));
  416. #if BUILDFLAG(USE_ARC_PROTECTED_MEDIA)
  417. // Check if this buffer needs HW protection. This can only happen if we
  418. // require a secure output.
  419. if (secure_output_only &&
  420. protected_buffer_state_ == ProtectedBufferState::UNKNOWN &&
  421. gpu_memory_buffer_ && protected_native_pixmap_query) {
  422. gfx::GpuMemoryBufferHandle gmb_handle = gpu_memory_buffer_->CloneHandle();
  423. if (!gmb_handle.native_pixmap_handle.planes.empty()) {
  424. base::ScopedFD pixmap_handle(HANDLE_EINTR(
  425. dup(gmb_handle.native_pixmap_handle.planes[0].fd.get())));
  426. if (pixmap_handle.is_valid()) {
  427. protected_buffer_state_ = ProtectedBufferState::QUERYING;
  428. protected_native_pixmap_query->IsProtectedNativePixmapHandle(
  429. std::move(pixmap_handle),
  430. base::BindOnce(&Buffer::OnIsProtectedNativePixmapHandle,
  431. AsWeakPtr()));
  432. }
  433. }
  434. }
  435. #endif // BUILDFLAG(USE_ARC_PROTECTED_MEDIA)
  436. // Zero-copy means using the contents texture directly.
  437. if (use_zero_copy_) {
  438. // This binds the latest contents of this buffer to |contents_texture|.
  439. gpu::SyncToken sync_token =
  440. contents_texture->UpdateSharedImage(std::move(acquire_fence));
  441. resource->mailbox_holder = gpu::MailboxHolder(contents_texture->mailbox(),
  442. sync_token, texture_target_);
  443. resource->is_overlay_candidate = is_overlay_candidate_;
  444. resource->format = viz::GetResourceFormat(gpu_memory_buffer_->GetFormat());
  445. if (context_provider->ContextCapabilities().chromium_gpu_fence &&
  446. request_release_fence) {
  447. resource->synchronization_type =
  448. viz::TransferableResource::SynchronizationType::kReleaseFence;
  449. }
  450. // The contents texture will be released when no longer used by the
  451. // compositor.
  452. resource_manager->SetResourceReleaseCallback(
  453. resource->id,
  454. base::BindOnce(&Buffer::Texture::ReleaseSharedImage,
  455. base::Unretained(contents_texture),
  456. base::BindOnce(&Buffer::ReleaseContentsTexture,
  457. AsWeakPtr(), std::move(contents_texture_),
  458. release_contents_callback_.callback(),
  459. next_commit_id_)));
  460. return true;
  461. }
  462. // Create a mailbox texture that we copy the buffer contents to.
  463. if (!texture_) {
  464. texture_ = std::make_unique<Texture>(context_provider,
  465. gpu_memory_buffer_->GetSize());
  466. }
  467. Texture* texture = texture_.get();
  468. // Copy the contents of |contents_texture| to |texture| and produce a
  469. // texture mailbox from the result in |texture|. The contents texture will
  470. // be released when copy has completed.
  471. gpu::SyncToken sync_token = contents_texture->CopyTexImage(
  472. std::move(acquire_fence), texture,
  473. base::BindOnce(&Buffer::ReleaseContentsTexture, AsWeakPtr(),
  474. std::move(contents_texture_),
  475. release_contents_callback_.callback(), next_commit_id_,
  476. /*release_fence=*/gfx::GpuFenceHandle()));
  477. resource->mailbox_holder =
  478. gpu::MailboxHolder(texture->mailbox(), sync_token, GL_TEXTURE_2D);
  479. resource->is_overlay_candidate = false;
  480. // The mailbox texture will be released when no longer used by the
  481. // compositor.
  482. resource_manager->SetResourceReleaseCallback(
  483. resource->id,
  484. base::BindOnce(&Buffer::Texture::Release, base::Unretained(texture),
  485. base::BindOnce(&Buffer::ReleaseTexture, AsWeakPtr(),
  486. std::move(texture_))));
  487. return true;
  488. }
  489. void Buffer::OnAttach() {
  490. DLOG_IF(WARNING, attach_count_)
  491. << "Reattaching a buffer that is already attached to another surface.";
  492. TRACE_EVENT2("exo", "Buffer::OnAttach", "buffer_id",
  493. static_cast<const void*>(gfx_buffer()), "count", attach_count_);
  494. ++attach_count_;
  495. }
  496. void Buffer::OnDetach() {
  497. DCHECK_GT(attach_count_, 0u);
  498. TRACE_EVENT2("exo", "Buffer::OnAttach", "buffer_id",
  499. static_cast<const void*>(gfx_buffer()), "count", attach_count_);
  500. --attach_count_;
  501. // Release buffer if no longer attached to a surface and content has been
  502. // released.
  503. if (!attach_count_ && release_contents_callback_.IsCancelled())
  504. Release();
  505. }
  506. gfx::Size Buffer::GetSize() const {
  507. return gpu_memory_buffer_->GetSize();
  508. }
  509. gfx::BufferFormat Buffer::GetFormat() const {
  510. return gpu_memory_buffer_->GetFormat();
  511. }
  512. SkColor4f Buffer::GetColor() const {
  513. return SkColors::kBlack;
  514. }
  515. #if BUILDFLAG(USE_ARC_PROTECTED_MEDIA)
  516. bool Buffer::NeedsHardwareProtection() {
  517. // We don't indicate protection is needed in the UNKNOWN state because we have
  518. // not seen a pixmap yet that could be protected.
  519. return protected_buffer_state_ == ProtectedBufferState::PROTECTED ||
  520. protected_buffer_state_ == ProtectedBufferState::QUERYING;
  521. }
  522. #endif // BUILDFLAG(USE_ARC_PROTECTED_MEDIA)
  523. ////////////////////////////////////////////////////////////////////////////////
  524. // Buffer, private:
  525. void Buffer::Release() {
  526. TRACE_EVENT_ASYNC_END0("exo", kBufferInUse, gpu_memory_buffer_.get());
  527. // Run release callback to notify the client that buffer has been released.
  528. if (!release_callback_.is_null())
  529. release_callback_.Run();
  530. }
  531. void Buffer::ReleaseTexture(std::unique_ptr<Texture> texture,
  532. gfx::GpuFenceHandle release_fence) {
  533. // Buffer was composited - we should not receive a release fence.
  534. DCHECK(release_fence.is_null());
  535. texture_ = std::move(texture);
  536. }
  537. void Buffer::ReleaseContentsTexture(std::unique_ptr<Texture> texture,
  538. base::OnceClosure callback,
  539. uint64_t commit_id,
  540. gfx::GpuFenceHandle release_fence) {
  541. contents_texture_ = std::move(texture);
  542. MaybeRunPerCommitRelease(commit_id, std::move(release_fence),
  543. std::move(callback));
  544. }
  545. void Buffer::ReleaseContents() {
  546. TRACE_EVENT1("exo", "Buffer::ReleaseContents", "buffer_id",
  547. static_cast<const void*>(gfx_buffer()));
  548. // Cancel callback to indicate that buffer has been released.
  549. release_contents_callback_.Cancel();
  550. if (attach_count_) {
  551. TRACE_EVENT_ASYNC_STEP_INTO0("exo", kBufferInUse, gpu_memory_buffer_.get(),
  552. "attached");
  553. } else {
  554. // Release buffer if not attached to surface.
  555. Release();
  556. }
  557. }
  558. void Buffer::MaybeRunPerCommitRelease(
  559. uint64_t commit_id,
  560. gfx::GpuFenceHandle release_fence,
  561. base::OnceClosure buffer_release_callback) {
  562. auto iter = pending_explicit_releases_.find(commit_id);
  563. if (iter != pending_explicit_releases_.end()) {
  564. std::move(iter->second).Run(release_fence.Clone());
  565. pending_explicit_releases_.erase(iter);
  566. }
  567. // We are still required to send these wl_buffer.release events even if
  568. // the client supports explicit synchronization.
  569. if (release_fence.is_null()) {
  570. std::move(buffer_release_callback).Run();
  571. } else {
  572. #if BUILDFLAG(IS_POSIX)
  573. // Watching the release fence's fd results in a context switch to the I/O
  574. // thread. That may steal thread time from other applications, which can
  575. // do something useful during that time. Moreover, most of the time the
  576. // fence can have already been signalled. Thus, only watch the fence is
  577. // readable iff it hasn't been signalled yet.
  578. base::TimeTicks ticks;
  579. auto status = gfx::GpuFence::GetStatusChangeTime(
  580. release_fence.owned_fd.get(), &ticks);
  581. if (status == gfx::GpuFence::kSignaled) {
  582. std::move(buffer_release_callback).Run();
  583. return;
  584. }
  585. auto controller = base::FileDescriptorWatcher::WatchReadable(
  586. release_fence.owned_fd.get(),
  587. base::BindRepeating(&Buffer::FenceSignalled, AsWeakPtr(), commit_id));
  588. buffer_releases_.emplace(
  589. commit_id,
  590. BufferRelease(std::move(release_fence), std::move(controller),
  591. std::move(buffer_release_callback)));
  592. #else
  593. NOTREACHED();
  594. #endif
  595. }
  596. }
  597. void Buffer::FenceSignalled(uint64_t commit_id) {
  598. auto iter = buffer_releases_.find(commit_id);
  599. DCHECK(iter != buffer_releases_.end());
  600. std::move(iter->second.buffer_release_callback).Run();
  601. buffer_releases_.erase(iter);
  602. }
  603. #if BUILDFLAG(USE_ARC_PROTECTED_MEDIA)
  604. void Buffer::OnIsProtectedNativePixmapHandle(bool is_protected) {
  605. protected_buffer_state_ = is_protected ? ProtectedBufferState::PROTECTED
  606. : ProtectedBufferState::UNPROTECTED;
  607. }
  608. #endif // BUILDFLAG(USE_ARC_PROTECTED_MEDIA)
  609. SolidColorBuffer::SolidColorBuffer(const SkColor4f& color,
  610. const gfx::Size& size)
  611. : Buffer(nullptr), color_(color), size_(size) {}
  612. SolidColorBuffer::~SolidColorBuffer() = default;
  613. bool SolidColorBuffer::ProduceTransferableResource(
  614. FrameSinkResourceManager* resource_manager,
  615. std::unique_ptr<gfx::GpuFence> acquire_fence,
  616. bool secure_output_only,
  617. viz::TransferableResource* resource,
  618. ProtectedNativePixmapQueryDelegate* protected_native_pixmap_query,
  619. PerCommitExplicitReleaseCallback per_commit_explicit_release_callback) {
  620. if (per_commit_explicit_release_callback)
  621. std::move(per_commit_explicit_release_callback)
  622. .Run(/*release_fence=*/gfx::GpuFenceHandle());
  623. return false;
  624. }
  625. SkColor4f SolidColorBuffer::GetColor() const {
  626. return color_;
  627. }
  628. gfx::Size SolidColorBuffer::GetSize() const {
  629. return size_;
  630. }
  631. } // namespace exo