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 "gpu/command_buffer/service/texture_definition.h" 6 7 #include <list> 8 9 #include "base/memory/linked_ptr.h" 10 #include "base/memory/scoped_ptr.h" 11 #include "base/synchronization/lock.h" 12 #include "gpu/command_buffer/service/texture_manager.h" 13 #include "ui/gl/gl_image.h" 14 #include "ui/gl/gl_implementation.h" 15 #include "ui/gl/scoped_binders.h" 16 17 #if !defined(OS_MACOSX) 18 #include "ui/gl/gl_surface_egl.h" 19 #endif 20 21 namespace gpu { 22 namespace gles2 { 23 24 namespace { 25 26 class GLImageSync : public gfx::GLImage { 27 public: 28 explicit GLImageSync(const scoped_refptr<NativeImageBuffer>& buffer, 29 const gfx::Size& size); 30 31 // Implement GLImage. 32 virtual void Destroy(bool have_context) OVERRIDE; 33 virtual gfx::Size GetSize() OVERRIDE; 34 virtual bool BindTexImage(unsigned target) OVERRIDE; 35 virtual void ReleaseTexImage(unsigned target) OVERRIDE; 36 virtual bool CopyTexImage(unsigned target) OVERRIDE; 37 virtual void WillUseTexImage() OVERRIDE; 38 virtual void WillModifyTexImage() OVERRIDE; 39 virtual void DidModifyTexImage() OVERRIDE; 40 virtual void DidUseTexImage() OVERRIDE; 41 virtual bool ScheduleOverlayPlane(gfx::AcceleratedWidget widget, 42 int z_order, 43 gfx::OverlayTransform transform, 44 const gfx::Rect& bounds_rect, 45 const gfx::RectF& crop_rect) OVERRIDE; 46 virtual void SetReleaseAfterUse() OVERRIDE; 47 48 protected: 49 virtual ~GLImageSync(); 50 51 private: 52 scoped_refptr<NativeImageBuffer> buffer_; 53 gfx::Size size_; 54 55 DISALLOW_COPY_AND_ASSIGN(GLImageSync); 56 }; 57 58 GLImageSync::GLImageSync(const scoped_refptr<NativeImageBuffer>& buffer, 59 const gfx::Size& size) 60 : buffer_(buffer), size_(size) { 61 if (buffer.get()) 62 buffer->AddClient(this); 63 } 64 65 GLImageSync::~GLImageSync() { 66 if (buffer_.get()) 67 buffer_->RemoveClient(this); 68 } 69 70 void GLImageSync::Destroy(bool have_context) { 71 } 72 73 gfx::Size GLImageSync::GetSize() { 74 return size_; 75 } 76 77 bool GLImageSync::BindTexImage(unsigned target) { 78 NOTREACHED(); 79 return false; 80 } 81 82 void GLImageSync::ReleaseTexImage(unsigned target) { 83 NOTREACHED(); 84 } 85 86 bool GLImageSync::CopyTexImage(unsigned target) { 87 return false; 88 } 89 90 void GLImageSync::WillUseTexImage() { 91 } 92 93 void GLImageSync::DidUseTexImage() { 94 } 95 96 void GLImageSync::WillModifyTexImage() { 97 } 98 99 void GLImageSync::DidModifyTexImage() { 100 } 101 102 bool GLImageSync::ScheduleOverlayPlane(gfx::AcceleratedWidget widget, 103 int z_order, 104 gfx::OverlayTransform transform, 105 const gfx::Rect& bounds_rect, 106 const gfx::RectF& crop_rect) { 107 NOTREACHED(); 108 return false; 109 } 110 111 void GLImageSync::SetReleaseAfterUse() { 112 NOTREACHED(); 113 } 114 115 #if !defined(OS_MACOSX) 116 class NativeImageBufferEGL : public NativeImageBuffer { 117 public: 118 static scoped_refptr<NativeImageBufferEGL> Create(GLuint texture_id); 119 120 private: 121 NativeImageBufferEGL(EGLDisplay display, EGLImageKHR image); 122 virtual ~NativeImageBufferEGL(); 123 virtual void AddClient(gfx::GLImage* client) OVERRIDE; 124 virtual void RemoveClient(gfx::GLImage* client) OVERRIDE; 125 virtual bool IsClient(gfx::GLImage* client) OVERRIDE; 126 virtual void BindToTexture(GLenum target) OVERRIDE; 127 128 EGLDisplay egl_display_; 129 EGLImageKHR egl_image_; 130 131 base::Lock lock_; 132 133 struct ClientInfo { 134 ClientInfo(gfx::GLImage* client); 135 ~ClientInfo(); 136 137 gfx::GLImage* client; 138 bool needs_wait_before_read; 139 }; 140 std::list<ClientInfo> client_infos_; 141 gfx::GLImage* write_client_; 142 143 DISALLOW_COPY_AND_ASSIGN(NativeImageBufferEGL); 144 }; 145 146 scoped_refptr<NativeImageBufferEGL> NativeImageBufferEGL::Create( 147 GLuint texture_id) { 148 EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay(); 149 EGLContext egl_context = eglGetCurrentContext(); 150 151 DCHECK_NE(EGL_NO_CONTEXT, egl_context); 152 DCHECK_NE(EGL_NO_DISPLAY, egl_display); 153 DCHECK(glIsTexture(texture_id)); 154 155 DCHECK(gfx::g_driver_egl.ext.b_EGL_KHR_image_base && 156 gfx::g_driver_egl.ext.b_EGL_KHR_gl_texture_2D_image && 157 gfx::g_driver_gl.ext.b_GL_OES_EGL_image); 158 159 const EGLint egl_attrib_list[] = { 160 EGL_GL_TEXTURE_LEVEL_KHR, 0, EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE}; 161 EGLClientBuffer egl_buffer = reinterpret_cast<EGLClientBuffer>(texture_id); 162 EGLenum egl_target = EGL_GL_TEXTURE_2D_KHR; // TODO 163 164 EGLImageKHR egl_image = eglCreateImageKHR( 165 egl_display, egl_context, egl_target, egl_buffer, egl_attrib_list); 166 167 if (egl_image == EGL_NO_IMAGE_KHR) 168 return NULL; 169 170 return new NativeImageBufferEGL(egl_display, egl_image); 171 } 172 173 NativeImageBufferEGL::ClientInfo::ClientInfo(gfx::GLImage* client) 174 : client(client), needs_wait_before_read(true) {} 175 176 NativeImageBufferEGL::ClientInfo::~ClientInfo() {} 177 178 NativeImageBufferEGL::NativeImageBufferEGL(EGLDisplay display, 179 EGLImageKHR image) 180 : NativeImageBuffer(), 181 egl_display_(display), 182 egl_image_(image), 183 write_client_(NULL) { 184 DCHECK(egl_display_ != EGL_NO_DISPLAY); 185 DCHECK(egl_image_ != EGL_NO_IMAGE_KHR); 186 } 187 188 NativeImageBufferEGL::~NativeImageBufferEGL() { 189 DCHECK(client_infos_.empty()); 190 if (egl_image_ != EGL_NO_IMAGE_KHR) 191 eglDestroyImageKHR(egl_display_, egl_image_); 192 } 193 194 void NativeImageBufferEGL::AddClient(gfx::GLImage* client) { 195 base::AutoLock lock(lock_); 196 client_infos_.push_back(ClientInfo(client)); 197 } 198 199 void NativeImageBufferEGL::RemoveClient(gfx::GLImage* client) { 200 base::AutoLock lock(lock_); 201 if (write_client_ == client) 202 write_client_ = NULL; 203 for (std::list<ClientInfo>::iterator it = client_infos_.begin(); 204 it != client_infos_.end(); 205 it++) { 206 if (it->client == client) { 207 client_infos_.erase(it); 208 return; 209 } 210 } 211 NOTREACHED(); 212 } 213 214 bool NativeImageBufferEGL::IsClient(gfx::GLImage* client) { 215 base::AutoLock lock(lock_); 216 for (std::list<ClientInfo>::iterator it = client_infos_.begin(); 217 it != client_infos_.end(); 218 it++) { 219 if (it->client == client) 220 return true; 221 } 222 return false; 223 } 224 225 void NativeImageBufferEGL::BindToTexture(GLenum target) { 226 DCHECK(egl_image_ != EGL_NO_IMAGE_KHR); 227 glEGLImageTargetTexture2DOES(target, egl_image_); 228 DCHECK_EQ(static_cast<EGLint>(EGL_SUCCESS), eglGetError()); 229 DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); 230 } 231 232 #endif 233 234 class NativeImageBufferStub : public NativeImageBuffer { 235 public: 236 NativeImageBufferStub() : NativeImageBuffer() {} 237 238 private: 239 virtual ~NativeImageBufferStub() {} 240 virtual void AddClient(gfx::GLImage* client) OVERRIDE {} 241 virtual void RemoveClient(gfx::GLImage* client) OVERRIDE {} 242 virtual bool IsClient(gfx::GLImage* client) OVERRIDE { return true; } 243 virtual void BindToTexture(GLenum target) OVERRIDE {} 244 245 DISALLOW_COPY_AND_ASSIGN(NativeImageBufferStub); 246 }; 247 248 } // anonymous namespace 249 250 // static 251 scoped_refptr<NativeImageBuffer> NativeImageBuffer::Create(GLuint texture_id) { 252 switch (gfx::GetGLImplementation()) { 253 #if !defined(OS_MACOSX) 254 case gfx::kGLImplementationEGLGLES2: 255 return NativeImageBufferEGL::Create(texture_id); 256 #endif 257 case gfx::kGLImplementationMockGL: 258 return new NativeImageBufferStub; 259 default: 260 NOTREACHED(); 261 return NULL; 262 } 263 } 264 265 TextureDefinition::LevelInfo::LevelInfo(GLenum target, 266 GLenum internal_format, 267 GLsizei width, 268 GLsizei height, 269 GLsizei depth, 270 GLint border, 271 GLenum format, 272 GLenum type, 273 bool cleared) 274 : target(target), 275 internal_format(internal_format), 276 width(width), 277 height(height), 278 depth(depth), 279 border(border), 280 format(format), 281 type(type), 282 cleared(cleared) {} 283 284 TextureDefinition::LevelInfo::~LevelInfo() {} 285 286 TextureDefinition::TextureDefinition( 287 GLenum target, 288 Texture* texture, 289 unsigned int version, 290 const scoped_refptr<NativeImageBuffer>& image_buffer) 291 : version_(version), 292 target_(target), 293 image_buffer_(image_buffer.get() 294 ? image_buffer 295 : NativeImageBuffer::Create(texture->service_id())), 296 min_filter_(texture->min_filter()), 297 mag_filter_(texture->mag_filter()), 298 wrap_s_(texture->wrap_s()), 299 wrap_t_(texture->wrap_t()), 300 usage_(texture->usage()), 301 immutable_(texture->IsImmutable()) { 302 // TODO 303 DCHECK(!texture->level_infos_.empty()); 304 DCHECK(!texture->level_infos_[0].empty()); 305 DCHECK(!texture->NeedsMips()); 306 DCHECK(texture->level_infos_[0][0].width); 307 DCHECK(texture->level_infos_[0][0].height); 308 309 scoped_refptr<gfx::GLImage> gl_image( 310 new GLImageSync(image_buffer_, 311 gfx::Size(texture->level_infos_[0][0].width, 312 texture->level_infos_[0][0].height))); 313 texture->SetLevelImage(NULL, target, 0, gl_image.get()); 314 315 // TODO: all levels 316 level_infos_.clear(); 317 const Texture::LevelInfo& level = texture->level_infos_[0][0]; 318 LevelInfo info(level.target, 319 level.internal_format, 320 level.width, 321 level.height, 322 level.depth, 323 level.border, 324 level.format, 325 level.type, 326 level.cleared); 327 std::vector<LevelInfo> infos; 328 infos.push_back(info); 329 level_infos_.push_back(infos); 330 } 331 332 TextureDefinition::~TextureDefinition() { 333 } 334 335 Texture* TextureDefinition::CreateTexture() const { 336 if (!image_buffer_.get()) 337 return NULL; 338 339 GLuint texture_id; 340 glGenTextures(1, &texture_id); 341 342 Texture* texture(new Texture(texture_id)); 343 UpdateTexture(texture); 344 345 return texture; 346 } 347 348 void TextureDefinition::UpdateTexture(Texture* texture) const { 349 gfx::ScopedTextureBinder texture_binder(target_, texture->service_id()); 350 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter_); 351 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter_); 352 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s_); 353 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t_); 354 if (image_buffer_.get()) 355 image_buffer_->BindToTexture(target_); 356 // We have to make sure the changes are visible to other clients in this share 357 // group. As far as the clients are concerned, the mailbox semantics only 358 // demand a single flush from the client after changes are first made, 359 // and it is not visible to them when another share group boundary is crossed. 360 // We could probably track this and be a bit smarter about when to flush 361 // though. 362 glFlush(); 363 364 texture->level_infos_.resize(1); 365 for (size_t i = 0; i < level_infos_.size(); i++) { 366 const LevelInfo& base_info = level_infos_[i][0]; 367 const size_t levels_needed = TextureManager::ComputeMipMapCount( 368 base_info.target, base_info.width, base_info.height, base_info.depth); 369 DCHECK(level_infos_.size() <= levels_needed); 370 texture->level_infos_[0].resize(levels_needed); 371 for (size_t n = 0; n < level_infos_.size(); n++) { 372 const LevelInfo& info = level_infos_[i][n]; 373 texture->SetLevelInfo(NULL, 374 info.target, 375 i, 376 info.internal_format, 377 info.width, 378 info.height, 379 info.depth, 380 info.border, 381 info.format, 382 info.type, 383 info.cleared); 384 } 385 } 386 if (image_buffer_.get()) { 387 texture->SetLevelImage( 388 NULL, 389 target_, 390 0, 391 new GLImageSync( 392 image_buffer_, 393 gfx::Size(level_infos_[0][0].width, level_infos_[0][0].height))); 394 } 395 396 texture->target_ = target_; 397 texture->SetImmutable(immutable_); 398 texture->min_filter_ = min_filter_; 399 texture->mag_filter_ = mag_filter_; 400 texture->wrap_s_ = wrap_s_; 401 texture->wrap_t_ = wrap_t_; 402 texture->usage_ = usage_; 403 } 404 405 bool TextureDefinition::Matches(const Texture* texture) const { 406 DCHECK(target_ == texture->target()); 407 if (texture->min_filter_ != min_filter_ || 408 texture->mag_filter_ != mag_filter_ || 409 texture->wrap_s_ != wrap_s_ || 410 texture->wrap_t_ != wrap_t_) { 411 return false; 412 } 413 414 // All structural changes should have orphaned the texture. 415 if (image_buffer_.get() && !texture->GetLevelImage(texture->target(), 0)) 416 return false; 417 418 return true; 419 } 420 421 } // namespace gles2 422 } // namespace gpu 423