Home | History | Annotate | Download | only in gl
      1 // Copyright 2014 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 "ui/gl/gl_image_memory.h"
      6 
      7 #include "base/debug/trace_event.h"
      8 #include "base/logging.h"
      9 #include "ui/gl/gl_bindings.h"
     10 #include "ui/gl/scoped_binders.h"
     11 
     12 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
     13     defined(USE_OZONE)
     14 #include "ui/gl/gl_surface_egl.h"
     15 #endif
     16 
     17 namespace gfx {
     18 namespace {
     19 
     20 bool ValidFormat(unsigned internalformat) {
     21   switch (internalformat) {
     22     case GL_BGRA8_EXT:
     23     case GL_RGBA8_OES:
     24       return true;
     25     default:
     26       return false;
     27   }
     28 }
     29 
     30 GLenum TextureFormat(unsigned internalformat) {
     31   switch (internalformat) {
     32     case GL_BGRA8_EXT:
     33       return GL_BGRA_EXT;
     34     case GL_RGBA8_OES:
     35       return GL_RGBA;
     36     default:
     37       NOTREACHED();
     38       return 0;
     39   }
     40 }
     41 
     42 GLenum DataFormat(unsigned internalformat) {
     43   return TextureFormat(internalformat);
     44 }
     45 
     46 GLenum DataType(unsigned internalformat) {
     47   switch (internalformat) {
     48     case GL_BGRA8_EXT:
     49     case GL_RGBA8_OES:
     50       return GL_UNSIGNED_BYTE;
     51     default:
     52       NOTREACHED();
     53       return 0;
     54   }
     55 }
     56 
     57 int BytesPerPixel(unsigned internalformat) {
     58   switch (internalformat) {
     59     case GL_BGRA8_EXT:
     60     case GL_RGBA8_OES:
     61       return 4;
     62     default:
     63       NOTREACHED();
     64       return 0;
     65   }
     66 }
     67 
     68 }  // namespace
     69 
     70 GLImageMemory::GLImageMemory(const gfx::Size& size, unsigned internalformat)
     71     : memory_(NULL),
     72       size_(size),
     73       internalformat_(internalformat),
     74       in_use_(false),
     75       target_(0),
     76       need_do_bind_tex_image_(false)
     77 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
     78     defined(USE_OZONE)
     79       ,
     80       egl_texture_id_(0u),
     81       egl_image_(EGL_NO_IMAGE_KHR)
     82 #endif
     83 {
     84 }
     85 
     86 GLImageMemory::~GLImageMemory() {
     87 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
     88     defined(USE_OZONE)
     89   DCHECK_EQ(EGL_NO_IMAGE_KHR, egl_image_);
     90   DCHECK_EQ(0u, egl_texture_id_);
     91 #endif
     92 }
     93 
     94 bool GLImageMemory::Initialize(const unsigned char* memory) {
     95   if (!ValidFormat(internalformat_)) {
     96     DVLOG(0) << "Invalid format: " << internalformat_;
     97     return false;
     98   }
     99 
    100   DCHECK(memory);
    101   DCHECK(!memory_);
    102   memory_ = memory;
    103   return true;
    104 }
    105 
    106 void GLImageMemory::Destroy(bool have_context) {
    107 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
    108     defined(USE_OZONE)
    109   if (egl_image_ != EGL_NO_IMAGE_KHR) {
    110     eglDestroyImageKHR(GLSurfaceEGL::GetHardwareDisplay(), egl_image_);
    111     egl_image_ = EGL_NO_IMAGE_KHR;
    112   }
    113 
    114   if (egl_texture_id_) {
    115     if (have_context)
    116       glDeleteTextures(1, &egl_texture_id_);
    117     egl_texture_id_ = 0u;
    118   }
    119 #endif
    120   memory_ = NULL;
    121 }
    122 
    123 gfx::Size GLImageMemory::GetSize() {
    124   return size_;
    125 }
    126 
    127 bool GLImageMemory::BindTexImage(unsigned target) {
    128   if (target_ && target_ != target) {
    129     LOG(ERROR) << "GLImage can only be bound to one target";
    130     return false;
    131   }
    132   target_ = target;
    133 
    134   // Defer DoBindTexImage if not currently in use.
    135   if (!in_use_) {
    136     need_do_bind_tex_image_ = true;
    137     return true;
    138   }
    139 
    140   DoBindTexImage(target);
    141   return true;
    142 }
    143 
    144 bool GLImageMemory::CopyTexImage(unsigned target) {
    145   TRACE_EVENT0("gpu", "GLImageMemory::CopyTexImage");
    146 
    147   // GL_TEXTURE_EXTERNAL_OES is not a supported CopyTexImage target.
    148   if (target == GL_TEXTURE_EXTERNAL_OES)
    149     return false;
    150 
    151   DCHECK(memory_);
    152   glTexImage2D(target,
    153                0,  // mip level
    154                TextureFormat(internalformat_),
    155                size_.width(),
    156                size_.height(),
    157                0,  // border
    158                DataFormat(internalformat_),
    159                DataType(internalformat_),
    160                memory_);
    161 
    162   return true;
    163 }
    164 
    165 void GLImageMemory::WillUseTexImage() {
    166   DCHECK(!in_use_);
    167   in_use_ = true;
    168 
    169   if (!need_do_bind_tex_image_)
    170     return;
    171 
    172   DCHECK(target_);
    173   DoBindTexImage(target_);
    174 }
    175 
    176 void GLImageMemory::DidUseTexImage() {
    177   DCHECK(in_use_);
    178   in_use_ = false;
    179 }
    180 
    181 bool GLImageMemory::ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
    182                                          int z_order,
    183                                          OverlayTransform transform,
    184                                          const Rect& bounds_rect,
    185                                          const RectF& crop_rect) {
    186   return false;
    187 }
    188 
    189 bool GLImageMemory::HasValidFormat() const {
    190   return ValidFormat(internalformat_);
    191 }
    192 
    193 size_t GLImageMemory::Bytes() const {
    194   return size_.GetArea() * BytesPerPixel(internalformat_);
    195 }
    196 
    197 void GLImageMemory::DoBindTexImage(unsigned target) {
    198   TRACE_EVENT0("gpu", "GLImageMemory::DoBindTexImage");
    199 
    200   DCHECK(need_do_bind_tex_image_);
    201   need_do_bind_tex_image_ = false;
    202 
    203   DCHECK(memory_);
    204 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
    205     defined(USE_OZONE)
    206   if (target == GL_TEXTURE_EXTERNAL_OES) {
    207     if (egl_image_ == EGL_NO_IMAGE_KHR) {
    208       DCHECK_EQ(0u, egl_texture_id_);
    209       glGenTextures(1, &egl_texture_id_);
    210 
    211       {
    212         ScopedTextureBinder texture_binder(GL_TEXTURE_2D, egl_texture_id_);
    213 
    214         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    215         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    216         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    217         glTexImage2D(GL_TEXTURE_2D,
    218                      0,  // mip level
    219                      TextureFormat(internalformat_),
    220                      size_.width(),
    221                      size_.height(),
    222                      0,  // border
    223                      DataFormat(internalformat_),
    224                      DataType(internalformat_),
    225                      memory_);
    226       }
    227 
    228       EGLint attrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
    229       // Need to pass current EGL rendering context to eglCreateImageKHR for
    230       // target type EGL_GL_TEXTURE_2D_KHR.
    231       egl_image_ =
    232           eglCreateImageKHR(GLSurfaceEGL::GetHardwareDisplay(),
    233                             eglGetCurrentContext(),
    234                             EGL_GL_TEXTURE_2D_KHR,
    235                             reinterpret_cast<EGLClientBuffer>(egl_texture_id_),
    236                             attrs);
    237       DCHECK_NE(EGL_NO_IMAGE_KHR, egl_image_)
    238           << "Error creating EGLImage: " << eglGetError();
    239     } else {
    240       ScopedTextureBinder texture_binder(GL_TEXTURE_2D, egl_texture_id_);
    241 
    242       glTexSubImage2D(GL_TEXTURE_2D,
    243                       0,  // mip level
    244                       0,  // x-offset
    245                       0,  // y-offset
    246                       size_.width(),
    247                       size_.height(),
    248                       DataFormat(internalformat_),
    249                       DataType(internalformat_),
    250                       memory_);
    251     }
    252 
    253     glEGLImageTargetTexture2DOES(target, egl_image_);
    254     DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
    255     return;
    256   }
    257 #endif
    258 
    259   DCHECK_NE(static_cast<GLenum>(GL_TEXTURE_EXTERNAL_OES), target);
    260   glTexImage2D(target,
    261                0,  // mip level
    262                TextureFormat(internalformat_),
    263                size_.width(),
    264                size_.height(),
    265                0,  // border
    266                DataFormat(internalformat_),
    267                DataType(internalformat_),
    268                memory_);
    269 }
    270 
    271 }  // namespace gfx
    272