blob: c3bbd143ed9e81c25a20ad932009b2fc4e8f6425 [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"
24#include "cc/output/context_provider.h"
25#include "cc/resources/single_release_callback.h"
26#include "cc/resources/texture_mailbox.h"
revemanc8623d5b2016-02-09 02:29:1027#include "gpu/command_buffer/client/context_support.h"
revemanb195f41d2015-11-19 22:16:4828#include "gpu/command_buffer/client/gles2_interface.h"
29#include "ui/aura/env.h"
30#include "ui/compositor/compositor.h"
31#include "ui/gfx/gpu_memory_buffer.h"
32
33namespace exo {
34namespace {
35
revemanae3b7c852016-02-25 01:50:0336// The amount of time before we wait for release queries using
37// GetQueryObjectuivEXT(GL_QUERY_RESULT_EXT).
38const int kWaitForReleaseDelayMs = 500;
39
revemanb195f41d2015-11-19 22:16:4840GLenum GLInternalFormat(gfx::BufferFormat format) {
41 const GLenum kGLInternalFormats[] = {
42 GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD, // ATC
43 GL_COMPRESSED_RGB_S3TC_DXT1_EXT, // ATCIA
44 GL_COMPRESSED_RGB_S3TC_DXT1_EXT, // DXT1
45 GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, // DXT5
46 GL_ETC1_RGB8_OES, // ETC1
47 GL_R8_EXT, // R_8
reveman5954fa12016-05-18 21:56:3848 GL_RGB, // BGR_565
revemanb195f41d2015-11-19 22:16:4849 GL_RGBA, // RGBA_4444
50 GL_RGB, // RGBX_8888
51 GL_RGBA, // RGBA_8888
52 GL_RGB, // BGRX_8888
53 GL_BGRA_EXT, // BGRA_8888
54 GL_RGB_YUV_420_CHROMIUM, // YUV_420
55 GL_INVALID_ENUM, // YUV_420_BIPLANAR
56 GL_RGB_YCBCR_422_CHROMIUM, // UYVY_422
57 };
58 static_assert(arraysize(kGLInternalFormats) ==
59 (static_cast<int>(gfx::BufferFormat::LAST) + 1),
60 "BufferFormat::LAST must be last value of kGLInternalFormats");
61
62 DCHECK(format <= gfx::BufferFormat::LAST);
63 return kGLInternalFormats[static_cast<int>(format)];
64}
65
revemanc8623d5b2016-02-09 02:29:1066unsigned CreateGLTexture(gpu::gles2::GLES2Interface* gles2, GLenum target) {
67 unsigned texture_id = 0;
68 gles2->GenTextures(1, &texture_id);
69 gles2->ActiveTexture(GL_TEXTURE0);
70 gles2->BindTexture(target, texture_id);
71 gles2->TexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
72 gles2->TexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
73 gles2->TexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
74 gles2->TexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
75 return texture_id;
76}
77
78void CreateGLTextureMailbox(gpu::gles2::GLES2Interface* gles2,
79 unsigned texture_id,
80 GLenum target,
81 gpu::Mailbox* mailbox) {
82 gles2->ActiveTexture(GL_TEXTURE0);
83 gles2->BindTexture(target, texture_id);
84 gles2->GenMailboxCHROMIUM(mailbox->name);
85 gles2->ProduceTextureCHROMIUM(target, mailbox->name);
86}
87
revemanb195f41d2015-11-19 22:16:4888} // namespace
89
90////////////////////////////////////////////////////////////////////////////////
revemanced21f862015-11-24 00:42:4991// Buffer::Texture
revemanb195f41d2015-11-19 22:16:4892
revemanced21f862015-11-24 00:42:4993// Encapsulates the state and logic needed to bind a buffer to a GLES2 texture.
94class Buffer::Texture {
95 public:
revemanc8623d5b2016-02-09 02:29:1096 explicit Texture(cc::ContextProvider* context_provider);
97 Texture(cc::ContextProvider* context_provider,
98 gfx::GpuMemoryBuffer* gpu_memory_buffer,
99 unsigned texture_target,
100 unsigned query_type);
revemanced21f862015-11-24 00:42:49101 ~Texture();
102
103 // Returns true if GLES2 resources for texture have been lost.
104 bool IsLost();
105
revemanc8623d5b2016-02-09 02:29:10106 // Allow texture to be reused after |sync_token| has passed and runs
107 // |callback|.
108 void Release(const base::Closure& callback,
109 const gpu::SyncToken& sync_token,
110 bool is_lost);
111
112 // Binds the contents referenced by |image_id_| to the texture returned by
113 // mailbox(). Returns a sync token that can be used when accessing texture
revemanced21f862015-11-24 00:42:49114 // from a different context.
115 gpu::SyncToken BindTexImage();
116
revemanc8623d5b2016-02-09 02:29:10117 // Releases the contents referenced by |image_id_| after |sync_token| has
118 // passed and runs |callback| when completed.
119 void ReleaseTexImage(const base::Closure& callback,
120 const gpu::SyncToken& sync_token,
121 bool is_lost);
122
123 // Copy the contents of texture to |destination| and runs |callback| when
124 // completed. Returns a sync token that can be used when accessing texture
125 // from a different context.
126 gpu::SyncToken CopyTexImage(Texture* destination,
127 const base::Closure& callback);
revemanced21f862015-11-24 00:42:49128
129 // Returns the mailbox for this texture.
130 gpu::Mailbox mailbox() const { return mailbox_; }
131
132 private:
revemanae3b7c852016-02-25 01:50:03133 void ReleaseWhenQueryResultIsAvailable(const base::Closure& callback);
134 void Released();
135 void ScheduleWaitForRelease(base::TimeDelta delay);
136 void WaitForRelease();
137
revemanced21f862015-11-24 00:42:49138 scoped_refptr<cc::ContextProvider> context_provider_;
139 const unsigned texture_target_;
revemanc8623d5b2016-02-09 02:29:10140 const unsigned query_type_;
141 const GLenum internalformat_;
revemanced21f862015-11-24 00:42:49142 unsigned image_id_;
revemanc8623d5b2016-02-09 02:29:10143 unsigned query_id_;
revemanced21f862015-11-24 00:42:49144 unsigned texture_id_;
145 gpu::Mailbox mailbox_;
revemanae3b7c852016-02-25 01:50:03146 base::Closure release_callback_;
147 base::TimeTicks wait_for_release_time_;
148 bool wait_for_release_pending_;
149 base::WeakPtrFactory<Texture> weak_ptr_factory_;
revemanced21f862015-11-24 00:42:49150
151 DISALLOW_COPY_AND_ASSIGN(Texture);
152};
153
revemanc8623d5b2016-02-09 02:29:10154Buffer::Texture::Texture(cc::ContextProvider* context_provider)
revemanced21f862015-11-24 00:42:49155 : context_provider_(context_provider),
revemanc8623d5b2016-02-09 02:29:10156 texture_target_(GL_TEXTURE_2D),
157 query_type_(GL_COMMANDS_COMPLETED_CHROMIUM),
158 internalformat_(GL_RGBA),
revemanced21f862015-11-24 00:42:49159 image_id_(0),
revemanc8623d5b2016-02-09 02:29:10160 query_id_(0),
revemanae3b7c852016-02-25 01:50:03161 texture_id_(0),
162 wait_for_release_pending_(false),
163 weak_ptr_factory_(this) {
revemanced21f862015-11-24 00:42:49164 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
revemanc8623d5b2016-02-09 02:29:10165 texture_id_ = CreateGLTexture(gles2, texture_target_);
revemanb195f41d2015-11-19 22:16:48166 // Generate a crypto-secure random mailbox name.
revemanc8623d5b2016-02-09 02:29:10167 CreateGLTextureMailbox(gles2, texture_id_, texture_target_, &mailbox_);
168}
169
170Buffer::Texture::Texture(cc::ContextProvider* context_provider,
171 gfx::GpuMemoryBuffer* gpu_memory_buffer,
172 unsigned texture_target,
173 unsigned query_type)
174 : context_provider_(context_provider),
175 texture_target_(texture_target),
176 query_type_(query_type),
177 internalformat_(GLInternalFormat(gpu_memory_buffer->GetFormat())),
178 image_id_(0),
179 query_id_(0),
revemanae3b7c852016-02-25 01:50:03180 texture_id_(0),
181 wait_for_release_pending_(false),
182 weak_ptr_factory_(this) {
revemanc8623d5b2016-02-09 02:29:10183 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
184 gfx::Size size = gpu_memory_buffer->GetSize();
185 image_id_ =
186 gles2->CreateImageCHROMIUM(gpu_memory_buffer->AsClientBuffer(),
187 size.width(), size.height(), internalformat_);
188 gles2->GenQueriesEXT(1, &query_id_);
189 texture_id_ = CreateGLTexture(gles2, texture_target_);
revemanb195f41d2015-11-19 22:16:48190}
191
revemanced21f862015-11-24 00:42:49192Buffer::Texture::~Texture() {
193 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
revemanced21f862015-11-24 00:42:49194 gles2->DeleteTextures(1, &texture_id_);
revemanc8623d5b2016-02-09 02:29:10195 if (query_id_)
196 gles2->DeleteQueriesEXT(1, &query_id_);
197 if (image_id_)
198 gles2->DestroyImageCHROMIUM(image_id_);
revemanb195f41d2015-11-19 22:16:48199}
200
revemanced21f862015-11-24 00:42:49201bool Buffer::Texture::IsLost() {
202 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
203 return gles2->GetGraphicsResetStatusKHR() != GL_NO_ERROR;
204}
revemanb195f41d2015-11-19 22:16:48205
revemanc8623d5b2016-02-09 02:29:10206void Buffer::Texture::Release(const base::Closure& callback,
207 const gpu::SyncToken& sync_token,
208 bool is_lost) {
209 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
210 if (sync_token.HasData())
211 gles2->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
212
213 // Run callback as texture can be reused immediately after waiting for sync
214 // token.
215 callback.Run();
216}
217
revemanced21f862015-11-24 00:42:49218gpu::SyncToken Buffer::Texture::BindTexImage() {
219 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
revemanb195f41d2015-11-19 22:16:48220 gles2->ActiveTexture(GL_TEXTURE0);
revemanced21f862015-11-24 00:42:49221 gles2->BindTexture(texture_target_, texture_id_);
revemanc8623d5b2016-02-09 02:29:10222 DCHECK_NE(image_id_, 0u);
revemanced21f862015-11-24 00:42:49223 gles2->BindTexImage2DCHROMIUM(texture_target_, image_id_);
revemanc8623d5b2016-02-09 02:29:10224 // Generate a crypto-secure random mailbox name if not already done.
225 if (mailbox_.IsZero())
226 CreateGLTextureMailbox(gles2, texture_id_, texture_target_, &mailbox_);
revemanced21f862015-11-24 00:42:49227 // Create and return a sync token that can be used to ensure that the
228 // BindTexImage2DCHROMIUM call is processed before issuing any commands
229 // that will read from the texture on a different context.
avibc5337b2015-12-25 23:16:33230 uint64_t fence_sync = gles2->InsertFenceSyncCHROMIUM();
revemanced21f862015-11-24 00:42:49231 gles2->OrderingBarrierCHROMIUM();
revemanb195f41d2015-11-19 22:16:48232 gpu::SyncToken sync_token;
233 gles2->GenUnverifiedSyncTokenCHROMIUM(fence_sync, sync_token.GetData());
revemanced21f862015-11-24 00:42:49234 return sync_token;
235}
236
revemanc8623d5b2016-02-09 02:29:10237void Buffer::Texture::ReleaseTexImage(const base::Closure& callback,
238 const gpu::SyncToken& sync_token,
239 bool is_lost) {
revemanced21f862015-11-24 00:42:49240 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
241 if (sync_token.HasData())
242 gles2->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
243 gles2->ActiveTexture(GL_TEXTURE0);
244 gles2->BindTexture(texture_target_, texture_id_);
revemanc8623d5b2016-02-09 02:29:10245 DCHECK_NE(query_id_, 0u);
246 gles2->BeginQueryEXT(query_type_, query_id_);
revemanced21f862015-11-24 00:42:49247 gles2->ReleaseTexImage2DCHROMIUM(texture_target_, image_id_);
revemanc8623d5b2016-02-09 02:29:10248 gles2->EndQueryEXT(query_type_);
revemanae3b7c852016-02-25 01:50:03249 // Run callback when query result is available and ReleaseTexImage has been
250 // handled if sync token has data and buffer has been used. If buffer was
251 // never used then run the callback immediately.
revemanc8623d5b2016-02-09 02:29:10252 if (sync_token.HasData()) {
revemanae3b7c852016-02-25 01:50:03253 ReleaseWhenQueryResultIsAvailable(callback);
revemanc8623d5b2016-02-09 02:29:10254 } else {
255 callback.Run();
256 }
257}
258
259gpu::SyncToken Buffer::Texture::CopyTexImage(Texture* destination,
260 const base::Closure& callback) {
261 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
262 gles2->ActiveTexture(GL_TEXTURE0);
263 gles2->BindTexture(texture_target_, texture_id_);
264 DCHECK_NE(image_id_, 0u);
265 gles2->BindTexImage2DCHROMIUM(texture_target_, image_id_);
266 gles2->CopyTextureCHROMIUM(texture_id_, destination->texture_id_,
267 internalformat_, GL_UNSIGNED_BYTE, false, false,
268 false);
269 DCHECK_NE(query_id_, 0u);
270 gles2->BeginQueryEXT(query_type_, query_id_);
271 gles2->ReleaseTexImage2DCHROMIUM(texture_target_, image_id_);
272 gles2->EndQueryEXT(query_type_);
revemanae3b7c852016-02-25 01:50:03273 // Run callback when query result is available and ReleaseTexImage has been
274 // handled.
275 ReleaseWhenQueryResultIsAvailable(callback);
revemanc8623d5b2016-02-09 02:29:10276 // Create and return a sync token that can be used to ensure that the
277 // CopyTextureCHROMIUM call is processed before issuing any commands
278 // that will read from the target texture on a different context.
279 uint64_t fence_sync = gles2->InsertFenceSyncCHROMIUM();
280 gles2->OrderingBarrierCHROMIUM();
281 gpu::SyncToken sync_token;
282 gles2->GenUnverifiedSyncTokenCHROMIUM(fence_sync, sync_token.GetData());
283 return sync_token;
revemanced21f862015-11-24 00:42:49284}
285
revemanae3b7c852016-02-25 01:50:03286void Buffer::Texture::ReleaseWhenQueryResultIsAvailable(
287 const base::Closure& callback) {
288 DCHECK(release_callback_.is_null());
289 release_callback_ = callback;
290 base::TimeDelta wait_for_release_delay =
291 base::TimeDelta::FromMilliseconds(kWaitForReleaseDelayMs);
292 wait_for_release_time_ = base::TimeTicks::Now() + wait_for_release_delay;
293 ScheduleWaitForRelease(wait_for_release_delay);
294 context_provider_->ContextSupport()->SignalQuery(
295 query_id_,
296 base::Bind(&Buffer::Texture::Released, weak_ptr_factory_.GetWeakPtr()));
297}
298
299void Buffer::Texture::Released() {
300 if (!release_callback_.is_null())
301 base::ResetAndReturn(&release_callback_).Run();
302}
303
304void Buffer::Texture::ScheduleWaitForRelease(base::TimeDelta delay) {
305 if (wait_for_release_pending_)
306 return;
307
308 wait_for_release_pending_ = true;
309 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
310 FROM_HERE, base::Bind(&Buffer::Texture::WaitForRelease,
311 weak_ptr_factory_.GetWeakPtr()),
312 delay);
313}
314
315void Buffer::Texture::WaitForRelease() {
316 DCHECK(wait_for_release_pending_);
317 wait_for_release_pending_ = false;
318
319 if (release_callback_.is_null())
320 return;
321
322 base::TimeTicks current_time = base::TimeTicks::Now();
323 if (current_time < wait_for_release_time_) {
324 ScheduleWaitForRelease(wait_for_release_time_ - current_time);
325 return;
326 }
327
328 base::Closure callback = base::ResetAndReturn(&release_callback_);
329
330 {
331 TRACE_EVENT0("exo", "Buffer::Texture::WaitForQueryResult");
332
333 // We need to wait for the result to be available. Getting the result of
334 // the query implies waiting for it to become available. The actual result
335 // is unimportant and also not well defined.
336 unsigned result = 0;
337 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
338 gles2->GetQueryObjectuivEXT(query_id_, GL_QUERY_RESULT_EXT, &result);
339 }
340
341 callback.Run();
342}
343
revemanced21f862015-11-24 00:42:49344////////////////////////////////////////////////////////////////////////////////
345// Buffer, public:
346
dcheng31759da2016-04-21 01:26:31347Buffer::Buffer(std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer)
revemanc8623d5b2016-02-09 02:29:10348 : gpu_memory_buffer_(std::move(gpu_memory_buffer)),
349 texture_target_(GL_TEXTURE_2D),
350 query_type_(GL_COMMANDS_COMPLETED_CHROMIUM),
351 use_zero_copy_(true),
reveman244f9622016-03-04 21:33:33352 is_overlay_candidate_(false),
revemanc8623d5b2016-02-09 02:29:10353 use_count_(0) {}
354
dcheng31759da2016-04-21 01:26:31355Buffer::Buffer(std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer,
revemanc8623d5b2016-02-09 02:29:10356 unsigned texture_target,
357 unsigned query_type,
reveman244f9622016-03-04 21:33:33358 bool use_zero_copy,
359 bool is_overlay_candidate)
dcheng27f7483f2015-12-29 22:26:56360 : gpu_memory_buffer_(std::move(gpu_memory_buffer)),
revemanced21f862015-11-24 00:42:49361 texture_target_(texture_target),
revemanc8623d5b2016-02-09 02:29:10362 query_type_(query_type),
363 use_zero_copy_(use_zero_copy),
reveman244f9622016-03-04 21:33:33364 is_overlay_candidate_(is_overlay_candidate),
revemanced21f862015-11-24 00:42:49365 use_count_(0) {}
366
367Buffer::~Buffer() {}
368
dcheng31759da2016-04-21 01:26:31369std::unique_ptr<cc::SingleReleaseCallback> Buffer::ProduceTextureMailbox(
revemanc8623d5b2016-02-09 02:29:10370 cc::TextureMailbox* texture_mailbox,
reveman85b7a562016-03-17 23:27:32371 bool secure_output_only,
reveman56f345902016-06-06 03:58:28372 bool client_usage) {
373 // Non-client usage can only be allowed when the client is not allowed to
374 // use the buffer. If the buffer has been released to the client then it
375 // can no longer be used as the client might be writing to it.
376 if (!client_usage && !use_count_)
377 return nullptr;
378
379 DLOG_IF(WARNING, use_count_ && client_usage)
revemanced21f862015-11-24 00:42:49380 << "Producing a texture mailbox for a buffer that has not been released";
381
revemanc8623d5b2016-02-09 02:29:10382 // Some clients think that they can reuse a buffer before it's released by
383 // performing a fast blit into the buffer. This behavior is bad as it prevents
384 // the client from knowing when the buffer is actually released (e.g. the
385 // release notification for the previous use of buffer can arrive after the
386 // buffer has been reused). We stop running the release callback when this
387 // type of behavior is detected as having the buffer always be busy will
388 // result in fewer drawing artifacts.
reveman56f345902016-06-06 03:58:28389 if (use_count_ && client_usage)
revemanc8623d5b2016-02-09 02:29:10390 release_callback_.Reset();
391
revemanced21f862015-11-24 00:42:49392 // Increment the use count for this buffer.
393 ++use_count_;
394
revemanc8623d5b2016-02-09 02:29:10395 // If textures are lost, destroy them to ensure that we create new ones below.
396 if (contents_texture_ && contents_texture_->IsLost())
397 contents_texture_.reset();
398 if (texture_ && texture_->IsLost())
399 texture_.reset();
revemanced21f862015-11-24 00:42:49400
revemanc8623d5b2016-02-09 02:29:10401 // Note: This can fail if GPU acceleration has been disabled.
402 scoped_refptr<cc::ContextProvider> context_provider =
403 aura::Env::GetInstance()
404 ->context_factory()
405 ->SharedMainThreadContextProvider();
406 if (!context_provider) {
407 DLOG(WARNING) << "Failed to acquire a context provider";
408 Release(); // Decrements the use count
409 return nullptr;
revemanced21f862015-11-24 00:42:49410 }
411
revemanc8623d5b2016-02-09 02:29:10412 // Create a new image texture for |gpu_memory_buffer_| with |texture_target_|
413 // if one doesn't already exist. The contents of this buffer are copied to
414 // |texture| using a call to CopyTexImage.
415 if (!contents_texture_) {
dcheng31759da2016-04-21 01:26:31416 contents_texture_ = base::WrapUnique(
revemanc8623d5b2016-02-09 02:29:10417 new Texture(context_provider.get(), gpu_memory_buffer_.get(),
418 texture_target_, query_type_));
419 }
revemanb195f41d2015-11-19 22:16:48420
revemanc8623d5b2016-02-09 02:29:10421 if (use_zero_copy_) {
422 // Zero-copy means using the contents texture directly.
423 Texture* texture = contents_texture_.get();
424
425 // This binds the latest contents of this buffer to |texture|.
426 gpu::SyncToken sync_token = texture->BindTexImage();
427
ccameron606662d2016-05-13 01:52:17428 *texture_mailbox = cc::TextureMailbox(
429 texture->mailbox(), sync_token, texture_target_,
430 gpu_memory_buffer_->GetSize(), gpu_memory_buffer_->GetId(),
431 is_overlay_candidate_, secure_output_only);
revemanc8623d5b2016-02-09 02:29:10432 // The contents texture will be released when no longer used by the
433 // compositor.
434 return cc::SingleReleaseCallback::Create(
435 base::Bind(&Buffer::Texture::ReleaseTexImage, base::Unretained(texture),
436 base::Bind(&Buffer::ReleaseContentsTexture, AsWeakPtr(),
437 base::Passed(&contents_texture_))));
438 }
439
440 // Create a mailbox texture that we copy the buffer contents to.
441 if (!texture_)
dcheng31759da2016-04-21 01:26:31442 texture_ = base::WrapUnique(new Texture(context_provider.get()));
revemanc8623d5b2016-02-09 02:29:10443
reveman17fdee02016-02-10 04:26:47444 // Copy the contents of |contents_texture| to |texture| and produce a
445 // texture mailbox from the result in |texture|.
446 Texture* contents_texture = contents_texture_.get();
revemanc8623d5b2016-02-09 02:29:10447 Texture* texture = texture_.get();
448
449 // The contents texture will be released when copy has completed.
reveman17fdee02016-02-10 04:26:47450 gpu::SyncToken sync_token = contents_texture->CopyTexImage(
revemanc8623d5b2016-02-09 02:29:10451 texture, base::Bind(&Buffer::ReleaseContentsTexture, AsWeakPtr(),
452 base::Passed(&contents_texture_)));
ccameron606662d2016-05-13 01:52:17453 *texture_mailbox = cc::TextureMailbox(
454 texture->mailbox(), sync_token, GL_TEXTURE_2D,
455 gpu_memory_buffer_->GetSize(), gfx::GpuMemoryBufferId(),
456 false /* is_overlay_candidate */, secure_output_only);
revemanc8623d5b2016-02-09 02:29:10457 // The mailbox texture will be released when no longer used by the
458 // compositor.
revemanb195f41d2015-11-19 22:16:48459 return cc::SingleReleaseCallback::Create(
revemanc8623d5b2016-02-09 02:29:10460 base::Bind(&Buffer::Texture::Release, base::Unretained(texture),
461 base::Bind(&Buffer::ReleaseTexture, AsWeakPtr(),
462 base::Passed(&texture_))));
revemanb195f41d2015-11-19 22:16:48463}
464
465gfx::Size Buffer::GetSize() const {
466 return gpu_memory_buffer_->GetSize();
467}
468
dcheng31759da2016-04-21 01:26:31469std::unique_ptr<base::trace_event::TracedValue> Buffer::AsTracedValue() const {
470 std::unique_ptr<base::trace_event::TracedValue> value(
primianocb1afb32016-02-29 20:46:05471 new base::trace_event::TracedValue());
revemanced21f862015-11-24 00:42:49472 gfx::Size size = gpu_memory_buffer_->GetSize();
473 value->SetInteger("width", size.width());
474 value->SetInteger("height", size.height());
revemanb195f41d2015-11-19 22:16:48475 value->SetInteger("format",
476 static_cast<int>(gpu_memory_buffer_->GetFormat()));
477 return value;
478}
479
480////////////////////////////////////////////////////////////////////////////////
481// Buffer, private:
482
revemanced21f862015-11-24 00:42:49483void Buffer::Release() {
484 DCHECK_GT(use_count_, 0u);
485 if (--use_count_)
revemanb195f41d2015-11-19 22:16:48486 return;
revemanb195f41d2015-11-19 22:16:48487
revemanced21f862015-11-24 00:42:49488 // Run release callback to notify the client that buffer has been released.
489 if (!release_callback_.is_null())
490 release_callback_.Run();
491}
revemanb195f41d2015-11-19 22:16:48492
dcheng31759da2016-04-21 01:26:31493void Buffer::ReleaseTexture(std::unique_ptr<Texture> texture) {
revemanc8623d5b2016-02-09 02:29:10494 texture_ = std::move(texture);
495}
revemanced21f862015-11-24 00:42:49496
dcheng31759da2016-04-21 01:26:31497void Buffer::ReleaseContentsTexture(std::unique_ptr<Texture> texture) {
revemanc8623d5b2016-02-09 02:29:10498 TRACE_EVENT0("exo", "Buffer::ReleaseContentsTexture");
revemanced21f862015-11-24 00:42:49499
revemanc8623d5b2016-02-09 02:29:10500 contents_texture_ = std::move(texture);
501 Release();
revemanb195f41d2015-11-19 22:16:48502}
503
504} // namespace exo