Home | History | Annotate | Download | only in gl
      1 // Copyright 2013 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_shm.h"
      6 
      7 #include "base/debug/trace_event.h"
      8 #include "base/process/process_handle.h"
      9 #include "ui/gl/scoped_binders.h"
     10 
     11 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
     12     defined(USE_OZONE)
     13 #include "ui/gl/gl_surface_egl.h"
     14 #endif
     15 
     16 namespace gfx {
     17 
     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 GLenum 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 GLImageShm::GLImageShm(gfx::Size size, unsigned internalformat)
     71     : size_(size),
     72       internalformat_(internalformat)
     73 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
     74     defined(USE_OZONE)
     75       ,
     76       egl_texture_id_(0u),
     77       egl_image_(EGL_NO_IMAGE_KHR)
     78 #endif
     79 {
     80 }
     81 
     82 GLImageShm::~GLImageShm() { Destroy(); }
     83 
     84 bool GLImageShm::Initialize(gfx::GpuMemoryBufferHandle buffer) {
     85   if (!ValidFormat(internalformat_)) {
     86     DVLOG(0) << "Invalid format: " << internalformat_;
     87     return false;
     88   }
     89 
     90   if (!base::SharedMemory::IsHandleValid(buffer.handle))
     91     return false;
     92 
     93   base::SharedMemory shared_memory(buffer.handle, true);
     94 
     95   // Duplicate the handle.
     96   base::SharedMemoryHandle duped_shared_memory_handle;
     97   if (!shared_memory.ShareToProcess(base::GetCurrentProcessHandle(),
     98                                     &duped_shared_memory_handle)) {
     99     DVLOG(0) << "Failed to duplicate shared memory handle.";
    100     return false;
    101   }
    102 
    103   shared_memory_.reset(
    104       new base::SharedMemory(duped_shared_memory_handle, true));
    105   return true;
    106 }
    107 
    108 void GLImageShm::Destroy() {
    109 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
    110     defined(USE_OZONE)
    111   if (egl_image_ != EGL_NO_IMAGE_KHR) {
    112     eglDestroyImageKHR(GLSurfaceEGL::GetHardwareDisplay(), egl_image_);
    113     egl_image_ = EGL_NO_IMAGE_KHR;
    114   }
    115 
    116   if (egl_texture_id_) {
    117     glDeleteTextures(1, &egl_texture_id_);
    118     egl_texture_id_ = 0u;
    119   }
    120 #endif
    121 }
    122 
    123 gfx::Size GLImageShm::GetSize() { return size_; }
    124 
    125 bool GLImageShm::BindTexImage(unsigned target) {
    126   TRACE_EVENT0("gpu", "GLImageShm::BindTexImage");
    127   DCHECK(shared_memory_);
    128   DCHECK(ValidFormat(internalformat_));
    129 
    130   size_t size = size_.GetArea() * BytesPerPixel(internalformat_);
    131   DCHECK(!shared_memory_->memory());
    132   if (!shared_memory_->Map(size)) {
    133     DVLOG(0) << "Failed to map shared memory.";
    134     return false;
    135   }
    136 
    137   DCHECK(shared_memory_->memory());
    138 
    139 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \
    140     defined(USE_OZONE)
    141   if (target == GL_TEXTURE_EXTERNAL_OES) {
    142     if (egl_image_ == EGL_NO_IMAGE_KHR) {
    143       DCHECK_EQ(0u, egl_texture_id_);
    144       glGenTextures(1, &egl_texture_id_);
    145 
    146       {
    147         ScopedTextureBinder texture_binder(GL_TEXTURE_2D, egl_texture_id_);
    148 
    149         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    150         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    151         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    152         glTexImage2D(GL_TEXTURE_2D,
    153                      0,  // mip level
    154                      TextureFormat(internalformat_),
    155                      size_.width(),
    156                      size_.height(),
    157                      0,  // border
    158                      DataFormat(internalformat_),
    159                      DataType(internalformat_),
    160                      shared_memory_->memory());
    161       }
    162 
    163       EGLint attrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
    164       // Need to pass current EGL rendering context to eglCreateImageKHR for
    165       // target type EGL_GL_TEXTURE_2D_KHR.
    166       egl_image_ =
    167           eglCreateImageKHR(GLSurfaceEGL::GetHardwareDisplay(),
    168                             eglGetCurrentContext(),
    169                             EGL_GL_TEXTURE_2D_KHR,
    170                             reinterpret_cast<EGLClientBuffer>(egl_texture_id_),
    171                             attrs);
    172       DCHECK_NE(EGL_NO_IMAGE_KHR, egl_image_)
    173           << "Error creating EGLImage: " << eglGetError();
    174     } else {
    175       ScopedTextureBinder texture_binder(GL_TEXTURE_2D, egl_texture_id_);
    176 
    177       glTexSubImage2D(GL_TEXTURE_2D,
    178                       0,  // mip level
    179                       0,  // x-offset
    180                       0,  // y-offset
    181                       size_.width(),
    182                       size_.height(),
    183                       DataFormat(internalformat_),
    184                       DataType(internalformat_),
    185                       shared_memory_->memory());
    186     }
    187 
    188     glEGLImageTargetTexture2DOES(target, egl_image_);
    189     DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
    190 
    191     shared_memory_->Unmap();
    192     return true;
    193   }
    194 #endif
    195 
    196   DCHECK_NE(static_cast<GLenum>(GL_TEXTURE_EXTERNAL_OES), target);
    197   glTexImage2D(target,
    198                0,  // mip level
    199                TextureFormat(internalformat_),
    200                size_.width(),
    201                size_.height(),
    202                0,  // border
    203                DataFormat(internalformat_),
    204                DataType(internalformat_),
    205                shared_memory_->memory());
    206 
    207   shared_memory_->Unmap();
    208   return true;
    209 }
    210 
    211 }  // namespace gfx
    212