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 |