Mark NavigateTest@testNavigateMany() as flaky
[chromium-blink-merge.git] / cc / resources / resource_provider.cc
blob9f680669c089de2a3781732f5f4fca54987caf44
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/trace_event/trace_event.h"
17 #include "cc/base/math_util.h"
18 #include "cc/resources/platform_color.h"
19 #include "cc/resources/returned_resource.h"
20 #include "cc/resources/shared_bitmap_manager.h"
21 #include "cc/resources/transferable_resource.h"
22 #include "gpu/GLES2/gl2extchromium.h"
23 #include "gpu/command_buffer/client/gles2_interface.h"
24 #include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
25 #include "third_party/khronos/GLES2/gl2.h"
26 #include "third_party/khronos/GLES2/gl2ext.h"
27 #include "third_party/skia/include/core/SkSurface.h"
28 #include "third_party/skia/include/gpu/GrContext.h"
29 #include "third_party/skia/include/gpu/GrTextureProvider.h"
30 #include "ui/gfx/geometry/rect.h"
31 #include "ui/gfx/geometry/vector2d.h"
32 #include "ui/gfx/gpu_memory_buffer.h"
34 using gpu::gles2::GLES2Interface;
36 namespace cc {
38 class IdAllocator {
39 public:
40 virtual ~IdAllocator() {}
42 virtual GLuint NextId() = 0;
44 protected:
45 IdAllocator(GLES2Interface* gl, size_t id_allocation_chunk_size)
46 : gl_(gl),
47 id_allocation_chunk_size_(id_allocation_chunk_size),
48 ids_(new GLuint[id_allocation_chunk_size]),
49 next_id_index_(id_allocation_chunk_size) {
50 DCHECK(id_allocation_chunk_size_);
51 DCHECK_LE(id_allocation_chunk_size_,
52 static_cast<size_t>(std::numeric_limits<int>::max()));
55 GLES2Interface* gl_;
56 const size_t id_allocation_chunk_size_;
57 scoped_ptr<GLuint[]> ids_;
58 size_t next_id_index_;
61 namespace {
63 GLenum TextureToStorageFormat(ResourceFormat format) {
64 GLenum storage_format = GL_RGBA8_OES;
65 switch (format) {
66 case RGBA_8888:
67 break;
68 case BGRA_8888:
69 storage_format = GL_BGRA8_EXT;
70 break;
71 case RGBA_4444:
72 case ALPHA_8:
73 case LUMINANCE_8:
74 case RGB_565:
75 case ETC1:
76 case RED_8:
77 NOTREACHED();
78 break;
81 return storage_format;
84 bool IsFormatSupportedForStorage(ResourceFormat format, bool use_bgra) {
85 switch (format) {
86 case RGBA_8888:
87 return true;
88 case BGRA_8888:
89 return use_bgra;
90 case RGBA_4444:
91 case ALPHA_8:
92 case LUMINANCE_8:
93 case RGB_565:
94 case ETC1:
95 case RED_8:
96 return false;
98 return false;
101 GrPixelConfig ToGrPixelConfig(ResourceFormat format) {
102 switch (format) {
103 case RGBA_8888:
104 return kRGBA_8888_GrPixelConfig;
105 case BGRA_8888:
106 return kBGRA_8888_GrPixelConfig;
107 case RGBA_4444:
108 return kRGBA_4444_GrPixelConfig;
109 default:
110 break;
112 DCHECK(false) << "Unsupported resource format.";
113 return kSkia8888_GrPixelConfig;
116 gfx::GpuMemoryBuffer::Format ToGpuMemoryBufferFormat(ResourceFormat format) {
117 switch (format) {
118 case RGBA_8888:
119 return gfx::GpuMemoryBuffer::RGBA_8888;
120 case BGRA_8888:
121 return gfx::GpuMemoryBuffer::BGRA_8888;
122 case RGBA_4444:
123 return gfx::GpuMemoryBuffer::RGBA_4444;
124 case ALPHA_8:
125 case LUMINANCE_8:
126 case RGB_565:
127 case ETC1:
128 case RED_8:
129 break;
131 NOTREACHED();
132 return gfx::GpuMemoryBuffer::RGBA_8888;
135 class ScopedSetActiveTexture {
136 public:
137 ScopedSetActiveTexture(GLES2Interface* gl, GLenum unit)
138 : gl_(gl), unit_(unit) {
139 DCHECK_EQ(GL_TEXTURE0, ResourceProvider::GetActiveTextureUnit(gl_));
141 if (unit_ != GL_TEXTURE0)
142 gl_->ActiveTexture(unit_);
145 ~ScopedSetActiveTexture() {
146 // Active unit being GL_TEXTURE0 is effectively the ground state.
147 if (unit_ != GL_TEXTURE0)
148 gl_->ActiveTexture(GL_TEXTURE0);
151 private:
152 GLES2Interface* gl_;
153 GLenum unit_;
156 class TextureIdAllocator : public IdAllocator {
157 public:
158 TextureIdAllocator(GLES2Interface* gl,
159 size_t texture_id_allocation_chunk_size)
160 : IdAllocator(gl, texture_id_allocation_chunk_size) {}
161 ~TextureIdAllocator() override {
162 gl_->DeleteTextures(
163 static_cast<int>(id_allocation_chunk_size_ - next_id_index_),
164 ids_.get() + next_id_index_);
167 // Overridden from IdAllocator:
168 GLuint NextId() override {
169 if (next_id_index_ == id_allocation_chunk_size_) {
170 gl_->GenTextures(static_cast<int>(id_allocation_chunk_size_), ids_.get());
171 next_id_index_ = 0;
174 return ids_[next_id_index_++];
177 private:
178 DISALLOW_COPY_AND_ASSIGN(TextureIdAllocator);
181 class BufferIdAllocator : public IdAllocator {
182 public:
183 BufferIdAllocator(GLES2Interface* gl, size_t buffer_id_allocation_chunk_size)
184 : IdAllocator(gl, buffer_id_allocation_chunk_size) {}
185 ~BufferIdAllocator() override {
186 gl_->DeleteBuffers(
187 static_cast<int>(id_allocation_chunk_size_ - next_id_index_),
188 ids_.get() + next_id_index_);
191 // Overridden from IdAllocator:
192 GLuint NextId() override {
193 if (next_id_index_ == id_allocation_chunk_size_) {
194 gl_->GenBuffers(static_cast<int>(id_allocation_chunk_size_), ids_.get());
195 next_id_index_ = 0;
198 return ids_[next_id_index_++];
201 private:
202 DISALLOW_COPY_AND_ASSIGN(BufferIdAllocator);
205 // Query object based fence implementation used to detect completion of copy
206 // texture operations. Fence has passed when query result is available.
207 class CopyTextureFence : public ResourceProvider::Fence {
208 public:
209 CopyTextureFence(gpu::gles2::GLES2Interface* gl, unsigned query_id)
210 : gl_(gl), query_id_(query_id) {}
212 // Overridden from ResourceProvider::Fence:
213 void Set() override {}
214 bool HasPassed() override {
215 unsigned available = 1;
216 gl_->GetQueryObjectuivEXT(
217 query_id_, GL_QUERY_RESULT_AVAILABLE_EXT, &available);
218 if (!available)
219 return false;
221 ProcessResult();
222 return true;
224 void Wait() override {
225 // ProcessResult() will wait for result to become available.
226 ProcessResult();
229 private:
230 ~CopyTextureFence() override {}
232 void ProcessResult() {
233 unsigned time_elapsed_us = 0;
234 gl_->GetQueryObjectuivEXT(query_id_, GL_QUERY_RESULT_EXT, &time_elapsed_us);
235 UMA_HISTOGRAM_CUSTOM_COUNTS("Renderer4.CopyTextureLatency", time_elapsed_us,
236 0, 256000, 50);
239 gpu::gles2::GLES2Interface* gl_;
240 unsigned query_id_;
242 DISALLOW_COPY_AND_ASSIGN(CopyTextureFence);
245 } // namespace
247 ResourceProvider::Resource::~Resource() {}
249 ResourceProvider::Resource::Resource(GLuint texture_id,
250 const gfx::Size& size,
251 Origin origin,
252 GLenum target,
253 GLenum filter,
254 GLenum texture_pool,
255 GLint wrap_mode,
256 TextureHint hint,
257 ResourceFormat format)
258 : child_id(0),
259 gl_id(texture_id),
260 gl_pixel_buffer_id(0),
261 gl_upload_query_id(0),
262 gl_read_lock_query_id(0),
263 pixels(NULL),
264 lock_for_read_count(0),
265 imported_count(0),
266 exported_count(0),
267 dirty_image(false),
268 locked_for_write(false),
269 lost(false),
270 marked_for_deletion(false),
271 pending_set_pixels(false),
272 set_pixels_completion_forced(false),
273 allocated(false),
274 read_lock_fences_enabled(false),
275 has_shared_bitmap_id(false),
276 read_lock_fence(NULL),
277 size(size),
278 origin(origin),
279 target(target),
280 original_filter(filter),
281 filter(filter),
282 image_id(0),
283 bound_image_id(0),
284 texture_pool(texture_pool),
285 wrap_mode(wrap_mode),
286 hint(hint),
287 type(RESOURCE_TYPE_GL_TEXTURE),
288 format(format),
289 shared_bitmap(NULL),
290 gpu_memory_buffer(NULL) {
291 DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT);
292 DCHECK_EQ(origin == INTERNAL, !!texture_pool);
295 ResourceProvider::Resource::Resource(uint8_t* pixels,
296 SharedBitmap* bitmap,
297 const gfx::Size& size,
298 Origin origin,
299 GLenum filter,
300 GLint wrap_mode)
301 : child_id(0),
302 gl_id(0),
303 gl_pixel_buffer_id(0),
304 gl_upload_query_id(0),
305 gl_read_lock_query_id(0),
306 pixels(pixels),
307 lock_for_read_count(0),
308 imported_count(0),
309 exported_count(0),
310 dirty_image(false),
311 locked_for_write(false),
312 lost(false),
313 marked_for_deletion(false),
314 pending_set_pixels(false),
315 set_pixels_completion_forced(false),
316 allocated(false),
317 read_lock_fences_enabled(false),
318 has_shared_bitmap_id(!!bitmap),
319 read_lock_fence(NULL),
320 size(size),
321 origin(origin),
322 target(0),
323 original_filter(filter),
324 filter(filter),
325 image_id(0),
326 bound_image_id(0),
327 texture_pool(0),
328 wrap_mode(wrap_mode),
329 hint(TEXTURE_HINT_IMMUTABLE),
330 type(RESOURCE_TYPE_BITMAP),
331 format(RGBA_8888),
332 shared_bitmap(bitmap),
333 gpu_memory_buffer(NULL) {
334 DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT);
335 DCHECK(origin == DELEGATED || pixels);
336 if (bitmap)
337 shared_bitmap_id = bitmap->id();
340 ResourceProvider::Resource::Resource(const SharedBitmapId& bitmap_id,
341 const gfx::Size& size,
342 Origin origin,
343 GLenum filter,
344 GLint wrap_mode)
345 : child_id(0),
346 gl_id(0),
347 gl_pixel_buffer_id(0),
348 gl_upload_query_id(0),
349 gl_read_lock_query_id(0),
350 pixels(NULL),
351 lock_for_read_count(0),
352 imported_count(0),
353 exported_count(0),
354 dirty_image(false),
355 locked_for_write(false),
356 lost(false),
357 marked_for_deletion(false),
358 pending_set_pixels(false),
359 set_pixels_completion_forced(false),
360 allocated(false),
361 read_lock_fences_enabled(false),
362 has_shared_bitmap_id(true),
363 read_lock_fence(NULL),
364 size(size),
365 origin(origin),
366 target(0),
367 original_filter(filter),
368 filter(filter),
369 image_id(0),
370 bound_image_id(0),
371 texture_pool(0),
372 wrap_mode(wrap_mode),
373 hint(TEXTURE_HINT_IMMUTABLE),
374 type(RESOURCE_TYPE_BITMAP),
375 format(RGBA_8888),
376 shared_bitmap_id(bitmap_id),
377 shared_bitmap(NULL),
378 gpu_memory_buffer(NULL) {
379 DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT);
382 ResourceProvider::Child::Child()
383 : marked_for_deletion(false), needs_sync_points(true) {
386 ResourceProvider::Child::~Child() {}
388 scoped_ptr<ResourceProvider> ResourceProvider::Create(
389 OutputSurface* output_surface,
390 SharedBitmapManager* shared_bitmap_manager,
391 gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
392 BlockingTaskRunner* blocking_main_thread_task_runner,
393 int highp_threshold_min,
394 bool use_rgba_4444_texture_format,
395 size_t id_allocation_chunk_size,
396 bool use_persistent_map_for_gpu_memory_buffers) {
397 scoped_ptr<ResourceProvider> resource_provider(new ResourceProvider(
398 output_surface, shared_bitmap_manager, gpu_memory_buffer_manager,
399 blocking_main_thread_task_runner, highp_threshold_min,
400 use_rgba_4444_texture_format, id_allocation_chunk_size,
401 use_persistent_map_for_gpu_memory_buffers));
402 resource_provider->Initialize();
403 return resource_provider;
406 ResourceProvider::~ResourceProvider() {
407 while (!children_.empty())
408 DestroyChildInternal(children_.begin(), FOR_SHUTDOWN);
409 while (!resources_.empty())
410 DeleteResourceInternal(resources_.begin(), FOR_SHUTDOWN);
412 GLES2Interface* gl = ContextGL();
413 if (default_resource_type_ != RESOURCE_TYPE_GL_TEXTURE) {
414 // We are not in GL mode, but double check before returning.
415 DCHECK(!gl);
416 return;
419 DCHECK(gl);
420 #if DCHECK_IS_ON()
421 // Check that all GL resources has been deleted.
422 for (ResourceMap::const_iterator itr = resources_.begin();
423 itr != resources_.end(); ++itr) {
424 DCHECK_NE(RESOURCE_TYPE_GL_TEXTURE, itr->second.type);
426 #endif // DCHECK_IS_ON()
428 texture_id_allocator_ = nullptr;
429 buffer_id_allocator_ = nullptr;
430 gl->Finish();
433 bool ResourceProvider::InUseByConsumer(ResourceId id) {
434 Resource* resource = GetResource(id);
435 return resource->lock_for_read_count > 0 || resource->exported_count > 0 ||
436 resource->lost;
439 bool ResourceProvider::IsLost(ResourceId id) {
440 Resource* resource = GetResource(id);
441 return resource->lost;
444 void ResourceProvider::LoseResourceForTesting(ResourceId id) {
445 Resource* resource = GetResource(id);
446 DCHECK(resource);
447 resource->lost = true;
450 ResourceId ResourceProvider::CreateResource(const gfx::Size& size,
451 GLint wrap_mode,
452 TextureHint hint,
453 ResourceFormat format) {
454 DCHECK(!size.IsEmpty());
455 switch (default_resource_type_) {
456 case RESOURCE_TYPE_GL_TEXTURE:
457 return CreateGLTexture(size,
458 GL_TEXTURE_2D,
459 GL_TEXTURE_POOL_UNMANAGED_CHROMIUM,
460 wrap_mode,
461 hint,
462 format);
463 case RESOURCE_TYPE_BITMAP:
464 DCHECK_EQ(RGBA_8888, format);
465 return CreateBitmap(size, wrap_mode);
468 LOG(FATAL) << "Invalid default resource type.";
469 return 0;
472 ResourceId ResourceProvider::CreateManagedResource(const gfx::Size& size,
473 GLenum target,
474 GLint wrap_mode,
475 TextureHint hint,
476 ResourceFormat format) {
477 DCHECK(!size.IsEmpty());
478 switch (default_resource_type_) {
479 case RESOURCE_TYPE_GL_TEXTURE:
480 return CreateGLTexture(size,
481 target,
482 GL_TEXTURE_POOL_MANAGED_CHROMIUM,
483 wrap_mode,
484 hint,
485 format);
486 case RESOURCE_TYPE_BITMAP:
487 DCHECK_EQ(RGBA_8888, format);
488 return CreateBitmap(size, wrap_mode);
491 LOG(FATAL) << "Invalid default resource type.";
492 return 0;
495 ResourceId ResourceProvider::CreateGLTexture(const gfx::Size& size,
496 GLenum target,
497 GLenum texture_pool,
498 GLint wrap_mode,
499 TextureHint hint,
500 ResourceFormat format) {
501 DCHECK_LE(size.width(), max_texture_size_);
502 DCHECK_LE(size.height(), max_texture_size_);
503 DCHECK(thread_checker_.CalledOnValidThread());
505 ResourceId id = next_id_++;
506 Resource* resource = InsertResource(
507 id, Resource(0, size, Resource::INTERNAL, target, GL_LINEAR, texture_pool,
508 wrap_mode, hint, format));
509 resource->allocated = false;
510 return id;
513 ResourceId ResourceProvider::CreateBitmap(const gfx::Size& size,
514 GLint wrap_mode) {
515 DCHECK(thread_checker_.CalledOnValidThread());
517 scoped_ptr<SharedBitmap> bitmap =
518 shared_bitmap_manager_->AllocateSharedBitmap(size);
519 uint8_t* pixels = bitmap->pixels();
520 DCHECK(pixels);
522 ResourceId id = next_id_++;
523 Resource* resource =
524 InsertResource(id, Resource(pixels, bitmap.release(), size,
525 Resource::INTERNAL, GL_LINEAR, wrap_mode));
526 resource->allocated = true;
527 return id;
530 ResourceId ResourceProvider::CreateResourceFromIOSurface(
531 const gfx::Size& size,
532 unsigned io_surface_id) {
533 DCHECK(thread_checker_.CalledOnValidThread());
535 ResourceId id = next_id_++;
536 Resource* resource = InsertResource(
537 id, Resource(0, gfx::Size(), Resource::INTERNAL, GL_TEXTURE_RECTANGLE_ARB,
538 GL_LINEAR, GL_TEXTURE_POOL_UNMANAGED_CHROMIUM,
539 GL_CLAMP_TO_EDGE, TEXTURE_HINT_IMMUTABLE, RGBA_8888));
540 LazyCreate(resource);
541 GLES2Interface* gl = ContextGL();
542 DCHECK(gl);
543 gl->BindTexture(GL_TEXTURE_RECTANGLE_ARB, resource->gl_id);
544 gl->TexImageIOSurface2DCHROMIUM(
545 GL_TEXTURE_RECTANGLE_ARB, size.width(), size.height(), io_surface_id, 0);
546 resource->allocated = true;
547 return id;
550 ResourceId ResourceProvider::CreateResourceFromTextureMailbox(
551 const TextureMailbox& mailbox,
552 scoped_ptr<SingleReleaseCallbackImpl> release_callback_impl,
553 bool read_lock_fences_enabled) {
554 DCHECK(thread_checker_.CalledOnValidThread());
555 // Just store the information. Mailbox will be consumed in LockForRead().
556 ResourceId id = next_id_++;
557 DCHECK(mailbox.IsValid());
558 Resource* resource = nullptr;
559 if (mailbox.IsTexture()) {
560 resource = InsertResource(
561 id, Resource(0, gfx::Size(), Resource::EXTERNAL, mailbox.target(),
562 mailbox.nearest_neighbor() ? GL_NEAREST : GL_LINEAR, 0,
563 GL_CLAMP_TO_EDGE, TEXTURE_HINT_IMMUTABLE, RGBA_8888));
564 } else {
565 DCHECK(mailbox.IsSharedMemory());
566 SharedBitmap* shared_bitmap = mailbox.shared_bitmap();
567 uint8_t* pixels = shared_bitmap->pixels();
568 DCHECK(pixels);
569 resource = InsertResource(
570 id, Resource(pixels, shared_bitmap, mailbox.size_in_pixels(),
571 Resource::EXTERNAL, GL_LINEAR, GL_CLAMP_TO_EDGE));
573 resource->allocated = true;
574 resource->mailbox = mailbox;
575 resource->release_callback_impl =
576 base::Bind(&SingleReleaseCallbackImpl::Run,
577 base::Owned(release_callback_impl.release()));
578 resource->read_lock_fences_enabled = read_lock_fences_enabled;
579 return id;
582 ResourceId ResourceProvider::CreateResourceFromTextureMailbox(
583 const TextureMailbox& mailbox,
584 scoped_ptr<SingleReleaseCallbackImpl> release_callback_impl) {
585 return CreateResourceFromTextureMailbox(mailbox, release_callback_impl.Pass(),
586 false);
589 void ResourceProvider::DeleteResource(ResourceId id) {
590 DCHECK(thread_checker_.CalledOnValidThread());
591 ResourceMap::iterator it = resources_.find(id);
592 CHECK(it != resources_.end());
593 Resource* resource = &it->second;
594 DCHECK(!resource->marked_for_deletion);
595 DCHECK_EQ(resource->imported_count, 0);
596 DCHECK(resource->pending_set_pixels || !resource->locked_for_write);
598 if (resource->exported_count > 0 || resource->lock_for_read_count > 0 ||
599 !ReadLockFenceHasPassed(resource)) {
600 resource->marked_for_deletion = true;
601 return;
602 } else {
603 DeleteResourceInternal(it, NORMAL);
607 void ResourceProvider::DeleteResourceInternal(ResourceMap::iterator it,
608 DeleteStyle style) {
609 TRACE_EVENT0("cc", "ResourceProvider::DeleteResourceInternal");
610 Resource* resource = &it->second;
611 bool lost_resource = resource->lost;
613 DCHECK(resource->exported_count == 0 || style != NORMAL);
614 if (style == FOR_SHUTDOWN && resource->exported_count > 0)
615 lost_resource = true;
617 if (resource->image_id) {
618 DCHECK(resource->origin == Resource::INTERNAL);
619 GLES2Interface* gl = ContextGL();
620 DCHECK(gl);
621 gl->DestroyImageCHROMIUM(resource->image_id);
623 if (resource->gl_upload_query_id) {
624 DCHECK(resource->origin == Resource::INTERNAL);
625 GLES2Interface* gl = ContextGL();
626 DCHECK(gl);
627 gl->DeleteQueriesEXT(1, &resource->gl_upload_query_id);
629 if (resource->gl_read_lock_query_id) {
630 DCHECK(resource->origin == Resource::INTERNAL);
631 GLES2Interface* gl = ContextGL();
632 DCHECK(gl);
633 gl->DeleteQueriesEXT(1, &resource->gl_read_lock_query_id);
635 if (resource->gl_pixel_buffer_id) {
636 DCHECK(resource->origin == Resource::INTERNAL);
637 GLES2Interface* gl = ContextGL();
638 DCHECK(gl);
639 gl->DeleteBuffers(1, &resource->gl_pixel_buffer_id);
641 if (resource->origin == Resource::EXTERNAL) {
642 DCHECK(resource->mailbox.IsValid());
643 GLuint sync_point = resource->mailbox.sync_point();
644 if (resource->type == RESOURCE_TYPE_GL_TEXTURE) {
645 DCHECK(resource->mailbox.IsTexture());
646 lost_resource |= lost_output_surface_;
647 GLES2Interface* gl = ContextGL();
648 DCHECK(gl);
649 if (resource->gl_id) {
650 gl->DeleteTextures(1, &resource->gl_id);
651 resource->gl_id = 0;
652 if (!lost_resource)
653 sync_point = gl->InsertSyncPointCHROMIUM();
655 } else {
656 DCHECK(resource->mailbox.IsSharedMemory());
657 resource->shared_bitmap = nullptr;
658 resource->pixels = nullptr;
660 resource->release_callback_impl.Run(
661 sync_point, lost_resource, blocking_main_thread_task_runner_);
663 if (resource->gl_id) {
664 GLES2Interface* gl = ContextGL();
665 DCHECK(gl);
666 gl->DeleteTextures(1, &resource->gl_id);
667 resource->gl_id = 0;
669 if (resource->shared_bitmap) {
670 DCHECK(resource->origin != Resource::EXTERNAL);
671 DCHECK_EQ(RESOURCE_TYPE_BITMAP, resource->type);
672 delete resource->shared_bitmap;
673 resource->pixels = NULL;
675 if (resource->pixels) {
676 DCHECK(resource->origin == Resource::INTERNAL);
677 delete[] resource->pixels;
678 resource->pixels = NULL;
680 if (resource->gpu_memory_buffer) {
681 DCHECK(resource->origin == Resource::INTERNAL);
682 delete resource->gpu_memory_buffer;
683 resource->gpu_memory_buffer = NULL;
685 resources_.erase(it);
688 ResourceProvider::ResourceType ResourceProvider::GetResourceType(
689 ResourceId id) {
690 return GetResource(id)->type;
693 void ResourceProvider::CopyToResource(ResourceId id,
694 const uint8_t* image,
695 const gfx::Size& image_size) {
696 Resource* resource = GetResource(id);
697 DCHECK(!resource->locked_for_write);
698 DCHECK(!resource->lock_for_read_count);
699 DCHECK(resource->origin == Resource::INTERNAL);
700 DCHECK_EQ(resource->exported_count, 0);
701 DCHECK(ReadLockFenceHasPassed(resource));
702 LazyAllocate(resource);
704 DCHECK_EQ(image_size.width(), resource->size.width());
705 DCHECK_EQ(image_size.height(), resource->size.height());
707 if (resource->type == RESOURCE_TYPE_BITMAP) {
708 DCHECK_EQ(RESOURCE_TYPE_BITMAP, resource->type);
709 DCHECK(resource->allocated);
710 DCHECK_EQ(RGBA_8888, resource->format);
711 SkImageInfo source_info =
712 SkImageInfo::MakeN32Premul(image_size.width(), image_size.height());
713 size_t image_stride = image_size.width() * 4;
715 ScopedWriteLockSoftware lock(this, id);
716 SkCanvas dest(lock.sk_bitmap());
717 dest.writePixels(source_info, image, image_stride, 0, 0);
718 } else {
719 DCHECK(resource->gl_id);
720 DCHECK(!resource->pending_set_pixels);
721 DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D));
722 GLES2Interface* gl = ContextGL();
723 DCHECK(gl);
724 gl->BindTexture(GL_TEXTURE_2D, resource->gl_id);
726 if (resource->format == ETC1) {
727 base::CheckedNumeric<int> num_bytes = BitsPerPixel(ETC1);
728 num_bytes *= image_size.width();
729 num_bytes *= image_size.height();
730 num_bytes /= 8;
731 gl->CompressedTexImage2D(GL_TEXTURE_2D, 0, GLInternalFormat(ETC1),
732 image_size.width(), image_size.height(), 0,
733 num_bytes.ValueOrDie(), image);
734 } else {
735 gl->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, image_size.width(),
736 image_size.height(), GLDataFormat(resource->format),
737 GLDataType(resource->format), image);
742 ResourceProvider::Resource* ResourceProvider::InsertResource(
743 ResourceId id,
744 const Resource& resource) {
745 std::pair<ResourceMap::iterator, bool> result =
746 resources_.insert(ResourceMap::value_type(id, resource));
747 DCHECK(result.second);
748 return &result.first->second;
751 ResourceProvider::Resource* ResourceProvider::GetResource(ResourceId id) {
752 DCHECK(thread_checker_.CalledOnValidThread());
753 DCHECK(id);
754 ResourceMap::iterator it = resources_.find(id);
755 DCHECK(it != resources_.end());
756 return &it->second;
759 const ResourceProvider::Resource* ResourceProvider::LockForRead(ResourceId id) {
760 Resource* resource = GetResource(id);
761 DCHECK(!resource->locked_for_write ||
762 resource->set_pixels_completion_forced) <<
763 "locked for write: " << resource->locked_for_write <<
764 " pixels completion forced: " << resource->set_pixels_completion_forced;
765 DCHECK_EQ(resource->exported_count, 0);
766 // Uninitialized! Call SetPixels or LockForWrite first.
767 DCHECK(resource->allocated);
769 LazyCreate(resource);
771 if (resource->type == RESOURCE_TYPE_GL_TEXTURE && !resource->gl_id) {
772 DCHECK(resource->origin != Resource::INTERNAL);
773 DCHECK(resource->mailbox.IsTexture());
775 // Mailbox sync_points must be processed by a call to
776 // WaitSyncPointIfNeeded() prior to calling LockForRead().
777 DCHECK(!resource->mailbox.sync_point());
779 GLES2Interface* gl = ContextGL();
780 DCHECK(gl);
781 resource->gl_id = gl->CreateAndConsumeTextureCHROMIUM(
782 resource->mailbox.target(), resource->mailbox.name());
785 if (!resource->pixels && resource->has_shared_bitmap_id &&
786 shared_bitmap_manager_) {
787 scoped_ptr<SharedBitmap> bitmap =
788 shared_bitmap_manager_->GetSharedBitmapFromId(
789 resource->size, resource->shared_bitmap_id);
790 if (bitmap) {
791 resource->shared_bitmap = bitmap.release();
792 resource->pixels = resource->shared_bitmap->pixels();
796 resource->lock_for_read_count++;
797 if (resource->read_lock_fences_enabled) {
798 if (current_read_lock_fence_.get())
799 current_read_lock_fence_->Set();
800 resource->read_lock_fence = current_read_lock_fence_;
803 return resource;
806 void ResourceProvider::UnlockForRead(ResourceId id) {
807 DCHECK(thread_checker_.CalledOnValidThread());
808 ResourceMap::iterator it = resources_.find(id);
809 CHECK(it != resources_.end());
811 Resource* resource = &it->second;
812 DCHECK_GT(resource->lock_for_read_count, 0);
813 DCHECK_EQ(resource->exported_count, 0);
814 resource->lock_for_read_count--;
815 if (resource->marked_for_deletion && !resource->lock_for_read_count) {
816 if (!resource->child_id) {
817 // The resource belongs to this ResourceProvider, so it can be destroyed.
818 DeleteResourceInternal(it, NORMAL);
819 } else {
820 ChildMap::iterator child_it = children_.find(resource->child_id);
821 ResourceIdArray unused;
822 unused.push_back(id);
823 DeleteAndReturnUnusedResourcesToChild(child_it, NORMAL, unused);
828 ResourceProvider::Resource* ResourceProvider::LockForWrite(ResourceId id) {
829 Resource* resource = GetResource(id);
830 DCHECK(CanLockForWrite(id));
832 resource->locked_for_write = true;
833 return resource;
836 bool ResourceProvider::CanLockForWrite(ResourceId id) {
837 Resource* resource = GetResource(id);
838 return !resource->locked_for_write && !resource->lock_for_read_count &&
839 !resource->exported_count && resource->origin == Resource::INTERNAL &&
840 !resource->lost && ReadLockFenceHasPassed(resource);
843 void ResourceProvider::UnlockForWrite(ResourceProvider::Resource* resource) {
844 DCHECK(resource->locked_for_write);
845 DCHECK_EQ(resource->exported_count, 0);
846 DCHECK(resource->origin == Resource::INTERNAL);
847 resource->locked_for_write = false;
850 void ResourceProvider::EnableReadLockFencesForTesting(ResourceId id) {
851 Resource* resource = GetResource(id);
852 DCHECK(resource);
853 resource->read_lock_fences_enabled = true;
856 ResourceProvider::ScopedReadLockGL::ScopedReadLockGL(
857 ResourceProvider* resource_provider,
858 ResourceId resource_id)
859 : resource_provider_(resource_provider),
860 resource_id_(resource_id),
861 resource_(resource_provider->LockForRead(resource_id)) {
862 DCHECK(resource_);
865 ResourceProvider::ScopedReadLockGL::~ScopedReadLockGL() {
866 resource_provider_->UnlockForRead(resource_id_);
869 ResourceProvider::ScopedSamplerGL::ScopedSamplerGL(
870 ResourceProvider* resource_provider,
871 ResourceId resource_id,
872 GLenum filter)
873 : ScopedReadLockGL(resource_provider, resource_id),
874 unit_(GL_TEXTURE0),
875 target_(resource_provider->BindForSampling(resource_id, unit_, filter)) {
878 ResourceProvider::ScopedSamplerGL::ScopedSamplerGL(
879 ResourceProvider* resource_provider,
880 ResourceId resource_id,
881 GLenum unit,
882 GLenum filter)
883 : ScopedReadLockGL(resource_provider, resource_id),
884 unit_(unit),
885 target_(resource_provider->BindForSampling(resource_id, unit_, filter)) {
888 ResourceProvider::ScopedSamplerGL::~ScopedSamplerGL() {
891 ResourceProvider::ScopedWriteLockGL::ScopedWriteLockGL(
892 ResourceProvider* resource_provider,
893 ResourceId resource_id)
894 : resource_provider_(resource_provider),
895 resource_(resource_provider->LockForWrite(resource_id)) {
896 resource_provider_->LazyAllocate(resource_);
897 texture_id_ = resource_->gl_id;
898 DCHECK(texture_id_);
901 ResourceProvider::ScopedWriteLockGL::~ScopedWriteLockGL() {
902 resource_provider_->UnlockForWrite(resource_);
905 void ResourceProvider::PopulateSkBitmapWithResource(
906 SkBitmap* sk_bitmap, const Resource* resource) {
907 DCHECK_EQ(RGBA_8888, resource->format);
908 SkImageInfo info = SkImageInfo::MakeN32Premul(resource->size.width(),
909 resource->size.height());
910 sk_bitmap->installPixels(info, resource->pixels, info.minRowBytes());
913 ResourceProvider::ScopedReadLockSoftware::ScopedReadLockSoftware(
914 ResourceProvider* resource_provider,
915 ResourceId resource_id)
916 : resource_provider_(resource_provider), resource_id_(resource_id) {
917 const Resource* resource = resource_provider->LockForRead(resource_id);
918 wrap_mode_ = resource->wrap_mode;
919 ResourceProvider::PopulateSkBitmapWithResource(&sk_bitmap_, resource);
922 ResourceProvider::ScopedReadLockSoftware::~ScopedReadLockSoftware() {
923 resource_provider_->UnlockForRead(resource_id_);
926 ResourceProvider::ScopedWriteLockSoftware::ScopedWriteLockSoftware(
927 ResourceProvider* resource_provider,
928 ResourceId resource_id)
929 : resource_provider_(resource_provider),
930 resource_(resource_provider->LockForWrite(resource_id)) {
931 ResourceProvider::PopulateSkBitmapWithResource(&sk_bitmap_, resource_);
932 DCHECK(valid());
935 ResourceProvider::ScopedWriteLockSoftware::~ScopedWriteLockSoftware() {
936 DCHECK(thread_checker_.CalledOnValidThread());
937 resource_provider_->UnlockForWrite(resource_);
940 ResourceProvider::ScopedWriteLockGpuMemoryBuffer::
941 ScopedWriteLockGpuMemoryBuffer(ResourceProvider* resource_provider,
942 ResourceId resource_id)
943 : resource_provider_(resource_provider),
944 resource_(resource_provider->LockForWrite(resource_id)),
945 gpu_memory_buffer_manager_(resource_provider->gpu_memory_buffer_manager_),
946 gpu_memory_buffer_(nullptr),
947 size_(resource_->size),
948 format_(resource_->format) {
949 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource_->type);
950 std::swap(gpu_memory_buffer_, resource_->gpu_memory_buffer);
953 ResourceProvider::ScopedWriteLockGpuMemoryBuffer::
954 ~ScopedWriteLockGpuMemoryBuffer() {
955 DCHECK(thread_checker_.CalledOnValidThread());
956 resource_provider_->UnlockForWrite(resource_);
957 if (!gpu_memory_buffer_)
958 return;
960 resource_provider_->LazyCreate(resource_);
962 if (!resource_->image_id) {
963 GLES2Interface* gl = resource_provider_->ContextGL();
964 DCHECK(gl);
966 #if defined(OS_CHROMEOS)
967 // TODO(reveman): GL_COMMANDS_ISSUED_CHROMIUM is used for synchronization
968 // on ChromeOS to avoid some performance issues. This only works with
969 // shared memory backed buffers. crbug.com/436314
970 DCHECK_EQ(gpu_memory_buffer_->GetHandle().type, gfx::SHARED_MEMORY_BUFFER);
971 #endif
973 resource_->image_id = gl->CreateImageCHROMIUM(
974 gpu_memory_buffer_->AsClientBuffer(), size_.width(), size_.height(),
975 GLInternalFormat(resource_->format));
978 std::swap(resource_->gpu_memory_buffer, gpu_memory_buffer_);
979 resource_->allocated = true;
980 resource_->dirty_image = true;
982 // GpuMemoryBuffer provides direct access to the memory used by the GPU.
983 // Read lock fences are required to ensure that we're not trying to map a
984 // buffer that is currently in-use by the GPU.
985 resource_->read_lock_fences_enabled = true;
988 gfx::GpuMemoryBuffer*
989 ResourceProvider::ScopedWriteLockGpuMemoryBuffer::GetGpuMemoryBuffer() {
990 if (gpu_memory_buffer_)
991 return gpu_memory_buffer_;
992 gfx::GpuMemoryBuffer::Usage usage =
993 resource_provider_->use_persistent_map_for_gpu_memory_buffers()
994 ? gfx::GpuMemoryBuffer::PERSISTENT_MAP
995 : gfx::GpuMemoryBuffer::MAP;
996 scoped_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer =
997 gpu_memory_buffer_manager_->AllocateGpuMemoryBuffer(
998 size_, ToGpuMemoryBufferFormat(format_), usage);
999 gpu_memory_buffer_ = gpu_memory_buffer.release();
1000 return gpu_memory_buffer_;
1003 ResourceProvider::ScopedWriteLockGr::ScopedWriteLockGr(
1004 ResourceProvider* resource_provider,
1005 ResourceId resource_id)
1006 : resource_provider_(resource_provider),
1007 resource_(resource_provider->LockForWrite(resource_id)) {
1008 DCHECK(thread_checker_.CalledOnValidThread());
1009 resource_provider_->LazyAllocate(resource_);
1012 ResourceProvider::ScopedWriteLockGr::~ScopedWriteLockGr() {
1013 DCHECK(thread_checker_.CalledOnValidThread());
1014 DCHECK(resource_->locked_for_write);
1015 resource_provider_->UnlockForWrite(resource_);
1018 void ResourceProvider::ScopedWriteLockGr::InitSkSurface(
1019 bool use_distance_field_text,
1020 bool can_use_lcd_text,
1021 int msaa_sample_count) {
1022 DCHECK(resource_->locked_for_write);
1024 GrBackendTextureDesc desc;
1025 desc.fFlags = kRenderTarget_GrBackendTextureFlag;
1026 desc.fWidth = resource_->size.width();
1027 desc.fHeight = resource_->size.height();
1028 desc.fConfig = ToGrPixelConfig(resource_->format);
1029 desc.fOrigin = kTopLeft_GrSurfaceOrigin;
1030 desc.fTextureHandle = resource_->gl_id;
1031 desc.fSampleCnt = msaa_sample_count;
1033 bool use_worker_context = true;
1034 class GrContext* gr_context =
1035 resource_provider_->GrContext(use_worker_context);
1036 uint32_t flags =
1037 use_distance_field_text ? SkSurfaceProps::kUseDistanceFieldFonts_Flag : 0;
1038 // Use unknown pixel geometry to disable LCD text.
1039 SkSurfaceProps surface_props(flags, kUnknown_SkPixelGeometry);
1040 if (can_use_lcd_text) {
1041 // LegacyFontHost will get LCD text and skia figures out what type to use.
1042 surface_props =
1043 SkSurfaceProps(flags, SkSurfaceProps::kLegacyFontHost_InitType);
1045 sk_surface_ = skia::AdoptRef(
1046 SkSurface::NewWrappedRenderTarget(gr_context, desc, &surface_props));
1049 void ResourceProvider::ScopedWriteLockGr::ReleaseSkSurface() {
1050 sk_surface_.clear();
1053 ResourceProvider::SynchronousFence::SynchronousFence(
1054 gpu::gles2::GLES2Interface* gl)
1055 : gl_(gl), has_synchronized_(true) {
1058 ResourceProvider::SynchronousFence::~SynchronousFence() {
1061 void ResourceProvider::SynchronousFence::Set() {
1062 has_synchronized_ = false;
1065 bool ResourceProvider::SynchronousFence::HasPassed() {
1066 if (!has_synchronized_) {
1067 has_synchronized_ = true;
1068 Synchronize();
1070 return true;
1073 void ResourceProvider::SynchronousFence::Wait() {
1074 HasPassed();
1077 void ResourceProvider::SynchronousFence::Synchronize() {
1078 TRACE_EVENT0("cc", "ResourceProvider::SynchronousFence::Synchronize");
1079 gl_->Finish();
1082 ResourceProvider::ResourceProvider(
1083 OutputSurface* output_surface,
1084 SharedBitmapManager* shared_bitmap_manager,
1085 gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
1086 BlockingTaskRunner* blocking_main_thread_task_runner,
1087 int highp_threshold_min,
1088 bool use_rgba_4444_texture_format,
1089 size_t id_allocation_chunk_size,
1090 bool use_persistent_map_for_gpu_memory_buffers)
1091 : output_surface_(output_surface),
1092 shared_bitmap_manager_(shared_bitmap_manager),
1093 gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
1094 blocking_main_thread_task_runner_(blocking_main_thread_task_runner),
1095 lost_output_surface_(false),
1096 highp_threshold_min_(highp_threshold_min),
1097 next_id_(1),
1098 next_child_(1),
1099 default_resource_type_(RESOURCE_TYPE_BITMAP),
1100 use_texture_storage_ext_(false),
1101 use_texture_format_bgra_(false),
1102 use_texture_usage_hint_(false),
1103 use_compressed_texture_etc1_(false),
1104 yuv_resource_format_(LUMINANCE_8),
1105 max_texture_size_(0),
1106 best_texture_format_(RGBA_8888),
1107 best_render_buffer_format_(RGBA_8888),
1108 use_rgba_4444_texture_format_(use_rgba_4444_texture_format),
1109 id_allocation_chunk_size_(id_allocation_chunk_size),
1110 use_sync_query_(false),
1111 use_persistent_map_for_gpu_memory_buffers_(
1112 use_persistent_map_for_gpu_memory_buffers) {
1113 DCHECK(output_surface_->HasClient());
1114 DCHECK(id_allocation_chunk_size_);
1117 void ResourceProvider::Initialize() {
1118 DCHECK(thread_checker_.CalledOnValidThread());
1120 GLES2Interface* gl = ContextGL();
1121 if (!gl) {
1122 default_resource_type_ = RESOURCE_TYPE_BITMAP;
1123 // Pick an arbitrary limit here similar to what hardware might.
1124 max_texture_size_ = 16 * 1024;
1125 best_texture_format_ = RGBA_8888;
1126 return;
1129 DCHECK(!texture_id_allocator_);
1130 DCHECK(!buffer_id_allocator_);
1132 const ContextProvider::Capabilities& caps =
1133 output_surface_->context_provider()->ContextCapabilities();
1135 default_resource_type_ = RESOURCE_TYPE_GL_TEXTURE;
1136 use_texture_storage_ext_ = caps.gpu.texture_storage;
1137 use_texture_format_bgra_ = caps.gpu.texture_format_bgra8888;
1138 use_texture_usage_hint_ = caps.gpu.texture_usage;
1139 use_compressed_texture_etc1_ = caps.gpu.texture_format_etc1;
1140 yuv_resource_format_ = caps.gpu.texture_rg ? RED_8 : LUMINANCE_8;
1141 use_sync_query_ = caps.gpu.sync_query;
1143 max_texture_size_ = 0; // Context expects cleared value.
1144 gl->GetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size_);
1145 best_texture_format_ =
1146 PlatformColor::BestTextureFormat(use_texture_format_bgra_);
1148 best_render_buffer_format_ =
1149 PlatformColor::BestTextureFormat(caps.gpu.render_buffer_format_bgra8888);
1151 texture_id_allocator_.reset(
1152 new TextureIdAllocator(gl, id_allocation_chunk_size_));
1153 buffer_id_allocator_.reset(
1154 new BufferIdAllocator(gl, id_allocation_chunk_size_));
1157 int ResourceProvider::CreateChild(const ReturnCallback& return_callback) {
1158 DCHECK(thread_checker_.CalledOnValidThread());
1160 Child child_info;
1161 child_info.return_callback = return_callback;
1163 int child = next_child_++;
1164 children_[child] = child_info;
1165 return child;
1168 void ResourceProvider::SetChildNeedsSyncPoints(int child_id, bool needs) {
1169 ChildMap::iterator it = children_.find(child_id);
1170 DCHECK(it != children_.end());
1171 it->second.needs_sync_points = needs;
1174 void ResourceProvider::DestroyChild(int child_id) {
1175 ChildMap::iterator it = children_.find(child_id);
1176 DCHECK(it != children_.end());
1177 DestroyChildInternal(it, NORMAL);
1180 void ResourceProvider::DestroyChildInternal(ChildMap::iterator it,
1181 DeleteStyle style) {
1182 DCHECK(thread_checker_.CalledOnValidThread());
1184 Child& child = it->second;
1185 DCHECK(style == FOR_SHUTDOWN || !child.marked_for_deletion);
1187 ResourceIdArray resources_for_child;
1189 for (ResourceIdMap::iterator child_it = child.child_to_parent_map.begin();
1190 child_it != child.child_to_parent_map.end();
1191 ++child_it) {
1192 ResourceId id = child_it->second;
1193 resources_for_child.push_back(id);
1196 child.marked_for_deletion = true;
1198 DeleteAndReturnUnusedResourcesToChild(it, style, resources_for_child);
1201 const ResourceProvider::ResourceIdMap& ResourceProvider::GetChildToParentMap(
1202 int child) const {
1203 DCHECK(thread_checker_.CalledOnValidThread());
1204 ChildMap::const_iterator it = children_.find(child);
1205 DCHECK(it != children_.end());
1206 DCHECK(!it->second.marked_for_deletion);
1207 return it->second.child_to_parent_map;
1210 void ResourceProvider::PrepareSendToParent(const ResourceIdArray& resources,
1211 TransferableResourceArray* list) {
1212 DCHECK(thread_checker_.CalledOnValidThread());
1213 GLES2Interface* gl = ContextGL();
1214 bool need_sync_point = false;
1215 for (ResourceIdArray::const_iterator it = resources.begin();
1216 it != resources.end();
1217 ++it) {
1218 TransferableResource resource;
1219 TransferResource(gl, *it, &resource);
1220 if (!resource.mailbox_holder.sync_point && !resource.is_software)
1221 need_sync_point = true;
1222 ++resources_.find(*it)->second.exported_count;
1223 list->push_back(resource);
1225 if (need_sync_point &&
1226 output_surface_->capabilities().delegated_sync_points_required) {
1227 GLuint sync_point = gl->InsertSyncPointCHROMIUM();
1228 for (TransferableResourceArray::iterator it = list->begin();
1229 it != list->end();
1230 ++it) {
1231 if (!it->mailbox_holder.sync_point)
1232 it->mailbox_holder.sync_point = sync_point;
1237 void ResourceProvider::ReceiveFromChild(
1238 int child, const TransferableResourceArray& resources) {
1239 DCHECK(thread_checker_.CalledOnValidThread());
1240 GLES2Interface* gl = ContextGL();
1241 Child& child_info = children_.find(child)->second;
1242 DCHECK(!child_info.marked_for_deletion);
1243 for (TransferableResourceArray::const_iterator it = resources.begin();
1244 it != resources.end();
1245 ++it) {
1246 ResourceIdMap::iterator resource_in_map_it =
1247 child_info.child_to_parent_map.find(it->id);
1248 if (resource_in_map_it != child_info.child_to_parent_map.end()) {
1249 Resource* resource = GetResource(resource_in_map_it->second);
1250 resource->marked_for_deletion = false;
1251 resource->imported_count++;
1252 continue;
1255 if ((!it->is_software && !gl) ||
1256 (it->is_software && !shared_bitmap_manager_)) {
1257 TRACE_EVENT0("cc", "ResourceProvider::ReceiveFromChild dropping invalid");
1258 ReturnedResourceArray to_return;
1259 to_return.push_back(it->ToReturnedResource());
1260 child_info.return_callback.Run(to_return,
1261 blocking_main_thread_task_runner_);
1262 continue;
1265 ResourceId local_id = next_id_++;
1266 Resource* resource = nullptr;
1267 if (it->is_software) {
1268 resource = InsertResource(
1269 local_id,
1270 Resource(it->mailbox_holder.mailbox, it->size, Resource::DELEGATED,
1271 GL_LINEAR, it->is_repeated ? GL_REPEAT : GL_CLAMP_TO_EDGE));
1272 } else {
1273 resource = InsertResource(
1274 local_id, Resource(0, it->size, Resource::DELEGATED,
1275 it->mailbox_holder.texture_target, it->filter, 0,
1276 it->is_repeated ? GL_REPEAT : GL_CLAMP_TO_EDGE,
1277 TEXTURE_HINT_IMMUTABLE, it->format));
1278 resource->mailbox = TextureMailbox(it->mailbox_holder.mailbox,
1279 it->mailbox_holder.texture_target,
1280 it->mailbox_holder.sync_point);
1281 resource->read_lock_fences_enabled = it->read_lock_fences_enabled;
1283 resource->child_id = child;
1284 // Don't allocate a texture for a child.
1285 resource->allocated = true;
1286 resource->imported_count = 1;
1287 child_info.parent_to_child_map[local_id] = it->id;
1288 child_info.child_to_parent_map[it->id] = local_id;
1292 void ResourceProvider::DeclareUsedResourcesFromChild(
1293 int child,
1294 const ResourceIdSet& resources_from_child) {
1295 DCHECK(thread_checker_.CalledOnValidThread());
1297 ChildMap::iterator child_it = children_.find(child);
1298 DCHECK(child_it != children_.end());
1299 Child& child_info = child_it->second;
1300 DCHECK(!child_info.marked_for_deletion);
1302 ResourceIdArray unused;
1303 for (ResourceIdMap::iterator it = child_info.child_to_parent_map.begin();
1304 it != child_info.child_to_parent_map.end();
1305 ++it) {
1306 ResourceId local_id = it->second;
1307 bool resource_is_in_use = resources_from_child.count(it->first) > 0;
1308 if (!resource_is_in_use)
1309 unused.push_back(local_id);
1311 DeleteAndReturnUnusedResourcesToChild(child_it, NORMAL, unused);
1314 void ResourceProvider::ReceiveReturnsFromParent(
1315 const ReturnedResourceArray& resources) {
1316 DCHECK(thread_checker_.CalledOnValidThread());
1317 GLES2Interface* gl = ContextGL();
1319 base::hash_map<int, ResourceIdArray> resources_for_child;
1321 for (const ReturnedResource& returned : resources) {
1322 ResourceId local_id = returned.id;
1323 ResourceMap::iterator map_iterator = resources_.find(local_id);
1324 // Resource was already lost (e.g. it belonged to a child that was
1325 // destroyed).
1326 if (map_iterator == resources_.end())
1327 continue;
1329 Resource* resource = &map_iterator->second;
1331 CHECK_GE(resource->exported_count, returned.count);
1332 resource->exported_count -= returned.count;
1333 resource->lost |= returned.lost;
1334 if (resource->exported_count)
1335 continue;
1337 if (returned.sync_point) {
1338 DCHECK(!resource->has_shared_bitmap_id);
1339 if (resource->origin == Resource::INTERNAL) {
1340 DCHECK(resource->gl_id);
1341 gl->WaitSyncPointCHROMIUM(returned.sync_point);
1342 } else {
1343 DCHECK(!resource->gl_id);
1344 resource->mailbox.set_sync_point(returned.sync_point);
1348 if (!resource->marked_for_deletion)
1349 continue;
1351 if (!resource->child_id) {
1352 // The resource belongs to this ResourceProvider, so it can be destroyed.
1353 DeleteResourceInternal(map_iterator, NORMAL);
1354 continue;
1357 DCHECK(resource->origin == Resource::DELEGATED);
1358 resources_for_child[resource->child_id].push_back(local_id);
1361 for (const auto& children : resources_for_child) {
1362 ChildMap::iterator child_it = children_.find(children.first);
1363 DCHECK(child_it != children_.end());
1364 DeleteAndReturnUnusedResourcesToChild(child_it, NORMAL, children.second);
1368 void ResourceProvider::TransferResource(GLES2Interface* gl,
1369 ResourceId id,
1370 TransferableResource* resource) {
1371 Resource* source = GetResource(id);
1372 DCHECK(!source->locked_for_write);
1373 DCHECK(!source->lock_for_read_count);
1374 DCHECK(source->origin != Resource::EXTERNAL || source->mailbox.IsValid());
1375 DCHECK(source->allocated);
1376 resource->id = id;
1377 resource->format = source->format;
1378 resource->mailbox_holder.texture_target = source->target;
1379 resource->filter = source->filter;
1380 resource->size = source->size;
1381 resource->read_lock_fences_enabled = source->read_lock_fences_enabled;
1382 resource->is_repeated = (source->wrap_mode == GL_REPEAT);
1384 if (source->type == RESOURCE_TYPE_BITMAP) {
1385 resource->mailbox_holder.mailbox = source->shared_bitmap_id;
1386 resource->is_software = true;
1387 } else if (!source->mailbox.IsValid()) {
1388 LazyCreate(source);
1389 DCHECK(source->gl_id);
1390 DCHECK(source->origin == Resource::INTERNAL);
1391 if (source->image_id) {
1392 DCHECK(source->dirty_image);
1393 gl->BindTexture(resource->mailbox_holder.texture_target, source->gl_id);
1394 BindImageForSampling(source);
1396 // This is a resource allocated by the compositor, we need to produce it.
1397 // Don't set a sync point, the caller will do it.
1398 gl->GenMailboxCHROMIUM(resource->mailbox_holder.mailbox.name);
1399 gl->ProduceTextureDirectCHROMIUM(source->gl_id,
1400 resource->mailbox_holder.texture_target,
1401 resource->mailbox_holder.mailbox.name);
1403 source->mailbox = TextureMailbox(resource->mailbox_holder);
1404 } else {
1405 DCHECK(source->mailbox.IsTexture());
1406 if (source->image_id && source->dirty_image) {
1407 DCHECK(source->gl_id);
1408 DCHECK(source->origin == Resource::INTERNAL);
1409 gl->BindTexture(resource->mailbox_holder.texture_target, source->gl_id);
1410 BindImageForSampling(source);
1412 // This is either an external resource, or a compositor resource that we
1413 // already exported. Make sure to forward the sync point that we were given.
1414 resource->mailbox_holder.mailbox = source->mailbox.mailbox();
1415 resource->mailbox_holder.texture_target = source->mailbox.target();
1416 resource->mailbox_holder.sync_point = source->mailbox.sync_point();
1417 source->mailbox.set_sync_point(0);
1421 void ResourceProvider::DeleteAndReturnUnusedResourcesToChild(
1422 ChildMap::iterator child_it,
1423 DeleteStyle style,
1424 const ResourceIdArray& unused) {
1425 DCHECK(thread_checker_.CalledOnValidThread());
1426 DCHECK(child_it != children_.end());
1427 Child* child_info = &child_it->second;
1429 if (unused.empty() && !child_info->marked_for_deletion)
1430 return;
1432 ReturnedResourceArray to_return;
1434 GLES2Interface* gl = ContextGL();
1435 bool need_sync_point = false;
1436 for (size_t i = 0; i < unused.size(); ++i) {
1437 ResourceId local_id = unused[i];
1439 ResourceMap::iterator it = resources_.find(local_id);
1440 CHECK(it != resources_.end());
1441 Resource& resource = it->second;
1443 DCHECK(!resource.locked_for_write);
1444 DCHECK(child_info->parent_to_child_map.count(local_id));
1446 ResourceId child_id = child_info->parent_to_child_map[local_id];
1447 DCHECK(child_info->child_to_parent_map.count(child_id));
1449 bool is_lost =
1450 resource.lost ||
1451 (resource.type == RESOURCE_TYPE_GL_TEXTURE && lost_output_surface_);
1452 if (resource.exported_count > 0 || resource.lock_for_read_count > 0) {
1453 if (style != FOR_SHUTDOWN) {
1454 // Defer this resource deletion.
1455 resource.marked_for_deletion = true;
1456 continue;
1458 // We can't postpone the deletion, so we'll have to lose it.
1459 is_lost = true;
1460 } else if (!ReadLockFenceHasPassed(&resource)) {
1461 // TODO(dcastagna): see if it's possible to use this logic for
1462 // the branch above too, where the resource is locked or still exported.
1463 if (style != FOR_SHUTDOWN && !child_info->marked_for_deletion) {
1464 // Defer this resource deletion.
1465 resource.marked_for_deletion = true;
1466 continue;
1468 // We can't postpone the deletion, so we'll have to lose it.
1469 is_lost = true;
1472 if (gl && resource.filter != resource.original_filter) {
1473 DCHECK(resource.target);
1474 DCHECK(resource.gl_id);
1476 gl->BindTexture(resource.target, resource.gl_id);
1477 gl->TexParameteri(resource.target, GL_TEXTURE_MIN_FILTER,
1478 resource.original_filter);
1479 gl->TexParameteri(resource.target, GL_TEXTURE_MAG_FILTER,
1480 resource.original_filter);
1483 ReturnedResource returned;
1484 returned.id = child_id;
1485 returned.sync_point = resource.mailbox.sync_point();
1486 if (!returned.sync_point && resource.type == RESOURCE_TYPE_GL_TEXTURE)
1487 need_sync_point = true;
1488 returned.count = resource.imported_count;
1489 returned.lost = is_lost;
1490 to_return.push_back(returned);
1492 child_info->parent_to_child_map.erase(local_id);
1493 child_info->child_to_parent_map.erase(child_id);
1494 resource.imported_count = 0;
1495 DeleteResourceInternal(it, style);
1497 if (need_sync_point && child_info->needs_sync_points) {
1498 DCHECK(gl);
1499 GLuint sync_point = gl->InsertSyncPointCHROMIUM();
1500 for (size_t i = 0; i < to_return.size(); ++i) {
1501 if (!to_return[i].sync_point)
1502 to_return[i].sync_point = sync_point;
1506 if (!to_return.empty())
1507 child_info->return_callback.Run(to_return,
1508 blocking_main_thread_task_runner_);
1510 if (child_info->marked_for_deletion &&
1511 child_info->parent_to_child_map.empty()) {
1512 DCHECK(child_info->child_to_parent_map.empty());
1513 children_.erase(child_it);
1517 void ResourceProvider::AcquirePixelBuffer(ResourceId id) {
1518 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1519 "ResourceProvider::AcquirePixelBuffer");
1521 Resource* resource = GetResource(id);
1522 DCHECK(resource->origin == Resource::INTERNAL);
1523 DCHECK_EQ(resource->exported_count, 0);
1524 DCHECK(!resource->image_id);
1525 DCHECK_NE(ETC1, resource->format);
1527 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
1528 GLES2Interface* gl = ContextGL();
1529 DCHECK(gl);
1530 if (!resource->gl_pixel_buffer_id)
1531 resource->gl_pixel_buffer_id = buffer_id_allocator_->NextId();
1532 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1533 resource->gl_pixel_buffer_id);
1534 unsigned bytes_per_pixel = BitsPerPixel(resource->format) / 8;
1535 gl->BufferData(
1536 GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1537 resource->size.height() *
1538 MathUtil::RoundUp(bytes_per_pixel * resource->size.width(), 4u),
1539 NULL, GL_DYNAMIC_DRAW);
1540 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
1543 void ResourceProvider::ReleasePixelBuffer(ResourceId id) {
1544 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1545 "ResourceProvider::ReleasePixelBuffer");
1547 Resource* resource = GetResource(id);
1548 DCHECK(resource->origin == Resource::INTERNAL);
1549 DCHECK_EQ(resource->exported_count, 0);
1550 DCHECK(!resource->image_id);
1552 // The pixel buffer can be released while there is a pending "set pixels"
1553 // if completion has been forced. Any shared memory associated with this
1554 // pixel buffer will not be freed until the waitAsyncTexImage2DCHROMIUM
1555 // command has been processed on the service side. It is also safe to
1556 // reuse any query id associated with this resource before they complete
1557 // as each new query has a unique submit count.
1558 if (resource->pending_set_pixels) {
1559 DCHECK(resource->set_pixels_completion_forced);
1560 resource->pending_set_pixels = false;
1561 resource->locked_for_write = false;
1564 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
1565 if (!resource->gl_pixel_buffer_id)
1566 return;
1567 GLES2Interface* gl = ContextGL();
1568 DCHECK(gl);
1569 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1570 resource->gl_pixel_buffer_id);
1571 gl->BufferData(
1572 GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0, NULL, GL_DYNAMIC_DRAW);
1573 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
1576 uint8_t* ResourceProvider::MapPixelBuffer(ResourceId id, int* stride) {
1577 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1578 "ResourceProvider::MapPixelBuffer");
1580 Resource* resource = GetResource(id);
1581 DCHECK(resource->origin == Resource::INTERNAL);
1582 DCHECK_EQ(resource->exported_count, 0);
1583 DCHECK(!resource->image_id);
1585 *stride = 0;
1586 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
1587 GLES2Interface* gl = ContextGL();
1588 DCHECK(gl);
1589 DCHECK(resource->gl_pixel_buffer_id);
1590 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1591 resource->gl_pixel_buffer_id);
1592 uint8_t* image = static_cast<uint8_t*>(gl->MapBufferCHROMIUM(
1593 GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, GL_WRITE_ONLY));
1594 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
1595 // Buffer is required to be 4-byte aligned.
1596 CHECK(!(reinterpret_cast<intptr_t>(image) & 3));
1597 return image;
1600 void ResourceProvider::UnmapPixelBuffer(ResourceId id) {
1601 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1602 "ResourceProvider::UnmapPixelBuffer");
1604 Resource* resource = GetResource(id);
1605 DCHECK(resource->origin == Resource::INTERNAL);
1606 DCHECK_EQ(resource->exported_count, 0);
1607 DCHECK(!resource->image_id);
1609 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
1610 GLES2Interface* gl = ContextGL();
1611 DCHECK(gl);
1612 DCHECK(resource->gl_pixel_buffer_id);
1613 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1614 resource->gl_pixel_buffer_id);
1615 gl->UnmapBufferCHROMIUM(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM);
1616 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
1619 GLenum ResourceProvider::BindForSampling(ResourceId resource_id,
1620 GLenum unit,
1621 GLenum filter) {
1622 DCHECK(thread_checker_.CalledOnValidThread());
1623 GLES2Interface* gl = ContextGL();
1624 ResourceMap::iterator it = resources_.find(resource_id);
1625 DCHECK(it != resources_.end());
1626 Resource* resource = &it->second;
1627 DCHECK(resource->lock_for_read_count);
1628 DCHECK(!resource->locked_for_write || resource->set_pixels_completion_forced);
1630 ScopedSetActiveTexture scoped_active_tex(gl, unit);
1631 GLenum target = resource->target;
1632 gl->BindTexture(target, resource->gl_id);
1633 if (filter != resource->filter) {
1634 gl->TexParameteri(target, GL_TEXTURE_MIN_FILTER, filter);
1635 gl->TexParameteri(target, GL_TEXTURE_MAG_FILTER, filter);
1636 resource->filter = filter;
1639 if (resource->image_id && resource->dirty_image)
1640 BindImageForSampling(resource);
1642 return target;
1645 void ResourceProvider::BeginSetPixels(ResourceId id) {
1646 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1647 "ResourceProvider::BeginSetPixels");
1649 Resource* resource = GetResource(id);
1650 DCHECK(!resource->pending_set_pixels);
1652 LazyCreate(resource);
1653 DCHECK(resource->origin == Resource::INTERNAL);
1654 DCHECK(resource->gl_id || resource->allocated);
1655 DCHECK(ReadLockFenceHasPassed(resource));
1656 DCHECK(!resource->image_id);
1658 bool allocate = !resource->allocated;
1659 resource->allocated = true;
1660 LockForWrite(id);
1662 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
1663 DCHECK(resource->gl_id);
1664 GLES2Interface* gl = ContextGL();
1665 DCHECK(gl);
1666 DCHECK(resource->gl_pixel_buffer_id);
1667 DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D));
1668 gl->BindTexture(GL_TEXTURE_2D, resource->gl_id);
1669 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1670 resource->gl_pixel_buffer_id);
1671 if (!resource->gl_upload_query_id)
1672 gl->GenQueriesEXT(1, &resource->gl_upload_query_id);
1673 gl->BeginQueryEXT(GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM,
1674 resource->gl_upload_query_id);
1675 if (allocate) {
1676 gl->AsyncTexImage2DCHROMIUM(GL_TEXTURE_2D,
1677 0, /* level */
1678 GLInternalFormat(resource->format),
1679 resource->size.width(),
1680 resource->size.height(),
1681 0, /* border */
1682 GLDataFormat(resource->format),
1683 GLDataType(resource->format),
1684 NULL);
1685 } else {
1686 gl->AsyncTexSubImage2DCHROMIUM(GL_TEXTURE_2D,
1687 0, /* level */
1688 0, /* x */
1689 0, /* y */
1690 resource->size.width(),
1691 resource->size.height(),
1692 GLDataFormat(resource->format),
1693 GLDataType(resource->format),
1694 NULL);
1696 gl->EndQueryEXT(GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM);
1697 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
1699 resource->pending_set_pixels = true;
1700 resource->set_pixels_completion_forced = false;
1703 void ResourceProvider::ForceSetPixelsToComplete(ResourceId id) {
1704 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1705 "ResourceProvider::ForceSetPixelsToComplete");
1707 Resource* resource = GetResource(id);
1709 DCHECK(resource->locked_for_write);
1710 DCHECK(resource->pending_set_pixels);
1711 DCHECK(!resource->set_pixels_completion_forced);
1713 if (resource->gl_id) {
1714 GLES2Interface* gl = ContextGL();
1715 gl->BindTexture(GL_TEXTURE_2D, resource->gl_id);
1716 gl->WaitAsyncTexImage2DCHROMIUM(GL_TEXTURE_2D);
1717 gl->BindTexture(GL_TEXTURE_2D, 0);
1720 resource->set_pixels_completion_forced = true;
1723 bool ResourceProvider::DidSetPixelsComplete(ResourceId id) {
1724 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1725 "ResourceProvider::DidSetPixelsComplete");
1727 Resource* resource = GetResource(id);
1729 DCHECK(resource->locked_for_write);
1730 DCHECK(resource->pending_set_pixels);
1732 if (resource->gl_id) {
1733 GLES2Interface* gl = ContextGL();
1734 DCHECK(gl);
1735 DCHECK(resource->gl_upload_query_id);
1736 GLuint complete = 1;
1737 gl->GetQueryObjectuivEXT(
1738 resource->gl_upload_query_id, GL_QUERY_RESULT_AVAILABLE_EXT, &complete);
1739 if (!complete)
1740 return false;
1743 resource->pending_set_pixels = false;
1744 UnlockForWrite(resource);
1746 // Async set pixels commands are not necessarily processed in-sequence with
1747 // drawing commands. Read lock fences are required to ensure that async
1748 // commands don't access the resource while used for drawing.
1749 resource->read_lock_fences_enabled = true;
1751 return true;
1754 void ResourceProvider::CreateForTesting(ResourceId id) {
1755 LazyCreate(GetResource(id));
1758 GLenum ResourceProvider::TargetForTesting(ResourceId id) {
1759 Resource* resource = GetResource(id);
1760 return resource->target;
1763 void ResourceProvider::LazyCreate(Resource* resource) {
1764 if (resource->type != RESOURCE_TYPE_GL_TEXTURE ||
1765 resource->origin != Resource::INTERNAL)
1766 return;
1768 if (resource->gl_id)
1769 return;
1771 DCHECK(resource->texture_pool);
1772 DCHECK(resource->origin == Resource::INTERNAL);
1773 DCHECK(!resource->mailbox.IsValid());
1774 resource->gl_id = texture_id_allocator_->NextId();
1776 GLES2Interface* gl = ContextGL();
1777 DCHECK(gl);
1779 // Create and set texture properties. Allocation is delayed until needed.
1780 gl->BindTexture(resource->target, resource->gl_id);
1781 gl->TexParameteri(resource->target, GL_TEXTURE_MIN_FILTER,
1782 resource->original_filter);
1783 gl->TexParameteri(resource->target, GL_TEXTURE_MAG_FILTER,
1784 resource->original_filter);
1785 gl->TexParameteri(resource->target, GL_TEXTURE_WRAP_S, resource->wrap_mode);
1786 gl->TexParameteri(resource->target, GL_TEXTURE_WRAP_T, resource->wrap_mode);
1787 gl->TexParameteri(resource->target, GL_TEXTURE_POOL_CHROMIUM,
1788 resource->texture_pool);
1789 if (use_texture_usage_hint_ && (resource->hint & TEXTURE_HINT_FRAMEBUFFER)) {
1790 gl->TexParameteri(resource->target, GL_TEXTURE_USAGE_ANGLE,
1791 GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
1795 void ResourceProvider::AllocateForTesting(ResourceId id) {
1796 LazyAllocate(GetResource(id));
1799 void ResourceProvider::LazyAllocate(Resource* resource) {
1800 DCHECK(resource);
1801 if (resource->allocated)
1802 return;
1803 LazyCreate(resource);
1804 if (!resource->gl_id)
1805 return;
1806 resource->allocated = true;
1807 GLES2Interface* gl = ContextGL();
1808 gfx::Size& size = resource->size;
1809 ResourceFormat format = resource->format;
1810 gl->BindTexture(resource->target, resource->gl_id);
1811 if (use_texture_storage_ext_ &&
1812 IsFormatSupportedForStorage(format, use_texture_format_bgra_) &&
1813 (resource->hint & TEXTURE_HINT_IMMUTABLE)) {
1814 GLenum storage_format = TextureToStorageFormat(format);
1815 gl->TexStorage2DEXT(resource->target, 1, storage_format, size.width(),
1816 size.height());
1817 } else {
1818 // ETC1 does not support preallocation.
1819 if (format != ETC1) {
1820 gl->TexImage2D(resource->target, 0, GLInternalFormat(format),
1821 size.width(), size.height(), 0, GLDataFormat(format),
1822 GLDataType(format), NULL);
1827 void ResourceProvider::BindImageForSampling(Resource* resource) {
1828 GLES2Interface* gl = ContextGL();
1829 DCHECK(resource->gl_id);
1830 DCHECK(resource->image_id);
1832 // Release image currently bound to texture.
1833 if (resource->bound_image_id)
1834 gl->ReleaseTexImage2DCHROMIUM(resource->target, resource->bound_image_id);
1835 gl->BindTexImage2DCHROMIUM(resource->target, resource->image_id);
1836 resource->bound_image_id = resource->image_id;
1837 resource->dirty_image = false;
1840 void ResourceProvider::CopyResource(ResourceId source_id,
1841 ResourceId dest_id,
1842 const gfx::Rect& rect) {
1843 TRACE_EVENT0("cc", "ResourceProvider::CopyResource");
1845 Resource* source_resource = GetResource(source_id);
1846 DCHECK(!source_resource->lock_for_read_count);
1847 DCHECK(source_resource->origin == Resource::INTERNAL);
1848 DCHECK_EQ(source_resource->exported_count, 0);
1849 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, source_resource->type);
1850 LazyAllocate(source_resource);
1852 Resource* dest_resource = GetResource(dest_id);
1853 DCHECK(!dest_resource->locked_for_write);
1854 DCHECK(!dest_resource->lock_for_read_count);
1855 DCHECK(dest_resource->origin == Resource::INTERNAL);
1856 DCHECK_EQ(dest_resource->exported_count, 0);
1857 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, dest_resource->type);
1858 LazyAllocate(dest_resource);
1860 DCHECK_EQ(source_resource->type, dest_resource->type);
1861 DCHECK_EQ(source_resource->format, dest_resource->format);
1862 DCHECK(source_resource->size == dest_resource->size);
1863 DCHECK(gfx::Rect(dest_resource->size).Contains(rect));
1865 GLES2Interface* gl = ContextGL();
1866 DCHECK(gl);
1867 if (source_resource->image_id && source_resource->dirty_image) {
1868 gl->BindTexture(source_resource->target, source_resource->gl_id);
1869 BindImageForSampling(source_resource);
1871 if (use_sync_query_) {
1872 if (!source_resource->gl_read_lock_query_id)
1873 gl->GenQueriesEXT(1, &source_resource->gl_read_lock_query_id);
1874 #if defined(OS_CHROMEOS)
1875 // TODO(reveman): This avoids a performance problem on some ChromeOS
1876 // devices. This needs to be removed to support native GpuMemoryBuffer
1877 // implementations. crbug.com/436314
1878 gl->BeginQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM,
1879 source_resource->gl_read_lock_query_id);
1880 #else
1881 gl->BeginQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM,
1882 source_resource->gl_read_lock_query_id);
1883 #endif
1885 DCHECK(!dest_resource->image_id);
1886 dest_resource->allocated = true;
1887 gl->CopySubTextureCHROMIUM(dest_resource->target, source_resource->gl_id,
1888 dest_resource->gl_id, rect.x(), rect.y(), rect.x(),
1889 rect.y(), rect.width(), rect.height(),
1890 false, false, false);
1891 if (source_resource->gl_read_lock_query_id) {
1892 // End query and create a read lock fence that will prevent access to
1893 // source resource until CopySubTextureCHROMIUM command has completed.
1894 #if defined(OS_CHROMEOS)
1895 gl->EndQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM);
1896 #else
1897 gl->EndQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM);
1898 #endif
1899 source_resource->read_lock_fence = make_scoped_refptr(
1900 new CopyTextureFence(gl, source_resource->gl_read_lock_query_id));
1901 } else {
1902 // Create a SynchronousFence when CHROMIUM_sync_query extension is missing.
1903 // Try to use one synchronous fence for as many CopyResource operations as
1904 // possible as that reduce the number of times we have to synchronize with
1905 // the GL.
1906 if (!synchronous_fence_.get() || synchronous_fence_->has_synchronized())
1907 synchronous_fence_ = make_scoped_refptr(new SynchronousFence(gl));
1908 source_resource->read_lock_fence = synchronous_fence_;
1909 source_resource->read_lock_fence->Set();
1913 void ResourceProvider::WaitSyncPointIfNeeded(ResourceId id) {
1914 Resource* resource = GetResource(id);
1915 DCHECK_EQ(resource->exported_count, 0);
1916 DCHECK(resource->allocated);
1917 if (resource->type != RESOURCE_TYPE_GL_TEXTURE || resource->gl_id)
1918 return;
1919 if (!resource->mailbox.sync_point())
1920 return;
1921 DCHECK(resource->mailbox.IsValid());
1922 GLES2Interface* gl = ContextGL();
1923 DCHECK(gl);
1924 gl->WaitSyncPointCHROMIUM(resource->mailbox.sync_point());
1925 resource->mailbox.set_sync_point(0);
1928 void ResourceProvider::WaitReadLockIfNeeded(ResourceId id) {
1929 Resource* resource = GetResource(id);
1930 DCHECK_EQ(resource->exported_count, 0);
1931 if (!resource->read_lock_fence.get())
1932 return;
1934 resource->read_lock_fence->Wait();
1937 GLint ResourceProvider::GetActiveTextureUnit(GLES2Interface* gl) {
1938 GLint active_unit = 0;
1939 gl->GetIntegerv(GL_ACTIVE_TEXTURE, &active_unit);
1940 return active_unit;
1943 void ResourceProvider::ValidateResource(ResourceId id) const {
1944 DCHECK(thread_checker_.CalledOnValidThread());
1945 DCHECK(id);
1946 DCHECK(resources_.find(id) != resources_.end());
1949 GLES2Interface* ResourceProvider::ContextGL() const {
1950 ContextProvider* context_provider = output_surface_->context_provider();
1951 return context_provider ? context_provider->ContextGL() : NULL;
1954 class GrContext* ResourceProvider::GrContext(bool worker_context) const {
1955 ContextProvider* context_provider =
1956 worker_context ? output_surface_->worker_context_provider()
1957 : output_surface_->context_provider();
1958 return context_provider ? context_provider->GrContext() : NULL;
1961 } // namespace cc