| 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 | |
| 16 | 10 |
| 17 namespace gfx { | 11 namespace gfx { |
| 18 namespace { | 12 namespace { |
| 19 | 13 |
| 20 bool ValidInternalFormat(unsigned internalformat) { | 14 bool ValidInternalFormat(unsigned internalformat) { |
| 21 switch (internalformat) { | 15 switch (internalformat) { |
| 22 case GL_ATC_RGB_AMD: | 16 case GL_ATC_RGB_AMD: |
| 23 case GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD: | 17 case GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD: |
| 24 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: | 18 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: |
| 25 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: | 19 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 145 size.width(), format, &stride_in_bytes); | 139 size.width(), format, &stride_in_bytes); |
| 146 DCHECK(valid_stride); | 140 DCHECK(valid_stride); |
| 147 return static_cast<GLsizei>(stride_in_bytes * size.height()); | 141 return static_cast<GLsizei>(stride_in_bytes * size.height()); |
| 148 } | 142 } |
| 149 | 143 |
| 150 } // namespace | 144 } // namespace |
| 151 | 145 |
| 152 GLImageMemory::GLImageMemory(const Size& size, unsigned internalformat) | 146 GLImageMemory::GLImageMemory(const Size& size, unsigned internalformat) |
| 153 : size_(size), | 147 : size_(size), |
| 154 internalformat_(internalformat), | 148 internalformat_(internalformat), |
| 155 memory_(NULL), | 149 memory_(nullptr), |
| 156 format_(BufferFormat::RGBA_8888), | 150 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 } | |
| 168 | 151 |
| 169 GLImageMemory::~GLImageMemory() { | 152 GLImageMemory::~GLImageMemory() { |
| 170 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \ | 153 DCHECK(!memory_); |
| 171 defined(USE_OZONE) | |
| 172 DCHECK_EQ(EGL_NO_IMAGE_KHR, egl_image_); | |
| 173 DCHECK_EQ(0u, egl_texture_id_); | |
| 174 #endif | |
| 175 } | 154 } |
| 176 | 155 |
| 177 // static | 156 // static |
| 178 bool GLImageMemory::StrideInBytes(size_t width, | 157 bool GLImageMemory::StrideInBytes(size_t width, |
| 179 BufferFormat format, | 158 BufferFormat format, |
| 180 size_t* stride_in_bytes) { | 159 size_t* stride_in_bytes) { |
| 181 base::CheckedNumeric<size_t> checked_stride = width; | 160 base::CheckedNumeric<size_t> checked_stride = width; |
| 182 switch (format) { | 161 switch (format) { |
| 183 case BufferFormat::ATCIA: | 162 case BufferFormat::ATCIA: |
| 184 case BufferFormat::DXT5: | 163 case BufferFormat::DXT5: |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 236 DCHECK(memory); | 215 DCHECK(memory); |
| 237 DCHECK(!memory_); | 216 DCHECK(!memory_); |
| 238 DCHECK_IMPLIES(IsCompressedFormat(format), size_.width() % 4 == 0); | 217 DCHECK_IMPLIES(IsCompressedFormat(format), size_.width() % 4 == 0); |
| 239 DCHECK_IMPLIES(IsCompressedFormat(format), size_.height() % 4 == 0); | 218 DCHECK_IMPLIES(IsCompressedFormat(format), size_.height() % 4 == 0); |
| 240 memory_ = memory; | 219 memory_ = memory; |
| 241 format_ = format; | 220 format_ = format; |
| 242 return true; | 221 return true; |
| 243 } | 222 } |
| 244 | 223 |
| 245 void GLImageMemory::Destroy(bool have_context) { | 224 void GLImageMemory::Destroy(bool have_context) { |
| 246 #if defined(OS_WIN) || defined(USE_X11) || defined(OS_ANDROID) || \ | 225 memory_ = nullptr; |
| 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; | |
| 260 } | 226 } |
| 261 | 227 |
| 262 Size GLImageMemory::GetSize() { | 228 Size GLImageMemory::GetSize() { |
| 263 return size_; | 229 return size_; |
| 264 } | 230 } |
| 265 | 231 |
| 266 unsigned GLImageMemory::GetInternalFormat() { | 232 unsigned GLImageMemory::GetInternalFormat() { |
| 267 return internalformat_; | 233 return internalformat_; |
| 268 } | 234 } |
| 269 | 235 |
| 270 bool GLImageMemory::BindTexImage(unsigned target) { | 236 bool GLImageMemory::BindTexImage(unsigned target) { |
| 271 if (target_ && target_ != target) { | 237 return false; |
| 272 LOG(ERROR) << "GLImage can only be bound to one target"; | 238 } |
| 239 |
| 240 bool GLImageMemory::CopyTexImage(unsigned target) { |
| 241 TRACE_EVENT2("gpu", "GLImageMemory::CopyTexImage", "width", size_.width(), |
| 242 "height", size_.height()); |
| 243 |
| 244 // GL_TEXTURE_EXTERNAL_OES is not a supported target. |
| 245 if (target == GL_TEXTURE_EXTERNAL_OES) |
| 273 return false; | 246 return false; |
| 274 } | |
| 275 target_ = target; | |
| 276 | 247 |
| 277 // Defer DoBindTexImage if not currently in use. | 248 if (IsCompressedFormat(format_)) { |
| 278 if (!in_use_) { | 249 glCompressedTexImage2D(target, 0, TextureFormat(format_), size_.width(), |
| 279 need_do_bind_tex_image_ = true; | 250 size_.height(), 0, SizeInBytes(size_, format_), |
| 280 return true; | 251 memory_); |
| 252 } else { |
| 253 glTexImage2D(target, 0, TextureFormat(format_), size_.width(), |
| 254 size_.height(), 0, DataFormat(format_), DataType(format_), |
| 255 memory_); |
| 281 } | 256 } |
| 282 | 257 |
| 283 DoBindTexImage(target); | |
| 284 return true; | 258 return true; |
| 285 } | 259 } |
| 286 | 260 |
| 287 bool GLImageMemory::CopyTexSubImage(unsigned target, | 261 bool GLImageMemory::CopyTexSubImage(unsigned target, |
| 288 const Point& offset, | 262 const Point& offset, |
| 289 const Rect& rect) { | 263 const Rect& rect) { |
| 290 TRACE_EVENT2("gpu", "GLImageMemory::CopyTexSubImage", "width", rect.width(), | 264 TRACE_EVENT2("gpu", "GLImageMemory::CopyTexSubImage", "width", rect.width(), |
| 291 "height", rect.height()); | 265 "height", rect.height()); |
| 292 | 266 |
| 293 // GL_TEXTURE_EXTERNAL_OES is not a supported CopyTexSubImage target. | 267 // GL_TEXTURE_EXTERNAL_OES is not a supported target. |
| 294 if (target == GL_TEXTURE_EXTERNAL_OES) | 268 if (target == GL_TEXTURE_EXTERNAL_OES) |
| 295 return false; | 269 return false; |
| 296 | 270 |
| 297 // Sub width is not supported. | 271 // Sub width is not supported. |
| 298 if (rect.width() != size_.width()) | 272 if (rect.width() != size_.width()) |
| 299 return false; | 273 return false; |
| 300 | 274 |
| 301 // Height must be a multiple of 4 if compressed. | 275 // Height must be a multiple of 4 if compressed. |
| 302 if (IsCompressedFormat(format_) && rect.height() % 4) | 276 if (IsCompressedFormat(format_) && rect.height() % 4) |
| 303 return false; | 277 return false; |
| 304 | 278 |
| 305 size_t stride_in_bytes = 0; | 279 size_t stride_in_bytes = 0; |
| 306 bool rv = StrideInBytes(size_.width(), format_, &stride_in_bytes); | 280 bool rv = StrideInBytes(size_.width(), format_, &stride_in_bytes); |
| 307 DCHECK(rv); | 281 DCHECK(rv); |
| 308 DCHECK(memory_); | 282 DCHECK(memory_); |
| 309 const unsigned char* data = memory_ + rect.y() * stride_in_bytes; | 283 const unsigned char* data = memory_ + rect.y() * stride_in_bytes; |
| 310 if (IsCompressedFormat(format_)) { | 284 if (IsCompressedFormat(format_)) { |
| 311 glCompressedTexSubImage2D(target, | 285 glCompressedTexSubImage2D(target, 0, offset.x(), offset.y(), rect.width(), |
| 312 0, // level | |
| 313 offset.x(), offset.y(), rect.width(), | |
| 314 rect.height(), DataFormat(format_), | 286 rect.height(), DataFormat(format_), |
| 315 SizeInBytes(rect.size(), format_), data); | 287 SizeInBytes(rect.size(), format_), data); |
| 316 } else { | 288 } else { |
| 317 glTexSubImage2D(target, 0, // level | 289 glTexSubImage2D(target, 0, offset.x(), offset.y(), rect.width(), |
| 318 offset.x(), offset.y(), rect.width(), rect.height(), | 290 rect.height(), DataFormat(format_), DataType(format_), |
| 319 DataFormat(format_), DataType(format_), data); | 291 data); |
| 320 } | 292 } |
| 321 | 293 |
| 322 return true; | 294 return true; |
| 323 } | 295 } |
| 324 | 296 |
| 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 | |
| 341 bool GLImageMemory::ScheduleOverlayPlane(AcceleratedWidget widget, | 297 bool GLImageMemory::ScheduleOverlayPlane(AcceleratedWidget widget, |
| 342 int z_order, | 298 int z_order, |
| 343 OverlayTransform transform, | 299 OverlayTransform transform, |
| 344 const Rect& bounds_rect, | 300 const Rect& bounds_rect, |
| 345 const RectF& crop_rect) { | 301 const RectF& crop_rect) { |
| 346 return false; | 302 return false; |
| 347 } | 303 } |
| 348 | 304 |
| 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 | |
| 477 } // namespace gfx | 305 } // namespace gfx |
| OLD | NEW |