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