| Index: components/exo/buffer.cc | 
| diff --git a/components/exo/buffer.cc b/components/exo/buffer.cc | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..2f229ad65aa03a11715facc269442a50791ae877 | 
| --- /dev/null | 
| +++ b/components/exo/buffer.cc | 
| @@ -0,0 +1,187 @@ | 
| +// Copyright 2015 The Chromium Authors. All rights reserved. | 
| +// Use of this source code is governed by a BSD-style license that can be | 
| +// found in the LICENSE file. | 
| + | 
| +#include "components/exo/buffer.h" | 
| + | 
| +#include <GLES2/gl2.h> | 
| +#include <GLES2/gl2ext.h> | 
| +#include <GLES2/gl2extchromium.h> | 
| + | 
| +#include <algorithm> | 
| + | 
| +#include "base/logging.h" | 
| +#include "base/trace_event/trace_event.h" | 
| +#include "base/trace_event/trace_event_argument.h" | 
| +#include "cc/output/context_provider.h" | 
| +#include "cc/resources/single_release_callback.h" | 
| +#include "cc/resources/texture_mailbox.h" | 
| +#include "gpu/command_buffer/client/gles2_interface.h" | 
| +#include "ui/aura/env.h" | 
| +#include "ui/compositor/compositor.h" | 
| +#include "ui/gfx/gpu_memory_buffer.h" | 
| + | 
| +namespace exo { | 
| +namespace { | 
| + | 
| +GLenum GLInternalFormat(gfx::BufferFormat format) { | 
| +  const GLenum kGLInternalFormats[] = { | 
| +      GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD,  // ATC | 
| +      GL_COMPRESSED_RGB_S3TC_DXT1_EXT,     // ATCIA | 
| +      GL_COMPRESSED_RGB_S3TC_DXT1_EXT,     // DXT1 | 
| +      GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,    // DXT5 | 
| +      GL_ETC1_RGB8_OES,                    // ETC1 | 
| +      GL_R8_EXT,                           // R_8 | 
| +      GL_RGBA,                             // RGBA_4444 | 
| +      GL_RGB,                              // RGBX_8888 | 
| +      GL_RGBA,                             // RGBA_8888 | 
| +      GL_RGB,                              // BGRX_8888 | 
| +      GL_BGRA_EXT,                         // BGRA_8888 | 
| +      GL_RGB_YUV_420_CHROMIUM,             // YUV_420 | 
| +      GL_INVALID_ENUM,                     // YUV_420_BIPLANAR | 
| +      GL_RGB_YCBCR_422_CHROMIUM,           // UYVY_422 | 
| +  }; | 
| +  static_assert(arraysize(kGLInternalFormats) == | 
| +                    (static_cast<int>(gfx::BufferFormat::LAST) + 1), | 
| +                "BufferFormat::LAST must be last value of kGLInternalFormats"); | 
| + | 
| +  DCHECK(format <= gfx::BufferFormat::LAST); | 
| +  return kGLInternalFormats[static_cast<int>(format)]; | 
| +} | 
| + | 
| +gpu::gles2::GLES2Interface* GetContextGL() { | 
| +  ui::ContextFactory* context_factory = | 
| +      aura::Env::GetInstance()->context_factory(); | 
| +  return context_factory->SharedMainThreadContextProvider()->ContextGL(); | 
| +} | 
| + | 
| +}  // namespace | 
| + | 
| +//////////////////////////////////////////////////////////////////////////////// | 
| +// Buffer, public: | 
| + | 
| +Buffer::Buffer(scoped_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer, | 
| +               unsigned texture_target) | 
| +    : gpu_memory_buffer_(gpu_memory_buffer.Pass()), | 
| +      texture_target_(texture_target), | 
| +      texture_id_(0), | 
| +      image_id_(0) { | 
| +  gpu::gles2::GLES2Interface* gles2 = GetContextGL(); | 
| +  // Create an image for |gpu_memory_buffer_|. | 
| +  gfx::Size size = gpu_memory_buffer_->GetSize(); | 
| +  image_id_ = gles2->CreateImageCHROMIUM( | 
| +      gpu_memory_buffer_->AsClientBuffer(), size.width(), size.height(), | 
| +      GLInternalFormat(gpu_memory_buffer_->GetFormat())); | 
| +  // Create a texture with |texture_target_|. | 
| +  gles2->ActiveTexture(GL_TEXTURE0); | 
| +  gles2->GenTextures(1, &texture_id_); | 
| +  gles2->BindTexture(texture_target_, texture_id_); | 
| +  gles2->TexParameteri(texture_target_, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | 
| +  gles2->TexParameteri(texture_target_, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | 
| +  gles2->TexParameteri(texture_target_, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | 
| +  gles2->TexParameteri(texture_target_, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | 
| +  // Generate a crypto-secure random mailbox name. | 
| +  gles2->GenMailboxCHROMIUM(mailbox_.name); | 
| +  gles2->ProduceTextureCHROMIUM(texture_target_, mailbox_.name); | 
| +} | 
| + | 
| +Buffer::~Buffer() { | 
| +  gpu::gles2::GLES2Interface* gles2 = GetContextGL(); | 
| +  if (texture_id_) | 
| +    gles2->DeleteTextures(1, &texture_id_); | 
| +  if (image_id_) | 
| +    gles2->DestroyImageCHROMIUM(image_id_); | 
| +} | 
| + | 
| +scoped_ptr<cc::SingleReleaseCallback> Buffer::AcquireTextureMailbox( | 
| +    cc::TextureMailbox* texture_mailbox) { | 
| +  // Buffer can only be used by one client at a time. If texture id is 0, then a | 
| +  // previous call to AcquireTextureMailbox() is using this buffer and it has | 
| +  // not been released yet. | 
| +  if (!texture_id_) { | 
| +    DLOG(WARNING) << "Client tried to use a buffer that has not been released"; | 
| +    return nullptr; | 
| +  } | 
| + | 
| +  // Take ownerhsip of image and texture ids. | 
| +  unsigned texture_id = 0; | 
| +  unsigned image_id = 0; | 
| +  std::swap(texture_id, texture_id_); | 
| +  DCHECK_NE(image_id_, 0u); | 
| +  std::swap(image_id, image_id_); | 
| + | 
| +  // Bind texture to |texture_target_|. | 
| +  gpu::gles2::GLES2Interface* gles2 = GetContextGL(); | 
| +  gles2->ActiveTexture(GL_TEXTURE0); | 
| +  gles2->BindTexture(texture_target_, texture_id); | 
| + | 
| +  // Bind the image to texture. | 
| +  gles2->BindTexImage2DCHROMIUM(texture_target_, image_id); | 
| + | 
| +  // Create a sync token to ensure that the BindTexImage2DCHROMIUM call is | 
| +  // processed before issuing any commands that will read from texture. | 
| +  uint64 fence_sync = gles2->InsertFenceSyncCHROMIUM(); | 
| +  gles2->ShallowFlushCHROMIUM(); | 
| +  gpu::SyncToken sync_token; | 
| +  gles2->GenUnverifiedSyncTokenCHROMIUM(fence_sync, sync_token.GetData()); | 
| + | 
| +  bool is_overlay_candidate = false; | 
| +  *texture_mailbox = | 
| +      cc::TextureMailbox(mailbox_, sync_token, texture_target_, | 
| +                         gpu_memory_buffer_->GetSize(), is_overlay_candidate); | 
| +  return cc::SingleReleaseCallback::Create( | 
| +             base::Bind(&Buffer::Release, AsWeakPtr(), texture_target_, | 
| +                        texture_id, image_id)) | 
| +      .Pass(); | 
| +} | 
| + | 
| +gfx::Size Buffer::GetSize() const { | 
| +  return gpu_memory_buffer_->GetSize(); | 
| +} | 
| + | 
| +scoped_refptr<base::trace_event::TracedValue> Buffer::AsTracedValue() const { | 
| +  scoped_refptr<base::trace_event::TracedValue> value = | 
| +      new base::trace_event::TracedValue; | 
| +  value->SetInteger("width", GetSize().width()); | 
| +  value->SetInteger("height", GetSize().height()); | 
| +  value->SetInteger("format", | 
| +                    static_cast<int>(gpu_memory_buffer_->GetFormat())); | 
| +  return value; | 
| +} | 
| + | 
| +//////////////////////////////////////////////////////////////////////////////// | 
| +// Buffer, private: | 
| + | 
| +// static | 
| +void Buffer::Release(base::WeakPtr<Buffer> buffer, | 
| +                     unsigned texture_target, | 
| +                     unsigned texture_id, | 
| +                     unsigned image_id, | 
| +                     const gpu::SyncToken& sync_token, | 
| +                     bool is_lost) { | 
| +  TRACE_EVENT1("exo", "Buffer::Release", "is_lost", is_lost); | 
| + | 
| +  gpu::gles2::GLES2Interface* gles2 = GetContextGL(); | 
| +  if (sync_token.HasData()) | 
| +    gles2->WaitSyncTokenCHROMIUM(sync_token.GetConstData()); | 
| +  gles2->ActiveTexture(GL_TEXTURE0); | 
| +  gles2->BindTexture(texture_target, texture_id); | 
| +  gles2->ReleaseTexImage2DCHROMIUM(texture_target, image_id); | 
| + | 
| +  // Delete resources and return if buffer is gone. | 
| +  if (!buffer) { | 
| +    gles2->DeleteTextures(1, &texture_id); | 
| +    gles2->DestroyImageCHROMIUM(image_id); | 
| +    return; | 
| +  } | 
| + | 
| +  DCHECK_EQ(buffer->texture_id_, 0u); | 
| +  buffer->texture_id_ = texture_id; | 
| +  DCHECK_EQ(buffer->image_id_, 0u); | 
| +  buffer->image_id_ = image_id; | 
| + | 
| +  if (!buffer->release_callback_.is_null()) | 
| +    buffer->release_callback_.Run(); | 
| +} | 
| + | 
| +}  // namespace exo | 
|  |