blob: e3e98871aa78bc91337e1113b775a7593dfc56ea [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;
Jeremy Roman47d432e2019-08-20 14:24:00118 base::WeakPtrFactory<Texture> weak_ptr_factory_{this};
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),
Jeremy Roman47d432e2019-08-20 14:24:00130 query_type_(GL_COMMANDS_COMPLETED_CHROMIUM) {
Daniele Castagnaa8ace632019-04-03 18:01:29131 gpu::SharedImageInterface* sii = context_provider_->SharedImageInterface();
132 const uint32_t usage =
133 gpu::SHARED_IMAGE_USAGE_RASTER | gpu::SHARED_IMAGE_USAGE_DISPLAY;
134
135 mailbox_ = sii->CreateSharedImage(viz::ResourceFormat::RGBA_8888, size,
Nathan Zabriskie659c2742020-07-16 03:49:32136 gfx::ColorSpace(), kTopLeft_GrSurfaceOrigin,
137 kPremul_SkAlphaType, usage,
138 gpu::kNullSurfaceHandle);
Daniele Castagnaa8ace632019-04-03 18:01:29139 DCHECK(!mailbox_.IsZero());
140 gpu::raster::RasterInterface* ri = context_provider_->RasterInterface();
141 ri->WaitSyncTokenCHROMIUM(sii->GenUnverifiedSyncToken().GetConstData());
142
revemand0b75c32016-08-12 02:46:52143 // Provides a notification when |context_provider_| is lost.
kylechar46d2e912019-05-07 21:08:08144 context_provider_->AddObserver(this);
revemanc8623d5b2016-02-09 02:29:10145}
146
kylechar46d2e912019-05-07 21:08:08147Buffer::Texture::Texture(
148 scoped_refptr<viz::RasterContextProvider> context_provider,
149 gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
150 gfx::GpuMemoryBuffer* gpu_memory_buffer,
151 unsigned texture_target,
152 unsigned query_type,
153 base::TimeDelta wait_for_release_delay)
David Reveman66cbc512017-05-31 21:21:20154 : gpu_memory_buffer_(gpu_memory_buffer),
Daniele Castagnaa8ace632019-04-03 18:01:29155 size_(gpu_memory_buffer->GetSize()),
kylechar46d2e912019-05-07 21:08:08156 context_provider_(std::move(context_provider)),
revemanc8623d5b2016-02-09 02:29:10157 texture_target_(texture_target),
158 query_type_(query_type),
Jeremy Roman47d432e2019-08-20 14:24:00159 wait_for_release_delay_(wait_for_release_delay) {
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(
Nathan Zabriskie659c2742020-07-16 03:49:32166 gpu_memory_buffer_, gpu_memory_buffer_manager, gfx::ColorSpace(),
167 kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, usage);
Daniele Castagnaa8ace632019-04-03 18:01:29168 DCHECK(!mailbox_.IsZero());
169 gpu::raster::RasterInterface* ri = context_provider_->RasterInterface();
170 ri->WaitSyncTokenCHROMIUM(sii->GenUnverifiedSyncToken().GetConstData());
171 ri->GenQueriesEXT(1, &query_id_);
172
revemand0b75c32016-08-12 02:46:52173 // Provides a notification when |context_provider_| is lost.
kylechar46d2e912019-05-07 21:08:08174 context_provider_->AddObserver(this);
revemanb195f41d2015-11-19 22:16:48175}
176
revemanced21f82015-11-24 00:42:49177Buffer::Texture::~Texture() {
revemand0b75c32016-08-12 02:46:52178 DestroyResources();
kylechar46d2e912019-05-07 21:08:08179 if (context_provider_)
180 context_provider_->RemoveObserver(this);
revemand0b75c32016-08-12 02:46:52181}
182
kylechar46d2e912019-05-07 21:08:08183void Buffer::Texture::OnContextLost() {
revemand0b75c32016-08-12 02:46:52184 DestroyResources();
kylechar46d2e912019-05-07 21:08:08185 context_provider_->RemoveObserver(this);
186 context_provider_.reset();
revemanb195f41d2015-11-19 22:16:48187}
188
revemanced21f82015-11-24 00:42:49189bool Buffer::Texture::IsLost() {
revemand0b75c32016-08-12 02:46:52190 if (context_provider_) {
Daniele Castagnaa8ace632019-04-03 18:01:29191 gpu::raster::RasterInterface* ri = context_provider_->RasterInterface();
192 return ri->GetGraphicsResetStatusKHR() != GL_NO_ERROR;
revemand0b75c32016-08-12 02:46:52193 }
194 return true;
revemanced21f82015-11-24 00:42:49195}
revemanb195f41d2015-11-19 22:16:48196
Daniele Castagna9f15eb72019-03-30 01:11:36197void Buffer::Texture::Release(base::OnceClosure callback,
revemanc8623d5b2016-02-09 02:29:10198 const gpu::SyncToken& sync_token,
199 bool is_lost) {
revemand0b75c32016-08-12 02:46:52200 if (context_provider_) {
Daniele Castagnaa8ace632019-04-03 18:01:29201 if (sync_token.HasData()) {
202 gpu::raster::RasterInterface* ri = context_provider_->RasterInterface();
203 ri->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
204 }
revemand0b75c32016-08-12 02:46:52205 }
revemanc8623d5b2016-02-09 02:29:10206
207 // Run callback as texture can be reused immediately after waiting for sync
208 // token.
Daniele Castagna9f15eb72019-03-30 01:11:36209 std::move(callback).Run();
revemanc8623d5b2016-02-09 02:29:10210}
211
Daniele Castagnafade73662019-06-04 03:30:31212gpu::SyncToken Buffer::Texture::UpdateSharedImage(
213 std::unique_ptr<gfx::GpuFence> acquire_fence) {
revemanb195f41d2015-11-19 22:16:48214 gpu::SyncToken sync_token;
revemand0b75c32016-08-12 02:46:52215 if (context_provider_) {
Daniele Castagnaa8ace632019-04-03 18:01:29216 gpu::SharedImageInterface* sii = context_provider_->SharedImageInterface();
217 DCHECK(!mailbox_.IsZero());
218 // UpdateSharedImage gets called only after |mailbox_| can be reused.
219 // A buffer can be reattached to a surface only after it has been returned
220 // to wayland clients. We return buffers to clients only after the query
221 // |query_type_| is available.
Daniele Castagnafade73662019-06-04 03:30:31222 sii->UpdateSharedImage(gpu::SyncToken(), std::move(acquire_fence),
223 mailbox_);
Daniele Castagnaa8ace632019-04-03 18:01:29224 sync_token = sii->GenUnverifiedSyncToken();
[email protected]29befae2019-01-09 22:55:35225 TRACE_EVENT_ASYNC_STEP_INTO0("exo", kBufferInUse, gpu_memory_buffer_,
David Reveman66cbc512017-05-31 21:21:20226 "bound");
revemand0b75c32016-08-12 02:46:52227 }
revemanced21f82015-11-24 00:42:49228 return sync_token;
229}
230
Daniele Castagnaa8ace632019-04-03 18:01:29231void Buffer::Texture::ReleaseSharedImage(base::OnceClosure callback,
232 const gpu::SyncToken& sync_token,
233 bool is_lost) {
revemand0b75c32016-08-12 02:46:52234 if (context_provider_) {
Daniele Castagnaa8ace632019-04-03 18:01:29235 gpu::raster::RasterInterface* ri = context_provider_->RasterInterface();
revemand0b75c32016-08-12 02:46:52236 if (sync_token.HasData())
Daniele Castagnaa8ace632019-04-03 18:01:29237 ri->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
238 ri->BeginQueryEXT(query_type_, query_id_);
239 ri->EndQueryEXT(query_type_);
240 // Run callback when query result is available (i.e., when all operations on
241 // the shared image have completed and it's ready to be reused) if sync
242 // token has data and buffer has been used. If buffer was never used then
243 // run the callback immediately.
revemand0b75c32016-08-12 02:46:52244 if (sync_token.HasData()) {
Daniele Castagna9f15eb72019-03-30 01:11:36245 ReleaseWhenQueryResultIsAvailable(std::move(callback));
revemand0b75c32016-08-12 02:46:52246 return;
247 }
revemanc8623d5b2016-02-09 02:29:10248 }
Daniele Castagna9f15eb72019-03-30 01:11:36249 std::move(callback).Run();
revemanc8623d5b2016-02-09 02:29:10250}
251
Daniele Castagnafade73662019-06-04 03:30:31252gpu::SyncToken Buffer::Texture::CopyTexImage(
253 std::unique_ptr<gfx::GpuFence> acquire_fence,
254 Texture* destination,
255 base::OnceClosure callback) {
revemanc8623d5b2016-02-09 02:29:10256 gpu::SyncToken sync_token;
revemand0b75c32016-08-12 02:46:52257 if (context_provider_) {
Daniele Castagnaa8ace632019-04-03 18:01:29258 DCHECK(!mailbox_.IsZero());
259 gpu::SharedImageInterface* sii = context_provider_->SharedImageInterface();
Daniele Castagnafade73662019-06-04 03:30:31260 sii->UpdateSharedImage(gpu::SyncToken(), std::move(acquire_fence),
261 mailbox_);
Daniele Castagnaa8ace632019-04-03 18:01:29262 sync_token = sii->GenUnverifiedSyncToken();
263
264 gpu::raster::RasterInterface* ri = context_provider_->RasterInterface();
265 ri->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
revemand0b75c32016-08-12 02:46:52266 DCHECK_NE(query_id_, 0u);
Daniele Castagnaa8ace632019-04-03 18:01:29267 ri->BeginQueryEXT(query_type_, query_id_);
268 ri->CopySubTexture(mailbox_, destination->mailbox_,
269 destination->texture_target_, 0, 0, 0, 0, size_.width(),
Nathan Zabriskief1095d7b2019-12-21 00:33:57270 size_.height(), /*unpack_flip_y=*/false,
271 /*unpack_premultiply_alpha=*/false);
Daniele Castagnaa8ace632019-04-03 18:01:29272 ri->EndQueryEXT(query_type_);
273 // Run callback when query result is available.
Daniele Castagna9f15eb72019-03-30 01:11:36274 ReleaseWhenQueryResultIsAvailable(std::move(callback));
revemand0b75c32016-08-12 02:46:52275 // Create and return a sync token that can be used to ensure that the
Daniele Castagnaa8ace632019-04-03 18:01:29276 // CopySubTexture call is processed before issuing any commands
revemand0b75c32016-08-12 02:46:52277 // that will read from the target texture on a different context.
Daniele Castagnaa8ace632019-04-03 18:01:29278 ri->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData());
revemand0b75c32016-08-12 02:46:52279 }
revemanc8623d5b2016-02-09 02:29:10280 return sync_token;
revemanced21f82015-11-24 00:42:49281}
282
revemand0b75c32016-08-12 02:46:52283void Buffer::Texture::DestroyResources() {
284 if (context_provider_) {
Daniele Castagnaa8ace632019-04-03 18:01:29285 if (query_id_) {
286 gpu::raster::RasterInterface* ri = context_provider_->RasterInterface();
287 ri->DeleteQueriesEXT(1, &query_id_);
288 query_id_ = 0;
289 }
290 gpu::SharedImageInterface* sii = context_provider_->SharedImageInterface();
291 sii->DestroySharedImage(gpu::SyncToken(), mailbox_);
revemand0b75c32016-08-12 02:46:52292 }
293}
294
revemanae3b7c852016-02-25 01:50:03295void Buffer::Texture::ReleaseWhenQueryResultIsAvailable(
Daniele Castagna9f15eb72019-03-30 01:11:36296 base::OnceClosure callback) {
revemand0b75c32016-08-12 02:46:52297 DCHECK(context_provider_);
revemanae3b7c852016-02-25 01:50:03298 DCHECK(release_callback_.is_null());
Daniele Castagna9f15eb72019-03-30 01:11:36299 release_callback_ = std::move(callback);
David Revemanf8fde1902017-10-20 23:01:04300 wait_for_release_time_ = base::TimeTicks::Now() + wait_for_release_delay_;
301 ScheduleWaitForRelease(wait_for_release_delay_);
[email protected]29befae2019-01-09 22:55:35302 TRACE_EVENT_ASYNC_STEP_INTO0("exo", kBufferInUse, gpu_memory_buffer_,
David Reveman66cbc512017-05-31 21:21:20303 "pending_query");
revemanae3b7c852016-02-25 01:50:03304 context_provider_->ContextSupport()->SignalQuery(
tzik2bcf8e42018-07-31 11:22:15305 query_id_, base::BindOnce(&Buffer::Texture::Released,
306 weak_ptr_factory_.GetWeakPtr()));
revemanae3b7c852016-02-25 01:50:03307}
308
309void Buffer::Texture::Released() {
310 if (!release_callback_.is_null())
Daniele Castagna9f15eb72019-03-30 01:11:36311 std::move(release_callback_).Run();
revemanae3b7c852016-02-25 01:50:03312}
313
314void Buffer::Texture::ScheduleWaitForRelease(base::TimeDelta delay) {
315 if (wait_for_release_pending_)
316 return;
317
318 wait_for_release_pending_ = true;
319 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
tzik2bcf8e42018-07-31 11:22:15320 FROM_HERE,
321 base::BindOnce(&Buffer::Texture::WaitForRelease,
322 weak_ptr_factory_.GetWeakPtr()),
revemanae3b7c852016-02-25 01:50:03323 delay);
324}
325
326void Buffer::Texture::WaitForRelease() {
327 DCHECK(wait_for_release_pending_);
328 wait_for_release_pending_ = false;
329
330 if (release_callback_.is_null())
331 return;
332
333 base::TimeTicks current_time = base::TimeTicks::Now();
334 if (current_time < wait_for_release_time_) {
335 ScheduleWaitForRelease(wait_for_release_time_ - current_time);
336 return;
337 }
338
Daniele Castagna9f15eb72019-03-30 01:11:36339 base::OnceClosure callback = std::move(release_callback_);
revemanae3b7c852016-02-25 01:50:03340
revemand0b75c32016-08-12 02:46:52341 if (context_provider_) {
revemanae3b7c852016-02-25 01:50:03342 TRACE_EVENT0("exo", "Buffer::Texture::WaitForQueryResult");
343
344 // We need to wait for the result to be available. Getting the result of
345 // the query implies waiting for it to become available. The actual result
346 // is unimportant and also not well defined.
347 unsigned result = 0;
Daniele Castagnaa8ace632019-04-03 18:01:29348 gpu::raster::RasterInterface* ri = context_provider_->RasterInterface();
349 ri->GetQueryObjectuivEXT(query_id_, GL_QUERY_RESULT_EXT, &result);
revemanae3b7c852016-02-25 01:50:03350 }
351
Daniele Castagna9f15eb72019-03-30 01:11:36352 std::move(callback).Run();
revemanae3b7c852016-02-25 01:50:03353}
354
revemanced21f82015-11-24 00:42:49355////////////////////////////////////////////////////////////////////////////////
356// Buffer, public:
357
dcheng31759da2016-04-21 01:26:31358Buffer::Buffer(std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer)
David Revemanf8fde1902017-10-20 23:01:04359 : Buffer(std::move(gpu_memory_buffer),
360 GL_TEXTURE_2D /* texture_target */,
361 GL_COMMANDS_COMPLETED_CHROMIUM /* query_type */,
362 true /* use_zero_copy */,
Zach Reizner8bcce6e2018-10-31 00:04:37363 false /* is_overlay_candidate */,
364 false /* y_invert */) {}
revemanc8623d5b2016-02-09 02:29:10365
dcheng31759da2016-04-21 01:26:31366Buffer::Buffer(std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer,
revemanc8623d5b2016-02-09 02:29:10367 unsigned texture_target,
368 unsigned query_type,
reveman244f9622016-03-04 21:33:33369 bool use_zero_copy,
Zach Reizner8bcce6e2018-10-31 00:04:37370 bool is_overlay_candidate,
371 bool y_invert)
dcheng27f7483f2015-12-29 22:26:56372 : gpu_memory_buffer_(std::move(gpu_memory_buffer)),
revemanced21f82015-11-24 00:42:49373 texture_target_(texture_target),
revemanc8623d5b2016-02-09 02:29:10374 query_type_(query_type),
375 use_zero_copy_(use_zero_copy),
David Revemanf8fde1902017-10-20 23:01:04376 is_overlay_candidate_(is_overlay_candidate),
Zach Reizner8bcce6e2018-10-31 00:04:37377 y_invert_(y_invert),
David Revemanf8fde1902017-10-20 23:01:04378 wait_for_release_delay_(
379 base::TimeDelta::FromMilliseconds(kWaitForReleaseDelayMs)) {}
revemanced21f82015-11-24 00:42:49380
381Buffer::~Buffer() {}
382
starazd40f0362017-01-04 00:46:13383bool Buffer::ProduceTransferableResource(
Albert Chaulk56e96582019-01-30 19:33:18384 FrameSinkResourceManager* resource_manager,
Daniele Castagnafade73662019-06-04 03:30:31385 std::unique_ptr<gfx::GpuFence> acquire_fence,
reveman85b7a562016-03-17 23:27:32386 bool secure_output_only,
Fady Samuel4f7f0fb32017-07-28 15:33:37387 viz::TransferableResource* resource) {
[email protected]29befae2019-01-09 22:55:35388 TRACE_EVENT1("exo", "Buffer::ProduceTransferableResource", "buffer_id",
389 gfx_buffer());
jbauman45c06862016-06-23 19:35:02390 DCHECK(attach_count_);
revemanced21f82015-11-24 00:42:49391
revemanc8623d5b2016-02-09 02:29:10392 // If textures are lost, destroy them to ensure that we create new ones below.
393 if (contents_texture_ && contents_texture_->IsLost())
394 contents_texture_.reset();
395 if (texture_ && texture_->IsLost())
396 texture_.reset();
revemanced21f82015-11-24 00:42:49397
revemand0b75c32016-08-12 02:46:52398 ui::ContextFactory* context_factory =
Jun Mukai1f426ff2019-05-16 18:19:24399 aura::Env::GetInstance()->context_factory();
revemanc8623d5b2016-02-09 02:29:10400 // Note: This can fail if GPU acceleration has been disabled.
Daniele Castagnaa8ace632019-04-03 18:01:29401 scoped_refptr<viz::RasterContextProvider> context_provider =
402 context_factory->SharedMainThreadRasterContextProvider();
revemanc8623d5b2016-02-09 02:29:10403 if (!context_provider) {
404 DLOG(WARNING) << "Failed to acquire a context provider";
starazd40f0362017-01-04 00:46:13405 resource->id = 0;
406 resource->size = gfx::Size();
407 return false;
revemanced21f82015-11-24 00:42:49408 }
409
Albert Chaulk56e96582019-01-30 19:33:18410 resource->id = resource_manager->AllocateResourceId();
Fady Samuel555c8d12017-07-07 23:14:09411 resource->format = viz::RGBA_8888;
starazd40f0362017-01-04 00:46:13412 resource->filter = GL_LINEAR;
413 resource->size = gpu_memory_buffer_->GetSize();
414
revemanc8623d5b2016-02-09 02:29:10415 // Create a new image texture for |gpu_memory_buffer_| with |texture_target_|
416 // if one doesn't already exist. The contents of this buffer are copied to
417 // |texture| using a call to CopyTexImage.
418 if (!contents_texture_) {
David Revemand0ab1fb82017-09-18 22:27:57419 contents_texture_ = std::make_unique<Texture>(
kylechar46d2e912019-05-07 21:08:08420 context_provider, context_factory->GetGpuMemoryBufferManager(),
421 gpu_memory_buffer_.get(), texture_target_, query_type_,
Daniele Castagnaa8ace632019-04-03 18:01:29422 wait_for_release_delay_);
revemanc8623d5b2016-02-09 02:29:10423 }
reveman2cd69782017-02-01 20:19:44424 Texture* contents_texture = contents_texture_.get();
revemanb195f41d2015-11-19 22:16:48425
David Reveman66cbc512017-05-31 21:21:20426 if (release_contents_callback_.IsCancelled())
[email protected]29befae2019-01-09 22:55:35427 TRACE_EVENT_ASYNC_BEGIN1("exo", kBufferInUse, gpu_memory_buffer_.get(),
428 "buffer_id", gfx_buffer());
David Reveman66cbc512017-05-31 21:21:20429
reveman2cd69782017-02-01 20:19:44430 // Cancel pending contents release callback.
431 release_contents_callback_.Reset(
Daniele Castagna9f15eb72019-03-30 01:11:36432 base::BindOnce(&Buffer::ReleaseContents, base::Unretained(this)));
reveman2cd69782017-02-01 20:19:44433
434 // Zero-copy means using the contents texture directly.
revemanc8623d5b2016-02-09 02:29:10435 if (use_zero_copy_) {
reveman2cd69782017-02-01 20:19:44436 // This binds the latest contents of this buffer to |contents_texture|.
Daniele Castagnafade73662019-06-04 03:30:31437 gpu::SyncToken sync_token =
438 contents_texture->UpdateSharedImage(std::move(acquire_fence));
reveman2cd69782017-02-01 20:19:44439 resource->mailbox_holder = gpu::MailboxHolder(contents_texture->mailbox(),
440 sync_token, texture_target_);
starazd40f0362017-01-04 00:46:13441 resource->is_overlay_candidate = is_overlay_candidate_;
sohanfc3065e2018-07-02 22:36:04442 resource->format = viz::GetResourceFormat(gpu_memory_buffer_->GetFormat());
starazd40f0362017-01-04 00:46:13443
revemanc8623d5b2016-02-09 02:29:10444 // The contents texture will be released when no longer used by the
445 // compositor.
Albert Chaulk56e96582019-01-30 19:33:18446 resource_manager->SetResourceReleaseCallback(
Peng Huang583c9dc62017-07-27 23:38:28447 resource->id,
Daniele Castagnaa8ace632019-04-03 18:01:29448 base::BindOnce(&Buffer::Texture::ReleaseSharedImage,
tzik2bcf8e42018-07-31 11:22:15449 base::Unretained(contents_texture),
Daniele Castagna9f15eb72019-03-30 01:11:36450 base::BindOnce(&Buffer::ReleaseContentsTexture,
451 AsWeakPtr(), std::move(contents_texture_),
452 release_contents_callback_.callback())));
starazd40f0362017-01-04 00:46:13453 return true;
revemanc8623d5b2016-02-09 02:29:10454 }
455
456 // Create a mailbox texture that we copy the buffer contents to.
revemand0b75c32016-08-12 02:46:52457 if (!texture_) {
kylechar46d2e912019-05-07 21:08:08458 texture_ = std::make_unique<Texture>(context_provider,
Daniele Castagnaa8ace632019-04-03 18:01:29459 gpu_memory_buffer_->GetSize());
revemand0b75c32016-08-12 02:46:52460 }
revemanc8623d5b2016-02-09 02:29:10461 Texture* texture = texture_.get();
462
reveman2cd69782017-02-01 20:19:44463 // Copy the contents of |contents_texture| to |texture| and produce a
464 // texture mailbox from the result in |texture|. The contents texture will
465 // be released when copy has completed.
reveman7ee8b4e2017-01-11 22:10:53466 gpu::SyncToken sync_token = contents_texture->CopyTexImage(
Daniele Castagnafade73662019-06-04 03:30:31467 std::move(acquire_fence), texture,
468 base::BindOnce(&Buffer::ReleaseContentsTexture, AsWeakPtr(),
469 std::move(contents_texture_),
470 release_contents_callback_.callback()));
reveman7ee8b4e2017-01-11 22:10:53471 resource->mailbox_holder =
472 gpu::MailboxHolder(texture->mailbox(), sync_token, GL_TEXTURE_2D);
starazd40f0362017-01-04 00:46:13473 resource->is_overlay_candidate = false;
474
revemanc8623d5b2016-02-09 02:29:10475 // The mailbox texture will be released when no longer used by the
476 // compositor.
Albert Chaulk56e96582019-01-30 19:33:18477 resource_manager->SetResourceReleaseCallback(
Peng Huang583c9dc62017-07-27 23:38:28478 resource->id,
tzik2bcf8e42018-07-31 11:22:15479 base::BindOnce(&Buffer::Texture::Release, base::Unretained(texture),
Daniele Castagna9f15eb72019-03-30 01:11:36480 base::BindOnce(&Buffer::ReleaseTexture, AsWeakPtr(),
481 std::move(texture_))));
starazd40f0362017-01-04 00:46:13482 return true;
revemanb195f41d2015-11-19 22:16:48483}
484
jbauman45c06862016-06-23 19:35:02485void Buffer::OnAttach() {
reveman2cd69782017-02-01 20:19:44486 DLOG_IF(WARNING, attach_count_)
jbauman45c06862016-06-23 19:35:02487 << "Reattaching a buffer that is already attached to another surface.";
[email protected]29befae2019-01-09 22:55:35488 TRACE_EVENT2("exo", "Buffer::OnAttach", "buffer_id", gfx_buffer(), "count",
489 attach_count_);
reveman2cd69782017-02-01 20:19:44490 ++attach_count_;
jbauman45c06862016-06-23 19:35:02491}
492
493void Buffer::OnDetach() {
494 DCHECK_GT(attach_count_, 0u);
[email protected]29befae2019-01-09 22:55:35495 TRACE_EVENT2("exo", "Buffer::OnAttach", "buffer_id", gfx_buffer(), "count",
496 attach_count_);
jbauman45c06862016-06-23 19:35:02497 --attach_count_;
reveman2cd69782017-02-01 20:19:44498
499 // Release buffer if no longer attached to a surface and content has been
500 // released.
501 if (!attach_count_ && release_contents_callback_.IsCancelled())
502 Release();
jbauman45c06862016-06-23 19:35:02503}
504
revemanb195f41d2015-11-19 22:16:48505gfx::Size Buffer::GetSize() const {
506 return gpu_memory_buffer_->GetSize();
507}
508
revemanca132dc2017-01-31 22:35:54509gfx::BufferFormat Buffer::GetFormat() const {
510 return gpu_memory_buffer_->GetFormat();
511}
512
revemanb195f41d2015-11-19 22:16:48513////////////////////////////////////////////////////////////////////////////////
514// Buffer, private:
515
revemanced21f82015-11-24 00:42:49516void Buffer::Release() {
[email protected]29befae2019-01-09 22:55:35517 TRACE_EVENT_ASYNC_END0("exo", kBufferInUse, gpu_memory_buffer_.get());
David Reveman66cbc512017-05-31 21:21:20518
revemanced21f82015-11-24 00:42:49519 // Run release callback to notify the client that buffer has been released.
520 if (!release_callback_.is_null())
521 release_callback_.Run();
522}
revemanb195f41d2015-11-19 22:16:48523
dcheng31759da2016-04-21 01:26:31524void Buffer::ReleaseTexture(std::unique_ptr<Texture> texture) {
revemanc8623d5b2016-02-09 02:29:10525 texture_ = std::move(texture);
526}
revemanced21f82015-11-24 00:42:49527
reveman2cd69782017-02-01 20:19:44528void Buffer::ReleaseContentsTexture(std::unique_ptr<Texture> texture,
Daniele Castagna9f15eb72019-03-30 01:11:36529 base::OnceClosure callback) {
revemanc8623d5b2016-02-09 02:29:10530 contents_texture_ = std::move(texture);
Daniele Castagna9f15eb72019-03-30 01:11:36531 std::move(callback).Run();
reveman2cd69782017-02-01 20:19:44532}
533
534void Buffer::ReleaseContents() {
[email protected]29befae2019-01-09 22:55:35535 TRACE_EVENT1("exo", "Buffer::ReleaseContents", "buffer_id", gfx_buffer());
reveman2cd69782017-02-01 20:19:44536
537 // Cancel callback to indicate that buffer has been released.
538 release_contents_callback_.Cancel();
539
David Reveman66cbc512017-05-31 21:21:20540 if (attach_count_) {
[email protected]29befae2019-01-09 22:55:35541 TRACE_EVENT_ASYNC_STEP_INTO0("exo", kBufferInUse, gpu_memory_buffer_.get(),
David Reveman66cbc512017-05-31 21:21:20542 "attached");
543 } else {
544 // Release buffer if not attached to surface.
reveman2cd69782017-02-01 20:19:44545 Release();
David Reveman66cbc512017-05-31 21:21:20546 }
revemanb195f41d2015-11-19 22:16:48547}
548
549} // namespace exo