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 |