blob: 03e2ddbf37e363e0d02ca258828bdae894c7e96e [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
dcastagnacbea4262016-06-08 00:26:0254 GL_RGB_YCRCB_420_CHROMIUM, // YVU_420
revemanb195f41d2015-11-19 22:16:4855 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_;
reveman2d3815d2016-06-26 20:13:25142 unsigned image_id_ = 0;
143 unsigned query_id_ = 0;
144 unsigned texture_id_ = 0;
revemanced21f862015-11-24 00:42:49145 gpu::Mailbox mailbox_;
revemanae3b7c852016-02-25 01:50:03146 base::Closure release_callback_;
147 base::TimeTicks wait_for_release_time_;
reveman2d3815d2016-06-26 20:13:25148 bool wait_for_release_pending_ = false;
revemanae3b7c852016-02-25 01:50:03149 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),
revemanae3b7c852016-02-25 01:50:03159 weak_ptr_factory_(this) {
revemanced21f862015-11-24 00:42:49160 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
revemanc8623d5b2016-02-09 02:29:10161 texture_id_ = CreateGLTexture(gles2, texture_target_);
revemanb195f41d2015-11-19 22:16:48162 // Generate a crypto-secure random mailbox name.
revemanc8623d5b2016-02-09 02:29:10163 CreateGLTextureMailbox(gles2, texture_id_, texture_target_, &mailbox_);
164}
165
166Buffer::Texture::Texture(cc::ContextProvider* context_provider,
167 gfx::GpuMemoryBuffer* gpu_memory_buffer,
168 unsigned texture_target,
169 unsigned query_type)
170 : context_provider_(context_provider),
171 texture_target_(texture_target),
172 query_type_(query_type),
173 internalformat_(GLInternalFormat(gpu_memory_buffer->GetFormat())),
revemanae3b7c852016-02-25 01:50:03174 weak_ptr_factory_(this) {
revemanc8623d5b2016-02-09 02:29:10175 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
176 gfx::Size size = gpu_memory_buffer->GetSize();
177 image_id_ =
178 gles2->CreateImageCHROMIUM(gpu_memory_buffer->AsClientBuffer(),
179 size.width(), size.height(), internalformat_);
dcastagna2db83c7ef2016-06-13 23:33:22180 DLOG_IF(WARNING, !image_id_) << "Failed to create GLImage";
181
revemanc8623d5b2016-02-09 02:29:10182 gles2->GenQueriesEXT(1, &query_id_);
183 texture_id_ = CreateGLTexture(gles2, texture_target_);
revemanb195f41d2015-11-19 22:16:48184}
185
revemanced21f862015-11-24 00:42:49186Buffer::Texture::~Texture() {
187 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
revemanced21f862015-11-24 00:42:49188 gles2->DeleteTextures(1, &texture_id_);
revemanc8623d5b2016-02-09 02:29:10189 if (query_id_)
190 gles2->DeleteQueriesEXT(1, &query_id_);
191 if (image_id_)
192 gles2->DestroyImageCHROMIUM(image_id_);
revemanb195f41d2015-11-19 22:16:48193}
194
revemanced21f862015-11-24 00:42:49195bool Buffer::Texture::IsLost() {
196 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
197 return gles2->GetGraphicsResetStatusKHR() != GL_NO_ERROR;
198}
revemanb195f41d2015-11-19 22:16:48199
revemanc8623d5b2016-02-09 02:29:10200void Buffer::Texture::Release(const base::Closure& callback,
201 const gpu::SyncToken& sync_token,
202 bool is_lost) {
203 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
204 if (sync_token.HasData())
205 gles2->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
206
207 // Run callback as texture can be reused immediately after waiting for sync
208 // token.
209 callback.Run();
210}
211
revemanced21f862015-11-24 00:42:49212gpu::SyncToken Buffer::Texture::BindTexImage() {
213 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
revemanb195f41d2015-11-19 22:16:48214 gles2->ActiveTexture(GL_TEXTURE0);
revemanced21f862015-11-24 00:42:49215 gles2->BindTexture(texture_target_, texture_id_);
revemanc8623d5b2016-02-09 02:29:10216 DCHECK_NE(image_id_, 0u);
revemanced21f862015-11-24 00:42:49217 gles2->BindTexImage2DCHROMIUM(texture_target_, image_id_);
revemanc8623d5b2016-02-09 02:29:10218 // Generate a crypto-secure random mailbox name if not already done.
219 if (mailbox_.IsZero())
220 CreateGLTextureMailbox(gles2, texture_id_, texture_target_, &mailbox_);
revemanced21f862015-11-24 00:42:49221 // Create and return a sync token that can be used to ensure that the
222 // BindTexImage2DCHROMIUM call is processed before issuing any commands
223 // that will read from the texture on a different context.
avibc5337b2015-12-25 23:16:33224 uint64_t fence_sync = gles2->InsertFenceSyncCHROMIUM();
revemanced21f862015-11-24 00:42:49225 gles2->OrderingBarrierCHROMIUM();
revemanb195f41d2015-11-19 22:16:48226 gpu::SyncToken sync_token;
227 gles2->GenUnverifiedSyncTokenCHROMIUM(fence_sync, sync_token.GetData());
revemanced21f862015-11-24 00:42:49228 return sync_token;
229}
230
revemanc8623d5b2016-02-09 02:29:10231void Buffer::Texture::ReleaseTexImage(const base::Closure& callback,
232 const gpu::SyncToken& sync_token,
233 bool is_lost) {
revemanced21f862015-11-24 00:42:49234 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
235 if (sync_token.HasData())
236 gles2->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
237 gles2->ActiveTexture(GL_TEXTURE0);
238 gles2->BindTexture(texture_target_, texture_id_);
revemanc8623d5b2016-02-09 02:29:10239 DCHECK_NE(query_id_, 0u);
240 gles2->BeginQueryEXT(query_type_, query_id_);
revemanced21f862015-11-24 00:42:49241 gles2->ReleaseTexImage2DCHROMIUM(texture_target_, image_id_);
revemanc8623d5b2016-02-09 02:29:10242 gles2->EndQueryEXT(query_type_);
revemanae3b7c852016-02-25 01:50:03243 // Run callback when query result is available and ReleaseTexImage has been
244 // handled if sync token has data and buffer has been used. If buffer was
245 // never used then run the callback immediately.
revemanc8623d5b2016-02-09 02:29:10246 if (sync_token.HasData()) {
revemanae3b7c852016-02-25 01:50:03247 ReleaseWhenQueryResultIsAvailable(callback);
revemanc8623d5b2016-02-09 02:29:10248 } else {
249 callback.Run();
250 }
251}
252
253gpu::SyncToken Buffer::Texture::CopyTexImage(Texture* destination,
254 const base::Closure& callback) {
255 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
256 gles2->ActiveTexture(GL_TEXTURE0);
257 gles2->BindTexture(texture_target_, texture_id_);
258 DCHECK_NE(image_id_, 0u);
259 gles2->BindTexImage2DCHROMIUM(texture_target_, image_id_);
260 gles2->CopyTextureCHROMIUM(texture_id_, destination->texture_id_,
261 internalformat_, GL_UNSIGNED_BYTE, false, false,
262 false);
263 DCHECK_NE(query_id_, 0u);
264 gles2->BeginQueryEXT(query_type_, query_id_);
265 gles2->ReleaseTexImage2DCHROMIUM(texture_target_, image_id_);
266 gles2->EndQueryEXT(query_type_);
revemanae3b7c852016-02-25 01:50:03267 // Run callback when query result is available and ReleaseTexImage has been
268 // handled.
269 ReleaseWhenQueryResultIsAvailable(callback);
revemanc8623d5b2016-02-09 02:29:10270 // Create and return a sync token that can be used to ensure that the
271 // CopyTextureCHROMIUM call is processed before issuing any commands
272 // that will read from the target texture on a different context.
273 uint64_t fence_sync = gles2->InsertFenceSyncCHROMIUM();
274 gles2->OrderingBarrierCHROMIUM();
275 gpu::SyncToken sync_token;
276 gles2->GenUnverifiedSyncTokenCHROMIUM(fence_sync, sync_token.GetData());
277 return sync_token;
revemanced21f862015-11-24 00:42:49278}
279
revemanae3b7c852016-02-25 01:50:03280void Buffer::Texture::ReleaseWhenQueryResultIsAvailable(
281 const base::Closure& callback) {
282 DCHECK(release_callback_.is_null());
283 release_callback_ = callback;
284 base::TimeDelta wait_for_release_delay =
285 base::TimeDelta::FromMilliseconds(kWaitForReleaseDelayMs);
286 wait_for_release_time_ = base::TimeTicks::Now() + wait_for_release_delay;
287 ScheduleWaitForRelease(wait_for_release_delay);
288 context_provider_->ContextSupport()->SignalQuery(
289 query_id_,
290 base::Bind(&Buffer::Texture::Released, weak_ptr_factory_.GetWeakPtr()));
291}
292
293void Buffer::Texture::Released() {
294 if (!release_callback_.is_null())
295 base::ResetAndReturn(&release_callback_).Run();
296}
297
298void Buffer::Texture::ScheduleWaitForRelease(base::TimeDelta delay) {
299 if (wait_for_release_pending_)
300 return;
301
302 wait_for_release_pending_ = true;
303 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
304 FROM_HERE, base::Bind(&Buffer::Texture::WaitForRelease,
305 weak_ptr_factory_.GetWeakPtr()),
306 delay);
307}
308
309void Buffer::Texture::WaitForRelease() {
310 DCHECK(wait_for_release_pending_);
311 wait_for_release_pending_ = false;
312
313 if (release_callback_.is_null())
314 return;
315
316 base::TimeTicks current_time = base::TimeTicks::Now();
317 if (current_time < wait_for_release_time_) {
318 ScheduleWaitForRelease(wait_for_release_time_ - current_time);
319 return;
320 }
321
322 base::Closure callback = base::ResetAndReturn(&release_callback_);
323
324 {
325 TRACE_EVENT0("exo", "Buffer::Texture::WaitForQueryResult");
326
327 // We need to wait for the result to be available. Getting the result of
328 // the query implies waiting for it to become available. The actual result
329 // is unimportant and also not well defined.
330 unsigned result = 0;
331 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
332 gles2->GetQueryObjectuivEXT(query_id_, GL_QUERY_RESULT_EXT, &result);
333 }
334
335 callback.Run();
336}
337
revemanced21f862015-11-24 00:42:49338////////////////////////////////////////////////////////////////////////////////
339// Buffer, public:
340
dcheng31759da2016-04-21 01:26:31341Buffer::Buffer(std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer)
revemanc8623d5b2016-02-09 02:29:10342 : gpu_memory_buffer_(std::move(gpu_memory_buffer)),
343 texture_target_(GL_TEXTURE_2D),
344 query_type_(GL_COMMANDS_COMPLETED_CHROMIUM),
345 use_zero_copy_(true),
reveman2d3815d2016-06-26 20:13:25346 is_overlay_candidate_(false) {}
revemanc8623d5b2016-02-09 02:29:10347
dcheng31759da2016-04-21 01:26:31348Buffer::Buffer(std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer,
revemanc8623d5b2016-02-09 02:29:10349 unsigned texture_target,
350 unsigned query_type,
reveman244f9622016-03-04 21:33:33351 bool use_zero_copy,
352 bool is_overlay_candidate)
dcheng27f7483f2015-12-29 22:26:56353 : gpu_memory_buffer_(std::move(gpu_memory_buffer)),
revemanced21f862015-11-24 00:42:49354 texture_target_(texture_target),
revemanc8623d5b2016-02-09 02:29:10355 query_type_(query_type),
356 use_zero_copy_(use_zero_copy),
reveman2d3815d2016-06-26 20:13:25357 is_overlay_candidate_(is_overlay_candidate) {}
revemanced21f862015-11-24 00:42:49358
359Buffer::~Buffer() {}
360
dcheng31759da2016-04-21 01:26:31361std::unique_ptr<cc::SingleReleaseCallback> Buffer::ProduceTextureMailbox(
revemanc8623d5b2016-02-09 02:29:10362 cc::TextureMailbox* texture_mailbox,
reveman85b7a562016-03-17 23:27:32363 bool secure_output_only,
reveman56f345902016-06-06 03:58:28364 bool client_usage) {
jbauman45c06862016-06-23 19:35:02365 DCHECK(attach_count_);
reveman56f345902016-06-06 03:58:28366 DLOG_IF(WARNING, use_count_ && client_usage)
revemanced21f862015-11-24 00:42:49367 << "Producing a texture mailbox for a buffer that has not been released";
368
revemanc8623d5b2016-02-09 02:29:10369 // Some clients think that they can reuse a buffer before it's released by
370 // performing a fast blit into the buffer. This behavior is bad as it prevents
371 // the client from knowing when the buffer is actually released (e.g. the
372 // release notification for the previous use of buffer can arrive after the
373 // buffer has been reused). We stop running the release callback when this
374 // type of behavior is detected as having the buffer always be busy will
375 // result in fewer drawing artifacts.
reveman56f345902016-06-06 03:58:28376 if (use_count_ && client_usage)
revemanc8623d5b2016-02-09 02:29:10377 release_callback_.Reset();
378
revemanced21f862015-11-24 00:42:49379 // Increment the use count for this buffer.
380 ++use_count_;
381
revemanc8623d5b2016-02-09 02:29:10382 // If textures are lost, destroy them to ensure that we create new ones below.
383 if (contents_texture_ && contents_texture_->IsLost())
384 contents_texture_.reset();
385 if (texture_ && texture_->IsLost())
386 texture_.reset();
revemanced21f862015-11-24 00:42:49387
revemanc8623d5b2016-02-09 02:29:10388 // Note: This can fail if GPU acceleration has been disabled.
389 scoped_refptr<cc::ContextProvider> context_provider =
390 aura::Env::GetInstance()
391 ->context_factory()
392 ->SharedMainThreadContextProvider();
393 if (!context_provider) {
394 DLOG(WARNING) << "Failed to acquire a context provider";
395 Release(); // Decrements the use count
396 return nullptr;
revemanced21f862015-11-24 00:42:49397 }
398
revemanc8623d5b2016-02-09 02:29:10399 // Create a new image texture for |gpu_memory_buffer_| with |texture_target_|
400 // if one doesn't already exist. The contents of this buffer are copied to
401 // |texture| using a call to CopyTexImage.
402 if (!contents_texture_) {
dcheng31759da2016-04-21 01:26:31403 contents_texture_ = base::WrapUnique(
revemanc8623d5b2016-02-09 02:29:10404 new Texture(context_provider.get(), gpu_memory_buffer_.get(),
405 texture_target_, query_type_));
406 }
revemanb195f41d2015-11-19 22:16:48407
revemanc8623d5b2016-02-09 02:29:10408 if (use_zero_copy_) {
409 // Zero-copy means using the contents texture directly.
410 Texture* texture = contents_texture_.get();
411
412 // This binds the latest contents of this buffer to |texture|.
413 gpu::SyncToken sync_token = texture->BindTexImage();
414
ccameron399d94a2016-06-22 03:08:58415 *texture_mailbox =
416 cc::TextureMailbox(texture->mailbox(), sync_token, texture_target_,
417 gpu_memory_buffer_->GetSize(), is_overlay_candidate_,
418 secure_output_only);
revemanc8623d5b2016-02-09 02:29:10419 // The contents texture will be released when no longer used by the
420 // compositor.
421 return cc::SingleReleaseCallback::Create(
422 base::Bind(&Buffer::Texture::ReleaseTexImage, base::Unretained(texture),
423 base::Bind(&Buffer::ReleaseContentsTexture, AsWeakPtr(),
424 base::Passed(&contents_texture_))));
425 }
426
427 // Create a mailbox texture that we copy the buffer contents to.
428 if (!texture_)
dcheng31759da2016-04-21 01:26:31429 texture_ = base::WrapUnique(new Texture(context_provider.get()));
revemanc8623d5b2016-02-09 02:29:10430
reveman17fdee02016-02-10 04:26:47431 // Copy the contents of |contents_texture| to |texture| and produce a
432 // texture mailbox from the result in |texture|.
433 Texture* contents_texture = contents_texture_.get();
revemanc8623d5b2016-02-09 02:29:10434 Texture* texture = texture_.get();
435
436 // The contents texture will be released when copy has completed.
reveman17fdee02016-02-10 04:26:47437 gpu::SyncToken sync_token = contents_texture->CopyTexImage(
revemanc8623d5b2016-02-09 02:29:10438 texture, base::Bind(&Buffer::ReleaseContentsTexture, AsWeakPtr(),
439 base::Passed(&contents_texture_)));
ccameron399d94a2016-06-22 03:08:58440 *texture_mailbox =
441 cc::TextureMailbox(texture->mailbox(), sync_token, GL_TEXTURE_2D,
442 gpu_memory_buffer_->GetSize(),
443 false /* is_overlay_candidate */, secure_output_only);
revemanc8623d5b2016-02-09 02:29:10444 // The mailbox texture will be released when no longer used by the
445 // compositor.
revemanb195f41d2015-11-19 22:16:48446 return cc::SingleReleaseCallback::Create(
revemanc8623d5b2016-02-09 02:29:10447 base::Bind(&Buffer::Texture::Release, base::Unretained(texture),
448 base::Bind(&Buffer::ReleaseTexture, AsWeakPtr(),
449 base::Passed(&texture_))));
revemanb195f41d2015-11-19 22:16:48450}
451
jbauman45c06862016-06-23 19:35:02452void Buffer::OnAttach() {
453 DLOG_IF(WARNING, attach_count_ > 0u)
454 << "Reattaching a buffer that is already attached to another surface.";
455 attach_count_++;
456}
457
458void Buffer::OnDetach() {
459 DCHECK_GT(attach_count_, 0u);
460 --attach_count_;
461 CheckReleaseCallback();
462}
463
revemanb195f41d2015-11-19 22:16:48464gfx::Size Buffer::GetSize() const {
465 return gpu_memory_buffer_->GetSize();
466}
467
dcheng31759da2016-04-21 01:26:31468std::unique_ptr<base::trace_event::TracedValue> Buffer::AsTracedValue() const {
469 std::unique_ptr<base::trace_event::TracedValue> value(
primianocb1afb32016-02-29 20:46:05470 new base::trace_event::TracedValue());
revemanced21f862015-11-24 00:42:49471 gfx::Size size = gpu_memory_buffer_->GetSize();
472 value->SetInteger("width", size.width());
473 value->SetInteger("height", size.height());
revemanb195f41d2015-11-19 22:16:48474 value->SetInteger("format",
475 static_cast<int>(gpu_memory_buffer_->GetFormat()));
476 return value;
477}
478
479////////////////////////////////////////////////////////////////////////////////
480// Buffer, private:
481
revemanced21f862015-11-24 00:42:49482void Buffer::Release() {
483 DCHECK_GT(use_count_, 0u);
jbauman45c06862016-06-23 19:35:02484 --use_count_;
485 CheckReleaseCallback();
486}
487
488void Buffer::CheckReleaseCallback() {
489 if (attach_count_ || use_count_)
revemanb195f41d2015-11-19 22:16:48490 return;
revemanb195f41d2015-11-19 22:16:48491
revemanced21f862015-11-24 00:42:49492 // Run release callback to notify the client that buffer has been released.
493 if (!release_callback_.is_null())
494 release_callback_.Run();
495}
revemanb195f41d2015-11-19 22:16:48496
dcheng31759da2016-04-21 01:26:31497void Buffer::ReleaseTexture(std::unique_ptr<Texture> texture) {
revemanc8623d5b2016-02-09 02:29:10498 texture_ = std::move(texture);
499}
revemanced21f862015-11-24 00:42:49500
dcheng31759da2016-04-21 01:26:31501void Buffer::ReleaseContentsTexture(std::unique_ptr<Texture> texture) {
revemanc8623d5b2016-02-09 02:29:10502 TRACE_EVENT0("exo", "Buffer::ReleaseContentsTexture");
revemanced21f862015-11-24 00:42:49503
revemanc8623d5b2016-02-09 02:29:10504 contents_texture_ = std::move(texture);
505 Release();
revemanb195f41d2015-11-19 22:16:48506}
507
508} // namespace exo