Add GN isolate support for a bunch of unittests.
[chromium-blink-merge.git] / cc / resources / resource_provider.cc
blob4c7c9dae8aedbca3ac221362f45a60ad9f90daa3
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 ResourceId ResourceProvider::CreateResource(const gfx::Size& size,
445 GLint wrap_mode,
446 TextureHint hint,
447 ResourceFormat format) {
448 DCHECK(!size.IsEmpty());
449 switch (default_resource_type_) {
450 case RESOURCE_TYPE_GL_TEXTURE:
451 return CreateGLTexture(size,
452 GL_TEXTURE_2D,
453 GL_TEXTURE_POOL_UNMANAGED_CHROMIUM,
454 wrap_mode,
455 hint,
456 format);
457 case RESOURCE_TYPE_BITMAP:
458 DCHECK_EQ(RGBA_8888, format);
459 return CreateBitmap(size, wrap_mode);
462 LOG(FATAL) << "Invalid default resource type.";
463 return 0;
466 ResourceId ResourceProvider::CreateManagedResource(const gfx::Size& size,
467 GLenum target,
468 GLint wrap_mode,
469 TextureHint hint,
470 ResourceFormat format) {
471 DCHECK(!size.IsEmpty());
472 switch (default_resource_type_) {
473 case RESOURCE_TYPE_GL_TEXTURE:
474 return CreateGLTexture(size,
475 target,
476 GL_TEXTURE_POOL_MANAGED_CHROMIUM,
477 wrap_mode,
478 hint,
479 format);
480 case RESOURCE_TYPE_BITMAP:
481 DCHECK_EQ(RGBA_8888, format);
482 return CreateBitmap(size, wrap_mode);
485 LOG(FATAL) << "Invalid default resource type.";
486 return 0;
489 ResourceId ResourceProvider::CreateGLTexture(const gfx::Size& size,
490 GLenum target,
491 GLenum texture_pool,
492 GLint wrap_mode,
493 TextureHint hint,
494 ResourceFormat format) {
495 DCHECK_LE(size.width(), max_texture_size_);
496 DCHECK_LE(size.height(), max_texture_size_);
497 DCHECK(thread_checker_.CalledOnValidThread());
499 ResourceId id = next_id_++;
500 Resource* resource = InsertResource(
501 id, Resource(0, size, Resource::INTERNAL, target, GL_LINEAR, texture_pool,
502 wrap_mode, hint, format));
503 resource->allocated = false;
504 return id;
507 ResourceId ResourceProvider::CreateBitmap(const gfx::Size& size,
508 GLint wrap_mode) {
509 DCHECK(thread_checker_.CalledOnValidThread());
511 scoped_ptr<SharedBitmap> bitmap =
512 shared_bitmap_manager_->AllocateSharedBitmap(size);
513 uint8_t* pixels = bitmap->pixels();
514 DCHECK(pixels);
516 ResourceId id = next_id_++;
517 Resource* resource =
518 InsertResource(id, Resource(pixels, bitmap.release(), size,
519 Resource::INTERNAL, GL_LINEAR, wrap_mode));
520 resource->allocated = true;
521 return id;
524 ResourceId ResourceProvider::CreateResourceFromIOSurface(
525 const gfx::Size& size,
526 unsigned io_surface_id) {
527 DCHECK(thread_checker_.CalledOnValidThread());
529 ResourceId id = next_id_++;
530 Resource* resource = InsertResource(
531 id, Resource(0, gfx::Size(), Resource::INTERNAL, GL_TEXTURE_RECTANGLE_ARB,
532 GL_LINEAR, GL_TEXTURE_POOL_UNMANAGED_CHROMIUM,
533 GL_CLAMP_TO_EDGE, TEXTURE_HINT_IMMUTABLE, RGBA_8888));
534 LazyCreate(resource);
535 GLES2Interface* gl = ContextGL();
536 DCHECK(gl);
537 gl->BindTexture(GL_TEXTURE_RECTANGLE_ARB, resource->gl_id);
538 gl->TexImageIOSurface2DCHROMIUM(
539 GL_TEXTURE_RECTANGLE_ARB, size.width(), size.height(), io_surface_id, 0);
540 resource->allocated = true;
541 return id;
544 ResourceId ResourceProvider::CreateResourceFromTextureMailbox(
545 const TextureMailbox& mailbox,
546 scoped_ptr<SingleReleaseCallbackImpl> release_callback_impl,
547 bool read_lock_fences_enabled) {
548 DCHECK(thread_checker_.CalledOnValidThread());
549 // Just store the information. Mailbox will be consumed in LockForRead().
550 ResourceId id = next_id_++;
551 DCHECK(mailbox.IsValid());
552 Resource* resource = nullptr;
553 if (mailbox.IsTexture()) {
554 resource = InsertResource(
555 id, Resource(0, gfx::Size(), Resource::EXTERNAL, mailbox.target(),
556 mailbox.nearest_neighbor() ? GL_NEAREST : GL_LINEAR, 0,
557 GL_CLAMP_TO_EDGE, TEXTURE_HINT_IMMUTABLE, RGBA_8888));
558 } else {
559 DCHECK(mailbox.IsSharedMemory());
560 SharedBitmap* shared_bitmap = mailbox.shared_bitmap();
561 uint8_t* pixels = shared_bitmap->pixels();
562 DCHECK(pixels);
563 resource = InsertResource(
564 id, Resource(pixels, shared_bitmap, mailbox.size_in_pixels(),
565 Resource::EXTERNAL, GL_LINEAR, GL_CLAMP_TO_EDGE));
567 resource->allocated = true;
568 resource->mailbox = mailbox;
569 resource->release_callback_impl =
570 base::Bind(&SingleReleaseCallbackImpl::Run,
571 base::Owned(release_callback_impl.release()));
572 resource->read_lock_fences_enabled = read_lock_fences_enabled;
573 return id;
576 ResourceId ResourceProvider::CreateResourceFromTextureMailbox(
577 const TextureMailbox& mailbox,
578 scoped_ptr<SingleReleaseCallbackImpl> release_callback_impl) {
579 return CreateResourceFromTextureMailbox(mailbox, release_callback_impl.Pass(),
580 false);
583 void ResourceProvider::DeleteResource(ResourceId id) {
584 DCHECK(thread_checker_.CalledOnValidThread());
585 ResourceMap::iterator it = resources_.find(id);
586 CHECK(it != resources_.end());
587 Resource* resource = &it->second;
588 DCHECK(!resource->marked_for_deletion);
589 DCHECK_EQ(resource->imported_count, 0);
590 DCHECK(resource->pending_set_pixels || !resource->locked_for_write);
592 if (resource->exported_count > 0 || resource->lock_for_read_count > 0 ||
593 !ReadLockFenceHasPassed(resource)) {
594 resource->marked_for_deletion = true;
595 return;
596 } else {
597 DeleteResourceInternal(it, NORMAL);
601 void ResourceProvider::DeleteResourceInternal(ResourceMap::iterator it,
602 DeleteStyle style) {
603 TRACE_EVENT0("cc", "ResourceProvider::DeleteResourceInternal");
604 Resource* resource = &it->second;
605 bool lost_resource = resource->lost;
607 DCHECK(resource->exported_count == 0 || style != NORMAL);
608 if (style == FOR_SHUTDOWN && resource->exported_count > 0)
609 lost_resource = true;
611 if (resource->image_id) {
612 DCHECK(resource->origin == Resource::INTERNAL);
613 GLES2Interface* gl = ContextGL();
614 DCHECK(gl);
615 gl->DestroyImageCHROMIUM(resource->image_id);
617 if (resource->gl_upload_query_id) {
618 DCHECK(resource->origin == Resource::INTERNAL);
619 GLES2Interface* gl = ContextGL();
620 DCHECK(gl);
621 gl->DeleteQueriesEXT(1, &resource->gl_upload_query_id);
623 if (resource->gl_read_lock_query_id) {
624 DCHECK(resource->origin == Resource::INTERNAL);
625 GLES2Interface* gl = ContextGL();
626 DCHECK(gl);
627 gl->DeleteQueriesEXT(1, &resource->gl_read_lock_query_id);
629 if (resource->gl_pixel_buffer_id) {
630 DCHECK(resource->origin == Resource::INTERNAL);
631 GLES2Interface* gl = ContextGL();
632 DCHECK(gl);
633 gl->DeleteBuffers(1, &resource->gl_pixel_buffer_id);
635 if (resource->origin == Resource::EXTERNAL) {
636 DCHECK(resource->mailbox.IsValid());
637 GLuint sync_point = resource->mailbox.sync_point();
638 if (resource->type == RESOURCE_TYPE_GL_TEXTURE) {
639 DCHECK(resource->mailbox.IsTexture());
640 lost_resource |= lost_output_surface_;
641 GLES2Interface* gl = ContextGL();
642 DCHECK(gl);
643 if (resource->gl_id) {
644 gl->DeleteTextures(1, &resource->gl_id);
645 resource->gl_id = 0;
646 if (!lost_resource)
647 sync_point = gl->InsertSyncPointCHROMIUM();
649 } else {
650 DCHECK(resource->mailbox.IsSharedMemory());
651 resource->shared_bitmap = nullptr;
652 resource->pixels = nullptr;
654 resource->release_callback_impl.Run(
655 sync_point, lost_resource, blocking_main_thread_task_runner_);
657 if (resource->gl_id) {
658 GLES2Interface* gl = ContextGL();
659 DCHECK(gl);
660 gl->DeleteTextures(1, &resource->gl_id);
661 resource->gl_id = 0;
663 if (resource->shared_bitmap) {
664 DCHECK(resource->origin != Resource::EXTERNAL);
665 DCHECK_EQ(RESOURCE_TYPE_BITMAP, resource->type);
666 delete resource->shared_bitmap;
667 resource->pixels = NULL;
669 if (resource->pixels) {
670 DCHECK(resource->origin == Resource::INTERNAL);
671 delete[] resource->pixels;
672 resource->pixels = NULL;
674 if (resource->gpu_memory_buffer) {
675 DCHECK(resource->origin == Resource::INTERNAL);
676 delete resource->gpu_memory_buffer;
677 resource->gpu_memory_buffer = NULL;
679 resources_.erase(it);
682 ResourceProvider::ResourceType ResourceProvider::GetResourceType(
683 ResourceId id) {
684 return GetResource(id)->type;
687 void ResourceProvider::CopyToResource(ResourceId id,
688 const uint8_t* image,
689 const gfx::Size& image_size) {
690 Resource* resource = GetResource(id);
691 DCHECK(!resource->locked_for_write);
692 DCHECK(!resource->lock_for_read_count);
693 DCHECK(resource->origin == Resource::INTERNAL);
694 DCHECK_EQ(resource->exported_count, 0);
695 DCHECK(ReadLockFenceHasPassed(resource));
696 LazyAllocate(resource);
698 DCHECK_EQ(image_size.width(), resource->size.width());
699 DCHECK_EQ(image_size.height(), resource->size.height());
701 if (resource->type == RESOURCE_TYPE_BITMAP) {
702 DCHECK_EQ(RESOURCE_TYPE_BITMAP, resource->type);
703 DCHECK(resource->allocated);
704 DCHECK_EQ(RGBA_8888, resource->format);
705 SkImageInfo source_info =
706 SkImageInfo::MakeN32Premul(image_size.width(), image_size.height());
707 size_t image_stride = image_size.width() * 4;
709 ScopedWriteLockSoftware lock(this, id);
710 SkCanvas dest(lock.sk_bitmap());
711 dest.writePixels(source_info, image, image_stride, 0, 0);
712 } else {
713 DCHECK(resource->gl_id);
714 DCHECK(!resource->pending_set_pixels);
715 DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D));
716 GLES2Interface* gl = ContextGL();
717 DCHECK(gl);
718 gl->BindTexture(GL_TEXTURE_2D, resource->gl_id);
720 if (resource->format == ETC1) {
721 base::CheckedNumeric<int> num_bytes = BitsPerPixel(ETC1);
722 num_bytes *= image_size.width();
723 num_bytes *= image_size.height();
724 num_bytes /= 8;
725 gl->CompressedTexImage2D(GL_TEXTURE_2D, 0, GLInternalFormat(ETC1),
726 image_size.width(), image_size.height(), 0,
727 num_bytes.ValueOrDie(), image);
728 } else {
729 gl->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, image_size.width(),
730 image_size.height(), GLDataFormat(resource->format),
731 GLDataType(resource->format), image);
736 ResourceProvider::Resource* ResourceProvider::InsertResource(
737 ResourceId id,
738 const Resource& resource) {
739 std::pair<ResourceMap::iterator, bool> result =
740 resources_.insert(ResourceMap::value_type(id, resource));
741 DCHECK(result.second);
742 return &result.first->second;
745 ResourceProvider::Resource* ResourceProvider::GetResource(ResourceId id) {
746 DCHECK(thread_checker_.CalledOnValidThread());
747 DCHECK(id);
748 ResourceMap::iterator it = resources_.find(id);
749 DCHECK(it != resources_.end());
750 return &it->second;
753 const ResourceProvider::Resource* ResourceProvider::LockForRead(ResourceId id) {
754 Resource* resource = GetResource(id);
755 DCHECK(!resource->locked_for_write ||
756 resource->set_pixels_completion_forced) <<
757 "locked for write: " << resource->locked_for_write <<
758 " pixels completion forced: " << resource->set_pixels_completion_forced;
759 DCHECK_EQ(resource->exported_count, 0);
760 // Uninitialized! Call SetPixels or LockForWrite first.
761 DCHECK(resource->allocated);
763 LazyCreate(resource);
765 if (resource->type == RESOURCE_TYPE_GL_TEXTURE && !resource->gl_id) {
766 DCHECK(resource->origin != Resource::INTERNAL);
767 DCHECK(resource->mailbox.IsTexture());
769 // Mailbox sync_points must be processed by a call to
770 // WaitSyncPointIfNeeded() prior to calling LockForRead().
771 DCHECK(!resource->mailbox.sync_point());
773 GLES2Interface* gl = ContextGL();
774 DCHECK(gl);
775 resource->gl_id = gl->CreateAndConsumeTextureCHROMIUM(
776 resource->mailbox.target(), resource->mailbox.name());
779 if (!resource->pixels && resource->has_shared_bitmap_id &&
780 shared_bitmap_manager_) {
781 scoped_ptr<SharedBitmap> bitmap =
782 shared_bitmap_manager_->GetSharedBitmapFromId(
783 resource->size, resource->shared_bitmap_id);
784 if (bitmap) {
785 resource->shared_bitmap = bitmap.release();
786 resource->pixels = resource->shared_bitmap->pixels();
790 resource->lock_for_read_count++;
791 if (resource->read_lock_fences_enabled) {
792 if (current_read_lock_fence_.get())
793 current_read_lock_fence_->Set();
794 resource->read_lock_fence = current_read_lock_fence_;
797 return resource;
800 void ResourceProvider::UnlockForRead(ResourceId id) {
801 DCHECK(thread_checker_.CalledOnValidThread());
802 ResourceMap::iterator it = resources_.find(id);
803 CHECK(it != resources_.end());
805 Resource* resource = &it->second;
806 DCHECK_GT(resource->lock_for_read_count, 0);
807 DCHECK_EQ(resource->exported_count, 0);
808 resource->lock_for_read_count--;
809 if (resource->marked_for_deletion && !resource->lock_for_read_count) {
810 if (!resource->child_id) {
811 // The resource belongs to this ResourceProvider, so it can be destroyed.
812 DeleteResourceInternal(it, NORMAL);
813 } else {
814 ChildMap::iterator child_it = children_.find(resource->child_id);
815 ResourceIdArray unused;
816 unused.push_back(id);
817 DeleteAndReturnUnusedResourcesToChild(child_it, NORMAL, unused);
822 ResourceProvider::Resource* ResourceProvider::LockForWrite(ResourceId id) {
823 Resource* resource = GetResource(id);
824 DCHECK(CanLockForWrite(id));
826 resource->locked_for_write = true;
827 return resource;
830 bool ResourceProvider::CanLockForWrite(ResourceId id) {
831 Resource* resource = GetResource(id);
832 return !resource->locked_for_write && !resource->lock_for_read_count &&
833 !resource->exported_count && resource->origin == Resource::INTERNAL &&
834 !resource->lost && ReadLockFenceHasPassed(resource);
837 void ResourceProvider::UnlockForWrite(ResourceProvider::Resource* resource) {
838 DCHECK(resource->locked_for_write);
839 DCHECK_EQ(resource->exported_count, 0);
840 DCHECK(resource->origin == Resource::INTERNAL);
841 resource->locked_for_write = false;
844 void ResourceProvider::EnableReadLockFencesForTesting(ResourceId id) {
845 Resource* resource = GetResource(id);
846 DCHECK(resource);
847 resource->read_lock_fences_enabled = true;
850 ResourceProvider::ScopedReadLockGL::ScopedReadLockGL(
851 ResourceProvider* resource_provider,
852 ResourceId resource_id)
853 : resource_provider_(resource_provider),
854 resource_id_(resource_id),
855 resource_(resource_provider->LockForRead(resource_id)) {
856 DCHECK(resource_);
859 ResourceProvider::ScopedReadLockGL::~ScopedReadLockGL() {
860 resource_provider_->UnlockForRead(resource_id_);
863 ResourceProvider::ScopedSamplerGL::ScopedSamplerGL(
864 ResourceProvider* resource_provider,
865 ResourceId resource_id,
866 GLenum filter)
867 : ScopedReadLockGL(resource_provider, resource_id),
868 unit_(GL_TEXTURE0),
869 target_(resource_provider->BindForSampling(resource_id, unit_, filter)) {
872 ResourceProvider::ScopedSamplerGL::ScopedSamplerGL(
873 ResourceProvider* resource_provider,
874 ResourceId resource_id,
875 GLenum unit,
876 GLenum filter)
877 : ScopedReadLockGL(resource_provider, resource_id),
878 unit_(unit),
879 target_(resource_provider->BindForSampling(resource_id, unit_, filter)) {
882 ResourceProvider::ScopedSamplerGL::~ScopedSamplerGL() {
885 ResourceProvider::ScopedWriteLockGL::ScopedWriteLockGL(
886 ResourceProvider* resource_provider,
887 ResourceId resource_id)
888 : resource_provider_(resource_provider),
889 resource_(resource_provider->LockForWrite(resource_id)) {
890 resource_provider_->LazyAllocate(resource_);
891 texture_id_ = resource_->gl_id;
892 DCHECK(texture_id_);
895 ResourceProvider::ScopedWriteLockGL::~ScopedWriteLockGL() {
896 resource_provider_->UnlockForWrite(resource_);
899 void ResourceProvider::PopulateSkBitmapWithResource(
900 SkBitmap* sk_bitmap, const Resource* resource) {
901 DCHECK_EQ(RGBA_8888, resource->format);
902 SkImageInfo info = SkImageInfo::MakeN32Premul(resource->size.width(),
903 resource->size.height());
904 sk_bitmap->installPixels(info, resource->pixels, info.minRowBytes());
907 ResourceProvider::ScopedReadLockSoftware::ScopedReadLockSoftware(
908 ResourceProvider* resource_provider,
909 ResourceId resource_id)
910 : resource_provider_(resource_provider), resource_id_(resource_id) {
911 const Resource* resource = resource_provider->LockForRead(resource_id);
912 wrap_mode_ = resource->wrap_mode;
913 ResourceProvider::PopulateSkBitmapWithResource(&sk_bitmap_, resource);
916 ResourceProvider::ScopedReadLockSoftware::~ScopedReadLockSoftware() {
917 resource_provider_->UnlockForRead(resource_id_);
920 ResourceProvider::ScopedWriteLockSoftware::ScopedWriteLockSoftware(
921 ResourceProvider* resource_provider,
922 ResourceId resource_id)
923 : resource_provider_(resource_provider),
924 resource_(resource_provider->LockForWrite(resource_id)) {
925 ResourceProvider::PopulateSkBitmapWithResource(&sk_bitmap_, resource_);
926 DCHECK(valid());
929 ResourceProvider::ScopedWriteLockSoftware::~ScopedWriteLockSoftware() {
930 DCHECK(thread_checker_.CalledOnValidThread());
931 resource_provider_->UnlockForWrite(resource_);
934 ResourceProvider::ScopedWriteLockGpuMemoryBuffer::
935 ScopedWriteLockGpuMemoryBuffer(ResourceProvider* resource_provider,
936 ResourceId resource_id)
937 : resource_provider_(resource_provider),
938 resource_(resource_provider->LockForWrite(resource_id)),
939 gpu_memory_buffer_manager_(resource_provider->gpu_memory_buffer_manager_),
940 gpu_memory_buffer_(nullptr),
941 size_(resource_->size),
942 format_(resource_->format) {
943 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource_->type);
944 std::swap(gpu_memory_buffer_, resource_->gpu_memory_buffer);
947 ResourceProvider::ScopedWriteLockGpuMemoryBuffer::
948 ~ScopedWriteLockGpuMemoryBuffer() {
949 DCHECK(thread_checker_.CalledOnValidThread());
950 resource_provider_->UnlockForWrite(resource_);
951 if (!gpu_memory_buffer_)
952 return;
954 resource_provider_->LazyCreate(resource_);
956 if (!resource_->image_id) {
957 GLES2Interface* gl = resource_provider_->ContextGL();
958 DCHECK(gl);
960 #if defined(OS_CHROMEOS)
961 // TODO(reveman): GL_COMMANDS_ISSUED_CHROMIUM is used for synchronization
962 // on ChromeOS to avoid some performance issues. This only works with
963 // shared memory backed buffers. crbug.com/436314
964 DCHECK_EQ(gpu_memory_buffer_->GetHandle().type, gfx::SHARED_MEMORY_BUFFER);
965 #endif
967 resource_->image_id = gl->CreateImageCHROMIUM(
968 gpu_memory_buffer_->AsClientBuffer(), size_.width(), size_.height(),
969 GLInternalFormat(resource_->format));
972 std::swap(resource_->gpu_memory_buffer, gpu_memory_buffer_);
973 resource_->allocated = true;
974 resource_->dirty_image = true;
976 // GpuMemoryBuffer provides direct access to the memory used by the GPU.
977 // Read lock fences are required to ensure that we're not trying to map a
978 // buffer that is currently in-use by the GPU.
979 resource_->read_lock_fences_enabled = true;
982 gfx::GpuMemoryBuffer*
983 ResourceProvider::ScopedWriteLockGpuMemoryBuffer::GetGpuMemoryBuffer() {
984 if (gpu_memory_buffer_)
985 return gpu_memory_buffer_;
986 gfx::GpuMemoryBuffer::Usage usage =
987 resource_provider_->use_persistent_map_for_gpu_memory_buffers()
988 ? gfx::GpuMemoryBuffer::PERSISTENT_MAP
989 : gfx::GpuMemoryBuffer::MAP;
990 scoped_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer =
991 gpu_memory_buffer_manager_->AllocateGpuMemoryBuffer(
992 size_, ToGpuMemoryBufferFormat(format_), usage);
993 gpu_memory_buffer_ = gpu_memory_buffer.release();
994 return gpu_memory_buffer_;
997 ResourceProvider::ScopedWriteLockGr::ScopedWriteLockGr(
998 ResourceProvider* resource_provider,
999 ResourceId resource_id)
1000 : resource_provider_(resource_provider),
1001 resource_(resource_provider->LockForWrite(resource_id)) {
1002 DCHECK(thread_checker_.CalledOnValidThread());
1003 resource_provider_->LazyAllocate(resource_);
1006 ResourceProvider::ScopedWriteLockGr::~ScopedWriteLockGr() {
1007 DCHECK(thread_checker_.CalledOnValidThread());
1008 DCHECK(resource_->locked_for_write);
1009 resource_provider_->UnlockForWrite(resource_);
1012 void ResourceProvider::ScopedWriteLockGr::InitSkSurface(
1013 bool use_distance_field_text,
1014 bool can_use_lcd_text,
1015 int msaa_sample_count) {
1016 DCHECK(resource_->locked_for_write);
1018 GrBackendTextureDesc desc;
1019 desc.fFlags = kRenderTarget_GrBackendTextureFlag;
1020 desc.fWidth = resource_->size.width();
1021 desc.fHeight = resource_->size.height();
1022 desc.fConfig = ToGrPixelConfig(resource_->format);
1023 desc.fOrigin = kTopLeft_GrSurfaceOrigin;
1024 desc.fTextureHandle = resource_->gl_id;
1025 desc.fSampleCnt = msaa_sample_count;
1027 bool use_worker_context = true;
1028 class GrContext* gr_context =
1029 resource_provider_->GrContext(use_worker_context);
1030 uint32_t flags =
1031 use_distance_field_text ? SkSurfaceProps::kUseDistanceFieldFonts_Flag : 0;
1032 // Use unknown pixel geometry to disable LCD text.
1033 SkSurfaceProps surface_props(flags, kUnknown_SkPixelGeometry);
1034 if (can_use_lcd_text) {
1035 // LegacyFontHost will get LCD text and skia figures out what type to use.
1036 surface_props =
1037 SkSurfaceProps(flags, SkSurfaceProps::kLegacyFontHost_InitType);
1039 sk_surface_ = skia::AdoptRef(
1040 SkSurface::NewWrappedRenderTarget(gr_context, desc, &surface_props));
1043 void ResourceProvider::ScopedWriteLockGr::ReleaseSkSurface() {
1044 sk_surface_.clear();
1047 ResourceProvider::SynchronousFence::SynchronousFence(
1048 gpu::gles2::GLES2Interface* gl)
1049 : gl_(gl), has_synchronized_(true) {
1052 ResourceProvider::SynchronousFence::~SynchronousFence() {
1055 void ResourceProvider::SynchronousFence::Set() {
1056 has_synchronized_ = false;
1059 bool ResourceProvider::SynchronousFence::HasPassed() {
1060 if (!has_synchronized_) {
1061 has_synchronized_ = true;
1062 Synchronize();
1064 return true;
1067 void ResourceProvider::SynchronousFence::Wait() {
1068 HasPassed();
1071 void ResourceProvider::SynchronousFence::Synchronize() {
1072 TRACE_EVENT0("cc", "ResourceProvider::SynchronousFence::Synchronize");
1073 gl_->Finish();
1076 ResourceProvider::ResourceProvider(
1077 OutputSurface* output_surface,
1078 SharedBitmapManager* shared_bitmap_manager,
1079 gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
1080 BlockingTaskRunner* blocking_main_thread_task_runner,
1081 int highp_threshold_min,
1082 bool use_rgba_4444_texture_format,
1083 size_t id_allocation_chunk_size,
1084 bool use_persistent_map_for_gpu_memory_buffers)
1085 : output_surface_(output_surface),
1086 shared_bitmap_manager_(shared_bitmap_manager),
1087 gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
1088 blocking_main_thread_task_runner_(blocking_main_thread_task_runner),
1089 lost_output_surface_(false),
1090 highp_threshold_min_(highp_threshold_min),
1091 next_id_(1),
1092 next_child_(1),
1093 default_resource_type_(RESOURCE_TYPE_BITMAP),
1094 use_texture_storage_ext_(false),
1095 use_texture_format_bgra_(false),
1096 use_texture_usage_hint_(false),
1097 use_compressed_texture_etc1_(false),
1098 yuv_resource_format_(LUMINANCE_8),
1099 max_texture_size_(0),
1100 best_texture_format_(RGBA_8888),
1101 best_render_buffer_format_(RGBA_8888),
1102 use_rgba_4444_texture_format_(use_rgba_4444_texture_format),
1103 id_allocation_chunk_size_(id_allocation_chunk_size),
1104 use_sync_query_(false),
1105 use_persistent_map_for_gpu_memory_buffers_(
1106 use_persistent_map_for_gpu_memory_buffers) {
1107 DCHECK(output_surface_->HasClient());
1108 DCHECK(id_allocation_chunk_size_);
1111 void ResourceProvider::Initialize() {
1112 DCHECK(thread_checker_.CalledOnValidThread());
1114 GLES2Interface* gl = ContextGL();
1115 if (!gl) {
1116 default_resource_type_ = RESOURCE_TYPE_BITMAP;
1117 // Pick an arbitrary limit here similar to what hardware might.
1118 max_texture_size_ = 16 * 1024;
1119 best_texture_format_ = RGBA_8888;
1120 return;
1123 DCHECK(!texture_id_allocator_);
1124 DCHECK(!buffer_id_allocator_);
1126 const ContextProvider::Capabilities& caps =
1127 output_surface_->context_provider()->ContextCapabilities();
1129 default_resource_type_ = RESOURCE_TYPE_GL_TEXTURE;
1130 use_texture_storage_ext_ = caps.gpu.texture_storage;
1131 use_texture_format_bgra_ = caps.gpu.texture_format_bgra8888;
1132 use_texture_usage_hint_ = caps.gpu.texture_usage;
1133 use_compressed_texture_etc1_ = caps.gpu.texture_format_etc1;
1134 yuv_resource_format_ = caps.gpu.texture_rg ? RED_8 : LUMINANCE_8;
1135 use_sync_query_ = caps.gpu.sync_query;
1137 max_texture_size_ = 0; // Context expects cleared value.
1138 gl->GetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size_);
1139 best_texture_format_ =
1140 PlatformColor::BestTextureFormat(use_texture_format_bgra_);
1142 best_render_buffer_format_ =
1143 PlatformColor::BestTextureFormat(caps.gpu.render_buffer_format_bgra8888);
1145 texture_id_allocator_.reset(
1146 new TextureIdAllocator(gl, id_allocation_chunk_size_));
1147 buffer_id_allocator_.reset(
1148 new BufferIdAllocator(gl, id_allocation_chunk_size_));
1151 int ResourceProvider::CreateChild(const ReturnCallback& return_callback) {
1152 DCHECK(thread_checker_.CalledOnValidThread());
1154 Child child_info;
1155 child_info.return_callback = return_callback;
1157 int child = next_child_++;
1158 children_[child] = child_info;
1159 return child;
1162 void ResourceProvider::SetChildNeedsSyncPoints(int child_id, bool needs) {
1163 ChildMap::iterator it = children_.find(child_id);
1164 DCHECK(it != children_.end());
1165 it->second.needs_sync_points = needs;
1168 void ResourceProvider::DestroyChild(int child_id) {
1169 ChildMap::iterator it = children_.find(child_id);
1170 DCHECK(it != children_.end());
1171 DestroyChildInternal(it, NORMAL);
1174 void ResourceProvider::DestroyChildInternal(ChildMap::iterator it,
1175 DeleteStyle style) {
1176 DCHECK(thread_checker_.CalledOnValidThread());
1178 Child& child = it->second;
1179 DCHECK(style == FOR_SHUTDOWN || !child.marked_for_deletion);
1181 ResourceIdArray resources_for_child;
1183 for (ResourceIdMap::iterator child_it = child.child_to_parent_map.begin();
1184 child_it != child.child_to_parent_map.end();
1185 ++child_it) {
1186 ResourceId id = child_it->second;
1187 resources_for_child.push_back(id);
1190 child.marked_for_deletion = true;
1192 DeleteAndReturnUnusedResourcesToChild(it, style, resources_for_child);
1195 const ResourceProvider::ResourceIdMap& ResourceProvider::GetChildToParentMap(
1196 int child) const {
1197 DCHECK(thread_checker_.CalledOnValidThread());
1198 ChildMap::const_iterator it = children_.find(child);
1199 DCHECK(it != children_.end());
1200 DCHECK(!it->second.marked_for_deletion);
1201 return it->second.child_to_parent_map;
1204 void ResourceProvider::PrepareSendToParent(const ResourceIdArray& resources,
1205 TransferableResourceArray* list) {
1206 DCHECK(thread_checker_.CalledOnValidThread());
1207 GLES2Interface* gl = ContextGL();
1208 bool need_sync_point = false;
1209 for (ResourceIdArray::const_iterator it = resources.begin();
1210 it != resources.end();
1211 ++it) {
1212 TransferableResource resource;
1213 TransferResource(gl, *it, &resource);
1214 if (!resource.mailbox_holder.sync_point && !resource.is_software)
1215 need_sync_point = true;
1216 ++resources_.find(*it)->second.exported_count;
1217 list->push_back(resource);
1219 if (need_sync_point &&
1220 output_surface_->capabilities().delegated_sync_points_required) {
1221 GLuint sync_point = gl->InsertSyncPointCHROMIUM();
1222 for (TransferableResourceArray::iterator it = list->begin();
1223 it != list->end();
1224 ++it) {
1225 if (!it->mailbox_holder.sync_point)
1226 it->mailbox_holder.sync_point = sync_point;
1231 void ResourceProvider::ReceiveFromChild(
1232 int child, const TransferableResourceArray& resources) {
1233 DCHECK(thread_checker_.CalledOnValidThread());
1234 GLES2Interface* gl = ContextGL();
1235 Child& child_info = children_.find(child)->second;
1236 DCHECK(!child_info.marked_for_deletion);
1237 for (TransferableResourceArray::const_iterator it = resources.begin();
1238 it != resources.end();
1239 ++it) {
1240 ResourceIdMap::iterator resource_in_map_it =
1241 child_info.child_to_parent_map.find(it->id);
1242 if (resource_in_map_it != child_info.child_to_parent_map.end()) {
1243 Resource* resource = GetResource(resource_in_map_it->second);
1244 resource->marked_for_deletion = false;
1245 resource->imported_count++;
1246 continue;
1249 if ((!it->is_software && !gl) ||
1250 (it->is_software && !shared_bitmap_manager_)) {
1251 TRACE_EVENT0("cc", "ResourceProvider::ReceiveFromChild dropping invalid");
1252 ReturnedResourceArray to_return;
1253 to_return.push_back(it->ToReturnedResource());
1254 child_info.return_callback.Run(to_return,
1255 blocking_main_thread_task_runner_);
1256 continue;
1259 ResourceId local_id = next_id_++;
1260 Resource* resource = nullptr;
1261 if (it->is_software) {
1262 resource = InsertResource(
1263 local_id,
1264 Resource(it->mailbox_holder.mailbox, it->size, Resource::DELEGATED,
1265 GL_LINEAR, it->is_repeated ? GL_REPEAT : GL_CLAMP_TO_EDGE));
1266 } else {
1267 resource = InsertResource(
1268 local_id, Resource(0, it->size, Resource::DELEGATED,
1269 it->mailbox_holder.texture_target, it->filter, 0,
1270 it->is_repeated ? GL_REPEAT : GL_CLAMP_TO_EDGE,
1271 TEXTURE_HINT_IMMUTABLE, it->format));
1272 resource->mailbox = TextureMailbox(it->mailbox_holder.mailbox,
1273 it->mailbox_holder.texture_target,
1274 it->mailbox_holder.sync_point);
1275 resource->read_lock_fences_enabled = it->read_lock_fences_enabled;
1277 resource->child_id = child;
1278 // Don't allocate a texture for a child.
1279 resource->allocated = true;
1280 resource->imported_count = 1;
1281 child_info.parent_to_child_map[local_id] = it->id;
1282 child_info.child_to_parent_map[it->id] = local_id;
1286 void ResourceProvider::DeclareUsedResourcesFromChild(
1287 int child,
1288 const ResourceIdSet& resources_from_child) {
1289 DCHECK(thread_checker_.CalledOnValidThread());
1291 ChildMap::iterator child_it = children_.find(child);
1292 DCHECK(child_it != children_.end());
1293 Child& child_info = child_it->second;
1294 DCHECK(!child_info.marked_for_deletion);
1296 ResourceIdArray unused;
1297 for (ResourceIdMap::iterator it = child_info.child_to_parent_map.begin();
1298 it != child_info.child_to_parent_map.end();
1299 ++it) {
1300 ResourceId local_id = it->second;
1301 bool resource_is_in_use = resources_from_child.count(it->first) > 0;
1302 if (!resource_is_in_use)
1303 unused.push_back(local_id);
1305 DeleteAndReturnUnusedResourcesToChild(child_it, NORMAL, unused);
1308 void ResourceProvider::ReceiveReturnsFromParent(
1309 const ReturnedResourceArray& resources) {
1310 DCHECK(thread_checker_.CalledOnValidThread());
1311 GLES2Interface* gl = ContextGL();
1313 base::hash_map<int, ResourceIdArray> resources_for_child;
1315 for (const ReturnedResource& returned : resources) {
1316 ResourceId local_id = returned.id;
1317 ResourceMap::iterator map_iterator = resources_.find(local_id);
1318 // Resource was already lost (e.g. it belonged to a child that was
1319 // destroyed).
1320 if (map_iterator == resources_.end())
1321 continue;
1323 Resource* resource = &map_iterator->second;
1325 CHECK_GE(resource->exported_count, returned.count);
1326 resource->exported_count -= returned.count;
1327 resource->lost |= returned.lost;
1328 if (resource->exported_count)
1329 continue;
1331 if (returned.sync_point) {
1332 DCHECK(!resource->has_shared_bitmap_id);
1333 if (resource->origin == Resource::INTERNAL) {
1334 DCHECK(resource->gl_id);
1335 gl->WaitSyncPointCHROMIUM(returned.sync_point);
1336 } else {
1337 DCHECK(!resource->gl_id);
1338 resource->mailbox.set_sync_point(returned.sync_point);
1342 if (!resource->marked_for_deletion)
1343 continue;
1345 if (!resource->child_id) {
1346 // The resource belongs to this ResourceProvider, so it can be destroyed.
1347 DeleteResourceInternal(map_iterator, NORMAL);
1348 continue;
1351 DCHECK(resource->origin == Resource::DELEGATED);
1352 resources_for_child[resource->child_id].push_back(local_id);
1355 for (const auto& children : resources_for_child) {
1356 ChildMap::iterator child_it = children_.find(children.first);
1357 DCHECK(child_it != children_.end());
1358 DeleteAndReturnUnusedResourcesToChild(child_it, NORMAL, children.second);
1362 void ResourceProvider::TransferResource(GLES2Interface* gl,
1363 ResourceId id,
1364 TransferableResource* resource) {
1365 Resource* source = GetResource(id);
1366 DCHECK(!source->locked_for_write);
1367 DCHECK(!source->lock_for_read_count);
1368 DCHECK(source->origin != Resource::EXTERNAL || source->mailbox.IsValid());
1369 DCHECK(source->allocated);
1370 resource->id = id;
1371 resource->format = source->format;
1372 resource->mailbox_holder.texture_target = source->target;
1373 resource->filter = source->filter;
1374 resource->size = source->size;
1375 resource->read_lock_fences_enabled = source->read_lock_fences_enabled;
1376 resource->is_repeated = (source->wrap_mode == GL_REPEAT);
1378 if (source->type == RESOURCE_TYPE_BITMAP) {
1379 resource->mailbox_holder.mailbox = source->shared_bitmap_id;
1380 resource->is_software = true;
1381 } else if (!source->mailbox.IsValid()) {
1382 LazyCreate(source);
1383 DCHECK(source->gl_id);
1384 DCHECK(source->origin == Resource::INTERNAL);
1385 if (source->image_id) {
1386 DCHECK(source->dirty_image);
1387 gl->BindTexture(resource->mailbox_holder.texture_target, source->gl_id);
1388 BindImageForSampling(source);
1390 // This is a resource allocated by the compositor, we need to produce it.
1391 // Don't set a sync point, the caller will do it.
1392 gl->GenMailboxCHROMIUM(resource->mailbox_holder.mailbox.name);
1393 gl->ProduceTextureDirectCHROMIUM(source->gl_id,
1394 resource->mailbox_holder.texture_target,
1395 resource->mailbox_holder.mailbox.name);
1397 source->mailbox = TextureMailbox(resource->mailbox_holder);
1398 } else {
1399 DCHECK(source->mailbox.IsTexture());
1400 if (source->image_id && source->dirty_image) {
1401 DCHECK(source->gl_id);
1402 DCHECK(source->origin == Resource::INTERNAL);
1403 gl->BindTexture(resource->mailbox_holder.texture_target, source->gl_id);
1404 BindImageForSampling(source);
1406 // This is either an external resource, or a compositor resource that we
1407 // already exported. Make sure to forward the sync point that we were given.
1408 resource->mailbox_holder.mailbox = source->mailbox.mailbox();
1409 resource->mailbox_holder.texture_target = source->mailbox.target();
1410 resource->mailbox_holder.sync_point = source->mailbox.sync_point();
1411 source->mailbox.set_sync_point(0);
1415 void ResourceProvider::DeleteAndReturnUnusedResourcesToChild(
1416 ChildMap::iterator child_it,
1417 DeleteStyle style,
1418 const ResourceIdArray& unused) {
1419 DCHECK(thread_checker_.CalledOnValidThread());
1420 DCHECK(child_it != children_.end());
1421 Child* child_info = &child_it->second;
1423 if (unused.empty() && !child_info->marked_for_deletion)
1424 return;
1426 ReturnedResourceArray to_return;
1428 GLES2Interface* gl = ContextGL();
1429 bool need_sync_point = false;
1430 for (size_t i = 0; i < unused.size(); ++i) {
1431 ResourceId local_id = unused[i];
1433 ResourceMap::iterator it = resources_.find(local_id);
1434 CHECK(it != resources_.end());
1435 Resource& resource = it->second;
1437 DCHECK(!resource.locked_for_write);
1438 DCHECK(child_info->parent_to_child_map.count(local_id));
1440 ResourceId child_id = child_info->parent_to_child_map[local_id];
1441 DCHECK(child_info->child_to_parent_map.count(child_id));
1443 bool is_lost =
1444 resource.lost ||
1445 (resource.type == RESOURCE_TYPE_GL_TEXTURE && lost_output_surface_);
1446 if (resource.exported_count > 0 || resource.lock_for_read_count > 0) {
1447 if (style != FOR_SHUTDOWN) {
1448 // Defer this resource deletion.
1449 resource.marked_for_deletion = true;
1450 continue;
1452 // We can't postpone the deletion, so we'll have to lose it.
1453 is_lost = true;
1454 } else if (!ReadLockFenceHasPassed(&resource)) {
1455 // TODO(dcastagna): see if it's possible to use this logic for
1456 // the branch above too, where the resource is locked or still exported.
1457 if (style != FOR_SHUTDOWN && !child_info->marked_for_deletion) {
1458 // Defer this resource deletion.
1459 resource.marked_for_deletion = true;
1460 continue;
1462 // We can't postpone the deletion, so we'll have to lose it.
1463 is_lost = true;
1466 if (gl && resource.filter != resource.original_filter) {
1467 DCHECK(resource.target);
1468 DCHECK(resource.gl_id);
1470 gl->BindTexture(resource.target, resource.gl_id);
1471 gl->TexParameteri(resource.target, GL_TEXTURE_MIN_FILTER,
1472 resource.original_filter);
1473 gl->TexParameteri(resource.target, GL_TEXTURE_MAG_FILTER,
1474 resource.original_filter);
1477 ReturnedResource returned;
1478 returned.id = child_id;
1479 returned.sync_point = resource.mailbox.sync_point();
1480 if (!returned.sync_point && resource.type == RESOURCE_TYPE_GL_TEXTURE)
1481 need_sync_point = true;
1482 returned.count = resource.imported_count;
1483 returned.lost = is_lost;
1484 to_return.push_back(returned);
1486 child_info->parent_to_child_map.erase(local_id);
1487 child_info->child_to_parent_map.erase(child_id);
1488 resource.imported_count = 0;
1489 DeleteResourceInternal(it, style);
1491 if (need_sync_point && child_info->needs_sync_points) {
1492 DCHECK(gl);
1493 GLuint sync_point = gl->InsertSyncPointCHROMIUM();
1494 for (size_t i = 0; i < to_return.size(); ++i) {
1495 if (!to_return[i].sync_point)
1496 to_return[i].sync_point = sync_point;
1500 if (!to_return.empty())
1501 child_info->return_callback.Run(to_return,
1502 blocking_main_thread_task_runner_);
1504 if (child_info->marked_for_deletion &&
1505 child_info->parent_to_child_map.empty()) {
1506 DCHECK(child_info->child_to_parent_map.empty());
1507 children_.erase(child_it);
1511 void ResourceProvider::AcquirePixelBuffer(ResourceId id) {
1512 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1513 "ResourceProvider::AcquirePixelBuffer");
1515 Resource* resource = GetResource(id);
1516 DCHECK(resource->origin == Resource::INTERNAL);
1517 DCHECK_EQ(resource->exported_count, 0);
1518 DCHECK(!resource->image_id);
1519 DCHECK_NE(ETC1, resource->format);
1521 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
1522 GLES2Interface* gl = ContextGL();
1523 DCHECK(gl);
1524 if (!resource->gl_pixel_buffer_id)
1525 resource->gl_pixel_buffer_id = buffer_id_allocator_->NextId();
1526 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1527 resource->gl_pixel_buffer_id);
1528 unsigned bytes_per_pixel = BitsPerPixel(resource->format) / 8;
1529 gl->BufferData(
1530 GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1531 resource->size.height() *
1532 MathUtil::RoundUp(bytes_per_pixel * resource->size.width(), 4u),
1533 NULL, GL_DYNAMIC_DRAW);
1534 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
1537 void ResourceProvider::ReleasePixelBuffer(ResourceId id) {
1538 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1539 "ResourceProvider::ReleasePixelBuffer");
1541 Resource* resource = GetResource(id);
1542 DCHECK(resource->origin == Resource::INTERNAL);
1543 DCHECK_EQ(resource->exported_count, 0);
1544 DCHECK(!resource->image_id);
1546 // The pixel buffer can be released while there is a pending "set pixels"
1547 // if completion has been forced. Any shared memory associated with this
1548 // pixel buffer will not be freed until the waitAsyncTexImage2DCHROMIUM
1549 // command has been processed on the service side. It is also safe to
1550 // reuse any query id associated with this resource before they complete
1551 // as each new query has a unique submit count.
1552 if (resource->pending_set_pixels) {
1553 DCHECK(resource->set_pixels_completion_forced);
1554 resource->pending_set_pixels = false;
1555 resource->locked_for_write = false;
1558 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
1559 if (!resource->gl_pixel_buffer_id)
1560 return;
1561 GLES2Interface* gl = ContextGL();
1562 DCHECK(gl);
1563 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1564 resource->gl_pixel_buffer_id);
1565 gl->BufferData(
1566 GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0, NULL, GL_DYNAMIC_DRAW);
1567 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
1570 uint8_t* ResourceProvider::MapPixelBuffer(ResourceId id, int* stride) {
1571 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1572 "ResourceProvider::MapPixelBuffer");
1574 Resource* resource = GetResource(id);
1575 DCHECK(resource->origin == Resource::INTERNAL);
1576 DCHECK_EQ(resource->exported_count, 0);
1577 DCHECK(!resource->image_id);
1579 *stride = 0;
1580 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
1581 GLES2Interface* gl = ContextGL();
1582 DCHECK(gl);
1583 DCHECK(resource->gl_pixel_buffer_id);
1584 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1585 resource->gl_pixel_buffer_id);
1586 uint8_t* image = static_cast<uint8_t*>(gl->MapBufferCHROMIUM(
1587 GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, GL_WRITE_ONLY));
1588 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
1589 // Buffer is required to be 4-byte aligned.
1590 CHECK(!(reinterpret_cast<intptr_t>(image) & 3));
1591 return image;
1594 void ResourceProvider::UnmapPixelBuffer(ResourceId id) {
1595 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1596 "ResourceProvider::UnmapPixelBuffer");
1598 Resource* resource = GetResource(id);
1599 DCHECK(resource->origin == Resource::INTERNAL);
1600 DCHECK_EQ(resource->exported_count, 0);
1601 DCHECK(!resource->image_id);
1603 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
1604 GLES2Interface* gl = ContextGL();
1605 DCHECK(gl);
1606 DCHECK(resource->gl_pixel_buffer_id);
1607 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1608 resource->gl_pixel_buffer_id);
1609 gl->UnmapBufferCHROMIUM(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM);
1610 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
1613 GLenum ResourceProvider::BindForSampling(ResourceId resource_id,
1614 GLenum unit,
1615 GLenum filter) {
1616 DCHECK(thread_checker_.CalledOnValidThread());
1617 GLES2Interface* gl = ContextGL();
1618 ResourceMap::iterator it = resources_.find(resource_id);
1619 DCHECK(it != resources_.end());
1620 Resource* resource = &it->second;
1621 DCHECK(resource->lock_for_read_count);
1622 DCHECK(!resource->locked_for_write || resource->set_pixels_completion_forced);
1624 ScopedSetActiveTexture scoped_active_tex(gl, unit);
1625 GLenum target = resource->target;
1626 gl->BindTexture(target, resource->gl_id);
1627 if (filter != resource->filter) {
1628 gl->TexParameteri(target, GL_TEXTURE_MIN_FILTER, filter);
1629 gl->TexParameteri(target, GL_TEXTURE_MAG_FILTER, filter);
1630 resource->filter = filter;
1633 if (resource->image_id && resource->dirty_image)
1634 BindImageForSampling(resource);
1636 return target;
1639 void ResourceProvider::BeginSetPixels(ResourceId id) {
1640 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1641 "ResourceProvider::BeginSetPixels");
1643 Resource* resource = GetResource(id);
1644 DCHECK(!resource->pending_set_pixels);
1646 LazyCreate(resource);
1647 DCHECK(resource->origin == Resource::INTERNAL);
1648 DCHECK(resource->gl_id || resource->allocated);
1649 DCHECK(ReadLockFenceHasPassed(resource));
1650 DCHECK(!resource->image_id);
1652 bool allocate = !resource->allocated;
1653 resource->allocated = true;
1654 LockForWrite(id);
1656 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
1657 DCHECK(resource->gl_id);
1658 GLES2Interface* gl = ContextGL();
1659 DCHECK(gl);
1660 DCHECK(resource->gl_pixel_buffer_id);
1661 DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D));
1662 gl->BindTexture(GL_TEXTURE_2D, resource->gl_id);
1663 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
1664 resource->gl_pixel_buffer_id);
1665 if (!resource->gl_upload_query_id)
1666 gl->GenQueriesEXT(1, &resource->gl_upload_query_id);
1667 gl->BeginQueryEXT(GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM,
1668 resource->gl_upload_query_id);
1669 if (allocate) {
1670 gl->AsyncTexImage2DCHROMIUM(GL_TEXTURE_2D,
1671 0, /* level */
1672 GLInternalFormat(resource->format),
1673 resource->size.width(),
1674 resource->size.height(),
1675 0, /* border */
1676 GLDataFormat(resource->format),
1677 GLDataType(resource->format),
1678 NULL);
1679 } else {
1680 gl->AsyncTexSubImage2DCHROMIUM(GL_TEXTURE_2D,
1681 0, /* level */
1682 0, /* x */
1683 0, /* y */
1684 resource->size.width(),
1685 resource->size.height(),
1686 GLDataFormat(resource->format),
1687 GLDataType(resource->format),
1688 NULL);
1690 gl->EndQueryEXT(GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM);
1691 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
1693 resource->pending_set_pixels = true;
1694 resource->set_pixels_completion_forced = false;
1697 void ResourceProvider::ForceSetPixelsToComplete(ResourceId id) {
1698 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1699 "ResourceProvider::ForceSetPixelsToComplete");
1701 Resource* resource = GetResource(id);
1703 DCHECK(resource->locked_for_write);
1704 DCHECK(resource->pending_set_pixels);
1705 DCHECK(!resource->set_pixels_completion_forced);
1707 if (resource->gl_id) {
1708 GLES2Interface* gl = ContextGL();
1709 gl->BindTexture(GL_TEXTURE_2D, resource->gl_id);
1710 gl->WaitAsyncTexImage2DCHROMIUM(GL_TEXTURE_2D);
1711 gl->BindTexture(GL_TEXTURE_2D, 0);
1714 resource->set_pixels_completion_forced = true;
1717 bool ResourceProvider::DidSetPixelsComplete(ResourceId id) {
1718 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
1719 "ResourceProvider::DidSetPixelsComplete");
1721 Resource* resource = GetResource(id);
1723 DCHECK(resource->locked_for_write);
1724 DCHECK(resource->pending_set_pixels);
1726 if (resource->gl_id) {
1727 GLES2Interface* gl = ContextGL();
1728 DCHECK(gl);
1729 DCHECK(resource->gl_upload_query_id);
1730 GLuint complete = 1;
1731 gl->GetQueryObjectuivEXT(
1732 resource->gl_upload_query_id, GL_QUERY_RESULT_AVAILABLE_EXT, &complete);
1733 if (!complete)
1734 return false;
1737 resource->pending_set_pixels = false;
1738 UnlockForWrite(resource);
1740 // Async set pixels commands are not necessarily processed in-sequence with
1741 // drawing commands. Read lock fences are required to ensure that async
1742 // commands don't access the resource while used for drawing.
1743 resource->read_lock_fences_enabled = true;
1745 return true;
1748 void ResourceProvider::CreateForTesting(ResourceId id) {
1749 LazyCreate(GetResource(id));
1752 GLenum ResourceProvider::TargetForTesting(ResourceId id) {
1753 Resource* resource = GetResource(id);
1754 return resource->target;
1757 void ResourceProvider::LazyCreate(Resource* resource) {
1758 if (resource->type != RESOURCE_TYPE_GL_TEXTURE ||
1759 resource->origin != Resource::INTERNAL)
1760 return;
1762 if (resource->gl_id)
1763 return;
1765 DCHECK(resource->texture_pool);
1766 DCHECK(resource->origin == Resource::INTERNAL);
1767 DCHECK(!resource->mailbox.IsValid());
1768 resource->gl_id = texture_id_allocator_->NextId();
1770 GLES2Interface* gl = ContextGL();
1771 DCHECK(gl);
1773 // Create and set texture properties. Allocation is delayed until needed.
1774 gl->BindTexture(resource->target, resource->gl_id);
1775 gl->TexParameteri(resource->target, GL_TEXTURE_MIN_FILTER,
1776 resource->original_filter);
1777 gl->TexParameteri(resource->target, GL_TEXTURE_MAG_FILTER,
1778 resource->original_filter);
1779 gl->TexParameteri(resource->target, GL_TEXTURE_WRAP_S, resource->wrap_mode);
1780 gl->TexParameteri(resource->target, GL_TEXTURE_WRAP_T, resource->wrap_mode);
1781 gl->TexParameteri(resource->target, GL_TEXTURE_POOL_CHROMIUM,
1782 resource->texture_pool);
1783 if (use_texture_usage_hint_ && (resource->hint & TEXTURE_HINT_FRAMEBUFFER)) {
1784 gl->TexParameteri(resource->target, GL_TEXTURE_USAGE_ANGLE,
1785 GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
1789 void ResourceProvider::AllocateForTesting(ResourceId id) {
1790 LazyAllocate(GetResource(id));
1793 void ResourceProvider::LazyAllocate(Resource* resource) {
1794 DCHECK(resource);
1795 if (resource->allocated)
1796 return;
1797 LazyCreate(resource);
1798 if (!resource->gl_id)
1799 return;
1800 resource->allocated = true;
1801 GLES2Interface* gl = ContextGL();
1802 gfx::Size& size = resource->size;
1803 ResourceFormat format = resource->format;
1804 gl->BindTexture(resource->target, resource->gl_id);
1805 if (use_texture_storage_ext_ &&
1806 IsFormatSupportedForStorage(format, use_texture_format_bgra_) &&
1807 (resource->hint & TEXTURE_HINT_IMMUTABLE)) {
1808 GLenum storage_format = TextureToStorageFormat(format);
1809 gl->TexStorage2DEXT(resource->target, 1, storage_format, size.width(),
1810 size.height());
1811 } else {
1812 // ETC1 does not support preallocation.
1813 if (format != ETC1) {
1814 gl->TexImage2D(resource->target, 0, GLInternalFormat(format),
1815 size.width(), size.height(), 0, GLDataFormat(format),
1816 GLDataType(format), NULL);
1821 void ResourceProvider::BindImageForSampling(Resource* resource) {
1822 GLES2Interface* gl = ContextGL();
1823 DCHECK(resource->gl_id);
1824 DCHECK(resource->image_id);
1826 // Release image currently bound to texture.
1827 if (resource->bound_image_id)
1828 gl->ReleaseTexImage2DCHROMIUM(resource->target, resource->bound_image_id);
1829 gl->BindTexImage2DCHROMIUM(resource->target, resource->image_id);
1830 resource->bound_image_id = resource->image_id;
1831 resource->dirty_image = false;
1834 void ResourceProvider::CopyResource(ResourceId source_id,
1835 ResourceId dest_id,
1836 const gfx::Rect& rect) {
1837 TRACE_EVENT0("cc", "ResourceProvider::CopyResource");
1839 Resource* source_resource = GetResource(source_id);
1840 DCHECK(!source_resource->lock_for_read_count);
1841 DCHECK(source_resource->origin == Resource::INTERNAL);
1842 DCHECK_EQ(source_resource->exported_count, 0);
1843 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, source_resource->type);
1844 LazyAllocate(source_resource);
1846 Resource* dest_resource = GetResource(dest_id);
1847 DCHECK(!dest_resource->locked_for_write);
1848 DCHECK(!dest_resource->lock_for_read_count);
1849 DCHECK(dest_resource->origin == Resource::INTERNAL);
1850 DCHECK_EQ(dest_resource->exported_count, 0);
1851 DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, dest_resource->type);
1852 LazyAllocate(dest_resource);
1854 DCHECK_EQ(source_resource->type, dest_resource->type);
1855 DCHECK_EQ(source_resource->format, dest_resource->format);
1856 DCHECK(source_resource->size == dest_resource->size);
1857 DCHECK(gfx::Rect(dest_resource->size).Contains(rect));
1859 GLES2Interface* gl = ContextGL();
1860 DCHECK(gl);
1861 if (source_resource->image_id && source_resource->dirty_image) {
1862 gl->BindTexture(source_resource->target, source_resource->gl_id);
1863 BindImageForSampling(source_resource);
1865 if (use_sync_query_) {
1866 if (!source_resource->gl_read_lock_query_id)
1867 gl->GenQueriesEXT(1, &source_resource->gl_read_lock_query_id);
1868 #if defined(OS_CHROMEOS)
1869 // TODO(reveman): This avoids a performance problem on some ChromeOS
1870 // devices. This needs to be removed to support native GpuMemoryBuffer
1871 // implementations. crbug.com/436314
1872 gl->BeginQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM,
1873 source_resource->gl_read_lock_query_id);
1874 #else
1875 gl->BeginQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM,
1876 source_resource->gl_read_lock_query_id);
1877 #endif
1879 DCHECK(!dest_resource->image_id);
1880 dest_resource->allocated = true;
1881 gl->CopySubTextureCHROMIUM(dest_resource->target, source_resource->gl_id,
1882 dest_resource->gl_id, rect.x(), rect.y(), rect.x(),
1883 rect.y(), rect.width(), rect.height(),
1884 false, false, false);
1885 if (source_resource->gl_read_lock_query_id) {
1886 // End query and create a read lock fence that will prevent access to
1887 // source resource until CopySubTextureCHROMIUM command has completed.
1888 #if defined(OS_CHROMEOS)
1889 gl->EndQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM);
1890 #else
1891 gl->EndQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM);
1892 #endif
1893 source_resource->read_lock_fence = make_scoped_refptr(
1894 new CopyTextureFence(gl, source_resource->gl_read_lock_query_id));
1895 } else {
1896 // Create a SynchronousFence when CHROMIUM_sync_query extension is missing.
1897 // Try to use one synchronous fence for as many CopyResource operations as
1898 // possible as that reduce the number of times we have to synchronize with
1899 // the GL.
1900 if (!synchronous_fence_.get() || synchronous_fence_->has_synchronized())
1901 synchronous_fence_ = make_scoped_refptr(new SynchronousFence(gl));
1902 source_resource->read_lock_fence = synchronous_fence_;
1903 source_resource->read_lock_fence->Set();
1907 void ResourceProvider::WaitSyncPointIfNeeded(ResourceId id) {
1908 Resource* resource = GetResource(id);
1909 DCHECK_EQ(resource->exported_count, 0);
1910 DCHECK(resource->allocated);
1911 if (resource->type != RESOURCE_TYPE_GL_TEXTURE || resource->gl_id)
1912 return;
1913 if (!resource->mailbox.sync_point())
1914 return;
1915 DCHECK(resource->mailbox.IsValid());
1916 GLES2Interface* gl = ContextGL();
1917 DCHECK(gl);
1918 gl->WaitSyncPointCHROMIUM(resource->mailbox.sync_point());
1919 resource->mailbox.set_sync_point(0);
1922 void ResourceProvider::WaitReadLockIfNeeded(ResourceId id) {
1923 Resource* resource = GetResource(id);
1924 DCHECK_EQ(resource->exported_count, 0);
1925 if (!resource->read_lock_fence.get())
1926 return;
1928 resource->read_lock_fence->Wait();
1931 GLint ResourceProvider::GetActiveTextureUnit(GLES2Interface* gl) {
1932 GLint active_unit = 0;
1933 gl->GetIntegerv(GL_ACTIVE_TEXTURE, &active_unit);
1934 return active_unit;
1937 void ResourceProvider::ValidateResource(ResourceId id) const {
1938 DCHECK(thread_checker_.CalledOnValidThread());
1939 DCHECK(id);
1940 DCHECK(resources_.find(id) != resources_.end());
1943 GLES2Interface* ResourceProvider::ContextGL() const {
1944 ContextProvider* context_provider = output_surface_->context_provider();
1945 return context_provider ? context_provider->ContextGL() : NULL;
1948 class GrContext* ResourceProvider::GrContext(bool worker_context) const {
1949 ContextProvider* context_provider =
1950 worker_context ? output_surface_->worker_context_provider()
1951 : output_surface_->context_provider();
1952 return context_provider ? context_provider->GrContext() : NULL;
1955 } // namespace cc