blob: ff8c613b40fa34c8d33b92e18d0ab2b89cac6587 [file] [log] [blame]
revemanb195f41d2015-11-19 22:16:481// 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
5#include "components/exo/buffer.h"
6
avibc5337b2015-12-25 23:16:337#include <stdint.h>
dcheng31759da2016-04-21 01:26:318
revemanb195f41d2015-11-19 22:16:489#include <algorithm>
dcheng27f7483f2015-12-29 22:26:5610#include <utility>
revemanb195f41d2015-11-19 22:16:4811
Sebastien Marchand53801a32019-01-25 16:26:1112#include "base/bind.h"
revemanae3b7c852016-02-25 01:50:0313#include "base/callback_helpers.h"
revemanb195f41d2015-11-19 22:16:4814#include "base/logging.h"
revemanae3b7c852016-02-25 01:50:0315#include "base/memory/weak_ptr.h"
Avi Drissman8171db7d2018-12-25 23:08:3116#include "base/stl_util.h"
gab7966d312016-05-11 20:35:0117#include "base/threading/thread_task_runner_handle.h"
revemanae3b7c852016-02-25 01:50:0318#include "base/time/time.h"
revemanb195f41d2015-11-19 22:16:4819#include "base/trace_event/trace_event.h"
David 'Digit' Turnerea071142018-10-29 15:38:1220#include "base/trace_event/traced_value.h"
Albert Chaulk56e96582019-01-30 19:33:1821#include "components/exo/frame_sink_resource_manager.h"
kylechar46d2e912019-05-07 21:08:0822#include "components/viz/common/gpu/context_lost_observer.h"
Xu Xing32549162017-07-17 22:25:4323#include "components/viz/common/gpu/context_provider.h"
Vladimir Levine348e2dc2017-08-22 15:56:4224#include "components/viz/common/resources/resource_format.h"
sohanfc3065e2018-07-02 22:36:0425#include "components/viz/common/resources/resource_format_utils.h"
danakjf20f4502017-09-26 17:13:3126#include "components/viz/common/resources/single_release_callback.h"
Daniele Castagnaa8ace632019-04-03 18:01:2927#include "gpu/GLES2/gl2extchromium.h"
revemanc8623d5b2016-02-09 02:29:1028#include "gpu/command_buffer/client/context_support.h"
Daniele Castagnaa8ace632019-04-03 18:01:2929#include "gpu/command_buffer/client/raster_interface.h"
30#include "gpu/command_buffer/client/shared_image_interface.h"
danakj33d8fbb2017-11-23 17:50:3631#include "gpu/command_buffer/common/mailbox.h"
Daniele Castagnaa8ace632019-04-03 18:01:2932#include "gpu/command_buffer/common/shared_image_usage.h"
danakj33d8fbb2017-11-23 17:50:3633#include "gpu/command_buffer/common/sync_token.h"
revemanb195f41d2015-11-19 22:16:4834#include "ui/aura/env.h"
35#include "ui/compositor/compositor.h"
36#include "ui/gfx/gpu_memory_buffer.h"
37
38namespace exo {
39namespace {
40
revemanae3b7c852016-02-25 01:50:0341// The amount of time before we wait for release queries using
42// GetQueryObjectuivEXT(GL_QUERY_RESULT_EXT).
43const int kWaitForReleaseDelayMs = 500;
44
[email protected]29befae2019-01-09 22:55:3545constexpr char kBufferInUse[] = "BufferInUse";
46
revemanb195f41d2015-11-19 22:16:4847} // namespace
48
49////////////////////////////////////////////////////////////////////////////////
revemanced21f82015-11-24 00:42:4950// Buffer::Texture
revemanb195f41d2015-11-19 22:16:4851
Daniele Castagnaa8ace632019-04-03 18:01:2952// Encapsulates the state and logic needed to bind a buffer to a SharedImage.
kylechar46d2e912019-05-07 21:08:0853class Buffer::Texture : public viz::ContextLostObserver {
revemanced21f82015-11-24 00:42:4954 public:
kylechar46d2e912019-05-07 21:08:0855 Texture(scoped_refptr<viz::RasterContextProvider> context_provider,
56 const gfx::Size& size);
57 Texture(scoped_refptr<viz::RasterContextProvider> context_provider,
58 gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
revemanc8623d5b2016-02-09 02:29:1059 gfx::GpuMemoryBuffer* gpu_memory_buffer,
60 unsigned texture_target,
David Revemanf8fde1902017-10-20 23:01:0461 unsigned query_type,
62 base::TimeDelta wait_for_release_time);
revemand0b75c32016-08-12 02:46:5263 ~Texture() override;
64
kylechar46d2e912019-05-07 21:08:0865 // Overridden from viz::ContextLostObserver:
66 void OnContextLost() override;
revemanced21f82015-11-24 00:42:4967
Daniele Castagnaa8ace632019-04-03 18:01:2968 // Returns true if the RasterInterface context has been lost.
revemanced21f82015-11-24 00:42:4969 bool IsLost();
70
revemanc8623d5b2016-02-09 02:29:1071 // Allow texture to be reused after |sync_token| has passed and runs
72 // |callback|.
Daniele Castagna9f15eb72019-03-30 01:11:3673 void Release(base::OnceClosure callback,
revemanc8623d5b2016-02-09 02:29:1074 const gpu::SyncToken& sync_token,
75 bool is_lost);
76
Daniele Castagnaa8ace632019-04-03 18:01:2977 // Updates the contents referenced by |gpu_memory_buffer_| returned by
78 // mailbox().
79 // Returns a sync token that can be used when accessing the SharedImage from a
80 // different context.
Daniele Castagnafade73662019-06-04 03:30:3181 gpu::SyncToken UpdateSharedImage(
82 std::unique_ptr<gfx::GpuFence> acquire_fence);
revemanced21f82015-11-24 00:42:4983
Daniele Castagnaa8ace632019-04-03 18:01:2984 // Releases the contents referenced by |mailbox_| after |sync_token| has
revemanc8623d5b2016-02-09 02:29:1085 // passed and runs |callback| when completed.
Daniele Castagnaa8ace632019-04-03 18:01:2986 void ReleaseSharedImage(base::OnceClosure callback,
87 const gpu::SyncToken& sync_token,
88 bool is_lost);
revemanc8623d5b2016-02-09 02:29:1089
90 // Copy the contents of texture to |destination| and runs |callback| when
91 // completed. Returns a sync token that can be used when accessing texture
92 // from a different context.
Daniele Castagnafade73662019-06-04 03:30:3193 gpu::SyncToken CopyTexImage(std::unique_ptr<gfx::GpuFence> acquire_fence,
94 Texture* destination,
95 base::OnceClosure callback);
revemanced21f82015-11-24 00:42:4996
97 // Returns the mailbox for this texture.
98 gpu::Mailbox mailbox() const { return mailbox_; }
99
100 private:
revemand0b75c32016-08-12 02:46:52101 void DestroyResources();
Daniele Castagna9f15eb72019-03-30 01:11:36102 void ReleaseWhenQueryResultIsAvailable(base::OnceClosure callback);
revemanae3b7c852016-02-25 01:50:03103 void Released();
104 void ScheduleWaitForRelease(base::TimeDelta delay);
105 void WaitForRelease();
106
David Reveman66cbc512017-05-31 21:21:20107 gfx::GpuMemoryBuffer* const gpu_memory_buffer_;
Daniele Castagnaa8ace632019-04-03 18:01:29108 const gfx::Size size_;
Daniele Castagnaa8ace632019-04-03 18:01:29109 scoped_refptr<viz::RasterContextProvider> context_provider_;
revemanced21f82015-11-24 00:42:49110 const unsigned texture_target_;
revemanc8623d5b2016-02-09 02:29:10111 const unsigned query_type_;
reveman2d3815d2016-06-26 20:13:25112 unsigned query_id_ = 0;
revemanced21f82015-11-24 00:42:49113 gpu::Mailbox mailbox_;
Daniele Castagna9f15eb72019-03-30 01:11:36114 base::OnceClosure release_callback_;
David Revemanf8fde1902017-10-20 23:01:04115 const base::TimeDelta wait_for_release_delay_;
revemanae3b7c852016-02-25 01:50:03116 base::TimeTicks wait_for_release_time_;
reveman2d3815d2016-06-26 20:13:25117 bool wait_for_release_pending_ = false;
revemanae3b7c852016-02-25 01:50:03118 base::WeakPtrFactory<Texture> weak_ptr_factory_;
revemanced21f82015-11-24 00:42:49119
120 DISALLOW_COPY_AND_ASSIGN(Texture);
121};
122
kylechar46d2e912019-05-07 21:08:08123Buffer::Texture::Texture(
124 scoped_refptr<viz::RasterContextProvider> context_provider,
125 const gfx::Size& size)
David Reveman66cbc512017-05-31 21:21:20126 : gpu_memory_buffer_(nullptr),
Daniele Castagnaa8ace632019-04-03 18:01:29127 size_(size),
kylechar46d2e912019-05-07 21:08:08128 context_provider_(std::move(context_provider)),
revemanc8623d5b2016-02-09 02:29:10129 texture_target_(GL_TEXTURE_2D),
130 query_type_(GL_COMMANDS_COMPLETED_CHROMIUM),
revemanae3b7c852016-02-25 01:50:03131 weak_ptr_factory_(this) {
Daniele Castagnaa8ace632019-04-03 18:01:29132 gpu::SharedImageInterface* sii = context_provider_->SharedImageInterface();
133 const uint32_t usage =
134 gpu::SHARED_IMAGE_USAGE_RASTER | gpu::SHARED_IMAGE_USAGE_DISPLAY;
135
136 mailbox_ = sii->CreateSharedImage(viz::ResourceFormat::RGBA_8888, size,
137 gfx::ColorSpace(), usage);
138 DCHECK(!mailbox_.IsZero());
139 gpu::raster::RasterInterface* ri = context_provider_->RasterInterface();
140 ri->WaitSyncTokenCHROMIUM(sii->GenUnverifiedSyncToken().GetConstData());
141
revemand0b75c32016-08-12 02:46:52142 // Provides a notification when |context_provider_| is lost.
kylechar46d2e912019-05-07 21:08:08143 context_provider_->AddObserver(this);
revemanc8623d5b2016-02-09 02:29:10144}
145
kylechar46d2e912019-05-07 21:08:08146Buffer::Texture::Texture(
147 scoped_refptr<viz::RasterContextProvider> context_provider,
148 gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
149 gfx::GpuMemoryBuffer* gpu_memory_buffer,
150 unsigned texture_target,
151 unsigned query_type,
152 base::TimeDelta wait_for_release_delay)
David Reveman66cbc512017-05-31 21:21:20153 : gpu_memory_buffer_(gpu_memory_buffer),
Daniele Castagnaa8ace632019-04-03 18:01:29154 size_(gpu_memory_buffer->GetSize()),
kylechar46d2e912019-05-07 21:08:08155 context_provider_(std::move(context_provider)),
revemanc8623d5b2016-02-09 02:29:10156 texture_target_(texture_target),
157 query_type_(query_type),
David Revemanf8fde1902017-10-20 23:01:04158 wait_for_release_delay_(wait_for_release_delay),
revemanae3b7c852016-02-25 01:50:03159 weak_ptr_factory_(this) {
Daniele Castagnaa8ace632019-04-03 18:01:29160 gpu::SharedImageInterface* sii = context_provider_->SharedImageInterface();
161 const uint32_t usage = gpu::SHARED_IMAGE_USAGE_RASTER |
162 gpu::SHARED_IMAGE_USAGE_DISPLAY |
163 gpu::SHARED_IMAGE_USAGE_SCANOUT;
dcastagna2db83c7ef2016-06-13 23:33:22164
Daniele Castagnaa8ace632019-04-03 18:01:29165 mailbox_ = sii->CreateSharedImage(
kylechar46d2e912019-05-07 21:08:08166 gpu_memory_buffer_, gpu_memory_buffer_manager, gfx::ColorSpace(), usage);
Daniele Castagnaa8ace632019-04-03 18:01:29167 DCHECK(!mailbox_.IsZero());
168 gpu::raster::RasterInterface* ri = context_provider_->RasterInterface();
169 ri->WaitSyncTokenCHROMIUM(sii->GenUnverifiedSyncToken().GetConstData());
170 ri->GenQueriesEXT(1, &query_id_);
171
revemand0b75c32016-08-12 02:46:52172 // Provides a notification when |context_provider_| is lost.
kylechar46d2e912019-05-07 21:08:08173 context_provider_->AddObserver(this);
revemanb195f41d2015-11-19 22:16:48174}
175
revemanced21f82015-11-24 00:42:49176Buffer::Texture::~Texture() {
revemand0b75c32016-08-12 02:46:52177 DestroyResources();
kylechar46d2e912019-05-07 21:08:08178 if (context_provider_)
179 context_provider_->RemoveObserver(this);
revemand0b75c32016-08-12 02:46:52180}
181
kylechar46d2e912019-05-07 21:08:08182void Buffer::Texture::OnContextLost() {
revemand0b75c32016-08-12 02:46:52183 DestroyResources();
kylechar46d2e912019-05-07 21:08:08184 context_provider_->RemoveObserver(this);
185 context_provider_.reset();
revemanb195f41d2015-11-19 22:16:48186}
187
revemanced21f82015-11-24 00:42:49188bool Buffer::Texture::IsLost() {
revemand0b75c32016-08-12 02:46:52189 if (context_provider_) {
Daniele Castagnaa8ace632019-04-03 18:01:29190 gpu::raster::RasterInterface* ri = context_provider_->RasterInterface();
191 return ri->GetGraphicsResetStatusKHR() != GL_NO_ERROR;
revemand0b75c32016-08-12 02:46:52192 }
193 return true;
revemanced21f82015-11-24 00:42:49194}
revemanb195f41d2015-11-19 22:16:48195
Daniele Castagna9f15eb72019-03-30 01:11:36196void Buffer::Texture::Release(base::OnceClosure callback,
revemanc8623d5b2016-02-09 02:29:10197 const gpu::SyncToken& sync_token,
198 bool is_lost) {
revemand0b75c32016-08-12 02:46:52199 if (context_provider_) {
Daniele Castagnaa8ace632019-04-03 18:01:29200 if (sync_token.HasData()) {
201 gpu::raster::RasterInterface* ri = context_provider_->RasterInterface();
202 ri->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
203 }
revemand0b75c32016-08-12 02:46:52204 }
revemanc8623d5b2016-02-09 02:29:10205
206 // Run callback as texture can be reused immediately after waiting for sync
207 // token.
Daniele Castagna9f15eb72019-03-30 01:11:36208 std::move(callback).Run();
revemanc8623d5b2016-02-09 02:29:10209}
210
Daniele Castagnafade73662019-06-04 03:30:31211gpu::SyncToken Buffer::Texture::UpdateSharedImage(
212 std::unique_ptr<gfx::GpuFence> acquire_fence) {
revemanb195f41d2015-11-19 22:16:48213 gpu::SyncToken sync_token;
revemand0b75c32016-08-12 02:46:52214 if (context_provider_) {
Daniele Castagnaa8ace632019-04-03 18:01:29215 gpu::SharedImageInterface* sii = context_provider_->SharedImageInterface();
216 DCHECK(!mailbox_.IsZero());
217 // UpdateSharedImage gets called only after |mailbox_| can be reused.
218 // A buffer can be reattached to a surface only after it has been returned
219 // to wayland clients. We return buffers to clients only after the query
220 // |query_type_| is available.
Daniele Castagnafade73662019-06-04 03:30:31221 sii->UpdateSharedImage(gpu::SyncToken(), std::move(acquire_fence),
222 mailbox_);
Daniele Castagnaa8ace632019-04-03 18:01:29223 sync_token = sii->GenUnverifiedSyncToken();
[email protected]29befae2019-01-09 22:55:35224 TRACE_EVENT_ASYNC_STEP_INTO0("exo", kBufferInUse, gpu_memory_buffer_,
David Reveman66cbc512017-05-31 21:21:20225 "bound");
revemand0b75c32016-08-12 02:46:52226 }
revemanced21f82015-11-24 00:42:49227 return sync_token;
228}
229
Daniele Castagnaa8ace632019-04-03 18:01:29230void Buffer::Texture::ReleaseSharedImage(base::OnceClosure callback,
231 const gpu::SyncToken& sync_token,
232 bool is_lost) {
revemand0b75c32016-08-12 02:46:52233 if (context_provider_) {
Daniele Castagnaa8ace632019-04-03 18:01:29234 gpu::raster::RasterInterface* ri = context_provider_->RasterInterface();
revemand0b75c32016-08-12 02:46:52235 if (sync_token.HasData())
Daniele Castagnaa8ace632019-04-03 18:01:29236 ri->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
237 ri->BeginQueryEXT(query_type_, query_id_);
238 ri->EndQueryEXT(query_type_);
239 // Run callback when query result is available (i.e., when all operations on
240 // the shared image have completed and it's ready to be reused) if sync
241 // token has data and buffer has been used. If buffer was never used then
242 // run the callback immediately.
revemand0b75c32016-08-12 02:46:52243 if (sync_token.HasData()) {
Daniele Castagna9f15eb72019-03-30 01:11:36244 ReleaseWhenQueryResultIsAvailable(std::move(callback));
revemand0b75c32016-08-12 02:46:52245 return;
246 }
revemanc8623d5b2016-02-09 02:29:10247 }
Daniele Castagna9f15eb72019-03-30 01:11:36248 std::move(callback).Run();
revemanc8623d5b2016-02-09 02:29:10249}
250
Daniele Castagnafade73662019-06-04 03:30:31251gpu::SyncToken Buffer::Texture::CopyTexImage(
252 std::unique_ptr<gfx::GpuFence> acquire_fence,
253 Texture* destination,
254 base::OnceClosure callback) {
revemanc8623d5b2016-02-09 02:29:10255 gpu::SyncToken sync_token;
revemand0b75c32016-08-12 02:46:52256 if (context_provider_) {
Daniele Castagnaa8ace632019-04-03 18:01:29257 DCHECK(!mailbox_.IsZero());
258 gpu::SharedImageInterface* sii = context_provider_->SharedImageInterface();
Daniele Castagnafade73662019-06-04 03:30:31259 sii->UpdateSharedImage(gpu::SyncToken(), std::move(acquire_fence),
260 mailbox_);
Daniele Castagnaa8ace632019-04-03 18:01:29261 sync_token = sii->GenUnverifiedSyncToken();
262
263 gpu::raster::RasterInterface* ri = context_provider_->RasterInterface();
264 ri->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
revemand0b75c32016-08-12 02:46:52265 DCHECK_NE(query_id_, 0u);
Daniele Castagnaa8ace632019-04-03 18:01:29266 ri->BeginQueryEXT(query_type_, query_id_);
267 ri->CopySubTexture(mailbox_, destination->mailbox_,
268 destination->texture_target_, 0, 0, 0, 0, size_.width(),
269 size_.height());
270 ri->EndQueryEXT(query_type_);
271 // Run callback when query result is available.
Daniele Castagna9f15eb72019-03-30 01:11:36272 ReleaseWhenQueryResultIsAvailable(std::move(callback));
revemand0b75c32016-08-12 02:46:52273 // Create and return a sync token that can be used to ensure that the
Daniele Castagnaa8ace632019-04-03 18:01:29274 // CopySubTexture call is processed before issuing any commands
revemand0b75c32016-08-12 02:46:52275 // that will read from the target texture on a different context.
Daniele Castagnaa8ace632019-04-03 18:01:29276 ri->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData());
revemand0b75c32016-08-12 02:46:52277 }
revemanc8623d5b2016-02-09 02:29:10278 return sync_token;
revemanced21f82015-11-24 00:42:49279}
280
revemand0b75c32016-08-12 02:46:52281void Buffer::Texture::DestroyResources() {
282 if (context_provider_) {
Daniele Castagnaa8ace632019-04-03 18:01:29283 if (query_id_) {
284 gpu::raster::RasterInterface* ri = context_provider_->RasterInterface();
285 ri->DeleteQueriesEXT(1, &query_id_);
286 query_id_ = 0;
287 }
288 gpu::SharedImageInterface* sii = context_provider_->SharedImageInterface();
289 sii->DestroySharedImage(gpu::SyncToken(), mailbox_);
revemand0b75c32016-08-12 02:46:52290 }
291}
292
revemanae3b7c852016-02-25 01:50:03293void Buffer::Texture::ReleaseWhenQueryResultIsAvailable(
Daniele Castagna9f15eb72019-03-30 01:11:36294 base::OnceClosure callback) {
revemand0b75c32016-08-12 02:46:52295 DCHECK(context_provider_);
revemanae3b7c852016-02-25 01:50:03296 DCHECK(release_callback_.is_null());
Daniele Castagna9f15eb72019-03-30 01:11:36297 release_callback_ = std::move(callback);
David Revemanf8fde1902017-10-20 23:01:04298 wait_for_release_time_ = base::TimeTicks::Now() + wait_for_release_delay_;
299 ScheduleWaitForRelease(wait_for_release_delay_);
[email protected]29befae2019-01-09 22:55:35300 TRACE_EVENT_ASYNC_STEP_INTO0("exo", kBufferInUse, gpu_memory_buffer_,
David Reveman66cbc512017-05-31 21:21:20301 "pending_query");
revemanae3b7c852016-02-25 01:50:03302 context_provider_->ContextSupport()->SignalQuery(
tzik2bcf8e42018-07-31 11:22:15303 query_id_, base::BindOnce(&Buffer::Texture::Released,
304 weak_ptr_factory_.GetWeakPtr()));
revemanae3b7c852016-02-25 01:50:03305}
306
307void Buffer::Texture::Released() {
308 if (!release_callback_.is_null())
Daniele Castagna9f15eb72019-03-30 01:11:36309 std::move(release_callback_).Run();
revemanae3b7c852016-02-25 01:50:03310}
311
312void Buffer::Texture::ScheduleWaitForRelease(base::TimeDelta delay) {
313 if (wait_for_release_pending_)
314 return;
315
316 wait_for_release_pending_ = true;
317 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
tzik2bcf8e42018-07-31 11:22:15318 FROM_HERE,
319 base::BindOnce(&Buffer::Texture::WaitForRelease,
320 weak_ptr_factory_.GetWeakPtr()),
revemanae3b7c852016-02-25 01:50:03321 delay);
322}
323
324void Buffer::Texture::WaitForRelease() {
325 DCHECK(wait_for_release_pending_);
326 wait_for_release_pending_ = false;
327
328 if (release_callback_.is_null())
329 return;
330
331 base::TimeTicks current_time = base::TimeTicks::Now();
332 if (current_time < wait_for_release_time_) {
333 ScheduleWaitForRelease(wait_for_release_time_ - current_time);
334 return;
335 }
336
Daniele Castagna9f15eb72019-03-30 01:11:36337 base::OnceClosure callback = std::move(release_callback_);
revemanae3b7c852016-02-25 01:50:03338
revemand0b75c32016-08-12 02:46:52339 if (context_provider_) {
revemanae3b7c852016-02-25 01:50:03340 TRACE_EVENT0("exo", "Buffer::Texture::WaitForQueryResult");
341
342 // We need to wait for the result to be available. Getting the result of
343 // the query implies waiting for it to become available. The actual result
344 // is unimportant and also not well defined.
345 unsigned result = 0;
Daniele Castagnaa8ace632019-04-03 18:01:29346 gpu::raster::RasterInterface* ri = context_provider_->RasterInterface();
347 ri->GetQueryObjectuivEXT(query_id_, GL_QUERY_RESULT_EXT, &result);
revemanae3b7c852016-02-25 01:50:03348 }
349
Daniele Castagna9f15eb72019-03-30 01:11:36350 std::move(callback).Run();
revemanae3b7c852016-02-25 01:50:03351}
352
revemanced21f82015-11-24 00:42:49353////////////////////////////////////////////////////////////////////////////////
354// Buffer, public:
355
dcheng31759da2016-04-21 01:26:31356Buffer::Buffer(std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer)
David Revemanf8fde1902017-10-20 23:01:04357 : Buffer(std::move(gpu_memory_buffer),
358 GL_TEXTURE_2D /* texture_target */,
359 GL_COMMANDS_COMPLETED_CHROMIUM /* query_type */,
360 true /* use_zero_copy */,
Zach Reizner8bcce6e2018-10-31 00:04:37361 false /* is_overlay_candidate */,
362 false /* y_invert */) {}
revemanc8623d5b2016-02-09 02:29:10363
dcheng31759da2016-04-21 01:26:31364Buffer::Buffer(std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer,
revemanc8623d5b2016-02-09 02:29:10365 unsigned texture_target,
366 unsigned query_type,
reveman244f9622016-03-04 21:33:33367 bool use_zero_copy,
Zach Reizner8bcce6e2018-10-31 00:04:37368 bool is_overlay_candidate,
369 bool y_invert)
dcheng27f7483f2015-12-29 22:26:56370 : gpu_memory_buffer_(std::move(gpu_memory_buffer)),
revemanced21f82015-11-24 00:42:49371 texture_target_(texture_target),
revemanc8623d5b2016-02-09 02:29:10372 query_type_(query_type),
373 use_zero_copy_(use_zero_copy),
David Revemanf8fde1902017-10-20 23:01:04374 is_overlay_candidate_(is_overlay_candidate),
Zach Reizner8bcce6e2018-10-31 00:04:37375 y_invert_(y_invert),
David Revemanf8fde1902017-10-20 23:01:04376 wait_for_release_delay_(
377 base::TimeDelta::FromMilliseconds(kWaitForReleaseDelayMs)) {}
revemanced21f82015-11-24 00:42:49378
379Buffer::~Buffer() {}
380
starazd40f0362017-01-04 00:46:13381bool Buffer::ProduceTransferableResource(
Albert Chaulk56e96582019-01-30 19:33:18382 FrameSinkResourceManager* resource_manager,
Daniele Castagnafade73662019-06-04 03:30:31383 std::unique_ptr<gfx::GpuFence> acquire_fence,
reveman85b7a562016-03-17 23:27:32384 bool secure_output_only,
Fady Samuel4f7f0fb32017-07-28 15:33:37385 viz::TransferableResource* resource) {
[email protected]29befae2019-01-09 22:55:35386 TRACE_EVENT1("exo", "Buffer::ProduceTransferableResource", "buffer_id",
387 gfx_buffer());
jbauman45c06862016-06-23 19:35:02388 DCHECK(attach_count_);
revemanced21f82015-11-24 00:42:49389
revemanc8623d5b2016-02-09 02:29:10390 // If textures are lost, destroy them to ensure that we create new ones below.
391 if (contents_texture_ && contents_texture_->IsLost())
392 contents_texture_.reset();
393 if (texture_ && texture_->IsLost())
394 texture_.reset();
revemanced21f82015-11-24 00:42:49395
revemand0b75c32016-08-12 02:46:52396 ui::ContextFactory* context_factory =
Jun Mukai1f426ff2019-05-16 18:19:24397 aura::Env::GetInstance()->context_factory();
revemanc8623d5b2016-02-09 02:29:10398 // Note: This can fail if GPU acceleration has been disabled.
Daniele Castagnaa8ace632019-04-03 18:01:29399 scoped_refptr<viz::RasterContextProvider> context_provider =
400 context_factory->SharedMainThreadRasterContextProvider();
revemanc8623d5b2016-02-09 02:29:10401 if (!context_provider) {
402 DLOG(WARNING) << "Failed to acquire a context provider";
starazd40f0362017-01-04 00:46:13403 resource->id = 0;
404 resource->size = gfx::Size();
405 return false;
revemanced21f82015-11-24 00:42:49406 }
407
Albert Chaulk56e96582019-01-30 19:33:18408 resource->id = resource_manager->AllocateResourceId();
Fady Samuel555c8d12017-07-07 23:14:09409 resource->format = viz::RGBA_8888;
starazd40f0362017-01-04 00:46:13410 resource->filter = GL_LINEAR;
411 resource->size = gpu_memory_buffer_->GetSize();
412
revemanc8623d5b2016-02-09 02:29:10413 // Create a new image texture for |gpu_memory_buffer_| with |texture_target_|
414 // if one doesn't already exist. The contents of this buffer are copied to
415 // |texture| using a call to CopyTexImage.
416 if (!contents_texture_) {
David Revemand0ab1fb82017-09-18 22:27:57417 contents_texture_ = std::make_unique<Texture>(
kylechar46d2e912019-05-07 21:08:08418 context_provider, context_factory->GetGpuMemoryBufferManager(),
419 gpu_memory_buffer_.get(), texture_target_, query_type_,
Daniele Castagnaa8ace632019-04-03 18:01:29420 wait_for_release_delay_);
revemanc8623d5b2016-02-09 02:29:10421 }
reveman2cd69782017-02-01 20:19:44422 Texture* contents_texture = contents_texture_.get();
revemanb195f41d2015-11-19 22:16:48423
David Reveman66cbc512017-05-31 21:21:20424 if (release_contents_callback_.IsCancelled())
[email protected]29befae2019-01-09 22:55:35425 TRACE_EVENT_ASYNC_BEGIN1("exo", kBufferInUse, gpu_memory_buffer_.get(),
426 "buffer_id", gfx_buffer());
David Reveman66cbc512017-05-31 21:21:20427
reveman2cd69782017-02-01 20:19:44428 // Cancel pending contents release callback.
429 release_contents_callback_.Reset(
Daniele Castagna9f15eb72019-03-30 01:11:36430 base::BindOnce(&Buffer::ReleaseContents, base::Unretained(this)));
reveman2cd69782017-02-01 20:19:44431
432 // Zero-copy means using the contents texture directly.
revemanc8623d5b2016-02-09 02:29:10433 if (use_zero_copy_) {
reveman2cd69782017-02-01 20:19:44434 // This binds the latest contents of this buffer to |contents_texture|.
Daniele Castagnafade73662019-06-04 03:30:31435 gpu::SyncToken sync_token =
436 contents_texture->UpdateSharedImage(std::move(acquire_fence));
reveman2cd69782017-02-01 20:19:44437 resource->mailbox_holder = gpu::MailboxHolder(contents_texture->mailbox(),
438 sync_token, texture_target_);
starazd40f0362017-01-04 00:46:13439 resource->is_overlay_candidate = is_overlay_candidate_;
sohanfc3065e2018-07-02 22:36:04440 resource->format = viz::GetResourceFormat(gpu_memory_buffer_->GetFormat());
starazd40f0362017-01-04 00:46:13441
revemanc8623d5b2016-02-09 02:29:10442 // The contents texture will be released when no longer used by the
443 // compositor.
Albert Chaulk56e96582019-01-30 19:33:18444 resource_manager->SetResourceReleaseCallback(
Peng Huang583c9dc62017-07-27 23:38:28445 resource->id,
Daniele Castagnaa8ace632019-04-03 18:01:29446 base::BindOnce(&Buffer::Texture::ReleaseSharedImage,
tzik2bcf8e42018-07-31 11:22:15447 base::Unretained(contents_texture),
Daniele Castagna9f15eb72019-03-30 01:11:36448 base::BindOnce(&Buffer::ReleaseContentsTexture,
449 AsWeakPtr(), std::move(contents_texture_),
450 release_contents_callback_.callback())));
starazd40f0362017-01-04 00:46:13451 return true;
revemanc8623d5b2016-02-09 02:29:10452 }
453
454 // Create a mailbox texture that we copy the buffer contents to.
revemand0b75c32016-08-12 02:46:52455 if (!texture_) {
kylechar46d2e912019-05-07 21:08:08456 texture_ = std::make_unique<Texture>(context_provider,
Daniele Castagnaa8ace632019-04-03 18:01:29457 gpu_memory_buffer_->GetSize());
revemand0b75c32016-08-12 02:46:52458 }
revemanc8623d5b2016-02-09 02:29:10459 Texture* texture = texture_.get();
460
reveman2cd69782017-02-01 20:19:44461 // Copy the contents of |contents_texture| to |texture| and produce a
462 // texture mailbox from the result in |texture|. The contents texture will
463 // be released when copy has completed.
reveman7ee8b4e2017-01-11 22:10:53464 gpu::SyncToken sync_token = contents_texture->CopyTexImage(
Daniele Castagnafade73662019-06-04 03:30:31465 std::move(acquire_fence), texture,
466 base::BindOnce(&Buffer::ReleaseContentsTexture, AsWeakPtr(),
467 std::move(contents_texture_),
468 release_contents_callback_.callback()));
reveman7ee8b4e2017-01-11 22:10:53469 resource->mailbox_holder =
470 gpu::MailboxHolder(texture->mailbox(), sync_token, GL_TEXTURE_2D);
starazd40f0362017-01-04 00:46:13471 resource->is_overlay_candidate = false;
472
revemanc8623d5b2016-02-09 02:29:10473 // The mailbox texture will be released when no longer used by the
474 // compositor.
Albert Chaulk56e96582019-01-30 19:33:18475 resource_manager->SetResourceReleaseCallback(
Peng Huang583c9dc62017-07-27 23:38:28476 resource->id,
tzik2bcf8e42018-07-31 11:22:15477 base::BindOnce(&Buffer::Texture::Release, base::Unretained(texture),
Daniele Castagna9f15eb72019-03-30 01:11:36478 base::BindOnce(&Buffer::ReleaseTexture, AsWeakPtr(),
479 std::move(texture_))));
starazd40f0362017-01-04 00:46:13480 return true;
revemanb195f41d2015-11-19 22:16:48481}
482
jbauman45c06862016-06-23 19:35:02483void Buffer::OnAttach() {
reveman2cd69782017-02-01 20:19:44484 DLOG_IF(WARNING, attach_count_)
jbauman45c06862016-06-23 19:35:02485 << "Reattaching a buffer that is already attached to another surface.";
[email protected]29befae2019-01-09 22:55:35486 TRACE_EVENT2("exo", "Buffer::OnAttach", "buffer_id", gfx_buffer(), "count",
487 attach_count_);
reveman2cd69782017-02-01 20:19:44488 ++attach_count_;
jbauman45c06862016-06-23 19:35:02489}
490
491void Buffer::OnDetach() {
492 DCHECK_GT(attach_count_, 0u);
[email protected]29befae2019-01-09 22:55:35493 TRACE_EVENT2("exo", "Buffer::OnAttach", "buffer_id", gfx_buffer(), "count",
494 attach_count_);
jbauman45c06862016-06-23 19:35:02495 --attach_count_;
reveman2cd69782017-02-01 20:19:44496
497 // Release buffer if no longer attached to a surface and content has been
498 // released.
499 if (!attach_count_ && release_contents_callback_.IsCancelled())
500 Release();
jbauman45c06862016-06-23 19:35:02501}
502
revemanb195f41d2015-11-19 22:16:48503gfx::Size Buffer::GetSize() const {
504 return gpu_memory_buffer_->GetSize();
505}
506
revemanca132dc2017-01-31 22:35:54507gfx::BufferFormat Buffer::GetFormat() const {
508 return gpu_memory_buffer_->GetFormat();
509}
510
revemanb195f41d2015-11-19 22:16:48511////////////////////////////////////////////////////////////////////////////////
512// Buffer, private:
513
revemanced21f82015-11-24 00:42:49514void Buffer::Release() {
[email protected]29befae2019-01-09 22:55:35515 TRACE_EVENT_ASYNC_END0("exo", kBufferInUse, gpu_memory_buffer_.get());
David Reveman66cbc512017-05-31 21:21:20516
revemanced21f82015-11-24 00:42:49517 // Run release callback to notify the client that buffer has been released.
518 if (!release_callback_.is_null())
519 release_callback_.Run();
520}
revemanb195f41d2015-11-19 22:16:48521
dcheng31759da2016-04-21 01:26:31522void Buffer::ReleaseTexture(std::unique_ptr<Texture> texture) {
revemanc8623d5b2016-02-09 02:29:10523 texture_ = std::move(texture);
524}
revemanced21f82015-11-24 00:42:49525
reveman2cd69782017-02-01 20:19:44526void Buffer::ReleaseContentsTexture(std::unique_ptr<Texture> texture,
Daniele Castagna9f15eb72019-03-30 01:11:36527 base::OnceClosure callback) {
revemanc8623d5b2016-02-09 02:29:10528 contents_texture_ = std::move(texture);
Daniele Castagna9f15eb72019-03-30 01:11:36529 std::move(callback).Run();
reveman2cd69782017-02-01 20:19:44530}
531
532void Buffer::ReleaseContents() {
[email protected]29befae2019-01-09 22:55:35533 TRACE_EVENT1("exo", "Buffer::ReleaseContents", "buffer_id", gfx_buffer());
reveman2cd69782017-02-01 20:19:44534
535 // Cancel callback to indicate that buffer has been released.
536 release_contents_callback_.Cancel();
537
David Reveman66cbc512017-05-31 21:21:20538 if (attach_count_) {
[email protected]29befae2019-01-09 22:55:35539 TRACE_EVENT_ASYNC_STEP_INTO0("exo", kBufferInUse, gpu_memory_buffer_.get(),
David Reveman66cbc512017-05-31 21:21:20540 "attached");
541 } else {
542 // Release buffer if not attached to surface.
reveman2cd69782017-02-01 20:19:44543 Release();
David Reveman66cbc512017-05-31 21:21:20544 }
revemanb195f41d2015-11-19 22:16:48545}
546
547} // namespace exo