diff options
Diffstat (limited to 'ui/gl/gl_image_memory.cc')
-rw-r--r-- | ui/gl/gl_image_memory.cc | 224 |
1 files changed, 198 insertions, 26 deletions
diff --git a/ui/gl/gl_image_memory.cc b/ui/gl/gl_image_memory.cc index 045c50c..c91ad56 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 @@ GLsizei SizeInBytes(const Size& size, BufferFormat format) { 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 @@ bool GLImageMemory::Initialize(const unsigned char* memory, } 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 @@ unsigned GLImageMemory::GetInternalFormat() { } 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) + if (target_ && target_ != target) { + LOG(ERROR) << "GLImage can only be bound to one target"; return false; + } + target_ = target; - 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_); + // 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 @@ bool GLImageMemory::CopyTexSubImage(unsigned target, 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,18 +308,36 @@ bool GLImageMemory::CopyTexSubImage(unsigned target, 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, int z_order, OverlayTransform transform, @@ -302,4 +346,132 @@ bool GLImageMemory::ScheduleOverlayPlane(AcceleratedWidget widget, 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 |