Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / cc / resources / resource_provider.cc
blobb73dfe23101fd3e453e92d471f8b6c450de0ced5
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/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;
41 namespace cc {
43 class IdAllocator {
44 public:
45 virtual ~IdAllocator() {}
47 virtual GLuint NextId() = 0;
49 protected:
50 IdAllocator(GLES2Interface* gl, size_t id_allocation_chunk_size)
51 : gl_(gl),
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()));
60 GLES2Interface* gl_;
61 const size_t id_allocation_chunk_size_;
62 scoped_ptr<GLuint[]> ids_;
63 size_t next_id_index_;
66 namespace {
68 GLenum TextureToStorageFormat(ResourceFormat format) {
69 GLenum storage_format = GL_RGBA8_OES;
70 switch (format) {
71 case RGBA_8888:
72 break;
73 case BGRA_8888:
74 storage_format = GL_BGRA8_EXT;
75 break;
76 case RGBA_4444:
77 case ALPHA_8:
78 case LUMINANCE_8:
79 case RGB_565:
80 case ETC1:
81 case RED_8:
82 NOTREACHED();
83 break;
86 return storage_format;
89 bool IsFormatSupportedForStorage(ResourceFormat format, bool use_bgra) {
90 switch (format) {
91 case RGBA_8888:
92 return true;
93 case BGRA_8888:
94 return use_bgra;
95 case RGBA_4444:
96 case ALPHA_8:
97 case LUMINANCE_8:
98 case RGB_565:
99 case ETC1:
100 case RED_8:
101 return false;
103 return false;
106 GrPixelConfig ToGrPixelConfig(ResourceFormat format) {
107 switch (format) {
108 case RGBA_8888:
109 return kRGBA_8888_GrPixelConfig;
110 case BGRA_8888:
111 return kBGRA_8888_GrPixelConfig;
112 case RGBA_4444:
113 return kRGBA_4444_GrPixelConfig;
114 default:
115 break;
117 DCHECK(false) << "Unsupported resource format.";
118 return kSkia8888_GrPixelConfig;
121 class ScopedSetActiveTexture {
122 public:
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);
137 private:
138 GLES2Interface* gl_;
139 GLenum unit_;
142 class TextureIdAllocator : public IdAllocator {
143 public:
144 TextureIdAllocator(GLES2Interface* gl,
145 size_t texture_id_allocation_chunk_size)
146 : IdAllocator(gl, texture_id_allocation_chunk_size) {}
147 ~TextureIdAllocator() override {
148 gl_->DeleteTextures(
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());
157 next_id_index_ = 0;
160 return ids_[next_id_index_++];
163 private:
164 DISALLOW_COPY_AND_ASSIGN(TextureIdAllocator);
167 class BufferIdAllocator : public IdAllocator {
168 public:
169 BufferIdAllocator(GLES2Interface* gl, size_t buffer_id_allocation_chunk_size)
170 : IdAllocator(gl, buffer_id_allocation_chunk_size) {}
171 ~BufferIdAllocator() override {
172 gl_->DeleteBuffers(
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());
181 next_id_index_ = 0;
184 return ids_[next_id_index_++];
187 private:
188 DISALLOW_COPY_AND_ASSIGN(BufferIdAllocator);
191 // Generates process-unique IDs to use for tracing a ResourceProvider's
192 // resources.
193 base::StaticAtomicSequenceNumber g_next_resource_provider_tracing_id;
195 } // namespace
197 ResourceProvider::Resource::~Resource() {}
199 ResourceProvider::Resource::Resource(GLuint texture_id,
200 const gfx::Size& size,
201 Origin origin,
202 GLenum target,
203 GLenum filter,
204 GLenum texture_pool,
205 GLint wrap_mode,
206 TextureHint hint,
207 ResourceFormat format)
208 : child_id(0),
209 gl_id(texture_id),
210 gl_pixel_buffer_id(0),
211 gl_upload_query_id(0),
212 gl_read_lock_query_id(0),
213 pixels(NULL),
214 lock_for_read_count(0),
215 imported_count(0),
216 exported_count(0),
217 dirty_image(false),
218 locked_for_write(false),
219 lost(false),
220 marked_for_deletion(false),
221 allocated(false),
222 read_lock_fences_enabled(false),
223 has_shared_bitmap_id(false),
224 read_lock_fence(NULL),
225 size(size),
226 origin(origin),
227 target(target),
228 original_filter(filter),
229 filter(filter),
230 image_id(0),
231 bound_image_id(0),
232 texture_pool(texture_pool),
233 wrap_mode(wrap_mode),
234 hint(hint),
235 type(RESOURCE_TYPE_GL_TEXTURE),
236 format(format),
237 shared_bitmap(NULL),
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,
246 Origin origin,
247 GLenum filter,
248 GLint wrap_mode)
249 : child_id(0),
250 gl_id(0),
251 gl_pixel_buffer_id(0),
252 gl_upload_query_id(0),
253 gl_read_lock_query_id(0),
254 pixels(pixels),
255 lock_for_read_count(0),
256 imported_count(0),
257 exported_count(0),
258 dirty_image(false),
259 locked_for_write(false),
260 lost(false),
261 marked_for_deletion(false),
262 allocated(false),
263 read_lock_fences_enabled(false),
264 has_shared_bitmap_id(!!bitmap),
265 read_lock_fence(NULL),
266 size(size),
267 origin(origin),
268 target(0),
269 original_filter(filter),
270 filter(filter),
271 image_id(0),
272 bound_image_id(0),
273 texture_pool(0),
274 wrap_mode(wrap_mode),
275 hint(TEXTURE_HINT_IMMUTABLE),
276 type(RESOURCE_TYPE_BITMAP),
277 format(RGBA_8888),
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);
282 if (bitmap)
283 shared_bitmap_id = bitmap->id();
286 ResourceProvider::Resource::Resource(const SharedBitmapId& bitmap_id,
287 const gfx::Size& size,
288 Origin origin,
289 GLenum filter,
290 GLint wrap_mode)
291 : child_id(0),
292 gl_id(0),
293 gl_pixel_buffer_id(0),
294 gl_upload_query_id(0),
295 gl_read_lock_query_id(0),
296 pixels(NULL),
297 lock_for_read_count(0),
298 imported_count(0),
299 exported_count(0),
300 dirty_image(false),
301 locked_for_write(false),
302 lost(false),
303 marked_for_deletion(false),
304 allocated(false),
305 read_lock_fences_enabled(false),
306 has_shared_bitmap_id(true),
307 read_lock_fence(NULL),
308 size(size),
309 origin(origin),
310 target(0),
311 original_filter(filter),
312 filter(filter),
313 image_id(0),
314 bound_image_id(0),
315 texture_pool(0),
316 wrap_mode(wrap_mode),
317 hint(TEXTURE_HINT_IMMUTABLE),
318 type(RESOURCE_TYPE_BITMAP),
319 format(RGBA_8888),
320 shared_bitmap_id(bitmap_id),
321 shared_bitmap(NULL),
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(
352 this);
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.
362 DCHECK(!gl);
363 return;
366 DCHECK(gl);
367 #if DCHECK_IS_ON()
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;
377 gl->Finish();
380 bool ResourceProvider::InUseByConsumer(ResourceId id) {
381 Resource* resource = GetResource(id);
382 return resource->lock_for_read_count > 0 || resource->exported_count > 0 ||
383 resource->lost;
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);
393 DCHECK(resource);
394 resource->lost = true;
397 ResourceId ResourceProvider::CreateResource(const gfx::Size& size,
398 GLint wrap_mode,
399 TextureHint hint,
400 ResourceFormat format) {
401 DCHECK(!size.IsEmpty());
402 switch (default_resource_type_) {
403 case RESOURCE_TYPE_GL_TEXTURE:
404 return CreateGLTexture(size,
405 GL_TEXTURE_2D,
406 GL_TEXTURE_POOL_UNMANAGED_CHROMIUM,
407 wrap_mode,
408 hint,
409 format);
410 case RESOURCE_TYPE_BITMAP:
411 DCHECK_EQ(RGBA_8888, format);
412 return CreateBitmap(size, wrap_mode);
415 LOG(FATAL) << "Invalid default resource type.";
416 return 0;
419 ResourceId ResourceProvider::CreateManagedResource(const gfx::Size& size,
420 GLenum target,
421 GLint wrap_mode,
422 TextureHint hint,
423 ResourceFormat format) {
424 DCHECK(!size.IsEmpty());
425 switch (default_resource_type_) {
426 case RESOURCE_TYPE_GL_TEXTURE:
427 return CreateGLTexture(size,
428 target,
429 GL_TEXTURE_POOL_MANAGED_CHROMIUM,
430 wrap_mode,
431 hint,
432 format);
433 case RESOURCE_TYPE_BITMAP:
434 DCHECK_EQ(RGBA_8888, format);
435 return CreateBitmap(size, wrap_mode);
438 LOG(FATAL) << "Invalid default resource type.";
439 return 0;
442 ResourceId ResourceProvider::CreateGLTexture(const gfx::Size& size,
443 GLenum target,
444 GLenum texture_pool,
445 GLint wrap_mode,
446 TextureHint hint,
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;
457 return id;
460 ResourceId ResourceProvider::CreateBitmap(const gfx::Size& size,
461 GLint wrap_mode) {
462 DCHECK(thread_checker_.CalledOnValidThread());
464 scoped_ptr<SharedBitmap> bitmap =
465 shared_bitmap_manager_->AllocateSharedBitmap(size);
466 uint8_t* pixels = bitmap->pixels();
467 DCHECK(pixels);
469 ResourceId id = next_id_++;
470 Resource* resource =
471 InsertResource(id, Resource(pixels, bitmap.release(), size,
472 Resource::INTERNAL, GL_LINEAR, wrap_mode));
473 resource->allocated = true;
474 return id;
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();
489 DCHECK(gl);
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;
494 return id;
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));
511 } else {
512 DCHECK(mailbox.IsSharedMemory());
513 SharedBitmap* shared_bitmap = mailbox.shared_bitmap();
514 uint8_t* pixels = shared_bitmap->pixels();
515 DCHECK(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;
526 return id;
529 ResourceId ResourceProvider::CreateResourceFromTextureMailbox(
530 const TextureMailbox& mailbox,
531 scoped_ptr<SingleReleaseCallbackImpl> release_callback_impl) {
532 return CreateResourceFromTextureMailbox(mailbox, release_callback_impl.Pass(),
533 false);
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;
548 return;
549 } else {
550 DeleteResourceInternal(it, NORMAL);
554 void ResourceProvider::DeleteResourceInternal(ResourceMap::iterator it,
555 DeleteStyle style) {
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();
567 DCHECK(gl);
568 gl->DestroyImageCHROMIUM(resource->image_id);
570 if (resource->gl_upload_query_id) {
571 DCHECK(resource->origin == Resource::INTERNAL);
572 GLES2Interface* gl = ContextGL();
573 DCHECK(gl);
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();
579 DCHECK(gl);
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();
585 DCHECK(gl);
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();
595 DCHECK(gl);
596 if (resource->gl_id) {
597 gl->DeleteTextures(1, &resource->gl_id);
598 resource->gl_id = 0;
599 if (!lost_resource)
600 sync_point = gl->InsertSyncPointCHROMIUM();
602 } else {
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();
612 DCHECK(gl);
613 gl->DeleteTextures(1, &resource->gl_id);
614 resource->gl_id = 0;
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(
636 ResourceId id) {
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);
665 } else {
666 DCHECK(resource->gl_id);
667 DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D));
668 GLES2Interface* gl = ContextGL();
669 DCHECK(gl);
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,
676 image_bytes, image);
677 } else {
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(
686 ResourceId id,
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());
696 DCHECK(id);
697 ResourceMap::iterator it = resources_.find(id);
698 DCHECK(it != resources_.end());
699 return &it->second;
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();
721 DCHECK(gl);
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);
731 if (bitmap) {
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_;
744 return resource;
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);
760 } else {
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;
774 return resource;
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);
793 DCHECK(resource);
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)) {
803 DCHECK(resource_);
806 ResourceProvider::ScopedReadLockGL::~ScopedReadLockGL() {
807 resource_provider_->UnlockForRead(resource_id_);
810 ResourceProvider::ScopedSamplerGL::ScopedSamplerGL(
811 ResourceProvider* resource_provider,
812 ResourceId resource_id,
813 GLenum filter)
814 : ScopedReadLockGL(resource_provider, resource_id),
815 unit_(GL_TEXTURE0),
816 target_(resource_provider->BindForSampling(resource_id, unit_, filter)) {
819 ResourceProvider::ScopedSamplerGL::ScopedSamplerGL(
820 ResourceProvider* resource_provider,
821 ResourceId resource_id,
822 GLenum unit,
823 GLenum filter)
824 : ScopedReadLockGL(resource_provider, resource_id),
825 unit_(unit),
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;
839 DCHECK(texture_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_);
873 DCHECK(valid());
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_)
899 return;
901 resource_provider_->LazyCreate(resource_);
903 if (!resource_->image_id) {
904 GLES2Interface* gl = resource_provider_->ContextGL();
905 DCHECK(gl);
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);
912 #endif
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);
973 uint32_t flags =
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.
979 surface_props =
980 SkSurfaceProps(flags, SkSurfaceProps::kLegacyFontHost_InitType);
982 sk_surface_ = skia::AdoptRef(
983 SkSurface::NewWrappedRenderTarget(gr_context, desc, &surface_props));
986 void ResourceProvider::ScopedWriteLockGr::ReleaseSkSurface() {
987 sk_surface_.clear();
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;
1005 Synchronize();
1007 return true;
1010 void ResourceProvider::SynchronousFence::Wait() {
1011 HasPassed();
1014 void ResourceProvider::SynchronousFence::Synchronize() {
1015 TRACE_EVENT0("cc", "ResourceProvider::SynchronousFence::Synchronize");
1016 gl_->Finish();
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),
1034 next_id_(1),
1035 next_child_(1),
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();
1066 if (!gl) {
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;
1071 return;
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());
1105 Child child_info;
1106 child_info.return_callback = return_callback;
1108 int child = next_child_++;
1109 children_[child] = child_info;
1110 return child;
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();
1136 ++child_it) {
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(
1147 int child) const {
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();
1162 ++it) {
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();
1174 it != list->end();
1175 ++it) {
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();
1190 ++it) {
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++;
1197 continue;
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_);
1207 continue;
1210 ResourceId local_id = next_id_++;
1211 Resource* resource = nullptr;
1212 if (it->is_software) {
1213 resource = InsertResource(
1214 local_id,
1215 Resource(it->mailbox_holder.mailbox, it->size, Resource::DELEGATED,
1216 GL_LINEAR, it->is_repeated ? GL_REPEAT : GL_CLAMP_TO_EDGE));
1217 } else {
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(
1238 int child,
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();
1250 ++it) {
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
1270 // destroyed).
1271 if (map_iterator == resources_.end())
1272 continue;
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)
1280 continue;
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);
1287 } else {
1288 DCHECK(!resource->gl_id);
1289 resource->mailbox.set_sync_point(returned.sync_point);
1293 if (!resource->marked_for_deletion)
1294 continue;
1296 if (!resource->child_id) {
1297 // The resource belongs to this ResourceProvider, so it can be destroyed.
1298 DeleteResourceInternal(map_iterator, NORMAL);
1299 continue;
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,
1314 ResourceId id,
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);
1321 resource->id = id;
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()) {
1333 LazyCreate(source);
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);
1349 } else {
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,
1368 DeleteStyle style,
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)
1375 return;
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));
1394 bool is_lost =
1395 resource.lost ||
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;
1401 continue;
1403 // We can't postpone the deletion, so we'll have to lose it.
1404 is_lost = true;
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;
1411 continue;
1413 // We can't postpone the deletion, so we'll have to lose it.
1414 is_lost = true;
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) {
1443 DCHECK(gl);
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,
1463 GLenum unit,
1464 GLenum filter) {
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);
1485 return target;
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)
1500 return;
1502 if (resource->gl_id)
1503 return;
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();
1511 DCHECK(gl);
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) {
1534 DCHECK(resource);
1535 if (resource->allocated)
1536 return;
1537 LazyCreate(resource);
1538 if (!resource->gl_id)
1539 return;
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(),
1550 size.height());
1551 } else {
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)
1579 return;
1580 if (!resource->mailbox.sync_point())
1581 return;
1582 DCHECK(resource->mailbox.IsValid());
1583 GLES2Interface* gl = ContextGL();
1584 DCHECK(gl);
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);
1592 return 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());
1604 DCHECK(id);
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
1633 // unique id.
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()
1658 ->ContextSupport()
1659 ->ShareGroupTracingGUID(),
1660 resource.gl_id);
1663 if (!guid.empty()) {
1664 const int kImportance = 2;
1665 pmd->CreateSharedGlobalAllocatorDump(guid);
1666 pmd->AddOwnershipEdge(dump->guid(), guid, kImportance);
1670 return true;
1673 } // namespace cc