OLD | NEW |
(Empty) | |
| 1 // Copyright 2012 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 "cc/resources/resource_provider.h" |
| 6 |
| 7 #include <algorithm> |
| 8 #include <limits> |
| 9 |
| 10 #include "base/containers/hash_tables.h" |
| 11 #include "base/metrics/histogram.h" |
| 12 #include "base/stl_util.h" |
| 13 #include "base/strings/string_split.h" |
| 14 #include "base/strings/string_util.h" |
| 15 #include "base/trace_event/trace_event.h" |
| 16 #include "cc/base/util.h" |
| 17 #include "cc/output/gl_renderer.h" // For the GLC() macro. |
| 18 #include "cc/resources/platform_color.h" |
| 19 #include "cc/resources/returned_resource.h" |
| 20 #include "cc/resources/shared_bitmap_manager.h" |
| 21 #include "cc/resources/texture_uploader.h" |
| 22 #include "cc/resources/transferable_resource.h" |
| 23 #include "gpu/GLES2/gl2extchromium.h" |
| 24 #include "gpu/command_buffer/client/gles2_interface.h" |
| 25 #include "gpu/command_buffer/client/gpu_memory_buffer_manager.h" |
| 26 #include "third_party/khronos/GLES2/gl2.h" |
| 27 #include "third_party/khronos/GLES2/gl2ext.h" |
| 28 #include "third_party/skia/include/core/SkSurface.h" |
| 29 #include "third_party/skia/include/gpu/GrContext.h" |
| 30 #include "ui/gfx/frame_time.h" |
| 31 #include "ui/gfx/geometry/rect.h" |
| 32 #include "ui/gfx/geometry/vector2d.h" |
| 33 #include "ui/gfx/gpu_memory_buffer.h" |
| 34 |
| 35 using gpu::gles2::GLES2Interface; |
| 36 |
| 37 namespace cc { |
| 38 |
| 39 class IdAllocator { |
| 40 public: |
| 41 virtual ~IdAllocator() {} |
| 42 |
| 43 virtual GLuint NextId() = 0; |
| 44 |
| 45 protected: |
| 46 IdAllocator(GLES2Interface* gl, size_t id_allocation_chunk_size) |
| 47 : gl_(gl), |
| 48 id_allocation_chunk_size_(id_allocation_chunk_size), |
| 49 ids_(new GLuint[id_allocation_chunk_size]), |
| 50 next_id_index_(id_allocation_chunk_size) { |
| 51 DCHECK(id_allocation_chunk_size_); |
| 52 } |
| 53 |
| 54 GLES2Interface* gl_; |
| 55 const size_t id_allocation_chunk_size_; |
| 56 scoped_ptr<GLuint[]> ids_; |
| 57 size_t next_id_index_; |
| 58 }; |
| 59 |
| 60 namespace { |
| 61 |
| 62 // Measured in seconds. |
| 63 const double kSoftwareUploadTickRate = 0.000250; |
| 64 const double kTextureUploadTickRate = 0.004; |
| 65 |
| 66 GLenum TextureToStorageFormat(ResourceFormat format) { |
| 67 GLenum storage_format = GL_RGBA8_OES; |
| 68 switch (format) { |
| 69 case RGBA_8888: |
| 70 break; |
| 71 case BGRA_8888: |
| 72 storage_format = GL_BGRA8_EXT; |
| 73 break; |
| 74 case RGBA_4444: |
| 75 case ALPHA_8: |
| 76 case LUMINANCE_8: |
| 77 case RGB_565: |
| 78 case ETC1: |
| 79 case RED_8: |
| 80 NOTREACHED(); |
| 81 break; |
| 82 } |
| 83 |
| 84 return storage_format; |
| 85 } |
| 86 |
| 87 bool IsFormatSupportedForStorage(ResourceFormat format, bool use_bgra) { |
| 88 switch (format) { |
| 89 case RGBA_8888: |
| 90 return true; |
| 91 case BGRA_8888: |
| 92 return use_bgra; |
| 93 case RGBA_4444: |
| 94 case ALPHA_8: |
| 95 case LUMINANCE_8: |
| 96 case RGB_565: |
| 97 case ETC1: |
| 98 case RED_8: |
| 99 return false; |
| 100 } |
| 101 return false; |
| 102 } |
| 103 |
| 104 GrPixelConfig ToGrPixelConfig(ResourceFormat format) { |
| 105 switch (format) { |
| 106 case RGBA_8888: |
| 107 return kRGBA_8888_GrPixelConfig; |
| 108 case BGRA_8888: |
| 109 return kBGRA_8888_GrPixelConfig; |
| 110 case RGBA_4444: |
| 111 return kRGBA_4444_GrPixelConfig; |
| 112 default: |
| 113 break; |
| 114 } |
| 115 DCHECK(false) << "Unsupported resource format."; |
| 116 return kSkia8888_GrPixelConfig; |
| 117 } |
| 118 |
| 119 gfx::GpuMemoryBuffer::Format ToGpuMemoryBufferFormat(ResourceFormat format) { |
| 120 switch (format) { |
| 121 case RGBA_8888: |
| 122 return gfx::GpuMemoryBuffer::Format::RGBA_8888; |
| 123 case BGRA_8888: |
| 124 return gfx::GpuMemoryBuffer::Format::BGRA_8888; |
| 125 case RGBA_4444: |
| 126 case ALPHA_8: |
| 127 case LUMINANCE_8: |
| 128 case RGB_565: |
| 129 case ETC1: |
| 130 case RED_8: |
| 131 break; |
| 132 } |
| 133 NOTREACHED(); |
| 134 return gfx::GpuMemoryBuffer::Format::RGBA_8888; |
| 135 } |
| 136 |
| 137 class ScopedSetActiveTexture { |
| 138 public: |
| 139 ScopedSetActiveTexture(GLES2Interface* gl, GLenum unit) |
| 140 : gl_(gl), unit_(unit) { |
| 141 DCHECK_EQ(GL_TEXTURE0, ResourceProvider::GetActiveTextureUnit(gl_)); |
| 142 |
| 143 if (unit_ != GL_TEXTURE0) |
| 144 GLC(gl_, gl_->ActiveTexture(unit_)); |
| 145 } |
| 146 |
| 147 ~ScopedSetActiveTexture() { |
| 148 // Active unit being GL_TEXTURE0 is effectively the ground state. |
| 149 if (unit_ != GL_TEXTURE0) |
| 150 GLC(gl_, gl_->ActiveTexture(GL_TEXTURE0)); |
| 151 } |
| 152 |
| 153 private: |
| 154 GLES2Interface* gl_; |
| 155 GLenum unit_; |
| 156 }; |
| 157 |
| 158 class TextureIdAllocator : public IdAllocator { |
| 159 public: |
| 160 TextureIdAllocator(GLES2Interface* gl, |
| 161 size_t texture_id_allocation_chunk_size) |
| 162 : IdAllocator(gl, texture_id_allocation_chunk_size) {} |
| 163 ~TextureIdAllocator() override { |
| 164 gl_->DeleteTextures(id_allocation_chunk_size_ - next_id_index_, |
| 165 ids_.get() + next_id_index_); |
| 166 } |
| 167 |
| 168 // Overridden from IdAllocator: |
| 169 GLuint NextId() override { |
| 170 if (next_id_index_ == id_allocation_chunk_size_) { |
| 171 gl_->GenTextures(id_allocation_chunk_size_, ids_.get()); |
| 172 next_id_index_ = 0; |
| 173 } |
| 174 |
| 175 return ids_[next_id_index_++]; |
| 176 } |
| 177 |
| 178 private: |
| 179 DISALLOW_COPY_AND_ASSIGN(TextureIdAllocator); |
| 180 }; |
| 181 |
| 182 class BufferIdAllocator : public IdAllocator { |
| 183 public: |
| 184 BufferIdAllocator(GLES2Interface* gl, size_t buffer_id_allocation_chunk_size) |
| 185 : IdAllocator(gl, buffer_id_allocation_chunk_size) {} |
| 186 ~BufferIdAllocator() override { |
| 187 gl_->DeleteBuffers(id_allocation_chunk_size_ - next_id_index_, |
| 188 ids_.get() + next_id_index_); |
| 189 } |
| 190 |
| 191 // Overridden from IdAllocator: |
| 192 GLuint NextId() override { |
| 193 if (next_id_index_ == id_allocation_chunk_size_) { |
| 194 gl_->GenBuffers(id_allocation_chunk_size_, ids_.get()); |
| 195 next_id_index_ = 0; |
| 196 } |
| 197 |
| 198 return ids_[next_id_index_++]; |
| 199 } |
| 200 |
| 201 private: |
| 202 DISALLOW_COPY_AND_ASSIGN(BufferIdAllocator); |
| 203 }; |
| 204 |
| 205 // Query object based fence implementation used to detect completion of copy |
| 206 // texture operations. Fence has passed when query result is available. |
| 207 class CopyTextureFence : public ResourceProvider::Fence { |
| 208 public: |
| 209 CopyTextureFence(gpu::gles2::GLES2Interface* gl, unsigned query_id) |
| 210 : gl_(gl), query_id_(query_id) {} |
| 211 |
| 212 // Overridden from ResourceProvider::Fence: |
| 213 void Set() override {} |
| 214 bool HasPassed() override { |
| 215 unsigned available = 1; |
| 216 gl_->GetQueryObjectuivEXT( |
| 217 query_id_, GL_QUERY_RESULT_AVAILABLE_EXT, &available); |
| 218 if (!available) |
| 219 return false; |
| 220 |
| 221 ProcessResult(); |
| 222 return true; |
| 223 } |
| 224 void Wait() override { |
| 225 // ProcessResult() will wait for result to become available. |
| 226 ProcessResult(); |
| 227 } |
| 228 |
| 229 private: |
| 230 ~CopyTextureFence() override {} |
| 231 |
| 232 void ProcessResult() { |
| 233 unsigned time_elapsed_us = 0; |
| 234 gl_->GetQueryObjectuivEXT(query_id_, GL_QUERY_RESULT_EXT, &time_elapsed_us); |
| 235 UMA_HISTOGRAM_CUSTOM_COUNTS("Renderer4.CopyTextureLatency", time_elapsed_us, |
| 236 0, 256000, 50); |
| 237 } |
| 238 |
| 239 gpu::gles2::GLES2Interface* gl_; |
| 240 unsigned query_id_; |
| 241 |
| 242 DISALLOW_COPY_AND_ASSIGN(CopyTextureFence); |
| 243 }; |
| 244 |
| 245 } // namespace |
| 246 |
| 247 ResourceProvider::Resource::Resource() |
| 248 : child_id(0), |
| 249 gl_id(0), |
| 250 gl_pixel_buffer_id(0), |
| 251 gl_upload_query_id(0), |
| 252 gl_read_lock_query_id(0), |
| 253 pixels(NULL), |
| 254 lock_for_read_count(0), |
| 255 imported_count(0), |
| 256 exported_count(0), |
| 257 dirty_image(false), |
| 258 locked_for_write(false), |
| 259 lost(false), |
| 260 marked_for_deletion(false), |
| 261 pending_set_pixels(false), |
| 262 set_pixels_completion_forced(false), |
| 263 allocated(false), |
| 264 read_lock_fences_enabled(false), |
| 265 has_shared_bitmap_id(false), |
| 266 allow_overlay(false), |
| 267 read_lock_fence(NULL), |
| 268 size(), |
| 269 origin(INTERNAL), |
| 270 target(0), |
| 271 original_filter(0), |
| 272 filter(0), |
| 273 image_id(0), |
| 274 bound_image_id(0), |
| 275 texture_pool(0), |
| 276 wrap_mode(0), |
| 277 hint(TEXTURE_HINT_IMMUTABLE), |
| 278 type(RESOURCE_TYPE_INVALID), |
| 279 format(RGBA_8888), |
| 280 shared_bitmap(NULL), |
| 281 gpu_memory_buffer(NULL) { |
| 282 } |
| 283 |
| 284 ResourceProvider::Resource::~Resource() {} |
| 285 |
| 286 ResourceProvider::Resource::Resource(GLuint texture_id, |
| 287 const gfx::Size& size, |
| 288 Origin origin, |
| 289 GLenum target, |
| 290 GLenum filter, |
| 291 GLenum texture_pool, |
| 292 GLint wrap_mode, |
| 293 TextureHint hint, |
| 294 ResourceFormat format) |
| 295 : child_id(0), |
| 296 gl_id(texture_id), |
| 297 gl_pixel_buffer_id(0), |
| 298 gl_upload_query_id(0), |
| 299 gl_read_lock_query_id(0), |
| 300 pixels(NULL), |
| 301 lock_for_read_count(0), |
| 302 imported_count(0), |
| 303 exported_count(0), |
| 304 dirty_image(false), |
| 305 locked_for_write(false), |
| 306 lost(false), |
| 307 marked_for_deletion(false), |
| 308 pending_set_pixels(false), |
| 309 set_pixels_completion_forced(false), |
| 310 allocated(false), |
| 311 read_lock_fences_enabled(false), |
| 312 has_shared_bitmap_id(false), |
| 313 allow_overlay(false), |
| 314 read_lock_fence(NULL), |
| 315 size(size), |
| 316 origin(origin), |
| 317 target(target), |
| 318 original_filter(filter), |
| 319 filter(filter), |
| 320 image_id(0), |
| 321 bound_image_id(0), |
| 322 texture_pool(texture_pool), |
| 323 wrap_mode(wrap_mode), |
| 324 hint(hint), |
| 325 type(RESOURCE_TYPE_GL_TEXTURE), |
| 326 format(format), |
| 327 shared_bitmap(NULL), |
| 328 gpu_memory_buffer(NULL) { |
| 329 DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT); |
| 330 DCHECK_EQ(origin == INTERNAL, !!texture_pool); |
| 331 } |
| 332 |
| 333 ResourceProvider::Resource::Resource(uint8_t* pixels, |
| 334 SharedBitmap* bitmap, |
| 335 const gfx::Size& size, |
| 336 Origin origin, |
| 337 GLenum filter, |
| 338 GLint wrap_mode) |
| 339 : child_id(0), |
| 340 gl_id(0), |
| 341 gl_pixel_buffer_id(0), |
| 342 gl_upload_query_id(0), |
| 343 gl_read_lock_query_id(0), |
| 344 pixels(pixels), |
| 345 lock_for_read_count(0), |
| 346 imported_count(0), |
| 347 exported_count(0), |
| 348 dirty_image(false), |
| 349 locked_for_write(false), |
| 350 lost(false), |
| 351 marked_for_deletion(false), |
| 352 pending_set_pixels(false), |
| 353 set_pixels_completion_forced(false), |
| 354 allocated(false), |
| 355 read_lock_fences_enabled(false), |
| 356 has_shared_bitmap_id(!!bitmap), |
| 357 allow_overlay(false), |
| 358 read_lock_fence(NULL), |
| 359 size(size), |
| 360 origin(origin), |
| 361 target(0), |
| 362 original_filter(filter), |
| 363 filter(filter), |
| 364 image_id(0), |
| 365 bound_image_id(0), |
| 366 texture_pool(0), |
| 367 wrap_mode(wrap_mode), |
| 368 hint(TEXTURE_HINT_IMMUTABLE), |
| 369 type(RESOURCE_TYPE_BITMAP), |
| 370 format(RGBA_8888), |
| 371 shared_bitmap(bitmap), |
| 372 gpu_memory_buffer(NULL) { |
| 373 DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT); |
| 374 DCHECK(origin == DELEGATED || pixels); |
| 375 if (bitmap) |
| 376 shared_bitmap_id = bitmap->id(); |
| 377 } |
| 378 |
| 379 ResourceProvider::Resource::Resource(const SharedBitmapId& bitmap_id, |
| 380 const gfx::Size& size, |
| 381 Origin origin, |
| 382 GLenum filter, |
| 383 GLint wrap_mode) |
| 384 : child_id(0), |
| 385 gl_id(0), |
| 386 gl_pixel_buffer_id(0), |
| 387 gl_upload_query_id(0), |
| 388 gl_read_lock_query_id(0), |
| 389 pixels(NULL), |
| 390 lock_for_read_count(0), |
| 391 imported_count(0), |
| 392 exported_count(0), |
| 393 dirty_image(false), |
| 394 locked_for_write(false), |
| 395 lost(false), |
| 396 marked_for_deletion(false), |
| 397 pending_set_pixels(false), |
| 398 set_pixels_completion_forced(false), |
| 399 allocated(false), |
| 400 read_lock_fences_enabled(false), |
| 401 has_shared_bitmap_id(true), |
| 402 allow_overlay(false), |
| 403 read_lock_fence(NULL), |
| 404 size(size), |
| 405 origin(origin), |
| 406 target(0), |
| 407 original_filter(filter), |
| 408 filter(filter), |
| 409 image_id(0), |
| 410 bound_image_id(0), |
| 411 texture_pool(0), |
| 412 wrap_mode(wrap_mode), |
| 413 hint(TEXTURE_HINT_IMMUTABLE), |
| 414 type(RESOURCE_TYPE_BITMAP), |
| 415 format(RGBA_8888), |
| 416 shared_bitmap_id(bitmap_id), |
| 417 shared_bitmap(NULL), |
| 418 gpu_memory_buffer(NULL) { |
| 419 DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT); |
| 420 } |
| 421 |
| 422 ResourceProvider::Child::Child() : marked_for_deletion(false) {} |
| 423 |
| 424 ResourceProvider::Child::~Child() {} |
| 425 |
| 426 scoped_ptr<ResourceProvider> ResourceProvider::Create( |
| 427 OutputSurface* output_surface, |
| 428 SharedBitmapManager* shared_bitmap_manager, |
| 429 gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, |
| 430 BlockingTaskRunner* blocking_main_thread_task_runner, |
| 431 int highp_threshold_min, |
| 432 bool use_rgba_4444_texture_format, |
| 433 size_t id_allocation_chunk_size) { |
| 434 scoped_ptr<ResourceProvider> resource_provider( |
| 435 new ResourceProvider(output_surface, |
| 436 shared_bitmap_manager, |
| 437 gpu_memory_buffer_manager, |
| 438 blocking_main_thread_task_runner, |
| 439 highp_threshold_min, |
| 440 use_rgba_4444_texture_format, |
| 441 id_allocation_chunk_size)); |
| 442 |
| 443 if (resource_provider->ContextGL()) |
| 444 resource_provider->InitializeGL(); |
| 445 else |
| 446 resource_provider->InitializeSoftware(); |
| 447 |
| 448 DCHECK_NE(RESOURCE_TYPE_INVALID, resource_provider->default_resource_type()); |
| 449 return resource_provider.Pass(); |
| 450 } |
| 451 |
| 452 ResourceProvider::~ResourceProvider() { |
| 453 while (!children_.empty()) |
| 454 DestroyChildInternal(children_.begin(), FOR_SHUTDOWN); |
| 455 while (!resources_.empty()) |
| 456 DeleteResourceInternal(resources_.begin(), FOR_SHUTDOWN); |
| 457 |
| 458 CleanUpGLIfNeeded(); |
| 459 } |
| 460 |
| 461 bool ResourceProvider::InUseByConsumer(ResourceId id) { |
| 462 Resource* resource = GetResource(id); |
| 463 return resource->lock_for_read_count > 0 || resource->exported_count > 0 || |
| 464 resource->lost; |
| 465 } |
| 466 |
| 467 bool ResourceProvider::IsLost(ResourceId id) { |
| 468 Resource* resource = GetResource(id); |
| 469 return resource->lost; |
| 470 } |
| 471 |
| 472 bool ResourceProvider::AllowOverlay(ResourceId id) { |
| 473 Resource* resource = GetResource(id); |
| 474 return resource->allow_overlay; |
| 475 } |
| 476 |
| 477 ResourceProvider::ResourceId ResourceProvider::CreateResource( |
| 478 const gfx::Size& size, |
| 479 GLint wrap_mode, |
| 480 TextureHint hint, |
| 481 ResourceFormat format) { |
| 482 DCHECK(!size.IsEmpty()); |
| 483 switch (default_resource_type_) { |
| 484 case RESOURCE_TYPE_GL_TEXTURE: |
| 485 return CreateGLTexture(size, |
| 486 GL_TEXTURE_2D, |
| 487 GL_TEXTURE_POOL_UNMANAGED_CHROMIUM, |
| 488 wrap_mode, |
| 489 hint, |
| 490 format); |
| 491 case RESOURCE_TYPE_BITMAP: |
| 492 DCHECK_EQ(RGBA_8888, format); |
| 493 return CreateBitmap(size, wrap_mode); |
| 494 case RESOURCE_TYPE_INVALID: |
| 495 break; |
| 496 } |
| 497 |
| 498 LOG(FATAL) << "Invalid default resource type."; |
| 499 return 0; |
| 500 } |
| 501 |
| 502 ResourceProvider::ResourceId ResourceProvider::CreateManagedResource( |
| 503 const gfx::Size& size, |
| 504 GLenum target, |
| 505 GLint wrap_mode, |
| 506 TextureHint hint, |
| 507 ResourceFormat format) { |
| 508 DCHECK(!size.IsEmpty()); |
| 509 switch (default_resource_type_) { |
| 510 case RESOURCE_TYPE_GL_TEXTURE: |
| 511 return CreateGLTexture(size, |
| 512 target, |
| 513 GL_TEXTURE_POOL_MANAGED_CHROMIUM, |
| 514 wrap_mode, |
| 515 hint, |
| 516 format); |
| 517 case RESOURCE_TYPE_BITMAP: |
| 518 DCHECK_EQ(RGBA_8888, format); |
| 519 return CreateBitmap(size, wrap_mode); |
| 520 case RESOURCE_TYPE_INVALID: |
| 521 break; |
| 522 } |
| 523 |
| 524 LOG(FATAL) << "Invalid default resource type."; |
| 525 return 0; |
| 526 } |
| 527 |
| 528 ResourceProvider::ResourceId ResourceProvider::CreateGLTexture( |
| 529 const gfx::Size& size, |
| 530 GLenum target, |
| 531 GLenum texture_pool, |
| 532 GLint wrap_mode, |
| 533 TextureHint hint, |
| 534 ResourceFormat format) { |
| 535 DCHECK_LE(size.width(), max_texture_size_); |
| 536 DCHECK_LE(size.height(), max_texture_size_); |
| 537 DCHECK(thread_checker_.CalledOnValidThread()); |
| 538 |
| 539 ResourceId id = next_id_++; |
| 540 Resource resource(0, size, Resource::INTERNAL, target, GL_LINEAR, |
| 541 texture_pool, wrap_mode, hint, format); |
| 542 resource.allocated = false; |
| 543 resources_[id] = resource; |
| 544 return id; |
| 545 } |
| 546 |
| 547 ResourceProvider::ResourceId ResourceProvider::CreateBitmap( |
| 548 const gfx::Size& size, GLint wrap_mode) { |
| 549 DCHECK(thread_checker_.CalledOnValidThread()); |
| 550 |
| 551 scoped_ptr<SharedBitmap> bitmap = |
| 552 shared_bitmap_manager_->AllocateSharedBitmap(size); |
| 553 uint8_t* pixels = bitmap->pixels(); |
| 554 DCHECK(pixels); |
| 555 |
| 556 ResourceId id = next_id_++; |
| 557 Resource resource(pixels, bitmap.release(), size, Resource::INTERNAL, |
| 558 GL_LINEAR, wrap_mode); |
| 559 resource.allocated = true; |
| 560 resources_[id] = resource; |
| 561 return id; |
| 562 } |
| 563 |
| 564 ResourceProvider::ResourceId ResourceProvider::CreateResourceFromIOSurface( |
| 565 const gfx::Size& size, |
| 566 unsigned io_surface_id) { |
| 567 DCHECK(thread_checker_.CalledOnValidThread()); |
| 568 |
| 569 ResourceId id = next_id_++; |
| 570 Resource resource(0, gfx::Size(), Resource::INTERNAL, |
| 571 GL_TEXTURE_RECTANGLE_ARB, GL_LINEAR, |
| 572 GL_TEXTURE_POOL_UNMANAGED_CHROMIUM, GL_CLAMP_TO_EDGE, |
| 573 TEXTURE_HINT_IMMUTABLE, RGBA_8888); |
| 574 LazyCreate(&resource); |
| 575 GLES2Interface* gl = ContextGL(); |
| 576 DCHECK(gl); |
| 577 gl->BindTexture(GL_TEXTURE_RECTANGLE_ARB, resource.gl_id); |
| 578 gl->TexImageIOSurface2DCHROMIUM( |
| 579 GL_TEXTURE_RECTANGLE_ARB, size.width(), size.height(), io_surface_id, 0); |
| 580 resource.allocated = true; |
| 581 resources_[id] = resource; |
| 582 return id; |
| 583 } |
| 584 |
| 585 ResourceProvider::ResourceId ResourceProvider::CreateResourceFromTextureMailbox( |
| 586 const TextureMailbox& mailbox, |
| 587 scoped_ptr<SingleReleaseCallbackImpl> release_callback_impl) { |
| 588 DCHECK(thread_checker_.CalledOnValidThread()); |
| 589 // Just store the information. Mailbox will be consumed in LockForRead(). |
| 590 ResourceId id = next_id_++; |
| 591 DCHECK(mailbox.IsValid()); |
| 592 Resource& resource = resources_[id]; |
| 593 if (mailbox.IsTexture()) { |
| 594 resource = Resource(0, gfx::Size(), Resource::EXTERNAL, mailbox.target(), |
| 595 mailbox.nearest_neighbor() ? GL_NEAREST : GL_LINEAR, 0, |
| 596 GL_CLAMP_TO_EDGE, TEXTURE_HINT_IMMUTABLE, RGBA_8888); |
| 597 } else { |
| 598 DCHECK(mailbox.IsSharedMemory()); |
| 599 SharedBitmap* shared_bitmap = mailbox.shared_bitmap(); |
| 600 uint8_t* pixels = shared_bitmap->pixels(); |
| 601 DCHECK(pixels); |
| 602 resource = Resource(pixels, shared_bitmap, mailbox.shared_memory_size(), |
| 603 Resource::EXTERNAL, GL_LINEAR, GL_CLAMP_TO_EDGE); |
| 604 } |
| 605 resource.allocated = true; |
| 606 resource.mailbox = mailbox; |
| 607 resource.release_callback_impl = |
| 608 base::Bind(&SingleReleaseCallbackImpl::Run, |
| 609 base::Owned(release_callback_impl.release())); |
| 610 resource.allow_overlay = mailbox.allow_overlay(); |
| 611 return id; |
| 612 } |
| 613 |
| 614 void ResourceProvider::DeleteResource(ResourceId id) { |
| 615 DCHECK(thread_checker_.CalledOnValidThread()); |
| 616 ResourceMap::iterator it = resources_.find(id); |
| 617 CHECK(it != resources_.end()); |
| 618 Resource* resource = &it->second; |
| 619 DCHECK(!resource->marked_for_deletion); |
| 620 DCHECK_EQ(resource->imported_count, 0); |
| 621 DCHECK(resource->pending_set_pixels || !resource->locked_for_write); |
| 622 |
| 623 if (resource->exported_count > 0 || resource->lock_for_read_count > 0) { |
| 624 resource->marked_for_deletion = true; |
| 625 return; |
| 626 } else { |
| 627 DeleteResourceInternal(it, NORMAL); |
| 628 } |
| 629 } |
| 630 |
| 631 void ResourceProvider::DeleteResourceInternal(ResourceMap::iterator it, |
| 632 DeleteStyle style) { |
| 633 TRACE_EVENT0("cc", "ResourceProvider::DeleteResourceInternal"); |
| 634 Resource* resource = &it->second; |
| 635 bool lost_resource = resource->lost; |
| 636 |
| 637 DCHECK(resource->exported_count == 0 || style != NORMAL); |
| 638 if (style == FOR_SHUTDOWN && resource->exported_count > 0) |
| 639 lost_resource = true; |
| 640 |
| 641 if (resource->image_id) { |
| 642 DCHECK(resource->origin == Resource::INTERNAL); |
| 643 GLES2Interface* gl = ContextGL(); |
| 644 DCHECK(gl); |
| 645 GLC(gl, gl->DestroyImageCHROMIUM(resource->image_id)); |
| 646 } |
| 647 if (resource->gl_upload_query_id) { |
| 648 DCHECK(resource->origin == Resource::INTERNAL); |
| 649 GLES2Interface* gl = ContextGL(); |
| 650 DCHECK(gl); |
| 651 GLC(gl, gl->DeleteQueriesEXT(1, &resource->gl_upload_query_id)); |
| 652 } |
| 653 if (resource->gl_read_lock_query_id) { |
| 654 DCHECK(resource->origin == Resource::INTERNAL); |
| 655 GLES2Interface* gl = ContextGL(); |
| 656 DCHECK(gl); |
| 657 GLC(gl, gl->DeleteQueriesEXT(1, &resource->gl_read_lock_query_id)); |
| 658 } |
| 659 if (resource->gl_pixel_buffer_id) { |
| 660 DCHECK(resource->origin == Resource::INTERNAL); |
| 661 GLES2Interface* gl = ContextGL(); |
| 662 DCHECK(gl); |
| 663 GLC(gl, gl->DeleteBuffers(1, &resource->gl_pixel_buffer_id)); |
| 664 } |
| 665 if (resource->origin == Resource::EXTERNAL) { |
| 666 DCHECK(resource->mailbox.IsValid()); |
| 667 GLuint sync_point = resource->mailbox.sync_point(); |
| 668 if (resource->type == RESOURCE_TYPE_GL_TEXTURE) { |
| 669 DCHECK(resource->mailbox.IsTexture()); |
| 670 lost_resource |= lost_output_surface_; |
| 671 GLES2Interface* gl = ContextGL(); |
| 672 DCHECK(gl); |
| 673 if (resource->gl_id) { |
| 674 GLC(gl, gl->DeleteTextures(1, &resource->gl_id)); |
| 675 resource->gl_id = 0; |
| 676 if (!lost_resource) |
| 677 sync_point = gl->InsertSyncPointCHROMIUM(); |
| 678 } |
| 679 } else { |
| 680 DCHECK(resource->mailbox.IsSharedMemory()); |
| 681 resource->shared_bitmap = nullptr; |
| 682 resource->pixels = nullptr; |
| 683 } |
| 684 resource->release_callback_impl.Run( |
| 685 sync_point, lost_resource, blocking_main_thread_task_runner_); |
| 686 } |
| 687 if (resource->gl_id) { |
| 688 GLES2Interface* gl = ContextGL(); |
| 689 DCHECK(gl); |
| 690 GLC(gl, gl->DeleteTextures(1, &resource->gl_id)); |
| 691 resource->gl_id = 0; |
| 692 } |
| 693 if (resource->shared_bitmap) { |
| 694 DCHECK(resource->origin != Resource::EXTERNAL); |
| 695 DCHECK_EQ(RESOURCE_TYPE_BITMAP, resource->type); |
| 696 delete resource->shared_bitmap; |
| 697 resource->pixels = NULL; |
| 698 } |
| 699 if (resource->pixels) { |
| 700 DCHECK(resource->origin == Resource::INTERNAL); |
| 701 delete[] resource->pixels; |
| 702 resource->pixels = NULL; |
| 703 } |
| 704 if (resource->gpu_memory_buffer) { |
| 705 DCHECK(resource->origin == Resource::INTERNAL); |
| 706 delete resource->gpu_memory_buffer; |
| 707 resource->gpu_memory_buffer = NULL; |
| 708 } |
| 709 resources_.erase(it); |
| 710 } |
| 711 |
| 712 ResourceProvider::ResourceType ResourceProvider::GetResourceType( |
| 713 ResourceId id) { |
| 714 return GetResource(id)->type; |
| 715 } |
| 716 |
| 717 void ResourceProvider::SetPixels(ResourceId id, |
| 718 const uint8_t* image, |
| 719 const gfx::Rect& image_rect, |
| 720 const gfx::Rect& source_rect, |
| 721 const gfx::Vector2d& dest_offset) { |
| 722 Resource* resource = GetResource(id); |
| 723 DCHECK(!resource->locked_for_write); |
| 724 DCHECK(!resource->lock_for_read_count); |
| 725 DCHECK(resource->origin == Resource::INTERNAL); |
| 726 DCHECK_EQ(resource->exported_count, 0); |
| 727 DCHECK(ReadLockFenceHasPassed(resource)); |
| 728 LazyAllocate(resource); |
| 729 |
| 730 if (resource->type == RESOURCE_TYPE_GL_TEXTURE) { |
| 731 DCHECK(resource->gl_id); |
| 732 DCHECK(!resource->pending_set_pixels); |
| 733 DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D)); |
| 734 GLES2Interface* gl = ContextGL(); |
| 735 DCHECK(gl); |
| 736 DCHECK(texture_uploader_.get()); |
| 737 gl->BindTexture(GL_TEXTURE_2D, resource->gl_id); |
| 738 texture_uploader_->Upload(image, |
| 739 image_rect, |
| 740 source_rect, |
| 741 dest_offset, |
| 742 resource->format, |
| 743 resource->size); |
| 744 } else { |
| 745 DCHECK_EQ(RESOURCE_TYPE_BITMAP, resource->type); |
| 746 DCHECK(resource->allocated); |
| 747 DCHECK_EQ(RGBA_8888, resource->format); |
| 748 DCHECK(source_rect.x() >= image_rect.x()); |
| 749 DCHECK(source_rect.y() >= image_rect.y()); |
| 750 DCHECK(source_rect.right() <= image_rect.right()); |
| 751 DCHECK(source_rect.bottom() <= image_rect.bottom()); |
| 752 SkImageInfo source_info = |
| 753 SkImageInfo::MakeN32Premul(source_rect.width(), source_rect.height()); |
| 754 size_t image_row_bytes = image_rect.width() * 4; |
| 755 gfx::Vector2d source_offset = source_rect.origin() - image_rect.origin(); |
| 756 image += source_offset.y() * image_row_bytes + source_offset.x() * 4; |
| 757 |
| 758 ScopedWriteLockSoftware lock(this, id); |
| 759 SkCanvas dest(lock.sk_bitmap()); |
| 760 dest.writePixels(source_info, image, image_row_bytes, dest_offset.x(), |
| 761 dest_offset.y()); |
| 762 } |
| 763 } |
| 764 |
| 765 void ResourceProvider::CopyToResource(ResourceId id, |
| 766 const uint8_t* image, |
| 767 const gfx::Size& image_size) { |
| 768 Resource* resource = GetResource(id); |
| 769 DCHECK(!resource->locked_for_write); |
| 770 DCHECK(!resource->lock_for_read_count); |
| 771 DCHECK(resource->origin == Resource::INTERNAL); |
| 772 DCHECK_EQ(resource->exported_count, 0); |
| 773 DCHECK(ReadLockFenceHasPassed(resource)); |
| 774 LazyAllocate(resource); |
| 775 |
| 776 DCHECK_EQ(image_size.width(), resource->size.width()); |
| 777 DCHECK_EQ(image_size.height(), resource->size.height()); |
| 778 |
| 779 if (resource->type == RESOURCE_TYPE_BITMAP) { |
| 780 DCHECK_EQ(RESOURCE_TYPE_BITMAP, resource->type); |
| 781 DCHECK(resource->allocated); |
| 782 DCHECK_EQ(RGBA_8888, resource->format); |
| 783 SkImageInfo source_info = |
| 784 SkImageInfo::MakeN32Premul(image_size.width(), image_size.height()); |
| 785 size_t image_stride = image_size.width() * 4; |
| 786 |
| 787 ScopedWriteLockSoftware lock(this, id); |
| 788 SkCanvas dest(lock.sk_bitmap()); |
| 789 dest.writePixels(source_info, image, image_stride, 0, 0); |
| 790 } else { |
| 791 DCHECK(resource->gl_id); |
| 792 DCHECK(!resource->pending_set_pixels); |
| 793 DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D)); |
| 794 GLES2Interface* gl = ContextGL(); |
| 795 DCHECK(gl); |
| 796 DCHECK(texture_uploader_.get()); |
| 797 gl->BindTexture(GL_TEXTURE_2D, resource->gl_id); |
| 798 |
| 799 if (resource->format == ETC1) { |
| 800 size_t num_bytes = static_cast<size_t>(image_size.width()) * |
| 801 image_size.height() * BitsPerPixel(ETC1) / 8; |
| 802 gl->CompressedTexImage2D(GL_TEXTURE_2D, 0, GLInternalFormat(ETC1), |
| 803 image_size.width(), image_size.height(), 0, |
| 804 num_bytes, image); |
| 805 } else { |
| 806 gl->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, image_size.width(), |
| 807 image_size.height(), GLDataFormat(resource->format), |
| 808 GLDataType(resource->format), image); |
| 809 } |
| 810 } |
| 811 } |
| 812 |
| 813 size_t ResourceProvider::NumBlockingUploads() { |
| 814 if (!texture_uploader_) |
| 815 return 0; |
| 816 |
| 817 return texture_uploader_->NumBlockingUploads(); |
| 818 } |
| 819 |
| 820 void ResourceProvider::MarkPendingUploadsAsNonBlocking() { |
| 821 if (!texture_uploader_) |
| 822 return; |
| 823 |
| 824 texture_uploader_->MarkPendingUploadsAsNonBlocking(); |
| 825 } |
| 826 |
| 827 size_t ResourceProvider::EstimatedUploadsPerTick() { |
| 828 if (!texture_uploader_) |
| 829 return 1u; |
| 830 |
| 831 double textures_per_second = texture_uploader_->EstimatedTexturesPerSecond(); |
| 832 size_t textures_per_tick = floor( |
| 833 kTextureUploadTickRate * textures_per_second); |
| 834 return textures_per_tick ? textures_per_tick : 1u; |
| 835 } |
| 836 |
| 837 void ResourceProvider::FlushUploads() { |
| 838 if (!texture_uploader_) |
| 839 return; |
| 840 |
| 841 texture_uploader_->Flush(); |
| 842 } |
| 843 |
| 844 void ResourceProvider::ReleaseCachedData() { |
| 845 if (!texture_uploader_) |
| 846 return; |
| 847 |
| 848 texture_uploader_->ReleaseCachedQueries(); |
| 849 } |
| 850 |
| 851 base::TimeTicks ResourceProvider::EstimatedUploadCompletionTime( |
| 852 size_t uploads_per_tick) { |
| 853 if (lost_output_surface_) |
| 854 return base::TimeTicks(); |
| 855 |
| 856 // Software resource uploads happen on impl thread, so don't bother batching |
| 857 // them up and trying to wait for them to complete. |
| 858 if (!texture_uploader_) { |
| 859 return gfx::FrameTime::Now() + base::TimeDelta::FromMicroseconds( |
| 860 base::Time::kMicrosecondsPerSecond * kSoftwareUploadTickRate); |
| 861 } |
| 862 |
| 863 base::TimeDelta upload_one_texture_time = |
| 864 base::TimeDelta::FromMicroseconds( |
| 865 base::Time::kMicrosecondsPerSecond * kTextureUploadTickRate) / |
| 866 uploads_per_tick; |
| 867 |
| 868 size_t total_uploads = NumBlockingUploads() + uploads_per_tick; |
| 869 return gfx::FrameTime::Now() + upload_one_texture_time * total_uploads; |
| 870 } |
| 871 |
| 872 ResourceProvider::Resource* ResourceProvider::GetResource(ResourceId id) { |
| 873 DCHECK(thread_checker_.CalledOnValidThread()); |
| 874 ResourceMap::iterator it = resources_.find(id); |
| 875 CHECK(it != resources_.end()); |
| 876 return &it->second; |
| 877 } |
| 878 |
| 879 const ResourceProvider::Resource* ResourceProvider::LockForRead(ResourceId id) { |
| 880 Resource* resource = GetResource(id); |
| 881 DCHECK(!resource->locked_for_write || |
| 882 resource->set_pixels_completion_forced) << |
| 883 "locked for write: " << resource->locked_for_write << |
| 884 " pixels completion forced: " << resource->set_pixels_completion_forced; |
| 885 DCHECK_EQ(resource->exported_count, 0); |
| 886 // Uninitialized! Call SetPixels or LockForWrite first. |
| 887 DCHECK(resource->allocated); |
| 888 |
| 889 LazyCreate(resource); |
| 890 |
| 891 if (resource->type == RESOURCE_TYPE_GL_TEXTURE && !resource->gl_id) { |
| 892 DCHECK(resource->origin != Resource::INTERNAL); |
| 893 DCHECK(resource->mailbox.IsTexture()); |
| 894 |
| 895 // Mailbox sync_points must be processed by a call to |
| 896 // WaitSyncPointIfNeeded() prior to calling LockForRead(). |
| 897 DCHECK(!resource->mailbox.sync_point()); |
| 898 |
| 899 GLES2Interface* gl = ContextGL(); |
| 900 DCHECK(gl); |
| 901 resource->gl_id = |
| 902 GLC(gl, gl->CreateAndConsumeTextureCHROMIUM(resource->mailbox.target(), |
| 903 resource->mailbox.name())); |
| 904 } |
| 905 |
| 906 if (!resource->pixels && resource->has_shared_bitmap_id && |
| 907 shared_bitmap_manager_) { |
| 908 scoped_ptr<SharedBitmap> bitmap = |
| 909 shared_bitmap_manager_->GetSharedBitmapFromId( |
| 910 resource->size, resource->shared_bitmap_id); |
| 911 if (bitmap) { |
| 912 resource->shared_bitmap = bitmap.release(); |
| 913 resource->pixels = resource->shared_bitmap->pixels(); |
| 914 } |
| 915 } |
| 916 |
| 917 resource->lock_for_read_count++; |
| 918 if (resource->read_lock_fences_enabled) { |
| 919 if (current_read_lock_fence_.get()) |
| 920 current_read_lock_fence_->Set(); |
| 921 resource->read_lock_fence = current_read_lock_fence_; |
| 922 } |
| 923 |
| 924 return resource; |
| 925 } |
| 926 |
| 927 void ResourceProvider::UnlockForRead(ResourceId id) { |
| 928 DCHECK(thread_checker_.CalledOnValidThread()); |
| 929 ResourceMap::iterator it = resources_.find(id); |
| 930 CHECK(it != resources_.end()); |
| 931 |
| 932 Resource* resource = &it->second; |
| 933 DCHECK_GT(resource->lock_for_read_count, 0); |
| 934 DCHECK_EQ(resource->exported_count, 0); |
| 935 resource->lock_for_read_count--; |
| 936 if (resource->marked_for_deletion && !resource->lock_for_read_count) { |
| 937 if (!resource->child_id) { |
| 938 // The resource belongs to this ResourceProvider, so it can be destroyed. |
| 939 DeleteResourceInternal(it, NORMAL); |
| 940 } else { |
| 941 ChildMap::iterator child_it = children_.find(resource->child_id); |
| 942 ResourceIdArray unused; |
| 943 unused.push_back(id); |
| 944 DeleteAndReturnUnusedResourcesToChild(child_it, NORMAL, unused); |
| 945 } |
| 946 } |
| 947 } |
| 948 |
| 949 ResourceProvider::Resource* ResourceProvider::LockForWrite(ResourceId id) { |
| 950 Resource* resource = GetResource(id); |
| 951 DCHECK(CanLockForWrite(id)); |
| 952 |
| 953 resource->locked_for_write = true; |
| 954 return resource; |
| 955 } |
| 956 |
| 957 bool ResourceProvider::CanLockForWrite(ResourceId id) { |
| 958 Resource* resource = GetResource(id); |
| 959 return !resource->locked_for_write && !resource->lock_for_read_count && |
| 960 !resource->exported_count && resource->origin == Resource::INTERNAL && |
| 961 !resource->lost && ReadLockFenceHasPassed(resource); |
| 962 } |
| 963 |
| 964 void ResourceProvider::UnlockForWrite(ResourceProvider::Resource* resource) { |
| 965 DCHECK(resource->locked_for_write); |
| 966 DCHECK_EQ(resource->exported_count, 0); |
| 967 DCHECK(resource->origin == Resource::INTERNAL); |
| 968 resource->locked_for_write = false; |
| 969 } |
| 970 |
| 971 ResourceProvider::ScopedReadLockGL::ScopedReadLockGL( |
| 972 ResourceProvider* resource_provider, |
| 973 ResourceProvider::ResourceId resource_id) |
| 974 : resource_provider_(resource_provider), |
| 975 resource_id_(resource_id), |
| 976 texture_id_(resource_provider->LockForRead(resource_id)->gl_id) { |
| 977 DCHECK(texture_id_); |
| 978 } |
| 979 |
| 980 ResourceProvider::ScopedReadLockGL::~ScopedReadLockGL() { |
| 981 resource_provider_->UnlockForRead(resource_id_); |
| 982 } |
| 983 |
| 984 ResourceProvider::ScopedSamplerGL::ScopedSamplerGL( |
| 985 ResourceProvider* resource_provider, |
| 986 ResourceProvider::ResourceId resource_id, |
| 987 GLenum filter) |
| 988 : ScopedReadLockGL(resource_provider, resource_id), |
| 989 unit_(GL_TEXTURE0), |
| 990 target_(resource_provider->BindForSampling(resource_id, unit_, filter)) { |
| 991 } |
| 992 |
| 993 ResourceProvider::ScopedSamplerGL::ScopedSamplerGL( |
| 994 ResourceProvider* resource_provider, |
| 995 ResourceProvider::ResourceId resource_id, |
| 996 GLenum unit, |
| 997 GLenum filter) |
| 998 : ScopedReadLockGL(resource_provider, resource_id), |
| 999 unit_(unit), |
| 1000 target_(resource_provider->BindForSampling(resource_id, unit_, filter)) { |
| 1001 } |
| 1002 |
| 1003 ResourceProvider::ScopedSamplerGL::~ScopedSamplerGL() { |
| 1004 } |
| 1005 |
| 1006 ResourceProvider::ScopedWriteLockGL::ScopedWriteLockGL( |
| 1007 ResourceProvider* resource_provider, |
| 1008 ResourceProvider::ResourceId resource_id) |
| 1009 : resource_provider_(resource_provider), |
| 1010 resource_(resource_provider->LockForWrite(resource_id)) { |
| 1011 resource_provider_->LazyAllocate(resource_); |
| 1012 texture_id_ = resource_->gl_id; |
| 1013 DCHECK(texture_id_); |
| 1014 } |
| 1015 |
| 1016 ResourceProvider::ScopedWriteLockGL::~ScopedWriteLockGL() { |
| 1017 resource_provider_->UnlockForWrite(resource_); |
| 1018 } |
| 1019 |
| 1020 void ResourceProvider::PopulateSkBitmapWithResource( |
| 1021 SkBitmap* sk_bitmap, const Resource* resource) { |
| 1022 DCHECK_EQ(RGBA_8888, resource->format); |
| 1023 SkImageInfo info = SkImageInfo::MakeN32Premul(resource->size.width(), |
| 1024 resource->size.height()); |
| 1025 sk_bitmap->installPixels(info, resource->pixels, info.minRowBytes()); |
| 1026 } |
| 1027 |
| 1028 ResourceProvider::ScopedReadLockSoftware::ScopedReadLockSoftware( |
| 1029 ResourceProvider* resource_provider, |
| 1030 ResourceProvider::ResourceId resource_id) |
| 1031 : resource_provider_(resource_provider), |
| 1032 resource_id_(resource_id) { |
| 1033 const Resource* resource = resource_provider->LockForRead(resource_id); |
| 1034 wrap_mode_ = resource->wrap_mode; |
| 1035 ResourceProvider::PopulateSkBitmapWithResource(&sk_bitmap_, resource); |
| 1036 } |
| 1037 |
| 1038 ResourceProvider::ScopedReadLockSoftware::~ScopedReadLockSoftware() { |
| 1039 resource_provider_->UnlockForRead(resource_id_); |
| 1040 } |
| 1041 |
| 1042 ResourceProvider::ScopedWriteLockSoftware::ScopedWriteLockSoftware( |
| 1043 ResourceProvider* resource_provider, |
| 1044 ResourceProvider::ResourceId resource_id) |
| 1045 : resource_provider_(resource_provider), |
| 1046 resource_(resource_provider->LockForWrite(resource_id)) { |
| 1047 ResourceProvider::PopulateSkBitmapWithResource(&sk_bitmap_, resource_); |
| 1048 DCHECK(valid()); |
| 1049 } |
| 1050 |
| 1051 ResourceProvider::ScopedWriteLockSoftware::~ScopedWriteLockSoftware() { |
| 1052 DCHECK(thread_checker_.CalledOnValidThread()); |
| 1053 resource_provider_->UnlockForWrite(resource_); |
| 1054 } |
| 1055 |
| 1056 ResourceProvider::ScopedWriteLockGpuMemoryBuffer:: |
| 1057 ScopedWriteLockGpuMemoryBuffer(ResourceProvider* resource_provider, |
| 1058 ResourceProvider::ResourceId resource_id) |
| 1059 : resource_provider_(resource_provider), |
| 1060 resource_(resource_provider->LockForWrite(resource_id)), |
| 1061 gpu_memory_buffer_manager_(resource_provider->gpu_memory_buffer_manager_), |
| 1062 gpu_memory_buffer_(nullptr), |
| 1063 size_(resource_->size), |
| 1064 format_(resource_->format) { |
| 1065 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource_->type); |
| 1066 std::swap(gpu_memory_buffer_, resource_->gpu_memory_buffer); |
| 1067 } |
| 1068 |
| 1069 ResourceProvider::ScopedWriteLockGpuMemoryBuffer:: |
| 1070 ~ScopedWriteLockGpuMemoryBuffer() { |
| 1071 DCHECK(thread_checker_.CalledOnValidThread()); |
| 1072 resource_provider_->UnlockForWrite(resource_); |
| 1073 if (!gpu_memory_buffer_) |
| 1074 return; |
| 1075 |
| 1076 if (!resource_->image_id) { |
| 1077 GLES2Interface* gl = resource_provider_->ContextGL(); |
| 1078 DCHECK(gl); |
| 1079 |
| 1080 #if defined(OS_CHROMEOS) |
| 1081 // TODO(reveman): GL_COMMANDS_ISSUED_CHROMIUM is used for synchronization |
| 1082 // on ChromeOS to avoid some performance issues. This only works with |
| 1083 // shared memory backed buffers. crbug.com/436314 |
| 1084 DCHECK_EQ(gpu_memory_buffer_->GetHandle().type, gfx::SHARED_MEMORY_BUFFER); |
| 1085 #endif |
| 1086 |
| 1087 resource_->image_id = |
| 1088 gl->CreateImageCHROMIUM(gpu_memory_buffer_->AsClientBuffer(), |
| 1089 size_.width(), |
| 1090 size_.height(), |
| 1091 GL_RGBA); |
| 1092 } |
| 1093 |
| 1094 std::swap(resource_->gpu_memory_buffer, gpu_memory_buffer_); |
| 1095 resource_->allocated = true; |
| 1096 resource_->dirty_image = true; |
| 1097 |
| 1098 // GpuMemoryBuffer provides direct access to the memory used by the GPU. |
| 1099 // Read lock fences are required to ensure that we're not trying to map a |
| 1100 // buffer that is currently in-use by the GPU. |
| 1101 resource_->read_lock_fences_enabled = true; |
| 1102 } |
| 1103 |
| 1104 gfx::GpuMemoryBuffer* |
| 1105 ResourceProvider::ScopedWriteLockGpuMemoryBuffer::GetGpuMemoryBuffer() { |
| 1106 if (!gpu_memory_buffer_) { |
| 1107 scoped_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer = |
| 1108 gpu_memory_buffer_manager_->AllocateGpuMemoryBuffer( |
| 1109 size_, ToGpuMemoryBufferFormat(format_), gfx::GpuMemoryBuffer::MAP); |
| 1110 gpu_memory_buffer_ = gpu_memory_buffer.release(); |
| 1111 } |
| 1112 |
| 1113 return gpu_memory_buffer_; |
| 1114 } |
| 1115 |
| 1116 ResourceProvider::ScopedWriteLockGr::ScopedWriteLockGr( |
| 1117 ResourceProvider* resource_provider, |
| 1118 ResourceProvider::ResourceId resource_id) |
| 1119 : resource_provider_(resource_provider), |
| 1120 resource_(resource_provider->LockForWrite(resource_id)) { |
| 1121 DCHECK(thread_checker_.CalledOnValidThread()); |
| 1122 resource_provider_->LazyAllocate(resource_); |
| 1123 } |
| 1124 |
| 1125 ResourceProvider::ScopedWriteLockGr::~ScopedWriteLockGr() { |
| 1126 DCHECK(thread_checker_.CalledOnValidThread()); |
| 1127 DCHECK(resource_->locked_for_write); |
| 1128 resource_provider_->UnlockForWrite(resource_); |
| 1129 } |
| 1130 |
| 1131 void ResourceProvider::ScopedWriteLockGr::InitSkSurface( |
| 1132 bool use_worker_context, |
| 1133 bool use_distance_field_text, |
| 1134 bool can_use_lcd_text, |
| 1135 int msaa_sample_count) { |
| 1136 DCHECK(resource_->locked_for_write); |
| 1137 |
| 1138 GrBackendTextureDesc desc; |
| 1139 desc.fFlags = kRenderTarget_GrBackendTextureFlag; |
| 1140 desc.fWidth = resource_->size.width(); |
| 1141 desc.fHeight = resource_->size.height(); |
| 1142 desc.fConfig = ToGrPixelConfig(resource_->format); |
| 1143 desc.fOrigin = kTopLeft_GrSurfaceOrigin; |
| 1144 desc.fTextureHandle = resource_->gl_id; |
| 1145 desc.fSampleCnt = msaa_sample_count; |
| 1146 |
| 1147 class GrContext* gr_context = |
| 1148 resource_provider_->GrContext(use_worker_context); |
| 1149 skia::RefPtr<GrTexture> gr_texture = |
| 1150 skia::AdoptRef(gr_context->textureProvider()->wrapBackendTexture(desc)); |
| 1151 if (gr_texture) { |
| 1152 uint32_t flags = use_distance_field_text |
| 1153 ? SkSurfaceProps::kUseDistanceFieldFonts_Flag |
| 1154 : 0; |
| 1155 // Use unknown pixel geometry to disable LCD text. |
| 1156 SkSurfaceProps surface_props(flags, kUnknown_SkPixelGeometry); |
| 1157 if (can_use_lcd_text) { |
| 1158 // LegacyFontHost will get LCD text and skia figures out what type to use. |
| 1159 surface_props = |
| 1160 SkSurfaceProps(flags, SkSurfaceProps::kLegacyFontHost_InitType); |
| 1161 } |
| 1162 sk_surface_ = skia::AdoptRef(SkSurface::NewRenderTargetDirect( |
| 1163 gr_texture->asRenderTarget(), &surface_props)); |
| 1164 return; |
| 1165 } |
| 1166 sk_surface_.clear(); |
| 1167 } |
| 1168 |
| 1169 void ResourceProvider::ScopedWriteLockGr::ReleaseSkSurface() { |
| 1170 sk_surface_.clear(); |
| 1171 } |
| 1172 |
| 1173 ResourceProvider::SynchronousFence::SynchronousFence( |
| 1174 gpu::gles2::GLES2Interface* gl) |
| 1175 : gl_(gl), has_synchronized_(true) { |
| 1176 } |
| 1177 |
| 1178 ResourceProvider::SynchronousFence::~SynchronousFence() { |
| 1179 } |
| 1180 |
| 1181 void ResourceProvider::SynchronousFence::Set() { |
| 1182 has_synchronized_ = false; |
| 1183 } |
| 1184 |
| 1185 bool ResourceProvider::SynchronousFence::HasPassed() { |
| 1186 if (!has_synchronized_) { |
| 1187 has_synchronized_ = true; |
| 1188 Synchronize(); |
| 1189 } |
| 1190 return true; |
| 1191 } |
| 1192 |
| 1193 void ResourceProvider::SynchronousFence::Wait() { |
| 1194 HasPassed(); |
| 1195 } |
| 1196 |
| 1197 void ResourceProvider::SynchronousFence::Synchronize() { |
| 1198 TRACE_EVENT0("cc", "ResourceProvider::SynchronousFence::Synchronize"); |
| 1199 gl_->Finish(); |
| 1200 } |
| 1201 |
| 1202 ResourceProvider::ResourceProvider( |
| 1203 OutputSurface* output_surface, |
| 1204 SharedBitmapManager* shared_bitmap_manager, |
| 1205 gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, |
| 1206 BlockingTaskRunner* blocking_main_thread_task_runner, |
| 1207 int highp_threshold_min, |
| 1208 bool use_rgba_4444_texture_format, |
| 1209 size_t id_allocation_chunk_size) |
| 1210 : output_surface_(output_surface), |
| 1211 shared_bitmap_manager_(shared_bitmap_manager), |
| 1212 gpu_memory_buffer_manager_(gpu_memory_buffer_manager), |
| 1213 blocking_main_thread_task_runner_(blocking_main_thread_task_runner), |
| 1214 lost_output_surface_(false), |
| 1215 highp_threshold_min_(highp_threshold_min), |
| 1216 next_id_(1), |
| 1217 next_child_(1), |
| 1218 default_resource_type_(RESOURCE_TYPE_INVALID), |
| 1219 use_texture_storage_ext_(false), |
| 1220 use_texture_format_bgra_(false), |
| 1221 use_texture_usage_hint_(false), |
| 1222 use_compressed_texture_etc1_(false), |
| 1223 yuv_resource_format_(LUMINANCE_8), |
| 1224 max_texture_size_(0), |
| 1225 best_texture_format_(RGBA_8888), |
| 1226 use_rgba_4444_texture_format_(use_rgba_4444_texture_format), |
| 1227 id_allocation_chunk_size_(id_allocation_chunk_size), |
| 1228 use_sync_query_(false) { |
| 1229 DCHECK(output_surface_->HasClient()); |
| 1230 DCHECK(id_allocation_chunk_size_); |
| 1231 } |
| 1232 |
| 1233 void ResourceProvider::InitializeSoftware() { |
| 1234 DCHECK(thread_checker_.CalledOnValidThread()); |
| 1235 DCHECK_NE(RESOURCE_TYPE_BITMAP, default_resource_type_); |
| 1236 |
| 1237 CleanUpGLIfNeeded(); |
| 1238 |
| 1239 default_resource_type_ = RESOURCE_TYPE_BITMAP; |
| 1240 // Pick an arbitrary limit here similar to what hardware might. |
| 1241 max_texture_size_ = 16 * 1024; |
| 1242 best_texture_format_ = RGBA_8888; |
| 1243 } |
| 1244 |
| 1245 void ResourceProvider::InitializeGL() { |
| 1246 DCHECK(thread_checker_.CalledOnValidThread()); |
| 1247 DCHECK(!texture_uploader_); |
| 1248 DCHECK_NE(RESOURCE_TYPE_GL_TEXTURE, default_resource_type_); |
| 1249 DCHECK(!texture_id_allocator_); |
| 1250 DCHECK(!buffer_id_allocator_); |
| 1251 |
| 1252 default_resource_type_ = RESOURCE_TYPE_GL_TEXTURE; |
| 1253 |
| 1254 const ContextProvider::Capabilities& caps = |
| 1255 output_surface_->context_provider()->ContextCapabilities(); |
| 1256 |
| 1257 bool use_bgra = caps.gpu.texture_format_bgra8888; |
| 1258 use_texture_storage_ext_ = caps.gpu.texture_storage; |
| 1259 use_texture_format_bgra_ = caps.gpu.texture_format_bgra8888; |
| 1260 use_texture_usage_hint_ = caps.gpu.texture_usage; |
| 1261 use_compressed_texture_etc1_ = caps.gpu.texture_format_etc1; |
| 1262 yuv_resource_format_ = caps.gpu.texture_rg ? RED_8 : LUMINANCE_8; |
| 1263 use_sync_query_ = caps.gpu.sync_query; |
| 1264 |
| 1265 GLES2Interface* gl = ContextGL(); |
| 1266 DCHECK(gl); |
| 1267 |
| 1268 texture_uploader_ = TextureUploader::Create(gl); |
| 1269 max_texture_size_ = 0; // Context expects cleared value. |
| 1270 GLC(gl, gl->GetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size_)); |
| 1271 best_texture_format_ = PlatformColor::BestTextureFormat(use_bgra); |
| 1272 |
| 1273 texture_id_allocator_.reset( |
| 1274 new TextureIdAllocator(gl, id_allocation_chunk_size_)); |
| 1275 buffer_id_allocator_.reset( |
| 1276 new BufferIdAllocator(gl, id_allocation_chunk_size_)); |
| 1277 } |
| 1278 |
| 1279 void ResourceProvider::CleanUpGLIfNeeded() { |
| 1280 GLES2Interface* gl = ContextGL(); |
| 1281 if (default_resource_type_ != RESOURCE_TYPE_GL_TEXTURE) { |
| 1282 // We are not in GL mode, but double check before returning. |
| 1283 DCHECK(!gl); |
| 1284 DCHECK(!texture_uploader_); |
| 1285 return; |
| 1286 } |
| 1287 |
| 1288 DCHECK(gl); |
| 1289 #if DCHECK_IS_ON() |
| 1290 // Check that all GL resources has been deleted. |
| 1291 for (ResourceMap::const_iterator itr = resources_.begin(); |
| 1292 itr != resources_.end(); |
| 1293 ++itr) { |
| 1294 DCHECK_NE(RESOURCE_TYPE_GL_TEXTURE, itr->second.type); |
| 1295 } |
| 1296 #endif // DCHECK_IS_ON() |
| 1297 |
| 1298 texture_uploader_ = nullptr; |
| 1299 texture_id_allocator_ = nullptr; |
| 1300 buffer_id_allocator_ = nullptr; |
| 1301 gl->Finish(); |
| 1302 } |
| 1303 |
| 1304 int ResourceProvider::CreateChild(const ReturnCallback& return_callback) { |
| 1305 DCHECK(thread_checker_.CalledOnValidThread()); |
| 1306 |
| 1307 Child child_info; |
| 1308 child_info.return_callback = return_callback; |
| 1309 |
| 1310 int child = next_child_++; |
| 1311 children_[child] = child_info; |
| 1312 return child; |
| 1313 } |
| 1314 |
| 1315 void ResourceProvider::DestroyChild(int child_id) { |
| 1316 ChildMap::iterator it = children_.find(child_id); |
| 1317 DCHECK(it != children_.end()); |
| 1318 DestroyChildInternal(it, NORMAL); |
| 1319 } |
| 1320 |
| 1321 void ResourceProvider::DestroyChildInternal(ChildMap::iterator it, |
| 1322 DeleteStyle style) { |
| 1323 DCHECK(thread_checker_.CalledOnValidThread()); |
| 1324 |
| 1325 Child& child = it->second; |
| 1326 DCHECK(style == FOR_SHUTDOWN || !child.marked_for_deletion); |
| 1327 |
| 1328 ResourceIdArray resources_for_child; |
| 1329 |
| 1330 for (ResourceIdMap::iterator child_it = child.child_to_parent_map.begin(); |
| 1331 child_it != child.child_to_parent_map.end(); |
| 1332 ++child_it) { |
| 1333 ResourceId id = child_it->second; |
| 1334 resources_for_child.push_back(id); |
| 1335 } |
| 1336 |
| 1337 // If the child is going away, don't consider any resources in use. |
| 1338 child.in_use_resources.clear(); |
| 1339 child.marked_for_deletion = true; |
| 1340 |
| 1341 DeleteAndReturnUnusedResourcesToChild(it, style, resources_for_child); |
| 1342 } |
| 1343 |
| 1344 const ResourceProvider::ResourceIdMap& ResourceProvider::GetChildToParentMap( |
| 1345 int child) const { |
| 1346 DCHECK(thread_checker_.CalledOnValidThread()); |
| 1347 ChildMap::const_iterator it = children_.find(child); |
| 1348 DCHECK(it != children_.end()); |
| 1349 DCHECK(!it->second.marked_for_deletion); |
| 1350 return it->second.child_to_parent_map; |
| 1351 } |
| 1352 |
| 1353 void ResourceProvider::PrepareSendToParent(const ResourceIdArray& resources, |
| 1354 TransferableResourceArray* list) { |
| 1355 DCHECK(thread_checker_.CalledOnValidThread()); |
| 1356 GLES2Interface* gl = ContextGL(); |
| 1357 bool need_sync_point = false; |
| 1358 for (ResourceIdArray::const_iterator it = resources.begin(); |
| 1359 it != resources.end(); |
| 1360 ++it) { |
| 1361 TransferableResource resource; |
| 1362 TransferResource(gl, *it, &resource); |
| 1363 if (!resource.mailbox_holder.sync_point && !resource.is_software) |
| 1364 need_sync_point = true; |
| 1365 ++resources_.find(*it)->second.exported_count; |
| 1366 list->push_back(resource); |
| 1367 } |
| 1368 if (need_sync_point) { |
| 1369 GLuint sync_point = gl->InsertSyncPointCHROMIUM(); |
| 1370 for (TransferableResourceArray::iterator it = list->begin(); |
| 1371 it != list->end(); |
| 1372 ++it) { |
| 1373 if (!it->mailbox_holder.sync_point) |
| 1374 it->mailbox_holder.sync_point = sync_point; |
| 1375 } |
| 1376 } |
| 1377 } |
| 1378 |
| 1379 void ResourceProvider::ReceiveFromChild( |
| 1380 int child, const TransferableResourceArray& resources) { |
| 1381 DCHECK(thread_checker_.CalledOnValidThread()); |
| 1382 GLES2Interface* gl = ContextGL(); |
| 1383 Child& child_info = children_.find(child)->second; |
| 1384 DCHECK(!child_info.marked_for_deletion); |
| 1385 for (TransferableResourceArray::const_iterator it = resources.begin(); |
| 1386 it != resources.end(); |
| 1387 ++it) { |
| 1388 ResourceIdMap::iterator resource_in_map_it = |
| 1389 child_info.child_to_parent_map.find(it->id); |
| 1390 if (resource_in_map_it != child_info.child_to_parent_map.end()) { |
| 1391 Resource& resource = resources_[resource_in_map_it->second]; |
| 1392 resource.marked_for_deletion = false; |
| 1393 resource.imported_count++; |
| 1394 continue; |
| 1395 } |
| 1396 |
| 1397 if ((!it->is_software && !gl) || |
| 1398 (it->is_software && !shared_bitmap_manager_)) { |
| 1399 TRACE_EVENT0("cc", "ResourceProvider::ReceiveFromChild dropping invalid"); |
| 1400 ReturnedResourceArray to_return; |
| 1401 to_return.push_back(it->ToReturnedResource()); |
| 1402 child_info.return_callback.Run(to_return, |
| 1403 blocking_main_thread_task_runner_); |
| 1404 continue; |
| 1405 } |
| 1406 |
| 1407 ResourceId local_id = next_id_++; |
| 1408 Resource& resource = resources_[local_id]; |
| 1409 if (it->is_software) { |
| 1410 resource = |
| 1411 Resource(it->mailbox_holder.mailbox, it->size, Resource::DELEGATED, |
| 1412 GL_LINEAR, it->is_repeated ? GL_REPEAT : GL_CLAMP_TO_EDGE); |
| 1413 } else { |
| 1414 resource = Resource(0, it->size, Resource::DELEGATED, |
| 1415 it->mailbox_holder.texture_target, it->filter, 0, |
| 1416 it->is_repeated ? GL_REPEAT : GL_CLAMP_TO_EDGE, |
| 1417 TEXTURE_HINT_IMMUTABLE, it->format); |
| 1418 resource.mailbox = TextureMailbox(it->mailbox_holder.mailbox, |
| 1419 it->mailbox_holder.texture_target, |
| 1420 it->mailbox_holder.sync_point); |
| 1421 } |
| 1422 resource.child_id = child; |
| 1423 // Don't allocate a texture for a child. |
| 1424 resource.allocated = true; |
| 1425 resource.imported_count = 1; |
| 1426 resource.allow_overlay = it->allow_overlay; |
| 1427 child_info.parent_to_child_map[local_id] = it->id; |
| 1428 child_info.child_to_parent_map[it->id] = local_id; |
| 1429 } |
| 1430 } |
| 1431 |
| 1432 void ResourceProvider::DeclareUsedResourcesFromChild( |
| 1433 int child, |
| 1434 const ResourceIdArray& resources_from_child) { |
| 1435 DCHECK(thread_checker_.CalledOnValidThread()); |
| 1436 |
| 1437 ChildMap::iterator child_it = children_.find(child); |
| 1438 DCHECK(child_it != children_.end()); |
| 1439 Child& child_info = child_it->second; |
| 1440 DCHECK(!child_info.marked_for_deletion); |
| 1441 child_info.in_use_resources.clear(); |
| 1442 |
| 1443 for (size_t i = 0; i < resources_from_child.size(); ++i) { |
| 1444 ResourceIdMap::iterator it = |
| 1445 child_info.child_to_parent_map.find(resources_from_child[i]); |
| 1446 DCHECK(it != child_info.child_to_parent_map.end()); |
| 1447 |
| 1448 ResourceId local_id = it->second; |
| 1449 DCHECK(!resources_[local_id].marked_for_deletion); |
| 1450 child_info.in_use_resources.insert(local_id); |
| 1451 } |
| 1452 |
| 1453 ResourceIdArray unused; |
| 1454 for (ResourceIdMap::iterator it = child_info.child_to_parent_map.begin(); |
| 1455 it != child_info.child_to_parent_map.end(); |
| 1456 ++it) { |
| 1457 ResourceId local_id = it->second; |
| 1458 bool resource_is_in_use = child_info.in_use_resources.count(local_id) > 0; |
| 1459 if (!resource_is_in_use) |
| 1460 unused.push_back(local_id); |
| 1461 } |
| 1462 DeleteAndReturnUnusedResourcesToChild(child_it, NORMAL, unused); |
| 1463 } |
| 1464 |
| 1465 // static |
| 1466 bool ResourceProvider::CompareResourceMapIteratorsByChildId( |
| 1467 const std::pair<ReturnedResource, ResourceMap::iterator>& a, |
| 1468 const std::pair<ReturnedResource, ResourceMap::iterator>& b) { |
| 1469 const ResourceMap::iterator& a_it = a.second; |
| 1470 const ResourceMap::iterator& b_it = b.second; |
| 1471 const Resource& a_resource = a_it->second; |
| 1472 const Resource& b_resource = b_it->second; |
| 1473 return a_resource.child_id < b_resource.child_id; |
| 1474 } |
| 1475 |
| 1476 void ResourceProvider::ReceiveReturnsFromParent( |
| 1477 const ReturnedResourceArray& resources) { |
| 1478 DCHECK(thread_checker_.CalledOnValidThread()); |
| 1479 GLES2Interface* gl = ContextGL(); |
| 1480 |
| 1481 int child_id = 0; |
| 1482 ResourceIdArray resources_for_child; |
| 1483 |
| 1484 std::vector<std::pair<ReturnedResource, ResourceMap::iterator>> |
| 1485 sorted_resources; |
| 1486 |
| 1487 for (ReturnedResourceArray::const_iterator it = resources.begin(); |
| 1488 it != resources.end(); |
| 1489 ++it) { |
| 1490 ResourceId local_id = it->id; |
| 1491 ResourceMap::iterator map_iterator = resources_.find(local_id); |
| 1492 |
| 1493 // Resource was already lost (e.g. it belonged to a child that was |
| 1494 // destroyed). |
| 1495 if (map_iterator == resources_.end()) |
| 1496 continue; |
| 1497 |
| 1498 sorted_resources.push_back( |
| 1499 std::pair<ReturnedResource, ResourceMap::iterator>(*it, map_iterator)); |
| 1500 } |
| 1501 |
| 1502 std::sort(sorted_resources.begin(), |
| 1503 sorted_resources.end(), |
| 1504 CompareResourceMapIteratorsByChildId); |
| 1505 |
| 1506 ChildMap::iterator child_it = children_.end(); |
| 1507 for (size_t i = 0; i < sorted_resources.size(); ++i) { |
| 1508 ReturnedResource& returned = sorted_resources[i].first; |
| 1509 ResourceMap::iterator& map_iterator = sorted_resources[i].second; |
| 1510 ResourceId local_id = map_iterator->first; |
| 1511 Resource* resource = &map_iterator->second; |
| 1512 |
| 1513 CHECK_GE(resource->exported_count, returned.count); |
| 1514 resource->exported_count -= returned.count; |
| 1515 resource->lost |= returned.lost; |
| 1516 if (resource->exported_count) |
| 1517 continue; |
| 1518 |
| 1519 // Need to wait for the current read lock fence to pass before we can |
| 1520 // recycle this resource. |
| 1521 if (resource->read_lock_fences_enabled) { |
| 1522 if (current_read_lock_fence_.get()) |
| 1523 current_read_lock_fence_->Set(); |
| 1524 resource->read_lock_fence = current_read_lock_fence_; |
| 1525 } |
| 1526 |
| 1527 if (returned.sync_point) { |
| 1528 DCHECK(!resource->has_shared_bitmap_id); |
| 1529 if (resource->origin == Resource::INTERNAL) { |
| 1530 DCHECK(resource->gl_id); |
| 1531 GLC(gl, gl->WaitSyncPointCHROMIUM(returned.sync_point)); |
| 1532 } else { |
| 1533 DCHECK(!resource->gl_id); |
| 1534 resource->mailbox.set_sync_point(returned.sync_point); |
| 1535 } |
| 1536 } |
| 1537 |
| 1538 if (!resource->marked_for_deletion) |
| 1539 continue; |
| 1540 |
| 1541 if (!resource->child_id) { |
| 1542 // The resource belongs to this ResourceProvider, so it can be destroyed. |
| 1543 DeleteResourceInternal(map_iterator, NORMAL); |
| 1544 continue; |
| 1545 } |
| 1546 |
| 1547 DCHECK(resource->origin == Resource::DELEGATED); |
| 1548 // Delete the resource and return it to the child it came from one. |
| 1549 if (resource->child_id != child_id) { |
| 1550 if (child_id) { |
| 1551 DCHECK_NE(resources_for_child.size(), 0u); |
| 1552 DCHECK(child_it != children_.end()); |
| 1553 DeleteAndReturnUnusedResourcesToChild(child_it, NORMAL, |
| 1554 resources_for_child); |
| 1555 resources_for_child.clear(); |
| 1556 } |
| 1557 |
| 1558 child_it = children_.find(resource->child_id); |
| 1559 DCHECK(child_it != children_.end()); |
| 1560 child_id = resource->child_id; |
| 1561 } |
| 1562 resources_for_child.push_back(local_id); |
| 1563 } |
| 1564 |
| 1565 if (child_id) { |
| 1566 DCHECK_NE(resources_for_child.size(), 0u); |
| 1567 DCHECK(child_it != children_.end()); |
| 1568 DeleteAndReturnUnusedResourcesToChild(child_it, NORMAL, |
| 1569 resources_for_child); |
| 1570 } |
| 1571 } |
| 1572 |
| 1573 void ResourceProvider::TransferResource(GLES2Interface* gl, |
| 1574 ResourceId id, |
| 1575 TransferableResource* resource) { |
| 1576 Resource* source = GetResource(id); |
| 1577 DCHECK(!source->locked_for_write); |
| 1578 DCHECK(!source->lock_for_read_count); |
| 1579 DCHECK(source->origin != Resource::EXTERNAL || source->mailbox.IsValid()); |
| 1580 DCHECK(source->allocated); |
| 1581 resource->id = id; |
| 1582 resource->format = source->format; |
| 1583 resource->mailbox_holder.texture_target = source->target; |
| 1584 resource->filter = source->filter; |
| 1585 resource->size = source->size; |
| 1586 resource->is_repeated = (source->wrap_mode == GL_REPEAT); |
| 1587 resource->allow_overlay = source->allow_overlay; |
| 1588 |
| 1589 if (source->type == RESOURCE_TYPE_BITMAP) { |
| 1590 resource->mailbox_holder.mailbox = source->shared_bitmap_id; |
| 1591 resource->is_software = true; |
| 1592 } else if (!source->mailbox.IsValid()) { |
| 1593 LazyCreate(source); |
| 1594 DCHECK(source->gl_id); |
| 1595 DCHECK(source->origin == Resource::INTERNAL); |
| 1596 if (source->image_id) { |
| 1597 DCHECK(source->dirty_image); |
| 1598 BindImageForSampling(source); |
| 1599 } |
| 1600 // This is a resource allocated by the compositor, we need to produce it. |
| 1601 // Don't set a sync point, the caller will do it. |
| 1602 GLC(gl, gl->GenMailboxCHROMIUM(resource->mailbox_holder.mailbox.name)); |
| 1603 GLC(gl, gl->ProduceTextureDirectCHROMIUM( |
| 1604 source->gl_id, resource->mailbox_holder.texture_target, |
| 1605 resource->mailbox_holder.mailbox.name)); |
| 1606 |
| 1607 source->mailbox = TextureMailbox(resource->mailbox_holder); |
| 1608 } else { |
| 1609 DCHECK(source->mailbox.IsTexture()); |
| 1610 if (source->image_id && source->dirty_image) { |
| 1611 DCHECK(source->gl_id); |
| 1612 DCHECK(source->origin == Resource::INTERNAL); |
| 1613 GLC(gl, |
| 1614 gl->BindTexture(resource->mailbox_holder.texture_target, |
| 1615 source->gl_id)); |
| 1616 BindImageForSampling(source); |
| 1617 } |
| 1618 // This is either an external resource, or a compositor resource that we |
| 1619 // already exported. Make sure to forward the sync point that we were given. |
| 1620 resource->mailbox_holder.mailbox = source->mailbox.mailbox(); |
| 1621 resource->mailbox_holder.texture_target = source->mailbox.target(); |
| 1622 resource->mailbox_holder.sync_point = source->mailbox.sync_point(); |
| 1623 source->mailbox.set_sync_point(0); |
| 1624 } |
| 1625 } |
| 1626 |
| 1627 void ResourceProvider::DeleteAndReturnUnusedResourcesToChild( |
| 1628 ChildMap::iterator child_it, |
| 1629 DeleteStyle style, |
| 1630 const ResourceIdArray& unused) { |
| 1631 DCHECK(thread_checker_.CalledOnValidThread()); |
| 1632 DCHECK(child_it != children_.end()); |
| 1633 Child* child_info = &child_it->second; |
| 1634 |
| 1635 if (unused.empty() && !child_info->marked_for_deletion) |
| 1636 return; |
| 1637 |
| 1638 ReturnedResourceArray to_return; |
| 1639 |
| 1640 GLES2Interface* gl = ContextGL(); |
| 1641 bool need_sync_point = false; |
| 1642 for (size_t i = 0; i < unused.size(); ++i) { |
| 1643 ResourceId local_id = unused[i]; |
| 1644 |
| 1645 ResourceMap::iterator it = resources_.find(local_id); |
| 1646 CHECK(it != resources_.end()); |
| 1647 Resource& resource = it->second; |
| 1648 |
| 1649 DCHECK(!resource.locked_for_write); |
| 1650 DCHECK_EQ(0u, child_info->in_use_resources.count(local_id)); |
| 1651 DCHECK(child_info->parent_to_child_map.count(local_id)); |
| 1652 |
| 1653 ResourceId child_id = child_info->parent_to_child_map[local_id]; |
| 1654 DCHECK(child_info->child_to_parent_map.count(child_id)); |
| 1655 |
| 1656 bool is_lost = |
| 1657 resource.lost || |
| 1658 (resource.type == RESOURCE_TYPE_GL_TEXTURE && lost_output_surface_); |
| 1659 if (resource.exported_count > 0 || resource.lock_for_read_count > 0) { |
| 1660 if (style != FOR_SHUTDOWN) { |
| 1661 // Defer this until we receive the resource back from the parent or |
| 1662 // the read lock is released. |
| 1663 resource.marked_for_deletion = true; |
| 1664 continue; |
| 1665 } |
| 1666 |
| 1667 // We still have an exported_count, so we'll have to lose it. |
| 1668 is_lost = true; |
| 1669 } |
| 1670 |
| 1671 if (gl && resource.filter != resource.original_filter) { |
| 1672 DCHECK(resource.target); |
| 1673 DCHECK(resource.gl_id); |
| 1674 |
| 1675 GLC(gl, gl->BindTexture(resource.target, resource.gl_id)); |
| 1676 GLC(gl, |
| 1677 gl->TexParameteri(resource.target, |
| 1678 GL_TEXTURE_MIN_FILTER, |
| 1679 resource.original_filter)); |
| 1680 GLC(gl, |
| 1681 gl->TexParameteri(resource.target, |
| 1682 GL_TEXTURE_MAG_FILTER, |
| 1683 resource.original_filter)); |
| 1684 } |
| 1685 |
| 1686 ReturnedResource returned; |
| 1687 returned.id = child_id; |
| 1688 returned.sync_point = resource.mailbox.sync_point(); |
| 1689 if (!returned.sync_point && resource.type == RESOURCE_TYPE_GL_TEXTURE) |
| 1690 need_sync_point = true; |
| 1691 returned.count = resource.imported_count; |
| 1692 returned.lost = is_lost; |
| 1693 to_return.push_back(returned); |
| 1694 |
| 1695 child_info->parent_to_child_map.erase(local_id); |
| 1696 child_info->child_to_parent_map.erase(child_id); |
| 1697 resource.imported_count = 0; |
| 1698 DeleteResourceInternal(it, style); |
| 1699 } |
| 1700 if (need_sync_point) { |
| 1701 DCHECK(gl); |
| 1702 GLuint sync_point = gl->InsertSyncPointCHROMIUM(); |
| 1703 for (size_t i = 0; i < to_return.size(); ++i) { |
| 1704 if (!to_return[i].sync_point) |
| 1705 to_return[i].sync_point = sync_point; |
| 1706 } |
| 1707 } |
| 1708 |
| 1709 if (!to_return.empty()) |
| 1710 child_info->return_callback.Run(to_return, |
| 1711 blocking_main_thread_task_runner_); |
| 1712 |
| 1713 if (child_info->marked_for_deletion && |
| 1714 child_info->parent_to_child_map.empty()) { |
| 1715 DCHECK(child_info->child_to_parent_map.empty()); |
| 1716 children_.erase(child_it); |
| 1717 } |
| 1718 } |
| 1719 |
| 1720 void ResourceProvider::AcquirePixelBuffer(ResourceId id) { |
| 1721 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), |
| 1722 "ResourceProvider::AcquirePixelBuffer"); |
| 1723 |
| 1724 Resource* resource = GetResource(id); |
| 1725 DCHECK(resource->origin == Resource::INTERNAL); |
| 1726 DCHECK_EQ(resource->exported_count, 0); |
| 1727 DCHECK(!resource->image_id); |
| 1728 DCHECK_NE(ETC1, resource->format); |
| 1729 |
| 1730 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type); |
| 1731 GLES2Interface* gl = ContextGL(); |
| 1732 DCHECK(gl); |
| 1733 if (!resource->gl_pixel_buffer_id) |
| 1734 resource->gl_pixel_buffer_id = buffer_id_allocator_->NextId(); |
| 1735 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, |
| 1736 resource->gl_pixel_buffer_id); |
| 1737 unsigned bytes_per_pixel = BitsPerPixel(resource->format) / 8; |
| 1738 gl->BufferData(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, |
| 1739 resource->size.height() * |
| 1740 RoundUp(bytes_per_pixel * resource->size.width(), 4u), |
| 1741 NULL, |
| 1742 GL_DYNAMIC_DRAW); |
| 1743 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0); |
| 1744 } |
| 1745 |
| 1746 void ResourceProvider::ReleasePixelBuffer(ResourceId id) { |
| 1747 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), |
| 1748 "ResourceProvider::ReleasePixelBuffer"); |
| 1749 |
| 1750 Resource* resource = GetResource(id); |
| 1751 DCHECK(resource->origin == Resource::INTERNAL); |
| 1752 DCHECK_EQ(resource->exported_count, 0); |
| 1753 DCHECK(!resource->image_id); |
| 1754 |
| 1755 // The pixel buffer can be released while there is a pending "set pixels" |
| 1756 // if completion has been forced. Any shared memory associated with this |
| 1757 // pixel buffer will not be freed until the waitAsyncTexImage2DCHROMIUM |
| 1758 // command has been processed on the service side. It is also safe to |
| 1759 // reuse any query id associated with this resource before they complete |
| 1760 // as each new query has a unique submit count. |
| 1761 if (resource->pending_set_pixels) { |
| 1762 DCHECK(resource->set_pixels_completion_forced); |
| 1763 resource->pending_set_pixels = false; |
| 1764 resource->locked_for_write = false; |
| 1765 } |
| 1766 |
| 1767 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type); |
| 1768 if (!resource->gl_pixel_buffer_id) |
| 1769 return; |
| 1770 GLES2Interface* gl = ContextGL(); |
| 1771 DCHECK(gl); |
| 1772 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, |
| 1773 resource->gl_pixel_buffer_id); |
| 1774 gl->BufferData( |
| 1775 GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0, NULL, GL_DYNAMIC_DRAW); |
| 1776 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0); |
| 1777 } |
| 1778 |
| 1779 uint8_t* ResourceProvider::MapPixelBuffer(ResourceId id, int* stride) { |
| 1780 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), |
| 1781 "ResourceProvider::MapPixelBuffer"); |
| 1782 |
| 1783 Resource* resource = GetResource(id); |
| 1784 DCHECK(resource->origin == Resource::INTERNAL); |
| 1785 DCHECK_EQ(resource->exported_count, 0); |
| 1786 DCHECK(!resource->image_id); |
| 1787 |
| 1788 *stride = 0; |
| 1789 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type); |
| 1790 GLES2Interface* gl = ContextGL(); |
| 1791 DCHECK(gl); |
| 1792 DCHECK(resource->gl_pixel_buffer_id); |
| 1793 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, |
| 1794 resource->gl_pixel_buffer_id); |
| 1795 uint8_t* image = static_cast<uint8_t*>(gl->MapBufferCHROMIUM( |
| 1796 GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, GL_WRITE_ONLY)); |
| 1797 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0); |
| 1798 // Buffer is required to be 4-byte aligned. |
| 1799 CHECK(!(reinterpret_cast<intptr_t>(image) & 3)); |
| 1800 return image; |
| 1801 } |
| 1802 |
| 1803 void ResourceProvider::UnmapPixelBuffer(ResourceId id) { |
| 1804 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), |
| 1805 "ResourceProvider::UnmapPixelBuffer"); |
| 1806 |
| 1807 Resource* resource = GetResource(id); |
| 1808 DCHECK(resource->origin == Resource::INTERNAL); |
| 1809 DCHECK_EQ(resource->exported_count, 0); |
| 1810 DCHECK(!resource->image_id); |
| 1811 |
| 1812 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type); |
| 1813 GLES2Interface* gl = ContextGL(); |
| 1814 DCHECK(gl); |
| 1815 DCHECK(resource->gl_pixel_buffer_id); |
| 1816 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, |
| 1817 resource->gl_pixel_buffer_id); |
| 1818 gl->UnmapBufferCHROMIUM(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM); |
| 1819 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0); |
| 1820 } |
| 1821 |
| 1822 GLenum ResourceProvider::BindForSampling(ResourceId resource_id, |
| 1823 GLenum unit, |
| 1824 GLenum filter) { |
| 1825 DCHECK(thread_checker_.CalledOnValidThread()); |
| 1826 GLES2Interface* gl = ContextGL(); |
| 1827 ResourceMap::iterator it = resources_.find(resource_id); |
| 1828 DCHECK(it != resources_.end()); |
| 1829 Resource* resource = &it->second; |
| 1830 DCHECK(resource->lock_for_read_count); |
| 1831 DCHECK(!resource->locked_for_write || resource->set_pixels_completion_forced); |
| 1832 |
| 1833 ScopedSetActiveTexture scoped_active_tex(gl, unit); |
| 1834 GLenum target = resource->target; |
| 1835 GLC(gl, gl->BindTexture(target, resource->gl_id)); |
| 1836 if (filter != resource->filter) { |
| 1837 GLC(gl, gl->TexParameteri(target, GL_TEXTURE_MIN_FILTER, filter)); |
| 1838 GLC(gl, gl->TexParameteri(target, GL_TEXTURE_MAG_FILTER, filter)); |
| 1839 resource->filter = filter; |
| 1840 } |
| 1841 |
| 1842 if (resource->image_id && resource->dirty_image) |
| 1843 BindImageForSampling(resource); |
| 1844 |
| 1845 return target; |
| 1846 } |
| 1847 |
| 1848 void ResourceProvider::BeginSetPixels(ResourceId id) { |
| 1849 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), |
| 1850 "ResourceProvider::BeginSetPixels"); |
| 1851 |
| 1852 Resource* resource = GetResource(id); |
| 1853 DCHECK(!resource->pending_set_pixels); |
| 1854 |
| 1855 LazyCreate(resource); |
| 1856 DCHECK(resource->origin == Resource::INTERNAL); |
| 1857 DCHECK(resource->gl_id || resource->allocated); |
| 1858 DCHECK(ReadLockFenceHasPassed(resource)); |
| 1859 DCHECK(!resource->image_id); |
| 1860 |
| 1861 bool allocate = !resource->allocated; |
| 1862 resource->allocated = true; |
| 1863 LockForWrite(id); |
| 1864 |
| 1865 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type); |
| 1866 DCHECK(resource->gl_id); |
| 1867 GLES2Interface* gl = ContextGL(); |
| 1868 DCHECK(gl); |
| 1869 DCHECK(resource->gl_pixel_buffer_id); |
| 1870 DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D)); |
| 1871 gl->BindTexture(GL_TEXTURE_2D, resource->gl_id); |
| 1872 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, |
| 1873 resource->gl_pixel_buffer_id); |
| 1874 if (!resource->gl_upload_query_id) |
| 1875 gl->GenQueriesEXT(1, &resource->gl_upload_query_id); |
| 1876 gl->BeginQueryEXT(GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM, |
| 1877 resource->gl_upload_query_id); |
| 1878 if (allocate) { |
| 1879 gl->AsyncTexImage2DCHROMIUM(GL_TEXTURE_2D, |
| 1880 0, /* level */ |
| 1881 GLInternalFormat(resource->format), |
| 1882 resource->size.width(), |
| 1883 resource->size.height(), |
| 1884 0, /* border */ |
| 1885 GLDataFormat(resource->format), |
| 1886 GLDataType(resource->format), |
| 1887 NULL); |
| 1888 } else { |
| 1889 gl->AsyncTexSubImage2DCHROMIUM(GL_TEXTURE_2D, |
| 1890 0, /* level */ |
| 1891 0, /* x */ |
| 1892 0, /* y */ |
| 1893 resource->size.width(), |
| 1894 resource->size.height(), |
| 1895 GLDataFormat(resource->format), |
| 1896 GLDataType(resource->format), |
| 1897 NULL); |
| 1898 } |
| 1899 gl->EndQueryEXT(GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM); |
| 1900 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0); |
| 1901 |
| 1902 resource->pending_set_pixels = true; |
| 1903 resource->set_pixels_completion_forced = false; |
| 1904 } |
| 1905 |
| 1906 void ResourceProvider::ForceSetPixelsToComplete(ResourceId id) { |
| 1907 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), |
| 1908 "ResourceProvider::ForceSetPixelsToComplete"); |
| 1909 |
| 1910 Resource* resource = GetResource(id); |
| 1911 |
| 1912 DCHECK(resource->locked_for_write); |
| 1913 DCHECK(resource->pending_set_pixels); |
| 1914 DCHECK(!resource->set_pixels_completion_forced); |
| 1915 |
| 1916 if (resource->gl_id) { |
| 1917 GLES2Interface* gl = ContextGL(); |
| 1918 GLC(gl, gl->BindTexture(GL_TEXTURE_2D, resource->gl_id)); |
| 1919 GLC(gl, gl->WaitAsyncTexImage2DCHROMIUM(GL_TEXTURE_2D)); |
| 1920 GLC(gl, gl->BindTexture(GL_TEXTURE_2D, 0)); |
| 1921 } |
| 1922 |
| 1923 resource->set_pixels_completion_forced = true; |
| 1924 } |
| 1925 |
| 1926 bool ResourceProvider::DidSetPixelsComplete(ResourceId id) { |
| 1927 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), |
| 1928 "ResourceProvider::DidSetPixelsComplete"); |
| 1929 |
| 1930 Resource* resource = GetResource(id); |
| 1931 |
| 1932 DCHECK(resource->locked_for_write); |
| 1933 DCHECK(resource->pending_set_pixels); |
| 1934 |
| 1935 if (resource->gl_id) { |
| 1936 GLES2Interface* gl = ContextGL(); |
| 1937 DCHECK(gl); |
| 1938 DCHECK(resource->gl_upload_query_id); |
| 1939 GLuint complete = 1; |
| 1940 gl->GetQueryObjectuivEXT( |
| 1941 resource->gl_upload_query_id, GL_QUERY_RESULT_AVAILABLE_EXT, &complete); |
| 1942 if (!complete) |
| 1943 return false; |
| 1944 } |
| 1945 |
| 1946 resource->pending_set_pixels = false; |
| 1947 UnlockForWrite(resource); |
| 1948 |
| 1949 // Async set pixels commands are not necessarily processed in-sequence with |
| 1950 // drawing commands. Read lock fences are required to ensure that async |
| 1951 // commands don't access the resource while used for drawing. |
| 1952 resource->read_lock_fences_enabled = true; |
| 1953 |
| 1954 return true; |
| 1955 } |
| 1956 |
| 1957 void ResourceProvider::CreateForTesting(ResourceId id) { |
| 1958 LazyCreate(GetResource(id)); |
| 1959 } |
| 1960 |
| 1961 GLenum ResourceProvider::TargetForTesting(ResourceId id) { |
| 1962 Resource* resource = GetResource(id); |
| 1963 return resource->target; |
| 1964 } |
| 1965 |
| 1966 void ResourceProvider::LazyCreate(Resource* resource) { |
| 1967 if (resource->type != RESOURCE_TYPE_GL_TEXTURE || |
| 1968 resource->origin != Resource::INTERNAL) |
| 1969 return; |
| 1970 |
| 1971 if (resource->gl_id) |
| 1972 return; |
| 1973 |
| 1974 DCHECK(resource->texture_pool); |
| 1975 DCHECK(resource->origin == Resource::INTERNAL); |
| 1976 DCHECK(!resource->mailbox.IsValid()); |
| 1977 resource->gl_id = texture_id_allocator_->NextId(); |
| 1978 |
| 1979 GLES2Interface* gl = ContextGL(); |
| 1980 DCHECK(gl); |
| 1981 |
| 1982 // Create and set texture properties. Allocation is delayed until needed. |
| 1983 GLC(gl, gl->BindTexture(resource->target, resource->gl_id)); |
| 1984 GLC(gl, |
| 1985 gl->TexParameteri( |
| 1986 resource->target, GL_TEXTURE_MIN_FILTER, resource->original_filter)); |
| 1987 GLC(gl, |
| 1988 gl->TexParameteri( |
| 1989 resource->target, GL_TEXTURE_MAG_FILTER, resource->original_filter)); |
| 1990 GLC(gl, |
| 1991 gl->TexParameteri( |
| 1992 resource->target, GL_TEXTURE_WRAP_S, resource->wrap_mode)); |
| 1993 GLC(gl, |
| 1994 gl->TexParameteri( |
| 1995 resource->target, GL_TEXTURE_WRAP_T, resource->wrap_mode)); |
| 1996 GLC(gl, |
| 1997 gl->TexParameteri( |
| 1998 resource->target, GL_TEXTURE_POOL_CHROMIUM, resource->texture_pool)); |
| 1999 if (use_texture_usage_hint_ && (resource->hint & TEXTURE_HINT_FRAMEBUFFER)) { |
| 2000 GLC(gl, |
| 2001 gl->TexParameteri(resource->target, |
| 2002 GL_TEXTURE_USAGE_ANGLE, |
| 2003 GL_FRAMEBUFFER_ATTACHMENT_ANGLE)); |
| 2004 } |
| 2005 } |
| 2006 |
| 2007 void ResourceProvider::AllocateForTesting(ResourceId id) { |
| 2008 LazyAllocate(GetResource(id)); |
| 2009 } |
| 2010 |
| 2011 void ResourceProvider::LazyAllocate(Resource* resource) { |
| 2012 DCHECK(resource); |
| 2013 if (resource->allocated) |
| 2014 return; |
| 2015 LazyCreate(resource); |
| 2016 if (!resource->gl_id) |
| 2017 return; |
| 2018 resource->allocated = true; |
| 2019 GLES2Interface* gl = ContextGL(); |
| 2020 gfx::Size& size = resource->size; |
| 2021 DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D)); |
| 2022 ResourceFormat format = resource->format; |
| 2023 GLC(gl, gl->BindTexture(GL_TEXTURE_2D, resource->gl_id)); |
| 2024 if (use_texture_storage_ext_ && |
| 2025 IsFormatSupportedForStorage(format, use_texture_format_bgra_) && |
| 2026 (resource->hint & TEXTURE_HINT_IMMUTABLE)) { |
| 2027 GLenum storage_format = TextureToStorageFormat(format); |
| 2028 GLC(gl, |
| 2029 gl->TexStorage2DEXT( |
| 2030 GL_TEXTURE_2D, 1, storage_format, size.width(), size.height())); |
| 2031 } else { |
| 2032 // ETC1 does not support preallocation. |
| 2033 if (format != ETC1) { |
| 2034 GLC(gl, |
| 2035 gl->TexImage2D(GL_TEXTURE_2D, |
| 2036 0, |
| 2037 GLInternalFormat(format), |
| 2038 size.width(), |
| 2039 size.height(), |
| 2040 0, |
| 2041 GLDataFormat(format), |
| 2042 GLDataType(format), |
| 2043 NULL)); |
| 2044 } |
| 2045 } |
| 2046 } |
| 2047 |
| 2048 void ResourceProvider::BindImageForSampling(Resource* resource) { |
| 2049 GLES2Interface* gl = ContextGL(); |
| 2050 DCHECK(resource->gl_id); |
| 2051 DCHECK(resource->image_id); |
| 2052 |
| 2053 // Release image currently bound to texture. |
| 2054 if (resource->bound_image_id) |
| 2055 gl->ReleaseTexImage2DCHROMIUM(resource->target, resource->bound_image_id); |
| 2056 gl->BindTexImage2DCHROMIUM(resource->target, resource->image_id); |
| 2057 resource->bound_image_id = resource->image_id; |
| 2058 resource->dirty_image = false; |
| 2059 } |
| 2060 |
| 2061 void ResourceProvider::CopyResource(ResourceId source_id, ResourceId dest_id) { |
| 2062 TRACE_EVENT0("cc", "ResourceProvider::CopyResource"); |
| 2063 |
| 2064 Resource* source_resource = GetResource(source_id); |
| 2065 DCHECK(!source_resource->lock_for_read_count); |
| 2066 DCHECK(source_resource->origin == Resource::INTERNAL); |
| 2067 DCHECK_EQ(source_resource->exported_count, 0); |
| 2068 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, source_resource->type); |
| 2069 DCHECK(source_resource->allocated); |
| 2070 LazyCreate(source_resource); |
| 2071 |
| 2072 Resource* dest_resource = GetResource(dest_id); |
| 2073 DCHECK(!dest_resource->locked_for_write); |
| 2074 DCHECK(!dest_resource->lock_for_read_count); |
| 2075 DCHECK(dest_resource->origin == Resource::INTERNAL); |
| 2076 DCHECK_EQ(dest_resource->exported_count, 0); |
| 2077 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, dest_resource->type); |
| 2078 LazyAllocate(dest_resource); |
| 2079 |
| 2080 DCHECK_EQ(source_resource->type, dest_resource->type); |
| 2081 DCHECK_EQ(source_resource->format, dest_resource->format); |
| 2082 DCHECK(source_resource->size == dest_resource->size); |
| 2083 |
| 2084 GLES2Interface* gl = ContextGL(); |
| 2085 DCHECK(gl); |
| 2086 if (source_resource->image_id && source_resource->dirty_image) { |
| 2087 gl->BindTexture(source_resource->target, source_resource->gl_id); |
| 2088 BindImageForSampling(source_resource); |
| 2089 } |
| 2090 if (use_sync_query_) { |
| 2091 if (!source_resource->gl_read_lock_query_id) |
| 2092 gl->GenQueriesEXT(1, &source_resource->gl_read_lock_query_id); |
| 2093 #if defined(OS_CHROMEOS) |
| 2094 // TODO(reveman): This avoids a performance problem on some ChromeOS |
| 2095 // devices. This needs to be removed to support native GpuMemoryBuffer |
| 2096 // implementations. crbug.com/436314 |
| 2097 gl->BeginQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM, |
| 2098 source_resource->gl_read_lock_query_id); |
| 2099 #else |
| 2100 gl->BeginQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM, |
| 2101 source_resource->gl_read_lock_query_id); |
| 2102 #endif |
| 2103 } |
| 2104 DCHECK(!dest_resource->image_id); |
| 2105 dest_resource->allocated = true; |
| 2106 gl->CopySubTextureCHROMIUM(dest_resource->target, source_resource->gl_id, |
| 2107 dest_resource->gl_id, 0, 0); |
| 2108 if (source_resource->gl_read_lock_query_id) { |
| 2109 // End query and create a read lock fence that will prevent access to |
| 2110 // source resource until CopySubTextureCHROMIUM command has completed. |
| 2111 #if defined(OS_CHROMEOS) |
| 2112 gl->EndQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM); |
| 2113 #else |
| 2114 gl->EndQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM); |
| 2115 #endif |
| 2116 source_resource->read_lock_fence = make_scoped_refptr( |
| 2117 new CopyTextureFence(gl, source_resource->gl_read_lock_query_id)); |
| 2118 } else { |
| 2119 // Create a SynchronousFence when CHROMIUM_sync_query extension is missing. |
| 2120 // Try to use one synchronous fence for as many CopyResource operations as |
| 2121 // possible as that reduce the number of times we have to synchronize with |
| 2122 // the GL. |
| 2123 if (!synchronous_fence_.get() || synchronous_fence_->has_synchronized()) |
| 2124 synchronous_fence_ = make_scoped_refptr(new SynchronousFence(gl)); |
| 2125 source_resource->read_lock_fence = synchronous_fence_; |
| 2126 source_resource->read_lock_fence->Set(); |
| 2127 } |
| 2128 } |
| 2129 |
| 2130 void ResourceProvider::WaitSyncPointIfNeeded(ResourceId id) { |
| 2131 Resource* resource = GetResource(id); |
| 2132 DCHECK_EQ(resource->exported_count, 0); |
| 2133 DCHECK(resource->allocated); |
| 2134 if (resource->type != RESOURCE_TYPE_GL_TEXTURE || resource->gl_id) |
| 2135 return; |
| 2136 if (!resource->mailbox.sync_point()) |
| 2137 return; |
| 2138 DCHECK(resource->mailbox.IsValid()); |
| 2139 GLES2Interface* gl = ContextGL(); |
| 2140 DCHECK(gl); |
| 2141 GLC(gl, gl->WaitSyncPointCHROMIUM(resource->mailbox.sync_point())); |
| 2142 resource->mailbox.set_sync_point(0); |
| 2143 } |
| 2144 |
| 2145 void ResourceProvider::WaitReadLockIfNeeded(ResourceId id) { |
| 2146 Resource* resource = GetResource(id); |
| 2147 DCHECK_EQ(resource->exported_count, 0); |
| 2148 if (!resource->read_lock_fence.get()) |
| 2149 return; |
| 2150 |
| 2151 resource->read_lock_fence->Wait(); |
| 2152 } |
| 2153 |
| 2154 GLint ResourceProvider::GetActiveTextureUnit(GLES2Interface* gl) { |
| 2155 GLint active_unit = 0; |
| 2156 gl->GetIntegerv(GL_ACTIVE_TEXTURE, &active_unit); |
| 2157 return active_unit; |
| 2158 } |
| 2159 |
| 2160 GLES2Interface* ResourceProvider::ContextGL() const { |
| 2161 ContextProvider* context_provider = output_surface_->context_provider(); |
| 2162 return context_provider ? context_provider->ContextGL() : NULL; |
| 2163 } |
| 2164 |
| 2165 class GrContext* ResourceProvider::GrContext(bool worker_context) const { |
| 2166 ContextProvider* context_provider = |
| 2167 worker_context ? output_surface_->worker_context_provider() |
| 2168 : output_surface_->context_provider(); |
| 2169 return context_provider ? context_provider->GrContext() : NULL; |
| 2170 } |
| 2171 |
| 2172 } // namespace cc |
OLD | NEW |