Upstreaming browser/ui/uikit_ui_util from iOS.
[chromium-blink-merge.git] / cc / resources / resource_provider.cc
blob204422c187f36353f28ca864006c83cc4c53dbc9
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/containers/hash_tables.h"
11 #include "base/metrics/histogram.h"
12 #include "base/numerics/safe_math.h"
13 #include "base/stl_util.h"
14 #include "base/strings/string_split.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/thread_task_runner_handle.h"
18 #include "base/trace_event/memory_dump_manager.h"
19 #include "base/trace_event/trace_event.h"
20 #include "cc/resources/platform_color.h"
21 #include "cc/resources/resource_util.h"
22 #include "cc/resources/returned_resource.h"
23 #include "cc/resources/shared_bitmap_manager.h"
24 #include "cc/resources/transferable_resource.h"
25 #include "gpu/GLES2/gl2extchromium.h"
26 #include "gpu/command_buffer/client/gles2_interface.h"
27 #include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
28 #include "third_party/khronos/GLES2/gl2.h"
29 #include "third_party/khronos/GLES2/gl2ext.h"
30 #include "third_party/skia/include/core/SkSurface.h"
31 #include "third_party/skia/include/gpu/GrContext.h"
32 #include "third_party/skia/include/gpu/GrTextureProvider.h"
33 #include "ui/gfx/geometry/rect.h"
34 #include "ui/gfx/geometry/vector2d.h"
35 #include "ui/gfx/gpu_memory_buffer.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 gfx::BufferFormat ToGpuMemoryBufferFormat(ResourceFormat format) {
121 switch (format) {
122 case RGBA_8888:
123 return gfx::BufferFormat::RGBA_8888;
124 case BGRA_8888:
125 return gfx::BufferFormat::BGRA_8888;
126 case RGBA_4444:
127 return gfx::BufferFormat::RGBA_4444;
128 case ALPHA_8:
129 case LUMINANCE_8:
130 case RGB_565:
131 case ETC1:
132 case RED_8:
133 break;
135 NOTREACHED();
136 return gfx::BufferFormat::RGBA_8888;
139 class ScopedSetActiveTexture {
140 public:
141 ScopedSetActiveTexture(GLES2Interface* gl, GLenum unit)
142 : gl_(gl), unit_(unit) {
143 DCHECK_EQ(GL_TEXTURE0, ResourceProvider::GetActiveTextureUnit(gl_));
145 if (unit_ != GL_TEXTURE0)
146 gl_->ActiveTexture(unit_);
149 ~ScopedSetActiveTexture() {
150 // Active unit being GL_TEXTURE0 is effectively the ground state.
151 if (unit_ != GL_TEXTURE0)
152 gl_->ActiveTexture(GL_TEXTURE0);
155 private:
156 GLES2Interface* gl_;
157 GLenum unit_;
160 class TextureIdAllocator : public IdAllocator {
161 public:
162 TextureIdAllocator(GLES2Interface* gl,
163 size_t texture_id_allocation_chunk_size)
164 : IdAllocator(gl, texture_id_allocation_chunk_size) {}
165 ~TextureIdAllocator() override {
166 gl_->DeleteTextures(
167 static_cast<int>(id_allocation_chunk_size_ - next_id_index_),
168 ids_.get() + next_id_index_);
171 // Overridden from IdAllocator:
172 GLuint NextId() override {
173 if (next_id_index_ == id_allocation_chunk_size_) {
174 gl_->GenTextures(static_cast<int>(id_allocation_chunk_size_), ids_.get());
175 next_id_index_ = 0;
178 return ids_[next_id_index_++];
181 private:
182 DISALLOW_COPY_AND_ASSIGN(TextureIdAllocator);
185 class BufferIdAllocator : public IdAllocator {
186 public:
187 BufferIdAllocator(GLES2Interface* gl, size_t buffer_id_allocation_chunk_size)
188 : IdAllocator(gl, buffer_id_allocation_chunk_size) {}
189 ~BufferIdAllocator() override {
190 gl_->DeleteBuffers(
191 static_cast<int>(id_allocation_chunk_size_ - next_id_index_),
192 ids_.get() + next_id_index_);
195 // Overridden from IdAllocator:
196 GLuint NextId() override {
197 if (next_id_index_ == id_allocation_chunk_size_) {
198 gl_->GenBuffers(static_cast<int>(id_allocation_chunk_size_), ids_.get());
199 next_id_index_ = 0;
202 return ids_[next_id_index_++];
205 private:
206 DISALLOW_COPY_AND_ASSIGN(BufferIdAllocator);
209 // Query object based fence implementation used to detect completion of copy
210 // texture operations. Fence has passed when query result is available.
211 class CopyTextureFence : public ResourceProvider::Fence {
212 public:
213 CopyTextureFence(gpu::gles2::GLES2Interface* gl, unsigned query_id)
214 : gl_(gl), query_id_(query_id) {}
216 // Overridden from ResourceProvider::Fence:
217 void Set() override {}
218 bool HasPassed() override {
219 unsigned available = 1;
220 gl_->GetQueryObjectuivEXT(
221 query_id_, GL_QUERY_RESULT_AVAILABLE_EXT, &available);
222 if (!available)
223 return false;
225 ProcessResult();
226 return true;
228 void Wait() override {
229 // ProcessResult() will wait for result to become available.
230 ProcessResult();
233 private:
234 ~CopyTextureFence() override {}
236 void ProcessResult() {
237 unsigned time_elapsed_us = 0;
238 gl_->GetQueryObjectuivEXT(query_id_, GL_QUERY_RESULT_EXT, &time_elapsed_us);
239 UMA_HISTOGRAM_CUSTOM_COUNTS("Renderer4.CopyTextureLatency", time_elapsed_us,
240 0, 256000, 50);
243 gpu::gles2::GLES2Interface* gl_;
244 unsigned query_id_;
246 DISALLOW_COPY_AND_ASSIGN(CopyTextureFence);
249 } // namespace
251 ResourceProvider::Resource::~Resource() {}
253 ResourceProvider::Resource::Resource(GLuint texture_id,
254 const gfx::Size& size,
255 Origin origin,
256 GLenum target,
257 GLenum filter,
258 GLenum texture_pool,
259 GLint wrap_mode,
260 TextureHint hint,
261 ResourceFormat format)
262 : child_id(0),
263 gl_id(texture_id),
264 gl_pixel_buffer_id(0),
265 gl_upload_query_id(0),
266 gl_read_lock_query_id(0),
267 pixels(NULL),
268 lock_for_read_count(0),
269 imported_count(0),
270 exported_count(0),
271 dirty_image(false),
272 locked_for_write(false),
273 lost(false),
274 marked_for_deletion(false),
275 pending_set_pixels(false),
276 set_pixels_completion_forced(false),
277 allocated(false),
278 read_lock_fences_enabled(false),
279 has_shared_bitmap_id(false),
280 read_lock_fence(NULL),
281 size(size),
282 origin(origin),
283 target(target),
284 original_filter(filter),
285 filter(filter),
286 image_id(0),
287 bound_image_id(0),
288 texture_pool(texture_pool),
289 wrap_mode(wrap_mode),
290 hint(hint),
291 type(RESOURCE_TYPE_GL_TEXTURE),
292 format(format),
293 shared_bitmap(NULL),
294 gpu_memory_buffer(NULL) {
295 DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT);
296 DCHECK_EQ(origin == INTERNAL, !!texture_pool);
299 ResourceProvider::Resource::Resource(uint8_t* pixels,
300 SharedBitmap* bitmap,
301 const gfx::Size& size,
302 Origin origin,
303 GLenum filter,
304 GLint wrap_mode)
305 : child_id(0),
306 gl_id(0),
307 gl_pixel_buffer_id(0),
308 gl_upload_query_id(0),
309 gl_read_lock_query_id(0),
310 pixels(pixels),
311 lock_for_read_count(0),
312 imported_count(0),
313 exported_count(0),
314 dirty_image(false),
315 locked_for_write(false),
316 lost(false),
317 marked_for_deletion(false),
318 pending_set_pixels(false),
319 set_pixels_completion_forced(false),
320 allocated(false),
321 read_lock_fences_enabled(false),
322 has_shared_bitmap_id(!!bitmap),
323 read_lock_fence(NULL),
324 size(size),
325 origin(origin),
326 target(0),
327 original_filter(filter),
328 filter(filter),
329 image_id(0),
330 bound_image_id(0),
331 texture_pool(0),
332 wrap_mode(wrap_mode),
333 hint(TEXTURE_HINT_IMMUTABLE),
334 type(RESOURCE_TYPE_BITMAP),
335 format(RGBA_8888),
336 shared_bitmap(bitmap),
337 gpu_memory_buffer(NULL) {
338 DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT);
339 DCHECK(origin == DELEGATED || pixels);
340 if (bitmap)
341 shared_bitmap_id = bitmap->id();
344 ResourceProvider::Resource::Resource(const SharedBitmapId& bitmap_id,
345 const gfx::Size& size,
346 Origin origin,
347 GLenum filter,
348 GLint wrap_mode)
349 : child_id(0),
350 gl_id(0),
351 gl_pixel_buffer_id(0),
352 gl_upload_query_id(0),
353 gl_read_lock_query_id(0),
354 pixels(NULL),
355 lock_for_read_count(0),
356 imported_count(0),
357 exported_count(0),
358 dirty_image(false),
359 locked_for_write(false),
360 lost(false),
361 marked_for_deletion(false),
362 pending_set_pixels(false),
363 set_pixels_completion_forced(false),
364 allocated(false),
365 read_lock_fences_enabled(false),
366 has_shared_bitmap_id(true),
367 read_lock_fence(NULL),
368 size(size),
369 origin(origin),
370 target(0),
371 original_filter(filter),
372 filter(filter),
373 image_id(0),
374 bound_image_id(0),
375 texture_pool(0),
376 wrap_mode(wrap_mode),
377 hint(TEXTURE_HINT_IMMUTABLE),
378 type(RESOURCE_TYPE_BITMAP),
379 format(RGBA_8888),
380 shared_bitmap_id(bitmap_id),
381 shared_bitmap(NULL),
382 gpu_memory_buffer(NULL) {
383 DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT);
386 ResourceProvider::Child::Child()
387 : marked_for_deletion(false), needs_sync_points(true) {
390 ResourceProvider::Child::~Child() {}
392 scoped_ptr<ResourceProvider> ResourceProvider::Create(
393 OutputSurface* output_surface,
394 SharedBitmapManager* shared_bitmap_manager,
395 gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
396 BlockingTaskRunner* blocking_main_thread_task_runner,
397 int highp_threshold_min,
398 bool use_rgba_4444_texture_format,
399 size_t id_allocation_chunk_size,
400 bool use_persistent_map_for_gpu_memory_buffers) {
401 scoped_ptr<ResourceProvider> resource_provider(new ResourceProvider(
402 output_surface, shared_bitmap_manager, gpu_memory_buffer_manager,
403 blocking_main_thread_task_runner, highp_threshold_min,
404 use_rgba_4444_texture_format, id_allocation_chunk_size,
405 use_persistent_map_for_gpu_memory_buffers));
406 resource_provider->Initialize();
407 return resource_provider;
410 ResourceProvider::~ResourceProvider() {
411 base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
412 this);
414 while (!children_.empty())
415 DestroyChildInternal(children_.begin(), FOR_SHUTDOWN);
416 while (!resources_.empty())
417 DeleteResourceInternal(resources_.begin(), FOR_SHUTDOWN);
419 GLES2Interface* gl = ContextGL();
420 if (default_resource_type_ != RESOURCE_TYPE_GL_TEXTURE) {
421 // We are not in GL mode, but double check before returning.
422 DCHECK(!gl);
423 return;
426 DCHECK(gl);
427 #if DCHECK_IS_ON()
428 // Check that all GL resources has been deleted.
429 for (ResourceMap::const_iterator itr = resources_.begin();
430 itr != resources_.end(); ++itr) {
431 DCHECK_NE(RESOURCE_TYPE_GL_TEXTURE, itr->second.type);
433 #endif // DCHECK_IS_ON()
435 texture_id_allocator_ = nullptr;
436 buffer_id_allocator_ = nullptr;
437 gl->Finish();
440 bool ResourceProvider::InUseByConsumer(ResourceId id) {
441 Resource* resource = GetResource(id);
442 return resource->lock_for_read_count > 0 || resource->exported_count > 0 ||
443 resource->lost;
446 bool ResourceProvider::IsLost(ResourceId id) {
447 Resource* resource = GetResource(id);
448 return resource->lost;
451 void ResourceProvider::LoseResourceForTesting(ResourceId id) {
452 Resource* resource = GetResource(id);
453 DCHECK(resource);
454 resource->lost = true;
457 ResourceId ResourceProvider::CreateResource(const gfx::Size& size,
458 GLint wrap_mode,
459 TextureHint hint,
460 ResourceFormat format) {
461 DCHECK(!size.IsEmpty());
462 switch (default_resource_type_) {
463 case RESOURCE_TYPE_GL_TEXTURE:
464 return CreateGLTexture(size,
465 GL_TEXTURE_2D,
466 GL_TEXTURE_POOL_UNMANAGED_CHROMIUM,
467 wrap_mode,
468 hint,
469 format);
470 case RESOURCE_TYPE_BITMAP:
471 DCHECK_EQ(RGBA_8888, format);
472 return CreateBitmap(size, wrap_mode);
475 LOG(FATAL) << "Invalid default resource type.";
476 return 0;
479 ResourceId ResourceProvider::CreateManagedResource(const gfx::Size& size,
480 GLenum target,
481 GLint wrap_mode,
482 TextureHint hint,
483 ResourceFormat format) {
484 DCHECK(!size.IsEmpty());
485 switch (default_resource_type_) {
486 case RESOURCE_TYPE_GL_TEXTURE:
487 return CreateGLTexture(size,
488 target,
489 GL_TEXTURE_POOL_MANAGED_CHROMIUM,
490 wrap_mode,
491 hint,
492 format);
493 case RESOURCE_TYPE_BITMAP:
494 DCHECK_EQ(RGBA_8888, format);
495 return CreateBitmap(size, wrap_mode);
498 LOG(FATAL) << "Invalid default resource type.";
499 return 0;
502 ResourceId ResourceProvider::CreateGLTexture(const gfx::Size& size,
503 GLenum target,
504 GLenum texture_pool,
505 GLint wrap_mode,
506 TextureHint hint,
507 ResourceFormat format) {
508 DCHECK_LE(size.width(), max_texture_size_);
509 DCHECK_LE(size.height(), max_texture_size_);
510 DCHECK(thread_checker_.CalledOnValidThread());
512 ResourceId id = next_id_++;
513 Resource* resource = InsertResource(
514 id, Resource(0, size, Resource::INTERNAL, target, GL_LINEAR, texture_pool,
515 wrap_mode, hint, format));
516 resource->allocated = false;
517 return id;
520 ResourceId ResourceProvider::CreateBitmap(const gfx::Size& size,
521 GLint wrap_mode) {
522 DCHECK(thread_checker_.CalledOnValidThread());
524 scoped_ptr<SharedBitmap> bitmap =
525 shared_bitmap_manager_->AllocateSharedBitmap(size);
526 uint8_t* pixels = bitmap->pixels();
527 DCHECK(pixels);
529 ResourceId id = next_id_++;
530 Resource* resource =
531 InsertResource(id, Resource(pixels, bitmap.release(), size,
532 Resource::INTERNAL, GL_LINEAR, wrap_mode));
533 resource->allocated = true;
534 return id;
537 ResourceId ResourceProvider::CreateResourceFromIOSurface(
538 const gfx::Size& size,
539 unsigned io_surface_id) {
540 DCHECK(thread_checker_.CalledOnValidThread());
542 ResourceId id = next_id_++;
543 Resource* resource = InsertResource(
544 id, Resource(0, gfx::Size(), Resource::INTERNAL, GL_TEXTURE_RECTANGLE_ARB,
545 GL_LINEAR, GL_TEXTURE_POOL_UNMANAGED_CHROMIUM,
546 GL_CLAMP_TO_EDGE, TEXTURE_HINT_IMMUTABLE, RGBA_8888));
547 LazyCreate(resource);
548 GLES2Interface* gl = ContextGL();
549 DCHECK(gl);
550 gl->BindTexture(GL_TEXTURE_RECTANGLE_ARB, resource->gl_id);
551 gl->TexImageIOSurface2DCHROMIUM(
552 GL_TEXTURE_RECTANGLE_ARB, size.width(), size.height(), io_surface_id, 0);
553 resource->allocated = true;
554 return id;
557 ResourceId ResourceProvider::CreateResourceFromTextureMailbox(
558 const TextureMailbox& mailbox,
559 scoped_ptr<SingleReleaseCallbackImpl> release_callback_impl,
560 bool read_lock_fences_enabled) {
561 DCHECK(thread_checker_.CalledOnValidThread());
562 // Just store the information. Mailbox will be consumed in LockForRead().
563 ResourceId id = next_id_++;
564 DCHECK(mailbox.IsValid());
565 Resource* resource = nullptr;
566 if (mailbox.IsTexture()) {
567 resource = InsertResource(
568 id, Resource(0, gfx::Size(), Resource::EXTERNAL, mailbox.target(),
569 mailbox.nearest_neighbor() ? GL_NEAREST : GL_LINEAR, 0,
570 GL_CLAMP_TO_EDGE, TEXTURE_HINT_IMMUTABLE, RGBA_8888));
571 } else {
572 DCHECK(mailbox.IsSharedMemory());
573 SharedBitmap* shared_bitmap = mailbox.shared_bitmap();
574 uint8_t* pixels = shared_bitmap->pixels();
575 DCHECK(pixels);
576 resource = InsertResource(
577 id, Resource(pixels, shared_bitmap, mailbox.size_in_pixels(),
578 Resource::EXTERNAL, GL_LINEAR, GL_CLAMP_TO_EDGE));
580 resource->allocated = true;
581 resource->mailbox = mailbox;
582 resource->release_callback_impl =
583 base::Bind(&SingleReleaseCallbackImpl::Run,
584 base::Owned(release_callback_impl.release()));
585 resource->read_lock_fences_enabled = read_lock_fences_enabled;
586 return id;
589 ResourceId ResourceProvider::CreateResourceFromTextureMailbox(
590 const TextureMailbox& mailbox,
591 scoped_ptr<SingleReleaseCallbackImpl> release_callback_impl) {
592 return CreateResourceFromTextureMailbox(mailbox, release_callback_impl.Pass(),
593 false);
596 void ResourceProvider::DeleteResource(ResourceId id) {
597 DCHECK(thread_checker_.CalledOnValidThread());
598 ResourceMap::iterator it = resources_.find(id);
599 CHECK(it != resources_.end());
600 Resource* resource = &it->second;
601 DCHECK(!resource->marked_for_deletion);
602 DCHECK_EQ(resource->imported_count, 0);
603 DCHECK(resource->pending_set_pixels || !resource->locked_for_write);
605 if (resource->exported_count > 0 || resource->lock_for_read_count > 0 ||
606 !ReadLockFenceHasPassed(resource)) {
607 resource->marked_for_deletion = true;
608 return;
609 } else {
610 DeleteResourceInternal(it, NORMAL);
614 void ResourceProvider::DeleteResourceInternal(ResourceMap::iterator it,
615 DeleteStyle style) {
616 TRACE_EVENT0("cc", "ResourceProvider::DeleteResourceInternal");
617 Resource* resource = &it->second;
618 bool lost_resource = resource->lost;
620 DCHECK(resource->exported_count == 0 || style != NORMAL);
621 if (style == FOR_SHUTDOWN && resource->exported_count > 0)
622 lost_resource = true;
624 if (resource->image_id) {
625 DCHECK(resource->origin == Resource::INTERNAL);
626 GLES2Interface* gl = ContextGL();
627 DCHECK(gl);
628 gl->DestroyImageCHROMIUM(resource->image_id);
630 if (resource->gl_upload_query_id) {
631 DCHECK(resource->origin == Resource::INTERNAL);
632 GLES2Interface* gl = ContextGL();
633 DCHECK(gl);
634 gl->DeleteQueriesEXT(1, &resource->gl_upload_query_id);
636 if (resource->gl_read_lock_query_id) {
637 DCHECK(resource->origin == Resource::INTERNAL);
638 GLES2Interface* gl = ContextGL();
639 DCHECK(gl);
640 gl->DeleteQueriesEXT(1, &resource->gl_read_lock_query_id);
642 if (resource->gl_pixel_buffer_id) {
643 DCHECK(resource->origin == Resource::INTERNAL);
644 GLES2Interface* gl = ContextGL();
645 DCHECK(gl);
646 gl->DeleteBuffers(1, &resource->gl_pixel_buffer_id);
648 if (resource->origin == Resource::EXTERNAL) {
649 DCHECK(resource->mailbox.IsValid());
650 GLuint sync_point = resource->mailbox.sync_point();
651 if (resource->type == RESOURCE_TYPE_GL_TEXTURE) {
652 DCHECK(resource->mailbox.IsTexture());
653 lost_resource |= lost_output_surface_;
654 GLES2Interface* gl = ContextGL();
655 DCHECK(gl);
656 if (resource->gl_id) {
657 gl->DeleteTextures(1, &resource->gl_id);
658 resource->gl_id = 0;
659 if (!lost_resource)
660 sync_point = gl->InsertSyncPointCHROMIUM();
662 } else {
663 DCHECK(resource->mailbox.IsSharedMemory());
664 resource->shared_bitmap = nullptr;
665 resource->pixels = nullptr;
667 resource->release_callback_impl.Run(
668 sync_point, lost_resource, blocking_main_thread_task_runner_);
670 if (resource->gl_id) {
671 GLES2Interface* gl = ContextGL();
672 DCHECK(gl);
673 gl->DeleteTextures(1, &resource->gl_id);
674 resource->gl_id = 0;
676 if (resource->shared_bitmap) {
677 DCHECK(resource->origin != Resource::EXTERNAL);
678 DCHECK_EQ(RESOURCE_TYPE_BITMAP, resource->type);
679 delete resource->shared_bitmap;
680 resource->pixels = NULL;
682 if (resource->pixels) {
683 DCHECK(resource->origin == Resource::INTERNAL);
684 delete[] resource->pixels;
685 resource->pixels = NULL;
687 if (resource->gpu_memory_buffer) {
688 DCHECK(resource->origin == Resource::INTERNAL);
689 delete resource->gpu_memory_buffer;
690 resource->gpu_memory_buffer = NULL;
692 resources_.erase(it);
695 ResourceProvider::ResourceType ResourceProvider::GetResourceType(
696 ResourceId id) {
697 return GetResource(id)->type;
700 void ResourceProvider::CopyToResource(ResourceId id,
701 const uint8_t* image,
702 const gfx::Size& image_size) {
703 Resource* resource = GetResource(id);
704 DCHECK(!resource->locked_for_write);
705 DCHECK(!resource->lock_for_read_count);
706 DCHECK(resource->origin == Resource::INTERNAL);
707 DCHECK_EQ(resource->exported_count, 0);
708 DCHECK(ReadLockFenceHasPassed(resource));
709 LazyAllocate(resource);
711 DCHECK_EQ(image_size.width(), resource->size.width());
712 DCHECK_EQ(image_size.height(), resource->size.height());
714 if (resource->type == RESOURCE_TYPE_BITMAP) {
715 DCHECK_EQ(RESOURCE_TYPE_BITMAP, resource->type);
716 DCHECK(resource->allocated);
717 DCHECK_EQ(RGBA_8888, resource->format);
718 SkImageInfo source_info =
719 SkImageInfo::MakeN32Premul(image_size.width(), image_size.height());
720 size_t image_stride = image_size.width() * 4;
722 ScopedWriteLockSoftware lock(this, id);
723 SkCanvas dest(lock.sk_bitmap());
724 dest.writePixels(source_info, image, image_stride, 0, 0);
725 } else {
726 DCHECK(resource->gl_id);
727 DCHECK(!resource->pending_set_pixels);
728 DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D));
729 GLES2Interface* gl = ContextGL();
730 DCHECK(gl);
731 gl->BindTexture(GL_TEXTURE_2D, resource->gl_id);
733 if (resource->format == ETC1) {
734 int image_bytes = ResourceUtil::CheckedSizeInBytes<int>(image_size, ETC1);
735 gl->CompressedTexImage2D(GL_TEXTURE_2D, 0, GLInternalFormat(ETC1),
736 image_size.width(), image_size.height(), 0,
737 image_bytes, image);
738 } else {
739 gl->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, image_size.width(),
740 image_size.height(), GLDataFormat(resource->format),
741 GLDataType(resource->format), image);
746 ResourceProvider::Resource* ResourceProvider::InsertResource(
747 ResourceId id,
748 const Resource& resource) {
749 std::pair<ResourceMap::iterator, bool> result =
750 resources_.insert(ResourceMap::value_type(id, resource));
751 DCHECK(result.second);
752 return &result.first->second;
755 ResourceProvider::Resource* ResourceProvider::GetResource(ResourceId id) {
756 DCHECK(thread_checker_.CalledOnValidThread());
757 DCHECK(id);
758 ResourceMap::iterator it = resources_.find(id);
759 DCHECK(it != resources_.end());
760 return &it->second;
763 const ResourceProvider::Resource* ResourceProvider::LockForRead(ResourceId id) {
764 Resource* resource = GetResource(id);
765 DCHECK(!resource->locked_for_write ||
766 resource->set_pixels_completion_forced) <<
767 "locked for write: " << resource->locked_for_write <<
768 " pixels completion forced: " << resource->set_pixels_completion_forced;
769 DCHECK_EQ(resource->exported_count, 0);
770 // Uninitialized! Call SetPixels or LockForWrite first.
771 DCHECK(resource->allocated);
773 LazyCreate(resource);
775 if (resource->type == RESOURCE_TYPE_GL_TEXTURE && !resource->gl_id) {
776 DCHECK(resource->origin != Resource::INTERNAL);
777 DCHECK(resource->mailbox.IsTexture());
779 // Mailbox sync_points must be processed by a call to
780 // WaitSyncPointIfNeeded() prior to calling LockForRead().
781 DCHECK(!resource->mailbox.sync_point());
783 GLES2Interface* gl = ContextGL();
784 DCHECK(gl);
785 resource->gl_id = gl->CreateAndConsumeTextureCHROMIUM(
786 resource->mailbox.target(), resource->mailbox.name());
789 if (!resource->pixels && resource->has_shared_bitmap_id &&
790 shared_bitmap_manager_) {
791 scoped_ptr<SharedBitmap> bitmap =
792 shared_bitmap_manager_->GetSharedBitmapFromId(
793 resource->size, resource->shared_bitmap_id);
794 if (bitmap) {
795 resource->shared_bitmap = bitmap.release();
796 resource->pixels = resource->shared_bitmap->pixels();
800 resource->lock_for_read_count++;
801 if (resource->read_lock_fences_enabled) {
802 if (current_read_lock_fence_.get())
803 current_read_lock_fence_->Set();
804 resource->read_lock_fence = current_read_lock_fence_;
807 return resource;
810 void ResourceProvider::UnlockForRead(ResourceId id) {
811 DCHECK(thread_checker_.CalledOnValidThread());
812 ResourceMap::iterator it = resources_.find(id);
813 CHECK(it != resources_.end());
815 Resource* resource = &it->second;
816 DCHECK_GT(resource->lock_for_read_count, 0);
817 DCHECK_EQ(resource->exported_count, 0);
818 resource->lock_for_read_count--;
819 if (resource->marked_for_deletion && !resource->lock_for_read_count) {
820 if (!resource->child_id) {
821 // The resource belongs to this ResourceProvider, so it can be destroyed.
822 DeleteResourceInternal(it, NORMAL);
823 } else {
824 ChildMap::iterator child_it = children_.find(resource->child_id);
825 ResourceIdArray unused;
826 unused.push_back(id);
827 DeleteAndReturnUnusedResourcesToChild(child_it, NORMAL, unused);
832 ResourceProvider::Resource* ResourceProvider::LockForWrite(ResourceId id) {
833 Resource* resource = GetResource(id);
834 DCHECK(CanLockForWrite(id));
836 resource->locked_for_write = true;
837 return resource;
840 bool ResourceProvider::CanLockForWrite(ResourceId id) {
841 Resource* resource = GetResource(id);
842 return !resource->locked_for_write && !resource->lock_for_read_count &&
843 !resource->exported_count && resource->origin == Resource::INTERNAL &&
844 !resource->lost && ReadLockFenceHasPassed(resource);
847 void ResourceProvider::UnlockForWrite(ResourceProvider::Resource* resource) {
848 DCHECK(resource->locked_for_write);
849 DCHECK_EQ(resource->exported_count, 0);
850 DCHECK(resource->origin == Resource::INTERNAL);
851 resource->locked_for_write = false;
854 void ResourceProvider::EnableReadLockFencesForTesting(ResourceId id) {
855 Resource* resource = GetResource(id);
856 DCHECK(resource);
857 resource->read_lock_fences_enabled = true;
860 ResourceProvider::ScopedReadLockGL::ScopedReadLockGL(
861 ResourceProvider* resource_provider,
862 ResourceId resource_id)
863 : resource_provider_(resource_provider),
864 resource_id_(resource_id),
865 resource_(resource_provider->LockForRead(resource_id)) {
866 DCHECK(resource_);
869 ResourceProvider::ScopedReadLockGL::~ScopedReadLockGL() {
870 resource_provider_->UnlockForRead(resource_id_);
873 ResourceProvider::ScopedSamplerGL::ScopedSamplerGL(
874 ResourceProvider* resource_provider,
875 ResourceId resource_id,
876 GLenum filter)
877 : ScopedReadLockGL(resource_provider, resource_id),
878 unit_(GL_TEXTURE0),
879 target_(resource_provider->BindForSampling(resource_id, unit_, filter)) {
882 ResourceProvider::ScopedSamplerGL::ScopedSamplerGL(
883 ResourceProvider* resource_provider,
884 ResourceId resource_id,
885 GLenum unit,
886 GLenum filter)
887 : ScopedReadLockGL(resource_provider, resource_id),
888 unit_(unit),
889 target_(resource_provider->BindForSampling(resource_id, unit_, filter)) {
892 ResourceProvider::ScopedSamplerGL::~ScopedSamplerGL() {
895 ResourceProvider::ScopedWriteLockGL::ScopedWriteLockGL(
896 ResourceProvider* resource_provider,
897 ResourceId resource_id)
898 : resource_provider_(resource_provider),
899 resource_(resource_provider->LockForWrite(resource_id)) {
900 resource_provider_->LazyAllocate(resource_);
901 texture_id_ = resource_->gl_id;
902 DCHECK(texture_id_);
905 ResourceProvider::ScopedWriteLockGL::~ScopedWriteLockGL() {
906 resource_provider_->UnlockForWrite(resource_);
909 void ResourceProvider::PopulateSkBitmapWithResource(
910 SkBitmap* sk_bitmap, const Resource* resource) {
911 DCHECK_EQ(RGBA_8888, resource->format);
912 SkImageInfo info = SkImageInfo::MakeN32Premul(resource->size.width(),
913 resource->size.height());
914 sk_bitmap->installPixels(info, resource->pixels, info.minRowBytes());
917 ResourceProvider::ScopedReadLockSoftware::ScopedReadLockSoftware(
918 ResourceProvider* resource_provider,
919 ResourceId resource_id)
920 : resource_provider_(resource_provider), resource_id_(resource_id) {
921 const Resource* resource = resource_provider->LockForRead(resource_id);
922 wrap_mode_ = resource->wrap_mode;
923 ResourceProvider::PopulateSkBitmapWithResource(&sk_bitmap_, resource);
926 ResourceProvider::ScopedReadLockSoftware::~ScopedReadLockSoftware() {
927 resource_provider_->UnlockForRead(resource_id_);
930 ResourceProvider::ScopedWriteLockSoftware::ScopedWriteLockSoftware(
931 ResourceProvider* resource_provider,
932 ResourceId resource_id)
933 : resource_provider_(resource_provider),
934 resource_(resource_provider->LockForWrite(resource_id)) {
935 ResourceProvider::PopulateSkBitmapWithResource(&sk_bitmap_, resource_);
936 DCHECK(valid());
939 ResourceProvider::ScopedWriteLockSoftware::~ScopedWriteLockSoftware() {
940 DCHECK(thread_checker_.CalledOnValidThread());
941 resource_provider_->UnlockForWrite(resource_);
944 ResourceProvider::ScopedWriteLockGpuMemoryBuffer::
945 ScopedWriteLockGpuMemoryBuffer(ResourceProvider* resource_provider,
946 ResourceId resource_id)
947 : resource_provider_(resource_provider),
948 resource_(resource_provider->LockForWrite(resource_id)),
949 gpu_memory_buffer_manager_(resource_provider->gpu_memory_buffer_manager_),
950 gpu_memory_buffer_(nullptr),
951 size_(resource_->size),
952 format_(resource_->format) {
953 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource_->type);
954 std::swap(gpu_memory_buffer_, resource_->gpu_memory_buffer);
957 ResourceProvider::ScopedWriteLockGpuMemoryBuffer::
958 ~ScopedWriteLockGpuMemoryBuffer() {
959 DCHECK(thread_checker_.CalledOnValidThread());
960 resource_provider_->UnlockForWrite(resource_);
961 if (!gpu_memory_buffer_)
962 return;
964 resource_provider_->LazyCreate(resource_);
966 if (!resource_->image_id) {
967 GLES2Interface* gl = resource_provider_->ContextGL();
968 DCHECK(gl);
970 #if defined(OS_CHROMEOS)
971 // TODO(reveman): GL_COMMANDS_ISSUED_CHROMIUM is used for synchronization
972 // on ChromeOS to avoid some performance issues. This only works with
973 // shared memory backed buffers. crbug.com/436314
974 DCHECK_EQ(gpu_memory_buffer_->GetHandle().type, gfx::SHARED_MEMORY_BUFFER);
975 #endif
977 resource_->image_id = gl->CreateImageCHROMIUM(
978 gpu_memory_buffer_->AsClientBuffer(), size_.width(), size_.height(),
979 GLInternalFormat(resource_->format));
982 std::swap(resource_->gpu_memory_buffer, gpu_memory_buffer_);
983 resource_->allocated = true;
984 resource_->dirty_image = true;
986 // GpuMemoryBuffer provides direct access to the memory used by the GPU.
987 // Read lock fences are required to ensure that we're not trying to map a
988 // buffer that is currently in-use by the GPU.
989 resource_->read_lock_fences_enabled = true;
992 gfx::GpuMemoryBuffer*
993 ResourceProvider::ScopedWriteLockGpuMemoryBuffer::GetGpuMemoryBuffer() {
994 if (gpu_memory_buffer_)
995 return gpu_memory_buffer_;
996 gfx::BufferUsage usage =
997 resource_provider_->use_persistent_map_for_gpu_memory_buffers()
998 ? gfx::BufferUsage::PERSISTENT_MAP
999 : gfx::BufferUsage::MAP;
1000 scoped_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer =
1001 gpu_memory_buffer_manager_->AllocateGpuMemoryBuffer(
1002 size_, ToGpuMemoryBufferFormat(format_), usage);
1003 gpu_memory_buffer_ = gpu_memory_buffer.release();
1004 return gpu_memory_buffer_;
1007 ResourceProvider::ScopedWriteLockGr::ScopedWriteLockGr(
1008 ResourceProvider* resource_provider,
1009 ResourceId resource_id)
1010 : resource_provider_(resource_provider),
1011 resource_(resource_provider->LockForWrite(resource_id)) {
1012 DCHECK(thread_checker_.CalledOnValidThread());
1013 resource_provider_->LazyAllocate(resource_);
1016 ResourceProvider::ScopedWriteLockGr::~ScopedWriteLockGr() {
1017 DCHECK(thread_checker_.CalledOnValidThread());
1018 DCHECK(resource_->locked_for_write);
1019 resource_provider_->UnlockForWrite(resource_);
1022 void ResourceProvider::ScopedWriteLockGr::InitSkSurface(
1023 bool use_distance_field_text,
1024 bool can_use_lcd_text,
1025 int msaa_sample_count) {
1026 DCHECK(resource_->locked_for_write);
1028 GrBackendTextureDesc desc;
1029 desc.fFlags = kRenderTarget_GrBackendTextureFlag;
1030 desc.fWidth = resource_->size.width();
1031 desc.fHeight = resource_->size.height();
1032 desc.fConfig = ToGrPixelConfig(resource_->format);
1033 desc.fOrigin = kTopLeft_GrSurfaceOrigin;
1034 desc.fTextureHandle = resource_->gl_id;
1035 desc.fSampleCnt = msaa_sample_count;
1037 bool use_worker_context = true;
1038 class GrContext* gr_context =
1039 resource_provider_->GrContext(use_worker_context);
1040 uint32_t flags =
1041 use_distance_field_text ? SkSurfaceProps::kUseDistanceFieldFonts_Flag : 0;
1042 // Use unknown pixel geometry to disable LCD text.
1043 SkSurfaceProps surface_props(flags, kUnknown_SkPixelGeometry);
1044 if (can_use_lcd_text) {
1045 // LegacyFontHost will get LCD text and skia figures out what type to use.
1046 surface_props =
1047 SkSurfaceProps(flags, SkSurfaceProps::kLegacyFontHost_InitType);
1049 sk_surface_ = skia::AdoptRef(
1050 SkSurface::NewWrappedRenderTarget(gr_context, desc, &surface_props));
1053 void ResourceProvider::ScopedWriteLockGr::ReleaseSkSurface() {
1054 sk_surface_.clear();
1057 ResourceProvider::SynchronousFence::SynchronousFence(
1058 gpu::gles2::GLES2Interface* gl)
1059 : gl_(gl), has_synchronized_(true) {
1062 ResourceProvider::SynchronousFence::~SynchronousFence() {
1065 void ResourceProvider::SynchronousFence::Set() {
1066 has_synchronized_ = false;
1069 bool ResourceProvider::SynchronousFence::HasPassed() {
1070 if (!has_synchronized_) {
1071 has_synchronized_ = true;
1072 Synchronize();
1074 return true;
1077 void ResourceProvider::SynchronousFence::Wait() {
1078 HasPassed();
1081 void ResourceProvider::SynchronousFence::Synchronize() {
1082 TRACE_EVENT0("cc", "ResourceProvider::SynchronousFence::Synchronize");
1083 gl_->Finish();
1086 ResourceProvider::ResourceProvider(
1087 OutputSurface* output_surface,
1088 SharedBitmapManager* shared_bitmap_manager,
1089 gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
1090 BlockingTaskRunner* blocking_main_thread_task_runner,
1091 int highp_threshold_min,
1092 bool use_rgba_4444_texture_format,
1093 size_t id_allocation_chunk_size,
1094 bool use_persistent_map_for_gpu_memory_buffers)
1095 : output_surface_(output_surface),
1096 shared_bitmap_manager_(shared_bitmap_manager),
1097 gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
1098 blocking_main_thread_task_runner_(blocking_main_thread_task_runner),
1099 lost_output_surface_(false),
1100 highp_threshold_min_(highp_threshold_min),
1101 next_id_(1),
1102 next_child_(1),
1103 default_resource_type_(RESOURCE_TYPE_BITMAP),
1104 use_texture_storage_ext_(false),
1105 use_texture_format_bgra_(false),
1106 use_texture_usage_hint_(false),
1107 use_compressed_texture_etc1_(false),
1108 yuv_resource_format_(LUMINANCE_8),
1109 max_texture_size_(0),
1110 best_texture_format_(RGBA_8888),
1111 best_render_buffer_format_(RGBA_8888),
1112 use_rgba_4444_texture_format_(use_rgba_4444_texture_format),
1113 id_allocation_chunk_size_(id_allocation_chunk_size),
1114 use_sync_query_(false),
1115 use_persistent_map_for_gpu_memory_buffers_(
1116 use_persistent_map_for_gpu_memory_buffers) {
1117 DCHECK(output_surface_->HasClient());
1118 DCHECK(id_allocation_chunk_size_);
1121 void ResourceProvider::Initialize() {
1122 DCHECK(thread_checker_.CalledOnValidThread());
1124 // In certain cases, ThreadTaskRunnerHandle isn't set (Android Webview).
1125 // Don't register a dump provider in these cases.
1126 // TODO(ericrk): Get this working in Android Webview. crbug.com/517156
1127 if (base::ThreadTaskRunnerHandle::IsSet()) {
1128 base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
1129 this, base::ThreadTaskRunnerHandle::Get());
1132 GLES2Interface* gl = ContextGL();
1133 if (!gl) {
1134 default_resource_type_ = RESOURCE_TYPE_BITMAP;
1135 // Pick an arbitrary limit here similar to what hardware might.
1136 max_texture_size_ = 16 * 1024;
1137 best_texture_format_ = RGBA_8888;
1138 return;
1141 DCHECK(!texture_id_allocator_);
1142 DCHECK(!buffer_id_allocator_);
1144 const ContextProvider::Capabilities& caps =
1145 output_surface_->context_provider()->ContextCapabilities();
1147 default_resource_type_ = RESOURCE_TYPE_GL_TEXTURE;
1148 use_texture_storage_ext_ = caps.gpu.texture_storage;
1149 use_texture_format_bgra_ = caps.gpu.texture_format_bgra8888;
1150 use_texture_usage_hint_ = caps.gpu.texture_usage;
1151 use_compressed_texture_etc1_ = caps.gpu.texture_format_etc1;
1152 yuv_resource_format_ = caps.gpu.texture_rg ? RED_8 : LUMINANCE_8;
1153 use_sync_query_ = caps.gpu.sync_query;
1155 max_texture_size_ = 0; // Context expects cleared value.
1156 gl->GetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size_);
1157 best_texture_format_ =
1158 PlatformColor::BestTextureFormat(use_texture_format_bgra_);
1160 best_render_buffer_format_ =
1161 PlatformColor::BestTextureFormat(caps.gpu.render_buffer_format_bgra8888);
1163 texture_id_allocator_.reset(
1164 new TextureIdAllocator(gl, id_allocation_chunk_size_));
1165 buffer_id_allocator_.reset(
1166 new BufferIdAllocator(gl, id_allocation_chunk_size_));
1169 int ResourceProvider::CreateChild(const ReturnCallback& return_callback) {
1170 DCHECK(thread_checker_.CalledOnValidThread());
1172 Child child_info;
1173 child_info.return_callback = return_callback;
1175 int child = next_child_++;
1176 children_[child] = child_info;
1177 return child;
1180 void ResourceProvider::SetChildNeedsSyncPoints(int child_id, bool needs) {
1181 ChildMap::iterator it = children_.find(child_id);
1182 DCHECK(it != children_.end());
1183 it->second.needs_sync_points = needs;
1186 void ResourceProvider::DestroyChild(int child_id) {
1187 ChildMap::iterator it = children_.find(child_id);
1188 DCHECK(it != children_.end());
1189 DestroyChildInternal(it, NORMAL);
1192 void ResourceProvider::DestroyChildInternal(ChildMap::iterator it,
1193 DeleteStyle style) {
1194 DCHECK(thread_checker_.CalledOnValidThread());
1196 Child& child = it->second;
1197 DCHECK(style == FOR_SHUTDOWN || !child.marked_for_deletion);
1199 ResourceIdArray resources_for_child;
1201 for (ResourceIdMap::iterator child_it = child.child_to_parent_map.begin();
1202 child_it != child.child_to_parent_map.end();
1203 ++child_it) {
1204 ResourceId id = child_it->second;
1205 resources_for_child.push_back(id);
1208 child.marked_for_deletion = true;
1210 DeleteAndReturnUnusedResourcesToChild(it, style, resources_for_child);
1213 const ResourceProvider::ResourceIdMap& ResourceProvider::GetChildToParentMap(
1214 int child) const {
1215 DCHECK(thread_checker_.CalledOnValidThread());
1216 ChildMap::const_iterator it = children_.find(child);
1217 DCHECK(it != children_.end());
1218 DCHECK(!it->second.marked_for_deletion);
1219 return it->second.child_to_parent_map;
1222 void ResourceProvider::PrepareSendToParent(const ResourceIdArray& resources,
1223 TransferableResourceArray* list) {
1224 DCHECK(thread_checker_.CalledOnValidThread());
1225 GLES2Interface* gl = ContextGL();
1226 bool need_sync_point = false;
1227 for (ResourceIdArray::const_iterator it = resources.begin();
1228 it != resources.end();
1229 ++it) {
1230 TransferableResource resource;
1231 TransferResource(gl, *it, &resource);
1232 if (!resource.mailbox_holder.sync_point && !resource.is_software)
1233 need_sync_point = true;
1234 ++resources_.find(*it)->second.exported_count;
1235 list->push_back(resource);
1237 if (need_sync_point &&
1238 output_surface_->capabilities().delegated_sync_points_required) {
1239 GLuint sync_point = gl->InsertSyncPointCHROMIUM();
1240 for (TransferableResourceArray::iterator it = list->begin();
1241 it != list->end();
1242 ++it) {
1243 if (!it->mailbox_holder.sync_point)
1244 it->mailbox_holder.sync_point = sync_point;
1249 void ResourceProvider::ReceiveFromChild(
1250 int child, const TransferableResourceArray& resources) {
1251 DCHECK(thread_checker_.CalledOnValidThread());
1252 GLES2Interface* gl = ContextGL();
1253 Child& child_info = children_.find(child)->second;
1254 DCHECK(!child_info.marked_for_deletion);
1255 for (TransferableResourceArray::const_iterator it = resources.begin();
1256 it != resources.end();
1257 ++it) {
1258 ResourceIdMap::iterator resource_in_map_it =
1259 child_info.child_to_parent_map.find(it->id);
1260 if (resource_in_map_it != child_info.child_to_parent_map.end()) {
1261 Resource* resource = GetResource(resource_in_map_it->second);
1262 resource->marked_for_deletion = false;
1263 resource->imported_count++;
1264 continue;
1267 if ((!it->is_software && !gl) ||
1268 (it->is_software && !shared_bitmap_manager_)) {
1269 TRACE_EVENT0("cc", "ResourceProvider::ReceiveFromChild dropping invalid");
1270 ReturnedResourceArray to_return;
1271 to_return.push_back(it->ToReturnedResource());
1272 child_info.return_callback.Run(to_return,
1273 blocking_main_thread_task_runner_);
1274 continue;
1277 ResourceId local_id = next_id_++;
1278 Resource* resource = nullptr;
1279 if (it->is_software) {
1280 resource = InsertResource(
1281 local_id,
1282 Resource(it->mailbox_holder.mailbox, it->size, Resource::DELEGATED,
1283 GL_LINEAR, it->is_repeated ? GL_REPEAT : GL_CLAMP_TO_EDGE));
1284 } else {
1285 resource = InsertResource(
1286 local_id, Resource(0, it->size, Resource::DELEGATED,
1287 it->mailbox_holder.texture_target, it->filter, 0,
1288 it->is_repeated ? GL_REPEAT : GL_CLAMP_TO_EDGE,
1289 TEXTURE_HINT_IMMUTABLE, it->format));
1290 resource->mailbox = TextureMailbox(it->mailbox_holder.mailbox,
1291 it->mailbox_holder.texture_target,
1292 it->mailbox_holder.sync_point);
1293 resource->read_lock_fences_enabled = it->read_lock_fences_enabled;
1295 resource->child_id = child;
1296 // Don't allocate a texture for a child.
1297 resource->allocated = true;
1298 resource->imported_count = 1;
1299 child_info.parent_to_child_map[local_id] = it->id;
1300 child_info.child_to_parent_map[it->id] = local_id;
1304 void ResourceProvider::DeclareUsedResourcesFromChild(
1305 int child,
1306 const ResourceIdSet& resources_from_child) {
1307 DCHECK(thread_checker_.CalledOnValidThread());
1309 ChildMap::iterator child_it = children_.find(child);
1310 DCHECK(child_it != children_.end());
1311 Child& child_info = child_it->second;
1312 DCHECK(!child_info.marked_for_deletion);
1314 ResourceIdArray unused;
1315 for (ResourceIdMap::iterator it = child_info.child_to_parent_map.begin();
1316 it != child_info.child_to_parent_map.end();
1317 ++it) {
1318 ResourceId local_id = it->second;
1319 bool resource_is_in_use = resources_from_child.count(it->first) > 0;
1320 if (!resource_is_in_use)
1321 unused.push_back(local_id);
1323 DeleteAndReturnUnusedResourcesToChild(child_it, NORMAL, unused);
1326 void ResourceProvider::ReceiveReturnsFromParent(
1327 const ReturnedResourceArray& resources) {
1328 DCHECK(thread_checker_.CalledOnValidThread());
1329 GLES2Interface* gl = ContextGL();
1331 base::hash_map<int, ResourceIdArray> resources_for_child;
1333 for (const ReturnedResource& returned : resources) {
1334 ResourceId local_id = returned.id;
1335 ResourceMap::iterator map_iterator = resources_.find(local_id);
1336 // Resource was already lost (e.g. it belonged to a child that was
1337 // destroyed).
1338 if (map_iterator == resources_.end())
1339 continue;
1341 Resource* resource = &map_iterator->second;
1343 CHECK_GE(resource->exported_count, returned.count);
1344 resource->exported_count -= returned.count;
1345 resource->lost |= returned.lost;
1346 if (resource->exported_count)
1347 continue;
1349 if (returned.sync_point) {
1350 DCHECK(!resource->has_shared_bitmap_id);
1351 if (resource->origin == Resource::INTERNAL) {
1352 DCHECK(resource->gl_id);
1353 gl->WaitSyncPointCHROMIUM(returned.sync_point);
1354 } else {
1355 DCHECK(!resource->gl_id);
1356 resource->mailbox.set_sync_point(returned.sync_point);
1360 if (!resource->marked_for_deletion)
1361 continue;
1363 if (!resource->child_id) {
1364 // The resource belongs to this ResourceProvider, so it can be destroyed.
1365 DeleteResourceInternal(map_iterator, NORMAL);
1366 continue;
1369 DCHECK(resource->origin == Resource::DELEGATED);
1370 resources_for_child[resource->child_id].push_back(local_id);
1373 for (const auto& children : resources_for_child) {
1374 ChildMap::iterator child_it = children_.find(children.first);
1375 DCHECK(child_it != children_.end());
1376 DeleteAndReturnUnusedResourcesToChild(child_it, NORMAL, children.second);
1380 void ResourceProvider::TransferResource(GLES2Interface* gl,
1381 ResourceId id,
1382 TransferableResource* resource) {
1383 Resource* source = GetResource(id);
1384 DCHECK(!source->locked_for_write);
1385 DCHECK(!source->lock_for_read_count);
1386 DCHECK(source->origin != Resource::EXTERNAL || source->mailbox.IsValid());
1387 DCHECK(source->allocated);
1388 resource->id = id;
1389 resource->format = source->format;
1390 resource->mailbox_holder.texture_target = source->target;
1391 resource->filter = source->filter;
1392 resource->size = source->size;
1393 resource->read_lock_fences_enabled = source->read_lock_fences_enabled;
1394 resource->is_repeated = (source->wrap_mode == GL_REPEAT);
1396 if (source->type == RESOURCE_TYPE_BITMAP) {
1397 resource->mailbox_holder.mailbox = source->shared_bitmap_id;
1398 resource->is_software = true;
1399 } else if (!source->mailbox.IsValid()) {
1400 LazyCreate(source);
1401 DCHECK(source->gl_id);
1402 DCHECK(source->origin == Resource::INTERNAL);
1403 if (source->image_id) {
1404 DCHECK(source->dirty_image);
1405 gl->BindTexture(resource->mailbox_holder.texture_target, source->gl_id);
1406 BindImageForSampling(source);
1408 // This is a resource allocated by the compositor, we need to produce it.
1409 // Don't set a sync point, the caller will do it.
1410 gl->GenMailboxCHROMIUM(resource->mailbox_holder.mailbox.name);
1411 gl->ProduceTextureDirectCHROMIUM(source->gl_id,
1412 resource->mailbox_holder.texture_target,
1413 resource->mailbox_holder.mailbox.name);
1415 source->mailbox = TextureMailbox(resource->mailbox_holder);
1416 } else {
1417 DCHECK(source->mailbox.IsTexture());
1418 if (source->image_id && source->dirty_image) {
1419 DCHECK(source->gl_id);
1420 DCHECK(source->origin == Resource::INTERNAL);
1421 gl->BindTexture(resource->mailbox_holder.texture_target, source->gl_id);
1422 BindImageForSampling(source);
1424 // This is either an external resource, or a compositor resource that we
1425 // already exported. Make sure to forward the sync point that we were given.
1426 resource->mailbox_holder.mailbox = source->mailbox.mailbox();
1427 resource->mailbox_holder.texture_target = source->mailbox.target();
1428 resource->mailbox_holder.sync_point = source->mailbox.sync_point();
1429 source->mailbox.set_sync_point(0);
1433 void ResourceProvider::DeleteAndReturnUnusedResourcesToChild(
1434 ChildMap::iterator child_it,
1435 DeleteStyle style,
1436 const ResourceIdArray& unused) {
1437 DCHECK(thread_checker_.CalledOnValidThread());
1438 DCHECK(child_it != children_.end());
1439 Child* child_info = &child_it->second;
1441 if (unused.empty() && !child_info->marked_for_deletion)
1442 return;
1444 ReturnedResourceArray to_return;
1446 GLES2Interface* gl = ContextGL();
1447 bool need_sync_point = false;
1448 for (size_t i = 0; i < unused.size(); ++i) {
1449 ResourceId local_id = unused[i];
1451 ResourceMap::iterator it = resources_.find(local_id);
1452 CHECK(it != resources_.end());
1453 Resource& resource = it->second;
1455 DCHECK(!resource.locked_for_write);
1456 DCHECK(child_info->parent_to_child_map.count(local_id));
1458 ResourceId child_id = child_info->parent_to_child_map[local_id];
1459 DCHECK(child_info->child_to_parent_map.count(child_id));
1461 bool is_lost =
1462 resource.lost ||
1463 (resource.type == RESOURCE_TYPE_GL_TEXTURE && lost_output_surface_);
1464 if (resource.exported_count > 0 || resource.lock_for_read_count > 0) {
1465 if (style != FOR_SHUTDOWN) {
1466 // Defer this resource deletion.
1467 resource.marked_for_deletion = true;
1468 continue;
1470 // We can't postpone the deletion, so we'll have to lose it.
1471 is_lost = true;
1472 } else if (!ReadLockFenceHasPassed(&resource)) {
1473 // TODO(dcastagna): see if it's possible to use this logic for
1474 // the branch above too, where the resource is locked or still exported.
1475 if (style != FOR_SHUTDOWN && !child_info->marked_for_deletion) {
1476 // Defer this resource deletion.
1477 resource.marked_for_deletion = true;
1478 continue;
1480 // We can't postpone the deletion, so we'll have to lose it.
1481 is_lost = true;
1484 if (gl && resource.filter != resource.original_filter) {
1485 DCHECK(resource.target);
1486 DCHECK(resource.gl_id);
1488 gl->BindTexture(resource.target, resource.gl_id);
1489 gl->TexParameteri(resource.target, GL_TEXTURE_MIN_FILTER,
1490 resource.original_filter);
1491 gl->TexParameteri(resource.target, GL_TEXTURE_MAG_FILTER,
1492 resource.original_filter);
1495 ReturnedResource returned;
1496 returned.id = child_id;
1497 returned.sync_point = resource.mailbox.sync_point();
1498 if (!returned.sync_point && resource.type == RESOURCE_TYPE_GL_TEXTURE)
1499 need_sync_point = true;
1500 returned.count = resource.imported_count;
1501 returned.lost = is_lost;
1502 to_return.push_back(returned);
1504 child_info->parent_to_child_map.erase(local_id);
1505 child_info->child_to_parent_map.erase(child_id);
1506 resource.imported_count = 0;
1507 DeleteResourceInternal(it, style);
1509 if (need_sync_point && child_info->needs_sync_points) {
1510 DCHECK(gl);
1511 GLuint sync_point = gl->InsertSyncPointCHROMIUM();
1512 for (size_t i = 0; i < to_return.size(); ++i) {
1513 if (!to_return[i].sync_point)
1514 to_return[i].sync_point = sync_point;
1518 if (!to_return.empty())
1519 child_info->return_callback.Run(to_return,
1520 blocking_main_thread_task_runner_);
1522 if (child_info->marked_for_deletion &&
1523 child_info->parent_to_child_map.empty()) {
1524 DCHECK(child_info->child_to_parent_map.empty());
1525 children_.erase(child_it);
1529 void ResourceProvider::AcquirePixelBuffer(ResourceId id) {
1530 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1531 "ResourceProvider::AcquirePixelBuffer");
1533 Resource* resource = GetResource(id);
1534 DCHECK(resource->origin == Resource::INTERNAL);
1535 DCHECK_EQ(resource->exported_count, 0);
1536 DCHECK(!resource->image_id);
1537 DCHECK_NE(ETC1, resource->format);
1539 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
1540 GLES2Interface* gl = ContextGL();
1541 DCHECK(gl);
1542 if (!resource->gl_pixel_buffer_id)
1543 resource->gl_pixel_buffer_id = buffer_id_allocator_->NextId();
1544 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1545 resource->gl_pixel_buffer_id);
1546 size_t resource_bytes = ResourceUtil::UncheckedSizeInBytesAligned<size_t>(
1547 resource->size, resource->format);
1548 gl->BufferData(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, resource_bytes, NULL,
1549 GL_DYNAMIC_DRAW);
1550 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
1553 void ResourceProvider::ReleasePixelBuffer(ResourceId id) {
1554 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1555 "ResourceProvider::ReleasePixelBuffer");
1557 Resource* resource = GetResource(id);
1558 DCHECK(resource->origin == Resource::INTERNAL);
1559 DCHECK_EQ(resource->exported_count, 0);
1560 DCHECK(!resource->image_id);
1562 // The pixel buffer can be released while there is a pending "set pixels"
1563 // if completion has been forced. Any shared memory associated with this
1564 // pixel buffer will not be freed until the waitAsyncTexImage2DCHROMIUM
1565 // command has been processed on the service side. It is also safe to
1566 // reuse any query id associated with this resource before they complete
1567 // as each new query has a unique submit count.
1568 if (resource->pending_set_pixels) {
1569 DCHECK(resource->set_pixels_completion_forced);
1570 resource->pending_set_pixels = false;
1571 resource->locked_for_write = false;
1574 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
1575 if (!resource->gl_pixel_buffer_id)
1576 return;
1577 GLES2Interface* gl = ContextGL();
1578 DCHECK(gl);
1579 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1580 resource->gl_pixel_buffer_id);
1581 gl->BufferData(
1582 GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0, NULL, GL_DYNAMIC_DRAW);
1583 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
1586 uint8_t* ResourceProvider::MapPixelBuffer(ResourceId id, int* stride) {
1587 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1588 "ResourceProvider::MapPixelBuffer");
1590 Resource* resource = GetResource(id);
1591 DCHECK(resource->origin == Resource::INTERNAL);
1592 DCHECK_EQ(resource->exported_count, 0);
1593 DCHECK(!resource->image_id);
1595 *stride = 0;
1596 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
1597 GLES2Interface* gl = ContextGL();
1598 DCHECK(gl);
1599 DCHECK(resource->gl_pixel_buffer_id);
1600 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1601 resource->gl_pixel_buffer_id);
1602 uint8_t* image = static_cast<uint8_t*>(gl->MapBufferCHROMIUM(
1603 GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, GL_WRITE_ONLY));
1604 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
1605 // Buffer is required to be 4-byte aligned.
1606 CHECK(!(reinterpret_cast<intptr_t>(image) & 3));
1607 return image;
1610 void ResourceProvider::UnmapPixelBuffer(ResourceId id) {
1611 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1612 "ResourceProvider::UnmapPixelBuffer");
1614 Resource* resource = GetResource(id);
1615 DCHECK(resource->origin == Resource::INTERNAL);
1616 DCHECK_EQ(resource->exported_count, 0);
1617 DCHECK(!resource->image_id);
1619 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
1620 GLES2Interface* gl = ContextGL();
1621 DCHECK(gl);
1622 DCHECK(resource->gl_pixel_buffer_id);
1623 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1624 resource->gl_pixel_buffer_id);
1625 gl->UnmapBufferCHROMIUM(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM);
1626 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
1629 GLenum ResourceProvider::BindForSampling(ResourceId resource_id,
1630 GLenum unit,
1631 GLenum filter) {
1632 DCHECK(thread_checker_.CalledOnValidThread());
1633 GLES2Interface* gl = ContextGL();
1634 ResourceMap::iterator it = resources_.find(resource_id);
1635 DCHECK(it != resources_.end());
1636 Resource* resource = &it->second;
1637 DCHECK(resource->lock_for_read_count);
1638 DCHECK(!resource->locked_for_write || resource->set_pixels_completion_forced);
1640 ScopedSetActiveTexture scoped_active_tex(gl, unit);
1641 GLenum target = resource->target;
1642 gl->BindTexture(target, resource->gl_id);
1643 if (filter != resource->filter) {
1644 gl->TexParameteri(target, GL_TEXTURE_MIN_FILTER, filter);
1645 gl->TexParameteri(target, GL_TEXTURE_MAG_FILTER, filter);
1646 resource->filter = filter;
1649 if (resource->image_id && resource->dirty_image)
1650 BindImageForSampling(resource);
1652 return target;
1655 void ResourceProvider::BeginSetPixels(ResourceId id) {
1656 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1657 "ResourceProvider::BeginSetPixels");
1659 Resource* resource = GetResource(id);
1660 DCHECK(!resource->pending_set_pixels);
1662 LazyCreate(resource);
1663 DCHECK(resource->origin == Resource::INTERNAL);
1664 DCHECK(resource->gl_id || resource->allocated);
1665 DCHECK(ReadLockFenceHasPassed(resource));
1666 DCHECK(!resource->image_id);
1668 bool allocate = !resource->allocated;
1669 resource->allocated = true;
1670 LockForWrite(id);
1672 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
1673 DCHECK(resource->gl_id);
1674 GLES2Interface* gl = ContextGL();
1675 DCHECK(gl);
1676 DCHECK(resource->gl_pixel_buffer_id);
1677 DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D));
1678 gl->BindTexture(GL_TEXTURE_2D, resource->gl_id);
1679 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1680 resource->gl_pixel_buffer_id);
1681 if (!resource->gl_upload_query_id)
1682 gl->GenQueriesEXT(1, &resource->gl_upload_query_id);
1683 gl->BeginQueryEXT(GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM,
1684 resource->gl_upload_query_id);
1685 if (allocate) {
1686 gl->AsyncTexImage2DCHROMIUM(GL_TEXTURE_2D,
1687 0, /* level */
1688 GLInternalFormat(resource->format),
1689 resource->size.width(),
1690 resource->size.height(),
1691 0, /* border */
1692 GLDataFormat(resource->format),
1693 GLDataType(resource->format),
1694 NULL);
1695 } else {
1696 gl->AsyncTexSubImage2DCHROMIUM(GL_TEXTURE_2D,
1697 0, /* level */
1698 0, /* x */
1699 0, /* y */
1700 resource->size.width(),
1701 resource->size.height(),
1702 GLDataFormat(resource->format),
1703 GLDataType(resource->format),
1704 NULL);
1706 gl->EndQueryEXT(GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM);
1707 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
1709 resource->pending_set_pixels = true;
1710 resource->set_pixels_completion_forced = false;
1713 void ResourceProvider::ForceSetPixelsToComplete(ResourceId id) {
1714 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1715 "ResourceProvider::ForceSetPixelsToComplete");
1717 Resource* resource = GetResource(id);
1719 DCHECK(resource->locked_for_write);
1720 DCHECK(resource->pending_set_pixels);
1721 DCHECK(!resource->set_pixels_completion_forced);
1723 if (resource->gl_id) {
1724 GLES2Interface* gl = ContextGL();
1725 gl->BindTexture(GL_TEXTURE_2D, resource->gl_id);
1726 gl->WaitAsyncTexImage2DCHROMIUM(GL_TEXTURE_2D);
1727 gl->BindTexture(GL_TEXTURE_2D, 0);
1730 resource->set_pixels_completion_forced = true;
1733 bool ResourceProvider::DidSetPixelsComplete(ResourceId id) {
1734 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1735 "ResourceProvider::DidSetPixelsComplete");
1737 Resource* resource = GetResource(id);
1739 DCHECK(resource->locked_for_write);
1740 DCHECK(resource->pending_set_pixels);
1742 if (resource->gl_id) {
1743 GLES2Interface* gl = ContextGL();
1744 DCHECK(gl);
1745 DCHECK(resource->gl_upload_query_id);
1746 GLuint complete = 1;
1747 gl->GetQueryObjectuivEXT(
1748 resource->gl_upload_query_id, GL_QUERY_RESULT_AVAILABLE_EXT, &complete);
1749 if (!complete)
1750 return false;
1753 resource->pending_set_pixels = false;
1754 UnlockForWrite(resource);
1756 // Async set pixels commands are not necessarily processed in-sequence with
1757 // drawing commands. Read lock fences are required to ensure that async
1758 // commands don't access the resource while used for drawing.
1759 resource->read_lock_fences_enabled = true;
1761 return true;
1764 void ResourceProvider::CreateForTesting(ResourceId id) {
1765 LazyCreate(GetResource(id));
1768 GLenum ResourceProvider::TargetForTesting(ResourceId id) {
1769 Resource* resource = GetResource(id);
1770 return resource->target;
1773 void ResourceProvider::LazyCreate(Resource* resource) {
1774 if (resource->type != RESOURCE_TYPE_GL_TEXTURE ||
1775 resource->origin != Resource::INTERNAL)
1776 return;
1778 if (resource->gl_id)
1779 return;
1781 DCHECK(resource->texture_pool);
1782 DCHECK(resource->origin == Resource::INTERNAL);
1783 DCHECK(!resource->mailbox.IsValid());
1784 resource->gl_id = texture_id_allocator_->NextId();
1786 GLES2Interface* gl = ContextGL();
1787 DCHECK(gl);
1789 // Create and set texture properties. Allocation is delayed until needed.
1790 gl->BindTexture(resource->target, resource->gl_id);
1791 gl->TexParameteri(resource->target, GL_TEXTURE_MIN_FILTER,
1792 resource->original_filter);
1793 gl->TexParameteri(resource->target, GL_TEXTURE_MAG_FILTER,
1794 resource->original_filter);
1795 gl->TexParameteri(resource->target, GL_TEXTURE_WRAP_S, resource->wrap_mode);
1796 gl->TexParameteri(resource->target, GL_TEXTURE_WRAP_T, resource->wrap_mode);
1797 gl->TexParameteri(resource->target, GL_TEXTURE_POOL_CHROMIUM,
1798 resource->texture_pool);
1799 if (use_texture_usage_hint_ && (resource->hint & TEXTURE_HINT_FRAMEBUFFER)) {
1800 gl->TexParameteri(resource->target, GL_TEXTURE_USAGE_ANGLE,
1801 GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
1805 void ResourceProvider::AllocateForTesting(ResourceId id) {
1806 LazyAllocate(GetResource(id));
1809 void ResourceProvider::LazyAllocate(Resource* resource) {
1810 DCHECK(resource);
1811 if (resource->allocated)
1812 return;
1813 LazyCreate(resource);
1814 if (!resource->gl_id)
1815 return;
1816 resource->allocated = true;
1817 GLES2Interface* gl = ContextGL();
1818 gfx::Size& size = resource->size;
1819 ResourceFormat format = resource->format;
1820 gl->BindTexture(resource->target, resource->gl_id);
1821 if (use_texture_storage_ext_ &&
1822 IsFormatSupportedForStorage(format, use_texture_format_bgra_) &&
1823 (resource->hint & TEXTURE_HINT_IMMUTABLE)) {
1824 GLenum storage_format = TextureToStorageFormat(format);
1825 gl->TexStorage2DEXT(resource->target, 1, storage_format, size.width(),
1826 size.height());
1827 } else {
1828 // ETC1 does not support preallocation.
1829 if (format != ETC1) {
1830 gl->TexImage2D(resource->target, 0, GLInternalFormat(format),
1831 size.width(), size.height(), 0, GLDataFormat(format),
1832 GLDataType(format), NULL);
1837 void ResourceProvider::BindImageForSampling(Resource* resource) {
1838 GLES2Interface* gl = ContextGL();
1839 DCHECK(resource->gl_id);
1840 DCHECK(resource->image_id);
1842 // Release image currently bound to texture.
1843 if (resource->bound_image_id)
1844 gl->ReleaseTexImage2DCHROMIUM(resource->target, resource->bound_image_id);
1845 gl->BindTexImage2DCHROMIUM(resource->target, resource->image_id);
1846 resource->bound_image_id = resource->image_id;
1847 resource->dirty_image = false;
1850 void ResourceProvider::CopyResource(ResourceId source_id,
1851 ResourceId dest_id,
1852 const gfx::Rect& rect) {
1853 TRACE_EVENT0("cc", "ResourceProvider::CopyResource");
1855 Resource* source_resource = GetResource(source_id);
1856 DCHECK(!source_resource->lock_for_read_count);
1857 DCHECK(source_resource->origin == Resource::INTERNAL);
1858 DCHECK_EQ(source_resource->exported_count, 0);
1859 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, source_resource->type);
1860 LazyAllocate(source_resource);
1862 Resource* dest_resource = GetResource(dest_id);
1863 DCHECK(!dest_resource->locked_for_write);
1864 DCHECK(!dest_resource->lock_for_read_count);
1865 DCHECK(dest_resource->origin == Resource::INTERNAL);
1866 DCHECK_EQ(dest_resource->exported_count, 0);
1867 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, dest_resource->type);
1868 LazyAllocate(dest_resource);
1870 DCHECK_EQ(source_resource->type, dest_resource->type);
1871 DCHECK_EQ(source_resource->format, dest_resource->format);
1872 DCHECK(source_resource->size == dest_resource->size);
1873 DCHECK(gfx::Rect(dest_resource->size).Contains(rect));
1875 GLES2Interface* gl = ContextGL();
1876 DCHECK(gl);
1877 if (source_resource->image_id && source_resource->dirty_image) {
1878 gl->BindTexture(source_resource->target, source_resource->gl_id);
1879 BindImageForSampling(source_resource);
1881 if (use_sync_query_) {
1882 if (!source_resource->gl_read_lock_query_id)
1883 gl->GenQueriesEXT(1, &source_resource->gl_read_lock_query_id);
1884 #if defined(OS_CHROMEOS)
1885 // TODO(reveman): This avoids a performance problem on some ChromeOS
1886 // devices. This needs to be removed to support native GpuMemoryBuffer
1887 // implementations. crbug.com/436314
1888 gl->BeginQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM,
1889 source_resource->gl_read_lock_query_id);
1890 #else
1891 gl->BeginQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM,
1892 source_resource->gl_read_lock_query_id);
1893 #endif
1895 DCHECK(!dest_resource->image_id);
1896 dest_resource->allocated = true;
1897 gl->CopySubTextureCHROMIUM(dest_resource->target, source_resource->gl_id,
1898 dest_resource->gl_id, rect.x(), rect.y(), rect.x(),
1899 rect.y(), rect.width(), rect.height(),
1900 false, false, false);
1901 if (source_resource->gl_read_lock_query_id) {
1902 // End query and create a read lock fence that will prevent access to
1903 // source resource until CopySubTextureCHROMIUM command has completed.
1904 #if defined(OS_CHROMEOS)
1905 gl->EndQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM);
1906 #else
1907 gl->EndQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM);
1908 #endif
1909 source_resource->read_lock_fence = make_scoped_refptr(
1910 new CopyTextureFence(gl, source_resource->gl_read_lock_query_id));
1911 } else {
1912 // Create a SynchronousFence when CHROMIUM_sync_query extension is missing.
1913 // Try to use one synchronous fence for as many CopyResource operations as
1914 // possible as that reduce the number of times we have to synchronize with
1915 // the GL.
1916 if (!synchronous_fence_.get() || synchronous_fence_->has_synchronized())
1917 synchronous_fence_ = make_scoped_refptr(new SynchronousFence(gl));
1918 source_resource->read_lock_fence = synchronous_fence_;
1919 source_resource->read_lock_fence->Set();
1923 void ResourceProvider::WaitSyncPointIfNeeded(ResourceId id) {
1924 Resource* resource = GetResource(id);
1925 DCHECK_EQ(resource->exported_count, 0);
1926 DCHECK(resource->allocated);
1927 if (resource->type != RESOURCE_TYPE_GL_TEXTURE || resource->gl_id)
1928 return;
1929 if (!resource->mailbox.sync_point())
1930 return;
1931 DCHECK(resource->mailbox.IsValid());
1932 GLES2Interface* gl = ContextGL();
1933 DCHECK(gl);
1934 gl->WaitSyncPointCHROMIUM(resource->mailbox.sync_point());
1935 resource->mailbox.set_sync_point(0);
1938 void ResourceProvider::WaitReadLockIfNeeded(ResourceId id) {
1939 Resource* resource = GetResource(id);
1940 DCHECK_EQ(resource->exported_count, 0);
1941 if (!resource->read_lock_fence.get())
1942 return;
1944 resource->read_lock_fence->Wait();
1947 GLint ResourceProvider::GetActiveTextureUnit(GLES2Interface* gl) {
1948 GLint active_unit = 0;
1949 gl->GetIntegerv(GL_ACTIVE_TEXTURE, &active_unit);
1950 return active_unit;
1953 void ResourceProvider::ValidateResource(ResourceId id) const {
1954 DCHECK(thread_checker_.CalledOnValidThread());
1955 DCHECK(id);
1956 DCHECK(resources_.find(id) != resources_.end());
1959 GLES2Interface* ResourceProvider::ContextGL() const {
1960 ContextProvider* context_provider = output_surface_->context_provider();
1961 return context_provider ? context_provider->ContextGL() : NULL;
1964 class GrContext* ResourceProvider::GrContext(bool worker_context) const {
1965 ContextProvider* context_provider =
1966 worker_context ? output_surface_->worker_context_provider()
1967 : output_surface_->context_provider();
1968 return context_provider ? context_provider->GrContext() : NULL;
1971 bool ResourceProvider::OnMemoryDump(
1972 const base::trace_event::MemoryDumpArgs& args,
1973 base::trace_event::ProcessMemoryDump* pmd) {
1974 DCHECK(thread_checker_.CalledOnValidThread());
1976 const uint64 tracing_process_id =
1977 base::trace_event::MemoryDumpManager::GetInstance()
1978 ->GetTracingProcessId();
1980 for (const auto& resource_entry : resources_) {
1981 const auto& resource = resource_entry.second;
1983 // TODO(ericrk): Add per-compositor ID in name.
1984 std::string dump_name = base::StringPrintf("cc/resource_memory/resource_%d",
1985 resource_entry.first);
1986 base::trace_event::MemoryAllocatorDump* dump =
1987 pmd->CreateAllocatorDump(dump_name);
1989 uint64_t total_bytes = ResourceUtil::UncheckedSizeInBytesAligned<size_t>(
1990 resource.size, resource.format);
1991 dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
1992 base::trace_event::MemoryAllocatorDump::kUnitsBytes,
1993 static_cast<uint64_t>(total_bytes));
1995 // Resources which are shared across processes require a shared GUID to
1996 // prevent double counting the memory. We currently support shared GUIDs for
1997 // GpuMemoryBuffer, SharedBitmap, and GL backed resources.
1998 base::trace_event::MemoryAllocatorDumpGuid guid;
1999 if (resource.gpu_memory_buffer) {
2000 guid = gfx::GetGpuMemoryBufferGUIDForTracing(
2001 tracing_process_id, resource.gpu_memory_buffer->GetHandle().id);
2002 } else if (resource.shared_bitmap) {
2003 guid = GetSharedBitmapGUIDForTracing(resource.shared_bitmap->id());
2004 } else if (resource.gl_id && resource.allocated) {
2005 guid =
2006 gfx::GetGLTextureGUIDForTracing(tracing_process_id, resource.gl_id);
2009 if (!guid.empty()) {
2010 const int kImportance = 2;
2011 pmd->CreateSharedGlobalAllocatorDump(guid);
2012 pmd->AddOwnershipEdge(dump->guid(), guid, kImportance);
2016 return true;
2019 } // namespace cc