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