Delete unused downloads page asset.
[chromium-blink-merge.git] / cc / resources / resource_provider.cc
blobe9082bbd01dee37b6251b13d50a9623cb7a82892
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"
7 #include <algorithm>
8 #include <limits>
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/gles2_interface.h"
28 #include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
29 #include "third_party/khronos/GLES2/gl2.h"
30 #include "third_party/khronos/GLES2/gl2ext.h"
31 #include "third_party/skia/include/core/SkSurface.h"
32 #include "third_party/skia/include/gpu/GrContext.h"
33 #include "third_party/skia/include/gpu/GrTextureProvider.h"
34 #include "ui/gfx/geometry/rect.h"
35 #include "ui/gfx/geometry/vector2d.h"
36 #include "ui/gl/trace_util.h"
38 using gpu::gles2::GLES2Interface;
40 namespace cc {
42 class IdAllocator {
43 public:
44 virtual ~IdAllocator() {}
46 virtual GLuint NextId() = 0;
48 protected:
49 IdAllocator(GLES2Interface* gl, size_t id_allocation_chunk_size)
50 : gl_(gl),
51 id_allocation_chunk_size_(id_allocation_chunk_size),
52 ids_(new GLuint[id_allocation_chunk_size]),
53 next_id_index_(id_allocation_chunk_size) {
54 DCHECK(id_allocation_chunk_size_);
55 DCHECK_LE(id_allocation_chunk_size_,
56 static_cast<size_t>(std::numeric_limits<int>::max()));
59 GLES2Interface* gl_;
60 const size_t id_allocation_chunk_size_;
61 scoped_ptr<GLuint[]> ids_;
62 size_t next_id_index_;
65 namespace {
67 GLenum TextureToStorageFormat(ResourceFormat format) {
68 GLenum storage_format = GL_RGBA8_OES;
69 switch (format) {
70 case RGBA_8888:
71 break;
72 case BGRA_8888:
73 storage_format = GL_BGRA8_EXT;
74 break;
75 case RGBA_4444:
76 case ALPHA_8:
77 case LUMINANCE_8:
78 case RGB_565:
79 case ETC1:
80 case RED_8:
81 NOTREACHED();
82 break;
85 return storage_format;
88 bool IsFormatSupportedForStorage(ResourceFormat format, bool use_bgra) {
89 switch (format) {
90 case RGBA_8888:
91 return true;
92 case BGRA_8888:
93 return use_bgra;
94 case RGBA_4444:
95 case ALPHA_8:
96 case LUMINANCE_8:
97 case RGB_565:
98 case ETC1:
99 case RED_8:
100 return false;
102 return false;
105 GrPixelConfig ToGrPixelConfig(ResourceFormat format) {
106 switch (format) {
107 case RGBA_8888:
108 return kRGBA_8888_GrPixelConfig;
109 case BGRA_8888:
110 return kBGRA_8888_GrPixelConfig;
111 case RGBA_4444:
112 return kRGBA_4444_GrPixelConfig;
113 default:
114 break;
116 DCHECK(false) << "Unsupported resource format.";
117 return kSkia8888_GrPixelConfig;
120 class ScopedSetActiveTexture {
121 public:
122 ScopedSetActiveTexture(GLES2Interface* gl, GLenum unit)
123 : gl_(gl), unit_(unit) {
124 DCHECK_EQ(GL_TEXTURE0, ResourceProvider::GetActiveTextureUnit(gl_));
126 if (unit_ != GL_TEXTURE0)
127 gl_->ActiveTexture(unit_);
130 ~ScopedSetActiveTexture() {
131 // Active unit being GL_TEXTURE0 is effectively the ground state.
132 if (unit_ != GL_TEXTURE0)
133 gl_->ActiveTexture(GL_TEXTURE0);
136 private:
137 GLES2Interface* gl_;
138 GLenum unit_;
141 class TextureIdAllocator : public IdAllocator {
142 public:
143 TextureIdAllocator(GLES2Interface* gl,
144 size_t texture_id_allocation_chunk_size)
145 : IdAllocator(gl, texture_id_allocation_chunk_size) {}
146 ~TextureIdAllocator() override {
147 gl_->DeleteTextures(
148 static_cast<int>(id_allocation_chunk_size_ - next_id_index_),
149 ids_.get() + next_id_index_);
152 // Overridden from IdAllocator:
153 GLuint NextId() override {
154 if (next_id_index_ == id_allocation_chunk_size_) {
155 gl_->GenTextures(static_cast<int>(id_allocation_chunk_size_), ids_.get());
156 next_id_index_ = 0;
159 return ids_[next_id_index_++];
162 private:
163 DISALLOW_COPY_AND_ASSIGN(TextureIdAllocator);
166 class BufferIdAllocator : public IdAllocator {
167 public:
168 BufferIdAllocator(GLES2Interface* gl, size_t buffer_id_allocation_chunk_size)
169 : IdAllocator(gl, buffer_id_allocation_chunk_size) {}
170 ~BufferIdAllocator() override {
171 gl_->DeleteBuffers(
172 static_cast<int>(id_allocation_chunk_size_ - next_id_index_),
173 ids_.get() + next_id_index_);
176 // Overridden from IdAllocator:
177 GLuint NextId() override {
178 if (next_id_index_ == id_allocation_chunk_size_) {
179 gl_->GenBuffers(static_cast<int>(id_allocation_chunk_size_), ids_.get());
180 next_id_index_ = 0;
183 return ids_[next_id_index_++];
186 private:
187 DISALLOW_COPY_AND_ASSIGN(BufferIdAllocator);
190 // Generates process-unique IDs to use for tracing a ResourceProvider's
191 // resources.
192 base::StaticAtomicSequenceNumber g_next_resource_provider_tracing_id;
194 } // namespace
196 ResourceProvider::Resource::~Resource() {}
198 ResourceProvider::Resource::Resource(GLuint texture_id,
199 const gfx::Size& size,
200 Origin origin,
201 GLenum target,
202 GLenum filter,
203 GLenum texture_pool,
204 GLint wrap_mode,
205 TextureHint hint,
206 ResourceFormat format)
207 : child_id(0),
208 gl_id(texture_id),
209 gl_pixel_buffer_id(0),
210 gl_upload_query_id(0),
211 gl_read_lock_query_id(0),
212 pixels(NULL),
213 lock_for_read_count(0),
214 imported_count(0),
215 exported_count(0),
216 dirty_image(false),
217 locked_for_write(false),
218 lost(false),
219 marked_for_deletion(false),
220 allocated(false),
221 read_lock_fences_enabled(false),
222 has_shared_bitmap_id(false),
223 read_lock_fence(NULL),
224 size(size),
225 origin(origin),
226 target(target),
227 original_filter(filter),
228 filter(filter),
229 image_id(0),
230 bound_image_id(0),
231 texture_pool(texture_pool),
232 wrap_mode(wrap_mode),
233 hint(hint),
234 type(RESOURCE_TYPE_GL_TEXTURE),
235 format(format),
236 shared_bitmap(NULL),
237 gpu_memory_buffer(NULL) {
238 DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT);
239 DCHECK_EQ(origin == INTERNAL, !!texture_pool);
242 ResourceProvider::Resource::Resource(uint8_t* pixels,
243 SharedBitmap* bitmap,
244 const gfx::Size& size,
245 Origin origin,
246 GLenum filter,
247 GLint wrap_mode)
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(pixels),
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 allocated(false),
262 read_lock_fences_enabled(false),
263 has_shared_bitmap_id(!!bitmap),
264 read_lock_fence(NULL),
265 size(size),
266 origin(origin),
267 target(0),
268 original_filter(filter),
269 filter(filter),
270 image_id(0),
271 bound_image_id(0),
272 texture_pool(0),
273 wrap_mode(wrap_mode),
274 hint(TEXTURE_HINT_IMMUTABLE),
275 type(RESOURCE_TYPE_BITMAP),
276 format(RGBA_8888),
277 shared_bitmap(bitmap),
278 gpu_memory_buffer(NULL) {
279 DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT);
280 DCHECK(origin == DELEGATED || pixels);
281 if (bitmap)
282 shared_bitmap_id = bitmap->id();
285 ResourceProvider::Resource::Resource(const SharedBitmapId& bitmap_id,
286 const gfx::Size& size,
287 Origin origin,
288 GLenum filter,
289 GLint wrap_mode)
290 : child_id(0),
291 gl_id(0),
292 gl_pixel_buffer_id(0),
293 gl_upload_query_id(0),
294 gl_read_lock_query_id(0),
295 pixels(NULL),
296 lock_for_read_count(0),
297 imported_count(0),
298 exported_count(0),
299 dirty_image(false),
300 locked_for_write(false),
301 lost(false),
302 marked_for_deletion(false),
303 allocated(false),
304 read_lock_fences_enabled(false),
305 has_shared_bitmap_id(true),
306 read_lock_fence(NULL),
307 size(size),
308 origin(origin),
309 target(0),
310 original_filter(filter),
311 filter(filter),
312 image_id(0),
313 bound_image_id(0),
314 texture_pool(0),
315 wrap_mode(wrap_mode),
316 hint(TEXTURE_HINT_IMMUTABLE),
317 type(RESOURCE_TYPE_BITMAP),
318 format(RGBA_8888),
319 shared_bitmap_id(bitmap_id),
320 shared_bitmap(NULL),
321 gpu_memory_buffer(NULL) {
322 DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT);
325 ResourceProvider::Child::Child()
326 : marked_for_deletion(false), needs_sync_points(true) {
329 ResourceProvider::Child::~Child() {}
331 scoped_ptr<ResourceProvider> ResourceProvider::Create(
332 OutputSurface* output_surface,
333 SharedBitmapManager* shared_bitmap_manager,
334 gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
335 BlockingTaskRunner* blocking_main_thread_task_runner,
336 int highp_threshold_min,
337 bool use_rgba_4444_texture_format,
338 size_t id_allocation_chunk_size,
339 const std::vector<unsigned>& use_image_texture_targets) {
340 scoped_ptr<ResourceProvider> resource_provider(new ResourceProvider(
341 output_surface, shared_bitmap_manager, gpu_memory_buffer_manager,
342 blocking_main_thread_task_runner, highp_threshold_min,
343 use_rgba_4444_texture_format, id_allocation_chunk_size,
344 use_image_texture_targets));
345 resource_provider->Initialize();
346 return resource_provider;
349 ResourceProvider::~ResourceProvider() {
350 base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
351 this);
353 while (!children_.empty())
354 DestroyChildInternal(children_.begin(), FOR_SHUTDOWN);
355 while (!resources_.empty())
356 DeleteResourceInternal(resources_.begin(), FOR_SHUTDOWN);
358 GLES2Interface* gl = ContextGL();
359 if (default_resource_type_ != RESOURCE_TYPE_GL_TEXTURE) {
360 // We are not in GL mode, but double check before returning.
361 DCHECK(!gl);
362 return;
365 DCHECK(gl);
366 #if DCHECK_IS_ON()
367 // Check that all GL resources has been deleted.
368 for (ResourceMap::const_iterator itr = resources_.begin();
369 itr != resources_.end(); ++itr) {
370 DCHECK_NE(RESOURCE_TYPE_GL_TEXTURE, itr->second.type);
372 #endif // DCHECK_IS_ON()
374 texture_id_allocator_ = nullptr;
375 buffer_id_allocator_ = nullptr;
376 gl->Finish();
379 bool ResourceProvider::InUseByConsumer(ResourceId id) {
380 Resource* resource = GetResource(id);
381 return resource->lock_for_read_count > 0 || resource->exported_count > 0 ||
382 resource->lost;
385 bool ResourceProvider::IsLost(ResourceId id) {
386 Resource* resource = GetResource(id);
387 return resource->lost;
390 void ResourceProvider::LoseResourceForTesting(ResourceId id) {
391 Resource* resource = GetResource(id);
392 DCHECK(resource);
393 resource->lost = true;
396 ResourceId ResourceProvider::CreateResource(const gfx::Size& size,
397 GLint wrap_mode,
398 TextureHint hint,
399 ResourceFormat format) {
400 DCHECK(!size.IsEmpty());
401 switch (default_resource_type_) {
402 case RESOURCE_TYPE_GL_TEXTURE:
403 return CreateGLTexture(size,
404 GL_TEXTURE_2D,
405 GL_TEXTURE_POOL_UNMANAGED_CHROMIUM,
406 wrap_mode,
407 hint,
408 format);
409 case RESOURCE_TYPE_BITMAP:
410 DCHECK_EQ(RGBA_8888, format);
411 return CreateBitmap(size, wrap_mode);
414 LOG(FATAL) << "Invalid default resource type.";
415 return 0;
418 ResourceId ResourceProvider::CreateManagedResource(const gfx::Size& size,
419 GLenum target,
420 GLint wrap_mode,
421 TextureHint hint,
422 ResourceFormat format) {
423 DCHECK(!size.IsEmpty());
424 switch (default_resource_type_) {
425 case RESOURCE_TYPE_GL_TEXTURE:
426 return CreateGLTexture(size,
427 target,
428 GL_TEXTURE_POOL_MANAGED_CHROMIUM,
429 wrap_mode,
430 hint,
431 format);
432 case RESOURCE_TYPE_BITMAP:
433 DCHECK_EQ(RGBA_8888, format);
434 return CreateBitmap(size, wrap_mode);
437 LOG(FATAL) << "Invalid default resource type.";
438 return 0;
441 ResourceId ResourceProvider::CreateGLTexture(const gfx::Size& size,
442 GLenum target,
443 GLenum texture_pool,
444 GLint wrap_mode,
445 TextureHint hint,
446 ResourceFormat format) {
447 DCHECK_LE(size.width(), max_texture_size_);
448 DCHECK_LE(size.height(), max_texture_size_);
449 DCHECK(thread_checker_.CalledOnValidThread());
451 ResourceId id = next_id_++;
452 Resource* resource = InsertResource(
453 id, Resource(0, size, Resource::INTERNAL, target, GL_LINEAR, texture_pool,
454 wrap_mode, hint, format));
455 resource->allocated = false;
456 return id;
459 ResourceId ResourceProvider::CreateBitmap(const gfx::Size& size,
460 GLint wrap_mode) {
461 DCHECK(thread_checker_.CalledOnValidThread());
463 scoped_ptr<SharedBitmap> bitmap =
464 shared_bitmap_manager_->AllocateSharedBitmap(size);
465 uint8_t* pixels = bitmap->pixels();
466 DCHECK(pixels);
468 ResourceId id = next_id_++;
469 Resource* resource =
470 InsertResource(id, Resource(pixels, bitmap.release(), size,
471 Resource::INTERNAL, GL_LINEAR, wrap_mode));
472 resource->allocated = true;
473 return id;
476 ResourceId ResourceProvider::CreateResourceFromIOSurface(
477 const gfx::Size& size,
478 unsigned io_surface_id) {
479 DCHECK(thread_checker_.CalledOnValidThread());
481 ResourceId id = next_id_++;
482 Resource* resource = InsertResource(
483 id, Resource(0, gfx::Size(), Resource::INTERNAL, GL_TEXTURE_RECTANGLE_ARB,
484 GL_LINEAR, GL_TEXTURE_POOL_UNMANAGED_CHROMIUM,
485 GL_CLAMP_TO_EDGE, TEXTURE_HINT_IMMUTABLE, RGBA_8888));
486 LazyCreate(resource);
487 GLES2Interface* gl = ContextGL();
488 DCHECK(gl);
489 gl->BindTexture(GL_TEXTURE_RECTANGLE_ARB, resource->gl_id);
490 gl->TexImageIOSurface2DCHROMIUM(
491 GL_TEXTURE_RECTANGLE_ARB, size.width(), size.height(), io_surface_id, 0);
492 resource->allocated = true;
493 return id;
496 ResourceId ResourceProvider::CreateResourceFromTextureMailbox(
497 const TextureMailbox& mailbox,
498 scoped_ptr<SingleReleaseCallbackImpl> release_callback_impl,
499 bool read_lock_fences_enabled) {
500 DCHECK(thread_checker_.CalledOnValidThread());
501 // Just store the information. Mailbox will be consumed in LockForRead().
502 ResourceId id = next_id_++;
503 DCHECK(mailbox.IsValid());
504 Resource* resource = nullptr;
505 if (mailbox.IsTexture()) {
506 resource = InsertResource(
507 id, Resource(0, gfx::Size(), Resource::EXTERNAL, mailbox.target(),
508 mailbox.nearest_neighbor() ? GL_NEAREST : GL_LINEAR, 0,
509 GL_CLAMP_TO_EDGE, TEXTURE_HINT_IMMUTABLE, RGBA_8888));
510 } else {
511 DCHECK(mailbox.IsSharedMemory());
512 SharedBitmap* shared_bitmap = mailbox.shared_bitmap();
513 uint8_t* pixels = shared_bitmap->pixels();
514 DCHECK(pixels);
515 resource = InsertResource(
516 id, Resource(pixels, shared_bitmap, mailbox.size_in_pixels(),
517 Resource::EXTERNAL, GL_LINEAR, GL_CLAMP_TO_EDGE));
519 resource->allocated = true;
520 resource->mailbox = mailbox;
521 resource->release_callback_impl =
522 base::Bind(&SingleReleaseCallbackImpl::Run,
523 base::Owned(release_callback_impl.release()));
524 resource->read_lock_fences_enabled = read_lock_fences_enabled;
525 return id;
528 ResourceId ResourceProvider::CreateResourceFromTextureMailbox(
529 const TextureMailbox& mailbox,
530 scoped_ptr<SingleReleaseCallbackImpl> release_callback_impl) {
531 return CreateResourceFromTextureMailbox(mailbox, release_callback_impl.Pass(),
532 false);
535 void ResourceProvider::DeleteResource(ResourceId id) {
536 DCHECK(thread_checker_.CalledOnValidThread());
537 ResourceMap::iterator it = resources_.find(id);
538 CHECK(it != resources_.end());
539 Resource* resource = &it->second;
540 DCHECK(!resource->marked_for_deletion);
541 DCHECK_EQ(resource->imported_count, 0);
542 DCHECK(!resource->locked_for_write);
544 if (resource->exported_count > 0 || resource->lock_for_read_count > 0 ||
545 !ReadLockFenceHasPassed(resource)) {
546 resource->marked_for_deletion = true;
547 return;
548 } else {
549 DeleteResourceInternal(it, NORMAL);
553 void ResourceProvider::DeleteResourceInternal(ResourceMap::iterator it,
554 DeleteStyle style) {
555 TRACE_EVENT0("cc", "ResourceProvider::DeleteResourceInternal");
556 Resource* resource = &it->second;
557 bool lost_resource = resource->lost;
559 DCHECK(resource->exported_count == 0 || style != NORMAL);
560 if (style == FOR_SHUTDOWN && resource->exported_count > 0)
561 lost_resource = true;
563 if (resource->image_id) {
564 DCHECK(resource->origin == Resource::INTERNAL);
565 GLES2Interface* gl = ContextGL();
566 DCHECK(gl);
567 gl->DestroyImageCHROMIUM(resource->image_id);
569 if (resource->gl_upload_query_id) {
570 DCHECK(resource->origin == Resource::INTERNAL);
571 GLES2Interface* gl = ContextGL();
572 DCHECK(gl);
573 gl->DeleteQueriesEXT(1, &resource->gl_upload_query_id);
575 if (resource->gl_read_lock_query_id) {
576 DCHECK(resource->origin == Resource::INTERNAL);
577 GLES2Interface* gl = ContextGL();
578 DCHECK(gl);
579 gl->DeleteQueriesEXT(1, &resource->gl_read_lock_query_id);
581 if (resource->gl_pixel_buffer_id) {
582 DCHECK(resource->origin == Resource::INTERNAL);
583 GLES2Interface* gl = ContextGL();
584 DCHECK(gl);
585 gl->DeleteBuffers(1, &resource->gl_pixel_buffer_id);
587 if (resource->origin == Resource::EXTERNAL) {
588 DCHECK(resource->mailbox.IsValid());
589 GLuint sync_point = resource->mailbox.sync_point();
590 if (resource->type == RESOURCE_TYPE_GL_TEXTURE) {
591 DCHECK(resource->mailbox.IsTexture());
592 lost_resource |= lost_output_surface_;
593 GLES2Interface* gl = ContextGL();
594 DCHECK(gl);
595 if (resource->gl_id) {
596 gl->DeleteTextures(1, &resource->gl_id);
597 resource->gl_id = 0;
598 if (!lost_resource)
599 sync_point = gl->InsertSyncPointCHROMIUM();
601 } else {
602 DCHECK(resource->mailbox.IsSharedMemory());
603 resource->shared_bitmap = nullptr;
604 resource->pixels = nullptr;
606 resource->release_callback_impl.Run(
607 sync_point, lost_resource, blocking_main_thread_task_runner_);
609 if (resource->gl_id) {
610 GLES2Interface* gl = ContextGL();
611 DCHECK(gl);
612 gl->DeleteTextures(1, &resource->gl_id);
613 resource->gl_id = 0;
615 if (resource->shared_bitmap) {
616 DCHECK(resource->origin != Resource::EXTERNAL);
617 DCHECK_EQ(RESOURCE_TYPE_BITMAP, resource->type);
618 delete resource->shared_bitmap;
619 resource->pixels = NULL;
621 if (resource->pixels) {
622 DCHECK(resource->origin == Resource::INTERNAL);
623 delete[] resource->pixels;
624 resource->pixels = NULL;
626 if (resource->gpu_memory_buffer) {
627 DCHECK(resource->origin == Resource::INTERNAL);
628 delete resource->gpu_memory_buffer;
629 resource->gpu_memory_buffer = NULL;
631 resources_.erase(it);
634 ResourceProvider::ResourceType ResourceProvider::GetResourceType(
635 ResourceId id) {
636 return GetResource(id)->type;
639 void ResourceProvider::CopyToResource(ResourceId id,
640 const uint8_t* image,
641 const gfx::Size& image_size) {
642 Resource* resource = GetResource(id);
643 DCHECK(!resource->locked_for_write);
644 DCHECK(!resource->lock_for_read_count);
645 DCHECK(resource->origin == Resource::INTERNAL);
646 DCHECK_EQ(resource->exported_count, 0);
647 DCHECK(ReadLockFenceHasPassed(resource));
648 LazyAllocate(resource);
650 DCHECK_EQ(image_size.width(), resource->size.width());
651 DCHECK_EQ(image_size.height(), resource->size.height());
653 if (resource->type == RESOURCE_TYPE_BITMAP) {
654 DCHECK_EQ(RESOURCE_TYPE_BITMAP, resource->type);
655 DCHECK(resource->allocated);
656 DCHECK_EQ(RGBA_8888, resource->format);
657 SkImageInfo source_info =
658 SkImageInfo::MakeN32Premul(image_size.width(), image_size.height());
659 size_t image_stride = image_size.width() * 4;
661 ScopedWriteLockSoftware lock(this, id);
662 SkCanvas dest(lock.sk_bitmap());
663 dest.writePixels(source_info, image, image_stride, 0, 0);
664 } else {
665 DCHECK(resource->gl_id);
666 DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D));
667 GLES2Interface* gl = ContextGL();
668 DCHECK(gl);
669 gl->BindTexture(GL_TEXTURE_2D, resource->gl_id);
671 if (resource->format == ETC1) {
672 int image_bytes = ResourceUtil::CheckedSizeInBytes<int>(image_size, ETC1);
673 gl->CompressedTexImage2D(GL_TEXTURE_2D, 0, GLInternalFormat(ETC1),
674 image_size.width(), image_size.height(), 0,
675 image_bytes, image);
676 } else {
677 gl->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, image_size.width(),
678 image_size.height(), GLDataFormat(resource->format),
679 GLDataType(resource->format), image);
684 ResourceProvider::Resource* ResourceProvider::InsertResource(
685 ResourceId id,
686 const Resource& resource) {
687 std::pair<ResourceMap::iterator, bool> result =
688 resources_.insert(ResourceMap::value_type(id, resource));
689 DCHECK(result.second);
690 return &result.first->second;
693 ResourceProvider::Resource* ResourceProvider::GetResource(ResourceId id) {
694 DCHECK(thread_checker_.CalledOnValidThread());
695 DCHECK(id);
696 ResourceMap::iterator it = resources_.find(id);
697 DCHECK(it != resources_.end());
698 return &it->second;
701 const ResourceProvider::Resource* ResourceProvider::LockForRead(ResourceId id) {
702 Resource* resource = GetResource(id);
703 DCHECK(!resource->locked_for_write) << "locked for write: "
704 << resource->locked_for_write;
705 DCHECK_EQ(resource->exported_count, 0);
706 // Uninitialized! Call SetPixels or LockForWrite first.
707 DCHECK(resource->allocated);
709 LazyCreate(resource);
711 if (resource->type == RESOURCE_TYPE_GL_TEXTURE && !resource->gl_id) {
712 DCHECK(resource->origin != Resource::INTERNAL);
713 DCHECK(resource->mailbox.IsTexture());
715 // Mailbox sync_points must be processed by a call to
716 // WaitSyncPointIfNeeded() prior to calling LockForRead().
717 DCHECK(!resource->mailbox.sync_point());
719 GLES2Interface* gl = ContextGL();
720 DCHECK(gl);
721 resource->gl_id = gl->CreateAndConsumeTextureCHROMIUM(
722 resource->mailbox.target(), resource->mailbox.name());
725 if (!resource->pixels && resource->has_shared_bitmap_id &&
726 shared_bitmap_manager_) {
727 scoped_ptr<SharedBitmap> bitmap =
728 shared_bitmap_manager_->GetSharedBitmapFromId(
729 resource->size, resource->shared_bitmap_id);
730 if (bitmap) {
731 resource->shared_bitmap = bitmap.release();
732 resource->pixels = resource->shared_bitmap->pixels();
736 resource->lock_for_read_count++;
737 if (resource->read_lock_fences_enabled) {
738 if (current_read_lock_fence_.get())
739 current_read_lock_fence_->Set();
740 resource->read_lock_fence = current_read_lock_fence_;
743 return resource;
746 void ResourceProvider::UnlockForRead(ResourceId id) {
747 DCHECK(thread_checker_.CalledOnValidThread());
748 ResourceMap::iterator it = resources_.find(id);
749 CHECK(it != resources_.end());
751 Resource* resource = &it->second;
752 DCHECK_GT(resource->lock_for_read_count, 0);
753 DCHECK_EQ(resource->exported_count, 0);
754 resource->lock_for_read_count--;
755 if (resource->marked_for_deletion && !resource->lock_for_read_count) {
756 if (!resource->child_id) {
757 // The resource belongs to this ResourceProvider, so it can be destroyed.
758 DeleteResourceInternal(it, NORMAL);
759 } else {
760 ChildMap::iterator child_it = children_.find(resource->child_id);
761 ResourceIdArray unused;
762 unused.push_back(id);
763 DeleteAndReturnUnusedResourcesToChild(child_it, NORMAL, unused);
768 ResourceProvider::Resource* ResourceProvider::LockForWrite(ResourceId id) {
769 Resource* resource = GetResource(id);
770 DCHECK(CanLockForWrite(id));
772 resource->locked_for_write = true;
773 return resource;
776 bool ResourceProvider::CanLockForWrite(ResourceId id) {
777 Resource* resource = GetResource(id);
778 return !resource->locked_for_write && !resource->lock_for_read_count &&
779 !resource->exported_count && resource->origin == Resource::INTERNAL &&
780 !resource->lost && ReadLockFenceHasPassed(resource);
783 void ResourceProvider::UnlockForWrite(ResourceProvider::Resource* resource) {
784 DCHECK(resource->locked_for_write);
785 DCHECK_EQ(resource->exported_count, 0);
786 DCHECK(resource->origin == Resource::INTERNAL);
787 resource->locked_for_write = false;
790 void ResourceProvider::EnableReadLockFencesForTesting(ResourceId id) {
791 Resource* resource = GetResource(id);
792 DCHECK(resource);
793 resource->read_lock_fences_enabled = true;
796 ResourceProvider::ScopedReadLockGL::ScopedReadLockGL(
797 ResourceProvider* resource_provider,
798 ResourceId resource_id)
799 : resource_provider_(resource_provider),
800 resource_id_(resource_id),
801 resource_(resource_provider->LockForRead(resource_id)) {
802 DCHECK(resource_);
805 ResourceProvider::ScopedReadLockGL::~ScopedReadLockGL() {
806 resource_provider_->UnlockForRead(resource_id_);
809 ResourceProvider::ScopedSamplerGL::ScopedSamplerGL(
810 ResourceProvider* resource_provider,
811 ResourceId resource_id,
812 GLenum filter)
813 : ScopedReadLockGL(resource_provider, resource_id),
814 unit_(GL_TEXTURE0),
815 target_(resource_provider->BindForSampling(resource_id, unit_, filter)) {
818 ResourceProvider::ScopedSamplerGL::ScopedSamplerGL(
819 ResourceProvider* resource_provider,
820 ResourceId resource_id,
821 GLenum unit,
822 GLenum filter)
823 : ScopedReadLockGL(resource_provider, resource_id),
824 unit_(unit),
825 target_(resource_provider->BindForSampling(resource_id, unit_, filter)) {
828 ResourceProvider::ScopedSamplerGL::~ScopedSamplerGL() {
831 ResourceProvider::ScopedWriteLockGL::ScopedWriteLockGL(
832 ResourceProvider* resource_provider,
833 ResourceId resource_id)
834 : resource_provider_(resource_provider),
835 resource_(resource_provider->LockForWrite(resource_id)) {
836 resource_provider_->LazyAllocate(resource_);
837 texture_id_ = resource_->gl_id;
838 DCHECK(texture_id_);
841 ResourceProvider::ScopedWriteLockGL::~ScopedWriteLockGL() {
842 resource_provider_->UnlockForWrite(resource_);
845 void ResourceProvider::PopulateSkBitmapWithResource(
846 SkBitmap* sk_bitmap, const Resource* resource) {
847 DCHECK_EQ(RGBA_8888, resource->format);
848 SkImageInfo info = SkImageInfo::MakeN32Premul(resource->size.width(),
849 resource->size.height());
850 sk_bitmap->installPixels(info, resource->pixels, info.minRowBytes());
853 ResourceProvider::ScopedReadLockSoftware::ScopedReadLockSoftware(
854 ResourceProvider* resource_provider,
855 ResourceId resource_id)
856 : resource_provider_(resource_provider), resource_id_(resource_id) {
857 const Resource* resource = resource_provider->LockForRead(resource_id);
858 wrap_mode_ = resource->wrap_mode;
859 ResourceProvider::PopulateSkBitmapWithResource(&sk_bitmap_, resource);
862 ResourceProvider::ScopedReadLockSoftware::~ScopedReadLockSoftware() {
863 resource_provider_->UnlockForRead(resource_id_);
866 ResourceProvider::ScopedWriteLockSoftware::ScopedWriteLockSoftware(
867 ResourceProvider* resource_provider,
868 ResourceId resource_id)
869 : resource_provider_(resource_provider),
870 resource_(resource_provider->LockForWrite(resource_id)) {
871 ResourceProvider::PopulateSkBitmapWithResource(&sk_bitmap_, resource_);
872 DCHECK(valid());
875 ResourceProvider::ScopedWriteLockSoftware::~ScopedWriteLockSoftware() {
876 DCHECK(thread_checker_.CalledOnValidThread());
877 resource_provider_->UnlockForWrite(resource_);
880 ResourceProvider::ScopedWriteLockGpuMemoryBuffer::
881 ScopedWriteLockGpuMemoryBuffer(ResourceProvider* resource_provider,
882 ResourceId resource_id)
883 : resource_provider_(resource_provider),
884 resource_(resource_provider->LockForWrite(resource_id)),
885 gpu_memory_buffer_manager_(resource_provider->gpu_memory_buffer_manager_),
886 gpu_memory_buffer_(nullptr),
887 size_(resource_->size),
888 format_(resource_->format) {
889 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource_->type);
890 std::swap(gpu_memory_buffer_, resource_->gpu_memory_buffer);
893 ResourceProvider::ScopedWriteLockGpuMemoryBuffer::
894 ~ScopedWriteLockGpuMemoryBuffer() {
895 DCHECK(thread_checker_.CalledOnValidThread());
896 resource_provider_->UnlockForWrite(resource_);
897 if (!gpu_memory_buffer_)
898 return;
900 resource_provider_->LazyCreate(resource_);
902 if (!resource_->image_id) {
903 GLES2Interface* gl = resource_provider_->ContextGL();
904 DCHECK(gl);
906 #if defined(OS_CHROMEOS)
907 // TODO(reveman): GL_COMMANDS_ISSUED_CHROMIUM is used for synchronization
908 // on ChromeOS to avoid some performance issues. This only works with
909 // shared memory backed buffers. crbug.com/436314
910 DCHECK_EQ(gpu_memory_buffer_->GetHandle().type, gfx::SHARED_MEMORY_BUFFER);
911 #endif
913 resource_->image_id = gl->CreateImageCHROMIUM(
914 gpu_memory_buffer_->AsClientBuffer(), size_.width(), size_.height(),
915 GLInternalFormat(resource_->format));
918 std::swap(resource_->gpu_memory_buffer, gpu_memory_buffer_);
919 resource_->allocated = true;
920 resource_->dirty_image = true;
922 // GpuMemoryBuffer provides direct access to the memory used by the GPU.
923 // Read lock fences are required to ensure that we're not trying to map a
924 // buffer that is currently in-use by the GPU.
925 resource_->read_lock_fences_enabled = true;
928 gfx::GpuMemoryBuffer*
929 ResourceProvider::ScopedWriteLockGpuMemoryBuffer::GetGpuMemoryBuffer() {
930 if (gpu_memory_buffer_)
931 return gpu_memory_buffer_;
932 scoped_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer =
933 gpu_memory_buffer_manager_->AllocateGpuMemoryBuffer(
934 size_, BufferFormat(format_), gfx::BufferUsage::MAP);
935 gpu_memory_buffer_ = gpu_memory_buffer.release();
936 return gpu_memory_buffer_;
939 ResourceProvider::ScopedWriteLockGr::ScopedWriteLockGr(
940 ResourceProvider* resource_provider,
941 ResourceId resource_id)
942 : resource_provider_(resource_provider),
943 resource_(resource_provider->LockForWrite(resource_id)) {
944 DCHECK(thread_checker_.CalledOnValidThread());
945 resource_provider_->LazyAllocate(resource_);
948 ResourceProvider::ScopedWriteLockGr::~ScopedWriteLockGr() {
949 DCHECK(thread_checker_.CalledOnValidThread());
950 DCHECK(resource_->locked_for_write);
951 resource_provider_->UnlockForWrite(resource_);
954 void ResourceProvider::ScopedWriteLockGr::InitSkSurface(
955 bool use_distance_field_text,
956 bool can_use_lcd_text,
957 int msaa_sample_count) {
958 DCHECK(resource_->locked_for_write);
960 GrBackendTextureDesc desc;
961 desc.fFlags = kRenderTarget_GrBackendTextureFlag;
962 desc.fWidth = resource_->size.width();
963 desc.fHeight = resource_->size.height();
964 desc.fConfig = ToGrPixelConfig(resource_->format);
965 desc.fOrigin = kTopLeft_GrSurfaceOrigin;
966 desc.fTextureHandle = resource_->gl_id;
967 desc.fSampleCnt = msaa_sample_count;
969 bool use_worker_context = true;
970 class GrContext* gr_context =
971 resource_provider_->GrContext(use_worker_context);
972 uint32_t flags =
973 use_distance_field_text ? SkSurfaceProps::kUseDistanceFieldFonts_Flag : 0;
974 // Use unknown pixel geometry to disable LCD text.
975 SkSurfaceProps surface_props(flags, kUnknown_SkPixelGeometry);
976 if (can_use_lcd_text) {
977 // LegacyFontHost will get LCD text and skia figures out what type to use.
978 surface_props =
979 SkSurfaceProps(flags, SkSurfaceProps::kLegacyFontHost_InitType);
981 sk_surface_ = skia::AdoptRef(
982 SkSurface::NewWrappedRenderTarget(gr_context, desc, &surface_props));
985 void ResourceProvider::ScopedWriteLockGr::ReleaseSkSurface() {
986 sk_surface_.clear();
989 ResourceProvider::SynchronousFence::SynchronousFence(
990 gpu::gles2::GLES2Interface* gl)
991 : gl_(gl), has_synchronized_(true) {
994 ResourceProvider::SynchronousFence::~SynchronousFence() {
997 void ResourceProvider::SynchronousFence::Set() {
998 has_synchronized_ = false;
1001 bool ResourceProvider::SynchronousFence::HasPassed() {
1002 if (!has_synchronized_) {
1003 has_synchronized_ = true;
1004 Synchronize();
1006 return true;
1009 void ResourceProvider::SynchronousFence::Wait() {
1010 HasPassed();
1013 void ResourceProvider::SynchronousFence::Synchronize() {
1014 TRACE_EVENT0("cc", "ResourceProvider::SynchronousFence::Synchronize");
1015 gl_->Finish();
1018 ResourceProvider::ResourceProvider(
1019 OutputSurface* output_surface,
1020 SharedBitmapManager* shared_bitmap_manager,
1021 gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
1022 BlockingTaskRunner* blocking_main_thread_task_runner,
1023 int highp_threshold_min,
1024 bool use_rgba_4444_texture_format,
1025 size_t id_allocation_chunk_size,
1026 const std::vector<unsigned>& use_image_texture_targets)
1027 : output_surface_(output_surface),
1028 shared_bitmap_manager_(shared_bitmap_manager),
1029 gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
1030 blocking_main_thread_task_runner_(blocking_main_thread_task_runner),
1031 lost_output_surface_(false),
1032 highp_threshold_min_(highp_threshold_min),
1033 next_id_(1),
1034 next_child_(1),
1035 default_resource_type_(RESOURCE_TYPE_BITMAP),
1036 use_texture_storage_ext_(false),
1037 use_texture_format_bgra_(false),
1038 use_texture_usage_hint_(false),
1039 use_compressed_texture_etc1_(false),
1040 yuv_resource_format_(LUMINANCE_8),
1041 max_texture_size_(0),
1042 best_texture_format_(RGBA_8888),
1043 best_render_buffer_format_(RGBA_8888),
1044 use_rgba_4444_texture_format_(use_rgba_4444_texture_format),
1045 id_allocation_chunk_size_(id_allocation_chunk_size),
1046 use_sync_query_(false),
1047 use_image_texture_targets_(use_image_texture_targets),
1048 tracing_id_(g_next_resource_provider_tracing_id.GetNext()) {
1049 DCHECK(output_surface_->HasClient());
1050 DCHECK(id_allocation_chunk_size_);
1053 void ResourceProvider::Initialize() {
1054 DCHECK(thread_checker_.CalledOnValidThread());
1056 // In certain cases, ThreadTaskRunnerHandle isn't set (Android Webview).
1057 // Don't register a dump provider in these cases.
1058 // TODO(ericrk): Get this working in Android Webview. crbug.com/517156
1059 if (base::ThreadTaskRunnerHandle::IsSet()) {
1060 base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
1061 this, base::ThreadTaskRunnerHandle::Get());
1064 GLES2Interface* gl = ContextGL();
1065 if (!gl) {
1066 default_resource_type_ = RESOURCE_TYPE_BITMAP;
1067 // Pick an arbitrary limit here similar to what hardware might.
1068 max_texture_size_ = 16 * 1024;
1069 best_texture_format_ = RGBA_8888;
1070 return;
1073 DCHECK(!texture_id_allocator_);
1074 DCHECK(!buffer_id_allocator_);
1076 const ContextProvider::Capabilities& caps =
1077 output_surface_->context_provider()->ContextCapabilities();
1079 default_resource_type_ = RESOURCE_TYPE_GL_TEXTURE;
1080 use_texture_storage_ext_ = caps.gpu.texture_storage;
1081 use_texture_format_bgra_ = caps.gpu.texture_format_bgra8888;
1082 use_texture_usage_hint_ = caps.gpu.texture_usage;
1083 use_compressed_texture_etc1_ = caps.gpu.texture_format_etc1;
1084 yuv_resource_format_ = caps.gpu.texture_rg ? RED_8 : LUMINANCE_8;
1085 use_sync_query_ = caps.gpu.sync_query;
1087 max_texture_size_ = 0; // Context expects cleared value.
1088 gl->GetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size_);
1089 best_texture_format_ =
1090 PlatformColor::BestTextureFormat(use_texture_format_bgra_);
1092 best_render_buffer_format_ =
1093 PlatformColor::BestTextureFormat(caps.gpu.render_buffer_format_bgra8888);
1095 texture_id_allocator_.reset(
1096 new TextureIdAllocator(gl, id_allocation_chunk_size_));
1097 buffer_id_allocator_.reset(
1098 new BufferIdAllocator(gl, id_allocation_chunk_size_));
1101 int ResourceProvider::CreateChild(const ReturnCallback& return_callback) {
1102 DCHECK(thread_checker_.CalledOnValidThread());
1104 Child child_info;
1105 child_info.return_callback = return_callback;
1107 int child = next_child_++;
1108 children_[child] = child_info;
1109 return child;
1112 void ResourceProvider::SetChildNeedsSyncPoints(int child_id, bool needs) {
1113 ChildMap::iterator it = children_.find(child_id);
1114 DCHECK(it != children_.end());
1115 it->second.needs_sync_points = needs;
1118 void ResourceProvider::DestroyChild(int child_id) {
1119 ChildMap::iterator it = children_.find(child_id);
1120 DCHECK(it != children_.end());
1121 DestroyChildInternal(it, NORMAL);
1124 void ResourceProvider::DestroyChildInternal(ChildMap::iterator it,
1125 DeleteStyle style) {
1126 DCHECK(thread_checker_.CalledOnValidThread());
1128 Child& child = it->second;
1129 DCHECK(style == FOR_SHUTDOWN || !child.marked_for_deletion);
1131 ResourceIdArray resources_for_child;
1133 for (ResourceIdMap::iterator child_it = child.child_to_parent_map.begin();
1134 child_it != child.child_to_parent_map.end();
1135 ++child_it) {
1136 ResourceId id = child_it->second;
1137 resources_for_child.push_back(id);
1140 child.marked_for_deletion = true;
1142 DeleteAndReturnUnusedResourcesToChild(it, style, resources_for_child);
1145 const ResourceProvider::ResourceIdMap& ResourceProvider::GetChildToParentMap(
1146 int child) const {
1147 DCHECK(thread_checker_.CalledOnValidThread());
1148 ChildMap::const_iterator it = children_.find(child);
1149 DCHECK(it != children_.end());
1150 DCHECK(!it->second.marked_for_deletion);
1151 return it->second.child_to_parent_map;
1154 void ResourceProvider::PrepareSendToParent(const ResourceIdArray& resources,
1155 TransferableResourceArray* list) {
1156 DCHECK(thread_checker_.CalledOnValidThread());
1157 GLES2Interface* gl = ContextGL();
1158 bool need_sync_point = false;
1159 for (ResourceIdArray::const_iterator it = resources.begin();
1160 it != resources.end();
1161 ++it) {
1162 TransferableResource resource;
1163 TransferResource(gl, *it, &resource);
1164 if (!resource.mailbox_holder.sync_point && !resource.is_software)
1165 need_sync_point = true;
1166 ++resources_.find(*it)->second.exported_count;
1167 list->push_back(resource);
1169 if (need_sync_point &&
1170 output_surface_->capabilities().delegated_sync_points_required) {
1171 GLuint sync_point = gl->InsertSyncPointCHROMIUM();
1172 for (TransferableResourceArray::iterator it = list->begin();
1173 it != list->end();
1174 ++it) {
1175 if (!it->mailbox_holder.sync_point)
1176 it->mailbox_holder.sync_point = sync_point;
1181 void ResourceProvider::ReceiveFromChild(
1182 int child, const TransferableResourceArray& resources) {
1183 DCHECK(thread_checker_.CalledOnValidThread());
1184 GLES2Interface* gl = ContextGL();
1185 Child& child_info = children_.find(child)->second;
1186 DCHECK(!child_info.marked_for_deletion);
1187 for (TransferableResourceArray::const_iterator it = resources.begin();
1188 it != resources.end();
1189 ++it) {
1190 ResourceIdMap::iterator resource_in_map_it =
1191 child_info.child_to_parent_map.find(it->id);
1192 if (resource_in_map_it != child_info.child_to_parent_map.end()) {
1193 Resource* resource = GetResource(resource_in_map_it->second);
1194 resource->marked_for_deletion = false;
1195 resource->imported_count++;
1196 continue;
1199 if ((!it->is_software && !gl) ||
1200 (it->is_software && !shared_bitmap_manager_)) {
1201 TRACE_EVENT0("cc", "ResourceProvider::ReceiveFromChild dropping invalid");
1202 ReturnedResourceArray to_return;
1203 to_return.push_back(it->ToReturnedResource());
1204 child_info.return_callback.Run(to_return,
1205 blocking_main_thread_task_runner_);
1206 continue;
1209 ResourceId local_id = next_id_++;
1210 Resource* resource = nullptr;
1211 if (it->is_software) {
1212 resource = InsertResource(
1213 local_id,
1214 Resource(it->mailbox_holder.mailbox, it->size, Resource::DELEGATED,
1215 GL_LINEAR, it->is_repeated ? GL_REPEAT : GL_CLAMP_TO_EDGE));
1216 } else {
1217 resource = InsertResource(
1218 local_id, Resource(0, it->size, Resource::DELEGATED,
1219 it->mailbox_holder.texture_target, it->filter, 0,
1220 it->is_repeated ? GL_REPEAT : GL_CLAMP_TO_EDGE,
1221 TEXTURE_HINT_IMMUTABLE, it->format));
1222 resource->mailbox = TextureMailbox(it->mailbox_holder.mailbox,
1223 it->mailbox_holder.texture_target,
1224 it->mailbox_holder.sync_point);
1225 resource->read_lock_fences_enabled = it->read_lock_fences_enabled;
1227 resource->child_id = child;
1228 // Don't allocate a texture for a child.
1229 resource->allocated = true;
1230 resource->imported_count = 1;
1231 child_info.parent_to_child_map[local_id] = it->id;
1232 child_info.child_to_parent_map[it->id] = local_id;
1236 void ResourceProvider::DeclareUsedResourcesFromChild(
1237 int child,
1238 const ResourceIdSet& resources_from_child) {
1239 DCHECK(thread_checker_.CalledOnValidThread());
1241 ChildMap::iterator child_it = children_.find(child);
1242 DCHECK(child_it != children_.end());
1243 Child& child_info = child_it->second;
1244 DCHECK(!child_info.marked_for_deletion);
1246 ResourceIdArray unused;
1247 for (ResourceIdMap::iterator it = child_info.child_to_parent_map.begin();
1248 it != child_info.child_to_parent_map.end();
1249 ++it) {
1250 ResourceId local_id = it->second;
1251 bool resource_is_in_use = resources_from_child.count(it->first) > 0;
1252 if (!resource_is_in_use)
1253 unused.push_back(local_id);
1255 DeleteAndReturnUnusedResourcesToChild(child_it, NORMAL, unused);
1258 void ResourceProvider::ReceiveReturnsFromParent(
1259 const ReturnedResourceArray& resources) {
1260 DCHECK(thread_checker_.CalledOnValidThread());
1261 GLES2Interface* gl = ContextGL();
1263 base::hash_map<int, ResourceIdArray> resources_for_child;
1265 for (const ReturnedResource& returned : resources) {
1266 ResourceId local_id = returned.id;
1267 ResourceMap::iterator map_iterator = resources_.find(local_id);
1268 // Resource was already lost (e.g. it belonged to a child that was
1269 // destroyed).
1270 if (map_iterator == resources_.end())
1271 continue;
1273 Resource* resource = &map_iterator->second;
1275 CHECK_GE(resource->exported_count, returned.count);
1276 resource->exported_count -= returned.count;
1277 resource->lost |= returned.lost;
1278 if (resource->exported_count)
1279 continue;
1281 if (returned.sync_point) {
1282 DCHECK(!resource->has_shared_bitmap_id);
1283 if (resource->origin == Resource::INTERNAL) {
1284 DCHECK(resource->gl_id);
1285 gl->WaitSyncPointCHROMIUM(returned.sync_point);
1286 } else {
1287 DCHECK(!resource->gl_id);
1288 resource->mailbox.set_sync_point(returned.sync_point);
1292 if (!resource->marked_for_deletion)
1293 continue;
1295 if (!resource->child_id) {
1296 // The resource belongs to this ResourceProvider, so it can be destroyed.
1297 DeleteResourceInternal(map_iterator, NORMAL);
1298 continue;
1301 DCHECK(resource->origin == Resource::DELEGATED);
1302 resources_for_child[resource->child_id].push_back(local_id);
1305 for (const auto& children : resources_for_child) {
1306 ChildMap::iterator child_it = children_.find(children.first);
1307 DCHECK(child_it != children_.end());
1308 DeleteAndReturnUnusedResourcesToChild(child_it, NORMAL, children.second);
1312 void ResourceProvider::TransferResource(GLES2Interface* gl,
1313 ResourceId id,
1314 TransferableResource* resource) {
1315 Resource* source = GetResource(id);
1316 DCHECK(!source->locked_for_write);
1317 DCHECK(!source->lock_for_read_count);
1318 DCHECK(source->origin != Resource::EXTERNAL || source->mailbox.IsValid());
1319 DCHECK(source->allocated);
1320 resource->id = id;
1321 resource->format = source->format;
1322 resource->mailbox_holder.texture_target = source->target;
1323 resource->filter = source->filter;
1324 resource->size = source->size;
1325 resource->read_lock_fences_enabled = source->read_lock_fences_enabled;
1326 resource->is_repeated = (source->wrap_mode == GL_REPEAT);
1328 if (source->type == RESOURCE_TYPE_BITMAP) {
1329 resource->mailbox_holder.mailbox = source->shared_bitmap_id;
1330 resource->is_software = true;
1331 } else if (!source->mailbox.IsValid()) {
1332 LazyCreate(source);
1333 DCHECK(source->gl_id);
1334 DCHECK(source->origin == Resource::INTERNAL);
1335 if (source->image_id) {
1336 DCHECK(source->dirty_image);
1337 gl->BindTexture(resource->mailbox_holder.texture_target, source->gl_id);
1338 BindImageForSampling(source);
1340 // This is a resource allocated by the compositor, we need to produce it.
1341 // Don't set a sync point, the caller will do it.
1342 gl->GenMailboxCHROMIUM(resource->mailbox_holder.mailbox.name);
1343 gl->ProduceTextureDirectCHROMIUM(source->gl_id,
1344 resource->mailbox_holder.texture_target,
1345 resource->mailbox_holder.mailbox.name);
1347 source->mailbox = TextureMailbox(resource->mailbox_holder);
1348 } else {
1349 DCHECK(source->mailbox.IsTexture());
1350 if (source->image_id && source->dirty_image) {
1351 DCHECK(source->gl_id);
1352 DCHECK(source->origin == Resource::INTERNAL);
1353 gl->BindTexture(resource->mailbox_holder.texture_target, source->gl_id);
1354 BindImageForSampling(source);
1356 // This is either an external resource, or a compositor resource that we
1357 // already exported. Make sure to forward the sync point that we were given.
1358 resource->mailbox_holder.mailbox = source->mailbox.mailbox();
1359 resource->mailbox_holder.texture_target = source->mailbox.target();
1360 resource->mailbox_holder.sync_point = source->mailbox.sync_point();
1361 source->mailbox.set_sync_point(0);
1365 void ResourceProvider::DeleteAndReturnUnusedResourcesToChild(
1366 ChildMap::iterator child_it,
1367 DeleteStyle style,
1368 const ResourceIdArray& unused) {
1369 DCHECK(thread_checker_.CalledOnValidThread());
1370 DCHECK(child_it != children_.end());
1371 Child* child_info = &child_it->second;
1373 if (unused.empty() && !child_info->marked_for_deletion)
1374 return;
1376 ReturnedResourceArray to_return;
1378 GLES2Interface* gl = ContextGL();
1379 bool need_sync_point = false;
1380 for (size_t i = 0; i < unused.size(); ++i) {
1381 ResourceId local_id = unused[i];
1383 ResourceMap::iterator it = resources_.find(local_id);
1384 CHECK(it != resources_.end());
1385 Resource& resource = it->second;
1387 DCHECK(!resource.locked_for_write);
1388 DCHECK(child_info->parent_to_child_map.count(local_id));
1390 ResourceId child_id = child_info->parent_to_child_map[local_id];
1391 DCHECK(child_info->child_to_parent_map.count(child_id));
1393 bool is_lost =
1394 resource.lost ||
1395 (resource.type == RESOURCE_TYPE_GL_TEXTURE && lost_output_surface_);
1396 if (resource.exported_count > 0 || resource.lock_for_read_count > 0) {
1397 if (style != FOR_SHUTDOWN) {
1398 // Defer this resource deletion.
1399 resource.marked_for_deletion = true;
1400 continue;
1402 // We can't postpone the deletion, so we'll have to lose it.
1403 is_lost = true;
1404 } else if (!ReadLockFenceHasPassed(&resource)) {
1405 // TODO(dcastagna): see if it's possible to use this logic for
1406 // the branch above too, where the resource is locked or still exported.
1407 if (style != FOR_SHUTDOWN && !child_info->marked_for_deletion) {
1408 // Defer this resource deletion.
1409 resource.marked_for_deletion = true;
1410 continue;
1412 // We can't postpone the deletion, so we'll have to lose it.
1413 is_lost = true;
1416 if (gl && resource.filter != resource.original_filter) {
1417 DCHECK(resource.target);
1418 DCHECK(resource.gl_id);
1420 gl->BindTexture(resource.target, resource.gl_id);
1421 gl->TexParameteri(resource.target, GL_TEXTURE_MIN_FILTER,
1422 resource.original_filter);
1423 gl->TexParameteri(resource.target, GL_TEXTURE_MAG_FILTER,
1424 resource.original_filter);
1427 ReturnedResource returned;
1428 returned.id = child_id;
1429 returned.sync_point = resource.mailbox.sync_point();
1430 if (!returned.sync_point && resource.type == RESOURCE_TYPE_GL_TEXTURE)
1431 need_sync_point = true;
1432 returned.count = resource.imported_count;
1433 returned.lost = is_lost;
1434 to_return.push_back(returned);
1436 child_info->parent_to_child_map.erase(local_id);
1437 child_info->child_to_parent_map.erase(child_id);
1438 resource.imported_count = 0;
1439 DeleteResourceInternal(it, style);
1441 if (need_sync_point && child_info->needs_sync_points) {
1442 DCHECK(gl);
1443 GLuint sync_point = gl->InsertSyncPointCHROMIUM();
1444 for (size_t i = 0; i < to_return.size(); ++i) {
1445 if (!to_return[i].sync_point)
1446 to_return[i].sync_point = sync_point;
1450 if (!to_return.empty())
1451 child_info->return_callback.Run(to_return,
1452 blocking_main_thread_task_runner_);
1454 if (child_info->marked_for_deletion &&
1455 child_info->parent_to_child_map.empty()) {
1456 DCHECK(child_info->child_to_parent_map.empty());
1457 children_.erase(child_it);
1461 GLenum ResourceProvider::BindForSampling(ResourceId resource_id,
1462 GLenum unit,
1463 GLenum filter) {
1464 DCHECK(thread_checker_.CalledOnValidThread());
1465 GLES2Interface* gl = ContextGL();
1466 ResourceMap::iterator it = resources_.find(resource_id);
1467 DCHECK(it != resources_.end());
1468 Resource* resource = &it->second;
1469 DCHECK(resource->lock_for_read_count);
1470 DCHECK(!resource->locked_for_write);
1472 ScopedSetActiveTexture scoped_active_tex(gl, unit);
1473 GLenum target = resource->target;
1474 gl->BindTexture(target, resource->gl_id);
1475 if (filter != resource->filter) {
1476 gl->TexParameteri(target, GL_TEXTURE_MIN_FILTER, filter);
1477 gl->TexParameteri(target, GL_TEXTURE_MAG_FILTER, filter);
1478 resource->filter = filter;
1481 if (resource->image_id && resource->dirty_image)
1482 BindImageForSampling(resource);
1484 return target;
1487 void ResourceProvider::CreateForTesting(ResourceId id) {
1488 LazyCreate(GetResource(id));
1491 GLenum ResourceProvider::TargetForTesting(ResourceId id) {
1492 Resource* resource = GetResource(id);
1493 return resource->target;
1496 void ResourceProvider::LazyCreate(Resource* resource) {
1497 if (resource->type != RESOURCE_TYPE_GL_TEXTURE ||
1498 resource->origin != Resource::INTERNAL)
1499 return;
1501 if (resource->gl_id)
1502 return;
1504 DCHECK(resource->texture_pool);
1505 DCHECK(resource->origin == Resource::INTERNAL);
1506 DCHECK(!resource->mailbox.IsValid());
1507 resource->gl_id = texture_id_allocator_->NextId();
1509 GLES2Interface* gl = ContextGL();
1510 DCHECK(gl);
1512 // Create and set texture properties. Allocation is delayed until needed.
1513 gl->BindTexture(resource->target, resource->gl_id);
1514 gl->TexParameteri(resource->target, GL_TEXTURE_MIN_FILTER,
1515 resource->original_filter);
1516 gl->TexParameteri(resource->target, GL_TEXTURE_MAG_FILTER,
1517 resource->original_filter);
1518 gl->TexParameteri(resource->target, GL_TEXTURE_WRAP_S, resource->wrap_mode);
1519 gl->TexParameteri(resource->target, GL_TEXTURE_WRAP_T, resource->wrap_mode);
1520 gl->TexParameteri(resource->target, GL_TEXTURE_POOL_CHROMIUM,
1521 resource->texture_pool);
1522 if (use_texture_usage_hint_ && (resource->hint & TEXTURE_HINT_FRAMEBUFFER)) {
1523 gl->TexParameteri(resource->target, GL_TEXTURE_USAGE_ANGLE,
1524 GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
1528 void ResourceProvider::AllocateForTesting(ResourceId id) {
1529 LazyAllocate(GetResource(id));
1532 void ResourceProvider::LazyAllocate(Resource* resource) {
1533 DCHECK(resource);
1534 if (resource->allocated)
1535 return;
1536 LazyCreate(resource);
1537 if (!resource->gl_id)
1538 return;
1539 resource->allocated = true;
1540 GLES2Interface* gl = ContextGL();
1541 gfx::Size& size = resource->size;
1542 ResourceFormat format = resource->format;
1543 gl->BindTexture(resource->target, resource->gl_id);
1544 if (use_texture_storage_ext_ &&
1545 IsFormatSupportedForStorage(format, use_texture_format_bgra_) &&
1546 (resource->hint & TEXTURE_HINT_IMMUTABLE)) {
1547 GLenum storage_format = TextureToStorageFormat(format);
1548 gl->TexStorage2DEXT(resource->target, 1, storage_format, size.width(),
1549 size.height());
1550 } else {
1551 // ETC1 does not support preallocation.
1552 if (format != ETC1) {
1553 gl->TexImage2D(resource->target, 0, GLInternalFormat(format),
1554 size.width(), size.height(), 0, GLDataFormat(format),
1555 GLDataType(format), NULL);
1560 void ResourceProvider::BindImageForSampling(Resource* resource) {
1561 GLES2Interface* gl = ContextGL();
1562 DCHECK(resource->gl_id);
1563 DCHECK(resource->image_id);
1565 // Release image currently bound to texture.
1566 if (resource->bound_image_id)
1567 gl->ReleaseTexImage2DCHROMIUM(resource->target, resource->bound_image_id);
1568 gl->BindTexImage2DCHROMIUM(resource->target, resource->image_id);
1569 resource->bound_image_id = resource->image_id;
1570 resource->dirty_image = false;
1573 void ResourceProvider::WaitSyncPointIfNeeded(ResourceId id) {
1574 Resource* resource = GetResource(id);
1575 DCHECK_EQ(resource->exported_count, 0);
1576 DCHECK(resource->allocated);
1577 if (resource->type != RESOURCE_TYPE_GL_TEXTURE || resource->gl_id)
1578 return;
1579 if (!resource->mailbox.sync_point())
1580 return;
1581 DCHECK(resource->mailbox.IsValid());
1582 GLES2Interface* gl = ContextGL();
1583 DCHECK(gl);
1584 gl->WaitSyncPointCHROMIUM(resource->mailbox.sync_point());
1585 resource->mailbox.set_sync_point(0);
1588 GLint ResourceProvider::GetActiveTextureUnit(GLES2Interface* gl) {
1589 GLint active_unit = 0;
1590 gl->GetIntegerv(GL_ACTIVE_TEXTURE, &active_unit);
1591 return active_unit;
1594 GLenum ResourceProvider::GetImageTextureTarget(ResourceFormat format) {
1595 gfx::BufferFormat buffer_format = BufferFormat(format);
1596 DCHECK_GT(use_image_texture_targets_.size(),
1597 static_cast<size_t>(buffer_format));
1598 return use_image_texture_targets_[static_cast<size_t>(buffer_format)];
1601 void ResourceProvider::ValidateResource(ResourceId id) const {
1602 DCHECK(thread_checker_.CalledOnValidThread());
1603 DCHECK(id);
1604 DCHECK(resources_.find(id) != resources_.end());
1607 GLES2Interface* ResourceProvider::ContextGL() const {
1608 ContextProvider* context_provider = output_surface_->context_provider();
1609 return context_provider ? context_provider->ContextGL() : NULL;
1612 class GrContext* ResourceProvider::GrContext(bool worker_context) const {
1613 ContextProvider* context_provider =
1614 worker_context ? output_surface_->worker_context_provider()
1615 : output_surface_->context_provider();
1616 return context_provider ? context_provider->GrContext() : NULL;
1619 bool ResourceProvider::OnMemoryDump(
1620 const base::trace_event::MemoryDumpArgs& args,
1621 base::trace_event::ProcessMemoryDump* pmd) {
1622 DCHECK(thread_checker_.CalledOnValidThread());
1624 const uint64 tracing_process_id =
1625 base::trace_event::MemoryDumpManager::GetInstance()
1626 ->GetTracingProcessId();
1628 for (const auto& resource_entry : resources_) {
1629 const auto& resource = resource_entry.second;
1631 // Resource IDs are not process-unique, so log with the ResourceProvider's
1632 // unique id.
1633 std::string dump_name =
1634 base::StringPrintf("cc/resource_memory/provider_%d/resource_%d",
1635 tracing_id_, resource_entry.first);
1636 base::trace_event::MemoryAllocatorDump* dump =
1637 pmd->CreateAllocatorDump(dump_name);
1639 uint64_t total_bytes = ResourceUtil::UncheckedSizeInBytesAligned<size_t>(
1640 resource.size, resource.format);
1641 dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
1642 base::trace_event::MemoryAllocatorDump::kUnitsBytes,
1643 static_cast<uint64_t>(total_bytes));
1645 // Resources which are shared across processes require a shared GUID to
1646 // prevent double counting the memory. We currently support shared GUIDs for
1647 // GpuMemoryBuffer, SharedBitmap, and GL backed resources.
1648 base::trace_event::MemoryAllocatorDumpGuid guid;
1649 if (resource.gpu_memory_buffer) {
1650 guid = gfx::GetGpuMemoryBufferGUIDForTracing(
1651 tracing_process_id, resource.gpu_memory_buffer->GetHandle().id);
1652 } else if (resource.shared_bitmap) {
1653 guid = GetSharedBitmapGUIDForTracing(resource.shared_bitmap->id());
1654 } else if (resource.gl_id && resource.allocated) {
1655 guid =
1656 gfx::GetGLTextureGUIDForTracing(tracing_process_id, resource.gl_id);
1659 if (!guid.empty()) {
1660 const int kImportance = 2;
1661 pmd->CreateSharedGlobalAllocatorDump(guid);
1662 pmd->AddOwnershipEdge(dump->guid(), guid, kImportance);
1666 return true;
1669 } // namespace cc