Index: ui/gl/gl_image_memory.cc |
diff --git a/ui/gl/gl_image_memory.cc b/ui/gl/gl_image_memory.cc |
index 045c50c464fa143353938887763329af87e22911..c91ad5635f9ccad1e124e926a436b49fcc442146 100644 |
--- a/ui/gl/gl_image_memory.cc |
+++ b/ui/gl/gl_image_memory.cc |
@@ -7,6 +7,12 @@ |
#include "base/logging.h" |
#include "base/trace_event/trace_event.h" |
#include "ui/gl/gl_bindings.h" |
+#include "ui/gl/scoped_binders.h" |
+ |
+#if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \ |
+ defined(USE_OZONE) |
+#include "ui/gl/gl_surface_egl.h" |
+#endif |
namespace gfx { |
namespace { |
@@ -146,11 +152,26 @@ |
GLImageMemory::GLImageMemory(const Size& size, unsigned internalformat) |
: size_(size), |
internalformat_(internalformat), |
- memory_(nullptr), |
- format_(BufferFormat::RGBA_8888) {} |
+ memory_(NULL), |
+ format_(BufferFormat::RGBA_8888), |
+ in_use_(false), |
+ target_(0), |
+ need_do_bind_tex_image_(false) |
+#if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \ |
+ defined(USE_OZONE) |
+ , |
+ egl_texture_id_(0u), |
+ egl_image_(EGL_NO_IMAGE_KHR) |
+#endif |
+{ |
+} |
GLImageMemory::~GLImageMemory() { |
- DCHECK(!memory_); |
+#if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \ |
+ defined(USE_OZONE) |
+ DCHECK_EQ(EGL_NO_IMAGE_KHR, egl_image_); |
+ DCHECK_EQ(0u, egl_texture_id_); |
+#endif |
} |
// static |
@@ -222,7 +243,20 @@ |
} |
void GLImageMemory::Destroy(bool have_context) { |
- memory_ = nullptr; |
+#if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \ |
+ defined(USE_OZONE) |
+ if (egl_image_ != EGL_NO_IMAGE_KHR) { |
+ eglDestroyImageKHR(GLSurfaceEGL::GetHardwareDisplay(), egl_image_); |
+ egl_image_ = EGL_NO_IMAGE_KHR; |
+ } |
+ |
+ if (egl_texture_id_) { |
+ if (have_context) |
+ glDeleteTextures(1, &egl_texture_id_); |
+ egl_texture_id_ = 0u; |
+ } |
+#endif |
+ memory_ = NULL; |
} |
Size GLImageMemory::GetSize() { |
@@ -234,27 +268,19 @@ |
} |
bool GLImageMemory::BindTexImage(unsigned target) { |
- return false; |
-} |
- |
-bool GLImageMemory::CopyTexImage(unsigned target) { |
- TRACE_EVENT2("gpu", "GLImageMemory::CopyTexImage", "width", size_.width(), |
- "height", size_.height()); |
- |
- // GL_TEXTURE_EXTERNAL_OES is not a supported target. |
- if (target == GL_TEXTURE_EXTERNAL_OES) |
- return false; |
- |
- if (IsCompressedFormat(format_)) { |
- glCompressedTexImage2D(target, 0, TextureFormat(format_), size_.width(), |
- size_.height(), 0, SizeInBytes(size_, format_), |
- memory_); |
- } else { |
- glTexImage2D(target, 0, TextureFormat(format_), size_.width(), |
- size_.height(), 0, DataFormat(format_), DataType(format_), |
- memory_); |
- } |
- |
+ if (target_ && target_ != target) { |
+ LOG(ERROR) << "GLImage can only be bound to one target"; |
+ return false; |
+ } |
+ target_ = target; |
+ |
+ // Defer DoBindTexImage if not currently in use. |
+ if (!in_use_) { |
+ need_do_bind_tex_image_ = true; |
+ return true; |
+ } |
+ |
+ DoBindTexImage(target); |
return true; |
} |
@@ -264,7 +290,7 @@ |
TRACE_EVENT2("gpu", "GLImageMemory::CopyTexSubImage", "width", rect.width(), |
"height", rect.height()); |
- // GL_TEXTURE_EXTERNAL_OES is not a supported target. |
+ // GL_TEXTURE_EXTERNAL_OES is not a supported CopyTexSubImage target. |
if (target == GL_TEXTURE_EXTERNAL_OES) |
return false; |
@@ -282,16 +308,34 @@ |
DCHECK(memory_); |
const unsigned char* data = memory_ + rect.y() * stride_in_bytes; |
if (IsCompressedFormat(format_)) { |
- glCompressedTexSubImage2D(target, 0, offset.x(), offset.y(), rect.width(), |
+ glCompressedTexSubImage2D(target, |
+ 0, // level |
+ offset.x(), offset.y(), rect.width(), |
rect.height(), DataFormat(format_), |
SizeInBytes(rect.size(), format_), data); |
} else { |
- glTexSubImage2D(target, 0, offset.x(), offset.y(), rect.width(), |
- rect.height(), DataFormat(format_), DataType(format_), |
- data); |
+ glTexSubImage2D(target, 0, // level |
+ offset.x(), offset.y(), rect.width(), rect.height(), |
+ DataFormat(format_), DataType(format_), data); |
} |
return true; |
+} |
+ |
+void GLImageMemory::WillUseTexImage() { |
+ DCHECK(!in_use_); |
+ in_use_ = true; |
+ |
+ if (!need_do_bind_tex_image_) |
+ return; |
+ |
+ DCHECK(target_); |
+ DoBindTexImage(target_); |
+} |
+ |
+void GLImageMemory::DidUseTexImage() { |
+ DCHECK(in_use_); |
+ in_use_ = false; |
} |
bool GLImageMemory::ScheduleOverlayPlane(AcceleratedWidget widget, |
@@ -302,4 +346,132 @@ |
return false; |
} |
+void GLImageMemory::DoBindTexImage(unsigned target) { |
+ TRACE_EVENT0("gpu", "GLImageMemory::DoBindTexImage"); |
+ |
+ DCHECK(need_do_bind_tex_image_); |
+ need_do_bind_tex_image_ = false; |
+ |
+ DCHECK(memory_); |
+#if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \ |
+ defined(USE_OZONE) |
+ if (target == GL_TEXTURE_EXTERNAL_OES) { |
+ if (egl_image_ == EGL_NO_IMAGE_KHR) { |
+ DCHECK_EQ(0u, egl_texture_id_); |
+ glGenTextures(1, &egl_texture_id_); |
+ |
+ { |
+ ScopedTextureBinder texture_binder(GL_TEXTURE_2D, egl_texture_id_); |
+ |
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
+ if (IsCompressedFormat(format_)) { |
+ glCompressedTexImage2D(GL_TEXTURE_2D, |
+ 0, // mip level |
+ TextureFormat(format_), size_.width(), |
+ size_.height(), |
+ 0, // border |
+ SizeInBytes(size_, format_), memory_); |
+ } else { |
+ glTexImage2D(GL_TEXTURE_2D, |
+ 0, // mip level |
+ TextureFormat(format_), |
+ size_.width(), |
+ size_.height(), |
+ 0, // border |
+ DataFormat(format_), |
+ DataType(format_), |
+ memory_); |
+ } |
+ } |
+ |
+ EGLint attrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE}; |
+ // Need to pass current EGL rendering context to eglCreateImageKHR for |
+ // target type EGL_GL_TEXTURE_2D_KHR. |
+ egl_image_ = |
+ eglCreateImageKHR(GLSurfaceEGL::GetHardwareDisplay(), |
+ eglGetCurrentContext(), |
+ EGL_GL_TEXTURE_2D_KHR, |
+ reinterpret_cast<EGLClientBuffer>(egl_texture_id_), |
+ attrs); |
+ DCHECK_NE(EGL_NO_IMAGE_KHR, egl_image_) |
+ << "Error creating EGLImage: " << eglGetError(); |
+ } else { |
+ ScopedTextureBinder texture_binder(GL_TEXTURE_2D, egl_texture_id_); |
+ |
+ if (IsCompressedFormat(format_)) { |
+ glCompressedTexSubImage2D(GL_TEXTURE_2D, |
+ 0, // mip level |
+ 0, // x-offset |
+ 0, // y-offset |
+ size_.width(), size_.height(), |
+ DataFormat(format_), |
+ SizeInBytes(size_, format_), memory_); |
+ } else { |
+ glTexSubImage2D(GL_TEXTURE_2D, |
+ 0, // mip level |
+ 0, // x-offset |
+ 0, // y-offset |
+ size_.width(), |
+ size_.height(), |
+ DataFormat(format_), |
+ DataType(format_), |
+ memory_); |
+ } |
+ } |
+ |
+ glEGLImageTargetTexture2DOES(target, egl_image_); |
+ DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); |
+ return; |
+ } |
+#endif |
+ |
+ DCHECK_NE(static_cast<GLenum>(GL_TEXTURE_EXTERNAL_OES), target); |
+ if (IsCompressedFormat(format_)) { |
+ glCompressedTexImage2D(target, |
+ 0, // mip level |
+ TextureFormat(format_), size_.width(), |
+ size_.height(), |
+ 0, // border |
+ SizeInBytes(size_, format_), memory_); |
+ } else { |
+ glTexImage2D(target, |
+ 0, // mip level |
+ TextureFormat(format_), |
+ size_.width(), |
+ size_.height(), |
+ 0, // border |
+ DataFormat(format_), |
+ DataType(format_), |
+ memory_); |
+ } |
+} |
+ |
+void GLImageMemory::OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd, |
+ uint64_t process_tracing_id, |
+ const std::string& dump_name) { |
+ // Note that the following calculation does not consider whether this GLImage |
+ // has been un-bound from a texture. It also relies on this GLImage only ever |
+ // being bound to a single texture. We could check these conditions more |
+ // thoroughly, but at the cost of extra GL queries. |
+ bool is_bound_to_texture = target_ && !need_do_bind_tex_image_; |
+ |
+#if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \ |
+ defined(USE_OZONE) |
+ is_bound_to_texture |= !!egl_texture_id_; |
+#endif |
+ |
+ size_t size_in_bytes = is_bound_to_texture ? SizeInBytes(size_, format_) : 0; |
+ |
+ base::trace_event::MemoryAllocatorDump* dump = |
+ pmd->CreateAllocatorDump(dump_name + "/texture_memory"); |
+ dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize, |
+ base::trace_event::MemoryAllocatorDump::kUnitsBytes, |
+ static_cast<uint64_t>(size_in_bytes)); |
+ |
+ // No need for a global shared edge here. This object in the GPU process is |
+ // the sole owner of this texture id. |
+} |
+ |
} // namespace gfx |