| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/gl/gl_image_memory.h" | 5 #include "ui/gl/gl_image_memory.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/trace_event/trace_event.h" | 8 #include "base/trace_event/trace_event.h" |
| 9 #include "ui/gl/gl_bindings.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 |
| 10 | 16 |
| 11 namespace gfx { | 17 namespace gfx { |
| 12 namespace { | 18 namespace { |
| 13 | 19 |
| 14 bool ValidInternalFormat(unsigned internalformat) { | 20 bool ValidInternalFormat(unsigned internalformat) { |
| 15 switch (internalformat) { | 21 switch (internalformat) { |
| 16 case GL_ATC_RGB_AMD: | 22 case GL_ATC_RGB_AMD: |
| 17 case GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD: | 23 case GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD: |
| 18 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: | 24 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: |
| 19 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: | 25 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 139 size.width(), format, &stride_in_bytes); | 145 size.width(), format, &stride_in_bytes); |
| 140 DCHECK(valid_stride); | 146 DCHECK(valid_stride); |
| 141 return static_cast<GLsizei>(stride_in_bytes * size.height()); | 147 return static_cast<GLsizei>(stride_in_bytes * size.height()); |
| 142 } | 148 } |
| 143 | 149 |
| 144 } // namespace | 150 } // namespace |
| 145 | 151 |
| 146 GLImageMemory::GLImageMemory(const Size& size, unsigned internalformat) | 152 GLImageMemory::GLImageMemory(const Size& size, unsigned internalformat) |
| 147 : size_(size), | 153 : size_(size), |
| 148 internalformat_(internalformat), | 154 internalformat_(internalformat), |
| 149 memory_(nullptr), | 155 memory_(NULL), |
| 150 format_(BufferFormat::RGBA_8888) {} | 156 format_(BufferFormat::RGBA_8888), |
| 157 in_use_(false), |
| 158 target_(0), |
| 159 need_do_bind_tex_image_(false) |
| 160 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \ |
| 161 defined(USE_OZONE) |
| 162 , |
| 163 egl_texture_id_(0u), |
| 164 egl_image_(EGL_NO_IMAGE_KHR) |
| 165 #endif |
| 166 { |
| 167 } |
| 151 | 168 |
| 152 GLImageMemory::~GLImageMemory() { | 169 GLImageMemory::~GLImageMemory() { |
| 153 DCHECK(!memory_); | 170 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \ |
| 171 defined(USE_OZONE) |
| 172 DCHECK_EQ(EGL_NO_IMAGE_KHR, egl_image_); |
| 173 DCHECK_EQ(0u, egl_texture_id_); |
| 174 #endif |
| 154 } | 175 } |
| 155 | 176 |
| 156 // static | 177 // static |
| 157 bool GLImageMemory::StrideInBytes(size_t width, | 178 bool GLImageMemory::StrideInBytes(size_t width, |
| 158 BufferFormat format, | 179 BufferFormat format, |
| 159 size_t* stride_in_bytes) { | 180 size_t* stride_in_bytes) { |
| 160 base::CheckedNumeric<size_t> checked_stride = width; | 181 base::CheckedNumeric<size_t> checked_stride = width; |
| 161 switch (format) { | 182 switch (format) { |
| 162 case BufferFormat::ATCIA: | 183 case BufferFormat::ATCIA: |
| 163 case BufferFormat::DXT5: | 184 case BufferFormat::DXT5: |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 215 DCHECK(memory); | 236 DCHECK(memory); |
| 216 DCHECK(!memory_); | 237 DCHECK(!memory_); |
| 217 DCHECK_IMPLIES(IsCompressedFormat(format), size_.width() % 4 == 0); | 238 DCHECK_IMPLIES(IsCompressedFormat(format), size_.width() % 4 == 0); |
| 218 DCHECK_IMPLIES(IsCompressedFormat(format), size_.height() % 4 == 0); | 239 DCHECK_IMPLIES(IsCompressedFormat(format), size_.height() % 4 == 0); |
| 219 memory_ = memory; | 240 memory_ = memory; |
| 220 format_ = format; | 241 format_ = format; |
| 221 return true; | 242 return true; |
| 222 } | 243 } |
| 223 | 244 |
| 224 void GLImageMemory::Destroy(bool have_context) { | 245 void GLImageMemory::Destroy(bool have_context) { |
| 225 memory_ = nullptr; | 246 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \ |
| 247 defined(USE_OZONE) |
| 248 if (egl_image_ != EGL_NO_IMAGE_KHR) { |
| 249 eglDestroyImageKHR(GLSurfaceEGL::GetHardwareDisplay(), egl_image_); |
| 250 egl_image_ = EGL_NO_IMAGE_KHR; |
| 251 } |
| 252 |
| 253 if (egl_texture_id_) { |
| 254 if (have_context) |
| 255 glDeleteTextures(1, &egl_texture_id_); |
| 256 egl_texture_id_ = 0u; |
| 257 } |
| 258 #endif |
| 259 memory_ = NULL; |
| 226 } | 260 } |
| 227 | 261 |
| 228 Size GLImageMemory::GetSize() { | 262 Size GLImageMemory::GetSize() { |
| 229 return size_; | 263 return size_; |
| 230 } | 264 } |
| 231 | 265 |
| 232 unsigned GLImageMemory::GetInternalFormat() { | 266 unsigned GLImageMemory::GetInternalFormat() { |
| 233 return internalformat_; | 267 return internalformat_; |
| 234 } | 268 } |
| 235 | 269 |
| 236 bool GLImageMemory::BindTexImage(unsigned target) { | 270 bool GLImageMemory::BindTexImage(unsigned target) { |
| 237 return false; | 271 if (target_ && target_ != target) { |
| 238 } | 272 LOG(ERROR) << "GLImage can only be bound to one target"; |
| 273 return false; |
| 274 } |
| 275 target_ = target; |
| 239 | 276 |
| 240 bool GLImageMemory::CopyTexImage(unsigned target) { | 277 // Defer DoBindTexImage if not currently in use. |
| 241 TRACE_EVENT2("gpu", "GLImageMemory::CopyTexImage", "width", size_.width(), | 278 if (!in_use_) { |
| 242 "height", size_.height()); | 279 need_do_bind_tex_image_ = true; |
| 243 | 280 return true; |
| 244 // GL_TEXTURE_EXTERNAL_OES is not a supported target. | |
| 245 if (target == GL_TEXTURE_EXTERNAL_OES) | |
| 246 return false; | |
| 247 | |
| 248 if (IsCompressedFormat(format_)) { | |
| 249 glCompressedTexImage2D(target, 0, TextureFormat(format_), size_.width(), | |
| 250 size_.height(), 0, SizeInBytes(size_, format_), | |
| 251 memory_); | |
| 252 } else { | |
| 253 glTexImage2D(target, 0, TextureFormat(format_), size_.width(), | |
| 254 size_.height(), 0, DataFormat(format_), DataType(format_), | |
| 255 memory_); | |
| 256 } | 281 } |
| 257 | 282 |
| 283 DoBindTexImage(target); |
| 258 return true; | 284 return true; |
| 259 } | 285 } |
| 260 | 286 |
| 261 bool GLImageMemory::CopyTexSubImage(unsigned target, | 287 bool GLImageMemory::CopyTexSubImage(unsigned target, |
| 262 const Point& offset, | 288 const Point& offset, |
| 263 const Rect& rect) { | 289 const Rect& rect) { |
| 264 TRACE_EVENT2("gpu", "GLImageMemory::CopyTexSubImage", "width", rect.width(), | 290 TRACE_EVENT2("gpu", "GLImageMemory::CopyTexSubImage", "width", rect.width(), |
| 265 "height", rect.height()); | 291 "height", rect.height()); |
| 266 | 292 |
| 267 // GL_TEXTURE_EXTERNAL_OES is not a supported target. | 293 // GL_TEXTURE_EXTERNAL_OES is not a supported CopyTexSubImage target. |
| 268 if (target == GL_TEXTURE_EXTERNAL_OES) | 294 if (target == GL_TEXTURE_EXTERNAL_OES) |
| 269 return false; | 295 return false; |
| 270 | 296 |
| 271 // Sub width is not supported. | 297 // Sub width is not supported. |
| 272 if (rect.width() != size_.width()) | 298 if (rect.width() != size_.width()) |
| 273 return false; | 299 return false; |
| 274 | 300 |
| 275 // Height must be a multiple of 4 if compressed. | 301 // Height must be a multiple of 4 if compressed. |
| 276 if (IsCompressedFormat(format_) && rect.height() % 4) | 302 if (IsCompressedFormat(format_) && rect.height() % 4) |
| 277 return false; | 303 return false; |
| 278 | 304 |
| 279 size_t stride_in_bytes = 0; | 305 size_t stride_in_bytes = 0; |
| 280 bool rv = StrideInBytes(size_.width(), format_, &stride_in_bytes); | 306 bool rv = StrideInBytes(size_.width(), format_, &stride_in_bytes); |
| 281 DCHECK(rv); | 307 DCHECK(rv); |
| 282 DCHECK(memory_); | 308 DCHECK(memory_); |
| 283 const unsigned char* data = memory_ + rect.y() * stride_in_bytes; | 309 const unsigned char* data = memory_ + rect.y() * stride_in_bytes; |
| 284 if (IsCompressedFormat(format_)) { | 310 if (IsCompressedFormat(format_)) { |
| 285 glCompressedTexSubImage2D(target, 0, offset.x(), offset.y(), rect.width(), | 311 glCompressedTexSubImage2D(target, |
| 312 0, // level |
| 313 offset.x(), offset.y(), rect.width(), |
| 286 rect.height(), DataFormat(format_), | 314 rect.height(), DataFormat(format_), |
| 287 SizeInBytes(rect.size(), format_), data); | 315 SizeInBytes(rect.size(), format_), data); |
| 288 } else { | 316 } else { |
| 289 glTexSubImage2D(target, 0, offset.x(), offset.y(), rect.width(), | 317 glTexSubImage2D(target, 0, // level |
| 290 rect.height(), DataFormat(format_), DataType(format_), | 318 offset.x(), offset.y(), rect.width(), rect.height(), |
| 291 data); | 319 DataFormat(format_), DataType(format_), data); |
| 292 } | 320 } |
| 293 | 321 |
| 294 return true; | 322 return true; |
| 295 } | 323 } |
| 296 | 324 |
| 325 void GLImageMemory::WillUseTexImage() { |
| 326 DCHECK(!in_use_); |
| 327 in_use_ = true; |
| 328 |
| 329 if (!need_do_bind_tex_image_) |
| 330 return; |
| 331 |
| 332 DCHECK(target_); |
| 333 DoBindTexImage(target_); |
| 334 } |
| 335 |
| 336 void GLImageMemory::DidUseTexImage() { |
| 337 DCHECK(in_use_); |
| 338 in_use_ = false; |
| 339 } |
| 340 |
| 297 bool GLImageMemory::ScheduleOverlayPlane(AcceleratedWidget widget, | 341 bool GLImageMemory::ScheduleOverlayPlane(AcceleratedWidget widget, |
| 298 int z_order, | 342 int z_order, |
| 299 OverlayTransform transform, | 343 OverlayTransform transform, |
| 300 const Rect& bounds_rect, | 344 const Rect& bounds_rect, |
| 301 const RectF& crop_rect) { | 345 const RectF& crop_rect) { |
| 302 return false; | 346 return false; |
| 303 } | 347 } |
| 304 | 348 |
| 349 void GLImageMemory::DoBindTexImage(unsigned target) { |
| 350 TRACE_EVENT0("gpu", "GLImageMemory::DoBindTexImage"); |
| 351 |
| 352 DCHECK(need_do_bind_tex_image_); |
| 353 need_do_bind_tex_image_ = false; |
| 354 |
| 355 DCHECK(memory_); |
| 356 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \ |
| 357 defined(USE_OZONE) |
| 358 if (target == GL_TEXTURE_EXTERNAL_OES) { |
| 359 if (egl_image_ == EGL_NO_IMAGE_KHR) { |
| 360 DCHECK_EQ(0u, egl_texture_id_); |
| 361 glGenTextures(1, &egl_texture_id_); |
| 362 |
| 363 { |
| 364 ScopedTextureBinder texture_binder(GL_TEXTURE_2D, egl_texture_id_); |
| 365 |
| 366 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| 367 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| 368 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| 369 if (IsCompressedFormat(format_)) { |
| 370 glCompressedTexImage2D(GL_TEXTURE_2D, |
| 371 0, // mip level |
| 372 TextureFormat(format_), size_.width(), |
| 373 size_.height(), |
| 374 0, // border |
| 375 SizeInBytes(size_, format_), memory_); |
| 376 } else { |
| 377 glTexImage2D(GL_TEXTURE_2D, |
| 378 0, // mip level |
| 379 TextureFormat(format_), |
| 380 size_.width(), |
| 381 size_.height(), |
| 382 0, // border |
| 383 DataFormat(format_), |
| 384 DataType(format_), |
| 385 memory_); |
| 386 } |
| 387 } |
| 388 |
| 389 EGLint attrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE}; |
| 390 // Need to pass current EGL rendering context to eglCreateImageKHR for |
| 391 // target type EGL_GL_TEXTURE_2D_KHR. |
| 392 egl_image_ = |
| 393 eglCreateImageKHR(GLSurfaceEGL::GetHardwareDisplay(), |
| 394 eglGetCurrentContext(), |
| 395 EGL_GL_TEXTURE_2D_KHR, |
| 396 reinterpret_cast<EGLClientBuffer>(egl_texture_id_), |
| 397 attrs); |
| 398 DCHECK_NE(EGL_NO_IMAGE_KHR, egl_image_) |
| 399 << "Error creating EGLImage: " << eglGetError(); |
| 400 } else { |
| 401 ScopedTextureBinder texture_binder(GL_TEXTURE_2D, egl_texture_id_); |
| 402 |
| 403 if (IsCompressedFormat(format_)) { |
| 404 glCompressedTexSubImage2D(GL_TEXTURE_2D, |
| 405 0, // mip level |
| 406 0, // x-offset |
| 407 0, // y-offset |
| 408 size_.width(), size_.height(), |
| 409 DataFormat(format_), |
| 410 SizeInBytes(size_, format_), memory_); |
| 411 } else { |
| 412 glTexSubImage2D(GL_TEXTURE_2D, |
| 413 0, // mip level |
| 414 0, // x-offset |
| 415 0, // y-offset |
| 416 size_.width(), |
| 417 size_.height(), |
| 418 DataFormat(format_), |
| 419 DataType(format_), |
| 420 memory_); |
| 421 } |
| 422 } |
| 423 |
| 424 glEGLImageTargetTexture2DOES(target, egl_image_); |
| 425 DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); |
| 426 return; |
| 427 } |
| 428 #endif |
| 429 |
| 430 DCHECK_NE(static_cast<GLenum>(GL_TEXTURE_EXTERNAL_OES), target); |
| 431 if (IsCompressedFormat(format_)) { |
| 432 glCompressedTexImage2D(target, |
| 433 0, // mip level |
| 434 TextureFormat(format_), size_.width(), |
| 435 size_.height(), |
| 436 0, // border |
| 437 SizeInBytes(size_, format_), memory_); |
| 438 } else { |
| 439 glTexImage2D(target, |
| 440 0, // mip level |
| 441 TextureFormat(format_), |
| 442 size_.width(), |
| 443 size_.height(), |
| 444 0, // border |
| 445 DataFormat(format_), |
| 446 DataType(format_), |
| 447 memory_); |
| 448 } |
| 449 } |
| 450 |
| 451 void GLImageMemory::OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd, |
| 452 uint64_t process_tracing_id, |
| 453 const std::string& dump_name) { |
| 454 // Note that the following calculation does not consider whether this GLImage |
| 455 // has been un-bound from a texture. It also relies on this GLImage only ever |
| 456 // being bound to a single texture. We could check these conditions more |
| 457 // thoroughly, but at the cost of extra GL queries. |
| 458 bool is_bound_to_texture = target_ && !need_do_bind_tex_image_; |
| 459 |
| 460 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \ |
| 461 defined(USE_OZONE) |
| 462 is_bound_to_texture |= !!egl_texture_id_; |
| 463 #endif |
| 464 |
| 465 size_t size_in_bytes = is_bound_to_texture ? SizeInBytes(size_, format_) : 0; |
| 466 |
| 467 base::trace_event::MemoryAllocatorDump* dump = |
| 468 pmd->CreateAllocatorDump(dump_name + "/texture_memory"); |
| 469 dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize, |
| 470 base::trace_event::MemoryAllocatorDump::kUnitsBytes, |
| 471 static_cast<uint64_t>(size_in_bytes)); |
| 472 |
| 473 // No need for a global shared edge here. This object in the GPU process is |
| 474 // the sole owner of this texture id. |
| 475 } |
| 476 |
| 305 } // namespace gfx | 477 } // namespace gfx |
| OLD | NEW |