blob: 0588175c463eca7ef2847355f8e7bc24fa39587d [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"
starazd40f0362017-01-04 00:46:1327#include "components/exo/compositor_frame_sink_holder.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"
30#include "ui/aura/env.h"
31#include "ui/compositor/compositor.h"
32#include "ui/gfx/gpu_memory_buffer.h"
33
34namespace exo {
35namespace {
36
revemanae3b7c852016-02-25 01:50:0337// The amount of time before we wait for release queries using
38// GetQueryObjectuivEXT(GL_QUERY_RESULT_EXT).
39const int kWaitForReleaseDelayMs = 500;
40
revemanb195f41d2015-11-19 22:16:4841GLenum GLInternalFormat(gfx::BufferFormat format) {
42 const GLenum kGLInternalFormats[] = {
43 GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD, // ATC
44 GL_COMPRESSED_RGB_S3TC_DXT1_EXT, // ATCIA
45 GL_COMPRESSED_RGB_S3TC_DXT1_EXT, // DXT1
46 GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, // DXT5
47 GL_ETC1_RGB8_OES, // ETC1
48 GL_R8_EXT, // R_8
dongseong.hwang961b0e12016-10-04 10:15:3049 GL_RG8_EXT, // RG_88
reveman5954fa12016-05-18 21:56:3850 GL_RGB, // BGR_565
revemanb195f41d2015-11-19 22:16:4851 GL_RGBA, // RGBA_4444
52 GL_RGB, // RGBX_8888
53 GL_RGBA, // RGBA_8888
54 GL_RGB, // BGRX_8888
55 GL_BGRA_EXT, // BGRA_8888
ccameronc1fcde52017-04-12 19:40:4956 GL_RGBA, // RGBA_F16
dcastagnacbea4262016-06-08 00:26:0257 GL_RGB_YCRCB_420_CHROMIUM, // YVU_420
dcastagna23d30bfd2016-09-24 02:06:2058 GL_RGB_YCBCR_420V_CHROMIUM, // YUV_420_BIPLANAR
revemanb195f41d2015-11-19 22:16:4859 GL_RGB_YCBCR_422_CHROMIUM, // UYVY_422
60 };
61 static_assert(arraysize(kGLInternalFormats) ==
62 (static_cast<int>(gfx::BufferFormat::LAST) + 1),
63 "BufferFormat::LAST must be last value of kGLInternalFormats");
64
65 DCHECK(format <= gfx::BufferFormat::LAST);
66 return kGLInternalFormats[static_cast<int>(format)];
67}
68
revemanc8623d5b2016-02-09 02:29:1069unsigned CreateGLTexture(gpu::gles2::GLES2Interface* gles2, GLenum target) {
70 unsigned texture_id = 0;
71 gles2->GenTextures(1, &texture_id);
72 gles2->ActiveTexture(GL_TEXTURE0);
73 gles2->BindTexture(target, texture_id);
74 gles2->TexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
75 gles2->TexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
76 gles2->TexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
77 gles2->TexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
78 return texture_id;
79}
80
81void CreateGLTextureMailbox(gpu::gles2::GLES2Interface* gles2,
82 unsigned texture_id,
83 GLenum target,
84 gpu::Mailbox* mailbox) {
85 gles2->ActiveTexture(GL_TEXTURE0);
86 gles2->BindTexture(target, texture_id);
87 gles2->GenMailboxCHROMIUM(mailbox->name);
88 gles2->ProduceTextureCHROMIUM(target, mailbox->name);
89}
90
revemanb195f41d2015-11-19 22:16:4891} // namespace
92
93////////////////////////////////////////////////////////////////////////////////
revemanced21f82015-11-24 00:42:4994// Buffer::Texture
revemanb195f41d2015-11-19 22:16:4895
revemanced21f82015-11-24 00:42:4996// Encapsulates the state and logic needed to bind a buffer to a GLES2 texture.
revemand0b75c32016-08-12 02:46:5297class Buffer::Texture : public ui::ContextFactoryObserver {
revemanced21f82015-11-24 00:42:4998 public:
revemand0b75c32016-08-12 02:46:5299 Texture(ui::ContextFactory* context_factory,
100 cc::ContextProvider* context_provider);
101 Texture(ui::ContextFactory* context_factory,
102 cc::ContextProvider* context_provider,
revemanc8623d5b2016-02-09 02:29:10103 gfx::GpuMemoryBuffer* gpu_memory_buffer,
104 unsigned texture_target,
105 unsigned query_type);
revemand0b75c32016-08-12 02:46:52106 ~Texture() override;
107
108 // Overridden from ui::ContextFactoryObserver:
109 void OnLostResources() override;
revemanced21f82015-11-24 00:42:49110
111 // Returns true if GLES2 resources for texture have been lost.
112 bool IsLost();
113
revemanc8623d5b2016-02-09 02:29:10114 // Allow texture to be reused after |sync_token| has passed and runs
115 // |callback|.
116 void Release(const base::Closure& callback,
117 const gpu::SyncToken& sync_token,
118 bool is_lost);
119
120 // Binds the contents referenced by |image_id_| to the texture returned by
121 // mailbox(). Returns a sync token that can be used when accessing texture
revemanced21f82015-11-24 00:42:49122 // from a different context.
123 gpu::SyncToken BindTexImage();
124
revemanc8623d5b2016-02-09 02:29:10125 // Releases the contents referenced by |image_id_| after |sync_token| has
126 // passed and runs |callback| when completed.
127 void ReleaseTexImage(const base::Closure& callback,
128 const gpu::SyncToken& sync_token,
129 bool is_lost);
130
131 // Copy the contents of texture to |destination| and runs |callback| when
132 // completed. Returns a sync token that can be used when accessing texture
133 // from a different context.
134 gpu::SyncToken CopyTexImage(Texture* destination,
135 const base::Closure& callback);
revemanced21f82015-11-24 00:42:49136
137 // Returns the mailbox for this texture.
138 gpu::Mailbox mailbox() const { return mailbox_; }
139
140 private:
revemand0b75c32016-08-12 02:46:52141 void DestroyResources();
revemanae3b7c852016-02-25 01:50:03142 void ReleaseWhenQueryResultIsAvailable(const base::Closure& callback);
143 void Released();
144 void ScheduleWaitForRelease(base::TimeDelta delay);
145 void WaitForRelease();
146
revemand0b75c32016-08-12 02:46:52147 ui::ContextFactory* context_factory_;
revemanced21f82015-11-24 00:42:49148 scoped_refptr<cc::ContextProvider> context_provider_;
149 const unsigned texture_target_;
revemanc8623d5b2016-02-09 02:29:10150 const unsigned query_type_;
151 const GLenum internalformat_;
reveman2d3815d2016-06-26 20:13:25152 unsigned image_id_ = 0;
153 unsigned query_id_ = 0;
154 unsigned texture_id_ = 0;
revemanced21f82015-11-24 00:42:49155 gpu::Mailbox mailbox_;
revemanae3b7c852016-02-25 01:50:03156 base::Closure release_callback_;
157 base::TimeTicks wait_for_release_time_;
reveman2d3815d2016-06-26 20:13:25158 bool wait_for_release_pending_ = false;
revemanae3b7c852016-02-25 01:50:03159 base::WeakPtrFactory<Texture> weak_ptr_factory_;
revemanced21f82015-11-24 00:42:49160
161 DISALLOW_COPY_AND_ASSIGN(Texture);
162};
163
revemand0b75c32016-08-12 02:46:52164Buffer::Texture::Texture(ui::ContextFactory* context_factory,
165 cc::ContextProvider* context_provider)
166 : context_factory_(context_factory),
167 context_provider_(context_provider),
revemanc8623d5b2016-02-09 02:29:10168 texture_target_(GL_TEXTURE_2D),
169 query_type_(GL_COMMANDS_COMPLETED_CHROMIUM),
170 internalformat_(GL_RGBA),
revemanae3b7c852016-02-25 01:50:03171 weak_ptr_factory_(this) {
revemanced21f82015-11-24 00:42:49172 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
revemanc8623d5b2016-02-09 02:29:10173 texture_id_ = CreateGLTexture(gles2, texture_target_);
revemanb195f41d2015-11-19 22:16:48174 // Generate a crypto-secure random mailbox name.
revemanc8623d5b2016-02-09 02:29:10175 CreateGLTextureMailbox(gles2, texture_id_, texture_target_, &mailbox_);
revemand0b75c32016-08-12 02:46:52176 // Provides a notification when |context_provider_| is lost.
177 context_factory_->AddObserver(this);
revemanc8623d5b2016-02-09 02:29:10178}
179
revemand0b75c32016-08-12 02:46:52180Buffer::Texture::Texture(ui::ContextFactory* context_factory,
181 cc::ContextProvider* context_provider,
revemanc8623d5b2016-02-09 02:29:10182 gfx::GpuMemoryBuffer* gpu_memory_buffer,
183 unsigned texture_target,
184 unsigned query_type)
revemand0b75c32016-08-12 02:46:52185 : context_factory_(context_factory),
186 context_provider_(context_provider),
revemanc8623d5b2016-02-09 02:29:10187 texture_target_(texture_target),
188 query_type_(query_type),
189 internalformat_(GLInternalFormat(gpu_memory_buffer->GetFormat())),
revemanae3b7c852016-02-25 01:50:03190 weak_ptr_factory_(this) {
revemanc8623d5b2016-02-09 02:29:10191 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
192 gfx::Size size = gpu_memory_buffer->GetSize();
193 image_id_ =
194 gles2->CreateImageCHROMIUM(gpu_memory_buffer->AsClientBuffer(),
195 size.width(), size.height(), internalformat_);
dcastagna2db83c7ef2016-06-13 23:33:22196 DLOG_IF(WARNING, !image_id_) << "Failed to create GLImage";
197
revemanc8623d5b2016-02-09 02:29:10198 gles2->GenQueriesEXT(1, &query_id_);
199 texture_id_ = CreateGLTexture(gles2, texture_target_);
revemand0b75c32016-08-12 02:46:52200 // Provides a notification when |context_provider_| is lost.
201 context_factory_->AddObserver(this);
revemanb195f41d2015-11-19 22:16:48202}
203
revemanced21f82015-11-24 00:42:49204Buffer::Texture::~Texture() {
revemand0b75c32016-08-12 02:46:52205 DestroyResources();
206 context_factory_->RemoveObserver(this);
207}
208
209void Buffer::Texture::OnLostResources() {
210 DestroyResources();
211 context_provider_ = nullptr;
revemanb195f41d2015-11-19 22:16:48212}
213
revemanced21f82015-11-24 00:42:49214bool Buffer::Texture::IsLost() {
revemand0b75c32016-08-12 02:46:52215 if (context_provider_) {
216 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
217 return gles2->GetGraphicsResetStatusKHR() != GL_NO_ERROR;
218 }
219 return true;
revemanced21f82015-11-24 00:42:49220}
revemanb195f41d2015-11-19 22:16:48221
revemanc8623d5b2016-02-09 02:29:10222void Buffer::Texture::Release(const base::Closure& callback,
223 const gpu::SyncToken& sync_token,
224 bool is_lost) {
revemand0b75c32016-08-12 02:46:52225 if (context_provider_) {
226 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
227 if (sync_token.HasData())
228 gles2->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
229 }
revemanc8623d5b2016-02-09 02:29:10230
231 // Run callback as texture can be reused immediately after waiting for sync
232 // token.
233 callback.Run();
234}
235
revemanced21f82015-11-24 00:42:49236gpu::SyncToken Buffer::Texture::BindTexImage() {
revemanb195f41d2015-11-19 22:16:48237 gpu::SyncToken sync_token;
revemand0b75c32016-08-12 02:46:52238 if (context_provider_) {
239 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
240 gles2->ActiveTexture(GL_TEXTURE0);
241 gles2->BindTexture(texture_target_, texture_id_);
242 DCHECK_NE(image_id_, 0u);
243 gles2->BindTexImage2DCHROMIUM(texture_target_, image_id_);
244 // Generate a crypto-secure random mailbox name if not already done.
245 if (mailbox_.IsZero())
246 CreateGLTextureMailbox(gles2, texture_id_, texture_target_, &mailbox_);
247 // Create and return a sync token that can be used to ensure that the
248 // BindTexImage2DCHROMIUM call is processed before issuing any commands
249 // that will read from the texture on a different context.
250 uint64_t fence_sync = gles2->InsertFenceSyncCHROMIUM();
251 gles2->OrderingBarrierCHROMIUM();
252 gles2->GenUnverifiedSyncTokenCHROMIUM(fence_sync, sync_token.GetData());
253 }
revemanced21f82015-11-24 00:42:49254 return sync_token;
255}
256
revemanc8623d5b2016-02-09 02:29:10257void Buffer::Texture::ReleaseTexImage(const base::Closure& callback,
258 const gpu::SyncToken& sync_token,
259 bool is_lost) {
revemand0b75c32016-08-12 02:46:52260 if (context_provider_) {
261 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
262 if (sync_token.HasData())
263 gles2->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
264 gles2->ActiveTexture(GL_TEXTURE0);
265 gles2->BindTexture(texture_target_, texture_id_);
266 DCHECK_NE(query_id_, 0u);
267 gles2->BeginQueryEXT(query_type_, query_id_);
268 gles2->ReleaseTexImage2DCHROMIUM(texture_target_, image_id_);
269 gles2->EndQueryEXT(query_type_);
270 // Run callback when query result is available and ReleaseTexImage has been
271 // handled if sync token has data and buffer has been used. If buffer was
272 // never used then run the callback immediately.
273 if (sync_token.HasData()) {
274 ReleaseWhenQueryResultIsAvailable(callback);
275 return;
276 }
revemanc8623d5b2016-02-09 02:29:10277 }
revemand0b75c32016-08-12 02:46:52278 callback.Run();
revemanc8623d5b2016-02-09 02:29:10279}
280
281gpu::SyncToken Buffer::Texture::CopyTexImage(Texture* destination,
282 const base::Closure& callback) {
revemanc8623d5b2016-02-09 02:29:10283 gpu::SyncToken sync_token;
revemand0b75c32016-08-12 02:46:52284 if (context_provider_) {
285 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
286 gles2->ActiveTexture(GL_TEXTURE0);
287 gles2->BindTexture(texture_target_, texture_id_);
288 DCHECK_NE(image_id_, 0u);
289 gles2->BindTexImage2DCHROMIUM(texture_target_, image_id_);
qiankun.miao728aa862017-01-22 15:03:03290 gles2->CopyTextureCHROMIUM(texture_id_, 0, destination->texture_target_,
291 destination->texture_id_, 0, internalformat_,
292 GL_UNSIGNED_BYTE, false, false, false);
revemand0b75c32016-08-12 02:46:52293 DCHECK_NE(query_id_, 0u);
294 gles2->BeginQueryEXT(query_type_, query_id_);
295 gles2->ReleaseTexImage2DCHROMIUM(texture_target_, image_id_);
296 gles2->EndQueryEXT(query_type_);
297 // Run callback when query result is available and ReleaseTexImage has been
298 // handled.
299 ReleaseWhenQueryResultIsAvailable(callback);
300 // Create and return a sync token that can be used to ensure that the
301 // CopyTextureCHROMIUM call is processed before issuing any commands
302 // that will read from the target texture on a different context.
303 uint64_t fence_sync = gles2->InsertFenceSyncCHROMIUM();
304 gles2->OrderingBarrierCHROMIUM();
305 gles2->GenUnverifiedSyncTokenCHROMIUM(fence_sync, sync_token.GetData());
306 }
revemanc8623d5b2016-02-09 02:29:10307 return sync_token;
revemanced21f82015-11-24 00:42:49308}
309
revemand0b75c32016-08-12 02:46:52310void Buffer::Texture::DestroyResources() {
311 if (context_provider_) {
312 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
313 gles2->DeleteTextures(1, &texture_id_);
314 if (query_id_)
315 gles2->DeleteQueriesEXT(1, &query_id_);
316 if (image_id_)
317 gles2->DestroyImageCHROMIUM(image_id_);
318 }
319}
320
revemanae3b7c852016-02-25 01:50:03321void Buffer::Texture::ReleaseWhenQueryResultIsAvailable(
322 const base::Closure& callback) {
revemand0b75c32016-08-12 02:46:52323 DCHECK(context_provider_);
revemanae3b7c852016-02-25 01:50:03324 DCHECK(release_callback_.is_null());
325 release_callback_ = callback;
326 base::TimeDelta wait_for_release_delay =
327 base::TimeDelta::FromMilliseconds(kWaitForReleaseDelayMs);
328 wait_for_release_time_ = base::TimeTicks::Now() + wait_for_release_delay;
329 ScheduleWaitForRelease(wait_for_release_delay);
330 context_provider_->ContextSupport()->SignalQuery(
331 query_id_,
332 base::Bind(&Buffer::Texture::Released, weak_ptr_factory_.GetWeakPtr()));
333}
334
335void Buffer::Texture::Released() {
336 if (!release_callback_.is_null())
337 base::ResetAndReturn(&release_callback_).Run();
338}
339
340void Buffer::Texture::ScheduleWaitForRelease(base::TimeDelta delay) {
341 if (wait_for_release_pending_)
342 return;
343
344 wait_for_release_pending_ = true;
345 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
346 FROM_HERE, base::Bind(&Buffer::Texture::WaitForRelease,
347 weak_ptr_factory_.GetWeakPtr()),
348 delay);
349}
350
351void Buffer::Texture::WaitForRelease() {
352 DCHECK(wait_for_release_pending_);
353 wait_for_release_pending_ = false;
354
355 if (release_callback_.is_null())
356 return;
357
358 base::TimeTicks current_time = base::TimeTicks::Now();
359 if (current_time < wait_for_release_time_) {
360 ScheduleWaitForRelease(wait_for_release_time_ - current_time);
361 return;
362 }
363
364 base::Closure callback = base::ResetAndReturn(&release_callback_);
365
revemand0b75c32016-08-12 02:46:52366 if (context_provider_) {
revemanae3b7c852016-02-25 01:50:03367 TRACE_EVENT0("exo", "Buffer::Texture::WaitForQueryResult");
368
369 // We need to wait for the result to be available. Getting the result of
370 // the query implies waiting for it to become available. The actual result
371 // is unimportant and also not well defined.
372 unsigned result = 0;
373 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
374 gles2->GetQueryObjectuivEXT(query_id_, GL_QUERY_RESULT_EXT, &result);
375 }
376
377 callback.Run();
378}
379
revemanced21f82015-11-24 00:42:49380////////////////////////////////////////////////////////////////////////////////
381// Buffer, public:
382
dcheng31759da2016-04-21 01:26:31383Buffer::Buffer(std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer)
revemanc8623d5b2016-02-09 02:29:10384 : gpu_memory_buffer_(std::move(gpu_memory_buffer)),
385 texture_target_(GL_TEXTURE_2D),
386 query_type_(GL_COMMANDS_COMPLETED_CHROMIUM),
387 use_zero_copy_(true),
reveman2d3815d2016-06-26 20:13:25388 is_overlay_candidate_(false) {}
revemanc8623d5b2016-02-09 02:29:10389
dcheng31759da2016-04-21 01:26:31390Buffer::Buffer(std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer,
revemanc8623d5b2016-02-09 02:29:10391 unsigned texture_target,
392 unsigned query_type,
reveman244f9622016-03-04 21:33:33393 bool use_zero_copy,
394 bool is_overlay_candidate)
dcheng27f7483f2015-12-29 22:26:56395 : gpu_memory_buffer_(std::move(gpu_memory_buffer)),
revemanced21f82015-11-24 00:42:49396 texture_target_(texture_target),
revemanc8623d5b2016-02-09 02:29:10397 query_type_(query_type),
398 use_zero_copy_(use_zero_copy),
reveman2d3815d2016-06-26 20:13:25399 is_overlay_candidate_(is_overlay_candidate) {}
revemanced21f82015-11-24 00:42:49400
401Buffer::~Buffer() {}
402
starazd40f0362017-01-04 00:46:13403bool Buffer::ProduceTransferableResource(
404 CompositorFrameSinkHolder* compositor_frame_sink_holder,
405 cc::ResourceId resource_id,
reveman85b7a562016-03-17 23:27:32406 bool secure_output_only,
starazd40f0362017-01-04 00:46:13407 bool client_usage,
408 cc::TransferableResource* resource) {
jbauman45c06862016-06-23 19:35:02409 DCHECK(attach_count_);
reveman2cd69782017-02-01 20:19:44410 DLOG_IF(WARNING, !release_contents_callback_.IsCancelled() && client_usage)
revemanced21f82015-11-24 00:42:49411 << "Producing a texture mailbox for a buffer that has not been released";
412
revemanc8623d5b2016-02-09 02:29:10413 // If textures are lost, destroy them to ensure that we create new ones below.
414 if (contents_texture_ && contents_texture_->IsLost())
415 contents_texture_.reset();
416 if (texture_ && texture_->IsLost())
417 texture_.reset();
revemanced21f82015-11-24 00:42:49418
revemand0b75c32016-08-12 02:46:52419 ui::ContextFactory* context_factory =
420 aura::Env::GetInstance()->context_factory();
revemanc8623d5b2016-02-09 02:29:10421 // Note: This can fail if GPU acceleration has been disabled.
422 scoped_refptr<cc::ContextProvider> context_provider =
revemand0b75c32016-08-12 02:46:52423 context_factory->SharedMainThreadContextProvider();
revemanc8623d5b2016-02-09 02:29:10424 if (!context_provider) {
425 DLOG(WARNING) << "Failed to acquire a context provider";
starazd40f0362017-01-04 00:46:13426 resource->id = 0;
427 resource->size = gfx::Size();
428 return false;
revemanced21f82015-11-24 00:42:49429 }
430
starazd40f0362017-01-04 00:46:13431 // The reference to the CompositorFrameSinkHolder keeps it alive until a
432 // release callback is received.
433 compositor_frame_sink_holder_ = compositor_frame_sink_holder;
434
435 resource->id = resource_id;
436 resource->format = cc::RGBA_8888;
437 resource->filter = GL_LINEAR;
438 resource->size = gpu_memory_buffer_->GetSize();
439
revemanc8623d5b2016-02-09 02:29:10440 // Create a new image texture for |gpu_memory_buffer_| with |texture_target_|
441 // if one doesn't already exist. The contents of this buffer are copied to
442 // |texture| using a call to CopyTexImage.
443 if (!contents_texture_) {
ricea85ec57952016-08-31 09:34:10444 contents_texture_ = base::MakeUnique<Texture>(
445 context_factory, context_provider.get(), gpu_memory_buffer_.get(),
446 texture_target_, query_type_);
revemanc8623d5b2016-02-09 02:29:10447 }
reveman2cd69782017-02-01 20:19:44448 Texture* contents_texture = contents_texture_.get();
revemanb195f41d2015-11-19 22:16:48449
reveman2cd69782017-02-01 20:19:44450 // Cancel pending contents release callback.
451 release_contents_callback_.Reset(
452 base::Bind(&Buffer::ReleaseContents, base::Unretained(this)));
453
454 // Zero-copy means using the contents texture directly.
revemanc8623d5b2016-02-09 02:29:10455 if (use_zero_copy_) {
reveman2cd69782017-02-01 20:19:44456 // This binds the latest contents of this buffer to |contents_texture|.
457 gpu::SyncToken sync_token = contents_texture->BindTexImage();
458 resource->mailbox_holder = gpu::MailboxHolder(contents_texture->mailbox(),
459 sync_token, texture_target_);
starazd40f0362017-01-04 00:46:13460 resource->is_overlay_candidate = is_overlay_candidate_;
dcastagna84093542017-03-14 02:11:13461 resource->buffer_format = gpu_memory_buffer_->GetFormat();
starazd40f0362017-01-04 00:46:13462
revemanc8623d5b2016-02-09 02:29:10463 // The contents texture will be released when no longer used by the
464 // compositor.
starazd40f0362017-01-04 00:46:13465 compositor_frame_sink_holder_->SetResourceReleaseCallback(
466 resource_id,
reveman2cd69782017-02-01 20:19:44467 base::Bind(&Buffer::Texture::ReleaseTexImage,
468 base::Unretained(contents_texture),
revemanc8623d5b2016-02-09 02:29:10469 base::Bind(&Buffer::ReleaseContentsTexture, AsWeakPtr(),
reveman2cd69782017-02-01 20:19:44470 base::Passed(&contents_texture_),
471 release_contents_callback_.callback())));
starazd40f0362017-01-04 00:46:13472 return true;
revemanc8623d5b2016-02-09 02:29:10473 }
474
475 // Create a mailbox texture that we copy the buffer contents to.
revemand0b75c32016-08-12 02:46:52476 if (!texture_) {
477 texture_ =
ricea85ec57952016-08-31 09:34:10478 base::MakeUnique<Texture>(context_factory, context_provider.get());
revemand0b75c32016-08-12 02:46:52479 }
revemanc8623d5b2016-02-09 02:29:10480 Texture* texture = texture_.get();
481
reveman2cd69782017-02-01 20:19:44482 // Copy the contents of |contents_texture| to |texture| and produce a
483 // texture mailbox from the result in |texture|. The contents texture will
484 // be released when copy has completed.
reveman7ee8b4e2017-01-11 22:10:53485 gpu::SyncToken sync_token = contents_texture->CopyTexImage(
486 texture, base::Bind(&Buffer::ReleaseContentsTexture, AsWeakPtr(),
reveman2cd69782017-02-01 20:19:44487 base::Passed(&contents_texture_),
488 release_contents_callback_.callback()));
reveman7ee8b4e2017-01-11 22:10:53489 resource->mailbox_holder =
490 gpu::MailboxHolder(texture->mailbox(), sync_token, GL_TEXTURE_2D);
starazd40f0362017-01-04 00:46:13491 resource->is_overlay_candidate = false;
492
revemanc8623d5b2016-02-09 02:29:10493 // The mailbox texture will be released when no longer used by the
494 // compositor.
starazd40f0362017-01-04 00:46:13495 compositor_frame_sink_holder_->SetResourceReleaseCallback(
496 resource_id,
revemanc8623d5b2016-02-09 02:29:10497 base::Bind(&Buffer::Texture::Release, base::Unretained(texture),
498 base::Bind(&Buffer::ReleaseTexture, AsWeakPtr(),
499 base::Passed(&texture_))));
starazd40f0362017-01-04 00:46:13500 return true;
revemanb195f41d2015-11-19 22:16:48501}
502
jbauman45c06862016-06-23 19:35:02503void Buffer::OnAttach() {
reveman2cd69782017-02-01 20:19:44504 DLOG_IF(WARNING, attach_count_)
jbauman45c06862016-06-23 19:35:02505 << "Reattaching a buffer that is already attached to another surface.";
reveman2cd69782017-02-01 20:19:44506 ++attach_count_;
jbauman45c06862016-06-23 19:35:02507}
508
509void Buffer::OnDetach() {
510 DCHECK_GT(attach_count_, 0u);
511 --attach_count_;
reveman2cd69782017-02-01 20:19:44512
513 // Release buffer if no longer attached to a surface and content has been
514 // released.
515 if (!attach_count_ && release_contents_callback_.IsCancelled())
516 Release();
jbauman45c06862016-06-23 19:35:02517}
518
revemanb195f41d2015-11-19 22:16:48519gfx::Size Buffer::GetSize() const {
520 return gpu_memory_buffer_->GetSize();
521}
522
revemanca132dc2017-01-31 22:35:54523gfx::BufferFormat Buffer::GetFormat() const {
524 return gpu_memory_buffer_->GetFormat();
525}
526
dcheng31759da2016-04-21 01:26:31527std::unique_ptr<base::trace_event::TracedValue> Buffer::AsTracedValue() const {
528 std::unique_ptr<base::trace_event::TracedValue> value(
primianocb1afb32016-02-29 20:46:05529 new base::trace_event::TracedValue());
revemanced21f82015-11-24 00:42:49530 gfx::Size size = gpu_memory_buffer_->GetSize();
531 value->SetInteger("width", size.width());
532 value->SetInteger("height", size.height());
revemanb195f41d2015-11-19 22:16:48533 value->SetInteger("format",
534 static_cast<int>(gpu_memory_buffer_->GetFormat()));
535 return value;
536}
537
538////////////////////////////////////////////////////////////////////////////////
539// Buffer, private:
540
revemanced21f82015-11-24 00:42:49541void Buffer::Release() {
revemanced21f82015-11-24 00:42:49542 // Run release callback to notify the client that buffer has been released.
543 if (!release_callback_.is_null())
544 release_callback_.Run();
545}
revemanb195f41d2015-11-19 22:16:48546
dcheng31759da2016-04-21 01:26:31547void Buffer::ReleaseTexture(std::unique_ptr<Texture> texture) {
revemanc8623d5b2016-02-09 02:29:10548 texture_ = std::move(texture);
549}
revemanced21f82015-11-24 00:42:49550
reveman2cd69782017-02-01 20:19:44551void Buffer::ReleaseContentsTexture(std::unique_ptr<Texture> texture,
552 const base::Closure& callback) {
revemanc8623d5b2016-02-09 02:29:10553 contents_texture_ = std::move(texture);
reveman2cd69782017-02-01 20:19:44554 callback.Run();
555}
556
557void Buffer::ReleaseContents() {
558 TRACE_EVENT0("exo", "Buffer::ReleaseContents");
559
560 // Cancel callback to indicate that buffer has been released.
561 release_contents_callback_.Cancel();
562
563 // Release buffer if not attached to surface.
564 if (!attach_count_)
565 Release();
revemanb195f41d2015-11-19 22:16:48566}
567
568} // namespace exo