blob: 5b350b216c50ed518037a00806c863070979a735 [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
revemanae3b7c852016-02-25 01:50:0315#include "base/callback_helpers.h"
revemanb195f41d2015-11-19 22:16:4816#include "base/logging.h"
avibc5337b2015-12-25 23:16:3317#include "base/macros.h"
dcheng31759da2016-04-21 01:26:3118#include "base/memory/ptr_util.h"
revemanae3b7c852016-02-25 01:50:0319#include "base/memory/weak_ptr.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"
23#include "base/trace_event/trace_event_argument.h"
danakjc7afae52017-06-20 21:12:4124#include "components/exo/layer_tree_frame_sink_holder.h"
Xu Xing32549162017-07-17 22:25:4325#include "components/viz/common/gpu/context_provider.h"
Vladimir Levine348e2dc2017-08-22 15:56:4226#include "components/viz/common/resources/resource_format.h"
danakjf20f4502017-09-26 17:13:3127#include "components/viz/common/resources/single_release_callback.h"
revemanc8623d5b2016-02-09 02:29:1028#include "gpu/command_buffer/client/context_support.h"
revemanb195f41d2015-11-19 22:16:4829#include "gpu/command_buffer/client/gles2_interface.h"
danakj33d8fbb2017-11-23 17:50:3630#include "gpu/command_buffer/common/mailbox.h"
31#include "gpu/command_buffer/common/sync_token.h"
revemanb195f41d2015-11-19 22:16:4832#include "ui/aura/env.h"
33#include "ui/compositor/compositor.h"
34#include "ui/gfx/gpu_memory_buffer.h"
35
36namespace exo {
37namespace {
38
revemanae3b7c852016-02-25 01:50:0339// The amount of time before we wait for release queries using
40// GetQueryObjectuivEXT(GL_QUERY_RESULT_EXT).
41const int kWaitForReleaseDelayMs = 500;
42
revemanb195f41d2015-11-19 22:16:4843GLenum GLInternalFormat(gfx::BufferFormat format) {
44 const GLenum kGLInternalFormats[] = {
45 GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD, // ATC
46 GL_COMPRESSED_RGB_S3TC_DXT1_EXT, // ATCIA
47 GL_COMPRESSED_RGB_S3TC_DXT1_EXT, // DXT1
48 GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, // DXT5
49 GL_ETC1_RGB8_OES, // ETC1
50 GL_R8_EXT, // R_8
rijubrata.bhaumik65f143d2017-06-21 11:50:4251 GL_R16_EXT, // R_16
dongseong.hwang961b0e12016-10-04 10:15:3052 GL_RG8_EXT, // RG_88
reveman5954fa12016-05-18 21:56:3853 GL_RGB, // BGR_565
revemanb195f41d2015-11-19 22:16:4854 GL_RGBA, // RGBA_4444
55 GL_RGB, // RGBX_8888
56 GL_RGBA, // RGBA_8888
57 GL_RGB, // BGRX_8888
Daniele Castagna3a416dfb2017-10-26 19:23:4958 GL_RGB, // BGRX_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 };
65 static_assert(arraysize(kGLInternalFormats) ==
66 (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
danakj4957a222017-11-21 17:23:1085void CreateGLMailbox(gpu::gles2::GLES2Interface* gles2,
86 unsigned texture_id,
87 GLenum target,
88 gpu::Mailbox* mailbox) {
revemanc8623d5b2016-02-09 02:29:1089 gles2->GenMailboxCHROMIUM(mailbox->name);
Victor Miurafa65dc62017-12-06 02:15:5190 gles2->ProduceTextureDirectCHROMIUM(texture_id, mailbox->name);
revemanc8623d5b2016-02-09 02:29:1091}
92
revemanb195f41d2015-11-19 22:16:4893} // namespace
94
95////////////////////////////////////////////////////////////////////////////////
revemanced21f82015-11-24 00:42:4996// Buffer::Texture
revemanb195f41d2015-11-19 22:16:4897
revemanced21f82015-11-24 00:42:4998// Encapsulates the state and logic needed to bind a buffer to a GLES2 texture.
revemand0b75c32016-08-12 02:46:5299class Buffer::Texture : public ui::ContextFactoryObserver {
revemanced21f82015-11-24 00:42:49100 public:
revemand0b75c32016-08-12 02:46:52101 Texture(ui::ContextFactory* context_factory,
Xu Xing32549162017-07-17 22:25:43102 viz::ContextProvider* context_provider);
revemand0b75c32016-08-12 02:46:52103 Texture(ui::ContextFactory* context_factory,
Xu Xing32549162017-07-17 22:25:43104 viz::ContextProvider* context_provider,
revemanc8623d5b2016-02-09 02:29:10105 gfx::GpuMemoryBuffer* gpu_memory_buffer,
106 unsigned texture_target,
David Revemanf8fde1902017-10-20 23:01:04107 unsigned query_type,
108 base::TimeDelta wait_for_release_time);
revemand0b75c32016-08-12 02:46:52109 ~Texture() override;
110
111 // Overridden from ui::ContextFactoryObserver:
112 void OnLostResources() override;
revemanced21f82015-11-24 00:42:49113
114 // Returns true if GLES2 resources for texture have been lost.
115 bool IsLost();
116
revemanc8623d5b2016-02-09 02:29:10117 // Allow texture to be reused after |sync_token| has passed and runs
118 // |callback|.
119 void Release(const base::Closure& callback,
120 const gpu::SyncToken& sync_token,
121 bool is_lost);
122
123 // Binds the contents referenced by |image_id_| to the texture returned by
124 // mailbox(). Returns a sync token that can be used when accessing texture
revemanced21f82015-11-24 00:42:49125 // from a different context.
126 gpu::SyncToken BindTexImage();
127
revemanc8623d5b2016-02-09 02:29:10128 // Releases the contents referenced by |image_id_| after |sync_token| has
129 // passed and runs |callback| when completed.
130 void ReleaseTexImage(const base::Closure& callback,
131 const gpu::SyncToken& sync_token,
132 bool is_lost);
133
134 // Copy the contents of texture to |destination| and runs |callback| when
135 // completed. Returns a sync token that can be used when accessing texture
136 // from a different context.
137 gpu::SyncToken CopyTexImage(Texture* destination,
138 const base::Closure& callback);
revemanced21f82015-11-24 00:42:49139
140 // Returns the mailbox for this texture.
141 gpu::Mailbox mailbox() const { return mailbox_; }
142
143 private:
revemand0b75c32016-08-12 02:46:52144 void DestroyResources();
revemanae3b7c852016-02-25 01:50:03145 void ReleaseWhenQueryResultIsAvailable(const base::Closure& callback);
146 void Released();
147 void ScheduleWaitForRelease(base::TimeDelta delay);
148 void WaitForRelease();
149
David Reveman66cbc512017-05-31 21:21:20150 gfx::GpuMemoryBuffer* const gpu_memory_buffer_;
revemand0b75c32016-08-12 02:46:52151 ui::ContextFactory* context_factory_;
Xu Xing32549162017-07-17 22:25:43152 scoped_refptr<viz::ContextProvider> context_provider_;
revemanced21f82015-11-24 00:42:49153 const unsigned texture_target_;
revemanc8623d5b2016-02-09 02:29:10154 const unsigned query_type_;
155 const GLenum internalformat_;
reveman2d3815d2016-06-26 20:13:25156 unsigned image_id_ = 0;
157 unsigned query_id_ = 0;
158 unsigned texture_id_ = 0;
revemanced21f82015-11-24 00:42:49159 gpu::Mailbox mailbox_;
revemanae3b7c852016-02-25 01:50:03160 base::Closure release_callback_;
David Revemanf8fde1902017-10-20 23:01:04161 const base::TimeDelta wait_for_release_delay_;
revemanae3b7c852016-02-25 01:50:03162 base::TimeTicks wait_for_release_time_;
reveman2d3815d2016-06-26 20:13:25163 bool wait_for_release_pending_ = false;
revemanae3b7c852016-02-25 01:50:03164 base::WeakPtrFactory<Texture> weak_ptr_factory_;
revemanced21f82015-11-24 00:42:49165
166 DISALLOW_COPY_AND_ASSIGN(Texture);
167};
168
revemand0b75c32016-08-12 02:46:52169Buffer::Texture::Texture(ui::ContextFactory* context_factory,
Xu Xing32549162017-07-17 22:25:43170 viz::ContextProvider* context_provider)
David Reveman66cbc512017-05-31 21:21:20171 : gpu_memory_buffer_(nullptr),
172 context_factory_(context_factory),
revemand0b75c32016-08-12 02:46:52173 context_provider_(context_provider),
revemanc8623d5b2016-02-09 02:29:10174 texture_target_(GL_TEXTURE_2D),
175 query_type_(GL_COMMANDS_COMPLETED_CHROMIUM),
176 internalformat_(GL_RGBA),
revemanae3b7c852016-02-25 01:50:03177 weak_ptr_factory_(this) {
revemanced21f82015-11-24 00:42:49178 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
revemanc8623d5b2016-02-09 02:29:10179 texture_id_ = CreateGLTexture(gles2, texture_target_);
revemanb195f41d2015-11-19 22:16:48180 // Generate a crypto-secure random mailbox name.
danakj4957a222017-11-21 17:23:10181 CreateGLMailbox(gles2, texture_id_, texture_target_, &mailbox_);
revemand0b75c32016-08-12 02:46:52182 // Provides a notification when |context_provider_| is lost.
183 context_factory_->AddObserver(this);
revemanc8623d5b2016-02-09 02:29:10184}
185
revemand0b75c32016-08-12 02:46:52186Buffer::Texture::Texture(ui::ContextFactory* context_factory,
Xu Xing32549162017-07-17 22:25:43187 viz::ContextProvider* context_provider,
revemanc8623d5b2016-02-09 02:29:10188 gfx::GpuMemoryBuffer* gpu_memory_buffer,
189 unsigned texture_target,
David Revemanf8fde1902017-10-20 23:01:04190 unsigned query_type,
191 base::TimeDelta wait_for_release_delay)
David Reveman66cbc512017-05-31 21:21:20192 : gpu_memory_buffer_(gpu_memory_buffer),
193 context_factory_(context_factory),
revemand0b75c32016-08-12 02:46:52194 context_provider_(context_provider),
revemanc8623d5b2016-02-09 02:29:10195 texture_target_(texture_target),
196 query_type_(query_type),
197 internalformat_(GLInternalFormat(gpu_memory_buffer->GetFormat())),
David Revemanf8fde1902017-10-20 23:01:04198 wait_for_release_delay_(wait_for_release_delay),
revemanae3b7c852016-02-25 01:50:03199 weak_ptr_factory_(this) {
revemanc8623d5b2016-02-09 02:29:10200 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
201 gfx::Size size = gpu_memory_buffer->GetSize();
202 image_id_ =
203 gles2->CreateImageCHROMIUM(gpu_memory_buffer->AsClientBuffer(),
204 size.width(), size.height(), internalformat_);
dcastagna2db83c7ef2016-06-13 23:33:22205 DLOG_IF(WARNING, !image_id_) << "Failed to create GLImage";
206
revemanc8623d5b2016-02-09 02:29:10207 gles2->GenQueriesEXT(1, &query_id_);
208 texture_id_ = CreateGLTexture(gles2, texture_target_);
revemand0b75c32016-08-12 02:46:52209 // Provides a notification when |context_provider_| is lost.
210 context_factory_->AddObserver(this);
revemanb195f41d2015-11-19 22:16:48211}
212
revemanced21f82015-11-24 00:42:49213Buffer::Texture::~Texture() {
revemand0b75c32016-08-12 02:46:52214 DestroyResources();
Alex Zhang3f8482b2017-08-01 15:16:24215 if (context_provider_)
216 context_factory_->RemoveObserver(this);
revemand0b75c32016-08-12 02:46:52217}
218
219void Buffer::Texture::OnLostResources() {
220 DestroyResources();
Alex Zhang3f8482b2017-08-01 15:16:24221 context_factory_->RemoveObserver(this);
revemand0b75c32016-08-12 02:46:52222 context_provider_ = nullptr;
Alex Zhang3f8482b2017-08-01 15:16:24223 context_factory_ = nullptr;
revemanb195f41d2015-11-19 22:16:48224}
225
revemanced21f82015-11-24 00:42:49226bool Buffer::Texture::IsLost() {
revemand0b75c32016-08-12 02:46:52227 if (context_provider_) {
228 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
229 return gles2->GetGraphicsResetStatusKHR() != GL_NO_ERROR;
230 }
231 return true;
revemanced21f82015-11-24 00:42:49232}
revemanb195f41d2015-11-19 22:16:48233
revemanc8623d5b2016-02-09 02:29:10234void Buffer::Texture::Release(const base::Closure& callback,
235 const gpu::SyncToken& sync_token,
236 bool is_lost) {
revemand0b75c32016-08-12 02:46:52237 if (context_provider_) {
238 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
239 if (sync_token.HasData())
240 gles2->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
241 }
revemanc8623d5b2016-02-09 02:29:10242
243 // Run callback as texture can be reused immediately after waiting for sync
244 // token.
245 callback.Run();
246}
247
revemanced21f82015-11-24 00:42:49248gpu::SyncToken Buffer::Texture::BindTexImage() {
revemanb195f41d2015-11-19 22:16:48249 gpu::SyncToken sync_token;
revemand0b75c32016-08-12 02:46:52250 if (context_provider_) {
251 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
252 gles2->ActiveTexture(GL_TEXTURE0);
253 gles2->BindTexture(texture_target_, texture_id_);
254 DCHECK_NE(image_id_, 0u);
255 gles2->BindTexImage2DCHROMIUM(texture_target_, image_id_);
256 // Generate a crypto-secure random mailbox name if not already done.
257 if (mailbox_.IsZero())
danakj4957a222017-11-21 17:23:10258 CreateGLMailbox(gles2, texture_id_, texture_target_, &mailbox_);
revemand0b75c32016-08-12 02:46:52259 // Create and return a sync token that can be used to ensure that the
260 // BindTexImage2DCHROMIUM call is processed before issuing any commands
261 // that will read from the texture on a different context.
Sunny Sachanandanic94b8de2017-12-16 03:30:30262 gles2->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData());
David Reveman66cbc512017-05-31 21:21:20263 TRACE_EVENT_ASYNC_STEP_INTO0("exo", "BufferInUse", gpu_memory_buffer_,
264 "bound");
revemand0b75c32016-08-12 02:46:52265 }
revemanced21f82015-11-24 00:42:49266 return sync_token;
267}
268
revemanc8623d5b2016-02-09 02:29:10269void Buffer::Texture::ReleaseTexImage(const base::Closure& callback,
270 const gpu::SyncToken& sync_token,
271 bool is_lost) {
revemand0b75c32016-08-12 02:46:52272 if (context_provider_) {
273 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
274 if (sync_token.HasData())
275 gles2->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
276 gles2->ActiveTexture(GL_TEXTURE0);
277 gles2->BindTexture(texture_target_, texture_id_);
278 DCHECK_NE(query_id_, 0u);
279 gles2->BeginQueryEXT(query_type_, query_id_);
280 gles2->ReleaseTexImage2DCHROMIUM(texture_target_, image_id_);
281 gles2->EndQueryEXT(query_type_);
282 // Run callback when query result is available and ReleaseTexImage has been
283 // handled if sync token has data and buffer has been used. If buffer was
284 // never used then run the callback immediately.
285 if (sync_token.HasData()) {
286 ReleaseWhenQueryResultIsAvailable(callback);
287 return;
288 }
revemanc8623d5b2016-02-09 02:29:10289 }
revemand0b75c32016-08-12 02:46:52290 callback.Run();
revemanc8623d5b2016-02-09 02:29:10291}
292
293gpu::SyncToken Buffer::Texture::CopyTexImage(Texture* destination,
294 const base::Closure& callback) {
revemanc8623d5b2016-02-09 02:29:10295 gpu::SyncToken sync_token;
revemand0b75c32016-08-12 02:46:52296 if (context_provider_) {
297 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
298 gles2->ActiveTexture(GL_TEXTURE0);
299 gles2->BindTexture(texture_target_, texture_id_);
300 DCHECK_NE(image_id_, 0u);
301 gles2->BindTexImage2DCHROMIUM(texture_target_, image_id_);
qiankun.miao728aa862017-01-22 15:03:03302 gles2->CopyTextureCHROMIUM(texture_id_, 0, destination->texture_target_,
303 destination->texture_id_, 0, internalformat_,
304 GL_UNSIGNED_BYTE, false, false, false);
revemand0b75c32016-08-12 02:46:52305 DCHECK_NE(query_id_, 0u);
306 gles2->BeginQueryEXT(query_type_, query_id_);
307 gles2->ReleaseTexImage2DCHROMIUM(texture_target_, image_id_);
308 gles2->EndQueryEXT(query_type_);
309 // Run callback when query result is available and ReleaseTexImage has been
310 // handled.
311 ReleaseWhenQueryResultIsAvailable(callback);
312 // Create and return a sync token that can be used to ensure that the
313 // CopyTextureCHROMIUM call is processed before issuing any commands
314 // that will read from the target texture on a different context.
Sunny Sachanandanic94b8de2017-12-16 03:30:30315 gles2->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData());
revemand0b75c32016-08-12 02:46:52316 }
revemanc8623d5b2016-02-09 02:29:10317 return sync_token;
revemanced21f82015-11-24 00:42:49318}
319
revemand0b75c32016-08-12 02:46:52320void Buffer::Texture::DestroyResources() {
321 if (context_provider_) {
322 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
323 gles2->DeleteTextures(1, &texture_id_);
324 if (query_id_)
325 gles2->DeleteQueriesEXT(1, &query_id_);
326 if (image_id_)
327 gles2->DestroyImageCHROMIUM(image_id_);
328 }
329}
330
revemanae3b7c852016-02-25 01:50:03331void Buffer::Texture::ReleaseWhenQueryResultIsAvailable(
332 const base::Closure& callback) {
revemand0b75c32016-08-12 02:46:52333 DCHECK(context_provider_);
revemanae3b7c852016-02-25 01:50:03334 DCHECK(release_callback_.is_null());
335 release_callback_ = callback;
David Revemanf8fde1902017-10-20 23:01:04336 wait_for_release_time_ = base::TimeTicks::Now() + wait_for_release_delay_;
337 ScheduleWaitForRelease(wait_for_release_delay_);
David Reveman66cbc512017-05-31 21:21:20338 TRACE_EVENT_ASYNC_STEP_INTO0("exo", "BufferInUse", gpu_memory_buffer_,
339 "pending_query");
revemanae3b7c852016-02-25 01:50:03340 context_provider_->ContextSupport()->SignalQuery(
341 query_id_,
342 base::Bind(&Buffer::Texture::Released, weak_ptr_factory_.GetWeakPtr()));
343}
344
345void Buffer::Texture::Released() {
346 if (!release_callback_.is_null())
347 base::ResetAndReturn(&release_callback_).Run();
348}
349
350void Buffer::Texture::ScheduleWaitForRelease(base::TimeDelta delay) {
351 if (wait_for_release_pending_)
352 return;
353
354 wait_for_release_pending_ = true;
355 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
356 FROM_HERE, base::Bind(&Buffer::Texture::WaitForRelease,
357 weak_ptr_factory_.GetWeakPtr()),
358 delay);
359}
360
361void Buffer::Texture::WaitForRelease() {
362 DCHECK(wait_for_release_pending_);
363 wait_for_release_pending_ = false;
364
365 if (release_callback_.is_null())
366 return;
367
368 base::TimeTicks current_time = base::TimeTicks::Now();
369 if (current_time < wait_for_release_time_) {
370 ScheduleWaitForRelease(wait_for_release_time_ - current_time);
371 return;
372 }
373
374 base::Closure callback = base::ResetAndReturn(&release_callback_);
375
revemand0b75c32016-08-12 02:46:52376 if (context_provider_) {
revemanae3b7c852016-02-25 01:50:03377 TRACE_EVENT0("exo", "Buffer::Texture::WaitForQueryResult");
378
379 // We need to wait for the result to be available. Getting the result of
380 // the query implies waiting for it to become available. The actual result
381 // is unimportant and also not well defined.
382 unsigned result = 0;
383 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
384 gles2->GetQueryObjectuivEXT(query_id_, GL_QUERY_RESULT_EXT, &result);
385 }
386
387 callback.Run();
388}
389
revemanced21f82015-11-24 00:42:49390////////////////////////////////////////////////////////////////////////////////
391// Buffer, public:
392
dcheng31759da2016-04-21 01:26:31393Buffer::Buffer(std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer)
David Revemanf8fde1902017-10-20 23:01:04394 : Buffer(std::move(gpu_memory_buffer),
395 GL_TEXTURE_2D /* texture_target */,
396 GL_COMMANDS_COMPLETED_CHROMIUM /* query_type */,
397 true /* use_zero_copy */,
398 false /* is_overlay_candidate */) {}
revemanc8623d5b2016-02-09 02:29:10399
dcheng31759da2016-04-21 01:26:31400Buffer::Buffer(std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer,
revemanc8623d5b2016-02-09 02:29:10401 unsigned texture_target,
402 unsigned query_type,
reveman244f9622016-03-04 21:33:33403 bool use_zero_copy,
404 bool is_overlay_candidate)
dcheng27f7483f2015-12-29 22:26:56405 : gpu_memory_buffer_(std::move(gpu_memory_buffer)),
revemanced21f82015-11-24 00:42:49406 texture_target_(texture_target),
revemanc8623d5b2016-02-09 02:29:10407 query_type_(query_type),
408 use_zero_copy_(use_zero_copy),
David Revemanf8fde1902017-10-20 23:01:04409 is_overlay_candidate_(is_overlay_candidate),
410 wait_for_release_delay_(
411 base::TimeDelta::FromMilliseconds(kWaitForReleaseDelayMs)) {}
revemanced21f82015-11-24 00:42:49412
413Buffer::~Buffer() {}
414
starazd40f0362017-01-04 00:46:13415bool Buffer::ProduceTransferableResource(
danakjc7afae52017-06-20 21:12:41416 LayerTreeFrameSinkHolder* layer_tree_frame_sink_holder,
reveman85b7a562016-03-17 23:27:32417 bool secure_output_only,
Fady Samuel4f7f0fb32017-07-28 15:33:37418 viz::TransferableResource* resource) {
David Reveman66cbc512017-05-31 21:21:20419 TRACE_EVENT0("exo", "Buffer::ProduceTransferableResource");
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 =
429 aura::Env::GetInstance()->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())
456 TRACE_EVENT_ASYNC_BEGIN0("exo", "BufferInUse", gpu_memory_buffer_.get());
457
reveman2cd69782017-02-01 20:19:44458 // Cancel pending contents release callback.
459 release_contents_callback_.Reset(
460 base::Bind(&Buffer::ReleaseContents, base::Unretained(this)));
461
462 // Zero-copy means using the contents texture directly.
revemanc8623d5b2016-02-09 02:29:10463 if (use_zero_copy_) {
reveman2cd69782017-02-01 20:19:44464 // This binds the latest contents of this buffer to |contents_texture|.
465 gpu::SyncToken sync_token = contents_texture->BindTexImage();
466 resource->mailbox_holder = gpu::MailboxHolder(contents_texture->mailbox(),
467 sync_token, texture_target_);
starazd40f0362017-01-04 00:46:13468 resource->is_overlay_candidate = is_overlay_candidate_;
dcastagna84093542017-03-14 02:11:13469 resource->buffer_format = gpu_memory_buffer_->GetFormat();
starazd40f0362017-01-04 00:46:13470
revemanc8623d5b2016-02-09 02:29:10471 // The contents texture will be released when no longer used by the
472 // compositor.
danakjc7afae52017-06-20 21:12:41473 layer_tree_frame_sink_holder->SetResourceReleaseCallback(
Peng Huang583c9dc62017-07-27 23:38:28474 resource->id,
reveman2cd69782017-02-01 20:19:44475 base::Bind(&Buffer::Texture::ReleaseTexImage,
476 base::Unretained(contents_texture),
revemanc8623d5b2016-02-09 02:29:10477 base::Bind(&Buffer::ReleaseContentsTexture, AsWeakPtr(),
reveman2cd69782017-02-01 20:19:44478 base::Passed(&contents_texture_),
479 release_contents_callback_.callback())));
starazd40f0362017-01-04 00:46:13480 return true;
revemanc8623d5b2016-02-09 02:29:10481 }
482
483 // Create a mailbox texture that we copy the buffer contents to.
revemand0b75c32016-08-12 02:46:52484 if (!texture_) {
485 texture_ =
David Revemand0ab1fb82017-09-18 22:27:57486 std::make_unique<Texture>(context_factory, context_provider.get());
revemand0b75c32016-08-12 02:46:52487 }
revemanc8623d5b2016-02-09 02:29:10488 Texture* texture = texture_.get();
489
reveman2cd69782017-02-01 20:19:44490 // Copy the contents of |contents_texture| to |texture| and produce a
491 // texture mailbox from the result in |texture|. The contents texture will
492 // be released when copy has completed.
reveman7ee8b4e2017-01-11 22:10:53493 gpu::SyncToken sync_token = contents_texture->CopyTexImage(
494 texture, base::Bind(&Buffer::ReleaseContentsTexture, AsWeakPtr(),
reveman2cd69782017-02-01 20:19:44495 base::Passed(&contents_texture_),
496 release_contents_callback_.callback()));
reveman7ee8b4e2017-01-11 22:10:53497 resource->mailbox_holder =
498 gpu::MailboxHolder(texture->mailbox(), sync_token, GL_TEXTURE_2D);
starazd40f0362017-01-04 00:46:13499 resource->is_overlay_candidate = false;
500
revemanc8623d5b2016-02-09 02:29:10501 // The mailbox texture will be released when no longer used by the
502 // compositor.
danakjc7afae52017-06-20 21:12:41503 layer_tree_frame_sink_holder->SetResourceReleaseCallback(
Peng Huang583c9dc62017-07-27 23:38:28504 resource->id,
revemanc8623d5b2016-02-09 02:29:10505 base::Bind(&Buffer::Texture::Release, base::Unretained(texture),
506 base::Bind(&Buffer::ReleaseTexture, AsWeakPtr(),
507 base::Passed(&texture_))));
starazd40f0362017-01-04 00:46:13508 return true;
revemanb195f41d2015-11-19 22:16:48509}
510
jbauman45c06862016-06-23 19:35:02511void Buffer::OnAttach() {
reveman2cd69782017-02-01 20:19:44512 DLOG_IF(WARNING, attach_count_)
jbauman45c06862016-06-23 19:35:02513 << "Reattaching a buffer that is already attached to another surface.";
reveman2cd69782017-02-01 20:19:44514 ++attach_count_;
jbauman45c06862016-06-23 19:35:02515}
516
517void Buffer::OnDetach() {
518 DCHECK_GT(attach_count_, 0u);
519 --attach_count_;
reveman2cd69782017-02-01 20:19:44520
521 // Release buffer if no longer attached to a surface and content has been
522 // released.
523 if (!attach_count_ && release_contents_callback_.IsCancelled())
524 Release();
jbauman45c06862016-06-23 19:35:02525}
526
revemanb195f41d2015-11-19 22:16:48527gfx::Size Buffer::GetSize() const {
528 return gpu_memory_buffer_->GetSize();
529}
530
revemanca132dc2017-01-31 22:35:54531gfx::BufferFormat Buffer::GetFormat() const {
532 return gpu_memory_buffer_->GetFormat();
533}
534
dcheng31759da2016-04-21 01:26:31535std::unique_ptr<base::trace_event::TracedValue> Buffer::AsTracedValue() const {
536 std::unique_ptr<base::trace_event::TracedValue> value(
primianocb1afb32016-02-29 20:46:05537 new base::trace_event::TracedValue());
revemanced21f82015-11-24 00:42:49538 gfx::Size size = gpu_memory_buffer_->GetSize();
539 value->SetInteger("width", size.width());
540 value->SetInteger("height", size.height());
revemanb195f41d2015-11-19 22:16:48541 value->SetInteger("format",
542 static_cast<int>(gpu_memory_buffer_->GetFormat()));
543 return value;
544}
545
546////////////////////////////////////////////////////////////////////////////////
547// Buffer, private:
548
revemanced21f82015-11-24 00:42:49549void Buffer::Release() {
David Reveman66cbc512017-05-31 21:21:20550 TRACE_EVENT_ASYNC_END0("exo", "BufferInUse", gpu_memory_buffer_.get());
551
revemanced21f82015-11-24 00:42:49552 // Run release callback to notify the client that buffer has been released.
553 if (!release_callback_.is_null())
554 release_callback_.Run();
555}
revemanb195f41d2015-11-19 22:16:48556
dcheng31759da2016-04-21 01:26:31557void Buffer::ReleaseTexture(std::unique_ptr<Texture> texture) {
revemanc8623d5b2016-02-09 02:29:10558 texture_ = std::move(texture);
559}
revemanced21f82015-11-24 00:42:49560
reveman2cd69782017-02-01 20:19:44561void Buffer::ReleaseContentsTexture(std::unique_ptr<Texture> texture,
562 const base::Closure& callback) {
revemanc8623d5b2016-02-09 02:29:10563 contents_texture_ = std::move(texture);
reveman2cd69782017-02-01 20:19:44564 callback.Run();
565}
566
567void Buffer::ReleaseContents() {
568 TRACE_EVENT0("exo", "Buffer::ReleaseContents");
569
570 // Cancel callback to indicate that buffer has been released.
571 release_contents_callback_.Cancel();
572
David Reveman66cbc512017-05-31 21:21:20573 if (attach_count_) {
574 TRACE_EVENT_ASYNC_STEP_INTO0("exo", "BufferInUse", gpu_memory_buffer_.get(),
575 "attached");
576 } else {
577 // Release buffer if not attached to surface.
reveman2cd69782017-02-01 20:19:44578 Release();
David Reveman66cbc512017-05-31 21:21:20579 }
revemanb195f41d2015-11-19 22:16:48580}
581
582} // namespace exo