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.
5 #include "cc/resources/resource_provider.h"
10 #include "base/atomic_sequence_num.h"
11 #include "base/containers/hash_tables.h"
12 #include "base/metrics/histogram.h"
13 #include "base/numerics/safe_math.h"
14 #include "base/stl_util.h"
15 #include "base/strings/string_split.h"
16 #include "base/strings/string_util.h"
17 #include "base/strings/stringprintf.h"
18 #include "base/thread_task_runner_handle.h"
19 #include "base/trace_event/memory_dump_manager.h"
20 #include "base/trace_event/trace_event.h"
21 #include "cc/resources/platform_color.h"
22 #include "cc/resources/resource_util.h"
23 #include "cc/resources/returned_resource.h"
24 #include "cc/resources/shared_bitmap_manager.h"
25 #include "cc/resources/transferable_resource.h"
26 #include "gpu/GLES2/gl2extchromium.h"
27 #include "gpu/command_buffer/client/context_support.h"
28 #include "gpu/command_buffer/client/gles2_interface.h"
29 #include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
30 #include "third_party/khronos/GLES2/gl2.h"
31 #include "third_party/khronos/GLES2/gl2ext.h"
32 #include "third_party/skia/include/core/SkSurface.h"
33 #include "third_party/skia/include/gpu/GrContext.h"
34 #include "third_party/skia/include/gpu/GrTextureProvider.h"
35 #include "ui/gfx/geometry/rect.h"
36 #include "ui/gfx/geometry/vector2d.h"
37 #include "ui/gl/trace_util.h"
39 using gpu::gles2::GLES2Interface
;
45 virtual ~IdAllocator() {}
47 virtual GLuint
NextId() = 0;
50 IdAllocator(GLES2Interface
* gl
, size_t id_allocation_chunk_size
)
52 id_allocation_chunk_size_(id_allocation_chunk_size
),
53 ids_(new GLuint
[id_allocation_chunk_size
]),
54 next_id_index_(id_allocation_chunk_size
) {
55 DCHECK(id_allocation_chunk_size_
);
56 DCHECK_LE(id_allocation_chunk_size_
,
57 static_cast<size_t>(std::numeric_limits
<int>::max()));
61 const size_t id_allocation_chunk_size_
;
62 scoped_ptr
<GLuint
[]> ids_
;
63 size_t next_id_index_
;
68 GLenum
TextureToStorageFormat(ResourceFormat format
) {
69 GLenum storage_format
= GL_RGBA8_OES
;
74 storage_format
= GL_BGRA8_EXT
;
86 return storage_format
;
89 bool IsFormatSupportedForStorage(ResourceFormat format
, bool use_bgra
) {
106 GrPixelConfig
ToGrPixelConfig(ResourceFormat format
) {
109 return kRGBA_8888_GrPixelConfig
;
111 return kBGRA_8888_GrPixelConfig
;
113 return kRGBA_4444_GrPixelConfig
;
117 DCHECK(false) << "Unsupported resource format.";
118 return kSkia8888_GrPixelConfig
;
121 class ScopedSetActiveTexture
{
123 ScopedSetActiveTexture(GLES2Interface
* gl
, GLenum unit
)
124 : gl_(gl
), unit_(unit
) {
125 DCHECK_EQ(GL_TEXTURE0
, ResourceProvider::GetActiveTextureUnit(gl_
));
127 if (unit_
!= GL_TEXTURE0
)
128 gl_
->ActiveTexture(unit_
);
131 ~ScopedSetActiveTexture() {
132 // Active unit being GL_TEXTURE0 is effectively the ground state.
133 if (unit_
!= GL_TEXTURE0
)
134 gl_
->ActiveTexture(GL_TEXTURE0
);
142 class TextureIdAllocator
: public IdAllocator
{
144 TextureIdAllocator(GLES2Interface
* gl
,
145 size_t texture_id_allocation_chunk_size
)
146 : IdAllocator(gl
, texture_id_allocation_chunk_size
) {}
147 ~TextureIdAllocator() override
{
149 static_cast<int>(id_allocation_chunk_size_
- next_id_index_
),
150 ids_
.get() + next_id_index_
);
153 // Overridden from IdAllocator:
154 GLuint
NextId() override
{
155 if (next_id_index_
== id_allocation_chunk_size_
) {
156 gl_
->GenTextures(static_cast<int>(id_allocation_chunk_size_
), ids_
.get());
160 return ids_
[next_id_index_
++];
164 DISALLOW_COPY_AND_ASSIGN(TextureIdAllocator
);
167 class BufferIdAllocator
: public IdAllocator
{
169 BufferIdAllocator(GLES2Interface
* gl
, size_t buffer_id_allocation_chunk_size
)
170 : IdAllocator(gl
, buffer_id_allocation_chunk_size
) {}
171 ~BufferIdAllocator() override
{
173 static_cast<int>(id_allocation_chunk_size_
- next_id_index_
),
174 ids_
.get() + next_id_index_
);
177 // Overridden from IdAllocator:
178 GLuint
NextId() override
{
179 if (next_id_index_
== id_allocation_chunk_size_
) {
180 gl_
->GenBuffers(static_cast<int>(id_allocation_chunk_size_
), ids_
.get());
184 return ids_
[next_id_index_
++];
188 DISALLOW_COPY_AND_ASSIGN(BufferIdAllocator
);
191 // Generates process-unique IDs to use for tracing a ResourceProvider's
193 base::StaticAtomicSequenceNumber g_next_resource_provider_tracing_id
;
197 ResourceProvider::Resource::~Resource() {}
199 ResourceProvider::Resource::Resource(GLuint texture_id
,
200 const gfx::Size
& size
,
207 ResourceFormat format
)
210 gl_pixel_buffer_id(0),
211 gl_upload_query_id(0),
212 gl_read_lock_query_id(0),
214 lock_for_read_count(0),
218 locked_for_write(false),
220 marked_for_deletion(false),
222 read_lock_fences_enabled(false),
223 has_shared_bitmap_id(false),
224 read_lock_fence(NULL
),
228 original_filter(filter
),
232 texture_pool(texture_pool
),
233 wrap_mode(wrap_mode
),
235 type(RESOURCE_TYPE_GL_TEXTURE
),
238 gpu_memory_buffer(NULL
) {
239 DCHECK(wrap_mode
== GL_CLAMP_TO_EDGE
|| wrap_mode
== GL_REPEAT
);
240 DCHECK_EQ(origin
== INTERNAL
, !!texture_pool
);
243 ResourceProvider::Resource::Resource(uint8_t* pixels
,
244 SharedBitmap
* bitmap
,
245 const gfx::Size
& size
,
251 gl_pixel_buffer_id(0),
252 gl_upload_query_id(0),
253 gl_read_lock_query_id(0),
255 lock_for_read_count(0),
259 locked_for_write(false),
261 marked_for_deletion(false),
263 read_lock_fences_enabled(false),
264 has_shared_bitmap_id(!!bitmap
),
265 read_lock_fence(NULL
),
269 original_filter(filter
),
274 wrap_mode(wrap_mode
),
275 hint(TEXTURE_HINT_IMMUTABLE
),
276 type(RESOURCE_TYPE_BITMAP
),
278 shared_bitmap(bitmap
),
279 gpu_memory_buffer(NULL
) {
280 DCHECK(wrap_mode
== GL_CLAMP_TO_EDGE
|| wrap_mode
== GL_REPEAT
);
281 DCHECK(origin
== DELEGATED
|| pixels
);
283 shared_bitmap_id
= bitmap
->id();
286 ResourceProvider::Resource::Resource(const SharedBitmapId
& bitmap_id
,
287 const gfx::Size
& size
,
293 gl_pixel_buffer_id(0),
294 gl_upload_query_id(0),
295 gl_read_lock_query_id(0),
297 lock_for_read_count(0),
301 locked_for_write(false),
303 marked_for_deletion(false),
305 read_lock_fences_enabled(false),
306 has_shared_bitmap_id(true),
307 read_lock_fence(NULL
),
311 original_filter(filter
),
316 wrap_mode(wrap_mode
),
317 hint(TEXTURE_HINT_IMMUTABLE
),
318 type(RESOURCE_TYPE_BITMAP
),
320 shared_bitmap_id(bitmap_id
),
322 gpu_memory_buffer(NULL
) {
323 DCHECK(wrap_mode
== GL_CLAMP_TO_EDGE
|| wrap_mode
== GL_REPEAT
);
326 ResourceProvider::Child::Child()
327 : marked_for_deletion(false), needs_sync_points(true) {
330 ResourceProvider::Child::~Child() {}
332 scoped_ptr
<ResourceProvider
> ResourceProvider::Create(
333 OutputSurface
* output_surface
,
334 SharedBitmapManager
* shared_bitmap_manager
,
335 gpu::GpuMemoryBufferManager
* gpu_memory_buffer_manager
,
336 BlockingTaskRunner
* blocking_main_thread_task_runner
,
337 int highp_threshold_min
,
338 bool use_rgba_4444_texture_format
,
339 size_t id_allocation_chunk_size
,
340 const std::vector
<unsigned>& use_image_texture_targets
) {
341 scoped_ptr
<ResourceProvider
> resource_provider(new ResourceProvider(
342 output_surface
, shared_bitmap_manager
, gpu_memory_buffer_manager
,
343 blocking_main_thread_task_runner
, highp_threshold_min
,
344 use_rgba_4444_texture_format
, id_allocation_chunk_size
,
345 use_image_texture_targets
));
346 resource_provider
->Initialize();
347 return resource_provider
;
350 ResourceProvider::~ResourceProvider() {
351 base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
354 while (!children_
.empty())
355 DestroyChildInternal(children_
.begin(), FOR_SHUTDOWN
);
356 while (!resources_
.empty())
357 DeleteResourceInternal(resources_
.begin(), FOR_SHUTDOWN
);
359 GLES2Interface
* gl
= ContextGL();
360 if (default_resource_type_
!= RESOURCE_TYPE_GL_TEXTURE
) {
361 // We are not in GL mode, but double check before returning.
368 // Check that all GL resources has been deleted.
369 for (ResourceMap::const_iterator itr
= resources_
.begin();
370 itr
!= resources_
.end(); ++itr
) {
371 DCHECK_NE(RESOURCE_TYPE_GL_TEXTURE
, itr
->second
.type
);
373 #endif // DCHECK_IS_ON()
375 texture_id_allocator_
= nullptr;
376 buffer_id_allocator_
= nullptr;
380 bool ResourceProvider::InUseByConsumer(ResourceId id
) {
381 Resource
* resource
= GetResource(id
);
382 return resource
->lock_for_read_count
> 0 || resource
->exported_count
> 0 ||
386 bool ResourceProvider::IsLost(ResourceId id
) {
387 Resource
* resource
= GetResource(id
);
388 return resource
->lost
;
391 void ResourceProvider::LoseResourceForTesting(ResourceId id
) {
392 Resource
* resource
= GetResource(id
);
394 resource
->lost
= true;
397 ResourceId
ResourceProvider::CreateResource(const gfx::Size
& size
,
400 ResourceFormat format
) {
401 DCHECK(!size
.IsEmpty());
402 switch (default_resource_type_
) {
403 case RESOURCE_TYPE_GL_TEXTURE
:
404 return CreateGLTexture(size
,
406 GL_TEXTURE_POOL_UNMANAGED_CHROMIUM
,
410 case RESOURCE_TYPE_BITMAP
:
411 DCHECK_EQ(RGBA_8888
, format
);
412 return CreateBitmap(size
, wrap_mode
);
415 LOG(FATAL
) << "Invalid default resource type.";
419 ResourceId
ResourceProvider::CreateManagedResource(const gfx::Size
& size
,
423 ResourceFormat format
) {
424 DCHECK(!size
.IsEmpty());
425 switch (default_resource_type_
) {
426 case RESOURCE_TYPE_GL_TEXTURE
:
427 return CreateGLTexture(size
,
429 GL_TEXTURE_POOL_MANAGED_CHROMIUM
,
433 case RESOURCE_TYPE_BITMAP
:
434 DCHECK_EQ(RGBA_8888
, format
);
435 return CreateBitmap(size
, wrap_mode
);
438 LOG(FATAL
) << "Invalid default resource type.";
442 ResourceId
ResourceProvider::CreateGLTexture(const gfx::Size
& size
,
447 ResourceFormat format
) {
448 DCHECK_LE(size
.width(), max_texture_size_
);
449 DCHECK_LE(size
.height(), max_texture_size_
);
450 DCHECK(thread_checker_
.CalledOnValidThread());
452 ResourceId id
= next_id_
++;
453 Resource
* resource
= InsertResource(
454 id
, Resource(0, size
, Resource::INTERNAL
, target
, GL_LINEAR
, texture_pool
,
455 wrap_mode
, hint
, format
));
456 resource
->allocated
= false;
460 ResourceId
ResourceProvider::CreateBitmap(const gfx::Size
& size
,
462 DCHECK(thread_checker_
.CalledOnValidThread());
464 scoped_ptr
<SharedBitmap
> bitmap
=
465 shared_bitmap_manager_
->AllocateSharedBitmap(size
);
466 uint8_t* pixels
= bitmap
->pixels();
469 ResourceId id
= next_id_
++;
471 InsertResource(id
, Resource(pixels
, bitmap
.release(), size
,
472 Resource::INTERNAL
, GL_LINEAR
, wrap_mode
));
473 resource
->allocated
= true;
477 ResourceId
ResourceProvider::CreateResourceFromIOSurface(
478 const gfx::Size
& size
,
479 unsigned io_surface_id
) {
480 DCHECK(thread_checker_
.CalledOnValidThread());
482 ResourceId id
= next_id_
++;
483 Resource
* resource
= InsertResource(
484 id
, Resource(0, gfx::Size(), Resource::INTERNAL
, GL_TEXTURE_RECTANGLE_ARB
,
485 GL_LINEAR
, GL_TEXTURE_POOL_UNMANAGED_CHROMIUM
,
486 GL_CLAMP_TO_EDGE
, TEXTURE_HINT_IMMUTABLE
, RGBA_8888
));
487 LazyCreate(resource
);
488 GLES2Interface
* gl
= ContextGL();
490 gl
->BindTexture(GL_TEXTURE_RECTANGLE_ARB
, resource
->gl_id
);
491 gl
->TexImageIOSurface2DCHROMIUM(
492 GL_TEXTURE_RECTANGLE_ARB
, size
.width(), size
.height(), io_surface_id
, 0);
493 resource
->allocated
= true;
497 ResourceId
ResourceProvider::CreateResourceFromTextureMailbox(
498 const TextureMailbox
& mailbox
,
499 scoped_ptr
<SingleReleaseCallbackImpl
> release_callback_impl
,
500 bool read_lock_fences_enabled
) {
501 DCHECK(thread_checker_
.CalledOnValidThread());
502 // Just store the information. Mailbox will be consumed in LockForRead().
503 ResourceId id
= next_id_
++;
504 DCHECK(mailbox
.IsValid());
505 Resource
* resource
= nullptr;
506 if (mailbox
.IsTexture()) {
507 resource
= InsertResource(
508 id
, Resource(0, gfx::Size(), Resource::EXTERNAL
, mailbox
.target(),
509 mailbox
.nearest_neighbor() ? GL_NEAREST
: GL_LINEAR
, 0,
510 GL_CLAMP_TO_EDGE
, TEXTURE_HINT_IMMUTABLE
, RGBA_8888
));
512 DCHECK(mailbox
.IsSharedMemory());
513 SharedBitmap
* shared_bitmap
= mailbox
.shared_bitmap();
514 uint8_t* pixels
= shared_bitmap
->pixels();
516 resource
= InsertResource(
517 id
, Resource(pixels
, shared_bitmap
, mailbox
.size_in_pixels(),
518 Resource::EXTERNAL
, GL_LINEAR
, GL_CLAMP_TO_EDGE
));
520 resource
->allocated
= true;
521 resource
->mailbox
= mailbox
;
522 resource
->release_callback_impl
=
523 base::Bind(&SingleReleaseCallbackImpl::Run
,
524 base::Owned(release_callback_impl
.release()));
525 resource
->read_lock_fences_enabled
= read_lock_fences_enabled
;
529 ResourceId
ResourceProvider::CreateResourceFromTextureMailbox(
530 const TextureMailbox
& mailbox
,
531 scoped_ptr
<SingleReleaseCallbackImpl
> release_callback_impl
) {
532 return CreateResourceFromTextureMailbox(mailbox
, release_callback_impl
.Pass(),
536 void ResourceProvider::DeleteResource(ResourceId id
) {
537 DCHECK(thread_checker_
.CalledOnValidThread());
538 ResourceMap::iterator it
= resources_
.find(id
);
539 CHECK(it
!= resources_
.end());
540 Resource
* resource
= &it
->second
;
541 DCHECK(!resource
->marked_for_deletion
);
542 DCHECK_EQ(resource
->imported_count
, 0);
543 DCHECK(!resource
->locked_for_write
);
545 if (resource
->exported_count
> 0 || resource
->lock_for_read_count
> 0 ||
546 !ReadLockFenceHasPassed(resource
)) {
547 resource
->marked_for_deletion
= true;
550 DeleteResourceInternal(it
, NORMAL
);
554 void ResourceProvider::DeleteResourceInternal(ResourceMap::iterator it
,
556 TRACE_EVENT0("cc", "ResourceProvider::DeleteResourceInternal");
557 Resource
* resource
= &it
->second
;
558 bool lost_resource
= resource
->lost
;
560 DCHECK(resource
->exported_count
== 0 || style
!= NORMAL
);
561 if (style
== FOR_SHUTDOWN
&& resource
->exported_count
> 0)
562 lost_resource
= true;
564 if (resource
->image_id
) {
565 DCHECK(resource
->origin
== Resource::INTERNAL
);
566 GLES2Interface
* gl
= ContextGL();
568 gl
->DestroyImageCHROMIUM(resource
->image_id
);
570 if (resource
->gl_upload_query_id
) {
571 DCHECK(resource
->origin
== Resource::INTERNAL
);
572 GLES2Interface
* gl
= ContextGL();
574 gl
->DeleteQueriesEXT(1, &resource
->gl_upload_query_id
);
576 if (resource
->gl_read_lock_query_id
) {
577 DCHECK(resource
->origin
== Resource::INTERNAL
);
578 GLES2Interface
* gl
= ContextGL();
580 gl
->DeleteQueriesEXT(1, &resource
->gl_read_lock_query_id
);
582 if (resource
->gl_pixel_buffer_id
) {
583 DCHECK(resource
->origin
== Resource::INTERNAL
);
584 GLES2Interface
* gl
= ContextGL();
586 gl
->DeleteBuffers(1, &resource
->gl_pixel_buffer_id
);
588 if (resource
->origin
== Resource::EXTERNAL
) {
589 DCHECK(resource
->mailbox
.IsValid());
590 GLuint sync_point
= resource
->mailbox
.sync_point();
591 if (resource
->type
== RESOURCE_TYPE_GL_TEXTURE
) {
592 DCHECK(resource
->mailbox
.IsTexture());
593 lost_resource
|= lost_output_surface_
;
594 GLES2Interface
* gl
= ContextGL();
596 if (resource
->gl_id
) {
597 gl
->DeleteTextures(1, &resource
->gl_id
);
600 sync_point
= gl
->InsertSyncPointCHROMIUM();
603 DCHECK(resource
->mailbox
.IsSharedMemory());
604 resource
->shared_bitmap
= nullptr;
605 resource
->pixels
= nullptr;
607 resource
->release_callback_impl
.Run(
608 sync_point
, lost_resource
, blocking_main_thread_task_runner_
);
610 if (resource
->gl_id
) {
611 GLES2Interface
* gl
= ContextGL();
613 gl
->DeleteTextures(1, &resource
->gl_id
);
616 if (resource
->shared_bitmap
) {
617 DCHECK(resource
->origin
!= Resource::EXTERNAL
);
618 DCHECK_EQ(RESOURCE_TYPE_BITMAP
, resource
->type
);
619 delete resource
->shared_bitmap
;
620 resource
->pixels
= NULL
;
622 if (resource
->pixels
) {
623 DCHECK(resource
->origin
== Resource::INTERNAL
);
624 delete[] resource
->pixels
;
625 resource
->pixels
= NULL
;
627 if (resource
->gpu_memory_buffer
) {
628 DCHECK(resource
->origin
== Resource::INTERNAL
);
629 delete resource
->gpu_memory_buffer
;
630 resource
->gpu_memory_buffer
= NULL
;
632 resources_
.erase(it
);
635 ResourceProvider::ResourceType
ResourceProvider::GetResourceType(
637 return GetResource(id
)->type
;
640 void ResourceProvider::CopyToResource(ResourceId id
,
641 const uint8_t* image
,
642 const gfx::Size
& image_size
) {
643 Resource
* resource
= GetResource(id
);
644 DCHECK(!resource
->locked_for_write
);
645 DCHECK(!resource
->lock_for_read_count
);
646 DCHECK(resource
->origin
== Resource::INTERNAL
);
647 DCHECK_EQ(resource
->exported_count
, 0);
648 DCHECK(ReadLockFenceHasPassed(resource
));
649 LazyAllocate(resource
);
651 DCHECK_EQ(image_size
.width(), resource
->size
.width());
652 DCHECK_EQ(image_size
.height(), resource
->size
.height());
654 if (resource
->type
== RESOURCE_TYPE_BITMAP
) {
655 DCHECK_EQ(RESOURCE_TYPE_BITMAP
, resource
->type
);
656 DCHECK(resource
->allocated
);
657 DCHECK_EQ(RGBA_8888
, resource
->format
);
658 SkImageInfo source_info
=
659 SkImageInfo::MakeN32Premul(image_size
.width(), image_size
.height());
660 size_t image_stride
= image_size
.width() * 4;
662 ScopedWriteLockSoftware
lock(this, id
);
663 SkCanvas
dest(lock
.sk_bitmap());
664 dest
.writePixels(source_info
, image
, image_stride
, 0, 0);
666 DCHECK(resource
->gl_id
);
667 DCHECK_EQ(resource
->target
, static_cast<GLenum
>(GL_TEXTURE_2D
));
668 GLES2Interface
* gl
= ContextGL();
670 gl
->BindTexture(GL_TEXTURE_2D
, resource
->gl_id
);
672 if (resource
->format
== ETC1
) {
673 int image_bytes
= ResourceUtil::CheckedSizeInBytes
<int>(image_size
, ETC1
);
674 gl
->CompressedTexImage2D(GL_TEXTURE_2D
, 0, GLInternalFormat(ETC1
),
675 image_size
.width(), image_size
.height(), 0,
678 gl
->TexSubImage2D(GL_TEXTURE_2D
, 0, 0, 0, image_size
.width(),
679 image_size
.height(), GLDataFormat(resource
->format
),
680 GLDataType(resource
->format
), image
);
685 ResourceProvider::Resource
* ResourceProvider::InsertResource(
687 const Resource
& resource
) {
688 std::pair
<ResourceMap::iterator
, bool> result
=
689 resources_
.insert(ResourceMap::value_type(id
, resource
));
690 DCHECK(result
.second
);
691 return &result
.first
->second
;
694 ResourceProvider::Resource
* ResourceProvider::GetResource(ResourceId id
) {
695 DCHECK(thread_checker_
.CalledOnValidThread());
697 ResourceMap::iterator it
= resources_
.find(id
);
698 DCHECK(it
!= resources_
.end());
702 const ResourceProvider::Resource
* ResourceProvider::LockForRead(ResourceId id
) {
703 Resource
* resource
= GetResource(id
);
704 DCHECK(!resource
->locked_for_write
) << "locked for write: "
705 << resource
->locked_for_write
;
706 DCHECK_EQ(resource
->exported_count
, 0);
707 // Uninitialized! Call SetPixels or LockForWrite first.
708 DCHECK(resource
->allocated
);
710 LazyCreate(resource
);
712 if (resource
->type
== RESOURCE_TYPE_GL_TEXTURE
&& !resource
->gl_id
) {
713 DCHECK(resource
->origin
!= Resource::INTERNAL
);
714 DCHECK(resource
->mailbox
.IsTexture());
716 // Mailbox sync_points must be processed by a call to
717 // WaitSyncPointIfNeeded() prior to calling LockForRead().
718 DCHECK(!resource
->mailbox
.sync_point());
720 GLES2Interface
* gl
= ContextGL();
722 resource
->gl_id
= gl
->CreateAndConsumeTextureCHROMIUM(
723 resource
->mailbox
.target(), resource
->mailbox
.name());
726 if (!resource
->pixels
&& resource
->has_shared_bitmap_id
&&
727 shared_bitmap_manager_
) {
728 scoped_ptr
<SharedBitmap
> bitmap
=
729 shared_bitmap_manager_
->GetSharedBitmapFromId(
730 resource
->size
, resource
->shared_bitmap_id
);
732 resource
->shared_bitmap
= bitmap
.release();
733 resource
->pixels
= resource
->shared_bitmap
->pixels();
737 resource
->lock_for_read_count
++;
738 if (resource
->read_lock_fences_enabled
) {
739 if (current_read_lock_fence_
.get())
740 current_read_lock_fence_
->Set();
741 resource
->read_lock_fence
= current_read_lock_fence_
;
747 void ResourceProvider::UnlockForRead(ResourceId id
) {
748 DCHECK(thread_checker_
.CalledOnValidThread());
749 ResourceMap::iterator it
= resources_
.find(id
);
750 CHECK(it
!= resources_
.end());
752 Resource
* resource
= &it
->second
;
753 DCHECK_GT(resource
->lock_for_read_count
, 0);
754 DCHECK_EQ(resource
->exported_count
, 0);
755 resource
->lock_for_read_count
--;
756 if (resource
->marked_for_deletion
&& !resource
->lock_for_read_count
) {
757 if (!resource
->child_id
) {
758 // The resource belongs to this ResourceProvider, so it can be destroyed.
759 DeleteResourceInternal(it
, NORMAL
);
761 ChildMap::iterator child_it
= children_
.find(resource
->child_id
);
762 ResourceIdArray unused
;
763 unused
.push_back(id
);
764 DeleteAndReturnUnusedResourcesToChild(child_it
, NORMAL
, unused
);
769 ResourceProvider::Resource
* ResourceProvider::LockForWrite(ResourceId id
) {
770 Resource
* resource
= GetResource(id
);
771 DCHECK(CanLockForWrite(id
));
773 resource
->locked_for_write
= true;
777 bool ResourceProvider::CanLockForWrite(ResourceId id
) {
778 Resource
* resource
= GetResource(id
);
779 return !resource
->locked_for_write
&& !resource
->lock_for_read_count
&&
780 !resource
->exported_count
&& resource
->origin
== Resource::INTERNAL
&&
781 !resource
->lost
&& ReadLockFenceHasPassed(resource
);
784 void ResourceProvider::UnlockForWrite(ResourceProvider::Resource
* resource
) {
785 DCHECK(resource
->locked_for_write
);
786 DCHECK_EQ(resource
->exported_count
, 0);
787 DCHECK(resource
->origin
== Resource::INTERNAL
);
788 resource
->locked_for_write
= false;
791 void ResourceProvider::EnableReadLockFencesForTesting(ResourceId id
) {
792 Resource
* resource
= GetResource(id
);
794 resource
->read_lock_fences_enabled
= true;
797 ResourceProvider::ScopedReadLockGL::ScopedReadLockGL(
798 ResourceProvider
* resource_provider
,
799 ResourceId resource_id
)
800 : resource_provider_(resource_provider
),
801 resource_id_(resource_id
),
802 resource_(resource_provider
->LockForRead(resource_id
)) {
806 ResourceProvider::ScopedReadLockGL::~ScopedReadLockGL() {
807 resource_provider_
->UnlockForRead(resource_id_
);
810 ResourceProvider::ScopedSamplerGL::ScopedSamplerGL(
811 ResourceProvider
* resource_provider
,
812 ResourceId resource_id
,
814 : ScopedReadLockGL(resource_provider
, resource_id
),
816 target_(resource_provider
->BindForSampling(resource_id
, unit_
, filter
)) {
819 ResourceProvider::ScopedSamplerGL::ScopedSamplerGL(
820 ResourceProvider
* resource_provider
,
821 ResourceId resource_id
,
824 : ScopedReadLockGL(resource_provider
, resource_id
),
826 target_(resource_provider
->BindForSampling(resource_id
, unit_
, filter
)) {
829 ResourceProvider::ScopedSamplerGL::~ScopedSamplerGL() {
832 ResourceProvider::ScopedWriteLockGL::ScopedWriteLockGL(
833 ResourceProvider
* resource_provider
,
834 ResourceId resource_id
)
835 : resource_provider_(resource_provider
),
836 resource_(resource_provider
->LockForWrite(resource_id
)) {
837 resource_provider_
->LazyAllocate(resource_
);
838 texture_id_
= resource_
->gl_id
;
842 ResourceProvider::ScopedWriteLockGL::~ScopedWriteLockGL() {
843 resource_provider_
->UnlockForWrite(resource_
);
846 void ResourceProvider::PopulateSkBitmapWithResource(
847 SkBitmap
* sk_bitmap
, const Resource
* resource
) {
848 DCHECK_EQ(RGBA_8888
, resource
->format
);
849 SkImageInfo info
= SkImageInfo::MakeN32Premul(resource
->size
.width(),
850 resource
->size
.height());
851 sk_bitmap
->installPixels(info
, resource
->pixels
, info
.minRowBytes());
854 ResourceProvider::ScopedReadLockSoftware::ScopedReadLockSoftware(
855 ResourceProvider
* resource_provider
,
856 ResourceId resource_id
)
857 : resource_provider_(resource_provider
), resource_id_(resource_id
) {
858 const Resource
* resource
= resource_provider
->LockForRead(resource_id
);
859 wrap_mode_
= resource
->wrap_mode
;
860 ResourceProvider::PopulateSkBitmapWithResource(&sk_bitmap_
, resource
);
863 ResourceProvider::ScopedReadLockSoftware::~ScopedReadLockSoftware() {
864 resource_provider_
->UnlockForRead(resource_id_
);
867 ResourceProvider::ScopedWriteLockSoftware::ScopedWriteLockSoftware(
868 ResourceProvider
* resource_provider
,
869 ResourceId resource_id
)
870 : resource_provider_(resource_provider
),
871 resource_(resource_provider
->LockForWrite(resource_id
)) {
872 ResourceProvider::PopulateSkBitmapWithResource(&sk_bitmap_
, resource_
);
876 ResourceProvider::ScopedWriteLockSoftware::~ScopedWriteLockSoftware() {
877 DCHECK(thread_checker_
.CalledOnValidThread());
878 resource_provider_
->UnlockForWrite(resource_
);
881 ResourceProvider::ScopedWriteLockGpuMemoryBuffer::
882 ScopedWriteLockGpuMemoryBuffer(ResourceProvider
* resource_provider
,
883 ResourceId resource_id
)
884 : resource_provider_(resource_provider
),
885 resource_(resource_provider
->LockForWrite(resource_id
)),
886 gpu_memory_buffer_manager_(resource_provider
->gpu_memory_buffer_manager_
),
887 gpu_memory_buffer_(nullptr),
888 size_(resource_
->size
),
889 format_(resource_
->format
) {
890 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE
, resource_
->type
);
891 std::swap(gpu_memory_buffer_
, resource_
->gpu_memory_buffer
);
894 ResourceProvider::ScopedWriteLockGpuMemoryBuffer::
895 ~ScopedWriteLockGpuMemoryBuffer() {
896 DCHECK(thread_checker_
.CalledOnValidThread());
897 resource_provider_
->UnlockForWrite(resource_
);
898 if (!gpu_memory_buffer_
)
901 resource_provider_
->LazyCreate(resource_
);
903 if (!resource_
->image_id
) {
904 GLES2Interface
* gl
= resource_provider_
->ContextGL();
907 #if defined(OS_CHROMEOS)
908 // TODO(reveman): GL_COMMANDS_ISSUED_CHROMIUM is used for synchronization
909 // on ChromeOS to avoid some performance issues. This only works with
910 // shared memory backed buffers. crbug.com/436314
911 DCHECK_EQ(gpu_memory_buffer_
->GetHandle().type
, gfx::SHARED_MEMORY_BUFFER
);
914 resource_
->image_id
= gl
->CreateImageCHROMIUM(
915 gpu_memory_buffer_
->AsClientBuffer(), size_
.width(), size_
.height(),
916 GLInternalFormat(resource_
->format
));
919 std::swap(resource_
->gpu_memory_buffer
, gpu_memory_buffer_
);
920 resource_
->allocated
= true;
921 resource_
->dirty_image
= true;
923 // GpuMemoryBuffer provides direct access to the memory used by the GPU.
924 // Read lock fences are required to ensure that we're not trying to map a
925 // buffer that is currently in-use by the GPU.
926 resource_
->read_lock_fences_enabled
= true;
929 gfx::GpuMemoryBuffer
*
930 ResourceProvider::ScopedWriteLockGpuMemoryBuffer::GetGpuMemoryBuffer() {
931 if (gpu_memory_buffer_
)
932 return gpu_memory_buffer_
;
933 scoped_ptr
<gfx::GpuMemoryBuffer
> gpu_memory_buffer
=
934 gpu_memory_buffer_manager_
->AllocateGpuMemoryBuffer(
935 size_
, BufferFormat(format_
), gfx::BufferUsage::MAP
);
936 gpu_memory_buffer_
= gpu_memory_buffer
.release();
937 return gpu_memory_buffer_
;
940 ResourceProvider::ScopedWriteLockGr::ScopedWriteLockGr(
941 ResourceProvider
* resource_provider
,
942 ResourceId resource_id
)
943 : resource_provider_(resource_provider
),
944 resource_(resource_provider
->LockForWrite(resource_id
)) {
945 DCHECK(thread_checker_
.CalledOnValidThread());
946 resource_provider_
->LazyAllocate(resource_
);
949 ResourceProvider::ScopedWriteLockGr::~ScopedWriteLockGr() {
950 DCHECK(thread_checker_
.CalledOnValidThread());
951 DCHECK(resource_
->locked_for_write
);
952 resource_provider_
->UnlockForWrite(resource_
);
955 void ResourceProvider::ScopedWriteLockGr::InitSkSurface(
956 bool use_distance_field_text
,
957 bool can_use_lcd_text
,
958 int msaa_sample_count
) {
959 DCHECK(resource_
->locked_for_write
);
961 GrBackendTextureDesc desc
;
962 desc
.fFlags
= kRenderTarget_GrBackendTextureFlag
;
963 desc
.fWidth
= resource_
->size
.width();
964 desc
.fHeight
= resource_
->size
.height();
965 desc
.fConfig
= ToGrPixelConfig(resource_
->format
);
966 desc
.fOrigin
= kTopLeft_GrSurfaceOrigin
;
967 desc
.fTextureHandle
= resource_
->gl_id
;
968 desc
.fSampleCnt
= msaa_sample_count
;
970 bool use_worker_context
= true;
971 class GrContext
* gr_context
=
972 resource_provider_
->GrContext(use_worker_context
);
974 use_distance_field_text
? SkSurfaceProps::kUseDistanceFieldFonts_Flag
: 0;
975 // Use unknown pixel geometry to disable LCD text.
976 SkSurfaceProps
surface_props(flags
, kUnknown_SkPixelGeometry
);
977 if (can_use_lcd_text
) {
978 // LegacyFontHost will get LCD text and skia figures out what type to use.
980 SkSurfaceProps(flags
, SkSurfaceProps::kLegacyFontHost_InitType
);
982 sk_surface_
= skia::AdoptRef(
983 SkSurface::NewWrappedRenderTarget(gr_context
, desc
, &surface_props
));
986 void ResourceProvider::ScopedWriteLockGr::ReleaseSkSurface() {
990 ResourceProvider::SynchronousFence::SynchronousFence(
991 gpu::gles2::GLES2Interface
* gl
)
992 : gl_(gl
), has_synchronized_(true) {
995 ResourceProvider::SynchronousFence::~SynchronousFence() {
998 void ResourceProvider::SynchronousFence::Set() {
999 has_synchronized_
= false;
1002 bool ResourceProvider::SynchronousFence::HasPassed() {
1003 if (!has_synchronized_
) {
1004 has_synchronized_
= true;
1010 void ResourceProvider::SynchronousFence::Wait() {
1014 void ResourceProvider::SynchronousFence::Synchronize() {
1015 TRACE_EVENT0("cc", "ResourceProvider::SynchronousFence::Synchronize");
1019 ResourceProvider::ResourceProvider(
1020 OutputSurface
* output_surface
,
1021 SharedBitmapManager
* shared_bitmap_manager
,
1022 gpu::GpuMemoryBufferManager
* gpu_memory_buffer_manager
,
1023 BlockingTaskRunner
* blocking_main_thread_task_runner
,
1024 int highp_threshold_min
,
1025 bool use_rgba_4444_texture_format
,
1026 size_t id_allocation_chunk_size
,
1027 const std::vector
<unsigned>& use_image_texture_targets
)
1028 : output_surface_(output_surface
),
1029 shared_bitmap_manager_(shared_bitmap_manager
),
1030 gpu_memory_buffer_manager_(gpu_memory_buffer_manager
),
1031 blocking_main_thread_task_runner_(blocking_main_thread_task_runner
),
1032 lost_output_surface_(false),
1033 highp_threshold_min_(highp_threshold_min
),
1036 default_resource_type_(RESOURCE_TYPE_BITMAP
),
1037 use_texture_storage_ext_(false),
1038 use_texture_format_bgra_(false),
1039 use_texture_usage_hint_(false),
1040 use_compressed_texture_etc1_(false),
1041 yuv_resource_format_(LUMINANCE_8
),
1042 max_texture_size_(0),
1043 best_texture_format_(RGBA_8888
),
1044 best_render_buffer_format_(RGBA_8888
),
1045 use_rgba_4444_texture_format_(use_rgba_4444_texture_format
),
1046 id_allocation_chunk_size_(id_allocation_chunk_size
),
1047 use_sync_query_(false),
1048 use_image_texture_targets_(use_image_texture_targets
),
1049 tracing_id_(g_next_resource_provider_tracing_id
.GetNext()) {
1050 DCHECK(output_surface_
->HasClient());
1051 DCHECK(id_allocation_chunk_size_
);
1054 void ResourceProvider::Initialize() {
1055 DCHECK(thread_checker_
.CalledOnValidThread());
1057 // In certain cases, ThreadTaskRunnerHandle isn't set (Android Webview).
1058 // Don't register a dump provider in these cases.
1059 // TODO(ericrk): Get this working in Android Webview. crbug.com/517156
1060 if (base::ThreadTaskRunnerHandle::IsSet()) {
1061 base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
1062 this, base::ThreadTaskRunnerHandle::Get());
1065 GLES2Interface
* gl
= ContextGL();
1067 default_resource_type_
= RESOURCE_TYPE_BITMAP
;
1068 // Pick an arbitrary limit here similar to what hardware might.
1069 max_texture_size_
= 16 * 1024;
1070 best_texture_format_
= RGBA_8888
;
1074 DCHECK(!texture_id_allocator_
);
1075 DCHECK(!buffer_id_allocator_
);
1077 const ContextProvider::Capabilities
& caps
=
1078 output_surface_
->context_provider()->ContextCapabilities();
1080 default_resource_type_
= RESOURCE_TYPE_GL_TEXTURE
;
1081 use_texture_storage_ext_
= caps
.gpu
.texture_storage
;
1082 use_texture_format_bgra_
= caps
.gpu
.texture_format_bgra8888
;
1083 use_texture_usage_hint_
= caps
.gpu
.texture_usage
;
1084 use_compressed_texture_etc1_
= caps
.gpu
.texture_format_etc1
;
1085 yuv_resource_format_
= caps
.gpu
.texture_rg
? RED_8
: LUMINANCE_8
;
1086 use_sync_query_
= caps
.gpu
.sync_query
;
1088 max_texture_size_
= 0; // Context expects cleared value.
1089 gl
->GetIntegerv(GL_MAX_TEXTURE_SIZE
, &max_texture_size_
);
1090 best_texture_format_
=
1091 PlatformColor::BestTextureFormat(use_texture_format_bgra_
);
1093 best_render_buffer_format_
=
1094 PlatformColor::BestTextureFormat(caps
.gpu
.render_buffer_format_bgra8888
);
1096 texture_id_allocator_
.reset(
1097 new TextureIdAllocator(gl
, id_allocation_chunk_size_
));
1098 buffer_id_allocator_
.reset(
1099 new BufferIdAllocator(gl
, id_allocation_chunk_size_
));
1102 int ResourceProvider::CreateChild(const ReturnCallback
& return_callback
) {
1103 DCHECK(thread_checker_
.CalledOnValidThread());
1106 child_info
.return_callback
= return_callback
;
1108 int child
= next_child_
++;
1109 children_
[child
] = child_info
;
1113 void ResourceProvider::SetChildNeedsSyncPoints(int child_id
, bool needs
) {
1114 ChildMap::iterator it
= children_
.find(child_id
);
1115 DCHECK(it
!= children_
.end());
1116 it
->second
.needs_sync_points
= needs
;
1119 void ResourceProvider::DestroyChild(int child_id
) {
1120 ChildMap::iterator it
= children_
.find(child_id
);
1121 DCHECK(it
!= children_
.end());
1122 DestroyChildInternal(it
, NORMAL
);
1125 void ResourceProvider::DestroyChildInternal(ChildMap::iterator it
,
1126 DeleteStyle style
) {
1127 DCHECK(thread_checker_
.CalledOnValidThread());
1129 Child
& child
= it
->second
;
1130 DCHECK(style
== FOR_SHUTDOWN
|| !child
.marked_for_deletion
);
1132 ResourceIdArray resources_for_child
;
1134 for (ResourceIdMap::iterator child_it
= child
.child_to_parent_map
.begin();
1135 child_it
!= child
.child_to_parent_map
.end();
1137 ResourceId id
= child_it
->second
;
1138 resources_for_child
.push_back(id
);
1141 child
.marked_for_deletion
= true;
1143 DeleteAndReturnUnusedResourcesToChild(it
, style
, resources_for_child
);
1146 const ResourceProvider::ResourceIdMap
& ResourceProvider::GetChildToParentMap(
1148 DCHECK(thread_checker_
.CalledOnValidThread());
1149 ChildMap::const_iterator it
= children_
.find(child
);
1150 DCHECK(it
!= children_
.end());
1151 DCHECK(!it
->second
.marked_for_deletion
);
1152 return it
->second
.child_to_parent_map
;
1155 void ResourceProvider::PrepareSendToParent(const ResourceIdArray
& resources
,
1156 TransferableResourceArray
* list
) {
1157 DCHECK(thread_checker_
.CalledOnValidThread());
1158 GLES2Interface
* gl
= ContextGL();
1159 bool need_sync_point
= false;
1160 for (ResourceIdArray::const_iterator it
= resources
.begin();
1161 it
!= resources
.end();
1163 TransferableResource resource
;
1164 TransferResource(gl
, *it
, &resource
);
1165 if (!resource
.mailbox_holder
.sync_point
&& !resource
.is_software
)
1166 need_sync_point
= true;
1167 ++resources_
.find(*it
)->second
.exported_count
;
1168 list
->push_back(resource
);
1170 if (need_sync_point
&&
1171 output_surface_
->capabilities().delegated_sync_points_required
) {
1172 GLuint sync_point
= gl
->InsertSyncPointCHROMIUM();
1173 for (TransferableResourceArray::iterator it
= list
->begin();
1176 if (!it
->mailbox_holder
.sync_point
)
1177 it
->mailbox_holder
.sync_point
= sync_point
;
1182 void ResourceProvider::ReceiveFromChild(
1183 int child
, const TransferableResourceArray
& resources
) {
1184 DCHECK(thread_checker_
.CalledOnValidThread());
1185 GLES2Interface
* gl
= ContextGL();
1186 Child
& child_info
= children_
.find(child
)->second
;
1187 DCHECK(!child_info
.marked_for_deletion
);
1188 for (TransferableResourceArray::const_iterator it
= resources
.begin();
1189 it
!= resources
.end();
1191 ResourceIdMap::iterator resource_in_map_it
=
1192 child_info
.child_to_parent_map
.find(it
->id
);
1193 if (resource_in_map_it
!= child_info
.child_to_parent_map
.end()) {
1194 Resource
* resource
= GetResource(resource_in_map_it
->second
);
1195 resource
->marked_for_deletion
= false;
1196 resource
->imported_count
++;
1200 if ((!it
->is_software
&& !gl
) ||
1201 (it
->is_software
&& !shared_bitmap_manager_
)) {
1202 TRACE_EVENT0("cc", "ResourceProvider::ReceiveFromChild dropping invalid");
1203 ReturnedResourceArray to_return
;
1204 to_return
.push_back(it
->ToReturnedResource());
1205 child_info
.return_callback
.Run(to_return
,
1206 blocking_main_thread_task_runner_
);
1210 ResourceId local_id
= next_id_
++;
1211 Resource
* resource
= nullptr;
1212 if (it
->is_software
) {
1213 resource
= InsertResource(
1215 Resource(it
->mailbox_holder
.mailbox
, it
->size
, Resource::DELEGATED
,
1216 GL_LINEAR
, it
->is_repeated
? GL_REPEAT
: GL_CLAMP_TO_EDGE
));
1218 resource
= InsertResource(
1219 local_id
, Resource(0, it
->size
, Resource::DELEGATED
,
1220 it
->mailbox_holder
.texture_target
, it
->filter
, 0,
1221 it
->is_repeated
? GL_REPEAT
: GL_CLAMP_TO_EDGE
,
1222 TEXTURE_HINT_IMMUTABLE
, it
->format
));
1223 resource
->mailbox
= TextureMailbox(it
->mailbox_holder
.mailbox
,
1224 it
->mailbox_holder
.texture_target
,
1225 it
->mailbox_holder
.sync_point
);
1226 resource
->read_lock_fences_enabled
= it
->read_lock_fences_enabled
;
1228 resource
->child_id
= child
;
1229 // Don't allocate a texture for a child.
1230 resource
->allocated
= true;
1231 resource
->imported_count
= 1;
1232 child_info
.parent_to_child_map
[local_id
] = it
->id
;
1233 child_info
.child_to_parent_map
[it
->id
] = local_id
;
1237 void ResourceProvider::DeclareUsedResourcesFromChild(
1239 const ResourceIdSet
& resources_from_child
) {
1240 DCHECK(thread_checker_
.CalledOnValidThread());
1242 ChildMap::iterator child_it
= children_
.find(child
);
1243 DCHECK(child_it
!= children_
.end());
1244 Child
& child_info
= child_it
->second
;
1245 DCHECK(!child_info
.marked_for_deletion
);
1247 ResourceIdArray unused
;
1248 for (ResourceIdMap::iterator it
= child_info
.child_to_parent_map
.begin();
1249 it
!= child_info
.child_to_parent_map
.end();
1251 ResourceId local_id
= it
->second
;
1252 bool resource_is_in_use
= resources_from_child
.count(it
->first
) > 0;
1253 if (!resource_is_in_use
)
1254 unused
.push_back(local_id
);
1256 DeleteAndReturnUnusedResourcesToChild(child_it
, NORMAL
, unused
);
1259 void ResourceProvider::ReceiveReturnsFromParent(
1260 const ReturnedResourceArray
& resources
) {
1261 DCHECK(thread_checker_
.CalledOnValidThread());
1262 GLES2Interface
* gl
= ContextGL();
1264 base::hash_map
<int, ResourceIdArray
> resources_for_child
;
1266 for (const ReturnedResource
& returned
: resources
) {
1267 ResourceId local_id
= returned
.id
;
1268 ResourceMap::iterator map_iterator
= resources_
.find(local_id
);
1269 // Resource was already lost (e.g. it belonged to a child that was
1271 if (map_iterator
== resources_
.end())
1274 Resource
* resource
= &map_iterator
->second
;
1276 CHECK_GE(resource
->exported_count
, returned
.count
);
1277 resource
->exported_count
-= returned
.count
;
1278 resource
->lost
|= returned
.lost
;
1279 if (resource
->exported_count
)
1282 if (returned
.sync_point
) {
1283 DCHECK(!resource
->has_shared_bitmap_id
);
1284 if (resource
->origin
== Resource::INTERNAL
) {
1285 DCHECK(resource
->gl_id
);
1286 gl
->WaitSyncPointCHROMIUM(returned
.sync_point
);
1288 DCHECK(!resource
->gl_id
);
1289 resource
->mailbox
.set_sync_point(returned
.sync_point
);
1293 if (!resource
->marked_for_deletion
)
1296 if (!resource
->child_id
) {
1297 // The resource belongs to this ResourceProvider, so it can be destroyed.
1298 DeleteResourceInternal(map_iterator
, NORMAL
);
1302 DCHECK(resource
->origin
== Resource::DELEGATED
);
1303 resources_for_child
[resource
->child_id
].push_back(local_id
);
1306 for (const auto& children
: resources_for_child
) {
1307 ChildMap::iterator child_it
= children_
.find(children
.first
);
1308 DCHECK(child_it
!= children_
.end());
1309 DeleteAndReturnUnusedResourcesToChild(child_it
, NORMAL
, children
.second
);
1313 void ResourceProvider::TransferResource(GLES2Interface
* gl
,
1315 TransferableResource
* resource
) {
1316 Resource
* source
= GetResource(id
);
1317 DCHECK(!source
->locked_for_write
);
1318 DCHECK(!source
->lock_for_read_count
);
1319 DCHECK(source
->origin
!= Resource::EXTERNAL
|| source
->mailbox
.IsValid());
1320 DCHECK(source
->allocated
);
1322 resource
->format
= source
->format
;
1323 resource
->mailbox_holder
.texture_target
= source
->target
;
1324 resource
->filter
= source
->filter
;
1325 resource
->size
= source
->size
;
1326 resource
->read_lock_fences_enabled
= source
->read_lock_fences_enabled
;
1327 resource
->is_repeated
= (source
->wrap_mode
== GL_REPEAT
);
1329 if (source
->type
== RESOURCE_TYPE_BITMAP
) {
1330 resource
->mailbox_holder
.mailbox
= source
->shared_bitmap_id
;
1331 resource
->is_software
= true;
1332 } else if (!source
->mailbox
.IsValid()) {
1334 DCHECK(source
->gl_id
);
1335 DCHECK(source
->origin
== Resource::INTERNAL
);
1336 if (source
->image_id
) {
1337 DCHECK(source
->dirty_image
);
1338 gl
->BindTexture(resource
->mailbox_holder
.texture_target
, source
->gl_id
);
1339 BindImageForSampling(source
);
1341 // This is a resource allocated by the compositor, we need to produce it.
1342 // Don't set a sync point, the caller will do it.
1343 gl
->GenMailboxCHROMIUM(resource
->mailbox_holder
.mailbox
.name
);
1344 gl
->ProduceTextureDirectCHROMIUM(source
->gl_id
,
1345 resource
->mailbox_holder
.texture_target
,
1346 resource
->mailbox_holder
.mailbox
.name
);
1348 source
->mailbox
= TextureMailbox(resource
->mailbox_holder
);
1350 DCHECK(source
->mailbox
.IsTexture());
1351 if (source
->image_id
&& source
->dirty_image
) {
1352 DCHECK(source
->gl_id
);
1353 DCHECK(source
->origin
== Resource::INTERNAL
);
1354 gl
->BindTexture(resource
->mailbox_holder
.texture_target
, source
->gl_id
);
1355 BindImageForSampling(source
);
1357 // This is either an external resource, or a compositor resource that we
1358 // already exported. Make sure to forward the sync point that we were given.
1359 resource
->mailbox_holder
.mailbox
= source
->mailbox
.mailbox();
1360 resource
->mailbox_holder
.texture_target
= source
->mailbox
.target();
1361 resource
->mailbox_holder
.sync_point
= source
->mailbox
.sync_point();
1362 source
->mailbox
.set_sync_point(0);
1366 void ResourceProvider::DeleteAndReturnUnusedResourcesToChild(
1367 ChildMap::iterator child_it
,
1369 const ResourceIdArray
& unused
) {
1370 DCHECK(thread_checker_
.CalledOnValidThread());
1371 DCHECK(child_it
!= children_
.end());
1372 Child
* child_info
= &child_it
->second
;
1374 if (unused
.empty() && !child_info
->marked_for_deletion
)
1377 ReturnedResourceArray to_return
;
1379 GLES2Interface
* gl
= ContextGL();
1380 bool need_sync_point
= false;
1381 for (size_t i
= 0; i
< unused
.size(); ++i
) {
1382 ResourceId local_id
= unused
[i
];
1384 ResourceMap::iterator it
= resources_
.find(local_id
);
1385 CHECK(it
!= resources_
.end());
1386 Resource
& resource
= it
->second
;
1388 DCHECK(!resource
.locked_for_write
);
1389 DCHECK(child_info
->parent_to_child_map
.count(local_id
));
1391 ResourceId child_id
= child_info
->parent_to_child_map
[local_id
];
1392 DCHECK(child_info
->child_to_parent_map
.count(child_id
));
1396 (resource
.type
== RESOURCE_TYPE_GL_TEXTURE
&& lost_output_surface_
);
1397 if (resource
.exported_count
> 0 || resource
.lock_for_read_count
> 0) {
1398 if (style
!= FOR_SHUTDOWN
) {
1399 // Defer this resource deletion.
1400 resource
.marked_for_deletion
= true;
1403 // We can't postpone the deletion, so we'll have to lose it.
1405 } else if (!ReadLockFenceHasPassed(&resource
)) {
1406 // TODO(dcastagna): see if it's possible to use this logic for
1407 // the branch above too, where the resource is locked or still exported.
1408 if (style
!= FOR_SHUTDOWN
&& !child_info
->marked_for_deletion
) {
1409 // Defer this resource deletion.
1410 resource
.marked_for_deletion
= true;
1413 // We can't postpone the deletion, so we'll have to lose it.
1417 if (gl
&& resource
.filter
!= resource
.original_filter
) {
1418 DCHECK(resource
.target
);
1419 DCHECK(resource
.gl_id
);
1421 gl
->BindTexture(resource
.target
, resource
.gl_id
);
1422 gl
->TexParameteri(resource
.target
, GL_TEXTURE_MIN_FILTER
,
1423 resource
.original_filter
);
1424 gl
->TexParameteri(resource
.target
, GL_TEXTURE_MAG_FILTER
,
1425 resource
.original_filter
);
1428 ReturnedResource returned
;
1429 returned
.id
= child_id
;
1430 returned
.sync_point
= resource
.mailbox
.sync_point();
1431 if (!returned
.sync_point
&& resource
.type
== RESOURCE_TYPE_GL_TEXTURE
)
1432 need_sync_point
= true;
1433 returned
.count
= resource
.imported_count
;
1434 returned
.lost
= is_lost
;
1435 to_return
.push_back(returned
);
1437 child_info
->parent_to_child_map
.erase(local_id
);
1438 child_info
->child_to_parent_map
.erase(child_id
);
1439 resource
.imported_count
= 0;
1440 DeleteResourceInternal(it
, style
);
1442 if (need_sync_point
&& child_info
->needs_sync_points
) {
1444 GLuint sync_point
= gl
->InsertSyncPointCHROMIUM();
1445 for (size_t i
= 0; i
< to_return
.size(); ++i
) {
1446 if (!to_return
[i
].sync_point
)
1447 to_return
[i
].sync_point
= sync_point
;
1451 if (!to_return
.empty())
1452 child_info
->return_callback
.Run(to_return
,
1453 blocking_main_thread_task_runner_
);
1455 if (child_info
->marked_for_deletion
&&
1456 child_info
->parent_to_child_map
.empty()) {
1457 DCHECK(child_info
->child_to_parent_map
.empty());
1458 children_
.erase(child_it
);
1462 GLenum
ResourceProvider::BindForSampling(ResourceId resource_id
,
1465 DCHECK(thread_checker_
.CalledOnValidThread());
1466 GLES2Interface
* gl
= ContextGL();
1467 ResourceMap::iterator it
= resources_
.find(resource_id
);
1468 DCHECK(it
!= resources_
.end());
1469 Resource
* resource
= &it
->second
;
1470 DCHECK(resource
->lock_for_read_count
);
1471 DCHECK(!resource
->locked_for_write
);
1473 ScopedSetActiveTexture
scoped_active_tex(gl
, unit
);
1474 GLenum target
= resource
->target
;
1475 gl
->BindTexture(target
, resource
->gl_id
);
1476 if (filter
!= resource
->filter
) {
1477 gl
->TexParameteri(target
, GL_TEXTURE_MIN_FILTER
, filter
);
1478 gl
->TexParameteri(target
, GL_TEXTURE_MAG_FILTER
, filter
);
1479 resource
->filter
= filter
;
1482 if (resource
->image_id
&& resource
->dirty_image
)
1483 BindImageForSampling(resource
);
1488 void ResourceProvider::CreateForTesting(ResourceId id
) {
1489 LazyCreate(GetResource(id
));
1492 GLenum
ResourceProvider::TargetForTesting(ResourceId id
) {
1493 Resource
* resource
= GetResource(id
);
1494 return resource
->target
;
1497 void ResourceProvider::LazyCreate(Resource
* resource
) {
1498 if (resource
->type
!= RESOURCE_TYPE_GL_TEXTURE
||
1499 resource
->origin
!= Resource::INTERNAL
)
1502 if (resource
->gl_id
)
1505 DCHECK(resource
->texture_pool
);
1506 DCHECK(resource
->origin
== Resource::INTERNAL
);
1507 DCHECK(!resource
->mailbox
.IsValid());
1508 resource
->gl_id
= texture_id_allocator_
->NextId();
1510 GLES2Interface
* gl
= ContextGL();
1513 // Create and set texture properties. Allocation is delayed until needed.
1514 gl
->BindTexture(resource
->target
, resource
->gl_id
);
1515 gl
->TexParameteri(resource
->target
, GL_TEXTURE_MIN_FILTER
,
1516 resource
->original_filter
);
1517 gl
->TexParameteri(resource
->target
, GL_TEXTURE_MAG_FILTER
,
1518 resource
->original_filter
);
1519 gl
->TexParameteri(resource
->target
, GL_TEXTURE_WRAP_S
, resource
->wrap_mode
);
1520 gl
->TexParameteri(resource
->target
, GL_TEXTURE_WRAP_T
, resource
->wrap_mode
);
1521 gl
->TexParameteri(resource
->target
, GL_TEXTURE_POOL_CHROMIUM
,
1522 resource
->texture_pool
);
1523 if (use_texture_usage_hint_
&& (resource
->hint
& TEXTURE_HINT_FRAMEBUFFER
)) {
1524 gl
->TexParameteri(resource
->target
, GL_TEXTURE_USAGE_ANGLE
,
1525 GL_FRAMEBUFFER_ATTACHMENT_ANGLE
);
1529 void ResourceProvider::AllocateForTesting(ResourceId id
) {
1530 LazyAllocate(GetResource(id
));
1533 void ResourceProvider::LazyAllocate(Resource
* resource
) {
1535 if (resource
->allocated
)
1537 LazyCreate(resource
);
1538 if (!resource
->gl_id
)
1540 resource
->allocated
= true;
1541 GLES2Interface
* gl
= ContextGL();
1542 gfx::Size
& size
= resource
->size
;
1543 ResourceFormat format
= resource
->format
;
1544 gl
->BindTexture(resource
->target
, resource
->gl_id
);
1545 if (use_texture_storage_ext_
&&
1546 IsFormatSupportedForStorage(format
, use_texture_format_bgra_
) &&
1547 (resource
->hint
& TEXTURE_HINT_IMMUTABLE
)) {
1548 GLenum storage_format
= TextureToStorageFormat(format
);
1549 gl
->TexStorage2DEXT(resource
->target
, 1, storage_format
, size
.width(),
1552 // ETC1 does not support preallocation.
1553 if (format
!= ETC1
) {
1554 gl
->TexImage2D(resource
->target
, 0, GLInternalFormat(format
),
1555 size
.width(), size
.height(), 0, GLDataFormat(format
),
1556 GLDataType(format
), NULL
);
1561 void ResourceProvider::BindImageForSampling(Resource
* resource
) {
1562 GLES2Interface
* gl
= ContextGL();
1563 DCHECK(resource
->gl_id
);
1564 DCHECK(resource
->image_id
);
1566 // Release image currently bound to texture.
1567 if (resource
->bound_image_id
)
1568 gl
->ReleaseTexImage2DCHROMIUM(resource
->target
, resource
->bound_image_id
);
1569 gl
->BindTexImage2DCHROMIUM(resource
->target
, resource
->image_id
);
1570 resource
->bound_image_id
= resource
->image_id
;
1571 resource
->dirty_image
= false;
1574 void ResourceProvider::WaitSyncPointIfNeeded(ResourceId id
) {
1575 Resource
* resource
= GetResource(id
);
1576 DCHECK_EQ(resource
->exported_count
, 0);
1577 DCHECK(resource
->allocated
);
1578 if (resource
->type
!= RESOURCE_TYPE_GL_TEXTURE
|| resource
->gl_id
)
1580 if (!resource
->mailbox
.sync_point())
1582 DCHECK(resource
->mailbox
.IsValid());
1583 GLES2Interface
* gl
= ContextGL();
1585 gl
->WaitSyncPointCHROMIUM(resource
->mailbox
.sync_point());
1586 resource
->mailbox
.set_sync_point(0);
1589 GLint
ResourceProvider::GetActiveTextureUnit(GLES2Interface
* gl
) {
1590 GLint active_unit
= 0;
1591 gl
->GetIntegerv(GL_ACTIVE_TEXTURE
, &active_unit
);
1595 GLenum
ResourceProvider::GetImageTextureTarget(ResourceFormat format
) {
1596 gfx::BufferFormat buffer_format
= BufferFormat(format
);
1597 DCHECK_GT(use_image_texture_targets_
.size(),
1598 static_cast<size_t>(buffer_format
));
1599 return use_image_texture_targets_
[static_cast<size_t>(buffer_format
)];
1602 void ResourceProvider::ValidateResource(ResourceId id
) const {
1603 DCHECK(thread_checker_
.CalledOnValidThread());
1605 DCHECK(resources_
.find(id
) != resources_
.end());
1608 GLES2Interface
* ResourceProvider::ContextGL() const {
1609 ContextProvider
* context_provider
= output_surface_
->context_provider();
1610 return context_provider
? context_provider
->ContextGL() : NULL
;
1613 class GrContext
* ResourceProvider::GrContext(bool worker_context
) const {
1614 ContextProvider
* context_provider
=
1615 worker_context
? output_surface_
->worker_context_provider()
1616 : output_surface_
->context_provider();
1617 return context_provider
? context_provider
->GrContext() : NULL
;
1620 bool ResourceProvider::OnMemoryDump(
1621 const base::trace_event::MemoryDumpArgs
& args
,
1622 base::trace_event::ProcessMemoryDump
* pmd
) {
1623 DCHECK(thread_checker_
.CalledOnValidThread());
1625 const uint64 tracing_process_id
=
1626 base::trace_event::MemoryDumpManager::GetInstance()
1627 ->GetTracingProcessId();
1629 for (const auto& resource_entry
: resources_
) {
1630 const auto& resource
= resource_entry
.second
;
1632 // Resource IDs are not process-unique, so log with the ResourceProvider's
1634 std::string dump_name
=
1635 base::StringPrintf("cc/resource_memory/provider_%d/resource_%d",
1636 tracing_id_
, resource_entry
.first
);
1637 base::trace_event::MemoryAllocatorDump
* dump
=
1638 pmd
->CreateAllocatorDump(dump_name
);
1640 uint64_t total_bytes
= ResourceUtil::UncheckedSizeInBytesAligned
<size_t>(
1641 resource
.size
, resource
.format
);
1642 dump
->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize
,
1643 base::trace_event::MemoryAllocatorDump::kUnitsBytes
,
1644 static_cast<uint64_t>(total_bytes
));
1646 // Resources which are shared across processes require a shared GUID to
1647 // prevent double counting the memory. We currently support shared GUIDs for
1648 // GpuMemoryBuffer, SharedBitmap, and GL backed resources.
1649 base::trace_event::MemoryAllocatorDumpGuid guid
;
1650 if (resource
.gpu_memory_buffer
) {
1651 guid
= gfx::GetGpuMemoryBufferGUIDForTracing(
1652 tracing_process_id
, resource
.gpu_memory_buffer
->GetHandle().id
);
1653 } else if (resource
.shared_bitmap
) {
1654 guid
= GetSharedBitmapGUIDForTracing(resource
.shared_bitmap
->id());
1655 } else if (resource
.gl_id
&& resource
.allocated
) {
1656 guid
= gfx::GetGLTextureClientGUIDForTracing(
1657 output_surface_
->context_provider()
1659 ->ShareGroupTracingGUID(),
1663 if (!guid
.empty()) {
1664 const int kImportance
= 2;
1665 pmd
->CreateSharedGlobalAllocatorDump(guid
);
1666 pmd
->AddOwnershipEdge(dump
->guid(), guid
, kImportance
);