blob: c0cbd5679a84b73ca14ddd6685cd3cc6a6752b54 [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
7#include <GLES2/gl2.h>
8#include <GLES2/gl2ext.h>
9#include <GLES2/gl2extchromium.h>
avibc5337b2015-12-25 23:16:3310#include <stdint.h>
dcheng31759da2016-04-21 01:26:3111
revemanb195f41d2015-11-19 22:16:4812#include <algorithm>
dcheng27f7483f2015-12-29 22:26:5613#include <utility>
revemanb195f41d2015-11-19 22:16:4814
Sebastien Marchand53801a32019-01-25 16:26:1115#include "base/bind.h"
revemanae3b7c852016-02-25 01:50:0316#include "base/callback_helpers.h"
revemanb195f41d2015-11-19 22:16:4817#include "base/logging.h"
revemanae3b7c852016-02-25 01:50:0318#include "base/memory/weak_ptr.h"
Avi Drissman8171db7d2018-12-25 23:08:3119#include "base/stl_util.h"
gab7966d312016-05-11 20:35:0120#include "base/threading/thread_task_runner_handle.h"
revemanae3b7c852016-02-25 01:50:0321#include "base/time/time.h"
revemanb195f41d2015-11-19 22:16:4822#include "base/trace_event/trace_event.h"
David 'Digit' Turnerea071142018-10-29 15:38:1223#include "base/trace_event/traced_value.h"
danakjc7afae52017-06-20 21:12:4124#include "components/exo/layer_tree_frame_sink_holder.h"
Scott Violet13de50d2018-08-10 20:07:1125#include "components/exo/wm_helper.h"
Xu Xing32549162017-07-17 22:25:4326#include "components/viz/common/gpu/context_provider.h"
Vladimir Levine348e2dc2017-08-22 15:56:4227#include "components/viz/common/resources/resource_format.h"
sohanfc3065e2018-07-02 22:36:0428#include "components/viz/common/resources/resource_format_utils.h"
danakjf20f4502017-09-26 17:13:3129#include "components/viz/common/resources/single_release_callback.h"
revemanc8623d5b2016-02-09 02:29:1030#include "gpu/command_buffer/client/context_support.h"
revemanb195f41d2015-11-19 22:16:4831#include "gpu/command_buffer/client/gles2_interface.h"
danakj33d8fbb2017-11-23 17:50:3632#include "gpu/command_buffer/common/mailbox.h"
33#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:4847GLenum GLInternalFormat(gfx::BufferFormat format) {
48 const GLenum kGLInternalFormats[] = {
revemanb195f41d2015-11-19 22:16:4849 GL_R8_EXT, // R_8
rijubrata.bhaumik65f143d2017-06-21 11:50:4250 GL_R16_EXT, // R_16
dongseong.hwang961b0e12016-10-04 10:15:3051 GL_RG8_EXT, // RG_88
reveman5954fa12016-05-18 21:56:3852 GL_RGB, // BGR_565
revemanb195f41d2015-11-19 22:16:4853 GL_RGBA, // RGBA_4444
54 GL_RGB, // RGBX_8888
55 GL_RGBA, // RGBA_8888
56 GL_RGB, // BGRX_8888
Miguel Casas02290322018-02-20 21:35:2357 GL_RGB10_A2_EXT, // BGRX_1010102
58 GL_RGB10_A2_EXT, // RGBX_1010102
revemanb195f41d2015-11-19 22:16:4859 GL_BGRA_EXT, // BGRA_8888
ccameronc1fcde52017-04-12 19:40:4960 GL_RGBA, // RGBA_F16
dcastagnacbea4262016-06-08 00:26:0261 GL_RGB_YCRCB_420_CHROMIUM, // YVU_420
dcastagna23d30bfd2016-09-24 02:06:2062 GL_RGB_YCBCR_420V_CHROMIUM, // YUV_420_BIPLANAR
revemanb195f41d2015-11-19 22:16:4863 GL_RGB_YCBCR_422_CHROMIUM, // UYVY_422
64 };
Avi Drissman8171db7d2018-12-25 23:08:3165 static_assert(base::size(kGLInternalFormats) ==
revemanb195f41d2015-11-19 22:16:4866 (static_cast<int>(gfx::BufferFormat::LAST) + 1),
67 "BufferFormat::LAST must be last value of kGLInternalFormats");
68
69 DCHECK(format <= gfx::BufferFormat::LAST);
70 return kGLInternalFormats[static_cast<int>(format)];
71}
72
revemanc8623d5b2016-02-09 02:29:1073unsigned CreateGLTexture(gpu::gles2::GLES2Interface* gles2, GLenum target) {
74 unsigned texture_id = 0;
75 gles2->GenTextures(1, &texture_id);
76 gles2->ActiveTexture(GL_TEXTURE0);
77 gles2->BindTexture(target, texture_id);
78 gles2->TexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
79 gles2->TexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
80 gles2->TexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
81 gles2->TexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
82 return texture_id;
83}
84
revemanb195f41d2015-11-19 22:16:4885} // namespace
86
87////////////////////////////////////////////////////////////////////////////////
revemanced21f82015-11-24 00:42:4988// Buffer::Texture
revemanb195f41d2015-11-19 22:16:4889
revemanced21f82015-11-24 00:42:4990// Encapsulates the state and logic needed to bind a buffer to a GLES2 texture.
revemand0b75c32016-08-12 02:46:5291class Buffer::Texture : public ui::ContextFactoryObserver {
revemanced21f82015-11-24 00:42:4992 public:
revemand0b75c32016-08-12 02:46:5293 Texture(ui::ContextFactory* context_factory,
Xu Xing32549162017-07-17 22:25:4394 viz::ContextProvider* context_provider);
revemand0b75c32016-08-12 02:46:5295 Texture(ui::ContextFactory* context_factory,
Xu Xing32549162017-07-17 22:25:4396 viz::ContextProvider* context_provider,
revemanc8623d5b2016-02-09 02:29:1097 gfx::GpuMemoryBuffer* gpu_memory_buffer,
98 unsigned texture_target,
David Revemanf8fde1902017-10-20 23:01:0499 unsigned query_type,
100 base::TimeDelta wait_for_release_time);
revemand0b75c32016-08-12 02:46:52101 ~Texture() override;
102
103 // Overridden from ui::ContextFactoryObserver:
kylecharb99b1042018-07-26 21:09:32104 void OnLostSharedContext() override;
105 void OnLostVizProcess() override;
revemanced21f82015-11-24 00:42:49106
107 // Returns true if GLES2 resources for texture have been lost.
108 bool IsLost();
109
revemanc8623d5b2016-02-09 02:29:10110 // Allow texture to be reused after |sync_token| has passed and runs
111 // |callback|.
112 void Release(const base::Closure& callback,
113 const gpu::SyncToken& sync_token,
114 bool is_lost);
115
116 // Binds the contents referenced by |image_id_| to the texture returned by
117 // mailbox(). Returns a sync token that can be used when accessing texture
revemanced21f82015-11-24 00:42:49118 // from a different context.
119 gpu::SyncToken BindTexImage();
120
revemanc8623d5b2016-02-09 02:29:10121 // Releases the contents referenced by |image_id_| after |sync_token| has
122 // passed and runs |callback| when completed.
123 void ReleaseTexImage(const base::Closure& callback,
124 const gpu::SyncToken& sync_token,
125 bool is_lost);
126
127 // Copy the contents of texture to |destination| and runs |callback| when
128 // completed. Returns a sync token that can be used when accessing texture
129 // from a different context.
130 gpu::SyncToken CopyTexImage(Texture* destination,
131 const base::Closure& callback);
revemanced21f82015-11-24 00:42:49132
133 // Returns the mailbox for this texture.
134 gpu::Mailbox mailbox() const { return mailbox_; }
135
136 private:
revemand0b75c32016-08-12 02:46:52137 void DestroyResources();
revemanae3b7c852016-02-25 01:50:03138 void ReleaseWhenQueryResultIsAvailable(const base::Closure& callback);
139 void Released();
140 void ScheduleWaitForRelease(base::TimeDelta delay);
141 void WaitForRelease();
142
David Reveman66cbc512017-05-31 21:21:20143 gfx::GpuMemoryBuffer* const gpu_memory_buffer_;
revemand0b75c32016-08-12 02:46:52144 ui::ContextFactory* context_factory_;
Xu Xing32549162017-07-17 22:25:43145 scoped_refptr<viz::ContextProvider> context_provider_;
revemanced21f82015-11-24 00:42:49146 const unsigned texture_target_;
revemanc8623d5b2016-02-09 02:29:10147 const unsigned query_type_;
148 const GLenum internalformat_;
reveman2d3815d2016-06-26 20:13:25149 unsigned image_id_ = 0;
150 unsigned query_id_ = 0;
151 unsigned texture_id_ = 0;
revemanced21f82015-11-24 00:42:49152 gpu::Mailbox mailbox_;
revemanae3b7c852016-02-25 01:50:03153 base::Closure release_callback_;
David Revemanf8fde1902017-10-20 23:01:04154 const base::TimeDelta wait_for_release_delay_;
revemanae3b7c852016-02-25 01:50:03155 base::TimeTicks wait_for_release_time_;
reveman2d3815d2016-06-26 20:13:25156 bool wait_for_release_pending_ = false;
revemanae3b7c852016-02-25 01:50:03157 base::WeakPtrFactory<Texture> weak_ptr_factory_;
revemanced21f82015-11-24 00:42:49158
159 DISALLOW_COPY_AND_ASSIGN(Texture);
160};
161
revemand0b75c32016-08-12 02:46:52162Buffer::Texture::Texture(ui::ContextFactory* context_factory,
Xu Xing32549162017-07-17 22:25:43163 viz::ContextProvider* context_provider)
David Reveman66cbc512017-05-31 21:21:20164 : gpu_memory_buffer_(nullptr),
165 context_factory_(context_factory),
revemand0b75c32016-08-12 02:46:52166 context_provider_(context_provider),
revemanc8623d5b2016-02-09 02:29:10167 texture_target_(GL_TEXTURE_2D),
168 query_type_(GL_COMMANDS_COMPLETED_CHROMIUM),
169 internalformat_(GL_RGBA),
revemanae3b7c852016-02-25 01:50:03170 weak_ptr_factory_(this) {
revemanced21f82015-11-24 00:42:49171 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
revemanc8623d5b2016-02-09 02:29:10172 texture_id_ = CreateGLTexture(gles2, texture_target_);
revemanb195f41d2015-11-19 22:16:48173 // Generate a crypto-secure random mailbox name.
Antoine Labour3a776dc12018-06-13 00:07:48174 gles2->ProduceTextureDirectCHROMIUM(texture_id_, mailbox_.name);
revemand0b75c32016-08-12 02:46:52175 // Provides a notification when |context_provider_| is lost.
176 context_factory_->AddObserver(this);
revemanc8623d5b2016-02-09 02:29:10177}
178
revemand0b75c32016-08-12 02:46:52179Buffer::Texture::Texture(ui::ContextFactory* context_factory,
Xu Xing32549162017-07-17 22:25:43180 viz::ContextProvider* context_provider,
revemanc8623d5b2016-02-09 02:29:10181 gfx::GpuMemoryBuffer* gpu_memory_buffer,
182 unsigned texture_target,
David Revemanf8fde1902017-10-20 23:01:04183 unsigned query_type,
184 base::TimeDelta wait_for_release_delay)
David Reveman66cbc512017-05-31 21:21:20185 : gpu_memory_buffer_(gpu_memory_buffer),
186 context_factory_(context_factory),
revemand0b75c32016-08-12 02:46:52187 context_provider_(context_provider),
revemanc8623d5b2016-02-09 02:29:10188 texture_target_(texture_target),
189 query_type_(query_type),
190 internalformat_(GLInternalFormat(gpu_memory_buffer->GetFormat())),
David Revemanf8fde1902017-10-20 23:01:04191 wait_for_release_delay_(wait_for_release_delay),
revemanae3b7c852016-02-25 01:50:03192 weak_ptr_factory_(this) {
revemanc8623d5b2016-02-09 02:29:10193 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
194 gfx::Size size = gpu_memory_buffer->GetSize();
195 image_id_ =
196 gles2->CreateImageCHROMIUM(gpu_memory_buffer->AsClientBuffer(),
197 size.width(), size.height(), internalformat_);
dcastagna2db83c7ef2016-06-13 23:33:22198 DLOG_IF(WARNING, !image_id_) << "Failed to create GLImage";
199
revemanc8623d5b2016-02-09 02:29:10200 gles2->GenQueriesEXT(1, &query_id_);
201 texture_id_ = CreateGLTexture(gles2, texture_target_);
revemand0b75c32016-08-12 02:46:52202 // Provides a notification when |context_provider_| is lost.
203 context_factory_->AddObserver(this);
revemanb195f41d2015-11-19 22:16:48204}
205
revemanced21f82015-11-24 00:42:49206Buffer::Texture::~Texture() {
revemand0b75c32016-08-12 02:46:52207 DestroyResources();
Alex Zhang3f8482b2017-08-01 15:16:24208 if (context_provider_)
209 context_factory_->RemoveObserver(this);
revemand0b75c32016-08-12 02:46:52210}
211
kylecharb99b1042018-07-26 21:09:32212void Buffer::Texture::OnLostSharedContext() {
revemand0b75c32016-08-12 02:46:52213 DestroyResources();
Alex Zhang3f8482b2017-08-01 15:16:24214 context_factory_->RemoveObserver(this);
revemand0b75c32016-08-12 02:46:52215 context_provider_ = nullptr;
Alex Zhang3f8482b2017-08-01 15:16:24216 context_factory_ = nullptr;
revemanb195f41d2015-11-19 22:16:48217}
218
kylecharb99b1042018-07-26 21:09:32219void Buffer::Texture::OnLostVizProcess() {}
220
revemanced21f82015-11-24 00:42:49221bool Buffer::Texture::IsLost() {
revemand0b75c32016-08-12 02:46:52222 if (context_provider_) {
223 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
224 return gles2->GetGraphicsResetStatusKHR() != GL_NO_ERROR;
225 }
226 return true;
revemanced21f82015-11-24 00:42:49227}
revemanb195f41d2015-11-19 22:16:48228
revemanc8623d5b2016-02-09 02:29:10229void Buffer::Texture::Release(const base::Closure& callback,
230 const gpu::SyncToken& sync_token,
231 bool is_lost) {
revemand0b75c32016-08-12 02:46:52232 if (context_provider_) {
233 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
234 if (sync_token.HasData())
235 gles2->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
236 }
revemanc8623d5b2016-02-09 02:29:10237
238 // Run callback as texture can be reused immediately after waiting for sync
239 // token.
240 callback.Run();
241}
242
revemanced21f82015-11-24 00:42:49243gpu::SyncToken Buffer::Texture::BindTexImage() {
revemanb195f41d2015-11-19 22:16:48244 gpu::SyncToken sync_token;
revemand0b75c32016-08-12 02:46:52245 if (context_provider_) {
246 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
247 gles2->ActiveTexture(GL_TEXTURE0);
248 gles2->BindTexture(texture_target_, texture_id_);
249 DCHECK_NE(image_id_, 0u);
250 gles2->BindTexImage2DCHROMIUM(texture_target_, image_id_);
251 // Generate a crypto-secure random mailbox name if not already done.
252 if (mailbox_.IsZero())
Antoine Labour3a776dc12018-06-13 00:07:48253 gles2->ProduceTextureDirectCHROMIUM(texture_id_, mailbox_.name);
revemand0b75c32016-08-12 02:46:52254 // Create and return a sync token that can be used to ensure that the
255 // BindTexImage2DCHROMIUM call is processed before issuing any commands
256 // that will read from the texture on a different context.
Sunny Sachanandanic94b8de2017-12-16 03:30:30257 gles2->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData());
[email protected]29befae2019-01-09 22:55:35258 TRACE_EVENT_ASYNC_STEP_INTO0("exo", kBufferInUse, gpu_memory_buffer_,
David Reveman66cbc512017-05-31 21:21:20259 "bound");
revemand0b75c32016-08-12 02:46:52260 }
revemanced21f82015-11-24 00:42:49261 return sync_token;
262}
263
revemanc8623d5b2016-02-09 02:29:10264void Buffer::Texture::ReleaseTexImage(const base::Closure& callback,
265 const gpu::SyncToken& sync_token,
266 bool is_lost) {
revemand0b75c32016-08-12 02:46:52267 if (context_provider_) {
268 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
269 if (sync_token.HasData())
270 gles2->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
271 gles2->ActiveTexture(GL_TEXTURE0);
272 gles2->BindTexture(texture_target_, texture_id_);
273 DCHECK_NE(query_id_, 0u);
274 gles2->BeginQueryEXT(query_type_, query_id_);
275 gles2->ReleaseTexImage2DCHROMIUM(texture_target_, image_id_);
276 gles2->EndQueryEXT(query_type_);
277 // Run callback when query result is available and ReleaseTexImage has been
278 // handled if sync token has data and buffer has been used. If buffer was
279 // never used then run the callback immediately.
280 if (sync_token.HasData()) {
281 ReleaseWhenQueryResultIsAvailable(callback);
282 return;
283 }
revemanc8623d5b2016-02-09 02:29:10284 }
revemand0b75c32016-08-12 02:46:52285 callback.Run();
revemanc8623d5b2016-02-09 02:29:10286}
287
288gpu::SyncToken Buffer::Texture::CopyTexImage(Texture* destination,
289 const base::Closure& callback) {
revemanc8623d5b2016-02-09 02:29:10290 gpu::SyncToken sync_token;
revemand0b75c32016-08-12 02:46:52291 if (context_provider_) {
292 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
293 gles2->ActiveTexture(GL_TEXTURE0);
294 gles2->BindTexture(texture_target_, texture_id_);
295 DCHECK_NE(image_id_, 0u);
296 gles2->BindTexImage2DCHROMIUM(texture_target_, image_id_);
qiankun.miao728aa862017-01-22 15:03:03297 gles2->CopyTextureCHROMIUM(texture_id_, 0, destination->texture_target_,
298 destination->texture_id_, 0, internalformat_,
299 GL_UNSIGNED_BYTE, false, false, false);
revemand0b75c32016-08-12 02:46:52300 DCHECK_NE(query_id_, 0u);
301 gles2->BeginQueryEXT(query_type_, query_id_);
302 gles2->ReleaseTexImage2DCHROMIUM(texture_target_, image_id_);
303 gles2->EndQueryEXT(query_type_);
304 // Run callback when query result is available and ReleaseTexImage has been
305 // handled.
306 ReleaseWhenQueryResultIsAvailable(callback);
307 // Create and return a sync token that can be used to ensure that the
308 // CopyTextureCHROMIUM call is processed before issuing any commands
309 // that will read from the target texture on a different context.
Sunny Sachanandanic94b8de2017-12-16 03:30:30310 gles2->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData());
revemand0b75c32016-08-12 02:46:52311 }
revemanc8623d5b2016-02-09 02:29:10312 return sync_token;
revemanced21f82015-11-24 00:42:49313}
314
revemand0b75c32016-08-12 02:46:52315void Buffer::Texture::DestroyResources() {
316 if (context_provider_) {
317 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
318 gles2->DeleteTextures(1, &texture_id_);
319 if (query_id_)
320 gles2->DeleteQueriesEXT(1, &query_id_);
321 if (image_id_)
322 gles2->DestroyImageCHROMIUM(image_id_);
323 }
324}
325
revemanae3b7c852016-02-25 01:50:03326void Buffer::Texture::ReleaseWhenQueryResultIsAvailable(
327 const base::Closure& callback) {
revemand0b75c32016-08-12 02:46:52328 DCHECK(context_provider_);
revemanae3b7c852016-02-25 01:50:03329 DCHECK(release_callback_.is_null());
330 release_callback_ = callback;
David Revemanf8fde1902017-10-20 23:01:04331 wait_for_release_time_ = base::TimeTicks::Now() + wait_for_release_delay_;
332 ScheduleWaitForRelease(wait_for_release_delay_);
[email protected]29befae2019-01-09 22:55:35333 TRACE_EVENT_ASYNC_STEP_INTO0("exo", kBufferInUse, gpu_memory_buffer_,
David Reveman66cbc512017-05-31 21:21:20334 "pending_query");
revemanae3b7c852016-02-25 01:50:03335 context_provider_->ContextSupport()->SignalQuery(
tzik2bcf8e42018-07-31 11:22:15336 query_id_, base::BindOnce(&Buffer::Texture::Released,
337 weak_ptr_factory_.GetWeakPtr()));
revemanae3b7c852016-02-25 01:50:03338}
339
340void Buffer::Texture::Released() {
341 if (!release_callback_.is_null())
342 base::ResetAndReturn(&release_callback_).Run();
343}
344
345void Buffer::Texture::ScheduleWaitForRelease(base::TimeDelta delay) {
346 if (wait_for_release_pending_)
347 return;
348
349 wait_for_release_pending_ = true;
350 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
tzik2bcf8e42018-07-31 11:22:15351 FROM_HERE,
352 base::BindOnce(&Buffer::Texture::WaitForRelease,
353 weak_ptr_factory_.GetWeakPtr()),
revemanae3b7c852016-02-25 01:50:03354 delay);
355}
356
357void Buffer::Texture::WaitForRelease() {
358 DCHECK(wait_for_release_pending_);
359 wait_for_release_pending_ = false;
360
361 if (release_callback_.is_null())
362 return;
363
364 base::TimeTicks current_time = base::TimeTicks::Now();
365 if (current_time < wait_for_release_time_) {
366 ScheduleWaitForRelease(wait_for_release_time_ - current_time);
367 return;
368 }
369
370 base::Closure callback = base::ResetAndReturn(&release_callback_);
371
revemand0b75c32016-08-12 02:46:52372 if (context_provider_) {
revemanae3b7c852016-02-25 01:50:03373 TRACE_EVENT0("exo", "Buffer::Texture::WaitForQueryResult");
374
375 // We need to wait for the result to be available. Getting the result of
376 // the query implies waiting for it to become available. The actual result
377 // is unimportant and also not well defined.
378 unsigned result = 0;
379 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
380 gles2->GetQueryObjectuivEXT(query_id_, GL_QUERY_RESULT_EXT, &result);
381 }
382
383 callback.Run();
384}
385
revemanced21f82015-11-24 00:42:49386////////////////////////////////////////////////////////////////////////////////
387// Buffer, public:
388
dcheng31759da2016-04-21 01:26:31389Buffer::Buffer(std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer)
David Revemanf8fde1902017-10-20 23:01:04390 : Buffer(std::move(gpu_memory_buffer),
391 GL_TEXTURE_2D /* texture_target */,
392 GL_COMMANDS_COMPLETED_CHROMIUM /* query_type */,
393 true /* use_zero_copy */,
Zach Reizner8bcce6e2018-10-31 00:04:37394 false /* is_overlay_candidate */,
395 false /* y_invert */) {}
revemanc8623d5b2016-02-09 02:29:10396
dcheng31759da2016-04-21 01:26:31397Buffer::Buffer(std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer,
revemanc8623d5b2016-02-09 02:29:10398 unsigned texture_target,
399 unsigned query_type,
reveman244f9622016-03-04 21:33:33400 bool use_zero_copy,
Zach Reizner8bcce6e2018-10-31 00:04:37401 bool is_overlay_candidate,
402 bool y_invert)
dcheng27f7483f2015-12-29 22:26:56403 : gpu_memory_buffer_(std::move(gpu_memory_buffer)),
revemanced21f82015-11-24 00:42:49404 texture_target_(texture_target),
revemanc8623d5b2016-02-09 02:29:10405 query_type_(query_type),
406 use_zero_copy_(use_zero_copy),
David Revemanf8fde1902017-10-20 23:01:04407 is_overlay_candidate_(is_overlay_candidate),
Zach Reizner8bcce6e2018-10-31 00:04:37408 y_invert_(y_invert),
David Revemanf8fde1902017-10-20 23:01:04409 wait_for_release_delay_(
410 base::TimeDelta::FromMilliseconds(kWaitForReleaseDelayMs)) {}
revemanced21f82015-11-24 00:42:49411
412Buffer::~Buffer() {}
413
starazd40f0362017-01-04 00:46:13414bool Buffer::ProduceTransferableResource(
danakjc7afae52017-06-20 21:12:41415 LayerTreeFrameSinkHolder* layer_tree_frame_sink_holder,
reveman85b7a562016-03-17 23:27:32416 bool secure_output_only,
Fady Samuel4f7f0fb32017-07-28 15:33:37417 viz::TransferableResource* resource) {
[email protected]29befae2019-01-09 22:55:35418 TRACE_EVENT1("exo", "Buffer::ProduceTransferableResource", "buffer_id",
419 gfx_buffer());
jbauman45c06862016-06-23 19:35:02420 DCHECK(attach_count_);
revemanced21f82015-11-24 00:42:49421
revemanc8623d5b2016-02-09 02:29:10422 // If textures are lost, destroy them to ensure that we create new ones below.
423 if (contents_texture_ && contents_texture_->IsLost())
424 contents_texture_.reset();
425 if (texture_ && texture_->IsLost())
426 texture_.reset();
revemanced21f82015-11-24 00:42:49427
revemand0b75c32016-08-12 02:46:52428 ui::ContextFactory* context_factory =
Scott Violet13de50d2018-08-10 20:07:11429 WMHelper::GetInstance()->env()->context_factory();
revemanc8623d5b2016-02-09 02:29:10430 // Note: This can fail if GPU acceleration has been disabled.
Xu Xing32549162017-07-17 22:25:43431 scoped_refptr<viz::ContextProvider> context_provider =
revemand0b75c32016-08-12 02:46:52432 context_factory->SharedMainThreadContextProvider();
revemanc8623d5b2016-02-09 02:29:10433 if (!context_provider) {
434 DLOG(WARNING) << "Failed to acquire a context provider";
starazd40f0362017-01-04 00:46:13435 resource->id = 0;
436 resource->size = gfx::Size();
437 return false;
revemanced21f82015-11-24 00:42:49438 }
439
Peng Huang583c9dc62017-07-27 23:38:28440 resource->id = layer_tree_frame_sink_holder->AllocateResourceId();
Fady Samuel555c8d12017-07-07 23:14:09441 resource->format = viz::RGBA_8888;
starazd40f0362017-01-04 00:46:13442 resource->filter = GL_LINEAR;
443 resource->size = gpu_memory_buffer_->GetSize();
444
revemanc8623d5b2016-02-09 02:29:10445 // Create a new image texture for |gpu_memory_buffer_| with |texture_target_|
446 // if one doesn't already exist. The contents of this buffer are copied to
447 // |texture| using a call to CopyTexImage.
448 if (!contents_texture_) {
David Revemand0ab1fb82017-09-18 22:27:57449 contents_texture_ = std::make_unique<Texture>(
ricea85ec57952016-08-31 09:34:10450 context_factory, context_provider.get(), gpu_memory_buffer_.get(),
David Revemanf8fde1902017-10-20 23:01:04451 texture_target_, query_type_, wait_for_release_delay_);
revemanc8623d5b2016-02-09 02:29:10452 }
reveman2cd69782017-02-01 20:19:44453 Texture* contents_texture = contents_texture_.get();
revemanb195f41d2015-11-19 22:16:48454
David Reveman66cbc512017-05-31 21:21:20455 if (release_contents_callback_.IsCancelled())
[email protected]29befae2019-01-09 22:55:35456 TRACE_EVENT_ASYNC_BEGIN1("exo", kBufferInUse, gpu_memory_buffer_.get(),
457 "buffer_id", gfx_buffer());
David Reveman66cbc512017-05-31 21:21:20458
reveman2cd69782017-02-01 20:19:44459 // Cancel pending contents release callback.
460 release_contents_callback_.Reset(
461 base::Bind(&Buffer::ReleaseContents, base::Unretained(this)));
462
463 // Zero-copy means using the contents texture directly.
revemanc8623d5b2016-02-09 02:29:10464 if (use_zero_copy_) {
reveman2cd69782017-02-01 20:19:44465 // This binds the latest contents of this buffer to |contents_texture|.
466 gpu::SyncToken sync_token = contents_texture->BindTexImage();
467 resource->mailbox_holder = gpu::MailboxHolder(contents_texture->mailbox(),
468 sync_token, texture_target_);
starazd40f0362017-01-04 00:46:13469 resource->is_overlay_candidate = is_overlay_candidate_;
sohanfc3065e2018-07-02 22:36:04470 resource->format = viz::GetResourceFormat(gpu_memory_buffer_->GetFormat());
starazd40f0362017-01-04 00:46:13471
revemanc8623d5b2016-02-09 02:29:10472 // The contents texture will be released when no longer used by the
473 // compositor.
danakjc7afae52017-06-20 21:12:41474 layer_tree_frame_sink_holder->SetResourceReleaseCallback(
Peng Huang583c9dc62017-07-27 23:38:28475 resource->id,
tzik2bcf8e42018-07-31 11:22:15476 base::BindOnce(&Buffer::Texture::ReleaseTexImage,
477 base::Unretained(contents_texture),
478 base::Bind(&Buffer::ReleaseContentsTexture, AsWeakPtr(),
479 base::Passed(&contents_texture_),
480 release_contents_callback_.callback())));
starazd40f0362017-01-04 00:46:13481 return true;
revemanc8623d5b2016-02-09 02:29:10482 }
483
484 // Create a mailbox texture that we copy the buffer contents to.
revemand0b75c32016-08-12 02:46:52485 if (!texture_) {
486 texture_ =
David Revemand0ab1fb82017-09-18 22:27:57487 std::make_unique<Texture>(context_factory, context_provider.get());
revemand0b75c32016-08-12 02:46:52488 }
revemanc8623d5b2016-02-09 02:29:10489 Texture* texture = texture_.get();
490
reveman2cd69782017-02-01 20:19:44491 // Copy the contents of |contents_texture| to |texture| and produce a
492 // texture mailbox from the result in |texture|. The contents texture will
493 // be released when copy has completed.
reveman7ee8b4e2017-01-11 22:10:53494 gpu::SyncToken sync_token = contents_texture->CopyTexImage(
495 texture, base::Bind(&Buffer::ReleaseContentsTexture, AsWeakPtr(),
reveman2cd69782017-02-01 20:19:44496 base::Passed(&contents_texture_),
497 release_contents_callback_.callback()));
reveman7ee8b4e2017-01-11 22:10:53498 resource->mailbox_holder =
499 gpu::MailboxHolder(texture->mailbox(), sync_token, GL_TEXTURE_2D);
starazd40f0362017-01-04 00:46:13500 resource->is_overlay_candidate = false;
501
revemanc8623d5b2016-02-09 02:29:10502 // The mailbox texture will be released when no longer used by the
503 // compositor.
danakjc7afae52017-06-20 21:12:41504 layer_tree_frame_sink_holder->SetResourceReleaseCallback(
Peng Huang583c9dc62017-07-27 23:38:28505 resource->id,
tzik2bcf8e42018-07-31 11:22:15506 base::BindOnce(&Buffer::Texture::Release, base::Unretained(texture),
507 base::Bind(&Buffer::ReleaseTexture, AsWeakPtr(),
508 base::Passed(&texture_))));
starazd40f0362017-01-04 00:46:13509 return true;
revemanb195f41d2015-11-19 22:16:48510}
511
jbauman45c06862016-06-23 19:35:02512void Buffer::OnAttach() {
reveman2cd69782017-02-01 20:19:44513 DLOG_IF(WARNING, attach_count_)
jbauman45c06862016-06-23 19:35:02514 << "Reattaching a buffer that is already attached to another surface.";
[email protected]29befae2019-01-09 22:55:35515 TRACE_EVENT2("exo", "Buffer::OnAttach", "buffer_id", gfx_buffer(), "count",
516 attach_count_);
reveman2cd69782017-02-01 20:19:44517 ++attach_count_;
jbauman45c06862016-06-23 19:35:02518}
519
520void Buffer::OnDetach() {
521 DCHECK_GT(attach_count_, 0u);
[email protected]29befae2019-01-09 22:55:35522 TRACE_EVENT2("exo", "Buffer::OnAttach", "buffer_id", gfx_buffer(), "count",
523 attach_count_);
jbauman45c06862016-06-23 19:35:02524 --attach_count_;
reveman2cd69782017-02-01 20:19:44525
526 // Release buffer if no longer attached to a surface and content has been
527 // released.
528 if (!attach_count_ && release_contents_callback_.IsCancelled())
529 Release();
jbauman45c06862016-06-23 19:35:02530}
531
revemanb195f41d2015-11-19 22:16:48532gfx::Size Buffer::GetSize() const {
533 return gpu_memory_buffer_->GetSize();
534}
535
revemanca132dc2017-01-31 22:35:54536gfx::BufferFormat Buffer::GetFormat() const {
537 return gpu_memory_buffer_->GetFormat();
538}
539
revemanb195f41d2015-11-19 22:16:48540////////////////////////////////////////////////////////////////////////////////
541// Buffer, private:
542
revemanced21f82015-11-24 00:42:49543void Buffer::Release() {
[email protected]29befae2019-01-09 22:55:35544 TRACE_EVENT_ASYNC_END0("exo", kBufferInUse, gpu_memory_buffer_.get());
David Reveman66cbc512017-05-31 21:21:20545
revemanced21f82015-11-24 00:42:49546 // Run release callback to notify the client that buffer has been released.
547 if (!release_callback_.is_null())
548 release_callback_.Run();
549}
revemanb195f41d2015-11-19 22:16:48550
dcheng31759da2016-04-21 01:26:31551void Buffer::ReleaseTexture(std::unique_ptr<Texture> texture) {
revemanc8623d5b2016-02-09 02:29:10552 texture_ = std::move(texture);
553}
revemanced21f82015-11-24 00:42:49554
reveman2cd69782017-02-01 20:19:44555void Buffer::ReleaseContentsTexture(std::unique_ptr<Texture> texture,
556 const base::Closure& callback) {
revemanc8623d5b2016-02-09 02:29:10557 contents_texture_ = std::move(texture);
reveman2cd69782017-02-01 20:19:44558 callback.Run();
559}
560
561void Buffer::ReleaseContents() {
[email protected]29befae2019-01-09 22:55:35562 TRACE_EVENT1("exo", "Buffer::ReleaseContents", "buffer_id", gfx_buffer());
reveman2cd69782017-02-01 20:19:44563
564 // Cancel callback to indicate that buffer has been released.
565 release_contents_callback_.Cancel();
566
David Reveman66cbc512017-05-31 21:21:20567 if (attach_count_) {
[email protected]29befae2019-01-09 22:55:35568 TRACE_EVENT_ASYNC_STEP_INTO0("exo", kBufferInUse, gpu_memory_buffer_.get(),
David Reveman66cbc512017-05-31 21:21:20569 "attached");
570 } else {
571 // Release buffer if not attached to surface.
reveman2cd69782017-02-01 20:19:44572 Release();
David Reveman66cbc512017-05-31 21:21:20573 }
revemanb195f41d2015-11-19 22:16:48574}
575
576} // namespace exo